aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHugo Hörnquist <hugo@hornquist.se>2019-01-19 19:06:09 +0100
committerHugo Hörnquist <hugo@hornquist.se>2019-01-19 19:06:14 +0100
commitc42c2834d8c7b5d81465b9d9d127d8384151b9cb (patch)
tree53b1a8eb0368d5f91525604eea2c3173083c1955
parentCan now parse entire directory in one go. (diff)
downloadcalp-c42c2834d8c7b5d81465b9d9d127d8384151b9cb.tar.gz
calp-c42c2834d8c7b5d81465b9d9d127d8384151b9cb.tar.xz
[BROKEN] Work on adding hash tables.
-rw-r--r--hash.c15
-rw-r--r--hash.h30
-rw-r--r--hash_help.inc41
-rw-r--r--macro.h10
-rw-r--r--main.c67
-rw-r--r--parse.c197
-rw-r--r--parse.h41
-rw-r--r--vcal.c69
-rw-r--r--vcal.h43
9 files changed, 357 insertions, 156 deletions
diff --git a/hash.c b/hash.c
new file mode 100644
index 00000000..47775b59
--- /dev/null
+++ b/hash.c
@@ -0,0 +1,15 @@
+#include "hash.h"
+
+/*
+ * http://www.cse.yorku.ca/~oz/hash.html
+ * djb2 from above url.
+ */
+unsigned long hash(char* str) {
+ unsigned long hash = 5381;
+ int c;
+
+ while ( (c = *str++) )
+ hash = ((hash << 5) + hash) + c;
+
+ return hash;
+}
diff --git a/hash.h b/hash.h
new file mode 100644
index 00000000..2a095cfd
--- /dev/null
+++ b/hash.h
@@ -0,0 +1,30 @@
+#ifndef HASH_H
+#define HASH_H
+
+#include <string.h>
+
+#include "macro.h"
+
+unsigned long hash(char*);
+
+#define TABLE(T) TP(table_, T)
+#define HASH_PUT(T) TP(hash_put_, T)
+#define HASH_GET(T) TP(hash_get_, T)
+#define HASH_INIT(T) TP(hash_init_, T)
+
+#endif /* HASH_H */
+#ifdef TYPE
+
+typedef struct {
+ int size;
+ int item_count;
+ TYPE* values;
+} TABLE(TYPE);
+
+int HASH_PUT(TYPE) ( TABLE(TYPE)* table, TYPE* value );
+
+int HASH_INIT(TYPE) ( TABLE(TYPE)* table, int init_size );
+
+TYPE* HASH_GET(TYPE) ( TABLE(TYPE)* table, char* key );
+
+#endif /* HASH_H */
diff --git a/hash_help.inc b/hash_help.inc
new file mode 100644
index 00000000..19463be4
--- /dev/null
+++ b/hash_help.inc
@@ -0,0 +1,41 @@
+#ifndef TYPE
+#error "Set TYPE to something before including this header"
+#else
+
+int HASH_PUT(TYPE) ( TABLE(TYPE)* table, TYPE* value) {
+ // TODO genicify the hash function
+ unsigned long h = hash(value->key.mem) % table->size;
+ table->values[h] = *value;
+
+ /* TODO conflict resolution */
+
+ ++table->item_count;
+ return 0;
+}
+
+int HASH_INIT(TYPE) ( TABLE(TYPE)* table, int init_size ) {
+ /*
+ * TODO parts of table might not get properly initialized to 0
+ */
+ table->values = calloc(sizeof(table->values), init_size);
+ table->size = init_size;
+ table->item_count = 0;
+ return 0;
+}
+
+TYPE* HASH_GET(TYPE) ( TABLE(TYPE)* table, char* key ) {
+ unsigned long h = hash(key) % table->size;
+ TYPE* mem = (table->values + h);
+ if (mem == NULL) {
+ return 0;
+ } else if (strcmp(mem->key.mem, key) == 0) {
+ return mem;
+ } else {
+ /* TODO fix retrival on invalid key */
+ }
+ return 0;
+}
+
+#endif /* TYPE */
+
+// vim: ft=c
diff --git a/macro.h b/macro.h
new file mode 100644
index 00000000..c4b3fc9b
--- /dev/null
+++ b/macro.h
@@ -0,0 +1,10 @@
+#ifndef MACRO_H
+#define MACRO_H
+
+#define TP(a, b) a ## b
+
+#define NEW(T, N, ...) \
+ T* N = malloc(sizeof(*N)); \
+ TP(T, _init) (N, __VA_ARGS__);
+
+#endif /* MACRO_H */
diff --git a/main.c b/main.c
new file mode 100644
index 00000000..ba6eb0e9
--- /dev/null
+++ b/main.c
@@ -0,0 +1,67 @@
+#include <dirent.h>
+#include <errno.h>
+
+/*
+ * These three are only for some FD hacks.
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "parse.h"
+
+int main (int argc, char* argv[argc]) {
+ if (argc < 2) {
+ //puts("Please give a ics file as first argument");
+ puts("Please give vdir as first argument");
+ exit (1);
+ }
+ vcalendar cal;
+ init_vcalendar(&cal);
+
+ char* dname = argv[1];
+ DIR* dir = opendir(dname);
+ struct dirent* d;
+ int fcount = 0;
+ while ((d = readdir(dir)) != NULL) {
+
+
+ /* Check that it's a regular file */
+ if (d->d_type != DT_REG) continue;
+
+ /* Check that we have an ICS file */
+ char *s, *fname;
+ s = fname = d->d_name;
+ while (*(s++) != '.');
+ if (strcmp(s, "ics") != 0) continue;
+
+ /* We now assume that it's a good file, and start parsing it */
+
+ int fd = openat(dirfd(dir), fname, O_RDONLY);
+
+ FILE* f = fdopen(fd, "r");
+ if (f == NULL) {
+ fprintf(stderr, "Error opening file [%s], errno = %i\n",
+ fname, errno);
+ exit (1);
+ }
+
+ printf("%3i | %s\n", fcount++, fname);
+ /* 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. */
+ parse_file(f, &cal);
+ fclose(f);
+
+ }
+
+ 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, cal.events[i].summary.mem);
+ printf("%3lu. %s\n", i + 1, get_property(&cal.events[i], "SUMMARY")->val.mem);
+ }
+
+ free_vcalendar(&cal);
+}
diff --git a/parse.c b/parse.c
index af5a5471..cce311a6 100644
--- a/parse.c
+++ b/parse.c
@@ -1,4 +1,7 @@
-#define SAFE_STR
+#include "parse.h"
+
+#include "macro.h"
+
/*
* TODO currently not all pointers inside strings are reset correctly,
@@ -8,44 +11,8 @@
* along with the introduction of a MSG macro.
*/
-#include <stdio.h>
-#include <stdlib.h>
#include <errno.h>
#include <string.h>
-#include <dirent.h>
-
-/*
- * These three are only for some FD hacks.
- */
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-#include "strbuf.h"
-#include "vcal.h"
-
-/*
- * Max length of a line.
- * TODO update this to allow longer lines, in case someone doesn't
- * follow the standard.
- */
-#define SEGSIZE 75
-
-#define ERR(x, line) do { \
- fprintf(stderr, "ERR %i: %s (cal %i)\n", __LINE__, (x), (line)); \
-} while(0)
-
-#define LINE(nr, key, value) fprintf(stderr, "%i: [%s] := [%s]\n", nr, key, value);
-
-typedef enum {
- p_key, p_value
-} part_context;
-
-typedef enum {
- s_none, s_calendar, s_event
-} scope_context;
-
-int handle_kv(vcalendar* cal, vevent* ev, string* key, string* val, int line, scope_context* s_ctx);
int parse_file(FILE* f, vcalendar* cal) {
int segments = 1;
@@ -58,18 +25,17 @@ int parse_file(FILE* f, vcalendar* cal) {
int keylen = 100;
int vallen = 100;
- string key, val;
-
- init_string(&key, keylen);
- init_string(&val, vallen);
-
int line = 0;
- vevent ev;
+ // TODO this can apparently segfault...
+ NEW(vevent, ev, /**/ 100);
+
+ content_line cline;
+ init_content_line (&cline, keylen, vallen);
char c;
- // TODO this segfaults...
while ( (c = fgetc(f)) != EOF) {
+ // D E S (-48 '\320')
/*
* A carrige return means that the current line is at an
* end. The following character should always be \n.
@@ -84,35 +50,47 @@ int parse_file(FILE* f, vcalendar* cal) {
if (s[0] != '\n') { ERR("expected newline after CR", line); }
else if (s[1] == ' ' || s[1] == '\t') {
+ /*
+ * Folded line, increase size of key and continue.
+ */
+
// TODO check return value
// TODO segments is always incremented here, meaning
// that segment grows larger for every multi line
// encountered.
-#if 1
if (realloc_string(&str, ++segments * SEGSIZE) != 0) { /* TODO signal error */
ERR("Failed to realloc string", line);
exit (1);
}
-#endif
continue;
} else {
+ /*
+ * Actuall end of line, handle values.
+ */
if (ungetc(s[1], f) != s[1]) { /* TODO signal error */
exit (2);
}
/* At TRUE end of line */
+ /*
if (str.ptr + 1 > vallen) {
vallen = str.ptr + 1;
- realloc_string(&val, vallen);
+ // TODO this fails
+ realloc_string(&cline.val, vallen);
}
- copy_strbuf(&val, &str);
- strbuf_cap(&val);
+ */
+ copy_strbuf(&cline.val, &str);
+ strbuf_cap(&cline.val);
++line;
/* We just got a value */
// LINE(line, key.mem, val.mem);
- handle_kv(cal, &ev, &key, &val, line, &s_ctx);
+ if (strbuf_c(&cline.key, "LOCATION")) {
+ if (strbuf_c(&cline.val, "")) return 1;
+ LINE(line, cline.key.mem, cline.val.mem);
+ }
+ handle_kv(cal, ev, &cline, line, &s_ctx);
strbuf_soft_reset(&str);
p_ctx = p_key;
@@ -120,14 +98,14 @@ int parse_file(FILE* f, vcalendar* cal) {
}
} else if (p_ctx == p_key && c == ':') {
/*
- if (str.ptr + 1 > keylen) {
- keylen = str.ptr + 1;
- // TODO this might break everything
- realloc_string(&key, keylen);
+ if (str.ptr + 1 > keylen) {
+ keylen = str.ptr + 1;
+ // TODO this might break everything
+ realloc_string(&key, keylen);
}
*/
- copy_strbuf(&key, &str);
- *strbuf_end(&key) = 0;
+ copy_strbuf(&cline.key, &str);
+ strbuf_cap(&cline.key);
strbuf_soft_reset(&str);
p_ctx = p_value;
continue;
@@ -135,7 +113,9 @@ int parse_file(FILE* f, vcalendar* cal) {
strbuf_append(&str, c);
}
- if (errno != 0) {
+
+
+ if (! feof(f)) {
ERR("Error parsing", errno);
} else {
/*
@@ -145,122 +125,63 @@ int parse_file(FILE* f, vcalendar* cal) {
*/
if (str.ptr + 1 > vallen) {
vallen = str.ptr + 1;
- realloc_string(&val, vallen);
+ realloc_string(&cline.val, vallen);
}
- copy_strbuf(&val, &str);
- *strbuf_cur(&val) = 0;
+ copy_strbuf(&cline.val, &str);
+ *strbuf_cur(&cline.val) = 0;
}
- free_vevent(&ev);
free_string(&str);
- free_string(&key);
- free_string(&val);
+ content_line_free(&cline);
return 0;
}
-int main (int argc, char* argv[argc]) {
- if (argc < 2) {
- //puts("Please give a ics file as first argument");
- puts("Please give vdir as first argument");
- exit (1);
- }
- vcalendar cal;
- init_vcalendar(&cal);
-
- char* dname = argv[1];
- DIR* dir = opendir(dname);
- struct dirent* d;
- int fcount = 0;
- while ((d = readdir(dir)) != NULL) {
-
-
- /* Check that it's a regular file */
- if (d->d_type != DT_REG) continue;
-
- /* Check that we have an ICS file */
- char *s, *fname;
- s = fname = d->d_name;
- while (*(s++) != '.');
- if (strcmp(s, "ics") != 0) continue;
-
- /* We now assume that it's a good file, and start parsing it */
-
- int fd = openat(dirfd(dir), fname, O_RDONLY);
-
- FILE* f = fdopen(fd, "r");
- if (f == NULL) {
- fprintf(stderr, "Error opening file [%s], errno = %i\n",
- fname, errno);
- exit (1);
- }
-
- printf("%3i | %s\n", fcount++, fname);
- /* 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. */
- parse_file(f, &cal);
- fclose(f);
-
- }
-
- 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, cal.events[i].summary.mem);
- }
-
- free_vcalendar(&cal);
-}
-
-int handle_kv(vcalendar* cal, vevent* ev, string* key, string* val, int line, scope_context* s_ctx) {
+int handle_kv(
+ vcalendar* cal,
+ vevent* ev,
+ content_line* cline,
+ int line,
+ scope_context* s_ctx
+ ) {
switch (*s_ctx) {
case s_none:
- /* Both key and val is null here */
- if (! (strbuf_c(key, "BEGIN") && strbuf_c(val, "VCALENDAR"))) {
+ if (! (strbuf_c(&cline->key, "BEGIN") && strbuf_c(&cline->val, "VCALENDAR"))) {
ERR("Invalid start of calendar", line);
return 1;
}
*s_ctx = s_calendar;
break;
case s_calendar:
- if (strbuf_c(key, "BEGIN")) {
- if (strbuf_c(val, "VEVENT")) {
+ if (strbuf_c(&cline->key, "BEGIN")) {
+ if (strbuf_c(&cline->val, "VEVENT")) {
*s_ctx = s_event;
break;
} else {
ERR("Unsupported start", line);
return 2;
}
- } else if (strbuf_c(key, "END")) {
- if (strbuf_c(val, "VCALENDAR")) {
+ } else if (strbuf_c(&cline->key, "END")) {
+ if (strbuf_c(&cline->val, "VCALENDAR")) {
*s_ctx = s_none;
- /* GOTO cleanup */
break;
}
}
break;
case s_event:
- /* */ if (strbuf_c(key, "DTSTART")) {
- strbuf_init_copy(&ev->dtstart, val);
- } else if (strbuf_c(key, "DTEND")) {
- strbuf_init_copy(&ev->dtend, val);
- } else if (strbuf_c(key, "SUMMARY")) {
- strbuf_init_copy(&ev->summary, val);
- } else if (strbuf_c(key, "DESCRIPTION")) {
- strbuf_init_copy(&ev->description, val);
- } else if (strbuf_c(key, "END")) {
- if (strbuf_c(val, "VEVENT")) {
+ if (strbuf_c(&cline->key, "END")) {
+ if (strbuf_c(&cline->val, "VEVENT")) {
push_event(cal, ev);
*s_ctx = s_calendar;
} else {
ERR("Trying to end something, expected VEVENT", line);
return 3;
}
+ } else {
+ content_line* c = malloc(sizeof(*c));
+ content_line_copy(c, cline);
+ add_content_line (ev, c);
}
-
break;
}
-
return 0;
}
diff --git a/parse.h b/parse.h
new file mode 100644
index 00000000..cb6c2d1e
--- /dev/null
+++ b/parse.h
@@ -0,0 +1,41 @@
+#ifndef PARSE_H
+#define PARSE_H
+
+#define SAFE_STR
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "strbuf.h"
+#include "vcal.h"
+
+/*
+ * Max length of a line.
+ * TODO update this to allow longer lines, in case someone doesn't
+ * follow the standard.
+ */
+#define SEGSIZE 75
+
+#define ERR(x, line) fprintf(stderr, "ERR %i: %s (cal %i)\n", __LINE__, (x), (line));
+
+#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;
+
+typedef enum {
+ s_none, s_calendar, s_event
+} scope_context;
+
+int handle_kv(
+ vcalendar* cal,
+ vevent* ev,
+ content_line* cline,
+ int line,
+ scope_context* s_ctx
+ );
+
+int parse_file(FILE* f, vcalendar* cal);
+
+#endif /* PARSE_H */
diff --git a/vcal.c b/vcal.c
index a67e0246..f0be7f73 100644
--- a/vcal.c
+++ b/vcal.c
@@ -2,27 +2,69 @@
#include <string.h>
+#define TYPE content_line
+#include "hash_help.inc"
+#undef TYPE
+
+int vevent_init(vevent* ev, int init_size) {
+ HASH_INIT(content_line)(&ev->clines, init_size);
+ return 0;
+}
+
+content_line* get_property (vevent* ev, char* key) {
+ return HASH_GET(content_line)(&ev->clines, key);
+}
+
+int add_content_line (vevent* ev, content_line* c) {
+ return HASH_PUT(content_line)(&ev->clines, c);
+}
+
+int init_content_line (content_line* c, int keylen, int vallen) {
+ init_string(&c->key, keylen);
+ init_string(&c->val, vallen);
+ // TODO remaining fields
+ return 0;
+}
+
+int content_line_copy (content_line* dest, content_line* src) {
+ strbuf_init_copy(&dest->key, &src->key);
+ strbuf_init_copy(&dest->val, &src->val);
+
+ // TODO remaining fields
+
+ return 0;
+}
+
+int content_line_free (content_line* c) {
+ free_string(&c->key);
+ free_string(&c->val);
+
+ // TODO remaining fields
+
+ return 0;
+}
+
int copy_vevent(vevent* dest, vevent* src) {
- copy_strbuf(&dest->dtstart , &src->dtstart);
- copy_strbuf(&dest->dtend , &src->dtend);
- copy_strbuf(&dest->summary , &src->summary);
- copy_strbuf(&dest->description , &src->description);
+ // copy_strbuf(&dest->dtstart , &src->dtstart);
+ // copy_strbuf(&dest->dtend , &src->dtend);
+ // copy_strbuf(&dest->summary , &src->summary);
+ // copy_strbuf(&dest->description , &src->description);
return 0;
}
int vevent_init_copy(vevent* dest, vevent* src) {
- strbuf_init_copy(&dest->dtstart , &src->dtstart);
- strbuf_init_copy(&dest->dtend , &src->dtend);
- strbuf_init_copy(&dest->summary , &src->summary);
- strbuf_init_copy(&dest->description , &src->description);
+ // strbuf_init_copy(&dest->dtstart , &src->dtstart);
+ // strbuf_init_copy(&dest->dtend , &src->dtend);
+ // strbuf_init_copy(&dest->summary , &src->summary);
+ // strbuf_init_copy(&dest->description , &src->description);
return 0;
}
int free_vevent (vevent* ev) {
- free_string(&ev->dtstart);
- free_string(&ev->dtend);
- free_string(&ev->summary);
- free_string(&ev->description);
+ // free_string(&ev->dtstart);
+ // free_string(&ev->dtend);
+ // free_string(&ev->summary);
+ // free_string(&ev->description);
return 0;
}
@@ -34,7 +76,8 @@ int push_event(vcalendar* cal, vevent* ev) {
cal->events = realloc(cal->events, sizeof(*cal->events) * cal->alloc);
}
- vevent_init_copy(&cal->events[cal->n_events], ev);
+ // vevent_init_copy(&cal->events[cal->n_events], ev);
+ cal->events[cal->n_events] = *ev;
cal->n_events++;
return 0;
diff --git a/vcal.h b/vcal.h
index e5f4cf7f..8335cbc4 100644
--- a/vcal.h
+++ b/vcal.h
@@ -5,17 +5,50 @@
#include "strbuf.h"
+typedef struct {
+ string key;
+ string value;
+ string* vals;
+ int val_count;
+} parameter;
-/*
- * It's intentionall that there is no vevent_init. That since
- * the length of the strings isn't known.
- */
typedef struct {
+ string key;
+ string val;
+
+ string* aux_values;
+ int value_count;
+
+ parameter* params;
+ int param_count;
+} content_line;
+
+#define TYPE content_line
+#include "hash.h"
+#undef TYPE
+
+struct s_vevent {
+ /*
string dtstart;
string dtend;
string summary;
string description;
-} vevent;
+ */
+ TABLE(content_line) clines;
+};
+
+struct s_vevent;
+typedef struct s_vevent vevent;
+
+int vevent_init (vevent* ev, int init_size);
+
+int init_content_line (content_line* c, int keylen, int vallen);
+int content_line_free (content_line* c);
+int content_line_copy (content_line* dest, content_line* src);
+
+content_line* get_property (vevent* ev, char* key);
+
+int add_content_line (vevent* ev, content_line* c);
/*
* Deep copy from src -> dest