Charles.Forsyth20070907-22049e6db7419 years agoHistory
2864 lines · 70.7 KB · Brainfuck
RawDownload
implement Build; include "common.m"; # local copies from CUsys: Sys;CU: CharonUtils;	ByteSource, CImage, ImageCache, color, Nameval: 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 sortedalign_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->Aonkeydown => 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->Aonresize => AGEN, LX->Aonselect => AGEN,	LX->Aonsubmit => AGEN, LX->Aonunload => AGEN,	* => byte 0}; # Some constantsFRKIDMARGIN: con 6;	# default margin around kid framesIMGHSPACE: con 0;		# default hspace for images (0 matches IE, Netscape)IMGVSPACE: con 0;		# default vspace for imagesFLTIMGHSPACE: con 2;	# default hspace for float imagesTABSP: con 2;			# default cellspacing for tablesTABPAD: con 2;		# default cell padding for tablesLISTTAB: con 1;		# number of tabs to indent listsBQTAB: con 1;			# number of tabs to indent blockquotesHRSZ: con 2;			# thickness of horizontal rulesSUBOFF: con 4;			# vertical offset for subscriptsSUPOFF: con 6;			# vertical offset for superscriptsNBSP: con ' ';			# non-breaking space character dbg := 0;warn := 0;doscripts := 0; utf8 : Btos;latin1 : Btos; 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;	utf8 = CU->getconv("utf8");	latin1 = CU->getconv("latin1");	if (utf8 == nil || latin1 == nil) {		sys->print("cannot load utf8 or latin1 charset converter\n");		raise "EXinternal:build init";	}	dbg = int (CU->config).dbg['h'];	warn = (int (CU->config).dbg['w']) || dbg;	doscripts = (CU->config).doscripts && J != nil;} # 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;# sys->print("chset = %s\n", di.chset);	chset := CU->getconv(di.chset);	if (chset == nil)		chset = latin1;	ts := TokenSource.new(bs, 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{	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 <PRE> 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 <len s)					s = s[i:j];			}			if(ps.skipwhite) {				s = S->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)* 		# <!ELEMENT A - - (%text) -(A)>		# 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 <A> or missing </A>\n");				endanchor(ps, di.text);			}			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 =>			endanchor(ps, di.text); 		# <!ELEMENT APPLET - - (PARAM | %text)* >		# 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: <APPLET> ignored\n"); 		# <!ELEMENT AREA - O EMPTY>		LX->Tarea =>			map := is.curmap;			if(map == nil) {				if(warn)					sys->print("warning: <AREA> not inside <MAP>\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; 		# <!ELEMENT (B|STRONG) - - (%text)*>		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); 		# <!ELEMENT BASE - O EMPTY>		LX->Tbase =>			di.base = aurlval(tok, LX->Ahref, di.base, di.base);			di.target = astrval(tok, LX->Atarget, di.target); 		# <!ELEMENT BASEFONT - O EMPTY>		LX->Tbasefont =>			ps.adjsize = aintval(tok, LX->Asize, 3) - 3; 		# <!ELEMENT (BIG|SMALL) - - (%text)*>		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); 		# <!ELEMENT BLOCKQUOTE - - %body.content>		LX->Tblockquote =>			changeindent(ps, BQTAB); 		LX->Tblockquote+RBRA =>			changeindent(ps, -BQTAB); 		# <!ELEMENT BODY O O %body.content>		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) {				pick ni := Item.newimage(di, bgurl, nil,"", Anone, 0, 0, 0, 0, 0, 0, 1, nil, nil, nil){				Iimage =>					bg.image = ni;				}				di.images = bg.image :: di.images;			}			di.background = ps.curbg = bg;			ps.curbg.image = nil;			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 </body>,			# but IE and Netscape don't			# ps.skipping = 1;			; 		# <!ELEMENT BR - O EMPTY>		LX->Tbr =>			addlinebrk(ps, atabval(tok, LX->Aclear, clear_tab, 0)); 		# <!ELEMENT CAPTION - - (%text;)*>		LX->Tcaption =>			if(curtab == nil) {				if(warn)					sys->print("warning: <CAPTION> outside <TABLE>\n");				continue;			}			if(curtab.caption != nil) {				if(warn)					sys->print("warning: more than one <CAPTION> in <TABLE>\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 </CAPTION>\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); 		# <!ELEMENT DD - O  %flow >		LX->Tdd =>			if(ps.hangstk == nil) {				if(warn)					sys->print("warning: <DD> not inside <DL\n");				continue;			}			h := hd ps.hangstk;			if(h != 0)				changehang(ps, -10*LISTTAB);			else				addbrk(ps, 0, 0);			ps.hangstk = 0 :: ps.hangstk; 		#<!ELEMENT (DIR|MENU) - - (LI)+ -(%block) >		#<!ELEMENT (OL|UL) - - (LI)+>		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); 		# <!ELEMENT DL - - (DT|DD)+ >		LX->Tdl =>			changeindent(ps, LISTTAB);			ps.hangstk = 0 :: ps.hangstk; 		LX->Tdl+RBRA =>			if(ps.hangstk == nil) {				if(warn)					sys->print("warning: unexpected </DL>\n");				continue;			}			changeindent(ps, -LISTTAB);			if(hd ps.hangstk != 0)				changehang(ps, -10*LISTTAB);			ps.hangstk = tl ps.hangstk; 		# <!ELEMENT DT - O (%text)* >		LX->Tdt =>			if(ps.hangstk == nil) {				if(warn)					sys->print("warning: <DT> not inside <DL>\n");				continue;			}

Lines 1–500 of 2864.