diff options
author | Hugo Hörnquist <hugo@lysator.liu.se> | 2019-02-09 00:19:58 +0100 |
---|---|---|
committer | Hugo Hörnquist <hugo@lysator.liu.se> | 2019-02-09 00:19:58 +0100 |
commit | c374807e9d73014ce57eacbbaa56e05460288368 (patch) | |
tree | af9974aa6b03c9e25c9e42c108d9f25277665b41 | |
parent | Fix minor memmory error. (diff) | |
download | calp-c374807e9d73014ce57eacbbaa56e05460288368.tar.gz calp-c374807e9d73014ce57eacbbaa56e05460288368.tar.xz |
Extend parsing to handle tree's of vcomponents.
Diffstat (limited to '')
-rw-r--r-- | calendar.c | 6 | ||||
-rw-r--r-- | linked_list.h | 8 | ||||
-rw-r--r-- | linked_list.inc.h | 27 | ||||
-rw-r--r-- | macro.h | 2 | ||||
-rw-r--r-- | main.c | 35 | ||||
-rw-r--r-- | parse.c | 157 | ||||
-rw-r--r-- | parse.h | 15 | ||||
-rw-r--r-- | strbuf.c | 6 | ||||
-rw-r--r-- | vcal.c | 24 | ||||
-rw-r--r-- | vcal.h | 12 |
10 files changed, 172 insertions, 120 deletions
@@ -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); @@ -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 */ @@ -1,6 +1,7 @@ #include <errno.h> #include <stdio.h> #include <string.h> +#include <assert.h> #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); } @@ -2,30 +2,31 @@ #include <errno.h> #include <string.h> +#include <assert.h> #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; } @@ -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 */ @@ -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); } @@ -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; +} @@ -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 */ |