1 /* $Id: mdoc_html.c,v 1.182 2011/11/03 20:37:00 schwarze 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 {mdoc_quote_pre, mdoc_quote_post}, /* 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 PAIR_INIT(&tag[2], ATTR_WIDTH, "100%"); 501 t = print_otag(h, TAG_TABLE, 3, tag); 502 PAIR_INIT(&tag[0], ATTR_WIDTH, "50%"); 503 print_otag(h, TAG_COL, 1, tag); 504 print_otag(h, TAG_COL, 1, tag); 505 506 print_otag(h, TAG_TBODY, 0, NULL); 507 508 tt = print_otag(h, TAG_TR, 0, NULL); 509 510 PAIR_CLASS_INIT(&tag[0], "foot-date"); 511 print_otag(h, TAG_TD, 1, tag); 512 print_text(h, m->date); 513 print_stagq(h, tt); 514 515 PAIR_CLASS_INIT(&tag[0], "foot-os"); 516 PAIR_INIT(&tag[1], ATTR_ALIGN, "right"); 517 print_otag(h, TAG_TD, 2, tag); 518 print_text(h, m->os); 519 print_tagq(h, t); 520 } 521 522 523 /* ARGSUSED */ 524 static int 525 mdoc_root_pre(MDOC_ARGS) 526 { 527 struct htmlpair tag[3]; 528 struct tag *t, *tt; 529 char b[BUFSIZ], title[BUFSIZ]; 530 531 strlcpy(b, m->vol, BUFSIZ); 532 533 if (m->arch) { 534 strlcat(b, " (", BUFSIZ); 535 strlcat(b, m->arch, BUFSIZ); 536 strlcat(b, ")", BUFSIZ); 537 } 538 539 snprintf(title, BUFSIZ - 1, "%s(%s)", m->title, m->msec); 540 541 PAIR_SUMMARY_INIT(&tag[0], "Document Header"); 542 PAIR_CLASS_INIT(&tag[1], "head"); 543 PAIR_INIT(&tag[2], ATTR_WIDTH, "100%"); 544 t = print_otag(h, TAG_TABLE, 3, tag); 545 PAIR_INIT(&tag[0], ATTR_WIDTH, "30%"); 546 print_otag(h, TAG_COL, 1, tag); 547 print_otag(h, TAG_COL, 1, tag); 548 print_otag(h, TAG_COL, 1, tag); 549 550 print_otag(h, TAG_TBODY, 0, NULL); 551 552 tt = print_otag(h, TAG_TR, 0, NULL); 553 554 PAIR_CLASS_INIT(&tag[0], "head-ltitle"); 555 print_otag(h, TAG_TD, 1, tag); 556 print_text(h, title); 557 print_stagq(h, tt); 558 559 PAIR_CLASS_INIT(&tag[0], "head-vol"); 560 PAIR_INIT(&tag[1], ATTR_ALIGN, "center"); 561 print_otag(h, TAG_TD, 2, tag); 562 print_text(h, b); 563 print_stagq(h, tt); 564 565 PAIR_CLASS_INIT(&tag[0], "head-rtitle"); 566 PAIR_INIT(&tag[1], ATTR_ALIGN, "right"); 567 print_otag(h, TAG_TD, 2, tag); 568 print_text(h, title); 569 print_tagq(h, t); 570 return(1); 571 } 572 573 574 /* ARGSUSED */ 575 static int 576 mdoc_sh_pre(MDOC_ARGS) 577 { 578 struct htmlpair tag; 579 580 if (MDOC_BLOCK == n->type) { 581 PAIR_CLASS_INIT(&tag, "section"); 582 print_otag(h, TAG_DIV, 1, &tag); 583 return(1); 584 } else if (MDOC_BODY == n->type) 585 return(1); 586 587 bufinit(h); 588 bufcat(h, "x"); 589 590 for (n = n->child; n && MDOC_TEXT == n->type; ) { 591 bufcat_id(h, n->string); 592 if (NULL != (n = n->next)) 593 bufcat_id(h, " "); 594 } 595 596 if (NULL == n) { 597 PAIR_ID_INIT(&tag, h->buf); 598 print_otag(h, TAG_H1, 1, &tag); 599 } else 600 print_otag(h, TAG_H1, 0, NULL); 601 602 return(1); 603 } 604 605 /* ARGSUSED */ 606 static int 607 mdoc_ss_pre(MDOC_ARGS) 608 { 609 struct htmlpair tag; 610 611 if (MDOC_BLOCK == n->type) { 612 PAIR_CLASS_INIT(&tag, "subsection"); 613 print_otag(h, TAG_DIV, 1, &tag); 614 return(1); 615 } else if (MDOC_BODY == n->type) 616 return(1); 617 618 bufinit(h); 619 bufcat(h, "x"); 620 621 for (n = n->child; n && MDOC_TEXT == n->type; ) { 622 bufcat_id(h, n->string); 623 if (NULL != (n = n->next)) 624 bufcat_id(h, " "); 625 } 626 627 if (NULL == n) { 628 PAIR_ID_INIT(&tag, h->buf); 629 print_otag(h, TAG_H2, 1, &tag); 630 } else 631 print_otag(h, TAG_H2, 0, NULL); 632 633 return(1); 634 } 635 636 637 /* ARGSUSED */ 638 static int 639 mdoc_fl_pre(MDOC_ARGS) 640 { 641 struct htmlpair tag; 642 643 PAIR_CLASS_INIT(&tag, "flag"); 644 print_otag(h, TAG_B, 1, &tag); 645 646 /* `Cm' has no leading hyphen. */ 647 648 if (MDOC_Cm == n->tok) 649 return(1); 650 651 print_text(h, "\\-"); 652 653 if (n->child) 654 h->flags |= HTML_NOSPACE; 655 else if (n->next && n->next->line == n->line) 656 h->flags |= HTML_NOSPACE; 657 658 return(1); 659 } 660 661 662 /* ARGSUSED */ 663 static int 664 mdoc_nd_pre(MDOC_ARGS) 665 { 666 struct htmlpair tag; 667 668 if (MDOC_BODY != n->type) 669 return(1); 670 671 /* XXX: this tag in theory can contain block elements. */ 672 673 print_text(h, "\\(em"); 674 PAIR_CLASS_INIT(&tag, "desc"); 675 print_otag(h, TAG_SPAN, 1, &tag); 676 return(1); 677 } 678 679 680 static int 681 mdoc_nm_pre(MDOC_ARGS) 682 { 683 struct htmlpair tag; 684 struct roffsu su; 685 int len; 686 687 switch (n->type) { 688 case (MDOC_ELEM): 689 synopsis_pre(h, n); 690 PAIR_CLASS_INIT(&tag, "name"); 691 print_otag(h, TAG_B, 1, &tag); 692 if (NULL == n->child && m->name) 693 print_text(h, m->name); 694 return(1); 695 case (MDOC_HEAD): 696 print_otag(h, TAG_TD, 0, NULL); 697 if (NULL == n->child && m->name) 698 print_text(h, m->name); 699 return(1); 700 case (MDOC_BODY): 701 print_otag(h, TAG_TD, 0, NULL); 702 return(1); 703 default: 704 break; 705 } 706 707 synopsis_pre(h, n); 708 PAIR_CLASS_INIT(&tag, "synopsis"); 709 print_otag(h, TAG_TABLE, 1, &tag); 710 711 for (len = 0, n = n->child; n; n = n->next) 712 if (MDOC_TEXT == n->type) 713 len += html_strlen(n->string); 714 715 if (0 == len && m->name) 716 len = html_strlen(m->name); 717 718 SCALE_HS_INIT(&su, (double)len); 719 bufinit(h); 720 bufcat_su(h, "width", &su); 721 PAIR_STYLE_INIT(&tag, h); 722 print_otag(h, TAG_COL, 1, &tag); 723 print_otag(h, TAG_COL, 0, NULL); 724 print_otag(h, TAG_TBODY, 0, NULL); 725 print_otag(h, TAG_TR, 0, NULL); 726 return(1); 727 } 728 729 730 /* ARGSUSED */ 731 static int 732 mdoc_xr_pre(MDOC_ARGS) 733 { 734 struct htmlpair tag[2]; 735 736 if (NULL == n->child) 737 return(0); 738 739 PAIR_CLASS_INIT(&tag[0], "link-man"); 740 741 if (h->base_man) { 742 buffmt_man(h, n->child->string, 743 n->child->next ? 744 n->child->next->string : NULL); 745 PAIR_HREF_INIT(&tag[1], h->buf); 746 print_otag(h, TAG_A, 2, tag); 747 } else 748 print_otag(h, TAG_A, 1, tag); 749 750 n = n->child; 751 print_text(h, n->string); 752 753 if (NULL == (n = n->next)) 754 return(0); 755 756 h->flags |= HTML_NOSPACE; 757 print_text(h, "("); 758 h->flags |= HTML_NOSPACE; 759 print_text(h, n->string); 760 h->flags |= HTML_NOSPACE; 761 print_text(h, ")"); 762 return(0); 763 } 764 765 766 /* ARGSUSED */ 767 static int 768 mdoc_ns_pre(MDOC_ARGS) 769 { 770 771 if ( ! (MDOC_LINE & n->flags)) 772 h->flags |= HTML_NOSPACE; 773 return(1); 774 } 775 776 777 /* ARGSUSED */ 778 static int 779 mdoc_ar_pre(MDOC_ARGS) 780 { 781 struct htmlpair tag; 782 783 PAIR_CLASS_INIT(&tag, "arg"); 784 print_otag(h, TAG_I, 1, &tag); 785 return(1); 786 } 787 788 789 /* ARGSUSED */ 790 static int 791 mdoc_xx_pre(MDOC_ARGS) 792 { 793 const char *pp; 794 struct htmlpair tag; 795 int flags; 796 797 switch (n->tok) { 798 case (MDOC_Bsx): 799 pp = "BSD/OS"; 800 break; 801 case (MDOC_Dx): 802 pp = "DragonFly"; 803 break; 804 case (MDOC_Fx): 805 pp = "FreeBSD"; 806 break; 807 case (MDOC_Nx): 808 pp = "NetBSD"; 809 break; 810 case (MDOC_Ox): 811 pp = "OpenBSD"; 812 break; 813 case (MDOC_Ux): 814 pp = "UNIX"; 815 break; 816 default: 817 return(1); 818 } 819 820 PAIR_CLASS_INIT(&tag, "unix"); 821 print_otag(h, TAG_SPAN, 1, &tag); 822 823 print_text(h, pp); 824 if (n->child) { 825 flags = h->flags; 826 h->flags |= HTML_KEEP; 827 print_text(h, n->child->string); 828 h->flags = flags; 829 } 830 return(0); 831 } 832 833 834 /* ARGSUSED */ 835 static int 836 mdoc_bx_pre(MDOC_ARGS) 837 { 838 struct htmlpair tag; 839 840 PAIR_CLASS_INIT(&tag, "unix"); 841 print_otag(h, TAG_SPAN, 1, &tag); 842 843 if (NULL != (n = n->child)) { 844 print_text(h, n->string); 845 h->flags |= HTML_NOSPACE; 846 print_text(h, "BSD"); 847 } else { 848 print_text(h, "BSD"); 849 return(0); 850 } 851 852 if (NULL != (n = n->next)) { 853 h->flags |= HTML_NOSPACE; 854 print_text(h, "-"); 855 h->flags |= HTML_NOSPACE; 856 print_text(h, n->string); 857 } 858 859 return(0); 860 } 861 862 /* ARGSUSED */ 863 static int 864 mdoc_it_pre(MDOC_ARGS) 865 { 866 struct roffsu su; 867 enum mdoc_list type; 868 struct htmlpair tag[2]; 869 const struct mdoc_node *bl; 870 871 bl = n->parent; 872 while (bl && MDOC_Bl != bl->tok) 873 bl = bl->parent; 874 875 assert(bl); 876 877 type = bl->norm->Bl.type; 878 879 assert(lists[type]); 880 PAIR_CLASS_INIT(&tag[0], lists[type]); 881 882 bufinit(h); 883 884 if (MDOC_HEAD == n->type) { 885 switch (type) { 886 case(LIST_bullet): 887 /* FALLTHROUGH */ 888 case(LIST_dash): 889 /* FALLTHROUGH */ 890 case(LIST_item): 891 /* FALLTHROUGH */ 892 case(LIST_hyphen): 893 /* FALLTHROUGH */ 894 case(LIST_enum): 895 return(0); 896 case(LIST_diag): 897 /* FALLTHROUGH */ 898 case(LIST_hang): 899 /* FALLTHROUGH */ 900 case(LIST_inset): 901 /* FALLTHROUGH */ 902 case(LIST_ohang): 903 /* FALLTHROUGH */ 904 case(LIST_tag): 905 SCALE_VS_INIT(&su, ! bl->norm->Bl.comp); 906 bufcat_su(h, "margin-top", &su); 907 PAIR_STYLE_INIT(&tag[1], h); 908 print_otag(h, TAG_DT, 2, tag); 909 if (LIST_diag != type) 910 break; 911 PAIR_CLASS_INIT(&tag[0], "diag"); 912 print_otag(h, TAG_B, 1, tag); 913 break; 914 case(LIST_column): 915 break; 916 default: 917 break; 918 } 919 } else if (MDOC_BODY == n->type) { 920 switch (type) { 921 case(LIST_bullet): 922 /* FALLTHROUGH */ 923 case(LIST_hyphen): 924 /* FALLTHROUGH */ 925 case(LIST_dash): 926 /* FALLTHROUGH */ 927 case(LIST_enum): 928 /* FALLTHROUGH */ 929 case(LIST_item): 930 SCALE_VS_INIT(&su, ! bl->norm->Bl.comp); 931 bufcat_su(h, "margin-top", &su); 932 PAIR_STYLE_INIT(&tag[1], h); 933 print_otag(h, TAG_LI, 2, tag); 934 break; 935 case(LIST_diag): 936 /* FALLTHROUGH */ 937 case(LIST_hang): 938 /* FALLTHROUGH */ 939 case(LIST_inset): 940 /* FALLTHROUGH */ 941 case(LIST_ohang): 942 /* FALLTHROUGH */ 943 case(LIST_tag): 944 if (NULL == bl->norm->Bl.width) { 945 print_otag(h, TAG_DD, 1, tag); 946 break; 947 } 948 a2width(bl->norm->Bl.width, &su); 949 bufcat_su(h, "margin-left", &su); 950 PAIR_STYLE_INIT(&tag[1], h); 951 print_otag(h, TAG_DD, 2, tag); 952 break; 953 case(LIST_column): 954 SCALE_VS_INIT(&su, ! bl->norm->Bl.comp); 955 bufcat_su(h, "margin-top", &su); 956 PAIR_STYLE_INIT(&tag[1], h); 957 print_otag(h, TAG_TD, 2, tag); 958 break; 959 default: 960 break; 961 } 962 } else { 963 switch (type) { 964 case (LIST_column): 965 print_otag(h, TAG_TR, 1, tag); 966 break; 967 default: 968 break; 969 } 970 } 971 972 return(1); 973 } 974 975 /* ARGSUSED */ 976 static int 977 mdoc_bl_pre(MDOC_ARGS) 978 { 979 int i; 980 struct htmlpair tag[3]; 981 struct roffsu su; 982 char buf[BUFSIZ]; 983 984 bufinit(h); 985 986 if (MDOC_BODY == n->type) { 987 if (LIST_column == n->norm->Bl.type) 988 print_otag(h, TAG_TBODY, 0, NULL); 989 return(1); 990 } 991 992 if (MDOC_HEAD == n->type) { 993 if (LIST_column != n->norm->Bl.type) 994 return(0); 995 996 /* 997 * For each column, print out the <COL> tag with our 998 * suggested width. The last column gets min-width, as 999 * in terminal mode it auto-sizes to the width of the 1000 * screen and we want to preserve that behaviour. 1001 */ 1002 1003 for (i = 0; i < (int)n->norm->Bl.ncols; i++) { 1004 a2width(n->norm->Bl.cols[i], &su); 1005 if (i < (int)n->norm->Bl.ncols - 1) 1006 bufcat_su(h, "width", &su); 1007 else 1008 bufcat_su(h, "min-width", &su); 1009 PAIR_STYLE_INIT(&tag[0], h); 1010 print_otag(h, TAG_COL, 1, tag); 1011 } 1012 1013 return(0); 1014 } 1015 1016 SCALE_VS_INIT(&su, 0); 1017 bufcat_su(h, "margin-top", &su); 1018 bufcat_su(h, "margin-bottom", &su); 1019 PAIR_STYLE_INIT(&tag[0], h); 1020 1021 assert(lists[n->norm->Bl.type]); 1022 strlcpy(buf, "list ", BUFSIZ); 1023 strlcat(buf, lists[n->norm->Bl.type], BUFSIZ); 1024 PAIR_INIT(&tag[1], ATTR_CLASS, buf); 1025 1026 /* Set the block's left-hand margin. */ 1027 1028 if (n->norm->Bl.offs) { 1029 a2offs(n->norm->Bl.offs, &su); 1030 bufcat_su(h, "margin-left", &su); 1031 } 1032 1033 switch (n->norm->Bl.type) { 1034 case(LIST_bullet): 1035 /* FALLTHROUGH */ 1036 case(LIST_dash): 1037 /* FALLTHROUGH */ 1038 case(LIST_hyphen): 1039 /* FALLTHROUGH */ 1040 case(LIST_item): 1041 print_otag(h, TAG_UL, 2, tag); 1042 break; 1043 case(LIST_enum): 1044 print_otag(h, TAG_OL, 2, tag); 1045 break; 1046 case(LIST_diag): 1047 /* FALLTHROUGH */ 1048 case(LIST_hang): 1049 /* FALLTHROUGH */ 1050 case(LIST_inset): 1051 /* FALLTHROUGH */ 1052 case(LIST_ohang): 1053 /* FALLTHROUGH */ 1054 case(LIST_tag): 1055 print_otag(h, TAG_DL, 2, tag); 1056 break; 1057 case(LIST_column): 1058 print_otag(h, TAG_TABLE, 2, tag); 1059 break; 1060 default: 1061 abort(); 1062 /* NOTREACHED */ 1063 } 1064 1065 return(1); 1066 } 1067 1068 /* ARGSUSED */ 1069 static int 1070 mdoc_ex_pre(MDOC_ARGS) 1071 { 1072 struct tag *t; 1073 struct htmlpair tag; 1074 int nchild; 1075 1076 if (n->prev) 1077 print_otag(h, TAG_BR, 0, NULL); 1078 1079 PAIR_CLASS_INIT(&tag, "utility"); 1080 1081 print_text(h, "The"); 1082 1083 nchild = n->nchild; 1084 for (n = n->child; n; n = n->next) { 1085 assert(MDOC_TEXT == n->type); 1086 1087 t = print_otag(h, TAG_B, 1, &tag); 1088 print_text(h, n->string); 1089 print_tagq(h, t); 1090 1091 if (nchild > 2 && n->next) { 1092 h->flags |= HTML_NOSPACE; 1093 print_text(h, ","); 1094 } 1095 1096 if (n->next && NULL == n->next->next) 1097 print_text(h, "and"); 1098 } 1099 1100 if (nchild > 1) 1101 print_text(h, "utilities exit"); 1102 else 1103 print_text(h, "utility exits"); 1104 1105 print_text(h, "0 on success, and >0 if an error occurs."); 1106 return(0); 1107 } 1108 1109 1110 /* ARGSUSED */ 1111 static int 1112 mdoc_em_pre(MDOC_ARGS) 1113 { 1114 struct htmlpair tag; 1115 1116 PAIR_CLASS_INIT(&tag, "emph"); 1117 print_otag(h, TAG_SPAN, 1, &tag); 1118 return(1); 1119 } 1120 1121 1122 /* ARGSUSED */ 1123 static int 1124 mdoc_d1_pre(MDOC_ARGS) 1125 { 1126 struct htmlpair tag[2]; 1127 struct roffsu su; 1128 1129 if (MDOC_BLOCK != n->type) 1130 return(1); 1131 1132 SCALE_VS_INIT(&su, 0); 1133 bufinit(h); 1134 bufcat_su(h, "margin-top", &su); 1135 bufcat_su(h, "margin-bottom", &su); 1136 PAIR_STYLE_INIT(&tag[0], h); 1137 print_otag(h, TAG_BLOCKQUOTE, 1, tag); 1138 1139 /* BLOCKQUOTE needs a block body. */ 1140 1141 PAIR_CLASS_INIT(&tag[0], "display"); 1142 print_otag(h, TAG_DIV, 1, tag); 1143 1144 if (MDOC_Dl == n->tok) { 1145 PAIR_CLASS_INIT(&tag[0], "lit"); 1146 print_otag(h, TAG_CODE, 1, tag); 1147 } 1148 1149 return(1); 1150 } 1151 1152 1153 /* ARGSUSED */ 1154 static int 1155 mdoc_sx_pre(MDOC_ARGS) 1156 { 1157 struct htmlpair tag[2]; 1158 1159 bufinit(h); 1160 bufcat(h, "#x"); 1161 1162 for (n = n->child; n; ) { 1163 bufcat_id(h, n->string); 1164 if (NULL != (n = n->next)) 1165 bufcat_id(h, " "); 1166 } 1167 1168 PAIR_CLASS_INIT(&tag[0], "link-sec"); 1169 PAIR_HREF_INIT(&tag[1], h->buf); 1170 1171 print_otag(h, TAG_I, 1, tag); 1172 print_otag(h, TAG_A, 2, tag); 1173 return(1); 1174 } 1175 1176 1177 /* ARGSUSED */ 1178 static int 1179 mdoc_bd_pre(MDOC_ARGS) 1180 { 1181 struct htmlpair tag[2]; 1182 int comp, sv; 1183 const struct mdoc_node *nn; 1184 struct roffsu su; 1185 1186 if (MDOC_HEAD == n->type) 1187 return(0); 1188 1189 if (MDOC_BLOCK == n->type) { 1190 comp = n->norm->Bd.comp; 1191 for (nn = n; nn && ! comp; nn = nn->parent) { 1192 if (MDOC_BLOCK != nn->type) 1193 continue; 1194 if (MDOC_Ss == nn->tok || MDOC_Sh == nn->tok) 1195 comp = 1; 1196 if (nn->prev) 1197 break; 1198 } 1199 if ( ! comp) 1200 print_otag(h, TAG_P, 0, NULL); 1201 return(1); 1202 } 1203 1204 SCALE_HS_INIT(&su, 0); 1205 if (n->norm->Bd.offs) 1206 a2offs(n->norm->Bd.offs, &su); 1207 1208 bufinit(h); 1209 bufcat_su(h, "margin-left", &su); 1210 PAIR_STYLE_INIT(&tag[0], h); 1211 1212 if (DISP_unfilled != n->norm->Bd.type && 1213 DISP_literal != n->norm->Bd.type) { 1214 PAIR_CLASS_INIT(&tag[1], "display"); 1215 print_otag(h, TAG_DIV, 2, tag); 1216 return(1); 1217 } 1218 1219 PAIR_CLASS_INIT(&tag[1], "lit display"); 1220 print_otag(h, TAG_PRE, 2, tag); 1221 1222 /* This can be recursive: save & set our literal state. */ 1223 1224 sv = h->flags & HTML_LITERAL; 1225 h->flags |= HTML_LITERAL; 1226 1227 for (nn = n->child; nn; nn = nn->next) { 1228 print_mdoc_node(m, nn, h); 1229 /* 1230 * If the printed node flushes its own line, then we 1231 * needn't do it here as well. This is hacky, but the 1232 * notion of selective eoln whitespace is pretty dumb 1233 * anyway, so don't sweat it. 1234 */ 1235 switch (nn->tok) { 1236 case (MDOC_Sm): 1237 /* FALLTHROUGH */ 1238 case (MDOC_br): 1239 /* FALLTHROUGH */ 1240 case (MDOC_sp): 1241 /* FALLTHROUGH */ 1242 case (MDOC_Bl): 1243 /* FALLTHROUGH */ 1244 case (MDOC_D1): 1245 /* FALLTHROUGH */ 1246 case (MDOC_Dl): 1247 /* FALLTHROUGH */ 1248 case (MDOC_Lp): 1249 /* FALLTHROUGH */ 1250 case (MDOC_Pp): 1251 continue; 1252 default: 1253 break; 1254 } 1255 if (nn->next && nn->next->line == nn->line) 1256 continue; 1257 else if (nn->next) 1258 print_text(h, "\n"); 1259 1260 h->flags |= HTML_NOSPACE; 1261 } 1262 1263 if (0 == sv) 1264 h->flags &= ~HTML_LITERAL; 1265 1266 return(0); 1267 } 1268 1269 1270 /* ARGSUSED */ 1271 static int 1272 mdoc_pa_pre(MDOC_ARGS) 1273 { 1274 struct htmlpair tag; 1275 1276 PAIR_CLASS_INIT(&tag, "file"); 1277 print_otag(h, TAG_I, 1, &tag); 1278 return(1); 1279 } 1280 1281 1282 /* ARGSUSED */ 1283 static int 1284 mdoc_ad_pre(MDOC_ARGS) 1285 { 1286 struct htmlpair tag; 1287 1288 PAIR_CLASS_INIT(&tag, "addr"); 1289 print_otag(h, TAG_I, 1, &tag); 1290 return(1); 1291 } 1292 1293 1294 /* ARGSUSED */ 1295 static int 1296 mdoc_an_pre(MDOC_ARGS) 1297 { 1298 struct htmlpair tag; 1299 1300 /* TODO: -split and -nosplit (see termp_an_pre()). */ 1301 1302 PAIR_CLASS_INIT(&tag, "author"); 1303 print_otag(h, TAG_SPAN, 1, &tag); 1304 return(1); 1305 } 1306 1307 1308 /* ARGSUSED */ 1309 static int 1310 mdoc_cd_pre(MDOC_ARGS) 1311 { 1312 struct htmlpair tag; 1313 1314 synopsis_pre(h, n); 1315 PAIR_CLASS_INIT(&tag, "config"); 1316 print_otag(h, TAG_B, 1, &tag); 1317 return(1); 1318 } 1319 1320 1321 /* ARGSUSED */ 1322 static int 1323 mdoc_dv_pre(MDOC_ARGS) 1324 { 1325 struct htmlpair tag; 1326 1327 PAIR_CLASS_INIT(&tag, "define"); 1328 print_otag(h, TAG_SPAN, 1, &tag); 1329 return(1); 1330 } 1331 1332 1333 /* ARGSUSED */ 1334 static int 1335 mdoc_ev_pre(MDOC_ARGS) 1336 { 1337 struct htmlpair tag; 1338 1339 PAIR_CLASS_INIT(&tag, "env"); 1340 print_otag(h, TAG_SPAN, 1, &tag); 1341 return(1); 1342 } 1343 1344 1345 /* ARGSUSED */ 1346 static int 1347 mdoc_er_pre(MDOC_ARGS) 1348 { 1349 struct htmlpair tag; 1350 1351 PAIR_CLASS_INIT(&tag, "errno"); 1352 print_otag(h, TAG_SPAN, 1, &tag); 1353 return(1); 1354 } 1355 1356 1357 /* ARGSUSED */ 1358 static int 1359 mdoc_fa_pre(MDOC_ARGS) 1360 { 1361 const struct mdoc_node *nn; 1362 struct htmlpair tag; 1363 struct tag *t; 1364 1365 PAIR_CLASS_INIT(&tag, "farg"); 1366 if (n->parent->tok != MDOC_Fo) { 1367 print_otag(h, TAG_I, 1, &tag); 1368 return(1); 1369 } 1370 1371 for (nn = n->child; nn; nn = nn->next) { 1372 t = print_otag(h, TAG_I, 1, &tag); 1373 print_text(h, nn->string); 1374 print_tagq(h, t); 1375 if (nn->next) { 1376 h->flags |= HTML_NOSPACE; 1377 print_text(h, ","); 1378 } 1379 } 1380 1381 if (n->child && n->next && n->next->tok == MDOC_Fa) { 1382 h->flags |= HTML_NOSPACE; 1383 print_text(h, ","); 1384 } 1385 1386 return(0); 1387 } 1388 1389 1390 /* ARGSUSED */ 1391 static int 1392 mdoc_fd_pre(MDOC_ARGS) 1393 { 1394 struct htmlpair tag[2]; 1395 char buf[BUFSIZ]; 1396 size_t sz; 1397 int i; 1398 struct tag *t; 1399 1400 synopsis_pre(h, n); 1401 1402 if (NULL == (n = n->child)) 1403 return(0); 1404 1405 assert(MDOC_TEXT == n->type); 1406 1407 if (strcmp(n->string, "#include")) { 1408 PAIR_CLASS_INIT(&tag[0], "macro"); 1409 print_otag(h, TAG_B, 1, tag); 1410 return(1); 1411 } 1412 1413 PAIR_CLASS_INIT(&tag[0], "includes"); 1414 print_otag(h, TAG_B, 1, tag); 1415 print_text(h, n->string); 1416 1417 if (NULL != (n = n->next)) { 1418 assert(MDOC_TEXT == n->type); 1419 strlcpy(buf, '<' == *n->string || '"' == *n->string ? 1420 n->string + 1 : n->string, BUFSIZ); 1421 1422 sz = strlen(buf); 1423 if (sz && ('>' == buf[sz - 1] || '"' == buf[sz - 1])) 1424 buf[sz - 1] = '\0'; 1425 1426 PAIR_CLASS_INIT(&tag[0], "link-includes"); 1427 1428 i = 1; 1429 if (h->base_includes) { 1430 buffmt_includes(h, buf); 1431 PAIR_HREF_INIT(&tag[i], h->buf); 1432 i++; 1433 } 1434 1435 t = print_otag(h, TAG_A, i, tag); 1436 print_text(h, n->string); 1437 print_tagq(h, t); 1438 1439 n = n->next; 1440 } 1441 1442 for ( ; n; n = n->next) { 1443 assert(MDOC_TEXT == n->type); 1444 print_text(h, n->string); 1445 } 1446 1447 return(0); 1448 } 1449 1450 1451 /* ARGSUSED */ 1452 static int 1453 mdoc_vt_pre(MDOC_ARGS) 1454 { 1455 struct htmlpair tag; 1456 1457 if (MDOC_BLOCK == n->type) { 1458 synopsis_pre(h, n); 1459 return(1); 1460 } else if (MDOC_ELEM == n->type) { 1461 synopsis_pre(h, n); 1462 } else if (MDOC_HEAD == n->type) 1463 return(0); 1464 1465 PAIR_CLASS_INIT(&tag, "type"); 1466 print_otag(h, TAG_SPAN, 1, &tag); 1467 return(1); 1468 } 1469 1470 1471 /* ARGSUSED */ 1472 static int 1473 mdoc_ft_pre(MDOC_ARGS) 1474 { 1475 struct htmlpair tag; 1476 1477 synopsis_pre(h, n); 1478 PAIR_CLASS_INIT(&tag, "ftype"); 1479 print_otag(h, TAG_I, 1, &tag); 1480 return(1); 1481 } 1482 1483 1484 /* ARGSUSED */ 1485 static int 1486 mdoc_fn_pre(MDOC_ARGS) 1487 { 1488 struct tag *t; 1489 struct htmlpair tag[2]; 1490 char nbuf[BUFSIZ]; 1491 const char *sp, *ep; 1492 int sz, i, pretty; 1493 1494 pretty = MDOC_SYNPRETTY & n->flags; 1495 synopsis_pre(h, n); 1496 1497 /* Split apart into type and name. */ 1498 assert(n->child->string); 1499 sp = n->child->string; 1500 1501 ep = strchr(sp, ' '); 1502 if (NULL != ep) { 1503 PAIR_CLASS_INIT(&tag[0], "ftype"); 1504 t = print_otag(h, TAG_I, 1, tag); 1505 1506 while (ep) { 1507 sz = MIN((int)(ep - sp), BUFSIZ - 1); 1508 (void)memcpy(nbuf, sp, (size_t)sz); 1509 nbuf[sz] = '\0'; 1510 print_text(h, nbuf); 1511 sp = ++ep; 1512 ep = strchr(sp, ' '); 1513 } 1514 print_tagq(h, t); 1515 } 1516 1517 PAIR_CLASS_INIT(&tag[0], "fname"); 1518 1519 /* 1520 * FIXME: only refer to IDs that we know exist. 1521 */ 1522 1523 #if 0 1524 if (MDOC_SYNPRETTY & n->flags) { 1525 nbuf[0] = '\0'; 1526 html_idcat(nbuf, sp, BUFSIZ); 1527 PAIR_ID_INIT(&tag[1], nbuf); 1528 } else { 1529 strlcpy(nbuf, "#", BUFSIZ); 1530 html_idcat(nbuf, sp, BUFSIZ); 1531 PAIR_HREF_INIT(&tag[1], nbuf); 1532 } 1533 #endif 1534 1535 t = print_otag(h, TAG_B, 1, tag); 1536 1537 if (sp) { 1538 strlcpy(nbuf, sp, BUFSIZ); 1539 print_text(h, nbuf); 1540 } 1541 1542 print_tagq(h, t); 1543 1544 h->flags |= HTML_NOSPACE; 1545 print_text(h, "("); 1546 h->flags |= HTML_NOSPACE; 1547 1548 PAIR_CLASS_INIT(&tag[0], "farg"); 1549 bufinit(h); 1550 bufcat_style(h, "white-space", "nowrap"); 1551 PAIR_STYLE_INIT(&tag[1], h); 1552 1553 for (n = n->child->next; n; n = n->next) { 1554 i = 1; 1555 if (MDOC_SYNPRETTY & n->flags) 1556 i = 2; 1557 t = print_otag(h, TAG_I, i, tag); 1558 print_text(h, n->string); 1559 print_tagq(h, t); 1560 if (n->next) { 1561 h->flags |= HTML_NOSPACE; 1562 print_text(h, ","); 1563 } 1564 } 1565 1566 h->flags |= HTML_NOSPACE; 1567 print_text(h, ")"); 1568 1569 if (pretty) { 1570 h->flags |= HTML_NOSPACE; 1571 print_text(h, ";"); 1572 } 1573 1574 return(0); 1575 } 1576 1577 1578 /* ARGSUSED */ 1579 static int 1580 mdoc_sm_pre(MDOC_ARGS) 1581 { 1582 1583 assert(n->child && MDOC_TEXT == n->child->type); 1584 if (0 == strcmp("on", n->child->string)) { 1585 /* 1586 * FIXME: no p->col to check. Thus, if we have 1587 * .Bd -literal 1588 * .Sm off 1589 * 1 2 1590 * .Sm on 1591 * 3 1592 * .Ed 1593 * the "3" is preceded by a space. 1594 */ 1595 h->flags &= ~HTML_NOSPACE; 1596 h->flags &= ~HTML_NONOSPACE; 1597 } else 1598 h->flags |= HTML_NONOSPACE; 1599 1600 return(0); 1601 } 1602 1603 /* ARGSUSED */ 1604 static int 1605 mdoc_pp_pre(MDOC_ARGS) 1606 { 1607 1608 print_otag(h, TAG_P, 0, NULL); 1609 return(0); 1610 1611 } 1612 1613 /* ARGSUSED */ 1614 static int 1615 mdoc_sp_pre(MDOC_ARGS) 1616 { 1617 struct roffsu su; 1618 struct htmlpair tag; 1619 1620 SCALE_VS_INIT(&su, 1); 1621 1622 if (MDOC_sp == n->tok) { 1623 if (NULL != (n = n->child)) 1624 if ( ! a2roffsu(n->string, &su, SCALE_VS)) 1625 SCALE_VS_INIT(&su, atoi(n->string)); 1626 } else 1627 su.scale = 0; 1628 1629 bufinit(h); 1630 bufcat_su(h, "height", &su); 1631 PAIR_STYLE_INIT(&tag, h); 1632 print_otag(h, TAG_DIV, 1, &tag); 1633 1634 /* So the div isn't empty: */ 1635 print_text(h, "\\~"); 1636 1637 return(0); 1638 1639 } 1640 1641 /* ARGSUSED */ 1642 static int 1643 mdoc_lk_pre(MDOC_ARGS) 1644 { 1645 struct htmlpair tag[2]; 1646 1647 if (NULL == (n = n->child)) 1648 return(0); 1649 1650 assert(MDOC_TEXT == n->type); 1651 1652 PAIR_CLASS_INIT(&tag[0], "link-ext"); 1653 PAIR_HREF_INIT(&tag[1], n->string); 1654 1655 print_otag(h, TAG_A, 2, tag); 1656 1657 if (NULL == n->next) 1658 print_text(h, n->string); 1659 1660 for (n = n->next; n; n = n->next) 1661 print_text(h, n->string); 1662 1663 return(0); 1664 } 1665 1666 1667 /* ARGSUSED */ 1668 static int 1669 mdoc_mt_pre(MDOC_ARGS) 1670 { 1671 struct htmlpair tag[2]; 1672 struct tag *t; 1673 1674 PAIR_CLASS_INIT(&tag[0], "link-mail"); 1675 1676 for (n = n->child; n; n = n->next) { 1677 assert(MDOC_TEXT == n->type); 1678 1679 bufinit(h); 1680 bufcat(h, "mailto:"); 1681 bufcat(h, n->string); 1682 1683 PAIR_HREF_INIT(&tag[1], h->buf); 1684 t = print_otag(h, TAG_A, 2, tag); 1685 print_text(h, n->string); 1686 print_tagq(h, t); 1687 } 1688 1689 return(0); 1690 } 1691 1692 1693 /* ARGSUSED */ 1694 static int 1695 mdoc_fo_pre(MDOC_ARGS) 1696 { 1697 struct htmlpair tag; 1698 struct tag *t; 1699 1700 if (MDOC_BODY == n->type) { 1701 h->flags |= HTML_NOSPACE; 1702 print_text(h, "("); 1703 h->flags |= HTML_NOSPACE; 1704 return(1); 1705 } else if (MDOC_BLOCK == n->type) { 1706 synopsis_pre(h, n); 1707 return(1); 1708 } 1709 1710 /* XXX: we drop non-initial arguments as per groff. */ 1711 1712 assert(n->child); 1713 assert(n->child->string); 1714 1715 PAIR_CLASS_INIT(&tag, "fname"); 1716 t = print_otag(h, TAG_B, 1, &tag); 1717 print_text(h, n->child->string); 1718 print_tagq(h, t); 1719 return(0); 1720 } 1721 1722 1723 /* ARGSUSED */ 1724 static void 1725 mdoc_fo_post(MDOC_ARGS) 1726 { 1727 1728 if (MDOC_BODY != n->type) 1729 return; 1730 h->flags |= HTML_NOSPACE; 1731 print_text(h, ")"); 1732 h->flags |= HTML_NOSPACE; 1733 print_text(h, ";"); 1734 } 1735 1736 1737 /* ARGSUSED */ 1738 static int 1739 mdoc_in_pre(MDOC_ARGS) 1740 { 1741 struct tag *t; 1742 struct htmlpair tag[2]; 1743 int i; 1744 1745 synopsis_pre(h, n); 1746 1747 PAIR_CLASS_INIT(&tag[0], "includes"); 1748 print_otag(h, TAG_B, 1, tag); 1749 1750 /* 1751 * The first argument of the `In' gets special treatment as 1752 * being a linked value. Subsequent values are printed 1753 * afterward. groff does similarly. This also handles the case 1754 * of no children. 1755 */ 1756 1757 if (MDOC_SYNPRETTY & n->flags && MDOC_LINE & n->flags) 1758 print_text(h, "#include"); 1759 1760 print_text(h, "<"); 1761 h->flags |= HTML_NOSPACE; 1762 1763 if (NULL != (n = n->child)) { 1764 assert(MDOC_TEXT == n->type); 1765 1766 PAIR_CLASS_INIT(&tag[0], "link-includes"); 1767 1768 i = 1; 1769 if (h->base_includes) { 1770 buffmt_includes(h, n->string); 1771 PAIR_HREF_INIT(&tag[i], h->buf); 1772 i++; 1773 } 1774 1775 t = print_otag(h, TAG_A, i, tag); 1776 print_text(h, n->string); 1777 print_tagq(h, t); 1778 1779 n = n->next; 1780 } 1781 1782 h->flags |= HTML_NOSPACE; 1783 print_text(h, ">"); 1784 1785 for ( ; n; n = n->next) { 1786 assert(MDOC_TEXT == n->type); 1787 print_text(h, n->string); 1788 } 1789 1790 return(0); 1791 } 1792 1793 1794 /* ARGSUSED */ 1795 static int 1796 mdoc_ic_pre(MDOC_ARGS) 1797 { 1798 struct htmlpair tag; 1799 1800 PAIR_CLASS_INIT(&tag, "cmd"); 1801 print_otag(h, TAG_B, 1, &tag); 1802 return(1); 1803 } 1804 1805 1806 /* ARGSUSED */ 1807 static int 1808 mdoc_rv_pre(MDOC_ARGS) 1809 { 1810 struct htmlpair tag; 1811 struct tag *t; 1812 int nchild; 1813 1814 if (n->prev) 1815 print_otag(h, TAG_BR, 0, NULL); 1816 1817 PAIR_CLASS_INIT(&tag, "fname"); 1818 1819 print_text(h, "The"); 1820 1821 nchild = n->nchild; 1822 for (n = n->child; n; n = n->next) { 1823 assert(MDOC_TEXT == n->type); 1824 1825 t = print_otag(h, TAG_B, 1, &tag); 1826 print_text(h, n->string); 1827 print_tagq(h, t); 1828 1829 h->flags |= HTML_NOSPACE; 1830 print_text(h, "()"); 1831 1832 if (nchild > 2 && n->next) { 1833 h->flags |= HTML_NOSPACE; 1834 print_text(h, ","); 1835 } 1836 1837 if (n->next && NULL == n->next->next) 1838 print_text(h, "and"); 1839 } 1840 1841 if (nchild > 1) 1842 print_text(h, "functions return"); 1843 else 1844 print_text(h, "function returns"); 1845 1846 print_text(h, "the value 0 if successful; otherwise the value " 1847 "-1 is returned and the global variable"); 1848 1849 PAIR_CLASS_INIT(&tag, "var"); 1850 t = print_otag(h, TAG_B, 1, &tag); 1851 print_text(h, "errno"); 1852 print_tagq(h, t); 1853 print_text(h, "is set to indicate the error."); 1854 return(0); 1855 } 1856 1857 1858 /* ARGSUSED */ 1859 static int 1860 mdoc_va_pre(MDOC_ARGS) 1861 { 1862 struct htmlpair tag; 1863 1864 PAIR_CLASS_INIT(&tag, "var"); 1865 print_otag(h, TAG_B, 1, &tag); 1866 return(1); 1867 } 1868 1869 1870 /* ARGSUSED */ 1871 static int 1872 mdoc_ap_pre(MDOC_ARGS) 1873 { 1874 1875 h->flags |= HTML_NOSPACE; 1876 print_text(h, "\\(aq"); 1877 h->flags |= HTML_NOSPACE; 1878 return(1); 1879 } 1880 1881 1882 /* ARGSUSED */ 1883 static int 1884 mdoc_bf_pre(MDOC_ARGS) 1885 { 1886 struct htmlpair tag[2]; 1887 struct roffsu su; 1888 1889 if (MDOC_HEAD == n->type) 1890 return(0); 1891 else if (MDOC_BODY != n->type) 1892 return(1); 1893 1894 if (FONT_Em == n->norm->Bf.font) 1895 PAIR_CLASS_INIT(&tag[0], "emph"); 1896 else if (FONT_Sy == n->norm->Bf.font) 1897 PAIR_CLASS_INIT(&tag[0], "symb"); 1898 else if (FONT_Li == n->norm->Bf.font) 1899 PAIR_CLASS_INIT(&tag[0], "lit"); 1900 else 1901 PAIR_CLASS_INIT(&tag[0], "none"); 1902 1903 /* 1904 * We want this to be inline-formatted, but needs to be div to 1905 * accept block children. 1906 */ 1907 bufinit(h); 1908 bufcat_style(h, "display", "inline"); 1909 SCALE_HS_INIT(&su, 1); 1910 /* Needs a left-margin for spacing. */ 1911 bufcat_su(h, "margin-left", &su); 1912 PAIR_STYLE_INIT(&tag[1], h); 1913 print_otag(h, TAG_DIV, 2, tag); 1914 return(1); 1915 } 1916 1917 1918 /* ARGSUSED */ 1919 static int 1920 mdoc_ms_pre(MDOC_ARGS) 1921 { 1922 struct htmlpair tag; 1923 1924 PAIR_CLASS_INIT(&tag, "symb"); 1925 print_otag(h, TAG_SPAN, 1, &tag); 1926 return(1); 1927 } 1928 1929 1930 /* ARGSUSED */ 1931 static int 1932 mdoc_igndelim_pre(MDOC_ARGS) 1933 { 1934 1935 h->flags |= HTML_IGNDELIM; 1936 return(1); 1937 } 1938 1939 1940 /* ARGSUSED */ 1941 static void 1942 mdoc_pf_post(MDOC_ARGS) 1943 { 1944 1945 h->flags |= HTML_NOSPACE; 1946 } 1947 1948 1949 /* ARGSUSED */ 1950 static int 1951 mdoc_rs_pre(MDOC_ARGS) 1952 { 1953 struct htmlpair tag; 1954 1955 if (MDOC_BLOCK != n->type) 1956 return(1); 1957 1958 if (n->prev && SEC_SEE_ALSO == n->sec) 1959 print_otag(h, TAG_P, 0, NULL); 1960 1961 PAIR_CLASS_INIT(&tag, "ref"); 1962 print_otag(h, TAG_SPAN, 1, &tag); 1963 return(1); 1964 } 1965 1966 1967 1968 /* ARGSUSED */ 1969 static int 1970 mdoc_li_pre(MDOC_ARGS) 1971 { 1972 struct htmlpair tag; 1973 1974 PAIR_CLASS_INIT(&tag, "lit"); 1975 print_otag(h, TAG_CODE, 1, &tag); 1976 return(1); 1977 } 1978 1979 1980 /* ARGSUSED */ 1981 static int 1982 mdoc_sy_pre(MDOC_ARGS) 1983 { 1984 struct htmlpair tag; 1985 1986 PAIR_CLASS_INIT(&tag, "symb"); 1987 print_otag(h, TAG_SPAN, 1, &tag); 1988 return(1); 1989 } 1990 1991 1992 /* ARGSUSED */ 1993 static int 1994 mdoc_bt_pre(MDOC_ARGS) 1995 { 1996 1997 print_text(h, "is currently in beta test."); 1998 return(0); 1999 } 2000 2001 2002 /* ARGSUSED */ 2003 static int 2004 mdoc_ud_pre(MDOC_ARGS) 2005 { 2006 2007 print_text(h, "currently under development."); 2008 return(0); 2009 } 2010 2011 2012 /* ARGSUSED */ 2013 static int 2014 mdoc_lb_pre(MDOC_ARGS) 2015 { 2016 struct htmlpair tag; 2017 2018 if (SEC_LIBRARY == n->sec && MDOC_LINE & n->flags && n->prev) 2019 print_otag(h, TAG_BR, 0, NULL); 2020 2021 PAIR_CLASS_INIT(&tag, "lib"); 2022 print_otag(h, TAG_SPAN, 1, &tag); 2023 return(1); 2024 } 2025 2026 2027 /* ARGSUSED */ 2028 static int 2029 mdoc__x_pre(MDOC_ARGS) 2030 { 2031 struct htmlpair tag[2]; 2032 enum htmltag t; 2033 2034 t = TAG_SPAN; 2035 2036 switch (n->tok) { 2037 case(MDOC__A): 2038 PAIR_CLASS_INIT(&tag[0], "ref-auth"); 2039 if (n->prev && MDOC__A == n->prev->tok) 2040 if (NULL == n->next || MDOC__A != n->next->tok) 2041 print_text(h, "and"); 2042 break; 2043 case(MDOC__B): 2044 PAIR_CLASS_INIT(&tag[0], "ref-book"); 2045 t = TAG_I; 2046 break; 2047 case(MDOC__C): 2048 PAIR_CLASS_INIT(&tag[0], "ref-city"); 2049 break; 2050 case(MDOC__D): 2051 PAIR_CLASS_INIT(&tag[0], "ref-date"); 2052 break; 2053 case(MDOC__I): 2054 PAIR_CLASS_INIT(&tag[0], "ref-issue"); 2055 t = TAG_I; 2056 break; 2057 case(MDOC__J): 2058 PAIR_CLASS_INIT(&tag[0], "ref-jrnl"); 2059 t = TAG_I; 2060 break; 2061 case(MDOC__N): 2062 PAIR_CLASS_INIT(&tag[0], "ref-num"); 2063 break; 2064 case(MDOC__O): 2065 PAIR_CLASS_INIT(&tag[0], "ref-opt"); 2066 break; 2067 case(MDOC__P): 2068 PAIR_CLASS_INIT(&tag[0], "ref-page"); 2069 break; 2070 case(MDOC__Q): 2071 PAIR_CLASS_INIT(&tag[0], "ref-corp"); 2072 break; 2073 case(MDOC__R): 2074 PAIR_CLASS_INIT(&tag[0], "ref-rep"); 2075 break; 2076 case(MDOC__T): 2077 PAIR_CLASS_INIT(&tag[0], "ref-title"); 2078 break; 2079 case(MDOC__U): 2080 PAIR_CLASS_INIT(&tag[0], "link-ref"); 2081 break; 2082 case(MDOC__V): 2083 PAIR_CLASS_INIT(&tag[0], "ref-vol"); 2084 break; 2085 default: 2086 abort(); 2087 /* NOTREACHED */ 2088 } 2089 2090 if (MDOC__U != n->tok) { 2091 print_otag(h, t, 1, tag); 2092 return(1); 2093 } 2094 2095 PAIR_HREF_INIT(&tag[1], n->child->string); 2096 print_otag(h, TAG_A, 2, tag); 2097 2098 return(1); 2099 } 2100 2101 2102 /* ARGSUSED */ 2103 static void 2104 mdoc__x_post(MDOC_ARGS) 2105 { 2106 2107 if (MDOC__A == n->tok && n->next && MDOC__A == n->next->tok) 2108 if (NULL == n->next->next || MDOC__A != n->next->next->tok) 2109 if (NULL == n->prev || MDOC__A != n->prev->tok) 2110 return; 2111 2112 /* TODO: %U */ 2113 2114 if (NULL == n->parent || MDOC_Rs != n->parent->tok) 2115 return; 2116 2117 h->flags |= HTML_NOSPACE; 2118 print_text(h, n->next ? "," : "."); 2119 } 2120 2121 2122 /* ARGSUSED */ 2123 static int 2124 mdoc_bk_pre(MDOC_ARGS) 2125 { 2126 2127 switch (n->type) { 2128 case (MDOC_BLOCK): 2129 break; 2130 case (MDOC_HEAD): 2131 return(0); 2132 case (MDOC_BODY): 2133 if (n->parent->args || 0 == n->prev->nchild) 2134 h->flags |= HTML_PREKEEP; 2135 break; 2136 default: 2137 abort(); 2138 /* NOTREACHED */ 2139 } 2140 2141 return(1); 2142 } 2143 2144 2145 /* ARGSUSED */ 2146 static void 2147 mdoc_bk_post(MDOC_ARGS) 2148 { 2149 2150 if (MDOC_BODY == n->type) 2151 h->flags &= ~(HTML_KEEP | HTML_PREKEEP); 2152 } 2153 2154 2155 /* ARGSUSED */ 2156 static int 2157 mdoc_quote_pre(MDOC_ARGS) 2158 { 2159 struct htmlpair tag; 2160 2161 if (MDOC_BODY != n->type) 2162 return(1); 2163 2164 switch (n->tok) { 2165 case (MDOC_Ao): 2166 /* FALLTHROUGH */ 2167 case (MDOC_Aq): 2168 print_text(h, "\\(la"); 2169 break; 2170 case (MDOC_Bro): 2171 /* FALLTHROUGH */ 2172 case (MDOC_Brq): 2173 print_text(h, "\\(lC"); 2174 break; 2175 case (MDOC_Bo): 2176 /* FALLTHROUGH */ 2177 case (MDOC_Bq): 2178 print_text(h, "\\(lB"); 2179 break; 2180 case (MDOC_Oo): 2181 /* FALLTHROUGH */ 2182 case (MDOC_Op): 2183 print_text(h, "\\(lB"); 2184 h->flags |= HTML_NOSPACE; 2185 PAIR_CLASS_INIT(&tag, "opt"); 2186 print_otag(h, TAG_SPAN, 1, &tag); 2187 break; 2188 case (MDOC_Eo): 2189 break; 2190 case (MDOC_Do): 2191 /* FALLTHROUGH */ 2192 case (MDOC_Dq): 2193 /* FALLTHROUGH */ 2194 case (MDOC_Qo): 2195 /* FALLTHROUGH */ 2196 case (MDOC_Qq): 2197 print_text(h, "\\(lq"); 2198 break; 2199 case (MDOC_Po): 2200 /* FALLTHROUGH */ 2201 case (MDOC_Pq): 2202 print_text(h, "("); 2203 break; 2204 case (MDOC_Ql): 2205 print_text(h, "\\(oq"); 2206 h->flags |= HTML_NOSPACE; 2207 PAIR_CLASS_INIT(&tag, "lit"); 2208 print_otag(h, TAG_CODE, 1, &tag); 2209 break; 2210 case (MDOC_So): 2211 /* FALLTHROUGH */ 2212 case (MDOC_Sq): 2213 print_text(h, "\\(oq"); 2214 break; 2215 default: 2216 abort(); 2217 /* NOTREACHED */ 2218 } 2219 2220 h->flags |= HTML_NOSPACE; 2221 return(1); 2222 } 2223 2224 2225 /* ARGSUSED */ 2226 static void 2227 mdoc_quote_post(MDOC_ARGS) 2228 { 2229 2230 if (MDOC_BODY != n->type) 2231 return; 2232 2233 h->flags |= HTML_NOSPACE; 2234 2235 switch (n->tok) { 2236 case (MDOC_Ao): 2237 /* FALLTHROUGH */ 2238 case (MDOC_Aq): 2239 print_text(h, "\\(ra"); 2240 break; 2241 case (MDOC_Bro): 2242 /* FALLTHROUGH */ 2243 case (MDOC_Brq): 2244 print_text(h, "\\(rC"); 2245 break; 2246 case (MDOC_Oo): 2247 /* FALLTHROUGH */ 2248 case (MDOC_Op): 2249 /* FALLTHROUGH */ 2250 case (MDOC_Bo): 2251 /* FALLTHROUGH */ 2252 case (MDOC_Bq): 2253 print_text(h, "\\(rB"); 2254 break; 2255 case (MDOC_Eo): 2256 break; 2257 case (MDOC_Qo): 2258 /* FALLTHROUGH */ 2259 case (MDOC_Qq): 2260 /* FALLTHROUGH */ 2261 case (MDOC_Do): 2262 /* FALLTHROUGH */ 2263 case (MDOC_Dq): 2264 print_text(h, "\\(rq"); 2265 break; 2266 case (MDOC_Po): 2267 /* FALLTHROUGH */ 2268 case (MDOC_Pq): 2269 print_text(h, ")"); 2270 break; 2271 case (MDOC_Ql): 2272 /* FALLTHROUGH */ 2273 case (MDOC_So): 2274 /* FALLTHROUGH */ 2275 case (MDOC_Sq): 2276 print_text(h, "\\(aq"); 2277 break; 2278 default: 2279 abort(); 2280 /* NOTREACHED */ 2281 } 2282 } 2283 2284