implement Build; include "common.m"; # local copies from CU sys: Sys; CU: CharonUtils; ByteSource, CImage, ImageCache, color: import CU; D: Draw; Point, Rect, Image: import D; S: String; T: StringIntTab; C: Ctype; LX: Lex; RBRA, Token, TokenSource: import LX; U: Url; ParsedUrl: import U; J: Script; ctype: array of byte; whitespace : con " \t\n\r"; notwhitespace : con "^ \t\n\r"; # These tables must be sorted align_tab := array[] of { T->StringInt ("baseline", int Abaseline), ("bottom", int Abottom), ("center", int Acenter), ("char", int Achar), ("justify", int Ajustify), ("left", int Aleft), ("middle", int Amiddle), ("right", int Aright), ("top", int Atop), }; input_tab := array[] of { T->StringInt ("button", Fbutton), ("checkbox", Fcheckbox), ("file", Ffile), ("hidden", Fhidden), ("image", Fimage), ("password", Fpassword), ("radio", Fradio), ("reset", Freset), ("submit", Fsubmit), ("text", Ftext), }; clear_tab := array[] of { T->StringInt ("all", IFcleft|IFcright), ("left", IFcleft), ("right", IFcright), }; fscroll_tab := array[] of { T->StringInt ("auto", FRhscrollauto|FRvscrollauto), ("no", FRnoscroll), ("yes", FRhscroll|FRvscroll), }; # blockbrk[tag] is break info for a block level element, or one # of a few others that get the same treatment re ending open paragraphs # and requiring a line break / vertical space before them. # If we want a line of space before the given element, SPBefore is OR'd in. # If we want a line of space after the given element, SPAfter is OR'd in. SPBefore: con byte 2; SPAfter: con byte 4; BL: con byte 1; BLBA: con BL|SPBefore|SPAfter; blockbrk := array[LX->Numtags] of { LX->Taddress => BLBA, LX->Tblockquote => BLBA, LX->Tcenter => BL, LX->Tdir => BLBA, LX->Tdiv => BL, LX->Tdd => BL, LX->Tdl => BLBA, LX->Tdt => BL, LX->Tform => BLBA, # headings and tables get breaks added manually LX->Th1 => BL, LX->Th2 => BL, LX->Th3 => BL, LX->Th4 => BL, LX->Th5 => BL, LX->Th6 => BL, LX->Thr => BL, LX->Tisindex => BLBA, LX->Tli => BL, LX->Tmenu => BLBA, LX->Tol => BLBA, LX->Tp => BLBA, LX->Tpre => BLBA, LX->Tul => BLBA, LX->Txmp => BLBA, * => byte 0 }; # attrinfo is information about attributes. # The AGEN value means that the attribute is generic (applies to almost all elements) AGEN: con byte 1; attrinfo := array[LX->Numattrs] of { LX->Aid => AGEN, LX->Aclass => AGEN, LX->Astyle => AGEN, LX->Atitle => AGEN, LX->Aonabort => AGEN, LX->Aonblur => AGEN, LX->Aonchange => AGEN, LX->Aonclick => AGEN, LX->Aondblclick => AGEN, LX->Aonerror => AGEN, LX->Aonfocus => AGEN, LX->Aonkeypress => AGEN, LX->Aonkeyup => AGEN, LX->Aonload => AGEN, LX->Aonmousedown => AGEN, LX->Aonmousemove => AGEN, LX->Aonmouseout => AGEN, LX->Aonmouseover => AGEN, LX->Aonmouseup => AGEN, LX->Aonreset => AGEN, LX->Aonselect => AGEN, LX->Aonsubmit => AGEN, LX->Aonunload => AGEN, * => byte 0 }; # Some constants FRKIDMARGIN: con 6; # default margin around kid frames IMGHSPACE: con 0; # default hspace for images (0 matches IE, Netscape) IMGVSPACE: con 0; # default vspace for images FLTIMGHSPACE: con 2; # default hspace for float images TABSP: con 2; # default cellspacing for tables TABPAD: con 2; # default cell padding for tables LISTTAB: con 1; # number of tabs to indent lists BQTAB: con 1; # number of tabs to indent blockquotes HRSZ: con 2; # thickness of horizontal rules SUBOFF: con 4; # vertical offset for subscripts SUPOFF: con 6; # vertical offset for superscripts NBSP: con ' '; # non-breaking space character dbg := 0; warn := 0; init(cu: CharonUtils) { CU = cu; sys = load Sys Sys->PATH; D = load Draw Draw->PATH; S = load String String->PATH;; T = load StringIntTab StringIntTab->PATH; U = load Url Url->PATH; if (U != nil) U->init(); C = cu->C; J = cu->J; LX = cu->LX; ctype = C->ctype; } # Assume f has been reset, and then had any values from HTTP headers # filled in (e.g., base, chset). ItemSource.new(bs: ref ByteSource, f: ref Layout->Frame, mtype: int) : ref ItemSource { di := f.doc; ts := TokenSource.new(bs, di.chset, mtype); psstk := list of { Pstate.new() }; if(mtype != CU->TextHtml) { ps := hd psstk; ps.curstate &= ~IFwrap; ps.literal = 1; pushfontstyle(ps, FntT); } return ref ItemSource(ts, mtype, di, f, psstk, 0, 0, 0, 0, nil, nil, nil, nil, nil, nil, nil); } ItemSource.getitems(is: self ref ItemSource) : ref Item { dbg = int (CU->config).dbg['h']; warn = (int (CU->config).dbg['w']) || dbg; doscripts := (CU->config).doscripts; psstk := is.psstk; ps := hd psstk; # ps is always same as hd psstk curtab: ref Table = nil; # curtab is always same as hd is.tabstk if(is.tabstk != nil) curtab = hd is.tabstk; toks := is.toks; is.toks = nil; tokslen := len toks; toki := 0; di := is.doc; TokLoop: for(;; toki++) { if(toki >= tokslen) { outerps := lastps(psstk); if(outerps.items.next != nil) break; toks = is.ts.gettoks(); tokslen = len toks; if(dbg) sys->print("build: got %d tokens from token source\n", tokslen); if(tokslen == 0) break; toki = 0; } tok := toks[toki]; if(dbg > 1) sys->print("build: curstate %ux, token %s\n", ps.curstate, tok.tostring()); tag := tok.tag; brk := byte 0; brksp := 0; if(tag < LX->Numtags) { brk = blockbrk[tag]; if((brk&SPBefore) != byte 0) brksp = 1; } else if(tag < LX->Numtags+RBRA) { brk = blockbrk[tag-RBRA]; if((brk&SPAfter) != byte 0) brksp = 1; } if(brk != byte 0) { addbrk(ps, brksp, 0); if(ps.inpar) { popjust(ps); ps.inpar = 0; } } # check common case first (Data), then case statement on tag if(tag == LX->Data) { # Lexing didn't pay attention to SGML record boundary rules: # \n after start tag or before end tag to be discarded. # (Lex has already discarded all \r's). # Some pages assume this doesn't happen in
 text,
			# so we won't do it if literal is true.
			# BUG: won't discard \n before a start tag that begins
			# the next bufferful of tokens.
			s := tok.text;
			if(!ps.literal) {
				i := 0;
				j := len s;
				if(toki > 0) {
					pt := toks[toki-1].tag;
					# IE and Netscape both ignore this rule (contrary to spec)
					# if previous tag was img
					if(pt < LX->Numtags && pt != LX->Timg && j>0 && s[0]=='\n')
						i++;
				}
				if(toki < tokslen-1) {
					nt := toks[toki+1].tag;
					if(nt >= RBRA && nt < LX->Numtags+RBRA && j>i && s[j-1]=='\n')
						j--;
				}
				if(i>0 || j drop(s, whitespace);
				if(s != "")
					ps.skipwhite = 0;
			}
			if(s != "")
				addtext(ps, s);
		}
		else case tag {
		# Some abbrevs used in following DTD comments
		# %text = #PCDATA
		#		| TT | I | B | U | STRIKE | BIG | SMALL | SUB | SUP
		#		| EM | STRONG | DFN | CODE | SAMP | KBD | VAR | CITE
		#		| A | IMG | APPLET | FONT | BASEFONT | BR | SCRIPT | MAP
		#		| INPUT | SELECT | TEXTAREA
		# %block = P | UL | OL | DIR | MENU | DL | PRE | DL | DIV | CENTER
		#		| BLOCKQUOTE | FORM | ISINDEX | HR | TABLE
		# %flow = (%text | %block)*
		# %body.content = (%heading | %text | %block | ADDRESS)*

		# 
		# Anchors are not supposed to be nested, but you sometimes see
		# href anchors inside destination anchors.
		LX->Ta =>
			if(ps.curanchor != 0) {
				if(warn)
					sys->print("warning: nested  or missing \n");
				ps.curanchor = 0;
			}
			name := aval(tok, LX->Aname);
			href := aurlval(tok, LX->Ahref, nil, di.base);
			target := astrval(tok, LX->Atarget, di.target);
			ga := getgenattr(tok);
			evl : list of Lex->Attr = nil;
			if(ga != nil) {
				evl = ga.events;
				if(evl != nil && doscripts)
					di.hasscripts = 1;
			}
			# ignore rel, rev, and title attrs
			if(href != nil) {
				di.anchors = ref Anchor(++is.nanchors, name, href, target, evl, 0) :: di.anchors;
				ps.curanchor = is.nanchors;
				ps.curfg = di.link;
				ps.fgstk = ps.curfg :: ps.fgstk;
				# underline, too
				ps.ulstk = ULunder :: ps.ulstk;
				ps.curul = ULunder;
			}
			if(name != nil) {
				# add a null item to be destination
				brkstate := ps.curstate & IFbrk;
				additem(ps, Item.newspacer(ISPnull, 0), tok);
				ps.curstate |= brkstate;	# not quite right
				di.dests = ref DestAnchor(++is.nanchors, name, ps.lastit) :: di.dests;
			}

		LX->Ta+RBRA =>
			if(ps.curanchor != 0) {
				if(ps.fgstk != nil) {
					ps.fgstk = tl ps.fgstk;
					if(ps.fgstk == nil)
						ps.curfg = di.text;
					else
						ps.curfg = hd ps.fgstk;
				}
				ps.curanchor = 0;
				if(ps.ulstk != nil) {
					ps.ulstk = tl ps.ulstk;
					if(ps.ulstk == nil)
						ps.curul = ULnone;
					else
						ps.curul = hd ps.ulstk;
				}
			}

		# 
		# We can't do applets, so ignore PARAMS, and let
		# the %text contents appear for the alternative rep
		LX->Tapplet or LX->Tapplet+RBRA =>
			if(warn && tag == LX->Tapplet)
				sys->print("warning:  ignored\n");

		# 
		LX->Tarea =>
			map := is.curmap;
			if(map == nil) {
				if(warn)
					sys->print("warning:  not inside \n");
				continue;
			}
			map.areas = Area(S->tolower(astrval(tok, LX->Ashape, "rect")),
						aurlval(tok, LX->Ahref, nil, di.base),
						astrval(tok, LX->Atarget, di.target),
						dimlist(tok, LX->Acoords)) :: map.areas;

		# 
		LX->Tb or LX->Tstrong =>
			pushfontstyle(ps, FntB);

		LX->Tb+RBRA or LX->Tcite+RBRA
		  or LX->Tcode+RBRA or LX->Tdfn+RBRA
		  or LX->Tem+RBRA or LX->Tkbd+RBRA
		  or LX->Ti+RBRA or LX->Tsamp+RBRA
		  or LX->Tstrong+RBRA or LX->Ttt+RBRA
		  or LX->Tvar+RBRA or LX->Taddress+RBRA =>
			popfontstyle(ps);

		# 
		LX->Tbase =>
			di.base = aurlval(tok, LX->Ahref, di.base, di.base);
			di.target = astrval(tok, LX->Atarget, di.target);

		# 
		LX->Tbasefont =>
			ps.adjsize = aintval(tok, LX->Asize, 3) - 3;

		# 
		LX->Tbig or LX->Tsmall =>
			sz := ps.adjsize;
			if(tag == LX->Tbig)
				sz += Large;
			else
				sz += Small;
			pushfontsize(ps, sz);

		LX->Tbig+RBRA or  LX->Tsmall+RBRA =>
			popfontsize(ps);

		# 
		LX->Tblockquote =>
			changeindent(ps, BQTAB);

		LX->Tblockquote+RBRA =>
			changeindent(ps, -BQTAB);

		# 
		LX->Tbody =>
			ps.skipping = 0;
			bg := Background(nil, color(aval(tok, LX->Abgcolor), di.background.color));
			bgurl := aurlval(tok, LX->Abackground, nil, di.base);
			if(bgurl != nil) {
				di.backgrounditem = Item.newimage(di, bgurl, nil,
					"", Anone, 0, 0, 0, 0, 0, 0, nil, nil, nil);
				di.images = di.backgrounditem :: di.images;
			}
			di.background = ps.curbg = bg;
			di.text = color(aval(tok, LX->Atext), di.text);
			di.link = color(aval(tok, LX->Alink), di.link);
			di.vlink = color(aval(tok, LX->Avlink), di.vlink);
			di.alink = color(aval(tok, LX->Aalink), di.alink);
			if(doscripts) {
				ga := getgenattr(tok);
				if(ga != nil && ga.events != nil) {
					di.events = ga.events;
					di.hasscripts = 1;
				}
			}
			if(di.text != ps.curfg) {
				ps.curfg = di.text;
				ps.fgstk = nil;
			}

		LX->Tbody+RBRA =>
			# HTML spec says ignore things after ,
			# but IE and Netscape don't
			# ps.skipping = 1;
			;

		# 
		LX->Tbr =>
			addlinebrk(ps, atabval(tok, LX->Aclear, clear_tab, 0));

		# 
		LX->Tcaption =>
			if(curtab == nil) {
				if(warn)
					sys->print("warning:  outside \n");
				continue;
			}
			if(curtab.caption != nil) {
				if(warn)
					sys->print("warning: more than one 
in \n"); continue; } ps = Pstate.new(); psstk = ps :: psstk; curtab.caption_place =atabbval(tok, LX->Aalign, align_tab, Atop); LX->Tcaption+RBRA => if(curtab == nil || tl psstk == nil) { if(warn) sys->print("warning: unexpected \n"); continue; } curtab.caption = ps.items.next; psstk = tl psstk; ps = hd psstk; LX->Tcenter or LX->Tdiv => if(tag == LX->Tcenter) al := Acenter; else al = atabbval(tok, LX->Aalign, align_tab, ps.curjust); pushjust(ps, al); LX->Tcenter+RBRA or LX->Tdiv+RBRA => popjust(ps); # LX->Tdd => if(ps.hangstk == nil) { if(warn) sys->print("warning:
not inside # LX->Tdir or LX->Tmenu or LX->Tol or LX->Tul => changeindent(ps, LISTTAB); if(tag == LX->Tol) tydef := LT1; else tydef = LTdisc; start := aintval(tok, LX->Astart, 1); ps.listtypestk = listtyval(tok, tydef) :: ps.listtypestk; ps.listcntstk = start :: ps.listcntstk; LX->Tdir+RBRA or LX->Tmenu+RBRA or LX->Tol+RBRA or LX->Tul+RBRA => if(ps.listtypestk == nil) { if(warn) sys->print("warning: %s ended no list\n", tok.tostring()); continue; } addbrk(ps, 0, 0); ps.listtypestk = tl ps.listtypestk; ps.listcntstk = tl ps.listcntstk; changeindent(ps, -LISTTAB); # LX->Tdl => changeindent(ps, LISTTAB); ps.hangstk = 0 :: ps.hangstk; LX->Tdl+RBRA => if(ps.hangstk == nil) { if(warn) sys->print("warning: unexpected \n"); continue; } changeindent(ps, -LISTTAB); if(hd ps.hangstk != 0) changehang(ps, -10*LISTTAB); ps.hangstk = tl ps.hangstk; # LX->Tdt => if(ps.hangstk == nil) { if(warn) sys->print("warning:
not inside
\n"); continue; } h := hd ps.hangstk; ps.hangstk = tl ps.hangstk; if(h != 0) changehang(ps, -10*LISTTAB); changehang(ps, 10*LISTTAB); ps.hangstk = 1 :: ps.hangstk; # LX->Tfont => sz := stackhd(ps.fntsizestk, Normal); (szfnd, nsz) := tok.aval(LX->Asize); if(szfnd) { if(S->prefix("+", nsz)) sz = Normal + int (nsz[1:]) + ps.adjsize; else if(S->prefix("-", nsz)) sz = Normal - int (nsz[1:]) + ps.adjsize; else if(nsz != "") sz = Normal + ( int nsz - 3); } ps.curfg = color(aval(tok, LX->Acolor), ps.curfg); ps.fgstk = ps.curfg :: ps.fgstk; pushfontsize(ps, sz); LX->Tfont+RBRA => if(ps.fgstk == nil) { if(warn) sys->print("warning: unexpected \n"); continue; } ps.fgstk = tl ps.fgstk; if(ps.fgstk == nil) ps.curfg = di.text; else ps.curfg = hd ps.fgstk; popfontsize(ps); # LX->Tform => if(is.curform != nil) { if(warn) sys->print("warning:
nested inside another\n"); continue; } action := aurlval(tok, LX->Aaction, di.base, di.base); name := astrval(tok, LX->Aname, aval(tok, LX->Aid)); target := astrval(tok, LX->Atarget, di.target); smethod := S->tolower(astrval(tok, LX->Amethod, "get")); method := CU->HGet; if(smethod == "post") method = CU->HPost; else if(smethod != "get") { if(warn) sys->print("warning: unknown form method %s\n", smethod); } (ecfnd, enctype) := tok.aval(LX->Aenctype); if(warn && ecfnd && enctype != "application/x-www-form-urlencoded") sys->print("form enctype %s not handled\n", enctype); ga := getgenattr(tok); evl : list of Lex->Attr = nil; if(ga != nil) { evl = ga.events; if(evl != nil && doscripts) di.hasscripts = 1; } frm := Form.new(++is.nforms, name, action, target, method, evl); di.forms = frm :: di.forms; is.curform = frm; LX->Tform+RBRA => if(is.curform == nil) { if(warn) sys->print("warning: unexpected \n"); continue; } # put fields back in input order fields : list of ref Formfield = nil; for(fl := is.curform.fields; fl != nil; fl = tl fl) fields = hd fl :: fields; is.curform.fields = fields; is.curform.state = FormDone; is.curform = nil; # HTML 4 # LX->Tframe => if(is.kidstk == nil) { if(warn) sys->print("warning: not in \n"); continue; } ks := hd is.kidstk; kd := Kidinfo.new(0); kd.src = aurlval(tok, LX->Asrc, nil, di.base); kd.name = aval(tok, LX->Aname); if(kd.name == "") kd.name = "_fr" + string (++is.nframes); kd.marginw = aintval(tok, LX->Amarginwidth, 0); kd.marginh = aintval(tok, LX->Amarginheight, 0); kd.framebd = aintval(tok, LX->Aframeborder, ks.framebd); kd.flags = atabval(tok, LX->Ascrolling, fscroll_tab, kd.flags); norsz := aflagval(tok, LX->Anoresize); if(norsz) kd.flags |= FRnoresize; ks.kidinfos = kd :: ks.kidinfos; # HTML 4 # LX->Tframeset => ks := Kidinfo.new(1); if(is.kidstk == nil) di.kidinfo = ks; else { pks := hd is.kidstk; pks.kidinfos = ks :: pks.kidinfos; } is.kidstk = ks :: is.kidstk; ks.framebd = aintval(tok, LX->Aborder, 1); ks.rows = dimlist(tok, LX->Arows); if(ks.rows == nil) ks.rows = array[] of {Dimen.make(Dpercent,100)}; ks.cols = dimlist(tok, LX->Acols); if(ks.cols == nil) ks.cols = array[] of {Dimen.make(Dpercent,100)}; if(doscripts) { ga := getgenattr(tok); if(ga != nil && ga.events != nil) { di.events = ga.events; di.hasscripts = 1; } } LX->Tframeset+RBRA => if(is.kidstk == nil) { if(warn) sys->print("warning: unexpected \n"); continue; } ks := hd is.kidstk; # put kids back in original order # and add blank frames to fill out cells n := (len ks.rows) * (len ks.cols); nblank := n - len ks.kidinfos; while(nblank-- > 0) ks.kidinfos = Kidinfo.new(0) :: ks.kidinfos; kids : list of ref Kidinfo = nil; for(kl := ks.kidinfos; kl != nil; kl = tl kl) kids = hd kl :: kids; ks.kidinfos= kids; is.kidstk = tl is.kidstk; if(is.kidstk == nil) { for(;;) { toks = is.ts.gettoks(); if(len toks == 0) break; } tokslen = 0; } # , etc. LX->Th1 or LX->Th2 or LX->Th3 or LX->Th4 or LX->Th5 or LX->Th6 => # don't want extra space if this is first addition # to this item list (BUG: problem if first of bufferful) bramt := 1; if(ps.items == ps.lastit) bramt = 0; addbrk(ps, bramt, IFcleft|IFcright); # assume Th2 = Th1+1, etc. sz := Verylarge - (tag - LX->Th1); if(sz < Tiny) sz = Tiny; pushfontsize(ps, sz); sty := stackhd(ps.fntstylestk, FntR); if(tag == LX->Th1) sty = FntB; pushfontstyle(ps, sty); pushjust(ps, atabbval(tok, LX->Aalign, align_tab, ps.curjust)); ps.skipwhite = 1; LX->Th1+RBRA or LX->Th2+RBRA or LX->Th3+RBRA or LX->Th4+RBRA or LX->Th5+RBRA or LX->Th6+RBRA => addbrk(ps, 1, IFcleft|IFcright); popfontsize(ps); popfontstyle(ps); popjust(ps); LX->Thead => # HTML spec says ignore regular markup in head, # but Netscape and IE don't # ps.skipping = 1; ; LX->Thead+RBRA => ps.skipping = 0; # LX->Thr => al := atabbval(tok, LX->Aalign, align_tab, Acenter); sz := aintval(tok, LX->Asize, HRSZ); wd := makedimen(tok, LX->Awidth); if(wd.kind() == Dnone) wd = Dimen.make(Dpercent, 100); nosh := aflagval(tok, LX->Anoshade); additem(ps, Item.newrule(al, sz, nosh, wd), tok); addbrk(ps, 0, 0); # LX->Ti or LX->Tcite or LX->Tdfn or LX->Tem or LX->Tvar or LX->Taddress => pushfontstyle(ps, FntI); # LX->Timage or # common html error supported by other browsers LX->Timg => tok.tag = LX->Timg; map : ref Map = nil; usemap := aval(tok, LX->Ausemap); oldcuranchor := ps.curanchor; if(usemap != "") { # can't handle non-local maps if(!S->prefix("#", usemap)) { if(warn) sys->print("warning: can't handle non-local map %s\n", usemap); } else { map = getmap(di, usemap[1:]); if(ps.curanchor == 0) { # make an anchor so charon's easy test for whether # there's an action for the item works di.anchors = ref Anchor(++is.nanchors, "", nil, di.target, nil, 0) :: di.anchors; ps.curanchor = is.nanchors; } } } align := atabbval(tok, LX->Aalign, align_tab, Abottom); dfltbd := 0; if(ps.curanchor != 0) dfltbd = 2; src := aurlval(tok, LX->Asrc, nil, di.base); if(src == nil) { if(warn) sys->print("warning: has no src attribute\n"); ps.curanchor = oldcuranchor; continue; } img := Item.newimage(di, src, aurlval(tok, LX->Alowsrc, nil, di.base), aval(tok, LX->Aalt), align, aintval(tok, LX->Awidth, 0), aintval(tok, LX->Aheight, 0), aintval(tok, LX->Ahspace, IMGHSPACE), aintval(tok, LX->Avspace, IMGVSPACE), aintval(tok, LX->Aborder, dfltbd), aflagval(tok, LX->Aismap), map, aval(tok, LX->Aname), getgenattr(tok)); if(align == Aleft || align == Aright) { additem(ps, Item.newfloat(img, align), tok); # if no hspace specified, use FLTIMGHSPACE (fnd,nil) := tok.aval(LX->Ahspace); if(!fnd) { pick ii := img { Iimage => ii.hspace = byte FLTIMGHSPACE; } } } else { ps.skipwhite = 0; additem(ps, img, tok); } if(!ps.skipping) di.images = img :: di.images; ps.curanchor = oldcuranchor; # LX->Tinput => if (ps.skipping) continue; ps.skipwhite = 0; if(is.curform ==nil) { if(warn) sys->print(" not inside
\n"); continue; } field := Formfield.new(atabval(tok, LX->Atype, input_tab, Ftext), ++is.curform.nfields, # fieldid is.curform, # form aval(tok, LX->Aname), aval(tok, LX->Avalue), aintval(tok, LX->Asize, 0), aintval(tok, LX->Amaxlength, 1000)); if(aflagval(tok, LX->Achecked)) field.flags = FFchecked; case field.ftype { Ftext or Fpassword or Ffile => if(field.size == 0) field.size = 20; Fcheckbox => if(field.name == "") { if(warn) sys->print("warning: checkbox form field missing name\n"); # continue; } if(field.value == "") field.value = "1"; Fradio => if(field.name == "" || field.value == "") { if(warn) sys->print("warning: radio form field missing name or value\n"); # continue; } Fsubmit => if(field.value == "") field.value = "Submit"; if(field.name == "") field.name = "_no_name_submit_"; Fimage => src := aurlval(tok, LX->Asrc, nil, di.base); if(src == nil) { if(warn) sys->print("warning: image form field missing src\n"); # continue; } # width and height attrs aren't specified in HTML 3.2, # but some people provide them and they help avoid # a relayout field.image = Item.newimage(di, src, aurlval(tok, LX->Alowsrc, nil, di.base), astrval(tok, LX->Aalt, "Submit"), atabbval(tok, LX->Aalign, align_tab, Abottom), aintval(tok, LX->Awidth, 0), aintval(tok, LX->Aheight, 0), 0, 0, 0, 0, nil, field.name, nil); di.images = field.image :: di.images; Freset => if(field.value == "") field.value = "Reset"; Fbutton => if(field.value == "") field.value = " "; } is.curform.fields = field :: is.curform.fields; ffit := Item.newformfield(field); additem(ps, ffit, tok); if(ffit.genattr != nil) { field.events = ffit.genattr.events; if(field.events != nil && doscripts) di.hasscripts = 1; } # LX->Tisindex => ps.skipwhite = 0; prompt := astrval(tok, LX->Aprompt, "Index search terms:"); target := astrval(tok, LX->Atarget, di.target); additem(ps, textit(ps, prompt), tok); frm := Form.new(++is.nforms, "", di.base, target, CU->HGet, nil); ff := Formfield.new(Ftext, 1, frm, "_ISINDEX_", "", 50, 1000); frm.fields = ff :: nil; frm.nfields = 1; di.forms = frm :: di.forms; additem(ps, Item.newformfield(ff), tok); addbrk(ps, 1, 0); # LX->Tli => if(ps.listtypestk == nil) { if(warn) sys->print("
  • not in list\n"); continue; } ty := hd ps.listtypestk; ty2 := listtyval(tok, ty); if(ty != ty2) { ty = ty2; ps.listtypestk = ty2 :: tl ps.listtypestk; } v := aintval(tok, LX->Avalue, hd ps.listcntstk); if(ty == LTdisc || ty == LTsquare || ty == LTcircle) hang := 10*LISTTAB - 3; else hang = 10*LISTTAB - 1; changehang(ps, hang); addtext(ps, listmark(ty, v)); ps.listcntstk = (v+1) :: (tl ps.listcntstk); changehang(ps, -hang); ps.skipwhite = 1; # LX->Tmap => is.curmap = getmap(di, aval(tok, LX->Aname)); LX->Tmap+RBRA => map := is.curmap; if(map == nil) { if(warn) sys->print("warning: unexpected \n"); continue; } # put areas back in input order areas : list of Area = nil; for(al := map.areas; al != nil; al = tl al) areas = hd al :: areas; map.areas = areas; is.curmap = nil; LX->Tmeta => if(ps.skipping) continue; (fnd, equiv) := tok.aval(LX->Ahttp_equiv); if(fnd) { v := aval(tok, LX->Acontent); case S->tolower(equiv) { "set-cookie" => if((CU->config).docookies > 0) { url := di.src; CU->setcookie(v, url.host, "/" + url.path); } "refresh" => di.refresh = v; "content-script-type" => if(v == "javascript" || v == "javascript1.1" || v == "jscript") di.scripttype = CU->TextJavascript; # TODO: other kinds else { if(warn) sys->print("unimplemented script type %s\n", v); di.scripttype = CU->UnknownType; } } } # Nobr is NOT in HMTL 4.0, but it is ubiquitous on the web LX->Tnobr => ps.skipwhite = 0; ps.curstate &= ~IFwrap; LX->Tnobr+RBRA => ps.curstate |= IFwrap; # We do frames, so skip stuff in noframes LX->Tnoframes => ps.skipping = 1; LX->Tnoframes+RBRA => ps.skipping = 0; # We do scripts (if enabled), so skip stuff in noscripts LX->Tnoscript => if(doscripts) ps.skipping = 1; LX->Tnoscript+RBRA => if(doscripts) ps.skipping = 0; # LX->Toption => if(is.curform == nil || is.curform.fields == nil) { if(warn) sys->print("warning: