ref: 5e39bdc9f4f8117890494e8a8ce632e77c6aaf46
dir: /libvcard/vcard.c/
#include <u.h> #include <libc.h> #include "vcard.h" extern Vcard *vcparsecard; extern char *vcparsestr; extern int yyparse(void); static char* estrdup(char *s) { char *t = strdup(s); if (!t) sysfatal("%r"); return t; } static Vcard* parse(char *s) { if (!s) { werrstr("parse string is nil"); return nil; } /* todo: somewhat weird, but this works */ memset(&vcstate, sizeof vcstate, 0); vcparsestr = s; vcstate.str = s; vcstate.s = nil; vcparsecard = nil; yyparse(); return vcparsecard; } static void fold(char *str) { char *s; char *end; if (!str) return; end = strchr(str, 0); while (str < end) { s = strchr(str, '\r'); if (!s) break; if (s[1] == 0) break; if (s[1] == '\n' && (s[2] == ' ' || s[2] == '\t')) { memmove(s, s+3, end-s-3); end -= 3; } str = s+1; } *end = 0; } #ifdef TEST void _vc_t_fold(char *s) { fold(s); } #endif Vcard* vcparse(char *s) { fold(s); return parse(s); } static void iltoupper(char *s) { while (*s) { if (*s >= 'a' && *s <= 'z') *s = *s - 'a' + 'A'; s++; } } Vcard* vcparsefile(char *file) { int fd, step; char *s, *t; long n; Vcard *vc; fd = open(file, OREAD); if (fd < 0) return nil; step = 1; s = mallocz(8192, 1); t = s; while ((n = read(fd, t, 8191)) > 0) { t += n; step++; s = realloc(s, 8192 * step); memset(s + 8192*(step-1), 0, 8192); } close(fd); vc = vcparse(s); free(s); return vc; } static char* serializeparams(Vparam *param) { Vparam *p; char *s, *ns, *ps; char *upper; if (!param) return nil; s = nil; for (p = param; p; p = p->next) { // TODO: only quote if needed upper = estrdup(p->name); iltoupper(upper); ps = smprint(";%s=\"%s\"", upper, p->value); free(upper); if (!ps) return nil; if (!s) s = ps; else { ns = smprint("%s%s", s, ps); free(s); free(ps); s = ns; } } return s; } static char* serializeline(Vline *l) { char *ps, *ls; char *upper; ls = nil; ps = serializeparams(l->params); upper = estrdup(l->name); iltoupper(upper); ls = smprint( "%s%s" /* group string */ "%s%s:%s\r\n", /* name, param, value */ (l->group && *l->group ? l->group : ""), /* group string */ (l->group && *l->group ? "." : ""), /* group dot */ upper, ps ? ps : "", l->value); free(upper); if (ps) free(ps); if (!ls) goto Err; return ls; Err: if (ls) free(ls); if (ps) free(ps); return nil; } static char* foldline(char *line) { Rune r; char *nline, *s, *lstart, *lend; char *cut; int l, n; int rlen; l = strlen(line); if (l <= 75) return line; n = l/75*3 + l; nline = realloc(line, n+1); if (!nline) return line; memset(nline + l, 0, l/75*3 + 1); lend = strchr(nline, 0); lstart = nline; s = nline; while (*s) { rlen = chartorune(&r, s); s += rlen; if (s - lstart < 73) continue; memmove(s+3, s, lend-s); s[0] = '\r'; s[1] = '\n'; s[2] = '\t'; s += 3; lend += 3; lstart = s; } return nline; } static char* serializelines(Vline *line) { Vline *l; char *s, *ns, *ls; s = nil; for (l = line; l; l = l->next) { if (cistrcmp(l->name, "version") == 0) { s = serializeline(l); break; } } if (!s) { werrstr("Vcard has no version property"); return nil; } for (l = line; l; l = l->next) { if (cistrcmp(l->name, "version") == 0) continue; ls = serializeline(l); if (!ls) { if (s) free(s); return nil; } ls = foldline(ls); if (!s) { s = ls; } else { ns = smprint("%s%s", s, ls); free(s); free(ls); s = ns; if (!s) return nil; } } return s; } char* vcmserialize(Vcard *card) { Vcard *c; char *s, *ns, *cs, *ls; s = nil; for (c = card; c; c = c->next) { if (!c->content) continue; ls = serializelines(c->content); if (!ls) { if (s) free(s); return nil; } cs = smprint( "BEGIN:VCARD\r\n" "%s" "END:VCARD\r\n", ls); if (!cs) { free(ls); if (s) free(s); return nil; } if (!s) { s = cs; free(ls); } else { ns = smprint("%s%s", s, cs); free(s); free(ls); free(cs); s = ns; if (!s) return nil; } } return s; } void vcfreeparams(Vparam *params) { Vparam *p, *np; for (p = params; p; p = np) { np = p->next; if (p->name) free(p->name); if (p->value) free(p->value); free(p); } } void vcfreelines(Vline *lines) { Vline *l, *nl; for (l = lines; l; l = nl) { nl = l->next; if (l->name) free(l->name); if (l->value) free(l->value); if (l->group) free(l->group); if (l->params) vcfreeparams(l->params); free(l); } } void vcfreecards(Vcard *cards) { Vcard *c, *nc; for (c = cards; c; c = nc) { nc = c->next; if (c->content) vcfreelines(c->content); free(c); } }