1*c1c95addSBrooks Davis /* $Id: man_html.c,v 1.187 2023/10/24 20:53:12 schwarze Exp $ */ 261d06d6bSBaptiste Daroussin /* 3*c1c95addSBrooks Davis * Copyright (c) 2013-15,2017-20,2022-23 Ingo Schwarze <schwarze@openbsd.org> 461d06d6bSBaptiste Daroussin * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv> 561d06d6bSBaptiste Daroussin * 661d06d6bSBaptiste Daroussin * Permission to use, copy, modify, and distribute this software for any 761d06d6bSBaptiste Daroussin * purpose with or without fee is hereby granted, provided that the above 861d06d6bSBaptiste Daroussin * copyright notice and this permission notice appear in all copies. 961d06d6bSBaptiste Daroussin * 1061d06d6bSBaptiste Daroussin * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES 1161d06d6bSBaptiste Daroussin * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1261d06d6bSBaptiste Daroussin * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR 1361d06d6bSBaptiste Daroussin * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1461d06d6bSBaptiste Daroussin * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1561d06d6bSBaptiste Daroussin * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1661d06d6bSBaptiste Daroussin * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 176d38604fSBaptiste Daroussin * 186d38604fSBaptiste Daroussin * HTML formatter for man(7) used by mandoc(1). 1961d06d6bSBaptiste Daroussin */ 2061d06d6bSBaptiste Daroussin #include "config.h" 2161d06d6bSBaptiste Daroussin 2261d06d6bSBaptiste Daroussin #include <sys/types.h> 2361d06d6bSBaptiste Daroussin 2461d06d6bSBaptiste Daroussin #include <assert.h> 2561d06d6bSBaptiste Daroussin #include <ctype.h> 2661d06d6bSBaptiste Daroussin #include <stdio.h> 2761d06d6bSBaptiste Daroussin #include <stdlib.h> 2861d06d6bSBaptiste Daroussin #include <string.h> 2961d06d6bSBaptiste Daroussin 3061d06d6bSBaptiste Daroussin #include "mandoc_aux.h" 3161d06d6bSBaptiste Daroussin #include "mandoc.h" 3261d06d6bSBaptiste Daroussin #include "roff.h" 3361d06d6bSBaptiste Daroussin #include "man.h" 3461d06d6bSBaptiste Daroussin #include "out.h" 3561d06d6bSBaptiste Daroussin #include "html.h" 3661d06d6bSBaptiste Daroussin #include "main.h" 3761d06d6bSBaptiste Daroussin 3861d06d6bSBaptiste Daroussin #define MAN_ARGS const struct roff_meta *man, \ 396d38604fSBaptiste Daroussin struct roff_node *n, \ 4061d06d6bSBaptiste Daroussin struct html *h 4161d06d6bSBaptiste Daroussin 427295610fSBaptiste Daroussin struct man_html_act { 4361d06d6bSBaptiste Daroussin int (*pre)(MAN_ARGS); 4461d06d6bSBaptiste Daroussin int (*post)(MAN_ARGS); 4561d06d6bSBaptiste Daroussin }; 4661d06d6bSBaptiste Daroussin 4761d06d6bSBaptiste Daroussin static void print_man_head(const struct roff_meta *, 4861d06d6bSBaptiste Daroussin struct html *); 4961d06d6bSBaptiste Daroussin static void print_man_nodelist(MAN_ARGS); 5061d06d6bSBaptiste Daroussin static void print_man_node(MAN_ARGS); 517295610fSBaptiste Daroussin static char list_continues(const struct roff_node *, 527295610fSBaptiste Daroussin const struct roff_node *); 5361d06d6bSBaptiste Daroussin static int man_B_pre(MAN_ARGS); 5461d06d6bSBaptiste Daroussin static int man_IP_pre(MAN_ARGS); 5561d06d6bSBaptiste Daroussin static int man_I_pre(MAN_ARGS); 56*c1c95addSBrooks Davis static int man_MR_pre(MAN_ARGS); 5761d06d6bSBaptiste Daroussin static int man_OP_pre(MAN_ARGS); 5861d06d6bSBaptiste Daroussin static int man_PP_pre(MAN_ARGS); 5961d06d6bSBaptiste Daroussin static int man_RS_pre(MAN_ARGS); 6061d06d6bSBaptiste Daroussin static int man_SH_pre(MAN_ARGS); 6161d06d6bSBaptiste Daroussin static int man_SM_pre(MAN_ARGS); 627295610fSBaptiste Daroussin static int man_SY_pre(MAN_ARGS); 6361d06d6bSBaptiste Daroussin static int man_UR_pre(MAN_ARGS); 6461d06d6bSBaptiste Daroussin static int man_alt_pre(MAN_ARGS); 6561d06d6bSBaptiste Daroussin static int man_ign_pre(MAN_ARGS); 6661d06d6bSBaptiste Daroussin static int man_in_pre(MAN_ARGS); 6761d06d6bSBaptiste Daroussin static void man_root_post(const struct roff_meta *, 6861d06d6bSBaptiste Daroussin struct html *); 6961d06d6bSBaptiste Daroussin static void man_root_pre(const struct roff_meta *, 7061d06d6bSBaptiste Daroussin struct html *); 7161d06d6bSBaptiste Daroussin 727295610fSBaptiste Daroussin static const struct man_html_act man_html_acts[MAN_MAX - MAN_TH] = { 7361d06d6bSBaptiste Daroussin { NULL, NULL }, /* TH */ 7461d06d6bSBaptiste Daroussin { man_SH_pre, NULL }, /* SH */ 757295610fSBaptiste Daroussin { man_SH_pre, NULL }, /* SS */ 7661d06d6bSBaptiste Daroussin { man_IP_pre, NULL }, /* TP */ 777295610fSBaptiste Daroussin { man_IP_pre, NULL }, /* TQ */ 78*c1c95addSBrooks Davis { man_PP_pre, NULL }, /* LP */ 7961d06d6bSBaptiste Daroussin { man_PP_pre, NULL }, /* PP */ 80*c1c95addSBrooks Davis { man_PP_pre, NULL }, /* P */ 8161d06d6bSBaptiste Daroussin { man_IP_pre, NULL }, /* IP */ 827295610fSBaptiste Daroussin { man_PP_pre, NULL }, /* HP */ 8361d06d6bSBaptiste Daroussin { man_SM_pre, NULL }, /* SM */ 8461d06d6bSBaptiste Daroussin { man_SM_pre, NULL }, /* SB */ 8561d06d6bSBaptiste Daroussin { man_alt_pre, NULL }, /* BI */ 8661d06d6bSBaptiste Daroussin { man_alt_pre, NULL }, /* IB */ 8761d06d6bSBaptiste Daroussin { man_alt_pre, NULL }, /* BR */ 8861d06d6bSBaptiste Daroussin { man_alt_pre, NULL }, /* RB */ 8961d06d6bSBaptiste Daroussin { NULL, NULL }, /* R */ 9061d06d6bSBaptiste Daroussin { man_B_pre, NULL }, /* B */ 9161d06d6bSBaptiste Daroussin { man_I_pre, NULL }, /* I */ 9261d06d6bSBaptiste Daroussin { man_alt_pre, NULL }, /* IR */ 9361d06d6bSBaptiste Daroussin { man_alt_pre, NULL }, /* RI */ 9461d06d6bSBaptiste Daroussin { NULL, NULL }, /* RE */ 9561d06d6bSBaptiste Daroussin { man_RS_pre, NULL }, /* RS */ 9661d06d6bSBaptiste Daroussin { man_ign_pre, NULL }, /* DT */ 9761d06d6bSBaptiste Daroussin { man_ign_pre, NULL }, /* UC */ 9861d06d6bSBaptiste Daroussin { man_ign_pre, NULL }, /* PD */ 9961d06d6bSBaptiste Daroussin { man_ign_pre, NULL }, /* AT */ 10061d06d6bSBaptiste Daroussin { man_in_pre, NULL }, /* in */ 1017295610fSBaptiste Daroussin { man_SY_pre, NULL }, /* SY */ 1027295610fSBaptiste Daroussin { NULL, NULL }, /* YS */ 10361d06d6bSBaptiste Daroussin { man_OP_pre, NULL }, /* OP */ 10461d06d6bSBaptiste Daroussin { NULL, NULL }, /* EX */ 10561d06d6bSBaptiste Daroussin { NULL, NULL }, /* EE */ 10661d06d6bSBaptiste Daroussin { man_UR_pre, NULL }, /* UR */ 10761d06d6bSBaptiste Daroussin { NULL, NULL }, /* UE */ 10861d06d6bSBaptiste Daroussin { man_UR_pre, NULL }, /* MT */ 10961d06d6bSBaptiste Daroussin { NULL, NULL }, /* ME */ 110*c1c95addSBrooks Davis { man_MR_pre, NULL }, /* MR */ 11161d06d6bSBaptiste Daroussin }; 11261d06d6bSBaptiste Daroussin 11361d06d6bSBaptiste Daroussin 11461d06d6bSBaptiste Daroussin void 1157295610fSBaptiste Daroussin html_man(void *arg, const struct roff_meta *man) 11661d06d6bSBaptiste Daroussin { 11761d06d6bSBaptiste Daroussin struct html *h; 11861d06d6bSBaptiste Daroussin struct roff_node *n; 11961d06d6bSBaptiste Daroussin struct tag *t; 12061d06d6bSBaptiste Daroussin 12161d06d6bSBaptiste Daroussin h = (struct html *)arg; 12261d06d6bSBaptiste Daroussin n = man->first->child; 12361d06d6bSBaptiste Daroussin 12461d06d6bSBaptiste Daroussin if ((h->oflags & HTML_FRAGMENT) == 0) { 12561d06d6bSBaptiste Daroussin print_gen_decls(h); 12661d06d6bSBaptiste Daroussin print_otag(h, TAG_HTML, ""); 12761d06d6bSBaptiste Daroussin t = print_otag(h, TAG_HEAD, ""); 1287295610fSBaptiste Daroussin print_man_head(man, h); 12961d06d6bSBaptiste Daroussin print_tagq(h, t); 130*c1c95addSBrooks Davis if (n != NULL && n->type == ROFFT_COMMENT) 131*c1c95addSBrooks Davis print_gen_comment(h, n); 13261d06d6bSBaptiste Daroussin print_otag(h, TAG_BODY, ""); 13361d06d6bSBaptiste Daroussin } 13461d06d6bSBaptiste Daroussin 1357295610fSBaptiste Daroussin man_root_pre(man, h); 136*c1c95addSBrooks Davis t = print_otag(h, TAG_MAIN, "c", "manual-text"); 1377295610fSBaptiste Daroussin print_man_nodelist(man, n, h); 13861d06d6bSBaptiste Daroussin print_tagq(h, t); 1397295610fSBaptiste Daroussin man_root_post(man, h); 14061d06d6bSBaptiste Daroussin print_tagq(h, NULL); 14161d06d6bSBaptiste Daroussin } 14261d06d6bSBaptiste Daroussin 14361d06d6bSBaptiste Daroussin static void 14461d06d6bSBaptiste Daroussin print_man_head(const struct roff_meta *man, struct html *h) 14561d06d6bSBaptiste Daroussin { 14661d06d6bSBaptiste Daroussin char *cp; 14761d06d6bSBaptiste Daroussin 14861d06d6bSBaptiste Daroussin print_gen_head(h); 14961d06d6bSBaptiste Daroussin mandoc_asprintf(&cp, "%s(%s)", man->title, man->msec); 15061d06d6bSBaptiste Daroussin print_otag(h, TAG_TITLE, ""); 15161d06d6bSBaptiste Daroussin print_text(h, cp); 15261d06d6bSBaptiste Daroussin free(cp); 15361d06d6bSBaptiste Daroussin } 15461d06d6bSBaptiste Daroussin 15561d06d6bSBaptiste Daroussin static void 15661d06d6bSBaptiste Daroussin print_man_nodelist(MAN_ARGS) 15761d06d6bSBaptiste Daroussin { 15861d06d6bSBaptiste Daroussin while (n != NULL) { 15961d06d6bSBaptiste Daroussin print_man_node(man, n, h); 16061d06d6bSBaptiste Daroussin n = n->next; 16161d06d6bSBaptiste Daroussin } 16261d06d6bSBaptiste Daroussin } 16361d06d6bSBaptiste Daroussin 16461d06d6bSBaptiste Daroussin static void 16561d06d6bSBaptiste Daroussin print_man_node(MAN_ARGS) 16661d06d6bSBaptiste Daroussin { 16761d06d6bSBaptiste Daroussin struct tag *t; 16861d06d6bSBaptiste Daroussin int child; 16961d06d6bSBaptiste Daroussin 1707295610fSBaptiste Daroussin if (n->type == ROFFT_COMMENT || n->flags & NODE_NOPRT) 17161d06d6bSBaptiste Daroussin return; 17261d06d6bSBaptiste Daroussin 1736d38604fSBaptiste Daroussin if ((n->flags & NODE_NOFILL) == 0) 1746d38604fSBaptiste Daroussin html_fillmode(h, ROFF_fi); 1756d38604fSBaptiste Daroussin else if (html_fillmode(h, ROFF_nf) == ROFF_nf && 1766d38604fSBaptiste Daroussin n->tok != ROFF_fi && n->flags & NODE_LINE && 1776d38604fSBaptiste Daroussin (n->prev == NULL || n->prev->tok != MAN_YS)) 1786d38604fSBaptiste Daroussin print_endline(h); 17961d06d6bSBaptiste Daroussin 18061d06d6bSBaptiste Daroussin child = 1; 18161d06d6bSBaptiste Daroussin switch (n->type) { 18261d06d6bSBaptiste Daroussin case ROFFT_TEXT: 1837295610fSBaptiste Daroussin if (*n->string == '\0') { 1847295610fSBaptiste Daroussin print_endline(h); 1857295610fSBaptiste Daroussin return; 1867295610fSBaptiste Daroussin } 1877295610fSBaptiste Daroussin if (*n->string == ' ' && n->flags & NODE_LINE && 1887295610fSBaptiste Daroussin (h->flags & HTML_NONEWLINE) == 0) 1896d38604fSBaptiste Daroussin print_otag(h, TAG_BR, ""); 1907295610fSBaptiste Daroussin else if (n->flags & NODE_DELIMC) 1917295610fSBaptiste Daroussin h->flags |= HTML_NOSPACE; 19261d06d6bSBaptiste Daroussin t = h->tag; 1937295610fSBaptiste Daroussin t->refcnt++; 19461d06d6bSBaptiste Daroussin print_text(h, n->string); 19561d06d6bSBaptiste Daroussin break; 19661d06d6bSBaptiste Daroussin case ROFFT_EQN: 19761d06d6bSBaptiste Daroussin t = h->tag; 1987295610fSBaptiste Daroussin t->refcnt++; 19961d06d6bSBaptiste Daroussin print_eqn(h, n->eqn); 20061d06d6bSBaptiste Daroussin break; 20161d06d6bSBaptiste Daroussin case ROFFT_TBL: 20261d06d6bSBaptiste Daroussin /* 20361d06d6bSBaptiste Daroussin * This will take care of initialising all of the table 20461d06d6bSBaptiste Daroussin * state data for the first table, then tearing it down 20561d06d6bSBaptiste Daroussin * for the last one. 20661d06d6bSBaptiste Daroussin */ 20761d06d6bSBaptiste Daroussin print_tbl(h, n->span); 20861d06d6bSBaptiste Daroussin return; 20961d06d6bSBaptiste Daroussin default: 21061d06d6bSBaptiste Daroussin /* 21161d06d6bSBaptiste Daroussin * Close out scope of font prior to opening a macro 21261d06d6bSBaptiste Daroussin * scope. 21361d06d6bSBaptiste Daroussin */ 21445a5aec3SBaptiste Daroussin if (h->metac != ESCAPE_FONTROMAN) { 21561d06d6bSBaptiste Daroussin h->metal = h->metac; 21645a5aec3SBaptiste Daroussin h->metac = ESCAPE_FONTROMAN; 21761d06d6bSBaptiste Daroussin } 21861d06d6bSBaptiste Daroussin 21961d06d6bSBaptiste Daroussin /* 22061d06d6bSBaptiste Daroussin * Close out the current table, if it's open, and unset 22161d06d6bSBaptiste Daroussin * the "meta" table state. This will be reopened on the 22261d06d6bSBaptiste Daroussin * next table element. 22361d06d6bSBaptiste Daroussin */ 2247295610fSBaptiste Daroussin if (h->tblt != NULL) 22561d06d6bSBaptiste Daroussin print_tblclose(h); 22661d06d6bSBaptiste Daroussin t = h->tag; 2277295610fSBaptiste Daroussin t->refcnt++; 22861d06d6bSBaptiste Daroussin if (n->tok < ROFF_MAX) { 22961d06d6bSBaptiste Daroussin roff_html_pre(h, n); 2307295610fSBaptiste Daroussin t->refcnt--; 2317295610fSBaptiste Daroussin print_stagq(h, t); 2327295610fSBaptiste Daroussin return; 23361d06d6bSBaptiste Daroussin } 23461d06d6bSBaptiste Daroussin assert(n->tok >= MAN_TH && n->tok < MAN_MAX); 2357295610fSBaptiste Daroussin if (man_html_acts[n->tok - MAN_TH].pre != NULL) 2367295610fSBaptiste Daroussin child = (*man_html_acts[n->tok - MAN_TH].pre)(man, 2377295610fSBaptiste Daroussin n, h); 23861d06d6bSBaptiste Daroussin break; 23961d06d6bSBaptiste Daroussin } 24061d06d6bSBaptiste Daroussin 2417295610fSBaptiste Daroussin if (child && n->child != NULL) 24261d06d6bSBaptiste Daroussin print_man_nodelist(man, n->child, h); 24361d06d6bSBaptiste Daroussin 24461d06d6bSBaptiste Daroussin /* This will automatically close out any font scope. */ 2457295610fSBaptiste Daroussin t->refcnt--; 2467295610fSBaptiste Daroussin if (n->type == ROFFT_BLOCK && 2477295610fSBaptiste Daroussin (n->tok == MAN_IP || n->tok == MAN_TP || n->tok == MAN_TQ)) { 2487295610fSBaptiste Daroussin t = h->tag; 2497295610fSBaptiste Daroussin while (t->tag != TAG_DL && t->tag != TAG_UL) 2507295610fSBaptiste Daroussin t = t->next; 2517295610fSBaptiste Daroussin /* 2527295610fSBaptiste Daroussin * Close the list if no further item of the same type 2537295610fSBaptiste Daroussin * follows; otherwise, close the item only. 2547295610fSBaptiste Daroussin */ 2556d38604fSBaptiste Daroussin if (list_continues(n, roff_node_next(n)) == '\0') { 2567295610fSBaptiste Daroussin print_tagq(h, t); 2577295610fSBaptiste Daroussin t = NULL; 2587295610fSBaptiste Daroussin } 2597295610fSBaptiste Daroussin } 2607295610fSBaptiste Daroussin if (t != NULL) 26161d06d6bSBaptiste Daroussin print_stagq(h, t); 26261d06d6bSBaptiste Daroussin } 26361d06d6bSBaptiste Daroussin 26461d06d6bSBaptiste Daroussin static void 26561d06d6bSBaptiste Daroussin man_root_pre(const struct roff_meta *man, struct html *h) 26661d06d6bSBaptiste Daroussin { 267*c1c95addSBrooks Davis struct tag *t; 26861d06d6bSBaptiste Daroussin char *title; 26961d06d6bSBaptiste Daroussin 27061d06d6bSBaptiste Daroussin assert(man->title); 27161d06d6bSBaptiste Daroussin assert(man->msec); 27261d06d6bSBaptiste Daroussin mandoc_asprintf(&title, "%s(%s)", man->title, man->msec); 27361d06d6bSBaptiste Daroussin 274*c1c95addSBrooks Davis t = print_otag(h, TAG_DIV, "cr?", "head", "doc-pageheader", 275*c1c95addSBrooks Davis "aria-label", "Manual header line"); 27661d06d6bSBaptiste Daroussin 277*c1c95addSBrooks Davis print_otag(h, TAG_SPAN, "c", "head-ltitle"); 27861d06d6bSBaptiste Daroussin print_text(h, title); 279*c1c95addSBrooks Davis print_stagq(h, t); 28061d06d6bSBaptiste Daroussin 281*c1c95addSBrooks Davis print_otag(h, TAG_SPAN, "c", "head-vol"); 2827295610fSBaptiste Daroussin if (man->vol != NULL) 28361d06d6bSBaptiste Daroussin print_text(h, man->vol); 284*c1c95addSBrooks Davis print_stagq(h, t); 28561d06d6bSBaptiste Daroussin 286*c1c95addSBrooks Davis print_otag(h, TAG_SPAN, "c", "head-rtitle"); 28761d06d6bSBaptiste Daroussin print_text(h, title); 28861d06d6bSBaptiste Daroussin print_tagq(h, t); 28961d06d6bSBaptiste Daroussin free(title); 29061d06d6bSBaptiste Daroussin } 29161d06d6bSBaptiste Daroussin 29261d06d6bSBaptiste Daroussin static void 29361d06d6bSBaptiste Daroussin man_root_post(const struct roff_meta *man, struct html *h) 29461d06d6bSBaptiste Daroussin { 295*c1c95addSBrooks Davis struct tag *t; 29661d06d6bSBaptiste Daroussin 297*c1c95addSBrooks Davis t = print_otag(h, TAG_DIV, "cr?", "foot", "doc-pagefooter", 298*c1c95addSBrooks Davis "aria-label", "Manual footer line"); 29961d06d6bSBaptiste Daroussin 300*c1c95addSBrooks Davis print_otag(h, TAG_SPAN, "c", "foot-left"); 301*c1c95addSBrooks Davis print_stagq(h, t); 302*c1c95addSBrooks Davis 303*c1c95addSBrooks Davis print_otag(h, TAG_SPAN, "c", "foot-date"); 30461d06d6bSBaptiste Daroussin print_text(h, man->date); 305*c1c95addSBrooks Davis print_stagq(h, t); 30661d06d6bSBaptiste Daroussin 307*c1c95addSBrooks Davis print_otag(h, TAG_SPAN, "c", "foot-os"); 3087295610fSBaptiste Daroussin if (man->os != NULL) 30961d06d6bSBaptiste Daroussin print_text(h, man->os); 31061d06d6bSBaptiste Daroussin print_tagq(h, t); 31161d06d6bSBaptiste Daroussin } 31261d06d6bSBaptiste Daroussin 31361d06d6bSBaptiste Daroussin static int 31461d06d6bSBaptiste Daroussin man_SH_pre(MAN_ARGS) 31561d06d6bSBaptiste Daroussin { 3167295610fSBaptiste Daroussin const char *class; 3177295610fSBaptiste Daroussin enum htmltag tag; 31861d06d6bSBaptiste Daroussin 3197295610fSBaptiste Daroussin if (n->tok == MAN_SH) { 320*c1c95addSBrooks Davis tag = TAG_H2; 3217295610fSBaptiste Daroussin class = "Sh"; 3227295610fSBaptiste Daroussin } else { 323*c1c95addSBrooks Davis tag = TAG_H3; 3247295610fSBaptiste Daroussin class = "Ss"; 3257295610fSBaptiste Daroussin } 3267295610fSBaptiste Daroussin switch (n->type) { 3277295610fSBaptiste Daroussin case ROFFT_BLOCK: 3287295610fSBaptiste Daroussin html_close_paragraph(h); 3297295610fSBaptiste Daroussin print_otag(h, TAG_SECTION, "c", class); 3307295610fSBaptiste Daroussin break; 3317295610fSBaptiste Daroussin case ROFFT_HEAD: 3326d38604fSBaptiste Daroussin print_otag_id(h, tag, class, n); 3337295610fSBaptiste Daroussin break; 3347295610fSBaptiste Daroussin case ROFFT_BODY: 3357295610fSBaptiste Daroussin break; 3367295610fSBaptiste Daroussin default: 3377295610fSBaptiste Daroussin abort(); 33861d06d6bSBaptiste Daroussin } 33961d06d6bSBaptiste Daroussin return 1; 34061d06d6bSBaptiste Daroussin } 34161d06d6bSBaptiste Daroussin 34261d06d6bSBaptiste Daroussin static int 34361d06d6bSBaptiste Daroussin man_alt_pre(MAN_ARGS) 34461d06d6bSBaptiste Daroussin { 34561d06d6bSBaptiste Daroussin const struct roff_node *nn; 3467295610fSBaptiste Daroussin struct tag *t; 34761d06d6bSBaptiste Daroussin int i; 34861d06d6bSBaptiste Daroussin enum htmltag fp; 34961d06d6bSBaptiste Daroussin 3507295610fSBaptiste Daroussin for (i = 0, nn = n->child; nn != NULL; nn = nn->next, i++) { 35161d06d6bSBaptiste Daroussin switch (n->tok) { 35261d06d6bSBaptiste Daroussin case MAN_BI: 35361d06d6bSBaptiste Daroussin fp = i % 2 ? TAG_I : TAG_B; 35461d06d6bSBaptiste Daroussin break; 35561d06d6bSBaptiste Daroussin case MAN_IB: 35661d06d6bSBaptiste Daroussin fp = i % 2 ? TAG_B : TAG_I; 35761d06d6bSBaptiste Daroussin break; 35861d06d6bSBaptiste Daroussin case MAN_RI: 35961d06d6bSBaptiste Daroussin fp = i % 2 ? TAG_I : TAG_MAX; 36061d06d6bSBaptiste Daroussin break; 36161d06d6bSBaptiste Daroussin case MAN_IR: 36261d06d6bSBaptiste Daroussin fp = i % 2 ? TAG_MAX : TAG_I; 36361d06d6bSBaptiste Daroussin break; 36461d06d6bSBaptiste Daroussin case MAN_BR: 36561d06d6bSBaptiste Daroussin fp = i % 2 ? TAG_MAX : TAG_B; 36661d06d6bSBaptiste Daroussin break; 36761d06d6bSBaptiste Daroussin case MAN_RB: 36861d06d6bSBaptiste Daroussin fp = i % 2 ? TAG_B : TAG_MAX; 36961d06d6bSBaptiste Daroussin break; 37061d06d6bSBaptiste Daroussin default: 37161d06d6bSBaptiste Daroussin abort(); 37261d06d6bSBaptiste Daroussin } 37361d06d6bSBaptiste Daroussin 37461d06d6bSBaptiste Daroussin if (i) 37561d06d6bSBaptiste Daroussin h->flags |= HTML_NOSPACE; 37661d06d6bSBaptiste Daroussin 37761d06d6bSBaptiste Daroussin if (fp != TAG_MAX) 37861d06d6bSBaptiste Daroussin t = print_otag(h, fp, ""); 37961d06d6bSBaptiste Daroussin 38061d06d6bSBaptiste Daroussin print_text(h, nn->string); 38161d06d6bSBaptiste Daroussin 38261d06d6bSBaptiste Daroussin if (fp != TAG_MAX) 38361d06d6bSBaptiste Daroussin print_tagq(h, t); 38461d06d6bSBaptiste Daroussin } 38561d06d6bSBaptiste Daroussin return 0; 38661d06d6bSBaptiste Daroussin } 38761d06d6bSBaptiste Daroussin 38861d06d6bSBaptiste Daroussin static int 38961d06d6bSBaptiste Daroussin man_SM_pre(MAN_ARGS) 39061d06d6bSBaptiste Daroussin { 39161d06d6bSBaptiste Daroussin print_otag(h, TAG_SMALL, ""); 3927295610fSBaptiste Daroussin if (n->tok == MAN_SB) 39361d06d6bSBaptiste Daroussin print_otag(h, TAG_B, ""); 39461d06d6bSBaptiste Daroussin return 1; 39561d06d6bSBaptiste Daroussin } 39661d06d6bSBaptiste Daroussin 39761d06d6bSBaptiste Daroussin static int 39861d06d6bSBaptiste Daroussin man_PP_pre(MAN_ARGS) 39961d06d6bSBaptiste Daroussin { 4007295610fSBaptiste Daroussin switch (n->type) { 4017295610fSBaptiste Daroussin case ROFFT_BLOCK: 4027295610fSBaptiste Daroussin html_close_paragraph(h); 4037295610fSBaptiste Daroussin break; 4047295610fSBaptiste Daroussin case ROFFT_HEAD: 40561d06d6bSBaptiste Daroussin return 0; 4067295610fSBaptiste Daroussin case ROFFT_BODY: 4077295610fSBaptiste Daroussin if (n->child != NULL && 4087295610fSBaptiste Daroussin (n->child->flags & NODE_NOFILL) == 0) 4097295610fSBaptiste Daroussin print_otag(h, TAG_P, "c", 410*c1c95addSBrooks Davis n->tok == MAN_HP ? "Pp HP" : "Pp"); 4117295610fSBaptiste Daroussin break; 4127295610fSBaptiste Daroussin default: 4137295610fSBaptiste Daroussin abort(); 4147295610fSBaptiste Daroussin } 41561d06d6bSBaptiste Daroussin return 1; 41661d06d6bSBaptiste Daroussin } 41761d06d6bSBaptiste Daroussin 4187295610fSBaptiste Daroussin static char 4197295610fSBaptiste Daroussin list_continues(const struct roff_node *n1, const struct roff_node *n2) 4207295610fSBaptiste Daroussin { 4217295610fSBaptiste Daroussin const char *s1, *s2; 4227295610fSBaptiste Daroussin char c1, c2; 4237295610fSBaptiste Daroussin 4247295610fSBaptiste Daroussin if (n1 == NULL || n1->type != ROFFT_BLOCK || 4257295610fSBaptiste Daroussin n2 == NULL || n2->type != ROFFT_BLOCK) 4267295610fSBaptiste Daroussin return '\0'; 4277295610fSBaptiste Daroussin if ((n1->tok == MAN_TP || n1->tok == MAN_TQ) && 4287295610fSBaptiste Daroussin (n2->tok == MAN_TP || n2->tok == MAN_TQ)) 4297295610fSBaptiste Daroussin return ' '; 4307295610fSBaptiste Daroussin if (n1->tok != MAN_IP || n2->tok != MAN_IP) 4317295610fSBaptiste Daroussin return '\0'; 4327295610fSBaptiste Daroussin n1 = n1->head->child; 4337295610fSBaptiste Daroussin n2 = n2->head->child; 4347295610fSBaptiste Daroussin s1 = n1 == NULL ? "" : n1->string; 4357295610fSBaptiste Daroussin s2 = n2 == NULL ? "" : n2->string; 4367295610fSBaptiste Daroussin c1 = strcmp(s1, "*") == 0 ? '*' : 4377295610fSBaptiste Daroussin strcmp(s1, "\\-") == 0 ? '-' : 438*c1c95addSBrooks Davis strcmp(s1, "\\(bu") == 0 ? 'b' : 439*c1c95addSBrooks Davis strcmp(s1, "\\[bu]") == 0 ? 'b' : ' '; 4407295610fSBaptiste Daroussin c2 = strcmp(s2, "*") == 0 ? '*' : 4417295610fSBaptiste Daroussin strcmp(s2, "\\-") == 0 ? '-' : 442*c1c95addSBrooks Davis strcmp(s2, "\\(bu") == 0 ? 'b' : 443*c1c95addSBrooks Davis strcmp(s2, "\\[bu]") == 0 ? 'b' : ' '; 4447295610fSBaptiste Daroussin return c1 != c2 ? '\0' : c1 == 'b' ? '*' : c1; 4457295610fSBaptiste Daroussin } 4467295610fSBaptiste Daroussin 44761d06d6bSBaptiste Daroussin static int 44861d06d6bSBaptiste Daroussin man_IP_pre(MAN_ARGS) 44961d06d6bSBaptiste Daroussin { 4506d38604fSBaptiste Daroussin struct roff_node *nn; 4517295610fSBaptiste Daroussin const char *list_class; 4527295610fSBaptiste Daroussin enum htmltag list_elem, body_elem; 4537295610fSBaptiste Daroussin char list_type; 45461d06d6bSBaptiste Daroussin 4557295610fSBaptiste Daroussin nn = n->type == ROFFT_BLOCK ? n : n->parent; 4566d38604fSBaptiste Daroussin list_type = list_continues(roff_node_prev(nn), nn); 4576d38604fSBaptiste Daroussin if (list_type == '\0') { 4587295610fSBaptiste Daroussin /* Start a new list. */ 4596d38604fSBaptiste Daroussin list_type = list_continues(nn, roff_node_next(nn)); 4606d38604fSBaptiste Daroussin if (list_type == '\0') 4617295610fSBaptiste Daroussin list_type = ' '; 4627295610fSBaptiste Daroussin switch (list_type) { 4637295610fSBaptiste Daroussin case ' ': 4647295610fSBaptiste Daroussin list_class = "Bl-tag"; 4657295610fSBaptiste Daroussin list_elem = TAG_DL; 4667295610fSBaptiste Daroussin break; 4677295610fSBaptiste Daroussin case '*': 4687295610fSBaptiste Daroussin list_class = "Bl-bullet"; 4697295610fSBaptiste Daroussin list_elem = TAG_UL; 4707295610fSBaptiste Daroussin break; 4717295610fSBaptiste Daroussin case '-': 4727295610fSBaptiste Daroussin list_class = "Bl-dash"; 4737295610fSBaptiste Daroussin list_elem = TAG_UL; 4747295610fSBaptiste Daroussin break; 4757295610fSBaptiste Daroussin default: 4767295610fSBaptiste Daroussin abort(); 4777295610fSBaptiste Daroussin } 4787295610fSBaptiste Daroussin } else { 4797295610fSBaptiste Daroussin /* Continue a list that was started earlier. */ 4807295610fSBaptiste Daroussin list_class = NULL; 4817295610fSBaptiste Daroussin list_elem = TAG_MAX; 4827295610fSBaptiste Daroussin } 4837295610fSBaptiste Daroussin body_elem = list_type == ' ' ? TAG_DD : TAG_LI; 4847295610fSBaptiste Daroussin 4857295610fSBaptiste Daroussin switch (n->type) { 4867295610fSBaptiste Daroussin case ROFFT_BLOCK: 4877295610fSBaptiste Daroussin html_close_paragraph(h); 4887295610fSBaptiste Daroussin if (list_elem != TAG_MAX) 4897295610fSBaptiste Daroussin print_otag(h, list_elem, "c", list_class); 49061d06d6bSBaptiste Daroussin return 1; 4917295610fSBaptiste Daroussin case ROFFT_HEAD: 4927295610fSBaptiste Daroussin if (body_elem == TAG_LI) 4937295610fSBaptiste Daroussin return 0; 4946d38604fSBaptiste Daroussin print_otag_id(h, TAG_DT, NULL, n); 4957295610fSBaptiste Daroussin break; 4967295610fSBaptiste Daroussin case ROFFT_BODY: 4977295610fSBaptiste Daroussin print_otag(h, body_elem, ""); 49861d06d6bSBaptiste Daroussin return 1; 4997295610fSBaptiste Daroussin default: 5007295610fSBaptiste Daroussin abort(); 50161d06d6bSBaptiste Daroussin } 5027295610fSBaptiste Daroussin switch(n->tok) { 5037295610fSBaptiste Daroussin case MAN_IP: /* Only print the first header element. */ 5047295610fSBaptiste Daroussin if (n->child != NULL) 50561d06d6bSBaptiste Daroussin print_man_node(man, n->child, h); 5067295610fSBaptiste Daroussin break; 5077295610fSBaptiste Daroussin case MAN_TP: /* Only print next-line header elements. */ 5087295610fSBaptiste Daroussin case MAN_TQ: 50961d06d6bSBaptiste Daroussin nn = n->child; 5107295610fSBaptiste Daroussin while (nn != NULL && (NODE_LINE & nn->flags) == 0) 51161d06d6bSBaptiste Daroussin nn = nn->next; 5127295610fSBaptiste Daroussin while (nn != NULL) { 51361d06d6bSBaptiste Daroussin print_man_node(man, nn, h); 51461d06d6bSBaptiste Daroussin nn = nn->next; 51561d06d6bSBaptiste Daroussin } 5167295610fSBaptiste Daroussin break; 5177295610fSBaptiste Daroussin default: 5187295610fSBaptiste Daroussin abort(); 51961d06d6bSBaptiste Daroussin } 52061d06d6bSBaptiste Daroussin return 0; 52161d06d6bSBaptiste Daroussin } 52261d06d6bSBaptiste Daroussin 52361d06d6bSBaptiste Daroussin static int 524*c1c95addSBrooks Davis man_MR_pre(MAN_ARGS) 525*c1c95addSBrooks Davis { 526*c1c95addSBrooks Davis struct tag *t; 527*c1c95addSBrooks Davis const char *name, *section, *suffix; 528*c1c95addSBrooks Davis char *label; 529*c1c95addSBrooks Davis 530*c1c95addSBrooks Davis html_setfont(h, ESCAPE_FONTROMAN); 531*c1c95addSBrooks Davis name = section = suffix = label = NULL; 532*c1c95addSBrooks Davis if (n->child != NULL) { 533*c1c95addSBrooks Davis name = n->child->string; 534*c1c95addSBrooks Davis if (n->child->next != NULL) { 535*c1c95addSBrooks Davis section = n->child->next->string; 536*c1c95addSBrooks Davis mandoc_asprintf(&label, 537*c1c95addSBrooks Davis "%s, section %s", name, section); 538*c1c95addSBrooks Davis if (n->child->next->next != NULL) 539*c1c95addSBrooks Davis suffix = n->child->next->next->string; 540*c1c95addSBrooks Davis } 541*c1c95addSBrooks Davis } 542*c1c95addSBrooks Davis 543*c1c95addSBrooks Davis if (name != NULL && section != NULL && h->base_man1 != NULL) 544*c1c95addSBrooks Davis t = print_otag(h, TAG_A, "chM?", "Xr", 545*c1c95addSBrooks Davis name, section, "aria-label", label); 546*c1c95addSBrooks Davis else 547*c1c95addSBrooks Davis t = print_otag(h, TAG_A, "c?", "Xr", "aria-label", label); 548*c1c95addSBrooks Davis 549*c1c95addSBrooks Davis free(label); 550*c1c95addSBrooks Davis if (name != NULL) { 551*c1c95addSBrooks Davis print_text(h, name); 552*c1c95addSBrooks Davis h->flags |= HTML_NOSPACE; 553*c1c95addSBrooks Davis } 554*c1c95addSBrooks Davis print_text(h, "("); 555*c1c95addSBrooks Davis h->flags |= HTML_NOSPACE; 556*c1c95addSBrooks Davis if (section != NULL) { 557*c1c95addSBrooks Davis print_text(h, section); 558*c1c95addSBrooks Davis h->flags |= HTML_NOSPACE; 559*c1c95addSBrooks Davis } 560*c1c95addSBrooks Davis print_text(h, ")"); 561*c1c95addSBrooks Davis print_tagq(h, t); 562*c1c95addSBrooks Davis if (suffix != NULL) { 563*c1c95addSBrooks Davis h->flags |= HTML_NOSPACE; 564*c1c95addSBrooks Davis print_text(h, suffix); 565*c1c95addSBrooks Davis } 566*c1c95addSBrooks Davis return 0; 567*c1c95addSBrooks Davis } 568*c1c95addSBrooks Davis 569*c1c95addSBrooks Davis static int 57061d06d6bSBaptiste Daroussin man_OP_pre(MAN_ARGS) 57161d06d6bSBaptiste Daroussin { 57261d06d6bSBaptiste Daroussin struct tag *tt; 57361d06d6bSBaptiste Daroussin 57461d06d6bSBaptiste Daroussin print_text(h, "["); 57561d06d6bSBaptiste Daroussin h->flags |= HTML_NOSPACE; 57661d06d6bSBaptiste Daroussin tt = print_otag(h, TAG_SPAN, "c", "Op"); 57761d06d6bSBaptiste Daroussin 5787295610fSBaptiste Daroussin if ((n = n->child) != NULL) { 57961d06d6bSBaptiste Daroussin print_otag(h, TAG_B, ""); 58061d06d6bSBaptiste Daroussin print_text(h, n->string); 58161d06d6bSBaptiste Daroussin } 58261d06d6bSBaptiste Daroussin 58361d06d6bSBaptiste Daroussin print_stagq(h, tt); 58461d06d6bSBaptiste Daroussin 5857295610fSBaptiste Daroussin if (n != NULL && n->next != NULL) { 58661d06d6bSBaptiste Daroussin print_otag(h, TAG_I, ""); 58761d06d6bSBaptiste Daroussin print_text(h, n->next->string); 58861d06d6bSBaptiste Daroussin } 58961d06d6bSBaptiste Daroussin 59061d06d6bSBaptiste Daroussin print_stagq(h, tt); 59161d06d6bSBaptiste Daroussin h->flags |= HTML_NOSPACE; 59261d06d6bSBaptiste Daroussin print_text(h, "]"); 59361d06d6bSBaptiste Daroussin return 0; 59461d06d6bSBaptiste Daroussin } 59561d06d6bSBaptiste Daroussin 59661d06d6bSBaptiste Daroussin static int 59761d06d6bSBaptiste Daroussin man_B_pre(MAN_ARGS) 59861d06d6bSBaptiste Daroussin { 59961d06d6bSBaptiste Daroussin print_otag(h, TAG_B, ""); 60061d06d6bSBaptiste Daroussin return 1; 60161d06d6bSBaptiste Daroussin } 60261d06d6bSBaptiste Daroussin 60361d06d6bSBaptiste Daroussin static int 60461d06d6bSBaptiste Daroussin man_I_pre(MAN_ARGS) 60561d06d6bSBaptiste Daroussin { 60661d06d6bSBaptiste Daroussin print_otag(h, TAG_I, ""); 60761d06d6bSBaptiste Daroussin return 1; 60861d06d6bSBaptiste Daroussin } 60961d06d6bSBaptiste Daroussin 61061d06d6bSBaptiste Daroussin static int 61161d06d6bSBaptiste Daroussin man_in_pre(MAN_ARGS) 61261d06d6bSBaptiste Daroussin { 61361d06d6bSBaptiste Daroussin print_otag(h, TAG_BR, ""); 61461d06d6bSBaptiste Daroussin return 0; 61561d06d6bSBaptiste Daroussin } 61661d06d6bSBaptiste Daroussin 61761d06d6bSBaptiste Daroussin static int 61861d06d6bSBaptiste Daroussin man_ign_pre(MAN_ARGS) 61961d06d6bSBaptiste Daroussin { 62061d06d6bSBaptiste Daroussin return 0; 62161d06d6bSBaptiste Daroussin } 62261d06d6bSBaptiste Daroussin 62361d06d6bSBaptiste Daroussin static int 62461d06d6bSBaptiste Daroussin man_RS_pre(MAN_ARGS) 62561d06d6bSBaptiste Daroussin { 6267295610fSBaptiste Daroussin switch (n->type) { 6277295610fSBaptiste Daroussin case ROFFT_BLOCK: 6287295610fSBaptiste Daroussin html_close_paragraph(h); 6297295610fSBaptiste Daroussin break; 6307295610fSBaptiste Daroussin case ROFFT_HEAD: 63161d06d6bSBaptiste Daroussin return 0; 6327295610fSBaptiste Daroussin case ROFFT_BODY: 63361d06d6bSBaptiste Daroussin print_otag(h, TAG_DIV, "c", "Bd-indent"); 6347295610fSBaptiste Daroussin break; 6357295610fSBaptiste Daroussin default: 6367295610fSBaptiste Daroussin abort(); 6377295610fSBaptiste Daroussin } 6387295610fSBaptiste Daroussin return 1; 6397295610fSBaptiste Daroussin } 6407295610fSBaptiste Daroussin 6417295610fSBaptiste Daroussin static int 6427295610fSBaptiste Daroussin man_SY_pre(MAN_ARGS) 6437295610fSBaptiste Daroussin { 6447295610fSBaptiste Daroussin switch (n->type) { 6457295610fSBaptiste Daroussin case ROFFT_BLOCK: 6467295610fSBaptiste Daroussin html_close_paragraph(h); 6477295610fSBaptiste Daroussin print_otag(h, TAG_TABLE, "c", "Nm"); 6487295610fSBaptiste Daroussin print_otag(h, TAG_TR, ""); 6497295610fSBaptiste Daroussin break; 6507295610fSBaptiste Daroussin case ROFFT_HEAD: 6517295610fSBaptiste Daroussin print_otag(h, TAG_TD, ""); 6527295610fSBaptiste Daroussin print_otag(h, TAG_CODE, "c", "Nm"); 6537295610fSBaptiste Daroussin break; 6547295610fSBaptiste Daroussin case ROFFT_BODY: 6557295610fSBaptiste Daroussin print_otag(h, TAG_TD, ""); 6567295610fSBaptiste Daroussin break; 6577295610fSBaptiste Daroussin default: 6587295610fSBaptiste Daroussin abort(); 6597295610fSBaptiste Daroussin } 66061d06d6bSBaptiste Daroussin return 1; 66161d06d6bSBaptiste Daroussin } 66261d06d6bSBaptiste Daroussin 66361d06d6bSBaptiste Daroussin static int 66461d06d6bSBaptiste Daroussin man_UR_pre(MAN_ARGS) 66561d06d6bSBaptiste Daroussin { 66661d06d6bSBaptiste Daroussin char *cp; 6677295610fSBaptiste Daroussin 66861d06d6bSBaptiste Daroussin n = n->child; 66961d06d6bSBaptiste Daroussin assert(n->type == ROFFT_HEAD); 67061d06d6bSBaptiste Daroussin if (n->child != NULL) { 67161d06d6bSBaptiste Daroussin assert(n->child->type == ROFFT_TEXT); 67261d06d6bSBaptiste Daroussin if (n->tok == MAN_MT) { 67361d06d6bSBaptiste Daroussin mandoc_asprintf(&cp, "mailto:%s", n->child->string); 6747295610fSBaptiste Daroussin print_otag(h, TAG_A, "ch", "Mt", cp); 67561d06d6bSBaptiste Daroussin free(cp); 67661d06d6bSBaptiste Daroussin } else 6777295610fSBaptiste Daroussin print_otag(h, TAG_A, "ch", "Lk", n->child->string); 67861d06d6bSBaptiste Daroussin } 67961d06d6bSBaptiste Daroussin 68061d06d6bSBaptiste Daroussin assert(n->next->type == ROFFT_BODY); 68161d06d6bSBaptiste Daroussin if (n->next->child != NULL) 68261d06d6bSBaptiste Daroussin n = n->next; 68361d06d6bSBaptiste Daroussin 68461d06d6bSBaptiste Daroussin print_man_nodelist(man, n->child, h); 68561d06d6bSBaptiste Daroussin return 0; 68661d06d6bSBaptiste Daroussin } 687