#include #include #include #include enum { SSIZE = 10, /* list types */ Lordered = 0, Lunordered, Lmenu, Ldir, }; Biobuf in, out; int lastc = '\n'; int inpre = 0; /* stack for fonts */ char *fontstack[SSIZE]; char *font = "R"; int fsp; /* stack for lists */ struct { int type; int ord; } liststack[SSIZE]; int lsp; int quoting; typedef struct Goobie Goobie; struct Goobie { char *name; void (*f)(Goobie*, char*); void (*ef)(Goobie*, char*); }; void eatwhite(void); void escape(void); typedef void Action(Goobie*, char*); Action g_ignore; Action g_unexpected; Action g_title; Action g_p; Action g_h; Action g_li; Action g_list, g_listend; Action g_pre; Action g_fpush, g_fpop; Action g_indent, g_exdent; Action g_dt; Action g_display; Action g_displayend; Action g_table, g_tableend, g_caption, g_captionend; Action g_br, g_hr; Goobie gtab[] = { "!--", g_ignore, g_unexpected, "!doctype", g_ignore, g_unexpected, "a", g_ignore, g_ignore, "address", g_display, g_displayend, "b", g_fpush, g_fpop, "base", g_ignore, g_unexpected, "blink", g_ignore, g_ignore, "blockquote", g_ignore, g_ignore, "body", g_ignore, g_ignore, "br", g_br, g_unexpected, "caption", g_caption, g_captionend, "center", g_ignore, g_ignore, "cite", g_ignore, g_ignore, "code", g_ignore, g_ignore, "dd", g_ignore, g_unexpected, "dfn", g_ignore, g_ignore, "dir", g_list, g_listend, "div", g_ignore, g_br, "dl", g_indent, g_exdent, "dt", g_dt, g_unexpected, "em", g_ignore, g_ignore, "font", g_ignore, g_ignore, "form", g_ignore, g_ignore, "h1", g_h, g_p, "h2", g_h, g_p, "h3", g_h, g_p, "h4", g_h, g_p, "h5", g_h, g_p, "h6", g_h, g_p, "head", g_ignore, g_ignore, "hr", g_hr, g_unexpected, "html", g_ignore, g_ignore, "i", g_fpush, g_fpop, "input", g_ignore, g_unexpected, "img", g_ignore, g_unexpected, "isindex", g_ignore, g_unexpected, "kbd", g_fpush, g_fpop, "key", g_ignore, g_ignore, "li", g_li, g_unexpected, "link", g_ignore, g_unexpected, "listing", g_ignore, g_ignore, "menu", g_list, g_listend, "meta", g_ignore, g_unexpected, "nextid", g_ignore, g_unexpected, "ol", g_list, g_listend, "option", g_ignore, g_unexpected, "p", g_p, g_ignore, "plaintext", g_ignore, g_unexpected, "pre", g_pre, g_displayend, "samp", g_ignore, g_ignore, "script", g_ignore, g_ignore, "select", g_ignore, g_ignore, "span", g_ignore, g_ignore, "strong", g_ignore, g_ignore, "table", g_table, g_tableend, "textarea", g_ignore, g_ignore, "title", g_title, g_ignore, "tt", g_fpush, g_fpop, "u", g_ignore, g_ignore, "ul", g_list, g_listend, "var", g_ignore, g_ignore, "xmp", g_ignore, g_ignore, 0, 0, 0, }; typedef struct Entity Entity; struct Entity { char *name; Rune value; }; Entity pl_entity[]= { "#SPACE", L' ', "#RS", L'\n', "#RE", L'\r', "quot", L'"', "AElig", L'Æ', "Aacute", L'Á', "Acirc", L'Â', "Agrave", L'À', "Aring", L'Å', "Atilde", L'Ã', "Auml", L'Ä', "Ccedil", L'Ç', "ETH", L'Ð', "Eacute", L'É', "Ecirc", L'Ê', "Egrave", L'È', "Euml", L'Ë', "Iacute", L'Í', "Icirc", L'Î', "Igrave", L'Ì', "Iuml", L'Ï', "Ntilde", L'Ñ', "Oacute", L'Ó', "Ocirc", L'Ô', "Ograve", L'Ò', "Oslash", L'Ø', "Otilde", L'Õ', "Ouml", L'Ö', "THORN", L'Þ', "Uacute", L'Ú', "Ucirc", L'Û', "Ugrave", L'Ù', "Uuml", L'Ü', "Yacute", L'Ý', "aacute", L'á', "acirc", L'â', "aelig", L'æ', "agrave", L'à', "amp", L'&', "aring", L'å', "atilde", L'ã', "auml", L'ä', "ccedil", L'ç', "eacute", L'é', "ecirc", L'ê', "egrave", L'è', "eth", L'ð', "euml", L'ë', "gt", L'>', "iacute", L'í', "icirc", L'î', "igrave", L'ì', "iuml", L'ï', "lt", L'<', "nbsp", L' ', "ntilde", L'ñ', "oacute", L'ó', "ocirc", L'ô', "ograve", L'ò', "oslash", L'ø', "otilde", L'õ', "ouml", L'ö', "szlig", L'ß', "thorn", L'þ', "uacute", L'ú', "ucirc", L'û', "ugrave", L'ù', "uuml", L'ü', "yacute", L'ý', "yuml", L'ÿ', 0 }; int cistrcmp(char *a, char *b) { int c, d; for(;; a++, b++){ d = tolower(*a); c = d - tolower(*b); if(c) break; if(d == 0) break; } return c; } int readupto(char *buf, int n, char d, char notme) { char *p; int c; buf[0] = 0; for(p = buf;; p++){ c = Bgetc(&in); if(c < 0){ *p = 0; return -1; } if(c == notme){ Bungetc(&in); return -1; } if(c == d){ *p = 0; return 0; } *p = c; if(p == buf + n){ *p = 0; Bprint(&out, "<%s", buf); return -1; } } } void dogoobie(void) { char *arg, *type; Goobie *g; char buf[1024]; int closing; if(readupto(buf, sizeof(buf), '>', '<') < 0){ Bprint(&out, "<%s", buf); return; } type = buf; if(*type == '/'){ type++; closing = 1; } else closing = 0; arg = strchr(type, ' '); if(arg == 0) arg = strchr(type, '\r'); if(arg == 0) arg = strchr(type, '\n'); if(arg) *arg++ = 0; for(g = gtab; g->name; g++) if(cistrcmp(type, g->name) == 0){ if(closing){ if(g->ef){ (*g->ef)(g, arg); return; } } else { if(g->f){ (*g->f)(g, arg); return; } } } if(closing) type--; if(arg) Bprint(&out, "<%s %s>\n", type, arg); else Bprint(&out, "<%s>\n", type); } void main(void) { int c, pos; Binit(&in, 0, OREAD); Binit(&out, 1, OWRITE); pos = 0; for(;;){ c = Bgetc(&in); if(c < 0) return; switch(c){ case '<': dogoobie(); break; case '&': escape(); break; case '\r': pos = 0; break; case '\n': if(quoting){ Bputc(&out, '"'); quoting = 0; } if(lastc != '\n') Bputc(&out, '\n'); /* can't emit leading spaces in filled troff docs */ if (!inpre) eatwhite(); lastc = c; break; default: ++pos; if(!inpre && isascii(c) && isspace(c) && pos > 80){ Bputc(&out, '\n'); eatwhite(); pos = 0; }else Bputc(&out, c); lastc = c; break; } } } void escape(void) { int c; Entity *e; char buf[8]; if(readupto(buf, sizeof(buf), ';', '\n') < 0){ Bprint(&out, "&%s", buf); return; } for(e = pl_entity; e->name; e++) if(strcmp(buf, e->name) == 0){ Bprint(&out, "%C", e->value); return; } if(*buf == '#'){ c = atoi(buf+1); if(isascii(c) && isprint(c)){ Bputc(&out, c); return; } } Bprint(&out, "&%s;", buf); } /* * whitespace is not significant to HTML, but newlines * and leading spaces are significant to troff. */ void eatwhite(void) { int c; for(;;){ c = Bgetc(&in); if(c < 0) break; if(!isspace(c)){ Bungetc(&in); break; } } } /* * print at start of line */ void printsol(char *fmt, ...) { va_list arg; if(quoting){ Bputc(&out, '"'); quoting = 0; } if(lastc != '\n') Bputc(&out, '\n'); va_start(arg, fmt); Bvprint(&out, fmt, arg); va_end(arg); lastc = '\n'; } void g_ignore(Goobie *g, char *arg) { USED(g, arg); } void g_unexpected(Goobie *g, char *arg) { USED(arg); fprint(2, "unexpected %s ending\n", g->name); } void g_title(Goobie *g, char *arg) { USED(arg); printsol(".TL\n", g->name); } void g_p(Goobie *g, char *arg) { USED(arg); printsol(".LP\n", g->name); } void g_h(Goobie *g, char *arg) { USED(arg); printsol(".SH %c\n", g->name[1]); } void g_list(Goobie *g, char *arg) { USED(arg); if(lsp != SSIZE){ switch(g->name[0]){ case 'o': liststack[lsp].type = Lordered; liststack[lsp].ord = 0; break; default: liststack[lsp].type = Lunordered; break; } } lsp++; } void g_br(Goobie *g, char *arg) { USED(g, arg); printsol(".br\n"); } void g_li(Goobie *g, char *arg) { USED(g, arg); if(lsp <= 0 || lsp > SSIZE){ printsol(".IP \\(bu\n"); return; } switch(liststack[lsp-1].type){ case Lunordered: printsol(".IP \\(bu\n"); break; case Lordered: printsol(".IP %d\n", ++liststack[lsp-1].ord); break; } } void g_listend(Goobie *g, char *arg) { USED(g, arg); if(--lsp < 0) lsp = 0; printsol(".LP\n"); } void g_display(Goobie *g, char *arg) { USED(g, arg); printsol(".DS\n"); } void g_pre(Goobie *g, char *arg) { USED(g, arg); printsol(".DS L\n"); inpre = 1; } void g_displayend(Goobie *g, char *arg) { USED(g, arg); printsol(".DE\n"); inpre = 0; } void g_fpush(Goobie *g, char *arg) { USED(arg); if(fsp < SSIZE) fontstack[fsp] = font; fsp++; switch(g->name[0]){ case 'b': font = "B"; break; case 'i': font = "I"; break; case 'k': /* kbd */ case 't': /* tt */ font = "(CW"; break; } Bprint(&out, "\\f%s", font); } void g_fpop(Goobie *g, char *arg) { USED(g, arg); fsp--; if(fsp < SSIZE) font = fontstack[fsp]; else font = "R"; Bprint(&out, "\\f%s", font); } void g_indent(Goobie *g, char *arg) { USED(g, arg); printsol(".RS\n"); } void g_exdent(Goobie *g, char *arg) { USED(g, arg); printsol(".RE\n"); } void g_dt(Goobie *g, char *arg) { USED(g, arg); printsol(".IP \""); quoting = 1; } void g_hr(Goobie *g, char *arg) { USED(g, arg); printsol(".br\n"); printsol("\\l'5i'\n"); } /*
Cumulative Class Data
DOSE
mg/kg
PARALYSISDEATH
NumberPercentNumberPercent
0.1



0.2



0.3



0.4



0.5



0.6



0.7



0.8



0.8 oral



*/ void g_table(Goobie *g, char *arg) { USED(g, arg); printsol(".TS\ncenter ;\n"); } void g_tableend(Goobie *g, char *arg) { USED(g, arg); printsol(".TE\n"); } void g_caption(Goobie *g, char *arg) { USED(g, arg); } void g_captionend(Goobie *g, char *arg) { USED(g, arg); }