1 /* $Vendor-Id: mdoc_html.c,v 1.163 2011/04/04 22:38:26 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 h->flags |= HTML_NOSPACE; 1562 1563 bufinit(h); 1564 PAIR_CLASS_INIT(&tag[0], "farg"); 1565 bufcat_style(h, "white-space", "nowrap"); 1566 PAIR_STYLE_INIT(&tag[1], h); 1567 1568 for (n = n->child->next; n; n = n->next) { 1569 i = 1; 1570 if (MDOC_SYNPRETTY & n->flags) 1571 i = 2; 1572 t = print_otag(h, TAG_I, i, tag); 1573 print_text(h, n->string); 1574 print_tagq(h, t); 1575 if (n->next) { 1576 h->flags |= HTML_NOSPACE; 1577 print_text(h, ","); 1578 } 1579 } 1580 1581 h->flags |= HTML_NOSPACE; 1582 print_text(h, ")"); 1583 1584 if (pretty) { 1585 h->flags |= HTML_NOSPACE; 1586 print_text(h, ";"); 1587 } 1588 1589 return(0); 1590 } 1591 1592 1593 /* ARGSUSED */ 1594 static int 1595 mdoc_sm_pre(MDOC_ARGS) 1596 { 1597 1598 assert(n->child && MDOC_TEXT == n->child->type); 1599 if (0 == strcmp("on", n->child->string)) { 1600 /* 1601 * FIXME: no p->col to check. Thus, if we have 1602 * .Bd -literal 1603 * .Sm off 1604 * 1 2 1605 * .Sm on 1606 * 3 1607 * .Ed 1608 * the "3" is preceded by a space. 1609 */ 1610 h->flags &= ~HTML_NOSPACE; 1611 h->flags &= ~HTML_NONOSPACE; 1612 } else 1613 h->flags |= HTML_NONOSPACE; 1614 1615 return(0); 1616 } 1617 1618 /* ARGSUSED */ 1619 static int 1620 mdoc_pp_pre(MDOC_ARGS) 1621 { 1622 1623 print_otag(h, TAG_P, 0, NULL); 1624 return(0); 1625 1626 } 1627 1628 /* ARGSUSED */ 1629 static int 1630 mdoc_sp_pre(MDOC_ARGS) 1631 { 1632 struct roffsu su; 1633 struct htmlpair tag; 1634 1635 SCALE_VS_INIT(&su, 1); 1636 1637 if (MDOC_sp == n->tok) { 1638 if (n->child) 1639 a2roffsu(n->child->string, &su, SCALE_VS); 1640 } else 1641 su.scale = 0; 1642 1643 bufcat_su(h, "height", &su); 1644 PAIR_STYLE_INIT(&tag, h); 1645 print_otag(h, TAG_DIV, 1, &tag); 1646 1647 /* So the div isn't empty: */ 1648 print_text(h, "\\~"); 1649 1650 return(0); 1651 1652 } 1653 1654 /* ARGSUSED */ 1655 static int 1656 mdoc_lk_pre(MDOC_ARGS) 1657 { 1658 struct htmlpair tag[2]; 1659 1660 if (NULL == (n = n->child)) 1661 return(0); 1662 1663 assert(MDOC_TEXT == n->type); 1664 1665 PAIR_CLASS_INIT(&tag[0], "link-ext"); 1666 PAIR_HREF_INIT(&tag[1], n->string); 1667 1668 print_otag(h, TAG_A, 2, tag); 1669 1670 for (n = n->next; n; n = n->next) { 1671 assert(MDOC_TEXT == n->type); 1672 print_text(h, n->string); 1673 } 1674 1675 return(0); 1676 } 1677 1678 1679 /* ARGSUSED */ 1680 static int 1681 mdoc_mt_pre(MDOC_ARGS) 1682 { 1683 struct htmlpair tag[2]; 1684 struct tag *t; 1685 1686 PAIR_CLASS_INIT(&tag[0], "link-mail"); 1687 1688 for (n = n->child; n; n = n->next) { 1689 assert(MDOC_TEXT == n->type); 1690 1691 bufinit(h); 1692 bufcat(h, "mailto:"); 1693 bufcat(h, n->string); 1694 1695 PAIR_HREF_INIT(&tag[1], h->buf); 1696 t = print_otag(h, TAG_A, 2, tag); 1697 print_text(h, n->string); 1698 print_tagq(h, t); 1699 } 1700 1701 return(0); 1702 } 1703 1704 1705 /* ARGSUSED */ 1706 static int 1707 mdoc_fo_pre(MDOC_ARGS) 1708 { 1709 struct htmlpair tag; 1710 struct tag *t; 1711 1712 if (MDOC_BODY == n->type) { 1713 h->flags |= HTML_NOSPACE; 1714 print_text(h, "("); 1715 h->flags |= HTML_NOSPACE; 1716 return(1); 1717 } else if (MDOC_BLOCK == n->type) { 1718 synopsis_pre(h, n); 1719 return(1); 1720 } 1721 1722 /* XXX: we drop non-initial arguments as per groff. */ 1723 1724 assert(n->child); 1725 assert(n->child->string); 1726 1727 PAIR_CLASS_INIT(&tag, "fname"); 1728 t = print_otag(h, TAG_B, 1, &tag); 1729 print_text(h, n->child->string); 1730 print_tagq(h, t); 1731 return(0); 1732 } 1733 1734 1735 /* ARGSUSED */ 1736 static void 1737 mdoc_fo_post(MDOC_ARGS) 1738 { 1739 1740 if (MDOC_BODY != n->type) 1741 return; 1742 h->flags |= HTML_NOSPACE; 1743 print_text(h, ")"); 1744 h->flags |= HTML_NOSPACE; 1745 print_text(h, ";"); 1746 } 1747 1748 1749 /* ARGSUSED */ 1750 static int 1751 mdoc_in_pre(MDOC_ARGS) 1752 { 1753 struct tag *t; 1754 struct htmlpair tag[2]; 1755 int i; 1756 1757 synopsis_pre(h, n); 1758 1759 PAIR_CLASS_INIT(&tag[0], "includes"); 1760 print_otag(h, TAG_B, 1, tag); 1761 1762 /* 1763 * The first argument of the `In' gets special treatment as 1764 * being a linked value. Subsequent values are printed 1765 * afterward. groff does similarly. This also handles the case 1766 * of no children. 1767 */ 1768 1769 if (MDOC_SYNPRETTY & n->flags && MDOC_LINE & n->flags) 1770 print_text(h, "#include"); 1771 1772 print_text(h, "<"); 1773 h->flags |= HTML_NOSPACE; 1774 1775 if (NULL != (n = n->child)) { 1776 assert(MDOC_TEXT == n->type); 1777 1778 PAIR_CLASS_INIT(&tag[0], "link-includes"); 1779 bufinit(h); 1780 1781 i = 1; 1782 1783 if (h->base_includes) { 1784 buffmt_includes(h, n->string); 1785 PAIR_HREF_INIT(&tag[i], h->buf); 1786 i++; 1787 } 1788 1789 t = print_otag(h, TAG_A, i, tag); 1790 print_text(h, n->string); 1791 print_tagq(h, t); 1792 1793 n = n->next; 1794 } 1795 1796 h->flags |= HTML_NOSPACE; 1797 print_text(h, ">"); 1798 1799 for ( ; n; n = n->next) { 1800 assert(MDOC_TEXT == n->type); 1801 print_text(h, n->string); 1802 } 1803 1804 return(0); 1805 } 1806 1807 1808 /* ARGSUSED */ 1809 static int 1810 mdoc_ic_pre(MDOC_ARGS) 1811 { 1812 struct htmlpair tag; 1813 1814 PAIR_CLASS_INIT(&tag, "cmd"); 1815 print_otag(h, TAG_B, 1, &tag); 1816 return(1); 1817 } 1818 1819 1820 /* ARGSUSED */ 1821 static int 1822 mdoc_rv_pre(MDOC_ARGS) 1823 { 1824 struct htmlpair tag; 1825 struct tag *t; 1826 int nchild; 1827 1828 if (n->prev) 1829 print_otag(h, TAG_BR, 0, NULL); 1830 1831 PAIR_CLASS_INIT(&tag, "fname"); 1832 1833 print_text(h, "The"); 1834 1835 nchild = n->nchild; 1836 for (n = n->child; n; n = n->next) { 1837 assert(MDOC_TEXT == n->type); 1838 1839 t = print_otag(h, TAG_B, 1, &tag); 1840 print_text(h, n->string); 1841 print_tagq(h, t); 1842 1843 h->flags |= HTML_NOSPACE; 1844 print_text(h, "()"); 1845 1846 if (nchild > 2 && n->next) { 1847 h->flags |= HTML_NOSPACE; 1848 print_text(h, ","); 1849 } 1850 1851 if (n->next && NULL == n->next->next) 1852 print_text(h, "and"); 1853 } 1854 1855 if (nchild > 1) 1856 print_text(h, "functions return"); 1857 else 1858 print_text(h, "function returns"); 1859 1860 print_text(h, "the value 0 if successful; otherwise the value " 1861 "-1 is returned and the global variable"); 1862 1863 PAIR_CLASS_INIT(&tag, "var"); 1864 t = print_otag(h, TAG_B, 1, &tag); 1865 print_text(h, "errno"); 1866 print_tagq(h, t); 1867 print_text(h, "is set to indicate the error."); 1868 return(0); 1869 } 1870 1871 1872 /* ARGSUSED */ 1873 static int 1874 mdoc_va_pre(MDOC_ARGS) 1875 { 1876 struct htmlpair tag; 1877 1878 PAIR_CLASS_INIT(&tag, "var"); 1879 print_otag(h, TAG_B, 1, &tag); 1880 return(1); 1881 } 1882 1883 1884 /* ARGSUSED */ 1885 static int 1886 mdoc_ap_pre(MDOC_ARGS) 1887 { 1888 1889 h->flags |= HTML_NOSPACE; 1890 print_text(h, "\\(aq"); 1891 h->flags |= HTML_NOSPACE; 1892 return(1); 1893 } 1894 1895 1896 /* ARGSUSED */ 1897 static int 1898 mdoc_bf_pre(MDOC_ARGS) 1899 { 1900 struct htmlpair tag[2]; 1901 struct roffsu su; 1902 1903 if (MDOC_HEAD == n->type) 1904 return(0); 1905 else if (MDOC_BODY != n->type) 1906 return(1); 1907 1908 if (FONT_Em == n->norm->Bf.font) 1909 PAIR_CLASS_INIT(&tag[0], "emph"); 1910 else if (FONT_Sy == n->norm->Bf.font) 1911 PAIR_CLASS_INIT(&tag[0], "symb"); 1912 else if (FONT_Li == n->norm->Bf.font) 1913 PAIR_CLASS_INIT(&tag[0], "lit"); 1914 else 1915 PAIR_CLASS_INIT(&tag[0], "none"); 1916 1917 /* 1918 * We want this to be inline-formatted, but needs to be div to 1919 * accept block children. 1920 */ 1921 bufcat_style(h, "display", "inline"); 1922 SCALE_HS_INIT(&su, 1); 1923 /* Needs a left-margin for spacing. */ 1924 bufcat_su(h, "margin-left", &su); 1925 PAIR_STYLE_INIT(&tag[1], h); 1926 print_otag(h, TAG_DIV, 2, tag); 1927 return(1); 1928 } 1929 1930 1931 /* ARGSUSED */ 1932 static int 1933 mdoc_ms_pre(MDOC_ARGS) 1934 { 1935 struct htmlpair tag; 1936 1937 PAIR_CLASS_INIT(&tag, "symb"); 1938 print_otag(h, TAG_SPAN, 1, &tag); 1939 return(1); 1940 } 1941 1942 1943 /* ARGSUSED */ 1944 static int 1945 mdoc_igndelim_pre(MDOC_ARGS) 1946 { 1947 1948 h->flags |= HTML_IGNDELIM; 1949 return(1); 1950 } 1951 1952 1953 /* ARGSUSED */ 1954 static void 1955 mdoc_pf_post(MDOC_ARGS) 1956 { 1957 1958 h->flags |= HTML_NOSPACE; 1959 } 1960 1961 1962 /* ARGSUSED */ 1963 static int 1964 mdoc_rs_pre(MDOC_ARGS) 1965 { 1966 struct htmlpair tag; 1967 1968 if (MDOC_BLOCK != n->type) 1969 return(1); 1970 1971 if (n->prev && SEC_SEE_ALSO == n->sec) 1972 print_otag(h, TAG_P, 0, NULL); 1973 1974 PAIR_CLASS_INIT(&tag, "ref"); 1975 print_otag(h, TAG_SPAN, 1, &tag); 1976 return(1); 1977 } 1978 1979 1980 1981 /* ARGSUSED */ 1982 static int 1983 mdoc_li_pre(MDOC_ARGS) 1984 { 1985 struct htmlpair tag; 1986 1987 PAIR_CLASS_INIT(&tag, "lit"); 1988 print_otag(h, TAG_SPAN, 1, &tag); 1989 return(1); 1990 } 1991 1992 1993 /* ARGSUSED */ 1994 static int 1995 mdoc_sy_pre(MDOC_ARGS) 1996 { 1997 struct htmlpair tag; 1998 1999 PAIR_CLASS_INIT(&tag, "symb"); 2000 print_otag(h, TAG_SPAN, 1, &tag); 2001 return(1); 2002 } 2003 2004 2005 /* ARGSUSED */ 2006 static int 2007 mdoc_bt_pre(MDOC_ARGS) 2008 { 2009 2010 print_text(h, "is currently in beta test."); 2011 return(0); 2012 } 2013 2014 2015 /* ARGSUSED */ 2016 static int 2017 mdoc_ud_pre(MDOC_ARGS) 2018 { 2019 2020 print_text(h, "currently under development."); 2021 return(0); 2022 } 2023 2024 2025 /* ARGSUSED */ 2026 static int 2027 mdoc_lb_pre(MDOC_ARGS) 2028 { 2029 struct htmlpair tag; 2030 2031 if (SEC_LIBRARY == n->sec && MDOC_LINE & n->flags && n->prev) 2032 print_otag(h, TAG_BR, 0, NULL); 2033 2034 PAIR_CLASS_INIT(&tag, "lib"); 2035 print_otag(h, TAG_SPAN, 1, &tag); 2036 return(1); 2037 } 2038 2039 2040 /* ARGSUSED */ 2041 static int 2042 mdoc__x_pre(MDOC_ARGS) 2043 { 2044 struct htmlpair tag[2]; 2045 enum htmltag t; 2046 2047 t = TAG_SPAN; 2048 2049 switch (n->tok) { 2050 case(MDOC__A): 2051 PAIR_CLASS_INIT(&tag[0], "ref-auth"); 2052 if (n->prev && MDOC__A == n->prev->tok) 2053 if (NULL == n->next || MDOC__A != n->next->tok) 2054 print_text(h, "and"); 2055 break; 2056 case(MDOC__B): 2057 PAIR_CLASS_INIT(&tag[0], "ref-book"); 2058 t = TAG_I; 2059 break; 2060 case(MDOC__C): 2061 PAIR_CLASS_INIT(&tag[0], "ref-city"); 2062 break; 2063 case(MDOC__D): 2064 PAIR_CLASS_INIT(&tag[0], "ref-date"); 2065 break; 2066 case(MDOC__I): 2067 PAIR_CLASS_INIT(&tag[0], "ref-issue"); 2068 t = TAG_I; 2069 break; 2070 case(MDOC__J): 2071 PAIR_CLASS_INIT(&tag[0], "ref-jrnl"); 2072 t = TAG_I; 2073 break; 2074 case(MDOC__N): 2075 PAIR_CLASS_INIT(&tag[0], "ref-num"); 2076 break; 2077 case(MDOC__O): 2078 PAIR_CLASS_INIT(&tag[0], "ref-opt"); 2079 break; 2080 case(MDOC__P): 2081 PAIR_CLASS_INIT(&tag[0], "ref-page"); 2082 break; 2083 case(MDOC__Q): 2084 PAIR_CLASS_INIT(&tag[0], "ref-corp"); 2085 break; 2086 case(MDOC__R): 2087 PAIR_CLASS_INIT(&tag[0], "ref-rep"); 2088 break; 2089 case(MDOC__T): 2090 PAIR_CLASS_INIT(&tag[0], "ref-title"); 2091 break; 2092 case(MDOC__U): 2093 PAIR_CLASS_INIT(&tag[0], "link-ref"); 2094 break; 2095 case(MDOC__V): 2096 PAIR_CLASS_INIT(&tag[0], "ref-vol"); 2097 break; 2098 default: 2099 abort(); 2100 /* NOTREACHED */ 2101 } 2102 2103 if (MDOC__U != n->tok) { 2104 print_otag(h, t, 1, tag); 2105 return(1); 2106 } 2107 2108 PAIR_HREF_INIT(&tag[1], n->child->string); 2109 print_otag(h, TAG_A, 2, tag); 2110 2111 return(1); 2112 } 2113 2114 2115 /* ARGSUSED */ 2116 static void 2117 mdoc__x_post(MDOC_ARGS) 2118 { 2119 2120 if (MDOC__A == n->tok && n->next && MDOC__A == n->next->tok) 2121 if (NULL == n->next->next || MDOC__A != n->next->next->tok) 2122 if (NULL == n->prev || MDOC__A != n->prev->tok) 2123 return; 2124 2125 /* TODO: %U */ 2126 2127 if (NULL == n->parent || MDOC_Rs != n->parent->tok) 2128 return; 2129 2130 h->flags |= HTML_NOSPACE; 2131 print_text(h, n->next ? "," : "."); 2132 } 2133 2134 2135 /* ARGSUSED */ 2136 static int 2137 mdoc_bk_pre(MDOC_ARGS) 2138 { 2139 2140 switch (n->type) { 2141 case (MDOC_BLOCK): 2142 break; 2143 case (MDOC_HEAD): 2144 return(0); 2145 case (MDOC_BODY): 2146 if (n->parent->args || 0 == n->prev->nchild) 2147 h->flags |= HTML_PREKEEP; 2148 break; 2149 default: 2150 abort(); 2151 /* NOTREACHED */ 2152 } 2153 2154 return(1); 2155 } 2156 2157 2158 /* ARGSUSED */ 2159 static void 2160 mdoc_bk_post(MDOC_ARGS) 2161 { 2162 2163 if (MDOC_BODY == n->type) 2164 h->flags &= ~(HTML_KEEP | HTML_PREKEEP); 2165 } 2166 2167 2168 /* ARGSUSED */ 2169 static int 2170 mdoc_quote_pre(MDOC_ARGS) 2171 { 2172 struct htmlpair tag; 2173 2174 if (MDOC_BODY != n->type) 2175 return(1); 2176 2177 switch (n->tok) { 2178 case (MDOC_Ao): 2179 /* FALLTHROUGH */ 2180 case (MDOC_Aq): 2181 print_text(h, "\\(la"); 2182 break; 2183 case (MDOC_Bro): 2184 /* FALLTHROUGH */ 2185 case (MDOC_Brq): 2186 print_text(h, "\\(lC"); 2187 break; 2188 case (MDOC_Bo): 2189 /* FALLTHROUGH */ 2190 case (MDOC_Bq): 2191 print_text(h, "\\(lB"); 2192 break; 2193 case (MDOC_Oo): 2194 /* FALLTHROUGH */ 2195 case (MDOC_Op): 2196 print_text(h, "\\(lB"); 2197 h->flags |= HTML_NOSPACE; 2198 PAIR_CLASS_INIT(&tag, "opt"); 2199 print_otag(h, TAG_SPAN, 1, &tag); 2200 break; 2201 case (MDOC_Do): 2202 /* FALLTHROUGH */ 2203 case (MDOC_Dq): 2204 /* FALLTHROUGH */ 2205 case (MDOC_Qo): 2206 /* FALLTHROUGH */ 2207 case (MDOC_Qq): 2208 print_text(h, "\\(lq"); 2209 break; 2210 case (MDOC_Po): 2211 /* FALLTHROUGH */ 2212 case (MDOC_Pq): 2213 print_text(h, "("); 2214 break; 2215 case (MDOC_Ql): 2216 /* FALLTHROUGH */ 2217 case (MDOC_So): 2218 /* FALLTHROUGH */ 2219 case (MDOC_Sq): 2220 print_text(h, "\\(oq"); 2221 break; 2222 default: 2223 abort(); 2224 /* NOTREACHED */ 2225 } 2226 2227 h->flags |= HTML_NOSPACE; 2228 return(1); 2229 } 2230 2231 2232 /* ARGSUSED */ 2233 static void 2234 mdoc_quote_post(MDOC_ARGS) 2235 { 2236 2237 if (MDOC_BODY != n->type) 2238 return; 2239 2240 h->flags |= HTML_NOSPACE; 2241 2242 switch (n->tok) { 2243 case (MDOC_Ao): 2244 /* FALLTHROUGH */ 2245 case (MDOC_Aq): 2246 print_text(h, "\\(ra"); 2247 break; 2248 case (MDOC_Bro): 2249 /* FALLTHROUGH */ 2250 case (MDOC_Brq): 2251 print_text(h, "\\(rC"); 2252 break; 2253 case (MDOC_Oo): 2254 /* FALLTHROUGH */ 2255 case (MDOC_Op): 2256 /* FALLTHROUGH */ 2257 case (MDOC_Bo): 2258 /* FALLTHROUGH */ 2259 case (MDOC_Bq): 2260 print_text(h, "\\(rB"); 2261 break; 2262 case (MDOC_Qo): 2263 /* FALLTHROUGH */ 2264 case (MDOC_Qq): 2265 /* FALLTHROUGH */ 2266 case (MDOC_Do): 2267 /* FALLTHROUGH */ 2268 case (MDOC_Dq): 2269 print_text(h, "\\(rq"); 2270 break; 2271 case (MDOC_Po): 2272 /* FALLTHROUGH */ 2273 case (MDOC_Pq): 2274 print_text(h, ")"); 2275 break; 2276 case (MDOC_Ql): 2277 /* FALLTHROUGH */ 2278 case (MDOC_So): 2279 /* FALLTHROUGH */ 2280 case (MDOC_Sq): 2281 print_text(h, "\\(aq"); 2282 break; 2283 default: 2284 abort(); 2285 /* NOTREACHED */ 2286 } 2287 } 2288 2289 2290