xref: /plan9/sys/src/cmd/html2ms.c (revision 6f8e93f6894df6375fc490745e7cb8df51855166)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <ctype.h>
47dd7cddfSDavid du Colombier #include <bio.h>
57dd7cddfSDavid du Colombier 
67dd7cddfSDavid du Colombier enum
77dd7cddfSDavid du Colombier {
87dd7cddfSDavid du Colombier 	SSIZE = 10,
97dd7cddfSDavid du Colombier 
107dd7cddfSDavid du Colombier 	/* list types */
117dd7cddfSDavid du Colombier 	Lordered = 0,
127dd7cddfSDavid du Colombier 	Lunordered,
137dd7cddfSDavid du Colombier 	Lmenu,
147dd7cddfSDavid du Colombier 	Ldir,
157dd7cddfSDavid du Colombier 
167dd7cddfSDavid du Colombier };
177dd7cddfSDavid du Colombier 
187dd7cddfSDavid du Colombier Biobuf in, out;
197dd7cddfSDavid du Colombier int lastc = '\n';
207dd7cddfSDavid du Colombier int inpre = 0;
217dd7cddfSDavid du Colombier 
227dd7cddfSDavid du Colombier /* stack for fonts */
237dd7cddfSDavid du Colombier char *fontstack[SSIZE];
247dd7cddfSDavid du Colombier char *font = "R";
257dd7cddfSDavid du Colombier int fsp;
267dd7cddfSDavid du Colombier 
277dd7cddfSDavid du Colombier /* stack for lists */
287dd7cddfSDavid du Colombier struct
297dd7cddfSDavid du Colombier {
307dd7cddfSDavid du Colombier 	int	type;
317dd7cddfSDavid du Colombier 	int	ord;
327dd7cddfSDavid du Colombier } liststack[SSIZE];
337dd7cddfSDavid du Colombier int lsp;
347dd7cddfSDavid du Colombier 
357dd7cddfSDavid du Colombier int quoting;
367dd7cddfSDavid du Colombier 
377dd7cddfSDavid du Colombier typedef struct Goobie Goobie;
387dd7cddfSDavid du Colombier struct Goobie
397dd7cddfSDavid du Colombier {
407dd7cddfSDavid du Colombier 	char *name;
417dd7cddfSDavid du Colombier 	void (*f)(Goobie*, char*);
427dd7cddfSDavid du Colombier 	void (*ef)(Goobie*, char*);
437dd7cddfSDavid du Colombier };
447dd7cddfSDavid du Colombier 
457dd7cddfSDavid du Colombier void	eatwhite(void);
467dd7cddfSDavid du Colombier void	escape(void);
477dd7cddfSDavid du Colombier 
487dd7cddfSDavid du Colombier typedef void Action(Goobie*, char*);
497dd7cddfSDavid du Colombier 
507dd7cddfSDavid du Colombier Action	g_ignore;
517dd7cddfSDavid du Colombier Action	g_unexpected;
527dd7cddfSDavid du Colombier Action	g_title;
537dd7cddfSDavid du Colombier Action	g_p;
547dd7cddfSDavid du Colombier Action	g_h;
557dd7cddfSDavid du Colombier Action	g_li;
567dd7cddfSDavid du Colombier Action	g_list, g_listend;
577dd7cddfSDavid du Colombier Action	g_pre;
587dd7cddfSDavid du Colombier Action	g_fpush, g_fpop;
597dd7cddfSDavid du Colombier Action	g_indent, g_exdent;
607dd7cddfSDavid du Colombier Action	g_dt;
617dd7cddfSDavid du Colombier Action	g_display;
627dd7cddfSDavid du Colombier Action	g_displayend;
637dd7cddfSDavid du Colombier Action	g_table, g_tableend, g_caption, g_captionend;
647dd7cddfSDavid du Colombier Action	g_br, g_hr;
657dd7cddfSDavid du Colombier 
667dd7cddfSDavid du Colombier Goobie gtab[] =
677dd7cddfSDavid du Colombier {
687dd7cddfSDavid du Colombier 	"!--",		g_ignore,	g_unexpected,
697dd7cddfSDavid du Colombier 	"!doctype",	g_ignore,	g_unexpected,
707dd7cddfSDavid du Colombier 	"a",		g_ignore,	g_ignore,
717dd7cddfSDavid du Colombier 	"address",	g_display,	g_displayend,
727dd7cddfSDavid du Colombier 	"b",		g_fpush,	g_fpop,
737dd7cddfSDavid du Colombier 	"base",		g_ignore,	g_unexpected,
747dd7cddfSDavid du Colombier 	"blink",	g_ignore,	g_ignore,
757dd7cddfSDavid du Colombier 	"blockquote",	g_ignore,	g_ignore,
767dd7cddfSDavid du Colombier 	"body",		g_ignore,	g_ignore,
777dd7cddfSDavid du Colombier 	"br",		g_br,		g_unexpected,
787dd7cddfSDavid du Colombier 	"caption",	g_caption,	g_captionend,
797dd7cddfSDavid du Colombier 	"center",	g_ignore,	g_ignore,
807dd7cddfSDavid du Colombier 	"cite",		g_ignore,	g_ignore,
817dd7cddfSDavid du Colombier 	"code",		g_ignore,	g_ignore,
827dd7cddfSDavid du Colombier 	"dd",		g_ignore,	g_unexpected,
837dd7cddfSDavid du Colombier 	"dfn",		g_ignore,	g_ignore,
847dd7cddfSDavid du Colombier 	"dir",		g_list,		g_listend,
85*6f8e93f6SDavid du Colombier 	"div",		g_ignore,		g_br,
867dd7cddfSDavid du Colombier 	"dl",		g_indent,	g_exdent,
877dd7cddfSDavid du Colombier 	"dt",		g_dt,		g_unexpected,
887dd7cddfSDavid du Colombier 	"em",		g_ignore,	g_ignore,
897dd7cddfSDavid du Colombier 	"font",		g_ignore,	g_ignore,
907dd7cddfSDavid du Colombier 	"form",		g_ignore,	g_ignore,
917dd7cddfSDavid du Colombier 	"h1",		g_h,		g_p,
927dd7cddfSDavid du Colombier 	"h2",		g_h,		g_p,
937dd7cddfSDavid du Colombier 	"h3",		g_h,		g_p,
947dd7cddfSDavid du Colombier 	"h4",		g_h,		g_p,
957dd7cddfSDavid du Colombier 	"h5",		g_h,		g_p,
967dd7cddfSDavid du Colombier 	"h6",		g_h,		g_p,
977dd7cddfSDavid du Colombier 	"head",		g_ignore,	g_ignore,
987dd7cddfSDavid du Colombier 	"hr",		g_hr,		g_unexpected,
997dd7cddfSDavid du Colombier 	"html",		g_ignore,	g_ignore,
1007dd7cddfSDavid du Colombier 	"i",		g_fpush,	g_fpop,
1017dd7cddfSDavid du Colombier 	"input",	g_ignore,	g_unexpected,
1027dd7cddfSDavid du Colombier 	"img",		g_ignore,	g_unexpected,
1037dd7cddfSDavid du Colombier 	"isindex",	g_ignore,	g_unexpected,
1047dd7cddfSDavid du Colombier 	"kbd",		g_fpush,	g_fpop,
1057dd7cddfSDavid du Colombier 	"key",		g_ignore,	g_ignore,
1067dd7cddfSDavid du Colombier 	"li",		g_li,		g_unexpected,
1077dd7cddfSDavid du Colombier 	"link",		g_ignore,	g_unexpected,
1087dd7cddfSDavid du Colombier 	"listing",	g_ignore,	g_ignore,
1097dd7cddfSDavid du Colombier 	"menu",		g_list,		g_listend,
1107dd7cddfSDavid du Colombier 	"meta",		g_ignore,	g_unexpected,
1117dd7cddfSDavid du Colombier 	"nextid",	g_ignore,	g_unexpected,
1127dd7cddfSDavid du Colombier 	"ol",		g_list,		g_listend,
1137dd7cddfSDavid du Colombier 	"option",	g_ignore,	g_unexpected,
1147dd7cddfSDavid du Colombier 	"p",		g_p,		g_ignore,
1157dd7cddfSDavid du Colombier 	"plaintext",	g_ignore,	g_unexpected,
1167dd7cddfSDavid du Colombier 	"pre",		g_pre,		g_displayend,
1177dd7cddfSDavid du Colombier 	"samp",		g_ignore,	g_ignore,
118*6f8e93f6SDavid du Colombier 	"script",	g_ignore,	g_ignore,
1197dd7cddfSDavid du Colombier 	"select",	g_ignore,	g_ignore,
120*6f8e93f6SDavid du Colombier 	"span",		g_ignore,	g_ignore,
1217dd7cddfSDavid du Colombier 	"strong",	g_ignore,	g_ignore,
1227dd7cddfSDavid du Colombier 	"table",	g_table,	g_tableend,
1237dd7cddfSDavid du Colombier 	"textarea",	g_ignore,	g_ignore,
1247dd7cddfSDavid du Colombier 	"title",	g_title,	g_ignore,
1257dd7cddfSDavid du Colombier 	"tt",		g_fpush,	g_fpop,
1267dd7cddfSDavid du Colombier 	"u",		g_ignore,	g_ignore,
1277dd7cddfSDavid du Colombier 	"ul",		g_list,		g_listend,
1287dd7cddfSDavid du Colombier 	"var",		g_ignore,	g_ignore,
1297dd7cddfSDavid du Colombier 	"xmp",		g_ignore,	g_ignore,
1307dd7cddfSDavid du Colombier 	0,		0,	0,
1317dd7cddfSDavid du Colombier };
1327dd7cddfSDavid du Colombier 
1337dd7cddfSDavid du Colombier typedef struct Entity Entity;
1347dd7cddfSDavid du Colombier struct Entity
1357dd7cddfSDavid du Colombier {
1367dd7cddfSDavid du Colombier 	char *name;
1377dd7cddfSDavid du Colombier 	Rune value;
1387dd7cddfSDavid du Colombier };
1397dd7cddfSDavid du Colombier 
1407dd7cddfSDavid du Colombier Entity pl_entity[]=
1417dd7cddfSDavid du Colombier {
1427dd7cddfSDavid du Colombier "#SPACE", L' ', "#RS",   L'\n', "#RE",   L'\r', "quot",   L'"',
1437dd7cddfSDavid du Colombier "AElig",  L'Æ', "Aacute", L'Á', "Acirc",  L'Â', "Agrave", L'À', "Aring",  L'Å',
1447dd7cddfSDavid du Colombier "Atilde", L'Ã', "Auml",   L'Ä', "Ccedil", L'Ç', "ETH",    L'Ð', "Eacute", L'É',
1457dd7cddfSDavid du Colombier "Ecirc",  L'Ê', "Egrave", L'È', "Euml",   L'Ë', "Iacute", L'Í', "Icirc",  L'Î',
1467dd7cddfSDavid du Colombier "Igrave", L'Ì', "Iuml",   L'Ï', "Ntilde", L'Ñ', "Oacute", L'Ó', "Ocirc",  L'Ô',
1477dd7cddfSDavid du Colombier "Ograve", L'Ò', "Oslash", L'Ø', "Otilde", L'Õ', "Ouml",   L'Ö', "THORN",  L'Þ',
1487dd7cddfSDavid du Colombier "Uacute", L'Ú', "Ucirc",  L'Û', "Ugrave", L'Ù', "Uuml",   L'Ü', "Yacute", L'Ý',
1497dd7cddfSDavid du Colombier "aacute", L'á', "acirc",  L'â', "aelig",  L'æ', "agrave", L'à', "amp",    L'&',
1507dd7cddfSDavid du Colombier "aring",  L'å', "atilde", L'ã', "auml",   L'ä', "ccedil", L'ç', "eacute", L'é',
1517dd7cddfSDavid du Colombier "ecirc",  L'ê', "egrave", L'è', "eth",    L'ð', "euml",   L'ë', "gt",     L'>',
1527dd7cddfSDavid du Colombier "iacute", L'í', "icirc",  L'î', "igrave", L'ì', "iuml",   L'ï', "lt",     L'<',
153*6f8e93f6SDavid du Colombier "nbsp", L' ',
1547dd7cddfSDavid du Colombier "ntilde", L'ñ', "oacute", L'ó', "ocirc",  L'ô', "ograve", L'ò', "oslash", L'ø',
1557dd7cddfSDavid du Colombier "otilde", L'õ', "ouml",   L'ö', "szlig",  L'ß', "thorn",  L'þ', "uacute", L'ú',
1567dd7cddfSDavid du Colombier "ucirc",  L'û', "ugrave", L'ù', "uuml",   L'ü', "yacute", L'ý', "yuml",   L'ÿ',
1577dd7cddfSDavid du Colombier 0
1587dd7cddfSDavid du Colombier };
1597dd7cddfSDavid du Colombier 
1607dd7cddfSDavid du Colombier int
cistrcmp(char * a,char * b)1617dd7cddfSDavid du Colombier cistrcmp(char *a, char *b)
1627dd7cddfSDavid du Colombier {
1637dd7cddfSDavid du Colombier 	int c, d;
1647dd7cddfSDavid du Colombier 
1657dd7cddfSDavid du Colombier 	for(;; a++, b++){
1667dd7cddfSDavid du Colombier 		d = tolower(*a);
1677dd7cddfSDavid du Colombier 		c = d - tolower(*b);
1687dd7cddfSDavid du Colombier 		if(c)
1697dd7cddfSDavid du Colombier 			break;
1707dd7cddfSDavid du Colombier 		if(d == 0)
1717dd7cddfSDavid du Colombier 			break;
1727dd7cddfSDavid du Colombier 	}
1737dd7cddfSDavid du Colombier 	return c;
1747dd7cddfSDavid du Colombier }
1757dd7cddfSDavid du Colombier 
1767dd7cddfSDavid du Colombier int
readupto(char * buf,int n,char d,char notme)1777dd7cddfSDavid du Colombier readupto(char *buf, int n, char d, char notme)
1787dd7cddfSDavid du Colombier {
1797dd7cddfSDavid du Colombier 	char *p;
1807dd7cddfSDavid du Colombier 	int c;
1817dd7cddfSDavid du Colombier 
1827dd7cddfSDavid du Colombier 	buf[0] = 0;
1837dd7cddfSDavid du Colombier 	for(p = buf;; p++){
1847dd7cddfSDavid du Colombier 		c = Bgetc(&in);
1857dd7cddfSDavid du Colombier 		if(c < 0){
1867dd7cddfSDavid du Colombier 			*p = 0;
1877dd7cddfSDavid du Colombier 			return -1;
1887dd7cddfSDavid du Colombier 		}
1897dd7cddfSDavid du Colombier 		if(c == notme){
1907dd7cddfSDavid du Colombier 			Bungetc(&in);
1917dd7cddfSDavid du Colombier 			return -1;
1927dd7cddfSDavid du Colombier 		}
1937dd7cddfSDavid du Colombier 		if(c == d){
1947dd7cddfSDavid du Colombier 			*p = 0;
1957dd7cddfSDavid du Colombier 			return 0;
1967dd7cddfSDavid du Colombier 		}
1977dd7cddfSDavid du Colombier 		*p = c;
1987dd7cddfSDavid du Colombier 		if(p == buf + n){
1997dd7cddfSDavid du Colombier 			*p = 0;
2007dd7cddfSDavid du Colombier 			Bprint(&out, "<%s", buf);
2017dd7cddfSDavid du Colombier 			return -1;
2027dd7cddfSDavid du Colombier 		}
2037dd7cddfSDavid du Colombier 	}
2047dd7cddfSDavid du Colombier }
2057dd7cddfSDavid du Colombier 
2067dd7cddfSDavid du Colombier void
dogoobie(void)2077dd7cddfSDavid du Colombier dogoobie(void)
2087dd7cddfSDavid du Colombier {
2097dd7cddfSDavid du Colombier 	char *arg, *type;
2107dd7cddfSDavid du Colombier 	Goobie *g;
2117dd7cddfSDavid du Colombier 	char buf[1024];
2127dd7cddfSDavid du Colombier 	int closing;
2137dd7cddfSDavid du Colombier 
2147dd7cddfSDavid du Colombier 	if(readupto(buf, sizeof(buf), '>', '<') < 0){
2157dd7cddfSDavid du Colombier 		Bprint(&out, "<%s", buf);
2167dd7cddfSDavid du Colombier 		return;
2177dd7cddfSDavid du Colombier 	}
2187dd7cddfSDavid du Colombier 	type = buf;
2197dd7cddfSDavid du Colombier 	if(*type == '/'){
2207dd7cddfSDavid du Colombier 		type++;
2217dd7cddfSDavid du Colombier 		closing = 1;
2227dd7cddfSDavid du Colombier 	} else
2237dd7cddfSDavid du Colombier 		closing = 0;
2247dd7cddfSDavid du Colombier 	arg = strchr(type, ' ');
2257dd7cddfSDavid du Colombier 	if(arg == 0)
2267dd7cddfSDavid du Colombier 		arg = strchr(type, '\r');
2277dd7cddfSDavid du Colombier 	if(arg == 0)
2287dd7cddfSDavid du Colombier 		arg = strchr(type, '\n');
2297dd7cddfSDavid du Colombier 	if(arg)
2307dd7cddfSDavid du Colombier 		*arg++ = 0;
2317dd7cddfSDavid du Colombier 	for(g = gtab; g->name; g++)
2327dd7cddfSDavid du Colombier 		if(cistrcmp(type, g->name) == 0){
2337dd7cddfSDavid du Colombier 			if(closing){
2347dd7cddfSDavid du Colombier 				if(g->ef){
2357dd7cddfSDavid du Colombier 					(*g->ef)(g, arg);
2367dd7cddfSDavid du Colombier 					return;
2377dd7cddfSDavid du Colombier 				}
2387dd7cddfSDavid du Colombier 			} else {
2397dd7cddfSDavid du Colombier 				if(g->f){
2407dd7cddfSDavid du Colombier 					(*g->f)(g, arg);
2417dd7cddfSDavid du Colombier 					return;
2427dd7cddfSDavid du Colombier 				}
2437dd7cddfSDavid du Colombier 			}
2447dd7cddfSDavid du Colombier 		}
2457dd7cddfSDavid du Colombier 	if(closing)
2467dd7cddfSDavid du Colombier 		type--;
2477dd7cddfSDavid du Colombier 	if(arg)
2487dd7cddfSDavid du Colombier 		Bprint(&out, "<%s %s>\n", type, arg);
2497dd7cddfSDavid du Colombier 	else
2507dd7cddfSDavid du Colombier 		Bprint(&out, "<%s>\n", type);
2517dd7cddfSDavid du Colombier }
2527dd7cddfSDavid du Colombier 
2537dd7cddfSDavid du Colombier void
main(void)2547dd7cddfSDavid du Colombier main(void)
2557dd7cddfSDavid du Colombier {
256cb8c047aSDavid du Colombier 	int c, pos;
2577dd7cddfSDavid du Colombier 
2587dd7cddfSDavid du Colombier 	Binit(&in, 0, OREAD);
2597dd7cddfSDavid du Colombier 	Binit(&out, 1, OWRITE);
2607dd7cddfSDavid du Colombier 
261cb8c047aSDavid du Colombier 	pos = 0;
2627dd7cddfSDavid du Colombier 	for(;;){
2637dd7cddfSDavid du Colombier 		c = Bgetc(&in);
2647dd7cddfSDavid du Colombier 		if(c < 0)
2657dd7cddfSDavid du Colombier 			return;
2667dd7cddfSDavid du Colombier 		switch(c){
2677dd7cddfSDavid du Colombier 		case '<':
2687dd7cddfSDavid du Colombier 			dogoobie();
2697dd7cddfSDavid du Colombier 			break;
2707dd7cddfSDavid du Colombier 		case '&':
2717dd7cddfSDavid du Colombier 			escape();
2727dd7cddfSDavid du Colombier 			break;
2737dd7cddfSDavid du Colombier 		case '\r':
274cb8c047aSDavid du Colombier 			pos = 0;
2757dd7cddfSDavid du Colombier 			break;
2767dd7cddfSDavid du Colombier 		case '\n':
2777dd7cddfSDavid du Colombier 			if(quoting){
2787dd7cddfSDavid du Colombier 				Bputc(&out, '"');
2797dd7cddfSDavid du Colombier 				quoting = 0;
2807dd7cddfSDavid du Colombier 			}
2817dd7cddfSDavid du Colombier 			if(lastc != '\n')
2827dd7cddfSDavid du Colombier 				Bputc(&out, '\n');
2837dd7cddfSDavid du Colombier 			/* can't emit leading spaces in filled troff docs */
2847dd7cddfSDavid du Colombier 			if (!inpre)
2857dd7cddfSDavid du Colombier 				eatwhite();
2867dd7cddfSDavid du Colombier 			lastc = c;
2877dd7cddfSDavid du Colombier 			break;
2887dd7cddfSDavid du Colombier 		default:
289cb8c047aSDavid du Colombier 			++pos;
290cb8c047aSDavid du Colombier 			if(!inpre && isascii(c) && isspace(c) && pos > 80){
291cb8c047aSDavid du Colombier 				Bputc(&out, '\n');
292cb8c047aSDavid du Colombier 				eatwhite();
293cb8c047aSDavid du Colombier 				pos = 0;
294cb8c047aSDavid du Colombier 			}else
2957dd7cddfSDavid du Colombier 				Bputc(&out, c);
2967dd7cddfSDavid du Colombier 			lastc = c;
2977dd7cddfSDavid du Colombier 			break;
2987dd7cddfSDavid du Colombier 		}
2997dd7cddfSDavid du Colombier 	}
3007dd7cddfSDavid du Colombier }
3017dd7cddfSDavid du Colombier 
3027dd7cddfSDavid du Colombier void
escape(void)3037dd7cddfSDavid du Colombier escape(void)
3047dd7cddfSDavid du Colombier {
305cb8c047aSDavid du Colombier 	int c;
3067dd7cddfSDavid du Colombier 	Entity *e;
3077dd7cddfSDavid du Colombier 	char buf[8];
3087dd7cddfSDavid du Colombier 
3097dd7cddfSDavid du Colombier 	if(readupto(buf, sizeof(buf), ';', '\n') < 0){
3107dd7cddfSDavid du Colombier 		Bprint(&out, "&%s", buf);
3117dd7cddfSDavid du Colombier 		return;
3127dd7cddfSDavid du Colombier 	}
3137dd7cddfSDavid du Colombier 	for(e = pl_entity; e->name; e++)
3147dd7cddfSDavid du Colombier 		if(strcmp(buf, e->name) == 0){
3157dd7cddfSDavid du Colombier 			Bprint(&out, "%C", e->value);
3167dd7cddfSDavid du Colombier 			return;
3177dd7cddfSDavid du Colombier 		}
318cb8c047aSDavid du Colombier 	if(*buf == '#'){
319cb8c047aSDavid du Colombier 		c = atoi(buf+1);
320cb8c047aSDavid du Colombier 		if(isascii(c) && isprint(c)){
321cb8c047aSDavid du Colombier 			Bputc(&out, c);
322cb8c047aSDavid du Colombier 			return;
323cb8c047aSDavid du Colombier 		}
324cb8c047aSDavid du Colombier 	}
3257dd7cddfSDavid du Colombier 	Bprint(&out, "&%s;", buf);
3267dd7cddfSDavid du Colombier }
3277dd7cddfSDavid du Colombier 
3287dd7cddfSDavid du Colombier /*
3297dd7cddfSDavid du Colombier  * whitespace is not significant to HTML, but newlines
3307dd7cddfSDavid du Colombier  * and leading spaces are significant to troff.
3317dd7cddfSDavid du Colombier  */
3327dd7cddfSDavid du Colombier void
eatwhite(void)3337dd7cddfSDavid du Colombier eatwhite(void)
3347dd7cddfSDavid du Colombier {
3357dd7cddfSDavid du Colombier 	int c;
3367dd7cddfSDavid du Colombier 
3377dd7cddfSDavid du Colombier 	for(;;){
3387dd7cddfSDavid du Colombier 		c = Bgetc(&in);
3397dd7cddfSDavid du Colombier 		if(c < 0)
3407dd7cddfSDavid du Colombier 			break;
3417dd7cddfSDavid du Colombier 		if(!isspace(c)){
3427dd7cddfSDavid du Colombier 			Bungetc(&in);
3437dd7cddfSDavid du Colombier 			break;
3447dd7cddfSDavid du Colombier 		}
3457dd7cddfSDavid du Colombier 	}
3467dd7cddfSDavid du Colombier }
3477dd7cddfSDavid du Colombier 
3487dd7cddfSDavid du Colombier /*
3497dd7cddfSDavid du Colombier  *  print at start of line
3507dd7cddfSDavid du Colombier  */
3517dd7cddfSDavid du Colombier void
printsol(char * fmt,...)3527dd7cddfSDavid du Colombier printsol(char *fmt, ...)
3537dd7cddfSDavid du Colombier {
3547dd7cddfSDavid du Colombier 	va_list arg;
3557dd7cddfSDavid du Colombier 
3567dd7cddfSDavid du Colombier 	if(quoting){
3577dd7cddfSDavid du Colombier 		Bputc(&out, '"');
3587dd7cddfSDavid du Colombier 		quoting = 0;
3597dd7cddfSDavid du Colombier 	}
3607dd7cddfSDavid du Colombier 	if(lastc != '\n')
3617dd7cddfSDavid du Colombier 		Bputc(&out, '\n');
3627dd7cddfSDavid du Colombier 	va_start(arg, fmt);
3639a747e4fSDavid du Colombier 	Bvprint(&out, fmt, arg);
3647dd7cddfSDavid du Colombier 	va_end(arg);
3659a747e4fSDavid du Colombier 	lastc = '\n';
3667dd7cddfSDavid du Colombier }
3677dd7cddfSDavid du Colombier 
3687dd7cddfSDavid du Colombier void
g_ignore(Goobie * g,char * arg)3697dd7cddfSDavid du Colombier g_ignore(Goobie *g, char *arg)
3707dd7cddfSDavid du Colombier {
3717dd7cddfSDavid du Colombier 	USED(g, arg);
3727dd7cddfSDavid du Colombier }
3737dd7cddfSDavid du Colombier 
3747dd7cddfSDavid du Colombier void
g_unexpected(Goobie * g,char * arg)3757dd7cddfSDavid du Colombier g_unexpected(Goobie *g, char *arg)
3767dd7cddfSDavid du Colombier {
3777dd7cddfSDavid du Colombier 	USED(arg);
3787dd7cddfSDavid du Colombier 	fprint(2, "unexpected %s ending\n", g->name);
3797dd7cddfSDavid du Colombier }
3807dd7cddfSDavid du Colombier 
3817dd7cddfSDavid du Colombier void
g_title(Goobie * g,char * arg)3827dd7cddfSDavid du Colombier g_title(Goobie *g, char *arg)
3837dd7cddfSDavid du Colombier {
3847dd7cddfSDavid du Colombier 	USED(arg);
3857dd7cddfSDavid du Colombier 	printsol(".TL\n", g->name);
3867dd7cddfSDavid du Colombier }
3877dd7cddfSDavid du Colombier 
3887dd7cddfSDavid du Colombier void
g_p(Goobie * g,char * arg)3897dd7cddfSDavid du Colombier g_p(Goobie *g, char *arg)
3907dd7cddfSDavid du Colombier {
3917dd7cddfSDavid du Colombier 	USED(arg);
3927dd7cddfSDavid du Colombier 	printsol(".LP\n", g->name);
3937dd7cddfSDavid du Colombier }
3947dd7cddfSDavid du Colombier 
3957dd7cddfSDavid du Colombier void
g_h(Goobie * g,char * arg)3967dd7cddfSDavid du Colombier g_h(Goobie *g, char *arg)
3977dd7cddfSDavid du Colombier {
3987dd7cddfSDavid du Colombier 	USED(arg);
3997dd7cddfSDavid du Colombier 	printsol(".SH %c\n", g->name[1]);
4007dd7cddfSDavid du Colombier }
4017dd7cddfSDavid du Colombier 
4027dd7cddfSDavid du Colombier void
g_list(Goobie * g,char * arg)4037dd7cddfSDavid du Colombier g_list(Goobie *g, char *arg)
4047dd7cddfSDavid du Colombier {
4057dd7cddfSDavid du Colombier 	USED(arg);
4067dd7cddfSDavid du Colombier 
4077dd7cddfSDavid du Colombier 	if(lsp != SSIZE){
4087dd7cddfSDavid du Colombier 		switch(g->name[0]){
4097dd7cddfSDavid du Colombier 		case 'o':
4107dd7cddfSDavid du Colombier 			liststack[lsp].type  = Lordered;
4117dd7cddfSDavid du Colombier 			liststack[lsp].ord = 0;
4127dd7cddfSDavid du Colombier 			break;
4137dd7cddfSDavid du Colombier 		default:
4147dd7cddfSDavid du Colombier 			liststack[lsp].type = Lunordered;
4157dd7cddfSDavid du Colombier 			break;
4167dd7cddfSDavid du Colombier 		}
4177dd7cddfSDavid du Colombier 	}
4187dd7cddfSDavid du Colombier 	lsp++;
4197dd7cddfSDavid du Colombier }
4207dd7cddfSDavid du Colombier 
4217dd7cddfSDavid du Colombier void
g_br(Goobie * g,char * arg)4227dd7cddfSDavid du Colombier g_br(Goobie *g, char *arg)
4237dd7cddfSDavid du Colombier {
4247dd7cddfSDavid du Colombier 	USED(g, arg);
4257dd7cddfSDavid du Colombier 	printsol(".br\n");
4267dd7cddfSDavid du Colombier }
4277dd7cddfSDavid du Colombier 
4287dd7cddfSDavid du Colombier void
g_li(Goobie * g,char * arg)4297dd7cddfSDavid du Colombier g_li(Goobie *g, char *arg)
4307dd7cddfSDavid du Colombier {
4317dd7cddfSDavid du Colombier 	USED(g, arg);
4327dd7cddfSDavid du Colombier 	if(lsp <= 0 || lsp > SSIZE){
4337dd7cddfSDavid du Colombier 		printsol(".IP \\(bu\n");
4347dd7cddfSDavid du Colombier 		return;
4357dd7cddfSDavid du Colombier 	}
4367dd7cddfSDavid du Colombier 	switch(liststack[lsp-1].type){
4377dd7cddfSDavid du Colombier 	case Lunordered:
4387dd7cddfSDavid du Colombier 		printsol(".IP \\(bu\n");
4397dd7cddfSDavid du Colombier 		break;
4407dd7cddfSDavid du Colombier 	case Lordered:
4417dd7cddfSDavid du Colombier 		printsol(".IP %d\n", ++liststack[lsp-1].ord);
4427dd7cddfSDavid du Colombier 		break;
4437dd7cddfSDavid du Colombier 	}
4447dd7cddfSDavid du Colombier }
4457dd7cddfSDavid du Colombier 
4467dd7cddfSDavid du Colombier void
g_listend(Goobie * g,char * arg)4477dd7cddfSDavid du Colombier g_listend(Goobie *g, char *arg)
4487dd7cddfSDavid du Colombier {
4497dd7cddfSDavid du Colombier 	USED(g, arg);
4507dd7cddfSDavid du Colombier 	if(--lsp < 0)
4517dd7cddfSDavid du Colombier 		lsp = 0;
4527dd7cddfSDavid du Colombier 	printsol(".LP\n");
4537dd7cddfSDavid du Colombier }
4547dd7cddfSDavid du Colombier 
4557dd7cddfSDavid du Colombier void
g_display(Goobie * g,char * arg)4567dd7cddfSDavid du Colombier g_display(Goobie *g, char *arg)
4577dd7cddfSDavid du Colombier {
4587dd7cddfSDavid du Colombier 	USED(g, arg);
4597dd7cddfSDavid du Colombier 	printsol(".DS\n");
4607dd7cddfSDavid du Colombier }
4617dd7cddfSDavid du Colombier 
4627dd7cddfSDavid du Colombier void
g_pre(Goobie * g,char * arg)4637dd7cddfSDavid du Colombier g_pre(Goobie *g, char *arg)
4647dd7cddfSDavid du Colombier {
4657dd7cddfSDavid du Colombier 	USED(g, arg);
4667dd7cddfSDavid du Colombier 	printsol(".DS L\n");
4677dd7cddfSDavid du Colombier 	inpre = 1;
4687dd7cddfSDavid du Colombier }
4697dd7cddfSDavid du Colombier 
4707dd7cddfSDavid du Colombier void
g_displayend(Goobie * g,char * arg)4717dd7cddfSDavid du Colombier g_displayend(Goobie *g, char *arg)
4727dd7cddfSDavid du Colombier {
4737dd7cddfSDavid du Colombier 	USED(g, arg);
4747dd7cddfSDavid du Colombier 	printsol(".DE\n");
4757dd7cddfSDavid du Colombier 	inpre = 0;
4767dd7cddfSDavid du Colombier }
4777dd7cddfSDavid du Colombier 
4787dd7cddfSDavid du Colombier void
g_fpush(Goobie * g,char * arg)4797dd7cddfSDavid du Colombier g_fpush(Goobie *g, char *arg)
4807dd7cddfSDavid du Colombier {
4817dd7cddfSDavid du Colombier 	USED(arg);
4827dd7cddfSDavid du Colombier 	if(fsp < SSIZE)
4837dd7cddfSDavid du Colombier 		fontstack[fsp] = font;
4847dd7cddfSDavid du Colombier 	fsp++;
4857dd7cddfSDavid du Colombier 	switch(g->name[0]){
4867dd7cddfSDavid du Colombier 	case 'b':
4877dd7cddfSDavid du Colombier 		font = "B";
4887dd7cddfSDavid du Colombier 		break;
4897dd7cddfSDavid du Colombier 	case 'i':
4907dd7cddfSDavid du Colombier 		font = "I";
4917dd7cddfSDavid du Colombier 		break;
4927dd7cddfSDavid du Colombier 	case 'k':		/* kbd */
4937dd7cddfSDavid du Colombier 	case 't':		/* tt */
4947dd7cddfSDavid du Colombier 		font = "(CW";
4957dd7cddfSDavid du Colombier 		break;
4967dd7cddfSDavid du Colombier 	}
4977dd7cddfSDavid du Colombier 	Bprint(&out, "\\f%s", font);
4987dd7cddfSDavid du Colombier }
4997dd7cddfSDavid du Colombier 
5007dd7cddfSDavid du Colombier void
g_fpop(Goobie * g,char * arg)5017dd7cddfSDavid du Colombier g_fpop(Goobie *g, char *arg)
5027dd7cddfSDavid du Colombier {
5037dd7cddfSDavid du Colombier 	USED(g, arg);
5047dd7cddfSDavid du Colombier 	fsp--;
5057dd7cddfSDavid du Colombier 	if(fsp < SSIZE)
5067dd7cddfSDavid du Colombier 		font = fontstack[fsp];
5077dd7cddfSDavid du Colombier 	else
5087dd7cddfSDavid du Colombier 		font = "R";
5097dd7cddfSDavid du Colombier 
5107dd7cddfSDavid du Colombier 	Bprint(&out, "\\f%s", font);
5117dd7cddfSDavid du Colombier }
5127dd7cddfSDavid du Colombier 
5137dd7cddfSDavid du Colombier void
g_indent(Goobie * g,char * arg)5147dd7cddfSDavid du Colombier g_indent(Goobie *g, char *arg)
5157dd7cddfSDavid du Colombier {
5167dd7cddfSDavid du Colombier 	USED(g, arg);
5177dd7cddfSDavid du Colombier 	printsol(".RS\n");
5187dd7cddfSDavid du Colombier }
5197dd7cddfSDavid du Colombier 
5207dd7cddfSDavid du Colombier void
g_exdent(Goobie * g,char * arg)5217dd7cddfSDavid du Colombier g_exdent(Goobie *g, char *arg)
5227dd7cddfSDavid du Colombier {
5237dd7cddfSDavid du Colombier 	USED(g, arg);
5247dd7cddfSDavid du Colombier 	printsol(".RE\n");
5257dd7cddfSDavid du Colombier }
5267dd7cddfSDavid du Colombier 
5277dd7cddfSDavid du Colombier void
g_dt(Goobie * g,char * arg)5287dd7cddfSDavid du Colombier g_dt(Goobie *g, char *arg)
5297dd7cddfSDavid du Colombier {
5307dd7cddfSDavid du Colombier 	USED(g, arg);
5317dd7cddfSDavid du Colombier 	printsol(".IP \"");
5327dd7cddfSDavid du Colombier 	quoting = 1;
5337dd7cddfSDavid du Colombier }
5347dd7cddfSDavid du Colombier 
5357dd7cddfSDavid du Colombier void
g_hr(Goobie * g,char * arg)5367dd7cddfSDavid du Colombier g_hr(Goobie *g, char *arg)
5377dd7cddfSDavid du Colombier {
5387dd7cddfSDavid du Colombier 	USED(g, arg);
5397dd7cddfSDavid du Colombier 	printsol(".br\n");
5407dd7cddfSDavid du Colombier 	printsol("\\l'5i'\n");
5417dd7cddfSDavid du Colombier }
5427dd7cddfSDavid du Colombier 
5437dd7cddfSDavid du Colombier 
5447dd7cddfSDavid du Colombier /*
5457dd7cddfSDavid du Colombier <table border>
5467dd7cddfSDavid du Colombier <caption><font size="+1"><b>Cumulative Class Data</b></font></caption>
5477dd7cddfSDavid du Colombier <tr><th rowspan=2>DOSE<br>mg/kg</th><th colspan=2>PARALYSIS</th><th colspan=2>DEATH</th>
5487dd7cddfSDavid du Colombier </tr>
5497dd7cddfSDavid du Colombier <tr><th width=80>Number</th><th width=80>Percent</th><th width=80>Number</th><th width=80>Percent</th>
5507dd7cddfSDavid du Colombier </tr>
5517dd7cddfSDavid du Colombier <tr align=center>
5527dd7cddfSDavid du Colombier <td>0.1</td><td><br></td> <td><br></td> <td><br></td> <td><br></td>
5537dd7cddfSDavid du Colombier </tr>
5547dd7cddfSDavid du Colombier <tr align=center>
5557dd7cddfSDavid du Colombier <td>0.2</td><td><br></td> <td><br></td> <td><br></td> <td><br></td>
5567dd7cddfSDavid du Colombier </tr>
5577dd7cddfSDavid du Colombier <tr align=center>
5587dd7cddfSDavid du Colombier <td>0.3</td><td><br></td> <td><br></td> <td><br></td> <td><br></td>
5597dd7cddfSDavid du Colombier </tr>
5607dd7cddfSDavid du Colombier <tr align=center>
5617dd7cddfSDavid du Colombier <td>0.4</td><td><br></td> <td><br></td> <td><br></td> <td><br></td>
5627dd7cddfSDavid du Colombier </tr>
5637dd7cddfSDavid du Colombier <tr align=center>
5647dd7cddfSDavid du Colombier <td>0.5</td><td><br></td> <td><br></td> <td><br></td> <td><br></td>
5657dd7cddfSDavid du Colombier </tr>
5667dd7cddfSDavid du Colombier <tr align=center>
5677dd7cddfSDavid du Colombier <td>0.6</td><td><br></td> <td><br></td> <td><br></td> <td><br></td>
5687dd7cddfSDavid du Colombier </tr>
5697dd7cddfSDavid du Colombier <tr align=center>
5707dd7cddfSDavid du Colombier <td>0.7</td><td><br></td> <td><br></td> <td><br></td> <td><br></td>
5717dd7cddfSDavid du Colombier </tr>
5727dd7cddfSDavid du Colombier <tr align=center>
5737dd7cddfSDavid du Colombier <td>0.8</td><td><br></td> <td><br></td> <td><br></td> <td><br></td>
5747dd7cddfSDavid du Colombier </tr>
5757dd7cddfSDavid du Colombier <tr align=center>
5767dd7cddfSDavid du Colombier <td>0.8 oral</td><td><br></td> <td><br></td> <td><br></td> <td><br></td>
5777dd7cddfSDavid du Colombier </tr>
5787dd7cddfSDavid du Colombier </table>
5797dd7cddfSDavid du Colombier */
5807dd7cddfSDavid du Colombier 
5817dd7cddfSDavid du Colombier void
g_table(Goobie * g,char * arg)5827dd7cddfSDavid du Colombier g_table(Goobie *g, char *arg)
5837dd7cddfSDavid du Colombier {
5847dd7cddfSDavid du Colombier 	USED(g, arg);
5857dd7cddfSDavid du Colombier 	printsol(".TS\ncenter ;\n");
5867dd7cddfSDavid du Colombier }
5877dd7cddfSDavid du Colombier 
5887dd7cddfSDavid du Colombier void
g_tableend(Goobie * g,char * arg)5897dd7cddfSDavid du Colombier g_tableend(Goobie *g, char *arg)
5907dd7cddfSDavid du Colombier {
5917dd7cddfSDavid du Colombier 	USED(g, arg);
5927dd7cddfSDavid du Colombier 	printsol(".TE\n");
5937dd7cddfSDavid du Colombier }
5947dd7cddfSDavid du Colombier 
5957dd7cddfSDavid du Colombier void
g_caption(Goobie * g,char * arg)5967dd7cddfSDavid du Colombier g_caption(Goobie *g, char *arg)
5977dd7cddfSDavid du Colombier {
5987dd7cddfSDavid du Colombier 	USED(g, arg);
5997dd7cddfSDavid du Colombier }
6007dd7cddfSDavid du Colombier 
6017dd7cddfSDavid du Colombier void
g_captionend(Goobie * g,char * arg)6027dd7cddfSDavid du Colombier g_captionend(Goobie *g, char *arg)
6037dd7cddfSDavid du Colombier {
6047dd7cddfSDavid du Colombier 	USED(g, arg);
6057dd7cddfSDavid du Colombier }
606