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