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