=================================================================== RCS file: /cvs/mandoc/html.c,v retrieving revision 1.23 retrieving revision 1.40 diff -u -p -r1.23 -r1.40 --- mandoc/html.c 2008/12/10 12:09:47 1.23 +++ mandoc/html.c 2009/09/20 19:44:16 1.40 @@ -1,1056 +1,1900 @@ -/* $Id: html.c,v 1.23 2008/12/10 12:09:47 kristaps Exp $ */ +/* $Id: html.c,v 1.40 2009/09/20 19:44:16 kristaps Exp $ */ /* - * Copyright (c) 2008 Kristaps Dzonsons + * Copyright (c) 2008, 2009 Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the - * above copyright notice and this permission notice appear in all - * copies. + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL - * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE - * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR - * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * 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 #include +#include #include -#include -#include "html.h" -#include "ml.h" +#include "chars.h" +#include "mdoc.h" +#include "man.h" -/* TODO: allow head/tail-less invocations (just "div" start). */ +#define DOCTYPE "-//W3C//DTD HTML 4.01//EN" +#define DTD "http://www.w3.org/TR/html4/strict.dtd" -struct htmlnode { - int tok; - enum md_ns ns; - int argc[ROFF_MAXLINEARG]; - char *argv[ROFF_MAXLINEARG]; - struct htmlnode *parent; +#define INDENT 5 +#define HALFINDENT 3 +#define PX_MULT 8 + +enum htmltag { + TAG_HTML, + TAG_HEAD, + TAG_BODY, + TAG_META, + TAG_TITLE, + TAG_DIV, + TAG_H1, + TAG_H2, + 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 }; -struct htmlq { - struct htmlnode *last; +enum htmlattr { + ATTR_HTTPEQUIV, + ATTR_CONTENT, + ATTR_NAME, + ATTR_REL, + ATTR_HREF, + ATTR_TYPE, + ATTR_MEDIA, + ATTR_CLASS, + ATTR_STYLE, + ATTR_WIDTH, + ATTR_VALIGN, + ATTR_MAX }; +struct htmldata { + char *name; + int flags; +#define HTML_CLRLINE (1 << 0) +#define HTML_NOSTACK (1 << 1) +}; -static int html_loadcss(struct md_mbuf *, - const char *); -static int html_alloc(void **); -static void html_free(void *); -static ssize_t html_endtag(struct md_mbuf *, void *, - const struct md_args *, - enum md_ns, int); -static ssize_t html_beginstring(struct md_mbuf *, - const struct md_args *, - const char *, size_t); -static ssize_t html_beginhttp(struct md_mbuf *, - const struct md_args *, - const char *, size_t); -static ssize_t html_endstring(struct md_mbuf *, - const struct md_args *, - const char *, size_t); -static ssize_t html_endhttp(struct md_mbuf *, - const struct md_args *, - const char *, size_t); -static ssize_t html_begintag(struct md_mbuf *, void *, - const struct md_args *, - enum md_ns, int, - const int *, const char **); -static int html_begin(struct md_mbuf *, - const struct md_args *, - const struct tm *, - const char *, const char *, - enum roffmsec, enum roffvol); -static int html_printargs(struct md_mbuf *, int, - const char *, const int *, - const char **, size_t *); -static int html_end(struct md_mbuf *, - const struct md_args *, - const struct tm *, - const char *, const char *, - enum roffmsec, enum roffvol); -static int html_blocktagname(struct md_mbuf *, - const struct md_args *, int, - struct htmlq *, const int *, - const char **, size_t *); -static int html_blocktagargs(struct md_mbuf *, - const struct md_args *, int, - const int *, const char **, size_t *); -static int html_headtagname(struct md_mbuf *, - const struct md_args *, int, - struct htmlq *, const int *, - const char **, size_t *); -static int html_headtagargs(struct md_mbuf *, - const struct md_args *, int, - const int *, const char **, size_t *); -static int html_bodytagname(struct md_mbuf *, - const struct md_args *, - int, struct htmlq *, const int *, - const char **, size_t *); -static int html_bodytagargs(struct md_mbuf *, - const struct md_args *, int, - const int *, const char **, size_t *); -static int html_inlinetagname(struct md_mbuf *, - const struct md_args *, int, size_t *); -static int html_inlinetagargs(struct md_mbuf *, - const struct md_args *, int, - const int *, const char **, size_t *); -static int html_Bl_bodytagname(struct md_mbuf *, - struct htmlq *, const int *, - const char **, size_t *); -static int html_It_blocktagname(struct md_mbuf *, - struct htmlq *, const int *, - const char **, size_t *); -static int html_It_headtagname(struct md_mbuf *, - struct htmlq *, const int *, - const char **, size_t *); -static int html_It_bodytagname(struct md_mbuf *, - struct htmlq *, const int *, - const char **, size_t *); -static int html_tputln(struct md_mbuf *, - enum ml_scope, int, enum html_tag); -static int html_aputln(struct md_mbuf *, enum ml_scope, - int, enum html_tag, - int, const struct html_pair *); +static const struct htmldata htmltags[TAG_MAX] = { + {"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_CLRLINE}, /* TAG_P */ + {"span", 0}, /* TAG_SPAN */ + {"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] = { + "http-equiv", + "content", + "name", + "rel", + "href", + "type", + "media", + "class", + "style", + "width", + "valign", +}; +struct htmlpair { + enum htmlattr key; + char *val; +}; + +struct tag { + enum htmltag tag; + SLIST_ENTRY(tag) entry; +}; + +struct ord { + int pos; + const void *cookie; + SLIST_ENTRY(ord) entry; +}; + +SLIST_HEAD(tagq, tag); +SLIST_HEAD(ordq, ord); + +struct html { + int flags; +#define HTML_NOSPACE (1 << 0) +#define HTML_NEWLINE (1 << 1) + struct tagq tags; + struct ordq ords; + void *symtab; +}; + +#define MDOC_ARGS const struct mdoc_meta *m, \ + const struct mdoc_node *n, \ + struct html *h +#define MAN_ARGS const struct man_meta *m, \ + const struct man_node *n, \ + struct html *h +struct htmlmdoc { + int (*pre)(MDOC_ARGS); + void (*post)(MDOC_ARGS); +}; + +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_mdoc_nodelist(MDOC_ARGS); +static void print_man(MAN_ARGS); +static void print_man_head(MAN_ARGS); +static void print_man_body(MAN_ARGS); +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(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 a2list(const struct mdoc_node *); + +static void mdoc_root_post(MDOC_ARGS); +static int mdoc_root_pre(MDOC_ARGS); +static int mdoc_tbl_pre(MDOC_ARGS, int); +static int mdoc_tbl_block_pre(MDOC_ARGS, int, int, int, int); +static int mdoc_tbl_body_pre(MDOC_ARGS, int, int); +static int mdoc_tbl_head_pre(MDOC_ARGS, int, int); + +static void mdoc_aq_post(MDOC_ARGS); +static int mdoc_aq_pre(MDOC_ARGS); +static int mdoc_ar_pre(MDOC_ARGS); +static int mdoc_bd_pre(MDOC_ARGS); +static void mdoc_bl_post(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 int mdoc_ns_pre(MDOC_ARGS); +static void mdoc_op_post(MDOC_ARGS); +static int mdoc_op_pre(MDOC_ARGS); +static int mdoc_pa_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 void mdoc_qq_post(MDOC_ARGS); +static int mdoc_qq_pre(MDOC_ARGS); +static int mdoc_sh_pre(MDOC_ARGS); +static void mdoc_sq_post(MDOC_ARGS); +static int mdoc_sq_pre(MDOC_ARGS); +static int mdoc_ss_pre(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] = { + {mdoc_pp_pre, NULL}, /* Ap */ + {NULL, NULL}, /* Dd */ + {NULL, NULL}, /* Dt */ + {NULL, NULL}, /* Os */ + {mdoc_sh_pre, NULL }, /* Sh */ + {mdoc_ss_pre, NULL }, /* Ss */ + {mdoc_pp_pre, NULL}, /* Pp */ + {mdoc_d1_pre, NULL}, /* D1 */ + {mdoc_d1_pre, NULL}, /* Dl */ + {mdoc_bd_pre, NULL}, /* Bd */ + {NULL, NULL}, /* Ed */ + {mdoc_bl_pre, mdoc_bl_post}, /* Bl */ + {NULL, NULL}, /* El */ + {mdoc_it_pre, NULL}, /* It */ + {NULL, NULL}, /* Ad */ + {NULL, NULL}, /* An */ + {mdoc_ar_pre, NULL}, /* Ar */ + {NULL, NULL}, /* Cd */ + {NULL, NULL}, /* Cm */ + {NULL, NULL}, /* Dv */ + {NULL, NULL}, /* Er */ + {NULL, NULL}, /* Ev */ + {mdoc_ex_pre, NULL}, /* Ex */ + {NULL, NULL}, /* Fa */ + {NULL, NULL}, /* Fd */ + {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, NULL}, /* Nm */ + {mdoc_op_pre, mdoc_op_post}, /* Op */ + {NULL, NULL}, /* Ot */ + {mdoc_pa_pre, NULL}, /* Pa */ + {NULL, NULL}, /* Rv */ + {NULL, NULL}, /* St */ + {NULL, NULL}, /* Va */ + {NULL, NULL}, /* Vt */ + {mdoc_xr_pre, NULL}, /* Xr */ + {NULL, NULL}, /* %A */ + {NULL, NULL}, /* %B */ + {NULL, NULL}, /* %D */ + {NULL, NULL}, /* %I */ + {NULL, NULL}, /* %J */ + {NULL, NULL}, /* %N */ + {NULL, NULL}, /* %O */ + {NULL, NULL}, /* %P */ + {NULL, NULL}, /* %R */ + {NULL, NULL}, /* %T */ + {NULL, NULL}, /* %V */ + {NULL, NULL}, /* Ac */ + {mdoc_aq_pre, mdoc_aq_post}, /* Ao */ + {mdoc_aq_pre, mdoc_aq_post}, /* Aq */ + {NULL, NULL}, /* At */ + {NULL, NULL}, /* Bc */ + {NULL, NULL}, /* Bf */ + {NULL, NULL}, /* Bo */ + {NULL, NULL}, /* Bq */ + {mdoc_xx_pre, NULL}, /* Bsx */ + {NULL, NULL}, /* Bx */ + {NULL, NULL}, /* Db */ + {NULL, NULL}, /* Dc */ + {NULL, NULL}, /* Do */ + {mdoc_dq_pre, mdoc_dq_post}, /* Dq */ + {NULL, NULL}, /* Ec */ + {NULL, NULL}, /* Ef */ + {mdoc_em_pre, NULL}, /* Em */ + {NULL, NULL}, /* Eo */ + {mdoc_xx_pre, NULL}, /* Fx */ + {NULL, NULL}, /* Ms */ + {NULL, NULL}, /* No */ + {mdoc_ns_pre, NULL}, /* Ns */ + {mdoc_xx_pre, NULL}, /* Nx */ + {mdoc_xx_pre, NULL}, /* Ox */ + {NULL, NULL}, /* Pc */ + {NULL, NULL}, /* Pf */ + {mdoc_pq_pre, mdoc_pq_post}, /* Po */ + {mdoc_pq_pre, mdoc_pq_post}, /* Pq */ + {NULL, NULL}, /* Qc */ + {NULL, NULL}, /* Ql */ + {mdoc_qq_pre, mdoc_qq_post}, /* Qo */ + {mdoc_qq_pre, mdoc_qq_post}, /* Qq */ + {NULL, NULL}, /* Re */ + {NULL, NULL}, /* Rs */ + {NULL, NULL}, /* Sc */ + {mdoc_sq_pre, mdoc_sq_post}, /* So */ + {mdoc_sq_pre, mdoc_sq_post}, /* Sq */ + {NULL, NULL}, /* Sm */ + {mdoc_sx_pre, NULL}, /* Sx */ + {NULL, NULL}, /* Sy */ + {NULL, NULL}, /* Tn */ + {mdoc_xx_pre, NULL}, /* Ux */ + {NULL, NULL}, /* Xc */ + {NULL, NULL}, /* Xo */ + {NULL, NULL}, /* Fo */ + {NULL, NULL}, /* Fc */ + {NULL, NULL}, /* Oo */ + {NULL, NULL}, /* Oc */ + {NULL, NULL}, /* Bk */ + {NULL, NULL}, /* Ek */ + {NULL, NULL}, /* Bt */ + {NULL, NULL}, /* Hf */ + {NULL, NULL}, /* Fr */ + {NULL, NULL}, /* Ud */ + {NULL, NULL}, /* Lb */ + {NULL, NULL}, /* Lp */ + {NULL, NULL}, /* Lk */ + {NULL, NULL}, /* Mt */ + {NULL, NULL}, /* Brq */ + {NULL, NULL}, /* Bro */ + {NULL, NULL}, /* Brc */ + {NULL, NULL}, /* %C */ + {NULL, NULL}, /* Es */ + {NULL, NULL}, /* En */ + {mdoc_xx_pre, NULL}, /* Dx */ + {NULL, NULL}, /* %Q */ + {NULL, NULL}, /* br */ + {NULL, NULL}, /* sp */ +}; + +static char buf[BUFSIZ]; /* XXX */ + +#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); + t = print_otag(h, TAG_HTML, 0, NULL); + print_mdoc(mdoc_meta(m), mdoc_node(m), h); + print_tagq(h, t); + + printf("\n"); +} + + +void +html_man(void *arg, const struct man *m) +{ + struct html *h; + struct tag *t; + + h = (struct html *)arg; + + print_gen_doctype(h); + t = print_otag(h, TAG_HTML, 0, NULL); + print_man(man_meta(m), man_node(m), h); + print_tagq(h, t); + + printf("\n"); +} + + +void * +html_alloc(void) +{ + struct html *h; + + if (NULL == (h = calloc(1, sizeof(struct html)))) + return(NULL); + + SLIST_INIT(&h->tags); + SLIST_INIT(&h->ords); + + if (NULL == (h->symtab = chars_init(CHARS_HTML))) { + free(h); + return(NULL); + } + return(h); +} + + +void +html_free(void *p) +{ + struct tag *tag; + struct ord *ord; + struct html *h; + + h = (struct html *)p; + + while ( ! SLIST_EMPTY(&h->ords)) { + ord = SLIST_FIRST(&h->ords); + SLIST_REMOVE_HEAD(&h->ords, entry); + free(ord); + } + + while ( ! SLIST_EMPTY(&h->tags)) { + tag = SLIST_FIRST(&h->tags); + SLIST_REMOVE_HEAD(&h->tags, entry); + free(tag); + } + + if (h->symtab) + chars_free(h->symtab); + free(h); +} + + +static void +print_mdoc(MDOC_ARGS) +{ + struct tag *t; + + t = print_otag(h, TAG_HEAD, 0, NULL); + print_mdoc_head(m, n, h); + print_tagq(h, t); + + t = print_otag(h, TAG_BODY, 0, NULL); + print_mdoc_title(m, n, h); + print_mdoc_nodelist(m, n, h); + print_tagq(h, t); +} + + +static void +print_gen_head(struct html *h) +{ + struct htmlpair meta0[2]; + struct htmlpair meta1[2]; + struct htmlpair link[4]; + + meta0[0].key = ATTR_HTTPEQUIV; + meta0[0].val = "Content-Type"; + meta0[1].key = ATTR_CONTENT; + meta0[1].val = "text/html; charset=utf-8"; + + meta1[0].key = ATTR_NAME; + meta1[0].val = "resource-type"; + meta1[1].key = ATTR_CONTENT; + meta1[1].val = "document"; + + link[0].key = ATTR_REL; + link[0].val = "stylesheet"; + link[1].key = ATTR_HREF; + link[1].val = "style.css"; /* XXX */ + link[2].key = ATTR_TYPE; + link[2].val = "text/css"; + link[3].key = ATTR_MEDIA; + link[3].val = "all"; + + print_otag(h, TAG_META, 2, meta0); + print_otag(h, TAG_META, 2, meta1); + print_otag(h, TAG_LINK, 4, link); +} + + /* ARGSUSED */ -static int -html_It_headtagname(struct md_mbuf *mbuf, struct htmlq *q, - const int *argc, const char **argv, size_t *res) +static void +print_mdoc_head(MDOC_ARGS) { - struct htmlnode *n; - int i; - for (n = q->last; n; n = n->parent) - if (n->tok == ROFF_Bl) - break; + print_gen_head(h); + print_otag(h, TAG_TITLE, 0, NULL); + print_encode(h, m->title); +} - assert(n); - /* LINTED */ - for (i = 0; ROFF_ARGMAX != n->argc[i] && - i < ROFF_MAXLINEARG; i++) { - switch (n->argc[i]) { - case (ROFF_Ohang): - return(html_stput(mbuf, HTML_TAG_DIV, res)); - case (ROFF_Tag): - /* FALLTHROUGH */ - case (ROFF_Column): - return(html_stput(mbuf, HTML_TAG_TD, res)); - default: - break; - } +/* ARGSUSED */ +static void +print_mdoc_title(MDOC_ARGS) +{ + + /* TODO */ +} + + +static void +print_mdoc_nodelist(MDOC_ARGS) +{ + + print_mdoc_node(m, n, h); + if (n->next) + print_mdoc_nodelist(m, n->next, h); +} + + +static void +print_mdoc_node(MDOC_ARGS) +{ + int child; + struct tag *t; + + child = 1; + t = SLIST_FIRST(&h->tags); + + bufinit(); + + switch (n->type) { + case (MDOC_ROOT): + child = mdoc_root_pre(m, n, h); + break; + case (MDOC_TEXT): + print_text(h, n->string); + break; + default: + if (mdocs[n->tok].pre) + child = (*mdocs[n->tok].pre)(m, n, h); + break; } - return(0); + if (child && n->child) + print_mdoc_nodelist(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; + default: + if (mdocs[n->tok].post) + (*mdocs[n->tok].post)(m, n, h); + break; + } } +static void +print_man(MAN_ARGS) +{ + struct tag *t; + + t = print_otag(h, TAG_HEAD, 0, NULL); + print_man_head(m, n, h); + print_tagq(h, t); + + t = print_otag(h, TAG_BODY, 0, NULL); + print_man_body(m, n, h); + print_tagq(h, t); +} + + /* ARGSUSED */ -static int -html_It_bodytagname(struct md_mbuf *mbuf, struct htmlq *q, - const int *argc, const char **argv, size_t *res) +static void +print_man_head(MAN_ARGS) { - struct htmlnode *n; + + print_gen_head(h); + print_otag(h, TAG_TITLE, 0, NULL); + print_encode(h, m->title); +} + + +/* ARGSUSED */ +static void +print_man_body(MAN_ARGS) +{ + + /* TODO */ +} + + +static void +print_spec(struct html *h, const char *p, int len) +{ + const char *rhs; int i; + size_t sz; - for (n = q->last; n; n = n->parent) - if (n->tok == ROFF_Bl) - break; + rhs = chars_a2ascii(h->symtab, p, (size_t)len, &sz); - assert(n); + if (NULL == rhs) + return; + for (i = 0; i < (int)sz; i++) + putchar(rhs[i]); +} - /* LINTED */ - for (i = 0; ROFF_ARGMAX != n->argc[i] && - i < ROFF_MAXLINEARG; i++) { - switch (n->argc[i]) { - case (ROFF_Enum): + +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 (ROFF_Bullet): - /* FALLTHROUGH */ - case (ROFF_Dash): - /* FALLTHROUGH */ - case (ROFF_Hyphen): - /* FALLTHROUGH */ - case (ROFF_Item): - /* FALLTHROUGH */ - case (ROFF_Diag): - /* FALLTHROUGH */ - case (ROFF_Hang): - /* FALLTHROUGH */ - case (ROFF_Ohang): - /* FALLTHROUGH */ - case (ROFF_Inset): - return(html_stput(mbuf, HTML_TAG_DIV, res)); - case (ROFF_Tag): - /* FALLTHROUGH */ - case (ROFF_Column): - return(html_stput(mbuf, HTML_TAG_TD, res)); + case ('R'): + /* TODO */ + break; default: break; } + + *p = wp; + return; + + } else if ('[' != *wp) { + print_spec(h, wp, 1); + *p = wp; + return; } - assert(i != ROFF_MAXLINEARG); - return(0); + 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; } -/* ARGSUSED */ -static int -html_Bl_bodytagname(struct md_mbuf *mbuf, struct htmlq *q, - const int *argc, const char **argv, size_t *res) +static void +print_encode(struct html *h, const char *p) { - int i; - for (i = 0; ROFF_ARGMAX != argc[i] - && i < ROFF_MAXLINEARG; i++) { - switch (argc[i]) { - case (ROFF_Enum): - return(html_stput(mbuf, HTML_TAG_OL, res)); - case (ROFF_Bullet): - /* FALLTHROUGH */ - case (ROFF_Dash): - /* FALLTHROUGH */ - case (ROFF_Hyphen): - /* FALLTHROUGH */ - case (ROFF_Item): - /* FALLTHROUGH */ - case (ROFF_Diag): - /* FALLTHROUGH */ - case (ROFF_Hang): - /* FALLTHROUGH */ - case (ROFF_Ohang): - /* FALLTHROUGH */ - case (ROFF_Inset): - return(html_stput(mbuf, HTML_TAG_UL, res)); - case (ROFF_Tag): - /* FALLTHROUGH */ - case (ROFF_Column): - return(html_stput(mbuf, HTML_TAG_TABLE, res)); + 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; } } +} - assert(i != ROFF_MAXLINEARG); - return(0); + +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->tags, t, entry); + } else + t = NULL; + + if ( ! (HTML_NOSPACE & h->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(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); } /* ARGSUSED */ -static int -html_It_blocktagname(struct md_mbuf *mbuf, struct htmlq *q, - const int *argc, const char **argv, size_t *res) +static void +print_ctag(struct html *h, enum htmltag tag) { - struct htmlnode *n; - int i; + + printf("", htmltags[tag].name); + 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; +} - for (n = q->last; n; n = n->parent) - if (n->tok == ROFF_Bl) - break; - assert(n); +/* ARGSUSED */ +static void +print_gen_doctype(struct html *h) +{ + + printf("\n", DOCTYPE, DTD); +} - /* LINTED */ - for (i = 0; ROFF_ARGMAX != n->argc[i] && - i < ROFF_MAXLINEARG; i++) { - switch (n->argc[i]) { - case (ROFF_Enum): + +static void +print_text(struct html *h, const char *p) +{ + + if (*p && 0 == *(p + 1)) + switch (*p) { + case('.'): /* FALLTHROUGH */ - case (ROFF_Bullet): + case(','): /* FALLTHROUGH */ - case (ROFF_Dash): + case(';'): /* FALLTHROUGH */ - case (ROFF_Hyphen): + case(':'): /* FALLTHROUGH */ - case (ROFF_Item): + case('?'): /* FALLTHROUGH */ - case (ROFF_Diag): + case('!'): /* FALLTHROUGH */ - case (ROFF_Hang): + case(')'): /* FALLTHROUGH */ - case (ROFF_Ohang): + case(']'): /* FALLTHROUGH */ - case (ROFF_Inset): - return(html_stput(mbuf, HTML_TAG_LI, res)); - case (ROFF_Tag): - /* FALLTHROUGH */ - case (ROFF_Column): - return(html_stput(mbuf, HTML_TAG_TR, res)); + case('}'): + h->flags |= HTML_NOSPACE; + break; default: break; } - } - assert(i != ROFF_MAXLINEARG); - return(0); -} + if ( ! (h->flags & HTML_NOSPACE)) + printf(" "); + h->flags &= ~HTML_NOSPACE; + h->flags &= ~HTML_NEWLINE; -static int -html_loadcss(struct md_mbuf *mbuf, const char *css) -{ - size_t res, bufsz; - char *buf; - struct stat st; - int fd, c; - ssize_t ssz; + if (p) + print_encode(h, p); - c = 0; - res = 0; - buf = NULL; + if (*p && 0 == *(p + 1)) + switch (*p) { + case('('): + /* FALLTHROUGH */ + case('['): + /* FALLTHROUGH */ + case('{'): + h->flags |= HTML_NOSPACE; + break; + default: + break; + } +} - if (-1 == (fd = open(css, O_RDONLY, 0))) { - warn("%s", css); - return(0); - } - - if (-1 == fstat(fd, &st)) { - warn("%s", css); - goto out; - } - bufsz = MAX(st.st_blksize, BUFSIZ); - if (NULL == (buf = malloc(bufsz))) { - warn("malloc"); - goto out; - } +static void +print_tagq(struct html *h, const struct tag *until) +{ + struct tag *tag; - for (;;) { - if (-1 == (ssz = read(fd, buf, bufsz))) { - warn("%s", css); - goto out; - } else if (0 == ssz) - break; - if ( ! ml_nputs(mbuf, buf, (size_t)ssz, &res)) - goto out; + while ( ! SLIST_EMPTY(&h->tags)) { + tag = SLIST_FIRST(&h->tags); + print_ctag(h, tag->tag); + SLIST_REMOVE_HEAD(&h->tags, entry); + free(tag); + if (until && tag == until) + return; } +} - c = 1; -out: - if (-1 == close(fd)) { - warn("%s", css); - c = 0; - } +static void +print_stagq(struct html *h, const struct tag *suntil) +{ + struct tag *tag; - if (buf) - free(buf); - - return(c); + while ( ! SLIST_EMPTY(&h->tags)) { + tag = SLIST_FIRST(&h->tags); + if (suntil && tag == suntil) + return; + print_ctag(h, tag->tag); + SLIST_REMOVE_HEAD(&h->tags, entry); + free(tag); + } } +/* FIXME: put in utility file for front-ends. */ static int -html_tputln(struct md_mbuf *mbuf, enum ml_scope scope, - int i, enum html_tag tag) +a2offs(const char *p) { + int len, i; - if ( ! ml_putchars(mbuf, ' ', INDENT(i) * INDENT_SZ, NULL)) + if (0 == strcmp(p, "left")) return(0); - if ( ! html_tput(mbuf, scope, tag, NULL)) + 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); - return(ml_nputs(mbuf, "\n", 1, NULL)); -} + for (i = 0; i < len - 1; i++) + if ( ! isdigit((u_char)p[i])) + break; -static int -html_aputln(struct md_mbuf *mbuf, enum ml_scope scope, int i, - enum html_tag tag, int sz, const struct html_pair *p) -{ + if (i == len - 1) + if ('n' == p[len - 1] || 'm' == p[len - 1]) + return(atoi(p)); - if ( ! ml_putchars(mbuf, ' ', INDENT(i) * INDENT_SZ, NULL)) - return(0); - if ( ! html_aput(mbuf, scope, tag, NULL, sz, p)) - return(0); - return(ml_nputs(mbuf, "\n", 1, NULL)); + return(len); } -/* ARGSUSED */ -static int -html_begin(struct md_mbuf *mbuf, const struct md_args *args, - const struct tm *tm, const char *os, - const char *name, enum roffmsec msec, enum roffvol vol) +/* FIXME: put in utility file for front-ends. */ +static int +a2list(const struct mdoc_node *bl) { - enum roffvol bvol; - struct html_pair attr[4]; - char ts[32], title[64]; int i; - (void)snprintf(ts, sizeof(ts), "%s(%s)", - name, roff_msecname(msec)); + assert(MDOC_BLOCK == bl->type && MDOC_Bl == bl->tok); + assert(bl->args); - if (vol >= ROFF_ARCH_START) { - switch (msec) { - case(ROFF_MSEC_1): + for (i = 0; i < (int)bl->args->argc; i++) + switch (bl->args->argv[i].arg) { + case (MDOC_Enum): /* FALLTHROUGH */ - case(ROFF_MSEC_6): + case (MDOC_Dash): /* FALLTHROUGH */ - case(ROFF_MSEC_7): - bvol = ROFF_VOL_URM; - break; - case(ROFF_MSEC_2): + case (MDOC_Hyphen): /* FALLTHROUGH */ - case(ROFF_MSEC_3): + case (MDOC_Bullet): /* FALLTHROUGH */ - case(ROFF_MSEC_3p): + case (MDOC_Tag): /* FALLTHROUGH */ - case(ROFF_MSEC_4): + case (MDOC_Hang): /* FALLTHROUGH */ - case(ROFF_MSEC_5): - bvol = ROFF_VOL_PRM; - break; - case(ROFF_MSEC_8): - bvol = ROFF_VOL_PRM; - break; - case(ROFF_MSEC_9): - bvol = ROFF_VOL_KM; - break; - case(ROFF_MSEC_UNASS): + case (MDOC_Inset): /* FALLTHROUGH */ - case(ROFF_MSEC_DRAFT): + case (MDOC_Diag): /* FALLTHROUGH */ - case(ROFF_MSEC_PAPER): - bvol = ROFF_VOL_NONE; - break; + case (MDOC_Item): + /* FALLTHROUGH */ + case (MDOC_Column): + /* FALLTHROUGH */ + case (MDOC_Ohang): + return(bl->args->argv[i].arg); default: - abort(); - /* NOTREACHED */ + break; } - (void)snprintf(title, sizeof(title), "%s (%s)", - roff_volname(bvol), roff_volname(vol)); - } else - (void)snprintf(title, sizeof(title), "%s", roff_volname(vol)); + abort(); + /* NOTREACHED */ +} - i = 0; +/* FIXME: put in utility file for front-ends. */ +static int +a2width(const char *p) +{ + int i, len; - if ( ! html_typeput(mbuf, HTML_TYPE_4_01_STRICT, NULL)) + if (0 == (len = (int)strlen(p))) return(0); - if ( ! html_tputln(mbuf, ML_OPEN, i, HTML_TAG_HTML)) - return(0); - if ( ! html_tputln(mbuf, ML_OPEN, i++, HTML_TAG_HEAD)) - return(0); + for (i = 0; i < len - 1; i++) + if ( ! isdigit((u_char)p[i])) + break; - attr[0].attr = HTML_ATTR_HTTP_EQUIV; - attr[0].val = "content-type"; - attr[1].attr = HTML_ATTR_CONTENT; - attr[1].val = "text/html;charset=utf-8"; + if (i == len - 1) + if ('n' == p[len - 1] || 'm' == p[len - 1]) + return(atoi(p) + 2); - if ( ! html_aputln(mbuf, ML_OPEN, i, HTML_TAG_META, 2, attr)) - return(0); + return(len + 2); +} - attr[0].attr = HTML_ATTR_NAME; - attr[0].val = "resource-type"; - attr[1].attr = HTML_ATTR_CONTENT; - attr[1].val = "document"; - if ( ! html_aputln(mbuf, ML_OPEN, i, HTML_TAG_META, 2, attr)) - return(0); +/* FIXME: parts should be in a utility file for front-ends. */ +/* ARGSUSED */ +static void +mdoc_root_post(MDOC_ARGS) +{ + struct tm *tm; + struct htmlpair tag; + struct tag *t; + char b[BUFSIZ], os[BUFSIZ]; - if ( ! html_tputln(mbuf, ML_OPEN, i, HTML_TAG_TITLE)) - return(0); - if ( ! ml_putstring(mbuf, ts, NULL)) - return(0); - if ( ! html_tputln(mbuf, ML_CLOSE, i, HTML_TAG_TITLE)) - return(0); + tm = localtime(&m->date); - if (HTML_CSS_EMBED & args->params.html.flags) { - attr[0].attr = HTML_ATTR_TYPE; - attr[0].val = "text/css"; + if (0 == strftime(b, BUFSIZ - 1, "%B %e, %Y", tm)) + err(EXIT_FAILURE, "strftime"); - if ( ! html_aputln(mbuf, ML_OPEN, i, - HTML_TAG_STYLE, 1, attr)) - return(0); - if ( ! html_commentput(mbuf, ML_OPEN, NULL)) - return(0); + strlcpy(os, m->os, BUFSIZ); - if ( ! html_loadcss(mbuf, args->params.html.css)) - return(0); + tag.key = ATTR_CLASS; + tag.val = "foot"; - if ( ! html_commentput(mbuf, ML_CLOSE, NULL)) - return(0); - if ( ! html_tputln(mbuf, ML_CLOSE, i, HTML_TAG_STYLE)) - return(0); - } else { - attr[0].attr = HTML_ATTR_REL; - attr[0].val = "stylesheet"; - attr[1].attr = HTML_ATTR_TYPE; - attr[1].val = "text/css"; - attr[2].attr = HTML_ATTR_HREF; - attr[2].val = args->params.html.css; + t = print_otag(h, TAG_DIV, 1, &tag); - if ( ! html_aputln(mbuf, ML_OPEN, i, - HTML_TAG_LINK, 3, attr)) - return(0); - } + tag.key = ATTR_STYLE; + tag.val = "width: 49%; display: " + "inline-block; text-align: left;"; + print_otag(h, TAG_SPAN, 1, &tag); + print_text(h, b); + print_stagq(h, t); - if ( ! html_tputln(mbuf, ML_CLOSE, --i, HTML_TAG_HEAD)) - return(0); - if ( ! html_tputln(mbuf, ML_OPEN, i, HTML_TAG_BODY)) - return(0); + tag.key = ATTR_STYLE; + tag.val = "width: 49%; display: " + "inline-block; text-align: right;"; + print_otag(h, TAG_SPAN, 1, &tag); + print_text(h, os); + print_tagq(h, t); - attr[0].attr = HTML_ATTR_CLASS; - attr[0].val = "mdoc"; +} - if ( ! html_aputln(mbuf, ML_OPEN, i, HTML_TAG_DIV, 1, attr)) - return(0); - attr[0].attr = HTML_ATTR_WIDTH; - attr[0].val = "100%"; - attr[1].attr = HTML_ATTR_CLASS; - attr[1].val = "header-table"; +/* FIXME: parts should be in a utility file for front-ends. */ +/* ARGSUSED */ +static int +mdoc_root_pre(MDOC_ARGS) +{ + struct htmlpair tag; + struct tag *t, *tt; + char b[BUFSIZ], title[BUFSIZ]; - if ( ! html_aputln(mbuf, ML_OPEN, i++, HTML_TAG_TABLE, 2, attr)) - return(0); - if ( ! html_tputln(mbuf, ML_OPEN, i++, HTML_TAG_TR)) - return(0); + assert(m->vol); + (void)strlcpy(b, m->vol, BUFSIZ); - attr[0].attr = HTML_ATTR_ALIGN; - attr[0].val = "left"; - attr[1].attr = HTML_ATTR_CLASS; - attr[1].val = "header-section"; + if (m->arch) { + strlcat(b, " (", BUFSIZ); + strlcat(b, m->arch, BUFSIZ); + strlcat(b, ")", BUFSIZ); + } - if ( ! html_aputln(mbuf, ML_OPEN, i, HTML_TAG_TD, 2, attr)) - return(0); - if ( ! ml_putstring(mbuf, ts, NULL)) - return(0); - if ( ! html_tputln(mbuf, ML_CLOSE, i, HTML_TAG_TD)) - return(0); + snprintf(title, BUFSIZ - 1, "%s(%d)", m->title, m->msec); - attr[0].attr = HTML_ATTR_ALIGN; - attr[0].val = "center"; - attr[1].attr = HTML_ATTR_CLASS; - attr[1].val = "header-volume"; + tag.key = ATTR_CLASS; + tag.val = "body"; - if ( ! html_aputln(mbuf, ML_OPEN, i, HTML_TAG_TD, 2, attr)) - return(0); - if ( ! ml_putstring(mbuf, title, NULL)) - return(0); - if ( ! html_tputln(mbuf, ML_CLOSE, i, HTML_TAG_TD)) - return(0); + t = print_otag(h, TAG_DIV, 1, &tag); - attr[0].attr = HTML_ATTR_ALIGN; - attr[0].val = "right"; - attr[1].attr = HTML_ATTR_CLASS; - attr[1].val = "header-section"; + tag.key = ATTR_CLASS; + tag.val = "head"; - if ( ! html_aputln(mbuf, ML_OPEN, i, HTML_TAG_TD, 2, attr)) - return(0); - if ( ! ml_putstring(mbuf, ts, NULL)) - return(0); - if ( ! html_tputln(mbuf, ML_CLOSE, i, HTML_TAG_TD)) - return(0); + tt = print_otag(h, TAG_DIV, 1, &tag); - if ( ! html_tputln(mbuf, ML_CLOSE, --i, HTML_TAG_TR)) - return(0); - return(html_tputln(mbuf, ML_CLOSE, --i, HTML_TAG_TABLE)); + tag.key = ATTR_STYLE; + tag.val = "width: 32%; text-align: left; " + "display: inline-block;"; + print_otag(h, TAG_SPAN, 1, &tag); + print_text(h, b); + print_stagq(h, tt); + + tag.key = ATTR_STYLE; + tag.val = "width: 32%; text-align: center; " + "display: inline-block;"; + print_otag(h, TAG_SPAN, 1, &tag); + print_text(h, title); + print_stagq(h, tt); + + tag.key = ATTR_STYLE; + tag.val = "width: 32%; text-align: right; " + "display: inline-block;"; + print_otag(h, TAG_SPAN, 1, &tag); + print_text(h, b); + print_stagq(h, t); + + return(1); } /* ARGSUSED */ -static int -html_end(struct md_mbuf *mbuf, const struct md_args *args, - const struct tm *tm, const char *os, - const char *name, enum roffmsec msec, enum roffvol vol) +static int +mdoc_sh_pre(MDOC_ARGS) { - struct html_pair attr[4]; - int i; - char ts[64]; + struct htmlpair tag[2]; - if (0 == strftime(ts, sizeof(ts), "%B %d, %Y", tm)) { - warn("strftime"); - return(0); + 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"; + + if (n->prev && NULL == n->prev->body->child) { + print_otag(h, TAG_DIV, 1, tag); + return(1); + } + + bufcat("margin-top: 1em;"); + if (NULL == n->next) + bufcat("margin-bottom: 1em;"); + + tag[1].key = ATTR_STYLE; + tag[1].val = buf; + + print_otag(h, TAG_DIV, 2, tag); + return(1); } - i = 0; + buffmt("margin-left: %dem;", INDENT); + + tag[0].key = ATTR_CLASS; + tag[0].val = "sec-body"; + tag[1].key = ATTR_STYLE; + tag[1].val = buf; - attr[0].attr = HTML_ATTR_WIDTH; - attr[0].val = "100%"; - attr[1].attr = HTML_ATTR_CLASS; - attr[1].val = "header-footer"; + print_otag(h, TAG_DIV, 2, tag); + return(1); +} - if ( ! html_aputln(mbuf, ML_OPEN, i++, HTML_TAG_TABLE, 2, attr)) - return(0); - if ( ! html_tputln(mbuf, ML_OPEN, i++, HTML_TAG_TR)) - return(0); - attr[0].attr = HTML_ATTR_ALIGN; - attr[0].val = "left"; - attr[1].attr = HTML_ATTR_CLASS; - attr[1].val = "footer-os"; +/* ARGSUSED */ +static int +mdoc_ss_pre(MDOC_ARGS) +{ + struct htmlpair tag[2]; + int i; - if ( ! html_aputln(mbuf, ML_OPEN, i, HTML_TAG_TD, 2, attr)) - return(0); - if ( ! ml_putstring(mbuf, os, NULL)) - return(0); - if ( ! html_tputln(mbuf, ML_CLOSE, i, HTML_TAG_TD)) - return(0); + i = 0; - attr[0].attr = HTML_ATTR_ALIGN; - attr[0].val = "right"; - attr[1].attr = HTML_ATTR_CLASS; - attr[1].val = "footer-date"; + 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); + } - if ( ! html_aputln(mbuf, ML_OPEN, i, HTML_TAG_TD, 2, attr)) - return(0); - if ( ! ml_putstring(mbuf, ts, NULL)) - return(0); - if ( ! html_tputln(mbuf, ML_CLOSE, i, HTML_TAG_TD)) - return(0); + buffmt("margin-left: -%dem;", INDENT - HALFINDENT); - if ( ! html_tputln(mbuf, ML_CLOSE, --i, HTML_TAG_TR)) - return(0); - if ( ! html_tputln(mbuf, ML_CLOSE, --i, HTML_TAG_TABLE)) - return(0); + tag[0].key = ATTR_CLASS; + tag[0].val = "ssec-head"; + tag[1].key = ATTR_STYLE; + tag[1].val = buf; - if ( ! html_tputln(mbuf, ML_CLOSE, 0, HTML_TAG_DIV)) - return(0); - if ( ! html_tputln(mbuf, ML_CLOSE, 0, HTML_TAG_BODY)) - return(0); - return(html_tputln(mbuf, ML_CLOSE, 0, HTML_TAG_HTML)); + print_otag(h, TAG_DIV, 2, tag); + print_otag(h, TAG_SPAN, 1, tag); + return(1); } /* ARGSUSED */ static int -html_bodytagname(struct md_mbuf *mbuf, - const struct md_args *args, int tok, struct htmlq *q, - const int *argc, const char **argv, size_t *res) +mdoc_fl_pre(MDOC_ARGS) { + struct htmlpair tag; - switch (tok) { - case (ROFF_Bl): - return(html_Bl_bodytagname(mbuf, q, argc, argv, res)); - case (ROFF_Fo): - return(html_stput(mbuf, HTML_TAG_SPAN, res)); - case (ROFF_It): - return(html_It_bodytagname(mbuf, q, argc, argv, res)); - case (ROFF_Oo): - return(html_stput(mbuf, HTML_TAG_SPAN, res)); - default: - break; - } + tag.key = ATTR_CLASS; + tag.val = "flag"; - return(html_stput(mbuf, HTML_TAG_DIV, res)); + print_otag(h, TAG_SPAN, 1, &tag); + print_text(h, "\\-"); + h->flags |= HTML_NOSPACE; + return(1); } /* ARGSUSED */ static int -html_headtagname(struct md_mbuf *mbuf, - const struct md_args *args, int tok, struct htmlq *q, - const int *argc, const char **argv, size_t *res) +mdoc_pp_pre(MDOC_ARGS) { + struct htmlpair tag; - switch (tok) { - case (ROFF_It): - return(html_It_headtagname(mbuf, q, argc, argv, res)); - case (ROFF_Fo): - /* FALLTHROUGH */ - case (ROFF_Oo): - return(html_stput(mbuf, HTML_TAG_SPAN, res)); - case (ROFF_Sh): - return(html_stput(mbuf, HTML_TAG_H1, res)); - case (ROFF_Ss): - return(html_stput(mbuf, HTML_TAG_H2, res)); - default: - break; - } + bufcat("clear: both;"); + bufcat("height: 1em;"); - return(html_stput(mbuf, HTML_TAG_DIV, res)); + tag.key = ATTR_STYLE; + tag.val = buf; + + print_otag(h, TAG_DIV, 1, &tag); + return(0); } /* ARGSUSED */ static int -html_blocktagname(struct md_mbuf *mbuf, const struct md_args *args, - int tok, struct htmlq *q, const int *argc, - const char **argv, size_t *res) +mdoc_nd_pre(MDOC_ARGS) { + struct htmlpair tag; - switch (tok) { - case (ROFF_Fo): - /* FALLTHROUGH */ - case (ROFF_Oo): - return(html_stput(mbuf, HTML_TAG_SPAN, res)); - case (ROFF_It): - return(html_It_blocktagname(mbuf, q, argc, argv, res)); - default: - break; - } + if (MDOC_BODY != n->type) + return(1); - return(html_stput(mbuf, HTML_TAG_DIV, res)); + /* 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 -html_printargs(struct md_mbuf *mbuf, int tok, const char *ns, - const int *argc, const char **argv, size_t *res) +mdoc_op_pre(MDOC_ARGS) { + struct htmlpair tag; - /* FIXME: use API in ml.h. */ + if (MDOC_BODY != n->type) + return(1); - if ( ! ml_puts(mbuf, " class=\"", res)) - return(0); - if ( ! ml_puts(mbuf, ns, res)) - return(0); - if ( ! ml_puts(mbuf, "-", res)) - return(0); - if ( ! ml_puts(mbuf, toknames[tok], res)) - return(0); - return(ml_puts(mbuf, "\"", res)); + /* 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 -html_headtagargs(struct md_mbuf *mbuf, - const struct md_args *args, int tok, - const int *argc, const char **argv, size_t *res) +mdoc_nm_pre(MDOC_ARGS) { + struct htmlpair tag; - return(html_printargs(mbuf, tok, "head", argc, argv, res)); + 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 -html_bodytagargs(struct md_mbuf *mbuf, - const struct md_args *args, int tok, - const int *argc, const char **argv, size_t *res) +mdoc_xr_pre(MDOC_ARGS) { + struct htmlpair tag[2]; - return(html_printargs(mbuf, tok, "body", argc, argv, res)); + 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 -html_blocktagargs(struct md_mbuf *mbuf, - const struct md_args *args, int tok, - const int *argc, const char **argv, size_t *res) +mdoc_ns_pre(MDOC_ARGS) { - return(html_printargs(mbuf, tok, "block", argc, argv, res)); + h->flags |= HTML_NOSPACE; + return(1); } /* ARGSUSED */ static int -html_inlinetagargs(struct md_mbuf *mbuf, - const struct md_args *args, int tok, - const int *argc, const char **argv, size_t *res) +mdoc_ar_pre(MDOC_ARGS) { + struct htmlpair tag; - if ( ! html_printargs(mbuf, tok, "inline", argc, argv, res)) - return(0); + tag.key = ATTR_CLASS; + tag.val = "arg"; - switch (tok) { - case (ROFF_Sx): + print_otag(h, TAG_SPAN, 1, &tag); + return(1); +} - /* FIXME: use API in ml.h. */ - assert(*argv); - if ( ! ml_nputs(mbuf, " href=\"#", 8, res)) - return(0); - if ( ! ml_putstring(mbuf, *argv, res)) - return(0); - if ( ! ml_nputs(mbuf, "\"", 1, res)) - return(0); +/* 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; - default: + 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 -html_inlinetagname(struct md_mbuf *mbuf, - const struct md_args *args, int tok, size_t *res) +mdoc_tbl_block_pre(MDOC_ARGS, int t, int w, int o, int c) { + struct htmlpair tag; - switch (tok) { - case (ROFF_Pp): - return(html_stput(mbuf, HTML_TAG_DIV, res)); - case (ROFF_Sx): - return(html_stput(mbuf, HTML_TAG_A, res)); + switch (t) { + case (MDOC_Column): + /* FALLTHROUGH */ + case (MDOC_Item): + /* FALLTHROUGH */ + case (MDOC_Ohang): + buffmt("margin-left: %dem; clear: both;", o); + break; default: + buffmt("margin-left: %dem; clear: both;", w + o); break; } - return(html_stput(mbuf, HTML_TAG_SPAN, res)); + if ( ! c && n->prev && n->prev->body->child) + bufcat("padding-top: 1em;"); + + tag.key = ATTR_STYLE; + tag.val = buf; + print_otag(h, TAG_DIV, 1, &tag); + return(1); } -static ssize_t -html_begintag(struct md_mbuf *mbuf, void *data, - const struct md_args *args, enum md_ns ns, - int tok, const int *argc, const char **argv) +/* ARGSUSED */ +static int +mdoc_tbl_body_pre(MDOC_ARGS, int t, int w) { - size_t res; - struct htmlq *q; - struct htmlnode *node; - int i; - assert(ns != MD_NS_DEFAULT); - res = 0; + print_otag(h, TAG_DIV, 0, NULL); + return(1); +} - assert(data); - q = (struct htmlq *)data; - if (NULL == (node = calloc(1, sizeof(struct htmlnode)))) { - warn("calloc"); - return(-1); - } +/* ARGSUSED */ +static int +mdoc_tbl_head_pre(MDOC_ARGS, int t, int w) +{ + struct htmlpair tag; + struct ord *ord; + char nbuf[BUFSIZ]; - node->parent = q->last; - node->tok = tok; - node->ns = ns; - - if (argc) { - /* TODO: argv. */ - - assert(argv); - /* LINTED */ - for (i = 0; ROFF_ARGMAX != argc[i] - && i < ROFF_MAXLINEARG; i++) - node->argc[i] = argc[i]; - assert(i != ROFF_MAXLINEARG); - } - - - q->last = node; - - switch (ns) { - case (MD_NS_BLOCK): - if ( ! html_blocktagname(mbuf, args, tok, - q, argc, argv, &res)) - return(-1); - if ( ! html_blocktagargs(mbuf, args, tok, - argc, argv, &res)) - return(-1); + switch (t) { + case (MDOC_Item): + /* FALLTHROUGH */ + case (MDOC_Ohang): + print_otag(h, TAG_DIV, 0, NULL); break; - case (MD_NS_BODY): - if ( ! html_bodytagname(mbuf, args, tok, - q, argc, argv, &res)) - return(-1); - if ( ! html_bodytagargs(mbuf, args, tok, - argc, argv, &res)) - return(-1); + case (MDOC_Column): + buffmt("min-width: %dem;", w); + bufcat("clear: none;"); + if (n->next && MDOC_HEAD == n->next->type) + bufcat("float: left;"); + tag.key = ATTR_STYLE; + tag.val = buf; + print_otag(h, TAG_DIV, 1, &tag); break; - case (MD_NS_HEAD): - if ( ! html_headtagname(mbuf, args, tok, q, - argc, argv, &res)) - return(-1); - if ( ! html_headtagargs(mbuf, args, tok, - argc, argv, &res)) - return(-1); + default: + buffmt("margin-left: -%dem;", w); + bufcat("clear: left;"); + bufcat("float: left;"); + bufcat("padding-right: 1em;"); + tag.key = ATTR_STYLE; + tag.val = buf; + print_otag(h, TAG_DIV, 1, &tag); break; + } + + switch (t) { + case (MDOC_Diag): + tag.key = ATTR_CLASS; + tag.val = "diag"; + print_otag(h, TAG_SPAN, 1, &tag); + break; + case (MDOC_Enum): + ord = SLIST_FIRST(&h->ords); + assert(ord); + nbuf[BUFSIZ - 1] = 0; + (void)snprintf(nbuf, BUFSIZ - 1, "%d.", ord->pos++); + print_text(h, nbuf); + return(0); + case (MDOC_Dash): + print_text(h, "\\(en"); + return(0); + case (MDOC_Hyphen): + print_text(h, "\\-"); + return(0); + case (MDOC_Bullet): + print_text(h, "\\(bu"); + return(0); default: - if ( ! html_inlinetagname(mbuf, args, tok, &res)) - return(-1); - if ( ! html_inlinetagargs(mbuf, args, tok, - argc, argv, &res)) - return(-1); break; } - return((ssize_t)res); + return(1); } -static ssize_t -html_endtag(struct md_mbuf *mbuf, void *data, - const struct md_args *args, enum md_ns ns, int tok) +static int +mdoc_tbl_pre(MDOC_ARGS, int type) { - size_t res; - struct htmlq *q; - struct htmlnode *node; + int i, w, o, c, wp; + const struct mdoc_node *bl, *nn; - assert(ns != MD_NS_DEFAULT); - res = 0; + bl = n->parent->parent; + if (MDOC_BLOCK != n->type) + bl = bl->parent; - assert(data); - q = (struct htmlq *)data; - node = q->last; + /* FIXME: fmt_vspace() equivalent. */ - switch (ns) { - case (MD_NS_BLOCK): - if ( ! html_blocktagname(mbuf, args, tok, - q, node->argc, - (const char **)node->argv, &res)) - return(-1); + assert(bl->args); + + w = o = c = 0; + wp = -1; + + for (i = 0; i < (int)bl->args->argc; i++) + if (MDOC_Width == bl->args->argv[i].arg) { + assert(bl->args->argv[i].sz); + wp = i; + 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 (MDOC_HEAD == n->type && MDOC_Column == type) { + nn = n->parent->child; + assert(nn && MDOC_HEAD == nn->type); + for (i = 0; nn && nn != n; nn = nn->next, i++) + /* Counter... */ ; + assert(nn); + if (wp >= 0 && i < (int)bl->args[wp].argv->sz) + w = a2width(bl->args->argv[wp].value[i]); + } + + switch (type) { + case (MDOC_Enum): + /* FALLTHROUGH */ + case (MDOC_Dash): + /* FALLTHROUGH */ + case (MDOC_Hyphen): + /* FALLTHROUGH */ + case (MDOC_Bullet): + if (w < 4) + w = 4; break; - case (MD_NS_BODY): - if ( ! html_bodytagname(mbuf, args, tok, - q, node->argc, - (const char **)node->argv, &res)) - return(-1); + case (MDOC_Inset): + /* FALLTHROUGH */ + case (MDOC_Diag): + w = 1; break; - case (MD_NS_HEAD): - if ( ! html_headtagname(mbuf, args, tok, - q, node->argc, - (const char **)node->argv, &res)) - return(-1); - break; default: - if ( ! html_inlinetagname(mbuf, args, tok, &res)) - return(-1); + if (0 == w) + w = 10; break; } - q->last = node->parent; + 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 */ + } - free(node); + return(mdoc_tbl_block_pre(m, n, h, type, w, o, c)); +} - return((ssize_t)res); + +static int +mdoc_bl_pre(MDOC_ARGS) +{ + struct ord *ord; + + if (MDOC_BLOCK != n->type) + return(1); + if (MDOC_Enum != a2list(n)) + return(1); + + ord = malloc(sizeof(struct ord)); + if (NULL == ord) + err(EXIT_FAILURE, "malloc"); + ord->cookie = n; + ord->pos = 1; + SLIST_INSERT_HEAD(&h->ords, ord, entry); + + return(1); } +static void +mdoc_bl_post(MDOC_ARGS) +{ + struct ord *ord; + + if (MDOC_BLOCK != n->type) + return; + if (MDOC_Enum != a2list(n)) + return; + + ord = SLIST_FIRST(&h->ords); + assert(ord); + SLIST_REMOVE_HEAD(&h->ords, entry); + free(ord); +} + + static int -html_alloc(void **p) +mdoc_it_pre(MDOC_ARGS) { + int type; - if (NULL == (*p = calloc(1, sizeof(struct htmlq)))) { - warn("calloc"); - return(0); + if (MDOC_BLOCK == n->type) + type = a2list(n->parent->parent); + else + type = a2list(n->parent->parent->parent); + + return(mdoc_tbl_pre(m, n, h, type)); +} + + +/* 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 -html_free(void *p) +mdoc_dq_post(MDOC_ARGS) { - struct htmlq *q; - struct htmlnode *n; - assert(p); - q = (struct htmlq *)p; + if (MDOC_BODY != n->type) + return; + h->flags |= HTML_NOSPACE; + print_text(h, "\\(rq"); +} - /* LINTED */ - while ((n = q->last)) { - q->last = n->parent; - free(n); - } - free(q); +/* 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 ssize_t -html_beginhttp(struct md_mbuf *mbuf, - const struct md_args *args, - const char *buf, size_t sz) +static void +mdoc_pq_post(MDOC_ARGS) { - size_t res; - struct html_pair pair; - res = 0; - pair.attr = HTML_ATTR_HREF; - pair.val = (char *)buf; + if (MDOC_BODY != n->type) + return; + print_text(h, ")"); +} - if ( ! html_aput(mbuf, ML_OPEN, HTML_TAG_A, &res, 1, &pair)) - return(-1); - return((ssize_t)res); + +/* 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 ssize_t -html_endhttp(struct md_mbuf *mbuf, - const struct md_args *args, - const char *buf, size_t sz) +static void +mdoc_sq_post(MDOC_ARGS) { - size_t res; - res = 0; - if ( ! html_tput(mbuf, ML_CLOSE, HTML_TAG_A, &res)) - return(-1); - return((ssize_t)res); + if (MDOC_BODY != n->type) + return; + h->flags |= HTML_NOSPACE; + print_text(h, "\\(aq"); } /* ARGSUSED */ -static ssize_t -html_beginstring(struct md_mbuf *mbuf, - const struct md_args *args, - const char *buf, size_t sz) +static int +mdoc_em_pre(MDOC_ARGS) { + struct htmlpair tag; - if (0 == strncmp(buf, "http://", 7)) - return(html_beginhttp(mbuf, args, buf, sz)); + tag.key = ATTR_CLASS; + tag.val = "emph"; - return(0); + print_otag(h, TAG_SPAN, 1, &tag); + return(1); } /* ARGSUSED */ -static ssize_t -html_endstring(struct md_mbuf *mbuf, - const struct md_args *args, - const char *buf, size_t sz) +static int +mdoc_d1_pre(MDOC_ARGS) { - - if (0 == strncmp(buf, "http://", 7)) - return(html_endhttp(mbuf, args, buf, sz)); + struct htmlpair tag[2]; - return(0); + if (MDOC_BLOCK != n->type) + return(1); + + buffmt("margin-left: %dem;", INDENT); + + 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); } -int -md_line_html(void *data, char *buf) +/* ARGSUSED */ +static int +mdoc_sx_pre(MDOC_ARGS) { + struct htmlpair tag[2]; - return(mlg_line((struct md_mlg *)data, buf)); + 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); } -int -md_exit_html(void *data, int flush) +/* ARGSUSED */ +static int +mdoc_aq_pre(MDOC_ARGS) { - return(mlg_exit((struct md_mlg *)data, flush)); + if (MDOC_BODY != n->type) + return(1); + print_text(h, "\\(la"); + h->flags |= HTML_NOSPACE; + return(1); } -void * -md_init_html(const struct md_args *args, - struct md_mbuf *mbuf, const struct md_rbuf *rbuf) +/* ARGSUSED */ +static void +mdoc_aq_post(MDOC_ARGS) { - struct ml_cbs cbs; - cbs.ml_alloc = html_alloc; - cbs.ml_free = html_free; - cbs.ml_begintag = html_begintag; - cbs.ml_endtag = html_endtag; - cbs.ml_begin = html_begin; - cbs.ml_end = html_end; - cbs.ml_beginstring = html_beginstring; - cbs.ml_endstring = html_endstring; + if (MDOC_BODY != n->type) + return; + h->flags |= HTML_NOSPACE; + print_text(h, "\\(ra"); +} - return(mlg_alloc(args, rbuf, mbuf, &cbs)); + +/* ARGSUSED */ +static int +mdoc_bd_pre(MDOC_ARGS) +{ + struct htmlpair tag[2]; + int t, c, o, i; + const struct mdoc_node *bl; + + /* FIXME: fmt_vspace() shit. */ + + if (MDOC_BLOCK == n->type) + bl = n; + else if (MDOC_HEAD == n->type) + return(0); + else + bl = n->parent; + + t = o = c = 0; + + for (i = 0; i < (int)bl->args->argc; i++) + switch (bl->args->argv[i].arg) { + case (MDOC_Offset): + assert(bl->args->argv[i].sz); + o = a2offs(bl->args->argv[i].value[0]); + break; + case (MDOC_Compact): + c = 1; + break; + case (MDOC_Ragged): + /* FALLTHROUGH */ + case (MDOC_Filled): + /* FALLTHROUGH */ + case (MDOC_Unfilled): + /* FALLTHROUGH */ + case (MDOC_Literal): + t = bl->args->argv[i].arg; + break; + } + + if (MDOC_BLOCK == n->type) { + if (o) + buffmt("margin-left: %dem;", o); + bufcat("margin-top: 1em;"); + tag[0].key = ATTR_STYLE; + tag[0].val = buf; + print_otag(h, TAG_DIV, 1, tag); + return(1); + } + + switch (t) { + case (MDOC_Unfilled): + case (MDOC_Literal): + break; + default: + return(1); + } + + bufcat("white-space: pre;"); + tag[0].key = ATTR_STYLE; + tag[0].val = buf; + tag[1].key = ATTR_CLASS; + tag[1].val = "lit-block"; + + print_otag(h, TAG_DIV, 2, tag); + + for (n = n->child; n; n = n->next) { + h->flags |= HTML_NOSPACE; + print_mdoc_node(m, n, h); + if (n->next) + print_text(h, "\n"); + } + + return(0); +} + + +/* ARGSUSED */ +static int +mdoc_pa_pre(MDOC_ARGS) +{ + struct htmlpair tag; + + tag.key = ATTR_CLASS; + tag.val = "file"; + + print_otag(h, TAG_SPAN, 1, &tag); + return(1); +} + + +/* ARGSUSED */ +static int +mdoc_qq_pre(MDOC_ARGS) +{ + + if (MDOC_BODY != n->type) + return(1); + print_text(h, "\\*q"); + h->flags |= HTML_NOSPACE; + return(1); +} + + +/* ARGSUSED */ +static void +mdoc_qq_post(MDOC_ARGS) +{ + + if (MDOC_BODY != n->type) + return; + h->flags |= HTML_NOSPACE; + print_text(h, "\\*q"); }