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