#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', }, { """, L'"', }, { "Æ", L'Æ', }, { "Á", L'Á', }, { "Â", L'Â', }, { "À", L'À', }, { "Å", L'Å', }, { "Ã", L'Ã', }, { "Ä", L'Ä', }, { "Ç", L'Ç', }, { "Ð", L'Ð', }, { "É", L'É', }, { "Ê", L'Ê', }, { "È", L'È', }, { "Ë", L'Ë', }, { "Í", L'Í', }, { "Î", L'Î', }, { "Ì", L'Ì', }, { "Ï", L'Ï', }, { "Ñ", L'Ñ', }, { "Ó", L'Ó', }, { "Ô", L'Ô', }, { "Ò", L'Ò', }, { "Ø", L'Ø', }, { "Õ", L'Õ', }, { "Ö", L'Ö', }, { "Þ", L'Þ', }, { "Ú", L'Ú', }, { "Û", L'Û', }, { "Ù", L'Ù', }, { "Ü", L'Ü', }, { "Ý", L'Ý', }, { "á", L'á', }, { "â", L'â', }, { "æ", L'æ', }, { "à", L'à', }, { "&", L'&', }, { "å", L'å', }, { "ã", L'ã', }, { "ä", L'ä', }, { "ç", L'ç', }, { "é", L'é', }, { "ê", L'ê', }, { "è", L'è', }, { "ð", L'ð', }, { "ë", L'ë', }, { ">", L'>', }, { "í", L'í', }, { "î", L'î', }, { "ì", L'ì', }, { "ï", L'ï', }, { "<", L'<', }, { "ñ", L'ñ', }, { "ó", L'ó', }, { "ô", L'ô', }, { "ò", L'ò', }, { "ø", L'ø', }, { "õ", L'õ', }, { "ö", L'ö', }, { "ß", L'ß', }, { "þ", L'þ', }, { "ú", L'ú', }, { "û", L'û', }, { "ù", L'ù', }, { "ü", L'ü', }, { "ý", L'ý', }, { "ÿ", L'ÿ', }, {"∈", L'∈', }, { nil, 0 }, }; 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) { char buf[10]; int i; Entity *e; if(readupto(buf, sizeof(buf), ';', '\n') < 0){ Bprint(&out, "&%s", buf); return; } if(buf[0] == '#'){ i = strtoul(buf+1, 0, 10); if(i > 0 && i <= Runemax){ Bprint(&out, "%C", i); return; } } for(e = pl_entity; e->name; e++) if(strcmp(buf, e->name) == 0){ Bprint(&out, "%C", e->value); 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); }