aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHugo Hörnquist <hugo@lysator.liu.se>2019-02-09 00:19:58 +0100
committerHugo Hörnquist <hugo@lysator.liu.se>2019-02-09 00:19:58 +0100
commitc374807e9d73014ce57eacbbaa56e05460288368 (patch)
treeaf9974aa6b03c9e25c9e42c108d9f25277665b41
parentFix minor memmory error. (diff)
downloadcalp-c374807e9d73014ce57eacbbaa56e05460288368.tar.gz
calp-c374807e9d73014ce57eacbbaa56e05460288368.tar.xz
Extend parsing to handle tree's of vcomponents.
-rw-r--r--calendar.c6
-rw-r--r--linked_list.h8
-rw-r--r--linked_list.inc.h27
-rw-r--r--macro.h2
-rw-r--r--main.c35
-rw-r--r--parse.c157
-rw-r--r--parse.h15
-rw-r--r--strbuf.c6
-rw-r--r--vcal.c24
-rw-r--r--vcal.h12
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 <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);
}
diff --git a/parse.c b/parse.c
index 651572bb..77c3f8db 100644
--- a/parse.c
+++ b/parse.c
@@ -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;
}
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 */