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 // A stack for holding integer values
99a747e4fSDavid du Colombier enum {
109a747e4fSDavid du Colombier Nestmax = 40 // max nesting level of lists, font styles, etc.
119a747e4fSDavid du Colombier };
129a747e4fSDavid du Colombier
139a747e4fSDavid du Colombier struct Stack {
149a747e4fSDavid du Colombier int n; // next available slot (top of stack is stack[n-1])
159a747e4fSDavid du Colombier int slots[Nestmax]; // stack entries
169a747e4fSDavid du Colombier };
179a747e4fSDavid du Colombier
189a747e4fSDavid du Colombier // Parsing state
199a747e4fSDavid du Colombier struct Pstate
209a747e4fSDavid du Colombier {
219a747e4fSDavid du Colombier Pstate* next; // in stack of Pstates
229a747e4fSDavid du Colombier int skipping; // true when we shouldn't add items
239a747e4fSDavid du Colombier int skipwhite; // true when we should strip leading space
249a747e4fSDavid du Colombier int curfont; // font index for current font
259a747e4fSDavid du Colombier int curfg; // current foreground color
269a747e4fSDavid du Colombier Background curbg; // current background
279a747e4fSDavid du Colombier int curvoff; // current baseline offset
289a747e4fSDavid du Colombier uchar curul; // current underline/strike state
299a747e4fSDavid du Colombier uchar curjust; // current justify state
309a747e4fSDavid du Colombier int curanchor; // current (href) anchor id (if in one), or 0
319a747e4fSDavid du Colombier int curstate; // current value of item state
329a747e4fSDavid du Colombier int literal; // current literal state
339a747e4fSDavid du Colombier int inpar; // true when in a paragraph-like construct
349a747e4fSDavid du Colombier int adjsize; // current font size adjustment
359a747e4fSDavid du Colombier Item* items; // dummy head of item list we're building
369a747e4fSDavid du Colombier Item* lastit; // tail of item list we're building
379a747e4fSDavid du Colombier Item* prelastit; // item before lastit
389a747e4fSDavid du Colombier Stack fntstylestk; // style stack
399a747e4fSDavid du Colombier Stack fntsizestk; // size stack
409a747e4fSDavid du Colombier Stack fgstk; // text color stack
419a747e4fSDavid du Colombier Stack ulstk; // underline stack
429a747e4fSDavid du Colombier Stack voffstk; // vertical offset stack
439a747e4fSDavid du Colombier Stack listtypestk; // list type stack
449a747e4fSDavid du Colombier Stack listcntstk; // list counter stack
459a747e4fSDavid du Colombier Stack juststk; // justification stack
469a747e4fSDavid du Colombier Stack hangstk; // hanging stack
479a747e4fSDavid du Colombier };
489a747e4fSDavid du Colombier
499a747e4fSDavid du Colombier struct ItemSource
509a747e4fSDavid du Colombier {
519a747e4fSDavid du Colombier Docinfo* doc;
529a747e4fSDavid du Colombier Pstate* psstk;
539a747e4fSDavid du Colombier int nforms;
549a747e4fSDavid du Colombier int ntables;
559a747e4fSDavid du Colombier int nanchors;
569a747e4fSDavid du Colombier int nframes;
579a747e4fSDavid du Colombier Form* curform;
589a747e4fSDavid du Colombier Map* curmap;
599a747e4fSDavid du Colombier Table* tabstk;
609a747e4fSDavid du Colombier Kidinfo* kidstk;
619a747e4fSDavid du Colombier };
629a747e4fSDavid du Colombier
639a747e4fSDavid du Colombier // Some layout parameters
649a747e4fSDavid du Colombier enum {
659a747e4fSDavid du Colombier FRKIDMARGIN = 6, // default margin around kid frames
669a747e4fSDavid du Colombier IMGHSPACE = 0, // default hspace for images (0 matches IE, Netscape)
679a747e4fSDavid du Colombier IMGVSPACE = 0, // default vspace for images
689a747e4fSDavid du Colombier FLTIMGHSPACE = 2, // default hspace for float images
699a747e4fSDavid du Colombier TABSP = 5, // default cellspacing for tables
709a747e4fSDavid du Colombier TABPAD = 1, // default cell padding for tables
719a747e4fSDavid du Colombier LISTTAB = 1, // number of tabs to indent lists
729a747e4fSDavid du Colombier BQTAB = 1, // number of tabs to indent blockquotes
739a747e4fSDavid du Colombier HRSZ = 2, // thickness of horizontal rules
749a747e4fSDavid du Colombier SUBOFF = 4, // vertical offset for subscripts
759a747e4fSDavid du Colombier SUPOFF = 6, // vertical offset for superscripts
769a747e4fSDavid du Colombier NBSP = 160 // non-breaking space character
779a747e4fSDavid du Colombier };
789a747e4fSDavid du Colombier
799a747e4fSDavid du Colombier // These tables must be sorted
809a747e4fSDavid du Colombier static StringInt align_tab[] = {
819a747e4fSDavid du Colombier {L"baseline", ALbaseline},
829a747e4fSDavid du Colombier {L"bottom", ALbottom},
839a747e4fSDavid du Colombier {L"center", ALcenter},
849a747e4fSDavid du Colombier {L"char", ALchar},
859a747e4fSDavid du Colombier {L"justify", ALjustify},
869a747e4fSDavid du Colombier {L"left", ALleft},
879a747e4fSDavid du Colombier {L"middle", ALmiddle},
889a747e4fSDavid du Colombier {L"right", ALright},
899a747e4fSDavid du Colombier {L"top", ALtop}
909a747e4fSDavid du Colombier };
919a747e4fSDavid du Colombier #define NALIGNTAB (sizeof(align_tab)/sizeof(StringInt))
929a747e4fSDavid du Colombier
939a747e4fSDavid du Colombier static StringInt input_tab[] = {
949a747e4fSDavid du Colombier {L"button", Fbutton},
959a747e4fSDavid du Colombier {L"checkbox", Fcheckbox},
969a747e4fSDavid du Colombier {L"file", Ffile},
979a747e4fSDavid du Colombier {L"hidden", Fhidden},
989a747e4fSDavid du Colombier {L"image", Fimage},
999a747e4fSDavid du Colombier {L"password", Fpassword},
1009a747e4fSDavid du Colombier {L"radio", Fradio},
1019a747e4fSDavid du Colombier {L"reset", Freset},
1029a747e4fSDavid du Colombier {L"submit", Fsubmit},
1039a747e4fSDavid du Colombier {L"text", Ftext}
1049a747e4fSDavid du Colombier };
1059a747e4fSDavid du Colombier #define NINPUTTAB (sizeof(input_tab)/sizeof(StringInt))
1069a747e4fSDavid du Colombier
1079a747e4fSDavid du Colombier static StringInt clear_tab[] = {
1089a747e4fSDavid du Colombier {L"all", IFcleft|IFcright},
1099a747e4fSDavid du Colombier {L"left", IFcleft},
1109a747e4fSDavid du Colombier {L"right", IFcright}
1119a747e4fSDavid du Colombier };
1129a747e4fSDavid du Colombier #define NCLEARTAB (sizeof(clear_tab)/sizeof(StringInt))
1139a747e4fSDavid du Colombier
1149a747e4fSDavid du Colombier static StringInt fscroll_tab[] = {
1159a747e4fSDavid du Colombier {L"auto", FRhscrollauto|FRvscrollauto},
1169a747e4fSDavid du Colombier {L"no", FRnoscroll},
1179a747e4fSDavid du Colombier {L"yes", FRhscroll|FRvscroll},
1189a747e4fSDavid du Colombier };
1199a747e4fSDavid du Colombier #define NFSCROLLTAB (sizeof(fscroll_tab)/sizeof(StringInt))
1209a747e4fSDavid du Colombier
1219a747e4fSDavid du Colombier static StringInt shape_tab[] = {
1229a747e4fSDavid du Colombier {L"circ", SHcircle},
1239a747e4fSDavid du Colombier {L"circle", SHcircle},
1249a747e4fSDavid du Colombier {L"poly", SHpoly},
1259a747e4fSDavid du Colombier {L"polygon", SHpoly},
1269a747e4fSDavid du Colombier {L"rect", SHrect},
1279a747e4fSDavid du Colombier {L"rectangle", SHrect}
1289a747e4fSDavid du Colombier };
1299a747e4fSDavid du Colombier #define NSHAPETAB (sizeof(shape_tab)/sizeof(StringInt))
1309a747e4fSDavid du Colombier
1319a747e4fSDavid du Colombier static StringInt method_tab[] = {
1329a747e4fSDavid du Colombier {L"get", HGet},
1339a747e4fSDavid du Colombier {L"post", HPost}
1349a747e4fSDavid du Colombier };
1359a747e4fSDavid du Colombier #define NMETHODTAB (sizeof(method_tab)/sizeof(StringInt))
1369a747e4fSDavid du Colombier
1379a747e4fSDavid du Colombier static Rune* roman[15]= {
1389a747e4fSDavid du Colombier L"I", L"II", L"III", L"IV", L"V", L"VI", L"VII", L"VIII", L"IX", L"X",
1399a747e4fSDavid du Colombier L"XI", L"XII", L"XIII", L"XIV", L"XV"
1409a747e4fSDavid du Colombier };
1419a747e4fSDavid du Colombier #define NROMAN 15
1429a747e4fSDavid du Colombier
1439a747e4fSDavid du Colombier // List number types
1449a747e4fSDavid du Colombier enum {
1459a747e4fSDavid du Colombier LTdisc, LTsquare, LTcircle, LT1, LTa, LTA, LTi, LTI
1469a747e4fSDavid du Colombier };
1479a747e4fSDavid du Colombier
1489a747e4fSDavid du Colombier enum {
1499a747e4fSDavid du Colombier SPBefore = 2,
1509a747e4fSDavid du Colombier SPAfter = 4,
1519a747e4fSDavid du Colombier BL = 1,
1529a747e4fSDavid du Colombier BLBA = (BL|SPBefore|SPAfter)
1539a747e4fSDavid du Colombier };
1549a747e4fSDavid du Colombier
1559a747e4fSDavid du Colombier // blockbrk[tag] is break info for a block level element, or one
1569a747e4fSDavid du Colombier // of a few others that get the same treatment re ending open paragraphs
1579a747e4fSDavid du Colombier // and requiring a line break / vertical space before them.
1589a747e4fSDavid du Colombier // If we want a line of space before the given element, SPBefore is OR'd in.
1599a747e4fSDavid du Colombier // If we want a line of space after the given element, SPAfter is OR'd in.
1609a747e4fSDavid du Colombier
1619a747e4fSDavid du Colombier static uchar blockbrk[Numtags]= {
1629a747e4fSDavid du Colombier [Taddress] BLBA, [Tblockquote] BLBA, [Tcenter] BL,
1639a747e4fSDavid du Colombier [Tdir] BLBA, [Tdiv] BL, [Tdd] BL, [Tdl] BLBA,
1649a747e4fSDavid du Colombier [Tdt] BL, [Tform] BLBA,
1659a747e4fSDavid du Colombier // headings and tables get breaks added manually
1669a747e4fSDavid du Colombier [Th1] BL, [Th2] BL, [Th3] BL,
1679a747e4fSDavid du Colombier [Th4] BL, [Th5] BL, [Th6] BL,
1689a747e4fSDavid du Colombier [Thr] BL, [Tisindex] BLBA, [Tli] BL, [Tmenu] BLBA,
1699a747e4fSDavid du Colombier [Tol] BLBA, [Tp] BLBA, [Tpre] BLBA,
1709a747e4fSDavid du Colombier [Tul] BLBA
1719a747e4fSDavid du Colombier };
1729a747e4fSDavid du Colombier
1739a747e4fSDavid du Colombier enum {
1749a747e4fSDavid du Colombier AGEN = 1
1759a747e4fSDavid du Colombier };
1769a747e4fSDavid du Colombier
1779a747e4fSDavid du Colombier // attrinfo is information about attributes.
1789a747e4fSDavid du Colombier // The AGEN value means that the attribute is generic (applies to almost all elements)
1799a747e4fSDavid du Colombier static uchar attrinfo[Numattrs]= {
1809a747e4fSDavid du Colombier [Aid] AGEN, [Aclass] AGEN, [Astyle] AGEN, [Atitle] AGEN,
1819a747e4fSDavid du Colombier [Aonblur] AGEN, [Aonchange] AGEN, [Aonclick] AGEN,
1829a747e4fSDavid du Colombier [Aondblclick] AGEN, [Aonfocus] AGEN, [Aonkeypress] AGEN,
1839a747e4fSDavid du Colombier [Aonkeyup] AGEN, [Aonload] AGEN, [Aonmousedown] AGEN,
1849a747e4fSDavid du Colombier [Aonmousemove] AGEN, [Aonmouseout] AGEN, [Aonmouseover] AGEN,
1859a747e4fSDavid du Colombier [Aonmouseup] AGEN, [Aonreset] AGEN, [Aonselect] AGEN,
1869a747e4fSDavid du Colombier [Aonsubmit] AGEN, [Aonunload] AGEN
1879a747e4fSDavid du Colombier };
1889a747e4fSDavid du Colombier
1899a747e4fSDavid du Colombier static uchar scriptev[Numattrs]= {
1909a747e4fSDavid du Colombier [Aonblur] SEonblur, [Aonchange] SEonchange, [Aonclick] SEonclick,
1919a747e4fSDavid du Colombier [Aondblclick] SEondblclick, [Aonfocus] SEonfocus, [Aonkeypress] SEonkeypress,
1929a747e4fSDavid du Colombier [Aonkeyup] SEonkeyup, [Aonload] SEonload, [Aonmousedown] SEonmousedown,
1939a747e4fSDavid du Colombier [Aonmousemove] SEonmousemove, [Aonmouseout] SEonmouseout, [Aonmouseover] SEonmouseover,
1949a747e4fSDavid du Colombier [Aonmouseup] SEonmouseup, [Aonreset] SEonreset, [Aonselect] SEonselect,
1959a747e4fSDavid du Colombier [Aonsubmit] SEonsubmit, [Aonunload] SEonunload
1969a747e4fSDavid du Colombier };
1979a747e4fSDavid du Colombier
1989a747e4fSDavid du Colombier // Color lookup table
1999a747e4fSDavid du Colombier static StringInt color_tab[] = {
2009a747e4fSDavid du Colombier {L"aqua", 0x00FFFF},
2019a747e4fSDavid du Colombier {L"black", 0x000000},
2029a747e4fSDavid du Colombier {L"blue", 0x0000CC},
2039a747e4fSDavid du Colombier {L"fuchsia", 0xFF00FF},
2049a747e4fSDavid du Colombier {L"gray", 0x808080},
2059a747e4fSDavid du Colombier {L"green", 0x008000},
2069a747e4fSDavid du Colombier {L"lime", 0x00FF00},
2079a747e4fSDavid du Colombier {L"maroon", 0x800000},
2089a747e4fSDavid du Colombier {L"navy", 0x000080,},
2099a747e4fSDavid du Colombier {L"olive", 0x808000},
2109a747e4fSDavid du Colombier {L"purple", 0x800080},
2119a747e4fSDavid du Colombier {L"red", 0xFF0000},
2129a747e4fSDavid du Colombier {L"silver", 0xC0C0C0},
2139a747e4fSDavid du Colombier {L"teal", 0x008080},
2149a747e4fSDavid du Colombier {L"white", 0xFFFFFF},
2159a747e4fSDavid du Colombier {L"yellow", 0xFFFF00}
2169a747e4fSDavid du Colombier };
2179a747e4fSDavid du Colombier #define NCOLORS (sizeof(color_tab)/sizeof(StringInt))
2189a747e4fSDavid du Colombier
2199a747e4fSDavid du Colombier static StringInt *targetmap;
2209a747e4fSDavid du Colombier static int targetmapsize;
2219a747e4fSDavid du Colombier static int ntargets;
2229a747e4fSDavid du Colombier
2239a747e4fSDavid du Colombier static int buildinited = 0;
2249a747e4fSDavid du Colombier
2259a747e4fSDavid du Colombier #define SMALLBUFSIZE 240
2269a747e4fSDavid du Colombier #define BIGBUFSIZE 2000
2279a747e4fSDavid du Colombier
2289a747e4fSDavid du Colombier int dbgbuild = 0;
2299a747e4fSDavid du Colombier int warn = 0;
2309a747e4fSDavid du Colombier
2319a747e4fSDavid du Colombier static Align aalign(Token* tok);
2329a747e4fSDavid du Colombier static int acolorval(Token* tok, int attid, int dflt);
2339a747e4fSDavid du Colombier static void addbrk(Pstate* ps, int sp, int clr);
2349a747e4fSDavid du Colombier static void additem(Pstate* ps, Item* it, Token* tok);
2359a747e4fSDavid du Colombier static void addlinebrk(Pstate* ps, int clr);
2369a747e4fSDavid du Colombier static void addnbsp(Pstate* ps);
2379a747e4fSDavid du Colombier static void addtext(Pstate* ps, Rune* s);
2389a747e4fSDavid du Colombier static Dimen adimen(Token* tok, int attid);
2399a747e4fSDavid du Colombier static int aflagval(Token* tok, int attid);
2409a747e4fSDavid du Colombier static int aintval(Token* tok, int attid, int dflt);
2419a747e4fSDavid du Colombier static Rune* astrval(Token* tok, int attid, Rune* dflt);
2429a747e4fSDavid du Colombier static int atabval(Token* tok, int attid, StringInt* tab, int ntab, int dflt);
2439a747e4fSDavid du Colombier static int atargval(Token* tok, int dflt);
2449a747e4fSDavid du Colombier static int auintval(Token* tok, int attid, int dflt);
2459a747e4fSDavid du Colombier static Rune* aurlval(Token* tok, int attid, Rune* dflt, Rune* base);
2469a747e4fSDavid du Colombier static Rune* aval(Token* tok, int attid);
2479a747e4fSDavid du Colombier static void buildinit(void);
2489a747e4fSDavid du Colombier static Pstate* cell_pstate(Pstate* oldps, int ishead);
2499a747e4fSDavid du Colombier static void changehang(Pstate* ps, int delta);
2509a747e4fSDavid du Colombier static void changeindent(Pstate* ps, int delta);
2519a747e4fSDavid du Colombier static int color(Rune* s, int dflt);
2529a747e4fSDavid du Colombier static void copystack(Stack* tostk, Stack* fromstk);
2539a747e4fSDavid du Colombier static int dimprint(char* buf, int nbuf, Dimen d);
2549a747e4fSDavid du Colombier static Pstate* finishcell(Table* curtab, Pstate* psstk);
2559a747e4fSDavid du Colombier static void finish_table(Table* t);
2569a747e4fSDavid du Colombier static void freeanchor(Anchor* a);
2579a747e4fSDavid du Colombier static void freedestanchor(DestAnchor* da);
2589a747e4fSDavid du Colombier static void freeform(Form* f);
2599a747e4fSDavid du Colombier static void freeformfield(Formfield* ff);
2609a747e4fSDavid du Colombier static void freeitem(Item* it);
2619a747e4fSDavid du Colombier static void freepstate(Pstate* p);
2629a747e4fSDavid du Colombier static void freepstatestack(Pstate* pshead);
2639a747e4fSDavid du Colombier static void freescriptevents(SEvent* ehead);
2649a747e4fSDavid du Colombier static void freetable(Table* t);
2659a747e4fSDavid du Colombier static Map* getmap(Docinfo* di, Rune* name);
2669a747e4fSDavid du Colombier static Rune* getpcdata(Token* toks, int tokslen, int* ptoki);
2679a747e4fSDavid du Colombier static Pstate* lastps(Pstate* psl);
2689a747e4fSDavid du Colombier static Rune* listmark(uchar ty, int n);
2699a747e4fSDavid du Colombier static int listtyval(Token* tok, int dflt);
2709a747e4fSDavid du Colombier static Align makealign(int halign, int valign);
2719a747e4fSDavid du Colombier static Background makebackground(Rune* imgurl, int color);
2729a747e4fSDavid du Colombier static Dimen makedimen(int kind, int spec);
2739a747e4fSDavid du Colombier static Anchor* newanchor(int index, Rune* name, Rune* href, int target, Anchor* link);
2749a747e4fSDavid du Colombier static Area* newarea(int shape, Rune* href, int target, Area* link);
2759a747e4fSDavid du Colombier static DestAnchor* newdestanchor(int index, Rune* name, Item* item, DestAnchor* link);
2769a747e4fSDavid du Colombier static Docinfo* newdocinfo(void);
2779a747e4fSDavid du Colombier static Genattr* newgenattr(Rune* id, Rune* class, Rune* style, Rune* title, Attr* events);
2789a747e4fSDavid du Colombier static Form* newform(int formid, Rune* name, Rune* action,
2799a747e4fSDavid du Colombier int target, int method, Form* link);
2809a747e4fSDavid du Colombier static Formfield* newformfield(int ftype, int fieldid, Form* form, Rune* name,
2819a747e4fSDavid du Colombier Rune* value, int size, int maxlength, Formfield* link);
2829a747e4fSDavid du Colombier static Item* newifloat(Item* it, int side);
2839a747e4fSDavid du Colombier static Item* newiformfield(Formfield* ff);
2849a747e4fSDavid du Colombier static Item* newiimage(Rune* src, Rune* altrep, int align, int width, int height,
2859a747e4fSDavid du Colombier int hspace, int vspace, int border, int ismap, Map* map);
286*684b447eSDavid du Colombier static Item* newirule(int align, int size, int noshade, int color, Dimen wspec);
2879a747e4fSDavid du Colombier static Item* newispacer(int spkind);
2889a747e4fSDavid du Colombier static Item* newitable(Table* t);
2899a747e4fSDavid du Colombier static ItemSource* newitemsource(Docinfo* di);
2909a747e4fSDavid du Colombier static Item* newitext(Rune* s, int fnt, int fg, int voff, int ul);
2919a747e4fSDavid du Colombier static Kidinfo* newkidinfo(int isframeset, Kidinfo* link);
2929a747e4fSDavid du Colombier static Option* newoption(int selected, Rune* value, Rune* display, Option* link);
2939a747e4fSDavid du Colombier static Pstate* newpstate(Pstate* link);
2945d459b5aSDavid du Colombier static SEvent* newscriptevent(int type, Rune* script, SEvent* link);
2959a747e4fSDavid du Colombier static Table* newtable(int tableid, Align align, Dimen width, int border,
2969a747e4fSDavid du Colombier int cellspacing, int cellpadding, Background bg, Token* tok, Table* link);
2979a747e4fSDavid du Colombier static Tablecell* newtablecell(int cellid, int rowspan, int colspan, Align align, Dimen wspec,
2989a747e4fSDavid du Colombier int hspec, Background bg, int flags, Tablecell* link);
2999a747e4fSDavid du Colombier static Tablerow* newtablerow(Align align, Background bg, int flags, Tablerow* link);
3009a747e4fSDavid du Colombier static Dimen parsedim(Rune* s, int ns);
3019a747e4fSDavid du Colombier static void pop(Stack* stk);
3029a747e4fSDavid du Colombier static void popfontsize(Pstate* ps);
3039a747e4fSDavid du Colombier static void popfontstyle(Pstate* ps);
3049a747e4fSDavid du Colombier static void popjust(Pstate* ps);
3059a747e4fSDavid du Colombier static int popretnewtop(Stack* stk, int dflt);
3069a747e4fSDavid du Colombier static int push(Stack* stk, int val);
3079a747e4fSDavid du Colombier static void pushfontsize(Pstate* ps, int sz);
3089a747e4fSDavid du Colombier static void pushfontstyle(Pstate* ps, int sty);
3099a747e4fSDavid du Colombier static void pushjust(Pstate* ps, int j);
3109a747e4fSDavid du Colombier static Item* textit(Pstate* ps, Rune* s);
3119a747e4fSDavid du Colombier static Rune* removeallwhite(Rune* s);
3129a747e4fSDavid du Colombier static void resetdocinfo(Docinfo* d);
3139a747e4fSDavid du Colombier static void setcurfont(Pstate* ps);
3149a747e4fSDavid du Colombier static void setcurjust(Pstate* ps);
3159a747e4fSDavid du Colombier static void setdimarray(Token* tok, int attid, Dimen** pans, int* panslen);
3169a747e4fSDavid du Colombier static Rune* stringalign(int a);
3179a747e4fSDavid du Colombier static void targetmapinit(void);
3189a747e4fSDavid du Colombier static int toint(Rune* s);
3199a747e4fSDavid du Colombier static int top(Stack* stk, int dflt);
3209a747e4fSDavid du Colombier static void trim_cell(Tablecell* c);
3219a747e4fSDavid du Colombier static int validalign(Align a);
3229a747e4fSDavid du Colombier static int validdimen(Dimen d);
3239a747e4fSDavid du Colombier static int validformfield(Formfield* f);
3249a747e4fSDavid du Colombier static int validhalign(int a);
3259a747e4fSDavid du Colombier static int validptr(void* p);
3269a747e4fSDavid du Colombier static int validStr(Rune* s);
3279a747e4fSDavid du Colombier static int validtable(Table* t);
3289a747e4fSDavid du Colombier static int validtablerow(Tablerow* r);
3299a747e4fSDavid du Colombier static int validtablecol(Tablecol* c);
3309a747e4fSDavid du Colombier static int validtablecell(Tablecell* c);
3319a747e4fSDavid du Colombier static int validvalign(int a);
3329a747e4fSDavid du Colombier static int Iconv(Fmt *f);
3339a747e4fSDavid du Colombier
3349a747e4fSDavid du Colombier static void
buildinit(void)3359a747e4fSDavid du Colombier buildinit(void)
3369a747e4fSDavid du Colombier {
3379a747e4fSDavid du Colombier fmtinstall('I', Iconv);
3389a747e4fSDavid du Colombier targetmapinit();
3399a747e4fSDavid du Colombier buildinited = 1;
3409a747e4fSDavid du Colombier }
3419a747e4fSDavid du Colombier
3429a747e4fSDavid du Colombier static ItemSource*
newitemsource(Docinfo * di)3439a747e4fSDavid du Colombier newitemsource(Docinfo* di)
3449a747e4fSDavid du Colombier {
3459a747e4fSDavid du Colombier ItemSource* is;
3469a747e4fSDavid du Colombier Pstate* ps;
3479a747e4fSDavid du Colombier
3489a747e4fSDavid du Colombier ps = newpstate(nil);
3499a747e4fSDavid du Colombier if(di->mediatype != TextHtml) {
3509a747e4fSDavid du Colombier ps->curstate &= ~IFwrap;
3519a747e4fSDavid du Colombier ps->literal = 1;
3529a747e4fSDavid du Colombier pushfontstyle(ps, FntT);
3539a747e4fSDavid du Colombier }
3549a747e4fSDavid du Colombier is = (ItemSource*)emalloc(sizeof(ItemSource));
3559a747e4fSDavid du Colombier is->doc = di;
3569a747e4fSDavid du Colombier is->psstk = ps;
3579a747e4fSDavid du Colombier is->nforms = 0;
3589a747e4fSDavid du Colombier is->ntables = 0;
3599a747e4fSDavid du Colombier is->nanchors = 0;
3609a747e4fSDavid du Colombier is->nframes = 0;
3619a747e4fSDavid du Colombier is->curform = nil;
3629a747e4fSDavid du Colombier is->curmap = nil;
3639a747e4fSDavid du Colombier is->tabstk = nil;
3649a747e4fSDavid du Colombier is->kidstk = nil;
3659a747e4fSDavid du Colombier return is;
3669a747e4fSDavid du Colombier }
3679a747e4fSDavid du Colombier
3689a747e4fSDavid du Colombier static Item *getitems(ItemSource* is, uchar* data, int datalen);
3699a747e4fSDavid du Colombier
3709a747e4fSDavid du Colombier // Parse an html document and create a list of layout items.
3719a747e4fSDavid du Colombier // Allocate and return document info in *pdi.
3729a747e4fSDavid du Colombier // When caller is done with the items, it should call
3739a747e4fSDavid du Colombier // freeitems on the returned result, and then
3749a747e4fSDavid du Colombier // freedocinfo(*pdi).
3759a747e4fSDavid du Colombier Item*
parsehtml(uchar * data,int datalen,Rune * pagesrc,int mtype,int chset,Docinfo ** pdi)3769a747e4fSDavid du Colombier parsehtml(uchar* data, int datalen, Rune* pagesrc, int mtype, int chset, Docinfo** pdi)
3779a747e4fSDavid du Colombier {
3789a747e4fSDavid du Colombier Item *it;
3799a747e4fSDavid du Colombier Docinfo* di;
3809a747e4fSDavid du Colombier ItemSource* is;
3819a747e4fSDavid du Colombier
3829a747e4fSDavid du Colombier di = newdocinfo();
3839a747e4fSDavid du Colombier di->src = _Strdup(pagesrc);
3849a747e4fSDavid du Colombier di->base = _Strdup(pagesrc);
3859a747e4fSDavid du Colombier di->mediatype = mtype;
3869a747e4fSDavid du Colombier di->chset = chset;
3879a747e4fSDavid du Colombier *pdi = di;
3889a747e4fSDavid du Colombier is = newitemsource(di);
3899a747e4fSDavid du Colombier it = getitems(is, data, datalen);
3909a747e4fSDavid du Colombier freepstatestack(is->psstk);
3919a747e4fSDavid du Colombier free(is);
3929a747e4fSDavid du Colombier return it;
3939a747e4fSDavid du Colombier }
3949a747e4fSDavid du Colombier
3959a747e4fSDavid du Colombier // Get a group of tokens for lexer, parse them, and create
3969a747e4fSDavid du Colombier // a list of layout items.
3979a747e4fSDavid du Colombier // When caller is done with the items, it should call
3989a747e4fSDavid du Colombier // freeitems on the returned result.
3999a747e4fSDavid du Colombier static Item*
getitems(ItemSource * is,uchar * data,int datalen)4009a747e4fSDavid du Colombier getitems(ItemSource* is, uchar* data, int datalen)
4019a747e4fSDavid du Colombier {
4029a747e4fSDavid du Colombier int i;
4039a747e4fSDavid du Colombier int j;
4049a747e4fSDavid du Colombier int nt;
4059a747e4fSDavid du Colombier int pt;
4069a747e4fSDavid du Colombier int doscripts;
4079a747e4fSDavid du Colombier int tokslen;
4089a747e4fSDavid du Colombier int toki;
4099a747e4fSDavid du Colombier int h;
4109a747e4fSDavid du Colombier int sz;
4119a747e4fSDavid du Colombier int method;
4129a747e4fSDavid du Colombier int n;
4139a747e4fSDavid du Colombier int nblank;
4149a747e4fSDavid du Colombier int norsz;
4159a747e4fSDavid du Colombier int bramt;
4169a747e4fSDavid du Colombier int sty;
4179a747e4fSDavid du Colombier int nosh;
418*684b447eSDavid du Colombier int color;
4199a747e4fSDavid du Colombier int oldcuranchor;
4209a747e4fSDavid du Colombier int dfltbd;
4219a747e4fSDavid du Colombier int v;
4229a747e4fSDavid du Colombier int hang;
4239a747e4fSDavid du Colombier int isempty;
4249a747e4fSDavid du Colombier int tag;
4259a747e4fSDavid du Colombier int brksp;
4269a747e4fSDavid du Colombier int target;
4279a747e4fSDavid du Colombier uchar brk;
4289a747e4fSDavid du Colombier uchar flags;
4299a747e4fSDavid du Colombier uchar align;
4309a747e4fSDavid du Colombier uchar al;
4319a747e4fSDavid du Colombier uchar ty;
4329a747e4fSDavid du Colombier uchar ty2;
4339a747e4fSDavid du Colombier Pstate* ps;
4349a747e4fSDavid du Colombier Pstate* nextps;
4359a747e4fSDavid du Colombier Pstate* outerps;
4369a747e4fSDavid du Colombier Table* curtab;
4379a747e4fSDavid du Colombier Token* tok;
4389a747e4fSDavid du Colombier Token* toks;
4399a747e4fSDavid du Colombier Docinfo* di;
4409a747e4fSDavid du Colombier Item* ans;
4419a747e4fSDavid du Colombier Item* img;
4429a747e4fSDavid du Colombier Item* ffit;
4439a747e4fSDavid du Colombier Item* tabitem;
4449a747e4fSDavid du Colombier Rune* s;
4459a747e4fSDavid du Colombier Rune* t;
4469a747e4fSDavid du Colombier Rune* name;
4479a747e4fSDavid du Colombier Rune* enctype;
4489a747e4fSDavid du Colombier Rune* usemap;
4499a747e4fSDavid du Colombier Rune* prompt;
4509a747e4fSDavid du Colombier Rune* equiv;
4519a747e4fSDavid du Colombier Rune* val;
4529a747e4fSDavid du Colombier Rune* nsz;
4539a747e4fSDavid du Colombier Rune* script;
4549a747e4fSDavid du Colombier Map* map;
4559a747e4fSDavid du Colombier Form* frm;
4569a747e4fSDavid du Colombier Iimage* ii;
4579a747e4fSDavid du Colombier Kidinfo* kd;
4589a747e4fSDavid du Colombier Kidinfo* ks;
4599a747e4fSDavid du Colombier Kidinfo* pks;
4609a747e4fSDavid du Colombier Dimen wd;
4619a747e4fSDavid du Colombier Option* option;
4629a747e4fSDavid du Colombier Table* tab;
4639a747e4fSDavid du Colombier Tablecell* c;
4649a747e4fSDavid du Colombier Tablerow* tr;
4659a747e4fSDavid du Colombier Formfield* field;
4669a747e4fSDavid du Colombier Formfield* ff;
4679a747e4fSDavid du Colombier Rune* href;
4689a747e4fSDavid du Colombier Rune* src;
4699a747e4fSDavid du Colombier Rune* scriptsrc;
4709a747e4fSDavid du Colombier Rune* bgurl;
4719a747e4fSDavid du Colombier Rune* action;
4729a747e4fSDavid du Colombier Background bg;
4739a747e4fSDavid du Colombier
4749a747e4fSDavid du Colombier if(!buildinited)
4759a747e4fSDavid du Colombier buildinit();
4769a747e4fSDavid du Colombier doscripts = 0; // for now
4779a747e4fSDavid du Colombier ps = is->psstk;
4789a747e4fSDavid du Colombier curtab = is->tabstk;
4799a747e4fSDavid du Colombier di = is->doc;
4809a747e4fSDavid du Colombier toks = _gettoks(data, datalen, di->chset, di->mediatype, &tokslen);
4819a747e4fSDavid du Colombier toki = 0;
4829a747e4fSDavid du Colombier for(; toki < tokslen; toki++) {
4839a747e4fSDavid du Colombier tok = &toks[toki];
4849a747e4fSDavid du Colombier if(dbgbuild > 1)
4859a747e4fSDavid du Colombier fprint(2, "build: curstate %ux, token %T\n", ps->curstate, tok);
4869a747e4fSDavid du Colombier tag = tok->tag;
4879a747e4fSDavid du Colombier brk = 0;
4889a747e4fSDavid du Colombier brksp = 0;
4899a747e4fSDavid du Colombier if(tag < Numtags) {
4909a747e4fSDavid du Colombier brk = blockbrk[tag];
4919a747e4fSDavid du Colombier if(brk&SPBefore)
4929a747e4fSDavid du Colombier brksp = 1;
4939a747e4fSDavid du Colombier }
4949a747e4fSDavid du Colombier else if(tag < Numtags + RBRA) {
4959a747e4fSDavid du Colombier brk = blockbrk[tag - RBRA];
4969a747e4fSDavid du Colombier if(brk&SPAfter)
4979a747e4fSDavid du Colombier brksp = 1;
4989a747e4fSDavid du Colombier }
4999a747e4fSDavid du Colombier if(brk) {
5009a747e4fSDavid du Colombier addbrk(ps, brksp, 0);
5019a747e4fSDavid du Colombier if(ps->inpar) {
5029a747e4fSDavid du Colombier popjust(ps);
5039a747e4fSDavid du Colombier ps->inpar = 0;
5049a747e4fSDavid du Colombier }
5059a747e4fSDavid du Colombier }
5069a747e4fSDavid du Colombier // check common case first (Data), then switch statement on tag
5079a747e4fSDavid du Colombier if(tag == Data) {
5089a747e4fSDavid du Colombier // Lexing didn't pay attention to SGML record boundary rules:
5099a747e4fSDavid du Colombier // \n after start tag or before end tag to be discarded.
5109a747e4fSDavid du Colombier // (Lex has already discarded all \r's).
5119a747e4fSDavid du Colombier // Some pages assume this doesn't happen in <PRE> text,
5129a747e4fSDavid du Colombier // so we won't do it if literal is true.
5139a747e4fSDavid du Colombier // BUG: won't discard \n before a start tag that begins
5149a747e4fSDavid du Colombier // the next bufferful of tokens.
5159a747e4fSDavid du Colombier s = tok->text;
5165d459b5aSDavid du Colombier n = _Strlen(s);
5179a747e4fSDavid du Colombier if(!ps->literal) {
5189a747e4fSDavid du Colombier i = 0;
5199a747e4fSDavid du Colombier j = n;
5209a747e4fSDavid du Colombier if(toki > 0) {
5219a747e4fSDavid du Colombier pt = toks[toki - 1].tag;
5229a747e4fSDavid du Colombier // IE and Netscape both ignore this rule (contrary to spec)
5239a747e4fSDavid du Colombier // if previous tag was img
5249a747e4fSDavid du Colombier if(pt < Numtags && pt != Timg && j > 0 && s[0] == '\n')
5259a747e4fSDavid du Colombier i++;
5269a747e4fSDavid du Colombier }
5279a747e4fSDavid du Colombier if(toki < tokslen - 1) {
5289a747e4fSDavid du Colombier nt = toks[toki + 1].tag;
5299a747e4fSDavid du Colombier if(nt >= RBRA && nt < Numtags + RBRA && j > i && s[j - 1] == '\n')
5309a747e4fSDavid du Colombier j--;
5319a747e4fSDavid du Colombier }
5329a747e4fSDavid du Colombier if(i > 0 || j < n) {
5339a747e4fSDavid du Colombier t = s;
5349a747e4fSDavid du Colombier s = _Strsubstr(s, i, j);
5359a747e4fSDavid du Colombier free(t);
5369a747e4fSDavid du Colombier n = j-i;
5379a747e4fSDavid du Colombier }
5389a747e4fSDavid du Colombier }
5399a747e4fSDavid du Colombier if(ps->skipwhite) {
5409a747e4fSDavid du Colombier _trimwhite(s, n, &t, &nt);
5419a747e4fSDavid du Colombier if(t == nil) {
5429a747e4fSDavid du Colombier free(s);
5439a747e4fSDavid du Colombier s = nil;
5449a747e4fSDavid du Colombier }
5459a747e4fSDavid du Colombier else if(t != s) {
5469a747e4fSDavid du Colombier t = _Strndup(t, nt);
5479a747e4fSDavid du Colombier free(s);
5489a747e4fSDavid du Colombier s = t;
5499a747e4fSDavid du Colombier }
5509a747e4fSDavid du Colombier if(s != nil)
5519a747e4fSDavid du Colombier ps->skipwhite = 0;
5529a747e4fSDavid du Colombier }
5539a747e4fSDavid du Colombier tok->text = nil; // token doesn't own string anymore
5549a747e4fSDavid du Colombier if(s != nil)
5559a747e4fSDavid du Colombier addtext(ps, s);
5569a747e4fSDavid du Colombier }
5579a747e4fSDavid du Colombier else
5589a747e4fSDavid du Colombier switch(tag) {
5599a747e4fSDavid du Colombier // Some abbrevs used in following DTD comments
5609a747e4fSDavid du Colombier // %text = #PCDATA
5619a747e4fSDavid du Colombier // | TT | I | B | U | STRIKE | BIG | SMALL | SUB | SUP
5629a747e4fSDavid du Colombier // | EM | STRONG | DFN | CODE | SAMP | KBD | VAR | CITE
5639a747e4fSDavid du Colombier // | A | IMG | APPLET | FONT | BASEFONT | BR | SCRIPT | MAP
5649a747e4fSDavid du Colombier // | INPUT | SELECT | TEXTAREA
5659a747e4fSDavid du Colombier // %block = P | UL | OL | DIR | MENU | DL | PRE | DL | DIV | CENTER
5669a747e4fSDavid du Colombier // | BLOCKQUOTE | FORM | ISINDEX | HR | TABLE
5679a747e4fSDavid du Colombier // %flow = (%text | %block)*
5689a747e4fSDavid du Colombier // %body.content = (%heading | %text | %block | ADDRESS)*
5699a747e4fSDavid du Colombier
5709a747e4fSDavid du Colombier // <!ELEMENT A - - (%text) -(A)>
5719a747e4fSDavid du Colombier // Anchors are not supposed to be nested, but you sometimes see
5729a747e4fSDavid du Colombier // href anchors inside destination anchors.
5739a747e4fSDavid du Colombier case Ta:
5749a747e4fSDavid du Colombier if(ps->curanchor != 0) {
5759a747e4fSDavid du Colombier if(warn)
5769a747e4fSDavid du Colombier fprint(2, "warning: nested <A> or missing </A>\n");
5779a747e4fSDavid du Colombier ps->curanchor = 0;
5789a747e4fSDavid du Colombier }
5799a747e4fSDavid du Colombier name = aval(tok, Aname);
5809a747e4fSDavid du Colombier href = aurlval(tok, Ahref, nil, di->base);
5819a747e4fSDavid du Colombier // ignore rel, rev, and title attrs
5829a747e4fSDavid du Colombier if(href != nil) {
5839a747e4fSDavid du Colombier target = atargval(tok, di->target);
5849a747e4fSDavid du Colombier di->anchors = newanchor(++is->nanchors, name, href, target, di->anchors);
5859a747e4fSDavid du Colombier if(name != nil)
5869a747e4fSDavid du Colombier name = _Strdup(name); // for DestAnchor construction, below
5879a747e4fSDavid du Colombier ps->curanchor = is->nanchors;
5889a747e4fSDavid du Colombier ps->curfg = push(&ps->fgstk, di->link);
5899a747e4fSDavid du Colombier ps->curul = push(&ps->ulstk, ULunder);
5909a747e4fSDavid du Colombier }
5919a747e4fSDavid du Colombier if(name != nil) {
5929a747e4fSDavid du Colombier // add a null item to be destination
5939a747e4fSDavid du Colombier additem(ps, newispacer(ISPnull), tok);
5949a747e4fSDavid du Colombier di->dests = newdestanchor(++is->nanchors, name, ps->lastit, di->dests);
5959a747e4fSDavid du Colombier }
5969a747e4fSDavid du Colombier break;
5979a747e4fSDavid du Colombier
5989a747e4fSDavid du Colombier case Ta+RBRA :
5999a747e4fSDavid du Colombier if(ps->curanchor != 0) {
6009a747e4fSDavid du Colombier ps->curfg = popretnewtop(&ps->fgstk, di->text);
6019a747e4fSDavid du Colombier ps->curul = popretnewtop(&ps->ulstk, ULnone);
6029a747e4fSDavid du Colombier ps->curanchor = 0;
6039a747e4fSDavid du Colombier }
6049a747e4fSDavid du Colombier break;
6059a747e4fSDavid du Colombier
6069a747e4fSDavid du Colombier // <!ELEMENT APPLET - - (PARAM | %text)* >
6079a747e4fSDavid du Colombier // We can't do applets, so ignore PARAMS, and let
6089a747e4fSDavid du Colombier // the %text contents appear for the alternative rep
6099a747e4fSDavid du Colombier case Tapplet:
6109a747e4fSDavid du Colombier case Tapplet+RBRA:
6119a747e4fSDavid du Colombier if(warn && tag == Tapplet)
6129a747e4fSDavid du Colombier fprint(2, "warning: <APPLET> ignored\n");
6139a747e4fSDavid du Colombier break;
6149a747e4fSDavid du Colombier
6159a747e4fSDavid du Colombier // <!ELEMENT AREA - O EMPTY>
6169a747e4fSDavid du Colombier case Tarea:
6179a747e4fSDavid du Colombier map = di->maps;
6189a747e4fSDavid du Colombier if(map == nil) {
6199a747e4fSDavid du Colombier if(warn)
6209a747e4fSDavid du Colombier fprint(2, "warning: <AREA> not inside <MAP>\n");
6219a747e4fSDavid du Colombier continue;
6229a747e4fSDavid du Colombier }
6239a747e4fSDavid du Colombier map->areas = newarea(atabval(tok, Ashape, shape_tab, NSHAPETAB, SHrect),
6249a747e4fSDavid du Colombier aurlval(tok, Ahref, nil, di->base),
6259a747e4fSDavid du Colombier atargval(tok, di->target),
6269a747e4fSDavid du Colombier map->areas);
6279a747e4fSDavid du Colombier setdimarray(tok, Acoords, &map->areas->coords, &map->areas->ncoords);
6289a747e4fSDavid du Colombier break;
6299a747e4fSDavid du Colombier
6309a747e4fSDavid du Colombier // <!ELEMENT (B|STRONG) - - (%text)*>
6319a747e4fSDavid du Colombier case Tb:
6329a747e4fSDavid du Colombier case Tstrong:
6339a747e4fSDavid du Colombier pushfontstyle(ps, FntB);
6349a747e4fSDavid du Colombier break;
6359a747e4fSDavid du Colombier
6369a747e4fSDavid du Colombier case Tb+RBRA:
6379a747e4fSDavid du Colombier case Tcite+RBRA:
6389a747e4fSDavid du Colombier case Tcode+RBRA:
6399a747e4fSDavid du Colombier case Tdfn+RBRA:
6409a747e4fSDavid du Colombier case Tem+RBRA:
6419a747e4fSDavid du Colombier case Tkbd+RBRA:
6429a747e4fSDavid du Colombier case Ti+RBRA:
6439a747e4fSDavid du Colombier case Tsamp+RBRA:
6449a747e4fSDavid du Colombier case Tstrong+RBRA:
6459a747e4fSDavid du Colombier case Ttt+RBRA:
6469a747e4fSDavid du Colombier case Tvar+RBRA :
6479a747e4fSDavid du Colombier case Taddress+RBRA:
6489a747e4fSDavid du Colombier popfontstyle(ps);
6499a747e4fSDavid du Colombier break;
6509a747e4fSDavid du Colombier
6519a747e4fSDavid du Colombier // <!ELEMENT BASE - O EMPTY>
6529a747e4fSDavid du Colombier case Tbase:
6539a747e4fSDavid du Colombier t = di->base;
6549a747e4fSDavid du Colombier di->base = aurlval(tok, Ahref, di->base, di->base);
6559a747e4fSDavid du Colombier if(t != nil)
6569a747e4fSDavid du Colombier free(t);
6579a747e4fSDavid du Colombier di->target = atargval(tok, di->target);
6589a747e4fSDavid du Colombier break;
6599a747e4fSDavid du Colombier
6609a747e4fSDavid du Colombier // <!ELEMENT BASEFONT - O EMPTY>
6619a747e4fSDavid du Colombier case Tbasefont:
6629a747e4fSDavid du Colombier ps->adjsize = aintval(tok, Asize, 3) - 3;
6639a747e4fSDavid du Colombier break;
6649a747e4fSDavid du Colombier
6659a747e4fSDavid du Colombier // <!ELEMENT (BIG|SMALL) - - (%text)*>
6669a747e4fSDavid du Colombier case Tbig:
6679a747e4fSDavid du Colombier case Tsmall:
6689a747e4fSDavid du Colombier sz = ps->adjsize;
6699a747e4fSDavid du Colombier if(tag == Tbig)
6709a747e4fSDavid du Colombier sz += Large;
6719a747e4fSDavid du Colombier else
6729a747e4fSDavid du Colombier sz += Small;
6739a747e4fSDavid du Colombier pushfontsize(ps, sz);
6749a747e4fSDavid du Colombier break;
6759a747e4fSDavid du Colombier
6769a747e4fSDavid du Colombier case Tbig+RBRA:
6779a747e4fSDavid du Colombier case Tsmall+RBRA:
6789a747e4fSDavid du Colombier popfontsize(ps);
6799a747e4fSDavid du Colombier break;
6809a747e4fSDavid du Colombier
6819a747e4fSDavid du Colombier // <!ELEMENT BLOCKQUOTE - - %body.content>
6829a747e4fSDavid du Colombier case Tblockquote:
6839a747e4fSDavid du Colombier changeindent(ps, BQTAB);
6849a747e4fSDavid du Colombier break;
6859a747e4fSDavid du Colombier
6869a747e4fSDavid du Colombier case Tblockquote+RBRA:
6879a747e4fSDavid du Colombier changeindent(ps, -BQTAB);
6889a747e4fSDavid du Colombier break;
6899a747e4fSDavid du Colombier
6909a747e4fSDavid du Colombier // <!ELEMENT BODY O O %body.content>
6919a747e4fSDavid du Colombier case Tbody:
6929a747e4fSDavid du Colombier ps->skipping = 0;
6939a747e4fSDavid du Colombier bg = makebackground(nil, acolorval(tok, Abgcolor, di->background.color));
6949a747e4fSDavid du Colombier bgurl = aurlval(tok, Abackground, nil, di->base);
6959a747e4fSDavid du Colombier if(bgurl != nil) {
6969a747e4fSDavid du Colombier if(di->backgrounditem != nil)
6979a747e4fSDavid du Colombier freeitem((Item*)di->backgrounditem);
6989a747e4fSDavid du Colombier // really should remove old item from di->images list,
6999a747e4fSDavid du Colombier // but there should only be one BODY element ...
7009a747e4fSDavid du Colombier di->backgrounditem = (Iimage*)newiimage(bgurl, nil, ALnone, 0, 0, 0, 0, 0, 0, nil);
7019a747e4fSDavid du Colombier di->backgrounditem->nextimage = di->images;
7029a747e4fSDavid du Colombier di->images = di->backgrounditem;
7039a747e4fSDavid du Colombier }
7049a747e4fSDavid du Colombier ps->curbg = bg;
7059a747e4fSDavid du Colombier di->background = bg;
7069a747e4fSDavid du Colombier di->text = acolorval(tok, Atext, di->text);
7079a747e4fSDavid du Colombier di->link = acolorval(tok, Alink, di->link);
7089a747e4fSDavid du Colombier di->vlink = acolorval(tok, Avlink, di->vlink);
7099a747e4fSDavid du Colombier di->alink = acolorval(tok, Aalink, di->alink);
7109a747e4fSDavid du Colombier if(di->text != ps->curfg) {
7119a747e4fSDavid du Colombier ps->curfg = di->text;
7129a747e4fSDavid du Colombier ps->fgstk.n = 0;
7139a747e4fSDavid du Colombier }
7149a747e4fSDavid du Colombier break;
7159a747e4fSDavid du Colombier
7169a747e4fSDavid du Colombier case Tbody+RBRA:
7179a747e4fSDavid du Colombier // HTML spec says ignore things after </body>,
7189a747e4fSDavid du Colombier // but IE and Netscape don't
7199a747e4fSDavid du Colombier // ps.skipping = 1;
7209a747e4fSDavid du Colombier break;
7219a747e4fSDavid du Colombier
7229a747e4fSDavid du Colombier // <!ELEMENT BR - O EMPTY>
7239a747e4fSDavid du Colombier case Tbr:
7249a747e4fSDavid du Colombier addlinebrk(ps, atabval(tok, Aclear, clear_tab, NCLEARTAB, 0));
7259a747e4fSDavid du Colombier break;
7269a747e4fSDavid du Colombier
7279a747e4fSDavid du Colombier // <!ELEMENT CAPTION - - (%text;)*>
7289a747e4fSDavid du Colombier case Tcaption:
7299a747e4fSDavid du Colombier if(curtab == nil) {
7309a747e4fSDavid du Colombier if(warn)
7319a747e4fSDavid du Colombier fprint(2, "warning: <CAPTION> outside <TABLE>\n");
7329a747e4fSDavid du Colombier continue;
7339a747e4fSDavid du Colombier }
7349a747e4fSDavid du Colombier if(curtab->caption != nil) {
7359a747e4fSDavid du Colombier if(warn)
7369a747e4fSDavid du Colombier fprint(2, "warning: more than one <CAPTION> in <TABLE>\n");
7379a747e4fSDavid du Colombier continue;
7389a747e4fSDavid du Colombier }
7399a747e4fSDavid du Colombier ps = newpstate(ps);
7409a747e4fSDavid du Colombier curtab->caption_place = atabval(tok, Aalign, align_tab, NALIGNTAB, ALtop);
7419a747e4fSDavid du Colombier break;
7429a747e4fSDavid du Colombier
7439a747e4fSDavid du Colombier case Tcaption+RBRA:
7449a747e4fSDavid du Colombier nextps = ps->next;
7459a747e4fSDavid du Colombier if(curtab == nil || nextps == nil) {
7469a747e4fSDavid du Colombier if(warn)
7479a747e4fSDavid du Colombier fprint(2, "warning: unexpected </CAPTION>\n");
7489a747e4fSDavid du Colombier continue;
7499a747e4fSDavid du Colombier }
7509a747e4fSDavid du Colombier curtab->caption = ps->items->next;
7519a747e4fSDavid du Colombier free(ps);
7529a747e4fSDavid du Colombier ps = nextps;
7539a747e4fSDavid du Colombier break;
7549a747e4fSDavid du Colombier
7559a747e4fSDavid du Colombier case Tcenter:
7569a747e4fSDavid du Colombier case Tdiv:
7579a747e4fSDavid du Colombier if(tag == Tcenter)
7589a747e4fSDavid du Colombier al = ALcenter;
7599a747e4fSDavid du Colombier else
7609a747e4fSDavid du Colombier al = atabval(tok, Aalign, align_tab, NALIGNTAB, ps->curjust);
7619a747e4fSDavid du Colombier pushjust(ps, al);
7629a747e4fSDavid du Colombier break;
7639a747e4fSDavid du Colombier
7649a747e4fSDavid du Colombier case Tcenter+RBRA:
7659a747e4fSDavid du Colombier case Tdiv+RBRA:
7669a747e4fSDavid du Colombier popjust(ps);
7679a747e4fSDavid du Colombier break;
7689a747e4fSDavid du Colombier
7699a747e4fSDavid du Colombier // <!ELEMENT DD - O %flow >
7709a747e4fSDavid du Colombier case Tdd:
7719a747e4fSDavid du Colombier if(ps->hangstk.n == 0) {
7729a747e4fSDavid du Colombier if(warn)
7739a747e4fSDavid du Colombier fprint(2, "warning: <DD> not inside <DL\n");
7749a747e4fSDavid du Colombier continue;
7759a747e4fSDavid du Colombier }
7769a747e4fSDavid du Colombier h = top(&ps->hangstk, 0);
7779a747e4fSDavid du Colombier if(h != 0)
7789a747e4fSDavid du Colombier changehang(ps, -10*LISTTAB);
7799a747e4fSDavid du Colombier else
7809a747e4fSDavid du Colombier addbrk(ps, 0, 0);
7819a747e4fSDavid du Colombier push(&ps->hangstk, 0);
7829a747e4fSDavid du Colombier break;
7839a747e4fSDavid du Colombier
7849a747e4fSDavid du Colombier //<!ELEMENT (DIR|MENU) - - (LI)+ -(%block) >
7859a747e4fSDavid du Colombier //<!ELEMENT (OL|UL) - - (LI)+>
7869a747e4fSDavid du Colombier case Tdir:
7879a747e4fSDavid du Colombier case Tmenu:
7889a747e4fSDavid du Colombier case Tol:
7899a747e4fSDavid du Colombier case Tul:
7909a747e4fSDavid du Colombier changeindent(ps, LISTTAB);
7919a747e4fSDavid du Colombier push(&ps->listtypestk, listtyval(tok, (tag==Tol)? LT1 : LTdisc));
7929a747e4fSDavid du Colombier push(&ps->listcntstk, aintval(tok, Astart, 1));
7939a747e4fSDavid du Colombier break;
7949a747e4fSDavid du Colombier
7959a747e4fSDavid du Colombier case Tdir+RBRA:
7969a747e4fSDavid du Colombier case Tmenu+RBRA:
7979a747e4fSDavid du Colombier case Tol+RBRA:
7989a747e4fSDavid du Colombier case Tul+RBRA:
7999a747e4fSDavid du Colombier if(ps->listtypestk.n == 0) {
8009a747e4fSDavid du Colombier if(warn)
8019a747e4fSDavid du Colombier fprint(2, "warning: %T ended no list\n", tok);
8029a747e4fSDavid du Colombier continue;
8039a747e4fSDavid du Colombier }
8049a747e4fSDavid du Colombier addbrk(ps, 0, 0);
8059a747e4fSDavid du Colombier pop(&ps->listtypestk);
8069a747e4fSDavid du Colombier pop(&ps->listcntstk);
8079a747e4fSDavid du Colombier changeindent(ps, -LISTTAB);
8089a747e4fSDavid du Colombier break;
8099a747e4fSDavid du Colombier
8109a747e4fSDavid du Colombier // <!ELEMENT DL - - (DT|DD)+ >
8119a747e4fSDavid du Colombier case Tdl:
8129a747e4fSDavid du Colombier changeindent(ps, LISTTAB);
8139a747e4fSDavid du Colombier push(&ps->hangstk, 0);
8149a747e4fSDavid du Colombier break;
8159a747e4fSDavid du Colombier
8169a747e4fSDavid du Colombier case Tdl+RBRA:
8179a747e4fSDavid du Colombier if(ps->hangstk.n == 0) {
8189a747e4fSDavid du Colombier if(warn)
8199a747e4fSDavid du Colombier fprint(2, "warning: unexpected </DL>\n");
8209a747e4fSDavid du Colombier continue;
8219a747e4fSDavid du Colombier }
8229a747e4fSDavid du Colombier changeindent(ps, -LISTTAB);
8239a747e4fSDavid du Colombier if(top(&ps->hangstk, 0) != 0)
8249a747e4fSDavid du Colombier changehang(ps, -10*LISTTAB);
8259a747e4fSDavid du Colombier pop(&ps->hangstk);
8269a747e4fSDavid du Colombier break;
8279a747e4fSDavid du Colombier
8289a747e4fSDavid du Colombier // <!ELEMENT DT - O (%text)* >
8299a747e4fSDavid du Colombier case Tdt:
8309a747e4fSDavid du Colombier if(ps->hangstk.n == 0) {
8319a747e4fSDavid du Colombier if(warn)
8329a747e4fSDavid du Colombier fprint(2, "warning: <DT> not inside <DL>\n");
8339a747e4fSDavid du Colombier continue;
8349a747e4fSDavid du Colombier }
8359a747e4fSDavid du Colombier h = top(&ps->hangstk, 0);
8369a747e4fSDavid du Colombier pop(&ps->hangstk);
8379a747e4fSDavid du Colombier if(h != 0)
8389a747e4fSDavid du Colombier changehang(ps, -10*LISTTAB);
8399a747e4fSDavid du Colombier changehang(ps, 10*LISTTAB);
8409a747e4fSDavid du Colombier push(&ps->hangstk, 1);
8419a747e4fSDavid du Colombier break;
8429a747e4fSDavid du Colombier
8439a747e4fSDavid du Colombier // <!ELEMENT FONT - - (%text)*>
8449a747e4fSDavid du Colombier case Tfont:
8459a747e4fSDavid du Colombier sz = top(&ps->fntsizestk, Normal);
8469a747e4fSDavid du Colombier if(_tokaval(tok, Asize, &nsz, 0)) {
8479a747e4fSDavid du Colombier if(_prefix(L"+", nsz))
8489a747e4fSDavid du Colombier sz = Normal + _Strtol(nsz+1, nil, 10) + ps->adjsize;
8499a747e4fSDavid du Colombier else if(_prefix(L"-", nsz))
8509a747e4fSDavid du Colombier sz = Normal - _Strtol(nsz+1, nil, 10) + ps->adjsize;
8519a747e4fSDavid du Colombier else if(nsz != nil)
8529a747e4fSDavid du Colombier sz = Normal + (_Strtol(nsz, nil, 10) - 3);
8539a747e4fSDavid du Colombier }
8549a747e4fSDavid du Colombier ps->curfg = push(&ps->fgstk, acolorval(tok, Acolor, ps->curfg));
8559a747e4fSDavid du Colombier pushfontsize(ps, sz);
8569a747e4fSDavid du Colombier break;
8579a747e4fSDavid du Colombier
8589a747e4fSDavid du Colombier case Tfont+RBRA:
8599a747e4fSDavid du Colombier if(ps->fgstk.n == 0) {
8609a747e4fSDavid du Colombier if(warn)
8619a747e4fSDavid du Colombier fprint(2, "warning: unexpected </FONT>\n");
8629a747e4fSDavid du Colombier continue;
8639a747e4fSDavid du Colombier }
8649a747e4fSDavid du Colombier ps->curfg = popretnewtop(&ps->fgstk, di->text);
8659a747e4fSDavid du Colombier popfontsize(ps);
8669a747e4fSDavid du Colombier break;
8679a747e4fSDavid du Colombier
8689a747e4fSDavid du Colombier // <!ELEMENT FORM - - %body.content -(FORM) >
8699a747e4fSDavid du Colombier case Tform:
8709a747e4fSDavid du Colombier if(is->curform != nil) {
8719a747e4fSDavid du Colombier if(warn)
8729a747e4fSDavid du Colombier fprint(2, "warning: <FORM> nested inside another\n");
8739a747e4fSDavid du Colombier continue;
8749a747e4fSDavid du Colombier }
8759a747e4fSDavid du Colombier action = aurlval(tok, Aaction, di->base, di->base);
8769a747e4fSDavid du Colombier s = aval(tok, Aid);
8779a747e4fSDavid du Colombier name = astrval(tok, Aname, s);
8789a747e4fSDavid du Colombier if(s)
8799a747e4fSDavid du Colombier free(s);
8809a747e4fSDavid du Colombier target = atargval(tok, di->target);
8819a747e4fSDavid du Colombier method = atabval(tok, Amethod, method_tab, NMETHODTAB, HGet);
8829a747e4fSDavid du Colombier if(warn && _tokaval(tok, Aenctype, &enctype, 0) &&
8835d459b5aSDavid du Colombier _Strcmp(enctype, L"application/x-www-form-urlencoded"))
8849a747e4fSDavid du Colombier fprint(2, "form enctype %S not handled\n", enctype);
8859a747e4fSDavid du Colombier frm = newform(++is->nforms, name, action, target, method, di->forms);
8869a747e4fSDavid du Colombier di->forms = frm;
8879a747e4fSDavid du Colombier is->curform = frm;
8889a747e4fSDavid du Colombier break;
8899a747e4fSDavid du Colombier
8909a747e4fSDavid du Colombier case Tform+RBRA:
8919a747e4fSDavid du Colombier if(is->curform == nil) {
8929a747e4fSDavid du Colombier if(warn)
8939a747e4fSDavid du Colombier fprint(2, "warning: unexpected </FORM>\n");
8949a747e4fSDavid du Colombier continue;
8959a747e4fSDavid du Colombier }
8969a747e4fSDavid du Colombier // put fields back in input order
8979a747e4fSDavid du Colombier is->curform->fields = (Formfield*)_revlist((List*)is->curform->fields);
8989a747e4fSDavid du Colombier is->curform = nil;
8999a747e4fSDavid du Colombier break;
9009a747e4fSDavid du Colombier
9019a747e4fSDavid du Colombier // <!ELEMENT FRAME - O EMPTY>
9029a747e4fSDavid du Colombier case Tframe:
9039a747e4fSDavid du Colombier ks = is->kidstk;
9049a747e4fSDavid du Colombier if(ks == nil) {
9059a747e4fSDavid du Colombier if(warn)
9069a747e4fSDavid du Colombier fprint(2, "warning: <FRAME> not in <FRAMESET>\n");
9079a747e4fSDavid du Colombier continue;
9089a747e4fSDavid du Colombier }
9099a747e4fSDavid du Colombier ks->kidinfos = kd = newkidinfo(0, ks->kidinfos);
9109a747e4fSDavid du Colombier kd->src = aurlval(tok, Asrc, nil, di->base);
9119a747e4fSDavid du Colombier kd->name = aval(tok, Aname);
912c93608ccSDavid du Colombier if(kd->name == nil)
913c93608ccSDavid du Colombier kd->name = runesmprint("_fr%d", ++is->nframes);
9149a747e4fSDavid du Colombier kd->marginw = auintval(tok, Amarginwidth, 0);
9159a747e4fSDavid du Colombier kd->marginh = auintval(tok, Amarginheight, 0);
9169a747e4fSDavid du Colombier kd->framebd = auintval(tok, Aframeborder, 1);
9179a747e4fSDavid du Colombier kd->flags = atabval(tok, Ascrolling, fscroll_tab, NFSCROLLTAB, kd->flags);
9189a747e4fSDavid du Colombier norsz = aflagval(tok, Anoresize);
9199a747e4fSDavid du Colombier if(norsz)
9209a747e4fSDavid du Colombier kd->flags |= FRnoresize;
9219a747e4fSDavid du Colombier break;
9229a747e4fSDavid du Colombier
9239a747e4fSDavid du Colombier // <!ELEMENT FRAMESET - - (FRAME|FRAMESET)+>
9249a747e4fSDavid du Colombier case Tframeset:
9259a747e4fSDavid du Colombier ks = newkidinfo(1, nil);
9269a747e4fSDavid du Colombier pks = is->kidstk;
9279a747e4fSDavid du Colombier if(pks == nil)
9289a747e4fSDavid du Colombier di->kidinfo = ks;
9299a747e4fSDavid du Colombier else {
9309a747e4fSDavid du Colombier ks->next = pks->kidinfos;
9319a747e4fSDavid du Colombier pks->kidinfos = ks;
9329a747e4fSDavid du Colombier }
9339a747e4fSDavid du Colombier ks->nextframeset = pks;
9349a747e4fSDavid du Colombier is->kidstk = ks;
9359a747e4fSDavid du Colombier setdimarray(tok, Arows, &ks->rows, &ks->nrows);
9369a747e4fSDavid du Colombier if(ks->nrows == 0) {
9379a747e4fSDavid du Colombier ks->rows = (Dimen*)emalloc(sizeof(Dimen));
9389a747e4fSDavid du Colombier ks->nrows = 1;
9399a747e4fSDavid du Colombier ks->rows[0] = makedimen(Dpercent, 100);
9409a747e4fSDavid du Colombier }
9419a747e4fSDavid du Colombier setdimarray(tok, Acols, &ks->cols, &ks->ncols);
9429a747e4fSDavid du Colombier if(ks->ncols == 0) {
9439a747e4fSDavid du Colombier ks->cols = (Dimen*)emalloc(sizeof(Dimen));
9449a747e4fSDavid du Colombier ks->ncols = 1;
9459a747e4fSDavid du Colombier ks->cols[0] = makedimen(Dpercent, 100);
9469a747e4fSDavid du Colombier }
9479a747e4fSDavid du Colombier break;
9489a747e4fSDavid du Colombier
9499a747e4fSDavid du Colombier case Tframeset+RBRA:
9509a747e4fSDavid du Colombier if(is->kidstk == nil) {
9519a747e4fSDavid du Colombier if(warn)
9529a747e4fSDavid du Colombier fprint(2, "warning: unexpected </FRAMESET>\n");
9539a747e4fSDavid du Colombier continue;
9549a747e4fSDavid du Colombier }
9559a747e4fSDavid du Colombier ks = is->kidstk;
9569a747e4fSDavid du Colombier // put kids back in original order
9579a747e4fSDavid du Colombier // and add blank frames to fill out cells
9589a747e4fSDavid du Colombier n = ks->nrows*ks->ncols;
9599a747e4fSDavid du Colombier nblank = n - _listlen((List*)ks->kidinfos);
9609a747e4fSDavid du Colombier while(nblank-- > 0)
9619a747e4fSDavid du Colombier ks->kidinfos = newkidinfo(0, ks->kidinfos);
9629a747e4fSDavid du Colombier ks->kidinfos = (Kidinfo*)_revlist((List*)ks->kidinfos);
9639a747e4fSDavid du Colombier is->kidstk = is->kidstk->nextframeset;
9649a747e4fSDavid du Colombier if(is->kidstk == nil) {
9659a747e4fSDavid du Colombier // end input
9669a747e4fSDavid du Colombier ans = nil;
9679a747e4fSDavid du Colombier goto return_ans;
9689a747e4fSDavid du Colombier }
9699a747e4fSDavid du Colombier break;
9709a747e4fSDavid du Colombier
9719a747e4fSDavid du Colombier // <!ELEMENT H1 - - (%text;)*>, etc.
9729a747e4fSDavid du Colombier case Th1:
9739a747e4fSDavid du Colombier case Th2:
9749a747e4fSDavid du Colombier case Th3:
9759a747e4fSDavid du Colombier case Th4:
9769a747e4fSDavid du Colombier case Th5:
9779a747e4fSDavid du Colombier case Th6:
9789a747e4fSDavid du Colombier bramt = 1;
9799a747e4fSDavid du Colombier if(ps->items == ps->lastit)
9809a747e4fSDavid du Colombier bramt = 0;
9819a747e4fSDavid du Colombier addbrk(ps, bramt, IFcleft|IFcright);
9829a747e4fSDavid du Colombier sz = Verylarge - (tag - Th1);
9839a747e4fSDavid du Colombier if(sz < Tiny)
9849a747e4fSDavid du Colombier sz = Tiny;
9859a747e4fSDavid du Colombier pushfontsize(ps, sz);
9869a747e4fSDavid du Colombier sty = top(&ps->fntstylestk, FntR);
9879a747e4fSDavid du Colombier if(tag == Th1)
9889a747e4fSDavid du Colombier sty = FntB;
9899a747e4fSDavid du Colombier pushfontstyle(ps, sty);
9909a747e4fSDavid du Colombier pushjust(ps, atabval(tok, Aalign, align_tab, NALIGNTAB, ps->curjust));
9919a747e4fSDavid du Colombier ps->skipwhite = 1;
9929a747e4fSDavid du Colombier break;
9939a747e4fSDavid du Colombier
9949a747e4fSDavid du Colombier case Th1+RBRA:
9959a747e4fSDavid du Colombier case Th2+RBRA:
9969a747e4fSDavid du Colombier case Th3+RBRA:
9979a747e4fSDavid du Colombier case Th4+RBRA:
9989a747e4fSDavid du Colombier case Th5+RBRA:
9999a747e4fSDavid du Colombier case Th6+RBRA:
10009a747e4fSDavid du Colombier addbrk(ps, 1, IFcleft|IFcright);
10019a747e4fSDavid du Colombier popfontsize(ps);
10029a747e4fSDavid du Colombier popfontstyle(ps);
10039a747e4fSDavid du Colombier popjust(ps);
10049a747e4fSDavid du Colombier break;
10059a747e4fSDavid du Colombier
10069a747e4fSDavid du Colombier case Thead:
10079a747e4fSDavid du Colombier // HTML spec says ignore regular markup in head,
10089a747e4fSDavid du Colombier // but Netscape and IE don't
10099a747e4fSDavid du Colombier // ps.skipping = 1;
10109a747e4fSDavid du Colombier break;
10119a747e4fSDavid du Colombier
10129a747e4fSDavid du Colombier case Thead+RBRA:
10139a747e4fSDavid du Colombier ps->skipping = 0;
10149a747e4fSDavid du Colombier break;
10159a747e4fSDavid du Colombier
10169a747e4fSDavid du Colombier // <!ELEMENT HR - O EMPTY>
10179a747e4fSDavid du Colombier case Thr:
10189a747e4fSDavid du Colombier al = atabval(tok, Aalign, align_tab, NALIGNTAB, ALcenter);
10199a747e4fSDavid du Colombier sz = auintval(tok, Asize, HRSZ);
10209a747e4fSDavid du Colombier wd = adimen(tok, Awidth);
10219a747e4fSDavid du Colombier if(dimenkind(wd) == Dnone)
10229a747e4fSDavid du Colombier wd = makedimen(Dpercent, 100);
10239a747e4fSDavid du Colombier nosh = aflagval(tok, Anoshade);
1024*684b447eSDavid du Colombier color = acolorval(tok, Acolor, 0);
1025*684b447eSDavid du Colombier additem(ps, newirule(al, sz, nosh, color, wd), tok);
10269a747e4fSDavid du Colombier addbrk(ps, 0, 0);
10279a747e4fSDavid du Colombier break;
10289a747e4fSDavid du Colombier
10299a747e4fSDavid du Colombier case Ti:
10309a747e4fSDavid du Colombier case Tcite:
10319a747e4fSDavid du Colombier case Tdfn:
10329a747e4fSDavid du Colombier case Tem:
10339a747e4fSDavid du Colombier case Tvar:
10349a747e4fSDavid du Colombier case Taddress:
10359a747e4fSDavid du Colombier pushfontstyle(ps, FntI);
10369a747e4fSDavid du Colombier break;
10379a747e4fSDavid du Colombier
10389a747e4fSDavid du Colombier // <!ELEMENT IMG - O EMPTY>
10399a747e4fSDavid du Colombier case Timg:
10409a747e4fSDavid du Colombier map = nil;
10419a747e4fSDavid du Colombier oldcuranchor = ps->curanchor;
10429a747e4fSDavid du Colombier if(_tokaval(tok, Ausemap, &usemap, 0)) {
10439a747e4fSDavid du Colombier if(!_prefix(L"#", usemap)) {
10449a747e4fSDavid du Colombier if(warn)
10459a747e4fSDavid du Colombier fprint(2, "warning: can't handle non-local map %S\n", usemap);
10469a747e4fSDavid du Colombier }
10479a747e4fSDavid du Colombier else {
10489a747e4fSDavid du Colombier map = getmap(di, usemap+1);
10499a747e4fSDavid du Colombier if(ps->curanchor == 0) {
10509a747e4fSDavid du Colombier di->anchors = newanchor(++is->nanchors, nil, nil, di->target, di->anchors);
10519a747e4fSDavid du Colombier ps->curanchor = is->nanchors;
10529a747e4fSDavid du Colombier }
10539a747e4fSDavid du Colombier }
10549a747e4fSDavid du Colombier }
10559a747e4fSDavid du Colombier align = atabval(tok, Aalign, align_tab, NALIGNTAB, ALbottom);
10569a747e4fSDavid du Colombier dfltbd = 0;
10579a747e4fSDavid du Colombier if(ps->curanchor != 0)
10589a747e4fSDavid du Colombier dfltbd = 2;
10599a747e4fSDavid du Colombier src = aurlval(tok, Asrc, nil, di->base);
10609a747e4fSDavid du Colombier if(src == nil) {
10619a747e4fSDavid du Colombier if(warn)
10629a747e4fSDavid du Colombier fprint(2, "warning: <img> has no src attribute\n");
10639a747e4fSDavid du Colombier ps->curanchor = oldcuranchor;
10649a747e4fSDavid du Colombier continue;
10659a747e4fSDavid du Colombier }
10669a747e4fSDavid du Colombier img = newiimage(src,
10679a747e4fSDavid du Colombier aval(tok, Aalt),
10689a747e4fSDavid du Colombier align,
10699a747e4fSDavid du Colombier auintval(tok, Awidth, 0),
10709a747e4fSDavid du Colombier auintval(tok, Aheight, 0),
10719a747e4fSDavid du Colombier auintval(tok, Ahspace, IMGHSPACE),
10729a747e4fSDavid du Colombier auintval(tok, Avspace, IMGVSPACE),
10739a747e4fSDavid du Colombier auintval(tok, Aborder, dfltbd),
10749a747e4fSDavid du Colombier aflagval(tok, Aismap),
10759a747e4fSDavid du Colombier map);
10769a747e4fSDavid du Colombier if(align == ALleft || align == ALright) {
10779a747e4fSDavid du Colombier additem(ps, newifloat(img, align), tok);
10789a747e4fSDavid du Colombier // if no hspace specified, use FLTIMGHSPACE
10799a747e4fSDavid du Colombier if(!_tokaval(tok, Ahspace, &val, 0))
10809a747e4fSDavid du Colombier ((Iimage*)img)->hspace = FLTIMGHSPACE;
10819a747e4fSDavid du Colombier }
10829a747e4fSDavid du Colombier else {
10839a747e4fSDavid du Colombier ps->skipwhite = 0;
10849a747e4fSDavid du Colombier additem(ps, img, tok);
10859a747e4fSDavid du Colombier }
10869a747e4fSDavid du Colombier if(!ps->skipping) {
10879a747e4fSDavid du Colombier ((Iimage*)img)->nextimage = di->images;
10889a747e4fSDavid du Colombier di->images = (Iimage*)img;
10899a747e4fSDavid du Colombier }
10909a747e4fSDavid du Colombier ps->curanchor = oldcuranchor;
10919a747e4fSDavid du Colombier break;
10929a747e4fSDavid du Colombier
10939a747e4fSDavid du Colombier // <!ELEMENT INPUT - O EMPTY>
10949a747e4fSDavid du Colombier case Tinput:
10959a747e4fSDavid du Colombier ps->skipwhite = 0;
10969a747e4fSDavid du Colombier if(is->curform == nil) {
10979a747e4fSDavid du Colombier if(warn)
10989a747e4fSDavid du Colombier fprint(2, "<INPUT> not inside <FORM>\n");
10999a747e4fSDavid du Colombier continue;
11009a747e4fSDavid du Colombier }
11019a747e4fSDavid du Colombier is->curform->fields = field = newformfield(
11029a747e4fSDavid du Colombier atabval(tok, Atype, input_tab, NINPUTTAB, Ftext),
11039a747e4fSDavid du Colombier ++is->curform->nfields,
11049a747e4fSDavid du Colombier is->curform,
11059a747e4fSDavid du Colombier aval(tok, Aname),
11069a747e4fSDavid du Colombier aval(tok, Avalue),
11079a747e4fSDavid du Colombier auintval(tok, Asize, 0),
11089a747e4fSDavid du Colombier auintval(tok, Amaxlength, 1000),
11099a747e4fSDavid du Colombier is->curform->fields);
11109a747e4fSDavid du Colombier if(aflagval(tok, Achecked))
11119a747e4fSDavid du Colombier field->flags = FFchecked;
11129a747e4fSDavid du Colombier
11139a747e4fSDavid du Colombier switch(field->ftype) {
11149a747e4fSDavid du Colombier case Ftext:
11159a747e4fSDavid du Colombier case Fpassword:
11169a747e4fSDavid du Colombier case Ffile:
11179a747e4fSDavid du Colombier if(field->size == 0)
11189a747e4fSDavid du Colombier field->size = 20;
11199a747e4fSDavid du Colombier break;
11209a747e4fSDavid du Colombier
11219a747e4fSDavid du Colombier case Fcheckbox:
11229a747e4fSDavid du Colombier if(field->name == nil) {
11239a747e4fSDavid du Colombier if(warn)
11249a747e4fSDavid du Colombier fprint(2, "warning: checkbox form field missing name\n");
11259a747e4fSDavid du Colombier continue;
11269a747e4fSDavid du Colombier }
11279a747e4fSDavid du Colombier if(field->value == nil)
11289a747e4fSDavid du Colombier field->value = _Strdup(L"1");
11299a747e4fSDavid du Colombier break;
11309a747e4fSDavid du Colombier
11319a747e4fSDavid du Colombier case Fradio:
11329a747e4fSDavid du Colombier if(field->name == nil || field->value == nil) {
11339a747e4fSDavid du Colombier if(warn)
11349a747e4fSDavid du Colombier fprint(2, "warning: radio form field missing name or value\n");
11359a747e4fSDavid du Colombier continue;
11369a747e4fSDavid du Colombier }
11379a747e4fSDavid du Colombier break;
11389a747e4fSDavid du Colombier
11399a747e4fSDavid du Colombier case Fsubmit:
11409a747e4fSDavid du Colombier if(field->value == nil)
11419a747e4fSDavid du Colombier field->value = _Strdup(L"Submit");
11429a747e4fSDavid du Colombier if(field->name == nil)
11439a747e4fSDavid du Colombier field->name = _Strdup(L"_no_name_submit_");
11449a747e4fSDavid du Colombier break;
11459a747e4fSDavid du Colombier
11469a747e4fSDavid du Colombier case Fimage:
11479a747e4fSDavid du Colombier src = aurlval(tok, Asrc, nil, di->base);
11489a747e4fSDavid du Colombier if(src == nil) {
11499a747e4fSDavid du Colombier if(warn)
11509a747e4fSDavid du Colombier fprint(2, "warning: image form field missing src\n");
11519a747e4fSDavid du Colombier continue;
11529a747e4fSDavid du Colombier }
11539a747e4fSDavid du Colombier // width and height attrs aren't specified in HTML 3.2,
11549a747e4fSDavid du Colombier // but some people provide them and they help avoid
11559a747e4fSDavid du Colombier // a relayout
11569a747e4fSDavid du Colombier field->image = newiimage(src,
11579a747e4fSDavid du Colombier astrval(tok, Aalt, L"Submit"),
11589a747e4fSDavid du Colombier atabval(tok, Aalign, align_tab, NALIGNTAB, ALbottom),
11599a747e4fSDavid du Colombier auintval(tok, Awidth, 0), auintval(tok, Aheight, 0),
11609a747e4fSDavid du Colombier 0, 0, 0, 0, nil);
11619a747e4fSDavid du Colombier ii = (Iimage*)field->image;
11629a747e4fSDavid du Colombier ii->nextimage = di->images;
11639a747e4fSDavid du Colombier di->images = ii;
11649a747e4fSDavid du Colombier break;
11659a747e4fSDavid du Colombier
11669a747e4fSDavid du Colombier case Freset:
11679a747e4fSDavid du Colombier if(field->value == nil)
11689a747e4fSDavid du Colombier field->value = _Strdup(L"Reset");
11699a747e4fSDavid du Colombier break;
11709a747e4fSDavid du Colombier
11719a747e4fSDavid du Colombier case Fbutton:
11729a747e4fSDavid du Colombier if(field->value == nil)
11739a747e4fSDavid du Colombier field->value = _Strdup(L" ");
11749a747e4fSDavid du Colombier break;
11759a747e4fSDavid du Colombier }
11769a747e4fSDavid du Colombier ffit = newiformfield(field);
11779a747e4fSDavid du Colombier additem(ps, ffit, tok);
11789a747e4fSDavid du Colombier if(ffit->genattr != nil)
11799a747e4fSDavid du Colombier field->events = ffit->genattr->events;
11809a747e4fSDavid du Colombier break;
11819a747e4fSDavid du Colombier
11829a747e4fSDavid du Colombier // <!ENTITY ISINDEX - O EMPTY>
11839a747e4fSDavid du Colombier case Tisindex:
11849a747e4fSDavid du Colombier ps->skipwhite = 0;
11859a747e4fSDavid du Colombier prompt = astrval(tok, Aprompt, L"Index search terms:");
11869a747e4fSDavid du Colombier target = atargval(tok, di->target);
11879a747e4fSDavid du Colombier additem(ps, textit(ps, prompt), tok);
11889a747e4fSDavid du Colombier frm = newform(++is->nforms,
11899a747e4fSDavid du Colombier nil,
11909a747e4fSDavid du Colombier di->base,
11919a747e4fSDavid du Colombier target,
11929a747e4fSDavid du Colombier HGet,
11939a747e4fSDavid du Colombier di->forms);
11949a747e4fSDavid du Colombier di->forms = frm;
11959a747e4fSDavid du Colombier ff = newformfield(Ftext,
11969a747e4fSDavid du Colombier 1,
11979a747e4fSDavid du Colombier frm,
11989a747e4fSDavid du Colombier _Strdup(L"_ISINDEX_"),
11999a747e4fSDavid du Colombier nil,
12009a747e4fSDavid du Colombier 50,
12019a747e4fSDavid du Colombier 1000,
12029a747e4fSDavid du Colombier nil);
12039a747e4fSDavid du Colombier frm->fields = ff;
12049a747e4fSDavid du Colombier frm->nfields = 1;
12059a747e4fSDavid du Colombier additem(ps, newiformfield(ff), tok);
12069a747e4fSDavid du Colombier addbrk(ps, 1, 0);
12079a747e4fSDavid du Colombier break;
12089a747e4fSDavid du Colombier
12099a747e4fSDavid du Colombier // <!ELEMENT LI - O %flow>
12109a747e4fSDavid du Colombier case Tli:
12119a747e4fSDavid du Colombier if(ps->listtypestk.n == 0) {
12129a747e4fSDavid du Colombier if(warn)
12139a747e4fSDavid du Colombier fprint(2, "<LI> not in list\n");
12149a747e4fSDavid du Colombier continue;
12159a747e4fSDavid du Colombier }
12169a747e4fSDavid du Colombier ty = top(&ps->listtypestk, 0);
12179a747e4fSDavid du Colombier ty2 = listtyval(tok, ty);
12189a747e4fSDavid du Colombier if(ty != ty2) {
12199a747e4fSDavid du Colombier ty = ty2;
12209a747e4fSDavid du Colombier push(&ps->listtypestk, ty2);
12219a747e4fSDavid du Colombier }
12229a747e4fSDavid du Colombier v = aintval(tok, Avalue, top(&ps->listcntstk, 1));
12239a747e4fSDavid du Colombier if(ty == LTdisc || ty == LTsquare || ty == LTcircle)
12249a747e4fSDavid du Colombier hang = 10*LISTTAB - 3;
12259a747e4fSDavid du Colombier else
12269a747e4fSDavid du Colombier hang = 10*LISTTAB - 1;
12279a747e4fSDavid du Colombier changehang(ps, hang);
12289a747e4fSDavid du Colombier addtext(ps, listmark(ty, v));
12299a747e4fSDavid du Colombier push(&ps->listcntstk, v + 1);
12309a747e4fSDavid du Colombier changehang(ps, -hang);
12319a747e4fSDavid du Colombier ps->skipwhite = 1;
12329a747e4fSDavid du Colombier break;
12339a747e4fSDavid du Colombier
12349a747e4fSDavid du Colombier // <!ELEMENT MAP - - (AREA)+>
12359a747e4fSDavid du Colombier case Tmap:
12369a747e4fSDavid du Colombier if(_tokaval(tok, Aname, &name, 0))
12379a747e4fSDavid du Colombier is->curmap = getmap(di, name);
12389a747e4fSDavid du Colombier break;
12399a747e4fSDavid du Colombier
12409a747e4fSDavid du Colombier case Tmap+RBRA:
12419a747e4fSDavid du Colombier map = is->curmap;
12429a747e4fSDavid du Colombier if(map == nil) {
12439a747e4fSDavid du Colombier if(warn)
12449a747e4fSDavid du Colombier fprint(2, "warning: unexpected </MAP>\n");
12459a747e4fSDavid du Colombier continue;
12469a747e4fSDavid du Colombier }
12479a747e4fSDavid du Colombier map->areas = (Area*)_revlist((List*)map->areas);
12489a747e4fSDavid du Colombier break;
12499a747e4fSDavid du Colombier
12509a747e4fSDavid du Colombier case Tmeta:
12519a747e4fSDavid du Colombier if(ps->skipping)
12529a747e4fSDavid du Colombier continue;
12539a747e4fSDavid du Colombier if(_tokaval(tok, Ahttp_equiv, &equiv, 0)) {
12549a747e4fSDavid du Colombier val = aval(tok, Acontent);
12555d459b5aSDavid du Colombier n = _Strlen(equiv);
12569a747e4fSDavid du Colombier if(!_Strncmpci(equiv, n, L"refresh"))
12579a747e4fSDavid du Colombier di->refresh = val;
12589a747e4fSDavid du Colombier else if(!_Strncmpci(equiv, n, L"content-script-type")) {
12595d459b5aSDavid du Colombier n = _Strlen(val);
12609a747e4fSDavid du Colombier if(!_Strncmpci(val, n, L"javascript")
12619a747e4fSDavid du Colombier || !_Strncmpci(val, n, L"jscript1.1")
12629a747e4fSDavid du Colombier || !_Strncmpci(val, n, L"jscript"))
12639a747e4fSDavid du Colombier di->scripttype = TextJavascript;
12649a747e4fSDavid du Colombier else {
12659a747e4fSDavid du Colombier if(warn)
12669a747e4fSDavid du Colombier fprint(2, "unimplemented script type %S\n", val);
12679a747e4fSDavid du Colombier di->scripttype = UnknownType;
12689a747e4fSDavid du Colombier }
12699a747e4fSDavid du Colombier }
12709a747e4fSDavid du Colombier }
12719a747e4fSDavid du Colombier break;
12729a747e4fSDavid du Colombier
12739a747e4fSDavid du Colombier // Nobr is NOT in HMTL 4.0, but it is ubiquitous on the web
12749a747e4fSDavid du Colombier case Tnobr:
12759a747e4fSDavid du Colombier ps->skipwhite = 0;
12769a747e4fSDavid du Colombier ps->curstate &= ~IFwrap;
12779a747e4fSDavid du Colombier break;
12789a747e4fSDavid du Colombier
12799a747e4fSDavid du Colombier case Tnobr+RBRA:
12809a747e4fSDavid du Colombier ps->curstate |= IFwrap;
12819a747e4fSDavid du Colombier break;
12829a747e4fSDavid du Colombier
12839a747e4fSDavid du Colombier // We do frames, so skip stuff in noframes
12849a747e4fSDavid du Colombier case Tnoframes:
12859a747e4fSDavid du Colombier ps->skipping = 1;
12869a747e4fSDavid du Colombier break;
12879a747e4fSDavid du Colombier
12889a747e4fSDavid du Colombier case Tnoframes+RBRA:
12899a747e4fSDavid du Colombier ps->skipping = 0;
12909a747e4fSDavid du Colombier break;
12919a747e4fSDavid du Colombier
12929a747e4fSDavid du Colombier // We do scripts (if enabled), so skip stuff in noscripts
12939a747e4fSDavid du Colombier case Tnoscript:
12949a747e4fSDavid du Colombier if(doscripts)
12959a747e4fSDavid du Colombier ps->skipping = 1;
12969a747e4fSDavid du Colombier break;
12979a747e4fSDavid du Colombier
12989a747e4fSDavid du Colombier case Tnoscript+RBRA:
12999a747e4fSDavid du Colombier if(doscripts)
13009a747e4fSDavid du Colombier ps->skipping = 0;
13019a747e4fSDavid du Colombier break;
13029a747e4fSDavid du Colombier
13039a747e4fSDavid du Colombier // <!ELEMENT OPTION - O ( //PCDATA)>
13049a747e4fSDavid du Colombier case Toption:
13059a747e4fSDavid du Colombier if(is->curform == nil || is->curform->fields == nil) {
13069a747e4fSDavid du Colombier if(warn)
13079a747e4fSDavid du Colombier fprint(2, "warning: <OPTION> not in <SELECT>\n");
13089a747e4fSDavid du Colombier continue;
13099a747e4fSDavid du Colombier }
13109a747e4fSDavid du Colombier field = is->curform->fields;
13119a747e4fSDavid du Colombier if(field->ftype != Fselect) {
13129a747e4fSDavid du Colombier if(warn)
13139a747e4fSDavid du Colombier fprint(2, "warning: <OPTION> not in <SELECT>\n");
13149a747e4fSDavid du Colombier continue;
13159a747e4fSDavid du Colombier }
13169a747e4fSDavid du Colombier val = aval(tok, Avalue);
13179a747e4fSDavid du Colombier option = newoption(aflagval(tok, Aselected), val, nil, field->options);
13189a747e4fSDavid du Colombier field->options = option;
13199a747e4fSDavid du Colombier option->display = getpcdata(toks, tokslen, &toki);
13209a747e4fSDavid du Colombier if(val == nil)
13219a747e4fSDavid du Colombier option->value = _Strdup(option->display);
13229a747e4fSDavid du Colombier break;
13239a747e4fSDavid du Colombier
13249a747e4fSDavid du Colombier // <!ELEMENT P - O (%text)* >
13259a747e4fSDavid du Colombier case Tp:
13269a747e4fSDavid du Colombier pushjust(ps, atabval(tok, Aalign, align_tab, NALIGNTAB, ps->curjust));
13279a747e4fSDavid du Colombier ps->inpar = 1;
13289a747e4fSDavid du Colombier ps->skipwhite = 1;
13299a747e4fSDavid du Colombier break;
13309a747e4fSDavid du Colombier
13319a747e4fSDavid du Colombier case Tp+RBRA:
13329a747e4fSDavid du Colombier break;
13339a747e4fSDavid du Colombier
13349a747e4fSDavid du Colombier // <!ELEMENT PARAM - O EMPTY>
13359a747e4fSDavid du Colombier // Do something when we do applets...
13369a747e4fSDavid du Colombier case Tparam:
13379a747e4fSDavid du Colombier break;
13389a747e4fSDavid du Colombier
13399a747e4fSDavid du Colombier // <!ELEMENT PRE - - (%text)* -(IMG|BIG|SMALL|SUB|SUP|FONT) >
13409a747e4fSDavid du Colombier case Tpre:
13419a747e4fSDavid du Colombier ps->curstate &= ~IFwrap;
13429a747e4fSDavid du Colombier ps->literal = 1;
13439a747e4fSDavid du Colombier ps->skipwhite = 0;
13449a747e4fSDavid du Colombier pushfontstyle(ps, FntT);
13459a747e4fSDavid du Colombier break;
13469a747e4fSDavid du Colombier
13479a747e4fSDavid du Colombier case Tpre+RBRA:
13489a747e4fSDavid du Colombier ps->curstate |= IFwrap;
13499a747e4fSDavid du Colombier if(ps->literal) {
13509a747e4fSDavid du Colombier popfontstyle(ps);
13519a747e4fSDavid du Colombier ps->literal = 0;
13529a747e4fSDavid du Colombier }
13539a747e4fSDavid du Colombier break;
13549a747e4fSDavid du Colombier
13559a747e4fSDavid du Colombier // <!ELEMENT SCRIPT - - CDATA>
13569a747e4fSDavid du Colombier case Tscript:
13579a747e4fSDavid du Colombier if(doscripts) {
13589a747e4fSDavid du Colombier if(!di->hasscripts) {
13599a747e4fSDavid du Colombier if(di->scripttype == TextJavascript) {
13609a747e4fSDavid du Colombier // TODO: initialize script if nec.
13619a747e4fSDavid du Colombier // initjscript(di);
13629a747e4fSDavid du Colombier di->hasscripts = 1;
13639a747e4fSDavid du Colombier }
13649a747e4fSDavid du Colombier }
13659a747e4fSDavid du Colombier }
13669a747e4fSDavid du Colombier if(!di->hasscripts) {
13679a747e4fSDavid du Colombier if(warn)
13689a747e4fSDavid du Colombier fprint(2, "warning: <SCRIPT> ignored\n");
13699a747e4fSDavid du Colombier ps->skipping = 1;
13709a747e4fSDavid du Colombier }
13719a747e4fSDavid du Colombier else {
13729a747e4fSDavid du Colombier scriptsrc = aurlval(tok, Asrc, nil, di->base);
13739a747e4fSDavid du Colombier script = nil;
13749a747e4fSDavid du Colombier if(scriptsrc != nil) {
13759a747e4fSDavid du Colombier if(warn)
13769a747e4fSDavid du Colombier fprint(2, "warning: non-local <SCRIPT> ignored\n");
13779a747e4fSDavid du Colombier free(scriptsrc);
13789a747e4fSDavid du Colombier }
13799a747e4fSDavid du Colombier else {
13809a747e4fSDavid du Colombier script = getpcdata(toks, tokslen, &toki);
13819a747e4fSDavid du Colombier }
13829a747e4fSDavid du Colombier if(script != nil) {
13839a747e4fSDavid du Colombier if(warn)
13849a747e4fSDavid du Colombier fprint(2, "script ignored\n");
13859a747e4fSDavid du Colombier free(script);
13869a747e4fSDavid du Colombier }
13879a747e4fSDavid du Colombier }
13889a747e4fSDavid du Colombier break;
13899a747e4fSDavid du Colombier
13909a747e4fSDavid du Colombier case Tscript+RBRA:
13919a747e4fSDavid du Colombier ps->skipping = 0;
13929a747e4fSDavid du Colombier break;
13939a747e4fSDavid du Colombier
13949a747e4fSDavid du Colombier // <!ELEMENT SELECT - - (OPTION+)>
13959a747e4fSDavid du Colombier case Tselect:
13969a747e4fSDavid du Colombier if(is->curform == nil) {
13979a747e4fSDavid du Colombier if(warn)
13989a747e4fSDavid du Colombier fprint(2, "<SELECT> not inside <FORM>\n");
13999a747e4fSDavid du Colombier continue;
14009a747e4fSDavid du Colombier }
14019a747e4fSDavid du Colombier field = newformfield(Fselect,
14029a747e4fSDavid du Colombier ++is->curform->nfields,
14039a747e4fSDavid du Colombier is->curform,
14049a747e4fSDavid du Colombier aval(tok, Aname),
14059a747e4fSDavid du Colombier nil,
14069a747e4fSDavid du Colombier auintval(tok, Asize, 0),
14079a747e4fSDavid du Colombier 0,
14089a747e4fSDavid du Colombier is->curform->fields);
14099a747e4fSDavid du Colombier is->curform->fields = field;
14109a747e4fSDavid du Colombier if(aflagval(tok, Amultiple))
14119a747e4fSDavid du Colombier field->flags = FFmultiple;
14129a747e4fSDavid du Colombier ffit = newiformfield(field);
14139a747e4fSDavid du Colombier additem(ps, ffit, tok);
14149a747e4fSDavid du Colombier if(ffit->genattr != nil)
14159a747e4fSDavid du Colombier field->events = ffit->genattr->events;
14169a747e4fSDavid du Colombier // throw away stuff until next tag (should be <OPTION>)
14179a747e4fSDavid du Colombier s = getpcdata(toks, tokslen, &toki);
14189a747e4fSDavid du Colombier if(s != nil)
14199a747e4fSDavid du Colombier free(s);
14209a747e4fSDavid du Colombier break;
14219a747e4fSDavid du Colombier
14229a747e4fSDavid du Colombier case Tselect+RBRA:
14239a747e4fSDavid du Colombier if(is->curform == nil || is->curform->fields == nil) {
14249a747e4fSDavid du Colombier if(warn)
14259a747e4fSDavid du Colombier fprint(2, "warning: unexpected </SELECT>\n");
14269a747e4fSDavid du Colombier continue;
14279a747e4fSDavid du Colombier }
14289a747e4fSDavid du Colombier field = is->curform->fields;
14299a747e4fSDavid du Colombier if(field->ftype != Fselect)
14309a747e4fSDavid du Colombier continue;
14319a747e4fSDavid du Colombier // put options back in input order
14329a747e4fSDavid du Colombier field->options = (Option*)_revlist((List*)field->options);
14339a747e4fSDavid du Colombier break;
14349a747e4fSDavid du Colombier
14359a747e4fSDavid du Colombier // <!ELEMENT (STRIKE|U) - - (%text)*>
14369a747e4fSDavid du Colombier case Tstrike:
14379a747e4fSDavid du Colombier case Tu:
14389a747e4fSDavid du Colombier ps->curul = push(&ps->ulstk, (tag==Tstrike)? ULmid : ULunder);
14399a747e4fSDavid du Colombier break;
14409a747e4fSDavid du Colombier
14419a747e4fSDavid du Colombier case Tstrike+RBRA:
14429a747e4fSDavid du Colombier case Tu+RBRA:
14439a747e4fSDavid du Colombier if(ps->ulstk.n == 0) {
14449a747e4fSDavid du Colombier if(warn)
14459a747e4fSDavid du Colombier fprint(2, "warning: unexpected %T\n", tok);
14469a747e4fSDavid du Colombier continue;
14479a747e4fSDavid du Colombier }
14489a747e4fSDavid du Colombier ps->curul = popretnewtop(&ps->ulstk, ULnone);
14499a747e4fSDavid du Colombier break;
14509a747e4fSDavid du Colombier
14519a747e4fSDavid du Colombier // <!ELEMENT STYLE - - CDATA>
14529a747e4fSDavid du Colombier case Tstyle:
14539a747e4fSDavid du Colombier if(warn)
14549a747e4fSDavid du Colombier fprint(2, "warning: unimplemented <STYLE>\n");
14559a747e4fSDavid du Colombier ps->skipping = 1;
14569a747e4fSDavid du Colombier break;
14579a747e4fSDavid du Colombier
14589a747e4fSDavid du Colombier case Tstyle+RBRA:
14599a747e4fSDavid du Colombier ps->skipping = 0;
14609a747e4fSDavid du Colombier break;
14619a747e4fSDavid du Colombier
14629a747e4fSDavid du Colombier // <!ELEMENT (SUB|SUP) - - (%text)*>
14639a747e4fSDavid du Colombier case Tsub:
14649a747e4fSDavid du Colombier case Tsup:
14659a747e4fSDavid du Colombier if(tag == Tsub)
14669a747e4fSDavid du Colombier ps->curvoff += SUBOFF;
14679a747e4fSDavid du Colombier else
14689a747e4fSDavid du Colombier ps->curvoff -= SUPOFF;
14699a747e4fSDavid du Colombier push(&ps->voffstk, ps->curvoff);
14709a747e4fSDavid du Colombier sz = top(&ps->fntsizestk, Normal);
14719a747e4fSDavid du Colombier pushfontsize(ps, sz - 1);
14729a747e4fSDavid du Colombier break;
14739a747e4fSDavid du Colombier
14749a747e4fSDavid du Colombier case Tsub+RBRA:
14759a747e4fSDavid du Colombier case Tsup+RBRA:
14769a747e4fSDavid du Colombier if(ps->voffstk.n == 0) {
14779a747e4fSDavid du Colombier if(warn)
14789a747e4fSDavid du Colombier fprint(2, "warning: unexpected %T\n", tok);
14799a747e4fSDavid du Colombier continue;
14809a747e4fSDavid du Colombier }
14819a747e4fSDavid du Colombier ps->curvoff = popretnewtop(&ps->voffstk, 0);
14829a747e4fSDavid du Colombier popfontsize(ps);
14839a747e4fSDavid du Colombier break;
14849a747e4fSDavid du Colombier
14859a747e4fSDavid du Colombier // <!ELEMENT TABLE - - (CAPTION?, TR+)>
14869a747e4fSDavid du Colombier case Ttable:
14879a747e4fSDavid du Colombier ps->skipwhite = 0;
14889a747e4fSDavid du Colombier tab = newtable(++is->ntables,
14899a747e4fSDavid du Colombier aalign(tok),
14909a747e4fSDavid du Colombier adimen(tok, Awidth),
14919a747e4fSDavid du Colombier aflagval(tok, Aborder),
14929a747e4fSDavid du Colombier auintval(tok, Acellspacing, TABSP),
14939a747e4fSDavid du Colombier auintval(tok, Acellpadding, TABPAD),
14949a747e4fSDavid du Colombier makebackground(nil, acolorval(tok, Abgcolor, ps->curbg.color)),
14959a747e4fSDavid du Colombier tok,
14969a747e4fSDavid du Colombier is->tabstk);
14979a747e4fSDavid du Colombier is->tabstk = tab;
14989a747e4fSDavid du Colombier curtab = tab;
14999a747e4fSDavid du Colombier break;
15009a747e4fSDavid du Colombier
15019a747e4fSDavid du Colombier case Ttable+RBRA:
15029a747e4fSDavid du Colombier if(curtab == nil) {
15039a747e4fSDavid du Colombier if(warn)
15049a747e4fSDavid du Colombier fprint(2, "warning: unexpected </TABLE>\n");
15059a747e4fSDavid du Colombier continue;
15069a747e4fSDavid du Colombier }
15079a747e4fSDavid du Colombier isempty = (curtab->cells == nil);
15089a747e4fSDavid du Colombier if(isempty) {
15099a747e4fSDavid du Colombier if(warn)
15109a747e4fSDavid du Colombier fprint(2, "warning: <TABLE> has no cells\n");
15119a747e4fSDavid du Colombier }
15129a747e4fSDavid du Colombier else {
15139a747e4fSDavid du Colombier ps = finishcell(curtab, ps);
15149a747e4fSDavid du Colombier if(curtab->rows != nil)
15159a747e4fSDavid du Colombier curtab->rows->flags = 0;
15169a747e4fSDavid du Colombier finish_table(curtab);
15179a747e4fSDavid du Colombier }
15189a747e4fSDavid du Colombier ps->skipping = 0;
15199a747e4fSDavid du Colombier if(!isempty) {
15209a747e4fSDavid du Colombier tabitem = newitable(curtab);
15219a747e4fSDavid du Colombier al = curtab->align.halign;
15229a747e4fSDavid du Colombier switch(al) {
15239a747e4fSDavid du Colombier case ALleft:
15249a747e4fSDavid du Colombier case ALright:
15259a747e4fSDavid du Colombier additem(ps, newifloat(tabitem, al), tok);
15269a747e4fSDavid du Colombier break;
15279a747e4fSDavid du Colombier default:
15289a747e4fSDavid du Colombier if(al == ALcenter)
15299a747e4fSDavid du Colombier pushjust(ps, ALcenter);
15309a747e4fSDavid du Colombier addbrk(ps, 0, 0);
15319a747e4fSDavid du Colombier if(ps->inpar) {
15329a747e4fSDavid du Colombier popjust(ps);
15339a747e4fSDavid du Colombier ps->inpar = 0;
15349a747e4fSDavid du Colombier }
15359a747e4fSDavid du Colombier additem(ps, tabitem, curtab->tabletok);
15369a747e4fSDavid du Colombier if(al == ALcenter)
15379a747e4fSDavid du Colombier popjust(ps);
15389a747e4fSDavid du Colombier break;
15399a747e4fSDavid du Colombier }
15409a747e4fSDavid du Colombier }
15419a747e4fSDavid du Colombier if(is->tabstk == nil) {
15429a747e4fSDavid du Colombier if(warn)
15439a747e4fSDavid du Colombier fprint(2, "warning: table stack is wrong\n");
15449a747e4fSDavid du Colombier }
15459a747e4fSDavid du Colombier else
15469a747e4fSDavid du Colombier is->tabstk = is->tabstk->next;
15479a747e4fSDavid du Colombier curtab->next = di->tables;
15489a747e4fSDavid du Colombier di->tables = curtab;
15499a747e4fSDavid du Colombier curtab = is->tabstk;
15509a747e4fSDavid du Colombier if(!isempty)
15519a747e4fSDavid du Colombier addbrk(ps, 0, 0);
15529a747e4fSDavid du Colombier break;
15539a747e4fSDavid du Colombier
15549a747e4fSDavid du Colombier // <!ELEMENT (TH|TD) - O %body.content>
15559a747e4fSDavid du Colombier // Cells for a row are accumulated in reverse order.
15569a747e4fSDavid du Colombier // We push ps on a stack, and use a new one to accumulate
15579a747e4fSDavid du Colombier // the contents of the cell.
15589a747e4fSDavid du Colombier case Ttd:
15599a747e4fSDavid du Colombier case Tth:
15609a747e4fSDavid du Colombier if(curtab == nil) {
15619a747e4fSDavid du Colombier if(warn)
15629a747e4fSDavid du Colombier fprint(2, "%T outside <TABLE>\n", tok);
15639a747e4fSDavid du Colombier continue;
15649a747e4fSDavid du Colombier }
15659a747e4fSDavid du Colombier if(ps->inpar) {
15669a747e4fSDavid du Colombier popjust(ps);
15679a747e4fSDavid du Colombier ps->inpar = 0;
15689a747e4fSDavid du Colombier }
15699a747e4fSDavid du Colombier ps = finishcell(curtab, ps);
15709a747e4fSDavid du Colombier tr = nil;
15719a747e4fSDavid du Colombier if(curtab->rows != nil)
15729a747e4fSDavid du Colombier tr = curtab->rows;
15739a747e4fSDavid du Colombier if(tr == nil || !tr->flags) {
15749a747e4fSDavid du Colombier if(warn)
15759a747e4fSDavid du Colombier fprint(2, "%T outside row\n", tok);
15769a747e4fSDavid du Colombier tr = newtablerow(makealign(ALnone, ALnone),
15779a747e4fSDavid du Colombier makebackground(nil, curtab->background.color),
15789a747e4fSDavid du Colombier TFparsing,
15799a747e4fSDavid du Colombier curtab->rows);
15809a747e4fSDavid du Colombier curtab->rows = tr;
15819a747e4fSDavid du Colombier }
15829a747e4fSDavid du Colombier ps = cell_pstate(ps, tag == Tth);
15839a747e4fSDavid du Colombier flags = TFparsing;
15849a747e4fSDavid du Colombier if(aflagval(tok, Anowrap)) {
15859a747e4fSDavid du Colombier flags |= TFnowrap;
15869a747e4fSDavid du Colombier ps->curstate &= ~IFwrap;
15879a747e4fSDavid du Colombier }
15889a747e4fSDavid du Colombier if(tag == Tth)
15899a747e4fSDavid du Colombier flags |= TFisth;
15909a747e4fSDavid du Colombier c = newtablecell(curtab->cells==nil? 1 : curtab->cells->cellid+1,
15919a747e4fSDavid du Colombier auintval(tok, Arowspan, 1),
15929a747e4fSDavid du Colombier auintval(tok, Acolspan, 1),
15939a747e4fSDavid du Colombier aalign(tok),
15949a747e4fSDavid du Colombier adimen(tok, Awidth),
15959a747e4fSDavid du Colombier auintval(tok, Aheight, 0),
15969a747e4fSDavid du Colombier makebackground(nil, acolorval(tok, Abgcolor, tr->background.color)),
15979a747e4fSDavid du Colombier flags,
15989a747e4fSDavid du Colombier curtab->cells);
15999a747e4fSDavid du Colombier curtab->cells = c;
16009a747e4fSDavid du Colombier ps->curbg = c->background;
16019a747e4fSDavid du Colombier if(c->align.halign == ALnone) {
16029a747e4fSDavid du Colombier if(tr->align.halign != ALnone)
16039a747e4fSDavid du Colombier c->align.halign = tr->align.halign;
16049a747e4fSDavid du Colombier else if(tag == Tth)
16059a747e4fSDavid du Colombier c->align.halign = ALcenter;
16069a747e4fSDavid du Colombier else
16079a747e4fSDavid du Colombier c->align.halign = ALleft;
16089a747e4fSDavid du Colombier }
16099a747e4fSDavid du Colombier if(c->align.valign == ALnone) {
16109a747e4fSDavid du Colombier if(tr->align.valign != ALnone)
16119a747e4fSDavid du Colombier c->align.valign = tr->align.valign;
16129a747e4fSDavid du Colombier else
16139a747e4fSDavid du Colombier c->align.valign = ALmiddle;
16149a747e4fSDavid du Colombier }
16159a747e4fSDavid du Colombier c->nextinrow = tr->cells;
16169a747e4fSDavid du Colombier tr->cells = c;
16179a747e4fSDavid du Colombier break;
16189a747e4fSDavid du Colombier
16199a747e4fSDavid du Colombier case Ttd+RBRA:
16209a747e4fSDavid du Colombier case Tth+RBRA:
16219a747e4fSDavid du Colombier if(curtab == nil || curtab->cells == nil) {
16229a747e4fSDavid du Colombier if(warn)
16239a747e4fSDavid du Colombier fprint(2, "unexpected %T\n", tok);
16249a747e4fSDavid du Colombier continue;
16259a747e4fSDavid du Colombier }
16269a747e4fSDavid du Colombier ps = finishcell(curtab, ps);
16279a747e4fSDavid du Colombier break;
16289a747e4fSDavid du Colombier
16299a747e4fSDavid du Colombier // <!ELEMENT TEXTAREA - - ( //PCDATA)>
16309a747e4fSDavid du Colombier case Ttextarea:
16319a747e4fSDavid du Colombier if(is->curform == nil) {
16329a747e4fSDavid du Colombier if(warn)
16339a747e4fSDavid du Colombier fprint(2, "<TEXTAREA> not inside <FORM>\n");
16349a747e4fSDavid du Colombier continue;
16359a747e4fSDavid du Colombier }
16369a747e4fSDavid du Colombier field = newformfield(Ftextarea,
16379a747e4fSDavid du Colombier ++is->curform->nfields,
16389a747e4fSDavid du Colombier is->curform,
16399a747e4fSDavid du Colombier aval(tok, Aname),
16409a747e4fSDavid du Colombier nil,
16419a747e4fSDavid du Colombier 0,
16429a747e4fSDavid du Colombier 0,
16439a747e4fSDavid du Colombier is->curform->fields);
16449a747e4fSDavid du Colombier is->curform->fields = field;
16459a747e4fSDavid du Colombier field->rows = auintval(tok, Arows, 3);
16469a747e4fSDavid du Colombier field->cols = auintval(tok, Acols, 50);
16479a747e4fSDavid du Colombier field->value = getpcdata(toks, tokslen, &toki);
16489a747e4fSDavid du Colombier if(warn && toki < tokslen - 1 && toks[toki + 1].tag != Ttextarea + RBRA)
16499a747e4fSDavid du Colombier fprint(2, "warning: <TEXTAREA> data ended by %T\n", &toks[toki + 1]);
16509a747e4fSDavid du Colombier ffit = newiformfield(field);
16519a747e4fSDavid du Colombier additem(ps, ffit, tok);
16529a747e4fSDavid du Colombier if(ffit->genattr != nil)
16539a747e4fSDavid du Colombier field->events = ffit->genattr->events;
16549a747e4fSDavid du Colombier break;
16559a747e4fSDavid du Colombier
16569a747e4fSDavid du Colombier // <!ELEMENT TITLE - - ( //PCDATA)* -(%head.misc)>
16579a747e4fSDavid du Colombier case Ttitle:
16589a747e4fSDavid du Colombier di->doctitle = getpcdata(toks, tokslen, &toki);
16599a747e4fSDavid du Colombier if(warn && toki < tokslen - 1 && toks[toki + 1].tag != Ttitle + RBRA)
16609a747e4fSDavid du Colombier fprint(2, "warning: <TITLE> data ended by %T\n", &toks[toki + 1]);
16619a747e4fSDavid du Colombier break;
16629a747e4fSDavid du Colombier
16639a747e4fSDavid du Colombier // <!ELEMENT TR - O (TH|TD)+>
16649a747e4fSDavid du Colombier // rows are accumulated in reverse order in curtab->rows
16659a747e4fSDavid du Colombier case Ttr:
16669a747e4fSDavid du Colombier if(curtab == nil) {
16679a747e4fSDavid du Colombier if(warn)
16689a747e4fSDavid du Colombier fprint(2, "warning: <TR> outside <TABLE>\n");
16699a747e4fSDavid du Colombier continue;
16709a747e4fSDavid du Colombier }
16719a747e4fSDavid du Colombier if(ps->inpar) {
16729a747e4fSDavid du Colombier popjust(ps);
16739a747e4fSDavid du Colombier ps->inpar = 0;
16749a747e4fSDavid du Colombier }
16759a747e4fSDavid du Colombier ps = finishcell(curtab, ps);
16769a747e4fSDavid du Colombier if(curtab->rows != nil)
16779a747e4fSDavid du Colombier curtab->rows->flags = 0;
16789a747e4fSDavid du Colombier curtab->rows = newtablerow(aalign(tok),
16799a747e4fSDavid du Colombier makebackground(nil, acolorval(tok, Abgcolor, curtab->background.color)),
16809a747e4fSDavid du Colombier TFparsing,
16819a747e4fSDavid du Colombier curtab->rows);
16829a747e4fSDavid du Colombier break;
16839a747e4fSDavid du Colombier
16849a747e4fSDavid du Colombier case Ttr+RBRA:
16859a747e4fSDavid du Colombier if(curtab == nil || curtab->rows == nil) {
16869a747e4fSDavid du Colombier if(warn)
16879a747e4fSDavid du Colombier fprint(2, "warning: unexpected </TR>\n");
16889a747e4fSDavid du Colombier continue;
16899a747e4fSDavid du Colombier }
16909a747e4fSDavid du Colombier ps = finishcell(curtab, ps);
16919a747e4fSDavid du Colombier tr = curtab->rows;
16929a747e4fSDavid du Colombier if(tr->cells == nil) {
16939a747e4fSDavid du Colombier if(warn)
16949a747e4fSDavid du Colombier fprint(2, "warning: empty row\n");
16959a747e4fSDavid du Colombier curtab->rows = tr->next;
16969a747e4fSDavid du Colombier tr->next = nil;
16979a747e4fSDavid du Colombier }
16989a747e4fSDavid du Colombier else
16999a747e4fSDavid du Colombier tr->flags = 0;
17009a747e4fSDavid du Colombier break;
17019a747e4fSDavid du Colombier
17029a747e4fSDavid du Colombier // <!ELEMENT (TT|CODE|KBD|SAMP) - - (%text)*>
17039a747e4fSDavid du Colombier case Ttt:
17049a747e4fSDavid du Colombier case Tcode:
17059a747e4fSDavid du Colombier case Tkbd:
17069a747e4fSDavid du Colombier case Tsamp:
17079a747e4fSDavid du Colombier pushfontstyle(ps, FntT);
17089a747e4fSDavid du Colombier break;
17099a747e4fSDavid du Colombier
17109a747e4fSDavid du Colombier // Tags that have empty action
17119a747e4fSDavid du Colombier case Tabbr:
17129a747e4fSDavid du Colombier case Tabbr+RBRA:
17139a747e4fSDavid du Colombier case Tacronym:
17149a747e4fSDavid du Colombier case Tacronym+RBRA:
17159a747e4fSDavid du Colombier case Tarea+RBRA:
17169a747e4fSDavid du Colombier case Tbase+RBRA:
17179a747e4fSDavid du Colombier case Tbasefont+RBRA:
17189a747e4fSDavid du Colombier case Tbr+RBRA:
17199a747e4fSDavid du Colombier case Tdd+RBRA:
17209a747e4fSDavid du Colombier case Tdt+RBRA:
17219a747e4fSDavid du Colombier case Tframe+RBRA:
17229a747e4fSDavid du Colombier case Thr+RBRA:
17239a747e4fSDavid du Colombier case Thtml:
17249a747e4fSDavid du Colombier case Thtml+RBRA:
17259a747e4fSDavid du Colombier case Timg+RBRA:
17269a747e4fSDavid du Colombier case Tinput+RBRA:
17279a747e4fSDavid du Colombier case Tisindex+RBRA:
17289a747e4fSDavid du Colombier case Tli+RBRA:
17299a747e4fSDavid du Colombier case Tlink:
17309a747e4fSDavid du Colombier case Tlink+RBRA:
17319a747e4fSDavid du Colombier case Tmeta+RBRA:
17329a747e4fSDavid du Colombier case Toption+RBRA:
17339a747e4fSDavid du Colombier case Tparam+RBRA:
17349a747e4fSDavid du Colombier case Ttextarea+RBRA:
17359a747e4fSDavid du Colombier case Ttitle+RBRA:
17369a747e4fSDavid du Colombier break;
17379a747e4fSDavid du Colombier
17389a747e4fSDavid du Colombier
17399a747e4fSDavid du Colombier // Tags not implemented
17409a747e4fSDavid du Colombier case Tbdo:
17419a747e4fSDavid du Colombier case Tbdo+RBRA:
17429a747e4fSDavid du Colombier case Tbutton:
17439a747e4fSDavid du Colombier case Tbutton+RBRA:
17449a747e4fSDavid du Colombier case Tdel:
17459a747e4fSDavid du Colombier case Tdel+RBRA:
17469a747e4fSDavid du Colombier case Tfieldset:
17479a747e4fSDavid du Colombier case Tfieldset+RBRA:
17489a747e4fSDavid du Colombier case Tiframe:
17499a747e4fSDavid du Colombier case Tiframe+RBRA:
17509a747e4fSDavid du Colombier case Tins:
17519a747e4fSDavid du Colombier case Tins+RBRA:
17529a747e4fSDavid du Colombier case Tlabel:
17539a747e4fSDavid du Colombier case Tlabel+RBRA:
17549a747e4fSDavid du Colombier case Tlegend:
17559a747e4fSDavid du Colombier case Tlegend+RBRA:
17569a747e4fSDavid du Colombier case Tobject:
17579a747e4fSDavid du Colombier case Tobject+RBRA:
17589a747e4fSDavid du Colombier case Toptgroup:
17599a747e4fSDavid du Colombier case Toptgroup+RBRA:
17609a747e4fSDavid du Colombier case Tspan:
17619a747e4fSDavid du Colombier case Tspan+RBRA:
17629a747e4fSDavid du Colombier if(warn) {
17639a747e4fSDavid du Colombier if(tag > RBRA)
17649a747e4fSDavid du Colombier tag -= RBRA;
17659a747e4fSDavid du Colombier fprint(2, "warning: unimplemented HTML tag: %S\n", tagnames[tag]);
17669a747e4fSDavid du Colombier }
17679a747e4fSDavid du Colombier break;
17689a747e4fSDavid du Colombier
17699a747e4fSDavid du Colombier default:
17709a747e4fSDavid du Colombier if(warn)
17719a747e4fSDavid du Colombier fprint(2, "warning: unknown HTML tag: %S\n", tok->text);
17729a747e4fSDavid du Colombier break;
17739a747e4fSDavid du Colombier }
17749a747e4fSDavid du Colombier }
17759a747e4fSDavid du Colombier // some pages omit trailing </table>
17769a747e4fSDavid du Colombier while(curtab != nil) {
17779a747e4fSDavid du Colombier if(warn)
17789a747e4fSDavid du Colombier fprint(2, "warning: <TABLE> not closed\n");
17799a747e4fSDavid du Colombier if(curtab->cells != nil) {
17809a747e4fSDavid du Colombier ps = finishcell(curtab, ps);
17819a747e4fSDavid du Colombier if(curtab->cells == nil) {
17829a747e4fSDavid du Colombier if(warn)
17839a747e4fSDavid du Colombier fprint(2, "warning: empty table\n");
17849a747e4fSDavid du Colombier }
17859a747e4fSDavid du Colombier else {
17869a747e4fSDavid du Colombier if(curtab->rows != nil)
17879a747e4fSDavid du Colombier curtab->rows->flags = 0;
17889a747e4fSDavid du Colombier finish_table(curtab);
17899a747e4fSDavid du Colombier ps->skipping = 0;
17909a747e4fSDavid du Colombier additem(ps, newitable(curtab), curtab->tabletok);
17919a747e4fSDavid du Colombier addbrk(ps, 0, 0);
17929a747e4fSDavid du Colombier }
17939a747e4fSDavid du Colombier }
17949a747e4fSDavid du Colombier if(is->tabstk != nil)
17959a747e4fSDavid du Colombier is->tabstk = is->tabstk->next;
17969a747e4fSDavid du Colombier curtab->next = di->tables;
17979a747e4fSDavid du Colombier di->tables = curtab;
17989a747e4fSDavid du Colombier curtab = is->tabstk;
17999a747e4fSDavid du Colombier }
18009a747e4fSDavid du Colombier outerps = lastps(ps);
18019a747e4fSDavid du Colombier ans = outerps->items->next;
18021066d6deSDavid du Colombier freeitem(outerps->items);
18039a747e4fSDavid du Colombier // note: ans may be nil and di->kids not nil, if there's a frameset!
18049a747e4fSDavid du Colombier outerps->items = newispacer(ISPnull);
18059a747e4fSDavid du Colombier outerps->lastit = outerps->items;
18069a747e4fSDavid du Colombier is->psstk = ps;
18079a747e4fSDavid du Colombier if(ans != nil && di->hasscripts) {
18089a747e4fSDavid du Colombier // TODO evalscript(nil);
18099a747e4fSDavid du Colombier ;
18109a747e4fSDavid du Colombier }
18119a747e4fSDavid du Colombier
18129a747e4fSDavid du Colombier return_ans:
18139a747e4fSDavid du Colombier if(dbgbuild) {
18149a747e4fSDavid du Colombier assert(validitems(ans));
18159a747e4fSDavid du Colombier if(ans == nil)
18169a747e4fSDavid du Colombier fprint(2, "getitems returning nil\n");
18179a747e4fSDavid du Colombier else
18189a747e4fSDavid du Colombier printitems(ans, "getitems returning:");
18199a747e4fSDavid du Colombier }
18209a747e4fSDavid du Colombier return ans;
18219a747e4fSDavid du Colombier }
18229a747e4fSDavid du Colombier
18239a747e4fSDavid du Colombier // Concatenate together maximal set of Data tokens, starting at toks[toki+1].
18249a747e4fSDavid du Colombier // Lexer has ensured that there will either be a following non-data token or
18259a747e4fSDavid du Colombier // we will be at eof.
18269a747e4fSDavid du Colombier // Return emallocd trimmed concatenation, and update *ptoki to last used toki
18279a747e4fSDavid du Colombier static Rune*
getpcdata(Token * toks,int tokslen,int * ptoki)18289a747e4fSDavid du Colombier getpcdata(Token* toks, int tokslen, int* ptoki)
18299a747e4fSDavid du Colombier {
18309a747e4fSDavid du Colombier Rune* ans;
18319a747e4fSDavid du Colombier Rune* p;
18329a747e4fSDavid du Colombier Rune* trimans;
18339a747e4fSDavid du Colombier int anslen;
18349a747e4fSDavid du Colombier int trimanslen;
18359a747e4fSDavid du Colombier int toki;
18369a747e4fSDavid du Colombier Token* tok;
18379a747e4fSDavid du Colombier
18389a747e4fSDavid du Colombier ans = nil;
18399a747e4fSDavid du Colombier anslen = 0;
18409a747e4fSDavid du Colombier // first find length of answer
18419a747e4fSDavid du Colombier toki = (*ptoki) + 1;
18429a747e4fSDavid du Colombier while(toki < tokslen) {
18439a747e4fSDavid du Colombier tok = &toks[toki];
18449a747e4fSDavid du Colombier if(tok->tag == Data) {
18459a747e4fSDavid du Colombier toki++;
18465d459b5aSDavid du Colombier anslen += _Strlen(tok->text);
18479a747e4fSDavid du Colombier }
18489a747e4fSDavid du Colombier else
18499a747e4fSDavid du Colombier break;
18509a747e4fSDavid du Colombier }
18519a747e4fSDavid du Colombier // now make up the initial answer
18529a747e4fSDavid du Colombier if(anslen > 0) {
18539a747e4fSDavid du Colombier ans = _newstr(anslen);
18549a747e4fSDavid du Colombier p = ans;
18559a747e4fSDavid du Colombier toki = (*ptoki) + 1;
18569a747e4fSDavid du Colombier while(toki < tokslen) {
18579a747e4fSDavid du Colombier tok = &toks[toki];
18589a747e4fSDavid du Colombier if(tok->tag == Data) {
18599a747e4fSDavid du Colombier toki++;
18605d459b5aSDavid du Colombier p = _Stradd(p, tok->text, _Strlen(tok->text));
18619a747e4fSDavid du Colombier }
18629a747e4fSDavid du Colombier else
18639a747e4fSDavid du Colombier break;
18649a747e4fSDavid du Colombier }
18659a747e4fSDavid du Colombier *p = 0;
18669a747e4fSDavid du Colombier _trimwhite(ans, anslen, &trimans, &trimanslen);
18679a747e4fSDavid du Colombier if(trimanslen != anslen) {
18689a747e4fSDavid du Colombier p = ans;
18699a747e4fSDavid du Colombier ans = _Strndup(trimans, trimanslen);
18709a747e4fSDavid du Colombier free(p);
18719a747e4fSDavid du Colombier }
18729a747e4fSDavid du Colombier }
18739a747e4fSDavid du Colombier *ptoki = toki-1;
18749a747e4fSDavid du Colombier return ans;
18759a747e4fSDavid du Colombier }
18769a747e4fSDavid du Colombier
18779a747e4fSDavid du Colombier // If still parsing head of curtab->cells list, finish it off
18789a747e4fSDavid du Colombier // by transferring the items on the head of psstk to the cell.
18799a747e4fSDavid du Colombier // Then pop the psstk and return the new psstk.
18809a747e4fSDavid du Colombier static Pstate*
finishcell(Table * curtab,Pstate * psstk)18819a747e4fSDavid du Colombier finishcell(Table* curtab, Pstate* psstk)
18829a747e4fSDavid du Colombier {
18839a747e4fSDavid du Colombier Tablecell* c;
18849a747e4fSDavid du Colombier Pstate* psstknext;
18859a747e4fSDavid du Colombier
18869a747e4fSDavid du Colombier c = curtab->cells;
18879a747e4fSDavid du Colombier if(c != nil) {
18889a747e4fSDavid du Colombier if((c->flags&TFparsing)) {
18899a747e4fSDavid du Colombier psstknext = psstk->next;
18909a747e4fSDavid du Colombier if(psstknext == nil) {
18919a747e4fSDavid du Colombier if(warn)
18929a747e4fSDavid du Colombier fprint(2, "warning: parse state stack is wrong\n");
18939a747e4fSDavid du Colombier }
18949a747e4fSDavid du Colombier else {
18959a747e4fSDavid du Colombier c->content = psstk->items->next;
18969a747e4fSDavid du Colombier c->flags &= ~TFparsing;
18979a747e4fSDavid du Colombier freepstate(psstk);
18989a747e4fSDavid du Colombier psstk = psstknext;
18999a747e4fSDavid du Colombier }
19009a747e4fSDavid du Colombier }
19019a747e4fSDavid du Colombier }
19029a747e4fSDavid du Colombier return psstk;
19039a747e4fSDavid du Colombier }
19049a747e4fSDavid du Colombier
19059a747e4fSDavid du Colombier // Make a new Pstate for a cell, based on the old pstate, oldps.
19069a747e4fSDavid du Colombier // Also, put the new ps on the head of the oldps stack.
19079a747e4fSDavid du Colombier static Pstate*
cell_pstate(Pstate * oldps,int ishead)19089a747e4fSDavid du Colombier cell_pstate(Pstate* oldps, int ishead)
19099a747e4fSDavid du Colombier {
19109a747e4fSDavid du Colombier Pstate* ps;
19119a747e4fSDavid du Colombier int sty;
19129a747e4fSDavid du Colombier
19139a747e4fSDavid du Colombier ps = newpstate(oldps);
19149a747e4fSDavid du Colombier ps->skipwhite = 1;
19159a747e4fSDavid du Colombier ps->curanchor = oldps->curanchor;
19169a747e4fSDavid du Colombier copystack(&ps->fntstylestk, &oldps->fntstylestk);
19179a747e4fSDavid du Colombier copystack(&ps->fntsizestk, &oldps->fntsizestk);
19189a747e4fSDavid du Colombier ps->curfont = oldps->curfont;
19199a747e4fSDavid du Colombier ps->curfg = oldps->curfg;
19209a747e4fSDavid du Colombier ps->curbg = oldps->curbg;
19219a747e4fSDavid du Colombier copystack(&ps->fgstk, &oldps->fgstk);
19229a747e4fSDavid du Colombier ps->adjsize = oldps->adjsize;
19239a747e4fSDavid du Colombier if(ishead) {
19249a747e4fSDavid du Colombier sty = ps->curfont%NumSize;
19259a747e4fSDavid du Colombier ps->curfont = FntB*NumSize + sty;
19269a747e4fSDavid du Colombier }
19279a747e4fSDavid du Colombier return ps;
19289a747e4fSDavid du Colombier }
19299a747e4fSDavid du Colombier
19309a747e4fSDavid du Colombier // Return a new Pstate with default starting state.
19319a747e4fSDavid du Colombier // Use link to add it to head of a list, if any.
19329a747e4fSDavid du Colombier static Pstate*
newpstate(Pstate * link)19339a747e4fSDavid du Colombier newpstate(Pstate* link)
19349a747e4fSDavid du Colombier {
19359a747e4fSDavid du Colombier Pstate* ps;
19369a747e4fSDavid du Colombier
19379a747e4fSDavid du Colombier ps = (Pstate*)emalloc(sizeof(Pstate));
19389a747e4fSDavid du Colombier ps->curfont = DefFnt;
19399a747e4fSDavid du Colombier ps->curfg = Black;
19409a747e4fSDavid du Colombier ps->curbg.image = nil;
19419a747e4fSDavid du Colombier ps->curbg.color = White;
19429a747e4fSDavid du Colombier ps->curul = ULnone;
19439a747e4fSDavid du Colombier ps->curjust = ALleft;
19449a747e4fSDavid du Colombier ps->curstate = IFwrap;
19459a747e4fSDavid du Colombier ps->items = newispacer(ISPnull);
19469a747e4fSDavid du Colombier ps->lastit = ps->items;
19479a747e4fSDavid du Colombier ps->prelastit = nil;
19489a747e4fSDavid du Colombier ps->next = link;
19499a747e4fSDavid du Colombier return ps;
19509a747e4fSDavid du Colombier }
19519a747e4fSDavid du Colombier
19529a747e4fSDavid du Colombier // Return last Pstate on psl list
19539a747e4fSDavid du Colombier static Pstate*
lastps(Pstate * psl)19549a747e4fSDavid du Colombier lastps(Pstate* psl)
19559a747e4fSDavid du Colombier {
19569a747e4fSDavid du Colombier assert(psl != nil);
19579a747e4fSDavid du Colombier while(psl->next != nil)
19589a747e4fSDavid du Colombier psl = psl->next;
19599a747e4fSDavid du Colombier return psl;
19609a747e4fSDavid du Colombier }
19619a747e4fSDavid du Colombier
19629a747e4fSDavid du Colombier // Add it to end of ps item chain, adding in current state from ps.
19639a747e4fSDavid du Colombier // Also, if tok is not nil, scan it for generic attributes and assign
19649a747e4fSDavid du Colombier // the genattr field of the item accordingly.
19659a747e4fSDavid du Colombier static void
additem(Pstate * ps,Item * it,Token * tok)19669a747e4fSDavid du Colombier additem(Pstate* ps, Item* it, Token* tok)
19679a747e4fSDavid du Colombier {
19689a747e4fSDavid du Colombier int aid;
19699a747e4fSDavid du Colombier int any;
19709a747e4fSDavid du Colombier Rune* i;
19719a747e4fSDavid du Colombier Rune* c;
19729a747e4fSDavid du Colombier Rune* s;
19739a747e4fSDavid du Colombier Rune* t;
19749a747e4fSDavid du Colombier Attr* a;
19755d459b5aSDavid du Colombier SEvent* e;
19769a747e4fSDavid du Colombier
19779a747e4fSDavid du Colombier if(ps->skipping) {
19789a747e4fSDavid du Colombier if(warn)
19799a747e4fSDavid du Colombier fprint(2, "warning: skipping item: %I\n", it);
19809a747e4fSDavid du Colombier return;
19819a747e4fSDavid du Colombier }
19829a747e4fSDavid du Colombier it->anchorid = ps->curanchor;
19839a747e4fSDavid du Colombier it->state |= ps->curstate;
19849a747e4fSDavid du Colombier if(tok != nil) {
19859a747e4fSDavid du Colombier any = 0;
19869a747e4fSDavid du Colombier i = nil;
19879a747e4fSDavid du Colombier c = nil;
19889a747e4fSDavid du Colombier s = nil;
19899a747e4fSDavid du Colombier t = nil;
19909a747e4fSDavid du Colombier e = nil;
19919a747e4fSDavid du Colombier for(a = tok->attr; a != nil; a = a->next) {
19929a747e4fSDavid du Colombier aid = a->attid;
19939a747e4fSDavid du Colombier if(!attrinfo[aid])
19949a747e4fSDavid du Colombier continue;
19959a747e4fSDavid du Colombier switch(aid) {
19969a747e4fSDavid du Colombier case Aid:
19979a747e4fSDavid du Colombier i = a->value;
19989a747e4fSDavid du Colombier break;
19999a747e4fSDavid du Colombier
20009a747e4fSDavid du Colombier case Aclass:
20019a747e4fSDavid du Colombier c = a->value;
20029a747e4fSDavid du Colombier break;
20039a747e4fSDavid du Colombier
20049a747e4fSDavid du Colombier case Astyle:
20059a747e4fSDavid du Colombier s = a->value;
20069a747e4fSDavid du Colombier break;
20079a747e4fSDavid du Colombier
20089a747e4fSDavid du Colombier case Atitle:
20099a747e4fSDavid du Colombier t = a->value;
20109a747e4fSDavid du Colombier break;
20119a747e4fSDavid du Colombier
20129a747e4fSDavid du Colombier default:
20139a747e4fSDavid du Colombier assert(aid >= Aonblur && aid <= Aonunload);
20149a747e4fSDavid du Colombier e = newscriptevent(scriptev[a->attid], a->value, e);
20159a747e4fSDavid du Colombier break;
20169a747e4fSDavid du Colombier }
20179a747e4fSDavid du Colombier a->value = nil;
20189a747e4fSDavid du Colombier any = 1;
20199a747e4fSDavid du Colombier }
20209a747e4fSDavid du Colombier if(any)
20219a747e4fSDavid du Colombier it->genattr = newgenattr(i, c, s, t, e);
20229a747e4fSDavid du Colombier }
20239a747e4fSDavid du Colombier ps->curstate &= ~(IFbrk|IFbrksp|IFnobrk|IFcleft|IFcright);
20249a747e4fSDavid du Colombier ps->prelastit = ps->lastit;
20259a747e4fSDavid du Colombier ps->lastit->next = it;
20269a747e4fSDavid du Colombier ps->lastit = it;
20279a747e4fSDavid du Colombier }
20289a747e4fSDavid du Colombier
20299a747e4fSDavid du Colombier // Make a text item out of s,
20309a747e4fSDavid du Colombier // using current font, foreground, vertical offset and underline state.
20319a747e4fSDavid du Colombier static Item*
textit(Pstate * ps,Rune * s)20329a747e4fSDavid du Colombier textit(Pstate* ps, Rune* s)
20339a747e4fSDavid du Colombier {
20349a747e4fSDavid du Colombier assert(s != nil);
20359a747e4fSDavid du Colombier return newitext(s, ps->curfont, ps->curfg, ps->curvoff + Voffbias, ps->curul);
20369a747e4fSDavid du Colombier }
20379a747e4fSDavid du Colombier
20389a747e4fSDavid du Colombier // Add text item or items for s, paying attention to
20399a747e4fSDavid du Colombier // current font, foreground, baseline offset, underline state,
20409a747e4fSDavid du Colombier // and literal mode. Unless we're in literal mode, compress
20419a747e4fSDavid du Colombier // whitespace to single blank, and, if curstate has a break,
20429a747e4fSDavid du Colombier // trim any leading whitespace. Whether in literal mode or not,
20439a747e4fSDavid du Colombier // turn nonbreaking spaces into spacer items with IFnobrk set.
20449a747e4fSDavid du Colombier //
20459a747e4fSDavid du Colombier // In literal mode, break up s at newlines and add breaks instead.
20469a747e4fSDavid du Colombier // Also replace tabs appropriate number of spaces.
20479a747e4fSDavid du Colombier // In nonliteral mode, break up the items every 100 or so characters
20489a747e4fSDavid du Colombier // just to make the layout algorithm not go quadratic.
20499a747e4fSDavid du Colombier //
20509a747e4fSDavid du Colombier // addtext assumes ownership of s.
20519a747e4fSDavid du Colombier static void
addtext(Pstate * ps,Rune * s)20529a747e4fSDavid du Colombier addtext(Pstate* ps, Rune* s)
20539a747e4fSDavid du Colombier {
20549a747e4fSDavid du Colombier int n;
20559a747e4fSDavid du Colombier int i;
20569a747e4fSDavid du Colombier int j;
20579a747e4fSDavid du Colombier int k;
20589a747e4fSDavid du Colombier int col;
20599a747e4fSDavid du Colombier int c;
20609a747e4fSDavid du Colombier int nsp;
20619a747e4fSDavid du Colombier Item* it;
20629a747e4fSDavid du Colombier Rune* ss;
20639a747e4fSDavid du Colombier Rune* p;
20649a747e4fSDavid du Colombier Rune buf[SMALLBUFSIZE];
20659a747e4fSDavid du Colombier
20669a747e4fSDavid du Colombier assert(s != nil);
20679a747e4fSDavid du Colombier n = runestrlen(s);
20689a747e4fSDavid du Colombier i = 0;
20699a747e4fSDavid du Colombier j = 0;
20709a747e4fSDavid du Colombier if(ps->literal) {
20719a747e4fSDavid du Colombier col = 0;
20729a747e4fSDavid du Colombier while(i < n) {
20739a747e4fSDavid du Colombier if(s[i] == '\n') {
20749a747e4fSDavid du Colombier if(i > j) {
20759a747e4fSDavid du Colombier // trim trailing blanks from line
20769a747e4fSDavid du Colombier for(k = i; k > j; k--)
20779a747e4fSDavid du Colombier if(s[k - 1] != ' ')
20789a747e4fSDavid du Colombier break;
20799a747e4fSDavid du Colombier if(k > j)
20809a747e4fSDavid du Colombier additem(ps, textit(ps, _Strndup(s+j, k-j)), nil);
20819a747e4fSDavid du Colombier }
20829a747e4fSDavid du Colombier addlinebrk(ps, 0);
20839a747e4fSDavid du Colombier j = i + 1;
20849a747e4fSDavid du Colombier col = 0;
20859a747e4fSDavid du Colombier }
20869a747e4fSDavid du Colombier else {
20879a747e4fSDavid du Colombier if(s[i] == '\t') {
20889a747e4fSDavid du Colombier col += i - j;
20899a747e4fSDavid du Colombier nsp = 8 - (col%8);
20909a747e4fSDavid du Colombier // make ss = s[j:i] + nsp spaces
20919a747e4fSDavid du Colombier ss = _newstr(i-j+nsp);
20929a747e4fSDavid du Colombier p = _Stradd(ss, s+j, i-j);
20939a747e4fSDavid du Colombier p = _Stradd(p, L" ", nsp);
20949a747e4fSDavid du Colombier *p = 0;
20959a747e4fSDavid du Colombier additem(ps, textit(ps, ss), nil);
20969a747e4fSDavid du Colombier col += nsp;
20979a747e4fSDavid du Colombier j = i + 1;
20989a747e4fSDavid du Colombier }
20999a747e4fSDavid du Colombier else if(s[i] == NBSP) {
21009a747e4fSDavid du Colombier if(i > j)
21019a747e4fSDavid du Colombier additem(ps, textit(ps, _Strndup(s+j, i-j)), nil);
21029a747e4fSDavid du Colombier addnbsp(ps);
21039a747e4fSDavid du Colombier col += (i - j) + 1;
21049a747e4fSDavid du Colombier j = i + 1;
21059a747e4fSDavid du Colombier }
21069a747e4fSDavid du Colombier }
21079a747e4fSDavid du Colombier i++;
21089a747e4fSDavid du Colombier }
21099a747e4fSDavid du Colombier if(i > j) {
21109a747e4fSDavid du Colombier if(j == 0 && i == n) {
21119a747e4fSDavid du Colombier // just transfer s over
21129a747e4fSDavid du Colombier additem(ps, textit(ps, s), nil);
21139a747e4fSDavid du Colombier }
21149a747e4fSDavid du Colombier else {
21159a747e4fSDavid du Colombier additem(ps, textit(ps, _Strndup(s+j, i-j)), nil);
21169a747e4fSDavid du Colombier free(s);
21179a747e4fSDavid du Colombier }
21189a747e4fSDavid du Colombier }
21199a747e4fSDavid du Colombier }
21209a747e4fSDavid du Colombier else { // not literal mode
21219a747e4fSDavid du Colombier if((ps->curstate&IFbrk) || ps->lastit == ps->items)
21229a747e4fSDavid du Colombier while(i < n) {
21239a747e4fSDavid du Colombier c = s[i];
21249a747e4fSDavid du Colombier if(c >= 256 || !isspace(c))
21259a747e4fSDavid du Colombier break;
21269a747e4fSDavid du Colombier i++;
21279a747e4fSDavid du Colombier }
21289a747e4fSDavid du Colombier p = buf;
21299a747e4fSDavid du Colombier for(j = i; i < n; i++) {
21309a747e4fSDavid du Colombier assert(p+i-j < buf+SMALLBUFSIZE-1);
21319a747e4fSDavid du Colombier c = s[i];
21329a747e4fSDavid du Colombier if(c == NBSP) {
21339a747e4fSDavid du Colombier if(i > j)
21349a747e4fSDavid du Colombier p = _Stradd(p, s+j, i-j);
21359a747e4fSDavid du Colombier if(p > buf)
21369a747e4fSDavid du Colombier additem(ps, textit(ps, _Strndup(buf, p-buf)), nil);
21379a747e4fSDavid du Colombier p = buf;
21389a747e4fSDavid du Colombier addnbsp(ps);
21399a747e4fSDavid du Colombier j = i + 1;
21409a747e4fSDavid du Colombier continue;
21419a747e4fSDavid du Colombier }
21429a747e4fSDavid du Colombier if(c < 256 && isspace(c)) {
21439a747e4fSDavid du Colombier if(i > j)
21449a747e4fSDavid du Colombier p = _Stradd(p, s+j, i-j);
21459a747e4fSDavid du Colombier *p++ = ' ';
21469a747e4fSDavid du Colombier while(i < n - 1) {
21479a747e4fSDavid du Colombier c = s[i + 1];
21489a747e4fSDavid du Colombier if(c >= 256 || !isspace(c))
21499a747e4fSDavid du Colombier break;
21509a747e4fSDavid du Colombier i++;
21519a747e4fSDavid du Colombier }
21529a747e4fSDavid du Colombier j = i + 1;
21539a747e4fSDavid du Colombier }
21549a747e4fSDavid du Colombier if(i - j >= 100) {
21559a747e4fSDavid du Colombier p = _Stradd(p, s+j, i+1-j);
21569a747e4fSDavid du Colombier j = i + 1;
21579a747e4fSDavid du Colombier }
21589a747e4fSDavid du Colombier if(p-buf >= 100) {
21599a747e4fSDavid du Colombier additem(ps, textit(ps, _Strndup(buf, p-buf)), nil);
21609a747e4fSDavid du Colombier p = buf;
21619a747e4fSDavid du Colombier }
21629a747e4fSDavid du Colombier }
21639a747e4fSDavid du Colombier if(i > j && j < n) {
21649a747e4fSDavid du Colombier assert(p+i-j < buf+SMALLBUFSIZE-1);
21659a747e4fSDavid du Colombier p = _Stradd(p, s+j, i-j);
21669a747e4fSDavid du Colombier }
21679a747e4fSDavid du Colombier // don't add a space if previous item ended in a space
21689a747e4fSDavid du Colombier if(p-buf == 1 && buf[0] == ' ' && ps->lastit != nil) {
21699a747e4fSDavid du Colombier it = ps->lastit;
21709a747e4fSDavid du Colombier if(it->tag == Itexttag) {
21719a747e4fSDavid du Colombier ss = ((Itext*)it)->s;
21725d459b5aSDavid du Colombier k = _Strlen(ss);
21739a747e4fSDavid du Colombier if(k > 0 && ss[k] == ' ')
21749a747e4fSDavid du Colombier p = buf;
21759a747e4fSDavid du Colombier }
21769a747e4fSDavid du Colombier }
21779a747e4fSDavid du Colombier if(p > buf)
21789a747e4fSDavid du Colombier additem(ps, textit(ps, _Strndup(buf, p-buf)), nil);
21799a747e4fSDavid du Colombier free(s);
21809a747e4fSDavid du Colombier }
21819a747e4fSDavid du Colombier }
21829a747e4fSDavid du Colombier
21839a747e4fSDavid du Colombier // Add a break to ps->curstate, with extra space if sp is true.
21849a747e4fSDavid du Colombier // If there was a previous break, combine this one's parameters
21859a747e4fSDavid du Colombier // with that to make the amt be the max of the two and the clr
21869a747e4fSDavid du Colombier // be the most general. (amt will be 0 or 1)
21879a747e4fSDavid du Colombier // Also, if the immediately preceding item was a text item,
21889a747e4fSDavid du Colombier // trim any whitespace from the end of it, if not in literal mode.
21899a747e4fSDavid du Colombier // Finally, if this is at the very beginning of the item list
21909a747e4fSDavid du Colombier // (the only thing there is a null spacer), then don't add the space.
21919a747e4fSDavid du Colombier static void
addbrk(Pstate * ps,int sp,int clr)21929a747e4fSDavid du Colombier addbrk(Pstate* ps, int sp, int clr)
21939a747e4fSDavid du Colombier {
21949a747e4fSDavid du Colombier int state;
21959a747e4fSDavid du Colombier Rune* l;
21969a747e4fSDavid du Colombier int nl;
21979a747e4fSDavid du Colombier Rune* r;
21989a747e4fSDavid du Colombier int nr;
21999a747e4fSDavid du Colombier Itext* t;
22009a747e4fSDavid du Colombier Rune* s;
22019a747e4fSDavid du Colombier
22029a747e4fSDavid du Colombier state = ps->curstate;
22039a747e4fSDavid du Colombier clr = clr|(state&(IFcleft|IFcright));
22049a747e4fSDavid du Colombier if(sp && !(ps->lastit == ps->items))
22059a747e4fSDavid du Colombier sp = IFbrksp;
22069a747e4fSDavid du Colombier else
22079a747e4fSDavid du Colombier sp = 0;
22089a747e4fSDavid du Colombier ps->curstate = IFbrk|sp|(state&~(IFcleft|IFcright))|clr;
22099a747e4fSDavid du Colombier if(ps->lastit != ps->items) {
22109a747e4fSDavid du Colombier if(!ps->literal && ps->lastit->tag == Itexttag) {
22119a747e4fSDavid du Colombier t = (Itext*)ps->lastit;
22125d459b5aSDavid du Colombier _splitr(t->s, _Strlen(t->s), notwhitespace, &l, &nl, &r, &nr);
22139a747e4fSDavid du Colombier // try to avoid making empty items
22149a747e4fSDavid du Colombier // but not crucial f the occasional one gets through
22159a747e4fSDavid du Colombier if(nl == 0 && ps->prelastit != nil) {
22169a747e4fSDavid du Colombier ps->lastit = ps->prelastit;
22179a747e4fSDavid du Colombier ps->lastit->next = nil;
22189a747e4fSDavid du Colombier ps->prelastit = nil;
22199a747e4fSDavid du Colombier }
22209a747e4fSDavid du Colombier else {
22219a747e4fSDavid du Colombier s = t->s;
22229a747e4fSDavid du Colombier if(nl == 0) {
22239a747e4fSDavid du Colombier // need a non-nil pointer to empty string
22249a747e4fSDavid du Colombier // (_Strdup(L"") returns nil)
22259a747e4fSDavid du Colombier t->s = emalloc(sizeof(Rune));
22269a747e4fSDavid du Colombier t->s[0] = 0;
22279a747e4fSDavid du Colombier }
22289a747e4fSDavid du Colombier else
22299a747e4fSDavid du Colombier t->s = _Strndup(l, nl);
22309a747e4fSDavid du Colombier if(s)
22319a747e4fSDavid du Colombier free(s);
22329a747e4fSDavid du Colombier }
22339a747e4fSDavid du Colombier }
22349a747e4fSDavid du Colombier }
22359a747e4fSDavid du Colombier }
22369a747e4fSDavid du Colombier
22379a747e4fSDavid du Colombier // Add break due to a <br> or a newline within a preformatted section.
22389a747e4fSDavid du Colombier // We add a null item first, with current font's height and ascent, to make
22399a747e4fSDavid du Colombier // sure that the current line takes up at least that amount of vertical space.
22409a747e4fSDavid du Colombier // This ensures that <br>s on empty lines cause blank lines, and that
22419a747e4fSDavid du Colombier // multiple <br>s in a row give multiple blank lines.
22429a747e4fSDavid du Colombier // However don't add the spacer if the previous item was something that
22439a747e4fSDavid du Colombier // takes up space itself.
22449a747e4fSDavid du Colombier static void
addlinebrk(Pstate * ps,int clr)22459a747e4fSDavid du Colombier addlinebrk(Pstate* ps, int clr)
22469a747e4fSDavid du Colombier {
22479a747e4fSDavid du Colombier int obrkstate;
22489a747e4fSDavid du Colombier int b;
22499a747e4fSDavid du Colombier
22509a747e4fSDavid du Colombier // don't want break before our null item unless the previous item
22519a747e4fSDavid du Colombier // was also a null item for the purposes of line breaking
22529a747e4fSDavid du Colombier obrkstate = ps->curstate&(IFbrk|IFbrksp);
22539a747e4fSDavid du Colombier b = IFnobrk;
22549a747e4fSDavid du Colombier if(ps->lastit != nil) {
22559a747e4fSDavid du Colombier if(ps->lastit->tag == Ispacertag) {
22569a747e4fSDavid du Colombier if(((Ispacer*)ps->lastit)->spkind == ISPvline)
22579a747e4fSDavid du Colombier b = IFbrk;
22589a747e4fSDavid du Colombier }
22599a747e4fSDavid du Colombier }
22609a747e4fSDavid du Colombier ps->curstate = (ps->curstate&~(IFbrk|IFbrksp))|b;
22619a747e4fSDavid du Colombier additem(ps, newispacer(ISPvline), nil);
22629a747e4fSDavid du Colombier ps->curstate = (ps->curstate&~(IFbrk|IFbrksp))|obrkstate;
22639a747e4fSDavid du Colombier addbrk(ps, 0, clr);
22649a747e4fSDavid du Colombier }
22659a747e4fSDavid du Colombier
22669a747e4fSDavid du Colombier // Add a nonbreakable space
22679a747e4fSDavid du Colombier static void
addnbsp(Pstate * ps)22689a747e4fSDavid du Colombier addnbsp(Pstate* ps)
22699a747e4fSDavid du Colombier {
22709a747e4fSDavid du Colombier // if nbsp comes right where a break was specified,
22719a747e4fSDavid du Colombier // do the break anyway (nbsp is being used to generate undiscardable
22729a747e4fSDavid du Colombier // space rather than to prevent a break)
22739a747e4fSDavid du Colombier if((ps->curstate&IFbrk) == 0)
22749a747e4fSDavid du Colombier ps->curstate |= IFnobrk;
22759a747e4fSDavid du Colombier additem(ps, newispacer(ISPhspace), nil);
22769a747e4fSDavid du Colombier // but definitely no break on next item
22779a747e4fSDavid du Colombier ps->curstate |= IFnobrk;
22789a747e4fSDavid du Colombier }
22799a747e4fSDavid du Colombier
22809a747e4fSDavid du Colombier // Change hang in ps.curstate by delta.
22819a747e4fSDavid du Colombier // The amount is in 1/10ths of tabs, and is the amount that
22829a747e4fSDavid du Colombier // the current contiguous set of items with a hang value set
22839a747e4fSDavid du Colombier // is to be shifted left from its normal (indented) place.
22849a747e4fSDavid du Colombier static void
changehang(Pstate * ps,int delta)22859a747e4fSDavid du Colombier changehang(Pstate* ps, int delta)
22869a747e4fSDavid du Colombier {
22879a747e4fSDavid du Colombier int amt;
22889a747e4fSDavid du Colombier
22899a747e4fSDavid du Colombier amt = (ps->curstate&IFhangmask) + delta;
22909a747e4fSDavid du Colombier if(amt < 0) {
22919a747e4fSDavid du Colombier if(warn)
22929a747e4fSDavid du Colombier fprint(2, "warning: hang went negative\n");
22939a747e4fSDavid du Colombier amt = 0;
22949a747e4fSDavid du Colombier }
22959a747e4fSDavid du Colombier ps->curstate = (ps->curstate&~IFhangmask)|amt;
22969a747e4fSDavid du Colombier }
22979a747e4fSDavid du Colombier
22989a747e4fSDavid du Colombier // Change indent in ps.curstate by delta.
22999a747e4fSDavid du Colombier static void
changeindent(Pstate * ps,int delta)23009a747e4fSDavid du Colombier changeindent(Pstate* ps, int delta)
23019a747e4fSDavid du Colombier {
23029a747e4fSDavid du Colombier int amt;
23039a747e4fSDavid du Colombier
23049a747e4fSDavid du Colombier amt = ((ps->curstate&IFindentmask) >> IFindentshift) + delta;
23059a747e4fSDavid du Colombier if(amt < 0) {
23069a747e4fSDavid du Colombier if(warn)
23079a747e4fSDavid du Colombier fprint(2, "warning: indent went negative\n");
23089a747e4fSDavid du Colombier amt = 0;
23099a747e4fSDavid du Colombier }
23109a747e4fSDavid du Colombier ps->curstate = (ps->curstate&~IFindentmask)|(amt << IFindentshift);
23119a747e4fSDavid du Colombier }
23129a747e4fSDavid du Colombier
23139a747e4fSDavid du Colombier // Push val on top of stack, and also return value pushed
23149a747e4fSDavid du Colombier static int
push(Stack * stk,int val)23159a747e4fSDavid du Colombier push(Stack* stk, int val)
23169a747e4fSDavid du Colombier {
23179a747e4fSDavid du Colombier if(stk->n == Nestmax) {
23189a747e4fSDavid du Colombier if(warn)
23199a747e4fSDavid du Colombier fprint(2, "warning: build stack overflow\n");
23209a747e4fSDavid du Colombier }
23219a747e4fSDavid du Colombier else
23229a747e4fSDavid du Colombier stk->slots[stk->n++] = val;
23239a747e4fSDavid du Colombier return val;
23249a747e4fSDavid du Colombier }
23259a747e4fSDavid du Colombier
23269a747e4fSDavid du Colombier // Pop top of stack
23279a747e4fSDavid du Colombier static void
pop(Stack * stk)23289a747e4fSDavid du Colombier pop(Stack* stk)
23299a747e4fSDavid du Colombier {
23309a747e4fSDavid du Colombier if(stk->n > 0)
23319a747e4fSDavid du Colombier --stk->n;
23329a747e4fSDavid du Colombier }
23339a747e4fSDavid du Colombier
23349a747e4fSDavid du Colombier //Return top of stack, using dflt if stack is empty
23359a747e4fSDavid du Colombier static int
top(Stack * stk,int dflt)23369a747e4fSDavid du Colombier top(Stack* stk, int dflt)
23379a747e4fSDavid du Colombier {
23389a747e4fSDavid du Colombier if(stk->n == 0)
23399a747e4fSDavid du Colombier return dflt;
23409a747e4fSDavid du Colombier return stk->slots[stk->n-1];
23419a747e4fSDavid du Colombier }
23429a747e4fSDavid du Colombier
23439a747e4fSDavid du Colombier // pop, then return new top, with dflt if empty
23449a747e4fSDavid du Colombier static int
popretnewtop(Stack * stk,int dflt)23459a747e4fSDavid du Colombier popretnewtop(Stack* stk, int dflt)
23469a747e4fSDavid du Colombier {
23479a747e4fSDavid du Colombier if(stk->n == 0)
23489a747e4fSDavid du Colombier return dflt;
23499a747e4fSDavid du Colombier stk->n--;
23509a747e4fSDavid du Colombier if(stk->n == 0)
23519a747e4fSDavid du Colombier return dflt;
23529a747e4fSDavid du Colombier return stk->slots[stk->n-1];
23539a747e4fSDavid du Colombier }
23549a747e4fSDavid du Colombier
23559a747e4fSDavid du Colombier // Copy fromstk entries into tostk
23569a747e4fSDavid du Colombier static void
copystack(Stack * tostk,Stack * fromstk)23579a747e4fSDavid du Colombier copystack(Stack* tostk, Stack* fromstk)
23589a747e4fSDavid du Colombier {
23599a747e4fSDavid du Colombier int n;
23609a747e4fSDavid du Colombier
23619a747e4fSDavid du Colombier n = fromstk->n;
23629a747e4fSDavid du Colombier tostk->n = n;
23639a747e4fSDavid du Colombier memmove(tostk->slots, fromstk->slots, n*sizeof(int));
23649a747e4fSDavid du Colombier }
23659a747e4fSDavid du Colombier
23669a747e4fSDavid du Colombier static void
popfontstyle(Pstate * ps)23679a747e4fSDavid du Colombier popfontstyle(Pstate* ps)
23689a747e4fSDavid du Colombier {
23699a747e4fSDavid du Colombier pop(&ps->fntstylestk);
23709a747e4fSDavid du Colombier setcurfont(ps);
23719a747e4fSDavid du Colombier }
23729a747e4fSDavid du Colombier
23739a747e4fSDavid du Colombier static void
pushfontstyle(Pstate * ps,int sty)23749a747e4fSDavid du Colombier pushfontstyle(Pstate* ps, int sty)
23759a747e4fSDavid du Colombier {
23769a747e4fSDavid du Colombier push(&ps->fntstylestk, sty);
23779a747e4fSDavid du Colombier setcurfont(ps);
23789a747e4fSDavid du Colombier }
23799a747e4fSDavid du Colombier
23809a747e4fSDavid du Colombier static void
popfontsize(Pstate * ps)23819a747e4fSDavid du Colombier popfontsize(Pstate* ps)
23829a747e4fSDavid du Colombier {
23839a747e4fSDavid du Colombier pop(&ps->fntsizestk);
23849a747e4fSDavid du Colombier setcurfont(ps);
23859a747e4fSDavid du Colombier }
23869a747e4fSDavid du Colombier
23879a747e4fSDavid du Colombier static void
pushfontsize(Pstate * ps,int sz)23889a747e4fSDavid du Colombier pushfontsize(Pstate* ps, int sz)
23899a747e4fSDavid du Colombier {
23909a747e4fSDavid du Colombier push(&ps->fntsizestk, sz);
23919a747e4fSDavid du Colombier setcurfont(ps);
23929a747e4fSDavid du Colombier }
23939a747e4fSDavid du Colombier
23949a747e4fSDavid du Colombier static void
setcurfont(Pstate * ps)23959a747e4fSDavid du Colombier setcurfont(Pstate* ps)
23969a747e4fSDavid du Colombier {
23979a747e4fSDavid du Colombier int sty;
23989a747e4fSDavid du Colombier int sz;
23999a747e4fSDavid du Colombier
24009a747e4fSDavid du Colombier sty = top(&ps->fntstylestk, FntR);
24019a747e4fSDavid du Colombier sz = top(&ps->fntsizestk, Normal);
24029a747e4fSDavid du Colombier if(sz < Tiny)
24039a747e4fSDavid du Colombier sz = Tiny;
24049a747e4fSDavid du Colombier if(sz > Verylarge)
24059a747e4fSDavid du Colombier sz = Verylarge;
24069a747e4fSDavid du Colombier ps->curfont = sty*NumSize + sz;
24079a747e4fSDavid du Colombier }
24089a747e4fSDavid du Colombier
24099a747e4fSDavid du Colombier static void
popjust(Pstate * ps)24109a747e4fSDavid du Colombier popjust(Pstate* ps)
24119a747e4fSDavid du Colombier {
24129a747e4fSDavid du Colombier pop(&ps->juststk);
24139a747e4fSDavid du Colombier setcurjust(ps);
24149a747e4fSDavid du Colombier }
24159a747e4fSDavid du Colombier
24169a747e4fSDavid du Colombier static void
pushjust(Pstate * ps,int j)24179a747e4fSDavid du Colombier pushjust(Pstate* ps, int j)
24189a747e4fSDavid du Colombier {
24199a747e4fSDavid du Colombier push(&ps->juststk, j);
24209a747e4fSDavid du Colombier setcurjust(ps);
24219a747e4fSDavid du Colombier }
24229a747e4fSDavid du Colombier
24239a747e4fSDavid du Colombier static void
setcurjust(Pstate * ps)24249a747e4fSDavid du Colombier setcurjust(Pstate* ps)
24259a747e4fSDavid du Colombier {
24269a747e4fSDavid du Colombier int j;
24279a747e4fSDavid du Colombier int state;
24289a747e4fSDavid du Colombier
24299a747e4fSDavid du Colombier j = top(&ps->juststk, ALleft);
24309a747e4fSDavid du Colombier if(j != ps->curjust) {
24319a747e4fSDavid du Colombier ps->curjust = j;
24329a747e4fSDavid du Colombier state = ps->curstate;
24339a747e4fSDavid du Colombier state &= ~(IFrjust|IFcjust);
24349a747e4fSDavid du Colombier if(j == ALcenter)
24359a747e4fSDavid du Colombier state |= IFcjust;
24369a747e4fSDavid du Colombier else if(j == ALright)
24379a747e4fSDavid du Colombier state |= IFrjust;
24389a747e4fSDavid du Colombier ps->curstate = state;
24399a747e4fSDavid du Colombier }
24409a747e4fSDavid du Colombier }
24419a747e4fSDavid du Colombier
24429a747e4fSDavid du Colombier // Do final rearrangement after table parsing is finished
24439a747e4fSDavid du Colombier // and assign cells to grid points
24449a747e4fSDavid du Colombier static void
finish_table(Table * t)24459a747e4fSDavid du Colombier finish_table(Table* t)
24469a747e4fSDavid du Colombier {
24479a747e4fSDavid du Colombier int ncol;
24489a747e4fSDavid du Colombier int nrow;
24499a747e4fSDavid du Colombier int r;
24509a747e4fSDavid du Colombier Tablerow* rl;
24519a747e4fSDavid du Colombier Tablecell* cl;
24529a747e4fSDavid du Colombier int* rowspancnt;
24539a747e4fSDavid du Colombier Tablecell** rowspancell;
24549a747e4fSDavid du Colombier int ri;
24559a747e4fSDavid du Colombier int ci;
24569a747e4fSDavid du Colombier Tablecell* c;
24579a747e4fSDavid du Colombier Tablecell* cnext;
24589a747e4fSDavid du Colombier Tablerow* row;
24599a747e4fSDavid du Colombier Tablerow* rownext;
24609a747e4fSDavid du Colombier int rcols;
24619a747e4fSDavid du Colombier int newncol;
24629a747e4fSDavid du Colombier int k;
24639a747e4fSDavid du Colombier int j;
24649a747e4fSDavid du Colombier int cspan;
24659a747e4fSDavid du Colombier int rspan;
24669a747e4fSDavid du Colombier int i;
24679a747e4fSDavid du Colombier
24689a747e4fSDavid du Colombier rl = t->rows;
24699a747e4fSDavid du Colombier t->nrow = nrow = _listlen((List*)rl);
24709a747e4fSDavid du Colombier t->rows = (Tablerow*)emalloc(nrow * sizeof(Tablerow));
24719a747e4fSDavid du Colombier ncol = 0;
24729a747e4fSDavid du Colombier r = nrow - 1;
24739a747e4fSDavid du Colombier for(row = rl; row != nil; row = rownext) {
24749a747e4fSDavid du Colombier // copy the data from the allocated Tablerow into the array slot
24759a747e4fSDavid du Colombier t->rows[r] = *row;
24769a747e4fSDavid du Colombier rownext = row->next;
24779a747e4fSDavid du Colombier row = &t->rows[r];
24789a747e4fSDavid du Colombier r--;
24799a747e4fSDavid du Colombier rcols = 0;
24809a747e4fSDavid du Colombier c = row->cells;
24819a747e4fSDavid du Colombier
24829a747e4fSDavid du Colombier // If rowspan is > 1 but this is the last row,
24839a747e4fSDavid du Colombier // reset the rowspan
24849a747e4fSDavid du Colombier if(c != nil && c->rowspan > 1 && r == nrow-2)
24859a747e4fSDavid du Colombier c->rowspan = 1;
24869a747e4fSDavid du Colombier
24879a747e4fSDavid du Colombier // reverse row->cells list (along nextinrow pointers)
24889a747e4fSDavid du Colombier row->cells = nil;
24899a747e4fSDavid du Colombier while(c != nil) {
24909a747e4fSDavid du Colombier cnext = c->nextinrow;
24919a747e4fSDavid du Colombier c->nextinrow = row->cells;
24929a747e4fSDavid du Colombier row->cells = c;
24939a747e4fSDavid du Colombier rcols += c->colspan;
24949a747e4fSDavid du Colombier c = cnext;
24959a747e4fSDavid du Colombier }
24969a747e4fSDavid du Colombier if(rcols > ncol)
24979a747e4fSDavid du Colombier ncol = rcols;
24989a747e4fSDavid du Colombier }
24999a747e4fSDavid du Colombier t->ncol = ncol;
25009a747e4fSDavid du Colombier t->cols = (Tablecol*)emalloc(ncol * sizeof(Tablecol));
25019a747e4fSDavid du Colombier
25029a747e4fSDavid du Colombier // Reverse cells just so they are drawn in source order.
25039a747e4fSDavid du Colombier // Also, trim their contents so they don't end in whitespace.
25049a747e4fSDavid du Colombier t->cells = (Tablecell*)_revlist((List*)t->cells);
25059a747e4fSDavid du Colombier for(c = t->cells; c != nil; c= c->next)
25069a747e4fSDavid du Colombier trim_cell(c);
25079a747e4fSDavid du Colombier t->grid = (Tablecell***)emalloc(nrow * sizeof(Tablecell**));
25089a747e4fSDavid du Colombier for(i = 0; i < nrow; i++)
25099a747e4fSDavid du Colombier t->grid[i] = (Tablecell**)emalloc(ncol * sizeof(Tablecell*));
25109a747e4fSDavid du Colombier
25119a747e4fSDavid du Colombier // The following arrays keep track of cells that are spanning
25129a747e4fSDavid du Colombier // multiple rows; rowspancnt[i] is the number of rows left
25139a747e4fSDavid du Colombier // to be spanned in column i.
25149a747e4fSDavid du Colombier // When done, cell's (row,col) is upper left grid point.
25159a747e4fSDavid du Colombier rowspancnt = (int*)emalloc(ncol * sizeof(int));
25169a747e4fSDavid du Colombier rowspancell = (Tablecell**)emalloc(ncol * sizeof(Tablecell*));
25179a747e4fSDavid du Colombier for(ri = 0; ri < nrow; ri++) {
25189a747e4fSDavid du Colombier row = &t->rows[ri];
25199a747e4fSDavid du Colombier cl = row->cells;
25209a747e4fSDavid du Colombier ci = 0;
25219a747e4fSDavid du Colombier while(ci < ncol || cl != nil) {
25229a747e4fSDavid du Colombier if(ci < ncol && rowspancnt[ci] > 0) {
25239a747e4fSDavid du Colombier t->grid[ri][ci] = rowspancell[ci];
25249a747e4fSDavid du Colombier rowspancnt[ci]--;
25259a747e4fSDavid du Colombier ci++;
25269a747e4fSDavid du Colombier }
25279a747e4fSDavid du Colombier else {
25289a747e4fSDavid du Colombier if(cl == nil) {
25299a747e4fSDavid du Colombier ci++;
25309a747e4fSDavid du Colombier continue;
25319a747e4fSDavid du Colombier }
25329a747e4fSDavid du Colombier c = cl;
25339a747e4fSDavid du Colombier cl = cl->nextinrow;
25349a747e4fSDavid du Colombier cspan = c->colspan;
25359a747e4fSDavid du Colombier rspan = c->rowspan;
25369a747e4fSDavid du Colombier if(ci + cspan > ncol) {
25379a747e4fSDavid du Colombier // because of row spanning, we calculated
25389a747e4fSDavid du Colombier // ncol incorrectly; adjust it
25399a747e4fSDavid du Colombier newncol = ci + cspan;
25409a747e4fSDavid du Colombier t->cols = (Tablecol*)erealloc(t->cols, newncol * sizeof(Tablecol));
25419a747e4fSDavid du Colombier rowspancnt = (int*)erealloc(rowspancnt, newncol * sizeof(int));
25429a747e4fSDavid du Colombier rowspancell = (Tablecell**)erealloc(rowspancell, newncol * sizeof(Tablecell*));
25439a747e4fSDavid du Colombier k = newncol-ncol;
25449a747e4fSDavid du Colombier memset(t->cols+ncol, 0, k*sizeof(Tablecol));
25459a747e4fSDavid du Colombier memset(rowspancnt+ncol, 0, k*sizeof(int));
25469a747e4fSDavid du Colombier memset(rowspancell+ncol, 0, k*sizeof(Tablecell*));
25479a747e4fSDavid du Colombier for(j = 0; j < nrow; j++) {
25489a747e4fSDavid du Colombier t->grid[j] = (Tablecell**)erealloc(t->grid[j], newncol * sizeof(Tablecell*));
25499a747e4fSDavid du Colombier memset(t->grid[j], 0, k*sizeof(Tablecell*));
25509a747e4fSDavid du Colombier }
25519a747e4fSDavid du Colombier t->ncol = ncol = newncol;
25529a747e4fSDavid du Colombier }
25539a747e4fSDavid du Colombier c->row = ri;
25549a747e4fSDavid du Colombier c->col = ci;
25559a747e4fSDavid du Colombier for(i = 0; i < cspan; i++) {
25569a747e4fSDavid du Colombier t->grid[ri][ci] = c;
25579a747e4fSDavid du Colombier if(rspan > 1) {
25589a747e4fSDavid du Colombier rowspancnt[ci] = rspan - 1;
25599a747e4fSDavid du Colombier rowspancell[ci] = c;
25609a747e4fSDavid du Colombier }
25619a747e4fSDavid du Colombier ci++;
25629a747e4fSDavid du Colombier }
25639a747e4fSDavid du Colombier }
25649a747e4fSDavid du Colombier }
25659a747e4fSDavid du Colombier }
25661066d6deSDavid du Colombier free(rowspancnt);
25671066d6deSDavid du Colombier free(rowspancell);
25689a747e4fSDavid du Colombier }
25699a747e4fSDavid du Colombier
25709a747e4fSDavid du Colombier // Remove tail of cell content until it isn't whitespace.
25719a747e4fSDavid du Colombier static void
trim_cell(Tablecell * c)25729a747e4fSDavid du Colombier trim_cell(Tablecell* c)
25739a747e4fSDavid du Colombier {
25749a747e4fSDavid du Colombier int dropping;
25759a747e4fSDavid du Colombier Rune* s;
25769a747e4fSDavid du Colombier Rune* x;
25779a747e4fSDavid du Colombier Rune* y;
25789a747e4fSDavid du Colombier int nx;
25799a747e4fSDavid du Colombier int ny;
25809a747e4fSDavid du Colombier Item* p;
25819a747e4fSDavid du Colombier Itext* q;
25829a747e4fSDavid du Colombier Item* pprev;
25839a747e4fSDavid du Colombier
25849a747e4fSDavid du Colombier dropping = 1;
25859a747e4fSDavid du Colombier while(c->content != nil && dropping) {
25869a747e4fSDavid du Colombier p = c->content;
25879a747e4fSDavid du Colombier pprev = nil;
25889a747e4fSDavid du Colombier while(p->next != nil) {
25899a747e4fSDavid du Colombier pprev = p;
25909a747e4fSDavid du Colombier p = p->next;
25919a747e4fSDavid du Colombier }
25929a747e4fSDavid du Colombier dropping = 0;
25939a747e4fSDavid du Colombier if(!(p->state&IFnobrk)) {
25949a747e4fSDavid du Colombier if(p->tag == Itexttag) {
25959a747e4fSDavid du Colombier q = (Itext*)p;
25969a747e4fSDavid du Colombier s = q->s;
25975d459b5aSDavid du Colombier _splitr(s, _Strlen(s), notwhitespace, &x, &nx, &y, &ny);
25989a747e4fSDavid du Colombier if(nx != 0 && ny != 0) {
25999a747e4fSDavid du Colombier q->s = _Strndup(x, nx);
26009a747e4fSDavid du Colombier free(s);
26019a747e4fSDavid du Colombier }
26029a747e4fSDavid du Colombier break;
26039a747e4fSDavid du Colombier }
26049a747e4fSDavid du Colombier }
26059a747e4fSDavid du Colombier if(dropping) {
26069a747e4fSDavid du Colombier if(pprev == nil)
26079a747e4fSDavid du Colombier c->content = nil;
26089a747e4fSDavid du Colombier else
26099a747e4fSDavid du Colombier pprev->next = nil;
26109a747e4fSDavid du Colombier freeitem(p);
26119a747e4fSDavid du Colombier }
26129a747e4fSDavid du Colombier }
26139a747e4fSDavid du Colombier }
26149a747e4fSDavid du Colombier
26159a747e4fSDavid du Colombier // Caller must free answer (eventually).
26169a747e4fSDavid du Colombier static Rune*
listmark(uchar ty,int n)26179a747e4fSDavid du Colombier listmark(uchar ty, int n)
26189a747e4fSDavid du Colombier {
26199a747e4fSDavid du Colombier Rune* s;
26209a747e4fSDavid du Colombier Rune* t;
26219a747e4fSDavid du Colombier int n2;
26229a747e4fSDavid du Colombier int i;
26239a747e4fSDavid du Colombier
26249a747e4fSDavid du Colombier s = nil;
26259a747e4fSDavid du Colombier switch(ty) {
26269a747e4fSDavid du Colombier case LTdisc:
26279a747e4fSDavid du Colombier case LTsquare:
26289a747e4fSDavid du Colombier case LTcircle:
26299a747e4fSDavid du Colombier s = _newstr(1);
26309a747e4fSDavid du Colombier s[0] = (ty == LTdisc)? 0x2022 // bullet
26319a747e4fSDavid du Colombier : ((ty == LTsquare)? 0x220e // filled square
26329a747e4fSDavid du Colombier : 0x2218); // degree
26339a747e4fSDavid du Colombier s[1] = 0;
26349a747e4fSDavid du Colombier break;
26359a747e4fSDavid du Colombier
26369a747e4fSDavid du Colombier case LT1:
2637c93608ccSDavid du Colombier s = runesmprint("%d.", n);
26389a747e4fSDavid du Colombier break;
26399a747e4fSDavid du Colombier
26409a747e4fSDavid du Colombier case LTa:
26419a747e4fSDavid du Colombier case LTA:
26429a747e4fSDavid du Colombier n--;
26439a747e4fSDavid du Colombier i = 0;
26449a747e4fSDavid du Colombier if(n < 0)
26459a747e4fSDavid du Colombier n = 0;
26469a747e4fSDavid du Colombier s = _newstr((n <= 25)? 2 : 3);
26479a747e4fSDavid du Colombier if(n > 25) {
26489a747e4fSDavid du Colombier n2 = n%26;
26499a747e4fSDavid du Colombier n /= 26;
26509a747e4fSDavid du Colombier if(n2 > 25)
26519a747e4fSDavid du Colombier n2 = 25;
26529a747e4fSDavid du Colombier s[i++] = n2 + (ty == LTa)? 'a' : 'A';
26539a747e4fSDavid du Colombier }
26549a747e4fSDavid du Colombier s[i++] = n + (ty == LTa)? 'a' : 'A';
26559a747e4fSDavid du Colombier s[i++] = '.';
26569a747e4fSDavid du Colombier s[i] = 0;
26579a747e4fSDavid du Colombier break;
26589a747e4fSDavid du Colombier
26599a747e4fSDavid du Colombier case LTi:
26609a747e4fSDavid du Colombier case LTI:
26619a747e4fSDavid du Colombier if(n >= NROMAN) {
26629a747e4fSDavid du Colombier if(warn)
26639a747e4fSDavid du Colombier fprint(2, "warning: unimplemented roman number > %d\n", NROMAN);
26649a747e4fSDavid du Colombier n = NROMAN;
26659a747e4fSDavid du Colombier }
26669a747e4fSDavid du Colombier t = roman[n - 1];
26675d459b5aSDavid du Colombier n2 = _Strlen(t);
26689a747e4fSDavid du Colombier s = _newstr(n2+1);
26699a747e4fSDavid du Colombier for(i = 0; i < n2; i++)
26709a747e4fSDavid du Colombier s[i] = (ty == LTi)? tolower(t[i]) : t[i];
26719a747e4fSDavid du Colombier s[i++] = '.';
26729a747e4fSDavid du Colombier s[i] = 0;
26739a747e4fSDavid du Colombier break;
26749a747e4fSDavid du Colombier }
26759a747e4fSDavid du Colombier return s;
26769a747e4fSDavid du Colombier }
26779a747e4fSDavid du Colombier
26789a747e4fSDavid du Colombier // Find map with given name in di.maps.
26799a747e4fSDavid du Colombier // If not there, add one, copying name.
26809a747e4fSDavid du Colombier // Ownership of map remains with di->maps list.
26819a747e4fSDavid du Colombier static Map*
getmap(Docinfo * di,Rune * name)26829a747e4fSDavid du Colombier getmap(Docinfo* di, Rune* name)
26839a747e4fSDavid du Colombier {
26849a747e4fSDavid du Colombier Map* m;
26859a747e4fSDavid du Colombier
26869a747e4fSDavid du Colombier for(m = di->maps; m != nil; m = m->next) {
26875d459b5aSDavid du Colombier if(!_Strcmp(name, m->name))
26889a747e4fSDavid du Colombier return m;
26899a747e4fSDavid du Colombier }
26909a747e4fSDavid du Colombier m = (Map*)emalloc(sizeof(Map));
26919a747e4fSDavid du Colombier m->name = _Strdup(name);
26929a747e4fSDavid du Colombier m->areas = nil;
26939a747e4fSDavid du Colombier m->next = di->maps;
26949a747e4fSDavid du Colombier di->maps = m;
26959a747e4fSDavid du Colombier return m;
26969a747e4fSDavid du Colombier }
26979a747e4fSDavid du Colombier
26989a747e4fSDavid du Colombier // Transfers ownership of href to Area
26999a747e4fSDavid du Colombier static Area*
newarea(int shape,Rune * href,int target,Area * link)27009a747e4fSDavid du Colombier newarea(int shape, Rune* href, int target, Area* link)
27019a747e4fSDavid du Colombier {
27029a747e4fSDavid du Colombier Area* a;
27039a747e4fSDavid du Colombier
27049a747e4fSDavid du Colombier a = (Area*)emalloc(sizeof(Area));
27059a747e4fSDavid du Colombier a->shape = shape;
27069a747e4fSDavid du Colombier a->href = href;
27079a747e4fSDavid du Colombier a->target = target;
27089a747e4fSDavid du Colombier a->next = link;
27099a747e4fSDavid du Colombier return a;
27109a747e4fSDavid du Colombier }
27119a747e4fSDavid du Colombier
27129a747e4fSDavid du Colombier // Return string value associated with attid in tok, nil if none.
27139a747e4fSDavid du Colombier // Caller must free the result (eventually).
27149a747e4fSDavid du Colombier static Rune*
aval(Token * tok,int attid)27159a747e4fSDavid du Colombier aval(Token* tok, int attid)
27169a747e4fSDavid du Colombier {
27179a747e4fSDavid du Colombier Rune* ans;
27189a747e4fSDavid du Colombier
27199a747e4fSDavid du Colombier _tokaval(tok, attid, &ans, 1); // transfers string ownership from token to ans
27209a747e4fSDavid du Colombier return ans;
27219a747e4fSDavid du Colombier }
27229a747e4fSDavid du Colombier
27239a747e4fSDavid du Colombier // Like aval, but use dflt if there was no such attribute in tok.
27249a747e4fSDavid du Colombier // Caller must free the result (eventually).
27259a747e4fSDavid du Colombier static Rune*
astrval(Token * tok,int attid,Rune * dflt)27269a747e4fSDavid du Colombier astrval(Token* tok, int attid, Rune* dflt)
27279a747e4fSDavid du Colombier {
27289a747e4fSDavid du Colombier Rune* ans;
27299a747e4fSDavid du Colombier
27309a747e4fSDavid du Colombier if(_tokaval(tok, attid, &ans, 1))
27319a747e4fSDavid du Colombier return ans; // transfers string ownership from token to ans
27329a747e4fSDavid du Colombier else
27339a747e4fSDavid du Colombier return _Strdup(dflt);
27349a747e4fSDavid du Colombier }
27359a747e4fSDavid du Colombier
27369a747e4fSDavid du Colombier // Here we're supposed to convert to an int,
27379a747e4fSDavid du Colombier // and have a default when not found
27389a747e4fSDavid du Colombier static int
aintval(Token * tok,int attid,int dflt)27399a747e4fSDavid du Colombier aintval(Token* tok, int attid, int dflt)
27409a747e4fSDavid du Colombier {
27419a747e4fSDavid du Colombier Rune* ans;
27429a747e4fSDavid du Colombier
27439a747e4fSDavid du Colombier if(!_tokaval(tok, attid, &ans, 0) || ans == nil)
27449a747e4fSDavid du Colombier return dflt;
27459a747e4fSDavid du Colombier else
27469a747e4fSDavid du Colombier return toint(ans);
27479a747e4fSDavid du Colombier }
27489a747e4fSDavid du Colombier
27499a747e4fSDavid du Colombier // Like aintval, but result should be >= 0
27509a747e4fSDavid du Colombier static int
auintval(Token * tok,int attid,int dflt)27519a747e4fSDavid du Colombier auintval(Token* tok, int attid, int dflt)
27529a747e4fSDavid du Colombier {
27539a747e4fSDavid du Colombier Rune* ans;
27549a747e4fSDavid du Colombier int v;
27559a747e4fSDavid du Colombier
27569a747e4fSDavid du Colombier if(!_tokaval(tok, attid, &ans, 0) || ans == nil)
27579a747e4fSDavid du Colombier return dflt;
27589a747e4fSDavid du Colombier else {
27599a747e4fSDavid du Colombier v = toint(ans);
27609a747e4fSDavid du Colombier return v >= 0? v : 0;
27619a747e4fSDavid du Colombier }
27629a747e4fSDavid du Colombier }
27639a747e4fSDavid du Colombier
27649a747e4fSDavid du Colombier // int conversion, but with possible error check (if warning)
27659a747e4fSDavid du Colombier static int
toint(Rune * s)27669a747e4fSDavid du Colombier toint(Rune* s)
27679a747e4fSDavid du Colombier {
27689a747e4fSDavid du Colombier int ans;
27699a747e4fSDavid du Colombier Rune* eptr;
27709a747e4fSDavid du Colombier
27719a747e4fSDavid du Colombier ans = _Strtol(s, &eptr, 10);
27729a747e4fSDavid du Colombier if(warn) {
27739a747e4fSDavid du Colombier if(*eptr != 0) {
27749a747e4fSDavid du Colombier eptr = _Strclass(eptr, notwhitespace);
27759a747e4fSDavid du Colombier if(eptr != nil)
27769a747e4fSDavid du Colombier fprint(2, "warning: expected integer, got %S\n", s);
27779a747e4fSDavid du Colombier }
27789a747e4fSDavid du Colombier }
27799a747e4fSDavid du Colombier return ans;
27809a747e4fSDavid du Colombier }
27819a747e4fSDavid du Colombier
27829a747e4fSDavid du Colombier // Attribute value when need a table to convert strings to ints
27839a747e4fSDavid du Colombier static int
atabval(Token * tok,int attid,StringInt * tab,int ntab,int dflt)27849a747e4fSDavid du Colombier atabval(Token* tok, int attid, StringInt* tab, int ntab, int dflt)
27859a747e4fSDavid du Colombier {
27869a747e4fSDavid du Colombier Rune* aval;
27879a747e4fSDavid du Colombier int ans;
27889a747e4fSDavid du Colombier
27899a747e4fSDavid du Colombier ans = dflt;
27909a747e4fSDavid du Colombier if(_tokaval(tok, attid, &aval, 0)) {
27915d459b5aSDavid du Colombier if(!_lookup(tab, ntab, aval, _Strlen(aval), &ans)) {
27929a747e4fSDavid du Colombier ans = dflt;
27939a747e4fSDavid du Colombier if(warn)
27949a747e4fSDavid du Colombier fprint(2, "warning: name not found in table lookup: %S\n", aval);
27959a747e4fSDavid du Colombier }
27969a747e4fSDavid du Colombier }
27979a747e4fSDavid du Colombier return ans;
27989a747e4fSDavid du Colombier }
27999a747e4fSDavid du Colombier
28009a747e4fSDavid du Colombier // Attribute value when supposed to be a color
28019a747e4fSDavid du Colombier static int
acolorval(Token * tok,int attid,int dflt)28029a747e4fSDavid du Colombier acolorval(Token* tok, int attid, int dflt)
28039a747e4fSDavid du Colombier {
28049a747e4fSDavid du Colombier Rune* aval;
28059a747e4fSDavid du Colombier int ans;
28069a747e4fSDavid du Colombier
28079a747e4fSDavid du Colombier ans = dflt;
28089a747e4fSDavid du Colombier if(_tokaval(tok, attid, &aval, 0))
28099a747e4fSDavid du Colombier ans = color(aval, dflt);
28109a747e4fSDavid du Colombier return ans;
28119a747e4fSDavid du Colombier }
28129a747e4fSDavid du Colombier
28139a747e4fSDavid du Colombier // Attribute value when supposed to be a target frame name
28149a747e4fSDavid du Colombier static int
atargval(Token * tok,int dflt)28159a747e4fSDavid du Colombier atargval(Token* tok, int dflt)
28169a747e4fSDavid du Colombier {
28179a747e4fSDavid du Colombier int ans;
28189a747e4fSDavid du Colombier Rune* aval;
28199a747e4fSDavid du Colombier
28209a747e4fSDavid du Colombier ans = dflt;
28219a747e4fSDavid du Colombier if(_tokaval(tok, Atarget, &aval, 0)){
28229a747e4fSDavid du Colombier ans = targetid(aval);
28239a747e4fSDavid du Colombier }
28249a747e4fSDavid du Colombier return ans;
28259a747e4fSDavid du Colombier }
28269a747e4fSDavid du Colombier
28279a747e4fSDavid du Colombier // special for list types, where "i" and "I" are different,
28289a747e4fSDavid du Colombier // but "square" and "SQUARE" are the same
28299a747e4fSDavid du Colombier static int
listtyval(Token * tok,int dflt)28309a747e4fSDavid du Colombier listtyval(Token* tok, int dflt)
28319a747e4fSDavid du Colombier {
28329a747e4fSDavid du Colombier Rune* aval;
28339a747e4fSDavid du Colombier int ans;
28349a747e4fSDavid du Colombier int n;
28359a747e4fSDavid du Colombier
28369a747e4fSDavid du Colombier ans = dflt;
28379a747e4fSDavid du Colombier if(_tokaval(tok, Atype, &aval, 0)) {
28385d459b5aSDavid du Colombier n = _Strlen(aval);
28399a747e4fSDavid du Colombier if(n == 1) {
28409a747e4fSDavid du Colombier switch(aval[0]) {
28419a747e4fSDavid du Colombier case '1':
28429a747e4fSDavid du Colombier ans = LT1;
28439a747e4fSDavid du Colombier break;
28449a747e4fSDavid du Colombier case 'A':
28459a747e4fSDavid du Colombier ans = LTA;
28469a747e4fSDavid du Colombier break;
28479a747e4fSDavid du Colombier case 'I':
28489a747e4fSDavid du Colombier ans = LTI;
28499a747e4fSDavid du Colombier break;
28509a747e4fSDavid du Colombier case 'a':
28519a747e4fSDavid du Colombier ans = LTa;
28529a747e4fSDavid du Colombier break;
28539a747e4fSDavid du Colombier case 'i':
28549a747e4fSDavid du Colombier ans = LTi;
28559a747e4fSDavid du Colombier default:
28569a747e4fSDavid du Colombier if(warn)
28579a747e4fSDavid du Colombier fprint(2, "warning: unknown list element type %c\n", aval[0]);
28589a747e4fSDavid du Colombier }
28599a747e4fSDavid du Colombier }
28609a747e4fSDavid du Colombier else {
28619a747e4fSDavid du Colombier if(!_Strncmpci(aval, n, L"circle"))
28629a747e4fSDavid du Colombier ans = LTcircle;
28639a747e4fSDavid du Colombier else if(!_Strncmpci(aval, n, L"disc"))
28649a747e4fSDavid du Colombier ans = LTdisc;
28659a747e4fSDavid du Colombier else if(!_Strncmpci(aval, n, L"square"))
28669a747e4fSDavid du Colombier ans = LTsquare;
28679a747e4fSDavid du Colombier else {
28689a747e4fSDavid du Colombier if(warn)
28699a747e4fSDavid du Colombier fprint(2, "warning: unknown list element type %S\n", aval);
28709a747e4fSDavid du Colombier }
28719a747e4fSDavid du Colombier }
28729a747e4fSDavid du Colombier }
28739a747e4fSDavid du Colombier return ans;
28749a747e4fSDavid du Colombier }
28759a747e4fSDavid du Colombier
28769a747e4fSDavid du Colombier // Attribute value when value is a URL, possibly relative to base.
28779a747e4fSDavid du Colombier // FOR NOW: leave the url relative.
28789a747e4fSDavid du Colombier // Caller must free the result (eventually).
28799a747e4fSDavid du Colombier static Rune*
aurlval(Token * tok,int attid,Rune * dflt,Rune * base)28809a747e4fSDavid du Colombier aurlval(Token* tok, int attid, Rune* dflt, Rune* base)
28819a747e4fSDavid du Colombier {
28829a747e4fSDavid du Colombier Rune* ans;
28839a747e4fSDavid du Colombier Rune* url;
28849a747e4fSDavid du Colombier
28859a747e4fSDavid du Colombier USED(base);
28869a747e4fSDavid du Colombier ans = nil;
28879a747e4fSDavid du Colombier if(_tokaval(tok, attid, &url, 0) && url != nil)
28889a747e4fSDavid du Colombier ans = removeallwhite(url);
28899a747e4fSDavid du Colombier if(ans == nil)
28909a747e4fSDavid du Colombier ans = _Strdup(dflt);
28919a747e4fSDavid du Colombier return ans;
28929a747e4fSDavid du Colombier }
28939a747e4fSDavid du Colombier
28949a747e4fSDavid du Colombier // Return copy of s but with all whitespace (even internal) removed.
28959a747e4fSDavid du Colombier // This fixes some buggy URL specification strings.
28969a747e4fSDavid du Colombier static Rune*
removeallwhite(Rune * s)28979a747e4fSDavid du Colombier removeallwhite(Rune* s)
28989a747e4fSDavid du Colombier {
28999a747e4fSDavid du Colombier int j;
29009a747e4fSDavid du Colombier int n;
29019a747e4fSDavid du Colombier int i;
29029a747e4fSDavid du Colombier int c;
29039a747e4fSDavid du Colombier Rune* ans;
29049a747e4fSDavid du Colombier
29059a747e4fSDavid du Colombier j = 0;
29065d459b5aSDavid du Colombier n = _Strlen(s);
29079a747e4fSDavid du Colombier for(i = 0; i < n; i++) {
29089a747e4fSDavid du Colombier c = s[i];
29099a747e4fSDavid du Colombier if(c >= 256 || !isspace(c))
29109a747e4fSDavid du Colombier j++;
29119a747e4fSDavid du Colombier }
29129a747e4fSDavid du Colombier if(j < n) {
29139a747e4fSDavid du Colombier ans = _newstr(j);
29149a747e4fSDavid du Colombier j = 0;
29159a747e4fSDavid du Colombier for(i = 0; i < n; i++) {
29169a747e4fSDavid du Colombier c = s[i];
29179a747e4fSDavid du Colombier if(c >= 256 || !isspace(c))
29189a747e4fSDavid du Colombier ans[j++] = c;
29199a747e4fSDavid du Colombier }
29209a747e4fSDavid du Colombier ans[j] = 0;
29219a747e4fSDavid du Colombier }
29229a747e4fSDavid du Colombier else
29239a747e4fSDavid du Colombier ans = _Strdup(s);
29249a747e4fSDavid du Colombier return ans;
29259a747e4fSDavid du Colombier }
29269a747e4fSDavid du Colombier
29279a747e4fSDavid du Colombier // Attribute value when mere presence of attr implies value of 1,
29289a747e4fSDavid du Colombier // but if there is an integer there, return it as the value.
29299a747e4fSDavid du Colombier static int
aflagval(Token * tok,int attid)29309a747e4fSDavid du Colombier aflagval(Token* tok, int attid)
29319a747e4fSDavid du Colombier {
29329a747e4fSDavid du Colombier int val;
29339a747e4fSDavid du Colombier Rune* sval;
29349a747e4fSDavid du Colombier
29359a747e4fSDavid du Colombier val = 0;
29369a747e4fSDavid du Colombier if(_tokaval(tok, attid, &sval, 0)) {
29379a747e4fSDavid du Colombier val = 1;
29389a747e4fSDavid du Colombier if(sval != nil)
29399a747e4fSDavid du Colombier val = toint(sval);
29409a747e4fSDavid du Colombier }
29419a747e4fSDavid du Colombier return val;
29429a747e4fSDavid du Colombier }
29439a747e4fSDavid du Colombier
29449a747e4fSDavid du Colombier static Align
makealign(int halign,int valign)29459a747e4fSDavid du Colombier makealign(int halign, int valign)
29469a747e4fSDavid du Colombier {
29479a747e4fSDavid du Colombier Align al;
29489a747e4fSDavid du Colombier
29499a747e4fSDavid du Colombier al.halign = halign;
29509a747e4fSDavid du Colombier al.valign = valign;
29519a747e4fSDavid du Colombier return al;
29529a747e4fSDavid du Colombier }
29539a747e4fSDavid du Colombier
29549a747e4fSDavid du Colombier // Make an Align (two alignments, horizontal and vertical)
29559a747e4fSDavid du Colombier static Align
aalign(Token * tok)29569a747e4fSDavid du Colombier aalign(Token* tok)
29579a747e4fSDavid du Colombier {
29589a747e4fSDavid du Colombier return makealign(
29599a747e4fSDavid du Colombier atabval(tok, Aalign, align_tab, NALIGNTAB, ALnone),
29609a747e4fSDavid du Colombier atabval(tok, Avalign, align_tab, NALIGNTAB, ALnone));
29619a747e4fSDavid du Colombier }
29629a747e4fSDavid du Colombier
29639a747e4fSDavid du Colombier // Make a Dimen, based on value of attid attr
29649a747e4fSDavid du Colombier static Dimen
adimen(Token * tok,int attid)29659a747e4fSDavid du Colombier adimen(Token* tok, int attid)
29669a747e4fSDavid du Colombier {
29679a747e4fSDavid du Colombier Rune* wd;
29689a747e4fSDavid du Colombier
29699a747e4fSDavid du Colombier if(_tokaval(tok, attid, &wd, 0))
29705d459b5aSDavid du Colombier return parsedim(wd, _Strlen(wd));
29719a747e4fSDavid du Colombier else
29729a747e4fSDavid du Colombier return makedimen(Dnone, 0);
29739a747e4fSDavid du Colombier }
29749a747e4fSDavid du Colombier
29759a747e4fSDavid du Colombier // Parse s[0:n] as num[.[num]][unit][%|*]
29769a747e4fSDavid du Colombier static Dimen
parsedim(Rune * s,int ns)29779a747e4fSDavid du Colombier parsedim(Rune* s, int ns)
29789a747e4fSDavid du Colombier {
29799a747e4fSDavid du Colombier int kind;
29809a747e4fSDavid du Colombier int spec;
29819a747e4fSDavid du Colombier Rune* l;
29829a747e4fSDavid du Colombier int nl;
29839a747e4fSDavid du Colombier Rune* r;
29849a747e4fSDavid du Colombier int nr;
29859a747e4fSDavid du Colombier int mul;
29869a747e4fSDavid du Colombier int i;
29879a747e4fSDavid du Colombier Rune* f;
29889a747e4fSDavid du Colombier int nf;
29899a747e4fSDavid du Colombier int Tkdpi;
29909a747e4fSDavid du Colombier Rune* units;
29919a747e4fSDavid du Colombier
29929a747e4fSDavid du Colombier kind = Dnone;
29939a747e4fSDavid du Colombier spec = 0;
29949a747e4fSDavid du Colombier _splitl(s, ns, L"^0-9", &l, &nl, &r, &nr);
29959a747e4fSDavid du Colombier if(nl != 0) {
29969a747e4fSDavid du Colombier spec = 1000*_Strtol(l, nil, 10);
29979a747e4fSDavid du Colombier if(nr > 0 && r[0] == '.') {
29989a747e4fSDavid du Colombier _splitl(r+1, nr-1, L"^0-9", &f, &nf, &r, &nr);
29999a747e4fSDavid du Colombier if(nf != 0) {
30009a747e4fSDavid du Colombier mul = 100;
30019a747e4fSDavid du Colombier for(i = 0; i < nf; i++) {
30029a747e4fSDavid du Colombier spec = spec + mul*(f[i]-'0');
30039a747e4fSDavid du Colombier mul = mul/10;
30049a747e4fSDavid du Colombier }
30059a747e4fSDavid du Colombier }
30069a747e4fSDavid du Colombier }
30079a747e4fSDavid du Colombier kind = Dpixels;
30089a747e4fSDavid du Colombier if(nr != 0) {
30099a747e4fSDavid du Colombier if(nr >= 2) {
30109a747e4fSDavid du Colombier Tkdpi = 100;
30119a747e4fSDavid du Colombier units = r;
30129a747e4fSDavid du Colombier r = r+2;
30139a747e4fSDavid du Colombier nr -= 2;
30149a747e4fSDavid du Colombier if(!_Strncmpci(units, 2, L"pt"))
30159a747e4fSDavid du Colombier spec = (spec*Tkdpi)/72;
30169a747e4fSDavid du Colombier else if(!_Strncmpci(units, 2, L"pi"))
30179a747e4fSDavid du Colombier spec = (spec*12*Tkdpi)/72;
30189a747e4fSDavid du Colombier else if(!_Strncmpci(units, 2, L"in"))
30199a747e4fSDavid du Colombier spec = spec*Tkdpi;
30209a747e4fSDavid du Colombier else if(!_Strncmpci(units, 2, L"cm"))
30219a747e4fSDavid du Colombier spec = (spec*100*Tkdpi)/254;
30229a747e4fSDavid du Colombier else if(!_Strncmpci(units, 2, L"mm"))
30239a747e4fSDavid du Colombier spec = (spec*10*Tkdpi)/254;
30249a747e4fSDavid du Colombier else if(!_Strncmpci(units, 2, L"em"))
30259a747e4fSDavid du Colombier spec = spec*15;
30269a747e4fSDavid du Colombier else {
30279a747e4fSDavid du Colombier if(warn)
30289a747e4fSDavid du Colombier fprint(2, "warning: unknown units %C%Cs\n", units[0], units[1]);
30299a747e4fSDavid du Colombier }
30309a747e4fSDavid du Colombier }
30319a747e4fSDavid du Colombier if(nr >= 1) {
30329a747e4fSDavid du Colombier if(r[0] == '%')
30339a747e4fSDavid du Colombier kind = Dpercent;
30349a747e4fSDavid du Colombier else if(r[0] == '*')
30359a747e4fSDavid du Colombier kind = Drelative;
30369a747e4fSDavid du Colombier }
30379a747e4fSDavid du Colombier }
30389a747e4fSDavid du Colombier spec = spec/1000;
30399a747e4fSDavid du Colombier }
30409a747e4fSDavid du Colombier else if(nr == 1 && r[0] == '*') {
30419a747e4fSDavid du Colombier spec = 1;
30429a747e4fSDavid du Colombier kind = Drelative;
30439a747e4fSDavid du Colombier }
30449a747e4fSDavid du Colombier return makedimen(kind, spec);
30459a747e4fSDavid du Colombier }
30469a747e4fSDavid du Colombier
30479a747e4fSDavid du Colombier static void
setdimarray(Token * tok,int attid,Dimen ** pans,int * panslen)30489a747e4fSDavid du Colombier setdimarray(Token* tok, int attid, Dimen** pans, int* panslen)
30499a747e4fSDavid du Colombier {
30509a747e4fSDavid du Colombier Rune* s;
30519a747e4fSDavid du Colombier Dimen* d;
30529a747e4fSDavid du Colombier int k;
30539a747e4fSDavid du Colombier int nc;
30549a747e4fSDavid du Colombier Rune* a[SMALLBUFSIZE];
30559a747e4fSDavid du Colombier int an[SMALLBUFSIZE];
30569a747e4fSDavid du Colombier
30579a747e4fSDavid du Colombier if(_tokaval(tok, attid, &s, 0)) {
30585d459b5aSDavid du Colombier nc = _splitall(s, _Strlen(s), L", ", a, an, SMALLBUFSIZE);
30599a747e4fSDavid du Colombier if(nc > 0) {
30609a747e4fSDavid du Colombier d = (Dimen*)emalloc(nc * sizeof(Dimen));
30619a747e4fSDavid du Colombier for(k = 0; k < nc; k++) {
30629a747e4fSDavid du Colombier d[k] = parsedim(a[k], an[k]);
30639a747e4fSDavid du Colombier }
30649a747e4fSDavid du Colombier *pans = d;
30659a747e4fSDavid du Colombier *panslen = nc;
30669a747e4fSDavid du Colombier return;
30679a747e4fSDavid du Colombier }
30689a747e4fSDavid du Colombier }
30699a747e4fSDavid du Colombier *pans = nil;
30709a747e4fSDavid du Colombier *panslen = 0;
30719a747e4fSDavid du Colombier }
30729a747e4fSDavid du Colombier
30739a747e4fSDavid du Colombier static Background
makebackground(Rune * imageurl,int color)30749a747e4fSDavid du Colombier makebackground(Rune* imageurl, int color)
30759a747e4fSDavid du Colombier {
30769a747e4fSDavid du Colombier Background bg;
30779a747e4fSDavid du Colombier
30789a747e4fSDavid du Colombier bg.image = imageurl;
30799a747e4fSDavid du Colombier bg.color = color;
30809a747e4fSDavid du Colombier return bg;
30819a747e4fSDavid du Colombier }
30829a747e4fSDavid du Colombier
30839a747e4fSDavid du Colombier static Item*
newitext(Rune * s,int fnt,int fg,int voff,int ul)30849a747e4fSDavid du Colombier newitext(Rune* s, int fnt, int fg, int voff, int ul)
30859a747e4fSDavid du Colombier {
30869a747e4fSDavid du Colombier Itext* t;
30879a747e4fSDavid du Colombier
30889a747e4fSDavid du Colombier assert(s != nil);
30899a747e4fSDavid du Colombier t = (Itext*)emalloc(sizeof(Itext));
30909a747e4fSDavid du Colombier t->tag = Itexttag;
30919a747e4fSDavid du Colombier t->s = s;
30929a747e4fSDavid du Colombier t->fnt = fnt;
30939a747e4fSDavid du Colombier t->fg = fg;
30949a747e4fSDavid du Colombier t->voff = voff;
30959a747e4fSDavid du Colombier t->ul = ul;
30969a747e4fSDavid du Colombier return (Item*)t;
30979a747e4fSDavid du Colombier }
30989a747e4fSDavid du Colombier
30999a747e4fSDavid du Colombier static Item*
newirule(int align,int size,int noshade,int color,Dimen wspec)3100*684b447eSDavid du Colombier newirule(int align, int size, int noshade, int color, Dimen wspec)
31019a747e4fSDavid du Colombier {
31029a747e4fSDavid du Colombier Irule* r;
31039a747e4fSDavid du Colombier
31049a747e4fSDavid du Colombier r = (Irule*)emalloc(sizeof(Irule));
31059a747e4fSDavid du Colombier r->tag = Iruletag;
31069a747e4fSDavid du Colombier r->align = align;
31079a747e4fSDavid du Colombier r->size = size;
31089a747e4fSDavid du Colombier r->noshade = noshade;
3109*684b447eSDavid du Colombier r->color = color;
31109a747e4fSDavid du Colombier r->wspec = wspec;
31119a747e4fSDavid du Colombier return (Item*)r;
31129a747e4fSDavid du Colombier }
31139a747e4fSDavid du Colombier
31149a747e4fSDavid du Colombier // Map is owned elsewhere.
31159a747e4fSDavid du Colombier static Item*
newiimage(Rune * src,Rune * altrep,int align,int width,int height,int hspace,int vspace,int border,int ismap,Map * map)31169a747e4fSDavid du Colombier newiimage(Rune* src, Rune* altrep, int align, int width, int height,
31179a747e4fSDavid du Colombier int hspace, int vspace, int border, int ismap, Map* map)
31189a747e4fSDavid du Colombier {
31199a747e4fSDavid du Colombier Iimage* i;
31209a747e4fSDavid du Colombier int state;
31219a747e4fSDavid du Colombier
31229a747e4fSDavid du Colombier state = 0;
31239a747e4fSDavid du Colombier if(ismap)
31249a747e4fSDavid du Colombier state = IFsmap;
31259a747e4fSDavid du Colombier i = (Iimage*)emalloc(sizeof(Iimage));
31269a747e4fSDavid du Colombier i->tag = Iimagetag;
31279a747e4fSDavid du Colombier i->state = state;
31289a747e4fSDavid du Colombier i->imsrc = src;
31299a747e4fSDavid du Colombier i->altrep = altrep;
31309a747e4fSDavid du Colombier i->align = align;
31319a747e4fSDavid du Colombier i->imwidth = width;
31329a747e4fSDavid du Colombier i->imheight = height;
31339a747e4fSDavid du Colombier i->hspace = hspace;
31349a747e4fSDavid du Colombier i->vspace = vspace;
31359a747e4fSDavid du Colombier i->border = border;
31369a747e4fSDavid du Colombier i->map = map;
31379a747e4fSDavid du Colombier i->ctlid = -1;
31389a747e4fSDavid du Colombier return (Item*)i;
31399a747e4fSDavid du Colombier }
31409a747e4fSDavid du Colombier
31419a747e4fSDavid du Colombier static Item*
newiformfield(Formfield * ff)31429a747e4fSDavid du Colombier newiformfield(Formfield* ff)
31439a747e4fSDavid du Colombier {
31449a747e4fSDavid du Colombier Iformfield* f;
31459a747e4fSDavid du Colombier
31469a747e4fSDavid du Colombier f = (Iformfield*)emalloc(sizeof(Iformfield));
31479a747e4fSDavid du Colombier f->tag = Iformfieldtag;
31489a747e4fSDavid du Colombier f->formfield = ff;
31499a747e4fSDavid du Colombier return (Item*)f;
31509a747e4fSDavid du Colombier }
31519a747e4fSDavid du Colombier
31529a747e4fSDavid du Colombier static Item*
newitable(Table * tab)31539a747e4fSDavid du Colombier newitable(Table* tab)
31549a747e4fSDavid du Colombier {
31559a747e4fSDavid du Colombier Itable* t;
31569a747e4fSDavid du Colombier
31579a747e4fSDavid du Colombier t = (Itable*)emalloc(sizeof(Itable));
31589a747e4fSDavid du Colombier t->tag = Itabletag;
31599a747e4fSDavid du Colombier t->table = tab;
31609a747e4fSDavid du Colombier return (Item*)t;
31619a747e4fSDavid du Colombier }
31629a747e4fSDavid du Colombier
31639a747e4fSDavid du Colombier static Item*
newifloat(Item * it,int side)31649a747e4fSDavid du Colombier newifloat(Item* it, int side)
31659a747e4fSDavid du Colombier {
31669a747e4fSDavid du Colombier Ifloat* f;
31679a747e4fSDavid du Colombier
31689a747e4fSDavid du Colombier f = (Ifloat*)emalloc(sizeof(Ifloat));
31699a747e4fSDavid du Colombier f->tag = Ifloattag;
31709a747e4fSDavid du Colombier f->state = IFwrap;
31719a747e4fSDavid du Colombier f->item = it;
31729a747e4fSDavid du Colombier f->side = side;
31739a747e4fSDavid du Colombier return (Item*)f;
31749a747e4fSDavid du Colombier }
31759a747e4fSDavid du Colombier
31769a747e4fSDavid du Colombier static Item*
newispacer(int spkind)31779a747e4fSDavid du Colombier newispacer(int spkind)
31789a747e4fSDavid du Colombier {
31799a747e4fSDavid du Colombier Ispacer* s;
31809a747e4fSDavid du Colombier
31819a747e4fSDavid du Colombier s = (Ispacer*)emalloc(sizeof(Ispacer));
31829a747e4fSDavid du Colombier s->tag = Ispacertag;
31839a747e4fSDavid du Colombier s->spkind = spkind;
31849a747e4fSDavid du Colombier return (Item*)s;
31859a747e4fSDavid du Colombier }
31869a747e4fSDavid du Colombier
31879a747e4fSDavid du Colombier // Free one item (caller must deal with next pointer)
31889a747e4fSDavid du Colombier static void
freeitem(Item * it)31899a747e4fSDavid du Colombier freeitem(Item* it)
31909a747e4fSDavid du Colombier {
31919a747e4fSDavid du Colombier Iimage* ii;
31929a747e4fSDavid du Colombier Genattr* ga;
31939a747e4fSDavid du Colombier
31949a747e4fSDavid du Colombier if(it == nil)
31959a747e4fSDavid du Colombier return;
31969a747e4fSDavid du Colombier
31979a747e4fSDavid du Colombier switch(it->tag) {
31989a747e4fSDavid du Colombier case Itexttag:
31999a747e4fSDavid du Colombier free(((Itext*)it)->s);
32009a747e4fSDavid du Colombier break;
32019a747e4fSDavid du Colombier case Iimagetag:
32029a747e4fSDavid du Colombier ii = (Iimage*)it;
32039a747e4fSDavid du Colombier free(ii->imsrc);
32049a747e4fSDavid du Colombier free(ii->altrep);
32059a747e4fSDavid du Colombier break;
32069a747e4fSDavid du Colombier case Iformfieldtag:
32079a747e4fSDavid du Colombier freeformfield(((Iformfield*)it)->formfield);
32089a747e4fSDavid du Colombier break;
32099a747e4fSDavid du Colombier case Itabletag:
32109a747e4fSDavid du Colombier freetable(((Itable*)it)->table);
32119a747e4fSDavid du Colombier break;
32129a747e4fSDavid du Colombier case Ifloattag:
32139a747e4fSDavid du Colombier freeitem(((Ifloat*)it)->item);
32149a747e4fSDavid du Colombier break;
32159a747e4fSDavid du Colombier }
32169a747e4fSDavid du Colombier ga = it->genattr;
32179a747e4fSDavid du Colombier if(ga != nil) {
32189a747e4fSDavid du Colombier free(ga->id);
32199a747e4fSDavid du Colombier free(ga->class);
32209a747e4fSDavid du Colombier free(ga->style);
32219a747e4fSDavid du Colombier free(ga->title);
32229a747e4fSDavid du Colombier freescriptevents(ga->events);
32239a747e4fSDavid du Colombier }
32249a747e4fSDavid du Colombier free(it);
32259a747e4fSDavid du Colombier }
32269a747e4fSDavid du Colombier
32279a747e4fSDavid du Colombier // Free list of items chained through next pointer
32289a747e4fSDavid du Colombier void
freeitems(Item * ithead)32299a747e4fSDavid du Colombier freeitems(Item* ithead)
32309a747e4fSDavid du Colombier {
32319a747e4fSDavid du Colombier Item* it;
32329a747e4fSDavid du Colombier Item* itnext;
32339a747e4fSDavid du Colombier
32349a747e4fSDavid du Colombier it = ithead;
32359a747e4fSDavid du Colombier while(it != nil) {
32369a747e4fSDavid du Colombier itnext = it->next;
32379a747e4fSDavid du Colombier freeitem(it);
32389a747e4fSDavid du Colombier it = itnext;
32399a747e4fSDavid du Colombier }
32409a747e4fSDavid du Colombier }
32419a747e4fSDavid du Colombier
32429a747e4fSDavid du Colombier static void
freeformfield(Formfield * ff)32439a747e4fSDavid du Colombier freeformfield(Formfield* ff)
32449a747e4fSDavid du Colombier {
32459a747e4fSDavid du Colombier Option* o;
32469a747e4fSDavid du Colombier Option* onext;
32479a747e4fSDavid du Colombier
32489a747e4fSDavid du Colombier if(ff == nil)
32499a747e4fSDavid du Colombier return;
32509a747e4fSDavid du Colombier
32519a747e4fSDavid du Colombier free(ff->name);
32529a747e4fSDavid du Colombier free(ff->value);
32539a747e4fSDavid du Colombier for(o = ff->options; o != nil; o = onext) {
32549a747e4fSDavid du Colombier onext = o->next;
32559a747e4fSDavid du Colombier free(o->value);
32569a747e4fSDavid du Colombier free(o->display);
32579a747e4fSDavid du Colombier }
32589a747e4fSDavid du Colombier free(ff);
32599a747e4fSDavid du Colombier }
32609a747e4fSDavid du Colombier
32619a747e4fSDavid du Colombier static void
freetable(Table * t)32629a747e4fSDavid du Colombier freetable(Table* t)
32639a747e4fSDavid du Colombier {
32649a747e4fSDavid du Colombier int i;
32659a747e4fSDavid du Colombier Tablecell* c;
32669a747e4fSDavid du Colombier Tablecell* cnext;
32679a747e4fSDavid du Colombier
32689a747e4fSDavid du Colombier if(t == nil)
32699a747e4fSDavid du Colombier return;
32709a747e4fSDavid du Colombier
32719a747e4fSDavid du Colombier // We'll find all the unique cells via t->cells and next pointers.
32729a747e4fSDavid du Colombier // (Other pointers to cells in the table are duplicates of these)
32739a747e4fSDavid du Colombier for(c = t->cells; c != nil; c = cnext) {
32749a747e4fSDavid du Colombier cnext = c->next;
32759a747e4fSDavid du Colombier freeitems(c->content);
32769a747e4fSDavid du Colombier }
32779a747e4fSDavid du Colombier if(t->grid != nil) {
32789a747e4fSDavid du Colombier for(i = 0; i < t->nrow; i++)
32799a747e4fSDavid du Colombier free(t->grid[i]);
32809a747e4fSDavid du Colombier free(t->grid);
32819a747e4fSDavid du Colombier }
32829a747e4fSDavid du Colombier free(t->rows);
32839a747e4fSDavid du Colombier free(t->cols);
32849a747e4fSDavid du Colombier freeitems(t->caption);
32859a747e4fSDavid du Colombier free(t);
32869a747e4fSDavid du Colombier }
32879a747e4fSDavid du Colombier
32889a747e4fSDavid du Colombier static void
freeform(Form * f)32899a747e4fSDavid du Colombier freeform(Form* f)
32909a747e4fSDavid du Colombier {
32919a747e4fSDavid du Colombier if(f == nil)
32929a747e4fSDavid du Colombier return;
32939a747e4fSDavid du Colombier
32949a747e4fSDavid du Colombier free(f->name);
32959a747e4fSDavid du Colombier free(f->action);
32969a747e4fSDavid du Colombier // Form doesn't own its fields (Iformfield items do)
32979a747e4fSDavid du Colombier free(f);
32989a747e4fSDavid du Colombier }
32999a747e4fSDavid du Colombier
33009a747e4fSDavid du Colombier static void
freeforms(Form * fhead)33019a747e4fSDavid du Colombier freeforms(Form* fhead)
33029a747e4fSDavid du Colombier {
33039a747e4fSDavid du Colombier Form* f;
33049a747e4fSDavid du Colombier Form* fnext;
33059a747e4fSDavid du Colombier
33069a747e4fSDavid du Colombier for(f = fhead; f != nil; f = fnext) {
33079a747e4fSDavid du Colombier fnext = f->next;
33089a747e4fSDavid du Colombier freeform(f);
33099a747e4fSDavid du Colombier }
33109a747e4fSDavid du Colombier }
33119a747e4fSDavid du Colombier
33129a747e4fSDavid du Colombier static void
freeanchor(Anchor * a)33139a747e4fSDavid du Colombier freeanchor(Anchor* a)
33149a747e4fSDavid du Colombier {
33159a747e4fSDavid du Colombier if(a == nil)
33169a747e4fSDavid du Colombier return;
33179a747e4fSDavid du Colombier
33189a747e4fSDavid du Colombier free(a->name);
33199a747e4fSDavid du Colombier free(a->href);
33209a747e4fSDavid du Colombier free(a);
33219a747e4fSDavid du Colombier }
33229a747e4fSDavid du Colombier
33239a747e4fSDavid du Colombier static void
freeanchors(Anchor * ahead)33249a747e4fSDavid du Colombier freeanchors(Anchor* ahead)
33259a747e4fSDavid du Colombier {
33269a747e4fSDavid du Colombier Anchor* a;
33279a747e4fSDavid du Colombier Anchor* anext;
33289a747e4fSDavid du Colombier
33299a747e4fSDavid du Colombier for(a = ahead; a != nil; a = anext) {
33309a747e4fSDavid du Colombier anext = a->next;
33319a747e4fSDavid du Colombier freeanchor(a);
33329a747e4fSDavid du Colombier }
33339a747e4fSDavid du Colombier }
33349a747e4fSDavid du Colombier
33359a747e4fSDavid du Colombier static void
freedestanchor(DestAnchor * da)33369a747e4fSDavid du Colombier freedestanchor(DestAnchor* da)
33379a747e4fSDavid du Colombier {
33389a747e4fSDavid du Colombier if(da == nil)
33399a747e4fSDavid du Colombier return;
33409a747e4fSDavid du Colombier
33419a747e4fSDavid du Colombier free(da->name);
33429a747e4fSDavid du Colombier free(da);
33439a747e4fSDavid du Colombier }
33449a747e4fSDavid du Colombier
33459a747e4fSDavid du Colombier static void
freedestanchors(DestAnchor * dahead)33469a747e4fSDavid du Colombier freedestanchors(DestAnchor* dahead)
33479a747e4fSDavid du Colombier {
33489a747e4fSDavid du Colombier DestAnchor* da;
33499a747e4fSDavid du Colombier DestAnchor* danext;
33509a747e4fSDavid du Colombier
33519a747e4fSDavid du Colombier for(da = dahead; da != nil; da = danext) {
33529a747e4fSDavid du Colombier danext = da->next;
33539a747e4fSDavid du Colombier freedestanchor(da);
33549a747e4fSDavid du Colombier }
33559a747e4fSDavid du Colombier }
33569a747e4fSDavid du Colombier
33579a747e4fSDavid du Colombier static void
freearea(Area * a)33589a747e4fSDavid du Colombier freearea(Area* a)
33599a747e4fSDavid du Colombier {
33609a747e4fSDavid du Colombier if(a == nil)
33619a747e4fSDavid du Colombier return;
33629a747e4fSDavid du Colombier free(a->href);
33639a747e4fSDavid du Colombier free(a->coords);
33649a747e4fSDavid du Colombier }
33659a747e4fSDavid du Colombier
33669a747e4fSDavid du Colombier static void freekidinfos(Kidinfo* khead);
33679a747e4fSDavid du Colombier
33689a747e4fSDavid du Colombier static void
freekidinfo(Kidinfo * k)33699a747e4fSDavid du Colombier freekidinfo(Kidinfo* k)
33709a747e4fSDavid du Colombier {
33719a747e4fSDavid du Colombier if(k->isframeset) {
33729a747e4fSDavid du Colombier free(k->rows);
33739a747e4fSDavid du Colombier free(k->cols);
33749a747e4fSDavid du Colombier freekidinfos(k->kidinfos);
33759a747e4fSDavid du Colombier }
33769a747e4fSDavid du Colombier else {
33779a747e4fSDavid du Colombier free(k->src);
33789a747e4fSDavid du Colombier free(k->name);
33799a747e4fSDavid du Colombier }
33809a747e4fSDavid du Colombier free(k);
33819a747e4fSDavid du Colombier }
33829a747e4fSDavid du Colombier
33839a747e4fSDavid du Colombier static void
freekidinfos(Kidinfo * khead)33849a747e4fSDavid du Colombier freekidinfos(Kidinfo* khead)
33859a747e4fSDavid du Colombier {
33869a747e4fSDavid du Colombier Kidinfo* k;
33879a747e4fSDavid du Colombier Kidinfo* knext;
33889a747e4fSDavid du Colombier
33899a747e4fSDavid du Colombier for(k = khead; k != nil; k = knext) {
33909a747e4fSDavid du Colombier knext = k->next;
33919a747e4fSDavid du Colombier freekidinfo(k);
33929a747e4fSDavid du Colombier }
33939a747e4fSDavid du Colombier }
33949a747e4fSDavid du Colombier
33959a747e4fSDavid du Colombier static void
freemap(Map * m)33969a747e4fSDavid du Colombier freemap(Map* m)
33979a747e4fSDavid du Colombier {
33989a747e4fSDavid du Colombier Area* a;
33999a747e4fSDavid du Colombier Area* anext;
34009a747e4fSDavid du Colombier
34019a747e4fSDavid du Colombier if(m == nil)
34029a747e4fSDavid du Colombier return;
34039a747e4fSDavid du Colombier
34049a747e4fSDavid du Colombier free(m->name);
34059a747e4fSDavid du Colombier for(a = m->areas; a != nil; a = anext) {
34069a747e4fSDavid du Colombier anext = a->next;
34079a747e4fSDavid du Colombier freearea(a);
34089a747e4fSDavid du Colombier }
34099a747e4fSDavid du Colombier free(m);
34109a747e4fSDavid du Colombier }
34119a747e4fSDavid du Colombier
34129a747e4fSDavid du Colombier static void
freemaps(Map * mhead)34139a747e4fSDavid du Colombier freemaps(Map* mhead)
34149a747e4fSDavid du Colombier {
34159a747e4fSDavid du Colombier Map* m;
34169a747e4fSDavid du Colombier Map* mnext;
34179a747e4fSDavid du Colombier
34189a747e4fSDavid du Colombier for(m = mhead; m != nil; m = mnext) {
34199a747e4fSDavid du Colombier mnext = m->next;
34209a747e4fSDavid du Colombier freemap(m);
34219a747e4fSDavid du Colombier }
34229a747e4fSDavid du Colombier }
34239a747e4fSDavid du Colombier
34249a747e4fSDavid du Colombier void
freedocinfo(Docinfo * d)34259a747e4fSDavid du Colombier freedocinfo(Docinfo* d)
34269a747e4fSDavid du Colombier {
34279a747e4fSDavid du Colombier if(d == nil)
34289a747e4fSDavid du Colombier return;
34299a747e4fSDavid du Colombier free(d->src);
34309a747e4fSDavid du Colombier free(d->base);
34319a747e4fSDavid du Colombier freeitem((Item*)d->backgrounditem);
34329a747e4fSDavid du Colombier free(d->refresh);
34339a747e4fSDavid du Colombier freekidinfos(d->kidinfo);
34349a747e4fSDavid du Colombier freeanchors(d->anchors);
34359a747e4fSDavid du Colombier freedestanchors(d->dests);
34369a747e4fSDavid du Colombier freeforms(d->forms);
34379a747e4fSDavid du Colombier freemaps(d->maps);
34389a747e4fSDavid du Colombier // tables, images, and formfields are freed when
34399a747e4fSDavid du Colombier // the items pointing at them are freed
34409a747e4fSDavid du Colombier free(d);
34419a747e4fSDavid du Colombier }
34429a747e4fSDavid du Colombier
34439a747e4fSDavid du Colombier // Currently, someone else owns all the memory
34449a747e4fSDavid du Colombier // pointed to by things in a Pstate.
34459a747e4fSDavid du Colombier static void
freepstate(Pstate * p)34469a747e4fSDavid du Colombier freepstate(Pstate* p)
34479a747e4fSDavid du Colombier {
34489a747e4fSDavid du Colombier free(p);
34499a747e4fSDavid du Colombier }
34509a747e4fSDavid du Colombier
34519a747e4fSDavid du Colombier static void
freepstatestack(Pstate * pshead)34529a747e4fSDavid du Colombier freepstatestack(Pstate* pshead)
34539a747e4fSDavid du Colombier {
34549a747e4fSDavid du Colombier Pstate* p;
34559a747e4fSDavid du Colombier Pstate* pnext;
34569a747e4fSDavid du Colombier
34579a747e4fSDavid du Colombier for(p = pshead; p != nil; p = pnext) {
34589a747e4fSDavid du Colombier pnext = p->next;
34599a747e4fSDavid du Colombier free(p);
34609a747e4fSDavid du Colombier }
34619a747e4fSDavid du Colombier }
34629a747e4fSDavid du Colombier
34639a747e4fSDavid du Colombier static int
Iconv(Fmt * f)34649a747e4fSDavid du Colombier Iconv(Fmt *f)
34659a747e4fSDavid du Colombier {
34669a747e4fSDavid du Colombier Item* it;
34679a747e4fSDavid du Colombier Itext* t;
34689a747e4fSDavid du Colombier Irule* r;
34699a747e4fSDavid du Colombier Iimage* i;
34709a747e4fSDavid du Colombier Ifloat* fl;
34719a747e4fSDavid du Colombier int state;
34729a747e4fSDavid du Colombier Formfield* ff;
34739a747e4fSDavid du Colombier Rune* ty;
34749a747e4fSDavid du Colombier Tablecell* c;
34759a747e4fSDavid du Colombier Table* tab;
34769a747e4fSDavid du Colombier char* p;
34779a747e4fSDavid du Colombier int cl;
34789a747e4fSDavid du Colombier int hang;
34799a747e4fSDavid du Colombier int indent;
34809a747e4fSDavid du Colombier int bi;
34819a747e4fSDavid du Colombier int nbuf;
34829a747e4fSDavid du Colombier char buf[BIGBUFSIZE];
34839a747e4fSDavid du Colombier
34849a747e4fSDavid du Colombier it = va_arg(f->args, Item*);
34859a747e4fSDavid du Colombier bi = 0;
34869a747e4fSDavid du Colombier nbuf = sizeof(buf);
34879a747e4fSDavid du Colombier state = it->state;
34889a747e4fSDavid du Colombier nbuf = nbuf-1;
34899a747e4fSDavid du Colombier if(state&IFbrk) {
34909a747e4fSDavid du Colombier cl = state&(IFcleft|IFcright);
34919a747e4fSDavid du Colombier p = "";
34929a747e4fSDavid du Colombier if(cl) {
34939a747e4fSDavid du Colombier if(cl == (IFcleft|IFcright))
34949a747e4fSDavid du Colombier p = " both";
34959a747e4fSDavid du Colombier else if(cl == IFcleft)
34969a747e4fSDavid du Colombier p = " left";
34979a747e4fSDavid du Colombier else
34989a747e4fSDavid du Colombier p = " right";
34999a747e4fSDavid du Colombier }
35009a747e4fSDavid du Colombier bi = snprint(buf, nbuf, "brk(%d%s)", (state&IFbrksp)? 1 : 0, p);
35019a747e4fSDavid du Colombier }
35029a747e4fSDavid du Colombier if(state&IFnobrk)
35039a747e4fSDavid du Colombier bi += snprint(buf+bi, nbuf-bi, " nobrk");
35049a747e4fSDavid du Colombier if(!(state&IFwrap))
35059a747e4fSDavid du Colombier bi += snprint(buf+bi, nbuf-bi, " nowrap");
35069a747e4fSDavid du Colombier if(state&IFrjust)
35079a747e4fSDavid du Colombier bi += snprint(buf+bi, nbuf-bi, " rjust");
35089a747e4fSDavid du Colombier if(state&IFcjust)
35099a747e4fSDavid du Colombier bi += snprint(buf+bi, nbuf-bi, " cjust");
35109a747e4fSDavid du Colombier if(state&IFsmap)
35119a747e4fSDavid du Colombier bi += snprint(buf+bi, nbuf-bi, " smap");
35129a747e4fSDavid du Colombier indent = (state&IFindentmask) >> IFindentshift;
35139a747e4fSDavid du Colombier if(indent > 0)
35149a747e4fSDavid du Colombier bi += snprint(buf+bi, nbuf-bi, " indent=%d", indent);
35159a747e4fSDavid du Colombier hang = state&IFhangmask;
35169a747e4fSDavid du Colombier if(hang > 0)
35179a747e4fSDavid du Colombier bi += snprint(buf+bi, nbuf-bi, " hang=%d", hang);
35189a747e4fSDavid du Colombier
35199a747e4fSDavid du Colombier switch(it->tag) {
35209a747e4fSDavid du Colombier case Itexttag:
35219a747e4fSDavid du Colombier t = (Itext*)it;
35229a747e4fSDavid du Colombier bi += snprint(buf+bi, nbuf-bi, " Text '%S', fnt=%d, fg=%x", t->s, t->fnt, t->fg);
35239a747e4fSDavid du Colombier break;
35249a747e4fSDavid du Colombier
35259a747e4fSDavid du Colombier case Iruletag:
35269a747e4fSDavid du Colombier r = (Irule*)it;
35279a747e4fSDavid du Colombier bi += snprint(buf+bi, nbuf-bi, "Rule size=%d, al=%S, wspec=", r->size, stringalign(r->align));
35289a747e4fSDavid du Colombier bi += dimprint(buf+bi, nbuf-bi, r->wspec);
35299a747e4fSDavid du Colombier break;
35309a747e4fSDavid du Colombier
35319a747e4fSDavid du Colombier case Iimagetag:
35329a747e4fSDavid du Colombier i = (Iimage*)it;
35339a747e4fSDavid du Colombier bi += snprint(buf+bi, nbuf-bi,
35349a747e4fSDavid du Colombier "Image src=%S, alt=%S, al=%S, w=%d, h=%d hsp=%d, vsp=%d, bd=%d, map=%S",
35359a747e4fSDavid du Colombier i->imsrc, i->altrep? i->altrep : L"", stringalign(i->align), i->imwidth, i->imheight,
35369a747e4fSDavid du Colombier i->hspace, i->vspace, i->border, i->map? i->map->name : L"");
35379a747e4fSDavid du Colombier break;
35389a747e4fSDavid du Colombier
35399a747e4fSDavid du Colombier case Iformfieldtag:
35409a747e4fSDavid du Colombier ff = ((Iformfield*)it)->formfield;
35419a747e4fSDavid du Colombier if(ff->ftype == Ftextarea)
35429a747e4fSDavid du Colombier ty = L"textarea";
35439a747e4fSDavid du Colombier else if(ff->ftype == Fselect)
35449a747e4fSDavid du Colombier ty = L"select";
35459a747e4fSDavid du Colombier else {
35469a747e4fSDavid du Colombier ty = _revlookup(input_tab, NINPUTTAB, ff->ftype);
35479a747e4fSDavid du Colombier if(ty == nil)
35489a747e4fSDavid du Colombier ty = L"none";
35499a747e4fSDavid du Colombier }
35509a747e4fSDavid du Colombier bi += snprint(buf+bi, nbuf-bi, "Formfield %S, fieldid=%d, formid=%d, name=%S, value=%S",
35519a747e4fSDavid du Colombier ty, ff->fieldid, ff->form->formid, ff->name? ff->name : L"",
35529a747e4fSDavid du Colombier ff->value? ff->value : L"");
35539a747e4fSDavid du Colombier break;
35549a747e4fSDavid du Colombier
35559a747e4fSDavid du Colombier case Itabletag:
35569a747e4fSDavid du Colombier tab = ((Itable*)it)->table;
35579a747e4fSDavid du Colombier bi += snprint(buf+bi, nbuf-bi, "Table tableid=%d, width=", tab->tableid);
35589a747e4fSDavid du Colombier bi += dimprint(buf+bi, nbuf-bi, tab->width);
35599a747e4fSDavid du Colombier bi += snprint(buf+bi, nbuf-bi, ", nrow=%d, ncol=%d, ncell=%d, totw=%d, toth=%d\n",
35609a747e4fSDavid du Colombier tab->nrow, tab->ncol, tab->ncell, tab->totw, tab->toth);
35619a747e4fSDavid du Colombier for(c = tab->cells; c != nil; c = c->next)
35629a747e4fSDavid du Colombier bi += snprint(buf+bi, nbuf-bi, "Cell %d.%d, at (%d,%d) ",
35639a747e4fSDavid du Colombier tab->tableid, c->cellid, c->row, c->col);
35649a747e4fSDavid du Colombier bi += snprint(buf+bi, nbuf-bi, "End of Table %d", tab->tableid);
35659a747e4fSDavid du Colombier break;
35669a747e4fSDavid du Colombier
35679a747e4fSDavid du Colombier case Ifloattag:
35689a747e4fSDavid du Colombier fl = (Ifloat*)it;
35699a747e4fSDavid du Colombier bi += snprint(buf+bi, nbuf-bi, "Float, x=%d y=%d, side=%S, it=%I",
35709a747e4fSDavid du Colombier fl->x, fl->y, stringalign(fl->side), fl->item);
35719a747e4fSDavid du Colombier bi += snprint(buf+bi, nbuf-bi, "\n\t");
35729a747e4fSDavid du Colombier break;
35739a747e4fSDavid du Colombier
35749a747e4fSDavid du Colombier case Ispacertag:
35759a747e4fSDavid du Colombier p = "";
35769a747e4fSDavid du Colombier switch(((Ispacer*)it)->spkind) {
35779a747e4fSDavid du Colombier case ISPnull:
35789a747e4fSDavid du Colombier p = "null";
35799a747e4fSDavid du Colombier break;
35809a747e4fSDavid du Colombier case ISPvline:
35819a747e4fSDavid du Colombier p = "vline";
35829a747e4fSDavid du Colombier break;
35839a747e4fSDavid du Colombier case ISPhspace:
35849a747e4fSDavid du Colombier p = "hspace";
35859a747e4fSDavid du Colombier break;
35869a747e4fSDavid du Colombier }
35879a747e4fSDavid du Colombier bi += snprint(buf+bi, nbuf-bi, "Spacer %s ", p);
35889a747e4fSDavid du Colombier break;
35899a747e4fSDavid du Colombier }
35909a747e4fSDavid du Colombier bi += snprint(buf+bi, nbuf-bi, " w=%d, h=%d, a=%d, anchor=%d\n",
35919a747e4fSDavid du Colombier it->width, it->height, it->ascent, it->anchorid);
35929a747e4fSDavid du Colombier buf[bi] = 0;
35939a747e4fSDavid du Colombier return fmtstrcpy(f, buf);
35949a747e4fSDavid du Colombier }
35959a747e4fSDavid du Colombier
35969a747e4fSDavid du Colombier // String version of alignment 'a'
35979a747e4fSDavid du Colombier static Rune*
stringalign(int a)35989a747e4fSDavid du Colombier stringalign(int a)
35999a747e4fSDavid du Colombier {
36009a747e4fSDavid du Colombier Rune* s;
36019a747e4fSDavid du Colombier
36029a747e4fSDavid du Colombier s = _revlookup(align_tab, NALIGNTAB, a);
36035d459b5aSDavid du Colombier if(s == nil)
36049a747e4fSDavid du Colombier s = L"none";
36059a747e4fSDavid du Colombier return s;
36069a747e4fSDavid du Colombier }
36079a747e4fSDavid du Colombier
36089a747e4fSDavid du Colombier // Put at most nbuf chars of representation of d into buf,
36099a747e4fSDavid du Colombier // and return number of characters put
36109a747e4fSDavid du Colombier static int
dimprint(char * buf,int nbuf,Dimen d)36119a747e4fSDavid du Colombier dimprint(char* buf, int nbuf, Dimen d)
36129a747e4fSDavid du Colombier {
36139a747e4fSDavid du Colombier int n;
36149a747e4fSDavid du Colombier int k;
36159a747e4fSDavid du Colombier
36169a747e4fSDavid du Colombier n = 0;
36179a747e4fSDavid du Colombier n += snprint(buf, nbuf, "%d", dimenspec(d));
36189a747e4fSDavid du Colombier k = dimenkind(d);
36199a747e4fSDavid du Colombier if(k == Dpercent)
36209a747e4fSDavid du Colombier buf[n++] = '%';
36219a747e4fSDavid du Colombier if(k == Drelative)
36229a747e4fSDavid du Colombier buf[n++] = '*';
36239a747e4fSDavid du Colombier return n;
36249a747e4fSDavid du Colombier }
36259a747e4fSDavid du Colombier
36269a747e4fSDavid du Colombier void
printitems(Item * items,char * msg)36279a747e4fSDavid du Colombier printitems(Item* items, char* msg)
36289a747e4fSDavid du Colombier {
36299a747e4fSDavid du Colombier Item* il;
36309a747e4fSDavid du Colombier
36319a747e4fSDavid du Colombier fprint(2, "%s\n", msg);
36329a747e4fSDavid du Colombier il = items;
36339a747e4fSDavid du Colombier while(il != nil) {
36349a747e4fSDavid du Colombier fprint(2, "%I", il);
36359a747e4fSDavid du Colombier il = il->next;
36369a747e4fSDavid du Colombier }
36379a747e4fSDavid du Colombier }
36389a747e4fSDavid du Colombier
36399a747e4fSDavid du Colombier static Genattr*
newgenattr(Rune * id,Rune * class,Rune * style,Rune * title,SEvent * events)36405d459b5aSDavid du Colombier newgenattr(Rune* id, Rune* class, Rune* style, Rune* title, SEvent* events)
36419a747e4fSDavid du Colombier {
36429a747e4fSDavid du Colombier Genattr* g;
36439a747e4fSDavid du Colombier
36449a747e4fSDavid du Colombier g = (Genattr*)emalloc(sizeof(Genattr));
36459a747e4fSDavid du Colombier g->id = id;
36469a747e4fSDavid du Colombier g->class = class;
36479a747e4fSDavid du Colombier g->style = style;
36489a747e4fSDavid du Colombier g->title = title;
36499a747e4fSDavid du Colombier g->events = events;
36509a747e4fSDavid du Colombier return g;
36519a747e4fSDavid du Colombier }
36529a747e4fSDavid du Colombier
36539a747e4fSDavid du Colombier static Formfield*
newformfield(int ftype,int fieldid,Form * form,Rune * name,Rune * value,int size,int maxlength,Formfield * link)36549a747e4fSDavid du Colombier newformfield(int ftype, int fieldid, Form* form, Rune* name,
36559a747e4fSDavid du Colombier Rune* value, int size, int maxlength, Formfield* link)
36569a747e4fSDavid du Colombier {
36579a747e4fSDavid du Colombier Formfield* ff;
36589a747e4fSDavid du Colombier
36599a747e4fSDavid du Colombier ff = (Formfield*)emalloc(sizeof(Formfield));
36609a747e4fSDavid du Colombier ff->ftype = ftype;
36619a747e4fSDavid du Colombier ff->fieldid = fieldid;
36629a747e4fSDavid du Colombier ff->form = form;
36639a747e4fSDavid du Colombier ff->name = name;
36649a747e4fSDavid du Colombier ff->value = value;
36659a747e4fSDavid du Colombier ff->size = size;
36669a747e4fSDavid du Colombier ff->maxlength = maxlength;
36679a747e4fSDavid du Colombier ff->ctlid = -1;
36689a747e4fSDavid du Colombier ff->next = link;
36699a747e4fSDavid du Colombier return ff;
36709a747e4fSDavid du Colombier }
36719a747e4fSDavid du Colombier
36729a747e4fSDavid du Colombier // Transfers ownership of value and display to Option.
36739a747e4fSDavid du Colombier static Option*
newoption(int selected,Rune * value,Rune * display,Option * link)36749a747e4fSDavid du Colombier newoption(int selected, Rune* value, Rune* display, Option* link)
36759a747e4fSDavid du Colombier {
36769a747e4fSDavid du Colombier Option *o;
36779a747e4fSDavid du Colombier
36789a747e4fSDavid du Colombier o = (Option*)emalloc(sizeof(Option));
36799a747e4fSDavid du Colombier o->selected = selected;
36809a747e4fSDavid du Colombier o->value = value;
36819a747e4fSDavid du Colombier o->display = display;
36829a747e4fSDavid du Colombier o->next = link;
36839a747e4fSDavid du Colombier return o;
36849a747e4fSDavid du Colombier }
36859a747e4fSDavid du Colombier
36869a747e4fSDavid du Colombier static Form*
newform(int formid,Rune * name,Rune * action,int target,int method,Form * link)36879a747e4fSDavid du Colombier newform(int formid, Rune* name, Rune* action, int target, int method, Form* link)
36889a747e4fSDavid du Colombier {
36899a747e4fSDavid du Colombier Form* f;
36909a747e4fSDavid du Colombier
36919a747e4fSDavid du Colombier f = (Form*)emalloc(sizeof(Form));
36929a747e4fSDavid du Colombier f->formid = formid;
36939a747e4fSDavid du Colombier f->name = name;
36949a747e4fSDavid du Colombier f->action = action;
36959a747e4fSDavid du Colombier f->target = target;
36969a747e4fSDavid du Colombier f->method = method;
36979a747e4fSDavid du Colombier f->nfields = 0;
36989a747e4fSDavid du Colombier f->fields = nil;
36999a747e4fSDavid du Colombier f->next = link;
37009a747e4fSDavid du Colombier return f;
37019a747e4fSDavid du Colombier }
37029a747e4fSDavid du Colombier
37039a747e4fSDavid du Colombier static Table*
newtable(int tableid,Align align,Dimen width,int border,int cellspacing,int cellpadding,Background bg,Token * tok,Table * link)37049a747e4fSDavid du Colombier newtable(int tableid, Align align, Dimen width, int border,
37059a747e4fSDavid du Colombier int cellspacing, int cellpadding, Background bg, Token* tok, Table* link)
37069a747e4fSDavid du Colombier {
37079a747e4fSDavid du Colombier Table* t;
37089a747e4fSDavid du Colombier
37099a747e4fSDavid du Colombier t = (Table*)emalloc(sizeof(Table));
37109a747e4fSDavid du Colombier t->tableid = tableid;
37119a747e4fSDavid du Colombier t->align = align;
37129a747e4fSDavid du Colombier t->width = width;
37139a747e4fSDavid du Colombier t->border = border;
37149a747e4fSDavid du Colombier t->cellspacing = cellspacing;
37159a747e4fSDavid du Colombier t->cellpadding = cellpadding;
37169a747e4fSDavid du Colombier t->background = bg;
37179a747e4fSDavid du Colombier t->caption_place = ALbottom;
37189a747e4fSDavid du Colombier t->caption_lay = nil;
37199a747e4fSDavid du Colombier t->tabletok = tok;
37209a747e4fSDavid du Colombier t->tabletok = nil;
37219a747e4fSDavid du Colombier t->next = link;
37229a747e4fSDavid du Colombier return t;
37239a747e4fSDavid du Colombier }
37249a747e4fSDavid du Colombier
37259a747e4fSDavid du Colombier static Tablerow*
newtablerow(Align align,Background bg,int flags,Tablerow * link)37269a747e4fSDavid du Colombier newtablerow(Align align, Background bg, int flags, Tablerow* link)
37279a747e4fSDavid du Colombier {
37289a747e4fSDavid du Colombier Tablerow* tr;
37299a747e4fSDavid du Colombier
37309a747e4fSDavid du Colombier tr = (Tablerow*)emalloc(sizeof(Tablerow));
37319a747e4fSDavid du Colombier tr->align = align;
37329a747e4fSDavid du Colombier tr->background = bg;
37339a747e4fSDavid du Colombier tr->flags = flags;
37349a747e4fSDavid du Colombier tr->next = link;
37359a747e4fSDavid du Colombier return tr;
37369a747e4fSDavid du Colombier }
37379a747e4fSDavid du Colombier
37389a747e4fSDavid du Colombier static Tablecell*
newtablecell(int cellid,int rowspan,int colspan,Align align,Dimen wspec,int hspec,Background bg,int flags,Tablecell * link)37399a747e4fSDavid du Colombier newtablecell(int cellid, int rowspan, int colspan, Align align, Dimen wspec, int hspec,
37409a747e4fSDavid du Colombier Background bg, int flags, Tablecell* link)
37419a747e4fSDavid du Colombier {
37429a747e4fSDavid du Colombier Tablecell* c;
37439a747e4fSDavid du Colombier
37449a747e4fSDavid du Colombier c = (Tablecell*)emalloc(sizeof(Tablecell));
37459a747e4fSDavid du Colombier c->cellid = cellid;
37469a747e4fSDavid du Colombier c->lay = nil;
37479a747e4fSDavid du Colombier c->rowspan = rowspan;
37489a747e4fSDavid du Colombier c->colspan = colspan;
37499a747e4fSDavid du Colombier c->align = align;
37509a747e4fSDavid du Colombier c->flags = flags;
37519a747e4fSDavid du Colombier c->wspec = wspec;
37529a747e4fSDavid du Colombier c->hspec = hspec;
37539a747e4fSDavid du Colombier c->background = bg;
37549a747e4fSDavid du Colombier c->next = link;
37559a747e4fSDavid du Colombier return c;
37569a747e4fSDavid du Colombier }
37579a747e4fSDavid du Colombier
37589a747e4fSDavid du Colombier static Anchor*
newanchor(int index,Rune * name,Rune * href,int target,Anchor * link)37599a747e4fSDavid du Colombier newanchor(int index, Rune* name, Rune* href, int target, Anchor* link)
37609a747e4fSDavid du Colombier {
37619a747e4fSDavid du Colombier Anchor* a;
37629a747e4fSDavid du Colombier
37639a747e4fSDavid du Colombier a = (Anchor*)emalloc(sizeof(Anchor));
37649a747e4fSDavid du Colombier a->index = index;
37659a747e4fSDavid du Colombier a->name = name;
37669a747e4fSDavid du Colombier a->href = href;
37679a747e4fSDavid du Colombier a->target = target;
37689a747e4fSDavid du Colombier a->next = link;
37699a747e4fSDavid du Colombier return a;
37709a747e4fSDavid du Colombier }
37719a747e4fSDavid du Colombier
37729a747e4fSDavid du Colombier static DestAnchor*
newdestanchor(int index,Rune * name,Item * item,DestAnchor * link)37739a747e4fSDavid du Colombier newdestanchor(int index, Rune* name, Item* item, DestAnchor* link)
37749a747e4fSDavid du Colombier {
37759a747e4fSDavid du Colombier DestAnchor* d;
37769a747e4fSDavid du Colombier
37779a747e4fSDavid du Colombier d = (DestAnchor*)emalloc(sizeof(DestAnchor));
37789a747e4fSDavid du Colombier d->index = index;
37799a747e4fSDavid du Colombier d->name = name;
37809a747e4fSDavid du Colombier d->item = item;
37819a747e4fSDavid du Colombier d->next = link;
37829a747e4fSDavid du Colombier return d;
37839a747e4fSDavid du Colombier }
37849a747e4fSDavid du Colombier
37859a747e4fSDavid du Colombier static SEvent*
newscriptevent(int type,Rune * script,SEvent * link)37865d459b5aSDavid du Colombier newscriptevent(int type, Rune* script, SEvent* link)
37879a747e4fSDavid du Colombier {
37889a747e4fSDavid du Colombier SEvent* ans;
37899a747e4fSDavid du Colombier
37905d459b5aSDavid du Colombier ans = (SEvent*)emalloc(sizeof(SEvent));
37919a747e4fSDavid du Colombier ans->type = type;
37929a747e4fSDavid du Colombier ans->script = script;
37939a747e4fSDavid du Colombier ans->next = link;
37949a747e4fSDavid du Colombier return ans;
37959a747e4fSDavid du Colombier }
37969a747e4fSDavid du Colombier
37979a747e4fSDavid du Colombier static void
freescriptevents(SEvent * ehead)37989a747e4fSDavid du Colombier freescriptevents(SEvent* ehead)
37999a747e4fSDavid du Colombier {
38009a747e4fSDavid du Colombier SEvent* e;
38019a747e4fSDavid du Colombier SEvent* nexte;
38029a747e4fSDavid du Colombier
38039a747e4fSDavid du Colombier e = ehead;
38049a747e4fSDavid du Colombier while(e != nil) {
38059a747e4fSDavid du Colombier nexte = e->next;
38069a747e4fSDavid du Colombier free(e->script);
38079a747e4fSDavid du Colombier free(e);
38089a747e4fSDavid du Colombier e = nexte;
38099a747e4fSDavid du Colombier }
38109a747e4fSDavid du Colombier }
38119a747e4fSDavid du Colombier
38129a747e4fSDavid du Colombier static Dimen
makedimen(int kind,int spec)38139a747e4fSDavid du Colombier makedimen(int kind, int spec)
38149a747e4fSDavid du Colombier {
38159a747e4fSDavid du Colombier Dimen d;
38169a747e4fSDavid du Colombier
38179a747e4fSDavid du Colombier if(spec&Dkindmask) {
38189a747e4fSDavid du Colombier if(warn)
38199a747e4fSDavid du Colombier fprint(2, "warning: dimension spec too big: %d\n", spec);
38209a747e4fSDavid du Colombier spec = 0;
38219a747e4fSDavid du Colombier }
38229a747e4fSDavid du Colombier d.kindspec = kind|spec;
38239a747e4fSDavid du Colombier return d;
38249a747e4fSDavid du Colombier }
38259a747e4fSDavid du Colombier
38269a747e4fSDavid du Colombier int
dimenkind(Dimen d)38279a747e4fSDavid du Colombier dimenkind(Dimen d)
38289a747e4fSDavid du Colombier {
38299a747e4fSDavid du Colombier return (d.kindspec&Dkindmask);
38309a747e4fSDavid du Colombier }
38319a747e4fSDavid du Colombier
38329a747e4fSDavid du Colombier int
dimenspec(Dimen d)38339a747e4fSDavid du Colombier dimenspec(Dimen d)
38349a747e4fSDavid du Colombier {
38359a747e4fSDavid du Colombier return (d.kindspec&Dspecmask);
38369a747e4fSDavid du Colombier }
38379a747e4fSDavid du Colombier
38389a747e4fSDavid du Colombier static Kidinfo*
newkidinfo(int isframeset,Kidinfo * link)38399a747e4fSDavid du Colombier newkidinfo(int isframeset, Kidinfo* link)
38409a747e4fSDavid du Colombier {
38419a747e4fSDavid du Colombier Kidinfo* ki;
38429a747e4fSDavid du Colombier
38439a747e4fSDavid du Colombier ki = (Kidinfo*)emalloc(sizeof(Kidinfo));
38449a747e4fSDavid du Colombier ki->isframeset = isframeset;
38459a747e4fSDavid du Colombier if(!isframeset) {
38469a747e4fSDavid du Colombier ki->flags = FRhscrollauto|FRvscrollauto;
38479a747e4fSDavid du Colombier ki->marginw = FRKIDMARGIN;
38489a747e4fSDavid du Colombier ki->marginh = FRKIDMARGIN;
38499a747e4fSDavid du Colombier ki->framebd = 1;
38509a747e4fSDavid du Colombier }
38519a747e4fSDavid du Colombier ki->next = link;
38529a747e4fSDavid du Colombier return ki;
38539a747e4fSDavid du Colombier }
38549a747e4fSDavid du Colombier
38559a747e4fSDavid du Colombier static Docinfo*
newdocinfo(void)38569a747e4fSDavid du Colombier newdocinfo(void)
38579a747e4fSDavid du Colombier {
38589a747e4fSDavid du Colombier Docinfo* d;
38599a747e4fSDavid du Colombier
38609a747e4fSDavid du Colombier d = (Docinfo*)emalloc(sizeof(Docinfo));
38619a747e4fSDavid du Colombier resetdocinfo(d);
38629a747e4fSDavid du Colombier return d;
38639a747e4fSDavid du Colombier }
38649a747e4fSDavid du Colombier
38659a747e4fSDavid du Colombier static void
resetdocinfo(Docinfo * d)38669a747e4fSDavid du Colombier resetdocinfo(Docinfo* d)
38679a747e4fSDavid du Colombier {
38689a747e4fSDavid du Colombier memset(d, 0, sizeof(Docinfo));
38699a747e4fSDavid du Colombier d->background = makebackground(nil, White);
38709a747e4fSDavid du Colombier d->text = Black;
38719a747e4fSDavid du Colombier d->link = Blue;
38729a747e4fSDavid du Colombier d->vlink = Blue;
38739a747e4fSDavid du Colombier d->alink = Blue;
38749a747e4fSDavid du Colombier d->target = FTself;
38759a747e4fSDavid du Colombier d->chset = ISO_8859_1;
38769a747e4fSDavid du Colombier d->scripttype = TextJavascript;
38779a747e4fSDavid du Colombier d->frameid = -1;
38789a747e4fSDavid du Colombier }
38799a747e4fSDavid du Colombier
38809a747e4fSDavid du Colombier // Use targetmap array to keep track of name <-> targetid mapping.
38819a747e4fSDavid du Colombier // Use real malloc(), and never free
38829a747e4fSDavid du Colombier static void
targetmapinit(void)38839a747e4fSDavid du Colombier targetmapinit(void)
38849a747e4fSDavid du Colombier {
3885c93608ccSDavid du Colombier int l;
3886c93608ccSDavid du Colombier
38879a747e4fSDavid du Colombier targetmapsize = 10;
3888c93608ccSDavid du Colombier l = targetmapsize*sizeof *targetmap;
3889c93608ccSDavid du Colombier targetmap = emalloc(l);
3890c93608ccSDavid du Colombier memset(targetmap, 0, l);
38919a747e4fSDavid du Colombier targetmap[0].key = _Strdup(L"_top");
38929a747e4fSDavid du Colombier targetmap[0].val = FTtop;
38939a747e4fSDavid du Colombier targetmap[1].key = _Strdup(L"_self");
38949a747e4fSDavid du Colombier targetmap[1].val = FTself;
38959a747e4fSDavid du Colombier targetmap[2].key = _Strdup(L"_parent");
38969a747e4fSDavid du Colombier targetmap[2].val = FTparent;
38979a747e4fSDavid du Colombier targetmap[3].key = _Strdup(L"_blank");
38989a747e4fSDavid du Colombier targetmap[3].val = FTblank;
38999a747e4fSDavid du Colombier ntargets = 4;
39009a747e4fSDavid du Colombier }
39019a747e4fSDavid du Colombier
39029a747e4fSDavid du Colombier int
targetid(Rune * s)39039a747e4fSDavid du Colombier targetid(Rune* s)
39049a747e4fSDavid du Colombier {
39059a747e4fSDavid du Colombier int i;
39069a747e4fSDavid du Colombier int n;
39079a747e4fSDavid du Colombier
39085d459b5aSDavid du Colombier n = _Strlen(s);
39099a747e4fSDavid du Colombier if(n == 0)
39109a747e4fSDavid du Colombier return FTself;
39119a747e4fSDavid du Colombier for(i = 0; i < ntargets; i++)
39125d459b5aSDavid du Colombier if(_Strcmp(s, targetmap[i].key) == 0)
39139a747e4fSDavid du Colombier return targetmap[i].val;
3914c93608ccSDavid du Colombier if(i == targetmapsize) {
39159a747e4fSDavid du Colombier targetmapsize += 10;
3916c93608ccSDavid du Colombier targetmap = erealloc(targetmap, targetmapsize*sizeof(StringInt));
39179a747e4fSDavid du Colombier }
3918c93608ccSDavid du Colombier targetmap[i].key = _Strdup(s);
39199a747e4fSDavid du Colombier targetmap[i].val = i;
39209a747e4fSDavid du Colombier ntargets++;
39219a747e4fSDavid du Colombier return i;
39229a747e4fSDavid du Colombier }
39239a747e4fSDavid du Colombier
39249a747e4fSDavid du Colombier Rune*
targetname(int targid)39259a747e4fSDavid du Colombier targetname(int targid)
39269a747e4fSDavid du Colombier {
39279a747e4fSDavid du Colombier int i;
39289a747e4fSDavid du Colombier
39299a747e4fSDavid du Colombier for(i = 0; i < ntargets; i++)
39309a747e4fSDavid du Colombier if(targetmap[i].val == targid)
39319a747e4fSDavid du Colombier return targetmap[i].key;
39329a747e4fSDavid du Colombier return L"?";
39339a747e4fSDavid du Colombier }
39349a747e4fSDavid du Colombier
39359a747e4fSDavid du Colombier // Convert HTML color spec to RGB value, returning dflt if can't.
39369a747e4fSDavid du Colombier // Argument is supposed to be a valid HTML color, or "".
39379a747e4fSDavid du Colombier // Return the RGB value of the color, using dflt if s
39389a747e4fSDavid du Colombier // is nil or an invalid color.
39399a747e4fSDavid du Colombier static int
color(Rune * s,int dflt)39409a747e4fSDavid du Colombier color(Rune* s, int dflt)
39419a747e4fSDavid du Colombier {
39429a747e4fSDavid du Colombier int v;
39439a747e4fSDavid du Colombier Rune* rest;
39449a747e4fSDavid du Colombier
39459a747e4fSDavid du Colombier if(s == nil)
39469a747e4fSDavid du Colombier return dflt;
39475d459b5aSDavid du Colombier if(_lookup(color_tab, NCOLORS, s, _Strlen(s), &v))
39489a747e4fSDavid du Colombier return v;
39499a747e4fSDavid du Colombier if(s[0] == '#')
39509a747e4fSDavid du Colombier s++;
39519a747e4fSDavid du Colombier v = _Strtol(s, &rest, 16);
39529a747e4fSDavid du Colombier if(*rest == 0)
39539a747e4fSDavid du Colombier return v;
39549a747e4fSDavid du Colombier return dflt;
39559a747e4fSDavid du Colombier }
39569a747e4fSDavid du Colombier
39579a747e4fSDavid du Colombier // Debugging
39589a747e4fSDavid du Colombier
39599a747e4fSDavid du Colombier #define HUGEPIX 10000
39609a747e4fSDavid du Colombier
39619a747e4fSDavid du Colombier // A "shallow" validitem, that doesn't follow next links
39629a747e4fSDavid du Colombier // or descend into tables.
39639a747e4fSDavid du Colombier static int
validitem(Item * i)39649a747e4fSDavid du Colombier validitem(Item* i)
39659a747e4fSDavid du Colombier {
39669a747e4fSDavid du Colombier int ok;
39679a747e4fSDavid du Colombier Itext* ti;
39689a747e4fSDavid du Colombier Irule* ri;
39699a747e4fSDavid du Colombier Iimage* ii;
39709a747e4fSDavid du Colombier Ifloat* fi;
39719a747e4fSDavid du Colombier int a;
39729a747e4fSDavid du Colombier
39739a747e4fSDavid du Colombier ok = (i->tag >= Itexttag && i->tag <= Ispacertag) &&
39749a747e4fSDavid du Colombier (i->next == nil || validptr(i->next)) &&
39759a747e4fSDavid du Colombier (i->width >= 0 && i->width < HUGEPIX) &&
39769a747e4fSDavid du Colombier (i->height >= 0 && i->height < HUGEPIX) &&
39779a747e4fSDavid du Colombier (i->ascent > -HUGEPIX && i->ascent < HUGEPIX) &&
39789a747e4fSDavid du Colombier (i->anchorid >= 0) &&
39799a747e4fSDavid du Colombier (i->genattr == nil || validptr(i->genattr));
39809a747e4fSDavid du Colombier // also, could check state for ridiculous combinations
39819a747e4fSDavid du Colombier // also, could check anchorid for within-doc-range
39829a747e4fSDavid du Colombier if(ok)
39839a747e4fSDavid du Colombier switch(i->tag) {
39849a747e4fSDavid du Colombier case Itexttag:
39859a747e4fSDavid du Colombier ti = (Itext*)i;
39869a747e4fSDavid du Colombier ok = validStr(ti->s) &&
39879a747e4fSDavid du Colombier (ti->fnt >= 0 && ti->fnt < NumStyle*NumSize) &&
39889a747e4fSDavid du Colombier (ti->ul == ULnone || ti->ul == ULunder || ti->ul == ULmid);
39899a747e4fSDavid du Colombier break;
39909a747e4fSDavid du Colombier case Iruletag:
39919a747e4fSDavid du Colombier ri = (Irule*)i;
39929a747e4fSDavid du Colombier ok = (validvalign(ri->align) || validhalign(ri->align)) &&
39939a747e4fSDavid du Colombier (ri->size >=0 && ri->size < HUGEPIX);
39949a747e4fSDavid du Colombier break;
39959a747e4fSDavid du Colombier case Iimagetag:
39969a747e4fSDavid du Colombier ii = (Iimage*)i;
39979a747e4fSDavid du Colombier ok = (ii->imsrc == nil || validptr(ii->imsrc)) &&
39989a747e4fSDavid du Colombier (ii->width >= 0 && ii->width < HUGEPIX) &&
39999a747e4fSDavid du Colombier (ii->height >= 0 && ii->height < HUGEPIX) &&
40009a747e4fSDavid du Colombier (ii->imwidth >= 0 && ii->imwidth < HUGEPIX) &&
40019a747e4fSDavid du Colombier (ii->imheight >= 0 && ii->imheight < HUGEPIX) &&
40029a747e4fSDavid du Colombier (ii->altrep == nil || validStr(ii->altrep)) &&
40039a747e4fSDavid du Colombier (ii->map == nil || validptr(ii->map)) &&
40049a747e4fSDavid du Colombier (validvalign(ii->align) || validhalign(ii->align)) &&
40059a747e4fSDavid du Colombier (ii->nextimage == nil || validptr(ii->nextimage));
40069a747e4fSDavid du Colombier break;
40079a747e4fSDavid du Colombier case Iformfieldtag:
40089a747e4fSDavid du Colombier ok = validformfield(((Iformfield*)i)->formfield);
40099a747e4fSDavid du Colombier break;
40109a747e4fSDavid du Colombier case Itabletag:
40119a747e4fSDavid du Colombier ok = validptr((Itable*)i);
40129a747e4fSDavid du Colombier break;
40139a747e4fSDavid du Colombier case Ifloattag:
40149a747e4fSDavid du Colombier fi = (Ifloat*)i;
40159a747e4fSDavid du Colombier ok = (fi->side == ALleft || fi->side == ALright) &&
40169a747e4fSDavid du Colombier validitem(fi->item) &&
40179a747e4fSDavid du Colombier (fi->item->tag == Iimagetag || fi->item->tag == Itabletag);
40189a747e4fSDavid du Colombier break;
40199a747e4fSDavid du Colombier case Ispacertag:
40209a747e4fSDavid du Colombier a = ((Ispacer*)i)->spkind;
40219a747e4fSDavid du Colombier ok = a==ISPnull || a==ISPvline || a==ISPhspace || a==ISPgeneral;
40229a747e4fSDavid du Colombier break;
40239a747e4fSDavid du Colombier default:
40249a747e4fSDavid du Colombier ok = 0;
40259a747e4fSDavid du Colombier }
40269a747e4fSDavid du Colombier return ok;
40279a747e4fSDavid du Colombier }
40289a747e4fSDavid du Colombier
40299a747e4fSDavid du Colombier // "deep" validation, that checks whole list of items,
40309a747e4fSDavid du Colombier // and descends into tables and floated tables.
40319a747e4fSDavid du Colombier // nil is ok for argument.
40329a747e4fSDavid du Colombier int
validitems(Item * i)40339a747e4fSDavid du Colombier validitems(Item* i)
40349a747e4fSDavid du Colombier {
40359a747e4fSDavid du Colombier int ok;
40369a747e4fSDavid du Colombier Item* ii;
40379a747e4fSDavid du Colombier
40389a747e4fSDavid du Colombier ok = 1;
40399a747e4fSDavid du Colombier while(i != nil && ok) {
40409a747e4fSDavid du Colombier ok = validitem(i);
40419a747e4fSDavid du Colombier if(ok) {
40429a747e4fSDavid du Colombier if(i->tag == Itabletag) {
40439a747e4fSDavid du Colombier ok = validtable(((Itable*)i)->table);
40449a747e4fSDavid du Colombier }
40459a747e4fSDavid du Colombier else if(i->tag == Ifloattag) {
40469a747e4fSDavid du Colombier ii = ((Ifloat*)i)->item;
40479a747e4fSDavid du Colombier if(ii->tag == Itabletag)
40489a747e4fSDavid du Colombier ok = validtable(((Itable*)ii)->table);
40499a747e4fSDavid du Colombier }
40509a747e4fSDavid du Colombier }
40519a747e4fSDavid du Colombier if(!ok) {
40529a747e4fSDavid du Colombier fprint(2, "invalid item: %I\n", i);
40539a747e4fSDavid du Colombier }
40549a747e4fSDavid du Colombier i = i->next;
40559a747e4fSDavid du Colombier }
40569a747e4fSDavid du Colombier return ok;
40579a747e4fSDavid du Colombier }
40589a747e4fSDavid du Colombier
40599a747e4fSDavid du Colombier static int
validformfield(Formfield * f)40609a747e4fSDavid du Colombier validformfield(Formfield* f)
40619a747e4fSDavid du Colombier {
40629a747e4fSDavid du Colombier int ok;
40639a747e4fSDavid du Colombier
40649a747e4fSDavid du Colombier ok = (f->next == nil || validptr(f->next)) &&
40659a747e4fSDavid du Colombier (f->ftype >= 0 && f->ftype <= Ftextarea) &&
40669a747e4fSDavid du Colombier f->fieldid >= 0 &&
40679a747e4fSDavid du Colombier (f->form == nil || validptr(f->form)) &&
40689a747e4fSDavid du Colombier (f->name == nil || validStr(f->name)) &&
40699a747e4fSDavid du Colombier (f->value == nil || validStr(f->value)) &&
40709a747e4fSDavid du Colombier (f->options == nil || validptr(f->options)) &&
40719a747e4fSDavid du Colombier (f->image == nil || validitem(f->image)) &&
40729a747e4fSDavid du Colombier (f->events == nil || validptr(f->events));
40739a747e4fSDavid du Colombier // when all built, should have f->fieldid < f->form->nfields,
40749a747e4fSDavid du Colombier // but this may be called during build...
40759a747e4fSDavid du Colombier return ok;
40769a747e4fSDavid du Colombier }
40779a747e4fSDavid du Colombier
40789a747e4fSDavid du Colombier // "deep" validation -- checks cell contents too
40799a747e4fSDavid du Colombier static int
validtable(Table * t)40809a747e4fSDavid du Colombier validtable(Table* t)
40819a747e4fSDavid du Colombier {
40829a747e4fSDavid du Colombier int ok;
40839a747e4fSDavid du Colombier int i, j;
40849a747e4fSDavid du Colombier Tablecell* c;
40859a747e4fSDavid du Colombier
40869a747e4fSDavid du Colombier ok = (t->next == nil || validptr(t->next)) &&
40879a747e4fSDavid du Colombier t->nrow >= 0 &&
40889a747e4fSDavid du Colombier t->ncol >= 0 &&
40899a747e4fSDavid du Colombier t->ncell >= 0 &&
40909a747e4fSDavid du Colombier validalign(t->align) &&
40919a747e4fSDavid du Colombier validdimen(t->width) &&
40929a747e4fSDavid du Colombier (t->border >= 0 && t->border < HUGEPIX) &&
40939a747e4fSDavid du Colombier (t->cellspacing >= 0 && t->cellspacing < HUGEPIX) &&
40949a747e4fSDavid du Colombier (t->cellpadding >= 0 && t->cellpadding < HUGEPIX) &&
40959a747e4fSDavid du Colombier validitems(t->caption) &&
40969a747e4fSDavid du Colombier (t->caption_place == ALtop || t->caption_place == ALbottom) &&
40979a747e4fSDavid du Colombier (t->totw >= 0 && t->totw < HUGEPIX) &&
40989a747e4fSDavid du Colombier (t->toth >= 0 && t->toth < HUGEPIX) &&
40999a747e4fSDavid du Colombier (t->tabletok == nil || validptr(t->tabletok));
41009a747e4fSDavid du Colombier // during parsing, t->rows has list;
41019a747e4fSDavid du Colombier // only when parsing is done is t->nrow set > 0
41029a747e4fSDavid du Colombier if(ok && t->nrow > 0 && t->ncol > 0) {
41039a747e4fSDavid du Colombier // table is "finished"
41049a747e4fSDavid du Colombier for(i = 0; i < t->nrow && ok; i++)
41059a747e4fSDavid du Colombier ok = validtablerow(t->rows+i);
41069a747e4fSDavid du Colombier for(j = 0; j < t->ncol && ok; j++)
41079a747e4fSDavid du Colombier ok = validtablecol(t->cols+j);
41089a747e4fSDavid du Colombier for(c = t->cells; c != nil && ok; c = c->next)
41099a747e4fSDavid du Colombier ok = validtablecell(c);
41109a747e4fSDavid du Colombier for(i = 0; i < t->nrow && ok; i++)
41119a747e4fSDavid du Colombier for(j = 0; j < t->ncol && ok; j++)
41129a747e4fSDavid du Colombier ok = validptr(t->grid[i][j]);
41139a747e4fSDavid du Colombier }
41149a747e4fSDavid du Colombier return ok;
41159a747e4fSDavid du Colombier }
41169a747e4fSDavid du Colombier
41179a747e4fSDavid du Colombier static int
validvalign(int a)41189a747e4fSDavid du Colombier validvalign(int a)
41199a747e4fSDavid du Colombier {
41209a747e4fSDavid du Colombier return a == ALnone || a == ALmiddle || a == ALbottom || a == ALtop || a == ALbaseline;
41219a747e4fSDavid du Colombier }
41229a747e4fSDavid du Colombier
41239a747e4fSDavid du Colombier static int
validhalign(int a)41249a747e4fSDavid du Colombier validhalign(int a)
41259a747e4fSDavid du Colombier {
41269a747e4fSDavid du Colombier return a == ALnone || a == ALleft || a == ALcenter || a == ALright ||
41279a747e4fSDavid du Colombier a == ALjustify || a == ALchar;
41289a747e4fSDavid du Colombier }
41299a747e4fSDavid du Colombier
41309a747e4fSDavid du Colombier static int
validalign(Align a)41319a747e4fSDavid du Colombier validalign(Align a)
41329a747e4fSDavid du Colombier {
41339a747e4fSDavid du Colombier return validhalign(a.halign) && validvalign(a.valign);
41349a747e4fSDavid du Colombier }
41359a747e4fSDavid du Colombier
41369a747e4fSDavid du Colombier static int
validdimen(Dimen d)41379a747e4fSDavid du Colombier validdimen(Dimen d)
41389a747e4fSDavid du Colombier {
41399a747e4fSDavid du Colombier int ok;
41409a747e4fSDavid du Colombier int s;
41419a747e4fSDavid du Colombier
41429a747e4fSDavid du Colombier ok = 0;
41439a747e4fSDavid du Colombier s = d.kindspec&Dspecmask;
41449a747e4fSDavid du Colombier switch(d.kindspec&Dkindmask) {
41459a747e4fSDavid du Colombier case Dnone:
41469a747e4fSDavid du Colombier ok = s==0;
41479a747e4fSDavid du Colombier break;
41489a747e4fSDavid du Colombier case Dpixels:
41499a747e4fSDavid du Colombier ok = s < HUGEPIX;
41509a747e4fSDavid du Colombier break;
41519a747e4fSDavid du Colombier case Dpercent:
41529a747e4fSDavid du Colombier case Drelative:
41539a747e4fSDavid du Colombier ok = 1;
41549a747e4fSDavid du Colombier break;
41559a747e4fSDavid du Colombier }
41569a747e4fSDavid du Colombier return ok;
41579a747e4fSDavid du Colombier }
41589a747e4fSDavid du Colombier
41599a747e4fSDavid du Colombier static int
validtablerow(Tablerow * r)41609a747e4fSDavid du Colombier validtablerow(Tablerow* r)
41619a747e4fSDavid du Colombier {
41629a747e4fSDavid du Colombier return (r->cells == nil || validptr(r->cells)) &&
41639a747e4fSDavid du Colombier (r->height >= 0 && r->height < HUGEPIX) &&
41649a747e4fSDavid du Colombier (r->ascent > -HUGEPIX && r->ascent < HUGEPIX) &&
41659a747e4fSDavid du Colombier validalign(r->align);
41669a747e4fSDavid du Colombier }
41679a747e4fSDavid du Colombier
41689a747e4fSDavid du Colombier static int
validtablecol(Tablecol * c)41699a747e4fSDavid du Colombier validtablecol(Tablecol* c)
41709a747e4fSDavid du Colombier {
41719a747e4fSDavid du Colombier return c->width >= 0 && c->width < HUGEPIX
41729a747e4fSDavid du Colombier && validalign(c->align);
41739a747e4fSDavid du Colombier }
41749a747e4fSDavid du Colombier
41759a747e4fSDavid du Colombier static int
validtablecell(Tablecell * c)41769a747e4fSDavid du Colombier validtablecell(Tablecell* c)
41779a747e4fSDavid du Colombier {
41789a747e4fSDavid du Colombier int ok;
41799a747e4fSDavid du Colombier
41809a747e4fSDavid du Colombier ok = (c->next == nil || validptr(c->next)) &&
41819a747e4fSDavid du Colombier (c->nextinrow == nil || validptr(c->nextinrow)) &&
41829a747e4fSDavid du Colombier (c->content == nil || validptr(c->content)) &&
41839a747e4fSDavid du Colombier (c->lay == nil || validptr(c->lay)) &&
41849a747e4fSDavid du Colombier c->rowspan >= 0 &&
41859a747e4fSDavid du Colombier c->colspan >= 0 &&
41869a747e4fSDavid du Colombier validalign(c->align) &&
41879a747e4fSDavid du Colombier validdimen(c->wspec) &&
41889a747e4fSDavid du Colombier c->row >= 0 &&
41899a747e4fSDavid du Colombier c->col >= 0;
41909a747e4fSDavid du Colombier if(ok) {
41919a747e4fSDavid du Colombier if(c->content != nil)
41929a747e4fSDavid du Colombier ok = validitems(c->content);
41939a747e4fSDavid du Colombier }
41949a747e4fSDavid du Colombier return ok;
41959a747e4fSDavid du Colombier }
41969a747e4fSDavid du Colombier
41979a747e4fSDavid du Colombier static int
validptr(void * p)41989a747e4fSDavid du Colombier validptr(void* p)
41999a747e4fSDavid du Colombier {
42009a747e4fSDavid du Colombier // TODO: a better job of this.
42019a747e4fSDavid du Colombier // For now, just dereference, which cause a bomb
42029a747e4fSDavid du Colombier // if not valid
42039a747e4fSDavid du Colombier static char c;
42049a747e4fSDavid du Colombier
42059a747e4fSDavid du Colombier c = *((char*)p);
42069a747e4fSDavid du Colombier return 1;
42079a747e4fSDavid du Colombier }
42089a747e4fSDavid du Colombier
42099a747e4fSDavid du Colombier static int
validStr(Rune * s)42109a747e4fSDavid du Colombier validStr(Rune* s)
42119a747e4fSDavid du Colombier {
42129a747e4fSDavid du Colombier return s != nil && validptr(s);
42139a747e4fSDavid du Colombier }
4214