|  | #include <u.h> | 
|  | #include <libc.h> | 
|  | #include <bio.h> | 
|  | #include "hdr.h" | 
|  | #include "conv.h" | 
|  |  | 
|  | typedef struct Hchar Hchar; | 
|  | struct Hchar | 
|  | { | 
|  | char *s; | 
|  | Rune r; | 
|  | }; | 
|  |  | 
|  | /* <, >, ", & intentionally omitted */ | 
|  |  | 
|  | static Hchar byname[] = | 
|  | { | 
|  | {"AElig", 198}, | 
|  | {"Aacute", 193}, | 
|  | {"Acirc", 194}, | 
|  | {"Agrave", 192}, | 
|  | {"Alpha", 913}, | 
|  | {"Aring", 197}, | 
|  | {"Atilde", 195}, | 
|  | {"Auml", 196}, | 
|  | {"Beta", 914}, | 
|  | {"Ccedil", 199}, | 
|  | {"Chi", 935}, | 
|  | {"Dagger", 8225}, | 
|  | {"Delta", 916}, | 
|  | {"ETH", 208}, | 
|  | {"Eacute", 201}, | 
|  | {"Ecirc", 202}, | 
|  | {"Egrave", 200}, | 
|  | {"Epsilon", 917}, | 
|  | {"Eta", 919}, | 
|  | {"Euml", 203}, | 
|  | {"Gamma", 915}, | 
|  | {"Iacute", 205}, | 
|  | {"Icirc", 206}, | 
|  | {"Igrave", 204}, | 
|  | {"Iota", 921}, | 
|  | {"Iuml", 207}, | 
|  | {"Kappa", 922}, | 
|  | {"Lambda", 923}, | 
|  | {"Mu", 924}, | 
|  | {"Ntilde", 209}, | 
|  | {"Nu", 925}, | 
|  | {"OElig", 338}, | 
|  | {"Oacute", 211}, | 
|  | {"Ocirc", 212}, | 
|  | {"Ograve", 210}, | 
|  | {"Omega", 937}, | 
|  | {"Omicron", 927}, | 
|  | {"Oslash", 216}, | 
|  | {"Otilde", 213}, | 
|  | {"Ouml", 214}, | 
|  | {"Phi", 934}, | 
|  | {"Pi", 928}, | 
|  | {"Prime", 8243}, | 
|  | {"Psi", 936}, | 
|  | {"Rho", 929}, | 
|  | {"Scaron", 352}, | 
|  | {"Sigma", 931}, | 
|  | {"THORN", 222}, | 
|  | {"Tau", 932}, | 
|  | {"Theta", 920}, | 
|  | {"Uacute", 218}, | 
|  | {"Ucirc", 219}, | 
|  | {"Ugrave", 217}, | 
|  | {"Upsilon", 933}, | 
|  | {"Uuml", 220}, | 
|  | {"Xi", 926}, | 
|  | {"Yacute", 221}, | 
|  | {"Yuml", 376}, | 
|  | {"Zeta", 918}, | 
|  | {"aacute", 225}, | 
|  | {"acirc", 226}, | 
|  | {"acute", 180}, | 
|  | {"aelig", 230}, | 
|  | {"agrave", 224}, | 
|  | {"alefsym", 8501}, | 
|  | {"alpha", 945}, | 
|  | {"amp", 38}, | 
|  | {"and", 8743}, | 
|  | {"ang", 8736}, | 
|  | {"aring", 229}, | 
|  | {"asymp", 8776}, | 
|  | {"atilde", 227}, | 
|  | {"auml", 228}, | 
|  | {"bdquo", 8222}, | 
|  | {"beta", 946}, | 
|  | {"brvbar", 166}, | 
|  | {"bull", 8226}, | 
|  | {"cap", 8745}, | 
|  | {"ccedil", 231}, | 
|  | {"cdots", 8943}, | 
|  | {"cedil", 184}, | 
|  | {"cent", 162}, | 
|  | {"chi", 967}, | 
|  | {"circ", 710}, | 
|  | {"clubs", 9827}, | 
|  | {"cong", 8773}, | 
|  | {"copy", 169}, | 
|  | {"crarr", 8629}, | 
|  | {"cup", 8746}, | 
|  | {"curren", 164}, | 
|  | {"dArr", 8659}, | 
|  | {"dagger", 8224}, | 
|  | {"darr", 8595}, | 
|  | {"ddots", 8945}, | 
|  | {"deg", 176}, | 
|  | {"delta", 948}, | 
|  | {"diams", 9830}, | 
|  | {"divide", 247}, | 
|  | {"eacute", 233}, | 
|  | {"ecirc", 234}, | 
|  | {"egrave", 232}, | 
|  | {"emdash", 8212},	/* non-standard but commonly used */ | 
|  | {"empty", 8709}, | 
|  | {"emsp", 8195}, | 
|  | {"endash", 8211},	/* non-standard but commonly used */ | 
|  | {"ensp", 8194}, | 
|  | {"epsilon", 949}, | 
|  | {"equiv", 8801}, | 
|  | {"eta", 951}, | 
|  | {"eth", 240}, | 
|  | {"euml", 235}, | 
|  | {"euro", 8364}, | 
|  | {"exist", 8707}, | 
|  | {"fnof", 402}, | 
|  | {"forall", 8704}, | 
|  | {"frac12", 189}, | 
|  | {"frac14", 188}, | 
|  | {"frac34", 190}, | 
|  | {"frasl", 8260}, | 
|  | {"gamma", 947}, | 
|  | {"ge", 8805}, | 
|  | {"gt", 62}, | 
|  | {"hArr", 8660}, | 
|  | {"harr", 8596}, | 
|  | {"hearts", 9829}, | 
|  | {"hellip", 8230}, | 
|  | {"iacute", 237}, | 
|  | {"icirc", 238}, | 
|  | {"iexcl", 161}, | 
|  | {"igrave", 236}, | 
|  | {"image", 8465}, | 
|  | {"infin", 8734}, | 
|  | {"int", 8747}, | 
|  | {"iota", 953}, | 
|  | {"iquest", 191}, | 
|  | {"isin", 8712}, | 
|  | {"iuml", 239}, | 
|  | {"kappa", 954}, | 
|  | {"lArr", 8656}, | 
|  | {"lambda", 955}, | 
|  | {"lang", 9001}, | 
|  | {"laquo", 171}, | 
|  | {"larr", 8592}, | 
|  | {"lceil", 8968}, | 
|  | {"ldots", 8230}, | 
|  | {"ldquo", 8220}, | 
|  | {"le", 8804}, | 
|  | {"lfloor", 8970}, | 
|  | {"lowast", 8727}, | 
|  | {"loz", 9674}, | 
|  | {"lrm", 8206}, | 
|  | {"lsaquo", 8249}, | 
|  | {"lsquo", 8216}, | 
|  | {"lt", 60}, | 
|  | {"macr", 175}, | 
|  | {"mdash", 8212}, | 
|  | {"micro", 181}, | 
|  | {"middot", 183}, | 
|  | {"minus", 8722}, | 
|  | {"mu", 956}, | 
|  | {"nabla", 8711}, | 
|  | {"nbsp", 160}, | 
|  | {"ndash", 8211}, | 
|  | {"ne", 8800}, | 
|  | {"ni", 8715}, | 
|  | {"not", 172}, | 
|  | {"notin", 8713}, | 
|  | {"nsub", 8836}, | 
|  | {"ntilde", 241}, | 
|  | {"nu", 957}, | 
|  | {"oacute", 243}, | 
|  | {"ocirc", 244}, | 
|  | {"oelig", 339}, | 
|  | {"ograve", 242}, | 
|  | {"oline", 8254}, | 
|  | {"omega", 969}, | 
|  | {"omicron", 959}, | 
|  | {"oplus", 8853}, | 
|  | {"or", 8744}, | 
|  | {"ordf", 170}, | 
|  | {"ordm", 186}, | 
|  | {"oslash", 248}, | 
|  | {"otilde", 245}, | 
|  | {"otimes", 8855}, | 
|  | {"ouml", 246}, | 
|  | {"para", 182}, | 
|  | {"part", 8706}, | 
|  | {"permil", 8240}, | 
|  | {"perp", 8869}, | 
|  | {"phi", 966}, | 
|  | {"pi", 960}, | 
|  | {"piv", 982}, | 
|  | {"plusmn", 177}, | 
|  | {"pound", 163}, | 
|  | {"prime", 8242}, | 
|  | {"prod", 8719}, | 
|  | {"prop", 8733}, | 
|  | {"psi", 968}, | 
|  | {"quad", 8193}, | 
|  | {"quot", 34}, | 
|  | {"rArr", 8658}, | 
|  | {"radic", 8730}, | 
|  | {"rang", 9002}, | 
|  | {"raquo", 187}, | 
|  | {"rarr", 8594}, | 
|  | {"rceil", 8969}, | 
|  | {"rdquo", 8221}, | 
|  | {"real", 8476}, | 
|  | {"reg", 174}, | 
|  | {"rfloor", 8971}, | 
|  | {"rho", 961}, | 
|  | {"rlm", 8207}, | 
|  | {"rsaquo", 8250}, | 
|  | {"rsquo", 8217}, | 
|  | {"sbquo", 8218}, | 
|  | {"scaron", 353}, | 
|  | {"sdot", 8901}, | 
|  | {"sect", 167}, | 
|  | {"shy", 173}, | 
|  | {"sigma", 963}, | 
|  | {"sigmaf", 962}, | 
|  | {"sim", 8764}, | 
|  | {"sp", 8194}, | 
|  | {"spades", 9824}, | 
|  | {"sub", 8834}, | 
|  | {"sube", 8838}, | 
|  | {"sum", 8721}, | 
|  | {"sup", 8835}, | 
|  | {"sup1", 185}, | 
|  | {"sup2", 178}, | 
|  | {"sup3", 179}, | 
|  | {"supe", 8839}, | 
|  | {"szlig", 223}, | 
|  | {"tau", 964}, | 
|  | {"there4", 8756}, | 
|  | {"theta", 952}, | 
|  | {"thetasym", 977}, | 
|  | {"thinsp", 8201}, | 
|  | {"thorn", 254}, | 
|  | {"tilde", 732}, | 
|  | {"times", 215}, | 
|  | {"trade", 8482}, | 
|  | {"uArr", 8657}, | 
|  | {"uacute", 250}, | 
|  | {"uarr", 8593}, | 
|  | {"ucirc", 251}, | 
|  | {"ugrave", 249}, | 
|  | {"uml", 168}, | 
|  | {"upsih", 978}, | 
|  | {"upsilon", 965}, | 
|  | {"uuml", 252}, | 
|  | {"varepsilon", 8712}, | 
|  | {"varphi", 981}, | 
|  | {"varpi", 982}, | 
|  | {"varrho", 1009}, | 
|  | {"vdots", 8942}, | 
|  | {"vsigma", 962}, | 
|  | {"vtheta", 977}, | 
|  | {"weierp", 8472}, | 
|  | {"xi", 958}, | 
|  | {"yacute", 253}, | 
|  | {"yen", 165}, | 
|  | {"yuml", 255}, | 
|  | {"zeta", 950}, | 
|  | {"zwj", 8205}, | 
|  | {"zwnj", 8204} | 
|  | }; | 
|  |  | 
|  | static Hchar byrune[nelem(byname)]; | 
|  |  | 
|  | static int | 
|  | hnamecmp(const void *va, const void *vb) | 
|  | { | 
|  | Hchar *a, *b; | 
|  |  | 
|  | a = (Hchar*)va; | 
|  | b = (Hchar*)vb; | 
|  | return strcmp(a->s, b->s); | 
|  | } | 
|  |  | 
|  | static int | 
|  | hrunecmp(const void *va, const void *vb) | 
|  | { | 
|  | Hchar *a, *b; | 
|  |  | 
|  | a = (Hchar*)va; | 
|  | b = (Hchar*)vb; | 
|  | return a->r - b->r; | 
|  | } | 
|  |  | 
|  | static void | 
|  | html_init(void) | 
|  | { | 
|  | static int init; | 
|  |  | 
|  | if(init) | 
|  | return; | 
|  | init = 1; | 
|  | memmove(byrune, byname, sizeof byrune); | 
|  | qsort(byname, nelem(byname), sizeof byname[0], hnamecmp); | 
|  | qsort(byrune, nelem(byrune), sizeof byrune[0], hrunecmp); | 
|  | } | 
|  |  | 
|  | static Rune | 
|  | findbyname(char *s) | 
|  | { | 
|  | Hchar *h; | 
|  | int n, m, x; | 
|  |  | 
|  | h = byname; | 
|  | n = nelem(byname); | 
|  | while(n > 0){ | 
|  | m = n/2; | 
|  | x = strcmp(h[m].s, s); | 
|  | if(x == 0) | 
|  | return h[m].r; | 
|  | if(x < 0){ | 
|  | h += m+1; | 
|  | n -= m+1; | 
|  | }else | 
|  | n = m; | 
|  | } | 
|  | return Runeerror; | 
|  | } | 
|  |  | 
|  | static char* | 
|  | findbyrune(Rune r) | 
|  | { | 
|  | Hchar *h; | 
|  | int n, m; | 
|  |  | 
|  | h = byrune; | 
|  | n = nelem(byrune); | 
|  | while(n > 0){ | 
|  | m = n/2; | 
|  | if(h[m].r == r) | 
|  | return h[m].s; | 
|  | if(h[m].r < r){ | 
|  | h += m+1; | 
|  | n -= m+1; | 
|  | }else | 
|  | n = m; | 
|  | } | 
|  | return nil; | 
|  | } | 
|  |  | 
|  | void | 
|  | html_in(int fd, long *x, struct convert *out) | 
|  | { | 
|  | char buf[100], *p; | 
|  | Biobuf b; | 
|  | Rune rbuf[N]; | 
|  | Rune *r, *er; | 
|  | int c, i; | 
|  |  | 
|  | USED(x); | 
|  |  | 
|  | html_init(); | 
|  | r = rbuf; | 
|  | er = rbuf+N; | 
|  | Binit(&b, fd, OREAD); | 
|  | while((c = Bgetrune(&b)) != Beof){ | 
|  | if(r >= er){ | 
|  | OUT(out, rbuf, r-rbuf); | 
|  | r = rbuf; | 
|  | } | 
|  | if(c == '&'){ | 
|  | buf[0] = c; | 
|  | for(i=1; i<nelem(buf)-1;){ | 
|  | c = Bgetc(&b); | 
|  | if(c == Beof) | 
|  | break; | 
|  | buf[i++] = c; | 
|  | if(strchr("; \t\r\n", c)) | 
|  | break; | 
|  | } | 
|  | buf[i] = 0; | 
|  | if(buf[i-1] == ';'){ | 
|  | buf[i-1] = 0; | 
|  | if((c = findbyname(buf+1)) != Runeerror){ | 
|  | *r++ = c; | 
|  | continue; | 
|  | } | 
|  | buf[i-1] = ';'; | 
|  | if(buf[1] == '#'){ | 
|  | if(buf[2] == 'x') | 
|  | c = strtol(buf+3, &p, 16); | 
|  | else | 
|  | c = strtol(buf+2, &p, 10); | 
|  | if(*p != ';' || c >= NRUNE || c < 0) | 
|  | goto bad; | 
|  | *r++ = c; | 
|  | continue; | 
|  | } | 
|  | } | 
|  | bad: | 
|  | for(p=buf; p<buf+i; ){ | 
|  | p += chartorune(r++, p); | 
|  | if(r >= er){ | 
|  | OUT(out, rbuf, r-rbuf); | 
|  | r = rbuf; | 
|  | } | 
|  | } | 
|  | continue; | 
|  | } | 
|  | *r++ = c; | 
|  | } | 
|  | if(r > rbuf) | 
|  | OUT(out, rbuf, r-rbuf); | 
|  | OUT(out, rbuf, 0); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * use biobuf because can use more than UTFmax bytes per rune | 
|  | */ | 
|  | void | 
|  | html_out(Rune *r, int n, long *x) | 
|  | { | 
|  | char *s; | 
|  | Biobuf b; | 
|  | Rune *er; | 
|  |  | 
|  | USED(x); | 
|  | html_init(); | 
|  | Binit(&b, 1, OWRITE); | 
|  | er = r+n; | 
|  | for(; r<er; r++){ | 
|  | if(*r < Runeself) | 
|  | Bputrune(&b, *r); | 
|  | else if((s = findbyrune(*r)) != nil) | 
|  | Bprint(&b, "&%s;", s); | 
|  | else | 
|  | Bprint(&b, "&#%d;", *r); | 
|  | } | 
|  | Bflush(&b); | 
|  | } | 
|  |  |