Add tag listing functionality
authorChip Black <bytex64@bytex64.net>
Sun, 19 Dec 2010 06:19:26 +0000 (00:19 -0600)
committerChip Black <bytex64@bytex64.net>
Sun, 19 Dec 2010 06:19:26 +0000 (00:19 -0600)
.gitignore
Makefile
blergtool.c
config.h
tags.c
tags.h

index e1c975d..34b462f 100644 (file)
@@ -1,3 +1,8 @@
 *~
 *.o
+*.a
+*.so
 blergtool
+http_blerg
+cgi_blerg
+fcgi_blerg
index c0050db..a116407 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -5,8 +5,6 @@ targets = blerg.a blergtool tag_test
 blerg_a_objects = database.o tags.o
 blergtool_objects = blergtool.o blerg.a
 
-tag_test_objects = tag_test.o tags.o
-
 all: $(targets)
 
 clean:
@@ -18,8 +16,5 @@ blerg.a: $(blerg_a_objects)
 blergtool: $(blergtool_objects)
        gcc $^ -o $@
 
-tag_test: $(tag_test_objects)
-       gcc $^ -o $@
-
 %.o: %.c
        gcc $(CFLAGS) $(LIBS) -c $< -o $@
index a0148c0..d5aef50 100644 (file)
@@ -1,6 +1,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include "database.h"
+#include "tags.h"
 
 void help() {
        printf("Usage: blergtool <store|fetch> <storename> [record]\n");
@@ -50,6 +51,19 @@ int main(int argc, char *argv[]) {
                blerg_close(f);
                fwrite(data, 1, size, stdout);
                free(data);
+       } else if (strncmp(argv[1], "list", 4) == 0) {
+               char *tag = argv[2];
+               uint64_t count = 50;
+               struct tag *list = tag_list(tag, 0, &count, -1);
+               if (list == NULL) {
+                       printf("No entries");
+               } else {
+                       int i;
+                       for (i = 0; i < count; i++) {
+                               printf("%s %d\n", list[i].author, list[i].record);
+                       }
+                       free(list);
+               }
        } else {
                help();
        }
index 1b5e49d..726792e 100644 (file)
--- a/config.h
+++ b/config.h
@@ -2,6 +2,7 @@
 #define _CONFIG_H
 
 #define DATA_PATH "data"
-#define TAGS_PATH "tags"
+#define HASH_TAGS_PATH "hash_tags"
+#define AUTHOR_TAGS_PATH "author_tags"
 
 #endif //_CONFIG_H
diff --git a/tags.c b/tags.c
index 96e7378..4705b87 100644 (file)
--- a/tags.c
+++ b/tags.c
@@ -6,6 +6,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/file.h>
+#include <sys/mman.h>
 #include "tags.h"
 #include "config.h"
 
@@ -21,18 +22,19 @@ int tag_scan(const char *author, const char *data, int len, uint64_t record) {
 
        for (i = 0; i < len; i++) {
 tag_scan_start:
-               if (data[i] == '#') {
+               if (data[i] == '#' || data[i] == '@') {
                        if (n_tags == MAX_TAGS) {
                                fprintf(stderr, "Too many tags in message\n");
                                break;
                        }
+                       int begin = i;
                        int start = ++i;
                        while (i < len && TAG_CHAR(data[i]) && (i - start < MAX_TAG_LENGTH)) {
                                i++;
                        }
                        if (start - i == 0) continue;
-                       char *tag = calloc(1, MAX_TAG_LENGTH + 1);
-                       memcpy(tag, &data[start], i - start);
+                       char *tag = calloc(1, MAX_TAG_LENGTH + 2);
+                       memcpy(tag, &data[begin], i - begin);
                        for (j = 0; j < n_tags; j++) {
                                if (!strncmp(tag, taglist[j], MAX_TAG_LENGTH)) {
                                        // We already have this tag.  Start over.
@@ -61,7 +63,18 @@ int tag_add(const char *author, const char *tag, uint64_t record) {
        strncpy(t.author, author, 32);
        t.record = record;
 
-       snprintf(filename, 512, "%s/%s", TAGS_PATH, tag);
+       switch(tag[0]) {
+       case '#':
+               snprintf(filename, 512, "%s/%s", HASH_TAGS_PATH, tag + 1);
+               break;
+       case '@':
+               snprintf(filename, 512, "%s/%s", AUTHOR_TAGS_PATH, tag + 1);
+               break;
+       default:
+               fprintf(stderr, "Invalid tag type: %s\n", tag);
+               return 0;
+       }
+
        int tag_fd = open(filename, O_WRONLY | O_APPEND | O_CREAT, 0600);
        flock(tag_fd, LOCK_EX);
        if (tag_fd == -1) {
@@ -79,5 +92,72 @@ int tag_add(const char *author, const char *tag, uint64_t record) {
        return 1;
 }
 
-int tag_list(const char *tag, int start, int count) {
+struct tag * tag_list(const char *tag, uint64_t offset, uint64_t *count, int direction) {
+       char filename[512];
+       struct stat st;
+       struct tag *taglist;
+       struct tag *retlist;
+       uint64_t n_tag_records;
+       
+       switch(tag[0]) {
+       case '#':
+               snprintf(filename, 512, "%s/%s", HASH_TAGS_PATH, tag + 1);
+               break;
+       case '@':
+               snprintf(filename, 512, "%s/%s", AUTHOR_TAGS_PATH, tag + 1);
+               break;
+       default:
+               fprintf(stderr, "Invalid tag type: %s\n", tag);
+               return 0;
+       }
+
+       int tag_fd = open(filename, O_RDONLY, 0600);
+       if (tag_fd == -1) {
+               perror("Could not open tag file");
+               *count = 0;
+               return NULL;
+       }
+
+       fstat(tag_fd, &st);
+       if (st.st_size == 0) {
+               close(tag_fd);
+               *count = 0;
+               return NULL;
+       }
+       n_tag_records = st.st_size / sizeof(struct tag);
+       if (*count > n_tag_records)
+               *count = n_tag_records;
+       if (offset > n_tag_records) {
+               fprintf(stderr, "Cannot access tag record beyond end\n");
+               return NULL;
+       }
+
+       taglist = (struct tag *) mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, tag_fd, 0);
+       if (taglist == MAP_FAILED) {
+               perror("Could not mmap tag file");
+               goto tag_list_map_failed;
+       }
+       retlist = (struct tag *) malloc(sizeof(struct tag) * *count);
+       if (retlist == NULL) {
+               perror("Could not allocate memory for tag list");
+               goto tag_list_malloc_failed;
+       }
+       switch(direction) {
+       case 1:
+               memcpy(retlist, taglist + offset, sizeof(struct tag) * *count);
+               break;
+       case -1:
+               memcpy(retlist, taglist + (n_tag_records - *count - offset), sizeof(struct tag) * *count);
+               break;
+       }
+
+       munmap(taglist, st.st_size);
+       return retlist;
+
+tag_list_malloc_failed:
+       munmap(taglist, st.st_size);
+tag_list_map_failed:
+       close(tag_fd);
+tag_list_open_failed:
+       return NULL;
 }
diff --git a/tags.h b/tags.h
index 3247caa..df0cf98 100644 (file)
--- a/tags.h
+++ b/tags.h
@@ -10,6 +10,6 @@ struct tag {
 
 int tag_scan(const char *, const char *, int, uint64_t);
 int tag_add(const char *, const char *, uint64_t);
-int tag_list(const char *, int, int);
+struct tag * tag_list(const char *, uint64_t, uint64_t *, int);
 
 #endif //_TAGS_H