1 /* $Vendor-Id: mdoc_html.c,v 1.179 2011/10/05 21:35:17 kristaps Exp $ */ 2 /* 3 * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 #ifdef HAVE_CONFIG_H 18 #include "config.h" 19 #endif 20 21 #include <sys/types.h> 22 23 #include <assert.h> 24 #include <ctype.h> 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <string.h> 28 #include <unistd.h> 29 30 #include "mandoc.h" 31 #include "out.h" 32 #include "html.h" 33 #include "mdoc.h" 34 #include "main.h" 35 36 #define INDENT 5 37 38 #define MDOC_ARGS const struct mdoc_meta *m, \ 39 const struct mdoc_node *n, \ 40 struct html *h 41 42 #ifndef MIN 43 #define MIN(a,b) ((/*CONSTCOND*/(a)<(b))?(a):(b)) 44 #endif 45 46 struct htmlmdoc { 47 int (*pre)(MDOC_ARGS); 48 void (*post)(MDOC_ARGS); 49 }; 50 51 static void print_mdoc(MDOC_ARGS); 52 static void print_mdoc_head(MDOC_ARGS); 53 static void print_mdoc_node(MDOC_ARGS); 54 static void print_mdoc_nodelist(MDOC_ARGS); 55 static void synopsis_pre(struct html *, 56 const struct mdoc_node *); 57 58 static void a2width(const char *, struct roffsu *); 59 static void a2offs(const char *, struct roffsu *); 60 61 static void mdoc_root_post(MDOC_ARGS); 62 static int mdoc_root_pre(MDOC_ARGS); 63 64 static void mdoc__x_post(MDOC_ARGS); 65 static int mdoc__x_pre(MDOC_ARGS); 66 static int mdoc_ad_pre(MDOC_ARGS); 67 static int mdoc_an_pre(MDOC_ARGS); 68 static int mdoc_ap_pre(MDOC_ARGS); 69 static int mdoc_ar_pre(MDOC_ARGS); 70 static int mdoc_bd_pre(MDOC_ARGS); 71 static int mdoc_bf_pre(MDOC_ARGS); 72 static void mdoc_bk_post(MDOC_ARGS); 73 static int mdoc_bk_pre(MDOC_ARGS); 74 static int mdoc_bl_pre(MDOC_ARGS); 75 static int mdoc_bt_pre(MDOC_ARGS); 76 static int mdoc_bx_pre(MDOC_ARGS); 77 static int mdoc_cd_pre(MDOC_ARGS); 78 static int mdoc_d1_pre(MDOC_ARGS); 79 static int mdoc_dv_pre(MDOC_ARGS); 80 static int mdoc_fa_pre(MDOC_ARGS); 81 static int mdoc_fd_pre(MDOC_ARGS); 82 static int mdoc_fl_pre(MDOC_ARGS); 83 static int mdoc_fn_pre(MDOC_ARGS); 84 static int mdoc_ft_pre(MDOC_ARGS); 85 static int mdoc_em_pre(MDOC_ARGS); 86 static int mdoc_er_pre(MDOC_ARGS); 87 static int mdoc_ev_pre(MDOC_ARGS); 88 static int mdoc_ex_pre(MDOC_ARGS); 89 static void mdoc_fo_post(MDOC_ARGS); 90 static int mdoc_fo_pre(MDOC_ARGS); 91 static int mdoc_ic_pre(MDOC_ARGS); 92 static int mdoc_igndelim_pre(MDOC_ARGS); 93 static int mdoc_in_pre(MDOC_ARGS); 94 static int mdoc_it_pre(MDOC_ARGS); 95 static int mdoc_lb_pre(MDOC_ARGS); 96 static int mdoc_li_pre(MDOC_ARGS); 97 static int mdoc_lk_pre(MDOC_ARGS); 98 static int mdoc_mt_pre(MDOC_ARGS); 99 static int mdoc_ms_pre(MDOC_ARGS); 100 static int mdoc_nd_pre(MDOC_ARGS); 101 static int mdoc_nm_pre(MDOC_ARGS); 102 static int mdoc_ns_pre(MDOC_ARGS); 103 static int mdoc_pa_pre(MDOC_ARGS); 104 static void mdoc_pf_post(MDOC_ARGS); 105 static int mdoc_pp_pre(MDOC_ARGS); 106 static void mdoc_quote_post(MDOC_ARGS); 107 static int mdoc_quote_pre(MDOC_ARGS); 108 static int mdoc_rs_pre(MDOC_ARGS); 109 static int mdoc_rv_pre(MDOC_ARGS); 110 static int mdoc_sh_pre(MDOC_ARGS); 111 static int mdoc_sm_pre(MDOC_ARGS); 112 static int mdoc_sp_pre(MDOC_ARGS); 113 static int mdoc_ss_pre(MDOC_ARGS); 114 static int mdoc_sx_pre(MDOC_ARGS); 115 static int mdoc_sy_pre(MDOC_ARGS); 116 static int mdoc_ud_pre(MDOC_ARGS); 117 static int mdoc_va_pre(MDOC_ARGS); 118 static int mdoc_vt_pre(MDOC_ARGS); 119 static int mdoc_xr_pre(MDOC_ARGS); 120 static int mdoc_xx_pre(MDOC_ARGS); 121 122 static const struct htmlmdoc mdocs[MDOC_MAX] = { 123 {mdoc_ap_pre, NULL}, /* Ap */ 124 {NULL, NULL}, /* Dd */ 125 {NULL, NULL}, /* Dt */ 126 {NULL, NULL}, /* Os */ 127 {mdoc_sh_pre, NULL }, /* Sh */ 128 {mdoc_ss_pre, NULL }, /* Ss */ 129 {mdoc_pp_pre, NULL}, /* Pp */ 130 {mdoc_d1_pre, NULL}, /* D1 */ 131 {mdoc_d1_pre, NULL}, /* Dl */ 132 {mdoc_bd_pre, NULL}, /* Bd */ 133 {NULL, NULL}, /* Ed */ 134 {mdoc_bl_pre, NULL}, /* Bl */ 135 {NULL, NULL}, /* El */ 136 {mdoc_it_pre, NULL}, /* It */ 137 {mdoc_ad_pre, NULL}, /* Ad */ 138 {mdoc_an_pre, NULL}, /* An */ 139 {mdoc_ar_pre, NULL}, /* Ar */ 140 {mdoc_cd_pre, NULL}, /* Cd */ 141 {mdoc_fl_pre, NULL}, /* Cm */ 142 {mdoc_dv_pre, NULL}, /* Dv */ 143 {mdoc_er_pre, NULL}, /* Er */ 144 {mdoc_ev_pre, NULL}, /* Ev */ 145 {mdoc_ex_pre, NULL}, /* Ex */ 146 {mdoc_fa_pre, NULL}, /* Fa */ 147 {mdoc_fd_pre, NULL}, /* Fd */ 148 {mdoc_fl_pre, NULL}, /* Fl */ 149 {mdoc_fn_pre, NULL}, /* Fn */ 150 {mdoc_ft_pre, NULL}, /* Ft */ 151 {mdoc_ic_pre, NULL}, /* Ic */ 152 {mdoc_in_pre, NULL}, /* In */ 153 {mdoc_li_pre, NULL}, /* Li */ 154 {mdoc_nd_pre, NULL}, /* Nd */ 155 {mdoc_nm_pre, NULL}, /* Nm */ 156 {mdoc_quote_pre, mdoc_quote_post}, /* Op */ 157 {NULL, NULL}, /* Ot */ 158 {mdoc_pa_pre, NULL}, /* Pa */ 159 {mdoc_rv_pre, NULL}, /* Rv */ 160 {NULL, NULL}, /* St */ 161 {mdoc_va_pre, NULL}, /* Va */ 162 {mdoc_vt_pre, NULL}, /* Vt */ 163 {mdoc_xr_pre, NULL}, /* Xr */ 164 {mdoc__x_pre, mdoc__x_post}, /* %A */ 165 {mdoc__x_pre, mdoc__x_post}, /* %B */ 166 {mdoc__x_pre, mdoc__x_post}, /* %D */ 167 {mdoc__x_pre, mdoc__x_post}, /* %I */ 168 {mdoc__x_pre, mdoc__x_post}, /* %J */ 169 {mdoc__x_pre, mdoc__x_post}, /* %N */ 170 {mdoc__x_pre, mdoc__x_post}, /* %O */ 171 {mdoc__x_pre, mdoc__x_post}, /* %P */ 172 {mdoc__x_pre, mdoc__x_post}, /* %R */ 173 {mdoc__x_pre, mdoc__x_post}, /* %T */ 174 {mdoc__x_pre, mdoc__x_post}, /* %V */ 175 {NULL, NULL}, /* Ac */ 176 {mdoc_quote_pre, mdoc_quote_post}, /* Ao */ 177 {mdoc_quote_pre, mdoc_quote_post}, /* Aq */ 178 {NULL, NULL}, /* At */ 179 {NULL, NULL}, /* Bc */ 180 {mdoc_bf_pre, NULL}, /* Bf */ 181 {mdoc_quote_pre, mdoc_quote_post}, /* Bo */ 182 {mdoc_quote_pre, mdoc_quote_post}, /* Bq */ 183 {mdoc_xx_pre, NULL}, /* Bsx */ 184 {mdoc_bx_pre, NULL}, /* Bx */ 185 {NULL, NULL}, /* Db */ 186 {NULL, NULL}, /* Dc */ 187 {mdoc_quote_pre, mdoc_quote_post}, /* Do */ 188 {mdoc_quote_pre, mdoc_quote_post}, /* Dq */ 189 {NULL, NULL}, /* Ec */ /* FIXME: no space */ 190 {NULL, NULL}, /* Ef */ 191 {mdoc_em_pre, NULL}, /* Em */ 192 {NULL, NULL}, /* Eo */ 193 {mdoc_xx_pre, NULL}, /* Fx */ 194 {mdoc_ms_pre, NULL}, /* Ms */ 195 {mdoc_igndelim_pre, NULL}, /* No */ 196 {mdoc_ns_pre, NULL}, /* Ns */ 197 {mdoc_xx_pre, NULL}, /* Nx */ 198 {mdoc_xx_pre, NULL}, /* Ox */ 199 {NULL, NULL}, /* Pc */ 200 {mdoc_igndelim_pre, mdoc_pf_post}, /* Pf */ 201 {mdoc_quote_pre, mdoc_quote_post}, /* Po */ 202 {mdoc_quote_pre, mdoc_quote_post}, /* Pq */ 203 {NULL, NULL}, /* Qc */ 204 {mdoc_quote_pre, mdoc_quote_post}, /* Ql */ 205 {mdoc_quote_pre, mdoc_quote_post}, /* Qo */ 206 {mdoc_quote_pre, mdoc_quote_post}, /* Qq */ 207 {NULL, NULL}, /* Re */ 208 {mdoc_rs_pre, NULL}, /* Rs */ 209 {NULL, NULL}, /* Sc */ 210 {mdoc_quote_pre, mdoc_quote_post}, /* So */ 211 {mdoc_quote_pre, mdoc_quote_post}, /* Sq */ 212 {mdoc_sm_pre, NULL}, /* Sm */ 213 {mdoc_sx_pre, NULL}, /* Sx */ 214 {mdoc_sy_pre, NULL}, /* Sy */ 215 {NULL, NULL}, /* Tn */ 216 {mdoc_xx_pre, NULL}, /* Ux */ 217 {NULL, NULL}, /* Xc */ 218 {NULL, NULL}, /* Xo */ 219 {mdoc_fo_pre, mdoc_fo_post}, /* Fo */ 220 {NULL, NULL}, /* Fc */ 221 {mdoc_quote_pre, mdoc_quote_post}, /* Oo */ 222 {NULL, NULL}, /* Oc */ 223 {mdoc_bk_pre, mdoc_bk_post}, /* Bk */ 224 {NULL, NULL}, /* Ek */ 225 {mdoc_bt_pre, NULL}, /* Bt */ 226 {NULL, NULL}, /* Hf */ 227 {NULL, NULL}, /* Fr */ 228 {mdoc_ud_pre, NULL}, /* Ud */ 229 {mdoc_lb_pre, NULL}, /* Lb */ 230 {mdoc_pp_pre, NULL}, /* Lp */ 231 {mdoc_lk_pre, NULL}, /* Lk */ 232 {mdoc_mt_pre, NULL}, /* Mt */ 233 {mdoc_quote_pre, mdoc_quote_post}, /* Brq */ 234 {mdoc_quote_pre, mdoc_quote_post}, /* Bro */ 235 {NULL, NULL}, /* Brc */ 236 {mdoc__x_pre, mdoc__x_post}, /* %C */ 237 {NULL, NULL}, /* Es */ /* TODO */ 238 {NULL, NULL}, /* En */ /* TODO */ 239 {mdoc_xx_pre, NULL}, /* Dx */ 240 {mdoc__x_pre, mdoc__x_post}, /* %Q */ 241 {mdoc_sp_pre, NULL}, /* br */ 242 {mdoc_sp_pre, NULL}, /* sp */ 243 {mdoc__x_pre, mdoc__x_post}, /* %U */ 244 {NULL, NULL}, /* Ta */ 245 }; 246 247 static const char * const lists[LIST_MAX] = { 248 NULL, 249 "list-bul", 250 "list-col", 251 "list-dash", 252 "list-diag", 253 "list-enum", 254 "list-hang", 255 "list-hyph", 256 "list-inset", 257 "list-item", 258 "list-ohang", 259 "list-tag" 260 }; 261 262 void 263 html_mdoc(void *arg, const struct mdoc *m) 264 { 265 266 print_mdoc(mdoc_meta(m), mdoc_node(m), (struct html *)arg); 267 putchar('\n'); 268 } 269 270 271 /* 272 * Calculate the scaling unit passed in a `-width' argument. This uses 273 * either a native scaling unit (e.g., 1i, 2m) or the string length of 274 * the value. 275 */ 276 static void 277 a2width(const char *p, struct roffsu *su) 278 { 279 280 if ( ! a2roffsu(p, su, SCALE_MAX)) { 281 su->unit = SCALE_BU; 282 su->scale = html_strlen(p); 283 } 284 } 285 286 287 /* 288 * See the same function in mdoc_term.c for documentation. 289 */ 290 static void 291 synopsis_pre(struct html *h, const struct mdoc_node *n) 292 { 293 294 if (NULL == n->prev || ! (MDOC_SYNPRETTY & n->flags)) 295 return; 296 297 if (n->prev->tok == n->tok && 298 MDOC_Fo != n->tok && 299 MDOC_Ft != n->tok && 300 MDOC_Fn != n->tok) { 301 print_otag(h, TAG_BR, 0, NULL); 302 return; 303 } 304 305 switch (n->prev->tok) { 306 case (MDOC_Fd): 307 /* FALLTHROUGH */ 308 case (MDOC_Fn): 309 /* FALLTHROUGH */ 310 case (MDOC_Fo): 311 /* FALLTHROUGH */ 312 case (MDOC_In): 313 /* FALLTHROUGH */ 314 case (MDOC_Vt): 315 print_otag(h, TAG_P, 0, NULL); 316 break; 317 case (MDOC_Ft): 318 if (MDOC_Fn != n->tok && MDOC_Fo != n->tok) { 319 print_otag(h, TAG_P, 0, NULL); 320 break; 321 } 322 /* FALLTHROUGH */ 323 default: 324 print_otag(h, TAG_BR, 0, NULL); 325 break; 326 } 327 } 328 329 330 /* 331 * Calculate the scaling unit passed in an `-offset' argument. This 332 * uses either a native scaling unit (e.g., 1i, 2m), one of a set of 333 * predefined strings (indent, etc.), or the string length of the value. 334 */ 335 static void 336 a2offs(const char *p, struct roffsu *su) 337 { 338 339 /* FIXME: "right"? */ 340 341 if (0 == strcmp(p, "left")) 342 SCALE_HS_INIT(su, 0); 343 else if (0 == strcmp(p, "indent")) 344 SCALE_HS_INIT(su, INDENT); 345 else if (0 == strcmp(p, "indent-two")) 346 SCALE_HS_INIT(su, INDENT * 2); 347 else if ( ! a2roffsu(p, su, SCALE_MAX)) 348 SCALE_HS_INIT(su, html_strlen(p)); 349 } 350 351 352 static void 353 print_mdoc(MDOC_ARGS) 354 { 355 struct tag *t, *tt; 356 struct htmlpair tag; 357 358 PAIR_CLASS_INIT(&tag, "mandoc"); 359 360 if ( ! (HTML_FRAGMENT & h->oflags)) { 361 print_gen_decls(h); 362 t = print_otag(h, TAG_HTML, 0, NULL); 363 tt = print_otag(h, TAG_HEAD, 0, NULL); 364 print_mdoc_head(m, n, h); 365 print_tagq(h, tt); 366 print_otag(h, TAG_BODY, 0, NULL); 367 print_otag(h, TAG_DIV, 1, &tag); 368 } else 369 t = print_otag(h, TAG_DIV, 1, &tag); 370 371 print_mdoc_nodelist(m, n, h); 372 print_tagq(h, t); 373 } 374 375 376 /* ARGSUSED */ 377 static void 378 print_mdoc_head(MDOC_ARGS) 379 { 380 381 print_gen_head(h); 382 bufinit(h); 383 bufcat_fmt(h, "%s(%s)", m->title, m->msec); 384 385 if (m->arch) 386 bufcat_fmt(h, " (%s)", m->arch); 387 388 print_otag(h, TAG_TITLE, 0, NULL); 389 print_text(h, h->buf); 390 } 391 392 393 static void 394 print_mdoc_nodelist(MDOC_ARGS) 395 { 396 397 print_mdoc_node(m, n, h); 398 if (n->next) 399 print_mdoc_nodelist(m, n->next, h); 400 } 401 402 403 static void 404 print_mdoc_node(MDOC_ARGS) 405 { 406 int child; 407 struct tag *t; 408 409 child = 1; 410 t = h->tags.head; 411 412 switch (n->type) { 413 case (MDOC_ROOT): 414 child = mdoc_root_pre(m, n, h); 415 break; 416 case (MDOC_TEXT): 417 /* No tables in this mode... */ 418 assert(NULL == h->tblt); 419 420 /* 421 * Make sure that if we're in a literal mode already 422 * (i.e., within a <PRE>) don't print the newline. 423 */ 424 if (' ' == *n->string && MDOC_LINE & n->flags) 425 if ( ! (HTML_LITERAL & h->flags)) 426 print_otag(h, TAG_BR, 0, NULL); 427 if (MDOC_DELIMC & n->flags) 428 h->flags |= HTML_NOSPACE; 429 print_text(h, n->string); 430 if (MDOC_DELIMO & n->flags) 431 h->flags |= HTML_NOSPACE; 432 return; 433 case (MDOC_EQN): 434 print_eqn(h, n->eqn); 435 break; 436 case (MDOC_TBL): 437 /* 438 * This will take care of initialising all of the table 439 * state data for the first table, then tearing it down 440 * for the last one. 441 */ 442 print_tbl(h, n->span); 443 return; 444 default: 445 /* 446 * Close out the current table, if it's open, and unset 447 * the "meta" table state. This will be reopened on the 448 * next table element. 449 */ 450 if (h->tblt) { 451 print_tblclose(h); 452 t = h->tags.head; 453 } 454 455 assert(NULL == h->tblt); 456 if (mdocs[n->tok].pre && ENDBODY_NOT == n->end) 457 child = (*mdocs[n->tok].pre)(m, n, h); 458 break; 459 } 460 461 if (HTML_KEEP & h->flags) { 462 if (n->prev && n->prev->line != n->line) { 463 h->flags &= ~HTML_KEEP; 464 h->flags |= HTML_PREKEEP; 465 } else if (NULL == n->prev) { 466 if (n->parent && n->parent->line != n->line) { 467 h->flags &= ~HTML_KEEP; 468 h->flags |= HTML_PREKEEP; 469 } 470 } 471 } 472 473 if (child && n->child) 474 print_mdoc_nodelist(m, n->child, h); 475 476 print_stagq(h, t); 477 478 switch (n->type) { 479 case (MDOC_ROOT): 480 mdoc_root_post(m, n, h); 481 break; 482 case (MDOC_EQN): 483 break; 484 default: 485 if (mdocs[n->tok].post && ENDBODY_NOT == n->end) 486 (*mdocs[n->tok].post)(m, n, h); 487 break; 488 } 489 } 490 491 /* ARGSUSED */ 492 static void 493 mdoc_root_post(MDOC_ARGS) 494 { 495 struct htmlpair tag[3]; 496 struct tag *t, *tt; 497 498 PAIR_SUMMARY_INIT(&tag[0], "Document Footer"); 499 PAIR_CLASS_INIT(&tag[1], "foot"); 500 if (NULL == h->style) { 501 PAIR_INIT(&tag[2], ATTR_WIDTH, "100%"); 502 t = print_otag(h, TAG_TABLE, 3, tag); 503 PAIR_INIT(&tag[0], ATTR_WIDTH, "50%"); 504 print_otag(h, TAG_COL, 1, tag); 505 print_otag(h, TAG_COL, 1, tag); 506 } else 507 t = print_otag(h, TAG_TABLE, 2, tag); 508 509 t = print_otag(h, TAG_TBODY, 0, NULL); 510 511 tt = print_otag(h, TAG_TR, 0, NULL); 512 513 PAIR_CLASS_INIT(&tag[0], "foot-date"); 514 print_otag(h, TAG_TD, 1, tag); 515 516 print_text(h, m->date); 517 print_stagq(h, tt); 518 519 PAIR_CLASS_INIT(&tag[0], "foot-os"); 520 if (NULL == h->style) { 521 PAIR_INIT(&tag[1], ATTR_ALIGN, "right"); 522 print_otag(h, TAG_TD, 2, tag); 523 } else 524 print_otag(h, TAG_TD, 1, tag); 525 526 print_text(h, m->os); 527 print_tagq(h, t); 528 } 529 530 531 /* ARGSUSED */ 532 static int 533 mdoc_root_pre(MDOC_ARGS) 534 { 535 struct htmlpair tag[3]; 536 struct tag *t, *tt; 537 char b[BUFSIZ], title[BUFSIZ]; 538 539 strlcpy(b, m->vol, BUFSIZ); 540 541 if (m->arch) { 542 strlcat(b, " (", BUFSIZ); 543 strlcat(b, m->arch, BUFSIZ); 544 strlcat(b, ")", BUFSIZ); 545 } 546 547 snprintf(title, BUFSIZ - 1, "%s(%s)", m->title, m->msec); 548 549 PAIR_SUMMARY_INIT(&tag[0], "Document Header"); 550 PAIR_CLASS_INIT(&tag[1], "head"); 551 if (NULL == h->style) { 552 PAIR_INIT(&tag[2], ATTR_WIDTH, "100%"); 553 t = print_otag(h, TAG_TABLE, 3, tag); 554 PAIR_INIT(&tag[0], ATTR_WIDTH, "30%"); 555 print_otag(h, TAG_COL, 1, tag); 556 print_otag(h, TAG_COL, 1, tag); 557 print_otag(h, TAG_COL, 1, tag); 558 } else 559 t = print_otag(h, TAG_TABLE, 2, tag); 560 561 print_otag(h, TAG_TBODY, 0, NULL); 562 563 tt = print_otag(h, TAG_TR, 0, NULL); 564 565 PAIR_CLASS_INIT(&tag[0], "head-ltitle"); 566 print_otag(h, TAG_TD, 1, tag); 567 568 print_text(h, title); 569 print_stagq(h, tt); 570 571 PAIR_CLASS_INIT(&tag[0], "head-vol"); 572 if (NULL == h->style) { 573 PAIR_INIT(&tag[1], ATTR_ALIGN, "center"); 574 print_otag(h, TAG_TD, 2, tag); 575 } else 576 print_otag(h, TAG_TD, 1, tag); 577 578 print_text(h, b); 579 print_stagq(h, tt); 580 581 PAIR_CLASS_INIT(&tag[0], "head-rtitle"); 582 if (NULL == h->style) { 583 PAIR_INIT(&tag[1], ATTR_ALIGN, "right"); 584 print_otag(h, TAG_TD, 2, tag); 585 } else 586 print_otag(h, TAG_TD, 1, tag); 587 588 print_text(h, title); 589 print_tagq(h, t); 590 return(1); 591 } 592 593 594 /* ARGSUSED */ 595 static int 596 mdoc_sh_pre(MDOC_ARGS) 597 { 598 struct htmlpair tag; 599 600 if (MDOC_BLOCK == n->type) { 601 PAIR_CLASS_INIT(&tag, "section"); 602 print_otag(h, TAG_DIV, 1, &tag); 603 return(1); 604 } else if (MDOC_BODY == n->type) 605 return(1); 606 607 bufinit(h); 608 bufcat(h, "x"); 609 610 for (n = n->child; n && MDOC_TEXT == n->type; ) { 611 bufcat_id(h, n->string); 612 if (NULL != (n = n->next)) 613 bufcat_id(h, " "); 614 } 615 616 if (NULL == n) { 617 PAIR_ID_INIT(&tag, h->buf); 618 print_otag(h, TAG_H1, 1, &tag); 619 } else 620 print_otag(h, TAG_H1, 0, NULL); 621 622 return(1); 623 } 624 625 /* ARGSUSED */ 626 static int 627 mdoc_ss_pre(MDOC_ARGS) 628 { 629 struct htmlpair tag; 630 631 if (MDOC_BLOCK == n->type) { 632 PAIR_CLASS_INIT(&tag, "subsection"); 633 print_otag(h, TAG_DIV, 1, &tag); 634 return(1); 635 } else if (MDOC_BODY == n->type) 636 return(1); 637 638 bufinit(h); 639 bufcat(h, "x"); 640 641 for (n = n->child; n && MDOC_TEXT == n->type; ) { 642 bufcat_id(h, n->string); 643 if (NULL != (n = n->next)) 644 bufcat_id(h, " "); 645 } 646 647 if (NULL == n) { 648 PAIR_ID_INIT(&tag, h->buf); 649 print_otag(h, TAG_H2, 1, &tag); 650 } else 651 print_otag(h, TAG_H2, 0, NULL); 652 653 return(1); 654 } 655 656 657 /* ARGSUSED */ 658 static int 659 mdoc_fl_pre(MDOC_ARGS) 660 { 661 struct htmlpair tag; 662 663 PAIR_CLASS_INIT(&tag, "flag"); 664 print_otag(h, TAG_B, 1, &tag); 665 666 /* `Cm' has no leading hyphen. */ 667 668 if (MDOC_Cm == n->tok) 669 return(1); 670 671 print_text(h, "\\-"); 672 673 if (n->child) 674 h->flags |= HTML_NOSPACE; 675 else if (n->next && n->next->line == n->line) 676 h->flags |= HTML_NOSPACE; 677 678 return(1); 679 } 680 681 682 /* ARGSUSED */ 683 static int 684 mdoc_nd_pre(MDOC_ARGS) 685 { 686 struct htmlpair tag; 687 688 if (MDOC_BODY != n->type) 689 return(1); 690 691 /* XXX: this tag in theory can contain block elements. */ 692 693 print_text(h, "\\(em"); 694 PAIR_CLASS_INIT(&tag, "desc"); 695 print_otag(h, TAG_SPAN, 1, &tag); 696 return(1); 697 } 698 699 700 static int 701 mdoc_nm_pre(MDOC_ARGS) 702 { 703 struct htmlpair tag; 704 struct roffsu su; 705 int len; 706 707 switch (n->type) { 708 case (MDOC_ELEM): 709 synopsis_pre(h, n); 710 PAIR_CLASS_INIT(&tag, "name"); 711 print_otag(h, TAG_B, 1, &tag); 712 if (NULL == n->child && m->name) 713 print_text(h, m->name); 714 return(1); 715 case (MDOC_HEAD): 716 print_otag(h, TAG_TD, 0, NULL); 717 if (NULL == n->child && m->name) 718 print_text(h, m->name); 719 return(1); 720 case (MDOC_BODY): 721 print_otag(h, TAG_TD, 0, NULL); 722 return(1); 723 default: 724 break; 725 } 726 727 synopsis_pre(h, n); 728 PAIR_CLASS_INIT(&tag, "synopsis"); 729 print_otag(h, TAG_TABLE, 1, &tag); 730 731 for (len = 0, n = n->child; n; n = n->next) 732 if (MDOC_TEXT == n->type) 733 len += html_strlen(n->string); 734 735 if (0 == len && m->name) 736 len = html_strlen(m->name); 737 738 SCALE_HS_INIT(&su, (double)len); 739 bufinit(h); 740 bufcat_su(h, "width", &su); 741 PAIR_STYLE_INIT(&tag, h); 742 print_otag(h, TAG_COL, 1, &tag); 743 print_otag(h, TAG_COL, 0, NULL); 744 print_otag(h, TAG_TBODY, 0, NULL); 745 print_otag(h, TAG_TR, 0, NULL); 746 return(1); 747 } 748 749 750 /* ARGSUSED */ 751 static int 752 mdoc_xr_pre(MDOC_ARGS) 753 { 754 struct htmlpair tag[2]; 755 756 if (NULL == n->child) 757 return(0); 758 759 PAIR_CLASS_INIT(&tag[0], "link-man"); 760 761 if (h->base_man) { 762 buffmt_man(h, n->child->string, 763 n->child->next ? 764 n->child->next->string : NULL); 765 PAIR_HREF_INIT(&tag[1], h->buf); 766 print_otag(h, TAG_A, 2, tag); 767 } else 768 print_otag(h, TAG_A, 1, tag); 769 770 n = n->child; 771 print_text(h, n->string); 772 773 if (NULL == (n = n->next)) 774 return(0); 775 776 h->flags |= HTML_NOSPACE; 777 print_text(h, "("); 778 h->flags |= HTML_NOSPACE; 779 print_text(h, n->string); 780 h->flags |= HTML_NOSPACE; 781 print_text(h, ")"); 782 return(0); 783 } 784 785 786 /* ARGSUSED */ 787 static int 788 mdoc_ns_pre(MDOC_ARGS) 789 { 790 791 if ( ! (MDOC_LINE & n->flags)) 792 h->flags |= HTML_NOSPACE; 793 return(1); 794 } 795 796 797 /* ARGSUSED */ 798 static int 799 mdoc_ar_pre(MDOC_ARGS) 800 { 801 struct htmlpair tag; 802 803 PAIR_CLASS_INIT(&tag, "arg"); 804 print_otag(h, TAG_I, 1, &tag); 805 return(1); 806 } 807 808 809 /* ARGSUSED */ 810 static int 811 mdoc_xx_pre(MDOC_ARGS) 812 { 813 const char *pp; 814 struct htmlpair tag; 815 int flags; 816 817 switch (n->tok) { 818 case (MDOC_Bsx): 819 pp = "BSD/OS"; 820 break; 821 case (MDOC_Dx): 822 pp = "DragonFly"; 823 break; 824 case (MDOC_Fx): 825 pp = "FreeBSD"; 826 break; 827 case (MDOC_Nx): 828 pp = "NetBSD"; 829 break; 830 case (MDOC_Ox): 831 pp = "OpenBSD"; 832 break; 833 case (MDOC_Ux): 834 pp = "UNIX"; 835 break; 836 default: 837 return(1); 838 } 839 840 PAIR_CLASS_INIT(&tag, "unix"); 841 print_otag(h, TAG_SPAN, 1, &tag); 842 843 print_text(h, pp); 844 if (n->child) { 845 flags = h->flags; 846 h->flags |= HTML_KEEP; 847 print_text(h, n->child->string); 848 h->flags = flags; 849 } 850 return(0); 851 } 852 853 854 /* ARGSUSED */ 855 static int 856 mdoc_bx_pre(MDOC_ARGS) 857 { 858 struct htmlpair tag; 859 860 PAIR_CLASS_INIT(&tag, "unix"); 861 print_otag(h, TAG_SPAN, 1, &tag); 862 863 if (NULL != (n = n->child)) { 864 print_text(h, n->string); 865 h->flags |= HTML_NOSPACE; 866 print_text(h, "BSD"); 867 } else { 868 print_text(h, "BSD"); 869 return(0); 870 } 871 872 if (NULL != (n = n->next)) { 873 h->flags |= HTML_NOSPACE; 874 print_text(h, "-"); 875 h->flags |= HTML_NOSPACE; 876 print_text(h, n->string); 877 } 878 879 return(0); 880 } 881 882 /* ARGSUSED */ 883 static int 884 mdoc_it_pre(MDOC_ARGS) 885 { 886 struct roffsu su; 887 enum mdoc_list type; 888 struct htmlpair tag[2]; 889 const struct mdoc_node *bl; 890 891 bl = n->parent; 892 while (bl && MDOC_Bl != bl->tok) 893 bl = bl->parent; 894 895 assert(bl); 896 897 type = bl->norm->Bl.type; 898 899 assert(lists[type]); 900 PAIR_CLASS_INIT(&tag[0], lists[type]); 901 902 bufinit(h); 903 904 if (MDOC_HEAD == n->type) { 905 switch (type) { 906 case(LIST_bullet): 907 /* FALLTHROUGH */ 908 case(LIST_dash): 909 /* FALLTHROUGH */ 910 case(LIST_item): 911 /* FALLTHROUGH */ 912 case(LIST_hyphen): 913 /* FALLTHROUGH */ 914 case(LIST_enum): 915 return(0); 916 case(LIST_diag): 917 /* FALLTHROUGH */ 918 case(LIST_hang): 919 /* FALLTHROUGH */ 920 case(LIST_inset): 921 /* FALLTHROUGH */ 922 case(LIST_ohang): 923 /* FALLTHROUGH */ 924 case(LIST_tag): 925 SCALE_VS_INIT(&su, ! bl->norm->Bl.comp); 926 bufcat_su(h, "margin-top", &su); 927 PAIR_STYLE_INIT(&tag[1], h); 928 print_otag(h, TAG_DT, 2, tag); 929 if (LIST_diag != type) 930 break; 931 PAIR_CLASS_INIT(&tag[0], "diag"); 932 print_otag(h, TAG_B, 1, tag); 933 break; 934 case(LIST_column): 935 break; 936 default: 937 break; 938 } 939 } else if (MDOC_BODY == n->type) { 940 switch (type) { 941 case(LIST_bullet): 942 /* FALLTHROUGH */ 943 case(LIST_hyphen): 944 /* FALLTHROUGH */ 945 case(LIST_dash): 946 /* FALLTHROUGH */ 947 case(LIST_enum): 948 /* FALLTHROUGH */ 949 case(LIST_item): 950 SCALE_VS_INIT(&su, ! bl->norm->Bl.comp); 951 bufcat_su(h, "margin-top", &su); 952 PAIR_STYLE_INIT(&tag[1], h); 953 print_otag(h, TAG_LI, 2, tag); 954 break; 955 case(LIST_diag): 956 /* FALLTHROUGH */ 957 case(LIST_hang): 958 /* FALLTHROUGH */ 959 case(LIST_inset): 960 /* FALLTHROUGH */ 961 case(LIST_ohang): 962 /* FALLTHROUGH */ 963 case(LIST_tag): 964 if (NULL == bl->norm->Bl.width) { 965 print_otag(h, TAG_DD, 1, tag); 966 break; 967 } 968 a2width(bl->norm->Bl.width, &su); 969 bufcat_su(h, "margin-left", &su); 970 PAIR_STYLE_INIT(&tag[1], h); 971 print_otag(h, TAG_DD, 2, tag); 972 break; 973 case(LIST_column): 974 SCALE_VS_INIT(&su, ! bl->norm->Bl.comp); 975 bufcat_su(h, "margin-top", &su); 976 PAIR_STYLE_INIT(&tag[1], h); 977 print_otag(h, TAG_TD, 2, tag); 978 break; 979 default: 980 break; 981 } 982 } else { 983 switch (type) { 984 case (LIST_column): 985 print_otag(h, TAG_TR, 1, tag); 986 break; 987 default: 988 break; 989 } 990 } 991 992 return(1); 993 } 994 995 /* ARGSUSED */ 996 static int 997 mdoc_bl_pre(MDOC_ARGS) 998 { 999 int i; 1000 struct htmlpair tag[3]; 1001 struct roffsu su; 1002 char buf[BUFSIZ]; 1003 1004 bufinit(h); 1005 1006 if (MDOC_BODY == n->type) { 1007 if (LIST_column == n->norm->Bl.type) 1008 print_otag(h, TAG_TBODY, 0, NULL); 1009 return(1); 1010 } 1011 1012 if (MDOC_HEAD == n->type) { 1013 if (LIST_column != n->norm->Bl.type) 1014 return(0); 1015 1016 /* 1017 * For each column, print out the <COL> tag with our 1018 * suggested width. The last column gets min-width, as 1019 * in terminal mode it auto-sizes to the width of the 1020 * screen and we want to preserve that behaviour. 1021 */ 1022 1023 for (i = 0; i < (int)n->norm->Bl.ncols; i++) { 1024 a2width(n->norm->Bl.cols[i], &su); 1025 if (i < (int)n->norm->Bl.ncols - 1) 1026 bufcat_su(h, "width", &su); 1027 else 1028 bufcat_su(h, "min-width", &su); 1029 PAIR_STYLE_INIT(&tag[0], h); 1030 print_otag(h, TAG_COL, 1, tag); 1031 } 1032 1033 return(0); 1034 } 1035 1036 SCALE_VS_INIT(&su, 0); 1037 bufcat_su(h, "margin-top", &su); 1038 bufcat_su(h, "margin-bottom", &su); 1039 PAIR_STYLE_INIT(&tag[0], h); 1040 1041 assert(lists[n->norm->Bl.type]); 1042 strlcpy(buf, "list ", BUFSIZ); 1043 strlcat(buf, lists[n->norm->Bl.type], BUFSIZ); 1044 PAIR_INIT(&tag[1], ATTR_CLASS, buf); 1045 1046 /* Set the block's left-hand margin. */ 1047 1048 if (n->norm->Bl.offs) { 1049 a2offs(n->norm->Bl.offs, &su); 1050 bufcat_su(h, "margin-left", &su); 1051 } 1052 1053 switch (n->norm->Bl.type) { 1054 case(LIST_bullet): 1055 /* FALLTHROUGH */ 1056 case(LIST_dash): 1057 /* FALLTHROUGH */ 1058 case(LIST_hyphen): 1059 /* FALLTHROUGH */ 1060 case(LIST_item): 1061 print_otag(h, TAG_UL, 2, tag); 1062 break; 1063 case(LIST_enum): 1064 print_otag(h, TAG_OL, 2, tag); 1065 break; 1066 case(LIST_diag): 1067 /* FALLTHROUGH */ 1068 case(LIST_hang): 1069 /* FALLTHROUGH */ 1070 case(LIST_inset): 1071 /* FALLTHROUGH */ 1072 case(LIST_ohang): 1073 /* FALLTHROUGH */ 1074 case(LIST_tag): 1075 print_otag(h, TAG_DL, 2, tag); 1076 break; 1077 case(LIST_column): 1078 print_otag(h, TAG_TABLE, 2, tag); 1079 break; 1080 default: 1081 abort(); 1082 /* NOTREACHED */ 1083 } 1084 1085 return(1); 1086 } 1087 1088 /* ARGSUSED */ 1089 static int 1090 mdoc_ex_pre(MDOC_ARGS) 1091 { 1092 struct tag *t; 1093 struct htmlpair tag; 1094 int nchild; 1095 1096 if (n->prev) 1097 print_otag(h, TAG_BR, 0, NULL); 1098 1099 PAIR_CLASS_INIT(&tag, "utility"); 1100 1101 print_text(h, "The"); 1102 1103 nchild = n->nchild; 1104 for (n = n->child; n; n = n->next) { 1105 assert(MDOC_TEXT == n->type); 1106 1107 t = print_otag(h, TAG_B, 1, &tag); 1108 print_text(h, n->string); 1109 print_tagq(h, t); 1110 1111 if (nchild > 2 && n->next) { 1112 h->flags |= HTML_NOSPACE; 1113 print_text(h, ","); 1114 } 1115 1116 if (n->next && NULL == n->next->next) 1117 print_text(h, "and"); 1118 } 1119 1120 if (nchild > 1) 1121 print_text(h, "utilities exit"); 1122 else 1123 print_text(h, "utility exits"); 1124 1125 print_text(h, "0 on success, and >0 if an error occurs."); 1126 return(0); 1127 } 1128 1129 1130 /* ARGSUSED */ 1131 static int 1132 mdoc_em_pre(MDOC_ARGS) 1133 { 1134 struct htmlpair tag; 1135 1136 PAIR_CLASS_INIT(&tag, "emph"); 1137 print_otag(h, TAG_SPAN, 1, &tag); 1138 return(1); 1139 } 1140 1141 1142 /* ARGSUSED */ 1143 static int 1144 mdoc_d1_pre(MDOC_ARGS) 1145 { 1146 struct htmlpair tag[2]; 1147 struct roffsu su; 1148 1149 if (MDOC_BLOCK != n->type) 1150 return(1); 1151 1152 SCALE_VS_INIT(&su, 0); 1153 bufinit(h); 1154 bufcat_su(h, "margin-top", &su); 1155 bufcat_su(h, "margin-bottom", &su); 1156 PAIR_STYLE_INIT(&tag[0], h); 1157 print_otag(h, TAG_BLOCKQUOTE, 1, tag); 1158 1159 /* BLOCKQUOTE needs a block body. */ 1160 1161 PAIR_CLASS_INIT(&tag[0], "display"); 1162 print_otag(h, TAG_DIV, 1, tag); 1163 1164 if (MDOC_Dl == n->tok) { 1165 PAIR_CLASS_INIT(&tag[0], "lit"); 1166 print_otag(h, TAG_CODE, 1, tag); 1167 } 1168 1169 return(1); 1170 } 1171 1172 1173 /* ARGSUSED */ 1174 static int 1175 mdoc_sx_pre(MDOC_ARGS) 1176 { 1177 struct htmlpair tag[2]; 1178 1179 bufinit(h); 1180 bufcat(h, "#x"); 1181 1182 for (n = n->child; n; ) { 1183 bufcat_id(h, n->string); 1184 if (NULL != (n = n->next)) 1185 bufcat_id(h, " "); 1186 } 1187 1188 PAIR_CLASS_INIT(&tag[0], "link-sec"); 1189 PAIR_HREF_INIT(&tag[1], h->buf); 1190 1191 print_otag(h, TAG_I, 1, tag); 1192 print_otag(h, TAG_A, 2, tag); 1193 return(1); 1194 } 1195 1196 1197 /* ARGSUSED */ 1198 static int 1199 mdoc_bd_pre(MDOC_ARGS) 1200 { 1201 struct htmlpair tag[2]; 1202 int comp, sv; 1203 const struct mdoc_node *nn; 1204 struct roffsu su; 1205 1206 if (MDOC_HEAD == n->type) 1207 return(0); 1208 1209 if (MDOC_BLOCK == n->type) { 1210 comp = n->norm->Bd.comp; 1211 for (nn = n; nn && ! comp; nn = nn->parent) { 1212 if (MDOC_BLOCK != nn->type) 1213 continue; 1214 if (MDOC_Ss == nn->tok || MDOC_Sh == nn->tok) 1215 comp = 1; 1216 if (nn->prev) 1217 break; 1218 } 1219 if ( ! comp) 1220 print_otag(h, TAG_P, 0, NULL); 1221 return(1); 1222 } 1223 1224 SCALE_HS_INIT(&su, 0); 1225 if (n->norm->Bd.offs) 1226 a2offs(n->norm->Bd.offs, &su); 1227 1228 bufinit(h); 1229 bufcat_su(h, "margin-left", &su); 1230 PAIR_STYLE_INIT(&tag[0], h); 1231 1232 if (DISP_unfilled != n->norm->Bd.type && 1233 DISP_literal != n->norm->Bd.type) { 1234 PAIR_CLASS_INIT(&tag[1], "display"); 1235 print_otag(h, TAG_DIV, 2, tag); 1236 return(1); 1237 } 1238 1239 PAIR_CLASS_INIT(&tag[1], "lit display"); 1240 print_otag(h, TAG_PRE, 2, tag); 1241 1242 /* This can be recursive: save & set our literal state. */ 1243 1244 sv = h->flags & HTML_LITERAL; 1245 h->flags |= HTML_LITERAL; 1246 1247 for (nn = n->child; nn; nn = nn->next) { 1248 print_mdoc_node(m, nn, h); 1249 /* 1250 * If the printed node flushes its own line, then we 1251 * needn't do it here as well. This is hacky, but the 1252 * notion of selective eoln whitespace is pretty dumb 1253 * anyway, so don't sweat it. 1254 */ 1255 switch (nn->tok) { 1256 case (MDOC_Sm): 1257 /* FALLTHROUGH */ 1258 case (MDOC_br): 1259 /* FALLTHROUGH */ 1260 case (MDOC_sp): 1261 /* FALLTHROUGH */ 1262 case (MDOC_Bl): 1263 /* FALLTHROUGH */ 1264 case (MDOC_D1): 1265 /* FALLTHROUGH */ 1266 case (MDOC_Dl): 1267 /* FALLTHROUGH */ 1268 case (MDOC_Lp): 1269 /* FALLTHROUGH */ 1270 case (MDOC_Pp): 1271 continue; 1272 default: 1273 break; 1274 } 1275 if (nn->next && nn->next->line == nn->line) 1276 continue; 1277 else if (nn->next) 1278 print_text(h, "\n"); 1279 1280 h->flags |= HTML_NOSPACE; 1281 } 1282 1283 if (0 == sv) 1284 h->flags &= ~HTML_LITERAL; 1285 1286 return(0); 1287 } 1288 1289 1290 /* ARGSUSED */ 1291 static int 1292 mdoc_pa_pre(MDOC_ARGS) 1293 { 1294 struct htmlpair tag; 1295 1296 PAIR_CLASS_INIT(&tag, "file"); 1297 print_otag(h, TAG_I, 1, &tag); 1298 return(1); 1299 } 1300 1301 1302 /* ARGSUSED */ 1303 static int 1304 mdoc_ad_pre(MDOC_ARGS) 1305 { 1306 struct htmlpair tag; 1307 1308 PAIR_CLASS_INIT(&tag, "addr"); 1309 print_otag(h, TAG_I, 1, &tag); 1310 return(1); 1311 } 1312 1313 1314 /* ARGSUSED */ 1315 static int 1316 mdoc_an_pre(MDOC_ARGS) 1317 { 1318 struct htmlpair tag; 1319 1320 /* TODO: -split and -nosplit (see termp_an_pre()). */ 1321 1322 PAIR_CLASS_INIT(&tag, "author"); 1323 print_otag(h, TAG_SPAN, 1, &tag); 1324 return(1); 1325 } 1326 1327 1328 /* ARGSUSED */ 1329 static int 1330 mdoc_cd_pre(MDOC_ARGS) 1331 { 1332 struct htmlpair tag; 1333 1334 synopsis_pre(h, n); 1335 PAIR_CLASS_INIT(&tag, "config"); 1336 print_otag(h, TAG_B, 1, &tag); 1337 return(1); 1338 } 1339 1340 1341 /* ARGSUSED */ 1342 static int 1343 mdoc_dv_pre(MDOC_ARGS) 1344 { 1345 struct htmlpair tag; 1346 1347 PAIR_CLASS_INIT(&tag, "define"); 1348 print_otag(h, TAG_SPAN, 1, &tag); 1349 return(1); 1350 } 1351 1352 1353 /* ARGSUSED */ 1354 static int 1355 mdoc_ev_pre(MDOC_ARGS) 1356 { 1357 struct htmlpair tag; 1358 1359 PAIR_CLASS_INIT(&tag, "env"); 1360 print_otag(h, TAG_SPAN, 1, &tag); 1361 return(1); 1362 } 1363 1364 1365 /* ARGSUSED */ 1366 static int 1367 mdoc_er_pre(MDOC_ARGS) 1368 { 1369 struct htmlpair tag; 1370 1371 PAIR_CLASS_INIT(&tag, "errno"); 1372 print_otag(h, TAG_SPAN, 1, &tag); 1373 return(1); 1374 } 1375 1376 1377 /* ARGSUSED */ 1378 static int 1379 mdoc_fa_pre(MDOC_ARGS) 1380 { 1381 const struct mdoc_node *nn; 1382 struct htmlpair tag; 1383 struct tag *t; 1384 1385 PAIR_CLASS_INIT(&tag, "farg"); 1386 if (n->parent->tok != MDOC_Fo) { 1387 print_otag(h, TAG_I, 1, &tag); 1388 return(1); 1389 } 1390 1391 for (nn = n->child; nn; nn = nn->next) { 1392 t = print_otag(h, TAG_I, 1, &tag); 1393 print_text(h, nn->string); 1394 print_tagq(h, t); 1395 if (nn->next) { 1396 h->flags |= HTML_NOSPACE; 1397 print_text(h, ","); 1398 } 1399 } 1400 1401 if (n->child && n->next && n->next->tok == MDOC_Fa) { 1402 h->flags |= HTML_NOSPACE; 1403 print_text(h, ","); 1404 } 1405 1406 return(0); 1407 } 1408 1409 1410 /* ARGSUSED */ 1411 static int 1412 mdoc_fd_pre(MDOC_ARGS) 1413 { 1414 struct htmlpair tag[2]; 1415 char buf[BUFSIZ]; 1416 size_t sz; 1417 int i; 1418 struct tag *t; 1419 1420 synopsis_pre(h, n); 1421 1422 if (NULL == (n = n->child)) 1423 return(0); 1424 1425 assert(MDOC_TEXT == n->type); 1426 1427 if (strcmp(n->string, "#include")) { 1428 PAIR_CLASS_INIT(&tag[0], "macro"); 1429 print_otag(h, TAG_B, 1, tag); 1430 return(1); 1431 } 1432 1433 PAIR_CLASS_INIT(&tag[0], "includes"); 1434 print_otag(h, TAG_B, 1, tag); 1435 print_text(h, n->string); 1436 1437 if (NULL != (n = n->next)) { 1438 assert(MDOC_TEXT == n->type); 1439 strlcpy(buf, '<' == *n->string || '"' == *n->string ? 1440 n->string + 1 : n->string, BUFSIZ); 1441 1442 sz = strlen(buf); 1443 if (sz && ('>' == buf[sz - 1] || '"' == buf[sz - 1])) 1444 buf[sz - 1] = '\0'; 1445 1446 PAIR_CLASS_INIT(&tag[0], "link-includes"); 1447 1448 i = 1; 1449 if (h->base_includes) { 1450 buffmt_includes(h, buf); 1451 PAIR_HREF_INIT(&tag[i], h->buf); 1452 i++; 1453 } 1454 1455 t = print_otag(h, TAG_A, i, tag); 1456 print_text(h, n->string); 1457 print_tagq(h, t); 1458 1459 n = n->next; 1460 } 1461 1462 for ( ; n; n = n->next) { 1463 assert(MDOC_TEXT == n->type); 1464 print_text(h, n->string); 1465 } 1466 1467 return(0); 1468 } 1469 1470 1471 /* ARGSUSED */ 1472 static int 1473 mdoc_vt_pre(MDOC_ARGS) 1474 { 1475 struct htmlpair tag; 1476 1477 if (MDOC_BLOCK == n->type) { 1478 synopsis_pre(h, n); 1479 return(1); 1480 } else if (MDOC_ELEM == n->type) { 1481 synopsis_pre(h, n); 1482 } else if (MDOC_HEAD == n->type) 1483 return(0); 1484 1485 PAIR_CLASS_INIT(&tag, "type"); 1486 print_otag(h, TAG_SPAN, 1, &tag); 1487 return(1); 1488 } 1489 1490 1491 /* ARGSUSED */ 1492 static int 1493 mdoc_ft_pre(MDOC_ARGS) 1494 { 1495 struct htmlpair tag; 1496 1497 synopsis_pre(h, n); 1498 PAIR_CLASS_INIT(&tag, "ftype"); 1499 print_otag(h, TAG_I, 1, &tag); 1500 return(1); 1501 } 1502 1503 1504 /* ARGSUSED */ 1505 static int 1506 mdoc_fn_pre(MDOC_ARGS) 1507 { 1508 struct tag *t; 1509 struct htmlpair tag[2]; 1510 char nbuf[BUFSIZ]; 1511 const char *sp, *ep; 1512 int sz, i, pretty; 1513 1514 pretty = MDOC_SYNPRETTY & n->flags; 1515 synopsis_pre(h, n); 1516 1517 /* Split apart into type and name. */ 1518 assert(n->child->string); 1519 sp = n->child->string; 1520 1521 ep = strchr(sp, ' '); 1522 if (NULL != ep) { 1523 PAIR_CLASS_INIT(&tag[0], "ftype"); 1524 t = print_otag(h, TAG_I, 1, tag); 1525 1526 while (ep) { 1527 sz = MIN((int)(ep - sp), BUFSIZ - 1); 1528 (void)memcpy(nbuf, sp, (size_t)sz); 1529 nbuf[sz] = '\0'; 1530 print_text(h, nbuf); 1531 sp = ++ep; 1532 ep = strchr(sp, ' '); 1533 } 1534 print_tagq(h, t); 1535 } 1536 1537 PAIR_CLASS_INIT(&tag[0], "fname"); 1538 1539 /* 1540 * FIXME: only refer to IDs that we know exist. 1541 */ 1542 1543 #if 0 1544 if (MDOC_SYNPRETTY & n->flags) { 1545 nbuf[0] = '\0'; 1546 html_idcat(nbuf, sp, BUFSIZ); 1547 PAIR_ID_INIT(&tag[1], nbuf); 1548 } else { 1549 strlcpy(nbuf, "#", BUFSIZ); 1550 html_idcat(nbuf, sp, BUFSIZ); 1551 PAIR_HREF_INIT(&tag[1], nbuf); 1552 } 1553 #endif 1554 1555 t = print_otag(h, TAG_B, 1, tag); 1556 1557 if (sp) { 1558 strlcpy(nbuf, sp, BUFSIZ); 1559 print_text(h, nbuf); 1560 } 1561 1562 print_tagq(h, t); 1563 1564 h->flags |= HTML_NOSPACE; 1565 print_text(h, "("); 1566 h->flags |= HTML_NOSPACE; 1567 1568 PAIR_CLASS_INIT(&tag[0], "farg"); 1569 bufinit(h); 1570 bufcat_style(h, "white-space", "nowrap"); 1571 PAIR_STYLE_INIT(&tag[1], h); 1572 1573 for (n = n->child->next; n; n = n->next) { 1574 i = 1; 1575 if (MDOC_SYNPRETTY & n->flags) 1576 i = 2; 1577 t = print_otag(h, TAG_I, i, tag); 1578 print_text(h, n->string); 1579 print_tagq(h, t); 1580 if (n->next) { 1581 h->flags |= HTML_NOSPACE; 1582 print_text(h, ","); 1583 } 1584 } 1585 1586 h->flags |= HTML_NOSPACE; 1587 print_text(h, ")"); 1588 1589 if (pretty) { 1590 h->flags |= HTML_NOSPACE; 1591 print_text(h, ";"); 1592 } 1593 1594 return(0); 1595 } 1596 1597 1598 /* ARGSUSED */ 1599 static int 1600 mdoc_sm_pre(MDOC_ARGS) 1601 { 1602 1603 assert(n->child && MDOC_TEXT == n->child->type); 1604 if (0 == strcmp("on", n->child->string)) { 1605 /* 1606 * FIXME: no p->col to check. Thus, if we have 1607 * .Bd -literal 1608 * .Sm off 1609 * 1 2 1610 * .Sm on 1611 * 3 1612 * .Ed 1613 * the "3" is preceded by a space. 1614 */ 1615 h->flags &= ~HTML_NOSPACE; 1616 h->flags &= ~HTML_NONOSPACE; 1617 } else 1618 h->flags |= HTML_NONOSPACE; 1619 1620 return(0); 1621 } 1622 1623 /* ARGSUSED */ 1624 static int 1625 mdoc_pp_pre(MDOC_ARGS) 1626 { 1627 1628 print_otag(h, TAG_P, 0, NULL); 1629 return(0); 1630 1631 } 1632 1633 /* ARGSUSED */ 1634 static int 1635 mdoc_sp_pre(MDOC_ARGS) 1636 { 1637 struct roffsu su; 1638 struct htmlpair tag; 1639 1640 SCALE_VS_INIT(&su, 1); 1641 1642 if (MDOC_sp == n->tok) { 1643 if (NULL != (n = n->child)) 1644 if ( ! a2roffsu(n->string, &su, SCALE_VS)) 1645 SCALE_VS_INIT(&su, atoi(n->string)); 1646 } else 1647 su.scale = 0; 1648 1649 bufinit(h); 1650 bufcat_su(h, "height", &su); 1651 PAIR_STYLE_INIT(&tag, h); 1652 print_otag(h, TAG_DIV, 1, &tag); 1653 1654 /* So the div isn't empty: */ 1655 print_text(h, "\\~"); 1656 1657 return(0); 1658 1659 } 1660 1661 /* ARGSUSED */ 1662 static int 1663 mdoc_lk_pre(MDOC_ARGS) 1664 { 1665 struct htmlpair tag[2]; 1666 1667 if (NULL == (n = n->child)) 1668 return(0); 1669 1670 assert(MDOC_TEXT == n->type); 1671 1672 PAIR_CLASS_INIT(&tag[0], "link-ext"); 1673 PAIR_HREF_INIT(&tag[1], n->string); 1674 1675 print_otag(h, TAG_A, 2, tag); 1676 1677 if (NULL == n->next) 1678 print_text(h, n->string); 1679 1680 for (n = n->next; n; n = n->next) 1681 print_text(h, n->string); 1682 1683 return(0); 1684 } 1685 1686 1687 /* ARGSUSED */ 1688 static int 1689 mdoc_mt_pre(MDOC_ARGS) 1690 { 1691 struct htmlpair tag[2]; 1692 struct tag *t; 1693 1694 PAIR_CLASS_INIT(&tag[0], "link-mail"); 1695 1696 for (n = n->child; n; n = n->next) { 1697 assert(MDOC_TEXT == n->type); 1698 1699 bufinit(h); 1700 bufcat(h, "mailto:"); 1701 bufcat(h, n->string); 1702 1703 PAIR_HREF_INIT(&tag[1], h->buf); 1704 t = print_otag(h, TAG_A, 2, tag); 1705 print_text(h, n->string); 1706 print_tagq(h, t); 1707 } 1708 1709 return(0); 1710 } 1711 1712 1713 /* ARGSUSED */ 1714 static int 1715 mdoc_fo_pre(MDOC_ARGS) 1716 { 1717 struct htmlpair tag; 1718 struct tag *t; 1719 1720 if (MDOC_BODY == n->type) { 1721 h->flags |= HTML_NOSPACE; 1722 print_text(h, "("); 1723 h->flags |= HTML_NOSPACE; 1724 return(1); 1725 } else if (MDOC_BLOCK == n->type) { 1726 synopsis_pre(h, n); 1727 return(1); 1728 } 1729 1730 /* XXX: we drop non-initial arguments as per groff. */ 1731 1732 assert(n->child); 1733 assert(n->child->string); 1734 1735 PAIR_CLASS_INIT(&tag, "fname"); 1736 t = print_otag(h, TAG_B, 1, &tag); 1737 print_text(h, n->child->string); 1738 print_tagq(h, t); 1739 return(0); 1740 } 1741 1742 1743 /* ARGSUSED */ 1744 static void 1745 mdoc_fo_post(MDOC_ARGS) 1746 { 1747 1748 if (MDOC_BODY != n->type) 1749 return; 1750 h->flags |= HTML_NOSPACE; 1751 print_text(h, ")"); 1752 h->flags |= HTML_NOSPACE; 1753 print_text(h, ";"); 1754 } 1755 1756 1757 /* ARGSUSED */ 1758 static int 1759 mdoc_in_pre(MDOC_ARGS) 1760 { 1761 struct tag *t; 1762 struct htmlpair tag[2]; 1763 int i; 1764 1765 synopsis_pre(h, n); 1766 1767 PAIR_CLASS_INIT(&tag[0], "includes"); 1768 print_otag(h, TAG_B, 1, tag); 1769 1770 /* 1771 * The first argument of the `In' gets special treatment as 1772 * being a linked value. Subsequent values are printed 1773 * afterward. groff does similarly. This also handles the case 1774 * of no children. 1775 */ 1776 1777 if (MDOC_SYNPRETTY & n->flags && MDOC_LINE & n->flags) 1778 print_text(h, "#include"); 1779 1780 print_text(h, "<"); 1781 h->flags |= HTML_NOSPACE; 1782 1783 if (NULL != (n = n->child)) { 1784 assert(MDOC_TEXT == n->type); 1785 1786 PAIR_CLASS_INIT(&tag[0], "link-includes"); 1787 1788 i = 1; 1789 if (h->base_includes) { 1790 buffmt_includes(h, n->string); 1791 PAIR_HREF_INIT(&tag[i], h->buf); 1792 i++; 1793 } 1794 1795 t = print_otag(h, TAG_A, i, tag); 1796 print_text(h, n->string); 1797 print_tagq(h, t); 1798 1799 n = n->next; 1800 } 1801 1802 h->flags |= HTML_NOSPACE; 1803 print_text(h, ">"); 1804 1805 for ( ; n; n = n->next) { 1806 assert(MDOC_TEXT == n->type); 1807 print_text(h, n->string); 1808 } 1809 1810 return(0); 1811 } 1812 1813 1814 /* ARGSUSED */ 1815 static int 1816 mdoc_ic_pre(MDOC_ARGS) 1817 { 1818 struct htmlpair tag; 1819 1820 PAIR_CLASS_INIT(&tag, "cmd"); 1821 print_otag(h, TAG_B, 1, &tag); 1822 return(1); 1823 } 1824 1825 1826 /* ARGSUSED */ 1827 static int 1828 mdoc_rv_pre(MDOC_ARGS) 1829 { 1830 struct htmlpair tag; 1831 struct tag *t; 1832 int nchild; 1833 1834 if (n->prev) 1835 print_otag(h, TAG_BR, 0, NULL); 1836 1837 PAIR_CLASS_INIT(&tag, "fname"); 1838 1839 print_text(h, "The"); 1840 1841 nchild = n->nchild; 1842 for (n = n->child; n; n = n->next) { 1843 assert(MDOC_TEXT == n->type); 1844 1845 t = print_otag(h, TAG_B, 1, &tag); 1846 print_text(h, n->string); 1847 print_tagq(h, t); 1848 1849 h->flags |= HTML_NOSPACE; 1850 print_text(h, "()"); 1851 1852 if (nchild > 2 && n->next) { 1853 h->flags |= HTML_NOSPACE; 1854 print_text(h, ","); 1855 } 1856 1857 if (n->next && NULL == n->next->next) 1858 print_text(h, "and"); 1859 } 1860 1861 if (nchild > 1) 1862 print_text(h, "functions return"); 1863 else 1864 print_text(h, "function returns"); 1865 1866 print_text(h, "the value 0 if successful; otherwise the value " 1867 "-1 is returned and the global variable"); 1868 1869 PAIR_CLASS_INIT(&tag, "var"); 1870 t = print_otag(h, TAG_B, 1, &tag); 1871 print_text(h, "errno"); 1872 print_tagq(h, t); 1873 print_text(h, "is set to indicate the error."); 1874 return(0); 1875 } 1876 1877 1878 /* ARGSUSED */ 1879 static int 1880 mdoc_va_pre(MDOC_ARGS) 1881 { 1882 struct htmlpair tag; 1883 1884 PAIR_CLASS_INIT(&tag, "var"); 1885 print_otag(h, TAG_B, 1, &tag); 1886 return(1); 1887 } 1888 1889 1890 /* ARGSUSED */ 1891 static int 1892 mdoc_ap_pre(MDOC_ARGS) 1893 { 1894 1895 h->flags |= HTML_NOSPACE; 1896 print_text(h, "\\(aq"); 1897 h->flags |= HTML_NOSPACE; 1898 return(1); 1899 } 1900 1901 1902 /* ARGSUSED */ 1903 static int 1904 mdoc_bf_pre(MDOC_ARGS) 1905 { 1906 struct htmlpair tag[2]; 1907 struct roffsu su; 1908 1909 if (MDOC_HEAD == n->type) 1910 return(0); 1911 else if (MDOC_BODY != n->type) 1912 return(1); 1913 1914 if (FONT_Em == n->norm->Bf.font) 1915 PAIR_CLASS_INIT(&tag[0], "emph"); 1916 else if (FONT_Sy == n->norm->Bf.font) 1917 PAIR_CLASS_INIT(&tag[0], "symb"); 1918 else if (FONT_Li == n->norm->Bf.font) 1919 PAIR_CLASS_INIT(&tag[0], "lit"); 1920 else 1921 PAIR_CLASS_INIT(&tag[0], "none"); 1922 1923 /* 1924 * We want this to be inline-formatted, but needs to be div to 1925 * accept block children. 1926 */ 1927 bufinit(h); 1928 bufcat_style(h, "display", "inline"); 1929 SCALE_HS_INIT(&su, 1); 1930 /* Needs a left-margin for spacing. */ 1931 bufcat_su(h, "margin-left", &su); 1932 PAIR_STYLE_INIT(&tag[1], h); 1933 print_otag(h, TAG_DIV, 2, tag); 1934 return(1); 1935 } 1936 1937 1938 /* ARGSUSED */ 1939 static int 1940 mdoc_ms_pre(MDOC_ARGS) 1941 { 1942 struct htmlpair tag; 1943 1944 PAIR_CLASS_INIT(&tag, "symb"); 1945 print_otag(h, TAG_SPAN, 1, &tag); 1946 return(1); 1947 } 1948 1949 1950 /* ARGSUSED */ 1951 static int 1952 mdoc_igndelim_pre(MDOC_ARGS) 1953 { 1954 1955 h->flags |= HTML_IGNDELIM; 1956 return(1); 1957 } 1958 1959 1960 /* ARGSUSED */ 1961 static void 1962 mdoc_pf_post(MDOC_ARGS) 1963 { 1964 1965 h->flags |= HTML_NOSPACE; 1966 } 1967 1968 1969 /* ARGSUSED */ 1970 static int 1971 mdoc_rs_pre(MDOC_ARGS) 1972 { 1973 struct htmlpair tag; 1974 1975 if (MDOC_BLOCK != n->type) 1976 return(1); 1977 1978 if (n->prev && SEC_SEE_ALSO == n->sec) 1979 print_otag(h, TAG_P, 0, NULL); 1980 1981 PAIR_CLASS_INIT(&tag, "ref"); 1982 print_otag(h, TAG_SPAN, 1, &tag); 1983 return(1); 1984 } 1985 1986 1987 1988 /* ARGSUSED */ 1989 static int 1990 mdoc_li_pre(MDOC_ARGS) 1991 { 1992 struct htmlpair tag; 1993 1994 PAIR_CLASS_INIT(&tag, "lit"); 1995 print_otag(h, TAG_CODE, 1, &tag); 1996 return(1); 1997 } 1998 1999 2000 /* ARGSUSED */ 2001 static int 2002 mdoc_sy_pre(MDOC_ARGS) 2003 { 2004 struct htmlpair tag; 2005 2006 PAIR_CLASS_INIT(&tag, "symb"); 2007 print_otag(h, TAG_SPAN, 1, &tag); 2008 return(1); 2009 } 2010 2011 2012 /* ARGSUSED */ 2013 static int 2014 mdoc_bt_pre(MDOC_ARGS) 2015 { 2016 2017 print_text(h, "is currently in beta test."); 2018 return(0); 2019 } 2020 2021 2022 /* ARGSUSED */ 2023 static int 2024 mdoc_ud_pre(MDOC_ARGS) 2025 { 2026 2027 print_text(h, "currently under development."); 2028 return(0); 2029 } 2030 2031 2032 /* ARGSUSED */ 2033 static int 2034 mdoc_lb_pre(MDOC_ARGS) 2035 { 2036 struct htmlpair tag; 2037 2038 if (SEC_LIBRARY == n->sec && MDOC_LINE & n->flags && n->prev) 2039 print_otag(h, TAG_BR, 0, NULL); 2040 2041 PAIR_CLASS_INIT(&tag, "lib"); 2042 print_otag(h, TAG_SPAN, 1, &tag); 2043 return(1); 2044 } 2045 2046 2047 /* ARGSUSED */ 2048 static int 2049 mdoc__x_pre(MDOC_ARGS) 2050 { 2051 struct htmlpair tag[2]; 2052 enum htmltag t; 2053 2054 t = TAG_SPAN; 2055 2056 switch (n->tok) { 2057 case(MDOC__A): 2058 PAIR_CLASS_INIT(&tag[0], "ref-auth"); 2059 if (n->prev && MDOC__A == n->prev->tok) 2060 if (NULL == n->next || MDOC__A != n->next->tok) 2061 print_text(h, "and"); 2062 break; 2063 case(MDOC__B): 2064 PAIR_CLASS_INIT(&tag[0], "ref-book"); 2065 t = TAG_I; 2066 break; 2067 case(MDOC__C): 2068 PAIR_CLASS_INIT(&tag[0], "ref-city"); 2069 break; 2070 case(MDOC__D): 2071 PAIR_CLASS_INIT(&tag[0], "ref-date"); 2072 break; 2073 case(MDOC__I): 2074 PAIR_CLASS_INIT(&tag[0], "ref-issue"); 2075 t = TAG_I; 2076 break; 2077 case(MDOC__J): 2078 PAIR_CLASS_INIT(&tag[0], "ref-jrnl"); 2079 t = TAG_I; 2080 break; 2081 case(MDOC__N): 2082 PAIR_CLASS_INIT(&tag[0], "ref-num"); 2083 break; 2084 case(MDOC__O): 2085 PAIR_CLASS_INIT(&tag[0], "ref-opt"); 2086 break; 2087 case(MDOC__P): 2088 PAIR_CLASS_INIT(&tag[0], "ref-page"); 2089 break; 2090 case(MDOC__Q): 2091 PAIR_CLASS_INIT(&tag[0], "ref-corp"); 2092 break; 2093 case(MDOC__R): 2094 PAIR_CLASS_INIT(&tag[0], "ref-rep"); 2095 break; 2096 case(MDOC__T): 2097 PAIR_CLASS_INIT(&tag[0], "ref-title"); 2098 break; 2099 case(MDOC__U): 2100 PAIR_CLASS_INIT(&tag[0], "link-ref"); 2101 break; 2102 case(MDOC__V): 2103 PAIR_CLASS_INIT(&tag[0], "ref-vol"); 2104 break; 2105 default: 2106 abort(); 2107 /* NOTREACHED */ 2108 } 2109 2110 if (MDOC__U != n->tok) { 2111 print_otag(h, t, 1, tag); 2112 return(1); 2113 } 2114 2115 PAIR_HREF_INIT(&tag[1], n->child->string); 2116 print_otag(h, TAG_A, 2, tag); 2117 2118 return(1); 2119 } 2120 2121 2122 /* ARGSUSED */ 2123 static void 2124 mdoc__x_post(MDOC_ARGS) 2125 { 2126 2127 if (MDOC__A == n->tok && n->next && MDOC__A == n->next->tok) 2128 if (NULL == n->next->next || MDOC__A != n->next->next->tok) 2129 if (NULL == n->prev || MDOC__A != n->prev->tok) 2130 return; 2131 2132 /* TODO: %U */ 2133 2134 if (NULL == n->parent || MDOC_Rs != n->parent->tok) 2135 return; 2136 2137 h->flags |= HTML_NOSPACE; 2138 print_text(h, n->next ? "," : "."); 2139 } 2140 2141 2142 /* ARGSUSED */ 2143 static int 2144 mdoc_bk_pre(MDOC_ARGS) 2145 { 2146 2147 switch (n->type) { 2148 case (MDOC_BLOCK): 2149 break; 2150 case (MDOC_HEAD): 2151 return(0); 2152 case (MDOC_BODY): 2153 if (n->parent->args || 0 == n->prev->nchild) 2154 h->flags |= HTML_PREKEEP; 2155 break; 2156 default: 2157 abort(); 2158 /* NOTREACHED */ 2159 } 2160 2161 return(1); 2162 } 2163 2164 2165 /* ARGSUSED */ 2166 static void 2167 mdoc_bk_post(MDOC_ARGS) 2168 { 2169 2170 if (MDOC_BODY == n->type) 2171 h->flags &= ~(HTML_KEEP | HTML_PREKEEP); 2172 } 2173 2174 2175 /* ARGSUSED */ 2176 static int 2177 mdoc_quote_pre(MDOC_ARGS) 2178 { 2179 struct htmlpair tag; 2180 2181 if (MDOC_BODY != n->type) 2182 return(1); 2183 2184 switch (n->tok) { 2185 case (MDOC_Ao): 2186 /* FALLTHROUGH */ 2187 case (MDOC_Aq): 2188 print_text(h, "\\(la"); 2189 break; 2190 case (MDOC_Bro): 2191 /* FALLTHROUGH */ 2192 case (MDOC_Brq): 2193 print_text(h, "\\(lC"); 2194 break; 2195 case (MDOC_Bo): 2196 /* FALLTHROUGH */ 2197 case (MDOC_Bq): 2198 print_text(h, "\\(lB"); 2199 break; 2200 case (MDOC_Oo): 2201 /* FALLTHROUGH */ 2202 case (MDOC_Op): 2203 print_text(h, "\\(lB"); 2204 h->flags |= HTML_NOSPACE; 2205 PAIR_CLASS_INIT(&tag, "opt"); 2206 print_otag(h, TAG_SPAN, 1, &tag); 2207 break; 2208 case (MDOC_Do): 2209 /* FALLTHROUGH */ 2210 case (MDOC_Dq): 2211 /* FALLTHROUGH */ 2212 case (MDOC_Qo): 2213 /* FALLTHROUGH */ 2214 case (MDOC_Qq): 2215 print_text(h, "\\(lq"); 2216 break; 2217 case (MDOC_Po): 2218 /* FALLTHROUGH */ 2219 case (MDOC_Pq): 2220 print_text(h, "("); 2221 break; 2222 case (MDOC_Ql): 2223 print_text(h, "\\(oq"); 2224 h->flags |= HTML_NOSPACE; 2225 PAIR_CLASS_INIT(&tag, "lit"); 2226 print_otag(h, TAG_CODE, 1, &tag); 2227 break; 2228 case (MDOC_So): 2229 /* FALLTHROUGH */ 2230 case (MDOC_Sq): 2231 print_text(h, "\\(oq"); 2232 break; 2233 default: 2234 abort(); 2235 /* NOTREACHED */ 2236 } 2237 2238 h->flags |= HTML_NOSPACE; 2239 return(1); 2240 } 2241 2242 2243 /* ARGSUSED */ 2244 static void 2245 mdoc_quote_post(MDOC_ARGS) 2246 { 2247 2248 if (MDOC_BODY != n->type) 2249 return; 2250 2251 h->flags |= HTML_NOSPACE; 2252 2253 switch (n->tok) { 2254 case (MDOC_Ao): 2255 /* FALLTHROUGH */ 2256 case (MDOC_Aq): 2257 print_text(h, "\\(ra"); 2258 break; 2259 case (MDOC_Bro): 2260 /* FALLTHROUGH */ 2261 case (MDOC_Brq): 2262 print_text(h, "\\(rC"); 2263 break; 2264 case (MDOC_Oo): 2265 /* FALLTHROUGH */ 2266 case (MDOC_Op): 2267 /* FALLTHROUGH */ 2268 case (MDOC_Bo): 2269 /* FALLTHROUGH */ 2270 case (MDOC_Bq): 2271 print_text(h, "\\(rB"); 2272 break; 2273 case (MDOC_Qo): 2274 /* FALLTHROUGH */ 2275 case (MDOC_Qq): 2276 /* FALLTHROUGH */ 2277 case (MDOC_Do): 2278 /* FALLTHROUGH */ 2279 case (MDOC_Dq): 2280 print_text(h, "\\(rq"); 2281 break; 2282 case (MDOC_Po): 2283 /* FALLTHROUGH */ 2284 case (MDOC_Pq): 2285 print_text(h, ")"); 2286 break; 2287 case (MDOC_Ql): 2288 /* FALLTHROUGH */ 2289 case (MDOC_So): 2290 /* FALLTHROUGH */ 2291 case (MDOC_Sq): 2292 print_text(h, "\\(aq"); 2293 break; 2294 default: 2295 abort(); 2296 /* NOTREACHED */ 2297 } 2298 } 2299 2300 2301