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