Introduction
Introduction Statistics Contact Development Disclaimer Help
tical.c - ics2txt - convert icalendar .ics file to plain text
git clone git://bitreich.org/ics2txt git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws…
Log
Files
Refs
Tags
README
---
tical.c (5753B)
---
1 #include "ical.h"
2
3 #include <assert.h>
4 #include <errno.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <strings.h> /* strcase* */
9
10 #include "util.h"
11
12 enum ical_err ical_errno;
13
14 int
15 ical_getline(char **line, char **ln, size_t *sz, FILE *fp)
16 {
17 int c;
18 void *v;
19
20 if ((v = realloc(*line, 1)) == NULL)
21 return -ICAL_ERR_SYSTEM;
22 *line = v;
23 (*line)[0] = '\0';
24
25 do { top:
26 if (getline(ln, sz, fp) <= 0)
27 return ferror(fp) ? -ICAL_ERR_SYSTEM : 0;
28 strchomp(*ln);
29 if (**ln == '\0')
30 goto top;
31 if (strappend(line, *ln) < 0)
32 return -ICAL_ERR_SYSTEM;
33 if ((c = fgetc(fp)) == EOF)
34 return ferror(fp) ? -ICAL_ERR_SYSTEM : 1;
35 } while (c == ' ');
36
37 ungetc(c, fp);
38 assert(!ferror(fp));
39 return 1;
40 }
41
42 char *
43 ical_strerror(int i)
44 {
45 enum ical_err err = (i > 0) ? i : -i;
46
47 switch (err) {
48 case ICAL_ERR_OK:
49 return "no error";
50 case ICAL_ERR_SYSTEM:
51 return "system error";
52 case ICAL_ERR_END_MISMATCH:
53 return "END: does not match its corresponding BEGIN:";
54 case ICAL_ERR_MISSING_BEGIN:
55 return "unexpected content line before any BEGIN:";
56 case ICAL_ERR_MISSING_COLUMN:
57 return "missing ':' character from line";
58 case ICAL_ERR_MISSING_SEMICOLUMN:
59 return "missing ';' character before ':'";
60 case ICAL_ERR_MISSING_EQUAL:
61 return "missing '=' character in parameter before ':'";
62 case ICAL_ERR_MIN_NESTED:
63 return "too many END: for the number of BEGIN:";
64 case ICAL_ERR_MAX_NESTED:
65 return "maximum nesting level reached";
66 case ICAL_ERR_LENGTH:
67 assert(!"used internally, should not happen");
68 }
69 assert(!"unknown error code");
70 return "not a valid ical error code";
71 }
72
73 struct ical_value *
74 ical_new_value(char const *line)
75 {
76 struct ical_value *new;
77 size_t len;
78
79 len = strlen(line);
80 if ((new = calloc(1, sizeof *new + len + 1)) == NULL)
81 return NULL;
82 memcpy(new->buf, line, len + 1);
83 return new;
84 }
85
86 void
87 ical_free_value(struct ical_value *value)
88 {
89 map_free(&value->param, NULL);
90 free(value);
91 }
92
93 int
94 ical_parse_value(struct ical_value *value)
95 {
96 char *column, *equal, *param, *cp;
97 int e = errno;
98
99 value->name = value->buf;
100
101 if ((column = strchr(value->buf, ':')) == NULL)
102 return -ICAL_ERR_MISSING_COLUMN;
103 *column = '\0';
104 value->value = column + 1;
105
106 if ((cp = strchr(value->buf, ';')) != NULL)
107 *cp++ = '\0';
108 while ((param = strsep(&cp, ";")) != NULL) {
109 if ((equal = strchr(param, '=')) == NULL)
110 return -ICAL_ERR_MISSING_EQUAL;
111 *equal = '\0';
112 if (map_set(&value->param, param, equal + 1) < 0)
113 return -ICAL_ERR_SYSTEM;
114 }
115
116 assert(errno == e);
117 return 0;
118 }
119
120 struct ical_vnode *
121 ical_new_vnode(char const *name)
122 {
123 struct ical_vnode *new;
124 size_t sz;
125
126 if ((new = calloc(1, sizeof *new)) == NULL)
127 return NULL;
128 sz = sizeof new->name;
129 if (strlcpy(new->name, name, sz) >= sz) {
130 errno = EMSGSIZE;
131 goto err;
132 }
133 return new;
134 err:
135 ical_free_vnode(new);
136 return NULL;
137 }
138
139 static void
140 ical_free_value_void(void *v)
141 {
142 ical_free_value(v);
143 }
144
145 static void
146 ical_free_vnode_void(void *v)
147 {
148 ical_free_vnode(v);
149 }
150
151 void
152 ical_free_vnode(struct ical_vnode *node)
153 {
154 if (node == NULL)
155 return;
156 map_free(&node->values, ical_free_value_void);
157 map_free(&node->childs, ical_free_vnode_void);
158 ical_free_vnode(node->next);
159 free(node);
160 }
161
162 int
163 ical_push_nested(struct ical_vcalendar *vcal, struct ical_vnode *new)
164 {
165 struct ical_vnode **node;
166
167 node = vcal->nested;
168 for (int i = 0; *node != NULL; node++, i++) {
169 if (i >= ICAL_NESTED_MAX)
170 return -ICAL_ERR_MAX_NESTED;
171 }
172 node[0] = new;
173 node[1] = NULL;
174 return 0;
175 }
176
177 struct ical_vnode *
178 ical_pop_nested(struct ical_vcalendar *vcal)
179 {
180 struct ical_vnode **node, **prev = vcal->nested, *old;
181
182 for (prev = node = vcal->nested; *node != NULL; node++) {
183 vcal->current = *prev;
184 prev = node;
185 old = *node;
186 }
187 *prev = NULL;
188 if (vcal->nested[0] == NULL)
189 vcal->current = NULL;
190 return old;
191 }
192
193 int
194 ical_begin_vnode(struct ical_vcalendar *vcal, char const *name)
195 {
196 struct ical_vnode *new;
197 int e;
198
199 if ((new = ical_new_vnode(name)) == NULL)
200 return -ICAL_ERR_SYSTEM;
201 if ((e = ical_push_nested(vcal, new)) < 0)
202 goto err;
203 if (vcal->root == NULL) {
204 vcal->root = new;
205 } else {
206 new->next = map_get(&vcal->current->childs, new->name);
207 if (map_set(&vcal->current->childs, new->name, new) < 0)…
208 e = -ICAL_ERR_SYSTEM;
209 goto err;
210 }
211 }
212 vcal->current = new;
213 return 0;
214 err:
215 ical_free_vnode(new);
216 return e;
217 }
218
219 int
220 ical_end_vnode(struct ical_vcalendar *vcal, char const *name)
221 {
222 struct ical_vnode *old;
223
224 if ((old = ical_pop_nested(vcal)) == NULL)
225 return -ICAL_ERR_MIN_NESTED;
226 if (strcasecmp(name, old->name) != 0)
227 return -ICAL_ERR_END_MISMATCH;
228 return 0;
229 }
230
231 int
232 ical_push_value(struct ical_vcalendar *vcal, struct ical_value *new)
233 {
234 if (strcasecmp(new->name, "BEGIN") == 0) {
235 int e = ical_begin_vnode(vcal, new->value);
236 ical_free_value(new);
237 return e;
238 }
239 if (strcasecmp(new->name, "END") == 0) {
240 int e = ical_end_vnode(vcal, new->value);
241 ical_free_value(new);
242 return e;
243 }
244
245 if (vcal->current == NULL)
246 return -ICAL_ERR_MISSING_BEGIN;
247
248 new->next = map_get(&vcal->current->values, new->name);
249 if (map_set(&vcal->current->values, new->name, new) < 0)
250 return -ICAL_ERR_SYSTEM;
251
252 return 0;
253 }
254
255 int
256 ical_read_vcalendar(struct ical_vcalendar *vcal, FILE *fp)
257 {
258 char *line = NULL, *ln = NULL;
259 size_t sz = 0;
260 ssize_t r;
261 int e;
262
263 memset(vcal, 0, sizeof *vcal);
264
265 while ((r = ical_getline(&line, &ln, &sz, fp)) > 0) {
266 struct ical_value *new;
267
268 if ((new = ical_new_value(line)) == NULL) {
269 e = -ICAL_ERR_SYSTEM;
270 goto err;
271 }
272 if ((e = ical_parse_value(new)) < 0)
273 goto err;
274 if ((e = ical_push_value(vcal, new)) < 0)
275 goto err;
276 }
277 e = (r == 0) ? 0 : -ICAL_ERR_SYSTEM;
278 err:
279 free(line);
280 free(ln);
281 return e;
282 }
283
284 void
285 ical_free_vcalendar(struct ical_vcalendar *vcal)
286 {
287 ical_free_vnode(vcal->root);
288 }
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.