build.c
来自「这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易」· C语言 代码 · 共 2,670 行 · 第 1/5 页
C
2,670 行
additem(ps, textit(ps, _Strndup(buf, p-buf)), nil); p = buf; addnbsp(ps); j = i + 1; continue; } if(c < 256 && isspace(c)) { if(i > j) p = _Stradd(p, s+j, i-j); *p++ = ' '; while(i < n - 1) { c = s[i + 1]; if(c >= 256 || !isspace(c)) break; i++; } j = i + 1; } if(i - j >= 100) { p = _Stradd(p, s+j, i+1-j); j = i + 1; } if(p-buf >= 100) { additem(ps, textit(ps, _Strndup(buf, p-buf)), nil); p = buf; } } if(i > j && j < n) { assert(p+i-j < buf+SMALLBUFSIZE-1); p = _Stradd(p, s+j, i-j); } // don't add a space if previous item ended in a space if(p-buf == 1 && buf[0] == ' ' && ps->lastit != nil) { it = ps->lastit; if(it->tag == Itexttag) { ss = ((Itext*)it)->s; k = _Strlen(ss); if(k > 0 && ss[k] == ' ') p = buf; } } if(p > buf) additem(ps, textit(ps, _Strndup(buf, p-buf)), nil); free(s); }}// Add a break to ps->curstate, with extra space if sp is true.// If there was a previous break, combine this one's parameters// with that to make the amt be the max of the two and the clr// be the most general. (amt will be 0 or 1)// Also, if the immediately preceding item was a text item,// trim any whitespace from the end of it, if not in literal mode.// Finally, if this is at the very beginning of the item list// (the only thing there is a null spacer), then don't add the space.static voidaddbrk(Pstate* ps, int sp, int clr){ int state; Rune* l; int nl; Rune* r; int nr; Itext* t; Rune* s; state = ps->curstate; clr = clr|(state&(IFcleft|IFcright)); if(sp && !(ps->lastit == ps->items)) sp = IFbrksp; else sp = 0; ps->curstate = IFbrk|sp|(state&~(IFcleft|IFcright))|clr; if(ps->lastit != ps->items) { if(!ps->literal && ps->lastit->tag == Itexttag) { t = (Itext*)ps->lastit; _splitr(t->s, _Strlen(t->s), notwhitespace, &l, &nl, &r, &nr); // try to avoid making empty items // but not crucial f the occasional one gets through if(nl == 0 && ps->prelastit != nil) { ps->lastit = ps->prelastit; ps->lastit->next = nil; ps->prelastit = nil; } else { s = t->s; if(nl == 0) { // need a non-nil pointer to empty string // (_Strdup(L"") returns nil) t->s = emalloc(sizeof(Rune)); t->s[0] = 0; } else t->s = _Strndup(l, nl); if(s) free(s); } } }}// Add break due to a <br> or a newline within a preformatted section.// We add a null item first, with current font's height and ascent, to make// sure that the current line takes up at least that amount of vertical space.// This ensures that <br>s on empty lines cause blank lines, and that// multiple <br>s in a row give multiple blank lines.// However don't add the spacer if the previous item was something that// takes up space itself.static voidaddlinebrk(Pstate* ps, int clr){ int obrkstate; int b; // don't want break before our null item unless the previous item // was also a null item for the purposes of line breaking obrkstate = ps->curstate&(IFbrk|IFbrksp); b = IFnobrk; if(ps->lastit != nil) { if(ps->lastit->tag == Ispacertag) { if(((Ispacer*)ps->lastit)->spkind == ISPvline) b = IFbrk; } } ps->curstate = (ps->curstate&~(IFbrk|IFbrksp))|b; additem(ps, newispacer(ISPvline), nil); ps->curstate = (ps->curstate&~(IFbrk|IFbrksp))|obrkstate; addbrk(ps, 0, clr);}// Add a nonbreakable spacestatic voidaddnbsp(Pstate* ps){ // if nbsp comes right where a break was specified, // do the break anyway (nbsp is being used to generate undiscardable // space rather than to prevent a break) if((ps->curstate&IFbrk) == 0) ps->curstate |= IFnobrk; additem(ps, newispacer(ISPhspace), nil); // but definitely no break on next item ps->curstate |= IFnobrk;}// Change hang in ps.curstate by delta.// The amount is in 1/10ths of tabs, and is the amount that// the current contiguous set of items with a hang value set// is to be shifted left from its normal (indented) place.static voidchangehang(Pstate* ps, int delta){ int amt; amt = (ps->curstate&IFhangmask) + delta; if(amt < 0) { if(warn) fprint(2, "warning: hang went negative\n"); amt = 0; } ps->curstate = (ps->curstate&~IFhangmask)|amt;}// Change indent in ps.curstate by delta.static voidchangeindent(Pstate* ps, int delta){ int amt; amt = ((ps->curstate&IFindentmask) >> IFindentshift) + delta; if(amt < 0) { if(warn) fprint(2, "warning: indent went negative\n"); amt = 0; } ps->curstate = (ps->curstate&~IFindentmask)|(amt << IFindentshift);}// Push val on top of stack, and also return value pushedstatic intpush(Stack* stk, int val){ if(stk->n == Nestmax) { if(warn) fprint(2, "warning: build stack overflow\n"); } else stk->slots[stk->n++] = val; return val;}// Pop top of stackstatic voidpop(Stack* stk){ if(stk->n > 0) --stk->n;}//Return top of stack, using dflt if stack is emptystatic inttop(Stack* stk, int dflt){ if(stk->n == 0) return dflt; return stk->slots[stk->n-1];}// pop, then return new top, with dflt if emptystatic intpopretnewtop(Stack* stk, int dflt){ if(stk->n == 0) return dflt; stk->n--; if(stk->n == 0) return dflt; return stk->slots[stk->n-1];}// Copy fromstk entries into tostkstatic voidcopystack(Stack* tostk, Stack* fromstk){ int n; n = fromstk->n; tostk->n = n; memmove(tostk->slots, fromstk->slots, n*sizeof(int));}static voidpopfontstyle(Pstate* ps){ pop(&ps->fntstylestk); setcurfont(ps);}static voidpushfontstyle(Pstate* ps, int sty){ push(&ps->fntstylestk, sty); setcurfont(ps);}static voidpopfontsize(Pstate* ps){ pop(&ps->fntsizestk); setcurfont(ps);}static voidpushfontsize(Pstate* ps, int sz){ push(&ps->fntsizestk, sz); setcurfont(ps);}static voidsetcurfont(Pstate* ps){ int sty; int sz; sty = top(&ps->fntstylestk, FntR); sz = top(&ps->fntsizestk, Normal); if(sz < Tiny) sz = Tiny; if(sz > Verylarge) sz = Verylarge; ps->curfont = sty*NumSize + sz;}static voidpopjust(Pstate* ps){ pop(&ps->juststk); setcurjust(ps);}static voidpushjust(Pstate* ps, int j){ push(&ps->juststk, j); setcurjust(ps);}static voidsetcurjust(Pstate* ps){ int j; int state; j = top(&ps->juststk, ALleft); if(j != ps->curjust) { ps->curjust = j; state = ps->curstate; state &= ~(IFrjust|IFcjust); if(j == ALcenter) state |= IFcjust; else if(j == ALright) state |= IFrjust; ps->curstate = state; }}// Do final rearrangement after table parsing is finished// and assign cells to grid pointsstatic voidfinish_table(Table* t){ int ncol; int nrow; int r; Tablerow* rl; Tablecell* cl; int* rowspancnt; Tablecell** rowspancell; int ri; int ci; Tablecell* c; Tablecell* cnext; Tablerow* row; Tablerow* rownext; int rcols; int newncol; int k; int j; int cspan; int rspan; int i; rl = t->rows; t->nrow = nrow = _listlen((List*)rl); t->rows = (Tablerow*)emalloc(nrow * sizeof(Tablerow)); ncol = 0; r = nrow - 1; for(row = rl; row != nil; row = rownext) { // copy the data from the allocated Tablerow into the array slot t->rows[r] = *row; rownext = row->next; row = &t->rows[r]; r--; rcols = 0; c = row->cells; // If rowspan is > 1 but this is the last row, // reset the rowspan if(c != nil && c->rowspan > 1 && r == nrow-2) c->rowspan = 1; // reverse row->cells list (along nextinrow pointers) row->cells = nil; while(c != nil) { cnext = c->nextinrow; c->nextinrow = row->cells; row->cells = c; rcols += c->colspan; c = cnext; } if(rcols > ncol) ncol = rcols; } t->ncol = ncol; t->cols = (Tablecol*)emalloc(ncol * sizeof(Tablecol)); // Reverse cells just so they are drawn in source order. // Also, trim their contents so they don't end in whitespace. t->cells = (Tablecell*)_revlist((List*)t->cells); for(c = t->cells; c != nil; c= c->next) trim_cell(c); t->grid = (Tablecell***)emalloc(nrow * sizeof(Tablecell**)); for(i = 0; i < nrow; i++) t->grid[i] = (Tablecell**)emalloc(ncol * sizeof(Tablecell*)); // The following arrays keep track of cells that are spanning // multiple rows; rowspancnt[i] is the number of rows left // to be spanned in column i. // When done, cell's (row,col) is upper left grid point. rowspancnt = (int*)emalloc(ncol * sizeof(int)); rowspancell = (Tablecell**)emalloc(ncol * sizeof(Tablecell*)); for(ri = 0; ri < nrow; ri++) { row = &t->rows[ri]; cl = row->cells; ci = 0; while(ci < ncol || cl != nil) { if(ci < ncol && rowspancnt[ci] > 0) { t->grid[ri][ci] = rowspancell[ci]; rowspancnt[ci]--; ci++; } else { if(cl == nil) { ci++; continue; } c = cl; cl = cl->nextinrow; cspan = c->colspan; rspan = c->rowspan; if(ci + cspan > ncol) { // because of row spanning, we calculated // ncol incorrectly; adjust it newncol = ci + cspan; t->cols = (Tablecol*)erealloc(t->cols, newncol * sizeof(Tablecol)); rowspancnt = (int*)erealloc(rowspancnt, newncol * sizeof(int)); rowspancell = (Tablecell**)erealloc(rowspancell, newncol * sizeof(Tablecell*)); k = newncol-ncol; memset(t->cols+ncol, 0, k*sizeof(Tablecol)); memset(rowspancnt+ncol, 0, k*sizeof(int)); memset(rowspancell+ncol, 0, k*sizeof(Tablecell*)); for(j = 0; j < nrow; j++) { t->grid[j] = (Tablecell**)erealloc(t->grid[j], newncol * sizeof(Tablecell*)); memset(t->grid[j], 0, k*sizeof(Tablecell*)); } t->ncol = ncol = newncol; } c->row = ri; c->col = ci; for(i = 0; i < cspan; i++) { t->grid[ri][ci] = c; if(rspan > 1) { rowspancnt[ci] = rspan - 1; rowspancell[ci] = c; } ci++; } } } } free(rowspancnt); free(rowspancell);}// Remove tail of cell content until it isn't whitespace.static voidtrim_cell(Tablecell* c){ int dropping; Rune* s; Rune* x; Rune* y; int nx; int ny; Item* p; Itext* q; Item* pprev; dropping = 1; while(c->content != nil && dropping) { p = c->content; pprev = nil; while(p->next != nil) { pprev = p; p = p->next; } dropping = 0; if(!(p->state&IFnobrk)) { if(p->tag == Itexttag) { q = (Itext*)p; s = q->s; _splitr(s, _Strlen(s), notwhitespace, &x, &nx, &y, &ny); if(nx != 0 && ny != 0) { q->s = _Strndup(x, nx); free(s); } break; } } if(dropping) { if(pprev == nil) c->content = nil; else pprev->next = nil; freeitem(p); } }}// Caller must free answer (eventually).static Rune*listmark(uchar ty, int n){ Rune* s; Rune* t; int n2; int i; s = nil; switch(ty) { case LTdisc: case LTsquare: case LTcircle: s = _newstr(1); s[0] = (ty == LTdisc)? 0x2022 // bullet : ((ty == LTsquare)? 0x220e // filled square : 0x2218); // degree s[1] = 0; break; case LT1: t = _ltoStr(n); n2 = _Strlen(t); s = _newstr(n2+1); t = _Stradd(s, t, n2); *t++ = '.'; *t = 0; break; case LTa: case LTA: n--; i = 0; if(n < 0) n = 0; s = _newstr((n <= 25)? 2 : 3); if(n > 25) { n2 = n%26; n /= 26; if(n2 > 25) n2 = 25; s[i++] = n2 + (ty == LTa)? 'a' : 'A'; } s[i++] = n + (ty == LTa)? 'a' : 'A'; s[i++] = '.'; s[i] = 0; break; case LTi: case LTI: if(n >= NROMAN) { if(warn) fprint(2, "warning: unimplemented roman number > %d\n", NROMAN);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?