ref: 0f18bf0aaf945b20b24f3ec8f3ae37f42c9e08b7
dir: /libvcard/vlex.c/
#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 (!vcparsestr)
return 0;
if (!vcstate.s) {
vcstate.s = vcparsestr;
vcstate.str = vcparsestr;
}
/* 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;
}
/* TODO: 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;
}