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 + -
显示快捷键?