diff --git a/sys/src/cmd/html2ms.c b/sys/src/cmd/html2ms.c
index 9cd8fa4a8..229836216 100644
--- a/sys/src/cmd/html2ms.c
+++ b/sys/src/cmd/html2ms.c
@@ -3,599 +3,538 @@
#include
#include
-enum
-{
- SSIZE = 10,
-
- /* list types */
- Lordered = 0,
- Lunordered,
- Lmenu,
- Ldir,
+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;
+ int restore;
+ };
+};
+
+struct Text {
+ char font;
+ int pre;
+ int pos;
+ int space;
+ int output;
+};
+
+void eatwhite(void);
+Tag *parsetext(Text *, Tag *);
+int parsetag(Tag *);
+int parseattr(Attr *);
+
Biobuf in, out;
-int lastc = '\n';
-int inpre = 0;
-/* stack for fonts */
-char *fontstack[SSIZE];
-char *font = "R";
-int fsp;
-
-/* stack for lists */
-struct
+void
+emit(Text *text, char *fmt, ...)
{
- int type;
- int ord;
-} liststack[SSIZE];
-int lsp;
+ va_list a;
-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,
- "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,
- "select", 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'<',
-"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;
- }
+ if(text->pos > 0){
+ text->pos = 0;
+ Bputc(&out, '\n');
}
+ va_start(a, fmt);
+ Bvprint(&out, fmt, a);
+ va_end(a);
}
void
-dogoobie(void)
+restoreoutput(Text *text, Tag *tag)
{
- char *arg, *type;
- Goobie *g;
- char buf[1024];
- int closing;
+ text->output = tag->restore;
+}
- 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);
+void
+ongarbage(Text *text, Tag *tag)
+{
+ tag->restore = text->output;
+ tag->close = restoreoutput;
+ text->output = 0;
+}
+
+void
+onp(Text *text, Tag *)
+{
+ emit(text, ".LP\n");
+}
+
+void
+restorepre(Text *text, Tag *tag)
+{
+ text->pre = tag->restore;
+ emit(text, ".DE\n");
+}
+
+void
+onpre(Text *text, Tag *tag)
+{
+ tag->restore = text->pre;
+ tag->close = restorepre;
+ text->pre = 1;
+ emit(text, ".DS L\n");
+}
+
+void
+onli(Text *text, Tag *tag)
+{
+ if(tag->up && cistrcmp(tag->up->tag, "ol") == 0)
+ emit(text, ".IP\n");
else
- Bprint(&out, "<%s>\n", type);
+ emit(text, ".IP \\(bu\n");
+ if(tag->up)
+ tag->up->close = onp;
}
void
-main(void)
+onh(Text *text, Tag *tag)
{
- 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;
- }
- }
+ emit(text, ".SH %c\n", tag->tag[1]);
+ tag->close = onp;
}
void
-escape(void)
+onbr(Text *text, Tag *tag)
{
- 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);
+ tag->closing = 1;
+ emit(text, ".br\n");
+ if(cistrcmp(tag->tag, "hr") == 0)
+ emit(text, "\\l'5i'\n.br\n");
}
-/*
- * whitespace is not significant to HTML, but newlines
- * and leading spaces are significant to troff.
- */
+void
+restorefont(Text *text, Tag *tag)
+{
+ text->font = tag->restore;
+ text->pos += Bprint(&out, "\\f%c", text->font);
+}
+
+void
+onfont(Text *text, Tag *tag)
+{
+ if(text->font == 0)
+ text->font = 'R';
+ tag->restore = text->font;
+ tag->close = restorefont;
+ if(cistrcmp(tag->tag, "i") == 0)
+ text->font = 'I';
+ else if(cistrcmp(tag->tag, "b") == 0)
+ text->font = 'B';
+ text->pos += Bprint(&out, "\\f%c", text->font);
+}
+
+struct {
+ char *tag;
+ void (*open)(Text *, Tag *);
+} ontag[] = {
+ "br", onbr,
+ "hr", onbr,
+ "b", onfont,
+ "i", onfont,
+ "p", onp,
+ "h1", onh,
+ "h2", onh,
+ "h3", onh,
+ "h4", onh,
+ "h5", onh,
+ "li", onli,
+ "pre", onpre,
+ "head", ongarbage,
+ "style", ongarbage,
+ "script", ongarbage,
+};
+
void
eatwhite(void)
{
int c;
- for(;;){
- c = Bgetc(&in);
- if(c < 0)
- break;
- if(!isspace(c)){
+ while((c = Bgetc(&in)) > 0){
+ if(strchr("\n\r\t ", c) == nil){
+ Bungetc(&in);
+ return;
+ }
+ }
+}
+
+void
+parsecomment(void)
+{
+ char buf[64];
+ int n, c;
+
+ n = 0;
+ eatwhite();
+ while((c = Bgetc(&in)) > 0){
+ if(c == '>')
+ return;
+ if(n == 0 && c == '-'){
+ while((c = Bgetc(&in)) > 0){
+ if(c == '-')
+ if(Bgetc(&in) == '-')
+ if(Bgetc(&in) == '>')
+ return;
+ }
+ }
+ if(n+1 < sizeof(buf)){
+ buf[n++] = c;
+ if(n != 7 || cistrncmp(buf, "[CDATA[", 7))
+ continue;
+ while((c = Bgetc(&in)) > 0){
+ if(c == ']')
+ if(Bgetc(&in) == ']')
+ if(Bgetc(&in) == '>')
+ return;
+ }
+ }
+ }
+}
+
+int
+parseattr(Attr *a)
+{
+ int q, c, n;
+
+ n = 0;
+ eatwhite();
+ while((c = Bgetc(&in)) > 0){
+ if(strchr(">=?!", c)){
Bungetc(&in);
break;
}
+ if(strchr("\n\r\t ", c))
+ break;
+ if(n < sizeof(a->attr)-1)
+ a->attr[n++] = c;
+ }
+ if(n == 0)
+ return 0;
+ a->attr[n] = 0;
+ n = 0;
+ eatwhite();
+ if(Bgetc(&in) == '='){
+ eatwhite();
+ c = Bgetc(&in);
+ if(strchr("'\"", c)){
+ q = c;
+ while((c = Bgetc(&in)) > 0){
+ if(c == q)
+ break;
+ if(n < sizeof(a->val)-1)
+ a->val[n++] = c;
+ }
+ } else {
+ Bungetc(&in);
+ while((c = Bgetc(&in)) > 0){
+ if(strchr("\n\r\t >?!", c)){
+ Bungetc(&in);
+ break;
+ }
+ if(n < sizeof(a->val)-1)
+ a->val[n++] = c;
+ }
+ }
+ } else
+ Bungetc(&in);
+ a->val[n] = 0;
+ return 1;
+}
+
+int
+parsetag(Tag *t)
+{
+ int n, c;
+
+ t->nattr = 0;
+ t->opening = 1;
+ t->closing = 0;
+
+ n = 0;
+ eatwhite();
+ while((c = Bgetc(&in)) > 0){
+ if(c == '>')
+ break;
+ if(strchr("\n\r\t ", c)){
+ if(parseattr(t->attr + t->nattr))
+ if(t->nattr < nelem(t->attr)-1)
+ t->nattr++;
+ continue;
+ }
+ if(n == 0 && strchr("?!", c)){
+ parsecomment();
+ return 0;
+ }
+ if(c == '/'){
+ if(n == 0){
+ t->opening = 0;
+ t->closing = 1;
+ } else
+ t->closing = 1;
+ continue;
+ }
+ if(n < sizeof(t->tag)-1)
+ t->tag[n++] = c;
+ }
+ t->tag[n] = 0;
+ return n > 0;
+}
+
+struct {
+ char *entity;
+ Rune rune;
+} entities[] = {
+ "AElig", 198, "Aacute", 193, "Acirc", 194, "Agrave", 192,
+ "Alpha", 913, "Aring", 197, "Atilde", 195, "Auml", 196,
+ "Beta", 914, "Ccedil", 199, "Chi", 935, "Dagger", 8225,
+ "Delta", 916, "ETH", 208, "Eacute", 201, "Ecirc", 202,
+ "Egrave", 200, "Epsilon", 917, "Eta", 919, "Euml", 203,
+ "Gamma", 915, "Iacute", 205, "Icirc", 206, "Igrave", 204,
+ "Iota", 921, "Iuml", 207, "Kappa", 922, "Lambda", 923,
+ "Mu", 924, "Ntilde", 209, "Nu", 925, "OElig", 338,
+ "Oacute", 211, "Ocirc", 212, "Ograve", 210, "Omega", 937,
+ "Omicron", 927, "Oslash", 216, "Otilde", 213, "Ouml", 214,
+ "Phi", 934, "Pi", 928, "Prime", 8243, "Psi", 936,
+ "Rho", 929, "Scaron", 352, "Sigma", 931, "THORN", 222,
+ "Tau", 932, "Theta", 920, "Uacute", 218, "Ucirc", 219,
+ "Ugrave", 217, "Upsilon", 933, "Uuml", 220, "Xi", 926,
+ "Yacute", 221, "Yuml", 376, "Zeta", 918, "aacute", 225,
+ "acirc", 226, "acute", 180, "aelig", 230, "agrave", 224,
+ "alefsym", 8501,"alpha", 945, "amp", 38, "and", 8743,
+ "ang", 8736, "aring", 229, "asymp", 8776, "atilde", 227,
+ "auml", 228, "bdquo", 8222, "beta", 946, "brvbar", 166,
+ "bull", 8226, "cap", 8745, "ccedil", 231, "cdots", 8943,
+ "cedil", 184, "cent", 162, "chi", 967, "circ", 710,
+ "clubs", 9827, "cong", 8773, "copy", 169, "crarr", 8629,
+ "cup", 8746, "curren", 164, "dArr", 8659, "dagger", 8224,
+ "darr", 8595, "ddots", 8945, "deg", 176, "delta", 948,
+ "diams", 9830, "divide", 247, "eacute", 233, "ecirc", 234,
+ "egrave", 232, "emdash", 8212, "empty", 8709, "emsp", 8195,
+ "endash", 8211, "ensp", 8194, "epsilon", 949, "equiv", 8801,
+ "eta", 951, "eth", 240, "euml", 235, "euro", 8364,
+ "exist", 8707, "fnof", 402, "forall", 8704, "frac12", 189,
+ "frac14", 188, "frac34", 190, "frasl", 8260, "gamma", 947,
+ "ge", 8805, "gt", 62, "hArr", 8660, "harr", 8596,
+ "hearts", 9829, "hellip", 8230, "iacute", 237, "icirc", 238,
+ "iexcl", 161, "igrave", 236, "image", 8465, "infin", 8734,
+ "int", 8747, "iota", 953, "iquest", 191, "isin", 8712,
+ "iuml", 239, "kappa", 954, "lArr", 8656, "lambda", 955,
+ "lang", 9001, "laquo", 171, "larr", 8592, "lceil", 8968,
+ "ldots", 8230, "ldquo", 8220, "le", 8804, "lfloor", 8970,
+ "lowast", 8727, "loz", 9674, "lrm", 8206, "lsaquo", 8249,
+ "lsquo", 8216, "lt", 60, "macr", 175, "mdash", 8212,
+ "micro", 181, "middot", 183, "minus", 8722, "mu", 956,
+ "nabla", 8711, "nbsp", 160, "ndash", 8211, "ne", 8800,
+ "ni", 8715, "not", 172, "notin", 8713, "nsub", 8836,
+ "ntilde", 241, "nu", 957, "oacute", 243, "ocirc", 244,
+ "oelig", 339, "ograve", 242, "oline", 8254, "omega", 969,
+ "omicron", 959, "oplus", 8853, "or", 8744, "ordf", 170,
+ "ordm", 186, "oslash", 248, "otilde", 245, "otimes", 8855,
+ "ouml", 246, "para", 182, "part", 8706, "permil", 8240,
+ "perp", 8869, "phi", 966, "pi", 960, "piv", 982,
+ "plusmn", 177, "pound", 163, "prime", 8242, "prod", 8719,
+ "prop", 8733, "psi", 968, "quad", 8193, "quot", 34,
+ "rArr", 8658, "radic", 8730, "rang", 9002, "raquo", 187,
+ "rarr", 8594, "rceil", 8969, "rdquo", 8221, "real", 8476,
+ "reg", 174, "rfloor", 8971, "rho", 961, "rlm", 8207,
+ "rsaquo", 8250, "rsquo", 8217, "sbquo", 8218, "scaron", 353,
+ "sdot", 8901, "sect", 167, "shy", 173, "sigma", 963,
+ "sigmaf", 962, "sim", 8764, "sp", 8194, "spades", 9824,
+ "sub", 8834, "sube", 8838, "sum", 8721, "sup", 8835,
+ "sup1", 185, "sup2", 178, "sup3", 179, "supe", 8839,
+ "szlig", 223, "tau", 964, "there4", 8756, "theta", 952,
+ "thetasym", 977,"thinsp", 8201, "thorn", 254, "tilde", 732,
+ "times", 215, "trade", 8482, "uArr", 8657, "uacute", 250,
+ "uarr", 8593, "ucirc", 251, "ugrave", 249, "uml", 168,
+ "upsih", 978, "upsilon", 965, "uuml", 252, "varepsilon", 8712,
+ "varphi", 981, "varpi", 982, "varrho", 1009, "vdots", 8942,
+ "vsigma", 962, "vtheta", 977, "weierp", 8472, "xi", 958,
+ "yacute", 253, "yen", 165, "yuml", 255, "zeta", 950,
+ "zwj", 8205, "zwnj", 8204,
+};
+
+Rune
+parserune(int c)
+{
+ char buf[10];
+ int i, n;
+ Rune r;
+
+ n = 0;
+ if(c == '&'){
+ while((c = Bgetc(&in)) > 0){
+ if(strchr("\n\r\t ;>", c)){
+ if(c != ';')
+ Bungetc(&in);
+ if(n == 0)
+ return '&';
+ break;
+ }
+ if(n == sizeof(buf)-1)
+ break;
+ buf[n++] = c;
+ }
+ buf[n] = 0;
+ if(buf[0] == '#')
+ return atoi(buf+1);
+ for(i=0; i= UTFmax)
+ break;
+ } while((c = Bgetc(&in)) > 0);
+ }
+ return 0xFFFD;
+}
+
+Rune
+substrune(Rune r)
+{
+ switch(r){
+ case 0x2019:
+ case 0x2018:
+ return '\'';
+ case 0x201c:
+ case 0x201d:
+ return '"';
+ default:
+ return r;
}
}
-/*
- * print at start of line
- */
void
-printsol(char *fmt, ...)
+debugtag(Tag *tag, char *dbg)
{
- va_list arg;
+ if(1) return;
- 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';
+ if(tag == nil)
+ return;
+ debugtag(tag->up, nil);
+ fprint(2, "%s %s%s", tag->tag, dbg ? dbg : " > ", dbg ? "\n" : "");
}
-void
-g_ignore(Goobie *g, char *arg)
-{
- USED(g, arg);
-}
-void
-g_unexpected(Goobie *g, char *arg)
+Tag*
+parsetext(Text *text, Tag *tag)
{
- USED(arg);
- fprint(2, "unexpected %s ending\n", g->name);
-}
+ Tag *rtag;
+ Rune r;
+ int c;
-void
-g_title(Goobie *g, char *arg)
-{
- USED(arg);
- printsol(".TL\n", g->name);
-}
+ rtag = tag;
+ debugtag(tag, "open");
+ if(tag == nil || tag->closing == 0){
+ while((c = Bgetc(&in)) > 0){
+ if(c == '<'){
+ Tag t;
-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;
+ memset(&t, 0, sizeof(t));
+ if(parsetag(&t)){
+ if(t.opening){
+ t.up = tag;
+ for(c = 0; c < nelem(ontag); c++){
+ if(cistrcmp(t.tag, ontag[c].tag) == 0){
+ ontag[c].open(text, &t);
+ break;
+ }
+ }
+ rtag = parsetext(text, &t);
+ if(rtag == &t)
+ rtag = tag;
+ else
+ break;
+ } else if(t.closing){
+ while(rtag && cistrcmp(rtag->tag, t.tag))
+ rtag = rtag->up;
+ if(rtag == nil)
+ rtag = tag;
+ else
+ break;
+ }
+ }
+ continue;
+ }
+ if(!text->output)
+ continue;
+ r = substrune(parserune(c));
+ switch(r){
+ case '\n':
+ case '\r':
+ case ' ':
+ case '\t':
+ if(text->pre == 0){
+ text->space = 1;
+ continue;
+ }
+ default:
+ if(r == '\n' || r == '\r')
+ text->pos = 0;
+ if(text->space){
+ text->space = 0;
+ if(text->pos >= 70){
+ text->pos = 0;
+ Bputc(&out, '\n');
+ } else if(text->pos > 0){
+ text->pos++;
+ Bputc(&out, ' ');
+ }
+ }
+ if(text->pos == 0 && r == '.'){
+ text->pos++;
+ Bputc(&out, ' ');
+ }
+ text->pos++;
+ if(r == 0xA0){
+ r = ' ';
+ Bputc(&out, '\\');
+ }
+ Bprint(&out, "%C", r);
+ }
}
}
- lsp++;
+ debugtag(tag, "close");
+ if(tag && tag->close)
+ tag->close(text, tag);
+ return rtag;
}
void
-g_br(Goobie *g, char *arg)
+main(void)
{
- 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 | PARALYSIS | DEATH |
-
-Number | Percent | Number | Percent |
-
-
-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);
+ Text text;
+
+ Binit(&in, 0, OREAD);
+ Binit(&out, 1, OWRITE);
+
+ memset(&text, 0, sizeof(text));
+ text.output = 1;
+ parsetext(&text, nil);
+ emit(&text, "\n");
}
diff --git a/sys/src/cmd/page.c b/sys/src/cmd/page.c
index 298ebacd7..eb2e761c1 100644
--- a/sys/src/cmd/page.c
+++ b/sys/src/cmd/page.c
@@ -626,7 +626,7 @@ popenfile(Page *p)
else if(cistrncmp(buf, "data = "htmlfmt -c utf8 | lp -dstdout";
+ p->data = "html2ms | troff -ms | lp -dstdout";
p->open = popengs;
}
else if(memcmp(buf, "\xF7\x02\x01\x83\x92\xC0\x1C;", 8) == 0){