=================================================================== RCS file: /cvs/mandoc/html.c,v retrieving revision 1.29 retrieving revision 1.35 diff -u -p -r1.29 -r1.35 --- mandoc/html.c 2009/09/16 09:41:24 1.29 +++ mandoc/html.c 2009/09/20 11:05:22 1.35 @@ -1,4 +1,4 @@ -/* $Id: html.c,v 1.29 2009/09/16 09:41:24 kristaps Exp $ */ +/* $Id: html.c,v 1.35 2009/09/20 11:05:22 kristaps Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons * @@ -14,17 +14,26 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include + #include +#include #include #include #include +#include +#include "chars.h" #include "mdoc.h" #include "man.h" #define DOCTYPE "-//W3C//DTD HTML 4.01//EN" #define DTD "http://www.w3.org/TR/html4/strict.dtd" +#define INDENT 5 +#define HALFINDENT 3 +#define PX_MULT 8 + enum htmltag { TAG_HTML, TAG_HEAD, @@ -37,6 +46,15 @@ enum htmltag { TAG_P, TAG_SPAN, TAG_LINK, + TAG_BR, + TAG_A, + TAG_TABLE, + TAG_COL, + TAG_TR, + TAG_TD, + TAG_LI, + TAG_UL, + TAG_OL, TAG_MAX }; @@ -49,27 +67,40 @@ enum htmlattr { ATTR_TYPE, ATTR_MEDIA, ATTR_CLASS, + ATTR_STYLE, + ATTR_WIDTH, + ATTR_VALIGN, ATTR_MAX }; struct htmldata { char *name; int flags; -#define HTML_BLOCK (1 << 0) +#define HTML_CLRLINE (1 << 0) +#define HTML_NOSTACK (1 << 1) }; static const struct htmldata htmltags[TAG_MAX] = { - {"html", HTML_BLOCK}, /* TAG_HTML */ - {"head", HTML_BLOCK}, /* TAG_HEAD */ - {"body", HTML_BLOCK}, /* TAG_BODY */ - {"meta", HTML_BLOCK}, /* TAG_META */ - {"title", HTML_BLOCK}, /* TAG_TITLE */ - {"div", HTML_BLOCK}, /* TAG_DIV */ + {"html", HTML_CLRLINE}, /* TAG_HTML */ + {"head", HTML_CLRLINE}, /* TAG_HEAD */ + {"body", HTML_CLRLINE}, /* TAG_BODY */ + {"meta", HTML_CLRLINE | HTML_NOSTACK}, /* TAG_META */ + {"title", HTML_CLRLINE}, /* TAG_TITLE */ + {"div", HTML_CLRLINE}, /* TAG_DIV */ {"h1", 0}, /* TAG_H1 */ {"h2", 0}, /* TAG_H2 */ - {"p", HTML_BLOCK}, /* TAG_P */ + {"p", HTML_CLRLINE}, /* TAG_P */ {"span", 0}, /* TAG_SPAN */ - {"link", HTML_BLOCK}, /* TAG_LINK */ + {"link", HTML_CLRLINE | HTML_NOSTACK}, /* TAG_LINK */ + {"br", HTML_CLRLINE | HTML_NOSTACK}, /* TAG_LINK */ + {"a", 0}, /* TAG_A */ + {"table", HTML_CLRLINE}, /* TAG_TABLE */ + {"col", HTML_CLRLINE | HTML_NOSTACK}, /* TAG_COL */ + {"tr", HTML_CLRLINE}, /* TAG_TR */ + {"td", HTML_CLRLINE}, /* TAG_TD */ + {"li", HTML_CLRLINE}, /* TAG_LI */ + {"ul", HTML_CLRLINE}, /* TAG_UL */ + {"ol", HTML_CLRLINE}, /* TAG_OL */ }; static const char *const htmlattrs[ATTR_MAX] = { @@ -80,7 +111,10 @@ static const char *const htmlattrs[ATTR_MAX] = { "href", "type", "media", - "class" + "class", + "style", + "width", + "valign", }; struct htmlpair { @@ -88,9 +122,19 @@ struct htmlpair { char *val; }; +struct tag { + enum htmltag tag; + SLIST_ENTRY(tag) entry; +}; + +SLIST_HEAD(tagq, tag); + struct html { int flags; #define HTML_NOSPACE (1 << 0) +#define HTML_NEWLINE (1 << 1) + struct tagq stack; + void *symtab; }; #define MDOC_ARGS const struct mdoc_meta *m, \ @@ -108,69 +152,105 @@ static void print_gen_doctype(struct html *); static void print_gen_head(struct html *); static void print_mdoc(MDOC_ARGS); static void print_mdoc_head(MDOC_ARGS); +static void print_mdoc_title(MDOC_ARGS); static void print_mdoc_node(MDOC_ARGS); static void print_man(MAN_ARGS); static void print_man_head(MAN_ARGS); static void print_man_body(MAN_ARGS); -static void print_otag(struct html *, enum htmltag, +static struct tag *print_otag(struct html *, enum htmltag, int, const struct htmlpair *); +static void print_tagq(struct html *, const struct tag *); +static void print_stagq(struct html *, const struct tag *); static void print_ctag(struct html *, enum htmltag); -static void print_encode(const char *); +static void print_encode(struct html *, const char *); +static void print_escape(struct html *, const char **); static void print_text(struct html *, const char *); +static void print_res(struct html *, const char *, int); +static void print_spec(struct html *, const char *, int); + +static int a2width(const char *); +static int a2offs(const char *); + +static int mdoc_list_pre(MDOC_ARGS, int); +static int mdoc_listitem_pre(MDOC_ARGS); static int mdoc_root_pre(MDOC_ARGS); -static void mdoc_root_post(MDOC_ARGS); +static int mdoc_tbl_pre(MDOC_ARGS, int); +static int mdoc_tbl_block_pre(MDOC_ARGS, int, int, int); +static int mdoc_tbl_body_pre(MDOC_ARGS, int, int); +static int mdoc_tbl_head_pre(MDOC_ARGS, int, int); +static int mdoc_ar_pre(MDOC_ARGS); +static int mdoc_bl_pre(MDOC_ARGS); +static int mdoc_d1_pre(MDOC_ARGS); +static void mdoc_dq_post(MDOC_ARGS); +static int mdoc_dq_pre(MDOC_ARGS); +static int mdoc_fl_pre(MDOC_ARGS); +static int mdoc_em_pre(MDOC_ARGS); +static int mdoc_ex_pre(MDOC_ARGS); +static int mdoc_it_pre(MDOC_ARGS); static int mdoc_nd_pre(MDOC_ARGS); static int mdoc_nm_pre(MDOC_ARGS); -static void mdoc_nm_post(MDOC_ARGS); +static int mdoc_ns_pre(MDOC_ARGS); +static void mdoc_op_post(MDOC_ARGS); +static int mdoc_op_pre(MDOC_ARGS); static int mdoc_pp_pre(MDOC_ARGS); +static void mdoc_pq_post(MDOC_ARGS); +static int mdoc_pq_pre(MDOC_ARGS); static int mdoc_sh_pre(MDOC_ARGS); -static void mdoc_sh_post(MDOC_ARGS); +static void mdoc_sq_post(MDOC_ARGS); +static int mdoc_sq_pre(MDOC_ARGS); static int mdoc_ss_pre(MDOC_ARGS); -static void mdoc_ss_post(MDOC_ARGS); +static int mdoc_sx_pre(MDOC_ARGS); +static int mdoc_xr_pre(MDOC_ARGS); +static int mdoc_xx_pre(MDOC_ARGS); +#ifdef __linux__ +extern size_t strlcpy(char *, const char *, size_t); +extern size_t strlcat(char *, const char *, size_t); +#endif + static const struct htmlmdoc mdocs[MDOC_MAX] = { {NULL, NULL}, /* Ap */ {NULL, NULL}, /* Dd */ {NULL, NULL}, /* Dt */ {NULL, NULL}, /* Os */ - {mdoc_sh_pre, mdoc_sh_post }, /* Sh */ - {mdoc_ss_pre, mdoc_ss_post }, /* Ss */ + {mdoc_sh_pre, NULL }, /* Sh */ + {mdoc_ss_pre, NULL }, /* Ss */ {mdoc_pp_pre, NULL}, /* Pp */ - {NULL, NULL}, /* D1 */ - {NULL, NULL}, /* Dl */ + {mdoc_d1_pre, NULL}, /* D1 */ + {mdoc_d1_pre, NULL}, /* Dl */ {NULL, NULL}, /* Bd */ {NULL, NULL}, /* Ed */ - {NULL, NULL}, /* Bl */ + {mdoc_bl_pre, NULL}, /* Bl */ {NULL, NULL}, /* El */ - {NULL, NULL}, /* It */ + {mdoc_it_pre, NULL}, /* It */ {NULL, NULL}, /* Ad */ {NULL, NULL}, /* An */ - {NULL, NULL}, /* Ar */ + {mdoc_ar_pre, NULL}, /* Ar */ {NULL, NULL}, /* Cd */ {NULL, NULL}, /* Cm */ {NULL, NULL}, /* Dv */ {NULL, NULL}, /* Er */ {NULL, NULL}, /* Ev */ - {NULL, NULL}, /* Ex */ + {mdoc_ex_pre, NULL}, /* Ex */ {NULL, NULL}, /* Fa */ {NULL, NULL}, /* Fd */ - {NULL, NULL}, /* Fl */ + {mdoc_fl_pre, NULL}, /* Fl */ {NULL, NULL}, /* Fn */ {NULL, NULL}, /* Ft */ {NULL, NULL}, /* Ic */ {NULL, NULL}, /* In */ {NULL, NULL}, /* Li */ {mdoc_nd_pre, NULL}, /* Nd */ - {mdoc_nm_pre, mdoc_nm_post}, /* Nm */ - {NULL, NULL}, /* Op */ + {mdoc_nm_pre, NULL}, /* Nm */ + {mdoc_op_pre, mdoc_op_post}, /* Op */ {NULL, NULL}, /* Ot */ {NULL, NULL}, /* Pa */ {NULL, NULL}, /* Rv */ {NULL, NULL}, /* St */ {NULL, NULL}, /* Va */ {NULL, NULL}, /* Vt */ - {NULL, NULL}, /* Xr */ + {mdoc_xr_pre, NULL}, /* Xr */ {NULL, NULL}, /* %A */ {NULL, NULL}, /* %B */ {NULL, NULL}, /* %D */ @@ -190,26 +270,26 @@ static const struct htmlmdoc mdocs[MDOC_MAX] = { {NULL, NULL}, /* Bf */ {NULL, NULL}, /* Bo */ {NULL, NULL}, /* Bq */ - {NULL, NULL}, /* Bsx */ + {mdoc_xx_pre, NULL}, /* Bsx */ {NULL, NULL}, /* Bx */ {NULL, NULL}, /* Db */ {NULL, NULL}, /* Dc */ {NULL, NULL}, /* Do */ - {NULL, NULL}, /* Dq */ + {mdoc_dq_pre, mdoc_dq_post}, /* Dq */ {NULL, NULL}, /* Ec */ {NULL, NULL}, /* Ef */ - {NULL, NULL}, /* Em */ + {mdoc_em_pre, NULL}, /* Em */ {NULL, NULL}, /* Eo */ - {NULL, NULL}, /* Fx */ + {mdoc_xx_pre, NULL}, /* Fx */ {NULL, NULL}, /* Ms */ {NULL, NULL}, /* No */ - {NULL, NULL}, /* Ns */ - {NULL, NULL}, /* Nx */ - {NULL, NULL}, /* Ox */ + {mdoc_ns_pre, NULL}, /* Ns */ + {mdoc_xx_pre, NULL}, /* Nx */ + {mdoc_xx_pre, NULL}, /* Ox */ {NULL, NULL}, /* Pc */ {NULL, NULL}, /* Pf */ - {NULL, NULL}, /* Po */ - {NULL, NULL}, /* Pq */ + {mdoc_pq_pre, mdoc_pq_post}, /* Po */ + {mdoc_pq_pre, mdoc_pq_post}, /* Pq */ {NULL, NULL}, /* Qc */ {NULL, NULL}, /* Ql */ {NULL, NULL}, /* Qo */ @@ -217,13 +297,13 @@ static const struct htmlmdoc mdocs[MDOC_MAX] = { {NULL, NULL}, /* Re */ {NULL, NULL}, /* Rs */ {NULL, NULL}, /* Sc */ - {NULL, NULL}, /* So */ - {NULL, NULL}, /* Sq */ + {mdoc_sq_pre, mdoc_sq_post}, /* So */ + {mdoc_sq_pre, mdoc_sq_post}, /* Sq */ {NULL, NULL}, /* Sm */ - {NULL, NULL}, /* Sx */ + {mdoc_sx_pre, NULL}, /* Sx */ {NULL, NULL}, /* Sy */ {NULL, NULL}, /* Tn */ - {NULL, NULL}, /* Ux */ + {mdoc_xx_pre, NULL}, /* Ux */ {NULL, NULL}, /* Xc */ {NULL, NULL}, /* Xo */ {NULL, NULL}, /* Fo */ @@ -246,71 +326,99 @@ static const struct htmlmdoc mdocs[MDOC_MAX] = { {NULL, NULL}, /* %C */ {NULL, NULL}, /* Es */ {NULL, NULL}, /* En */ - {NULL, NULL}, /* Dx */ + {mdoc_xx_pre, NULL}, /* Dx */ {NULL, NULL}, /* %Q */ {NULL, NULL}, /* br */ {NULL, NULL}, /* sp */ }; +static char buf[BUFSIZ]; /* XXX */ -int +#define bufcat(x) (void)strlcat(buf, (x), BUFSIZ) +#define bufinit() buf[0] = 0 +#define buffmt(...) (void)snprintf(buf, BUFSIZ - 1, __VA_ARGS__) + +void html_mdoc(void *arg, const struct mdoc *m) { struct html *h; + struct tag *t; h = (struct html *)arg; print_gen_doctype(h); - print_otag(h, TAG_HTML, 0, NULL); + t = print_otag(h, TAG_HTML, 0, NULL); print_mdoc(mdoc_meta(m), mdoc_node(m), h); - print_ctag(h, TAG_HTML); + print_tagq(h, t); + printf("\n"); - return(1); } -int +void html_man(void *arg, const struct man *m) { struct html *h; + struct tag *t; h = (struct html *)arg; print_gen_doctype(h); - print_otag(h, TAG_HTML, 0, NULL); + t = print_otag(h, TAG_HTML, 0, NULL); print_man(man_meta(m), man_node(m), h); - print_ctag(h, TAG_HTML); + print_tagq(h, t); + printf("\n"); - return(1); } void * html_alloc(void) { + struct html *h; - return(calloc(1, sizeof(struct html))); + if (NULL == (h = calloc(1, sizeof(struct html)))) + return(NULL); + + SLIST_INIT(&h->stack); + if (NULL == (h->symtab = chars_init(CHARS_HTML))) { + free(h); + return(NULL); + } + return(h); } void html_free(void *p) { + struct tag *tag; + struct html *h; - free(p); + h = (struct html *)p; + + while ( ! SLIST_EMPTY(&h->stack)) { + tag = SLIST_FIRST(&h->stack); + SLIST_REMOVE_HEAD(&h->stack, entry); + free(tag); + } + free(h); } static void print_mdoc(MDOC_ARGS) { + struct tag *t; - print_otag(h, TAG_HEAD, 0, NULL); + t = print_otag(h, TAG_HEAD, 0, NULL); print_mdoc_head(m, n, h); - print_ctag(h, TAG_HEAD); - print_otag(h, TAG_BODY, 0, NULL); + print_tagq(h, t); + + t = print_otag(h, TAG_BODY, 0, NULL); + print_mdoc_title(m, n, h); print_mdoc_node(m, n, h); - print_ctag(h, TAG_BODY); + print_tagq(h, t); } @@ -324,7 +432,7 @@ print_gen_head(struct html *h) meta0[0].key = ATTR_HTTPEQUIV; meta0[0].val = "Content-Type"; meta0[1].key = ATTR_CONTENT; - meta0[1].val = "text/html; charest-utf-8"; + meta0[1].val = "text/html; charset=utf-8"; meta1[0].key = ATTR_NAME; meta1[0].val = "resource-type"; @@ -334,7 +442,7 @@ print_gen_head(struct html *h) link[0].key = ATTR_REL; link[0].val = "stylesheet"; link[1].key = ATTR_HREF; - link[1].val = "style.css"; + link[1].val = "style.css"; /* XXX */ link[2].key = ATTR_TYPE; link[2].val = "text/css"; link[3].key = ATTR_MEDIA; @@ -346,134 +454,37 @@ print_gen_head(struct html *h) } +/* ARGSUSED */ static void print_mdoc_head(MDOC_ARGS) { print_gen_head(h); print_otag(h, TAG_TITLE, 0, NULL); - print_encode(m->title); - print_ctag(h, TAG_TITLE); + print_encode(h, m->title); } -static int -mdoc_root_pre(MDOC_ARGS) -{ - struct htmlpair div; - - div.key = ATTR_CLASS; - div.val = "body"; - - print_otag(h, TAG_DIV, 1, &div); - return(1); -} - - +/* ARGSUSED */ static void -mdoc_root_post(MDOC_ARGS) +print_mdoc_title(MDOC_ARGS) { - print_ctag(h, TAG_DIV); + /* TODO */ } -static int -mdoc_ss_pre(MDOC_ARGS) -{ - - if (MDOC_BODY == n->type) - print_otag(h, TAG_P, 0, NULL); - if (MDOC_HEAD == n->type) - print_otag(h, TAG_H2, 0, NULL); - return(1); -} - - static void -mdoc_ss_post(MDOC_ARGS) -{ - - if (MDOC_BODY == n->type) - print_ctag(h, TAG_P); - if (MDOC_HEAD == n->type) - print_ctag(h, TAG_H2); -} - - -static int -mdoc_pp_pre(MDOC_ARGS) -{ - - print_otag(h, TAG_P, 0, NULL); - return(0); -} - - -static int -mdoc_nd_pre(MDOC_ARGS) -{ - - if (MDOC_BODY == n->type) - print_text(h, "--"); - return(1); -} - - -static int -mdoc_nm_pre(MDOC_ARGS) -{ - struct htmlpair class; - - class.key = ATTR_CLASS; - class.val = "name"; - - print_otag(h, TAG_SPAN, 1, &class); - if (NULL == n->child) - print_text(h, m->name); - - return(1); -} - - -static void -mdoc_nm_post(MDOC_ARGS) -{ - - print_ctag(h, TAG_SPAN); -} - - -static int -mdoc_sh_pre(MDOC_ARGS) -{ - - if (MDOC_BODY == n->type) - print_otag(h, TAG_P, 0, NULL); - if (MDOC_HEAD == n->type) - print_otag(h, TAG_H1, 0, NULL); - return(1); -} - - -static void -mdoc_sh_post(MDOC_ARGS) -{ - - if (MDOC_BODY == n->type) - print_ctag(h, TAG_P); - if (MDOC_HEAD == n->type) - print_ctag(h, TAG_H1); -} - - -static void print_mdoc_node(MDOC_ARGS) { int child; + struct tag *t; child = 1; + t = SLIST_FIRST(&h->stack); + bufinit(); + switch (n->type) { case (MDOC_ROOT): child = mdoc_root_pre(m, n, h); @@ -490,9 +501,12 @@ print_mdoc_node(MDOC_ARGS) if (child && n->child) print_mdoc_node(m, n->child, h); + print_stagq(h, t); + + bufinit(); + switch (n->type) { case (MDOC_ROOT): - mdoc_root_post(m, n, h); break; case (MDOC_TEXT): break; @@ -510,62 +524,232 @@ print_mdoc_node(MDOC_ARGS) static void print_man(MAN_ARGS) { + struct tag *t; - print_otag(h, TAG_HEAD, 0, NULL); + t = print_otag(h, TAG_HEAD, 0, NULL); print_man_head(m, n, h); - print_ctag(h, TAG_HEAD); - print_otag(h, TAG_BODY, 0, NULL); + print_tagq(h, t); + + t = print_otag(h, TAG_BODY, 0, NULL); print_man_body(m, n, h); - print_ctag(h, TAG_BODY); + print_tagq(h, t); } +/* ARGSUSED */ static void print_man_head(MAN_ARGS) { print_gen_head(h); print_otag(h, TAG_TITLE, 0, NULL); - print_encode(m->title); - print_ctag(h, TAG_TITLE); + print_encode(h, m->title); } +/* ARGSUSED */ static void print_man_body(MAN_ARGS) { + + /* TODO */ } static void -print_encode(const char *p) +print_spec(struct html *h, const char *p, int len) { + const char *rhs; + int i; + size_t sz; - printf("%s", p); /* XXX */ + rhs = chars_a2ascii(h->symtab, p, (size_t)len, &sz); + + if (NULL == rhs) + return; + for (i = 0; i < (int)sz; i++) + putchar(rhs[i]); } static void +print_res(struct html *h, const char *p, int len) +{ + const char *rhs; + int i; + size_t sz; + + rhs = chars_a2res(h->symtab, p, (size_t)len, &sz); + + if (NULL == rhs) + return; + for (i = 0; i < (int)sz; i++) + putchar(rhs[i]); +} + + +static void +print_escape(struct html *h, const char **p) +{ + int j, type; + const char *wp; + + wp = *p; + type = 1; + + if (0 == *(++wp)) { + *p = wp; + return; + } + + if ('(' == *wp) { + wp++; + if (0 == *wp || 0 == *(wp + 1)) { + *p = 0 == *wp ? wp : wp + 1; + return; + } + + print_spec(h, wp, 2); + *p = ++wp; + return; + + } else if ('*' == *wp) { + if (0 == *(++wp)) { + *p = wp; + return; + } + + switch (*wp) { + case ('('): + wp++; + if (0 == *wp || 0 == *(wp + 1)) { + *p = 0 == *wp ? wp : wp + 1; + return; + } + + print_res(h, wp, 2); + *p = ++wp; + return; + case ('['): + type = 0; + break; + default: + print_res(h, wp, 1); + *p = wp; + return; + } + + } else if ('f' == *wp) { + if (0 == *(++wp)) { + *p = wp; + return; + } + + switch (*wp) { + case ('B'): + /* TODO */ + break; + case ('I'): + /* TODO */ + break; + case ('P'): + /* FALLTHROUGH */ + case ('R'): + /* TODO */ + break; + default: + break; + } + + *p = wp; + return; + + } else if ('[' != *wp) { + print_spec(h, wp, 1); + *p = wp; + return; + } + + wp++; + for (j = 0; *wp && ']' != *wp; wp++, j++) + /* Loop... */ ; + + if (0 == *wp) { + *p = wp; + return; + } + + if (type) + print_spec(h, wp - j, j); + else + print_res(h, wp - j, j); + + *p = wp; +} + + +static void +print_encode(struct html *h, const char *p) +{ + + for (; *p; p++) { + if ('\\' == *p) { + print_escape(h, &p); + continue; + } + switch (*p) { + case ('<'): + printf("<"); + break; + case ('>'): + printf(">"); + break; + case ('&'): + printf("&"); + break; + default: + putchar(*p); + break; + } + } +} + + +static struct tag * print_otag(struct html *h, enum htmltag tag, int sz, const struct htmlpair *p) { int i; + struct tag *t; + if ( ! (HTML_NOSTACK & htmltags[tag].flags)) { + if (NULL == (t = malloc(sizeof(struct tag)))) + err(EXIT_FAILURE, "malloc"); + t->tag = tag; + SLIST_INSERT_HEAD(&h->stack, t, entry); + } else + t = NULL; + if ( ! (HTML_NOSPACE & h->flags)) - if ( ! (HTML_BLOCK & htmltags[tag].flags)) + if ( ! (HTML_CLRLINE & htmltags[tag].flags)) printf(" "); printf("<%s", htmltags[tag].name); for (i = 0; i < sz; i++) { printf(" %s=\"", htmlattrs[p[i].key]); assert(p->val); - print_encode(p[i].val); + print_encode(h, p[i].val); printf("\""); } printf(">"); h->flags |= HTML_NOSPACE; + if (HTML_CLRLINE & htmltags[tag].flags) + h->flags |= HTML_NEWLINE; + else + h->flags &= ~HTML_NEWLINE; + return(t); } @@ -575,8 +759,12 @@ print_ctag(struct html *h, enum htmltag tag) { printf("", htmltags[tag].name); - if (HTML_BLOCK & htmltags[tag].flags) + if (HTML_CLRLINE & htmltags[tag].flags) h->flags |= HTML_NOSPACE; + if (HTML_CLRLINE & htmltags[tag].flags) + h->flags |= HTML_NEWLINE; + else + h->flags &= ~HTML_NEWLINE; } @@ -613,16 +801,19 @@ print_text(struct html *h, const char *p) /* FALLTHROUGH */ case('}'): h->flags |= HTML_NOSPACE; + break; default: break; } if ( ! (h->flags & HTML_NOSPACE)) printf(" "); + h->flags &= ~HTML_NOSPACE; + h->flags &= ~HTML_NEWLINE; if (p) - print_encode(p); + print_encode(h, p); if (*p && 0 == *(p + 1)) switch (*p) { @@ -632,7 +823,817 @@ print_text(struct html *h, const char *p) /* FALLTHROUGH */ case('{'): h->flags |= HTML_NOSPACE; + break; default: break; } +} + + +static void +print_tagq(struct html *h, const struct tag *until) +{ + struct tag *tag; + + while ( ! SLIST_EMPTY(&h->stack)) { + tag = SLIST_FIRST(&h->stack); + print_ctag(h, tag->tag); + SLIST_REMOVE_HEAD(&h->stack, entry); + free(tag); + if (until && tag == until) + return; + } +} + + +static void +print_stagq(struct html *h, const struct tag *suntil) +{ + struct tag *tag; + + while ( ! SLIST_EMPTY(&h->stack)) { + tag = SLIST_FIRST(&h->stack); + if (suntil && tag == suntil) + return; + print_ctag(h, tag->tag); + SLIST_REMOVE_HEAD(&h->stack, entry); + free(tag); + } +} + + +/* FIXME: put in utility file for front-ends. */ +static int +a2offs(const char *p) +{ + int len, i; + + if (0 == strcmp(p, "left")) + return(0); + if (0 == strcmp(p, "indent")) + return(INDENT + 1); + if (0 == strcmp(p, "indent-two")) + return((INDENT + 1) * 2); + + if (0 == (len = (int)strlen(p))) + return(0); + + for (i = 0; i < len - 1; i++) + if ( ! isdigit((u_char)p[i])) + break; + + if (i == len - 1) + if ('n' == p[len - 1] || 'm' == p[len - 1]) + return(atoi(p)); + + return(len); +} + + +/* FIXME: put in utility file for front-ends. */ +static int +a2width(const char *p) +{ + int i, len; + + if (0 == (len = (int)strlen(p))) + return(0); + for (i = 0; i < len - 1; i++) + if ( ! isdigit((u_char)p[i])) + break; + + if (i == len - 1) + if ('n' == p[len - 1] || 'm' == p[len - 1]) + return(atoi(p) + 2); + + return(len + 2); +} + + + + +/* ARGSUSED */ +static int +mdoc_root_pre(MDOC_ARGS) +{ + struct htmlpair tag; + + tag.key = ATTR_CLASS; + tag.val = "body"; + + print_otag(h, TAG_DIV, 1, &tag); + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_sh_pre(MDOC_ARGS) +{ + struct htmlpair tag[2]; + + if (MDOC_HEAD == n->type) { + tag[0].key = ATTR_CLASS; + tag[0].val = "sec-head"; + print_otag(h, TAG_DIV, 1, tag); + print_otag(h, TAG_SPAN, 1, tag); + return(1); + } else if (MDOC_BLOCK == n->type) { + tag[0].key = ATTR_CLASS; + tag[0].val = "sec-block"; + print_otag(h, TAG_DIV, 1, tag); + return(1); + } + + buffmt("margin-left: %dem;", INDENT); + + if (n->parent->next && n->child) + bufcat("margin-bottom: 1em;"); + + tag[0].key = ATTR_CLASS; + tag[0].val = "sec-body"; + tag[1].key = ATTR_STYLE; + tag[1].val = buf; + + print_otag(h, TAG_DIV, 2, tag); + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_ss_pre(MDOC_ARGS) +{ + struct htmlpair tag[2]; + int i; + + i = 0; + + if (MDOC_BODY == n->type) { + tag[i].key = ATTR_CLASS; + tag[i++].val = "ssec-body"; + if (n->parent->next && n->child) { + bufcat("margin-bottom: 1em;"); + tag[i].key = ATTR_STYLE; + tag[i++].val = buf; + } + print_otag(h, TAG_DIV, i, tag); + return(1); + } else if (MDOC_BLOCK == n->type) { + tag[i].key = ATTR_CLASS; + tag[i++].val = "ssec-block"; + if (n->prev) { + bufcat("margin-top: 1em;"); + tag[i].key = ATTR_STYLE; + tag[i++].val = buf; + } + print_otag(h, TAG_DIV, i, tag); + return(1); + } + + buffmt("margin-left: -%dem;", INDENT - HALFINDENT); + + tag[0].key = ATTR_CLASS; + tag[0].val = "ssec-head"; + tag[1].key = ATTR_STYLE; + tag[1].val = buf; + + print_otag(h, TAG_DIV, 2, tag); + print_otag(h, TAG_SPAN, 1, tag); + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_fl_pre(MDOC_ARGS) +{ + struct htmlpair tag; + + tag.key = ATTR_CLASS; + tag.val = "flag"; + + print_otag(h, TAG_SPAN, 1, &tag); + print_text(h, "\\-"); + h->flags |= HTML_NOSPACE; + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_pp_pre(MDOC_ARGS) +{ + struct htmlpair tag; + + bufcat("clear: both;"); + bufcat("height: 1em;"); + + tag.key = ATTR_STYLE; + tag.val = buf; + + print_otag(h, TAG_DIV, 1, &tag); + return(0); +} + + +/* ARGSUSED */ +static int +mdoc_nd_pre(MDOC_ARGS) +{ + struct htmlpair tag; + + if (MDOC_BODY != n->type) + return(1); + + /* XXX - this can contain block elements! */ + print_text(h, "\\(em"); + tag.key = ATTR_CLASS; + tag.val = "desc-body"; + print_otag(h, TAG_SPAN, 1, &tag); + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_op_pre(MDOC_ARGS) +{ + struct htmlpair tag; + + if (MDOC_BODY != n->type) + return(1); + + /* XXX - this can contain block elements! */ + print_text(h, "\\(lB"); + tag.key = ATTR_CLASS; + tag.val = "opt"; + print_otag(h, TAG_SPAN, 1, &tag); + return(1); +} + + +/* ARGSUSED */ +static void +mdoc_op_post(MDOC_ARGS) +{ + + if (MDOC_BODY != n->type) + return; + h->flags |= HTML_NOSPACE; + print_text(h, "\\(rB"); +} + + +static int +mdoc_nm_pre(MDOC_ARGS) +{ + struct htmlpair tag; + + if ( ! (HTML_NEWLINE & h->flags)) + if (SEC_SYNOPSIS == n->sec) { + tag.key = ATTR_STYLE; + tag.val = "clear: both;"; + print_otag(h, TAG_BR, 1, &tag); + } + + tag.key = ATTR_CLASS; + tag.val = "name"; + + print_otag(h, TAG_SPAN, 1, &tag); + if (NULL == n->child) + print_text(h, m->name); + + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_xr_pre(MDOC_ARGS) +{ + struct htmlpair tag[2]; + + tag[0].key = ATTR_CLASS; + tag[0].val = "link-man"; + tag[1].key = ATTR_HREF; + tag[1].val = "#"; /* TODO */ + + print_otag(h, TAG_A, 2, tag); + + n = n->child; + print_text(h, n->string); + if (NULL == (n = n->next)) + return(0); + + h->flags |= HTML_NOSPACE; + print_text(h, "("); + h->flags |= HTML_NOSPACE; + print_text(h, n->string); + h->flags |= HTML_NOSPACE; + print_text(h, ")"); + + return(0); +} + + +/* ARGSUSED */ +static int +mdoc_ns_pre(MDOC_ARGS) +{ + + h->flags |= HTML_NOSPACE; + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_ar_pre(MDOC_ARGS) +{ + struct htmlpair tag; + + tag.key = ATTR_CLASS; + tag.val = "arg"; + + print_otag(h, TAG_SPAN, 1, &tag); + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_xx_pre(MDOC_ARGS) +{ + const char *pp; + struct htmlpair tag; + + switch (n->tok) { + case (MDOC_Bsx): + pp = "BSDI BSD/OS"; + break; + case (MDOC_Dx): + pp = "DragonFlyBSD"; + break; + case (MDOC_Fx): + pp = "FreeBSD"; + break; + case (MDOC_Nx): + pp = "NetBSD"; + break; + case (MDOC_Ox): + pp = "OpenBSD"; + break; + case (MDOC_Ux): + pp = "UNIX"; + break; + default: + return(1); + } + + tag.key = ATTR_CLASS; + tag.val = "unix"; + + print_otag(h, TAG_SPAN, 1, &tag); + print_text(h, pp); + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_tbl_block_pre(MDOC_ARGS, int w, int o, int c) +{ + struct htmlpair tag; + + buffmt("margin-left: %dem; clear: both;", w + o); + + if ( ! c) + bufcat("padding-top: 1em;"); + + tag.key = ATTR_STYLE; + tag.val = buf; + print_otag(h, TAG_DIV, 1, &tag); + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_tbl_body_pre(MDOC_ARGS, int t, int w) +{ + struct htmlpair tag; + int i; + + switch (t) { + case (MDOC_Tag): + i = 1; + tag.key = ATTR_STYLE; + tag.val = buf; + bufcat("clear: right;"); + bufcat("float: left;"); + bufcat("width: 100%%;"); + break; + default: + i = 0; + break; + } + + print_otag(h, TAG_DIV, i, &tag); + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_tbl_head_pre(MDOC_ARGS, int t, int w) +{ + struct htmlpair tag; + int i; + + switch (t) { + case (MDOC_Hang): + /* FALLTHROUGH */ + case (MDOC_Tag): + i = 1; + tag.key = ATTR_STYLE; + tag.val = buf; + buffmt("margin-left: -%dem;", w); + bufcat("clear: left;"); + bufcat("float: left;"); + bufcat("padding-right: 1em;"); + break; + default: + i = 0; + break; + } + + print_otag(h, TAG_DIV, i, &tag); + return(1); +} + + +static int +mdoc_tbl_pre(MDOC_ARGS, int type) +{ + int i, w, o, c; + const struct mdoc_node *bl; + + bl = n->parent->parent; + if (MDOC_BLOCK != n->type) + bl = bl->parent; + + /* FIXME: fmt_vspace() equivalent. */ + + assert(bl->args); + + w = o = c = 0; + + for (i = 0; i < (int)bl->args->argc; i++) + if (MDOC_Width == bl->args->argv[i].arg) { + assert(bl->args->argv[i].sz); + w = a2width(bl->args->argv[i].value[0]); + } else if (MDOC_Offset == bl->args->argv[i].arg) { + assert(bl->args->argv[i].sz); + o = a2offs(bl->args->argv[i].value[0]); + } else if (MDOC_Compact == bl->args->argv[i].arg) + c = 1; + + if (0 == w) + w = 10; + + switch (n->type) { + case (MDOC_BLOCK): + break; + case (MDOC_HEAD): + return(mdoc_tbl_head_pre(m, n, h, type, w)); + case (MDOC_BODY): + return(mdoc_tbl_body_pre(m, n, h, type, w)); + default: + abort(); + /* NOTREACHED */ + } + + return(mdoc_tbl_block_pre(m, n, h, w, o, c)); +} + + +/* ARGSUSED */ +static int +mdoc_listitem_pre(MDOC_ARGS) +{ + int i, w, o, c; + const struct mdoc_node *bl; + struct htmlpair tag; + + /* FIXME: fmt_vspace() equivalent. */ + + if (MDOC_BLOCK != n->type) + return(1); + + bl = n->parent->parent; + assert(bl); + + w = o = c = 0; + + for (i = 0; i < (int)bl->args->argc; i++) + if (MDOC_Width == bl->args->argv[i].arg) { + assert(bl->args->argv[i].sz); + w = a2width(bl->args->argv[i].value[0]); + } else if (MDOC_Offset == bl->args->argv[i].arg) { + assert(bl->args->argv[i].sz); + o = a2offs(bl->args->argv[i].value[0]); + } else if (MDOC_Compact == bl->args->argv[i].arg) + c = 1; + + if (o && w) + buffmt("margin-left: %dem; padding-left: %dem;", o, w); + else if (w) + buffmt("padding-left: %dem;", w > 4 ? w - 4 : w); + else if (o) + buffmt("margin-left: %dem;", o); + + if ( ! c) + bufcat("padding-top: 1em;"); + + tag.key = ATTR_STYLE; + tag.val = buf; + + print_otag(h, TAG_LI, 1, &tag); + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_list_pre(MDOC_ARGS, int type) +{ + + switch (type) { + case (MDOC_Enum): + print_otag(h, TAG_OL, 0, NULL); + break; + case (MDOC_Bullet): + print_otag(h, TAG_UL, 0, NULL); + break; + default: + break; + } + + return(1); +} + + +static int +mdoc_bl_pre(MDOC_ARGS) +{ + int i, len, type; + + if (MDOC_BLOCK != n->type) + return(1); + + assert(n->args); + len = (int)n->args->argc; + + for (i = 0; i < len; i++) + switch ((type = n->args->argv[i].arg)) { + case (MDOC_Enum): + /* FALLTHROUGH */ + case (MDOC_Bullet): + return(mdoc_list_pre(m, n, h, type)); + case (MDOC_Tag): + /* FALLTHROUGH */ + case (MDOC_Hang): + /* FALLTHROUGH */ + case (MDOC_Dash): + /* FALLTHROUGH */ + case (MDOC_Hyphen): + /* FALLTHROUGH */ + case (MDOC_Inset): + /* FALLTHROUGH */ + case (MDOC_Diag): + /* FALLTHROUGH */ + case (MDOC_Item): + /* FALLTHROUGH */ + case (MDOC_Column): + /* FALLTHROUGH */ + case (MDOC_Ohang): + return(1); + default: + break; + } + + abort(); + /* NOTREACHED */ +} + + +static int +mdoc_it_pre(MDOC_ARGS) +{ + int i, len, type; + const struct mdoc_node *bl; + + if (MDOC_BLOCK == n->type) + bl = n->parent->parent; + else + bl = n->parent->parent->parent; + + assert(bl->args); + len = (int)bl->args->argc; + + for (i = 0; i < len; i++) + switch ((type = bl->args->argv[i].arg)) { + case (MDOC_Tag): + /* FALLTHROUGH */ + case (MDOC_Hang): + return(mdoc_tbl_pre(m, n, h, type)); + case (MDOC_Enum): + /* FALLTHROUGH */ + case (MDOC_Bullet): + return(mdoc_listitem_pre(m, n, h)); + case (MDOC_Dash): + /* FALLTHROUGH */ + case (MDOC_Hyphen): + /* FALLTHROUGH */ + case (MDOC_Inset): + /* FALLTHROUGH */ + case (MDOC_Diag): + /* FALLTHROUGH */ + case (MDOC_Item): + /* FALLTHROUGH */ + case (MDOC_Column): + /* FALLTHROUGH */ + case (MDOC_Ohang): + return(0); + default: + break; + } + + abort(); + /* NOTREACHED */ +} + + +/* ARGSUSED */ +static int +mdoc_ex_pre(MDOC_ARGS) +{ + const struct mdoc_node *nn; + struct tag *t; + struct htmlpair tag; + + print_text(h, "The"); + + tag.key = ATTR_CLASS; + tag.val = "utility"; + + for (nn = n->child; nn; nn = nn->next) { + t = print_otag(h, TAG_SPAN, 1, &tag); + print_text(h, nn->string); + print_tagq(h, t); + + h->flags |= HTML_NOSPACE; + + if (nn->next && NULL == nn->next->next) + print_text(h, ", and"); + else if (nn->next) + print_text(h, ","); + else + h->flags &= ~HTML_NOSPACE; + } + + if (n->child->next) + print_text(h, "utilities exit"); + else + print_text(h, "utility exits"); + + print_text(h, "0 on success, and >0 if an error occurs."); + return(0); +} + + +/* ARGSUSED */ +static int +mdoc_dq_pre(MDOC_ARGS) +{ + + if (MDOC_BODY != n->type) + return(1); + print_text(h, "\\(lq"); + h->flags |= HTML_NOSPACE; + return(1); +} + + +/* ARGSUSED */ +static void +mdoc_dq_post(MDOC_ARGS) +{ + + if (MDOC_BODY != n->type) + return; + h->flags |= HTML_NOSPACE; + print_text(h, "\\(rq"); +} + + +/* ARGSUSED */ +static int +mdoc_pq_pre(MDOC_ARGS) +{ + + if (MDOC_BODY != n->type) + return(1); + print_text(h, "\\&("); + h->flags |= HTML_NOSPACE; + return(1); +} + + +/* ARGSUSED */ +static void +mdoc_pq_post(MDOC_ARGS) +{ + + if (MDOC_BODY != n->type) + return; + print_text(h, ")"); +} + + +/* ARGSUSED */ +static int +mdoc_sq_pre(MDOC_ARGS) +{ + + if (MDOC_BODY != n->type) + return(1); + print_text(h, "\\(oq"); + h->flags |= HTML_NOSPACE; + return(1); +} + + +/* ARGSUSED */ +static void +mdoc_sq_post(MDOC_ARGS) +{ + + if (MDOC_BODY != n->type) + return; + h->flags |= HTML_NOSPACE; + print_text(h, "\\(aq"); +} + + +/* ARGSUSED */ +static int +mdoc_em_pre(MDOC_ARGS) +{ + struct htmlpair tag; + + tag.key = ATTR_CLASS; + tag.val = "emph"; + + print_otag(h, TAG_SPAN, 1, &tag); + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_d1_pre(MDOC_ARGS) +{ + struct htmlpair tag[2]; + + if (MDOC_BLOCK != n->type) + return(1); + + buffmt("margin-left: %dem;", INDENT); + bufcat("margin-bottom: 0px;"); + + tag[0].key = ATTR_CLASS; + tag[0].val = "lit-block"; + tag[1].key = ATTR_STYLE; + tag[1].val = buf; + + print_otag(h, TAG_DIV, 2, tag); + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_sx_pre(MDOC_ARGS) +{ + struct htmlpair tag[2]; + + tag[0].key = ATTR_HREF; + tag[0].val = "#"; /* XXX */ + tag[1].key = ATTR_CLASS; + tag[1].val = "link-sec"; + + print_otag(h, TAG_A, 2, tag); + return(1); }