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