From efd3968627894943808fe1e5a35479a180f3c50e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Sun, 10 Feb 2019 15:42:29 +0100 Subject: Add support for parameters in parser! --- parse.c | 180 ++++++++++++++++++++++++++++++---------------------------------- parse.h | 22 ++++---- 2 files changed, 97 insertions(+), 105 deletions(-) diff --git a/parse.c b/parse.c index 18e45a04..bc0b5491 100644 --- a/parse.c +++ b/parse.c @@ -13,24 +13,24 @@ #include "linked_list.inc.h" #undef TYPE +#define TYPE key_val +#include "linked_list.inc.h" +#undef TYPE + /* * name *(";" param) ":" value CRLF */ int parse_file(char* filename, FILE* f, vcomponent* root) { - int segments = 1; - SNEW(strbuf, str, segments * SEGSIZE); - part_context p_ctx = p_key; SNEW(parse_ctx, ctx, filename); PUSH(LLIST(vcomponent))(&ctx.comp_stack, root); - int keylen = 100; - int vallen = 100; - - int line = 0; - - SNEW(content_line, cline, keylen, vallen); + // vallen -+ + // keylen -+ | + // | | + SNEW(content_line, cline, 100, 100); + SNEW(key_val, kv); char c; while ( (c = fgetc(f)) != EOF) { @@ -53,19 +53,9 @@ int parse_file(char* filename, FILE* f, vcomponent* root) { s[0] = (c == '\n' ? '\n' : fgetc(f)); s[1] = fgetc(f); - if (s[0] != '\n') { ERR_F("%s, %i", "expected newline after CR", line); } + if (s[0] != '\n') { ERR_F("%s, %i", "expected newline after CR", ctx.line); } else if (s[1] == ' ' || s[1] == '\t') { - /* Folded line, increase size of key and continue. */ - - /* TODO segments is always incremented here, meaning - * that segment grows larger for every multi line - * encountered. - */ - if (strbuf_realloc(&str, ++segments * SEGSIZE) != 0) { - ERR_F("%s, %i", "Failed to realloc strbuf", line); - exit (1); - } - continue; + /* Folded line, don't end line */ } else { /* Actuall end of line, handle values. */ @@ -74,96 +64,97 @@ int parse_file(char* filename, FILE* f, vcomponent* root) { * since it's part of the next line. */ if (ungetc(s[1], f) != s[1]) { - ERR_F("%s, %i", "Failed to put character back on FILE", line); + ERR_F("%s, %i", "Failed to put character back on FILE", ctx.line); exit (2); } - if (str.ptr + 1 > vallen) { - vallen = str.ptr + 1; - strbuf_realloc(cline.vals.cur->value, vallen); - } + strbuf_copy(cline.vals.cur->value, &ctx.str); + strbuf_cap(cline.vals.cur->value); + strbuf_soft_reset(&ctx.str); - strbuf_copy(cline.vals.cur->value, &str); + ++ctx.line; + ctx.column = 0; - /* TODO when do I actualy cap? */ - // strbuf_cap(cline.vals.cur->value); + handle_kv(&cline, &ctx); - ++line; - handle_kv(&cline, line, &ctx); - strbuf_soft_reset(&str); p_ctx = p_key; - - continue; } + /* - * TODO context for property_{key,val}. + * Border between param {key, value} */ - } else if (p_ctx == p_key && c == ':') { - if (str.ptr + 1 > keylen) { - keylen = str.ptr + 1; - /* - * Allow for key's longer than 100 octets. It - * currently is of no use, since key's can't be - * folded. - * TODO check if everything should be unfolded at 75 - * octets, or if that is only for values. - * - * TODO earlier there was a bug here. Test if that is - * fixed and reenable this line. - */ - // strbuf_realloc(&cline.key, keylen); + } else if (p_ctx == p_param_name && c == '=') { + strbuf_copy(&kv.key, &ctx.str); + strbuf_cap(&kv.key); + strbuf_soft_reset(&ctx.str); + + p_ctx = p_param_value; + + /* + * One of four cases: + * 1) end of key , start of value + * 2) ,, key , ,, param + * 3) ,, param, ,, param + * 4) ,, param, ,, value + */ + } else if ((p_ctx == p_key || p_ctx == p_param_value) && (c == ':' || c == ';')) { + strbuf* dest; + if (p_ctx == p_key) dest = &cline.key; + else if (p_ctx == p_param_value) dest = &kv.val; + + strbuf_copy(dest, &ctx.str); + strbuf_cap(dest); + strbuf_soft_reset(&ctx.str); + + if (p_ctx == p_param_value) { + /* push kv pair */ + NEW (key_val, _kv); + DEEP_COPY(key_val)(_kv, &kv); + PUSH(LLIST(key_val))(&cline.params, _kv); } - strbuf_copy(&cline.key, &str); - strbuf_cap(&cline.key); - strbuf_soft_reset(&str); - p_ctx = p_value; - continue; - } - strbuf_append(&str, c); + if (c == ':') p_ctx = p_value; + else if (c == ';') p_ctx = p_param_name; + + } else { + strbuf_append(&ctx.str, c); + ++ctx.column; + } } if (! feof(f)) { ERR("Error parsing"); - } else if (cline.vals.cur->value->len != 0 && str.ptr != 0) { + } else if (cline.vals.cur->value->len != 0 && ctx.str.ptr != 0) { /* * The standard (3.4, l. 2675) says that each icalobject must * end with CRLF. My files however does not, so we also parse * the end here. */ - if (str.ptr + 1 > vallen) { - vallen = str.ptr + 1; - strbuf_realloc(cline.vals.cur->value, vallen); - } - strbuf_copy(cline.vals.cur->value, &str); + strbuf_copy(cline.vals.cur->value, &ctx.str); strbuf_cap(cline.vals.cur->value); - handle_kv(&cline, line, &ctx); + handle_kv(&cline, &ctx); } - FREE(strbuf)(&str); + INFO("Parsed file, cleaning up."); + FREE(content_line)(&cline); - // 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); + FREE(parse_ctx)(&ctx); - FREE(strbuf)(&kv.key); - FREE(strbuf)(&kv.val); + FREE(key_val)(&kv); return 0; } int handle_kv ( content_line* cline, - int line, parse_ctx* ctx ) { @@ -172,8 +163,9 @@ int handle_kv ( * VCALENDAR, VEVENT, VALARM, VTODO, VTIMEZONE, * and possibly some others I forget. */ + NEW(strbuf, s); - strbuf_init_copy(s, cline->vals.cur->value); + strbuf_copy(s, cline->vals.cur->value); PUSH(LLIST(strbuf))(&ctx->key_stack, s); NEW(vcomponent, e, @@ -186,23 +178,29 @@ int handle_kv ( 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); + s->mem, cline->vals.cur->value->mem, PEEK(LLIST(vcomponent))(&ctx->comp_stack)->filename, ctx->line); PUSH(LLIST(strbuf))(&ctx->key_stack, s); return -1; } else { FFREE(strbuf, s); - /* Received propper end, push cur into parent */ + /* 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); + + if ( SIZE(LLIST(key_val))(&c->params) != 0 ) { + RESET(LLIST(key_val))(&cline->params); + } } return 0; @@ -213,31 +211,23 @@ INIT_F(parse_ctx, char* filename) { INIT(LLIST(vcomponent), &this->comp_stack); this->filename = calloc(sizeof(*filename), strlen(filename) + 1); strcpy(this->filename, filename); + + this->line = 0; + this->column = 0; + INIT(strbuf, &this->str); + return 0; } -int push_strbuf(strbuf* target, strbuf* src) { -#if 0 - if (src->ptr + 1 > keylen) { - keylen = str->ptr + 1; - /* - * Allow for key's longer than 100 octets. It - * currently is of no use, since key's can't be - * folded. - * TODO check if everything should be unfolded at 75 - * octets, or if that is only for values. - * - * TODO earlier there was a bug here. Test if that is - * fixed and reenable this line. - */ - // strbuf_realloc(&cline.key, keylen); - } -#endif +FREE_F(parse_ctx) { + + FREE(LLIST(strbuf))(&this->key_stack); + FREE(LLIST(vcomponent))(&this->comp_stack); + free(this->filename); - strbuf_copy(target, src); - strbuf_cap(target); - strbuf_soft_reset(src); + this->line = 0; + this->column = 0; + FREE(strbuf)(&this->str); - // continue; return 0; } diff --git a/parse.h b/parse.h index d46a5ad8..fae7485f 100644 --- a/parse.h +++ b/parse.h @@ -12,36 +12,38 @@ #undef TYPE /* - * Max length of a line. - * TODO update this to allow longer lines, in case someone doesn't - * follow the standard. - * (I currently only realloc memmory at end of lines, not when my - * buffer is full). + * The standard says that no line should be longer than 75 octets. + * This sets the default amount of memory to allocate for each string, + * but strings are reallocated when needed. */ #define SEGSIZE 75 -// #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; +/* + * Struct holding most state information needed while parsing. + * Kept together for simplicity. + */ typedef struct { char* filename; LLIST(strbuf) key_stack; LLIST(vcomponent) comp_stack; + + int line; + int column; + strbuf str; } parse_ctx; INIT_F(parse_ctx, char* filename); +FREE_F(parse_ctx); int handle_kv( content_line* cline, - int line, parse_ctx* ctx ); int parse_file(char* filename, FILE* f, vcomponent* cal); -int push_strbuf(strbuf* target, strbuf* src); - #endif /* PARSE_H */ -- cgit v1.2.3