ref: e0cac8cff0fad58496578de0bf11f111f765d3a8
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 strdup("");
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*
serializelines(Vline *line)
{
Vline *l;
char *s, *ns, *ls, *ps;
char *upper;
s = nil;
for (l = line; l; l = l->next) {
ps = serializeparams(l->params);
if (!ps) {
if (s) free(s);
return nil;
}
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, l->value);
free(upper);
if (!ls) {
if (s) free(s);
return nil;
}
if (!s) {
s = ls;
free(ps);
} else {
ns = smprint("%s%s", s, ls);
free(s);
free(ls);
free(ps);
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);
}
}