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