shithub: vcardfs

ref: 9828f53e5b542da92dfdffc124dd9941d308cb1d
dir: /libvcard/vcard.c/

View raw version
#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 : ""),  /* group string */
			(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"
			"VERSION:4.0\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;
}