diff options
-rw-r--r-- | hash.c | 15 | ||||
-rw-r--r-- | hash.h | 30 | ||||
-rw-r--r-- | hash_help.inc | 41 | ||||
-rw-r--r-- | macro.h | 10 | ||||
-rw-r--r-- | main.c | 67 | ||||
-rw-r--r-- | parse.c | 197 | ||||
-rw-r--r-- | parse.h | 41 | ||||
-rw-r--r-- | vcal.c | 69 | ||||
-rw-r--r-- | vcal.h | 43 |
9 files changed, 357 insertions, 156 deletions
@@ -0,0 +1,15 @@ +#include "hash.h" + +/* + * http://www.cse.yorku.ca/~oz/hash.html + * djb2 from above url. + */ +unsigned long hash(char* str) { + unsigned long hash = 5381; + int c; + + while ( (c = *str++) ) + hash = ((hash << 5) + hash) + c; + + return hash; +} @@ -0,0 +1,30 @@ +#ifndef HASH_H +#define HASH_H + +#include <string.h> + +#include "macro.h" + +unsigned long hash(char*); + +#define TABLE(T) TP(table_, T) +#define HASH_PUT(T) TP(hash_put_, T) +#define HASH_GET(T) TP(hash_get_, T) +#define HASH_INIT(T) TP(hash_init_, T) + +#endif /* HASH_H */ +#ifdef TYPE + +typedef struct { + int size; + int item_count; + TYPE* values; +} TABLE(TYPE); + +int HASH_PUT(TYPE) ( TABLE(TYPE)* table, TYPE* value ); + +int HASH_INIT(TYPE) ( TABLE(TYPE)* table, int init_size ); + +TYPE* HASH_GET(TYPE) ( TABLE(TYPE)* table, char* key ); + +#endif /* HASH_H */ diff --git a/hash_help.inc b/hash_help.inc new file mode 100644 index 00000000..19463be4 --- /dev/null +++ b/hash_help.inc @@ -0,0 +1,41 @@ +#ifndef TYPE +#error "Set TYPE to something before including this header" +#else + +int HASH_PUT(TYPE) ( TABLE(TYPE)* table, TYPE* value) { + // TODO genicify the hash function + unsigned long h = hash(value->key.mem) % table->size; + table->values[h] = *value; + + /* TODO conflict resolution */ + + ++table->item_count; + return 0; +} + +int HASH_INIT(TYPE) ( TABLE(TYPE)* table, int init_size ) { + /* + * TODO parts of table might not get properly initialized to 0 + */ + table->values = calloc(sizeof(table->values), init_size); + table->size = init_size; + table->item_count = 0; + return 0; +} + +TYPE* HASH_GET(TYPE) ( TABLE(TYPE)* table, char* key ) { + unsigned long h = hash(key) % table->size; + TYPE* mem = (table->values + h); + if (mem == NULL) { + return 0; + } else if (strcmp(mem->key.mem, key) == 0) { + return mem; + } else { + /* TODO fix retrival on invalid key */ + } + return 0; +} + +#endif /* TYPE */ + +// vim: ft=c diff --git a/macro.h b/macro.h new file mode 100644 index 00000000..c4b3fc9b --- /dev/null +++ b/macro.h @@ -0,0 +1,10 @@ +#ifndef MACRO_H +#define MACRO_H + +#define TP(a, b) a ## b + +#define NEW(T, N, ...) \ + T* N = malloc(sizeof(*N)); \ + TP(T, _init) (N, __VA_ARGS__); + +#endif /* MACRO_H */ @@ -0,0 +1,67 @@ +#include <dirent.h> +#include <errno.h> + +/* + * These three are only for some FD hacks. + */ +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include "parse.h" + +int main (int argc, char* argv[argc]) { + if (argc < 2) { + //puts("Please give a ics file as first argument"); + puts("Please give vdir as first argument"); + exit (1); + } + vcalendar cal; + init_vcalendar(&cal); + + char* dname = argv[1]; + DIR* dir = opendir(dname); + struct dirent* d; + int fcount = 0; + while ((d = readdir(dir)) != NULL) { + + + /* Check that it's a regular file */ + if (d->d_type != DT_REG) continue; + + /* Check that we have an ICS file */ + char *s, *fname; + s = fname = d->d_name; + while (*(s++) != '.'); + if (strcmp(s, "ics") != 0) continue; + + /* We now assume that it's a good file, and start parsing it */ + + int fd = openat(dirfd(dir), fname, O_RDONLY); + + FILE* f = fdopen(fd, "r"); + if (f == NULL) { + fprintf(stderr, "Error opening file [%s], errno = %i\n", + fname, errno); + exit (1); + } + + printf("%3i | %s\n", fcount++, fname); + /* TODO currently the hedaers cal is overwritten each + * iteration (not really, since I don't save any headers). + * Preferably, a special case is made for vdir structures + * which can assume that all headers are equal. */ + parse_file(f, &cal); + fclose(f); + + } + + printf("\nParsed calendar file containing [%lu] events\n", + cal.n_events); + for (size_t i = 0; i < cal.n_events; i++) { + // printf("%3lu. %s\n", i + 1, cal.events[i].summary.mem); + printf("%3lu. %s\n", i + 1, get_property(&cal.events[i], "SUMMARY")->val.mem); + } + + free_vcalendar(&cal); +} @@ -1,4 +1,7 @@ -#define SAFE_STR +#include "parse.h" + +#include "macro.h" + /* * TODO currently not all pointers inside strings are reset correctly, @@ -8,44 +11,8 @@ * along with the introduction of a MSG macro. */ -#include <stdio.h> -#include <stdlib.h> #include <errno.h> #include <string.h> -#include <dirent.h> - -/* - * These three are only for some FD hacks. - */ -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> - -#include "strbuf.h" -#include "vcal.h" - -/* - * Max length of a line. - * TODO update this to allow longer lines, in case someone doesn't - * follow the standard. - */ -#define SEGSIZE 75 - -#define ERR(x, line) do { \ - fprintf(stderr, "ERR %i: %s (cal %i)\n", __LINE__, (x), (line)); \ -} while(0) - -#define LINE(nr, key, value) fprintf(stderr, "%i: [%s] := [%s]\n", nr, key, value); - -typedef enum { - p_key, p_value -} part_context; - -typedef enum { - s_none, s_calendar, s_event -} scope_context; - -int handle_kv(vcalendar* cal, vevent* ev, string* key, string* val, int line, scope_context* s_ctx); int parse_file(FILE* f, vcalendar* cal) { int segments = 1; @@ -58,18 +25,17 @@ int parse_file(FILE* f, vcalendar* cal) { int keylen = 100; int vallen = 100; - string key, val; - - init_string(&key, keylen); - init_string(&val, vallen); - int line = 0; - vevent ev; + // TODO this can apparently segfault... + NEW(vevent, ev, /**/ 100); + + content_line cline; + init_content_line (&cline, keylen, vallen); char c; - // TODO this segfaults... while ( (c = fgetc(f)) != EOF) { + // D E S (-48 '\320') /* * A carrige return means that the current line is at an * end. The following character should always be \n. @@ -84,35 +50,47 @@ int parse_file(FILE* f, vcalendar* cal) { if (s[0] != '\n') { ERR("expected newline after CR", line); } else if (s[1] == ' ' || s[1] == '\t') { + /* + * Folded line, increase size of key and continue. + */ + // TODO check return value // TODO segments is always incremented here, meaning // that segment grows larger for every multi line // encountered. -#if 1 if (realloc_string(&str, ++segments * SEGSIZE) != 0) { /* TODO signal error */ ERR("Failed to realloc string", line); exit (1); } -#endif continue; } else { + /* + * Actuall end of line, handle values. + */ if (ungetc(s[1], f) != s[1]) { /* TODO signal error */ exit (2); } /* At TRUE end of line */ + /* if (str.ptr + 1 > vallen) { vallen = str.ptr + 1; - realloc_string(&val, vallen); + // TODO this fails + realloc_string(&cline.val, vallen); } - copy_strbuf(&val, &str); - strbuf_cap(&val); + */ + copy_strbuf(&cline.val, &str); + strbuf_cap(&cline.val); ++line; /* We just got a value */ // LINE(line, key.mem, val.mem); - handle_kv(cal, &ev, &key, &val, line, &s_ctx); + if (strbuf_c(&cline.key, "LOCATION")) { + if (strbuf_c(&cline.val, "")) return 1; + LINE(line, cline.key.mem, cline.val.mem); + } + handle_kv(cal, ev, &cline, line, &s_ctx); strbuf_soft_reset(&str); p_ctx = p_key; @@ -120,14 +98,14 @@ int parse_file(FILE* f, vcalendar* cal) { } } else if (p_ctx == p_key && c == ':') { /* - if (str.ptr + 1 > keylen) { - keylen = str.ptr + 1; - // TODO this might break everything - realloc_string(&key, keylen); + if (str.ptr + 1 > keylen) { + keylen = str.ptr + 1; + // TODO this might break everything + realloc_string(&key, keylen); } */ - copy_strbuf(&key, &str); - *strbuf_end(&key) = 0; + copy_strbuf(&cline.key, &str); + strbuf_cap(&cline.key); strbuf_soft_reset(&str); p_ctx = p_value; continue; @@ -135,7 +113,9 @@ int parse_file(FILE* f, vcalendar* cal) { strbuf_append(&str, c); } - if (errno != 0) { + + + if (! feof(f)) { ERR("Error parsing", errno); } else { /* @@ -145,122 +125,63 @@ int parse_file(FILE* f, vcalendar* cal) { */ if (str.ptr + 1 > vallen) { vallen = str.ptr + 1; - realloc_string(&val, vallen); + realloc_string(&cline.val, vallen); } - copy_strbuf(&val, &str); - *strbuf_cur(&val) = 0; + copy_strbuf(&cline.val, &str); + *strbuf_cur(&cline.val) = 0; } - free_vevent(&ev); free_string(&str); - free_string(&key); - free_string(&val); + content_line_free(&cline); return 0; } -int main (int argc, char* argv[argc]) { - if (argc < 2) { - //puts("Please give a ics file as first argument"); - puts("Please give vdir as first argument"); - exit (1); - } - vcalendar cal; - init_vcalendar(&cal); - - char* dname = argv[1]; - DIR* dir = opendir(dname); - struct dirent* d; - int fcount = 0; - while ((d = readdir(dir)) != NULL) { - - - /* Check that it's a regular file */ - if (d->d_type != DT_REG) continue; - - /* Check that we have an ICS file */ - char *s, *fname; - s = fname = d->d_name; - while (*(s++) != '.'); - if (strcmp(s, "ics") != 0) continue; - - /* We now assume that it's a good file, and start parsing it */ - - int fd = openat(dirfd(dir), fname, O_RDONLY); - - FILE* f = fdopen(fd, "r"); - if (f == NULL) { - fprintf(stderr, "Error opening file [%s], errno = %i\n", - fname, errno); - exit (1); - } - - printf("%3i | %s\n", fcount++, fname); - /* TODO currently the hedaers cal is overwritten each - * iteration (not really, since I don't save any headers). - * Preferably, a special case is made for vdir structures - * which can assume that all headers are equal. */ - parse_file(f, &cal); - fclose(f); - - } - - printf("\nParsed calendar file containing [%lu] events\n", - cal.n_events); - for (size_t i = 0; i < cal.n_events; i++) { - printf("%3lu. %s\n", i + 1, cal.events[i].summary.mem); - } - - free_vcalendar(&cal); -} - -int handle_kv(vcalendar* cal, vevent* ev, string* key, string* val, int line, scope_context* s_ctx) { +int handle_kv( + vcalendar* cal, + vevent* ev, + content_line* cline, + int line, + scope_context* s_ctx + ) { switch (*s_ctx) { case s_none: - /* Both key and val is null here */ - if (! (strbuf_c(key, "BEGIN") && strbuf_c(val, "VCALENDAR"))) { + if (! (strbuf_c(&cline->key, "BEGIN") && strbuf_c(&cline->val, "VCALENDAR"))) { ERR("Invalid start of calendar", line); return 1; } *s_ctx = s_calendar; break; case s_calendar: - if (strbuf_c(key, "BEGIN")) { - if (strbuf_c(val, "VEVENT")) { + if (strbuf_c(&cline->key, "BEGIN")) { + if (strbuf_c(&cline->val, "VEVENT")) { *s_ctx = s_event; break; } else { ERR("Unsupported start", line); return 2; } - } else if (strbuf_c(key, "END")) { - if (strbuf_c(val, "VCALENDAR")) { + } else if (strbuf_c(&cline->key, "END")) { + if (strbuf_c(&cline->val, "VCALENDAR")) { *s_ctx = s_none; - /* GOTO cleanup */ break; } } break; case s_event: - /* */ if (strbuf_c(key, "DTSTART")) { - strbuf_init_copy(&ev->dtstart, val); - } else if (strbuf_c(key, "DTEND")) { - strbuf_init_copy(&ev->dtend, val); - } else if (strbuf_c(key, "SUMMARY")) { - strbuf_init_copy(&ev->summary, val); - } else if (strbuf_c(key, "DESCRIPTION")) { - strbuf_init_copy(&ev->description, val); - } else if (strbuf_c(key, "END")) { - if (strbuf_c(val, "VEVENT")) { + if (strbuf_c(&cline->key, "END")) { + if (strbuf_c(&cline->val, "VEVENT")) { push_event(cal, ev); *s_ctx = s_calendar; } else { ERR("Trying to end something, expected VEVENT", line); return 3; } + } else { + content_line* c = malloc(sizeof(*c)); + content_line_copy(c, cline); + add_content_line (ev, c); } - break; } - return 0; } diff --git a/parse.h b/parse.h new file mode 100644 index 00000000..cb6c2d1e --- /dev/null +++ b/parse.h @@ -0,0 +1,41 @@ +#ifndef PARSE_H +#define PARSE_H + +#define SAFE_STR + +#include <stdio.h> +#include <stdlib.h> + +#include "strbuf.h" +#include "vcal.h" + +/* + * Max length of a line. + * TODO update this to allow longer lines, in case someone doesn't + * follow the standard. + */ +#define SEGSIZE 75 + +#define ERR(x, line) fprintf(stderr, "ERR %i: %s (cal %i)\n", __LINE__, (x), (line)); + +#define LINE(nr, key, value) fprintf(stderr, "(%i) %i: [%s] := [%s]\n", __LINE__, nr, key, value); + +typedef enum { + p_key, p_value, p_param_name, p_param_value +} part_context; + +typedef enum { + s_none, s_calendar, s_event +} scope_context; + +int handle_kv( + vcalendar* cal, + vevent* ev, + content_line* cline, + int line, + scope_context* s_ctx + ); + +int parse_file(FILE* f, vcalendar* cal); + +#endif /* PARSE_H */ @@ -2,27 +2,69 @@ #include <string.h> +#define TYPE content_line +#include "hash_help.inc" +#undef TYPE + +int vevent_init(vevent* ev, int init_size) { + HASH_INIT(content_line)(&ev->clines, init_size); + return 0; +} + +content_line* get_property (vevent* ev, char* key) { + return HASH_GET(content_line)(&ev->clines, key); +} + +int add_content_line (vevent* ev, content_line* c) { + return HASH_PUT(content_line)(&ev->clines, c); +} + +int init_content_line (content_line* c, int keylen, int vallen) { + init_string(&c->key, keylen); + init_string(&c->val, vallen); + // TODO remaining fields + return 0; +} + +int content_line_copy (content_line* dest, content_line* src) { + strbuf_init_copy(&dest->key, &src->key); + strbuf_init_copy(&dest->val, &src->val); + + // TODO remaining fields + + return 0; +} + +int content_line_free (content_line* c) { + free_string(&c->key); + free_string(&c->val); + + // TODO remaining fields + + return 0; +} + int copy_vevent(vevent* dest, vevent* src) { - copy_strbuf(&dest->dtstart , &src->dtstart); - copy_strbuf(&dest->dtend , &src->dtend); - copy_strbuf(&dest->summary , &src->summary); - copy_strbuf(&dest->description , &src->description); + // copy_strbuf(&dest->dtstart , &src->dtstart); + // copy_strbuf(&dest->dtend , &src->dtend); + // copy_strbuf(&dest->summary , &src->summary); + // copy_strbuf(&dest->description , &src->description); return 0; } int vevent_init_copy(vevent* dest, vevent* src) { - strbuf_init_copy(&dest->dtstart , &src->dtstart); - strbuf_init_copy(&dest->dtend , &src->dtend); - strbuf_init_copy(&dest->summary , &src->summary); - strbuf_init_copy(&dest->description , &src->description); + // strbuf_init_copy(&dest->dtstart , &src->dtstart); + // strbuf_init_copy(&dest->dtend , &src->dtend); + // strbuf_init_copy(&dest->summary , &src->summary); + // strbuf_init_copy(&dest->description , &src->description); return 0; } int free_vevent (vevent* ev) { - free_string(&ev->dtstart); - free_string(&ev->dtend); - free_string(&ev->summary); - free_string(&ev->description); + // free_string(&ev->dtstart); + // free_string(&ev->dtend); + // free_string(&ev->summary); + // free_string(&ev->description); return 0; } @@ -34,7 +76,8 @@ int push_event(vcalendar* cal, vevent* ev) { cal->events = realloc(cal->events, sizeof(*cal->events) * cal->alloc); } - vevent_init_copy(&cal->events[cal->n_events], ev); + // vevent_init_copy(&cal->events[cal->n_events], ev); + cal->events[cal->n_events] = *ev; cal->n_events++; return 0; @@ -5,17 +5,50 @@ #include "strbuf.h" +typedef struct { + string key; + string value; + string* vals; + int val_count; +} parameter; -/* - * It's intentionall that there is no vevent_init. That since - * the length of the strings isn't known. - */ typedef struct { + string key; + string val; + + string* aux_values; + int value_count; + + parameter* params; + int param_count; +} content_line; + +#define TYPE content_line +#include "hash.h" +#undef TYPE + +struct s_vevent { + /* string dtstart; string dtend; string summary; string description; -} vevent; + */ + TABLE(content_line) clines; +}; + +struct s_vevent; +typedef struct s_vevent vevent; + +int vevent_init (vevent* ev, int init_size); + +int init_content_line (content_line* c, int keylen, int vallen); +int content_line_free (content_line* c); +int content_line_copy (content_line* dest, content_line* src); + +content_line* get_property (vevent* ev, char* key); + +int add_content_line (vevent* ev, content_line* c); /* * Deep copy from src -> dest |