add initial parsing functions - ics2txt - convert icalendar .ics file to plain text
(HTM) git clone git://bitreich.org/ics2txt git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/ics2txt
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) Tags
(DIR) README
---
(DIR) commit 8248ba97aa609be30e0ecf481d93e59a9876afcd
(DIR) parent a7b4ceeaf4a57476c0952e0da2def5f92bdfdb9f
(HTM) Author: Josuah Demangeon <me@josuah.net>
Date: Sun, 28 Jun 2020 14:33:48 +0200
add initial parsing functions
Diffstat:
M ics2tsv.c | 7 ++++---
M src/ical.c | 93 +++++++++++++++++++++++++++----
M src/ical.h | 40 ++++++++++++++++++++++++++++----
M src/map.c | 3 ---
4 files changed, 122 insertions(+), 21 deletions(-)
---
(DIR) diff --git a/ics2tsv.c b/ics2tsv.c
@@ -1,5 +1,6 @@
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include "ical.h"
#include "log.h"
@@ -8,16 +9,16 @@
int
print_ical_to_tsv(FILE *fp)
{
- struct ical_contentline contentline;
+ struct ical_contentline cl;
char *line = NULL, *ln = NULL;
size_t sz = 0;
ssize_t r;
- ical_init_contentline(&contentline);
+ memset(&cl, 0, sizeof cl);
while ((r = ical_read_line(&line, &ln, &sz, fp)) > 0) {
debug("readling line \"%s\"", line);
- if (ical_parse_contentline(&contentline, line) < 0)
+ if (ical_parse_contentline(&cl, line) < 0)
die("parsing line \"%s\"", line);
}
free(line);
(DIR) diff --git a/src/ical.c b/src/ical.c
@@ -1,9 +1,11 @@
#include "ical.h"
+#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <strings.h> /* strcase* */
#include "util.h"
@@ -29,19 +31,21 @@ ical_read_line(char **line, char **ln, size_t *sz, FILE *fp)
} while (c == ' ');
ungetc(c, fp);
+ assert(!ferror(fp));
return 1;
}
int
-ical_parse_contentline(struct ical_contentline *contentline, char *line)
+ical_parse_contentline(struct ical_contentline *cl, char *line)
{
char *column, *equal, *param, *cp;
size_t sz;
+ int e = errno;
if ((column = strchr(line, ':')) == NULL)
return -1;
*column = '\0';
- if ((contentline->value = strdup(column + 1)) == NULL)
+ if ((cl->value = strdup(column + 1)) == NULL)
return -1;
if ((cp = strchr(line, ';')) != NULL)
@@ -50,27 +54,94 @@ ical_parse_contentline(struct ical_contentline *contentline, char *line)
if ((equal = strchr(param, '=')) == NULL)
return -1;
*equal = '\0';
- if (map_set(&contentline->param, param, equal + 1) < 0)
+ if (map_set(&cl->param, param, equal + 1) < 0)
return -1;
}
- sz = sizeof(contentline->name);
- if (strlcpy(contentline->name, line, sz) >= sz)
+ sz = sizeof cl->name;
+ if (strlcpy(cl->name, line, sz) >= sz)
return errno=EMSGSIZE, -1;
+ assert(errno == e);
return 0;
}
-void
-ical_init_contentline(struct ical_contentline *contentline)
+int
+ical_parse_tzid(struct ical_value *value, struct ical_contentline *cl)
+{
+ return 0;
+}
+
+int
+ical_parse_date(struct ical_value *value, struct ical_contentline *cl)
+{
+ return 0;
+}
+
+int
+ical_parse_attribute(struct ical_value *value, struct ical_contentline *cl)
+{
+ return 0;
+}
+
+int
+ical_begin_vnode(struct ical_vcalendar *vcal, char const *name)
{
- memset(contentline, 0, sizeof(*contentline));
+ if (strcasecmp(name, "VCALENDAR"))
+ return 0;
+ return -1;
}
+int
+ical_end_vnode(struct ical_vcalendar *vcal, char const *name)
+{
+ if (strcasecmp(name, "VCALENDAR"))
+ return 0;
+ return -1;
+}
+
+int
+ical_add_contentline(struct ical_vcalendar *vcal, struct ical_contentline *cl)
+{
+ 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;
+ return 0;
+}
+
+void
+ical_free_value(struct ical_value *value)
+{
+ ;
+}
void
-ical_free_contentline(struct ical_contentline *contentline)
+ical_free_contentline(struct ical_contentline *cl)
{
- map_free(&contentline->param);
- free(contentline->value);
+ map_free(&cl->param);
+ free(cl->value);
}
(DIR) diff --git a/src/ical.h b/src/ical.h
@@ -6,16 +6,48 @@
#include "map.h"
-struct ical_vevent {
- time_t beg, end;
- struct map map;
-};
+#define ICAL_NEST_MAX 4
+
+/* */
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;
+};
+
+/* 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 *current;
+};
+
+/* element part of an iCalendar document with eventual nested childs */
+
+struct ical_vnode {
+ char name[32];
+ time_t beg, end;
+ struct map properties; /* struct ical_value */
+ struct ical_vnode *child, *next;
+};
+
/** 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);
(DIR) diff --git a/src/map.c b/src/map.c
@@ -32,11 +32,8 @@ map_set(struct map *map, char *key, void *value)
size_t i, sz;
void *v;
- debug("%s: key=%s len=%zd", __func__, key, map->len);
-
for (i = 0; i < map->len; i++) {
int cmp = strcmp(key, map->entry[i].key);
- debug("cmp(%s,%s)=%d", key, map->entry[i].key, cmp);
if (cmp == 0) {
map->entry[i].value = value;