From aae3b8bfb83abec0f1bb8e4c854c156c03be5ca8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=B6rnquist?= Date: Tue, 19 Feb 2019 00:27:43 +0100 Subject: Started full rewrite in C++. --- Makefile | 8 +- calendar.c | 121 ---------------------- calendar.cpp | 121 ++++++++++++++++++++++ err.h | 4 +- linked_list.cpp | 38 +++++++ linked_list.h | 58 +++++------ linked_list.inc.h | 23 ----- macro.h | 131 ----------------------- parse.c | 302 ------------------------------------------------------ parse.cpp | 269 ++++++++++++++++++++++++++++++++++++++++++++++++ parse.h | 31 +++--- strbuf.c | 138 ------------------------- strbuf.cpp | 26 +++++ strbuf.h | 106 +++++++++---------- trie.cpp | 134 ++++++++++++++++++++++++ trie.h | 68 +++++++----- trie.inc.h | 166 ------------------------------ vcal.c | 130 ----------------------- vcal.cpp | 14 +++ vcal.h | 132 ++++++++---------------- 20 files changed, 785 insertions(+), 1235 deletions(-) delete mode 100644 calendar.c create mode 100644 calendar.cpp create mode 100644 linked_list.cpp delete mode 100644 macro.h delete mode 100644 parse.c create mode 100644 parse.cpp delete mode 100644 strbuf.c create mode 100644 strbuf.cpp create mode 100644 trie.cpp delete mode 100644 trie.inc.h delete mode 100644 vcal.c create mode 100644 vcal.cpp diff --git a/Makefile b/Makefile index 0ae2ccc0..e72ba47c 100644 --- a/Makefile +++ b/Makefile @@ -10,14 +10,14 @@ CFLAGS = -std=gnu++11 -Wall -Wextra \ LDFLAGS = -fPIC $(shell guile-config link) H_FILES = $(wildcard *.h) -C_FILES = $(wildcard *.c) +C_FILES = $(wildcard *.cpp) SCM_C_FILES = $(wildcard *.scm.c) -X_FILES = $(SCM_C_FILES:.scm.c=.x) +X_FILES = $(SCM_C_FILES:.scm.cpp=.x) .SECONDARY: $(X_FILES) -O_FILES = $(addprefix obj/,$(C_FILES:.c=.o)) +O_FILES = $(addprefix obj/,$(C_FILES:.cpp=.o)) all: parse libguile-calendar.so @@ -32,7 +32,7 @@ $(O_FILES): | $(OBJDIR) $(OBJDIR)/%.scm.o : %.scm.c %.x $(CC) -c $(CFLAGS) -o $@ $< -$(OBJDIR)/%.o : %.c # $(H_FILES) $(X_FILES) +$(OBJDIR)/%.o : %.cpp # $(H_FILES) $(X_FILES) $(CC) -c $(CFLAGS) -o $@ $< $(OBJDIR): diff --git a/calendar.c b/calendar.c deleted file mode 100644 index d0476583..00000000 --- a/calendar.c +++ /dev/null @@ -1,121 +0,0 @@ -#include "calendar.h" - -#include -#include -#include -#include -#include - -#include "parse.h" -#include "err.h" - -int read_vcalendar(vcomponent* cal, char* path) { - - struct stat statbuf; - if (stat (path, &statbuf) != 0) { - fprintf(stderr, - "Error stating file or directory, errno = %i\npath = [%s]\n", - errno, path); - } - - int type = statbuf.st_mode & 0777000; - int chmod = statbuf.st_mode & 0777; - INFO_F("file has mode 0%o, with chmod = 0%o", type, chmod); - - switch (type) { - case S_IFREG: handle_file(cal, path); break; - case S_IFDIR: handle_dir (cal, path); break; - case S_IFLNK: - ERR("Found symlink, can't be bothered to check it further."); - break; - - default: ; - } - - return 0; -} - -int handle_file(vcomponent* cal, char* path) { - INFO("Parsing a single file"); - - char* resolved_path = realpath(path, NULL); - open_ics (resolved_path, cal); - free (resolved_path); - - return 0; -} - - -int handle_dir(vcomponent* cal, char* path) { - INFO("Parsing a directory"); - DIR* dir = opendir(path); - - /* Buffer for holding search path and filename */ - char buf[PATH_MAX]; - strcpy(buf, path); - int path_len = strlen(path) + 1; - - /* Slash to guarantee we have at least one */ - buf[path_len - 1] = '/'; - - struct dirent* d; - while ((d = readdir(dir)) != NULL) { - /* Check that it's a regular file */ - if (d->d_type != DT_REG) continue; - - /* Append filename with currentt searchpath */ - strcat(buf, d->d_name); - char* resolved_path = realpath(buf, NULL); - /* Remove file part from combined path */ - buf[path_len] = '\0'; - - open_ics (resolved_path, cal); - - free (resolved_path); - } - - closedir(dir); - return 0; -} - -int get_extension(const char* filename, char* ext, ssize_t max_len) { - int ext_idx = -1; - ext[0] = '\0'; - for (int i = 0; filename[i] != '\0'; i++) { - if (filename[i] == '.') ext_idx = i + 1; - if (filename[i] == '/') ext_idx = -1; - } - - if (ext_idx == -1) return 0; - - int ext_len = 0; - for (int i = 0; i < max_len; i++, ext_len++) { - char c = filename[i + ext_idx]; - if (c == '\0') break; - ext[i] = c; - } - ext[ext_len] = '\0'; - return ext_len; -} - -int check_ext (const char* path, const char* ext) { - char buf[10]; - int has_ext = get_extension(path, buf, 9); - - return has_ext && strcmp(buf, ext) == 0; -} - -int open_ics (char* resolved_path, vcomponent* cal) { - puts(resolved_path); - if (! check_ext(resolved_path, "ics") ) return 2; - - FILE* f = fopen(resolved_path, "r"); - - if (f == NULL) return 1; - - parse_file(resolved_path, f, cal); - fclose(f); - - return 0; -} - diff --git a/calendar.cpp b/calendar.cpp new file mode 100644 index 00000000..d0476583 --- /dev/null +++ b/calendar.cpp @@ -0,0 +1,121 @@ +#include "calendar.h" + +#include +#include +#include +#include +#include + +#include "parse.h" +#include "err.h" + +int read_vcalendar(vcomponent* cal, char* path) { + + struct stat statbuf; + if (stat (path, &statbuf) != 0) { + fprintf(stderr, + "Error stating file or directory, errno = %i\npath = [%s]\n", + errno, path); + } + + int type = statbuf.st_mode & 0777000; + int chmod = statbuf.st_mode & 0777; + INFO_F("file has mode 0%o, with chmod = 0%o", type, chmod); + + switch (type) { + case S_IFREG: handle_file(cal, path); break; + case S_IFDIR: handle_dir (cal, path); break; + case S_IFLNK: + ERR("Found symlink, can't be bothered to check it further."); + break; + + default: ; + } + + return 0; +} + +int handle_file(vcomponent* cal, char* path) { + INFO("Parsing a single file"); + + char* resolved_path = realpath(path, NULL); + open_ics (resolved_path, cal); + free (resolved_path); + + return 0; +} + + +int handle_dir(vcomponent* cal, char* path) { + INFO("Parsing a directory"); + DIR* dir = opendir(path); + + /* Buffer for holding search path and filename */ + char buf[PATH_MAX]; + strcpy(buf, path); + int path_len = strlen(path) + 1; + + /* Slash to guarantee we have at least one */ + buf[path_len - 1] = '/'; + + struct dirent* d; + while ((d = readdir(dir)) != NULL) { + /* Check that it's a regular file */ + if (d->d_type != DT_REG) continue; + + /* Append filename with currentt searchpath */ + strcat(buf, d->d_name); + char* resolved_path = realpath(buf, NULL); + /* Remove file part from combined path */ + buf[path_len] = '\0'; + + open_ics (resolved_path, cal); + + free (resolved_path); + } + + closedir(dir); + return 0; +} + +int get_extension(const char* filename, char* ext, ssize_t max_len) { + int ext_idx = -1; + ext[0] = '\0'; + for (int i = 0; filename[i] != '\0'; i++) { + if (filename[i] == '.') ext_idx = i + 1; + if (filename[i] == '/') ext_idx = -1; + } + + if (ext_idx == -1) return 0; + + int ext_len = 0; + for (int i = 0; i < max_len; i++, ext_len++) { + char c = filename[i + ext_idx]; + if (c == '\0') break; + ext[i] = c; + } + ext[ext_len] = '\0'; + return ext_len; +} + +int check_ext (const char* path, const char* ext) { + char buf[10]; + int has_ext = get_extension(path, buf, 9); + + return has_ext && strcmp(buf, ext) == 0; +} + +int open_ics (char* resolved_path, vcomponent* cal) { + puts(resolved_path); + if (! check_ext(resolved_path, "ics") ) return 2; + + FILE* f = fopen(resolved_path, "r"); + + if (f == NULL) return 1; + + parse_file(resolved_path, f, cal); + fclose(f); + + return 0; +} + diff --git a/err.h b/err.h index d9d19ec7..ca5b09ef 100644 --- a/err.h +++ b/err.h @@ -3,8 +3,6 @@ #include -#include "macro.h" - #define _RESET "\x1b[m" #define _BLACK "\x1B[0;30m" #define _RED "\x1B[0;31m" @@ -27,6 +25,7 @@ #define INFO_F(fmt, ...) fprintf(stderr, _BLUE "INFO" _RESET " (%s:%i) " fmt "\n", \ __FILE__, __LINE__, ##__VA_ARGS__) +#if 0 #define LINE(len) do { \ printf(_GREEN); \ FOR(int, i, len) printf("_"); \ @@ -38,5 +37,6 @@ FMT(T)(v, buf); \ INFO_F("%s", buf); \ } while (0) +#endif #endif /* ERR_H */ diff --git a/linked_list.cpp b/linked_list.cpp new file mode 100644 index 00000000..bd49510e --- /dev/null +++ b/linked_list.cpp @@ -0,0 +1,38 @@ +#include "linked_list.h" + +template +llist::llist () { + this->length = 0; + this->cur = this->head = new link; + this->tail = new link; + + head->after = tail; + tail->before = head; +} + +template +link::~link () { + this.unlink(); +} + +template +void link::unlink () { + if (this->before != nullptr) this->before->after = this->after; + if (this->after != nullptr) this->after->before = this->before; +} + +template +void llist::push(T& val) { + auto l = new link(val); + + l->after = FIRST(this); + FIRST(this) = l; + + l->after->before = l; + l->before = this->head; + + ++this->length; + + // TODO do I want to change that? + this->cur = l; +} diff --git a/linked_list.h b/linked_list.h index a17bd797..7d11ca81 100644 --- a/linked_list.h +++ b/linked_list.h @@ -1,54 +1,48 @@ #ifndef LINKED_LIST_H #define LINKED_LIST_H -#include "macro.h" -#define LLIST(T) TEMPL(llist, T) -#define LINK(T) TEMPL(llist_link, T) +template +struct link { + link* before = nullptr; + link* after = nullptr; + T* value; -#define UNLINK(T) TEMPL(unlink, T) + link (); + link (T* val) : value(val) { } + ~link (); -#endif /* LINKED_LIST_H */ -#ifdef TYPE - -typedef struct LINK(TYPE) { - struct LINK(TYPE)* before; - struct LINK(TYPE)* after; - TYPE* value; -} LINK(TYPE); + void unlink (); +}; -#define L(link) (link)->value +// #define L(link) (link)->value -typedef struct { - LINK(TYPE)* head; - LINK(TYPE)* tail; - LINK(TYPE)* cur; +template +struct llist { + link* head; + link* tail; + link* cur; int length; -} LLIST(TYPE); + + llist (); + + void push ( T& ); + T& peek (); + T& pop (); + + llist& operator += (llist& other); +}; #define FIRST(lst) (lst)->head->after #define FIRST_V(lst) (lst)->head->after->value #define LAST(lst) (lst)->tail->before #define LAST_V(lst) (lst)->tail->before->value -INIT_F ( LLIST(TYPE) ); - /* * NOTE freeing a linked list alsa FFREE's all its contents. * TODO some form of shared pointer to ensure nothing is free'd twice * would be a good idea. */ -FREE_F ( LLIST(TYPE) ); - -INIT_F ( LINK(TYPE) ); -INIT_F ( LINK(TYPE), TYPE* val ); -FREE_F ( LINK(TYPE) ); - -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 ); @@ -85,4 +79,4 @@ FMT_F(LLIST(TYPE)); // #define __NXT_LLIST(T, l, set) l = L(__INTER(l) = __INTER(l)->after) #define NXT_LLIST(T) __NXT_LLIST -#endif /* TYPE */ +#endif /* LINKED_LIST_H */ diff --git a/linked_list.inc.h b/linked_list.inc.h index 8ae720ba..410fddba 100644 --- a/linked_list.inc.h +++ b/linked_list.inc.h @@ -1,26 +1,3 @@ -#ifndef TYPE -#error "Set TYPE before including self file" -#else - -INIT_F ( LLIST(TYPE) ) { - self->length = 0; - NEW(LINK(TYPE), head); - NEW(LINK(TYPE), tail); - self->head = head; - self->tail = tail; - head->after = tail; - tail->before = head; - self->cur = head; - return 0; -} - -FREE_F (LINK(TYPE)) { - UNLINK(LINK(TYPE))(self); - - if (self->value != NULL) FFREE(TYPE, self->value); - return 0; -} - FREE_F( LLIST(TYPE) ) { LINK(TYPE) *n, *next; n = self->head; diff --git a/macro.h b/macro.h deleted file mode 100644 index 6421b2fd..00000000 --- a/macro.h +++ /dev/null @@ -1,131 +0,0 @@ -#ifndef MACRO_H -#define MACRO_H - -/* - * Token paste - */ -#define TP(a, b) a ## b -#define TP3(a, b, c) a ## b ## c -#define TP4(a, b, c, d) a ## b ## c ## d -#define TP5(a, b, c, d, e) a ## b ## c ## d ## e -#define TP6(a, b, c, d, e, f) a ## b ## c ## d ## e ## f - -/* - * Get length of __VA_ARGS__ - * Borrowed fram: - * https://stackoverflow.com/a/35986932 - */ -#define VA_ARGS_NUM_PRIV(P1, P2, P3, P4, P5, P6, Pn, ...) Pn -#define VA_ARGS_NUM(...) VA_ARGS_NUM_PRIV(-1, ## __VA_ARGS__, 5, 4, 3, 2, 1, 0) - -/* - * Templatization macros. Forms symbols on the from name, which - * looks really good in debuggers and the like. Unicode characters - * written in \U notation since C apparently doesn't support unicode - * literals. - * - * Can be nested (useful for container types). - * - * Doesn't use ASCII <>, but rather some other ᐸᐳ, meaning that it's - * not a reserved character. - * - * nameᐸTᐳ - */ -#define TEMPL(name, T) TP4(name, \U00001438 , T, \U00001433 ) -#define TEMPL2(name, T, V) TP6(name, \U00001438\U00001438 , T , \U00001433_\U00001438 , V, \U00001433\U00001433) -#define TEMPL_N(name, T, argcount) TP6(name, \U00001438 , T, _, argcount, \U00001433 ) - -/* Constructor type name */ -#define __INIT_T(T, C) TEMPL_N(init, T, C) - -/* Returns full type of constructor */ -#define INIT_F(T, ...) \ - int __INIT_T(T, VA_ARGS_NUM(__VA_ARGS__)) (T* self, ## __VA_ARGS__) - -/* - * Call the constructor of an object - * `int` part of the macro, to ensure that any attempt to call self - * function results in an error. - */ -#define INIT(T, N, ...) \ - __INIT_T(T, VA_ARGS_NUM(__VA_ARGS__)) (N, ## __VA_ARGS__) - -/* Allocate a new_ object on the HEAP */ -#define NEW(T, N, ...) \ - T* N = (T*) malloc(sizeof(*N)); \ - INIT(T, N, ## __VA_ARGS__); - -/* - * Reconstructs a object. Use with caution. - */ -#define RENEW(T, N, ...) do { \ - N = (T*) malloc(sizeof(*N)); \ - INIT(T, N, ## __VA_ARGS__); \ -} while (0) - - -/* Allocate a new_ object on the STACK */ -#define SNEW(T, N, ...) \ - T N; \ - INIT(T, & N, ## __VA_ARGS__); - -/* Destructor for type */ -#define FREE(T) TEMPL(free, T) - -/* Call destructor for type, and free object */ -#define FFREE(T, N) do { FREE(T)(N); free(N); } while (0) - -/* Declare destructor */ -#define FREE_F(T) int FREE(T) (T* self) - -/* generate reusable internal symbol */ -#define __INTER(s) TP3(__, s, __internal) - -/* Iterator macros. */ -#define FOR(CONT_T, T, var, set) \ - PRE_FOR_ ## CONT_T (T) (T, var, set); \ - for( BEG_ ## CONT_T (T) (T, var, set); \ - END_ ## CONT_T (T) (T, var, set); \ - NXT_ ## CONT_T (T) (T, var, set)) - -/* Example int implementation - * FOR(int, i, 10) { } */ - -#define PRE_FOR_int(i, set) -#define BEG_int(i, set) int i = 0 -#define NXT_int(i, set) i++ -#define END_int(i, set) i < set - -/* - * General functions that different container types may implement. - * Actuall implementation and type signature is mostly left to - * individual implementations. - */ -#define DEEP_COPY(T) TEMPL(copy , T) -#define RESOLVE(T) TEMPL(resolve , T) -#define APPEND(T) TEMPL(append , T) -#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) -#define RESET(T) TEMPL(reset , T) - -/* - * Formatting macros. - * Transform objects into string representation of themselves. - * buf should be a suffisiently large memmory location, if it's to - * small then bad stuff might happen. - * - * Should return the number of bytes written (like sprintf). - */ - -#define FMT_T(T) TEMPL(format , T) -#define FMT_F(T) int FMT_T(T)(T* self, char* buf, ...) -// TODO change order of buf and item -#define __FMT_HELP(item, buf, ...) ((item), (buf), VA_ARGS_NUM(__VA_ARGS__), ## __VA_ARGS__) -#define FMT(T) FMT_T(T) __FMT_HELP -#define fmtf(...) seek += sprintf(buf + seek, __VA_ARGS__) - -#endif /* MACRO_H */ diff --git a/parse.c b/parse.c deleted file mode 100644 index 8f7a9102..00000000 --- a/parse.c +++ /dev/null @@ -1,302 +0,0 @@ -#include "parse.h" - -#include -#include -#include - -#include "macro.h" -#include "vcal.h" - -#include "err.h" - -#define TYPE vcomponent -#include "linked_list.inc.h" -#undef TYPE - -#define T strbuf -#define V strbuf -#include "pair.h" -#include "pair.inc.h" -#undef T -#undef V - -/* - * name *(";" param) ":" value CRLF - */ -int parse_file(char* filename, FILE* f, vcomponent* root) { - part_context p_ctx = p_key; - - SNEW(parse_ctx, ctx, filename); - PUSH(LLIST(vcomponent))(&ctx.comp_stack, root); - - SNEW(content_line, cline); - - char c; - while ( (c = fgetc(f)) != EOF) { - - /* We have a linebreak */ - if (c == '\r' || c == '\n') { - - if (fold(f, &ctx, c) > 0) { - /* Actuall end of line, handle value */ - - strbuf* target = CLINE_CUR_VAL(&cline); - - DEEP_COPY(strbuf)(target, &ctx.str); - strbuf_cap(target); - strbuf_soft_reset(&ctx.str); - - handle_kv(&cline, &ctx); - - p_ctx = p_key; - } /* Else continue on current line */ - - /* We have an escaped character */ - } else if (c == '\\') { - char esc = fgetc(f); - char target; - - /* - * An actuall linebreak after the backslash. Unfold the - * line and find the next "real" character, and escape - * that. - */ - if (esc == '\r' || esc == '\n') { - int ret; - if ( (ret = fold(f, &ctx, esc)) != 0) { - if (ret == 1) ERR_P(&ctx, "ESC before not folded line"); - else ERR_P(&ctx, "other error: val = %i", ret); - exit (2); - } else { - esc = fgetc(f); - } - } - - /* Escaped new_line */ - if (esc == 'n' || esc == 'N') { - target = '\n'; - - /* "Standard" escaped character */ - } else if (esc == ';' || esc == ',' || esc == '\\') { - target = esc; - - /* Invalid escaped character */ - } else { - ERR_P(&ctx, "Non escapable character '%c' (%i)", esc, esc); - } - - /* save escapade character as a normal character */ - strbuf_append(&ctx.str, target); - - ++ctx.column; - ++ctx.pcolumn; - - - /* Border between param {key, value} */ - } else if (p_ctx == p_param_name && c == '=') { - LLIST(param_set)* params = CLINE_CUR_PARAMS(&cline); - - NEW(param_set, ps); - DEEP_COPY(strbuf)(&ps->key, &ctx.str); - strbuf_cap(&ps->key); - strbuf_soft_reset(&ctx.str); - PUSH(LLIST(param_set))(params, ps); - - 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 == ';')) { - - if (p_ctx == p_param_value) { - /* push kv pair */ - - NEW(strbuf, s); - - DEEP_COPY(strbuf)(s, &ctx.str); - strbuf_cap(s); - strbuf_soft_reset(&ctx.str); - - LLIST(strbuf)* ls = & CLINE_CUR_PARAMS(&cline)->cur->value->val; - PUSH(LLIST(strbuf))(ls, s); - - } - - if (p_ctx == p_key) { - DEEP_COPY(strbuf)(&cline.key, &ctx.str); - strbuf_cap(&cline.key); - strbuf_soft_reset(&ctx.str); - - NEW(content_set, p); - PUSH(LLIST(content_set))(&cline.val, p); - } - - if (c == ':') p_ctx = p_value; - else if (c == ';') p_ctx = p_param_name; - - } else { - strbuf_append(&ctx.str, c); - - ++ctx.column; - ++ctx.pcolumn; - } - } - - if (! feof(f)) { - ERR("Error parsing"); - } - /* Check to see if empty line */ - else if (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. - */ - - strbuf* target = CLINE_CUR_VAL(&cline); - DEEP_COPY(strbuf)(target, &ctx.str); - strbuf_cap(target); - strbuf_soft_reset(&ctx.str); - - ++ctx.line; - ctx.column = 0; - - handle_kv(&cline, &ctx); - - } - - FREE(content_line)(&cline); - - assert(POP(LLIST(vcomponent))(&ctx.comp_stack) == root); - assert(EMPTY(LLIST(strbuf))(&ctx.key_stack)); - assert(EMPTY(LLIST(vcomponent))(&ctx.comp_stack)); - - FREE(parse_ctx)(&ctx); - - return 0; -} - -int handle_kv ( - content_line* cline, - 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* type = CLINE_CUR_VAL(cline); - DEEP_COPY(strbuf)(s, type); - PUSH(LLIST(strbuf))(&ctx->key_stack, s); - - RESET(LLIST(content_set))(&cline->val); - - 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_CUR_VAL(cline)) != 0) { - ERR_P(ctx, "Expected END:%s, got END:%s.\n%s line", - s->mem, - CLINE_CUR_VAL(cline)->mem, - PEEK(LLIST(vcomponent))(&ctx->comp_stack)->filename); - 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 self instead be done at creation time? - PUSH(vcomponent)(PEEK(LLIST(vcomponent))(&ctx->comp_stack), cur); - } - } else { - NEW(content_line, c); - DEEP_COPY(content_line)(c, cline); - - PUSH(TRIE(content_line))( - &PEEK(LLIST(vcomponent))(&ctx->comp_stack)->clines, - c->key.mem, c); - - RESET(LLIST(content_set))(&cline->val); - } - - return 0; -} - -int fold(FILE* f, parse_ctx* ctx, char c) { - int retval; - - char buf[2] = { - (c == '\n' ? '\n' : (char) fgetc(f)), - (char) fgetc(f) - }; - - ctx->pcolumn = 1; - - if (buf[0] != '\n') { - ERR_P(ctx, "expected new_line after CR"); - retval = -1; - - } else if (buf[1] == ' ' || buf[1] == '\t') { - retval = 0; - ctx->pcolumn++; - - } else if (ungetc(buf[1], f) != buf[1]) { - ERR_P(ctx, "Failed to put character back on FILE"); - retval = -2; - - } else { - retval = 1; - ++ctx->line; - ctx->column = 0; - } - - ++ctx->pline; - - return retval; -} - - -INIT_F(parse_ctx, char* filename) { - INIT(LLIST(strbuf), &self->key_stack); - INIT(LLIST(vcomponent), &self->comp_stack); - self->filename = (char*) calloc(sizeof(*filename), strlen(filename) + 1); - strcpy(self->filename, filename); - - self->line = 0; - self->column = 0; - - self->pline = 1; - self->pcolumn = 1; - - INIT(strbuf, &self->str); - - return 0; -} - -FREE_F(parse_ctx) { - - FREE(LLIST(strbuf))(&self->key_stack); - FREE(LLIST(vcomponent))(&self->comp_stack); - free(self->filename); - - self->line = 0; - self->column = 0; - FREE(strbuf)(&self->str); - - return 0; -} diff --git a/parse.cpp b/parse.cpp new file mode 100644 index 00000000..310ab7fe --- /dev/null +++ b/parse.cpp @@ -0,0 +1,269 @@ +#include "parse.h" + +#include +#include +#include + +#include "vcal.h" +#include "strbuf.h" + +#include "err.h" + +/* + * name *(";" param) ":" value CRLF + */ +int parse_file(char* filename, FILE* f, vcomponent& root) { + part_context p_ctx = p_key; + + parse_ctx ctx(filename); + ctx.comp_stack.push(root); + + content_line cline; + + char c; + while ( (c = fgetc(f)) != EOF) { + + /* We have a linebreak */ + if (c == '\r' || c == '\n') { + + if (fold(f, &ctx, c) > 0) { + /* Actuall end of line, handle value */ + + // std::string& target = CLINE_CUR_VAL(&cline); + // TODO solve current; + // std::string& target = cline + + strbuf target = ctx.str; + // DEEP_COPY(strbuf)(target, &ctx.str); + target.cap(); + // strbuf_cap(target); + ctx.str.soft_reset(); + // strbuf_soft_reset(&ctx.str); + + handle_kv(&cline, &ctx); + + p_ctx = p_key; + } /* Else continue on current line */ + + /* We have an escaped character */ + } else if (c == '\\') { + char esc = fgetc(f); + char target; + + /* + * An actuall linebreak after the backslash. Unfold the + * line and find the next "real" character, and escape + * that. + */ + if (esc == '\r' || esc == '\n') { + int ret; + if ( (ret = fold(f, &ctx, esc)) != 0) { + if (ret == 1) ERR_P(&ctx, "ESC before not folded line"); + else ERR_P(&ctx, "other error: val = %i", ret); + exit (2); + } else { + esc = fgetc(f); + } + } + + /* Escaped new_line */ + if (esc == 'n' || esc == 'N') { + target = '\n'; + + /* "Standard" escaped character */ + } else if (esc == ';' || esc == ',' || esc == '\\') { + target = esc; + + /* Invalid escaped character */ + } else { + ERR_P(&ctx, "Non escapable character '%c' (%i)", esc, esc); + } + + /* save escapade character as a normal character */ + // strbuf_append(&ctx.str, target); + ctx.str += target; + + ++ctx.column; + ++ctx.pcolumn; + + + /* Border between param {key, value} */ + } else if (p_ctx == p_param_name && c == '=') { + // LLIST(param_set)* params = CLINE_CUR_PARAMS(&cline); + std::list* params = cline.second.second; + + // NEW(param_set, ps); + auto ps = new param_set; + // TODO make sure this is a deep copy + ps->first = ctx.str; + ps->first.cap(); + ctx.str.soft_reset(); + PUSH(LLIST(param_set))(params, ps); + + 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 == ';')) { + + if (p_ctx == p_param_value) { + /* push kv pair */ + + NEW(strbuf, s); + + DEEP_COPY(strbuf)(s, &ctx.str); + strbuf_cap(s); + strbuf_soft_reset(&ctx.str); + + LLIST(strbuf)* ls = & CLINE_CUR_PARAMS(&cline)->cur->value->val; + PUSH(LLIST(strbuf))(ls, s); + + } + + if (p_ctx == p_key) { + DEEP_COPY(strbuf)(&cline.key, &ctx.str); + strbuf_cap(&cline.key); + strbuf_soft_reset(&ctx.str); + + NEW(content_set, p); + PUSH(LLIST(content_set))(&cline.val, p); + } + + if (c == ':') p_ctx = p_value; + else if (c == ';') p_ctx = p_param_name; + + } else { + strbuf_append(&ctx.str, c); + + ++ctx.column; + ++ctx.pcolumn; + } + } + + if (! feof(f)) { + ERR("Error parsing"); + } + /* Check to see if empty line */ + else if (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. + */ + + strbuf* target = CLINE_CUR_VAL(&cline); + DEEP_COPY(strbuf)(target, &ctx.str); + strbuf_cap(target); + strbuf_soft_reset(&ctx.str); + + ++ctx.line; + ctx.column = 0; + + handle_kv(&cline, &ctx); + + } + + FREE(content_line)(&cline); + + assert(POP(LLIST(vcomponent))(&ctx.comp_stack) == root); + assert(EMPTY(LLIST(strbuf))(&ctx.key_stack)); + assert(EMPTY(LLIST(vcomponent))(&ctx.comp_stack)); + + FREE(parse_ctx)(&ctx); + + return 0; +} + +int handle_kv ( + content_line* cline, + 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* type = CLINE_CUR_VAL(cline); + DEEP_COPY(strbuf)(s, type); + PUSH(LLIST(strbuf))(&ctx->key_stack, s); + + RESET(LLIST(content_set))(&cline->val); + + 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_CUR_VAL(cline)) != 0) { + ERR_P(ctx, "Expected END:%s, got END:%s.\n%s line", + s->mem, + CLINE_CUR_VAL(cline)->mem, + PEEK(LLIST(vcomponent))(&ctx->comp_stack)->filename); + 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 self instead be done at creation time? + PUSH(vcomponent)(PEEK(LLIST(vcomponent))(&ctx->comp_stack), cur); + } + } else { + NEW(content_line, c); + DEEP_COPY(content_line)(c, cline); + + PUSH(TRIE(content_line))( + &PEEK(LLIST(vcomponent))(&ctx->comp_stack)->clines, + c->key.mem, c); + + RESET(LLIST(content_set))(&cline->val); + } + + return 0; +} + +int fold(FILE* f, parse_ctx* ctx, char c) { + int retval; + + char buf[2] = { + (c == '\n' ? '\n' : (char) fgetc(f)), + (char) fgetc(f) + }; + + ctx->pcolumn = 1; + + if (buf[0] != '\n') { + ERR_P(ctx, "expected new_line after CR"); + retval = -1; + + } else if (buf[1] == ' ' || buf[1] == '\t') { + retval = 0; + ctx->pcolumn++; + + } else if (ungetc(buf[1], f) != buf[1]) { + ERR_P(ctx, "Failed to put character back on FILE"); + retval = -2; + + } else { + retval = 1; + ++ctx->line; + ctx->column = 0; + } + + ++ctx->pline; + + return retval; +} diff --git a/parse.h b/parse.h index b69bcfa5..6ab98bfd 100644 --- a/parse.h +++ b/parse.h @@ -4,12 +4,17 @@ #include #include +#include +#include + #include "strbuf.h" #include "vcal.h" +#if 0 #define TYPE vcomponent #include "linked_list.h" #undef TYPE +#endif /* * The standard says that no line should be longer than 75 octets. @@ -18,32 +23,32 @@ */ #define SEGSIZE 75 -typedef enum { +enum part_context { p_key, p_value, p_param_name, p_param_value, p_escape -} 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; +struct parse_ctx { + std::string filename; + std::stack key_stack; + std::stack comp_stack; /* Number for unfolded lines */ - int line; - int column; + int line = 0; + int column = 0; /* Actuall lines and columns from file */ - int pline; - int pcolumn; + int pline = 1; + int pcolumn = 1; strbuf str; -} parse_ctx; -INIT_F(parse_ctx, char* filename); -FREE_F(parse_ctx); + parse_ctx (const std::string& filename) + : filename(filename) { } +}; int handle_kv( content_line* cline, diff --git a/strbuf.c b/strbuf.c deleted file mode 100644 index f17de211..00000000 --- a/strbuf.c +++ /dev/null @@ -1,138 +0,0 @@ -#include "strbuf.h" - -#include -#include - -#include "err.h" - -INIT_F(strbuf) { - INIT(strbuf, self, 1); - return 0; -} - -/* - * Giving len < 1 is an error. - */ -INIT_F(strbuf, size_t len) { - self->mem = (char*) calloc(sizeof(*self->mem), len); - self->alloc = len; - self->ptr = 0; - self->len = 0; - return 0; -} - -int strbuf_realloc(strbuf* str, size_t len) { - str->mem = (char*) realloc(str->mem, len); - str->alloc = len; - return 0; -} - -FREE_F(strbuf) { - /* has already been freed */ - if (self->mem == NULL) return 1; - - free (self->mem); - self->mem = NULL; - self->alloc = 0; - self->len = 0; - return 0; -} - -/* - * Reallocates memmory for you. Returns 1 if memory was reallocated. - */ -int strbuf_append(strbuf* s, char c) { - int retval = 0; - - if (s->len + 1 > s->alloc) { - s->alloc <<= 1; - s->mem = (char*) realloc(s->mem, s->alloc); - retval = 1; - } - - s->mem[s->len] = c; - s->ptr = ++s->len; - return retval; -} - -int strbuf_cap(strbuf* s) { - /* - * TODO check memmory usage - */ - return strbuf_append(s, 0); -} - -int DEEP_COPY(strbuf)(strbuf* dest, strbuf* src) { - int retval = 0; - - if (dest->alloc < src->len) { - /* +1 in length is to have room for '\0'. */ - strbuf_realloc(dest, src->len + 1); - retval = 1; - } - - dest->len = src->len; - memcpy(dest->mem, src->mem, src->len); - return retval; -} - -int strbuf_cmp(strbuf* a, strbuf* b) { - if (a == NULL || a->alloc == 0 || - b == NULL || b->alloc == 0) - { - ERR("a or b not alloced"); - // return -1; - } - - return strncmp(a->mem, b->mem, a->len); -} - -int strbuf_c(strbuf* a, char* b) { - if (a == NULL || a->alloc == 0) { - ERR("a not allocated"); - return -1; - } - - return strcmp(a->mem, b) == 0; -} - -char* charat(strbuf* s, unsigned int idx) { - if (idx > s->len) { - ERR("Index out of bounds"); - return (char*) -1; - } - - return &s->mem[idx]; -} - -char* strbuf_cur(strbuf* s) { - return &s->mem[s->ptr]; -} - -char* strbuf_end(strbuf* s) { - return &s->mem[s->len]; -} - -int strbuf_reset(strbuf* s) { - s->ptr = 0; - return 0; -} - - -int strbuf_soft_reset(strbuf* s) { - s->ptr = s->len = 0; - return 0; -} - -strbuf* RESOLVE(strbuf)(strbuf* dest, strbuf* new_) { - if (dest == NULL) return new_; - else return dest; -} - -FMT_F(strbuf) { - return sprintf(buf, "%s", self->mem); -} - -int SIZE(strbuf)(strbuf* self) { - return self->len; -} diff --git a/strbuf.cpp b/strbuf.cpp new file mode 100644 index 00000000..3864b271 --- /dev/null +++ b/strbuf.cpp @@ -0,0 +1,26 @@ +#include "strbuf.h" + +#include + +void strbuf::realloc (size_t len) { + this->mem = static_cast(std::realloc(this->mem, len)); + this->alloc = len; +} + +strbuf::~strbuf() { + free (this->mem); + this->mem = NULL; + this->alloc = 0; + this->len = 0; +} + +strbuf& strbuf::operator+=(char c) { + if (this->len + 1 > this->alloc) { + this->alloc <<= 1; + this->mem = static_cast (std::realloc(this->mem, this->alloc)); + } + + this->mem[this->len] = c; + this->ptr = ++this->len; + return *this; +} diff --git a/strbuf.h b/strbuf.h index c531734e..07580f63 100644 --- a/strbuf.h +++ b/strbuf.h @@ -1,8 +1,9 @@ #ifndef STRBUF_H #define STRBUF_H -#include -#include "macro.h" +#include +#include +#include /* * A high level string type which holds it's own length, how much @@ -12,88 +13,74 @@ * Also comes with a number of functions which allow for safe(er) * access to the memmory. */ -typedef struct { +struct strbuf { char* mem; /* TODO add support for negative ptr */ - int ptr; - unsigned int alloc; - unsigned int len; -} strbuf; + int ptr = 0; + size_t alloc; + size_t len = 0; -/* - * Init strbuf to size of 0 - * Doesnt't call malloc. - */ -INIT_F(strbuf); + strbuf () : strbuf (1) { }; + strbuf (size_t alloc) + : alloc(alloc) + , mem(static_cast(malloc(alloc))) { }; -/* Constructor */ -INIT_F(strbuf, size_t len); + ~strbuf(); -/* - * Like realloc, but for strbuf - */ -int strbuf_realloc(strbuf* str, size_t len); + /* + * Like realloc, but for strbuf + */ + void realloc (size_t len); -/* - * Free's contents of str, but keeps str. - */ -FREE_F(strbuf); + bool operator==(strbuf& other) { + return strncmp(this->mem, other.mem, this->len) == 0; + } + bool operator==(char* other) + { strncmp(this->mem, other, this->len) == 0 ; } -int strbuf_cmp(strbuf* a, strbuf* b); -int strbuf_c(strbuf* a, char* b); + strbuf& operator=(strbuf* other); -/* - * Copy contents from src to dest. - * Assumes that dest is already initialized. - */ -int DEEP_COPY(strbuf)(strbuf*, strbuf*); + strbuf& operator+=(char c); -/* - * Append char to end of strbuf, determined by s->len. - */ -int strbuf_append(strbuf* s, char c); + void cap() { this->mem += '\0'; } -/* - * Calls strbuf_append with NULL. - */ -int strbuf_cap(strbuf* s); + /* + * Returns a pointer to character at index. Allows mutation of the + * value pointed to by the return address. + */ + char& operator[](int idx) + { return this->mem[idx]; } -/* - * Returns a pointer to character at index. Allows mutation of the - * value pointed to by the return address. - */ -char* charat(strbuf* s, unsigned int idx); + /* Same as `charat`, But returns the current character. */ + char& strbuf_cur() + { return this->mem[this->ptr]; } -/* - * Same as `charat`, But returns the current character. - */ -char* strbuf_cur(strbuf* s); + /* Returns the character after the last, so where null hopefully is. */ + char& back() + { return this->mem[this->len]; } -/* - * Resets the seek for strbuf to 0. - */ -int strbuf_reset(strbuf* s); + /* Resets the seek for strbuf to 0. */ + void reset(); -/* - * Sets the length and seek ptr to 0, but doesn't touch the memmory. - */ -int strbuf_soft_reset(strbuf* s); + /* Sets the length and seek ptr to 0, but doesn't touch the memmory. */ + void soft_reset(); -/* - * Returns the character after the last, so where null hopefully is. - */ -char* strbuf_end(strbuf* s); + std::string to_string() { + return std::string (this->mem); + } +}; /* * 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); +// 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 self call. */ +#if 0 int strbuf_init_copy(strbuf* dest, strbuf* src); strbuf* RESOLVE(strbuf)(strbuf*, strbuf*); @@ -101,5 +88,6 @@ strbuf* RESOLVE(strbuf)(strbuf*, strbuf*); FMT_F(strbuf); int SIZE(strbuf)(strbuf*); +#endif #endif /* STRBUF_H */ diff --git a/trie.cpp b/trie.cpp new file mode 100644 index 00000000..729277bd --- /dev/null +++ b/trie.cpp @@ -0,0 +1,134 @@ +#include "trie.h" + +template +trie::trie () { + this->root = new trie_node ('\0'); +} + +template +trie_node::trie_node (char c) { + this->c = c; +} + +template +trie_node::trie_node (char c, trie_node* next, trie_node* child) { + this->c = c; + this->next = next; + this->child = child; +} + +template +int trie::push_back (const char* key, const T& item) { + trie_node *cur, *last; + + last = this->root; + cur = last->child; + + char* subkey = key; + + while (true) { + if (cur == NULL) { + /* Build direct LL for remaining subkey */ + for (char* c = subkey; c[0] != '\0'; c++) { + // NEW(TRIE_NODE(TYPE), t, *c); + auto t = new trie_node(*c); + last->child = t; + last = t; + } + // TODO fix resolve + // last->value = RESOLVE(TYPE)(last->value, val); + last->value = item; + return 0; + } else if (cur->c == subkey[0]) { + /* This node belongs to the key, + * Decend further */ + last = cur; + cur = cur->child; + subkey++; + } else if (subkey[0] == '\0') { + /* Key finished */ + // TODO fix resolve + // last->value = RESOLVE(TYPE)(last->value, val); + last->value = item; + return 0; + } else if (cur->next != NULL) { + /* This node was not part of the set, but it's sibling might */ + cur = cur->next; + /* `last` not set since we aren't moving down */ + } else { + /* No node on self level was part of the set, create a new__ + * sibling and follow down that parse */ + // NEW(TRIE_NODE(TYPE), t, *subkey); + auto t = new trie_node(*subkey); + cur->next = t; + last = cur; + cur = t; + } + } +} + +template +T& trie::operator[] (char* key) { + trie_node* n = this->root->child; + char* subkey = key; + + while (n != NULL) { + if (subkey[1] == '\0') { + return n->value; + } else if (subkey[0] == n->c) { + n = n->child; + subkey++; + } else { + n = n->next; + } + } + + // ERR("Position not found"); + // return 0; + return nullptr; +} + +template +std::ostream& operator<<(std::ostream& o, trie_node* node) { +#if 0 + va_list ap; + va_start(ap, buf); + int argc = va_arg(ap, int); + int depth = argc >= 1 + ? va_arg(ap, int) + : 0; + va_end(ap); + + int seek = 0; +#endif + // TODO figure out depth + int depth = 1; + + trie_node* n = node; + + + if (n == NULL) { o << std::endl; } + while (n != NULL) { + o << '|'; + for (int i = 0; i < depth; i++) o << ' '; + o << (n->c == '\0' ? '0' : n->c); + if (n->value != NULL) { + o << n->value << std::endl; + } + + if (n->child != NULL) { + o << std::endl; + o << n->child; // depth + 1 + } + n = n->next; + } + return o; +} + +template +std::ostream& operator<<(std::ostream& o, trie* trie) { + o << "Trie: " << trie << " {\n"; + o << trie->root->child; + o << "}"; + return o; +} diff --git a/trie.h b/trie.h index 404864d3..d672125b 100644 --- a/trie.h +++ b/trie.h @@ -1,46 +1,60 @@ #ifndef TRIE_H #define TRIE_H -#include +#include -#include "macro.h" +template +struct trie_node { + char c; + T* value = NULL; + trie_node* next = NULL; + trie_node* child = NULL; -#define TRIE(T) TEMPL(trie, T) -#define TRIE_NODE(T) TEMPL(trie_node, T) + trie_node (char c); + trie_node (char c, trie_node* next, trie_node* child); -#endif /* TRIE_H */ -#ifdef TYPE + // ~trie_node (); +}; -typedef struct TRIE_NODE(TYPE) { - char c; - TYPE* value; - struct TRIE_NODE(TYPE)* next; - struct TRIE_NODE(TYPE)* child; -} TRIE_NODE(TYPE); +template +std::ostream& operator<<(std::ostream&, trie_node* node); + +template +struct trie { + trie_node* root; + + trie (); + // ~trie (); -typedef struct { - TRIE_NODE(TYPE)* root; -} TRIE(TYPE); + int push_back (const char* key, const T&); + T& operator[] ( char* key ); -INIT_F ( TRIE(TYPE) ); + bool empty () { return this->root->child == NULL; } +}; -INIT_F (TRIE_NODE(TYPE), char c); +template +std::ostream& operator<<(std::ostream&, trie* trie); -INIT_F (TRIE_NODE(TYPE), - char c, TRIE_NODE(TYPE)* next, TRIE_NODE(TYPE)* child ); -int PUSH(TRIE(TYPE)) ( TRIE(TYPE)* trie, char* key, TYPE* val ); +// INIT_F ( TRIE(TYPE) ); -TYPE* GET(TRIE(TYPE)) ( TRIE(TYPE)* trie, char* key ); +// INIT_F (TRIE_NODE(TYPE), char c); -FREE_F(TRIE_NODE(TYPE)); +// INIT_F (TRIE_NODE(TYPE), +// char c, TRIE_NODE(TYPE)* next, TRIE_NODE(TYPE)* child ); -FREE_F(TRIE(TYPE)); +// int PUSH(TRIE(TYPE)) ( TRIE(TYPE)* trie, char* key, TYPE* val ); -int EMPTY(TRIE(TYPE))(TRIE(TYPE)*); +// TYPE* GET(TRIE(TYPE)) ( TRIE(TYPE)* trie, char* key ); -FMT_F(TRIE_NODE(TYPE)); -FMT_F(TRIE(TYPE)); +// FREE_F(TRIE_NODE(TYPE)); -#endif /* TYPE */ +// FREE_F(TRIE(TYPE)); + +// int EMPTY(TRIE(TYPE))(TRIE(TYPE)*); + +// FMT_F(TRIE_NODE(TYPE)); +// FMT_F(TRIE(TYPE)); + +#endif /* TRIE_H */ diff --git a/trie.inc.h b/trie.inc.h deleted file mode 100644 index 5517939e..00000000 --- a/trie.inc.h +++ /dev/null @@ -1,166 +0,0 @@ -#ifndef TYPE -#error "Set TYPE before including self file" -#else - -#include - -#include "err.h" -#include "macro.h" - -INIT_F ( TRIE(TYPE) ) { - NEW(TRIE_NODE(TYPE), t, '\0'); - self->root = t; - return 0; -} - -INIT_F (TRIE_NODE(TYPE), char c) { - self->c = c; - self->value = NULL; - self->next = NULL; - self->child = NULL; - return 0; -} - -INIT_F (TRIE_NODE(TYPE), - char c, - TRIE_NODE(TYPE)* next, - TRIE_NODE(TYPE)* child ) -{ - self->c = c; - self->next = next; - self->child = child; - return 0; -} - -int PUSH(TRIE(TYPE)) ( TRIE(TYPE)* trie, char* key, TYPE* val ) { - TRIE_NODE(TYPE) *cur, *last; - - last = trie->root; - cur = last->child; - - char* subkey = key; - - while (1) { - if (cur == NULL) { - /* Build direct LL for remaining subkey */ - for (char* c = subkey; c[0] != '\0'; c++) { - NEW(TRIE_NODE(TYPE), t, *c); - last->child = t; - last = t; - } - last->value = RESOLVE(TYPE)(last->value, val); - return 0; - } else if (cur->c == subkey[0]) { - /* This node belongs to the key, - * Decend further */ - last = cur; - cur = cur->child; - subkey++; - } else if (subkey[0] == '\0') { - /* Key finished */ - last->value = RESOLVE(TYPE)(last->value, val); - return 0; - } else if (cur->next != NULL) { - /* This node was not part of the set, but it's sibling might */ - cur = cur->next; - /* `last` not set since we aren't moving down */ - } else { - /* No node on self level was part of the set, create a new__ - * sibling and follow down that parse */ - NEW(TRIE_NODE(TYPE), t, *subkey); - cur->next = t; - last = cur; - cur = t; - } - } - - return 0; -} - -/* - * TODO what happens when I give an invalid key? - */ -TYPE* GET(TRIE(TYPE)) ( TRIE(TYPE)* trie, char* key ) { - TRIE_NODE(TYPE)* n = trie->root->child; - char* subkey = key; - - while (n != NULL) { - if (subkey[1] == '\0') { - return n->value; - } else if (subkey[0] == n->c) { - n = n->child; - subkey++; - } else { - n = n->next; - } - } - - ERR("Position not found"); - return 0; -} - -FREE_F(TRIE_NODE(TYPE)) { - if (self == NULL) return 0; - if (self->value != NULL) FFREE(TYPE, self->value); - if (self->next != NULL) FREE(TRIE_NODE(TYPE))(self->next); - if (self->child != NULL) FREE(TRIE_NODE(TYPE))(self->child); - free (self); - return 0; -} - -FREE_F(TRIE(TYPE)) { - if (self->root->c != '\0') { - // ERR("Invalid trie"); - return 1; - } - return FREE(TRIE_NODE(TYPE))(self->root); -} - -int EMPTY(TRIE(TYPE))(TRIE(TYPE)* self) { - return self->root->child == NULL; -} - -FMT_F(TRIE_NODE(TYPE)) { - - va_list ap; - va_start(ap, buf); - int argc = va_arg(ap, int); - int depth = argc >= 1 - ? va_arg(ap, int) - : 0; - va_end(ap); - - int seek = 0; - - TRIE_NODE(TYPE)* n = self; - - if (n == NULL) { fmtf("\n"); } - while (n != NULL) { - fmtf("|"); - // FOR(int, i, depth) fmtf(" "); - for (int i = 0; i < depth; i++) fmtf(" "); - fmtf("%c ", n->c == '\0' ? '0' : n->c); - if (n->value != NULL) { - seek += FMT(TYPE)(n->value, buf + seek); - fmtf("\n"); - } - - if (n->child != NULL) { - fmtf("\n"); - seek += FMT(TRIE_NODE(TYPE))(n->child, buf + seek, depth + 1); - } - n = n->next; - } - return seek; - -} - -FMT_F(TRIE(TYPE)) { - int seek = 0; - fmtf("Trie: %p: {\n", self); - seek += FMT(TRIE_NODE(TYPE))(self->root->child, buf + seek); - fmtf("}"); - return seek; -} - -#endif /* TYPE */ diff --git a/vcal.c b/vcal.c deleted file mode 100644 index 7f674dac..00000000 --- a/vcal.c +++ /dev/null @@ -1,130 +0,0 @@ -#include "vcal.h" - -#include - -#define TYPE strbuf -#include "linked_list.inc.h" -#undef TYPE - -#define TYPE param_set -#include "linked_list.inc.h" -#undef TYPE - -#define TYPE content_set -#include "linked_list.inc.h" -#undef TYPE - -#define T strbuf - #define V LLIST(strbuf) - #include "pair.inc.h" - #undef V - #define V LLIST(param_set) - #include "pair.inc.h" - #undef V - #define V LLIST(content_set) - #include "pair.inc.h" - #undef V -#undef T - -#define TYPE content_line -// #include "hash.inc" -#include "trie.inc.h" -#undef TYPE - -#define TYPE vcomponent -#include "vector.inc.h" -#undef TYPE - -INIT_F(vcomponent) { - (void) self; - ERR("Do not use"); - return 0; -} - -INIT_F(vcomponent, char* type) { - return INIT(vcomponent, self, type, NULL); -} - -INIT_F(vcomponent, char* type, char* filename) { - - INIT(TRIE(content_line), &self->clines); - INIT(VECT(vcomponent), &self->components); - - self->filename = NULL; - if (filename != NULL) { - self->filename = (char*) calloc(sizeof(*filename), strlen(filename) + 1); - strcpy(self->filename, filename); - } - - self->type = (char*) calloc(sizeof(*type), strlen(type) + 1); - strcpy(self->type, type); - - self->parent = NULL; - - return 0; -} - -content_line* RESOLVE(content_line) - (content_line* dest, content_line* new_) -{ - if (dest == NULL) return new_; - - if (strbuf_cmp(&dest->key, &new_->key) != 0) { - ERR("Can't resolve between these two types"); - return NULL; - } - - /* This destroys new_->val. */ - APPEND(LLIST(content_set)) (&dest->val, &new_->val); - - FREE(strbuf)(&new_->key); - free(new_); - - return dest; -} - -content_line* get_property (vcomponent* ev, char* key) { - return GET(TRIE(content_line))(&ev->clines, key); -} - -FREE_F(vcomponent) { - if (self->filename != NULL) free(self->filename); - free(self->type); - - if (FREE(TRIE(content_line))(&self->clines) != 0) { - fprintf(stderr, "Error freeing vcomponent belonging to file \n %s \n", - self->filename); - } - - FREE(VECT(vcomponent))(&self->components); - - return 0; -} - -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; -} - -FMT_F(vcomponent) { - int seek = 0; - - for (int i = 0; i < 40; i++) fmtf("_"); - - seek += sprintf(buf + seek, _YELLOW); - seek += sprintf(buf + seek, "\nVComponet (Type := %s)\n", self->type); - seek += sprintf(buf + seek, _RESET); - seek += FMT(TRIE(content_line))(&self->clines, buf + seek); - seek += sprintf(buf + seek, "\nComponents:\n"); - FOR(VECT, vcomponent, comp, &self->components) { - seek += FMT(vcomponent)(comp, buf + seek); - } - - return seek; -} diff --git a/vcal.cpp b/vcal.cpp new file mode 100644 index 00000000..a104664d --- /dev/null +++ b/vcal.cpp @@ -0,0 +1,14 @@ +#include "vcal.h" +#include "err.h" + +std::ostream& operator<<(std::ostream& o, vcomponent* self) { + for (int i = 0; i < 40; i++) o << '_'; + + o << _YELLOW << std::endl + << "VComponet (Type := " << self->type << _RESET + << self->clines + << std::endl << "Components:" << std::endl + << self->components; + + return o; +} diff --git a/vcal.h b/vcal.h index 1c96c4c6..bb30e482 100644 --- a/vcal.h +++ b/vcal.h @@ -1,47 +1,20 @@ #ifndef VCAL_H #define VCAL_H -#include - -#include "strbuf.h" - -#define TYPE strbuf -#include "linked_list.h" -// #include "trie.h" -#undef TYPE - -#define T strbuf - #define V LLIST(strbuf) - #include "pair.h" - /* left := param_name | right := param_values */ - #define param_set PAIR(strbuf, LLIST(strbuf)) - #undef V -#undef T - -#define TYPE param_set -#include "linked_list.h" -#undef TYPE - -#define T strbuf - #define V LLIST(param_set) - #include "pair.h" - /* left := content | right := params */ - #define content_set PAIR(strbuf, LLIST(param_set)) - #undef V -#undef T - -#define TYPE content_set -#include "linked_list.h" -#undef TYPE - -#define T strbuf - #define V LLIST(content_set) - #include "pair.h" - /* left := content | right := params */ - #define content_line PAIR(strbuf, LLIST(content_set)) - #undef V -#undef T +#include +#include +#include +#include +#include +#include "trie.h" + + +typedef std::pair > param_set; +typedef std::pair > content_set; +typedef std::pair > content_line; + +#if 0 /* * Helper macros for accessing fields in * content_line, content_set, and param_set @@ -50,21 +23,36 @@ */ /* ptr -> ptr */ -#define CLINE_KEY(c) (&(c)->key) -#define CLINE_CUR_CSET(c) (&((c)->val.cur->value)) +#define CLINE_KEY(c) (&(c)->first) +#define CLINE_CUR_CSET(c) (&((c)->second.cur->value)) /* content_set */ -#define CLINE_CUR(c) ((c)->val.cur->value) +#define CLINE_CUR(c) ((c)->second.cur->value) /* strbuf */ -#define CLINE_CUR_VAL(c) (& CLINE_CUR(c)->key) +#define CLINE_CUR_VAL(c) (& CLINE_CUR(c)->first) -/* LLIST(param_set) */ -#define CLINE_CUR_PARAMS(c) (& CLINE_CUR(c)->val) + /* LLIST(param_set) */ +#define CLINE_CUR_PARAMS(c) (& CLINE_CUR(c)->second) + + /* strbuf */ +#define CLINE_CUR_PARAM_KEY(c) (CLINE_CUR_PARAMS(c)->cur->value->first) + /* strbuf */ +#define CLINE_CUR_PARAM_VAL(c) (CLINE_CUR_PARAMS(c)->cur->value->second.cur->value) +#endif + + struct vcomponent { + std::string filename; + std::string type; + vcomponent* parent = nullptr; + trie clines; + std::vector components; + + vcomponent(const std::string& type) : vcomponent(type, nullptr) { }; + vcomponent(const std::string& type, const std::string& filename) + : type(type) , filename(filename) { }; + + ~vcomponent(); -/* strbuf */ -#define CLINE_CUR_PARAM_KEY(c) (CLINE_CUR_PARAMS(c)->cur->value->key) -/* strbuf */ -#define CLINE_CUR_PARAM_VAL(c) (CLINE_CUR_PARAMS(c)->cur->value->val.cur->value) /* * Resolves a collision in some form of structure (probably a hash-map @@ -72,46 +60,16 @@ * to have the correct form, and returns it. Destroying new_ in the * process. */ -content_line* RESOLVE(content_line) - (content_line* dest, content_line* new_); + vcomponent* operator= (vcomponent* other); -#define TYPE content_line -#include "trie.h" -#undef TYPE + content_line& operator[] (char* key) { + return this->clines[key]; + } -typedef struct s_vcomponent vcomponent; - -#define TYPE vcomponent -#include "vector.h" -#undef TYPE - -struct s_vcomponent { - char* filename; - char* type; - vcomponent* parent; - TRIE(content_line) clines; - VECT(vcomponent) components; + void push_back(const vcomponent& child) + { this->components.push_back(child); } }; -#define FCHILD(v) GET(VECT(vcomponent))(&(v)->components, 0) - -INIT_F(vcomponent); -INIT_F(vcomponent, char* type); -INIT_F(vcomponent, char* type, char* filename); -FREE_F(vcomponent); - -content_line* get_property (vcomponent* ev, char* key); - -int add_content_line (vcomponent* ev, content_line* c); - -/* - * Appends ev to cal. Doesn't copy ev. So make sure that it wont go - * out of scope. - */ -int PUSH(vcomponent)(vcomponent*, vcomponent*); - -int DEEP_COPY(vcomponent)(vcomponent*, vcomponent*); - -FMT_F(vcomponent); +std::ostream& operator<<(std::ostream&, vcomponent*); #endif /* VCAL_H */ -- cgit v1.2.3