1322249Sbapt/* $Id: man_html.c,v 1.145 2017/06/25 11:42:02 schwarze Exp $ */ 2241675Suqs/* 3275432Sbapt * Copyright (c) 2008-2012, 2014 Kristaps Dzonsons <kristaps@bsd.lv> 4316420Sbapt * Copyright (c) 2013, 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org> 5241675Suqs * 6241675Suqs * Permission to use, copy, modify, and distribute this software for any 7241675Suqs * purpose with or without fee is hereby granted, provided that the above 8241675Suqs * copyright notice and this permission notice appear in all copies. 9241675Suqs * 10294113Sbapt * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES 11241675Suqs * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12294113Sbapt * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR 13241675Suqs * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14241675Suqs * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15241675Suqs * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16241675Suqs * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17241675Suqs */ 18241675Suqs#include "config.h" 19241675Suqs 20241675Suqs#include <sys/types.h> 21241675Suqs 22241675Suqs#include <assert.h> 23241675Suqs#include <ctype.h> 24241675Suqs#include <stdio.h> 25241675Suqs#include <stdlib.h> 26241675Suqs#include <string.h> 27241675Suqs 28274880Sbapt#include "mandoc_aux.h" 29322249Sbapt#include "mandoc.h" 30294113Sbapt#include "roff.h" 31276219Sbapt#include "man.h" 32241675Suqs#include "out.h" 33241675Suqs#include "html.h" 34241675Suqs#include "main.h" 35241675Suqs 36241675Suqs/* FIXME: have PD set the default vspace width. */ 37241675Suqs 38241675Suqs#define INDENT 5 39241675Suqs 40294113Sbapt#define MAN_ARGS const struct roff_meta *man, \ 41294113Sbapt const struct roff_node *n, \ 42241675Suqs struct html *h 43241675Suqs 44241675Suqsstruct htmlman { 45241675Suqs int (*pre)(MAN_ARGS); 46241675Suqs int (*post)(MAN_ARGS); 47241675Suqs}; 48241675Suqs 49274880Sbaptstatic void print_bvspace(struct html *, 50294113Sbapt const struct roff_node *); 51241675Suqsstatic void print_man_head(MAN_ARGS); 52241675Suqsstatic void print_man_nodelist(MAN_ARGS); 53241675Suqsstatic void print_man_node(MAN_ARGS); 54322249Sbaptstatic int fillmode(struct html *, int); 55294113Sbaptstatic int a2width(const struct roff_node *, 56241675Suqs struct roffsu *); 57241675Suqsstatic int man_B_pre(MAN_ARGS); 58241675Suqsstatic int man_HP_pre(MAN_ARGS); 59241675Suqsstatic int man_IP_pre(MAN_ARGS); 60241675Suqsstatic int man_I_pre(MAN_ARGS); 61241675Suqsstatic int man_OP_pre(MAN_ARGS); 62241675Suqsstatic int man_PP_pre(MAN_ARGS); 63241675Suqsstatic int man_RS_pre(MAN_ARGS); 64241675Suqsstatic int man_SH_pre(MAN_ARGS); 65241675Suqsstatic int man_SM_pre(MAN_ARGS); 66241675Suqsstatic int man_SS_pre(MAN_ARGS); 67261344Suqsstatic int man_UR_pre(MAN_ARGS); 68241675Suqsstatic int man_alt_pre(MAN_ARGS); 69241675Suqsstatic int man_ign_pre(MAN_ARGS); 70241675Suqsstatic int man_in_pre(MAN_ARGS); 71241675Suqsstatic void man_root_post(MAN_ARGS); 72241675Suqsstatic void man_root_pre(MAN_ARGS); 73241675Suqs 74322249Sbaptstatic const struct htmlman __mans[MAN_MAX - MAN_TH] = { 75241675Suqs { NULL, NULL }, /* TH */ 76241675Suqs { man_SH_pre, NULL }, /* SH */ 77241675Suqs { man_SS_pre, NULL }, /* SS */ 78241675Suqs { man_IP_pre, NULL }, /* TP */ 79241675Suqs { man_PP_pre, NULL }, /* LP */ 80241675Suqs { man_PP_pre, NULL }, /* PP */ 81241675Suqs { man_PP_pre, NULL }, /* P */ 82241675Suqs { man_IP_pre, NULL }, /* IP */ 83274880Sbapt { man_HP_pre, NULL }, /* HP */ 84241675Suqs { man_SM_pre, NULL }, /* SM */ 85241675Suqs { man_SM_pre, NULL }, /* SB */ 86241675Suqs { man_alt_pre, NULL }, /* BI */ 87241675Suqs { man_alt_pre, NULL }, /* IB */ 88241675Suqs { man_alt_pre, NULL }, /* BR */ 89241675Suqs { man_alt_pre, NULL }, /* RB */ 90241675Suqs { NULL, NULL }, /* R */ 91241675Suqs { man_B_pre, NULL }, /* B */ 92241675Suqs { man_I_pre, NULL }, /* I */ 93241675Suqs { man_alt_pre, NULL }, /* IR */ 94241675Suqs { man_alt_pre, NULL }, /* RI */ 95322249Sbapt { NULL, NULL }, /* nf */ 96322249Sbapt { NULL, NULL }, /* fi */ 97241675Suqs { NULL, NULL }, /* RE */ 98241675Suqs { man_RS_pre, NULL }, /* RS */ 99241675Suqs { man_ign_pre, NULL }, /* DT */ 100241675Suqs { man_ign_pre, NULL }, /* UC */ 101241675Suqs { man_ign_pre, NULL }, /* PD */ 102241675Suqs { man_ign_pre, NULL }, /* AT */ 103241675Suqs { man_in_pre, NULL }, /* in */ 104241675Suqs { man_OP_pre, NULL }, /* OP */ 105322249Sbapt { NULL, NULL }, /* EX */ 106322249Sbapt { NULL, NULL }, /* EE */ 107261344Suqs { man_UR_pre, NULL }, /* UR */ 108261344Suqs { NULL, NULL }, /* UE */ 109322249Sbapt { man_UR_pre, NULL }, /* MT */ 110322249Sbapt { NULL, NULL }, /* ME */ 111241675Suqs}; 112322249Sbaptstatic const struct htmlman *const mans = __mans - MAN_TH; 113241675Suqs 114274880Sbapt 115241675Suqs/* 116241675Suqs * Printing leading vertical space before a block. 117241675Suqs * This is used for the paragraph macros. 118241675Suqs * The rules are pretty simple, since there's very little nesting going 119241675Suqs * on here. Basically, if we're the first within another block (SS/SH), 120241675Suqs * then don't emit vertical space. If we are (RS), then do. If not the 121241675Suqs * first, print it. 122241675Suqs */ 123241675Suqsstatic void 124294113Sbaptprint_bvspace(struct html *h, const struct roff_node *n) 125241675Suqs{ 126241675Suqs 127241675Suqs if (n->body && n->body->child) 128294113Sbapt if (n->body->child->type == ROFFT_TBL) 129241675Suqs return; 130241675Suqs 131294113Sbapt if (n->parent->type == ROFFT_ROOT || n->parent->tok != MAN_RS) 132241675Suqs if (NULL == n->prev) 133241675Suqs return; 134241675Suqs 135275432Sbapt print_paragraph(h); 136241675Suqs} 137241675Suqs 138241675Suqsvoid 139294113Sbapthtml_man(void *arg, const struct roff_man *man) 140241675Suqs{ 141294113Sbapt struct html *h; 142316420Sbapt struct tag *t; 143241675Suqs 144294113Sbapt h = (struct html *)arg; 145241675Suqs 146316420Sbapt if ((h->oflags & HTML_FRAGMENT) == 0) { 147241675Suqs print_gen_decls(h); 148316420Sbapt print_otag(h, TAG_HTML, ""); 149316420Sbapt t = print_otag(h, TAG_HEAD, ""); 150322249Sbapt print_man_head(&man->meta, man->first, h); 151316420Sbapt print_tagq(h, t); 152316420Sbapt print_otag(h, TAG_BODY, ""); 153316420Sbapt } 154241675Suqs 155322249Sbapt man_root_pre(&man->meta, man->first, h); 156316420Sbapt t = print_otag(h, TAG_DIV, "c", "manual-text"); 157322249Sbapt print_man_nodelist(&man->meta, man->first->child, h); 158241675Suqs print_tagq(h, t); 159322249Sbapt man_root_post(&man->meta, man->first, h); 160316420Sbapt print_tagq(h, NULL); 161241675Suqs} 162241675Suqs 163241675Suqsstatic void 164241675Suqsprint_man_head(MAN_ARGS) 165241675Suqs{ 166316420Sbapt char *cp; 167241675Suqs 168241675Suqs print_gen_head(h); 169316420Sbapt mandoc_asprintf(&cp, "%s(%s)", man->title, man->msec); 170316420Sbapt print_otag(h, TAG_TITLE, ""); 171316420Sbapt print_text(h, cp); 172316420Sbapt free(cp); 173241675Suqs} 174241675Suqs 175241675Suqsstatic void 176241675Suqsprint_man_nodelist(MAN_ARGS) 177241675Suqs{ 178241675Suqs 179279527Sbapt while (n != NULL) { 180322249Sbapt print_man_node(man, n, h); 181279527Sbapt n = n->next; 182279527Sbapt } 183241675Suqs} 184241675Suqs 185241675Suqsstatic void 186241675Suqsprint_man_node(MAN_ARGS) 187241675Suqs{ 188322249Sbapt static int want_fillmode = MAN_fi; 189322249Sbapt static int save_fillmode; 190322249Sbapt 191322249Sbapt struct tag *t; 192241675Suqs int child; 193241675Suqs 194322249Sbapt /* 195322249Sbapt * Handle fill mode switch requests up front, 196322249Sbapt * they would just cause trouble in the subsequent code. 197322249Sbapt */ 198241675Suqs 199322249Sbapt switch (n->tok) { 200322249Sbapt case MAN_nf: 201322249Sbapt case MAN_EX: 202322249Sbapt want_fillmode = MAN_nf; 203322249Sbapt return; 204322249Sbapt case MAN_fi: 205322249Sbapt case MAN_EE: 206322249Sbapt want_fillmode = MAN_fi; 207322249Sbapt if (fillmode(h, 0) == MAN_fi) 208322249Sbapt print_otag(h, TAG_BR, ""); 209322249Sbapt return; 210322249Sbapt default: 211322249Sbapt break; 212322249Sbapt } 213322249Sbapt 214322249Sbapt /* Set up fill mode for the upcoming node. */ 215322249Sbapt 216241675Suqs switch (n->type) { 217322249Sbapt case ROFFT_BLOCK: 218322249Sbapt save_fillmode = 0; 219322249Sbapt /* Some block macros suspend or cancel .nf. */ 220322249Sbapt switch (n->tok) { 221322249Sbapt case MAN_TP: /* Tagged paragraphs */ 222322249Sbapt case MAN_IP: /* temporarily disable .nf */ 223322249Sbapt case MAN_HP: /* for the head. */ 224322249Sbapt save_fillmode = want_fillmode; 225322249Sbapt /* FALLTHROUGH */ 226322249Sbapt case MAN_SH: /* Section headers */ 227322249Sbapt case MAN_SS: /* permanently cancel .nf. */ 228322249Sbapt want_fillmode = MAN_fi; 229322249Sbapt /* FALLTHROUGH */ 230322249Sbapt case MAN_PP: /* These have no head. */ 231322249Sbapt case MAN_LP: /* They will simply */ 232322249Sbapt case MAN_P: /* reopen .nf in the body. */ 233322249Sbapt case MAN_RS: 234322249Sbapt case MAN_UR: 235322249Sbapt case MAN_MT: 236322249Sbapt fillmode(h, MAN_fi); 237322249Sbapt break; 238322249Sbapt default: 239322249Sbapt break; 240322249Sbapt } 241322249Sbapt break; 242322249Sbapt case ROFFT_TBL: 243322249Sbapt fillmode(h, MAN_fi); 244322249Sbapt break; 245322249Sbapt case ROFFT_ELEM: 246322249Sbapt /* 247322249Sbapt * Some in-line macros produce tags and/or text 248322249Sbapt * in the handler, so they require fill mode to be 249322249Sbapt * configured up front just like for text nodes. 250322249Sbapt * For the others, keep the traditional approach 251322249Sbapt * of doing the same, for now. 252322249Sbapt */ 253322249Sbapt fillmode(h, want_fillmode); 254322249Sbapt break; 255294113Sbapt case ROFFT_TEXT: 256322249Sbapt if (fillmode(h, want_fillmode) == MAN_fi && 257322249Sbapt want_fillmode == MAN_fi && 258322249Sbapt n->flags & NODE_LINE && *n->string == ' ' && 259322249Sbapt (h->flags & HTML_NONEWLINE) == 0) 260316420Sbapt print_otag(h, TAG_BR, ""); 261322249Sbapt if (*n->string != '\0') 262322249Sbapt break; 263322249Sbapt print_paragraph(h); 264322249Sbapt return; 265322249Sbapt default: 266322249Sbapt break; 267322249Sbapt } 268322249Sbapt 269322249Sbapt /* Produce output for this node. */ 270322249Sbapt 271322249Sbapt child = 1; 272322249Sbapt switch (n->type) { 273322249Sbapt case ROFFT_TEXT: 274322249Sbapt t = h->tag; 275241675Suqs print_text(h, n->string); 276322249Sbapt break; 277294113Sbapt case ROFFT_EQN: 278322249Sbapt t = h->tag; 279241675Suqs print_eqn(h, n->eqn); 280241675Suqs break; 281294113Sbapt case ROFFT_TBL: 282241675Suqs /* 283241675Suqs * This will take care of initialising all of the table 284241675Suqs * state data for the first table, then tearing it down 285241675Suqs * for the last one. 286241675Suqs */ 287241675Suqs print_tbl(h, n->span); 288241675Suqs return; 289241675Suqs default: 290274880Sbapt /* 291241675Suqs * Close out scope of font prior to opening a macro 292241675Suqs * scope. 293241675Suqs */ 294241675Suqs if (HTMLFONT_NONE != h->metac) { 295241675Suqs h->metal = h->metac; 296241675Suqs h->metac = HTMLFONT_NONE; 297241675Suqs } 298241675Suqs 299241675Suqs /* 300241675Suqs * Close out the current table, if it's open, and unset 301241675Suqs * the "meta" table state. This will be reopened on the 302241675Suqs * next table element. 303241675Suqs */ 304322249Sbapt if (h->tblt) 305241675Suqs print_tblclose(h); 306322249Sbapt 307322249Sbapt t = h->tag; 308322249Sbapt if (n->tok < ROFF_MAX) { 309322249Sbapt roff_html_pre(h, n); 310322249Sbapt child = 0; 311322249Sbapt break; 312241675Suqs } 313322249Sbapt 314322249Sbapt assert(n->tok >= MAN_TH && n->tok < MAN_MAX); 315241675Suqs if (mans[n->tok].pre) 316322249Sbapt child = (*mans[n->tok].pre)(man, n, h); 317322249Sbapt 318322249Sbapt /* Some block macros resume .nf in the body. */ 319322249Sbapt if (save_fillmode && n->type == ROFFT_BODY) 320322249Sbapt want_fillmode = save_fillmode; 321322249Sbapt 322241675Suqs break; 323241675Suqs } 324241675Suqs 325241675Suqs if (child && n->child) 326322249Sbapt print_man_nodelist(man, n->child, h); 327241675Suqs 328241675Suqs /* This will automatically close out any font scope. */ 329241675Suqs print_stagq(h, t); 330241675Suqs 331322249Sbapt if (fillmode(h, 0) == MAN_nf && 332322249Sbapt n->next != NULL && n->next->flags & NODE_LINE) 333322249Sbapt print_endline(h); 334322249Sbapt} 335322249Sbapt 336322249Sbapt/* 337322249Sbapt * MAN_nf switches to no-fill mode, MAN_fi to fill mode. 338322249Sbapt * Other arguments do not switch. 339322249Sbapt * The old mode is returned. 340322249Sbapt */ 341322249Sbaptstatic int 342322249Sbaptfillmode(struct html *h, int want) 343322249Sbapt{ 344322249Sbapt struct tag *pre; 345322249Sbapt int had; 346322249Sbapt 347322249Sbapt for (pre = h->tag; pre != NULL; pre = pre->next) 348322249Sbapt if (pre->tag == TAG_PRE) 349322249Sbapt break; 350322249Sbapt 351322249Sbapt had = pre == NULL ? MAN_fi : MAN_nf; 352322249Sbapt 353322249Sbapt if (want && want != had) { 354322249Sbapt if (want == MAN_nf) 355322249Sbapt print_otag(h, TAG_PRE, ""); 356322249Sbapt else 357322249Sbapt print_tagq(h, pre); 358241675Suqs } 359322249Sbapt return had; 360241675Suqs} 361241675Suqs 362241675Suqsstatic int 363294113Sbapta2width(const struct roff_node *n, struct roffsu *su) 364241675Suqs{ 365294113Sbapt if (n->type != ROFFT_TEXT) 366294113Sbapt return 0; 367322249Sbapt return a2roffsu(n->string, su, SCALE_EN) != NULL; 368241675Suqs} 369241675Suqs 370241675Suqsstatic void 371241675Suqsman_root_pre(MAN_ARGS) 372241675Suqs{ 373241675Suqs struct tag *t, *tt; 374274880Sbapt char *title; 375241675Suqs 376261344Suqs assert(man->title); 377261344Suqs assert(man->msec); 378274880Sbapt mandoc_asprintf(&title, "%s(%s)", man->title, man->msec); 379241675Suqs 380316420Sbapt t = print_otag(h, TAG_TABLE, "c", "head"); 381316420Sbapt tt = print_otag(h, TAG_TR, ""); 382241675Suqs 383316420Sbapt print_otag(h, TAG_TD, "c", "head-ltitle"); 384241675Suqs print_text(h, title); 385241675Suqs print_stagq(h, tt); 386241675Suqs 387316420Sbapt print_otag(h, TAG_TD, "c", "head-vol"); 388274880Sbapt if (NULL != man->vol) 389274880Sbapt print_text(h, man->vol); 390241675Suqs print_stagq(h, tt); 391241675Suqs 392316420Sbapt print_otag(h, TAG_TD, "c", "head-rtitle"); 393241675Suqs print_text(h, title); 394241675Suqs print_tagq(h, t); 395274880Sbapt free(title); 396241675Suqs} 397241675Suqs 398241675Suqsstatic void 399241675Suqsman_root_post(MAN_ARGS) 400241675Suqs{ 401241675Suqs struct tag *t, *tt; 402241675Suqs 403316420Sbapt t = print_otag(h, TAG_TABLE, "c", "foot"); 404316420Sbapt tt = print_otag(h, TAG_TR, ""); 405241675Suqs 406316420Sbapt print_otag(h, TAG_TD, "c", "foot-date"); 407261344Suqs print_text(h, man->date); 408241675Suqs print_stagq(h, tt); 409241675Suqs 410316420Sbapt print_otag(h, TAG_TD, "c", "foot-os"); 411294113Sbapt if (man->os) 412294113Sbapt print_text(h, man->os); 413241675Suqs print_tagq(h, t); 414241675Suqs} 415241675Suqs 416241675Suqsstatic int 417241675Suqsman_SH_pre(MAN_ARGS) 418241675Suqs{ 419322249Sbapt char *id; 420241675Suqs 421322249Sbapt if (n->type == ROFFT_HEAD) { 422322249Sbapt id = html_make_id(n); 423322249Sbapt print_otag(h, TAG_H1, "cTi", "Sh", id); 424322249Sbapt if (id != NULL) 425322249Sbapt print_otag(h, TAG_A, "chR", "selflink", id); 426322249Sbapt free(id); 427322249Sbapt } 428294113Sbapt return 1; 429241675Suqs} 430241675Suqs 431241675Suqsstatic int 432241675Suqsman_alt_pre(MAN_ARGS) 433241675Suqs{ 434294113Sbapt const struct roff_node *nn; 435322249Sbapt int i; 436241675Suqs enum htmltag fp; 437241675Suqs struct tag *t; 438241675Suqs 439241675Suqs for (i = 0, nn = n->child; nn; nn = nn->next, i++) { 440241675Suqs switch (n->tok) { 441274880Sbapt case MAN_BI: 442241675Suqs fp = i % 2 ? TAG_I : TAG_B; 443241675Suqs break; 444274880Sbapt case MAN_IB: 445241675Suqs fp = i % 2 ? TAG_B : TAG_I; 446241675Suqs break; 447274880Sbapt case MAN_RI: 448241675Suqs fp = i % 2 ? TAG_I : TAG_MAX; 449241675Suqs break; 450274880Sbapt case MAN_IR: 451241675Suqs fp = i % 2 ? TAG_MAX : TAG_I; 452241675Suqs break; 453274880Sbapt case MAN_BR: 454241675Suqs fp = i % 2 ? TAG_MAX : TAG_B; 455241675Suqs break; 456274880Sbapt case MAN_RB: 457241675Suqs fp = i % 2 ? TAG_B : TAG_MAX; 458241675Suqs break; 459241675Suqs default: 460241675Suqs abort(); 461241675Suqs } 462241675Suqs 463241675Suqs if (i) 464241675Suqs h->flags |= HTML_NOSPACE; 465241675Suqs 466322249Sbapt if (fp != TAG_MAX) 467316420Sbapt t = print_otag(h, fp, ""); 468241675Suqs 469322249Sbapt print_text(h, nn->string); 470241675Suqs 471322249Sbapt if (fp != TAG_MAX) 472241675Suqs print_tagq(h, t); 473241675Suqs } 474294113Sbapt return 0; 475241675Suqs} 476241675Suqs 477241675Suqsstatic int 478241675Suqsman_SM_pre(MAN_ARGS) 479241675Suqs{ 480316420Sbapt print_otag(h, TAG_SMALL, ""); 481241675Suqs if (MAN_SB == n->tok) 482316420Sbapt print_otag(h, TAG_B, ""); 483294113Sbapt return 1; 484241675Suqs} 485241675Suqs 486241675Suqsstatic int 487241675Suqsman_SS_pre(MAN_ARGS) 488241675Suqs{ 489322249Sbapt char *id; 490241675Suqs 491322249Sbapt if (n->type == ROFFT_HEAD) { 492322249Sbapt id = html_make_id(n); 493322249Sbapt print_otag(h, TAG_H2, "cTi", "Ss", id); 494322249Sbapt if (id != NULL) 495322249Sbapt print_otag(h, TAG_A, "chR", "selflink", id); 496322249Sbapt free(id); 497322249Sbapt } 498294113Sbapt return 1; 499241675Suqs} 500241675Suqs 501241675Suqsstatic int 502241675Suqsman_PP_pre(MAN_ARGS) 503241675Suqs{ 504241675Suqs 505294113Sbapt if (n->type == ROFFT_HEAD) 506294113Sbapt return 0; 507294113Sbapt else if (n->type == ROFFT_BLOCK) 508241675Suqs print_bvspace(h, n); 509241675Suqs 510294113Sbapt return 1; 511241675Suqs} 512241675Suqs 513241675Suqsstatic int 514241675Suqsman_IP_pre(MAN_ARGS) 515241675Suqs{ 516294113Sbapt const struct roff_node *nn; 517241675Suqs 518294113Sbapt if (n->type == ROFFT_BODY) { 519316420Sbapt print_otag(h, TAG_DD, "c", "It-tag"); 520294113Sbapt return 1; 521294113Sbapt } else if (n->type != ROFFT_HEAD) { 522316420Sbapt print_otag(h, TAG_DL, "c", "Bl-tag"); 523294113Sbapt return 1; 524241675Suqs } 525241675Suqs 526241675Suqs /* FIXME: width specification. */ 527241675Suqs 528316420Sbapt print_otag(h, TAG_DT, "c", "It-tag"); 529241675Suqs 530241675Suqs /* For IP, only print the first header element. */ 531241675Suqs 532241675Suqs if (MAN_IP == n->tok && n->child) 533322249Sbapt print_man_node(man, n->child, h); 534241675Suqs 535241675Suqs /* For TP, only print next-line header elements. */ 536241675Suqs 537274880Sbapt if (MAN_TP == n->tok) { 538274880Sbapt nn = n->child; 539316420Sbapt while (NULL != nn && 0 == (NODE_LINE & nn->flags)) 540274880Sbapt nn = nn->next; 541274880Sbapt while (NULL != nn) { 542322249Sbapt print_man_node(man, nn, h); 543274880Sbapt nn = nn->next; 544274880Sbapt } 545274880Sbapt } 546241675Suqs 547294113Sbapt return 0; 548241675Suqs} 549241675Suqs 550241675Suqsstatic int 551241675Suqsman_HP_pre(MAN_ARGS) 552241675Suqs{ 553316420Sbapt struct roffsu sum, sui; 554294113Sbapt const struct roff_node *np; 555241675Suqs 556294113Sbapt if (n->type == ROFFT_HEAD) 557294113Sbapt return 0; 558294113Sbapt else if (n->type != ROFFT_BLOCK) 559294113Sbapt return 1; 560241675Suqs 561241675Suqs np = n->head->child; 562241675Suqs 563316420Sbapt if (np == NULL || !a2width(np, &sum)) 564316420Sbapt SCALE_HS_INIT(&sum, INDENT); 565241675Suqs 566316420Sbapt sui.unit = sum.unit; 567316420Sbapt sui.scale = -sum.scale; 568241675Suqs 569241675Suqs print_bvspace(h, n); 570316420Sbapt print_otag(h, TAG_DIV, "csului", "Pp", &sum, &sui); 571294113Sbapt return 1; 572241675Suqs} 573241675Suqs 574241675Suqsstatic int 575241675Suqsman_OP_pre(MAN_ARGS) 576241675Suqs{ 577241675Suqs struct tag *tt; 578241675Suqs 579241675Suqs print_text(h, "["); 580241675Suqs h->flags |= HTML_NOSPACE; 581316420Sbapt tt = print_otag(h, TAG_SPAN, "c", "Op"); 582241675Suqs 583241675Suqs if (NULL != (n = n->child)) { 584316420Sbapt print_otag(h, TAG_B, ""); 585241675Suqs print_text(h, n->string); 586241675Suqs } 587241675Suqs 588241675Suqs print_stagq(h, tt); 589241675Suqs 590241675Suqs if (NULL != n && NULL != n->next) { 591316420Sbapt print_otag(h, TAG_I, ""); 592241675Suqs print_text(h, n->next->string); 593241675Suqs } 594241675Suqs 595241675Suqs print_stagq(h, tt); 596241675Suqs h->flags |= HTML_NOSPACE; 597241675Suqs print_text(h, "]"); 598294113Sbapt return 0; 599241675Suqs} 600241675Suqs 601241675Suqsstatic int 602241675Suqsman_B_pre(MAN_ARGS) 603241675Suqs{ 604316420Sbapt print_otag(h, TAG_B, ""); 605294113Sbapt return 1; 606241675Suqs} 607241675Suqs 608241675Suqsstatic int 609241675Suqsman_I_pre(MAN_ARGS) 610241675Suqs{ 611316420Sbapt print_otag(h, TAG_I, ""); 612294113Sbapt return 1; 613241675Suqs} 614241675Suqs 615241675Suqsstatic int 616241675Suqsman_in_pre(MAN_ARGS) 617241675Suqs{ 618316420Sbapt print_otag(h, TAG_BR, ""); 619294113Sbapt return 0; 620241675Suqs} 621241675Suqs 622241675Suqsstatic int 623241675Suqsman_ign_pre(MAN_ARGS) 624241675Suqs{ 625241675Suqs 626294113Sbapt return 0; 627241675Suqs} 628241675Suqs 629241675Suqsstatic int 630241675Suqsman_RS_pre(MAN_ARGS) 631241675Suqs{ 632241675Suqs struct roffsu su; 633241675Suqs 634294113Sbapt if (n->type == ROFFT_HEAD) 635294113Sbapt return 0; 636294113Sbapt else if (n->type == ROFFT_BODY) 637294113Sbapt return 1; 638241675Suqs 639241675Suqs SCALE_HS_INIT(&su, INDENT); 640241675Suqs if (n->head->child) 641241675Suqs a2width(n->head->child, &su); 642241675Suqs 643316420Sbapt print_otag(h, TAG_DIV, "sul", &su); 644294113Sbapt return 1; 645241675Suqs} 646261344Suqs 647261344Suqsstatic int 648261344Suqsman_UR_pre(MAN_ARGS) 649261344Suqs{ 650322249Sbapt char *cp; 651261344Suqs n = n->child; 652294113Sbapt assert(n->type == ROFFT_HEAD); 653294113Sbapt if (n->child != NULL) { 654294113Sbapt assert(n->child->type == ROFFT_TEXT); 655322249Sbapt if (n->tok == MAN_MT) { 656322249Sbapt mandoc_asprintf(&cp, "mailto:%s", n->child->string); 657322249Sbapt print_otag(h, TAG_A, "cTh", "Mt", cp); 658322249Sbapt free(cp); 659322249Sbapt } else 660322249Sbapt print_otag(h, TAG_A, "cTh", "Lk", n->child->string); 661261344Suqs } 662261344Suqs 663294113Sbapt assert(n->next->type == ROFFT_BODY); 664294113Sbapt if (n->next->child != NULL) 665261344Suqs n = n->next; 666261344Suqs 667322249Sbapt print_man_nodelist(man, n->child, h); 668261344Suqs 669294113Sbapt return 0; 670261344Suqs} 671