build.c
来自「这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易」· C语言 代码 · 共 2,670 行 · 第 1/5 页
C
2,670 行
if(tr->align.halign != ALnone) c->align.halign = tr->align.halign; else if(tag == Tth) c->align.halign = ALcenter; else c->align.halign = ALleft; } if(c->align.valign == ALnone) { if(tr->align.valign != ALnone) c->align.valign = tr->align.valign; else c->align.valign = ALmiddle; } c->nextinrow = tr->cells; tr->cells = c; break; case Ttd+RBRA: case Tth+RBRA: if(curtab == nil || curtab->cells == nil) { if(warn) fprint(2, "unexpected %T\n", tok); continue; } ps = finishcell(curtab, ps); break; // <!ELEMENT TEXTAREA - - ( //PCDATA)> case Ttextarea: if(is->curform == nil) { if(warn) fprint(2, "<TEXTAREA> not inside <FORM>\n"); continue; } field = newformfield(Ftextarea, ++is->curform->nfields, is->curform, aval(tok, Aname), nil, 0, 0, is->curform->fields); is->curform->fields = field; field->rows = auintval(tok, Arows, 3); field->cols = auintval(tok, Acols, 50); field->value = getpcdata(toks, tokslen, &toki); if(warn && toki < tokslen - 1 && toks[toki + 1].tag != Ttextarea + RBRA) fprint(2, "warning: <TEXTAREA> data ended by %T\n", &toks[toki + 1]); ffit = newiformfield(field); additem(ps, ffit, tok); if(ffit->genattr != nil) field->events = ffit->genattr->events; break; // <!ELEMENT TITLE - - ( //PCDATA)* -(%head.misc)> case Ttitle: di->doctitle = getpcdata(toks, tokslen, &toki); if(warn && toki < tokslen - 1 && toks[toki + 1].tag != Ttitle + RBRA) fprint(2, "warning: <TITLE> data ended by %T\n", &toks[toki + 1]); break; // <!ELEMENT TR - O (TH|TD)+> // rows are accumulated in reverse order in curtab->rows case Ttr: if(curtab == nil) { if(warn) fprint(2, "warning: <TR> outside <TABLE>\n"); continue; } if(ps->inpar) { popjust(ps); ps->inpar = 0; } ps = finishcell(curtab, ps); if(curtab->rows != nil) curtab->rows->flags = 0; curtab->rows = newtablerow(aalign(tok), makebackground(nil, acolorval(tok, Abgcolor, curtab->background.color)), TFparsing, curtab->rows); break; case Ttr+RBRA: if(curtab == nil || curtab->rows == nil) { if(warn) fprint(2, "warning: unexpected </TR>\n"); continue; } ps = finishcell(curtab, ps); tr = curtab->rows; if(tr->cells == nil) { if(warn) fprint(2, "warning: empty row\n"); curtab->rows = tr->next; tr->next = nil; } else tr->flags = 0; break; // <!ELEMENT (TT|CODE|KBD|SAMP) - - (%text)*> case Ttt: case Tcode: case Tkbd: case Tsamp: pushfontstyle(ps, FntT); break; // Tags that have empty action case Tabbr: case Tabbr+RBRA: case Tacronym: case Tacronym+RBRA: case Tarea+RBRA: case Tbase+RBRA: case Tbasefont+RBRA: case Tbr+RBRA: case Tdd+RBRA: case Tdt+RBRA: case Tframe+RBRA: case Thr+RBRA: case Thtml: case Thtml+RBRA: case Timg+RBRA: case Tinput+RBRA: case Tisindex+RBRA: case Tli+RBRA: case Tlink: case Tlink+RBRA: case Tmeta+RBRA: case Toption+RBRA: case Tparam+RBRA: case Ttextarea+RBRA: case Ttitle+RBRA: break; // Tags not implemented case Tbdo: case Tbdo+RBRA: case Tbutton: case Tbutton+RBRA: case Tdel: case Tdel+RBRA: case Tfieldset: case Tfieldset+RBRA: case Tiframe: case Tiframe+RBRA: case Tins: case Tins+RBRA: case Tlabel: case Tlabel+RBRA: case Tlegend: case Tlegend+RBRA: case Tobject: case Tobject+RBRA: case Toptgroup: case Toptgroup+RBRA: case Tspan: case Tspan+RBRA: if(warn) { if(tag > RBRA) tag -= RBRA; fprint(2, "warning: unimplemented HTML tag: %S\n", tagnames[tag]); } break; default: if(warn) fprint(2, "warning: unknown HTML tag: %S\n", tok->text); break; } } // some pages omit trailing </table> while(curtab != nil) { if(warn) fprint(2, "warning: <TABLE> not closed\n"); if(curtab->cells != nil) { ps = finishcell(curtab, ps); if(curtab->cells == nil) { if(warn) fprint(2, "warning: empty table\n"); } else { if(curtab->rows != nil) curtab->rows->flags = 0; finish_table(curtab); ps->skipping = 0; additem(ps, newitable(curtab), curtab->tabletok); addbrk(ps, 0, 0); } } if(is->tabstk != nil) is->tabstk = is->tabstk->next; curtab->next = di->tables; di->tables = curtab; curtab = is->tabstk; } outerps = lastps(ps); ans = outerps->items->next; freeitem(outerps->items); // note: ans may be nil and di->kids not nil, if there's a frameset! outerps->items = newispacer(ISPnull); outerps->lastit = outerps->items; is->psstk = ps; if(ans != nil && di->hasscripts) { // TODO evalscript(nil); ; }return_ans: if(dbgbuild) { assert(validitems(ans)); if(ans == nil) fprint(2, "getitems returning nil\n"); else printitems(ans, "getitems returning:"); } return ans;}// Concatenate together maximal set of Data tokens, starting at toks[toki+1].// Lexer has ensured that there will either be a following non-data token or// we will be at eof.// Return emallocd trimmed concatenation, and update *ptoki to last used tokistatic Rune*getpcdata(Token* toks, int tokslen, int* ptoki){ Rune* ans; Rune* p; Rune* trimans; int anslen; int trimanslen; int toki; Token* tok; ans = nil; anslen = 0; // first find length of answer toki = (*ptoki) + 1; while(toki < tokslen) { tok = &toks[toki]; if(tok->tag == Data) { toki++; anslen += _Strlen(tok->text); } else break; } // now make up the initial answer if(anslen > 0) { ans = _newstr(anslen); p = ans; toki = (*ptoki) + 1; while(toki < tokslen) { tok = &toks[toki]; if(tok->tag == Data) { toki++; p = _Stradd(p, tok->text, _Strlen(tok->text)); } else break; } *p = 0; _trimwhite(ans, anslen, &trimans, &trimanslen); if(trimanslen != anslen) { p = ans; ans = _Strndup(trimans, trimanslen); free(p); } } *ptoki = toki-1; return ans;}// If still parsing head of curtab->cells list, finish it off// by transferring the items on the head of psstk to the cell.// Then pop the psstk and return the new psstk.static Pstate*finishcell(Table* curtab, Pstate* psstk){ Tablecell* c; Pstate* psstknext; c = curtab->cells; if(c != nil) { if((c->flags&TFparsing)) { psstknext = psstk->next; if(psstknext == nil) { if(warn) fprint(2, "warning: parse state stack is wrong\n"); } else { c->content = psstk->items->next; c->flags &= ~TFparsing; freepstate(psstk); psstk = psstknext; } } } return psstk;}// Make a new Pstate for a cell, based on the old pstate, oldps.// Also, put the new ps on the head of the oldps stack.static Pstate*cell_pstate(Pstate* oldps, int ishead){ Pstate* ps; int sty; ps = newpstate(oldps); ps->skipwhite = 1; ps->curanchor = oldps->curanchor; copystack(&ps->fntstylestk, &oldps->fntstylestk); copystack(&ps->fntsizestk, &oldps->fntsizestk); ps->curfont = oldps->curfont; ps->curfg = oldps->curfg; ps->curbg = oldps->curbg; copystack(&ps->fgstk, &oldps->fgstk); ps->adjsize = oldps->adjsize; if(ishead) { sty = ps->curfont%NumSize; ps->curfont = FntB*NumSize + sty; } return ps;}// Return a new Pstate with default starting state.// Use link to add it to head of a list, if any.static Pstate*newpstate(Pstate* link){ Pstate* ps; ps = (Pstate*)emalloc(sizeof(Pstate)); ps->curfont = DefFnt; ps->curfg = Black; ps->curbg.image = nil; ps->curbg.color = White; ps->curul = ULnone; ps->curjust = ALleft; ps->curstate = IFwrap; ps->items = newispacer(ISPnull); ps->lastit = ps->items; ps->prelastit = nil; ps->next = link; return ps;}// Return last Pstate on psl liststatic Pstate*lastps(Pstate* psl){ assert(psl != nil); while(psl->next != nil) psl = psl->next; return psl;}// Add it to end of ps item chain, adding in current state from ps.// Also, if tok is not nil, scan it for generic attributes and assign// the genattr field of the item accordingly.static voidadditem(Pstate* ps, Item* it, Token* tok){ int aid; int any; Rune* i; Rune* c; Rune* s; Rune* t; Attr* a; SEvent* e; if(ps->skipping) { if(warn) fprint(2, "warning: skipping item: %I\n", it); return; } it->anchorid = ps->curanchor; it->state |= ps->curstate; if(tok != nil) { any = 0; i = nil; c = nil; s = nil; t = nil; e = nil; for(a = tok->attr; a != nil; a = a->next) { aid = a->attid; if(!attrinfo[aid]) continue; switch(aid) { case Aid: i = a->value; break; case Aclass: c = a->value; break; case Astyle: s = a->value; break; case Atitle: t = a->value; break; default: assert(aid >= Aonblur && aid <= Aonunload); e = newscriptevent(scriptev[a->attid], a->value, e); break; } a->value = nil; any = 1; } if(any) it->genattr = newgenattr(i, c, s, t, e); } ps->curstate &= ~(IFbrk|IFbrksp|IFnobrk|IFcleft|IFcright); ps->prelastit = ps->lastit; ps->lastit->next = it; ps->lastit = it;}// Make a text item out of s,// using current font, foreground, vertical offset and underline state.static Item*textit(Pstate* ps, Rune* s){ assert(s != nil); return newitext(s, ps->curfont, ps->curfg, ps->curvoff + Voffbias, ps->curul);}// Add text item or items for s, paying attention to// current font, foreground, baseline offset, underline state,// and literal mode. Unless we're in literal mode, compress// whitespace to single blank, and, if curstate has a break,// trim any leading whitespace. Whether in literal mode or not,// turn nonbreaking spaces into spacer items with IFnobrk set.//// In literal mode, break up s at newlines and add breaks instead.// Also replace tabs appropriate number of spaces.// In nonliteral mode, break up the items every 100 or so characters// just to make the layout algorithm not go quadratic.//// addtext assumes ownership of s.static voidaddtext(Pstate* ps, Rune* s){ int n; int i; int j; int k; int col; int c; int nsp; Item* it; Rune* ss; Rune* p; Rune buf[SMALLBUFSIZE]; assert(s != nil); n = runestrlen(s); i = 0; j = 0; if(ps->literal) { col = 0; while(i < n) { if(s[i] == '\n') { if(i > j) { // trim trailing blanks from line for(k = i; k > j; k--) if(s[k - 1] != ' ') break; if(k > j) additem(ps, textit(ps, _Strndup(s+j, k-j)), nil); } addlinebrk(ps, 0); j = i + 1; col = 0; } else { if(s[i] == '\t') { col += i - j; nsp = 8 - (col%8); // make ss = s[j:i] + nsp spaces ss = _newstr(i-j+nsp); p = _Stradd(ss, s+j, i-j); p = _Stradd(p, L" ", nsp); *p = 0; additem(ps, textit(ps, ss), nil); col += nsp; j = i + 1; } else if(s[i] == NBSP) { if(i > j) additem(ps, textit(ps, _Strndup(s+j, i-j)), nil); addnbsp(ps); col += (i - j) + 1; j = i + 1; } } i++; } if(i > j) { if(j == 0 && i == n) { // just transfer s over additem(ps, textit(ps, s), nil); } else { additem(ps, textit(ps, _Strndup(s+j, i-j)), nil); free(s); } } } else { // not literal mode if((ps->curstate&IFbrk) || ps->lastit == ps->items) while(i < n) { c = s[i]; if(c >= 256 || !isspace(c)) break; i++; } p = buf; for(j = i; i < n; i++) { assert(p+i-j < buf+SMALLBUFSIZE-1); c = s[i]; if(c == NBSP) { if(i > j) p = _Stradd(p, s+j, i-j); if(p > buf)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?