ref: d5d0e163bf6d6df97ac6d991f8fd5a7c9a40d936
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; }