1*54ba9607SSascha Wildner /* $Id: man_html.c,v 1.173 2019/03/02 16:30:53 schwarze Exp $ */ 280387638SSascha Wildner /* 3*54ba9607SSascha Wildner * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv> 4*54ba9607SSascha Wildner * Copyright (c) 2013-2015, 2017-2019 Ingo Schwarze <schwarze@openbsd.org> 580387638SSascha Wildner * 680387638SSascha Wildner * Permission to use, copy, modify, and distribute this software for any 780387638SSascha Wildner * purpose with or without fee is hereby granted, provided that the above 880387638SSascha Wildner * copyright notice and this permission notice appear in all copies. 980387638SSascha Wildner * 10*54ba9607SSascha Wildner * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES 1180387638SSascha Wildner * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12*54ba9607SSascha Wildner * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR 1380387638SSascha Wildner * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1480387638SSascha Wildner * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1580387638SSascha Wildner * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1680387638SSascha Wildner * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1780387638SSascha Wildner */ 1880387638SSascha Wildner #include "config.h" 1980387638SSascha Wildner 2080387638SSascha Wildner #include <sys/types.h> 2180387638SSascha Wildner 2280387638SSascha Wildner #include <assert.h> 2380387638SSascha Wildner #include <ctype.h> 2480387638SSascha Wildner #include <stdio.h> 2580387638SSascha Wildner #include <stdlib.h> 2680387638SSascha Wildner #include <string.h> 2780387638SSascha Wildner 28070c62a6SFranco Fichtner #include "mandoc_aux.h" 29*54ba9607SSascha Wildner #include "mandoc.h" 30*54ba9607SSascha Wildner #include "roff.h" 31*54ba9607SSascha Wildner #include "man.h" 3280387638SSascha Wildner #include "out.h" 3380387638SSascha Wildner #include "html.h" 3480387638SSascha Wildner #include "main.h" 3580387638SSascha Wildner 36*54ba9607SSascha Wildner #define MAN_ARGS const struct roff_meta *man, \ 37*54ba9607SSascha Wildner const struct roff_node *n, \ 3880387638SSascha Wildner struct html *h 3980387638SSascha Wildner 40*54ba9607SSascha Wildner struct man_html_act { 4180387638SSascha Wildner int (*pre)(MAN_ARGS); 4280387638SSascha Wildner int (*post)(MAN_ARGS); 4380387638SSascha Wildner }; 4480387638SSascha Wildner 45*54ba9607SSascha Wildner static void print_man_head(const struct roff_meta *, 46*54ba9607SSascha Wildner struct html *); 4780387638SSascha Wildner static void print_man_nodelist(MAN_ARGS); 4880387638SSascha Wildner static void print_man_node(MAN_ARGS); 49*54ba9607SSascha Wildner static char list_continues(const struct roff_node *, 50*54ba9607SSascha Wildner const struct roff_node *); 5136342e81SSascha Wildner static int man_B_pre(MAN_ARGS); 5236342e81SSascha Wildner static int man_IP_pre(MAN_ARGS); 5336342e81SSascha Wildner static int man_I_pre(MAN_ARGS); 5436342e81SSascha Wildner static int man_OP_pre(MAN_ARGS); 5536342e81SSascha Wildner static int man_PP_pre(MAN_ARGS); 5636342e81SSascha Wildner static int man_RS_pre(MAN_ARGS); 5736342e81SSascha Wildner static int man_SH_pre(MAN_ARGS); 5836342e81SSascha Wildner static int man_SM_pre(MAN_ARGS); 59*54ba9607SSascha Wildner static int man_SY_pre(MAN_ARGS); 607888c61dSFranco Fichtner static int man_UR_pre(MAN_ARGS); 61*54ba9607SSascha Wildner static int man_abort_pre(MAN_ARGS); 6280387638SSascha Wildner static int man_alt_pre(MAN_ARGS); 6380387638SSascha Wildner static int man_ign_pre(MAN_ARGS); 6480387638SSascha Wildner static int man_in_pre(MAN_ARGS); 65*54ba9607SSascha Wildner static void man_root_post(const struct roff_meta *, 66*54ba9607SSascha Wildner struct html *); 67*54ba9607SSascha Wildner static void man_root_pre(const struct roff_meta *, 68*54ba9607SSascha Wildner struct html *); 6980387638SSascha Wildner 70*54ba9607SSascha Wildner static const struct man_html_act man_html_acts[MAN_MAX - MAN_TH] = { 7180387638SSascha Wildner { NULL, NULL }, /* TH */ 7280387638SSascha Wildner { man_SH_pre, NULL }, /* SH */ 73*54ba9607SSascha Wildner { man_SH_pre, NULL }, /* SS */ 7480387638SSascha Wildner { man_IP_pre, NULL }, /* TP */ 75*54ba9607SSascha Wildner { man_IP_pre, NULL }, /* TQ */ 76*54ba9607SSascha Wildner { man_abort_pre, NULL }, /* LP */ 7780387638SSascha Wildner { man_PP_pre, NULL }, /* PP */ 78*54ba9607SSascha Wildner { man_abort_pre, NULL }, /* P */ 7980387638SSascha Wildner { man_IP_pre, NULL }, /* IP */ 80*54ba9607SSascha Wildner { man_PP_pre, NULL }, /* HP */ 8180387638SSascha Wildner { man_SM_pre, NULL }, /* SM */ 8280387638SSascha Wildner { man_SM_pre, NULL }, /* SB */ 8380387638SSascha Wildner { man_alt_pre, NULL }, /* BI */ 8480387638SSascha Wildner { man_alt_pre, NULL }, /* IB */ 8580387638SSascha Wildner { man_alt_pre, NULL }, /* BR */ 8680387638SSascha Wildner { man_alt_pre, NULL }, /* RB */ 8780387638SSascha Wildner { NULL, NULL }, /* R */ 8880387638SSascha Wildner { man_B_pre, NULL }, /* B */ 8980387638SSascha Wildner { man_I_pre, NULL }, /* I */ 9080387638SSascha Wildner { man_alt_pre, NULL }, /* IR */ 9180387638SSascha Wildner { man_alt_pre, NULL }, /* RI */ 9280387638SSascha Wildner { NULL, NULL }, /* RE */ 9380387638SSascha Wildner { man_RS_pre, NULL }, /* RS */ 9480387638SSascha Wildner { man_ign_pre, NULL }, /* DT */ 9580387638SSascha Wildner { man_ign_pre, NULL }, /* UC */ 9680387638SSascha Wildner { man_ign_pre, NULL }, /* PD */ 9780387638SSascha Wildner { man_ign_pre, NULL }, /* AT */ 9880387638SSascha Wildner { man_in_pre, NULL }, /* in */ 99*54ba9607SSascha Wildner { man_SY_pre, NULL }, /* SY */ 100*54ba9607SSascha Wildner { NULL, NULL }, /* YS */ 10136342e81SSascha Wildner { man_OP_pre, NULL }, /* OP */ 102*54ba9607SSascha Wildner { NULL, NULL }, /* EX */ 103*54ba9607SSascha Wildner { NULL, NULL }, /* EE */ 1047888c61dSFranco Fichtner { man_UR_pre, NULL }, /* UR */ 1057888c61dSFranco Fichtner { NULL, NULL }, /* UE */ 106*54ba9607SSascha Wildner { man_UR_pre, NULL }, /* MT */ 107*54ba9607SSascha Wildner { NULL, NULL }, /* ME */ 10880387638SSascha Wildner }; 10980387638SSascha Wildner 110070c62a6SFranco Fichtner 11180387638SSascha Wildner void 112*54ba9607SSascha Wildner html_man(void *arg, const struct roff_meta *man) 11380387638SSascha Wildner { 114*54ba9607SSascha Wildner struct html *h; 115*54ba9607SSascha Wildner struct roff_node *n; 116*54ba9607SSascha Wildner struct tag *t; 11780387638SSascha Wildner 118*54ba9607SSascha Wildner h = (struct html *)arg; 119*54ba9607SSascha Wildner n = man->first->child; 12080387638SSascha Wildner 121*54ba9607SSascha Wildner if ((h->oflags & HTML_FRAGMENT) == 0) { 12236342e81SSascha Wildner print_gen_decls(h); 123*54ba9607SSascha Wildner print_otag(h, TAG_HTML, ""); 124*54ba9607SSascha Wildner if (n != NULL && n->type == ROFFT_COMMENT) 125*54ba9607SSascha Wildner print_gen_comment(h, n); 126*54ba9607SSascha Wildner t = print_otag(h, TAG_HEAD, ""); 127*54ba9607SSascha Wildner print_man_head(man, h); 12880387638SSascha Wildner print_tagq(h, t); 129*54ba9607SSascha Wildner print_otag(h, TAG_BODY, ""); 130*54ba9607SSascha Wildner } 131*54ba9607SSascha Wildner 132*54ba9607SSascha Wildner man_root_pre(man, h); 133*54ba9607SSascha Wildner t = print_otag(h, TAG_DIV, "c", "manual-text"); 134*54ba9607SSascha Wildner print_man_nodelist(man, n, h); 135*54ba9607SSascha Wildner print_tagq(h, t); 136*54ba9607SSascha Wildner man_root_post(man, h); 137*54ba9607SSascha Wildner print_tagq(h, NULL); 13880387638SSascha Wildner } 13980387638SSascha Wildner 14080387638SSascha Wildner static void 141*54ba9607SSascha Wildner print_man_head(const struct roff_meta *man, struct html *h) 14280387638SSascha Wildner { 143*54ba9607SSascha Wildner char *cp; 14480387638SSascha Wildner 14580387638SSascha Wildner print_gen_head(h); 146*54ba9607SSascha Wildner mandoc_asprintf(&cp, "%s(%s)", man->title, man->msec); 147*54ba9607SSascha Wildner print_otag(h, TAG_TITLE, ""); 148*54ba9607SSascha Wildner print_text(h, cp); 149*54ba9607SSascha Wildner free(cp); 15080387638SSascha Wildner } 15180387638SSascha Wildner 15280387638SSascha Wildner static void 15380387638SSascha Wildner print_man_nodelist(MAN_ARGS) 15480387638SSascha Wildner { 155*54ba9607SSascha Wildner while (n != NULL) { 156*54ba9607SSascha Wildner print_man_node(man, n, h); 157*54ba9607SSascha Wildner n = n->next; 158*54ba9607SSascha Wildner } 15980387638SSascha Wildner } 16080387638SSascha Wildner 16180387638SSascha Wildner static void 16280387638SSascha Wildner print_man_node(MAN_ARGS) 16380387638SSascha Wildner { 16480387638SSascha Wildner struct tag *t; 165*54ba9607SSascha Wildner int child; 166*54ba9607SSascha Wildner 167*54ba9607SSascha Wildner if (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT) 168*54ba9607SSascha Wildner return; 169*54ba9607SSascha Wildner 170*54ba9607SSascha Wildner html_fillmode(h, n->flags & NODE_NOFILL ? ROFF_nf : ROFF_fi); 17180387638SSascha Wildner 17280387638SSascha Wildner child = 1; 17380387638SSascha Wildner switch (n->type) { 174*54ba9607SSascha Wildner case ROFFT_TEXT: 175*54ba9607SSascha Wildner if (*n->string == '\0') { 176*54ba9607SSascha Wildner print_endline(h); 17760e1e752SSascha Wildner return; 17836342e81SSascha Wildner } 179*54ba9607SSascha Wildner if (*n->string == ' ' && n->flags & NODE_LINE && 180*54ba9607SSascha Wildner (h->flags & HTML_NONEWLINE) == 0) 181*54ba9607SSascha Wildner print_endline(h); 182*54ba9607SSascha Wildner else if (n->flags & NODE_DELIMC) 183*54ba9607SSascha Wildner h->flags |= HTML_NOSPACE; 184*54ba9607SSascha Wildner t = h->tag; 185*54ba9607SSascha Wildner t->refcnt++; 18680387638SSascha Wildner print_text(h, n->string); 187*54ba9607SSascha Wildner break; 188*54ba9607SSascha Wildner case ROFFT_EQN: 189*54ba9607SSascha Wildner t = h->tag; 190*54ba9607SSascha Wildner t->refcnt++; 19136342e81SSascha Wildner print_eqn(h, n->eqn); 19280387638SSascha Wildner break; 193*54ba9607SSascha Wildner case ROFFT_TBL: 19460e1e752SSascha Wildner /* 19560e1e752SSascha Wildner * This will take care of initialising all of the table 19660e1e752SSascha Wildner * state data for the first table, then tearing it down 19760e1e752SSascha Wildner * for the last one. 19860e1e752SSascha Wildner */ 19960e1e752SSascha Wildner print_tbl(h, n->span); 20060e1e752SSascha Wildner return; 20180387638SSascha Wildner default: 20280387638SSascha Wildner /* 20380387638SSascha Wildner * Close out scope of font prior to opening a macro 20460e1e752SSascha Wildner * scope. 20580387638SSascha Wildner */ 20680387638SSascha Wildner if (HTMLFONT_NONE != h->metac) { 20780387638SSascha Wildner h->metal = h->metac; 20880387638SSascha Wildner h->metac = HTMLFONT_NONE; 20980387638SSascha Wildner } 21060e1e752SSascha Wildner 21160e1e752SSascha Wildner /* 21260e1e752SSascha Wildner * Close out the current table, if it's open, and unset 21360e1e752SSascha Wildner * the "meta" table state. This will be reopened on the 21460e1e752SSascha Wildner * next table element. 21560e1e752SSascha Wildner */ 216*54ba9607SSascha Wildner if (h->tblt != NULL) 21760e1e752SSascha Wildner print_tblclose(h); 218*54ba9607SSascha Wildner t = h->tag; 219*54ba9607SSascha Wildner t->refcnt++; 220*54ba9607SSascha Wildner if (n->tok < ROFF_MAX) { 221*54ba9607SSascha Wildner roff_html_pre(h, n); 222*54ba9607SSascha Wildner t->refcnt--; 223*54ba9607SSascha Wildner print_stagq(h, t); 224*54ba9607SSascha Wildner return; 22560e1e752SSascha Wildner } 226*54ba9607SSascha Wildner assert(n->tok >= MAN_TH && n->tok < MAN_MAX); 227*54ba9607SSascha Wildner if (man_html_acts[n->tok - MAN_TH].pre != NULL) 228*54ba9607SSascha Wildner child = (*man_html_acts[n->tok - MAN_TH].pre)(man, 229*54ba9607SSascha Wildner n, h); 23080387638SSascha Wildner break; 23180387638SSascha Wildner } 23280387638SSascha Wildner 233*54ba9607SSascha Wildner if (child && n->child != NULL) 234*54ba9607SSascha Wildner print_man_nodelist(man, n->child, h); 23580387638SSascha Wildner 23680387638SSascha Wildner /* This will automatically close out any font scope. */ 237*54ba9607SSascha Wildner t->refcnt--; 238*54ba9607SSascha Wildner if (n->type == ROFFT_BLOCK && 239*54ba9607SSascha Wildner (n->tok == MAN_IP || n->tok == MAN_TP || n->tok == MAN_TQ)) { 240*54ba9607SSascha Wildner t = h->tag; 241*54ba9607SSascha Wildner while (t->tag != TAG_DL && t->tag != TAG_UL) 242*54ba9607SSascha Wildner t = t->next; 243*54ba9607SSascha Wildner /* 244*54ba9607SSascha Wildner * Close the list if no further item of the same type 245*54ba9607SSascha Wildner * follows; otherwise, close the item only. 246*54ba9607SSascha Wildner */ 247*54ba9607SSascha Wildner if (list_continues(n, n->next) == '\0') { 248*54ba9607SSascha Wildner print_tagq(h, t); 249*54ba9607SSascha Wildner t = NULL; 250*54ba9607SSascha Wildner } 251*54ba9607SSascha Wildner } 252*54ba9607SSascha Wildner if (t != NULL) 25380387638SSascha Wildner print_stagq(h, t); 25480387638SSascha Wildner 255*54ba9607SSascha Wildner if (n->flags & NODE_NOFILL && n->tok != MAN_YS && 256*54ba9607SSascha Wildner (n->next != NULL && n->next->flags & NODE_LINE)) { 257*54ba9607SSascha Wildner /* In .nf = <pre>, print even empty lines. */ 258*54ba9607SSascha Wildner h->col++; 259*54ba9607SSascha Wildner print_endline(h); 26080387638SSascha Wildner } 26180387638SSascha Wildner } 26280387638SSascha Wildner 26360e1e752SSascha Wildner static void 264*54ba9607SSascha Wildner man_root_pre(const struct roff_meta *man, struct html *h) 26580387638SSascha Wildner { 26680387638SSascha Wildner struct tag *t, *tt; 267070c62a6SFranco Fichtner char *title; 26880387638SSascha Wildner 269f88b6c16SFranco Fichtner assert(man->title); 270f88b6c16SFranco Fichtner assert(man->msec); 271070c62a6SFranco Fichtner mandoc_asprintf(&title, "%s(%s)", man->title, man->msec); 27280387638SSascha Wildner 273*54ba9607SSascha Wildner t = print_otag(h, TAG_TABLE, "c", "head"); 274*54ba9607SSascha Wildner tt = print_otag(h, TAG_TR, ""); 27580387638SSascha Wildner 276*54ba9607SSascha Wildner print_otag(h, TAG_TD, "c", "head-ltitle"); 27780387638SSascha Wildner print_text(h, title); 27880387638SSascha Wildner print_stagq(h, tt); 27980387638SSascha Wildner 280*54ba9607SSascha Wildner print_otag(h, TAG_TD, "c", "head-vol"); 281*54ba9607SSascha Wildner if (man->vol != NULL) 282070c62a6SFranco Fichtner print_text(h, man->vol); 28380387638SSascha Wildner print_stagq(h, tt); 28480387638SSascha Wildner 285*54ba9607SSascha Wildner print_otag(h, TAG_TD, "c", "head-rtitle"); 28680387638SSascha Wildner print_text(h, title); 28780387638SSascha Wildner print_tagq(h, t); 288070c62a6SFranco Fichtner free(title); 28980387638SSascha Wildner } 29080387638SSascha Wildner 29180387638SSascha Wildner static void 292*54ba9607SSascha Wildner man_root_post(const struct roff_meta *man, struct html *h) 29380387638SSascha Wildner { 29480387638SSascha Wildner struct tag *t, *tt; 29580387638SSascha Wildner 296*54ba9607SSascha Wildner t = print_otag(h, TAG_TABLE, "c", "foot"); 297*54ba9607SSascha Wildner tt = print_otag(h, TAG_TR, ""); 29880387638SSascha Wildner 299*54ba9607SSascha Wildner print_otag(h, TAG_TD, "c", "foot-date"); 300f88b6c16SFranco Fichtner print_text(h, man->date); 30180387638SSascha Wildner print_stagq(h, tt); 30280387638SSascha Wildner 303*54ba9607SSascha Wildner print_otag(h, TAG_TD, "c", "foot-os"); 304*54ba9607SSascha Wildner if (man->os != NULL) 305*54ba9607SSascha Wildner print_text(h, man->os); 30680387638SSascha Wildner print_tagq(h, t); 30780387638SSascha Wildner } 30880387638SSascha Wildner 30980387638SSascha Wildner static int 31080387638SSascha Wildner man_SH_pre(MAN_ARGS) 31180387638SSascha Wildner { 312*54ba9607SSascha Wildner const char *class; 313*54ba9607SSascha Wildner char *id; 314*54ba9607SSascha Wildner enum htmltag tag; 31580387638SSascha Wildner 316*54ba9607SSascha Wildner if (n->tok == MAN_SH) { 317*54ba9607SSascha Wildner tag = TAG_H1; 318*54ba9607SSascha Wildner class = "Sh"; 319*54ba9607SSascha Wildner } else { 320*54ba9607SSascha Wildner tag = TAG_H2; 321*54ba9607SSascha Wildner class = "Ss"; 322*54ba9607SSascha Wildner } 323*54ba9607SSascha Wildner switch (n->type) { 324*54ba9607SSascha Wildner case ROFFT_BLOCK: 325*54ba9607SSascha Wildner html_close_paragraph(h); 326*54ba9607SSascha Wildner print_otag(h, TAG_SECTION, "c", class); 327*54ba9607SSascha Wildner break; 328*54ba9607SSascha Wildner case ROFFT_HEAD: 329*54ba9607SSascha Wildner id = html_make_id(n, 1); 330*54ba9607SSascha Wildner print_otag(h, tag, "ci", class, id); 331*54ba9607SSascha Wildner if (id != NULL) 332*54ba9607SSascha Wildner print_otag(h, TAG_A, "chR", "permalink", id); 333*54ba9607SSascha Wildner break; 334*54ba9607SSascha Wildner case ROFFT_BODY: 335*54ba9607SSascha Wildner break; 336*54ba9607SSascha Wildner default: 337*54ba9607SSascha Wildner abort(); 338*54ba9607SSascha Wildner } 339*54ba9607SSascha Wildner return 1; 34080387638SSascha Wildner } 34180387638SSascha Wildner 34280387638SSascha Wildner static int 34380387638SSascha Wildner man_alt_pre(MAN_ARGS) 34480387638SSascha Wildner { 345*54ba9607SSascha Wildner const struct roff_node *nn; 34680387638SSascha Wildner struct tag *t; 347*54ba9607SSascha Wildner int i; 348*54ba9607SSascha Wildner enum htmltag fp; 34980387638SSascha Wildner 350*54ba9607SSascha Wildner for (i = 0, nn = n->child; nn != NULL; nn = nn->next, i++) { 35180387638SSascha Wildner switch (n->tok) { 352070c62a6SFranco Fichtner case MAN_BI: 35380387638SSascha Wildner fp = i % 2 ? TAG_I : TAG_B; 35480387638SSascha Wildner break; 355070c62a6SFranco Fichtner case MAN_IB: 35680387638SSascha Wildner fp = i % 2 ? TAG_B : TAG_I; 35780387638SSascha Wildner break; 358070c62a6SFranco Fichtner case MAN_RI: 35980387638SSascha Wildner fp = i % 2 ? TAG_I : TAG_MAX; 36080387638SSascha Wildner break; 361070c62a6SFranco Fichtner case MAN_IR: 36280387638SSascha Wildner fp = i % 2 ? TAG_MAX : TAG_I; 36380387638SSascha Wildner break; 364070c62a6SFranco Fichtner case MAN_BR: 36580387638SSascha Wildner fp = i % 2 ? TAG_MAX : TAG_B; 36680387638SSascha Wildner break; 367070c62a6SFranco Fichtner case MAN_RB: 36880387638SSascha Wildner fp = i % 2 ? TAG_B : TAG_MAX; 36980387638SSascha Wildner break; 37080387638SSascha Wildner default: 37180387638SSascha Wildner abort(); 37280387638SSascha Wildner } 37380387638SSascha Wildner 37480387638SSascha Wildner if (i) 37580387638SSascha Wildner h->flags |= HTML_NOSPACE; 37680387638SSascha Wildner 377*54ba9607SSascha Wildner if (fp != TAG_MAX) 378*54ba9607SSascha Wildner t = print_otag(h, fp, ""); 37980387638SSascha Wildner 380*54ba9607SSascha Wildner print_text(h, nn->string); 38180387638SSascha Wildner 382*54ba9607SSascha Wildner if (fp != TAG_MAX) 38380387638SSascha Wildner print_tagq(h, t); 38480387638SSascha Wildner } 385*54ba9607SSascha Wildner return 0; 38680387638SSascha Wildner } 38780387638SSascha Wildner 38880387638SSascha Wildner static int 38980387638SSascha Wildner man_SM_pre(MAN_ARGS) 39080387638SSascha Wildner { 391*54ba9607SSascha Wildner print_otag(h, TAG_SMALL, ""); 392*54ba9607SSascha Wildner if (n->tok == MAN_SB) 393*54ba9607SSascha Wildner print_otag(h, TAG_B, ""); 394*54ba9607SSascha Wildner return 1; 39580387638SSascha Wildner } 39680387638SSascha Wildner 39780387638SSascha Wildner static int 39880387638SSascha Wildner man_PP_pre(MAN_ARGS) 39980387638SSascha Wildner { 400*54ba9607SSascha Wildner switch (n->type) { 401*54ba9607SSascha Wildner case ROFFT_BLOCK: 402*54ba9607SSascha Wildner html_close_paragraph(h); 403*54ba9607SSascha Wildner break; 404*54ba9607SSascha Wildner case ROFFT_HEAD: 405*54ba9607SSascha Wildner return 0; 406*54ba9607SSascha Wildner case ROFFT_BODY: 407*54ba9607SSascha Wildner if (n->child != NULL && 408*54ba9607SSascha Wildner (n->child->flags & NODE_NOFILL) == 0) 409*54ba9607SSascha Wildner print_otag(h, TAG_P, "c", 410*54ba9607SSascha Wildner n->tok == MAN_PP ? "Pp" : "Pp HP"); 411*54ba9607SSascha Wildner break; 412*54ba9607SSascha Wildner default: 413*54ba9607SSascha Wildner abort(); 414*54ba9607SSascha Wildner } 415*54ba9607SSascha Wildner return 1; 416*54ba9607SSascha Wildner } 41780387638SSascha Wildner 418*54ba9607SSascha Wildner static char 419*54ba9607SSascha Wildner list_continues(const struct roff_node *n1, const struct roff_node *n2) 420*54ba9607SSascha Wildner { 421*54ba9607SSascha Wildner const char *s1, *s2; 422*54ba9607SSascha Wildner char c1, c2; 42380387638SSascha Wildner 424*54ba9607SSascha Wildner if (n1 == NULL || n1->type != ROFFT_BLOCK || 425*54ba9607SSascha Wildner n2 == NULL || n2->type != ROFFT_BLOCK) 426*54ba9607SSascha Wildner return '\0'; 427*54ba9607SSascha Wildner if ((n1->tok == MAN_TP || n1->tok == MAN_TQ) && 428*54ba9607SSascha Wildner (n2->tok == MAN_TP || n2->tok == MAN_TQ)) 429*54ba9607SSascha Wildner return ' '; 430*54ba9607SSascha Wildner if (n1->tok != MAN_IP || n2->tok != MAN_IP) 431*54ba9607SSascha Wildner return '\0'; 432*54ba9607SSascha Wildner n1 = n1->head->child; 433*54ba9607SSascha Wildner n2 = n2->head->child; 434*54ba9607SSascha Wildner s1 = n1 == NULL ? "" : n1->string; 435*54ba9607SSascha Wildner s2 = n2 == NULL ? "" : n2->string; 436*54ba9607SSascha Wildner c1 = strcmp(s1, "*") == 0 ? '*' : 437*54ba9607SSascha Wildner strcmp(s1, "\\-") == 0 ? '-' : 438*54ba9607SSascha Wildner strcmp(s1, "\\(bu") == 0 ? 'b' : ' '; 439*54ba9607SSascha Wildner c2 = strcmp(s2, "*") == 0 ? '*' : 440*54ba9607SSascha Wildner strcmp(s2, "\\-") == 0 ? '-' : 441*54ba9607SSascha Wildner strcmp(s2, "\\(bu") == 0 ? 'b' : ' '; 442*54ba9607SSascha Wildner return c1 != c2 ? '\0' : c1 == 'b' ? '*' : c1; 44380387638SSascha Wildner } 44480387638SSascha Wildner 44580387638SSascha Wildner static int 44680387638SSascha Wildner man_IP_pre(MAN_ARGS) 44780387638SSascha Wildner { 448*54ba9607SSascha Wildner const struct roff_node *nn; 449*54ba9607SSascha Wildner const char *list_class; 450*54ba9607SSascha Wildner enum htmltag list_elem, body_elem; 451*54ba9607SSascha Wildner char list_type; 45280387638SSascha Wildner 453*54ba9607SSascha Wildner nn = n->type == ROFFT_BLOCK ? n : n->parent; 454*54ba9607SSascha Wildner if ((list_type = list_continues(nn->prev, nn)) == '\0') { 455*54ba9607SSascha Wildner /* Start a new list. */ 456*54ba9607SSascha Wildner if ((list_type = list_continues(nn, nn->next)) == '\0') 457*54ba9607SSascha Wildner list_type = ' '; 458*54ba9607SSascha Wildner switch (list_type) { 459*54ba9607SSascha Wildner case ' ': 460*54ba9607SSascha Wildner list_class = "Bl-tag"; 461*54ba9607SSascha Wildner list_elem = TAG_DL; 462*54ba9607SSascha Wildner break; 463*54ba9607SSascha Wildner case '*': 464*54ba9607SSascha Wildner list_class = "Bl-bullet"; 465*54ba9607SSascha Wildner list_elem = TAG_UL; 466*54ba9607SSascha Wildner break; 467*54ba9607SSascha Wildner case '-': 468*54ba9607SSascha Wildner list_class = "Bl-dash"; 469*54ba9607SSascha Wildner list_elem = TAG_UL; 470*54ba9607SSascha Wildner break; 471*54ba9607SSascha Wildner default: 472*54ba9607SSascha Wildner abort(); 473*54ba9607SSascha Wildner } 474*54ba9607SSascha Wildner } else { 475*54ba9607SSascha Wildner /* Continue a list that was started earlier. */ 476*54ba9607SSascha Wildner list_class = NULL; 477*54ba9607SSascha Wildner list_elem = TAG_MAX; 478*54ba9607SSascha Wildner } 479*54ba9607SSascha Wildner body_elem = list_type == ' ' ? TAG_DD : TAG_LI; 480*54ba9607SSascha Wildner 481*54ba9607SSascha Wildner switch (n->type) { 482*54ba9607SSascha Wildner case ROFFT_BLOCK: 483*54ba9607SSascha Wildner html_close_paragraph(h); 484*54ba9607SSascha Wildner if (list_elem != TAG_MAX) 485*54ba9607SSascha Wildner print_otag(h, list_elem, "c", list_class); 486*54ba9607SSascha Wildner return 1; 487*54ba9607SSascha Wildner case ROFFT_HEAD: 488*54ba9607SSascha Wildner if (body_elem == TAG_LI) 489*54ba9607SSascha Wildner return 0; 490*54ba9607SSascha Wildner print_otag(h, TAG_DT, ""); 491*54ba9607SSascha Wildner break; 492*54ba9607SSascha Wildner case ROFFT_BODY: 493*54ba9607SSascha Wildner print_otag(h, body_elem, ""); 494*54ba9607SSascha Wildner return 1; 495*54ba9607SSascha Wildner default: 496*54ba9607SSascha Wildner abort(); 49780387638SSascha Wildner } 49880387638SSascha Wildner 499*54ba9607SSascha Wildner switch(n->tok) { 500*54ba9607SSascha Wildner case MAN_IP: /* Only print the first header element. */ 501*54ba9607SSascha Wildner if (n->child != NULL) 502*54ba9607SSascha Wildner print_man_node(man, n->child, h); 503*54ba9607SSascha Wildner break; 504*54ba9607SSascha Wildner case MAN_TP: /* Only print next-line header elements. */ 505*54ba9607SSascha Wildner case MAN_TQ: 506070c62a6SFranco Fichtner nn = n->child; 507*54ba9607SSascha Wildner while (nn != NULL && (NODE_LINE & nn->flags) == 0) 508070c62a6SFranco Fichtner nn = nn->next; 509*54ba9607SSascha Wildner while (nn != NULL) { 510*54ba9607SSascha Wildner print_man_node(man, nn, h); 511070c62a6SFranco Fichtner nn = nn->next; 512070c62a6SFranco Fichtner } 513*54ba9607SSascha Wildner break; 514*54ba9607SSascha Wildner default: 515*54ba9607SSascha Wildner abort(); 516070c62a6SFranco Fichtner } 517*54ba9607SSascha Wildner return 0; 51880387638SSascha Wildner } 51980387638SSascha Wildner 52036342e81SSascha Wildner static int 52136342e81SSascha Wildner man_OP_pre(MAN_ARGS) 52236342e81SSascha Wildner { 52336342e81SSascha Wildner struct tag *tt; 52436342e81SSascha Wildner 52536342e81SSascha Wildner print_text(h, "["); 52636342e81SSascha Wildner h->flags |= HTML_NOSPACE; 527*54ba9607SSascha Wildner tt = print_otag(h, TAG_SPAN, "c", "Op"); 52836342e81SSascha Wildner 529*54ba9607SSascha Wildner if ((n = n->child) != NULL) { 530*54ba9607SSascha Wildner print_otag(h, TAG_B, ""); 53136342e81SSascha Wildner print_text(h, n->string); 53236342e81SSascha Wildner } 53336342e81SSascha Wildner 53436342e81SSascha Wildner print_stagq(h, tt); 53536342e81SSascha Wildner 536*54ba9607SSascha Wildner if (n != NULL && n->next != NULL) { 537*54ba9607SSascha Wildner print_otag(h, TAG_I, ""); 53836342e81SSascha Wildner print_text(h, n->next->string); 53936342e81SSascha Wildner } 54036342e81SSascha Wildner 54136342e81SSascha Wildner print_stagq(h, tt); 54236342e81SSascha Wildner h->flags |= HTML_NOSPACE; 54336342e81SSascha Wildner print_text(h, "]"); 544*54ba9607SSascha Wildner return 0; 54536342e81SSascha Wildner } 54636342e81SSascha Wildner 54780387638SSascha Wildner static int 54880387638SSascha Wildner man_B_pre(MAN_ARGS) 54980387638SSascha Wildner { 550*54ba9607SSascha Wildner print_otag(h, TAG_B, ""); 551*54ba9607SSascha Wildner return 1; 55280387638SSascha Wildner } 55380387638SSascha Wildner 55480387638SSascha Wildner static int 55580387638SSascha Wildner man_I_pre(MAN_ARGS) 55680387638SSascha Wildner { 557*54ba9607SSascha Wildner print_otag(h, TAG_I, ""); 558*54ba9607SSascha Wildner return 1; 55980387638SSascha Wildner } 56080387638SSascha Wildner 56180387638SSascha Wildner static int 56280387638SSascha Wildner man_in_pre(MAN_ARGS) 56380387638SSascha Wildner { 564*54ba9607SSascha Wildner print_otag(h, TAG_BR, ""); 565*54ba9607SSascha Wildner return 0; 56680387638SSascha Wildner } 56780387638SSascha Wildner 56880387638SSascha Wildner static int 56980387638SSascha Wildner man_ign_pre(MAN_ARGS) 57080387638SSascha Wildner { 571*54ba9607SSascha Wildner return 0; 57280387638SSascha Wildner } 57380387638SSascha Wildner 57480387638SSascha Wildner static int 57580387638SSascha Wildner man_RS_pre(MAN_ARGS) 57680387638SSascha Wildner { 577*54ba9607SSascha Wildner switch (n->type) { 578*54ba9607SSascha Wildner case ROFFT_BLOCK: 579*54ba9607SSascha Wildner html_close_paragraph(h); 580*54ba9607SSascha Wildner break; 581*54ba9607SSascha Wildner case ROFFT_HEAD: 582*54ba9607SSascha Wildner return 0; 583*54ba9607SSascha Wildner case ROFFT_BODY: 584*54ba9607SSascha Wildner print_otag(h, TAG_DIV, "c", "Bd-indent"); 585*54ba9607SSascha Wildner break; 586*54ba9607SSascha Wildner default: 587*54ba9607SSascha Wildner abort(); 588*54ba9607SSascha Wildner } 589*54ba9607SSascha Wildner return 1; 590*54ba9607SSascha Wildner } 59180387638SSascha Wildner 592*54ba9607SSascha Wildner static int 593*54ba9607SSascha Wildner man_SY_pre(MAN_ARGS) 594*54ba9607SSascha Wildner { 595*54ba9607SSascha Wildner switch (n->type) { 596*54ba9607SSascha Wildner case ROFFT_BLOCK: 597*54ba9607SSascha Wildner html_close_paragraph(h); 598*54ba9607SSascha Wildner print_otag(h, TAG_TABLE, "c", "Nm"); 599*54ba9607SSascha Wildner print_otag(h, TAG_TR, ""); 600*54ba9607SSascha Wildner break; 601*54ba9607SSascha Wildner case ROFFT_HEAD: 602*54ba9607SSascha Wildner print_otag(h, TAG_TD, ""); 603*54ba9607SSascha Wildner print_otag(h, TAG_CODE, "c", "Nm"); 604*54ba9607SSascha Wildner break; 605*54ba9607SSascha Wildner case ROFFT_BODY: 606*54ba9607SSascha Wildner print_otag(h, TAG_TD, ""); 607*54ba9607SSascha Wildner break; 608*54ba9607SSascha Wildner default: 609*54ba9607SSascha Wildner abort(); 610*54ba9607SSascha Wildner } 611*54ba9607SSascha Wildner return 1; 61280387638SSascha Wildner } 6137888c61dSFranco Fichtner 6147888c61dSFranco Fichtner static int 6157888c61dSFranco Fichtner man_UR_pre(MAN_ARGS) 6167888c61dSFranco Fichtner { 617*54ba9607SSascha Wildner char *cp; 6187888c61dSFranco Fichtner 6197888c61dSFranco Fichtner n = n->child; 620*54ba9607SSascha Wildner assert(n->type == ROFFT_HEAD); 621*54ba9607SSascha Wildner if (n->child != NULL) { 622*54ba9607SSascha Wildner assert(n->child->type == ROFFT_TEXT); 623*54ba9607SSascha Wildner if (n->tok == MAN_MT) { 624*54ba9607SSascha Wildner mandoc_asprintf(&cp, "mailto:%s", n->child->string); 625*54ba9607SSascha Wildner print_otag(h, TAG_A, "ch", "Mt", cp); 626*54ba9607SSascha Wildner free(cp); 627*54ba9607SSascha Wildner } else 628*54ba9607SSascha Wildner print_otag(h, TAG_A, "ch", "Lk", n->child->string); 6297888c61dSFranco Fichtner } 6307888c61dSFranco Fichtner 631*54ba9607SSascha Wildner assert(n->next->type == ROFFT_BODY); 632*54ba9607SSascha Wildner if (n->next->child != NULL) 6337888c61dSFranco Fichtner n = n->next; 6347888c61dSFranco Fichtner 635*54ba9607SSascha Wildner print_man_nodelist(man, n->child, h); 636*54ba9607SSascha Wildner return 0; 637*54ba9607SSascha Wildner } 6387888c61dSFranco Fichtner 639*54ba9607SSascha Wildner static int 640*54ba9607SSascha Wildner man_abort_pre(MAN_ARGS) 641*54ba9607SSascha Wildner { 642*54ba9607SSascha Wildner abort(); 6437888c61dSFranco Fichtner } 644