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