19a747e4fSDavid du Colombier #include <u.h>
29a747e4fSDavid du Colombier #include <libc.h>
39a747e4fSDavid du Colombier #include <draw.h>
49a747e4fSDavid du Colombier #include <ctype.h>
59a747e4fSDavid du Colombier #include <html.h>
69a747e4fSDavid du Colombier #include "impl.h"
79a747e4fSDavid du Colombier
89a747e4fSDavid du Colombier typedef struct TokenSource TokenSource;
99a747e4fSDavid du Colombier struct TokenSource
109a747e4fSDavid du Colombier {
119a747e4fSDavid du Colombier int i; // index of next byte to use
129a747e4fSDavid du Colombier uchar* data; // all the data
139a747e4fSDavid du Colombier int edata; // data[0:edata] is valid
149a747e4fSDavid du Colombier int chset; // one of US_Ascii, etc.
159a747e4fSDavid du Colombier int mtype; // TextHtml or TextPlain
169a747e4fSDavid du Colombier };
179a747e4fSDavid du Colombier
189a747e4fSDavid du Colombier enum {
199a747e4fSDavid du Colombier EOF = -2,
209a747e4fSDavid du Colombier EOB = -1
219a747e4fSDavid du Colombier };
229a747e4fSDavid du Colombier
239a747e4fSDavid du Colombier #define ISNAMCHAR(c) ((c)<256 && (isalpha(c) || isdigit(c) || (c) == '-' || (c) == '.'))
249a747e4fSDavid du Colombier
259a747e4fSDavid du Colombier #define SMALLBUFSIZE 240
269a747e4fSDavid du Colombier #define BIGBUFSIZE 2000
279a747e4fSDavid du Colombier
289a747e4fSDavid du Colombier // HTML 4.0 tag names.
299a747e4fSDavid du Colombier // Keep sorted, and in correspondence with enum in iparse.h.
309a747e4fSDavid du Colombier Rune* tagnames[] = {
319a747e4fSDavid du Colombier L" ",
329a747e4fSDavid du Colombier L"!",
339a747e4fSDavid du Colombier L"a",
349a747e4fSDavid du Colombier L"abbr",
359a747e4fSDavid du Colombier L"acronym",
369a747e4fSDavid du Colombier L"address",
379a747e4fSDavid du Colombier L"applet",
389a747e4fSDavid du Colombier L"area",
399a747e4fSDavid du Colombier L"b",
409a747e4fSDavid du Colombier L"base",
419a747e4fSDavid du Colombier L"basefont",
429a747e4fSDavid du Colombier L"bdo",
439a747e4fSDavid du Colombier L"big",
449a747e4fSDavid du Colombier L"blink",
459a747e4fSDavid du Colombier L"blockquote",
469a747e4fSDavid du Colombier L"body",
479a747e4fSDavid du Colombier L"bq",
489a747e4fSDavid du Colombier L"br",
499a747e4fSDavid du Colombier L"button",
509a747e4fSDavid du Colombier L"caption",
519a747e4fSDavid du Colombier L"center",
529a747e4fSDavid du Colombier L"cite",
539a747e4fSDavid du Colombier L"code",
549a747e4fSDavid du Colombier L"col",
559a747e4fSDavid du Colombier L"colgroup",
569a747e4fSDavid du Colombier L"dd",
579a747e4fSDavid du Colombier L"del",
589a747e4fSDavid du Colombier L"dfn",
599a747e4fSDavid du Colombier L"dir",
609a747e4fSDavid du Colombier L"div",
619a747e4fSDavid du Colombier L"dl",
629a747e4fSDavid du Colombier L"dt",
639a747e4fSDavid du Colombier L"em",
649a747e4fSDavid du Colombier L"fieldset",
659a747e4fSDavid du Colombier L"font",
669a747e4fSDavid du Colombier L"form",
679a747e4fSDavid du Colombier L"frame",
689a747e4fSDavid du Colombier L"frameset",
699a747e4fSDavid du Colombier L"h1",
709a747e4fSDavid du Colombier L"h2",
719a747e4fSDavid du Colombier L"h3",
729a747e4fSDavid du Colombier L"h4",
739a747e4fSDavid du Colombier L"h5",
749a747e4fSDavid du Colombier L"h6",
759a747e4fSDavid du Colombier L"head",
769a747e4fSDavid du Colombier L"hr",
779a747e4fSDavid du Colombier L"html",
789a747e4fSDavid du Colombier L"i",
799a747e4fSDavid du Colombier L"iframe",
809a747e4fSDavid du Colombier L"img",
819a747e4fSDavid du Colombier L"input",
829a747e4fSDavid du Colombier L"ins",
839a747e4fSDavid du Colombier L"isindex",
849a747e4fSDavid du Colombier L"kbd",
859a747e4fSDavid du Colombier L"label",
869a747e4fSDavid du Colombier L"legend",
879a747e4fSDavid du Colombier L"li",
889a747e4fSDavid du Colombier L"link",
899a747e4fSDavid du Colombier L"map",
909a747e4fSDavid du Colombier L"menu",
919a747e4fSDavid du Colombier L"meta",
929a747e4fSDavid du Colombier L"nobr",
939a747e4fSDavid du Colombier L"noframes",
949a747e4fSDavid du Colombier L"noscript",
959a747e4fSDavid du Colombier L"object",
969a747e4fSDavid du Colombier L"ol",
979a747e4fSDavid du Colombier L"optgroup",
989a747e4fSDavid du Colombier L"option",
999a747e4fSDavid du Colombier L"p",
1009a747e4fSDavid du Colombier L"param",
1019a747e4fSDavid du Colombier L"pre",
1029a747e4fSDavid du Colombier L"q",
1039a747e4fSDavid du Colombier L"s",
1049a747e4fSDavid du Colombier L"samp",
1059a747e4fSDavid du Colombier L"script",
1069a747e4fSDavid du Colombier L"select",
1079a747e4fSDavid du Colombier L"small",
1089a747e4fSDavid du Colombier L"span",
1099a747e4fSDavid du Colombier L"strike",
1109a747e4fSDavid du Colombier L"strong",
1119a747e4fSDavid du Colombier L"style",
1129a747e4fSDavid du Colombier L"sub",
1139a747e4fSDavid du Colombier L"sup",
1149a747e4fSDavid du Colombier L"table",
1159a747e4fSDavid du Colombier L"tbody",
1169a747e4fSDavid du Colombier L"td",
1179a747e4fSDavid du Colombier L"textarea",
1189a747e4fSDavid du Colombier L"tfoot",
1199a747e4fSDavid du Colombier L"th",
1209a747e4fSDavid du Colombier L"thead",
1219a747e4fSDavid du Colombier L"title",
1229a747e4fSDavid du Colombier L"tr",
1239a747e4fSDavid du Colombier L"tt",
1249a747e4fSDavid du Colombier L"u",
1259a747e4fSDavid du Colombier L"ul",
1269a747e4fSDavid du Colombier L"var"
1279a747e4fSDavid du Colombier };
1289a747e4fSDavid du Colombier
1299a747e4fSDavid du Colombier // HTML 4.0 attribute names.
130314a20f0SDavid du Colombier // Keep sorted, and in correspondence with enum in impl.h.
1319a747e4fSDavid du Colombier Rune* attrnames[] = {
1329a747e4fSDavid du Colombier L"abbr",
1339a747e4fSDavid du Colombier L"accept-charset",
1349a747e4fSDavid du Colombier L"access-key",
1359a747e4fSDavid du Colombier L"action",
1369a747e4fSDavid du Colombier L"align",
1379a747e4fSDavid du Colombier L"alink",
1389a747e4fSDavid du Colombier L"alt",
1399a747e4fSDavid du Colombier L"archive",
1409a747e4fSDavid du Colombier L"axis",
1419a747e4fSDavid du Colombier L"background",
1429a747e4fSDavid du Colombier L"bgcolor",
1439a747e4fSDavid du Colombier L"border",
1449a747e4fSDavid du Colombier L"cellpadding",
1459a747e4fSDavid du Colombier L"cellspacing",
1469a747e4fSDavid du Colombier L"char",
1479a747e4fSDavid du Colombier L"charoff",
1489a747e4fSDavid du Colombier L"charset",
1499a747e4fSDavid du Colombier L"checked",
1509a747e4fSDavid du Colombier L"cite",
1519a747e4fSDavid du Colombier L"class",
1529a747e4fSDavid du Colombier L"classid",
1539a747e4fSDavid du Colombier L"clear",
1549a747e4fSDavid du Colombier L"code",
1559a747e4fSDavid du Colombier L"codebase",
1569a747e4fSDavid du Colombier L"codetype",
1579a747e4fSDavid du Colombier L"color",
1589a747e4fSDavid du Colombier L"cols",
1599a747e4fSDavid du Colombier L"colspan",
1609a747e4fSDavid du Colombier L"compact",
1619a747e4fSDavid du Colombier L"content",
1629a747e4fSDavid du Colombier L"coords",
1639a747e4fSDavid du Colombier L"data",
1649a747e4fSDavid du Colombier L"datetime",
1659a747e4fSDavid du Colombier L"declare",
1669a747e4fSDavid du Colombier L"defer",
1679a747e4fSDavid du Colombier L"dir",
1689a747e4fSDavid du Colombier L"disabled",
1699a747e4fSDavid du Colombier L"enctype",
1709a747e4fSDavid du Colombier L"face",
1719a747e4fSDavid du Colombier L"for",
1729a747e4fSDavid du Colombier L"frame",
1739a747e4fSDavid du Colombier L"frameborder",
1749a747e4fSDavid du Colombier L"headers",
1759a747e4fSDavid du Colombier L"height",
1769a747e4fSDavid du Colombier L"href",
1779a747e4fSDavid du Colombier L"hreflang",
1789a747e4fSDavid du Colombier L"hspace",
1799a747e4fSDavid du Colombier L"http-equiv",
1809a747e4fSDavid du Colombier L"id",
1819a747e4fSDavid du Colombier L"ismap",
1829a747e4fSDavid du Colombier L"label",
1839a747e4fSDavid du Colombier L"lang",
1849a747e4fSDavid du Colombier L"link",
1859a747e4fSDavid du Colombier L"longdesc",
1869a747e4fSDavid du Colombier L"marginheight",
1879a747e4fSDavid du Colombier L"marginwidth",
1889a747e4fSDavid du Colombier L"maxlength",
1899a747e4fSDavid du Colombier L"media",
1909a747e4fSDavid du Colombier L"method",
1919a747e4fSDavid du Colombier L"multiple",
1929a747e4fSDavid du Colombier L"name",
1939a747e4fSDavid du Colombier L"nohref",
1949a747e4fSDavid du Colombier L"noresize",
1959a747e4fSDavid du Colombier L"noshade",
1969a747e4fSDavid du Colombier L"nowrap",
1979a747e4fSDavid du Colombier L"object",
1989a747e4fSDavid du Colombier L"onblur",
1999a747e4fSDavid du Colombier L"onchange",
2009a747e4fSDavid du Colombier L"onclick",
2019a747e4fSDavid du Colombier L"ondblclick",
2029a747e4fSDavid du Colombier L"onfocus",
2039a747e4fSDavid du Colombier L"onkeypress",
2049a747e4fSDavid du Colombier L"onkeyup",
2059a747e4fSDavid du Colombier L"onload",
2069a747e4fSDavid du Colombier L"onmousedown",
2079a747e4fSDavid du Colombier L"onmousemove",
2089a747e4fSDavid du Colombier L"onmouseout",
2099a747e4fSDavid du Colombier L"onmouseover",
2109a747e4fSDavid du Colombier L"onmouseup",
2119a747e4fSDavid du Colombier L"onreset",
2129a747e4fSDavid du Colombier L"onselect",
2139a747e4fSDavid du Colombier L"onsubmit",
2149a747e4fSDavid du Colombier L"onunload",
2159a747e4fSDavid du Colombier L"profile",
2169a747e4fSDavid du Colombier L"prompt",
2179a747e4fSDavid du Colombier L"readonly",
2189a747e4fSDavid du Colombier L"rel",
2199a747e4fSDavid du Colombier L"rev",
2209a747e4fSDavid du Colombier L"rows",
2219a747e4fSDavid du Colombier L"rowspan",
2229a747e4fSDavid du Colombier L"rules",
2239a747e4fSDavid du Colombier L"scheme",
2249a747e4fSDavid du Colombier L"scope",
2259a747e4fSDavid du Colombier L"scrolling",
2269a747e4fSDavid du Colombier L"selected",
2279a747e4fSDavid du Colombier L"shape",
2289a747e4fSDavid du Colombier L"size",
2299a747e4fSDavid du Colombier L"span",
2309a747e4fSDavid du Colombier L"src",
2319a747e4fSDavid du Colombier L"standby",
2329a747e4fSDavid du Colombier L"start",
2339a747e4fSDavid du Colombier L"style",
2349a747e4fSDavid du Colombier L"summary",
2359a747e4fSDavid du Colombier L"tabindex",
2369a747e4fSDavid du Colombier L"target",
2379a747e4fSDavid du Colombier L"text",
2389a747e4fSDavid du Colombier L"title",
2399a747e4fSDavid du Colombier L"type",
2409a747e4fSDavid du Colombier L"usemap",
2419a747e4fSDavid du Colombier L"valign",
2429a747e4fSDavid du Colombier L"value",
2439a747e4fSDavid du Colombier L"valuetype",
2449a747e4fSDavid du Colombier L"version",
2459a747e4fSDavid du Colombier L"vlink",
2469a747e4fSDavid du Colombier L"vspace",
2479a747e4fSDavid du Colombier L"width"
2489a747e4fSDavid du Colombier };
2499a747e4fSDavid du Colombier
2509a747e4fSDavid du Colombier
2519a747e4fSDavid du Colombier // Character entity to unicode character number map.
2529a747e4fSDavid du Colombier // Keep sorted by name.
2539027b8f7SDavid du Colombier StringInt chartab[]= {
2549a747e4fSDavid du Colombier {L"AElig", 198},
2559a747e4fSDavid du Colombier {L"Aacute", 193},
2569a747e4fSDavid du Colombier {L"Acirc", 194},
2579a747e4fSDavid du Colombier {L"Agrave", 192},
2584ac975e2SDavid du Colombier {L"Alpha", 913},
2599a747e4fSDavid du Colombier {L"Aring", 197},
2609a747e4fSDavid du Colombier {L"Atilde", 195},
2619a747e4fSDavid du Colombier {L"Auml", 196},
2624ac975e2SDavid du Colombier {L"Beta", 914},
2639a747e4fSDavid du Colombier {L"Ccedil", 199},
2644ac975e2SDavid du Colombier {L"Chi", 935},
2654ac975e2SDavid du Colombier {L"Dagger", 8225},
2664ac975e2SDavid du Colombier {L"Delta", 916},
2679a747e4fSDavid du Colombier {L"ETH", 208},
2689a747e4fSDavid du Colombier {L"Eacute", 201},
2699a747e4fSDavid du Colombier {L"Ecirc", 202},
2709a747e4fSDavid du Colombier {L"Egrave", 200},
2714ac975e2SDavid du Colombier {L"Epsilon", 917},
2724ac975e2SDavid du Colombier {L"Eta", 919},
2739a747e4fSDavid du Colombier {L"Euml", 203},
2744ac975e2SDavid du Colombier {L"Gamma", 915},
2759a747e4fSDavid du Colombier {L"Iacute", 205},
2769a747e4fSDavid du Colombier {L"Icirc", 206},
2779a747e4fSDavid du Colombier {L"Igrave", 204},
2784ac975e2SDavid du Colombier {L"Iota", 921},
2799a747e4fSDavid du Colombier {L"Iuml", 207},
2804ac975e2SDavid du Colombier {L"Kappa", 922},
2814ac975e2SDavid du Colombier {L"Lambda", 923},
2824ac975e2SDavid du Colombier {L"Mu", 924},
2839a747e4fSDavid du Colombier {L"Ntilde", 209},
2844ac975e2SDavid du Colombier {L"Nu", 925},
2854ac975e2SDavid du Colombier {L"OElig", 338},
2869a747e4fSDavid du Colombier {L"Oacute", 211},
2879a747e4fSDavid du Colombier {L"Ocirc", 212},
2889a747e4fSDavid du Colombier {L"Ograve", 210},
2894ac975e2SDavid du Colombier {L"Omega", 937},
2904ac975e2SDavid du Colombier {L"Omicron", 927},
2919a747e4fSDavid du Colombier {L"Oslash", 216},
2929a747e4fSDavid du Colombier {L"Otilde", 213},
2939a747e4fSDavid du Colombier {L"Ouml", 214},
2944ac975e2SDavid du Colombier {L"Phi", 934},
2954ac975e2SDavid du Colombier {L"Pi", 928},
2964ac975e2SDavid du Colombier {L"Prime", 8243},
2974ac975e2SDavid du Colombier {L"Psi", 936},
2984ac975e2SDavid du Colombier {L"Rho", 929},
2994ac975e2SDavid du Colombier {L"Scaron", 352},
3004ac975e2SDavid du Colombier {L"Sigma", 931},
3019a747e4fSDavid du Colombier {L"THORN", 222},
3024ac975e2SDavid du Colombier {L"Tau", 932},
3034ac975e2SDavid du Colombier {L"Theta", 920},
3049a747e4fSDavid du Colombier {L"Uacute", 218},
3059a747e4fSDavid du Colombier {L"Ucirc", 219},
3069a747e4fSDavid du Colombier {L"Ugrave", 217},
3074ac975e2SDavid du Colombier {L"Upsilon", 933},
3089a747e4fSDavid du Colombier {L"Uuml", 220},
3094ac975e2SDavid du Colombier {L"Xi", 926},
3109a747e4fSDavid du Colombier {L"Yacute", 221},
3114ac975e2SDavid du Colombier {L"Yuml", 376},
3124ac975e2SDavid du Colombier {L"Zeta", 918},
3139a747e4fSDavid du Colombier {L"aacute", 225},
3149a747e4fSDavid du Colombier {L"acirc", 226},
3159a747e4fSDavid du Colombier {L"acute", 180},
3169a747e4fSDavid du Colombier {L"aelig", 230},
3179a747e4fSDavid du Colombier {L"agrave", 224},
3184ac975e2SDavid du Colombier {L"alefsym", 8501},
3199a747e4fSDavid du Colombier {L"alpha", 945},
3209a747e4fSDavid du Colombier {L"amp", 38},
3214ac975e2SDavid du Colombier {L"and", 8743},
3224ac975e2SDavid du Colombier {L"ang", 8736},
3239a747e4fSDavid du Colombier {L"aring", 229},
3244ac975e2SDavid du Colombier {L"asymp", 8776},
3259a747e4fSDavid du Colombier {L"atilde", 227},
3269a747e4fSDavid du Colombier {L"auml", 228},
3274ac975e2SDavid du Colombier {L"bdquo", 8222},
3289a747e4fSDavid du Colombier {L"beta", 946},
3299a747e4fSDavid du Colombier {L"brvbar", 166},
3304ac975e2SDavid du Colombier {L"bull", 8226},
3314ac975e2SDavid du Colombier {L"cap", 8745},
3329a747e4fSDavid du Colombier {L"ccedil", 231},
3339a747e4fSDavid du Colombier {L"cdots", 8943},
3349a747e4fSDavid du Colombier {L"cedil", 184},
3359a747e4fSDavid du Colombier {L"cent", 162},
3369a747e4fSDavid du Colombier {L"chi", 967},
3374ac975e2SDavid du Colombier {L"circ", 710},
3384ac975e2SDavid du Colombier {L"clubs", 9827},
3394ac975e2SDavid du Colombier {L"cong", 8773},
3409a747e4fSDavid du Colombier {L"copy", 169},
3414ac975e2SDavid du Colombier {L"crarr", 8629},
3424ac975e2SDavid du Colombier {L"cup", 8746},
3439a747e4fSDavid du Colombier {L"curren", 164},
3444ac975e2SDavid du Colombier {L"dArr", 8659},
3454ac975e2SDavid du Colombier {L"dagger", 8224},
3464ac975e2SDavid du Colombier {L"darr", 8595},
3479a747e4fSDavid du Colombier {L"ddots", 8945},
3489a747e4fSDavid du Colombier {L"deg", 176},
3499a747e4fSDavid du Colombier {L"delta", 948},
3504ac975e2SDavid du Colombier {L"diams", 9830},
3519a747e4fSDavid du Colombier {L"divide", 247},
3529a747e4fSDavid du Colombier {L"eacute", 233},
3539a747e4fSDavid du Colombier {L"ecirc", 234},
3549a747e4fSDavid du Colombier {L"egrave", 232},
3559027b8f7SDavid du Colombier {L"emdash", 8212}, /* non-standard but commonly used */
3564ac975e2SDavid du Colombier {L"empty", 8709},
3579a747e4fSDavid du Colombier {L"emsp", 8195},
3589027b8f7SDavid du Colombier {L"endash", 8211}, /* non-standard but commonly used */
3599a747e4fSDavid du Colombier {L"ensp", 8194},
3609a747e4fSDavid du Colombier {L"epsilon", 949},
3614ac975e2SDavid du Colombier {L"equiv", 8801},
3629a747e4fSDavid du Colombier {L"eta", 951},
3639a747e4fSDavid du Colombier {L"eth", 240},
3649a747e4fSDavid du Colombier {L"euml", 235},
3654ac975e2SDavid du Colombier {L"euro", 8364},
3664ac975e2SDavid du Colombier {L"exist", 8707},
3674ac975e2SDavid du Colombier {L"fnof", 402},
3684ac975e2SDavid du Colombier {L"forall", 8704},
3699a747e4fSDavid du Colombier {L"frac12", 189},
3709a747e4fSDavid du Colombier {L"frac14", 188},
3719a747e4fSDavid du Colombier {L"frac34", 190},
3724ac975e2SDavid du Colombier {L"frasl", 8260},
3739a747e4fSDavid du Colombier {L"gamma", 947},
3744ac975e2SDavid du Colombier {L"ge", 8805},
3759a747e4fSDavid du Colombier {L"gt", 62},
3764ac975e2SDavid du Colombier {L"hArr", 8660},
3774ac975e2SDavid du Colombier {L"harr", 8596},
3784ac975e2SDavid du Colombier {L"hearts", 9829},
3794ac975e2SDavid du Colombier {L"hellip", 8230},
3809a747e4fSDavid du Colombier {L"iacute", 237},
3819a747e4fSDavid du Colombier {L"icirc", 238},
3829a747e4fSDavid du Colombier {L"iexcl", 161},
3839a747e4fSDavid du Colombier {L"igrave", 236},
3844ac975e2SDavid du Colombier {L"image", 8465},
3854ac975e2SDavid du Colombier {L"infin", 8734},
3864ac975e2SDavid du Colombier {L"int", 8747},
3879a747e4fSDavid du Colombier {L"iota", 953},
3889a747e4fSDavid du Colombier {L"iquest", 191},
3894ac975e2SDavid du Colombier {L"isin", 8712},
3909a747e4fSDavid du Colombier {L"iuml", 239},
3919a747e4fSDavid du Colombier {L"kappa", 954},
3924ac975e2SDavid du Colombier {L"lArr", 8656},
3939a747e4fSDavid du Colombier {L"lambda", 955},
3944ac975e2SDavid du Colombier {L"lang", 9001},
3959a747e4fSDavid du Colombier {L"laquo", 171},
3964ac975e2SDavid du Colombier {L"larr", 8592},
3974ac975e2SDavid du Colombier {L"lceil", 8968},
3989a747e4fSDavid du Colombier {L"ldots", 8230},
3994ac975e2SDavid du Colombier {L"ldquo", 8220},
4004ac975e2SDavid du Colombier {L"le", 8804},
4014ac975e2SDavid du Colombier {L"lfloor", 8970},
4024ac975e2SDavid du Colombier {L"lowast", 8727},
4034ac975e2SDavid du Colombier {L"loz", 9674},
4044ac975e2SDavid du Colombier {L"lrm", 8206},
4054ac975e2SDavid du Colombier {L"lsaquo", 8249},
4064ac975e2SDavid du Colombier {L"lsquo", 8216},
4079a747e4fSDavid du Colombier {L"lt", 60},
4089a747e4fSDavid du Colombier {L"macr", 175},
4099027b8f7SDavid du Colombier {L"mdash", 8212},
4109a747e4fSDavid du Colombier {L"micro", 181},
4119a747e4fSDavid du Colombier {L"middot", 183},
4124ac975e2SDavid du Colombier {L"minus", 8722},
4139a747e4fSDavid du Colombier {L"mu", 956},
4144ac975e2SDavid du Colombier {L"nabla", 8711},
4159a747e4fSDavid du Colombier {L"nbsp", 160},
4169027b8f7SDavid du Colombier {L"ndash", 8211},
4174ac975e2SDavid du Colombier {L"ne", 8800},
4184ac975e2SDavid du Colombier {L"ni", 8715},
4199a747e4fSDavid du Colombier {L"not", 172},
4204ac975e2SDavid du Colombier {L"notin", 8713},
4214ac975e2SDavid du Colombier {L"nsub", 8836},
4229a747e4fSDavid du Colombier {L"ntilde", 241},
4239a747e4fSDavid du Colombier {L"nu", 957},
4249a747e4fSDavid du Colombier {L"oacute", 243},
4259a747e4fSDavid du Colombier {L"ocirc", 244},
4264ac975e2SDavid du Colombier {L"oelig", 339},
4279a747e4fSDavid du Colombier {L"ograve", 242},
4284ac975e2SDavid du Colombier {L"oline", 8254},
4299a747e4fSDavid du Colombier {L"omega", 969},
4309a747e4fSDavid du Colombier {L"omicron", 959},
4314ac975e2SDavid du Colombier {L"oplus", 8853},
4324ac975e2SDavid du Colombier {L"or", 8744},
4339a747e4fSDavid du Colombier {L"ordf", 170},
4349a747e4fSDavid du Colombier {L"ordm", 186},
4359a747e4fSDavid du Colombier {L"oslash", 248},
4369a747e4fSDavid du Colombier {L"otilde", 245},
4374ac975e2SDavid du Colombier {L"otimes", 8855},
4389a747e4fSDavid du Colombier {L"ouml", 246},
4399a747e4fSDavid du Colombier {L"para", 182},
4404ac975e2SDavid du Colombier {L"part", 8706},
4414ac975e2SDavid du Colombier {L"permil", 8240},
4424ac975e2SDavid du Colombier {L"perp", 8869},
4439a747e4fSDavid du Colombier {L"phi", 966},
4449a747e4fSDavid du Colombier {L"pi", 960},
4454ac975e2SDavid du Colombier {L"piv", 982},
4469a747e4fSDavid du Colombier {L"plusmn", 177},
4479a747e4fSDavid du Colombier {L"pound", 163},
4484ac975e2SDavid du Colombier {L"prime", 8242},
4494ac975e2SDavid du Colombier {L"prod", 8719},
4504ac975e2SDavid du Colombier {L"prop", 8733},
4519a747e4fSDavid du Colombier {L"psi", 968},
4529a747e4fSDavid du Colombier {L"quad", 8193},
4539a747e4fSDavid du Colombier {L"quot", 34},
4544ac975e2SDavid du Colombier {L"rArr", 8658},
4554ac975e2SDavid du Colombier {L"radic", 8730},
4564ac975e2SDavid du Colombier {L"rang", 9002},
4579a747e4fSDavid du Colombier {L"raquo", 187},
4584ac975e2SDavid du Colombier {L"rarr", 8594},
4594ac975e2SDavid du Colombier {L"rceil", 8969},
4604ac975e2SDavid du Colombier {L"rdquo", 8221},
4614ac975e2SDavid du Colombier {L"real", 8476},
4629a747e4fSDavid du Colombier {L"reg", 174},
4634ac975e2SDavid du Colombier {L"rfloor", 8971},
4649a747e4fSDavid du Colombier {L"rho", 961},
4654ac975e2SDavid du Colombier {L"rlm", 8207},
4664ac975e2SDavid du Colombier {L"rsaquo", 8250},
4674ac975e2SDavid du Colombier {L"rsquo", 8217},
4684ac975e2SDavid du Colombier {L"sbquo", 8218},
4694ac975e2SDavid du Colombier {L"scaron", 353},
4704ac975e2SDavid du Colombier {L"sdot", 8901},
4719a747e4fSDavid du Colombier {L"sect", 167},
4729a747e4fSDavid du Colombier {L"shy", 173},
4739a747e4fSDavid du Colombier {L"sigma", 963},
4744ac975e2SDavid du Colombier {L"sigmaf", 962},
4754ac975e2SDavid du Colombier {L"sim", 8764},
4769a747e4fSDavid du Colombier {L"sp", 8194},
4774ac975e2SDavid du Colombier {L"spades", 9824},
4784ac975e2SDavid du Colombier {L"sub", 8834},
4794ac975e2SDavid du Colombier {L"sube", 8838},
4804ac975e2SDavid du Colombier {L"sum", 8721},
4814ac975e2SDavid du Colombier {L"sup", 8835},
4829a747e4fSDavid du Colombier {L"sup1", 185},
4839a747e4fSDavid du Colombier {L"sup2", 178},
4849a747e4fSDavid du Colombier {L"sup3", 179},
4854ac975e2SDavid du Colombier {L"supe", 8839},
4869a747e4fSDavid du Colombier {L"szlig", 223},
4879a747e4fSDavid du Colombier {L"tau", 964},
4884ac975e2SDavid du Colombier {L"there4", 8756},
4899a747e4fSDavid du Colombier {L"theta", 952},
4904ac975e2SDavid du Colombier {L"thetasym", 977},
4919a747e4fSDavid du Colombier {L"thinsp", 8201},
4929a747e4fSDavid du Colombier {L"thorn", 254},
4934ac975e2SDavid du Colombier {L"tilde", 732},
4949a747e4fSDavid du Colombier {L"times", 215},
4959a747e4fSDavid du Colombier {L"trade", 8482},
4964ac975e2SDavid du Colombier {L"uArr", 8657},
4979a747e4fSDavid du Colombier {L"uacute", 250},
4984ac975e2SDavid du Colombier {L"uarr", 8593},
4999a747e4fSDavid du Colombier {L"ucirc", 251},
5009a747e4fSDavid du Colombier {L"ugrave", 249},
5019a747e4fSDavid du Colombier {L"uml", 168},
5024ac975e2SDavid du Colombier {L"upsih", 978},
5039a747e4fSDavid du Colombier {L"upsilon", 965},
5049a747e4fSDavid du Colombier {L"uuml", 252},
5059a747e4fSDavid du Colombier {L"varepsilon", 8712},
5069a747e4fSDavid du Colombier {L"varphi", 981},
5079a747e4fSDavid du Colombier {L"varpi", 982},
5089a747e4fSDavid du Colombier {L"varrho", 1009},
5099a747e4fSDavid du Colombier {L"vdots", 8942},
5109a747e4fSDavid du Colombier {L"vsigma", 962},
5119a747e4fSDavid du Colombier {L"vtheta", 977},
5124ac975e2SDavid du Colombier {L"weierp", 8472},
5139a747e4fSDavid du Colombier {L"xi", 958},
5149a747e4fSDavid du Colombier {L"yacute", 253},
5159a747e4fSDavid du Colombier {L"yen", 165},
5169a747e4fSDavid du Colombier {L"yuml", 255},
5174ac975e2SDavid du Colombier {L"zeta", 950},
5184ac975e2SDavid du Colombier {L"zwj", 8205},
5194ac975e2SDavid du Colombier {L"zwnj", 8204}
5209a747e4fSDavid du Colombier };
5219a747e4fSDavid du Colombier #define NCHARTAB (sizeof(chartab)/sizeof(chartab[0]))
5229a747e4fSDavid du Colombier
5239a747e4fSDavid du Colombier // Characters Winstart..Winend are those that Windows
5249a747e4fSDavid du Colombier // uses interpolated into the Latin1 set.
5259a747e4fSDavid du Colombier // They aren't supposed to appear in HTML, but they do....
5269a747e4fSDavid du Colombier enum {
5279a747e4fSDavid du Colombier Winstart = 127,
5289a747e4fSDavid du Colombier Winend = 159
5299a747e4fSDavid du Colombier };
5309a747e4fSDavid du Colombier
5319a747e4fSDavid du Colombier static int winchars[]= { 8226, // 8226 is a bullet
5329a747e4fSDavid du Colombier 8226, 8226, 8218, 402, 8222, 8230, 8224, 8225,
5339a747e4fSDavid du Colombier 710, 8240, 352, 8249, 338, 8226, 8226, 8226,
5349a747e4fSDavid du Colombier 8226, 8216, 8217, 8220, 8221, 8226, 8211, 8212,
5359a747e4fSDavid du Colombier 732, 8482, 353, 8250, 339, 8226, 8226, 376};
5369a747e4fSDavid du Colombier
5379a747e4fSDavid du Colombier static StringInt* tagtable; // initialized from tagnames
5389a747e4fSDavid du Colombier static StringInt* attrtable; // initialized from attrnames
5399a747e4fSDavid du Colombier
540c93608ccSDavid du Colombier static void lexinit(void);
5419a747e4fSDavid du Colombier static int getplaindata(TokenSource* ts, Token* a, int* pai);
5429a747e4fSDavid du Colombier static int getdata(TokenSource* ts, int firstc, int starti, Token* a, int* pai);
543314a20f0SDavid du Colombier static int getscriptdata(TokenSource* ts, int firstc, int starti, Token* a, int* pai, int findtag);
5449a747e4fSDavid du Colombier static int gettag(TokenSource* ts, int starti, Token* a, int* pai);
5459a747e4fSDavid du Colombier static Rune* buftostr(Rune* s, Rune* buf, int j);
5469a747e4fSDavid du Colombier static int comment(TokenSource* ts);
5479a747e4fSDavid du Colombier static int findstr(TokenSource* ts, Rune* s);
5489a747e4fSDavid du Colombier static int ampersand(TokenSource* ts);
5499a747e4fSDavid du Colombier static int lowerc(int c);
5509a747e4fSDavid du Colombier static int getchar(TokenSource* ts);
5519a747e4fSDavid du Colombier static void ungetchar(TokenSource* ts, int c);
5529a747e4fSDavid du Colombier static void backup(TokenSource* ts, int savei);
5539a747e4fSDavid du Colombier static void freeinsidetoken(Token* t);
5549a747e4fSDavid du Colombier static void freeattrs(Attr* ahead);
5559a747e4fSDavid du Colombier static Attr* newattr(int attid, Rune* value, Attr* link);
5569a747e4fSDavid du Colombier static int Tconv(Fmt* f);
5579a747e4fSDavid du Colombier
5589a747e4fSDavid du Colombier int dbglex = 0;
5599a747e4fSDavid du Colombier static int lexinited = 0;
5609a747e4fSDavid du Colombier
5619a747e4fSDavid du Colombier static void
lexinit(void)5629a747e4fSDavid du Colombier lexinit(void)
5639a747e4fSDavid du Colombier {
5649a747e4fSDavid du Colombier tagtable = _makestrinttab(tagnames, Numtags);
5659a747e4fSDavid du Colombier attrtable = _makestrinttab(attrnames, Numattrs);
5669a747e4fSDavid du Colombier fmtinstall('T', Tconv);
5679a747e4fSDavid du Colombier lexinited = 1;
5689a747e4fSDavid du Colombier }
5699a747e4fSDavid du Colombier
5709a747e4fSDavid du Colombier static TokenSource*
newtokensource(uchar * data,int edata,int chset,int mtype)5719a747e4fSDavid du Colombier newtokensource(uchar* data, int edata, int chset, int mtype)
5729a747e4fSDavid du Colombier {
5739a747e4fSDavid du Colombier TokenSource* ans;
5749a747e4fSDavid du Colombier
5759a747e4fSDavid du Colombier assert(chset == US_Ascii || chset == ISO_8859_1 ||
5769a747e4fSDavid du Colombier chset == UTF_8 || chset == Unicode);
5779a747e4fSDavid du Colombier ans = (TokenSource*)emalloc(sizeof(TokenSource));
5789a747e4fSDavid du Colombier ans->i = 0;
5799a747e4fSDavid du Colombier ans->data = data;
5809a747e4fSDavid du Colombier ans->edata = edata;
5819a747e4fSDavid du Colombier ans->chset = chset;
5829a747e4fSDavid du Colombier ans->mtype = mtype;
5839a747e4fSDavid du Colombier return ans;
5849a747e4fSDavid du Colombier }
5859a747e4fSDavid du Colombier
5869a747e4fSDavid du Colombier enum {
587c93608ccSDavid du Colombier ToksChunk = 500,
5889a747e4fSDavid du Colombier };
5899a747e4fSDavid du Colombier
5909a747e4fSDavid du Colombier // Call this to get the tokens.
5919a747e4fSDavid du Colombier // The number of returned tokens is returned in *plen.
5929a747e4fSDavid du Colombier Token*
_gettoks(uchar * data,int datalen,int chset,int mtype,int * plen)5939a747e4fSDavid du Colombier _gettoks(uchar* data, int datalen, int chset, int mtype, int* plen)
5949a747e4fSDavid du Colombier {
5959a747e4fSDavid du Colombier TokenSource* ts;
5969a747e4fSDavid du Colombier Token* a;
5979a747e4fSDavid du Colombier int alen;
5989a747e4fSDavid du Colombier int ai;
5999a747e4fSDavid du Colombier int starti;
6009a747e4fSDavid du Colombier int c;
6019a747e4fSDavid du Colombier int tag;
6029a747e4fSDavid du Colombier
6039a747e4fSDavid du Colombier if(!lexinited)
6049a747e4fSDavid du Colombier lexinit();
6059a747e4fSDavid du Colombier ts = newtokensource(data, datalen, chset, mtype);
6069a747e4fSDavid du Colombier if(dbglex)
6079a747e4fSDavid du Colombier fprint(2, "_gettoks starts, ts.i=%d, ts.edata=%d\n", ts->i, ts->edata);
608c93608ccSDavid du Colombier alen = 0;
609c93608ccSDavid du Colombier ai = 0;
610c93608ccSDavid du Colombier a = 0;
6119a747e4fSDavid du Colombier if(ts->mtype == TextHtml) {
6129a747e4fSDavid du Colombier for(;;) {
613*edc15dd6SDavid du Colombier if(alen - ai < ToksChunk/32) {
6149a747e4fSDavid du Colombier alen += ToksChunk;
615c93608ccSDavid du Colombier a = erealloc(a, alen*sizeof *a);
6169a747e4fSDavid du Colombier }
6179a747e4fSDavid du Colombier starti = ts->i;
6189a747e4fSDavid du Colombier c = getchar(ts);
6199a747e4fSDavid du Colombier if(c < 0)
6209a747e4fSDavid du Colombier break;
6219a747e4fSDavid du Colombier if(c == '<') {
6229a747e4fSDavid du Colombier tag = gettag(ts, starti, a, &ai);
623314a20f0SDavid du Colombier if(tag == Tscript || tag == Tstyle) {
6249a747e4fSDavid du Colombier // special rules for getting Data after....
6259a747e4fSDavid du Colombier starti = ts->i;
6269a747e4fSDavid du Colombier c = getchar(ts);
627314a20f0SDavid du Colombier tag = getscriptdata(ts, c, starti, a, &ai, tag);
6289a747e4fSDavid du Colombier }
6299a747e4fSDavid du Colombier }
6309a747e4fSDavid du Colombier else
6319a747e4fSDavid du Colombier tag = getdata(ts, c, starti, a, &ai);
6329a747e4fSDavid du Colombier if(tag == -1)
6339a747e4fSDavid du Colombier break;
6349a747e4fSDavid du Colombier else if(dbglex > 1 && tag != Comment)
6359a747e4fSDavid du Colombier fprint(2, "lex: got token %T\n", &a[ai-1]);
6369a747e4fSDavid du Colombier }
6379a747e4fSDavid du Colombier }
6389a747e4fSDavid du Colombier else {
6399a747e4fSDavid du Colombier // plain text (non-html) tokens
6409a747e4fSDavid du Colombier for(;;) {
641*edc15dd6SDavid du Colombier if(alen - ai < ToksChunk/32) {
6429a747e4fSDavid du Colombier alen += ToksChunk;
643c93608ccSDavid du Colombier a = erealloc(a, alen*sizeof *a);
6449a747e4fSDavid du Colombier }
6459a747e4fSDavid du Colombier tag = getplaindata(ts, a, &ai);
6469a747e4fSDavid du Colombier if(tag == -1)
6479a747e4fSDavid du Colombier break;
6489a747e4fSDavid du Colombier if(dbglex > 1)
6499a747e4fSDavid du Colombier fprint(2, "lex: got token %T\n", &a[ai]);
6509a747e4fSDavid du Colombier }
6519a747e4fSDavid du Colombier }
652314a20f0SDavid du Colombier free(ts);
6539a747e4fSDavid du Colombier if(dbglex)
6549a747e4fSDavid du Colombier fprint(2, "lex: returning %d tokens\n", ai);
6559a747e4fSDavid du Colombier *plen = ai;
656c93608ccSDavid du Colombier if(ai == 0){
657c93608ccSDavid du Colombier free(a);
658c93608ccSDavid du Colombier a = 0;
659c93608ccSDavid du Colombier }
6609a747e4fSDavid du Colombier return a;
6619a747e4fSDavid du Colombier }
6629a747e4fSDavid du Colombier
6639a747e4fSDavid du Colombier // For case where source isn't HTML.
6649a747e4fSDavid du Colombier // Just make data tokens, one per line (or partial line,
6659a747e4fSDavid du Colombier // at end of buffer), ignoring non-whitespace control
6669a747e4fSDavid du Colombier // characters and dumping \r's.
6679a747e4fSDavid du Colombier // If find non-empty token, fill in a[*pai], bump *pai, and return Data.
6689a747e4fSDavid du Colombier // Otherwise return -1;
6699a747e4fSDavid du Colombier static int
getplaindata(TokenSource * ts,Token * a,int * pai)6709a747e4fSDavid du Colombier getplaindata(TokenSource* ts, Token* a, int* pai)
6719a747e4fSDavid du Colombier {
6729a747e4fSDavid du Colombier Rune* s;
6739a747e4fSDavid du Colombier int j;
6749a747e4fSDavid du Colombier int starti;
6759a747e4fSDavid du Colombier int c;
6769a747e4fSDavid du Colombier Token* tok;
6779a747e4fSDavid du Colombier Rune buf[BIGBUFSIZE];
6789a747e4fSDavid du Colombier
6799a747e4fSDavid du Colombier s = nil;
6809a747e4fSDavid du Colombier j = 0;
6819a747e4fSDavid du Colombier starti = ts->i;
6829a747e4fSDavid du Colombier for(c = getchar(ts); c >= 0; c = getchar(ts)) {
6839a747e4fSDavid du Colombier if(c < ' ') {
6849a747e4fSDavid du Colombier if(isspace(c)) {
6859a747e4fSDavid du Colombier if(c == '\r') {
6869a747e4fSDavid du Colombier // ignore it unless no following '\n',
6879a747e4fSDavid du Colombier // in which case treat it like '\n'
6889a747e4fSDavid du Colombier c = getchar(ts);
6899a747e4fSDavid du Colombier if(c != '\n') {
6909a747e4fSDavid du Colombier if(c >= 0)
6919a747e4fSDavid du Colombier ungetchar(ts, c);
6929a747e4fSDavid du Colombier c = '\n';
6939a747e4fSDavid du Colombier }
6949a747e4fSDavid du Colombier }
6959a747e4fSDavid du Colombier }
6969a747e4fSDavid du Colombier else
6979a747e4fSDavid du Colombier c = 0;
6989a747e4fSDavid du Colombier }
6999a747e4fSDavid du Colombier if(c != 0) {
7009a747e4fSDavid du Colombier buf[j++] = c;
701c93608ccSDavid du Colombier if(j == nelem(buf)-1) {
7029a747e4fSDavid du Colombier s = buftostr(s, buf, j);
7039a747e4fSDavid du Colombier j = 0;
7049a747e4fSDavid du Colombier }
7059a747e4fSDavid du Colombier }
7069a747e4fSDavid du Colombier if(c == '\n')
7079a747e4fSDavid du Colombier break;
7089a747e4fSDavid du Colombier }
7099a747e4fSDavid du Colombier s = buftostr(s, buf, j);
7109a747e4fSDavid du Colombier if(s == nil)
7119a747e4fSDavid du Colombier return -1;
7129a747e4fSDavid du Colombier tok = &a[(*pai)++];
7139a747e4fSDavid du Colombier tok->tag = Data;
7149a747e4fSDavid du Colombier tok->text = s;
7159a747e4fSDavid du Colombier tok->attr = nil;
7169a747e4fSDavid du Colombier tok->starti = starti;
7179a747e4fSDavid du Colombier return Data;
7189a747e4fSDavid du Colombier }
7199a747e4fSDavid du Colombier
7209a747e4fSDavid du Colombier // Return concatenation of s and buf[0:j]
7219a747e4fSDavid du Colombier static Rune*
buftostr(Rune * s,Rune * buf,int j)7229a747e4fSDavid du Colombier buftostr(Rune* s, Rune* buf, int j)
7239a747e4fSDavid du Colombier {
724c93608ccSDavid du Colombier int i;
725c93608ccSDavid du Colombier
7269a747e4fSDavid du Colombier if(s == nil)
7279a747e4fSDavid du Colombier s = _Strndup(buf, j);
728c93608ccSDavid du Colombier else {
729c93608ccSDavid du Colombier i = _Strlen(s);
730c93608ccSDavid du Colombier s = realloc(s, ( i+j+1)*sizeof *s);
731c93608ccSDavid du Colombier memcpy(&s[i], buf, j*sizeof *s);
732c93608ccSDavid du Colombier s[i+j] = 0;
733c93608ccSDavid du Colombier }
7349a747e4fSDavid du Colombier return s;
7359a747e4fSDavid du Colombier }
7369a747e4fSDavid du Colombier
7379a747e4fSDavid du Colombier // Gather data up to next start-of-tag or end-of-buffer.
7389a747e4fSDavid du Colombier // Translate entity references (&).
7399a747e4fSDavid du Colombier // Ignore non-whitespace control characters and get rid of \r's.
7409a747e4fSDavid du Colombier // If find non-empty token, fill in a[*pai], bump *pai, and return Data.
7419a747e4fSDavid du Colombier // Otherwise return -1;
7429a747e4fSDavid du Colombier static int
getdata(TokenSource * ts,int firstc,int starti,Token * a,int * pai)7439a747e4fSDavid du Colombier getdata(TokenSource* ts, int firstc, int starti, Token* a, int* pai)
7449a747e4fSDavid du Colombier {
7459a747e4fSDavid du Colombier Rune* s;
7469a747e4fSDavid du Colombier int j;
7479a747e4fSDavid du Colombier int c;
7489a747e4fSDavid du Colombier Token* tok;
749c93608ccSDavid du Colombier Rune buf[SMALLBUFSIZE];
7509a747e4fSDavid du Colombier
7519a747e4fSDavid du Colombier s = nil;
7529a747e4fSDavid du Colombier j = 0;
753c93608ccSDavid du Colombier for(c = firstc; c >= 0; c = getchar(ts)){
7549a747e4fSDavid du Colombier if(c == '&') {
7559a747e4fSDavid du Colombier c = ampersand(ts);
7569a747e4fSDavid du Colombier if(c < 0)
7579a747e4fSDavid du Colombier break;
7589a747e4fSDavid du Colombier }
7599a747e4fSDavid du Colombier else if(c < ' ') {
7609a747e4fSDavid du Colombier if(isspace(c)) {
7619a747e4fSDavid du Colombier if(c == '\r') {
7629a747e4fSDavid du Colombier // ignore it unless no following '\n',
7639a747e4fSDavid du Colombier // in which case treat it like '\n'
7649a747e4fSDavid du Colombier c = getchar(ts);
7659a747e4fSDavid du Colombier if(c != '\n') {
7669a747e4fSDavid du Colombier if(c >= 0)
7679a747e4fSDavid du Colombier ungetchar(ts, c);
7689a747e4fSDavid du Colombier c = '\n';
7699a747e4fSDavid du Colombier }
7709a747e4fSDavid du Colombier }
7719a747e4fSDavid du Colombier }
7729a747e4fSDavid du Colombier else {
7739a747e4fSDavid du Colombier if(warn)
7749a747e4fSDavid du Colombier fprint(2, "warning: non-whitespace control character %d ignored\n", c);
7759a747e4fSDavid du Colombier c = 0;
7769a747e4fSDavid du Colombier }
7779a747e4fSDavid du Colombier }
7789a747e4fSDavid du Colombier else if(c == '<') {
7799a747e4fSDavid du Colombier ungetchar(ts, c);
7809a747e4fSDavid du Colombier break;
7819a747e4fSDavid du Colombier }
7829a747e4fSDavid du Colombier if(c != 0) {
7839a747e4fSDavid du Colombier buf[j++] = c;
784c93608ccSDavid du Colombier if(j == nelem(buf)-1) {
7859a747e4fSDavid du Colombier s = buftostr(s, buf, j);
7869a747e4fSDavid du Colombier j = 0;
7879a747e4fSDavid du Colombier }
7889a747e4fSDavid du Colombier }
7899a747e4fSDavid du Colombier }
7909a747e4fSDavid du Colombier s = buftostr(s, buf, j);
7919a747e4fSDavid du Colombier if(s == nil)
7929a747e4fSDavid du Colombier return -1;
7939a747e4fSDavid du Colombier tok = &a[(*pai)++];
7949a747e4fSDavid du Colombier tok->tag = Data;
7959a747e4fSDavid du Colombier tok->text = s;
7969a747e4fSDavid du Colombier tok->attr = nil;
7979a747e4fSDavid du Colombier tok->starti = starti;
7989a747e4fSDavid du Colombier return Data;
7999a747e4fSDavid du Colombier }
8009a747e4fSDavid du Colombier
8019a747e4fSDavid du Colombier // The rules for lexing scripts are different (ugh).
802314a20f0SDavid du Colombier // Gather up everything until see an "</" tagnames[tok] ">"
8039a747e4fSDavid du Colombier static int
getscriptdata(TokenSource * ts,int firstc,int starti,Token * a,int * pai,int findtag)804314a20f0SDavid du Colombier getscriptdata(TokenSource* ts, int firstc, int starti, Token* a, int* pai, int findtag)
8059a747e4fSDavid du Colombier {
8069a747e4fSDavid du Colombier Rune* s;
8079a747e4fSDavid du Colombier int j;
8089a747e4fSDavid du Colombier int tstarti;
8099a747e4fSDavid du Colombier int savei;
8109a747e4fSDavid du Colombier int c;
8119a747e4fSDavid du Colombier int tag;
8129a747e4fSDavid du Colombier int done;
8139a747e4fSDavid du Colombier Token* tok;
8149a747e4fSDavid du Colombier Rune buf[BIGBUFSIZE];
8159a747e4fSDavid du Colombier
8169a747e4fSDavid du Colombier s = nil;
8179a747e4fSDavid du Colombier j = 0;
8189a747e4fSDavid du Colombier tstarti = starti;
8199a747e4fSDavid du Colombier c = firstc;
8209a747e4fSDavid du Colombier done = 0;
8219a747e4fSDavid du Colombier while(c >= 0) {
8229a747e4fSDavid du Colombier if(c == '<') {
8239a747e4fSDavid du Colombier // other browsers ignore stuff to end of line after <!
8249a747e4fSDavid du Colombier savei = ts->i;
8259a747e4fSDavid du Colombier c = getchar(ts);
8269a747e4fSDavid du Colombier if(c == '!') {
827314a20f0SDavid du Colombier if(comment(ts) == -1)
828314a20f0SDavid du Colombier break;
8299a747e4fSDavid du Colombier if(c == '\r')
8309a747e4fSDavid du Colombier c = getchar(ts);
8319a747e4fSDavid du Colombier if(c == '\n')
8329a747e4fSDavid du Colombier c = getchar(ts);
8339a747e4fSDavid du Colombier }
8349a747e4fSDavid du Colombier else if(c >= 0) {
8359a747e4fSDavid du Colombier backup(ts, savei);
8369a747e4fSDavid du Colombier tag = gettag(ts, tstarti, a, pai);
8379a747e4fSDavid du Colombier if(tag == -1)
8389a747e4fSDavid du Colombier break;
8399a747e4fSDavid du Colombier if(tag != Comment)
8409a747e4fSDavid du Colombier (*pai)--;
8419a747e4fSDavid du Colombier backup(ts, tstarti);
842314a20f0SDavid du Colombier if(tag == findtag + RBRA) {
8439a747e4fSDavid du Colombier done = 1;
8449a747e4fSDavid du Colombier break;
8459a747e4fSDavid du Colombier }
846314a20f0SDavid du Colombier // here tag was not the one we were looking for, so take as regular data
8479a747e4fSDavid du Colombier c = getchar(ts);
8489a747e4fSDavid du Colombier }
8499a747e4fSDavid du Colombier }
8509a747e4fSDavid du Colombier if(c < 0)
8519a747e4fSDavid du Colombier break;
8529a747e4fSDavid du Colombier if(c != 0) {
8539a747e4fSDavid du Colombier buf[j++] = c;
854c93608ccSDavid du Colombier if(j == nelem(buf)-1) {
8559a747e4fSDavid du Colombier s = buftostr(s, buf, j);
8569a747e4fSDavid du Colombier j = 0;
8579a747e4fSDavid du Colombier }
8589a747e4fSDavid du Colombier }
8599a747e4fSDavid du Colombier tstarti = ts->i;
8609a747e4fSDavid du Colombier c = getchar(ts);
8619a747e4fSDavid du Colombier }
8629a747e4fSDavid du Colombier if(done || ts->i == ts->edata) {
8639a747e4fSDavid du Colombier s = buftostr(s, buf, j);
8649a747e4fSDavid du Colombier tok = &a[(*pai)++];
8659a747e4fSDavid du Colombier tok->tag = Data;
8669a747e4fSDavid du Colombier tok->text = s;
8679a747e4fSDavid du Colombier tok->attr = nil;
8689a747e4fSDavid du Colombier tok->starti = starti;
8699a747e4fSDavid du Colombier return Data;
8709a747e4fSDavid du Colombier }
871c93608ccSDavid du Colombier free(s);
8729a747e4fSDavid du Colombier backup(ts, starti);
8739a747e4fSDavid du Colombier return -1;
8749a747e4fSDavid du Colombier }
8759a747e4fSDavid du Colombier
8769a747e4fSDavid du Colombier // We've just seen a '<'. Gather up stuff to closing '>' (if buffer
8779a747e4fSDavid du Colombier // ends before then, return -1).
8789a747e4fSDavid du Colombier // If it's a tag, look up the name, gather the attributes, and return
8799a747e4fSDavid du Colombier // the appropriate token.
8809a747e4fSDavid du Colombier // Else it's either just plain data or some kind of ignorable stuff:
8819a747e4fSDavid du Colombier // return Data or Comment as appropriate.
8829a747e4fSDavid du Colombier // If it's not a Comment, put it in a[*pai] and bump *pai.
8839a747e4fSDavid du Colombier static int
gettag(TokenSource * ts,int starti,Token * a,int * pai)8849a747e4fSDavid du Colombier gettag(TokenSource* ts, int starti, Token* a, int* pai)
8859a747e4fSDavid du Colombier {
8869a747e4fSDavid du Colombier int rbra;
8879a747e4fSDavid du Colombier int ans;
8889a747e4fSDavid du Colombier Attr* al;
8899a747e4fSDavid du Colombier int nexti;
8909a747e4fSDavid du Colombier int c;
8919a747e4fSDavid du Colombier int ti;
8929a747e4fSDavid du Colombier int afnd;
8939a747e4fSDavid du Colombier int attid;
8949a747e4fSDavid du Colombier int quote;
8959a747e4fSDavid du Colombier Rune* val;
8969a747e4fSDavid du Colombier int nv;
8979a747e4fSDavid du Colombier int i;
8989a747e4fSDavid du Colombier int tag;
8999a747e4fSDavid du Colombier Token* tok;
9009a747e4fSDavid du Colombier Rune buf[BIGBUFSIZE];
9019a747e4fSDavid du Colombier
9029a747e4fSDavid du Colombier rbra = 0;
9039a747e4fSDavid du Colombier nexti = ts->i;
9049a747e4fSDavid du Colombier tok = &a[*pai];
9059a747e4fSDavid du Colombier tok->tag = Notfound;
9069a747e4fSDavid du Colombier tok->text = nil;
9079a747e4fSDavid du Colombier tok->attr = nil;
9089a747e4fSDavid du Colombier tok->starti = starti;
9099a747e4fSDavid du Colombier c = getchar(ts);
9109a747e4fSDavid du Colombier if(c == '/') {
9119a747e4fSDavid du Colombier rbra = RBRA;
9129a747e4fSDavid du Colombier c = getchar(ts);
9139a747e4fSDavid du Colombier }
9149a747e4fSDavid du Colombier if(c < 0)
9159a747e4fSDavid du Colombier goto eob_done;
9169a747e4fSDavid du Colombier if(c >= 256 || !isalpha(c)) {
9179a747e4fSDavid du Colombier // not a tag
9189a747e4fSDavid du Colombier if(c == '!') {
9199a747e4fSDavid du Colombier ans = comment(ts);
9209a747e4fSDavid du Colombier if(ans != -1)
9219a747e4fSDavid du Colombier return ans;
9229a747e4fSDavid du Colombier goto eob_done;
9239a747e4fSDavid du Colombier }
9249a747e4fSDavid du Colombier else {
9259a747e4fSDavid du Colombier backup(ts, nexti);
9269a747e4fSDavid du Colombier tok->tag = Data;
9279a747e4fSDavid du Colombier tok->text = _Strdup(L"<");
9289a747e4fSDavid du Colombier (*pai)++;
9299a747e4fSDavid du Colombier return Data;
9309a747e4fSDavid du Colombier }
9319a747e4fSDavid du Colombier }
9329a747e4fSDavid du Colombier // c starts a tagname
9339a747e4fSDavid du Colombier buf[0] = c;
9349a747e4fSDavid du Colombier i = 1;
9359a747e4fSDavid du Colombier while(1) {
9369a747e4fSDavid du Colombier c = getchar(ts);
9379a747e4fSDavid du Colombier if(c < 0)
9389a747e4fSDavid du Colombier goto eob_done;
9399a747e4fSDavid du Colombier if(!ISNAMCHAR(c))
9409a747e4fSDavid du Colombier break;
9419a747e4fSDavid du Colombier // if name is bigger than buf it won't be found anyway...
9429a747e4fSDavid du Colombier if(i < BIGBUFSIZE)
9439a747e4fSDavid du Colombier buf[i++] = c;
9449a747e4fSDavid du Colombier }
9459a747e4fSDavid du Colombier if(_lookup(tagtable, Numtags, buf, i, &tag))
9469a747e4fSDavid du Colombier tok->tag = tag + rbra;
9479a747e4fSDavid du Colombier else
9489a747e4fSDavid du Colombier tok->text = _Strndup(buf, i); // for warning print, in build
9499a747e4fSDavid du Colombier // attribute gathering loop
9509a747e4fSDavid du Colombier al = nil;
9519a747e4fSDavid du Colombier while(1) {
9529a747e4fSDavid du Colombier // look for "ws name" or "ws name ws = ws val" (ws=whitespace)
9539a747e4fSDavid du Colombier // skip whitespace
9549a747e4fSDavid du Colombier attrloop_continue:
9559a747e4fSDavid du Colombier while(c < 256 && isspace(c)) {
9569a747e4fSDavid du Colombier c = getchar(ts);
9579a747e4fSDavid du Colombier if(c < 0)
9589a747e4fSDavid du Colombier goto eob_done;
9599a747e4fSDavid du Colombier }
9609a747e4fSDavid du Colombier if(c == '>')
9619a747e4fSDavid du Colombier goto attrloop_done;
9629a747e4fSDavid du Colombier if(c == '<') {
9639a747e4fSDavid du Colombier if(warn)
9649a747e4fSDavid du Colombier fprint(2, "warning: unclosed tag\n");
9659a747e4fSDavid du Colombier ungetchar(ts, c);
9669a747e4fSDavid du Colombier goto attrloop_done;
9679a747e4fSDavid du Colombier }
9689a747e4fSDavid du Colombier if(c >= 256 || !isalpha(c)) {
9699a747e4fSDavid du Colombier if(warn)
9709a747e4fSDavid du Colombier fprint(2, "warning: expected attribute name\n");
9719a747e4fSDavid du Colombier // skipt to next attribute name
9729a747e4fSDavid du Colombier while(1) {
9739a747e4fSDavid du Colombier c = getchar(ts);
9749a747e4fSDavid du Colombier if(c < 0)
9759a747e4fSDavid du Colombier goto eob_done;
9769a747e4fSDavid du Colombier if(c < 256 && isalpha(c))
9779a747e4fSDavid du Colombier goto attrloop_continue;
9789a747e4fSDavid du Colombier if(c == '<') {
9799a747e4fSDavid du Colombier if(warn)
9809a747e4fSDavid du Colombier fprint(2, "warning: unclosed tag\n");
9819a747e4fSDavid du Colombier ungetchar(ts, 60);
9829a747e4fSDavid du Colombier goto attrloop_done;
9839a747e4fSDavid du Colombier }
9849a747e4fSDavid du Colombier if(c == '>')
9859a747e4fSDavid du Colombier goto attrloop_done;
9869a747e4fSDavid du Colombier }
9879a747e4fSDavid du Colombier }
9889a747e4fSDavid du Colombier // gather attribute name
9899a747e4fSDavid du Colombier buf[0] = c;
9909a747e4fSDavid du Colombier i = 1;
9919a747e4fSDavid du Colombier while(1) {
9929a747e4fSDavid du Colombier c = getchar(ts);
9939a747e4fSDavid du Colombier if(c < 0)
9949a747e4fSDavid du Colombier goto eob_done;
9959a747e4fSDavid du Colombier if(!ISNAMCHAR(c))
9969a747e4fSDavid du Colombier break;
9979a747e4fSDavid du Colombier if(i < BIGBUFSIZE-1)
9989a747e4fSDavid du Colombier buf[i++] = c;
9999a747e4fSDavid du Colombier }
10009a747e4fSDavid du Colombier afnd = _lookup(attrtable, Numattrs, buf, i, &attid);
10019a747e4fSDavid du Colombier if(warn && !afnd) {
10029a747e4fSDavid du Colombier buf[i] = 0;
10039a747e4fSDavid du Colombier fprint(2, "warning: unknown attribute name %S\n", buf);
10049a747e4fSDavid du Colombier }
10059a747e4fSDavid du Colombier // skip whitespace
10069a747e4fSDavid du Colombier while(c < 256 && isspace(c)) {
10079a747e4fSDavid du Colombier c = getchar(ts);
10089a747e4fSDavid du Colombier if(c < 0)
10099a747e4fSDavid du Colombier goto eob_done;
10109a747e4fSDavid du Colombier }
10119a747e4fSDavid du Colombier if(c != '=') {
10129a747e4fSDavid du Colombier if(afnd)
10139a747e4fSDavid du Colombier al = newattr(attid, nil, al);
10149a747e4fSDavid du Colombier goto attrloop_continue;
10159a747e4fSDavid du Colombier }
10169a747e4fSDavid du Colombier //# c is '=' here; skip whitespace
10179a747e4fSDavid du Colombier while(1) {
10189a747e4fSDavid du Colombier c = getchar(ts);
10199a747e4fSDavid du Colombier if(c < 0)
10209a747e4fSDavid du Colombier goto eob_done;
10219a747e4fSDavid du Colombier if(c >= 256 || !isspace(c))
10229a747e4fSDavid du Colombier break;
10239a747e4fSDavid du Colombier }
10249a747e4fSDavid du Colombier quote = 0;
10259a747e4fSDavid du Colombier if(c == '\'' || c == '"') {
10269a747e4fSDavid du Colombier quote = c;
10279a747e4fSDavid du Colombier c = getchar(ts);
10289a747e4fSDavid du Colombier if(c < 0)
10299a747e4fSDavid du Colombier goto eob_done;
10309a747e4fSDavid du Colombier }
10319a747e4fSDavid du Colombier val = nil;
10329a747e4fSDavid du Colombier nv = 0;
10339a747e4fSDavid du Colombier while(1) {
10349a747e4fSDavid du Colombier valloop_continue:
10359a747e4fSDavid du Colombier if(c < 0)
10369a747e4fSDavid du Colombier goto eob_done;
10379a747e4fSDavid du Colombier if(c == '>') {
10389a747e4fSDavid du Colombier if(quote) {
10399a747e4fSDavid du Colombier // c might be part of string (though not good style)
10409a747e4fSDavid du Colombier // but if line ends before close quote, assume
10419a747e4fSDavid du Colombier // there was an unmatched quote
10429a747e4fSDavid du Colombier ti = ts->i;
10439a747e4fSDavid du Colombier while(1) {
10449a747e4fSDavid du Colombier c = getchar(ts);
10459a747e4fSDavid du Colombier if(c < 0)
10469a747e4fSDavid du Colombier goto eob_done;
10479a747e4fSDavid du Colombier if(c == quote) {
10489a747e4fSDavid du Colombier backup(ts, ti);
10499a747e4fSDavid du Colombier buf[nv++] = '>';
10509a747e4fSDavid du Colombier if(nv == BIGBUFSIZE-1) {
10519a747e4fSDavid du Colombier val = buftostr(val, buf, nv);
10529a747e4fSDavid du Colombier nv = 0;
10539a747e4fSDavid du Colombier }
10549a747e4fSDavid du Colombier c = getchar(ts);
10559a747e4fSDavid du Colombier goto valloop_continue;
10569a747e4fSDavid du Colombier }
10579a747e4fSDavid du Colombier if(c == '\n') {
10589a747e4fSDavid du Colombier if(warn)
10599a747e4fSDavid du Colombier fprint(2, "warning: apparent unmatched quote\n");
10609a747e4fSDavid du Colombier backup(ts, ti);
10619a747e4fSDavid du Colombier c = '>';
10629a747e4fSDavid du Colombier goto valloop_done;
10639a747e4fSDavid du Colombier }
10649a747e4fSDavid du Colombier }
10659a747e4fSDavid du Colombier }
10669a747e4fSDavid du Colombier else
10679a747e4fSDavid du Colombier goto valloop_done;
10689a747e4fSDavid du Colombier }
10699a747e4fSDavid du Colombier if(quote) {
10709a747e4fSDavid du Colombier if(c == quote) {
10719a747e4fSDavid du Colombier c = getchar(ts);
10729a747e4fSDavid du Colombier if(c < 0)
10739a747e4fSDavid du Colombier goto eob_done;
10749a747e4fSDavid du Colombier goto valloop_done;
10759a747e4fSDavid du Colombier }
10769a747e4fSDavid du Colombier if(c == '\r') {
10779a747e4fSDavid du Colombier c = getchar(ts);
10789a747e4fSDavid du Colombier goto valloop_continue;
10799a747e4fSDavid du Colombier }
10809a747e4fSDavid du Colombier if(c == '\t' || c == '\n')
10819a747e4fSDavid du Colombier c = ' ';
10829a747e4fSDavid du Colombier }
10839a747e4fSDavid du Colombier else {
10849a747e4fSDavid du Colombier if(c < 256 && isspace(c))
10859a747e4fSDavid du Colombier goto valloop_done;
10869a747e4fSDavid du Colombier }
10879a747e4fSDavid du Colombier if(c == '&') {
10889a747e4fSDavid du Colombier c = ampersand(ts);
10899a747e4fSDavid du Colombier if(c == -1)
10909a747e4fSDavid du Colombier goto eob_done;
10919a747e4fSDavid du Colombier }
10929a747e4fSDavid du Colombier buf[nv++] = c;
10939a747e4fSDavid du Colombier if(nv == BIGBUFSIZE-1) {
10949a747e4fSDavid du Colombier val = buftostr(val, buf, nv);
10959a747e4fSDavid du Colombier nv = 0;
10969a747e4fSDavid du Colombier }
10979a747e4fSDavid du Colombier c = getchar(ts);
10989a747e4fSDavid du Colombier }
10999a747e4fSDavid du Colombier valloop_done:
11009a747e4fSDavid du Colombier if(afnd) {
11019a747e4fSDavid du Colombier val = buftostr(val, buf, nv);
11029a747e4fSDavid du Colombier al = newattr(attid, val, al);
11039a747e4fSDavid du Colombier }
11049a747e4fSDavid du Colombier }
11059a747e4fSDavid du Colombier
11069a747e4fSDavid du Colombier attrloop_done:
11079a747e4fSDavid du Colombier tok->attr = al;
11089a747e4fSDavid du Colombier (*pai)++;
11099a747e4fSDavid du Colombier return tok->tag;
11109a747e4fSDavid du Colombier
11119a747e4fSDavid du Colombier eob_done:
11129a747e4fSDavid du Colombier if(warn)
11139a747e4fSDavid du Colombier fprint(2, "warning: incomplete tag at end of page\n");
11149a747e4fSDavid du Colombier backup(ts, nexti);
11159a747e4fSDavid du Colombier tok->tag = Data;
11169a747e4fSDavid du Colombier tok->text = _Strdup(L"<");
11179a747e4fSDavid du Colombier return Data;
11189a747e4fSDavid du Colombier }
11199a747e4fSDavid du Colombier
11209a747e4fSDavid du Colombier // We've just read a '<!' at position starti,
11219a747e4fSDavid du Colombier // so this may be a comment or other ignored section, or it may
11229a747e4fSDavid du Colombier // be just a literal string if there is no close before end of file
11239a747e4fSDavid du Colombier // (other browsers do that).
11249a747e4fSDavid du Colombier // The accepted practice seems to be (note: contrary to SGML spec!):
11259a747e4fSDavid du Colombier // If see <!--, look for --> to close, or if none, > to close.
11269a747e4fSDavid du Colombier // If see <!(not --), look for > to close.
11279a747e4fSDavid du Colombier // If no close before end of file, leave original characters in as literal data.
11289a747e4fSDavid du Colombier //
11299a747e4fSDavid du Colombier // If we see ignorable stuff, return Comment.
11309a747e4fSDavid du Colombier // Else return nil (caller should back up and try again when more data arrives,
11319a747e4fSDavid du Colombier // unless at end of file, in which case caller should just make '<' a data token).
11329a747e4fSDavid du Colombier static int
comment(TokenSource * ts)11339a747e4fSDavid du Colombier comment(TokenSource* ts)
11349a747e4fSDavid du Colombier {
11359a747e4fSDavid du Colombier int nexti;
11369a747e4fSDavid du Colombier int havecomment;
11379a747e4fSDavid du Colombier int c;
11389a747e4fSDavid du Colombier
11399a747e4fSDavid du Colombier nexti = ts->i;
11409a747e4fSDavid du Colombier havecomment = 0;
11419a747e4fSDavid du Colombier c = getchar(ts);
11429a747e4fSDavid du Colombier if(c == '-') {
11439a747e4fSDavid du Colombier c = getchar(ts);
11449a747e4fSDavid du Colombier if(c == '-') {
11459a747e4fSDavid du Colombier if(findstr(ts, L"-->"))
11469a747e4fSDavid du Colombier havecomment = 1;
11479a747e4fSDavid du Colombier else
11489a747e4fSDavid du Colombier backup(ts, nexti);
11499a747e4fSDavid du Colombier }
11509a747e4fSDavid du Colombier }
11519a747e4fSDavid du Colombier if(!havecomment) {
11529a747e4fSDavid du Colombier if(c == '>')
11539a747e4fSDavid du Colombier havecomment = 1;
11549a747e4fSDavid du Colombier else if(c >= 0) {
11559a747e4fSDavid du Colombier if(findstr(ts, L">"))
11569a747e4fSDavid du Colombier havecomment = 1;
11579a747e4fSDavid du Colombier }
11589a747e4fSDavid du Colombier }
11599a747e4fSDavid du Colombier if(havecomment)
11609a747e4fSDavid du Colombier return Comment;
11619a747e4fSDavid du Colombier return -1;
11629a747e4fSDavid du Colombier }
11639a747e4fSDavid du Colombier
11649a747e4fSDavid du Colombier // Look for string s in token source.
11659a747e4fSDavid du Colombier // If found, return 1, with buffer at next char after s,
11669a747e4fSDavid du Colombier // else return 0 (caller should back up).
11679a747e4fSDavid du Colombier static int
findstr(TokenSource * ts,Rune * s)11689a747e4fSDavid du Colombier findstr(TokenSource* ts, Rune* s)
11699a747e4fSDavid du Colombier {
11709a747e4fSDavid du Colombier int c0;
11719a747e4fSDavid du Colombier int n;
11729a747e4fSDavid du Colombier int nexti;
11739a747e4fSDavid du Colombier int i;
11749a747e4fSDavid du Colombier int c;
11759a747e4fSDavid du Colombier
11769a747e4fSDavid du Colombier c0 = s[0];
11779a747e4fSDavid du Colombier n = runestrlen(s);
11789a747e4fSDavid du Colombier while(1) {
11799a747e4fSDavid du Colombier c = getchar(ts);
11809a747e4fSDavid du Colombier if(c < 0)
11819a747e4fSDavid du Colombier break;
11829a747e4fSDavid du Colombier if(c == c0) {
11839a747e4fSDavid du Colombier if(n == 1)
11849a747e4fSDavid du Colombier return 1;
11859a747e4fSDavid du Colombier nexti = ts->i;
11869a747e4fSDavid du Colombier for(i = 1; i < n; i++) {
11879a747e4fSDavid du Colombier c = getchar(ts);
11889a747e4fSDavid du Colombier if(c < 0)
11899a747e4fSDavid du Colombier goto mainloop_done;
11909a747e4fSDavid du Colombier if(c != s[i])
11919a747e4fSDavid du Colombier break;
11929a747e4fSDavid du Colombier }
11939a747e4fSDavid du Colombier if(i == n)
11949a747e4fSDavid du Colombier return 1;
11959a747e4fSDavid du Colombier backup(ts, nexti);
11969a747e4fSDavid du Colombier }
11979a747e4fSDavid du Colombier }
11989a747e4fSDavid du Colombier mainloop_done:
11999a747e4fSDavid du Colombier return 0;
12009a747e4fSDavid du Colombier }
12019a747e4fSDavid du Colombier
12029a747e4fSDavid du Colombier // We've just read an '&'; look for an entity reference
12039a747e4fSDavid du Colombier // name, and if found, return translated char.
12049a747e4fSDavid du Colombier // if there is a complete entity name but it isn't known,
1205314a20f0SDavid du Colombier // back up to just past the '&' and return '&'.
12069a747e4fSDavid du Colombier // If the entity can't be completed in the current buffer, back up
12079a747e4fSDavid du Colombier // to the '&' and return -1.
12089a747e4fSDavid du Colombier static int
ampersand(TokenSource * ts)12099a747e4fSDavid du Colombier ampersand(TokenSource* ts)
12109a747e4fSDavid du Colombier {
12119a747e4fSDavid du Colombier int savei;
12129a747e4fSDavid du Colombier int c;
12139a747e4fSDavid du Colombier int fnd;
12149a747e4fSDavid du Colombier int ans;
12159a747e4fSDavid du Colombier int v;
12169a747e4fSDavid du Colombier int k;
1217c93608ccSDavid du Colombier Rune buf[25];
12189a747e4fSDavid du Colombier
12199a747e4fSDavid du Colombier savei = ts->i;
12209a747e4fSDavid du Colombier c = getchar(ts);
12219a747e4fSDavid du Colombier fnd = 0;
12229a747e4fSDavid du Colombier ans = -1;
12239a747e4fSDavid du Colombier if(c == '#') {
12249a747e4fSDavid du Colombier c = getchar(ts);
12259a747e4fSDavid du Colombier v = 0;
1226314a20f0SDavid du Colombier if(c == 'X' || c == 'x')
1227314a20f0SDavid du Colombier for(c = getchar(ts); c < 256; c = getchar(ts))
1228314a20f0SDavid du Colombier if(c >= '0' && c <= '9')
1229314a20f0SDavid du Colombier v = v*16+c-'0';
1230314a20f0SDavid du Colombier else if(c >= 'A' && c<= 'F')
1231314a20f0SDavid du Colombier v = v*16+c-'A'+10;
1232314a20f0SDavid du Colombier else if(c >= 'a' && c <= 'f')
1233314a20f0SDavid du Colombier v = v*16+c-'a'+10;
1234314a20f0SDavid du Colombier else
1235314a20f0SDavid du Colombier break;
1236314a20f0SDavid du Colombier else
12379a747e4fSDavid du Colombier while(c >= 0) {
12389a747e4fSDavid du Colombier if(!(c < 256 && isdigit(c)))
12399a747e4fSDavid du Colombier break;
12409a747e4fSDavid du Colombier v = v*10 + c - 48;
12419a747e4fSDavid du Colombier c = getchar(ts);
12429a747e4fSDavid du Colombier }
12439a747e4fSDavid du Colombier if(c >= 0) {
12449a747e4fSDavid du Colombier if(!(c == ';' || c == '\n' || c == '\r'))
12459a747e4fSDavid du Colombier ungetchar(ts, c);
12469a747e4fSDavid du Colombier c = v;
12479a747e4fSDavid du Colombier if(c == 160)
12489a747e4fSDavid du Colombier c = 160;
12499a747e4fSDavid du Colombier if(c >= Winstart && c <= Winend) {
12509a747e4fSDavid du Colombier c = winchars[c - Winstart];
12519a747e4fSDavid du Colombier }
12529a747e4fSDavid du Colombier ans = c;
12539a747e4fSDavid du Colombier fnd = 1;
12549a747e4fSDavid du Colombier }
12559a747e4fSDavid du Colombier }
12569a747e4fSDavid du Colombier else if(c < 256 && isalpha(c)) {
12579a747e4fSDavid du Colombier buf[0] = c;
12589a747e4fSDavid du Colombier k = 1;
12599a747e4fSDavid du Colombier while(1) {
12609a747e4fSDavid du Colombier c = getchar(ts);
12619a747e4fSDavid du Colombier if(c < 0)
12629a747e4fSDavid du Colombier break;
1263314a20f0SDavid du Colombier if(c < 256 && (isalpha(c) || isdigit(c))) {
1264c93608ccSDavid du Colombier if(k < nelem(buf)-1)
12659a747e4fSDavid du Colombier buf[k++] = c;
12669a747e4fSDavid du Colombier }
12679a747e4fSDavid du Colombier else {
12689a747e4fSDavid du Colombier if(!(c == ';' || c == '\n' || c == '\r'))
12699a747e4fSDavid du Colombier ungetchar(ts, c);
12709a747e4fSDavid du Colombier break;
12719a747e4fSDavid du Colombier }
12729a747e4fSDavid du Colombier }
1273314a20f0SDavid du Colombier if(c >= 256 || c != '=' && !(isalpha(c) || isdigit(c)))
12749a747e4fSDavid du Colombier fnd = _lookup(chartab, NCHARTAB, buf, k, &ans);
12759a747e4fSDavid du Colombier }
12769a747e4fSDavid du Colombier if(!fnd) {
12779a747e4fSDavid du Colombier backup(ts, savei);
12789a747e4fSDavid du Colombier ans = '&';
12799a747e4fSDavid du Colombier }
12809a747e4fSDavid du Colombier return ans;
12819a747e4fSDavid du Colombier }
12829a747e4fSDavid du Colombier
12839a747e4fSDavid du Colombier // Get next char, obeying ts.chset.
12849a747e4fSDavid du Colombier // Returns -1 if no complete character left before current end of data.
12859a747e4fSDavid du Colombier static int
getchar(TokenSource * ts)12869a747e4fSDavid du Colombier getchar(TokenSource* ts)
12879a747e4fSDavid du Colombier {
12889a747e4fSDavid du Colombier uchar* buf;
12899a747e4fSDavid du Colombier int c;
12909a747e4fSDavid du Colombier int n;
12919a747e4fSDavid du Colombier int ok;
12929a747e4fSDavid du Colombier Rune r;
12939a747e4fSDavid du Colombier
12949a747e4fSDavid du Colombier if(ts->i >= ts->edata)
12959a747e4fSDavid du Colombier return -1;
12969a747e4fSDavid du Colombier buf = ts->data;
12979a747e4fSDavid du Colombier c = buf[ts->i];
12989a747e4fSDavid du Colombier switch(ts->chset) {
12999a747e4fSDavid du Colombier case ISO_8859_1:
13009a747e4fSDavid du Colombier if(c >= Winstart && c <= Winend)
13019a747e4fSDavid du Colombier c = winchars[c - Winstart];
13029a747e4fSDavid du Colombier ts->i++;
13039a747e4fSDavid du Colombier break;
13049a747e4fSDavid du Colombier case US_Ascii:
13059a747e4fSDavid du Colombier if(c > 127) {
13069a747e4fSDavid du Colombier if(warn)
13079a747e4fSDavid du Colombier fprint(2, "non-ascii char (%x) when US-ASCII specified\n", c);
13089a747e4fSDavid du Colombier }
13099a747e4fSDavid du Colombier ts->i++;
13109a747e4fSDavid du Colombier break;
13119a747e4fSDavid du Colombier case UTF_8:
13129a747e4fSDavid du Colombier ok = fullrune((char*)(buf+ts->i), ts->edata-ts->i);
13139a747e4fSDavid du Colombier n = chartorune(&r, (char*)(buf+ts->i));
13149a747e4fSDavid du Colombier if(ok) {
13159a747e4fSDavid du Colombier if(warn && c == 0x80)
13169a747e4fSDavid du Colombier fprint(2, "warning: invalid utf-8 sequence (starts with %x)\n", ts->data[ts->i]);
13179a747e4fSDavid du Colombier ts->i += n;
13189a747e4fSDavid du Colombier c = r;
13199a747e4fSDavid du Colombier }
13209a747e4fSDavid du Colombier else {
13219a747e4fSDavid du Colombier // not enough bytes in buf to complete utf-8 char
13229a747e4fSDavid du Colombier ts->i = ts->edata; // mark "all used"
13239a747e4fSDavid du Colombier c = -1;
13249a747e4fSDavid du Colombier }
13259a747e4fSDavid du Colombier break;
13269a747e4fSDavid du Colombier case Unicode:
13279a747e4fSDavid du Colombier if(ts->i < ts->edata - 1) {
13289a747e4fSDavid du Colombier //standards say most-significant byte first
13299a747e4fSDavid du Colombier c = (c << 8)|(buf[ts->i + 1]);
13309a747e4fSDavid du Colombier ts->i += 2;
13319a747e4fSDavid du Colombier }
13329a747e4fSDavid du Colombier else {
13339a747e4fSDavid du Colombier ts->i = ts->edata; // mark "all used"
13349a747e4fSDavid du Colombier c = -1;
13359a747e4fSDavid du Colombier }
13369a747e4fSDavid du Colombier break;
1337*edc15dd6SDavid du Colombier default:
1338*edc15dd6SDavid du Colombier return -1;
13399a747e4fSDavid du Colombier }
13409a747e4fSDavid du Colombier return c;
13419a747e4fSDavid du Colombier }
13429a747e4fSDavid du Colombier
13439a747e4fSDavid du Colombier // Assuming c was the last character returned by getchar, set
13449a747e4fSDavid du Colombier // things up so that next getchar will get that same character
13459a747e4fSDavid du Colombier // followed by the current 'next character', etc.
13469a747e4fSDavid du Colombier static void
ungetchar(TokenSource * ts,int c)13479a747e4fSDavid du Colombier ungetchar(TokenSource* ts, int c)
13489a747e4fSDavid du Colombier {
13499a747e4fSDavid du Colombier int n;
13509a747e4fSDavid du Colombier Rune r;
13519a747e4fSDavid du Colombier char a[UTFmax];
13529a747e4fSDavid du Colombier
13539a747e4fSDavid du Colombier n = 1;
13549a747e4fSDavid du Colombier switch(ts->chset) {
13559a747e4fSDavid du Colombier case UTF_8:
13569a747e4fSDavid du Colombier if(c >= 128) {
13579a747e4fSDavid du Colombier r = c;
13589a747e4fSDavid du Colombier n = runetochar(a, &r);
13599a747e4fSDavid du Colombier }
13609a747e4fSDavid du Colombier break;
13619a747e4fSDavid du Colombier case Unicode:
13629a747e4fSDavid du Colombier n = 2;
13639a747e4fSDavid du Colombier break;
13649a747e4fSDavid du Colombier }
13659a747e4fSDavid du Colombier ts->i -= n;
13669a747e4fSDavid du Colombier }
13679a747e4fSDavid du Colombier
13689a747e4fSDavid du Colombier // Restore ts so that it is at the state where the index was savei.
13699a747e4fSDavid du Colombier static void
backup(TokenSource * ts,int savei)13709a747e4fSDavid du Colombier backup(TokenSource* ts, int savei)
13719a747e4fSDavid du Colombier {
13729a747e4fSDavid du Colombier if(dbglex)
13739a747e4fSDavid du Colombier fprint(2, "lex: backup; i=%d, savei=%d\n", ts->i, savei);
13749a747e4fSDavid du Colombier ts->i = savei;
13759a747e4fSDavid du Colombier }
13769a747e4fSDavid du Colombier
13779a747e4fSDavid du Colombier
13789a747e4fSDavid du Colombier // Look for value associated with attribute attid in token t.
13799a747e4fSDavid du Colombier // If there is one, return 1 and put the value in *pans,
13809a747e4fSDavid du Colombier // else return 0.
13819a747e4fSDavid du Colombier // If xfer is true, transfer ownership of the string to the caller
13829a747e4fSDavid du Colombier // (nil it out here); otherwise, caller must duplicate the answer
13839a747e4fSDavid du Colombier // if it needs to save it.
13849a747e4fSDavid du Colombier // OK to have pans==0, in which case this is just looking
13859a747e4fSDavid du Colombier // to see if token is present.
13869a747e4fSDavid du Colombier int
_tokaval(Token * t,int attid,Rune ** pans,int xfer)13879a747e4fSDavid du Colombier _tokaval(Token* t, int attid, Rune** pans, int xfer)
13889a747e4fSDavid du Colombier {
13899a747e4fSDavid du Colombier Attr* attr;
13909a747e4fSDavid du Colombier
13919a747e4fSDavid du Colombier attr = t->attr;
13929a747e4fSDavid du Colombier while(attr != nil) {
13939a747e4fSDavid du Colombier if(attr->attid == attid) {
13949a747e4fSDavid du Colombier if(pans != nil)
13959a747e4fSDavid du Colombier *pans = attr->value;
13969a747e4fSDavid du Colombier if(xfer)
13979a747e4fSDavid du Colombier attr->value = nil;
13989a747e4fSDavid du Colombier return 1;
13999a747e4fSDavid du Colombier }
14009a747e4fSDavid du Colombier attr = attr->next;
14019a747e4fSDavid du Colombier }
14029a747e4fSDavid du Colombier if(pans != nil)
14039a747e4fSDavid du Colombier *pans = nil;
14049a747e4fSDavid du Colombier return 0;
14059a747e4fSDavid du Colombier }
14069a747e4fSDavid du Colombier
14079a747e4fSDavid du Colombier static int
Tconv(Fmt * f)14089a747e4fSDavid du Colombier Tconv(Fmt *f)
14099a747e4fSDavid du Colombier {
14109a747e4fSDavid du Colombier Token* t;
14119a747e4fSDavid du Colombier int i;
14129a747e4fSDavid du Colombier int tag;
14139a747e4fSDavid du Colombier char* srbra;
14149a747e4fSDavid du Colombier Rune* aname;
14159a747e4fSDavid du Colombier Rune* tname;
14169a747e4fSDavid du Colombier Attr* a;
14179a747e4fSDavid du Colombier char buf[BIGBUFSIZE];
14189a747e4fSDavid du Colombier
14199a747e4fSDavid du Colombier t = va_arg(f->args, Token*);
14209a747e4fSDavid du Colombier if(t == nil)
14219a747e4fSDavid du Colombier sprint(buf, "<null>");
14229a747e4fSDavid du Colombier else {
14239a747e4fSDavid du Colombier i = 0;
14249a747e4fSDavid du Colombier if(dbglex > 1)
14259a747e4fSDavid du Colombier i = snprint(buf, sizeof(buf), "[%d]", t->starti);
14269a747e4fSDavid du Colombier tag = t->tag;
14279a747e4fSDavid du Colombier if(tag == Data) {
14289a747e4fSDavid du Colombier i += snprint(buf+i, sizeof(buf)-i-1, "'%S'", t->text);
14299a747e4fSDavid du Colombier }
14309a747e4fSDavid du Colombier else {
14319a747e4fSDavid du Colombier srbra = "";
14329a747e4fSDavid du Colombier if(tag >= RBRA) {
14339a747e4fSDavid du Colombier tag -= RBRA;
14349a747e4fSDavid du Colombier srbra = "/";
14359a747e4fSDavid du Colombier }
14369a747e4fSDavid du Colombier tname = tagnames[tag];
14379a747e4fSDavid du Colombier if(tag == Notfound)
14389a747e4fSDavid du Colombier tname = L"?";
14399a747e4fSDavid du Colombier i += snprint(buf+i, sizeof(buf)-i-1, "<%s%S", srbra, tname);
14409a747e4fSDavid du Colombier for(a = t->attr; a != nil; a = a->next) {
14419a747e4fSDavid du Colombier aname = attrnames[a->attid];
14429a747e4fSDavid du Colombier i += snprint(buf+i, sizeof(buf)-i-1, " %S", aname);
14439a747e4fSDavid du Colombier if(a->value != nil)
14449a747e4fSDavid du Colombier i += snprint(buf+i, sizeof(buf)-i-1, "=%S", a->value);
14459a747e4fSDavid du Colombier }
14469a747e4fSDavid du Colombier i += snprint(buf+i, sizeof(buf)-i-1, ">");
14479a747e4fSDavid du Colombier }
14489a747e4fSDavid du Colombier buf[i] = 0;
14499a747e4fSDavid du Colombier }
14509a747e4fSDavid du Colombier return fmtstrcpy(f, buf);
14519a747e4fSDavid du Colombier }
14529a747e4fSDavid du Colombier
14539a747e4fSDavid du Colombier // Attrs own their constituent strings, but build may eventually
14549a747e4fSDavid du Colombier // transfer some values to its items and nil them out in the Attr.
14559a747e4fSDavid du Colombier static Attr*
newattr(int attid,Rune * value,Attr * link)14569a747e4fSDavid du Colombier newattr(int attid, Rune* value, Attr* link)
14579a747e4fSDavid du Colombier {
14589a747e4fSDavid du Colombier Attr* ans;
14599a747e4fSDavid du Colombier
14609a747e4fSDavid du Colombier ans = (Attr*)emalloc(sizeof(Attr));
14619a747e4fSDavid du Colombier ans->attid = attid;
14629a747e4fSDavid du Colombier ans->value = value;
14639a747e4fSDavid du Colombier ans->next = link;
14649a747e4fSDavid du Colombier return ans;
14659a747e4fSDavid du Colombier }
14669a747e4fSDavid du Colombier
14679a747e4fSDavid du Colombier // Free list of Attrs linked through next field
14689a747e4fSDavid du Colombier static void
freeattrs(Attr * ahead)14699a747e4fSDavid du Colombier freeattrs(Attr* ahead)
14709a747e4fSDavid du Colombier {
14719a747e4fSDavid du Colombier Attr* a;
14729a747e4fSDavid du Colombier Attr* nexta;
14739a747e4fSDavid du Colombier
14749a747e4fSDavid du Colombier a = ahead;
14759a747e4fSDavid du Colombier while(a != nil) {
14769a747e4fSDavid du Colombier nexta = a->next;
14779a747e4fSDavid du Colombier free(a->value);
14789a747e4fSDavid du Colombier free(a);
14799a747e4fSDavid du Colombier a = nexta;
14809a747e4fSDavid du Colombier }
14819a747e4fSDavid du Colombier }
14829a747e4fSDavid du Colombier
14839a747e4fSDavid du Colombier // Free array of Tokens.
14849a747e4fSDavid du Colombier // Allocated space might have room for more than n tokens,
14859a747e4fSDavid du Colombier // but only n of them are initialized.
14869a747e4fSDavid du Colombier // If caller has transferred ownership of constitutent strings
14879a747e4fSDavid du Colombier // or attributes, it must have nil'd out the pointers in the Tokens.
14889a747e4fSDavid du Colombier void
_freetokens(Token * tarray,int n)14899a747e4fSDavid du Colombier _freetokens(Token* tarray, int n)
14909a747e4fSDavid du Colombier {
14919a747e4fSDavid du Colombier int i;
14929a747e4fSDavid du Colombier Token* t;
14939a747e4fSDavid du Colombier
14949a747e4fSDavid du Colombier if(tarray == nil)
14959a747e4fSDavid du Colombier return;
14969a747e4fSDavid du Colombier for(i = 0; i < n; i++) {
14979a747e4fSDavid du Colombier t = &tarray[i];
14989a747e4fSDavid du Colombier free(t->text);
14999a747e4fSDavid du Colombier freeattrs(t->attr);
15009a747e4fSDavid du Colombier }
15019a747e4fSDavid du Colombier free(tarray);
15029a747e4fSDavid du Colombier }
1503