aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHugo Hörnquist <hugo@lysator.liu.se>2019-01-17 00:20:06 +0100
committerHugo Hörnquist <hugo@lysator.liu.se>2019-01-17 00:20:06 +0100
commit649ade4fb2c588355e89aa060b4d5954f77579e5 (patch)
tree337943cf7e23069bcbfac4a973dee0a59784a0ba
parentFix memory leak. (diff)
downloadcalp-649ade4fb2c588355e89aa060b4d5954f77579e5.tar.gz
calp-649ade4fb2c588355e89aa060b4d5954f77579e5.tar.xz
Further work.
-rw-r--r--Makefile20
-rw-r--r--parse.c220
-rw-r--r--strbuf.c104
-rw-r--r--strbuf.h65
-rw-r--r--vcal.c45
-rw-r--r--vcal.h29
6 files changed, 423 insertions, 60 deletions
diff --git a/Makefile b/Makefile
index ce41926b..439b496b 100644
--- a/Makefile
+++ b/Makefile
@@ -1,3 +1,5 @@
+.PHONY: all clean
+
CC := gcc
LEX := flex
@@ -5,14 +7,18 @@ CFLAGS = -Wall -ggdb
#LFLAGS =
#LDFLAGS =
-#%.yy.c : %.yy
-# $(LEX) -o $@ ${LFLAGS} $<
+C_FILES = $(wildcard *.c)
+O_FILES = $(C_FILES:.c=.o)
+H_FILES = $(wildcard *.h)
-%.o : %.c
- $(CC) -c -o $@ $^ ${CFLAGS}
+all: parse
-parse: parse.o
- $(CC) -o $@ $^ ${LDFLAGS}
+%.o : %.c $(H_FILES)
+ $(CC) -c -o $@ $< ${CFLAGS}
-test: test.yy.o
+parse: $(O_FILES)
$(CC) -o $@ $^ ${LDFLAGS}
+
+clean:
+ -rm parse
+ -rm *.o
diff --git a/parse.c b/parse.c
index ba2a5a07..317a9acf 100644
--- a/parse.c
+++ b/parse.c
@@ -1,15 +1,20 @@
+#define SAFE_STR
+
+/*
+ * TODO currently not all pointers inside strings are reset correctly,
+ * leading to old garbage data being read way to much.
+ *
+ * A better ERR macro would solve most problems,
+ * along with the introduction of a MSG macro.
+ */
+
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
-typedef enum {
- key, value
-} context;
-
-typedef struct {
- char *key, *value;
-} kvpair;
+#include "strbuf.h"
+#include "vcal.h"
/*
* Max length of a line.
@@ -18,28 +23,44 @@ typedef struct {
*/
#define SEGSIZE 75
-int ii = 0;
+#define ERR(x, line) do { \
+ fprintf(stderr, "ERR %i: %s (cal %i)\n", __LINE__, (x), (line)); \
+} while(0)
-#define MARK do { printf("%i -- %i\n", __LINE__, ii++); } while (0)
+typedef enum {
+ p_key, p_value
+} part_context;
-#define ERR(x) do { \
- fprintf(stderr, "ERR %i: %s", __LINE__, (x)); \
-} while(0)
+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 main (int argc, char* argv[argc]) {
- FILE* F = fopen(argv[1], "r");
+int parse_file(char* fname, vcalendar* cal) {
+ FILE* f = fopen(fname, "r");
int segments = 1;
- char* str = malloc(segments * SEGSIZE);
- int i = 0;
+ string str;
+ init_string (&str, segments * SEGSIZE);
- context ctx = key;
- kvpair kvs[100];
- int ki = 0;
+ part_context p_ctx = p_key;
+ scope_context s_ctx = s_none;
+
+ int keylen = 100;
+ int vallen = 100;
+
+ string key, val;
+
+ init_string(&key, keylen);
+ init_string(&val, vallen);
+
+ int line = 0;
+
+ vevent ev;
char c;
- while ( (c = fgetc(F)) != EOF) {
+ while ( (c = fgetc(f)) != EOF) {
/*
* A carrige return means that the current line is at an
* end. The following character should always be \n.
@@ -49,62 +70,155 @@ int main (int argc, char* argv[argc]) {
if (c == '\r') {
char s[2];
- s[0] = fgetc(F);
- s[1] = fgetc(F);
+ s[0] = fgetc(f);
+ s[1] = fgetc(f);
- if (s[0] != '\n') { ERR("expected newline after CR"); }
+ if (s[0] != '\n') { ERR("expected newline after CR", line); }
else if (s[1] == ' ' || s[1] == '\t') {
- MARK;
// TODO check return value
// TODO segments is always incremented here, meaning
// that segment grows larger for every multi line
// encountered.
- str = realloc(str, ++segments * SEGSIZE);
- if (str == NULL) { /* TODO signal error */
+#if 0
+ if (realloc_string(&str, ++segments * SEGSIZE) != 0) { /* TODO signal error */
+ ERR("Failed to realloc string", line);
exit (1);
}
+#endif
continue;
} else {
- MARK;
- if (ungetc(s[1], F) != s[1]) { /* TODO signal error */
+ if (ungetc(s[1], f) != s[1]) { /* TODO signal error */
exit (2);
}
/* At TRUE end of line */
- kvs[ki].value = malloc(i + 1);
- memcpy(kvs[ki].value, str, i);
- kvs[ki].value[i] = 0;
- ki++;
- i = 0;
- ctx = key;
+ if (str.ptr + 1 > vallen) {
+ vallen = str.ptr + 1;
+ realloc_string(&val, vallen);
+ }
+ copy_strbuf(&val, &str);
+ *strbuf_cur(&val) = 0;
+
+ ++line;
+
+ /* We just got a value */
+ /* TODO for some reason both key and val is empty here */
+ handle_kv(cal, &ev, &key, &val, line, &s_ctx);
+ strbuf_soft_reset(&str);
+ p_ctx = p_key;
+
continue;
}
- } else if (ctx == key && c == ':') {
- kvs[ki].key = malloc(i + 1);
- memcpy(kvs[ki].key, str, i);
- kvs[ki].key[i] = 0;
- printf("key := %s\n", kvs[ki].key);
- i = 0;
- ctx = value;
+ } 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);
+ }
+ */
+ copy_strbuf(&key, &str);
+ *strbuf_end(&key) = 0;
+ strbuf_soft_reset(&str);
+ p_ctx = p_value;
continue;
}
- str[i] = c;
- ++i;
+ strbuf_append(&str, c);
}
if (errno != 0) {
- printf("Error parsing, errno = %i\n", errno);
+ ERR("Error parsing", -1);
+ } else {
+ /*
+ * Close last pair if the file is lacking trailing whitespace.
+ * A file with trailing whitespace would however fail.
+ * TODO check the spec and adjust accordingly
+ */
+ if (str.ptr + 1 > vallen) {
+ vallen = str.ptr + 1;
+ realloc_string(&val, vallen);
+ }
+ copy_strbuf(&val, &str);
+ *strbuf_cur(&val) = 0;
}
- puts("File parsed");
- free(str);
-
+ // TODO this segfaults
/*
- * Just print and free all collected data
- */
- for (int i = 0; i < ki; i++) {
- printf("[%s] := [%s]\n", kvs[i].key, kvs[i].value);
- free(kvs[i].key);
- free(kvs[i].value);
+ free_vevent(&ev);
+ free_string(&str);
+ free_string(&key);
+ free_string(&val);
+ */
+
+ // fclose(f);
+
+ return 0;
+}
+
+int main (int argc, char* argv[argc]) {
+ if (argc < 2) {
+ puts("Please give a ics file as first argument");
+ exit (1);
+ }
+ vcalendar cal;
+ init_vcalendar(&cal);
+ parse_file(argv[1], &cal);
+
+ printf("Parsed calendar file containing [%lu] events\n\n", cal.n_events);
+ for (size_t i = 0; i < cal.n_events; i++) {
+ printf("%lu: %s\n", i, 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) {
+ switch (*s_ctx) {
+ case s_none:
+ /* Both key and val is null here */
+ if (! (strbuf_c(key, "BEGIN") && strbuf_c(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")) {
+ *s_ctx = s_event;
+ break;
+ } else {
+ ERR("Unsupported start", line);
+ return 2;
+ }
+ } else if (strbuf_c(key, "END")) {
+ if (strbuf_c(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")) {
+ push_event(cal, ev);
+ *s_ctx = s_calendar;
+ } else {
+ ERR("Trying to end something, expected VEVENT", line);
+ return 3;
+ }
+ }
+
+ break;
}
+ return 0;
}
diff --git a/strbuf.c b/strbuf.c
new file mode 100644
index 00000000..2e25cf71
--- /dev/null
+++ b/strbuf.c
@@ -0,0 +1,104 @@
+#include "strbuf.h"
+
+#include <string.h>
+
+int init_string(string* str, size_t len) {
+ str->mem = malloc(len);
+ str->alloc = len;
+ str->ptr = 0;
+ str->len = 0;
+ return 0;
+}
+
+int realloc_string(string* str, size_t len) {
+#ifdef SAFE_STR
+ if (str->mem == NULL || str->alloc == 0) {
+ ERR("String memory not initialized");
+ return 1;
+ }
+#endif
+ str->mem = realloc(str->mem, len);
+ str->alloc = len;
+ return 0;
+}
+
+int free_string(string* str) {
+#ifdef SAFE_STR
+ if (str->alloc == 0) {
+ ERR("String not allocated");
+ return 1;
+ }
+#endif
+ free (str->mem);
+ str->alloc = 0;
+ return 0;
+}
+
+int strbuf_append(string* s, char c) {
+ s->mem[s->len] = c;
+ s->ptr = ++s->len;
+ return 0;
+}
+
+int copy_strbuf(string* dest, string* src) {
+#ifdef SAFE_STR
+ if (dest->alloc < src->len) {
+ ERR("Not enough memmory allocated");
+ return 1;
+ }
+#endif
+ dest->len = src->len;
+ memcpy(dest->mem, src->mem, src->len);
+ return 0;
+}
+
+int strbuf_cmp(string* a, string* b) {
+ return strcmp(a->mem, b->mem);
+}
+
+int strbuf_c(string* a, char* b) {
+ return strcmp(a->mem, b) == 0;
+}
+
+char* charat(string* s, int idx) {
+#ifdef SAFE_STR
+ if (idx > s->len) {
+ ERR("Index out of bounds");
+ return -1;
+ }
+#endif
+ return &s->mem[idx];
+}
+
+char* strbuf_cur(string* s) {
+ return &s->mem[s->ptr];
+}
+
+int strbuf_reset(string* s)
+{
+ s->ptr = 0;
+ return 0;
+}
+
+int strbuf_init_copy(string* dest, string* src) {
+#ifdef SAFE_STR
+ if (dest->alloc != 0) {
+ ERR("Dest already allocated", -1);
+ return 1;
+ }
+#endif
+
+ init_string(dest, src->alloc);
+ copy_strbuf(dest, src);
+
+ return 0;
+}
+
+char* strbuf_end(string* s) {
+ return &s->mem[s->len];
+}
+
+int strbuf_soft_reset(string* s) {
+ s->ptr = s->len = 0;
+ return 0;
+}
diff --git a/strbuf.h b/strbuf.h
new file mode 100644
index 00000000..ef6ea61f
--- /dev/null
+++ b/strbuf.h
@@ -0,0 +1,65 @@
+#ifndef STRBUF_H
+#define STRBUF_H
+
+#include <stdlib.h>
+
+typedef struct {
+ char* mem;
+ size_t ptr;
+ size_t alloc;
+ size_t len;
+} string;
+
+/*
+ * TODO rename everything to be on the form
+ * strbuf_.*
+ *
+ * TODO Check memmory allocation for last +1 byte for null.
+ */
+
+/*
+ * Constructor
+ */
+int init_string(string* str, size_t len);
+
+/*
+ * Like realloc, but for strbuf
+ */
+int realloc_string(string* str, size_t len);
+
+/*
+ * Free's contents of str, but keeps str.
+ */
+int free_string(string* str);
+
+/*
+ * Copy contents from src to dest.
+ * Assumes that dest is already initialized.
+ *
+ * also see: strbuf_alloc_copy
+ */
+int copy_strbuf(string* dest, string* src);
+int strbuf_cmp(string* a, string* b);
+int strbuf_c(string* a, char* b);
+int strbuf_append(string* a, char c);
+int strbuf_reset(string* s);
+char* charat(string* s, int idx);
+char* strbuf_cur(string* s);
+
+/*
+ * Sets the length and seek ptr to 0, but doesn't touch the memmory.
+ */
+int strbuf_soft_reset(string* s);
+
+/*
+ * Returns the character after the last, so where null hopefully is.
+ */
+char* strbuf_end(string* s);
+
+/*
+ * Copies contents from src to dest, also allocating dest in the
+ * process. dest should not be initialized before this call.
+ */
+int strbuf_init_copy(string* dest, string* src);
+
+#endif /* STRBUF_H */
diff --git a/vcal.c b/vcal.c
new file mode 100644
index 00000000..a40080fe
--- /dev/null
+++ b/vcal.c
@@ -0,0 +1,45 @@
+#include "vcal.h"
+
+#include <string.h>
+
+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);
+ return 0;
+}
+
+int free_vevent (vevent* ev) {
+ free_string(&ev->dtstart);
+ free_string(&ev->dtend);
+ free_string(&ev->summary);
+ free_string(&ev->description);
+ return 0;
+}
+
+int push_event(vcalendar* cal, vevent* ev) {
+ if (cal->n_events + 1> cal->alloc) {
+ cal->alloc <<= 1;
+ }
+ cal->events = realloc(cal->events, cal->alloc);
+ copy_vevent(&cal->events[cal->n_events], ev);
+ cal->n_events++;
+ return 0;
+}
+
+int init_vcalendar(vcalendar* cal) {
+ cal->events = malloc(sizeof(*cal->events));
+ cal->alloc = 1;
+ cal->n_events = 0;
+ return 0;
+}
+
+int free_vcalendar (vcalendar* cal) {
+ for (size_t i = 0; i < cal->n_events; i++) {
+ vevent* v = & cal->events[i];
+ free_vevent(v);
+ free(v);
+ }
+ return 0;
+}
diff --git a/vcal.h b/vcal.h
new file mode 100644
index 00000000..06ec61f9
--- /dev/null
+++ b/vcal.h
@@ -0,0 +1,29 @@
+#ifndef VCAL_H
+#define VCAL_H
+
+#include <stdlib.h>
+
+#include "strbuf.h"
+
+typedef struct {
+ string dtstart;
+ string dtend;
+ string summary;
+ string description;
+} vevent;
+
+int copy_vevent(vevent* dest, vevent* src);
+int free_vevent(vevent* ev);
+
+typedef struct {
+ size_t n_events;
+ size_t alloc;
+ vevent* events;
+} vcalendar;
+
+int init_vcalendar(vcalendar* cal);
+int free_vcalendar(vcalendar* cal);
+
+int push_event(vcalendar* cal, vevent* ev);
+
+#endif /* VCAL_H */