1*47a17e0dSchristos /* Id: mdoc_html.c,v 1.240 2016/01/08 17:48:09 schwarze Exp */ 24154958bSjoerg /* 30511d63cSchristos * Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv> 4*47a17e0dSchristos * Copyright (c) 2014, 2015, 2016 Ingo Schwarze <schwarze@openbsd.org> 54154958bSjoerg * 64154958bSjoerg * Permission to use, copy, modify, and distribute this software for any 74154958bSjoerg * purpose with or without fee is hereby granted, provided that the above 84154958bSjoerg * copyright notice and this permission notice appear in all copies. 94154958bSjoerg * 10*47a17e0dSchristos * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES 114154958bSjoerg * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12*47a17e0dSchristos * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR 134154958bSjoerg * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 144154958bSjoerg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 154154958bSjoerg * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 164154958bSjoerg * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 174154958bSjoerg */ 18d5e63c8dSjoerg #include "config.h" 19d5e63c8dSjoerg 204154958bSjoerg #include <sys/types.h> 214154958bSjoerg 224154958bSjoerg #include <assert.h> 234154958bSjoerg #include <ctype.h> 244154958bSjoerg #include <stdio.h> 254154958bSjoerg #include <stdlib.h> 264154958bSjoerg #include <string.h> 274154958bSjoerg #include <unistd.h> 284154958bSjoerg 290511d63cSchristos #include "mandoc_aux.h" 30*47a17e0dSchristos #include "roff.h" 310511d63cSchristos #include "mdoc.h" 324154958bSjoerg #include "out.h" 334154958bSjoerg #include "html.h" 344154958bSjoerg #include "main.h" 354154958bSjoerg 364154958bSjoerg #define INDENT 5 374154958bSjoerg 38*47a17e0dSchristos #define MDOC_ARGS const struct roff_meta *meta, \ 39*47a17e0dSchristos struct roff_node *n, \ 404154958bSjoerg struct html *h 414154958bSjoerg 42d5e63c8dSjoerg #ifndef MIN 43d5e63c8dSjoerg #define MIN(a,b) ((/*CONSTCOND*/(a)<(b))?(a):(b)) 44d5e63c8dSjoerg #endif 45d5e63c8dSjoerg 464154958bSjoerg struct htmlmdoc { 474154958bSjoerg int (*pre)(MDOC_ARGS); 484154958bSjoerg void (*post)(MDOC_ARGS); 494154958bSjoerg }; 504154958bSjoerg 514154958bSjoerg static void print_mdoc_head(MDOC_ARGS); 524154958bSjoerg static void print_mdoc_node(MDOC_ARGS); 534154958bSjoerg static void print_mdoc_nodelist(MDOC_ARGS); 547574e07eSjoerg static void synopsis_pre(struct html *, 55*47a17e0dSchristos const struct roff_node *); 564154958bSjoerg 574154958bSjoerg static void a2width(const char *, struct roffsu *); 584154958bSjoerg 594154958bSjoerg static void mdoc_root_post(MDOC_ARGS); 604154958bSjoerg static int mdoc_root_pre(MDOC_ARGS); 614154958bSjoerg 624154958bSjoerg static void mdoc__x_post(MDOC_ARGS); 634154958bSjoerg static int mdoc__x_pre(MDOC_ARGS); 644154958bSjoerg static int mdoc_ad_pre(MDOC_ARGS); 654154958bSjoerg static int mdoc_an_pre(MDOC_ARGS); 664154958bSjoerg static int mdoc_ap_pre(MDOC_ARGS); 674154958bSjoerg static int mdoc_ar_pre(MDOC_ARGS); 684154958bSjoerg static int mdoc_bd_pre(MDOC_ARGS); 694154958bSjoerg static int mdoc_bf_pre(MDOC_ARGS); 7082361f10Sjoerg static void mdoc_bk_post(MDOC_ARGS); 7182361f10Sjoerg static int mdoc_bk_pre(MDOC_ARGS); 724154958bSjoerg static int mdoc_bl_pre(MDOC_ARGS); 734154958bSjoerg static int mdoc_bt_pre(MDOC_ARGS); 744154958bSjoerg static int mdoc_bx_pre(MDOC_ARGS); 754154958bSjoerg static int mdoc_cd_pre(MDOC_ARGS); 764154958bSjoerg static int mdoc_d1_pre(MDOC_ARGS); 774154958bSjoerg static int mdoc_dv_pre(MDOC_ARGS); 784154958bSjoerg static int mdoc_fa_pre(MDOC_ARGS); 794154958bSjoerg static int mdoc_fd_pre(MDOC_ARGS); 804154958bSjoerg static int mdoc_fl_pre(MDOC_ARGS); 814154958bSjoerg static int mdoc_fn_pre(MDOC_ARGS); 824154958bSjoerg static int mdoc_ft_pre(MDOC_ARGS); 834154958bSjoerg static int mdoc_em_pre(MDOC_ARGS); 840511d63cSchristos static void mdoc_eo_post(MDOC_ARGS); 850511d63cSchristos static int mdoc_eo_pre(MDOC_ARGS); 864154958bSjoerg static int mdoc_er_pre(MDOC_ARGS); 874154958bSjoerg static int mdoc_ev_pre(MDOC_ARGS); 884154958bSjoerg static int mdoc_ex_pre(MDOC_ARGS); 894154958bSjoerg static void mdoc_fo_post(MDOC_ARGS); 904154958bSjoerg static int mdoc_fo_pre(MDOC_ARGS); 914154958bSjoerg static int mdoc_ic_pre(MDOC_ARGS); 92e4fbeb7eSjoerg static int mdoc_igndelim_pre(MDOC_ARGS); 934154958bSjoerg static int mdoc_in_pre(MDOC_ARGS); 944154958bSjoerg static int mdoc_it_pre(MDOC_ARGS); 954154958bSjoerg static int mdoc_lb_pre(MDOC_ARGS); 964154958bSjoerg static int mdoc_li_pre(MDOC_ARGS); 974154958bSjoerg static int mdoc_lk_pre(MDOC_ARGS); 984154958bSjoerg static int mdoc_mt_pre(MDOC_ARGS); 994154958bSjoerg static int mdoc_ms_pre(MDOC_ARGS); 1004154958bSjoerg static int mdoc_nd_pre(MDOC_ARGS); 1014154958bSjoerg static int mdoc_nm_pre(MDOC_ARGS); 1020511d63cSchristos static int mdoc_no_pre(MDOC_ARGS); 1034154958bSjoerg static int mdoc_ns_pre(MDOC_ARGS); 1044154958bSjoerg static int mdoc_pa_pre(MDOC_ARGS); 1054154958bSjoerg static void mdoc_pf_post(MDOC_ARGS); 106e4fbeb7eSjoerg static int mdoc_pp_pre(MDOC_ARGS); 107e4fbeb7eSjoerg static void mdoc_quote_post(MDOC_ARGS); 108e4fbeb7eSjoerg static int mdoc_quote_pre(MDOC_ARGS); 1094154958bSjoerg static int mdoc_rs_pre(MDOC_ARGS); 1104154958bSjoerg static int mdoc_rv_pre(MDOC_ARGS); 1114154958bSjoerg static int mdoc_sh_pre(MDOC_ARGS); 1120511d63cSchristos static int mdoc_skip_pre(MDOC_ARGS); 1137da9b934Sjoerg static int mdoc_sm_pre(MDOC_ARGS); 1144154958bSjoerg static int mdoc_sp_pre(MDOC_ARGS); 1154154958bSjoerg static int mdoc_ss_pre(MDOC_ARGS); 1164154958bSjoerg static int mdoc_sx_pre(MDOC_ARGS); 1174154958bSjoerg static int mdoc_sy_pre(MDOC_ARGS); 1184154958bSjoerg static int mdoc_ud_pre(MDOC_ARGS); 1194154958bSjoerg static int mdoc_va_pre(MDOC_ARGS); 1204154958bSjoerg static int mdoc_vt_pre(MDOC_ARGS); 1214154958bSjoerg static int mdoc_xr_pre(MDOC_ARGS); 1224154958bSjoerg static int mdoc_xx_pre(MDOC_ARGS); 1234154958bSjoerg 1244154958bSjoerg static const struct htmlmdoc mdocs[MDOC_MAX] = { 1254154958bSjoerg {mdoc_ap_pre, NULL}, /* Ap */ 1264154958bSjoerg {NULL, NULL}, /* Dd */ 1274154958bSjoerg {NULL, NULL}, /* Dt */ 1284154958bSjoerg {NULL, NULL}, /* Os */ 1294154958bSjoerg {mdoc_sh_pre, NULL }, /* Sh */ 1304154958bSjoerg {mdoc_ss_pre, NULL }, /* Ss */ 131e4fbeb7eSjoerg {mdoc_pp_pre, NULL}, /* Pp */ 1324154958bSjoerg {mdoc_d1_pre, NULL}, /* D1 */ 1334154958bSjoerg {mdoc_d1_pre, NULL}, /* Dl */ 1344154958bSjoerg {mdoc_bd_pre, NULL}, /* Bd */ 1354154958bSjoerg {NULL, NULL}, /* Ed */ 136e4fbeb7eSjoerg {mdoc_bl_pre, NULL}, /* Bl */ 1374154958bSjoerg {NULL, NULL}, /* El */ 1384154958bSjoerg {mdoc_it_pre, NULL}, /* It */ 1394154958bSjoerg {mdoc_ad_pre, NULL}, /* Ad */ 1404154958bSjoerg {mdoc_an_pre, NULL}, /* An */ 1414154958bSjoerg {mdoc_ar_pre, NULL}, /* Ar */ 1424154958bSjoerg {mdoc_cd_pre, NULL}, /* Cd */ 1434154958bSjoerg {mdoc_fl_pre, NULL}, /* Cm */ 1444154958bSjoerg {mdoc_dv_pre, NULL}, /* Dv */ 1454154958bSjoerg {mdoc_er_pre, NULL}, /* Er */ 1464154958bSjoerg {mdoc_ev_pre, NULL}, /* Ev */ 1474154958bSjoerg {mdoc_ex_pre, NULL}, /* Ex */ 1484154958bSjoerg {mdoc_fa_pre, NULL}, /* Fa */ 1494154958bSjoerg {mdoc_fd_pre, NULL}, /* Fd */ 1504154958bSjoerg {mdoc_fl_pre, NULL}, /* Fl */ 1514154958bSjoerg {mdoc_fn_pre, NULL}, /* Fn */ 1524154958bSjoerg {mdoc_ft_pre, NULL}, /* Ft */ 1534154958bSjoerg {mdoc_ic_pre, NULL}, /* Ic */ 1544154958bSjoerg {mdoc_in_pre, NULL}, /* In */ 1554154958bSjoerg {mdoc_li_pre, NULL}, /* Li */ 1564154958bSjoerg {mdoc_nd_pre, NULL}, /* Nd */ 1574154958bSjoerg {mdoc_nm_pre, NULL}, /* Nm */ 158e4fbeb7eSjoerg {mdoc_quote_pre, mdoc_quote_post}, /* Op */ 1590511d63cSchristos {mdoc_ft_pre, NULL}, /* Ot */ 1604154958bSjoerg {mdoc_pa_pre, NULL}, /* Pa */ 1614154958bSjoerg {mdoc_rv_pre, NULL}, /* Rv */ 1624154958bSjoerg {NULL, NULL}, /* St */ 1634154958bSjoerg {mdoc_va_pre, NULL}, /* Va */ 1644154958bSjoerg {mdoc_vt_pre, NULL}, /* Vt */ 1654154958bSjoerg {mdoc_xr_pre, NULL}, /* Xr */ 1664154958bSjoerg {mdoc__x_pre, mdoc__x_post}, /* %A */ 1674154958bSjoerg {mdoc__x_pre, mdoc__x_post}, /* %B */ 1684154958bSjoerg {mdoc__x_pre, mdoc__x_post}, /* %D */ 1694154958bSjoerg {mdoc__x_pre, mdoc__x_post}, /* %I */ 1704154958bSjoerg {mdoc__x_pre, mdoc__x_post}, /* %J */ 1714154958bSjoerg {mdoc__x_pre, mdoc__x_post}, /* %N */ 1724154958bSjoerg {mdoc__x_pre, mdoc__x_post}, /* %O */ 1734154958bSjoerg {mdoc__x_pre, mdoc__x_post}, /* %P */ 1744154958bSjoerg {mdoc__x_pre, mdoc__x_post}, /* %R */ 1754154958bSjoerg {mdoc__x_pre, mdoc__x_post}, /* %T */ 1764154958bSjoerg {mdoc__x_pre, mdoc__x_post}, /* %V */ 1774154958bSjoerg {NULL, NULL}, /* Ac */ 178e4fbeb7eSjoerg {mdoc_quote_pre, mdoc_quote_post}, /* Ao */ 179e4fbeb7eSjoerg {mdoc_quote_pre, mdoc_quote_post}, /* Aq */ 1804154958bSjoerg {NULL, NULL}, /* At */ 1814154958bSjoerg {NULL, NULL}, /* Bc */ 1824154958bSjoerg {mdoc_bf_pre, NULL}, /* Bf */ 183e4fbeb7eSjoerg {mdoc_quote_pre, mdoc_quote_post}, /* Bo */ 184e4fbeb7eSjoerg {mdoc_quote_pre, mdoc_quote_post}, /* Bq */ 1854154958bSjoerg {mdoc_xx_pre, NULL}, /* Bsx */ 1864154958bSjoerg {mdoc_bx_pre, NULL}, /* Bx */ 1870511d63cSchristos {mdoc_skip_pre, NULL}, /* Db */ 1884154958bSjoerg {NULL, NULL}, /* Dc */ 189e4fbeb7eSjoerg {mdoc_quote_pre, mdoc_quote_post}, /* Do */ 190e4fbeb7eSjoerg {mdoc_quote_pre, mdoc_quote_post}, /* Dq */ 19131e1f4e3Sjoerg {NULL, NULL}, /* Ec */ /* FIXME: no space */ 1924154958bSjoerg {NULL, NULL}, /* Ef */ 1934154958bSjoerg {mdoc_em_pre, NULL}, /* Em */ 1940511d63cSchristos {mdoc_eo_pre, mdoc_eo_post}, /* Eo */ 1954154958bSjoerg {mdoc_xx_pre, NULL}, /* Fx */ 1967da9b934Sjoerg {mdoc_ms_pre, NULL}, /* Ms */ 1970511d63cSchristos {mdoc_no_pre, NULL}, /* No */ 1984154958bSjoerg {mdoc_ns_pre, NULL}, /* Ns */ 1994154958bSjoerg {mdoc_xx_pre, NULL}, /* Nx */ 2004154958bSjoerg {mdoc_xx_pre, NULL}, /* Ox */ 2014154958bSjoerg {NULL, NULL}, /* Pc */ 202e4fbeb7eSjoerg {mdoc_igndelim_pre, mdoc_pf_post}, /* Pf */ 203e4fbeb7eSjoerg {mdoc_quote_pre, mdoc_quote_post}, /* Po */ 204e4fbeb7eSjoerg {mdoc_quote_pre, mdoc_quote_post}, /* Pq */ 2054154958bSjoerg {NULL, NULL}, /* Qc */ 206e4fbeb7eSjoerg {mdoc_quote_pre, mdoc_quote_post}, /* Ql */ 207e4fbeb7eSjoerg {mdoc_quote_pre, mdoc_quote_post}, /* Qo */ 208e4fbeb7eSjoerg {mdoc_quote_pre, mdoc_quote_post}, /* Qq */ 2094154958bSjoerg {NULL, NULL}, /* Re */ 2104154958bSjoerg {mdoc_rs_pre, NULL}, /* Rs */ 2114154958bSjoerg {NULL, NULL}, /* Sc */ 212e4fbeb7eSjoerg {mdoc_quote_pre, mdoc_quote_post}, /* So */ 213e4fbeb7eSjoerg {mdoc_quote_pre, mdoc_quote_post}, /* Sq */ 2147da9b934Sjoerg {mdoc_sm_pre, NULL}, /* Sm */ 2154154958bSjoerg {mdoc_sx_pre, NULL}, /* Sx */ 2164154958bSjoerg {mdoc_sy_pre, NULL}, /* Sy */ 2174154958bSjoerg {NULL, NULL}, /* Tn */ 2184154958bSjoerg {mdoc_xx_pre, NULL}, /* Ux */ 2194154958bSjoerg {NULL, NULL}, /* Xc */ 2204154958bSjoerg {NULL, NULL}, /* Xo */ 2214154958bSjoerg {mdoc_fo_pre, mdoc_fo_post}, /* Fo */ 2224154958bSjoerg {NULL, NULL}, /* Fc */ 223e4fbeb7eSjoerg {mdoc_quote_pre, mdoc_quote_post}, /* Oo */ 2244154958bSjoerg {NULL, NULL}, /* Oc */ 22582361f10Sjoerg {mdoc_bk_pre, mdoc_bk_post}, /* Bk */ 2264154958bSjoerg {NULL, NULL}, /* Ek */ 2274154958bSjoerg {mdoc_bt_pre, NULL}, /* Bt */ 2284154958bSjoerg {NULL, NULL}, /* Hf */ 2290511d63cSchristos {mdoc_em_pre, NULL}, /* Fr */ 2304154958bSjoerg {mdoc_ud_pre, NULL}, /* Ud */ 2314154958bSjoerg {mdoc_lb_pre, NULL}, /* Lb */ 232e4fbeb7eSjoerg {mdoc_pp_pre, NULL}, /* Lp */ 2334154958bSjoerg {mdoc_lk_pre, NULL}, /* Lk */ 2344154958bSjoerg {mdoc_mt_pre, NULL}, /* Mt */ 235e4fbeb7eSjoerg {mdoc_quote_pre, mdoc_quote_post}, /* Brq */ 236e4fbeb7eSjoerg {mdoc_quote_pre, mdoc_quote_post}, /* Bro */ 2374154958bSjoerg {NULL, NULL}, /* Brc */ 2384154958bSjoerg {mdoc__x_pre, mdoc__x_post}, /* %C */ 2390511d63cSchristos {mdoc_skip_pre, NULL}, /* Es */ 2400511d63cSchristos {mdoc_quote_pre, mdoc_quote_post}, /* En */ 2414154958bSjoerg {mdoc_xx_pre, NULL}, /* Dx */ 2424154958bSjoerg {mdoc__x_pre, mdoc__x_post}, /* %Q */ 2434154958bSjoerg {mdoc_sp_pre, NULL}, /* br */ 2444154958bSjoerg {mdoc_sp_pre, NULL}, /* sp */ 24522af4063Sjoerg {mdoc__x_pre, mdoc__x_post}, /* %U */ 2467574e07eSjoerg {NULL, NULL}, /* Ta */ 2470511d63cSchristos {mdoc_skip_pre, NULL}, /* ll */ 2484154958bSjoerg }; 2494154958bSjoerg 250e4fbeb7eSjoerg static const char * const lists[LIST_MAX] = { 251e4fbeb7eSjoerg NULL, 252e4fbeb7eSjoerg "list-bul", 253e4fbeb7eSjoerg "list-col", 254e4fbeb7eSjoerg "list-dash", 255e4fbeb7eSjoerg "list-diag", 256e4fbeb7eSjoerg "list-enum", 257e4fbeb7eSjoerg "list-hang", 258e4fbeb7eSjoerg "list-hyph", 259e4fbeb7eSjoerg "list-inset", 260e4fbeb7eSjoerg "list-item", 261e4fbeb7eSjoerg "list-ohang", 262e4fbeb7eSjoerg "list-tag" 263e4fbeb7eSjoerg }; 2644154958bSjoerg 2650511d63cSchristos 2664154958bSjoerg /* 2674154958bSjoerg * Calculate the scaling unit passed in a `-width' argument. This uses 2684154958bSjoerg * either a native scaling unit (e.g., 1i, 2m) or the string length of 2694154958bSjoerg * the value. 2704154958bSjoerg */ 2714154958bSjoerg static void 2724154958bSjoerg a2width(const char *p, struct roffsu *su) 2734154958bSjoerg { 2744154958bSjoerg 2750511d63cSchristos if (a2roffsu(p, su, SCALE_MAX) < 2) { 2760511d63cSchristos su->unit = SCALE_EN; 277f8126693Sjoerg su->scale = html_strlen(p); 2780511d63cSchristos } else if (su->scale < 0.0) 2790511d63cSchristos su->scale = 0.0; 2804154958bSjoerg } 2814154958bSjoerg 2824154958bSjoerg /* 2837574e07eSjoerg * See the same function in mdoc_term.c for documentation. 2847574e07eSjoerg */ 2857574e07eSjoerg static void 286*47a17e0dSchristos synopsis_pre(struct html *h, const struct roff_node *n) 2877574e07eSjoerg { 2887574e07eSjoerg 28982361f10Sjoerg if (NULL == n->prev || ! (MDOC_SYNPRETTY & n->flags)) 2907574e07eSjoerg return; 2917574e07eSjoerg 2927574e07eSjoerg if (n->prev->tok == n->tok && 2937574e07eSjoerg MDOC_Fo != n->tok && 2947574e07eSjoerg MDOC_Ft != n->tok && 2957574e07eSjoerg MDOC_Fn != n->tok) { 296e4fbeb7eSjoerg print_otag(h, TAG_BR, 0, NULL); 2977574e07eSjoerg return; 2987574e07eSjoerg } 2997574e07eSjoerg 3007574e07eSjoerg switch (n->prev->tok) { 3010511d63cSchristos case MDOC_Fd: 3020511d63cSchristos case MDOC_Fn: 3030511d63cSchristos case MDOC_Fo: 3040511d63cSchristos case MDOC_In: 3050511d63cSchristos case MDOC_Vt: 3060511d63cSchristos print_paragraph(h); 3077574e07eSjoerg break; 3080511d63cSchristos case MDOC_Ft: 3097574e07eSjoerg if (MDOC_Fn != n->tok && MDOC_Fo != n->tok) { 3100511d63cSchristos print_paragraph(h); 3117574e07eSjoerg break; 3127574e07eSjoerg } 3137574e07eSjoerg /* FALLTHROUGH */ 3147574e07eSjoerg default: 315e4fbeb7eSjoerg print_otag(h, TAG_BR, 0, NULL); 3167574e07eSjoerg break; 3177574e07eSjoerg } 3187574e07eSjoerg } 3197574e07eSjoerg 320*47a17e0dSchristos void 321*47a17e0dSchristos html_mdoc(void *arg, const struct roff_man *mdoc) 3224154958bSjoerg { 323f8126693Sjoerg struct htmlpair tag; 324*47a17e0dSchristos struct html *h; 325*47a17e0dSchristos struct tag *t, *tt; 3264154958bSjoerg 327f8126693Sjoerg PAIR_CLASS_INIT(&tag, "mandoc"); 328*47a17e0dSchristos h = (struct html *)arg; 329f8126693Sjoerg 330f8126693Sjoerg if ( ! (HTML_FRAGMENT & h->oflags)) { 331f8126693Sjoerg print_gen_decls(h); 332f8126693Sjoerg t = print_otag(h, TAG_HTML, 0, NULL); 333f8126693Sjoerg tt = print_otag(h, TAG_HEAD, 0, NULL); 334*47a17e0dSchristos print_mdoc_head(&mdoc->meta, mdoc->first->child, h); 335f8126693Sjoerg print_tagq(h, tt); 336f8126693Sjoerg print_otag(h, TAG_BODY, 0, NULL); 337f8126693Sjoerg print_otag(h, TAG_DIV, 1, &tag); 338f8126693Sjoerg } else 339f8126693Sjoerg t = print_otag(h, TAG_DIV, 1, &tag); 3404154958bSjoerg 341*47a17e0dSchristos mdoc_root_pre(&mdoc->meta, mdoc->first->child, h); 342*47a17e0dSchristos print_mdoc_nodelist(&mdoc->meta, mdoc->first->child, h); 343*47a17e0dSchristos mdoc_root_post(&mdoc->meta, mdoc->first->child, h); 3444154958bSjoerg print_tagq(h, t); 345*47a17e0dSchristos putchar('\n'); 3464154958bSjoerg } 3474154958bSjoerg 3484154958bSjoerg static void 3494154958bSjoerg print_mdoc_head(MDOC_ARGS) 3504154958bSjoerg { 3514154958bSjoerg 3524154958bSjoerg print_gen_head(h); 3534154958bSjoerg bufinit(h); 3540511d63cSchristos bufcat(h, meta->title); 3550511d63cSchristos if (meta->msec) 3560511d63cSchristos bufcat_fmt(h, "(%s)", meta->msec); 357ed7c7912Sjoerg if (meta->arch) 358ed7c7912Sjoerg bufcat_fmt(h, " (%s)", meta->arch); 3594154958bSjoerg 3604154958bSjoerg print_otag(h, TAG_TITLE, 0, NULL); 3614154958bSjoerg print_text(h, h->buf); 3624154958bSjoerg } 3634154958bSjoerg 3644154958bSjoerg static void 3654154958bSjoerg print_mdoc_nodelist(MDOC_ARGS) 3664154958bSjoerg { 3674154958bSjoerg 3680511d63cSchristos while (n != NULL) { 369ed7c7912Sjoerg print_mdoc_node(meta, n, h); 3700511d63cSchristos n = n->next; 3714154958bSjoerg } 3720511d63cSchristos } 3734154958bSjoerg 3744154958bSjoerg static void 3754154958bSjoerg print_mdoc_node(MDOC_ARGS) 3764154958bSjoerg { 3774154958bSjoerg int child; 3784154958bSjoerg struct tag *t; 3794154958bSjoerg 3804154958bSjoerg child = 1; 38122af4063Sjoerg t = h->tags.head; 3820511d63cSchristos n->flags &= ~MDOC_ENDED; 3834154958bSjoerg 3844154958bSjoerg switch (n->type) { 385*47a17e0dSchristos case ROFFT_TEXT: 38654a4f7feSjoerg /* No tables in this mode... */ 38754a4f7feSjoerg assert(NULL == h->tblt); 38854a4f7feSjoerg 38954a4f7feSjoerg /* 39054a4f7feSjoerg * Make sure that if we're in a literal mode already 39154a4f7feSjoerg * (i.e., within a <PRE>) don't print the newline. 39254a4f7feSjoerg */ 39354a4f7feSjoerg if (' ' == *n->string && MDOC_LINE & n->flags) 39454a4f7feSjoerg if ( ! (HTML_LITERAL & h->flags)) 39554a4f7feSjoerg print_otag(h, TAG_BR, 0, NULL); 39654a4f7feSjoerg if (MDOC_DELIMC & n->flags) 39754a4f7feSjoerg h->flags |= HTML_NOSPACE; 3984154958bSjoerg print_text(h, n->string); 39954a4f7feSjoerg if (MDOC_DELIMO & n->flags) 40054a4f7feSjoerg h->flags |= HTML_NOSPACE; 4017d71a621Sjoerg return; 402*47a17e0dSchristos case ROFFT_EQN: 4030511d63cSchristos if (n->flags & MDOC_LINE) 4040511d63cSchristos putchar('\n'); 405f8126693Sjoerg print_eqn(h, n->eqn); 406e4fbeb7eSjoerg break; 407*47a17e0dSchristos case ROFFT_TBL: 40854a4f7feSjoerg /* 40954a4f7feSjoerg * This will take care of initialising all of the table 41054a4f7feSjoerg * state data for the first table, then tearing it down 41154a4f7feSjoerg * for the last one. 41254a4f7feSjoerg */ 41354a4f7feSjoerg print_tbl(h, n->span); 41454a4f7feSjoerg return; 4154154958bSjoerg default: 41654a4f7feSjoerg /* 41754a4f7feSjoerg * Close out the current table, if it's open, and unset 41854a4f7feSjoerg * the "meta" table state. This will be reopened on the 41954a4f7feSjoerg * next table element. 42054a4f7feSjoerg */ 4210511d63cSchristos if (h->tblt != NULL) { 42254a4f7feSjoerg print_tblclose(h); 42354a4f7feSjoerg t = h->tags.head; 42454a4f7feSjoerg } 4250511d63cSchristos assert(h->tblt == NULL); 4260511d63cSchristos if (mdocs[n->tok].pre && (n->end == ENDBODY_NOT || n->child)) 427ed7c7912Sjoerg child = (*mdocs[n->tok].pre)(meta, n, h); 4284154958bSjoerg break; 4294154958bSjoerg } 4304154958bSjoerg 4310511d63cSchristos if (h->flags & HTML_KEEP && n->flags & MDOC_LINE) { 43282361f10Sjoerg h->flags &= ~HTML_KEEP; 43382361f10Sjoerg h->flags |= HTML_PREKEEP; 43482361f10Sjoerg } 43582361f10Sjoerg 4364154958bSjoerg if (child && n->child) 437ed7c7912Sjoerg print_mdoc_nodelist(meta, n->child, h); 4384154958bSjoerg 4394154958bSjoerg print_stagq(h, t); 4404154958bSjoerg 4414154958bSjoerg switch (n->type) { 442*47a17e0dSchristos case ROFFT_EQN: 443e4fbeb7eSjoerg break; 4444154958bSjoerg default: 4450511d63cSchristos if ( ! mdocs[n->tok].post || n->flags & MDOC_ENDED) 4460511d63cSchristos break; 447ed7c7912Sjoerg (*mdocs[n->tok].post)(meta, n, h); 4480511d63cSchristos if (n->end != ENDBODY_NOT) 4490511d63cSchristos n->body->flags |= MDOC_ENDED; 4500511d63cSchristos if (n->end == ENDBODY_NOSPACE) 4510511d63cSchristos h->flags |= HTML_NOSPACE; 4524154958bSjoerg break; 4534154958bSjoerg } 4544154958bSjoerg } 4554154958bSjoerg 4564154958bSjoerg static void 4574154958bSjoerg mdoc_root_post(MDOC_ARGS) 4584154958bSjoerg { 4590511d63cSchristos struct htmlpair tag; 4604154958bSjoerg struct tag *t, *tt; 4614154958bSjoerg 4620511d63cSchristos PAIR_CLASS_INIT(&tag, "foot"); 4630511d63cSchristos t = print_otag(h, TAG_TABLE, 1, &tag); 464e4fbeb7eSjoerg 465e7fe1698Sjoerg print_otag(h, TAG_TBODY, 0, NULL); 466e4fbeb7eSjoerg 4674154958bSjoerg tt = print_otag(h, TAG_TR, 0, NULL); 4684154958bSjoerg 4690511d63cSchristos PAIR_CLASS_INIT(&tag, "foot-date"); 4700511d63cSchristos print_otag(h, TAG_TD, 1, &tag); 471ed7c7912Sjoerg print_text(h, meta->date); 4724154958bSjoerg print_stagq(h, tt); 4734154958bSjoerg 4740511d63cSchristos PAIR_CLASS_INIT(&tag, "foot-os"); 4750511d63cSchristos print_otag(h, TAG_TD, 1, &tag); 476ed7c7912Sjoerg print_text(h, meta->os); 4774154958bSjoerg print_tagq(h, t); 4784154958bSjoerg } 4794154958bSjoerg 4804154958bSjoerg static int 4814154958bSjoerg mdoc_root_pre(MDOC_ARGS) 4824154958bSjoerg { 4830511d63cSchristos struct htmlpair tag; 4844154958bSjoerg struct tag *t, *tt; 4850511d63cSchristos char *volume, *title; 4864154958bSjoerg 4870511d63cSchristos if (NULL == meta->arch) 4880511d63cSchristos volume = mandoc_strdup(meta->vol); 4890511d63cSchristos else 4900511d63cSchristos mandoc_asprintf(&volume, "%s (%s)", 4910511d63cSchristos meta->vol, meta->arch); 4924154958bSjoerg 4930511d63cSchristos if (NULL == meta->msec) 4940511d63cSchristos title = mandoc_strdup(meta->title); 4950511d63cSchristos else 4960511d63cSchristos mandoc_asprintf(&title, "%s(%s)", 4970511d63cSchristos meta->title, meta->msec); 4984154958bSjoerg 4990511d63cSchristos PAIR_CLASS_INIT(&tag, "head"); 5000511d63cSchristos t = print_otag(h, TAG_TABLE, 1, &tag); 501e4fbeb7eSjoerg 502e4fbeb7eSjoerg print_otag(h, TAG_TBODY, 0, NULL); 5033514411fSjoerg 5044154958bSjoerg tt = print_otag(h, TAG_TR, 0, NULL); 5054154958bSjoerg 5060511d63cSchristos PAIR_CLASS_INIT(&tag, "head-ltitle"); 5070511d63cSchristos print_otag(h, TAG_TD, 1, &tag); 5084154958bSjoerg print_text(h, title); 5094154958bSjoerg print_stagq(h, tt); 5104154958bSjoerg 5110511d63cSchristos PAIR_CLASS_INIT(&tag, "head-vol"); 5120511d63cSchristos print_otag(h, TAG_TD, 1, &tag); 5130511d63cSchristos print_text(h, volume); 5144154958bSjoerg print_stagq(h, tt); 5154154958bSjoerg 5160511d63cSchristos PAIR_CLASS_INIT(&tag, "head-rtitle"); 5170511d63cSchristos print_otag(h, TAG_TD, 1, &tag); 5184154958bSjoerg print_text(h, title); 5194154958bSjoerg print_tagq(h, t); 5200511d63cSchristos 5210511d63cSchristos free(title); 5220511d63cSchristos free(volume); 523*47a17e0dSchristos return 1; 5244154958bSjoerg } 5254154958bSjoerg 5264154958bSjoerg static int 5274154958bSjoerg mdoc_sh_pre(MDOC_ARGS) 5284154958bSjoerg { 529e4fbeb7eSjoerg struct htmlpair tag; 5304154958bSjoerg 5310511d63cSchristos switch (n->type) { 532*47a17e0dSchristos case ROFFT_BLOCK: 533e4fbeb7eSjoerg PAIR_CLASS_INIT(&tag, "section"); 534e4fbeb7eSjoerg print_otag(h, TAG_DIV, 1, &tag); 535*47a17e0dSchristos return 1; 536*47a17e0dSchristos case ROFFT_BODY: 5370511d63cSchristos if (n->sec == SEC_AUTHORS) 5380511d63cSchristos h->flags &= ~(HTML_SPLIT|HTML_NOSPLIT); 539*47a17e0dSchristos return 1; 5400511d63cSchristos default: 5410511d63cSchristos break; 5420511d63cSchristos } 5434154958bSjoerg 544f8126693Sjoerg bufinit(h); 545f8126693Sjoerg 546*47a17e0dSchristos for (n = n->child; n != NULL && n->type == ROFFT_TEXT; ) { 547f8126693Sjoerg bufcat_id(h, n->string); 548f8126693Sjoerg if (NULL != (n = n->next)) 549f8126693Sjoerg bufcat_id(h, " "); 5504154958bSjoerg } 5514154958bSjoerg 552f8126693Sjoerg if (NULL == n) { 553f8126693Sjoerg PAIR_ID_INIT(&tag, h->buf); 554e4fbeb7eSjoerg print_otag(h, TAG_H1, 1, &tag); 555f8126693Sjoerg } else 556f8126693Sjoerg print_otag(h, TAG_H1, 0, NULL); 557f8126693Sjoerg 558*47a17e0dSchristos return 1; 5594154958bSjoerg } 5604154958bSjoerg 5614154958bSjoerg static int 5624154958bSjoerg mdoc_ss_pre(MDOC_ARGS) 5634154958bSjoerg { 564e4fbeb7eSjoerg struct htmlpair tag; 5654154958bSjoerg 566*47a17e0dSchristos if (n->type == ROFFT_BLOCK) { 567e4fbeb7eSjoerg PAIR_CLASS_INIT(&tag, "subsection"); 568e4fbeb7eSjoerg print_otag(h, TAG_DIV, 1, &tag); 569*47a17e0dSchristos return 1; 570*47a17e0dSchristos } else if (n->type == ROFFT_BODY) 571*47a17e0dSchristos return 1; 5724154958bSjoerg 573f8126693Sjoerg bufinit(h); 574f8126693Sjoerg 575*47a17e0dSchristos for (n = n->child; n != NULL && n->type == ROFFT_TEXT; ) { 576f8126693Sjoerg bufcat_id(h, n->string); 577f8126693Sjoerg if (NULL != (n = n->next)) 578f8126693Sjoerg bufcat_id(h, " "); 5794154958bSjoerg } 5804154958bSjoerg 581f8126693Sjoerg if (NULL == n) { 582f8126693Sjoerg PAIR_ID_INIT(&tag, h->buf); 583e4fbeb7eSjoerg print_otag(h, TAG_H2, 1, &tag); 584f8126693Sjoerg } else 585f8126693Sjoerg print_otag(h, TAG_H2, 0, NULL); 586f8126693Sjoerg 587*47a17e0dSchristos return 1; 5884154958bSjoerg } 5894154958bSjoerg 5904154958bSjoerg static int 5914154958bSjoerg mdoc_fl_pre(MDOC_ARGS) 5924154958bSjoerg { 5934154958bSjoerg struct htmlpair tag; 5944154958bSjoerg 5954154958bSjoerg PAIR_CLASS_INIT(&tag, "flag"); 596e4fbeb7eSjoerg print_otag(h, TAG_B, 1, &tag); 597d5e63c8dSjoerg 598d5e63c8dSjoerg /* `Cm' has no leading hyphen. */ 599d5e63c8dSjoerg 600d5e63c8dSjoerg if (MDOC_Cm == n->tok) 601*47a17e0dSchristos return 1; 602d5e63c8dSjoerg 6034154958bSjoerg print_text(h, "\\-"); 604d5e63c8dSjoerg 605*47a17e0dSchristos if (!(n->child == NULL && 6060511d63cSchristos (n->next == NULL || 607*47a17e0dSchristos n->next->type == ROFFT_TEXT || 6080511d63cSchristos n->next->flags & MDOC_LINE))) 6097bcc2a5fSjoerg h->flags |= HTML_NOSPACE; 610d5e63c8dSjoerg 611*47a17e0dSchristos return 1; 6124154958bSjoerg } 6134154958bSjoerg 6144154958bSjoerg static int 6154154958bSjoerg mdoc_nd_pre(MDOC_ARGS) 6164154958bSjoerg { 6174154958bSjoerg struct htmlpair tag; 6184154958bSjoerg 619*47a17e0dSchristos if (n->type != ROFFT_BODY) 620*47a17e0dSchristos return 1; 6214154958bSjoerg 6224154958bSjoerg /* XXX: this tag in theory can contain block elements. */ 6234154958bSjoerg 6244154958bSjoerg print_text(h, "\\(em"); 625e4fbeb7eSjoerg PAIR_CLASS_INIT(&tag, "desc"); 6264154958bSjoerg print_otag(h, TAG_SPAN, 1, &tag); 627*47a17e0dSchristos return 1; 6284154958bSjoerg } 6294154958bSjoerg 6304154958bSjoerg static int 6314154958bSjoerg mdoc_nm_pre(MDOC_ARGS) 6324154958bSjoerg { 6334154958bSjoerg struct htmlpair tag; 63482361f10Sjoerg struct roffsu su; 635f8126693Sjoerg int len; 6364154958bSjoerg 637e4fbeb7eSjoerg switch (n->type) { 638*47a17e0dSchristos case ROFFT_HEAD: 639*47a17e0dSchristos print_otag(h, TAG_TD, 0, NULL); 640*47a17e0dSchristos /* FALLTHROUGH */ 641*47a17e0dSchristos case ROFFT_ELEM: 6424154958bSjoerg PAIR_CLASS_INIT(&tag, "name"); 643e4fbeb7eSjoerg print_otag(h, TAG_B, 1, &tag); 644*47a17e0dSchristos if (n->child == NULL && meta->name != NULL) 645ed7c7912Sjoerg print_text(h, meta->name); 646*47a17e0dSchristos return 1; 647*47a17e0dSchristos case ROFFT_BODY: 648e4fbeb7eSjoerg print_otag(h, TAG_TD, 0, NULL); 649*47a17e0dSchristos return 1; 650e4fbeb7eSjoerg default: 651e4fbeb7eSjoerg break; 65282361f10Sjoerg } 65382361f10Sjoerg 654e4fbeb7eSjoerg synopsis_pre(h, n); 655e4fbeb7eSjoerg PAIR_CLASS_INIT(&tag, "synopsis"); 656e4fbeb7eSjoerg print_otag(h, TAG_TABLE, 1, &tag); 657e4fbeb7eSjoerg 658*47a17e0dSchristos for (len = 0, n = n->head->child; n; n = n->next) 659*47a17e0dSchristos if (n->type == ROFFT_TEXT) 660f8126693Sjoerg len += html_strlen(n->string); 661e4fbeb7eSjoerg 662*47a17e0dSchristos if (len == 0 && meta->name != NULL) 663ed7c7912Sjoerg len = html_strlen(meta->name); 664e4fbeb7eSjoerg 6650511d63cSchristos SCALE_HS_INIT(&su, len); 666f8126693Sjoerg bufinit(h); 667e4fbeb7eSjoerg bufcat_su(h, "width", &su); 668e4fbeb7eSjoerg PAIR_STYLE_INIT(&tag, h); 669e4fbeb7eSjoerg print_otag(h, TAG_COL, 1, &tag); 670e4fbeb7eSjoerg print_otag(h, TAG_COL, 0, NULL); 671e4fbeb7eSjoerg print_otag(h, TAG_TBODY, 0, NULL); 672e4fbeb7eSjoerg print_otag(h, TAG_TR, 0, NULL); 673*47a17e0dSchristos return 1; 6744154958bSjoerg } 6754154958bSjoerg 6764154958bSjoerg static int 6774154958bSjoerg mdoc_xr_pre(MDOC_ARGS) 6784154958bSjoerg { 6794154958bSjoerg struct htmlpair tag[2]; 6804154958bSjoerg 6817bcc2a5fSjoerg if (NULL == n->child) 682*47a17e0dSchristos return 0; 6837bcc2a5fSjoerg 6844154958bSjoerg PAIR_CLASS_INIT(&tag[0], "link-man"); 6854154958bSjoerg 6864154958bSjoerg if (h->base_man) { 6874154958bSjoerg buffmt_man(h, n->child->string, 6884154958bSjoerg n->child->next ? 6894154958bSjoerg n->child->next->string : NULL); 6907bcc2a5fSjoerg PAIR_HREF_INIT(&tag[1], h->buf); 6914154958bSjoerg print_otag(h, TAG_A, 2, tag); 6924154958bSjoerg } else 6934154958bSjoerg print_otag(h, TAG_A, 1, tag); 6944154958bSjoerg 69554a4f7feSjoerg n = n->child; 69654a4f7feSjoerg print_text(h, n->string); 6974154958bSjoerg 69854a4f7feSjoerg if (NULL == (n = n->next)) 699*47a17e0dSchristos return 0; 7004154958bSjoerg 7014154958bSjoerg h->flags |= HTML_NOSPACE; 7024154958bSjoerg print_text(h, "("); 7034154958bSjoerg h->flags |= HTML_NOSPACE; 70454a4f7feSjoerg print_text(h, n->string); 7054154958bSjoerg h->flags |= HTML_NOSPACE; 7064154958bSjoerg print_text(h, ")"); 707*47a17e0dSchristos return 0; 7084154958bSjoerg } 7094154958bSjoerg 7104154958bSjoerg static int 7114154958bSjoerg mdoc_ns_pre(MDOC_ARGS) 7124154958bSjoerg { 7134154958bSjoerg 71454a4f7feSjoerg if ( ! (MDOC_LINE & n->flags)) 7154154958bSjoerg h->flags |= HTML_NOSPACE; 716*47a17e0dSchristos return 1; 7174154958bSjoerg } 7184154958bSjoerg 7194154958bSjoerg static int 7204154958bSjoerg mdoc_ar_pre(MDOC_ARGS) 7214154958bSjoerg { 7224154958bSjoerg struct htmlpair tag; 7234154958bSjoerg 7244154958bSjoerg PAIR_CLASS_INIT(&tag, "arg"); 725e4fbeb7eSjoerg print_otag(h, TAG_I, 1, &tag); 726*47a17e0dSchristos return 1; 7274154958bSjoerg } 7284154958bSjoerg 7294154958bSjoerg static int 7304154958bSjoerg mdoc_xx_pre(MDOC_ARGS) 7314154958bSjoerg { 7324154958bSjoerg const char *pp; 7334154958bSjoerg struct htmlpair tag; 73454a4f7feSjoerg int flags; 7354154958bSjoerg 7364154958bSjoerg switch (n->tok) { 7370511d63cSchristos case MDOC_Bsx: 738e4fbeb7eSjoerg pp = "BSD/OS"; 7394154958bSjoerg break; 7400511d63cSchristos case MDOC_Dx: 7413514411fSjoerg pp = "DragonFly"; 7424154958bSjoerg break; 7430511d63cSchristos case MDOC_Fx: 7444154958bSjoerg pp = "FreeBSD"; 7454154958bSjoerg break; 7460511d63cSchristos case MDOC_Nx: 7474154958bSjoerg pp = "NetBSD"; 7484154958bSjoerg break; 7490511d63cSchristos case MDOC_Ox: 7504154958bSjoerg pp = "OpenBSD"; 7514154958bSjoerg break; 7520511d63cSchristos case MDOC_Ux: 7534154958bSjoerg pp = "UNIX"; 7544154958bSjoerg break; 7554154958bSjoerg default: 756*47a17e0dSchristos return 1; 7574154958bSjoerg } 7584154958bSjoerg 7594154958bSjoerg PAIR_CLASS_INIT(&tag, "unix"); 7604154958bSjoerg print_otag(h, TAG_SPAN, 1, &tag); 76154a4f7feSjoerg 7624154958bSjoerg print_text(h, pp); 76354a4f7feSjoerg if (n->child) { 76454a4f7feSjoerg flags = h->flags; 76554a4f7feSjoerg h->flags |= HTML_KEEP; 76654a4f7feSjoerg print_text(h, n->child->string); 76754a4f7feSjoerg h->flags = flags; 76854a4f7feSjoerg } 769*47a17e0dSchristos return 0; 7704154958bSjoerg } 7714154958bSjoerg 7724154958bSjoerg static int 7734154958bSjoerg mdoc_bx_pre(MDOC_ARGS) 7744154958bSjoerg { 7754154958bSjoerg struct htmlpair tag; 7764154958bSjoerg 7774154958bSjoerg PAIR_CLASS_INIT(&tag, "unix"); 7784154958bSjoerg print_otag(h, TAG_SPAN, 1, &tag); 7794154958bSjoerg 78054a4f7feSjoerg if (NULL != (n = n->child)) { 78154a4f7feSjoerg print_text(h, n->string); 7824154958bSjoerg h->flags |= HTML_NOSPACE; 7834154958bSjoerg print_text(h, "BSD"); 78454a4f7feSjoerg } else { 78554a4f7feSjoerg print_text(h, "BSD"); 786*47a17e0dSchristos return 0; 78754a4f7feSjoerg } 78854a4f7feSjoerg 78954a4f7feSjoerg if (NULL != (n = n->next)) { 79054a4f7feSjoerg h->flags |= HTML_NOSPACE; 79154a4f7feSjoerg print_text(h, "-"); 79254a4f7feSjoerg h->flags |= HTML_NOSPACE; 79354a4f7feSjoerg print_text(h, n->string); 79454a4f7feSjoerg } 79554a4f7feSjoerg 796*47a17e0dSchristos return 0; 7974154958bSjoerg } 7984154958bSjoerg 7994154958bSjoerg static int 8004154958bSjoerg mdoc_it_pre(MDOC_ARGS) 8014154958bSjoerg { 802e4fbeb7eSjoerg struct roffsu su; 8030a84adc5Sjoerg enum mdoc_list type; 804e4fbeb7eSjoerg struct htmlpair tag[2]; 805*47a17e0dSchristos const struct roff_node *bl; 8064154958bSjoerg 807e4fbeb7eSjoerg bl = n->parent; 808e4fbeb7eSjoerg while (bl && MDOC_Bl != bl->tok) 8094154958bSjoerg bl = bl->parent; 8104154958bSjoerg 811e4fbeb7eSjoerg assert(bl); 8124154958bSjoerg 813e4fbeb7eSjoerg type = bl->norm->Bl.type; 8146c26a9aaSjoerg 815e4fbeb7eSjoerg assert(lists[type]); 816e4fbeb7eSjoerg PAIR_CLASS_INIT(&tag[0], lists[type]); 8176c26a9aaSjoerg 818f8126693Sjoerg bufinit(h); 819f8126693Sjoerg 820*47a17e0dSchristos if (n->type == ROFFT_HEAD) { 8214154958bSjoerg switch (type) { 8220511d63cSchristos case LIST_bullet: 8230511d63cSchristos case LIST_dash: 8240511d63cSchristos case LIST_item: 8250511d63cSchristos case LIST_hyphen: 8260511d63cSchristos case LIST_enum: 827*47a17e0dSchristos return 0; 8280511d63cSchristos case LIST_diag: 8290511d63cSchristos case LIST_hang: 8300511d63cSchristos case LIST_inset: 8310511d63cSchristos case LIST_ohang: 8320511d63cSchristos case LIST_tag: 833e4fbeb7eSjoerg SCALE_VS_INIT(&su, ! bl->norm->Bl.comp); 834e4fbeb7eSjoerg bufcat_su(h, "margin-top", &su); 835e4fbeb7eSjoerg PAIR_STYLE_INIT(&tag[1], h); 836e4fbeb7eSjoerg print_otag(h, TAG_DT, 2, tag); 837e4fbeb7eSjoerg if (LIST_diag != type) 838e4fbeb7eSjoerg break; 839e4fbeb7eSjoerg PAIR_CLASS_INIT(&tag[0], "diag"); 840e4fbeb7eSjoerg print_otag(h, TAG_B, 1, tag); 841e4fbeb7eSjoerg break; 8420511d63cSchristos case LIST_column: 8434154958bSjoerg break; 8444154958bSjoerg default: 8454154958bSjoerg break; 8464154958bSjoerg } 847*47a17e0dSchristos } else if (n->type == ROFFT_BODY) { 848e4fbeb7eSjoerg switch (type) { 8490511d63cSchristos case LIST_bullet: 8500511d63cSchristos case LIST_hyphen: 8510511d63cSchristos case LIST_dash: 8520511d63cSchristos case LIST_enum: 8530511d63cSchristos case LIST_item: 854e4fbeb7eSjoerg SCALE_VS_INIT(&su, ! bl->norm->Bl.comp); 855e4fbeb7eSjoerg bufcat_su(h, "margin-top", &su); 856e4fbeb7eSjoerg PAIR_STYLE_INIT(&tag[1], h); 857e4fbeb7eSjoerg print_otag(h, TAG_LI, 2, tag); 858e4fbeb7eSjoerg break; 8590511d63cSchristos case LIST_diag: 8600511d63cSchristos case LIST_hang: 8610511d63cSchristos case LIST_inset: 8620511d63cSchristos case LIST_ohang: 8630511d63cSchristos case LIST_tag: 864e4fbeb7eSjoerg if (NULL == bl->norm->Bl.width) { 865e4fbeb7eSjoerg print_otag(h, TAG_DD, 1, tag); 866e4fbeb7eSjoerg break; 867e4fbeb7eSjoerg } 868e4fbeb7eSjoerg a2width(bl->norm->Bl.width, &su); 869e4fbeb7eSjoerg bufcat_su(h, "margin-left", &su); 870e4fbeb7eSjoerg PAIR_STYLE_INIT(&tag[1], h); 871e4fbeb7eSjoerg print_otag(h, TAG_DD, 2, tag); 872e4fbeb7eSjoerg break; 8730511d63cSchristos case LIST_column: 874e4fbeb7eSjoerg SCALE_VS_INIT(&su, ! bl->norm->Bl.comp); 875e4fbeb7eSjoerg bufcat_su(h, "margin-top", &su); 876e4fbeb7eSjoerg PAIR_STYLE_INIT(&tag[1], h); 877e4fbeb7eSjoerg print_otag(h, TAG_TD, 2, tag); 878e4fbeb7eSjoerg break; 879e4fbeb7eSjoerg default: 880e4fbeb7eSjoerg break; 881e4fbeb7eSjoerg } 882e4fbeb7eSjoerg } else { 883e4fbeb7eSjoerg switch (type) { 8840511d63cSchristos case LIST_column: 885e4fbeb7eSjoerg print_otag(h, TAG_TR, 1, tag); 886e4fbeb7eSjoerg break; 887e4fbeb7eSjoerg default: 888e4fbeb7eSjoerg break; 889e4fbeb7eSjoerg } 8904154958bSjoerg } 8914154958bSjoerg 892*47a17e0dSchristos return 1; 8934154958bSjoerg } 8944154958bSjoerg 8954154958bSjoerg static int 8964154958bSjoerg mdoc_bl_pre(MDOC_ARGS) 8974154958bSjoerg { 898e4fbeb7eSjoerg int i; 899e4fbeb7eSjoerg struct htmlpair tag[3]; 900e4fbeb7eSjoerg struct roffsu su; 901e4fbeb7eSjoerg char buf[BUFSIZ]; 9024154958bSjoerg 903*47a17e0dSchristos if (n->type == ROFFT_BODY) { 904e4fbeb7eSjoerg if (LIST_column == n->norm->Bl.type) 905e4fbeb7eSjoerg print_otag(h, TAG_TBODY, 0, NULL); 906*47a17e0dSchristos return 1; 907e4fbeb7eSjoerg } 908e4fbeb7eSjoerg 909*47a17e0dSchristos if (n->type == ROFFT_HEAD) { 910e4fbeb7eSjoerg if (LIST_column != n->norm->Bl.type) 911*47a17e0dSchristos return 0; 9124154958bSjoerg 913e4fbeb7eSjoerg /* 914e4fbeb7eSjoerg * For each column, print out the <COL> tag with our 915e4fbeb7eSjoerg * suggested width. The last column gets min-width, as 916e4fbeb7eSjoerg * in terminal mode it auto-sizes to the width of the 917e4fbeb7eSjoerg * screen and we want to preserve that behaviour. 918e4fbeb7eSjoerg */ 919e4fbeb7eSjoerg 920e4fbeb7eSjoerg for (i = 0; i < (int)n->norm->Bl.ncols; i++) { 921ed7c7912Sjoerg bufinit(h); 922e4fbeb7eSjoerg a2width(n->norm->Bl.cols[i], &su); 923e4fbeb7eSjoerg if (i < (int)n->norm->Bl.ncols - 1) 924e4fbeb7eSjoerg bufcat_su(h, "width", &su); 925e4fbeb7eSjoerg else 926e4fbeb7eSjoerg bufcat_su(h, "min-width", &su); 927e4fbeb7eSjoerg PAIR_STYLE_INIT(&tag[0], h); 928e4fbeb7eSjoerg print_otag(h, TAG_COL, 1, tag); 9294154958bSjoerg } 9304154958bSjoerg 931*47a17e0dSchristos return 0; 9324154958bSjoerg } 9334154958bSjoerg 934e4fbeb7eSjoerg SCALE_VS_INIT(&su, 0); 935ed7c7912Sjoerg bufinit(h); 936e4fbeb7eSjoerg bufcat_su(h, "margin-top", &su); 937e4fbeb7eSjoerg bufcat_su(h, "margin-bottom", &su); 938e4fbeb7eSjoerg PAIR_STYLE_INIT(&tag[0], h); 939e4fbeb7eSjoerg 940e4fbeb7eSjoerg assert(lists[n->norm->Bl.type]); 9410511d63cSchristos (void)strlcpy(buf, "list ", BUFSIZ); 9420511d63cSchristos (void)strlcat(buf, lists[n->norm->Bl.type], BUFSIZ); 943e4fbeb7eSjoerg PAIR_INIT(&tag[1], ATTR_CLASS, buf); 944e4fbeb7eSjoerg 945e4fbeb7eSjoerg /* Set the block's left-hand margin. */ 946e4fbeb7eSjoerg 947e4fbeb7eSjoerg if (n->norm->Bl.offs) { 9480511d63cSchristos a2width(n->norm->Bl.offs, &su); 949e4fbeb7eSjoerg bufcat_su(h, "margin-left", &su); 950e4fbeb7eSjoerg } 951e4fbeb7eSjoerg 952e4fbeb7eSjoerg switch (n->norm->Bl.type) { 9530511d63cSchristos case LIST_bullet: 9540511d63cSchristos case LIST_dash: 9550511d63cSchristos case LIST_hyphen: 9560511d63cSchristos case LIST_item: 957e4fbeb7eSjoerg print_otag(h, TAG_UL, 2, tag); 958e4fbeb7eSjoerg break; 9590511d63cSchristos case LIST_enum: 960e4fbeb7eSjoerg print_otag(h, TAG_OL, 2, tag); 961e4fbeb7eSjoerg break; 9620511d63cSchristos case LIST_diag: 9630511d63cSchristos case LIST_hang: 9640511d63cSchristos case LIST_inset: 9650511d63cSchristos case LIST_ohang: 9660511d63cSchristos case LIST_tag: 967e4fbeb7eSjoerg print_otag(h, TAG_DL, 2, tag); 968e4fbeb7eSjoerg break; 9690511d63cSchristos case LIST_column: 970e4fbeb7eSjoerg print_otag(h, TAG_TABLE, 2, tag); 971e4fbeb7eSjoerg break; 972e4fbeb7eSjoerg default: 973e4fbeb7eSjoerg abort(); 974e4fbeb7eSjoerg } 975e4fbeb7eSjoerg 976*47a17e0dSchristos return 1; 977e4fbeb7eSjoerg } 9784154958bSjoerg 9794154958bSjoerg static int 9804154958bSjoerg mdoc_ex_pre(MDOC_ARGS) 9814154958bSjoerg { 9824154958bSjoerg struct htmlpair tag; 983*47a17e0dSchristos struct tag *t; 984*47a17e0dSchristos struct roff_node *nch; 9854154958bSjoerg 986e4fbeb7eSjoerg if (n->prev) 987e4fbeb7eSjoerg print_otag(h, TAG_BR, 0, NULL); 988e4fbeb7eSjoerg 9894154958bSjoerg PAIR_CLASS_INIT(&tag, "utility"); 9904154958bSjoerg 9914154958bSjoerg print_text(h, "The"); 99254a4f7feSjoerg 993*47a17e0dSchristos for (nch = n->child; nch != NULL; nch = nch->next) { 994*47a17e0dSchristos assert(nch->type == ROFFT_TEXT); 99554a4f7feSjoerg 996e4fbeb7eSjoerg t = print_otag(h, TAG_B, 1, &tag); 997*47a17e0dSchristos print_text(h, nch->string); 9984154958bSjoerg print_tagq(h, t); 9994154958bSjoerg 1000*47a17e0dSchristos if (nch->next == NULL) 1001*47a17e0dSchristos continue; 1002*47a17e0dSchristos 1003*47a17e0dSchristos if (nch->prev != NULL || nch->next->next != NULL) { 10044154958bSjoerg h->flags |= HTML_NOSPACE; 10054154958bSjoerg print_text(h, ","); 10064154958bSjoerg } 10074154958bSjoerg 1008*47a17e0dSchristos if (nch->next->next == NULL) 100954a4f7feSjoerg print_text(h, "and"); 101054a4f7feSjoerg } 101154a4f7feSjoerg 1012*47a17e0dSchristos if (n->child != NULL && n->child->next != NULL) 10130511d63cSchristos print_text(h, "utilities exit\\~0"); 10144154958bSjoerg else 10150511d63cSchristos print_text(h, "utility exits\\~0"); 10164154958bSjoerg 10170511d63cSchristos print_text(h, "on success, and\\~>0 if an error occurs."); 1018*47a17e0dSchristos return 0; 10194154958bSjoerg } 10204154958bSjoerg 10214154958bSjoerg static int 10224154958bSjoerg mdoc_em_pre(MDOC_ARGS) 10234154958bSjoerg { 10244154958bSjoerg struct htmlpair tag; 10254154958bSjoerg 10264154958bSjoerg PAIR_CLASS_INIT(&tag, "emph"); 10274154958bSjoerg print_otag(h, TAG_SPAN, 1, &tag); 1028*47a17e0dSchristos return 1; 10294154958bSjoerg } 10304154958bSjoerg 10314154958bSjoerg static int 10324154958bSjoerg mdoc_d1_pre(MDOC_ARGS) 10334154958bSjoerg { 10344154958bSjoerg struct htmlpair tag[2]; 10354154958bSjoerg struct roffsu su; 10364154958bSjoerg 1037*47a17e0dSchristos if (n->type != ROFFT_BLOCK) 1038*47a17e0dSchristos return 1; 10394154958bSjoerg 1040e4fbeb7eSjoerg SCALE_VS_INIT(&su, 0); 1041f8126693Sjoerg bufinit(h); 1042e4fbeb7eSjoerg bufcat_su(h, "margin-top", &su); 1043e4fbeb7eSjoerg bufcat_su(h, "margin-bottom", &su); 1044e4fbeb7eSjoerg PAIR_STYLE_INIT(&tag[0], h); 1045e4fbeb7eSjoerg print_otag(h, TAG_BLOCKQUOTE, 1, tag); 10464154958bSjoerg 1047e4fbeb7eSjoerg /* BLOCKQUOTE needs a block body. */ 1048e4fbeb7eSjoerg 1049e4fbeb7eSjoerg PAIR_CLASS_INIT(&tag[0], "display"); 1050e4fbeb7eSjoerg print_otag(h, TAG_DIV, 1, tag); 1051e4fbeb7eSjoerg 1052e4fbeb7eSjoerg if (MDOC_Dl == n->tok) { 10534154958bSjoerg PAIR_CLASS_INIT(&tag[0], "lit"); 1054e4fbeb7eSjoerg print_otag(h, TAG_CODE, 1, tag); 1055e4fbeb7eSjoerg } 1056e4fbeb7eSjoerg 1057*47a17e0dSchristos return 1; 10584154958bSjoerg } 10594154958bSjoerg 10604154958bSjoerg static int 10614154958bSjoerg mdoc_sx_pre(MDOC_ARGS) 10624154958bSjoerg { 10634154958bSjoerg struct htmlpair tag[2]; 10644154958bSjoerg 1065f8126693Sjoerg bufinit(h); 1066*47a17e0dSchristos bufcat(h, "#"); 1067f8126693Sjoerg 1068f8126693Sjoerg for (n = n->child; n; ) { 1069f8126693Sjoerg bufcat_id(h, n->string); 1070f8126693Sjoerg if (NULL != (n = n->next)) 1071f8126693Sjoerg bufcat_id(h, " "); 10724154958bSjoerg } 10734154958bSjoerg 10744154958bSjoerg PAIR_CLASS_INIT(&tag[0], "link-sec"); 1075f8126693Sjoerg PAIR_HREF_INIT(&tag[1], h->buf); 10764154958bSjoerg 1077e4fbeb7eSjoerg print_otag(h, TAG_I, 1, tag); 10784154958bSjoerg print_otag(h, TAG_A, 2, tag); 1079*47a17e0dSchristos return 1; 10804154958bSjoerg } 10814154958bSjoerg 10824154958bSjoerg static int 10834154958bSjoerg mdoc_bd_pre(MDOC_ARGS) 10844154958bSjoerg { 10854154958bSjoerg struct htmlpair tag[2]; 108654a4f7feSjoerg int comp, sv; 1087*47a17e0dSchristos struct roff_node *nn; 10884154958bSjoerg struct roffsu su; 10894154958bSjoerg 1090*47a17e0dSchristos if (n->type == ROFFT_HEAD) 1091*47a17e0dSchristos return 0; 10924154958bSjoerg 1093*47a17e0dSchristos if (n->type == ROFFT_BLOCK) { 1094e4fbeb7eSjoerg comp = n->norm->Bd.comp; 10954154958bSjoerg for (nn = n; nn && ! comp; nn = nn->parent) { 1096*47a17e0dSchristos if (nn->type != ROFFT_BLOCK) 10974154958bSjoerg continue; 10984154958bSjoerg if (MDOC_Ss == nn->tok || MDOC_Sh == nn->tok) 10994154958bSjoerg comp = 1; 11004154958bSjoerg if (nn->prev) 11014154958bSjoerg break; 11024154958bSjoerg } 1103e4fbeb7eSjoerg if ( ! comp) 11040511d63cSchristos print_paragraph(h); 1105*47a17e0dSchristos return 1; 11064154958bSjoerg } 11074154958bSjoerg 11080511d63cSchristos /* Handle the -offset argument. */ 11090511d63cSchristos 11100511d63cSchristos if (n->norm->Bd.offs == NULL || 11110511d63cSchristos ! strcmp(n->norm->Bd.offs, "left")) 1112e4fbeb7eSjoerg SCALE_HS_INIT(&su, 0); 11130511d63cSchristos else if ( ! strcmp(n->norm->Bd.offs, "indent")) 11140511d63cSchristos SCALE_HS_INIT(&su, INDENT); 11150511d63cSchristos else if ( ! strcmp(n->norm->Bd.offs, "indent-two")) 11160511d63cSchristos SCALE_HS_INIT(&su, INDENT * 2); 11170511d63cSchristos else 11180511d63cSchristos a2width(n->norm->Bd.offs, &su); 11194154958bSjoerg 1120f8126693Sjoerg bufinit(h); 1121e4fbeb7eSjoerg bufcat_su(h, "margin-left", &su); 1122e4fbeb7eSjoerg PAIR_STYLE_INIT(&tag[0], h); 1123e4fbeb7eSjoerg 1124e4fbeb7eSjoerg if (DISP_unfilled != n->norm->Bd.type && 1125e4fbeb7eSjoerg DISP_literal != n->norm->Bd.type) { 1126e4fbeb7eSjoerg PAIR_CLASS_INIT(&tag[1], "display"); 11274154958bSjoerg print_otag(h, TAG_DIV, 2, tag); 1128*47a17e0dSchristos return 1; 1129e4fbeb7eSjoerg } 1130e4fbeb7eSjoerg 1131e4fbeb7eSjoerg PAIR_CLASS_INIT(&tag[1], "lit display"); 1132e4fbeb7eSjoerg print_otag(h, TAG_PRE, 2, tag); 11334154958bSjoerg 113454a4f7feSjoerg /* This can be recursive: save & set our literal state. */ 113554a4f7feSjoerg 113654a4f7feSjoerg sv = h->flags & HTML_LITERAL; 113754a4f7feSjoerg h->flags |= HTML_LITERAL; 113854a4f7feSjoerg 11394154958bSjoerg for (nn = n->child; nn; nn = nn->next) { 1140ed7c7912Sjoerg print_mdoc_node(meta, nn, h); 1141e4fbeb7eSjoerg /* 1142e4fbeb7eSjoerg * If the printed node flushes its own line, then we 1143e4fbeb7eSjoerg * needn't do it here as well. This is hacky, but the 1144e4fbeb7eSjoerg * notion of selective eoln whitespace is pretty dumb 1145e4fbeb7eSjoerg * anyway, so don't sweat it. 1146e4fbeb7eSjoerg */ 1147e4fbeb7eSjoerg switch (nn->tok) { 11480511d63cSchristos case MDOC_Sm: 11490511d63cSchristos case MDOC_br: 11500511d63cSchristos case MDOC_sp: 11510511d63cSchristos case MDOC_Bl: 11520511d63cSchristos case MDOC_D1: 11530511d63cSchristos case MDOC_Dl: 11540511d63cSchristos case MDOC_Lp: 11550511d63cSchristos case MDOC_Pp: 1156e4fbeb7eSjoerg continue; 1157e4fbeb7eSjoerg default: 1158e4fbeb7eSjoerg break; 1159e4fbeb7eSjoerg } 11600511d63cSchristos if (h->flags & HTML_NONEWLINE || 11610511d63cSchristos (nn->next && ! (nn->next->flags & MDOC_LINE))) 1162e4fbeb7eSjoerg continue; 1163e4fbeb7eSjoerg else if (nn->next) 1164e4fbeb7eSjoerg print_text(h, "\n"); 1165e4fbeb7eSjoerg 1166e4fbeb7eSjoerg h->flags |= HTML_NOSPACE; 11674154958bSjoerg } 11684154958bSjoerg 116954a4f7feSjoerg if (0 == sv) 117054a4f7feSjoerg h->flags &= ~HTML_LITERAL; 117154a4f7feSjoerg 1172*47a17e0dSchristos return 0; 11734154958bSjoerg } 11744154958bSjoerg 11754154958bSjoerg static int 11764154958bSjoerg mdoc_pa_pre(MDOC_ARGS) 11774154958bSjoerg { 11784154958bSjoerg struct htmlpair tag; 11794154958bSjoerg 11804154958bSjoerg PAIR_CLASS_INIT(&tag, "file"); 1181e4fbeb7eSjoerg print_otag(h, TAG_I, 1, &tag); 1182*47a17e0dSchristos return 1; 11834154958bSjoerg } 11844154958bSjoerg 11854154958bSjoerg static int 11864154958bSjoerg mdoc_ad_pre(MDOC_ARGS) 11874154958bSjoerg { 11884154958bSjoerg struct htmlpair tag; 11894154958bSjoerg 11904154958bSjoerg PAIR_CLASS_INIT(&tag, "addr"); 1191e4fbeb7eSjoerg print_otag(h, TAG_I, 1, &tag); 1192*47a17e0dSchristos return 1; 11934154958bSjoerg } 11944154958bSjoerg 11954154958bSjoerg static int 11964154958bSjoerg mdoc_an_pre(MDOC_ARGS) 11974154958bSjoerg { 11984154958bSjoerg struct htmlpair tag; 11994154958bSjoerg 12000511d63cSchristos if (n->norm->An.auth == AUTH_split) { 12010511d63cSchristos h->flags &= ~HTML_NOSPLIT; 12020511d63cSchristos h->flags |= HTML_SPLIT; 1203*47a17e0dSchristos return 0; 12040511d63cSchristos } 12050511d63cSchristos if (n->norm->An.auth == AUTH_nosplit) { 12060511d63cSchristos h->flags &= ~HTML_SPLIT; 12070511d63cSchristos h->flags |= HTML_NOSPLIT; 1208*47a17e0dSchristos return 0; 12090511d63cSchristos } 12100511d63cSchristos 12110511d63cSchristos if (h->flags & HTML_SPLIT) 12120511d63cSchristos print_otag(h, TAG_BR, 0, NULL); 12130511d63cSchristos 12140511d63cSchristos if (n->sec == SEC_AUTHORS && ! (h->flags & HTML_NOSPLIT)) 12150511d63cSchristos h->flags |= HTML_SPLIT; 12164154958bSjoerg 12174154958bSjoerg PAIR_CLASS_INIT(&tag, "author"); 12184154958bSjoerg print_otag(h, TAG_SPAN, 1, &tag); 1219*47a17e0dSchristos return 1; 12204154958bSjoerg } 12214154958bSjoerg 12224154958bSjoerg static int 12234154958bSjoerg mdoc_cd_pre(MDOC_ARGS) 12244154958bSjoerg { 12254154958bSjoerg struct htmlpair tag; 12264154958bSjoerg 12277574e07eSjoerg synopsis_pre(h, n); 12284154958bSjoerg PAIR_CLASS_INIT(&tag, "config"); 1229e4fbeb7eSjoerg print_otag(h, TAG_B, 1, &tag); 1230*47a17e0dSchristos return 1; 12314154958bSjoerg } 12324154958bSjoerg 12334154958bSjoerg static int 12344154958bSjoerg mdoc_dv_pre(MDOC_ARGS) 12354154958bSjoerg { 12364154958bSjoerg struct htmlpair tag; 12374154958bSjoerg 12384154958bSjoerg PAIR_CLASS_INIT(&tag, "define"); 12394154958bSjoerg print_otag(h, TAG_SPAN, 1, &tag); 1240*47a17e0dSchristos return 1; 12414154958bSjoerg } 12424154958bSjoerg 12434154958bSjoerg static int 12444154958bSjoerg mdoc_ev_pre(MDOC_ARGS) 12454154958bSjoerg { 12464154958bSjoerg struct htmlpair tag; 12474154958bSjoerg 12484154958bSjoerg PAIR_CLASS_INIT(&tag, "env"); 12494154958bSjoerg print_otag(h, TAG_SPAN, 1, &tag); 1250*47a17e0dSchristos return 1; 12514154958bSjoerg } 12524154958bSjoerg 12534154958bSjoerg static int 12544154958bSjoerg mdoc_er_pre(MDOC_ARGS) 12554154958bSjoerg { 12564154958bSjoerg struct htmlpair tag; 12574154958bSjoerg 12584154958bSjoerg PAIR_CLASS_INIT(&tag, "errno"); 12594154958bSjoerg print_otag(h, TAG_SPAN, 1, &tag); 1260*47a17e0dSchristos return 1; 12614154958bSjoerg } 12624154958bSjoerg 12634154958bSjoerg static int 12644154958bSjoerg mdoc_fa_pre(MDOC_ARGS) 12654154958bSjoerg { 1266*47a17e0dSchristos const struct roff_node *nn; 12674154958bSjoerg struct htmlpair tag; 12684154958bSjoerg struct tag *t; 12694154958bSjoerg 12704154958bSjoerg PAIR_CLASS_INIT(&tag, "farg"); 12714154958bSjoerg if (n->parent->tok != MDOC_Fo) { 1272e4fbeb7eSjoerg print_otag(h, TAG_I, 1, &tag); 1273*47a17e0dSchristos return 1; 12744154958bSjoerg } 12754154958bSjoerg 12764154958bSjoerg for (nn = n->child; nn; nn = nn->next) { 1277e4fbeb7eSjoerg t = print_otag(h, TAG_I, 1, &tag); 12784154958bSjoerg print_text(h, nn->string); 12794154958bSjoerg print_tagq(h, t); 128054a4f7feSjoerg if (nn->next) { 128154a4f7feSjoerg h->flags |= HTML_NOSPACE; 12824154958bSjoerg print_text(h, ","); 12834154958bSjoerg } 128454a4f7feSjoerg } 12854154958bSjoerg 128654a4f7feSjoerg if (n->child && n->next && n->next->tok == MDOC_Fa) { 128754a4f7feSjoerg h->flags |= HTML_NOSPACE; 12884154958bSjoerg print_text(h, ","); 128954a4f7feSjoerg } 12904154958bSjoerg 1291*47a17e0dSchristos return 0; 12924154958bSjoerg } 12934154958bSjoerg 12944154958bSjoerg static int 12954154958bSjoerg mdoc_fd_pre(MDOC_ARGS) 12964154958bSjoerg { 129754a4f7feSjoerg struct htmlpair tag[2]; 129854a4f7feSjoerg char buf[BUFSIZ]; 129954a4f7feSjoerg size_t sz; 130054a4f7feSjoerg int i; 130154a4f7feSjoerg struct tag *t; 13024154958bSjoerg 13037574e07eSjoerg synopsis_pre(h, n); 13044154958bSjoerg 130554a4f7feSjoerg if (NULL == (n = n->child)) 1306*47a17e0dSchristos return 0; 130754a4f7feSjoerg 1308*47a17e0dSchristos assert(n->type == ROFFT_TEXT); 130954a4f7feSjoerg 131054a4f7feSjoerg if (strcmp(n->string, "#include")) { 131154a4f7feSjoerg PAIR_CLASS_INIT(&tag[0], "macro"); 131254a4f7feSjoerg print_otag(h, TAG_B, 1, tag); 1313*47a17e0dSchristos return 1; 13144154958bSjoerg } 13154154958bSjoerg 131654a4f7feSjoerg PAIR_CLASS_INIT(&tag[0], "includes"); 131754a4f7feSjoerg print_otag(h, TAG_B, 1, tag); 131854a4f7feSjoerg print_text(h, n->string); 131954a4f7feSjoerg 132054a4f7feSjoerg if (NULL != (n = n->next)) { 1321*47a17e0dSchristos assert(n->type == ROFFT_TEXT); 13220511d63cSchristos 13230511d63cSchristos /* 13240511d63cSchristos * XXX This is broken and not easy to fix. 13250511d63cSchristos * When using -Oincludes, truncation may occur. 13260511d63cSchristos * Dynamic allocation wouldn't help because 13270511d63cSchristos * passing long strings to buffmt_includes() 13280511d63cSchristos * does not work either. 13290511d63cSchristos */ 13300511d63cSchristos 133154a4f7feSjoerg strlcpy(buf, '<' == *n->string || '"' == *n->string ? 133254a4f7feSjoerg n->string + 1 : n->string, BUFSIZ); 133354a4f7feSjoerg 133454a4f7feSjoerg sz = strlen(buf); 133554a4f7feSjoerg if (sz && ('>' == buf[sz - 1] || '"' == buf[sz - 1])) 133654a4f7feSjoerg buf[sz - 1] = '\0'; 133754a4f7feSjoerg 133854a4f7feSjoerg PAIR_CLASS_INIT(&tag[0], "link-includes"); 133954a4f7feSjoerg 134054a4f7feSjoerg i = 1; 134154a4f7feSjoerg if (h->base_includes) { 134254a4f7feSjoerg buffmt_includes(h, buf); 134354a4f7feSjoerg PAIR_HREF_INIT(&tag[i], h->buf); 134454a4f7feSjoerg i++; 134554a4f7feSjoerg } 134654a4f7feSjoerg 134754a4f7feSjoerg t = print_otag(h, TAG_A, i, tag); 134854a4f7feSjoerg print_text(h, n->string); 134954a4f7feSjoerg print_tagq(h, t); 135054a4f7feSjoerg 135154a4f7feSjoerg n = n->next; 135254a4f7feSjoerg } 135354a4f7feSjoerg 135454a4f7feSjoerg for ( ; n; n = n->next) { 1355*47a17e0dSchristos assert(n->type == ROFFT_TEXT); 135654a4f7feSjoerg print_text(h, n->string); 135754a4f7feSjoerg } 135854a4f7feSjoerg 1359*47a17e0dSchristos return 0; 136054a4f7feSjoerg } 136154a4f7feSjoerg 13624154958bSjoerg static int 13634154958bSjoerg mdoc_vt_pre(MDOC_ARGS) 13644154958bSjoerg { 13654154958bSjoerg struct htmlpair tag; 13664154958bSjoerg 1367*47a17e0dSchristos if (n->type == ROFFT_BLOCK) { 13687574e07eSjoerg synopsis_pre(h, n); 1369*47a17e0dSchristos return 1; 1370*47a17e0dSchristos } else if (n->type == ROFFT_ELEM) { 13717574e07eSjoerg synopsis_pre(h, n); 1372*47a17e0dSchristos } else if (n->type == ROFFT_HEAD) 1373*47a17e0dSchristos return 0; 13744154958bSjoerg 13754154958bSjoerg PAIR_CLASS_INIT(&tag, "type"); 13764154958bSjoerg print_otag(h, TAG_SPAN, 1, &tag); 1377*47a17e0dSchristos return 1; 13784154958bSjoerg } 13794154958bSjoerg 13804154958bSjoerg static int 13814154958bSjoerg mdoc_ft_pre(MDOC_ARGS) 13824154958bSjoerg { 13834154958bSjoerg struct htmlpair tag; 13844154958bSjoerg 13857574e07eSjoerg synopsis_pre(h, n); 13864154958bSjoerg PAIR_CLASS_INIT(&tag, "ftype"); 1387e4fbeb7eSjoerg print_otag(h, TAG_I, 1, &tag); 1388*47a17e0dSchristos return 1; 13894154958bSjoerg } 13904154958bSjoerg 13914154958bSjoerg static int 13924154958bSjoerg mdoc_fn_pre(MDOC_ARGS) 13934154958bSjoerg { 13944154958bSjoerg struct tag *t; 13954154958bSjoerg struct htmlpair tag[2]; 13964154958bSjoerg char nbuf[BUFSIZ]; 13974154958bSjoerg const char *sp, *ep; 139854a4f7feSjoerg int sz, i, pretty; 13994154958bSjoerg 140054a4f7feSjoerg pretty = MDOC_SYNPRETTY & n->flags; 14017574e07eSjoerg synopsis_pre(h, n); 14024154958bSjoerg 14034154958bSjoerg /* Split apart into type and name. */ 14044154958bSjoerg assert(n->child->string); 14054154958bSjoerg sp = n->child->string; 14064154958bSjoerg 14074154958bSjoerg ep = strchr(sp, ' '); 14084154958bSjoerg if (NULL != ep) { 14094154958bSjoerg PAIR_CLASS_INIT(&tag[0], "ftype"); 1410e4fbeb7eSjoerg t = print_otag(h, TAG_I, 1, tag); 14114154958bSjoerg 14124154958bSjoerg while (ep) { 14134154958bSjoerg sz = MIN((int)(ep - sp), BUFSIZ - 1); 14144154958bSjoerg (void)memcpy(nbuf, sp, (size_t)sz); 14154154958bSjoerg nbuf[sz] = '\0'; 14164154958bSjoerg print_text(h, nbuf); 14174154958bSjoerg sp = ++ep; 14184154958bSjoerg ep = strchr(sp, ' '); 14194154958bSjoerg } 14204154958bSjoerg print_tagq(h, t); 14214154958bSjoerg } 14224154958bSjoerg 14234154958bSjoerg PAIR_CLASS_INIT(&tag[0], "fname"); 14247bcc2a5fSjoerg 14257bcc2a5fSjoerg /* 14267bcc2a5fSjoerg * FIXME: only refer to IDs that we know exist. 14277bcc2a5fSjoerg */ 14287bcc2a5fSjoerg 14297bcc2a5fSjoerg #if 0 143082361f10Sjoerg if (MDOC_SYNPRETTY & n->flags) { 14317bcc2a5fSjoerg nbuf[0] = '\0'; 14327bcc2a5fSjoerg html_idcat(nbuf, sp, BUFSIZ); 14337bcc2a5fSjoerg PAIR_ID_INIT(&tag[1], nbuf); 14347bcc2a5fSjoerg } else { 14357bcc2a5fSjoerg strlcpy(nbuf, "#", BUFSIZ); 14367bcc2a5fSjoerg html_idcat(nbuf, sp, BUFSIZ); 14377bcc2a5fSjoerg PAIR_HREF_INIT(&tag[1], nbuf); 14387bcc2a5fSjoerg } 14397bcc2a5fSjoerg #endif 14407bcc2a5fSjoerg 1441e4fbeb7eSjoerg t = print_otag(h, TAG_B, 1, tag); 14424154958bSjoerg 14430511d63cSchristos if (sp) 14440511d63cSchristos print_text(h, sp); 14454154958bSjoerg 14464154958bSjoerg print_tagq(h, t); 14474154958bSjoerg 14484154958bSjoerg h->flags |= HTML_NOSPACE; 14494154958bSjoerg print_text(h, "("); 145054a4f7feSjoerg h->flags |= HTML_NOSPACE; 14514154958bSjoerg 14524154958bSjoerg PAIR_CLASS_INIT(&tag[0], "farg"); 1453f8126693Sjoerg bufinit(h); 14544154958bSjoerg bufcat_style(h, "white-space", "nowrap"); 14554154958bSjoerg PAIR_STYLE_INIT(&tag[1], h); 14564154958bSjoerg 145754a4f7feSjoerg for (n = n->child->next; n; n = n->next) { 14584154958bSjoerg i = 1; 145982361f10Sjoerg if (MDOC_SYNPRETTY & n->flags) 14604154958bSjoerg i = 2; 1461e4fbeb7eSjoerg t = print_otag(h, TAG_I, i, tag); 146254a4f7feSjoerg print_text(h, n->string); 14634154958bSjoerg print_tagq(h, t); 146454a4f7feSjoerg if (n->next) { 146554a4f7feSjoerg h->flags |= HTML_NOSPACE; 14664154958bSjoerg print_text(h, ","); 14674154958bSjoerg } 146854a4f7feSjoerg } 14694154958bSjoerg 147054a4f7feSjoerg h->flags |= HTML_NOSPACE; 14714154958bSjoerg print_text(h, ")"); 147254a4f7feSjoerg 147354a4f7feSjoerg if (pretty) { 147454a4f7feSjoerg h->flags |= HTML_NOSPACE; 14754154958bSjoerg print_text(h, ";"); 147654a4f7feSjoerg } 14774154958bSjoerg 1478*47a17e0dSchristos return 0; 14794154958bSjoerg } 14804154958bSjoerg 14814154958bSjoerg static int 14827da9b934Sjoerg mdoc_sm_pre(MDOC_ARGS) 14837da9b934Sjoerg { 14847da9b934Sjoerg 14850511d63cSchristos if (NULL == n->child) 14860511d63cSchristos h->flags ^= HTML_NONOSPACE; 14870511d63cSchristos else if (0 == strcmp("on", n->child->string)) 14887da9b934Sjoerg h->flags &= ~HTML_NONOSPACE; 14890511d63cSchristos else 14907da9b934Sjoerg h->flags |= HTML_NONOSPACE; 14917da9b934Sjoerg 14920511d63cSchristos if ( ! (HTML_NONOSPACE & h->flags)) 14930511d63cSchristos h->flags &= ~HTML_NOSPACE; 14940511d63cSchristos 1495*47a17e0dSchristos return 0; 14967da9b934Sjoerg } 14977da9b934Sjoerg 14980511d63cSchristos static int 14990511d63cSchristos mdoc_skip_pre(MDOC_ARGS) 15000511d63cSchristos { 15010511d63cSchristos 1502*47a17e0dSchristos return 0; 15030511d63cSchristos } 15040511d63cSchristos 1505e4fbeb7eSjoerg static int 1506e4fbeb7eSjoerg mdoc_pp_pre(MDOC_ARGS) 1507e4fbeb7eSjoerg { 1508e4fbeb7eSjoerg 15090511d63cSchristos print_paragraph(h); 1510*47a17e0dSchristos return 0; 1511e4fbeb7eSjoerg } 15127da9b934Sjoerg 15137da9b934Sjoerg static int 15144154958bSjoerg mdoc_sp_pre(MDOC_ARGS) 15154154958bSjoerg { 15164154958bSjoerg struct roffsu su; 1517e4fbeb7eSjoerg struct htmlpair tag; 15184154958bSjoerg 1519e4fbeb7eSjoerg SCALE_VS_INIT(&su, 1); 15204154958bSjoerg 1521e4fbeb7eSjoerg if (MDOC_sp == n->tok) { 15220511d63cSchristos if (NULL != (n = n->child)) { 1523f8126693Sjoerg if ( ! a2roffsu(n->string, &su, SCALE_VS)) 15240511d63cSchristos su.scale = 1.0; 15250511d63cSchristos else if (su.scale < 0.0) 15260511d63cSchristos su.scale = 0.0; 15270511d63cSchristos } 1528e4fbeb7eSjoerg } else 15290511d63cSchristos su.scale = 0.0; 1530e4fbeb7eSjoerg 1531f8126693Sjoerg bufinit(h); 15324154958bSjoerg bufcat_su(h, "height", &su); 15334154958bSjoerg PAIR_STYLE_INIT(&tag, h); 15344154958bSjoerg print_otag(h, TAG_DIV, 1, &tag); 1535e4fbeb7eSjoerg 15363514411fSjoerg /* So the div isn't empty: */ 15373514411fSjoerg print_text(h, "\\~"); 15383514411fSjoerg 1539*47a17e0dSchristos return 0; 15404154958bSjoerg 15414154958bSjoerg } 15424154958bSjoerg 15434154958bSjoerg static int 15444154958bSjoerg mdoc_lk_pre(MDOC_ARGS) 15454154958bSjoerg { 15464154958bSjoerg struct htmlpair tag[2]; 15474154958bSjoerg 154854a4f7feSjoerg if (NULL == (n = n->child)) 1549*47a17e0dSchristos return 0; 155054a4f7feSjoerg 1551*47a17e0dSchristos assert(n->type == ROFFT_TEXT); 15524154958bSjoerg 15534154958bSjoerg PAIR_CLASS_INIT(&tag[0], "link-ext"); 155454a4f7feSjoerg PAIR_HREF_INIT(&tag[1], n->string); 155554a4f7feSjoerg 15564154958bSjoerg print_otag(h, TAG_A, 2, tag); 15574154958bSjoerg 1558f8126693Sjoerg if (NULL == n->next) 155954a4f7feSjoerg print_text(h, n->string); 1560f8126693Sjoerg 1561f8126693Sjoerg for (n = n->next; n; n = n->next) 1562f8126693Sjoerg print_text(h, n->string); 15634154958bSjoerg 1564*47a17e0dSchristos return 0; 15654154958bSjoerg } 15664154958bSjoerg 15674154958bSjoerg static int 15684154958bSjoerg mdoc_mt_pre(MDOC_ARGS) 15694154958bSjoerg { 15704154958bSjoerg struct htmlpair tag[2]; 15714154958bSjoerg struct tag *t; 15724154958bSjoerg 15734154958bSjoerg PAIR_CLASS_INIT(&tag[0], "link-mail"); 15744154958bSjoerg 157554a4f7feSjoerg for (n = n->child; n; n = n->next) { 1576*47a17e0dSchristos assert(n->type == ROFFT_TEXT); 157754a4f7feSjoerg 15784154958bSjoerg bufinit(h); 15794154958bSjoerg bufcat(h, "mailto:"); 158054a4f7feSjoerg bufcat(h, n->string); 158154a4f7feSjoerg 15827bcc2a5fSjoerg PAIR_HREF_INIT(&tag[1], h->buf); 15834154958bSjoerg t = print_otag(h, TAG_A, 2, tag); 158454a4f7feSjoerg print_text(h, n->string); 15854154958bSjoerg print_tagq(h, t); 15864154958bSjoerg } 15874154958bSjoerg 1588*47a17e0dSchristos return 0; 15894154958bSjoerg } 15904154958bSjoerg 15914154958bSjoerg static int 15924154958bSjoerg mdoc_fo_pre(MDOC_ARGS) 15934154958bSjoerg { 15944154958bSjoerg struct htmlpair tag; 15957574e07eSjoerg struct tag *t; 15964154958bSjoerg 1597*47a17e0dSchristos if (n->type == ROFFT_BODY) { 15984154958bSjoerg h->flags |= HTML_NOSPACE; 15994154958bSjoerg print_text(h, "("); 16004154958bSjoerg h->flags |= HTML_NOSPACE; 1601*47a17e0dSchristos return 1; 1602*47a17e0dSchristos } else if (n->type == ROFFT_BLOCK) { 16037574e07eSjoerg synopsis_pre(h, n); 1604*47a17e0dSchristos return 1; 16057bcc2a5fSjoerg } 16064154958bSjoerg 1607*47a17e0dSchristos if (n->child == NULL) 1608*47a17e0dSchristos return 0; 16097574e07eSjoerg 16107574e07eSjoerg assert(n->child->string); 16114154958bSjoerg PAIR_CLASS_INIT(&tag, "fname"); 1612e4fbeb7eSjoerg t = print_otag(h, TAG_B, 1, &tag); 16137574e07eSjoerg print_text(h, n->child->string); 16147574e07eSjoerg print_tagq(h, t); 1615*47a17e0dSchristos return 0; 16164154958bSjoerg } 16174154958bSjoerg 16184154958bSjoerg static void 16194154958bSjoerg mdoc_fo_post(MDOC_ARGS) 16204154958bSjoerg { 16217574e07eSjoerg 1622*47a17e0dSchristos if (n->type != ROFFT_BODY) 16234154958bSjoerg return; 162454a4f7feSjoerg h->flags |= HTML_NOSPACE; 16254154958bSjoerg print_text(h, ")"); 162654a4f7feSjoerg h->flags |= HTML_NOSPACE; 16274154958bSjoerg print_text(h, ";"); 16284154958bSjoerg } 16294154958bSjoerg 16304154958bSjoerg static int 16314154958bSjoerg mdoc_in_pre(MDOC_ARGS) 16324154958bSjoerg { 16334154958bSjoerg struct tag *t; 16344154958bSjoerg struct htmlpair tag[2]; 16354154958bSjoerg int i; 16364154958bSjoerg 16377574e07eSjoerg synopsis_pre(h, n); 16384154958bSjoerg 16394154958bSjoerg PAIR_CLASS_INIT(&tag[0], "includes"); 1640e4fbeb7eSjoerg print_otag(h, TAG_B, 1, tag); 16414154958bSjoerg 164254a4f7feSjoerg /* 164354a4f7feSjoerg * The first argument of the `In' gets special treatment as 164454a4f7feSjoerg * being a linked value. Subsequent values are printed 164554a4f7feSjoerg * afterward. groff does similarly. This also handles the case 164654a4f7feSjoerg * of no children. 164754a4f7feSjoerg */ 164854a4f7feSjoerg 164982361f10Sjoerg if (MDOC_SYNPRETTY & n->flags && MDOC_LINE & n->flags) 16504154958bSjoerg print_text(h, "#include"); 16514154958bSjoerg 16524154958bSjoerg print_text(h, "<"); 16534154958bSjoerg h->flags |= HTML_NOSPACE; 16544154958bSjoerg 165554a4f7feSjoerg if (NULL != (n = n->child)) { 1656*47a17e0dSchristos assert(n->type == ROFFT_TEXT); 165754a4f7feSjoerg 16584154958bSjoerg PAIR_CLASS_INIT(&tag[0], "link-includes"); 165954a4f7feSjoerg 166054a4f7feSjoerg i = 1; 16614154958bSjoerg if (h->base_includes) { 166254a4f7feSjoerg buffmt_includes(h, n->string); 16637bcc2a5fSjoerg PAIR_HREF_INIT(&tag[i], h->buf); 16647bcc2a5fSjoerg i++; 16654154958bSjoerg } 166654a4f7feSjoerg 16674154958bSjoerg t = print_otag(h, TAG_A, i, tag); 166854a4f7feSjoerg print_text(h, n->string); 16694154958bSjoerg print_tagq(h, t); 167054a4f7feSjoerg 167154a4f7feSjoerg n = n->next; 16724154958bSjoerg } 16734154958bSjoerg 16744154958bSjoerg h->flags |= HTML_NOSPACE; 16754154958bSjoerg print_text(h, ">"); 16764154958bSjoerg 167754a4f7feSjoerg for ( ; n; n = n->next) { 1678*47a17e0dSchristos assert(n->type == ROFFT_TEXT); 167954a4f7feSjoerg print_text(h, n->string); 168054a4f7feSjoerg } 168154a4f7feSjoerg 1682*47a17e0dSchristos return 0; 16834154958bSjoerg } 16844154958bSjoerg 16854154958bSjoerg static int 16864154958bSjoerg mdoc_ic_pre(MDOC_ARGS) 16874154958bSjoerg { 16884154958bSjoerg struct htmlpair tag; 16894154958bSjoerg 16904154958bSjoerg PAIR_CLASS_INIT(&tag, "cmd"); 1691e4fbeb7eSjoerg print_otag(h, TAG_B, 1, &tag); 1692*47a17e0dSchristos return 1; 16934154958bSjoerg } 16944154958bSjoerg 16954154958bSjoerg static int 16964154958bSjoerg mdoc_rv_pre(MDOC_ARGS) 16974154958bSjoerg { 16984154958bSjoerg struct htmlpair tag; 16994154958bSjoerg struct tag *t; 1700*47a17e0dSchristos struct roff_node *nch; 17014154958bSjoerg 1702e4fbeb7eSjoerg if (n->prev) 1703e4fbeb7eSjoerg print_otag(h, TAG_BR, 0, NULL); 1704e4fbeb7eSjoerg 170554a4f7feSjoerg PAIR_CLASS_INIT(&tag, "fname"); 170654a4f7feSjoerg 1707*47a17e0dSchristos if (n->child != NULL) { 17084154958bSjoerg print_text(h, "The"); 17094154958bSjoerg 1710*47a17e0dSchristos for (nch = n->child; nch != NULL; nch = nch->next) { 1711e4fbeb7eSjoerg t = print_otag(h, TAG_B, 1, &tag); 1712*47a17e0dSchristos print_text(h, nch->string); 17134154958bSjoerg print_tagq(h, t); 17144154958bSjoerg 17154154958bSjoerg h->flags |= HTML_NOSPACE; 17164154958bSjoerg print_text(h, "()"); 171754a4f7feSjoerg 1718*47a17e0dSchristos if (nch->next == NULL) 17190511d63cSchristos continue; 17200511d63cSchristos 1721*47a17e0dSchristos if (nch->prev != NULL || nch->next->next != NULL) { 172254a4f7feSjoerg h->flags |= HTML_NOSPACE; 172354a4f7feSjoerg print_text(h, ","); 17244154958bSjoerg } 1725*47a17e0dSchristos if (nch->next->next == NULL) 172654a4f7feSjoerg print_text(h, "and"); 172754a4f7feSjoerg } 172854a4f7feSjoerg 1729*47a17e0dSchristos if (n->child != NULL && n->child->next != NULL) 17304154958bSjoerg print_text(h, "functions return"); 17314154958bSjoerg else 17324154958bSjoerg print_text(h, "function returns"); 17334154958bSjoerg 17340511d63cSchristos print_text(h, "the value\\~0 if successful;"); 17350511d63cSchristos } else 17360511d63cSchristos print_text(h, "Upon successful completion," 17370511d63cSchristos " the value\\~0 is returned;"); 17380511d63cSchristos 17390511d63cSchristos print_text(h, "otherwise the value\\~\\-1 is returned" 17400511d63cSchristos " and the global variable"); 17414154958bSjoerg 17424154958bSjoerg PAIR_CLASS_INIT(&tag, "var"); 1743e4fbeb7eSjoerg t = print_otag(h, TAG_B, 1, &tag); 17444154958bSjoerg print_text(h, "errno"); 17454154958bSjoerg print_tagq(h, t); 17464154958bSjoerg print_text(h, "is set to indicate the error."); 1747*47a17e0dSchristos return 0; 17484154958bSjoerg } 17494154958bSjoerg 17504154958bSjoerg static int 17514154958bSjoerg mdoc_va_pre(MDOC_ARGS) 17524154958bSjoerg { 17534154958bSjoerg struct htmlpair tag; 17544154958bSjoerg 17554154958bSjoerg PAIR_CLASS_INIT(&tag, "var"); 1756e4fbeb7eSjoerg print_otag(h, TAG_B, 1, &tag); 1757*47a17e0dSchristos return 1; 17584154958bSjoerg } 17594154958bSjoerg 17604154958bSjoerg static int 17614154958bSjoerg mdoc_ap_pre(MDOC_ARGS) 17624154958bSjoerg { 17634154958bSjoerg 17644154958bSjoerg h->flags |= HTML_NOSPACE; 17654154958bSjoerg print_text(h, "\\(aq"); 17664154958bSjoerg h->flags |= HTML_NOSPACE; 1767*47a17e0dSchristos return 1; 17684154958bSjoerg } 17694154958bSjoerg 17704154958bSjoerg static int 17714154958bSjoerg mdoc_bf_pre(MDOC_ARGS) 17724154958bSjoerg { 17734154958bSjoerg struct htmlpair tag[2]; 17744154958bSjoerg struct roffsu su; 17754154958bSjoerg 1776*47a17e0dSchristos if (n->type == ROFFT_HEAD) 1777*47a17e0dSchristos return 0; 1778*47a17e0dSchristos else if (n->type != ROFFT_BODY) 1779*47a17e0dSchristos return 1; 17804154958bSjoerg 1781e4fbeb7eSjoerg if (FONT_Em == n->norm->Bf.font) 17824154958bSjoerg PAIR_CLASS_INIT(&tag[0], "emph"); 1783e4fbeb7eSjoerg else if (FONT_Sy == n->norm->Bf.font) 17844154958bSjoerg PAIR_CLASS_INIT(&tag[0], "symb"); 1785e4fbeb7eSjoerg else if (FONT_Li == n->norm->Bf.font) 17864154958bSjoerg PAIR_CLASS_INIT(&tag[0], "lit"); 178782361f10Sjoerg else 178882361f10Sjoerg PAIR_CLASS_INIT(&tag[0], "none"); 17894154958bSjoerg 179082361f10Sjoerg /* 179182361f10Sjoerg * We want this to be inline-formatted, but needs to be div to 179282361f10Sjoerg * accept block children. 179382361f10Sjoerg */ 1794f8126693Sjoerg bufinit(h); 17954154958bSjoerg bufcat_style(h, "display", "inline"); 17964154958bSjoerg SCALE_HS_INIT(&su, 1); 179782361f10Sjoerg /* Needs a left-margin for spacing. */ 179882361f10Sjoerg bufcat_su(h, "margin-left", &su); 17994154958bSjoerg PAIR_STYLE_INIT(&tag[1], h); 18004154958bSjoerg print_otag(h, TAG_DIV, 2, tag); 1801*47a17e0dSchristos return 1; 18024154958bSjoerg } 18034154958bSjoerg 18044154958bSjoerg static int 18054154958bSjoerg mdoc_ms_pre(MDOC_ARGS) 18064154958bSjoerg { 18074154958bSjoerg struct htmlpair tag; 18084154958bSjoerg 18094154958bSjoerg PAIR_CLASS_INIT(&tag, "symb"); 18104154958bSjoerg print_otag(h, TAG_SPAN, 1, &tag); 1811*47a17e0dSchristos return 1; 18124154958bSjoerg } 18134154958bSjoerg 18144154958bSjoerg static int 1815e4fbeb7eSjoerg mdoc_igndelim_pre(MDOC_ARGS) 18164154958bSjoerg { 18174154958bSjoerg 18184154958bSjoerg h->flags |= HTML_IGNDELIM; 1819*47a17e0dSchristos return 1; 18204154958bSjoerg } 18214154958bSjoerg 18224154958bSjoerg static void 18234154958bSjoerg mdoc_pf_post(MDOC_ARGS) 18244154958bSjoerg { 18254154958bSjoerg 18260511d63cSchristos if ( ! (n->next == NULL || n->next->flags & MDOC_LINE)) 18274154958bSjoerg h->flags |= HTML_NOSPACE; 18284154958bSjoerg } 18294154958bSjoerg 18304154958bSjoerg static int 18314154958bSjoerg mdoc_rs_pre(MDOC_ARGS) 18324154958bSjoerg { 18334154958bSjoerg struct htmlpair tag; 18344154958bSjoerg 1835*47a17e0dSchristos if (n->type != ROFFT_BLOCK) 1836*47a17e0dSchristos return 1; 18374154958bSjoerg 1838e4fbeb7eSjoerg if (n->prev && SEC_SEE_ALSO == n->sec) 18390511d63cSchristos print_paragraph(h); 18404154958bSjoerg 18414154958bSjoerg PAIR_CLASS_INIT(&tag, "ref"); 18424154958bSjoerg print_otag(h, TAG_SPAN, 1, &tag); 1843*47a17e0dSchristos return 1; 18444154958bSjoerg } 18454154958bSjoerg 18460511d63cSchristos static int 18470511d63cSchristos mdoc_no_pre(MDOC_ARGS) 18480511d63cSchristos { 18490511d63cSchristos struct htmlpair tag; 18504154958bSjoerg 18510511d63cSchristos PAIR_CLASS_INIT(&tag, "none"); 18520511d63cSchristos print_otag(h, TAG_CODE, 1, &tag); 1853*47a17e0dSchristos return 1; 18540511d63cSchristos } 18554154958bSjoerg 18564154958bSjoerg static int 18574154958bSjoerg mdoc_li_pre(MDOC_ARGS) 18584154958bSjoerg { 18594154958bSjoerg struct htmlpair tag; 18604154958bSjoerg 18614154958bSjoerg PAIR_CLASS_INIT(&tag, "lit"); 1862f8126693Sjoerg print_otag(h, TAG_CODE, 1, &tag); 1863*47a17e0dSchristos return 1; 18644154958bSjoerg } 18654154958bSjoerg 18664154958bSjoerg static int 18674154958bSjoerg mdoc_sy_pre(MDOC_ARGS) 18684154958bSjoerg { 18694154958bSjoerg struct htmlpair tag; 18704154958bSjoerg 18714154958bSjoerg PAIR_CLASS_INIT(&tag, "symb"); 18724154958bSjoerg print_otag(h, TAG_SPAN, 1, &tag); 1873*47a17e0dSchristos return 1; 18744154958bSjoerg } 18754154958bSjoerg 18764154958bSjoerg static int 18774154958bSjoerg mdoc_bt_pre(MDOC_ARGS) 18784154958bSjoerg { 18794154958bSjoerg 18804154958bSjoerg print_text(h, "is currently in beta test."); 1881*47a17e0dSchristos return 0; 18824154958bSjoerg } 18834154958bSjoerg 18844154958bSjoerg static int 18854154958bSjoerg mdoc_ud_pre(MDOC_ARGS) 18864154958bSjoerg { 18874154958bSjoerg 18884154958bSjoerg print_text(h, "currently under development."); 1889*47a17e0dSchristos return 0; 18904154958bSjoerg } 18914154958bSjoerg 18924154958bSjoerg static int 18934154958bSjoerg mdoc_lb_pre(MDOC_ARGS) 18944154958bSjoerg { 18954154958bSjoerg struct htmlpair tag; 18964154958bSjoerg 1897e4fbeb7eSjoerg if (SEC_LIBRARY == n->sec && MDOC_LINE & n->flags && n->prev) 1898e4fbeb7eSjoerg print_otag(h, TAG_BR, 0, NULL); 1899e4fbeb7eSjoerg 19004154958bSjoerg PAIR_CLASS_INIT(&tag, "lib"); 19014154958bSjoerg print_otag(h, TAG_SPAN, 1, &tag); 1902*47a17e0dSchristos return 1; 19034154958bSjoerg } 19044154958bSjoerg 19054154958bSjoerg static int 19064154958bSjoerg mdoc__x_pre(MDOC_ARGS) 19074154958bSjoerg { 190822af4063Sjoerg struct htmlpair tag[2]; 1909e4fbeb7eSjoerg enum htmltag t; 1910e4fbeb7eSjoerg 1911e4fbeb7eSjoerg t = TAG_SPAN; 19124154958bSjoerg 19134154958bSjoerg switch (n->tok) { 19140511d63cSchristos case MDOC__A: 191522af4063Sjoerg PAIR_CLASS_INIT(&tag[0], "ref-auth"); 1916e4fbeb7eSjoerg if (n->prev && MDOC__A == n->prev->tok) 1917e4fbeb7eSjoerg if (NULL == n->next || MDOC__A != n->next->tok) 1918e4fbeb7eSjoerg print_text(h, "and"); 19194154958bSjoerg break; 19200511d63cSchristos case MDOC__B: 192122af4063Sjoerg PAIR_CLASS_INIT(&tag[0], "ref-book"); 1922e4fbeb7eSjoerg t = TAG_I; 19234154958bSjoerg break; 19240511d63cSchristos case MDOC__C: 192522af4063Sjoerg PAIR_CLASS_INIT(&tag[0], "ref-city"); 19264154958bSjoerg break; 19270511d63cSchristos case MDOC__D: 192822af4063Sjoerg PAIR_CLASS_INIT(&tag[0], "ref-date"); 19294154958bSjoerg break; 19300511d63cSchristos case MDOC__I: 193122af4063Sjoerg PAIR_CLASS_INIT(&tag[0], "ref-issue"); 1932e4fbeb7eSjoerg t = TAG_I; 19334154958bSjoerg break; 19340511d63cSchristos case MDOC__J: 193522af4063Sjoerg PAIR_CLASS_INIT(&tag[0], "ref-jrnl"); 1936e4fbeb7eSjoerg t = TAG_I; 19374154958bSjoerg break; 19380511d63cSchristos case MDOC__N: 193922af4063Sjoerg PAIR_CLASS_INIT(&tag[0], "ref-num"); 19404154958bSjoerg break; 19410511d63cSchristos case MDOC__O: 194222af4063Sjoerg PAIR_CLASS_INIT(&tag[0], "ref-opt"); 19434154958bSjoerg break; 19440511d63cSchristos case MDOC__P: 194522af4063Sjoerg PAIR_CLASS_INIT(&tag[0], "ref-page"); 19464154958bSjoerg break; 19470511d63cSchristos case MDOC__Q: 194822af4063Sjoerg PAIR_CLASS_INIT(&tag[0], "ref-corp"); 19494154958bSjoerg break; 19500511d63cSchristos case MDOC__R: 195122af4063Sjoerg PAIR_CLASS_INIT(&tag[0], "ref-rep"); 19524154958bSjoerg break; 19530511d63cSchristos case MDOC__T: 195422af4063Sjoerg PAIR_CLASS_INIT(&tag[0], "ref-title"); 19554154958bSjoerg break; 19560511d63cSchristos case MDOC__U: 195722af4063Sjoerg PAIR_CLASS_INIT(&tag[0], "link-ref"); 195822af4063Sjoerg break; 19590511d63cSchristos case MDOC__V: 196022af4063Sjoerg PAIR_CLASS_INIT(&tag[0], "ref-vol"); 19614154958bSjoerg break; 19624154958bSjoerg default: 19634154958bSjoerg abort(); 19644154958bSjoerg } 19654154958bSjoerg 196622af4063Sjoerg if (MDOC__U != n->tok) { 1967e4fbeb7eSjoerg print_otag(h, t, 1, tag); 1968*47a17e0dSchristos return 1; 196922af4063Sjoerg } 197022af4063Sjoerg 197122af4063Sjoerg PAIR_HREF_INIT(&tag[1], n->child->string); 197222af4063Sjoerg print_otag(h, TAG_A, 2, tag); 1973e4fbeb7eSjoerg 1974*47a17e0dSchristos return 1; 19754154958bSjoerg } 19764154958bSjoerg 19774154958bSjoerg static void 19784154958bSjoerg mdoc__x_post(MDOC_ARGS) 19794154958bSjoerg { 19804154958bSjoerg 1981e4fbeb7eSjoerg if (MDOC__A == n->tok && n->next && MDOC__A == n->next->tok) 1982e4fbeb7eSjoerg if (NULL == n->next->next || MDOC__A != n->next->next->tok) 1983e4fbeb7eSjoerg if (NULL == n->prev || MDOC__A != n->prev->tok) 1984e4fbeb7eSjoerg return; 1985e4fbeb7eSjoerg 19860a84adc5Sjoerg /* TODO: %U */ 19870a84adc5Sjoerg 1988e4fbeb7eSjoerg if (NULL == n->parent || MDOC_Rs != n->parent->tok) 1989e4fbeb7eSjoerg return; 1990e4fbeb7eSjoerg 199154a4f7feSjoerg h->flags |= HTML_NOSPACE; 19924154958bSjoerg print_text(h, n->next ? "," : "."); 19934154958bSjoerg } 199482361f10Sjoerg 199582361f10Sjoerg static int 199682361f10Sjoerg mdoc_bk_pre(MDOC_ARGS) 199782361f10Sjoerg { 199882361f10Sjoerg 199982361f10Sjoerg switch (n->type) { 2000*47a17e0dSchristos case ROFFT_BLOCK: 200182361f10Sjoerg break; 2002*47a17e0dSchristos case ROFFT_HEAD: 2003*47a17e0dSchristos return 0; 2004*47a17e0dSchristos case ROFFT_BODY: 2005*47a17e0dSchristos if (n->parent->args != NULL || n->prev->child == NULL) 200682361f10Sjoerg h->flags |= HTML_PREKEEP; 200782361f10Sjoerg break; 200882361f10Sjoerg default: 200982361f10Sjoerg abort(); 201082361f10Sjoerg } 201182361f10Sjoerg 2012*47a17e0dSchristos return 1; 201382361f10Sjoerg } 201482361f10Sjoerg 201582361f10Sjoerg static void 201682361f10Sjoerg mdoc_bk_post(MDOC_ARGS) 201782361f10Sjoerg { 201882361f10Sjoerg 2019*47a17e0dSchristos if (n->type == ROFFT_BODY) 202082361f10Sjoerg h->flags &= ~(HTML_KEEP | HTML_PREKEEP); 202182361f10Sjoerg } 2022e4fbeb7eSjoerg 2023e4fbeb7eSjoerg static int 2024e4fbeb7eSjoerg mdoc_quote_pre(MDOC_ARGS) 2025e4fbeb7eSjoerg { 2026e4fbeb7eSjoerg struct htmlpair tag; 2027e4fbeb7eSjoerg 2028*47a17e0dSchristos if (n->type != ROFFT_BODY) 2029*47a17e0dSchristos return 1; 2030e4fbeb7eSjoerg 2031e4fbeb7eSjoerg switch (n->tok) { 20320511d63cSchristos case MDOC_Ao: 20330511d63cSchristos case MDOC_Aq: 2034*47a17e0dSchristos print_text(h, n->child != NULL && n->child->next == NULL && 20350511d63cSchristos n->child->tok == MDOC_Mt ? "<" : "\\(la"); 2036e4fbeb7eSjoerg break; 20370511d63cSchristos case MDOC_Bro: 20380511d63cSchristos case MDOC_Brq: 2039e4fbeb7eSjoerg print_text(h, "\\(lC"); 2040e4fbeb7eSjoerg break; 20410511d63cSchristos case MDOC_Bo: 20420511d63cSchristos case MDOC_Bq: 2043e4fbeb7eSjoerg print_text(h, "\\(lB"); 2044e4fbeb7eSjoerg break; 20450511d63cSchristos case MDOC_Oo: 20460511d63cSchristos case MDOC_Op: 2047e4fbeb7eSjoerg print_text(h, "\\(lB"); 2048e4fbeb7eSjoerg h->flags |= HTML_NOSPACE; 2049e4fbeb7eSjoerg PAIR_CLASS_INIT(&tag, "opt"); 2050e4fbeb7eSjoerg print_otag(h, TAG_SPAN, 1, &tag); 2051e4fbeb7eSjoerg break; 20520511d63cSchristos case MDOC_En: 20530511d63cSchristos if (NULL == n->norm->Es || 20540511d63cSchristos NULL == n->norm->Es->child) 2055*47a17e0dSchristos return 1; 20560511d63cSchristos print_text(h, n->norm->Es->child->string); 2057e7fe1698Sjoerg break; 20580511d63cSchristos case MDOC_Do: 20590511d63cSchristos case MDOC_Dq: 20600511d63cSchristos case MDOC_Qo: 20610511d63cSchristos case MDOC_Qq: 2062e4fbeb7eSjoerg print_text(h, "\\(lq"); 2063e4fbeb7eSjoerg break; 20640511d63cSchristos case MDOC_Po: 20650511d63cSchristos case MDOC_Pq: 2066e4fbeb7eSjoerg print_text(h, "("); 2067e4fbeb7eSjoerg break; 20680511d63cSchristos case MDOC_Ql: 2069f8126693Sjoerg print_text(h, "\\(oq"); 2070f8126693Sjoerg h->flags |= HTML_NOSPACE; 2071f8126693Sjoerg PAIR_CLASS_INIT(&tag, "lit"); 2072f8126693Sjoerg print_otag(h, TAG_CODE, 1, &tag); 2073f8126693Sjoerg break; 20740511d63cSchristos case MDOC_So: 20750511d63cSchristos case MDOC_Sq: 2076e4fbeb7eSjoerg print_text(h, "\\(oq"); 2077e4fbeb7eSjoerg break; 2078e4fbeb7eSjoerg default: 2079e4fbeb7eSjoerg abort(); 2080e4fbeb7eSjoerg } 2081e4fbeb7eSjoerg 2082e4fbeb7eSjoerg h->flags |= HTML_NOSPACE; 2083*47a17e0dSchristos return 1; 2084e4fbeb7eSjoerg } 2085e4fbeb7eSjoerg 2086e4fbeb7eSjoerg static void 2087e4fbeb7eSjoerg mdoc_quote_post(MDOC_ARGS) 2088e4fbeb7eSjoerg { 2089e4fbeb7eSjoerg 2090*47a17e0dSchristos if (n->type != ROFFT_BODY && n->type != ROFFT_ELEM) 2091e4fbeb7eSjoerg return; 2092e4fbeb7eSjoerg 2093e4fbeb7eSjoerg h->flags |= HTML_NOSPACE; 2094e4fbeb7eSjoerg 2095e4fbeb7eSjoerg switch (n->tok) { 20960511d63cSchristos case MDOC_Ao: 20970511d63cSchristos case MDOC_Aq: 2098*47a17e0dSchristos print_text(h, n->child != NULL && n->child->next == NULL && 20990511d63cSchristos n->child->tok == MDOC_Mt ? ">" : "\\(ra"); 2100e4fbeb7eSjoerg break; 21010511d63cSchristos case MDOC_Bro: 21020511d63cSchristos case MDOC_Brq: 2103e4fbeb7eSjoerg print_text(h, "\\(rC"); 2104e4fbeb7eSjoerg break; 21050511d63cSchristos case MDOC_Oo: 21060511d63cSchristos case MDOC_Op: 21070511d63cSchristos case MDOC_Bo: 21080511d63cSchristos case MDOC_Bq: 2109e4fbeb7eSjoerg print_text(h, "\\(rB"); 2110e4fbeb7eSjoerg break; 21110511d63cSchristos case MDOC_En: 21120511d63cSchristos if (n->norm->Es == NULL || 21130511d63cSchristos n->norm->Es->child == NULL || 21140511d63cSchristos n->norm->Es->child->next == NULL) 21150511d63cSchristos h->flags &= ~HTML_NOSPACE; 21160511d63cSchristos else 21170511d63cSchristos print_text(h, n->norm->Es->child->next->string); 2118e7fe1698Sjoerg break; 21190511d63cSchristos case MDOC_Qo: 21200511d63cSchristos case MDOC_Qq: 21210511d63cSchristos case MDOC_Do: 21220511d63cSchristos case MDOC_Dq: 2123e4fbeb7eSjoerg print_text(h, "\\(rq"); 2124e4fbeb7eSjoerg break; 21250511d63cSchristos case MDOC_Po: 21260511d63cSchristos case MDOC_Pq: 2127e4fbeb7eSjoerg print_text(h, ")"); 2128e4fbeb7eSjoerg break; 21290511d63cSchristos case MDOC_Ql: 21300511d63cSchristos case MDOC_So: 21310511d63cSchristos case MDOC_Sq: 2132ed7c7912Sjoerg print_text(h, "\\(cq"); 2133e4fbeb7eSjoerg break; 2134e4fbeb7eSjoerg default: 2135e4fbeb7eSjoerg abort(); 2136e4fbeb7eSjoerg } 2137e4fbeb7eSjoerg } 2138e4fbeb7eSjoerg 21390511d63cSchristos static int 21400511d63cSchristos mdoc_eo_pre(MDOC_ARGS) 21410511d63cSchristos { 2142e4fbeb7eSjoerg 2143*47a17e0dSchristos if (n->type != ROFFT_BODY) 2144*47a17e0dSchristos return 1; 21450511d63cSchristos 21460511d63cSchristos if (n->end == ENDBODY_NOT && 21470511d63cSchristos n->parent->head->child == NULL && 21480511d63cSchristos n->child != NULL && 21490511d63cSchristos n->child->end != ENDBODY_NOT) 21500511d63cSchristos print_text(h, "\\&"); 21510511d63cSchristos else if (n->end != ENDBODY_NOT ? n->child != NULL : 21520511d63cSchristos n->parent->head->child != NULL && (n->child != NULL || 21530511d63cSchristos (n->parent->tail != NULL && n->parent->tail->child != NULL))) 21540511d63cSchristos h->flags |= HTML_NOSPACE; 2155*47a17e0dSchristos return 1; 21560511d63cSchristos } 21570511d63cSchristos 21580511d63cSchristos static void 21590511d63cSchristos mdoc_eo_post(MDOC_ARGS) 21600511d63cSchristos { 21610511d63cSchristos int body, tail; 21620511d63cSchristos 2163*47a17e0dSchristos if (n->type != ROFFT_BODY) 21640511d63cSchristos return; 21650511d63cSchristos 21660511d63cSchristos if (n->end != ENDBODY_NOT) { 21670511d63cSchristos h->flags &= ~HTML_NOSPACE; 21680511d63cSchristos return; 21690511d63cSchristos } 21700511d63cSchristos 21710511d63cSchristos body = n->child != NULL || n->parent->head->child != NULL; 21720511d63cSchristos tail = n->parent->tail != NULL && n->parent->tail->child != NULL; 21730511d63cSchristos 21740511d63cSchristos if (body && tail) 21750511d63cSchristos h->flags |= HTML_NOSPACE; 21760511d63cSchristos else if ( ! tail) 21770511d63cSchristos h->flags &= ~HTML_NOSPACE; 21780511d63cSchristos } 2179