968 lines · 14.4 KB · C
RawDownload
#include <u.h>#include <libc.h>#include <ctype.h>#include <bio.h> typedef struct Tag Tag;typedef struct Attr Attr;typedef struct Text Text; struct Attr {	char	attr[64];	char	val[256-64];}; struct Tag {	Tag	*up;	char	tag[32];	Attr	attr[16];	int	nattr;	int	opening;	int	closing; 	void	(*close)(Text *, Tag *);	union {		void	*aux;	};}; struct Text {	char*	fontstyle;	char*	fontsize;	int	pre;	int	pos;	int	space;	int	output; 	char	*bp;	char	*wp;	int	nb;}; void eatwhite(void);void parsetext(Text *, Tag *);int parsetag(Tag *);int parseattr(Attr *);void flushtext(Text *);char* getattr(Tag *, char *);int gotattr(Tag *, char *, char *);int gotstyle(Tag *, char *, char *);void reparent(Text *, Tag *, Tag *);void debugtag(Tag *, char *); Biobuf in; voidemitbuf(Text *text, char *buf, int nbuf){	int nw; 	nw = text->wp - text->bp;	if((text->nb - nw) < nbuf){		if(nbuf < 4096)			text->nb = nw + 4096;		else			text->nb = nw + nbuf;		text->bp = realloc(text->bp, text->nb);		text->wp = text->bp + nw;	}	memmove(text->wp, buf, nbuf);	text->wp += nbuf;} voidemitrune(Text *text, Rune r){	char buf[UTFmax+1]; 	if(r == '\r' || r =='\n'){		text->pos = 0;		text->space = 0;	}else		text->pos++;	emitbuf(text, buf, runetochar(buf, &r));} voidemit(Text *text, char *fmt, ...){	Rune buf[64];	va_list a;	int i; 	if(fmt[0] == '.' && text->pos)		emitrune(text, '\n');	va_start(a, fmt);	runevsnprint(buf, nelem(buf), fmt, a);	va_end(a);	for(i=0; buf[i]; i++)		emitrune(text, buf[i]);} voidrestoreoutput(Text *text, Tag *){	text->output = 1;} voidongarbage(Text *text, Tag *tag){	if(text->output == 0)		return;	tag->close = restoreoutput;	text->output = 0;} voidonmeta(Text *, Tag *tag){	tag->closing = 1;} voidonp(Text *text, Tag *){	emit(text, ".LP\n");} voidrestorepre(Text *text, Tag *){	text->pre = 0;	emit(text, ".DE\n");} voidonpre(Text *text, Tag *tag){	if(text->pre)		return;	tag->close = restorepre;	text->pre = 1;	emit(text, ".DS L\n");} voidonli(Text *text, Tag *tag){	if(tag->up && cistrcmp(tag->up->tag, "ol") == 0)		emit(text, ".IP\n");	else		emit(text, ".IP \\(bu\n");	if(tag->up)		tag->up->close = onp;} voidonh(Text *text, Tag *tag){	emit(text, ".SH\n");	tag->close = onp;} voidonbr(Text *text, Tag *tag){	tag->closing = 1;	emit(text, ".br\n");	if(cistrcmp(tag->tag, "hr") == 0)		emit(text, "\\l'5i'\n.br\n");} voidfontstyle(Text *text, char *style){	if(strcmp(text->fontstyle, style) == 0)		return;	text->fontstyle = style;	emit(text, "\\f%s", style);} voidfontsize(Text *text, char *size){	if(strcmp(text->fontsize, size) == 0)		return;	text->fontsize = size;	emit(text, ".%s\n", size);} voidrestorefontstyle(Text *text, Tag *tag){	fontstyle(text, tag->aux);} voidrestorefontsize(Text *text, Tag *tag){	fontsize(text, tag->aux);} voidoni(Text *text, Tag *tag){	tag->aux = text->fontstyle;	tag->close = restorefontstyle;	fontstyle(text, "I");} voidonb(Text *text, Tag *tag){	tag->aux = text->fontstyle;	tag->close = restorefontstyle;	fontstyle(text, "B");} void onsmall(Text *text, Tag *tag);void onsup(Text *text, Tag *tag); voidonsub(Text *text, Tag *tag){	emit(text, "\\v\'0.5\'");	if(cistrcmp(tag->tag, "sub") == 0){		emit(text, "\\x\'0.5\'");		onsmall(text, tag);	} else		restorefontsize(text, tag);	tag->close = onsup;} voidonsup(Text *text, Tag *tag){	emit(text, "\\v\'-0.5\'");	if(cistrcmp(tag->tag, "sup") == 0){		emit(text, "\\x\'-0.5\'");		onsmall(text, tag);	}else		restorefontsize(text, tag);	tag->close = onsub;} /* * this is poor mans CSS handler. */voidonspan(Text *text, Tag *tag){	Attr *a; 	if(!tag->opening)		return; 	for(a=tag->attr; a < tag->attr+tag->nattr; a++){		if(cistrcmp(a->attr, "class") != 0)			continue; 		if(cistrcmp(a->val, "bold") == 0){			onb(text, tag);			return;		}		if(cistrcmp(a->val, "italic") == 0){			oni(text, tag);			return;		}		if(cistrcmp(a->val, "subscript") == 0){			strcpy(tag->tag, "sub");			onsub(text, tag);			strcpy(tag->tag, "span");			return;		}		if(cistrcmp(a->val, "superscript") == 0){			strcpy(tag->tag, "sup");			onsup(text, tag);			strcpy(tag->tag, "span");			return;		}	}} voidontt(Text *text, Tag *tag){	tag->aux = text->fontstyle;	tag->close = restorefontstyle;	fontstyle(text, "C");} voidonsmall(Text *text, Tag *tag){	tag->aux = text->fontsize;	tag->close = restorefontsize;	fontsize(text, "SM");} voidonbig(Text *text, Tag *tag){	tag->aux = text->fontsize;	tag->close = restorefontsize;	fontsize(text, "LG");} voidendquote(Text *text, Tag *tag){	if(cistrcmp(tag->tag, "q") == 0)		emitrune(text, '"');	emit(text, ".QE\n");} voidonquote(Text *text, Tag *tag){	tag->close = endquote;	if(cistrcmp(tag->tag, "q") == 0)		emit(text, ".QS\n\"");	else		emit(text, ".QP\n");} typedef struct Table Table;struct Table{	char	*bp;	int	nb; 	Table	*next;	Table	*prev;	int	enclose;	int	brk; 	char	fmt[4]; 	Text	save;}; Tag*tabletag(Tag *tag){	if(tag == nil)		return nil;	if(cistrcmp(tag->tag, "table") == 0)		return tag;	return tabletag(tag->up);} voiddumprows(Text *text, Table *s, Table *e){		for(; s != e; s = s->next){		if(s->enclose)			emit(text, "T{\n");		if(s->nb <= 0)			emit(text, "\\ ");		else			emitbuf(text, s->bp, s->nb);		if(s->enclose)			emit(text, "\nT}");		emitrune(text, s->brk ? '\n' : '\t');	}} voidendtable(Text *text, Tag *tag){	int i, cols, rows;	Table *t, *h, *s;	Tag *tt; 	/* reverse list */	h = nil;	t = tag->aux; 	for(; t; t = t->prev){		t->next = h;		h = t;	} 	/*	 * nested table case, add our cells to the next table up.	 * this is the best we can do, tbl doesnt support nesting	 */	if(tt = tabletag(tag->up)){		while(t = h){			h = h->next;			t->next = nil;			t->prev = tt->aux;			tt->aux = t;		}		return;	} 	cols = 0;	rows = 0;	for(i = 0, t = h; t; t = t->next){		i++;		if(t->brk){			rows++;			if(i > cols)				cols = i;			i = 0;		}	} 	i = 0; 	for(t = h; t; t = t->next){		i++;		if(t->brk){			while(i < cols){				s = mallocz(sizeof(Table), 1);				strcpy(s->fmt, "L");				s->brk = t->brk;				t->brk = 0;				s->next = t->next;				t->next = s;				i++;			}			break;		}	} 	s = h;	while(s){		emit(text, ".TS\n");		if(gotattr(tag, "align", "center"))			emit(text, "center ;\n");		i = 0;		for(t = s; t; t = t->next){			emit(text, "%s", t->fmt);			if(t->brk){				emitrune(text, '\n');				if(++i > 30){					t = t->next;					break;				}			}else				emitrune(text, ' ');		}		emit(text, ".\n");		dumprows(text, s, t);		emit(text, ".TE\n");		s = t;	} 	while(t = h){		h = t->next;		free(t->bp);		free(t);	}} voidontable(Text *, Tag *tag){	tag->aux = nil;	tag->close = endtable;} voidendcell(Text *text, Tag *tag){	Table *t;	Tag *tt;	int i; 	if((tt = tabletag(tag)) == nil)		return;	if(cistrcmp(tag->tag, "tr") == 0){		if(t = tt->aux)			t->brk = 1;	} else {		t = tag->aux;		t->bp = text->bp;		t->nb = text->wp - text->bp; 		for(i=0; i<t->nb; i++)			if(strchr(" \t\r\n", t->bp[i]) == nil)				break;		if(i > 0){			memmove(t->bp, t->bp+i, t->nb - i);			t->nb -= i;		}		while(t->nb > 0 && strchr(" \t\r\n", t->bp[t->nb-1]))			t->nb--;		if(t->nb < 32){			for(i=0; i<t->nb; i++)				if(strchr("\t\r\n", t->bp[i]))					break;			t->enclose = i < t->nb;		} else {			t->enclose = 1;		}		if(gotstyle(tag, "text-align", "center") || gotstyle(tt, "text-align", "center"))			strcpy(t->fmt, "C");		else

Lines 1–500 of 968.