From 7b22939c20afa4f4a08c13a25d71f2720f0b6a29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Sun, 3 Feb 2019 21:35:13 +0100 Subject: Loads of memmory fixes, among other. --- Makefile | 3 +++ calendar.c | 35 ++++++++++++++++++++++++----- main.c | 27 ++++++++++++++++++---- parse.c | 76 +++++++++++++++++++++++++++++++++++++++++++------------------- parse.h | 13 ++++++++--- strbuf.c | 18 +++++++++------ strbuf.h | 6 +++++ trie.inc.h | 4 ++++ vcal.c | 32 +++++++++++++++++++++++--- vcal.h | 10 ++++++--- 10 files changed, 175 insertions(+), 49 deletions(-) diff --git a/Makefile b/Makefile index cea10f18..57e78210 100644 --- a/Makefile +++ b/Makefile @@ -49,6 +49,9 @@ CALDIR = cal %.pdf: %.dot dot -Tpdf -o $@ $< +tags: $(C_FILES) $(H_FILES) + ctags -R + clean: -rm parse -rm $(OBJDIR)/*.o diff --git a/calendar.c b/calendar.c index abecef89..5ac47f58 100644 --- a/calendar.c +++ b/calendar.c @@ -14,6 +14,28 @@ #include "macro.h" #include "parse.h" +/* + * Returns 0 if file has no extersion + */ +int get_extension(const char* filename, char* ext, ssize_t max_len) { + int ext_idx = -1; + ext[0] = '\0'; + for (char* c = (char*) filename; *c != '\0'; c++) { + if (*c == '.') { + ext_idx = 0; + continue; + } + if (ext_idx >= 0) { + ext[ext_idx++] = *c; + if (ext_idx == max_len) break; + } + } + ext[ext_idx] = '\0'; + return (ext_idx == -1) + ? 0 + : ext_idx; +} + int read_vcalendar(vcalendar* cal, char* path) { DIR* dir = opendir(path); @@ -24,11 +46,11 @@ int read_vcalendar(vcalendar* cal, char* path) { if (d->d_type != DT_REG) continue; /* Check that we have an ICS file */ - char *s, *fname; - s = fname = d->d_name; - while (*(s++) != '.'); + char* fname = d->d_name; - if (strcmp(s, "ics") != 0) continue; + char ext[10]; + int has_ext = get_extension(fname, ext, 9); + if (! has_ext || strcmp(ext, "ics") != 0) continue; /* We now assume that it's a good file, and start parsing it */ @@ -45,10 +67,11 @@ int read_vcalendar(vcalendar* cal, char* path) { * 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); - cal->events[cal->n_events - 1]->filename = fname; + parse_file(fname, f, cal); + fclose(f); + ; } closedir(dir); diff --git a/main.c b/main.c index 27385b55..6783c3e3 100644 --- a/main.c +++ b/main.c @@ -29,24 +29,43 @@ int main (int argc, char* argv[argc]) { } SNEW(vcalendar, cal); - read_vcalendar(&cal, args.argv[0]); + arg_shift(&args); if (args.argc == 0 || strcmp(args.argv[0], "-p") == 0) { 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, get_property(cal.events[i], "SUMMARY")->val.mem); + char* filename = cal.events[i]->filename; + + printf("%3lu | %s | %s\n", + i + 1, + filename, + get_property(cal.events[i], "SUMMARY")->val.mem); } } else if (strcmp(args.argv[0], "-g") == 0) { if (arg_shift(&args) == 0) { - create_graph(cal.events[0], "graph.dot"); + for (size_t i = 0; i < cal.n_events; i++) { + char target[0xFF]; + target[0] = '\0'; + strcat(target, "/tmp/dot/"); + strcat(target, cal.events[i]->filename); + strcat(target, ".dot"); + create_graph(cal.events[i], target); + } + // create_graph(cal.events[0], "graph.dot"); } else { create_graph(cal.events[0], args.argv[0]); } } + free_vcalendar(&cal); + for (int i = 0; i < cline_ptr; i++) { + if (clines[i] != NULL) { + printf("clines[%i] : [%s] := [%s]\n", i, clines[i]->key.mem, clines[i]->val.mem); + } + } - free_vcalendar(&cal); + free(clines); } diff --git a/parse.c b/parse.c index 6b0f835b..82a60671 100644 --- a/parse.c +++ b/parse.c @@ -4,20 +4,27 @@ #include #include "macro.h" +#include "vcal.h" -int parse_file(FILE* f, vcalendar* cal) { +int parse_file(char* fname, FILE* f, vcalendar* cal) { int segments = 1; SNEW(strbuf, str, segments * SEGSIZE); part_context p_ctx = p_key; - scope_context s_ctx = s_none; + SNEW(strbuf, skip, SEGSIZE); + parse_ctx ctx = { + .scope = s_none, + .skip_to = &skip + }; + // scope_context s_ctx = s_none; int keylen = 100; int vallen = 100; int line = 0; - NEW(vevent, ev); + // NEW(vevent, ev, fname); + vevent* ev = NULL; SNEW(content_line, cline, keylen, vallen); @@ -66,23 +73,27 @@ int parse_file(FILE* f, vcalendar* cal) { ++line; - handle_kv(cal, ev, &cline, line, &s_ctx); + switch (handle_kv(cal, ev, &cline, line, &ctx)) { + case s_event: + ev = malloc(sizeof(*ev)); + CONSTRUCT(vevent, ev, fname); + break; + } strbuf_soft_reset(&str); p_ctx = p_key; continue; } + /* * TODO context for property_{key,val}. */ } else if (p_ctx == p_key && c == ':') { - /* - if (str.ptr + 1 > keylen) { - keylen = str.ptr + 1; - // TODO this might break everything - strbuf_realloc(&key, keylen); + if (str.ptr + 1 > keylen) { + keylen = str.ptr + 1; + // TODO this might break everything + // strbuf_realloc(&cline.key, keylen); } - */ strbuf_copy(&cline.key, &str); strbuf_cap(&cline.key); strbuf_soft_reset(&str); @@ -93,7 +104,6 @@ int parse_file(FILE* f, vcalendar* cal) { strbuf_append(&str, c); } - if (! feof(f)) { ERR("Error parsing", errno); } else { @@ -101,7 +111,7 @@ int parse_file(FILE* f, vcalendar* cal) { * 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. - * TODO this doesn't do anything with its read value + * TODO -- this doesn't do anything with its read value * TODO This might crash if we have the CRLF */ if (str.ptr + 1 > vallen) { @@ -109,10 +119,12 @@ int parse_file(FILE* f, vcalendar* cal) { strbuf_realloc(&cline.val, vallen); } strbuf_copy(&cline.val, &str); - *strbuf_cur(&cline.val) = 0; + strbuf_cap(&cline.val); + handle_kv(cal, ev, &cline, line, &ctx); } FREE(strbuf)(&str); FREE(content_line)(&cline); + FREE(strbuf)(ctx.skip_to); return 0; } @@ -125,40 +137,58 @@ int handle_kv( vevent* ev, content_line* cline, int line, - scope_context* s_ctx + // scope_context* s_ctx + parse_ctx* ctx ) { - switch (*s_ctx) { + switch (ctx->scope) { + + case s_skip: + if (strbuf_c(&cline->key, "END") && strbuf_cmp(&cline->val, ctx->skip_to)) { + ctx->scope = s_calendar; + // FREE(strbuf)(ctx->skip_to); + } + break; + case s_none: if (! (strbuf_c(&cline->key, "BEGIN") && strbuf_c(&cline->val, "VCALENDAR"))) { ERR("Invalid start of calendar", line); - return 1; + return -1; } - *s_ctx = s_calendar; + ctx->scope = s_calendar; break; + case s_calendar: if (strbuf_c(&cline->key, "BEGIN")) { if (strbuf_c(&cline->val, "VEVENT")) { - *s_ctx = s_event; + ctx->scope = s_event; + return ctx->scope; break; } else { - ERR("Unsupported start", line); - return 2; + // ERR("Unsupported start", line); + ctx->scope = s_skip; + strbuf_copy(ctx->skip_to, &cline->val); } } else if (strbuf_c(&cline->key, "END")) { if (strbuf_c(&cline->val, "VCALENDAR")) { - *s_ctx = s_none; + ctx->scope = s_none; break; } } break; + case s_event: + if (ev == NULL) { + ERR("Something has gone terribly wrong", line); + return -5; + } if (strbuf_c(&cline->key, "END")) { if (strbuf_c(&cline->val, "VEVENT")) { push_event(cal, ev); - *s_ctx = s_calendar; + ctx->scope = s_calendar; + return ctx->scope; } else { ERR("Trying to end something, expected VEVENT", line); - return 3; + return -3; } } else { NEW(content_line, c); diff --git a/parse.h b/parse.h index 76611599..667ccd35 100644 --- a/parse.h +++ b/parse.h @@ -25,17 +25,24 @@ typedef enum { } part_context; typedef enum { - s_none, s_calendar, s_event + s_none = 1, s_calendar, s_event, + s_skip } scope_context; +typedef struct { + scope_context scope; + strbuf* skip_to; +} parse_ctx; + int handle_kv( vcalendar* cal, vevent* ev, content_line* cline, int line, - scope_context* s_ctx + // scope_context* s_ctx + parse_ctx* ctx ); -int parse_file(FILE* f, vcalendar* cal); +int parse_file(char* fname, FILE* f, vcalendar* cal); #endif /* PARSE_H */ diff --git a/strbuf.c b/strbuf.c index 353b6d84..0dbaa0c7 100644 --- a/strbuf.c +++ b/strbuf.c @@ -25,9 +25,9 @@ int CONSTRUCTOR_DECL(strbuf, size_t len) { int strbuf_realloc(strbuf* str, size_t len) { #ifdef SAFE_STR - if (str->mem == NULL || str->alloc == 0) { + if (str->mem == NULL /*|| str->alloc == -1*/) { ERR("String memory not initialized"); - return 1; + // return 1; } #endif str->mem = realloc(str->mem, len); @@ -38,14 +38,12 @@ int strbuf_realloc(strbuf* str, size_t len) { // int strbuf_free(strbuf* str) { int FREE_DECL(strbuf) { #ifdef SAFE_STR - if (this->alloc == 0 || this->mem == NULL) { - ERR("String not allocated"); - return 1; - } + if (this->mem == NULL) return 1; #endif - // fprintf(stderr, "Memmory = %p | %4lu | %s\n", this->mem, this->alloc, this->mem); free (this->mem); + this->mem = NULL; this->alloc = 0; + this->len = 0; return 0; } @@ -103,6 +101,12 @@ int strbuf_reset(strbuf* s) return 0; } +int strbuf_realloc_copy(strbuf* dest, strbuf* src) { + strbuf_realloc(dest, src->len); + strbuf_copy(dest, src); + return 0; +} + int strbuf_init_copy(strbuf* dest, strbuf* src) { #ifdef SAFE_STR if (dest->alloc != 0) { diff --git a/strbuf.h b/strbuf.h index 678d87ff..b5cd085f 100644 --- a/strbuf.h +++ b/strbuf.h @@ -71,6 +71,12 @@ int strbuf_soft_reset(strbuf* s); */ char* strbuf_end(strbuf* s); +/* + * Reallocs dest to be the same size as src, and copies the contents + * of src into dest. + */ +int strbuf_realloc_copy(strbuf* dest, strbuf* src); + /* * Copies contents from src to dest, also allocating dest in the * process. dest should not be initialized before this call. diff --git a/trie.inc.h b/trie.inc.h index 316b54b2..b839a7e8 100644 --- a/trie.inc.h +++ b/trie.inc.h @@ -107,6 +107,10 @@ int TRIE_NODE_FREE(TYPE) ( TRIE_NODE(TYPE)* node ) { } int TRIE_FREE(TYPE) ( TRIE(TYPE)* trie ) { + if (trie->root->c != '\0') { + // ERR("Invalid trie"); + return 1; + } return TRIE_NODE_FREE(TYPE)(trie->root); } diff --git a/vcal.c b/vcal.c index 2310c3fb..7464c72b 100644 --- a/vcal.c +++ b/vcal.c @@ -7,8 +7,18 @@ #include "trie.inc.h" #undef TYPE -int CONSTRUCTOR_DECL(vevent) { +content_line** clines; +int cline_ptr; + +int CONSTRUCTOR_DECL(vevent, char* filename) { + CONSTRUCT(TRIE(content_line), &this->clines); + + this->filename = calloc(sizeof(*filename), strlen(filename) + 1); + strcpy(this->filename, filename); + + this->calendar = NULL; + return 0; } @@ -22,6 +32,7 @@ int add_content_line (vevent* ev, content_line* c) { } int CONSTRUCTOR_DECL(content_line) { + clines[cline_ptr++] = this; CONSTRUCT(strbuf, &this->key); CONSTRUCT(strbuf, &this->val); // TODO remaining fields @@ -29,6 +40,7 @@ int CONSTRUCTOR_DECL(content_line) { } int CONSTRUCTOR_DECL(content_line, int keylen, int vallen) { + clines[cline_ptr++] = this; CONSTRUCT(strbuf, &this->key, keylen); CONSTRUCT(strbuf, &this->val, vallen); // TODO remaining fields @@ -46,18 +58,30 @@ int content_line_copy (content_line* dest, content_line* src) { int FREE_DECL(content_line) { FREE(strbuf)(&this->key); FREE(strbuf)(&this->val); + for (int i = 0; i < cline_ptr; i++) { + if (clines[i] == this) { + clines[i] = NULL; + } + } // TODO remaining fields return 0; } int FREE_DECL(vevent) { - TRIE_FREE(content_line)(&this->clines); + if (this->filename != NULL) free(this->filename); + if (TRIE_FREE(content_line)(&this->clines) != 0) { + fprintf(stderr, "Error freeing vevent belonging to file \n %s \n", + this->filename); + } + return 0; } int push_event(vcalendar* cal, vevent* ev) { - /* Make sure that cal->events is large enough */ + ev->calendar = cal; + + /* Make sure that cal->eents is large enough */ if (cal->n_events + 1 > cal->alloc) { cal->alloc <<= 1; cal->events = realloc(cal->events, sizeof(*cal->events) * cal->alloc); @@ -71,6 +95,8 @@ int push_event(vcalendar* cal, vevent* ev) { } int CONSTRUCTOR_DECL(vcalendar) { + clines = calloc(sizeof(*clines), 10000); + cline_ptr = 0; this->alloc = 1; this->events = calloc(sizeof(*this->events), this->alloc); this->n_events = 0; diff --git a/vcal.h b/vcal.h index 32564cb2..350871b7 100644 --- a/vcal.h +++ b/vcal.h @@ -14,8 +14,8 @@ typedef struct { typedef struct { strbuf key; - strbuf val; + strbuf val; strbuf* aux_values; int value_count; @@ -33,10 +33,11 @@ int CONSTRUCTOR_DECL(content_line, int keylen, int vallen); typedef struct s_vevent { char* filename; + struct s_vcalendar* calendar; TRIE(content_line) clines; } vevent; -int CONSTRUCTOR_DECL(vevent); +int CONSTRUCTOR_DECL(vevent, char* filename); int FREE_DECL(content_line); int content_line_copy (content_line* dest, content_line* src); @@ -47,7 +48,7 @@ int add_content_line (vevent* ev, content_line* c); int free_vevent(vevent* ev); -typedef struct { +typedef struct s_vcalendar { size_t n_events; size_t alloc; vevent** events; @@ -62,4 +63,7 @@ int free_vcalendar (vcalendar* cal); */ int push_event(vcalendar* cal, vevent* ev); +extern content_line** clines; +extern int cline_ptr; + #endif /* VCAL_H */ -- cgit v1.2.3