build.c

来自「这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易」· C语言 代码 · 共 2,670 行 · 第 1/5 页

C
2,670
字号
#include <u.h>#include <libc.h>#include <draw.h>#include <ctype.h>#include <html.h>#include "impl.h"// A stack for holding integer valuesenum {	Nestmax = 40	// max nesting level of lists, font styles, etc.};struct Stack {	int		n;				// next available slot (top of stack is stack[n-1])	int		slots[Nestmax];	// stack entries};// Parsing statestruct Pstate{	Pstate*	next;			// in stack of Pstates	int		skipping;		// true when we shouldn't add items	int		skipwhite;		// true when we should strip leading space	int		curfont;		// font index for current font	int		curfg;		// current foreground color	Background	curbg;	// current background	int		curvoff;		// current baseline offset	uchar	curul;		// current underline/strike state	uchar	curjust;		// current justify state	int		curanchor;	// current (href) anchor id (if in one), or 0	int		curstate;		// current value of item state	int		literal;		// current literal state	int		inpar;		// true when in a paragraph-like construct	int		adjsize;		// current font size adjustment	Item*	items;		// dummy head of item list we're building	Item*	lastit;		// tail of item list we're building	Item*	prelastit;		// item before lastit	Stack	fntstylestk;	// style stack	Stack	fntsizestk;		// size stack	Stack	fgstk;		// text color stack	Stack	ulstk;		// underline stack	Stack	voffstk;		// vertical offset stack	Stack	listtypestk;	// list type stack	Stack	listcntstk;		// list counter stack	Stack	juststk;		// justification stack	Stack	hangstk;		// hanging stack};struct ItemSource{	Docinfo*		doc;	Pstate*		psstk;	int			nforms;	int			ntables;	int			nanchors;	int			nframes;	Form*		curform;	Map*		curmap;	Table*		tabstk;	Kidinfo*		kidstk;};// Some layout parametersenum {	FRKIDMARGIN = 6,	// default margin around kid frames	IMGHSPACE = 0,	// default hspace for images (0 matches IE, Netscape)	IMGVSPACE = 0,	// default vspace for images	FLTIMGHSPACE = 2,	// default hspace for float images	TABSP = 5,		// default cellspacing for tables	TABPAD = 1,		// default cell padding for tables	LISTTAB = 1,		// number of tabs to indent lists	BQTAB = 1,		// number of tabs to indent blockquotes	HRSZ = 2,			// thickness of horizontal rules	SUBOFF = 4,		// vertical offset for subscripts	SUPOFF = 6,		// vertical offset for superscripts	NBSP = 160		// non-breaking space character};// These tables must be sortedstatic StringInt align_tab[] = {	{L"baseline",	ALbaseline},	{L"bottom",	ALbottom},	{L"center",	ALcenter},	{L"char",		ALchar},	{L"justify",	ALjustify},	{L"left",		ALleft},	{L"middle",	ALmiddle},	{L"right",		ALright},	{L"top",		ALtop}};#define NALIGNTAB (sizeof(align_tab)/sizeof(StringInt))static StringInt input_tab[] = {	{L"button",	Fbutton},	{L"checkbox",	Fcheckbox},	{L"file",		Ffile},	{L"hidden",	Fhidden},	{L"image",	Fimage},	{L"password",	Fpassword},	{L"radio",		Fradio},	{L"reset",		Freset},	{L"submit",	Fsubmit},	{L"text",		Ftext}};#define NINPUTTAB (sizeof(input_tab)/sizeof(StringInt))static StringInt clear_tab[] = {	{L"all",	IFcleft|IFcright},	{L"left",	IFcleft},	{L"right",	IFcright}};#define NCLEARTAB (sizeof(clear_tab)/sizeof(StringInt))static StringInt fscroll_tab[] = {	{L"auto",	FRhscrollauto|FRvscrollauto},	{L"no",	FRnoscroll},	{L"yes",	FRhscroll|FRvscroll},};#define NFSCROLLTAB (sizeof(fscroll_tab)/sizeof(StringInt))static StringInt shape_tab[] = {	{L"circ",		SHcircle},	{L"circle",		SHcircle},	{L"poly",		SHpoly},	{L"polygon",	SHpoly},	{L"rect",		SHrect},	{L"rectangle",	SHrect}};#define NSHAPETAB (sizeof(shape_tab)/sizeof(StringInt))static StringInt method_tab[] = {	{L"get",		HGet},	{L"post",		HPost}};#define NMETHODTAB (sizeof(method_tab)/sizeof(StringInt))static Rune* roman[15]= {	L"I", L"II", L"III", L"IV", L"V", L"VI", L"VII", L"VIII", L"IX", L"X",	L"XI", L"XII", L"XIII", L"XIV", L"XV"};#define NROMAN 15// List number typesenum {	LTdisc, LTsquare, LTcircle, LT1, LTa, LTA, LTi, LTI};enum {	SPBefore = 2,	SPAfter = 4,	BL = 1,	BLBA = (BL|SPBefore|SPAfter)};// 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.static uchar blockbrk[Numtags]= {	[Taddress] BLBA, [Tblockquote] BLBA, [Tcenter] BL,	[Tdir] BLBA, [Tdiv] BL, [Tdd] BL, [Tdl] BLBA,	[Tdt] BL, [Tform] BLBA,	// headings and tables get breaks added manually	[Th1] BL, [Th2] BL, [Th3] BL,	[Th4] BL, [Th5] BL, [Th6] BL,	[Thr] BL, [Tisindex] BLBA, [Tli] BL, [Tmenu] BLBA,	[Tol] BLBA, [Tp] BLBA, [Tpre] BLBA,	[Tul] BLBA};enum {	AGEN = 1};// attrinfo is information about attributes.// The AGEN value means that the attribute is generic (applies to almost all elements)static uchar attrinfo[Numattrs]= {	[Aid] AGEN, [Aclass] AGEN, [Astyle] AGEN, [Atitle] AGEN,	[Aonblur] AGEN, [Aonchange] AGEN, [Aonclick] AGEN,	[Aondblclick] AGEN, [Aonfocus] AGEN, [Aonkeypress] AGEN,	[Aonkeyup] AGEN, [Aonload] AGEN, [Aonmousedown] AGEN,	[Aonmousemove] AGEN, [Aonmouseout] AGEN, [Aonmouseover] AGEN,	[Aonmouseup] AGEN, [Aonreset] AGEN, [Aonselect] AGEN,	[Aonsubmit] AGEN, [Aonunload] AGEN};static uchar scriptev[Numattrs]= {	[Aonblur] SEonblur, [Aonchange] SEonchange, [Aonclick] SEonclick,	[Aondblclick] SEondblclick, [Aonfocus] SEonfocus, [Aonkeypress] SEonkeypress,	[Aonkeyup] SEonkeyup, [Aonload] SEonload, [Aonmousedown] SEonmousedown,	[Aonmousemove] SEonmousemove, [Aonmouseout] SEonmouseout, [Aonmouseover] SEonmouseover,	[Aonmouseup] SEonmouseup, [Aonreset] SEonreset, [Aonselect] SEonselect,	[Aonsubmit] SEonsubmit, [Aonunload] SEonunload};// Color lookup tablestatic StringInt color_tab[] = {	{L"aqua", 0x00FFFF},	{L"black",  0x000000},	{L"blue", 0x0000CC},	{L"fuchsia", 0xFF00FF},	{L"gray", 0x808080},	{L"green", 0x008000},	{L"lime", 0x00FF00},	{L"maroon", 0x800000},	{L"navy", 0x000080,},	{L"olive", 0x808000},	{L"purple", 0x800080},	{L"red", 0xFF0000},	{L"silver", 0xC0C0C0},	{L"teal", 0x008080},	{L"white", 0xFFFFFF},	{L"yellow", 0xFFFF00}};#define NCOLORS (sizeof(color_tab)/sizeof(StringInt))static StringInt 		*targetmap;static int			targetmapsize;static int			ntargets;static int buildinited = 0;#define SMALLBUFSIZE 240#define BIGBUFSIZE 2000int	dbgbuild = 0;int	warn = 0;static Align		aalign(Token* tok);static int			acolorval(Token* tok, int attid, int dflt);static void			addbrk(Pstate* ps, int sp, int clr);static void			additem(Pstate* ps, Item* it, Token* tok);static void			addlinebrk(Pstate* ps, int clr);static void			addnbsp(Pstate* ps);static void			addtext(Pstate* ps, Rune* s);static Dimen		adimen(Token* tok, int attid);static int			aflagval(Token* tok, int attid);static int			aintval(Token* tok, int attid, int dflt);static Rune*		astrval(Token* tok, int attid, Rune* dflt);static int			atabval(Token* tok, int attid, StringInt* tab, int ntab, int dflt);static int			atargval(Token* tok, int dflt);static int			auintval(Token* tok, int attid, int dflt);static Rune*		aurlval(Token* tok, int attid, Rune* dflt, Rune* base);static Rune*		aval(Token* tok, int attid);static void			buildinit(void);static Pstate*		cell_pstate(Pstate* oldps, int ishead);static void			changehang(Pstate* ps, int delta);static void			changeindent(Pstate* ps, int delta);static int			color(Rune* s, int dflt);static void			copystack(Stack* tostk, Stack* fromstk);static int			dimprint(char* buf, int nbuf, Dimen d);static Pstate*		finishcell(Table* curtab, Pstate* psstk);static void			finish_table(Table* t);static void			freeanchor(Anchor* a);static void			freedestanchor(DestAnchor* da);static void			freeform(Form* f);static void			freeformfield(Formfield* ff);static void			freeitem(Item* it);static void			freepstate(Pstate* p);static void			freepstatestack(Pstate* pshead);static void			freescriptevents(SEvent* ehead);static void			freetable(Table* t);static Map*		getmap(Docinfo* di, Rune* name);static Rune*		getpcdata(Token* toks, int tokslen, int* ptoki);static Pstate*		lastps(Pstate* psl);static Rune*		listmark(uchar ty, int n);static int			listtyval(Token* tok, int dflt);static Align		makealign(int halign, int valign);static Background	makebackground(Rune* imgurl, int color);static Dimen		makedimen(int kind, int spec);static Anchor*		newanchor(int index, Rune* name, Rune* href, int target, Anchor* link);static Area*		newarea(int shape, Rune* href, int target, Area* link);static DestAnchor*	newdestanchor(int index, Rune* name, Item* item, DestAnchor* link);static Docinfo*		newdocinfo(void);static Genattr*		newgenattr(Rune* id, Rune* class, Rune* style, Rune* title, Attr* events);static Form*		newform(int formid, Rune* name, Rune* action,					int target, int method, Form* link);static Formfield*	newformfield(int ftype, int fieldid, Form* form, Rune* name,					Rune* value, int size, int maxlength, Formfield* link);static Item*		newifloat(Item* it, int side);static Item*		newiformfield(Formfield* ff);static Item*		newiimage(Rune* src, Rune* altrep, int align, int width, int height,					int hspace, int vspace, int border, int ismap, Map* map);static Item*		newirule(int align, int size, int noshade, Dimen wspec);static Item*		newispacer(int spkind);static Item*		newitable(Table* t);static ItemSource*	newitemsource(Docinfo* di);static Item*		newitext(Rune* s, int fnt, int fg, int voff, int ul);static Kidinfo*		newkidinfo(int isframeset, Kidinfo* link);static Option*		newoption(int selected, Rune* value, Rune* display, Option* link);static Pstate*		newpstate(Pstate* link);static SEvent*		newscriptevent(int type, Rune* script, SEvent* link);static Table*		newtable(int tableid, Align align, Dimen width, int border,					int cellspacing, int cellpadding, Background bg, Token* tok, Table* link);static Tablecell*	newtablecell(int cellid, int rowspan, int colspan, Align align, Dimen wspec,					int hspec, Background bg, int flags, Tablecell* link);static Tablerow*	newtablerow(Align align, Background bg, int flags, Tablerow* link);static Dimen		parsedim(Rune* s, int ns);static void			pop(Stack* stk);static void			popfontsize(Pstate* ps);static void			popfontstyle(Pstate* ps);static void			popjust(Pstate* ps);static int			popretnewtop(Stack* stk, int dflt);static int			push(Stack* stk, int val);static void			pushfontsize(Pstate* ps, int sz);static void			pushfontstyle(Pstate* ps, int sty);static void			pushjust(Pstate* ps, int j);static Item*		textit(Pstate* ps, Rune* s);static Rune*		removeallwhite(Rune* s);static void			resetdocinfo(Docinfo* d);static void			setcurfont(Pstate* ps);static void			setcurjust(Pstate* ps);static void			setdimarray(Token* tok, int attid, Dimen** pans, int* panslen);static Rune*		stringalign(int a);static void			targetmapinit(void);static int			toint(Rune* s);static int			top(Stack* stk, int dflt);static void			trim_cell(Tablecell* c);static int			validalign(Align a);static int			validdimen(Dimen d);static int			validformfield(Formfield* f);static int			validhalign(int a);static int			validptr(void* p);static int			validStr(Rune* s);static int			validtable(Table* t);static int			validtablerow(Tablerow* r);static int			validtablecol(Tablecol* c);static int			validtablecell(Tablecell* c);static int			validvalign(int a);static int			Iconv(Fmt *f);static voidbuildinit(void){	fmtinstall('I', Iconv);	targetmapinit();	buildinited = 1;}static ItemSource*newitemsource(Docinfo* di){	ItemSource*	is;	Pstate*	ps;	ps = newpstate(nil);	if(di->mediatype != TextHtml) {		ps->curstate &= ~IFwrap;		ps->literal = 1;		pushfontstyle(ps, FntT);	}	is = (ItemSource*)emalloc(sizeof(ItemSource));	is->doc = di;	is->psstk = ps;	is->nforms = 0;	is->ntables = 0;	is->nanchors = 0;	is->nframes = 0;	is->curform = nil;	is->curmap = nil;	is->tabstk = nil;	is->kidstk = nil;	return is;}static Item *getitems(ItemSource* is, uchar* data, int datalen);// Parse an html document and create a list of layout items.// Allocate and return document info in *pdi.// When caller is done with the items, it should call// freeitems on the returned result, and then// freedocinfo(*pdi).Item*parsehtml(uchar* data, int datalen, Rune* pagesrc, int mtype, int chset, Docinfo** pdi){	Item *it;	Docinfo*	di;	ItemSource*	is;	di = newdocinfo();	di->src = _Strdup(pagesrc);	di->base = _Strdup(pagesrc);	di->mediatype = mtype;	di->chset = chset;	*pdi = di;	is = newitemsource(di);	it = getitems(is, data, datalen);	freepstatestack(is->psstk);	free(is);	return it;}// Get a group of tokens for lexer, parse them, and create// a list of layout items.// When caller is done with the items, it should call// freeitems on the returned result.static Item*getitems(ItemSource* is, uchar* data, int datalen){	int	i;	int	j;	int	nt;	int	pt;	int	doscripts;	int	tokslen;	int	toki;	int	h;	int	sz;	int	method;	int	n;	int	nblank;	int	norsz;	int	bramt;	int	sty;	int	nosh;	int	oldcuranchor;	int	dfltbd;	int	v;	int	hang;	int	isempty;	int	tag;	int	brksp;	int	target;	uchar	brk;	uchar	flags;	uchar	align;	uchar	al;	uchar	ty;	uchar	ty2;	Pstate*	ps;	Pstate*	nextps;	Pstate*	outerps;	Table*	curtab;	Token*	tok;	Token*	toks;	Docinfo*	di;	Item*	ans;	Item*	img;	Item*	ffit;	Item*	tabitem;	Rune*	s;	Rune*	t;	Rune*	name;	Rune*	enctype;	Rune*	usemap;	Rune*	prompt;	Rune*	equiv;	Rune*	val;	Rune*	nsz;	Rune*	script;	Map*	map;	Form*	frm;	Iimage*	ii;	Kidinfo*	kd;	Kidinfo*	ks;	Kidinfo*	pks;	Dimen	wd;	Option*	option;	Table*	tab;	Tablecell*	c;	Tablerow*	tr;	Formfield*	field;	Formfield*	ff;	Rune*	href;	Rune*	src;	Rune*	scriptsrc;	Rune*	bgurl;	Rune*	action;	Background	bg;	if(!buildinited)		buildinit();	doscripts = 0;	// for now	ps = is->psstk;	curtab = is->tabstk;	di = is->doc;	toks = _gettoks(data, datalen, di->chset, di->mediatype, &tokslen);	toki = 0;	for(; toki < tokslen; toki++) {		tok = &toks[toki];		if(dbgbuild > 1)			fprint(2, "build: curstate %ux, token %T\n", ps->curstate, tok);		tag = tok->tag;		brk = 0;		brksp = 0;		if(tag < Numtags) {			brk = blockbrk[tag];			if(brk&SPBefore)				brksp = 1;		}		else if(tag < Numtags + RBRA) {			brk = blockbrk[tag - RBRA];			if(brk&SPAfter)				brksp = 1;		}		if(brk) {			addbrk(ps, brksp, 0);			if(ps->inpar) {				popjust(ps);				ps->inpar = 0;			}		}		// check common case first (Data), then switch statement on tag		if(tag == 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;			n = _Strlen(s);			if(!ps->literal) {				i = 0;				j = n;				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 < Numtags && pt != Timg && j > 0 && s[0] == '\n')						i++;				}				if(toki < tokslen - 1) {					nt = toks[toki + 1].tag;					if(nt >= RBRA && nt < Numtags + RBRA && j > i && s[j - 1] == '\n')						j--;				}				if(i > 0 || j < n) {					t = s;					s = _Strsubstr(s, i, j);					free(t);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?