From c374807e9d73014ce57eacbbaa56e05460288368 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Sat, 9 Feb 2019 00:19:58 +0100 Subject: Extend parsing to handle tree's of vcomponents. --- calendar.c | 6 +-- linked_list.h | 8 ++- linked_list.inc.h | 27 +++++++++- macro.h | 2 + main.c | 35 ++++++++---- parse.c | 157 +++++++++++++++++++++++------------------------------- parse.h | 15 ++++-- strbuf.c | 6 +++ vcal.c | 24 +++++++-- vcal.h | 12 +++-- 10 files changed, 172 insertions(+), 120 deletions(-) diff --git a/calendar.c b/calendar.c index 477de492..fef4ab28 100644 --- a/calendar.c +++ b/calendar.c @@ -70,10 +70,7 @@ int parse_dir(vcomponent* cal, char* path) { exit (1); } - /* 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. */ + // TODO complete path parse_file(fname, f, cal); fclose(f); @@ -115,6 +112,7 @@ int read_vcalendar(vcomponent* cal, char* path) { exit (1); } + // TODO absolute path parse_file(path, f, cal); fclose(f); break; diff --git a/linked_list.h b/linked_list.h index 5f9e2711..4199ba57 100644 --- a/linked_list.h +++ b/linked_list.h @@ -6,6 +6,8 @@ #define LLIST(T) TEMPL(llist, T) #define LINK(T) TEMPL(llist_link, T) +#define UNLINK(T) TEMPL(unlink, T) + #endif /* LINKED_LIST_H */ #ifdef TYPE @@ -38,7 +40,11 @@ INIT_F ( LINK(TYPE) ); INIT_F ( LINK(TYPE), TYPE* val ); FREE_F ( LINK(TYPE) ); -int PUSH(LLIST(TYPE)) ( LLIST(TYPE)* lst, TYPE* val); +int UNLINK(LINK(TYPE)) ( LINK(TYPE)* ); + +int PUSH(LLIST(TYPE)) ( LLIST(TYPE)*, TYPE* ); +TYPE* PEEK(LLIST(TYPE)) ( LLIST(TYPE)* ); +TYPE* POP(LLIST(TYPE)) ( LLIST(TYPE)* ); int DEEP_COPY(LLIST(TYPE)) ( LLIST(TYPE)* dest, LLIST(TYPE)* src ); diff --git a/linked_list.inc.h b/linked_list.inc.h index e91cdc9f..ada0b424 100644 --- a/linked_list.inc.h +++ b/linked_list.inc.h @@ -15,8 +15,7 @@ INIT_F ( LLIST(TYPE) ) { } FREE_F (LINK(TYPE)) { - if (this->before != NULL) this->before->after = NULL; - if (this->after != NULL) this->after->before = NULL; + UNLINK(LINK(TYPE))(this); if (this->value != NULL) FFREE(TYPE, this->value); return 0; @@ -50,6 +49,13 @@ INIT_F ( LINK(TYPE), TYPE* val ) { return 0; } +int UNLINK(LINK(TYPE)) ( LINK(TYPE)* this ) { + if (this->before != NULL) this->before->after = this->after; + if (this->after != NULL) this->after->before = this->before; + return 0; +} + + int PUSH(LLIST(TYPE)) ( LLIST(TYPE)* lst, TYPE* val) { NEW(LINK(TYPE), link, val); @@ -67,6 +73,23 @@ int PUSH(LLIST(TYPE)) ( LLIST(TYPE)* lst, TYPE* val) { return 0; } +TYPE* PEEK(LLIST(TYPE)) ( LLIST(TYPE)* lst ) { + if (EMPTY(LLIST(TYPE))(lst)) return NULL; + + return FIRST(lst)->value; +} + +TYPE* POP(LLIST(TYPE)) ( LLIST(TYPE)* lst) { + if (EMPTY(LLIST(TYPE))(lst)) return NULL; + + LINK(TYPE)* frst = FIRST(lst); + UNLINK(LINK(TYPE))(frst); + + TYPE* retval = frst->value; + free (frst); + return retval; +} + int DEEP_COPY(LLIST(TYPE)) ( LLIST(TYPE)* dest, LLIST(TYPE)* src ) { LINK(TYPE)* n = FIRST(src); diff --git a/macro.h b/macro.h index 493b9537..b3831086 100644 --- a/macro.h +++ b/macro.h @@ -88,6 +88,8 @@ #define SIZE(T) TEMPL(size , T) #define EMPTY(T) TEMPL(empty , T) #define PUSH(T) TEMPL(push , T) +#define PEEK(T) TEMPL(peek , T) +#define POP(T) TEMPL(pop , T) #define GET(T) TEMPL(get , T) #endif /* MACRO_H */ diff --git a/main.c b/main.c index c52b0554..6b52d96e 100644 --- a/main.c +++ b/main.c @@ -1,6 +1,7 @@ #include #include #include +#include #include "calendar.h" #include "macro.h" @@ -28,36 +29,48 @@ int main (int argc, char* argv[argc]) { exit (1); } - SNEW(vcomponent, cal); - read_vcalendar(&cal, args.argv[0]); + char* rootpath = args.argv[0]; + SNEW(vcomponent, root, "ROOT", rootpath); + read_vcalendar(&root, rootpath); arg_shift(&args); + vcomponent* cal = FCHILD(&root); + + assert(strcmp(root.type, "ROOT") == 0); + assert(strcmp(cal->type, "VCALENDAR") == 0); + if (args.argc == 0 || strcmp(args.argv[0], "-p") == 0) { printf("\nParsed calendar file containing [%u] events\n", - cal.components.length + root.components.length ); - for (size_t i = 0; i < cal.components.length; i++) { - char* filename = cal.components.items[i]->filename; + for (size_t i = 0; i < cal->components.length; i++) { + char* filename = cal->components.items[i]->filename; + vcomponent* ev = GET(VECT(vcomponent))(&cal->components, i); + + printf("TYPE = %s\n", ev->type); + if (strcmp(ev->type, "VEVENT") != 0) continue; printf("%3lu | %s | %s\n", i + 1, filename, - get_property(cal.components.items[i], "SUMMARY")->vals.cur->value->mem); + get_property(ev, "SUMMARY")->vals.cur->value->mem); } } else if (strcmp(args.argv[0], "-g") == 0) { if (arg_shift(&args) == 0) { - for (size_t i = 0; i < cal.components.length; i++) { + for (size_t i = 0; i < cal->components.length; i++) { char target[0xFF]; target[0] = '\0'; strcat(target, "/tmp/dot/"); - strcat(target, cal.components.items[i]->filename); + vcomponent* ev = GET(VECT(vcomponent))(&cal->components, i); + strcat(target, ev->filename); strcat(target, ".dot"); - create_graph(cal.components.items[i], target); + create_graph(ev, target); } } else { - create_graph(cal.components.items[0], args.argv[0]); + create_graph(GET(VECT(vcomponent))(&cal->components, 0), args.argv[0]); } } - FREE(vcomponent)(&cal); + + FREE(vcomponent)(&root); } diff --git a/parse.c b/parse.c index 651572bb..77c3f8db 100644 --- a/parse.c +++ b/parse.c @@ -2,30 +2,31 @@ #include #include +#include #include "macro.h" #include "vcal.h" #include "err.h" -int parse_file(char* fname, FILE* f, vcomponent* cal) { +#define TYPE vcomponent +#include "linked_list.inc.h" +#undef TYPE + +int parse_file(char* filename, FILE* f, vcomponent* root) { int segments = 1; SNEW(strbuf, str, segments * SEGSIZE); part_context p_ctx = p_key; - SNEW(strbuf, skip, SEGSIZE); - parse_ctx ctx = { - .scope = s_none, - .skip_to = &skip - }; + + SNEW(parse_ctx, ctx, filename); + PUSH(LLIST(vcomponent))(&ctx.comp_stack, root); int keylen = 100; int vallen = 100; int line = 0; - vcomponent* ev = NULL; - SNEW(content_line, cline, keylen, vallen); char c; @@ -84,12 +85,7 @@ int parse_file(char* fname, FILE* f, vcomponent* cal) { // strbuf_cap(cline.vals.cur->value); ++line; - - switch (handle_kv(cal, ev, &cline, line, &ctx)) { - case s_event: - RENEW(vcomponent, ev, fname); - break; - } + handle_kv(&cline, line, &ctx); strbuf_soft_reset(&str); p_ctx = p_key; @@ -138,11 +134,17 @@ int parse_file(char* fname, FILE* f, vcomponent* cal) { } strbuf_copy(cline.vals.cur->value, &str); strbuf_cap(cline.vals.cur->value); - handle_kv(cal, ev, &cline, line, &ctx); + handle_kv(&cline, line, &ctx); } FREE(strbuf)(&str); FREE(content_line)(&cline); - FREE(strbuf)(ctx.skip_to); + // FREE(strbuf)(ctx.skip_to); + assert(POP(LLIST(vcomponent))(&ctx.comp_stack) == root); + assert(EMPTY(LLIST(strbuf))(&ctx.key_stack)); + assert(EMPTY(LLIST(vcomponent))(&ctx.comp_stack)); + FREE(LLIST(strbuf))(&ctx.key_stack); + FREE(LLIST(vcomponent))(&ctx.comp_stack); + free(ctx.filename); return 0; } @@ -150,80 +152,57 @@ int parse_file(char* fname, FILE* f, vcomponent* cal) { /* * TODO Extend this to handle properties */ -int handle_kv( - vcomponent* cal, - vcomponent* ev, - content_line* cline, - int line, - parse_ctx* ctx - ) { - switch (ctx->scope) { - - case s_skip: - if (strbuf_c(&cline->key, "END") && strbuf_cmp(cline->vals.cur->value, ctx->skip_to)) { - ctx->scope = s_calendar; - } - break; - - case s_none: - if (! (strbuf_c(&cline->key, "BEGIN") && strbuf_c(cline->vals.cur->value, "VCALENDAR"))) { - ERR_F("%s, %i\n%s", "Invalid start of calendar", line, ev->filename); - return -1; - } - ctx->scope = s_calendar; - break; - - case s_calendar: - /* - * TODO - * BEGIN's can be nested, extend this with a stack - * Apparently only VALARM can be nested. - */ - if (strbuf_c(&cline->key, "BEGIN")) { - if (strbuf_c(cline->vals.cur->value, "VEVENT")) { - ctx->scope = s_event; - return ctx->scope; - break; - } else { - - /* - * Here we found the start of some form of block - * we don't understand. Just skip everything until - * we find the matching END - */ - ctx->scope = s_skip; - strbuf_copy(ctx->skip_to, cline->vals.cur->value); +int handle_kv ( + content_line* cline, + int line, + parse_ctx* ctx + ) { + + if (strbuf_c(&cline->key, "BEGIN")) { + /* should be one of: + * VCALENDAR, VEVENT, VALARM, VTODO, VTIMEZONE, + * and possibly some others I forget. + */ + NEW(strbuf, s); + strbuf_init_copy(s, cline->vals.cur->value); + PUSH(LLIST(strbuf))(&ctx->key_stack, s); + + NEW(vcomponent, e, + s->mem, + ctx->filename); + e->parent = PEEK(LLIST(vcomponent))(&ctx->comp_stack); + PUSH(LLIST(vcomponent))(&ctx->comp_stack, e); + + } else if (strbuf_c(&cline->key, "END")) { + strbuf* s = POP(LLIST(strbuf))(&ctx->key_stack); + if (strbuf_cmp(s, cline->vals.cur->value) != 0) { + ERR_F("Expected END:%s, got END:%s.\n%s line %i", + s->mem, cline->vals.cur->value->mem, PEEK(LLIST(vcomponent))(&ctx->comp_stack)->filename, line); + PUSH(LLIST(strbuf))(&ctx->key_stack, s); + return -1; + + } else { + FFREE(strbuf, s); + /* Received propper end, push cur into parent */ + vcomponent* cur = POP(LLIST(vcomponent))(&ctx->comp_stack); + // TODO should this instead be done at creation time? + PUSH(vcomponent)(PEEK(LLIST(vcomponent))(&ctx->comp_stack), cur); + } + } else { + NEW(content_line, c); + content_line_copy(c, cline); + PUSH(TRIE(content_line))( + &PEEK(LLIST(vcomponent))(&ctx->comp_stack)->clines, + c->key.mem, c); + } - } - } else if (strbuf_c(&cline->key, "END")) { - if (strbuf_c(cline->vals.cur->value, "VCALENDAR")) { - ctx->scope = s_none; - break; - } - } - break; + return 0; +} - case s_event: - if (ev == NULL) { - ERR_F("%s, %i", "Something has gone terribly wrong", line); - return -5; - } - if (strbuf_c(&cline->key, "END")) { - if (strbuf_c(cline->vals.cur->value, "VEVENT")) { - PUSH(vcomponent)(cal, ev); - ctx->scope = s_calendar; - return ctx->scope; - } else { - ERR_F("Trying to end something, expected VEVENT, Got [%s]\n%s : %i", - cline->vals.cur->value->mem, ev->filename, line); - return -3; - } - } else { - NEW(content_line, c); - content_line_copy(c, cline); - PUSH(TRIE(content_line))(&ev->clines, c->key.mem, c); - } - break; - } +INIT_F(parse_ctx, char* filename) { + INIT(LLIST(strbuf), &this->key_stack); + INIT(LLIST(vcomponent), &this->comp_stack); + this->filename = calloc(sizeof(*filename), strlen(filename) + 1); + strcpy(this->filename, filename); return 0; } diff --git a/parse.h b/parse.h index ea60461f..ad1cebc2 100644 --- a/parse.h +++ b/parse.h @@ -7,6 +7,10 @@ #include "strbuf.h" #include "vcal.h" +#define TYPE vcomponent +#include "linked_list.h" +#undef TYPE + /* * Max length of a line. * TODO update this to allow longer lines, in case someone doesn't @@ -28,18 +32,19 @@ typedef enum { } scope_context; typedef struct { - scope_context scope; - strbuf* skip_to; + char* filename; + LLIST(strbuf) key_stack; + LLIST(vcomponent) comp_stack; } parse_ctx; +INIT_F(parse_ctx, char* filename); + int handle_kv( - vcomponent* cal, - vcomponent* ev, content_line* cline, int line, parse_ctx* ctx ); -int parse_file(char* fname, FILE* f, vcomponent* cal); +int parse_file(char* filename, FILE* f, vcomponent* cal); #endif /* PARSE_H */ diff --git a/strbuf.c b/strbuf.c index 38aca4f4..8d1c7f15 100644 --- a/strbuf.c +++ b/strbuf.c @@ -82,6 +82,12 @@ int strbuf_copy(strbuf* dest, strbuf* src) { } int strbuf_cmp(strbuf* a, strbuf* b) { +#ifdef SAFE_STR + if (a->alloc == 0 || b->alloc == 0) { + ERR("a or b not alloced"); + return -1; + } +#endif return strcmp(a->mem, b->mem); } diff --git a/vcal.c b/vcal.c index e3a1af9c..5937f04a 100644 --- a/vcal.c +++ b/vcal.c @@ -16,21 +16,29 @@ #undef TYPE INIT_F(vcomponent) { - return INIT(vcomponent, this, NULL); + (void) this; + ERR("Do not use"); + return 0; +} + +INIT_F(vcomponent, char* type) { + return INIT(vcomponent, this, type, NULL); } -INIT_F(vcomponent, char* filename) { +INIT_F(vcomponent, char* type, char* filename) { INIT(TRIE(content_line), &this->clines); INIT(VECT(vcomponent), &this->components); + this->filename = NULL; if (filename != NULL) { this->filename = calloc(sizeof(*filename), strlen(filename) + 1); strcpy(this->filename, filename); - } else { - this->filename = NULL; } + this->type = calloc(sizeof(*type), strlen(type) + 1); + strcpy(this->type, type); + this->parent = NULL; return 0; @@ -98,6 +106,7 @@ int content_line_copy (content_line* dest, content_line* src) { FREE_F(vcomponent) { if (this->filename != NULL) free(this->filename); + free(this->type); if (FREE(TRIE(content_line))(&this->clines) != 0) { fprintf(stderr, "Error freeing vcomponent belonging to file \n %s \n", @@ -113,4 +122,9 @@ int PUSH(vcomponent)(vcomponent* parent, vcomponent* child) { return PUSH(VECT(vcomponent))(&parent->components, child); } - +int DEEP_COPY(vcomponent)(vcomponent* a, vcomponent* b) { + (void) a; + (void) b; + ERR("Deep copy not implemented for vcomponent"); + return -1; +} diff --git a/vcal.h b/vcal.h index 6b3667bf..08d706a6 100644 --- a/vcal.h +++ b/vcal.h @@ -29,6 +29,8 @@ INIT_F(content_line); INIT_F(content_line, int keylen, int vallen); FREE_F(content_line); +int content_line_copy (content_line* dest, content_line* src); + /* * Resolves a collision in some form of structure (probably a hash-map * or a trie). If dest is NULL just return new. Otherwise mutates dest @@ -50,17 +52,19 @@ typedef struct s_vcomponent vcomponent; struct s_vcomponent { char* filename; + char* type; vcomponent* parent; TRIE(content_line) clines; VECT(vcomponent) components; }; +#define FCHILD(v) GET(VECT(vcomponent))(&(v)->components, 0) + INIT_F(vcomponent); -INIT_F(vcomponent, char* filename); +INIT_F(vcomponent, char* type); +INIT_F(vcomponent, char* type, char* filename); FREE_F(vcomponent); -int content_line_copy (content_line* dest, content_line* src); - content_line* get_property (vcomponent* ev, char* key); int add_content_line (vcomponent* ev, content_line* c); @@ -71,4 +75,6 @@ int add_content_line (vcomponent* ev, content_line* c); */ int PUSH(vcomponent)(vcomponent*, vcomponent*); +int DEEP_COPY(vcomponent)(vcomponent*, vcomponent*); + #endif /* VCAL_H */ -- cgit v1.2.3