Introduction
Introduction Statistics Contact Development Disclaimer Help
add a tool to print the tree of it - ics2txt - convert icalendar .ics file to p…
git clone git://bitreich.org/ics2txt git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws…
Log
Files
Refs
Tags
README
---
commit d4d55c6876bf51dd555a0dbfae0316343d44997e
parent 8248ba97aa609be30e0ecf481d93e59a9876afcd
Author: Josuah Demangeon <[email protected]>
Date: Sun, 28 Jun 2020 18:44:32 +0200
add a tool to print the tree of it
Diffstat:
M .gitignore | 1 +
M Makefile | 2 +-
A ics2tree.c | 100 +++++++++++++++++++++++++++++…
M ics2tsv.c | 25 +++++++++----------------
M src/ical.c | 249 +++++++++++++++++++++++------…
M src/ical.h | 65 ++++++++++++++++++-----------…
M src/map.c | 16 +++++++++-------
M src/map.h | 4 ++--
8 files changed, 348 insertions(+), 114 deletions(-)
---
diff --git a/.gitignore b/.gitignore
@@ -1,2 +1,3 @@
*.o
ics2tsv
+ics2tree
diff --git a/Makefile b/Makefile
@@ -11,7 +11,7 @@ MANPREFIX = ${PREFIX}/man
SRC = src/ical.c src/map.c src/util.c src/log.c
HDR = src/ical.h src/map.h src/util.h src/log.h
OBJ = ${SRC:.c=.o}
-BIN = ics2tsv
+BIN = ics2tsv ics2tree
all: ${BIN}
diff --git a/ics2tree.c b/ics2tree.c
@@ -0,0 +1,100 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ical.h"
+#include "log.h"
+#include "util.h"
+
+void
+print_ical_tree_param(struct map_entry *entry, int level)
+{
+ if (entry == NULL)
+ return;
+ for (int i = 0; i < level; i++)
+ printf(": ");
+ fprintf(stdout, "param %s=%s\n", entry->key, (char *)entry->value);
+}
+
+void
+print_ical_tree_value(struct ical_value *value, int level)
+{
+ if (value == NULL)
+ return;
+ for (int i = 0; i < level; i++)
+ printf(": ");
+ fprintf(stdout, "value %s:%s\n", value->name, value->value);
+ for (size_t i = 0; i < value->param.len; i++)
+ print_ical_tree_param(value->param.entry + i, level + 1);
+ print_ical_tree_value(value->next, level);
+}
+
+void
+print_ical_tree_vnode(struct ical_vnode *node, int level)
+{
+ if (node == NULL)
+ return;
+ for (int i = 0; i < level; i++)
+ printf(": ");
+ fprintf(stdout, "node %p %s child=%p next=%p\n", node, node->name, nod…
+ for (size_t i = 0; i < node->values.len; i++)
+ print_ical_tree_value(node->values.entry[i].value, level + 1);
+ print_ical_tree_vnode(node->child, level + 1);
+ print_ical_tree_vnode(node->next, level);
+}
+
+int
+print_ical_tree(FILE *fp)
+{
+ struct ical_vcalendar vcal;
+ int e;
+
+ if ((e = ical_read_vcalendar(&vcal, fp)) < 0)
+ die("reading ical file: %s", ical_strerror(e));
+
+ print_ical_tree_vnode(vcal.root, 0);
+ fprintf(stdout, ".\n");
+ fflush(stdout);
+
+ ical_free_vcalendar(&vcal);
+ return 0;
+}
+
+void
+print_header(void)
+{
+ char *fields[] = { "", NULL };
+
+ printf("%s\t%s", "beg", "end");
+
+ for (char **f = fields; *f != NULL; f++) {
+ fprintf(stdout, "\t%s", *f);
+ }
+ fprintf(stdout, "\n");
+}
+
+int
+main(int argc, char **argv)
+{
+ print_header();
+
+ log_arg0 = *argv++;
+
+ if (*argv == NULL) {
+ if (print_ical_tree(stdin) < 0)
+ die("converting stdin");
+ }
+
+ for (; *argv != NULL; argv++, argc--) {
+ FILE *fp;
+
+ info("converting \"%s\"", *argv);
+ if ((fp = fopen(*argv, "r")) == NULL)
+ die("opening %s", *argv);
+ if (print_ical_tree(fp) < 0)
+ die("converting %s", *argv);
+ fclose(fp);
+ }
+
+ return 0;
+}
diff --git a/ics2tsv.c b/ics2tsv.c
@@ -7,23 +7,16 @@
#include "util.h"
int
-print_ical_to_tsv(FILE *fp)
+print_ical_tsv(FILE *fp)
{
- struct ical_contentline cl;
- char *line = NULL, *ln = NULL;
- size_t sz = 0;
- ssize_t r;
+ struct ical_vcalendar vcal;
+ int e;
- memset(&cl, 0, sizeof cl);
+ if ((e = ical_read_vcalendar(&vcal, fp)) < 0)
+ die("reading ical file: %s", ical_strerror(e));
- while ((r = ical_read_line(&line, &ln, &sz, fp)) > 0) {
- debug("readling line \"%s\"", line);
- if (ical_parse_contentline(&cl, line) < 0)
- die("parsing line \"%s\"", line);
- }
- free(line);
- free(ln);
- return r;
+ ical_free_vcalendar(&vcal);
+ return 0;
}
void
@@ -47,7 +40,7 @@ main(int argc, char **argv)
log_arg0 = *argv++;
if (*argv == NULL) {
- if (print_ical_to_tsv(stdin) < 0)
+ if (print_ical_tsv(stdin) < 0)
die("converting stdin");
}
@@ -57,7 +50,7 @@ main(int argc, char **argv)
info("converting \"%s\"", *argv);
if ((fp = fopen(*argv, "r")) == NULL)
die("opening %s", *argv);
- if (print_ical_to_tsv(fp) < 0)
+ if (print_ical_tsv(fp) < 0)
die("converting %s", *argv);
fclose(fp);
}
diff --git a/src/ical.c b/src/ical.c
@@ -9,8 +9,10 @@
#include "util.h"
+enum ical_err ical_errno;
+
int
-ical_read_line(char **line, char **ln, size_t *sz, FILE *fp)
+ical_getline(char **line, char **ln, size_t *sz, FILE *fp)
{
int c;
void *v;
@@ -35,113 +37,240 @@ ical_read_line(char **line, char **ln, size_t *sz, FILE *…
return 1;
}
+char *
+ical_strerror(int i)
+{
+ enum ical_err err = (i > 0) ? i : -i;
+
+ switch (err) {
+ case ICAL_ERR_OK:
+ return "no error";
+ case ICAL_ERR_SYSTEM:
+ return "system error";
+ case ICAL_ERR_END_MISMATCH:
+ return "END: does not match its corresponding BEGIN:";
+ case ICAL_ERR_MISSING_BEGIN:
+ return "unexpected content line before any BEGIN:";
+ case ICAL_ERR_MIN_NESTED:
+ return "too many END: for the number of BEGIN:";
+ case ICAL_ERR_MAX_NESTED:
+ return "maximum nesting level reached";
+ case ICAL_ERR_LENGTH:
+ assert(!"used internally, should not happen");
+ }
+ assert(!"unknown error code");
+ return "not a valid ical error code";
+}
+
+struct ical_value *
+ical_new_value(char const *line)
+{
+ struct ical_value *new;
+ size_t len;
+
+ len = strlen(line);
+ if ((new = calloc(1, sizeof *new + len + 1)) == NULL)
+ return NULL;
+ memcpy(new->buf, line, len + 1);
+ return new;
+}
+
+void
+ical_free_value(struct ical_value *value)
+{
+ debug("free value %p (%s:%s)", value, value->name, value->value);
+ map_free(&value->param, free);
+ free(value);
+}
+
int
-ical_parse_contentline(struct ical_contentline *cl, char *line)
+ical_parse_value(struct ical_value *value)
{
char *column, *equal, *param, *cp;
- size_t sz;
int e = errno;
- if ((column = strchr(line, ':')) == NULL)
+ value->name = value->buf;
+
+ if ((column = strchr(value->buf, ':')) == NULL)
return -1;
*column = '\0';
- if ((cl->value = strdup(column + 1)) == NULL)
- return -1;
+ value->value = column + 1;
- if ((cp = strchr(line, ';')) != NULL)
- cp++;
+ if ((cp = strchr(value->buf, ';')) != NULL)
+ *cp++ = '\0';
while ((param = strsep(&cp, ";")) != NULL) {
if ((equal = strchr(param, '=')) == NULL)
return -1;
*equal = '\0';
- if (map_set(&cl->param, param, equal + 1) < 0)
+ if (map_set(&value->param, param, equal + 1) < 0)
return -1;
}
- sz = sizeof cl->name;
- if (strlcpy(cl->name, line, sz) >= sz)
- return errno=EMSGSIZE, -1;
-
assert(errno == e);
return 0;
}
-int
-ical_parse_tzid(struct ical_value *value, struct ical_contentline *cl)
+struct ical_vnode *
+ical_new_vnode(char const *name)
{
- return 0;
+ struct ical_vnode *new;
+ size_t sz;
+
+ if ((new = calloc(1, sizeof *new)) == NULL)
+ return NULL;
+ sz = sizeof new->name;
+ if (strlcpy(new->name, name, sz) >= sz) {
+ errno = EMSGSIZE;
+ goto err;
+ }
+ return new;
+err:
+ ical_free_vnode(new);
+ return NULL;
}
-int
-ical_parse_date(struct ical_value *value, struct ical_contentline *cl)
+static void
+ical_free_vnode_value(void *v)
{
- return 0;
+ ical_free_value(v);
+}
+
+void
+ical_free_vnode(struct ical_vnode *node)
+{
+ if (node == NULL)
+ return;
+ debug("free vnode %p %s", node, node->name);
+ map_free(&node->values, ical_free_vnode_value);
+ ical_free_vnode(node->child);
+ ical_free_vnode(node->next);
+ free(node);
}
int
-ical_parse_attribute(struct ical_value *value, struct ical_contentline *cl)
+ical_push_nested(struct ical_vcalendar *vcal, struct ical_vnode *new)
{
+ struct ical_vnode **node;
+
+ node = vcal->nested;
+ for (int i = 0; *node != NULL; node++, i++) {
+ if (i >= ICAL_NESTED_MAX)
+ return -ICAL_ERR_MAX_NESTED;
+ }
+ node[0] = new;
+ node[1] = NULL;
return 0;
}
+struct ical_vnode *
+ical_pop_nested(struct ical_vcalendar *vcal)
+{
+ struct ical_vnode **node, **prev = vcal->nested, *old;
+
+ for (prev = node = vcal->nested; *node != NULL; node++) {
+ vcal->current = *prev;
+ prev = node;
+ old = *node;
+ }
+ *prev = NULL;
+ if (vcal->nested[0] == NULL)
+ vcal->current = NULL;
+ return old;
+}
+
int
ical_begin_vnode(struct ical_vcalendar *vcal, char const *name)
{
- if (strcasecmp(name, "VCALENDAR"))
- return 0;
- return -1;
+ struct ical_vnode *new;
+ int e;
+
+ if ((new = ical_new_vnode(name)) == NULL)
+ return -ICAL_ERR_SYSTEM;
+ if ((e = ical_push_nested(vcal, new)) < 0)
+ goto err;
+ if (vcal->root == NULL) {
+ vcal->root = new;
+ vcal->current = new;
+ } else {
+ new->next = vcal->current->child;
+ vcal->current->child = new;
+ vcal->current = new;
+ }
+ return 0;
+err:
+ ical_free_vnode(new);
+ return e;
}
int
ical_end_vnode(struct ical_vcalendar *vcal, char const *name)
{
- if (strcasecmp(name, "VCALENDAR"))
- return 0;
- return -1;
+ struct ical_vnode *old;
+
+ if ((old = ical_pop_nested(vcal)) == NULL)
+ return -ICAL_ERR_MIN_NESTED;
+ if (strcasecmp(name, old->name) != 0)
+ return -ICAL_ERR_END_MISMATCH;
+ return 0;
}
int
-ical_add_contentline(struct ical_vcalendar *vcal, struct ical_contentline *cl)
+ical_push_value(struct ical_vcalendar *vcal, struct ical_value *new)
{
- struct ical_value value_buf, *value = &value_buf;
- int i;
- struct {
- char *name;
- enum ical_value_type type;
- int (*fn)(struct ical_value *, struct ical_contentline *);
- } map[] = {
- { "DTSTART", ICAL_VALUE_TIME, ical_parse_date },
- { "DTEND", ICAL_VALUE_TIME, ical_parse_date },
- { "TZID", ICAL_VALUE_TIME, ical_parse_tzid },
- { NULL, ICAL_VALUE_ATTRIBUTE, ical_parse_attribute },
- };
-
- if (strcasecmp(cl->name, "BEGIN") == 0)
- return ical_begin_vnode(vcal, cl->value);
-
- if (strcasecmp(cl->name, "END") == 0)
- return ical_end_vnode(vcal, cl->value);
-
- memset(value, 0, sizeof *value);
-
- for (i = 0; map[i].name == NULL; i++)
- if (strcasecmp(cl->name, map[i].name) == 0)
- break;
- value->type = map[i].type;
- if (map[i].fn(value, cl) < 0)
- return -1;
+ if (strcasecmp(new->name, "BEGIN") == 0) {
+ int e = ical_begin_vnode(vcal, new->value);
+ ical_free_value(new);
+ return e;
+ }
+ if (strcasecmp(new->name, "END") == 0) {
+ int e = ical_end_vnode(vcal, new->value);
+ ical_free_value(new);
+ return e;
+ }
+
+ if (vcal->current == NULL)
+ return -ICAL_ERR_MISSING_BEGIN;
+
+ debug("new %p %s:%s", new, new->name, new->value);
+ new->next = map_get(&vcal->current->values, new->name);
+ if (map_set(&vcal->current->values, new->name, new) < 0)
+ return -ICAL_ERR_SYSTEM;
+
return 0;
}
-void
-ical_free_value(struct ical_value *value)
+int
+ical_read_vcalendar(struct ical_vcalendar *vcal, FILE *fp)
{
- ;
+ char *line = NULL, *ln = NULL;
+ size_t sz = 0;
+ ssize_t r;
+ int e;
+
+ memset(vcal, 0, sizeof *vcal);
+
+ while ((r = ical_getline(&line, &ln, &sz, fp)) > 0) {
+ struct ical_value *new;
+
+ if ((new = ical_new_value(line)) == NULL) {
+ e = -ICAL_ERR_SYSTEM;
+ goto err;
+ }
+ if ((e = ical_parse_value(new)) < 0)
+ goto err;
+ if ((e = ical_push_value(vcal, new)) < 0)
+ goto err;
+ }
+ e = (r == 0) ? 0 : -ICAL_ERR_SYSTEM;
+err:
+ free(line);
+ free(ln);
+ return e;
}
void
-ical_free_contentline(struct ical_contentline *cl)
+ical_free_vcalendar(struct ical_vcalendar *vcal)
{
- map_free(&cl->param);
- free(cl->value);
+ debug("free vcalendar");
+ ical_free_vnode(vcal->root);
}
diff --git a/src/ical.h b/src/ical.h
@@ -6,36 +6,25 @@
#include "map.h"
-#define ICAL_NEST_MAX 4
+#define ICAL_NESTED_MAX 4
-/* */
+enum ical_err {
+ ICAL_ERR_OK,
+ ICAL_ERR_SYSTEM,
+ ICAL_ERR_END_MISMATCH,
+ ICAL_ERR_MISSING_BEGIN,
+ ICAL_ERR_MIN_NESTED,
+ ICAL_ERR_MAX_NESTED,
-struct ical_contentline {
- char name[32], *value;
- struct map param;
-};
-
-/* single value for an iCalendar element attribute */
-
-enum ical_value_type {
- ICAL_VALUE_TIME, ICAL_VALUE_ATTRIBUTE,
-} type;
-
-union ical_value_union {
- time_t *time;
- char *str;
-};
-
-struct ical_value {
- enum ical_value_type type;
- union ical_value_union value;
+ ICAL_ERR_LENGTH,
};
/* global propoerties for an iCalendar document as well as parsing state */
struct ical_vcalendar {
time_t tzid;
- char *stack[ICAL_NEST_MAX + 1];
+ struct ical_vnode *root;
+ struct ical_vnode *nested[ICAL_NESTED_MAX + 1];
struct ical_vnode *current;
};
@@ -44,14 +33,34 @@ struct ical_vcalendar {
struct ical_vnode {
char name[32];
time_t beg, end;
- struct map properties; /* struct ical_value */
- struct ical_vnode *child, *next;
+ struct map values; /*(struct ical_value *)*/
+ struct ical_vnode *child;
+ struct ical_vnode *next;
+};
+
+/* one line whith the whole content unfolded */
+
+struct ical_value {
+ char *name, *value;
+ struct map param;
+ struct ical_value *next;
+ char buf[];
};
/** src/ical.c **/
-int ical_read_line(char **line, char **ln, size_t *sz, FILE *fp);
-int ical_parse_contentline(struct ical_contentline *contentline, char *line);
-void ical_init_contentline(struct ical_contentline *contentline);
-void ical_free_contentline(struct ical_contentline *contentline);
+int ical_getline(char **line, char **ln, size_t *sz, FILE *fp);
+char * ical_strerror(int i);
+struct ical_value * ical_new_value(char const *line);
+void ical_free_value(struct ical_value *value);
+int ical_parse_value(struct ical_value *value);
+struct ical_vnode * ical_new_vnode(char const *name);
+void ical_free_vnode(struct ical_vnode *node);
+int ical_push_nested(struct ical_vcalendar *vcal, struct ical_vnode *new);
+struct ical_vnode * ical_pop_nested(struct ical_vcalendar *vcal);
+int ical_begin_vnode(struct ical_vcalendar *vcal, char const *name);
+int ical_end_vnode(struct ical_vcalendar *vcal, char const *name);
+int ical_push_value(struct ical_vcalendar *vcal, struct ical_value *new);
+void ical_free_vcalendar(struct ical_vcalendar *vcal);
+int ical_read_vcalendar(struct ical_vcalendar *vcal, FILE *fp);
#endif
diff --git a/src/map.c b/src/map.c
@@ -54,8 +54,7 @@ map_set(struct map *map, char *key, void *value)
for (; e >= insert; e--)
e[1].key = e[0].key;
- if ((insert->key = strdup(key)) == NULL)
- return -1;
+ insert->key = key;
insert->value = value;
return 0;
@@ -90,16 +89,19 @@ map_init(struct map *map)
}
void
-map_free_values(struct map *map)
+map_free_keys(struct map *map)
{
for (size_t i = 0; i < map->len; i++)
- free(map->entry[map->len - 1].value);
+ free(map->entry[i].key);
}
void
-map_free(struct map *map)
+map_free(struct map *map, void (*fn)(void *))
{
- for (size_t i = 0; i < map->len; i++)
- free(map->entry[map->len - 1].key);
+ if (fn != NULL) {
+ for (size_t i = 0; i < map->len; i++)
+ fn(map->entry[i].value);
+ }
free(map->entry);
+ map->len = 0;
}
diff --git a/src/map.h b/src/map.h
@@ -18,7 +18,7 @@ void * map_get(struct map *map, char *key);
int map_set(struct map *map, char *key, void *value);
int map_del(struct map *map, char *key);
void map_init(struct map *map);
-void map_free_values(struct map *map);
-void map_free(struct map *map);
+void map_free_keys(struct map *map);
+void map_free(struct map *map, void (*fn)(void *));
#endif
You are viewing proxied material from bitreich.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.