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