shithub: vcardfs

ref: 63ab1619dbd1d7b3aefb05a04b0ce65a85f8f8e7
dir: /libvcard/vlex.c/

View raw version
#include <u.h>
#include <libc.h>
#include "vcard.h"
#include "y.tab.h"

static void
iltolower(char *s)
{
	while (*s) {
		if (*s >= 'A' && *s <= 'Z')
			*s = *s - 'A' + 'a';
		s++;
	}
}

char *vcparsestr;
Vstate vcstate;

typedef struct Vcname Vcname;
struct Vcname {
	char *str;
	int token;
};

static char beginstr[] = "begin:vcard\r\nversion:4.0\r\n";

Vcname vcnames[] = {
	{ "end:vcard", END },
	/* fields */
	{ "kind", KIND },
	{ "fn", FN },
	{ "n", N },
	{ "nickname", NICKNAME },
	{ "photo", PHOTO },
	{ "bday", BDAY },
	{ "anniversary", ANNIVERSARY },
	{ "gender", GENDER },
	{ "adr", ADR },
	{ "tel", TEL },
	{ "email", EMAIL },
	{ "impp", IMPP },
	{ "lang", LANG },
	{ "tz", TZ },
	{ "geo", GEO },
	{ "title", TITLE },
	{ "role", ROLE },
	{ "logo", LOGO },
	{ "org", ORG },
	{ "member", MEMBER },
	{ "related", RELATED },
	{ "categories", CATEGORIES },
	{ "note", NOTE },
	{ "prodid", PRODID },
	{ "rev", REV },
	{ "sound", SOUND },
	{ "uid", UID },
	{ "clientpidmap", CLIENTPIDMAP },
	{ "url", URL },
	{ "key", KEY },
	{ "fburl", FBURL },
	{ "caladruri", CALADRURI },
	{ "caluri", CALURI },
	{ "xml", XML },
	/* params */
	{ "language", SWORD },
	{ "value", SWORD },
	{ "pref", SWORD },
	{ "altid", SWORD },
	{ "pid", SWORD },
	{ "type", SWORD },
	{ "mediatype", SWORD },
	{ "calscale", SWORD },
	{ "sort-as", SWORD },
	{ "geo", SWORD },
	{ "tz", SWORD }, /* TODO: it's a duplicate! make state-dependent */
	{ nil, 0 }
};

static char verbchars[] = ":;\"=";

int
yylex(void)
{
	Vcname *nm;
	int n;
	char *s, *t;
	
	if (!vcstate.s) {
		vcstate.s = vcstate.str;
	}
	
	/*
	fprint(2, "vcstate:\n"
		"  str: %p\n"
		"  s: %c\n"
		"  invalue: %d\n"
		"  inquote: %d\n",
		vcstate.str, *vcstate.s, vcstate.invalue, vcstate.inquote);
	*/
	
	/* value string */
	if (vcstate.invalue) {
		s = strstr(vcstate.s, "\r\n");
		if (!s) {
			yylval.s = strdup(vcstate.s);
			vcstate.s = strchr(vcstate.s, 0);
			return FWORD;
		}
		yylval.s = mallocz(s - vcstate.s + 1, 1);
		memcpy(yylval.s, vcstate.s, s - vcstate.s);
		vcstate.s = s;
		vcstate.invalue = 0;
		return FWORD;
	}
	
	/* quoted string */
	if (vcstate.inquote == 1) {
		s = strchr(vcstate.s, '"');
		if (!s) {
			fprint(2, "parse error: quotes not closing!\n");
			return -1;
		}
		yylval.s = mallocz(s - vcstate.s + 1, 1);
		memcpy(yylval.s, vcstate.s, s - vcstate.s);
		vcstate.s = s;
		vcstate.inquote = 2;
		return FWORD;
	}
	
	/* verbatim characters */
	if (strchr(verbchars, *vcstate.s)) {
		switch (*vcstate.s) {
		case ':':
			vcstate.invalue++;
			break;
		case '"':
			if (vcstate.inquote == 2) {
				vcstate.inquote = 0;
			} else {
				vcstate.inquote++;
			}
			break;
		}
		n = *vcstate.s;
		vcstate.s++;
		return n;
	}
	
	/* newline */
	if (cistrncmp(vcstate.s, "\r\n", 2) == 0) {
		vcstate.s += 2;
		return CRLF;
	}
	
	/* begin block */
	n = strlen(beginstr);
	if (cistrncmp(vcstate.s, beginstr, n) == 0) {
		vcstate.s += n;
		return BEGIN;
	}
	
	/* reserved keywords */
	for (nm = vcnames; nm->str; nm++) {
		n = strlen(nm->str);
		if (cistrncmp(vcstate.s, nm->str, n) == 0) {
			yylval.s = mallocz(n+1, 1);
			memcpy(yylval.s, vcstate.s, n);
			iltolower(yylval.s);
			vcstate.s += n;
			return nm->token;
		}
	}
	
	/* assume SWORD string (unquoted param value) */
	s = strchr(vcstate.s, ':');
	t = strchr(vcstate.s, ';');
	s = s < t ? s : t;
	n = s - vcstate.s;
	yylval.s = mallocz(n + 1, 1);
	memcpy(yylval.s, vcstate.s, n);
	vcstate.s += n;
	return SWORD;
}