1 /* $Vendor-Id: mdoc_html.c,v 1.60 2010/04/07 07:49:38 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 */ /* FIXME: no space */ 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 PAIR_CLASS_INIT(&tag[0], "sec-head"); 593 PAIR_ID_INIT(&tag[1], buf); 594 595 print_otag(h, TAG_DIV, 2, tag); 596 return(1); 597 } 598 599 600 /* ARGSUSED */ 601 static int 602 mdoc_ss_pre(MDOC_ARGS) 603 { 604 struct htmlpair tag[3]; 605 const struct mdoc_node *nn; 606 char buf[BUFSIZ]; 607 struct roffsu su; 608 609 SCALE_VS_INIT(&su, 1); 610 611 if (MDOC_BODY == n->type) { 612 PAIR_CLASS_INIT(&tag[0], "ssec-body"); 613 if (n->parent->next && n->child) { 614 bufcat_su(h, "margin-bottom", &su); 615 PAIR_STYLE_INIT(&tag[1], h); 616 print_otag(h, TAG_DIV, 2, tag); 617 } else 618 print_otag(h, TAG_DIV, 1, tag); 619 return(1); 620 } else if (MDOC_BLOCK == n->type) { 621 PAIR_CLASS_INIT(&tag[0], "ssec-block"); 622 if (n->prev) { 623 bufcat_su(h, "margin-top", &su); 624 PAIR_STYLE_INIT(&tag[1], h); 625 print_otag(h, TAG_DIV, 2, tag); 626 } else 627 print_otag(h, TAG_DIV, 1, tag); 628 return(1); 629 } 630 631 /* TODO: see note in mdoc_sh_pre() about duplicates. */ 632 633 buf[0] = '\0'; 634 for (nn = n->child; nn; nn = nn->next) { 635 html_idcat(buf, nn->string, BUFSIZ); 636 if (nn->next) 637 html_idcat(buf, " ", BUFSIZ); 638 } 639 640 SCALE_HS_INIT(&su, INDENT - HALFINDENT); 641 su.scale = -su.scale; 642 bufcat_su(h, "margin-left", &su); 643 644 PAIR_CLASS_INIT(&tag[0], "ssec-head"); 645 PAIR_STYLE_INIT(&tag[1], h); 646 PAIR_ID_INIT(&tag[2], buf); 647 648 print_otag(h, TAG_DIV, 3, tag); 649 return(1); 650 } 651 652 653 /* ARGSUSED */ 654 static int 655 mdoc_fl_pre(MDOC_ARGS) 656 { 657 struct htmlpair tag; 658 659 PAIR_CLASS_INIT(&tag, "flag"); 660 print_otag(h, TAG_SPAN, 1, &tag); 661 662 /* `Cm' has no leading hyphen. */ 663 664 if (MDOC_Cm == n->tok) 665 return(1); 666 667 print_text(h, "\\-"); 668 669 if (n->child) 670 h->flags |= HTML_NOSPACE; 671 else if (n->next && n->next->line == n->line) 672 h->flags |= HTML_NOSPACE; 673 674 return(1); 675 } 676 677 678 /* ARGSUSED */ 679 static int 680 mdoc_nd_pre(MDOC_ARGS) 681 { 682 struct htmlpair tag; 683 684 if (MDOC_BODY != n->type) 685 return(1); 686 687 /* XXX: this tag in theory can contain block elements. */ 688 689 print_text(h, "\\(em"); 690 PAIR_CLASS_INIT(&tag, "desc-body"); 691 print_otag(h, TAG_SPAN, 1, &tag); 692 return(1); 693 } 694 695 696 /* ARGSUSED */ 697 static int 698 mdoc_op_pre(MDOC_ARGS) 699 { 700 struct htmlpair tag; 701 702 if (MDOC_BODY != n->type) 703 return(1); 704 705 /* XXX: this tag in theory can contain block elements. */ 706 707 print_text(h, "\\(lB"); 708 h->flags |= HTML_NOSPACE; 709 PAIR_CLASS_INIT(&tag, "opt"); 710 print_otag(h, TAG_SPAN, 1, &tag); 711 return(1); 712 } 713 714 715 /* ARGSUSED */ 716 static void 717 mdoc_op_post(MDOC_ARGS) 718 { 719 720 if (MDOC_BODY != n->type) 721 return; 722 h->flags |= HTML_NOSPACE; 723 print_text(h, "\\(rB"); 724 } 725 726 727 static int 728 mdoc_nm_pre(MDOC_ARGS) 729 { 730 struct htmlpair tag; 731 732 if (SEC_SYNOPSIS == n->sec && n->prev) { 733 bufcat_style(h, "clear", "both"); 734 PAIR_STYLE_INIT(&tag, h); 735 print_otag(h, TAG_BR, 1, &tag); 736 } 737 738 PAIR_CLASS_INIT(&tag, "name"); 739 print_otag(h, TAG_SPAN, 1, &tag); 740 if (NULL == n->child) 741 print_text(h, m->name); 742 743 return(1); 744 } 745 746 747 /* ARGSUSED */ 748 static int 749 mdoc_xr_pre(MDOC_ARGS) 750 { 751 struct htmlpair tag[2]; 752 const struct mdoc_node *nn; 753 754 if (NULL == n->child) 755 return(0); 756 757 PAIR_CLASS_INIT(&tag[0], "link-man"); 758 759 if (h->base_man) { 760 buffmt_man(h, n->child->string, 761 n->child->next ? 762 n->child->next->string : NULL); 763 PAIR_HREF_INIT(&tag[1], h->buf); 764 print_otag(h, TAG_A, 2, tag); 765 } else 766 print_otag(h, TAG_A, 1, tag); 767 768 nn = n->child; 769 print_text(h, nn->string); 770 771 if (NULL == (nn = nn->next)) 772 return(0); 773 774 h->flags |= HTML_NOSPACE; 775 print_text(h, "("); 776 h->flags |= HTML_NOSPACE; 777 print_text(h, nn->string); 778 h->flags |= HTML_NOSPACE; 779 print_text(h, ")"); 780 return(0); 781 } 782 783 784 /* ARGSUSED */ 785 static int 786 mdoc_ns_pre(MDOC_ARGS) 787 { 788 789 h->flags |= HTML_NOSPACE; 790 return(1); 791 } 792 793 794 /* ARGSUSED */ 795 static int 796 mdoc_ar_pre(MDOC_ARGS) 797 { 798 struct htmlpair tag; 799 800 PAIR_CLASS_INIT(&tag, "arg"); 801 print_otag(h, TAG_SPAN, 1, &tag); 802 return(1); 803 } 804 805 806 /* ARGSUSED */ 807 static int 808 mdoc_xx_pre(MDOC_ARGS) 809 { 810 const char *pp; 811 struct htmlpair tag; 812 813 switch (n->tok) { 814 case (MDOC_Bsx): 815 pp = "BSDI BSD/OS"; 816 break; 817 case (MDOC_Dx): 818 pp = "DragonFly"; 819 break; 820 case (MDOC_Fx): 821 pp = "FreeBSD"; 822 break; 823 case (MDOC_Nx): 824 pp = "NetBSD"; 825 break; 826 case (MDOC_Ox): 827 pp = "OpenBSD"; 828 break; 829 case (MDOC_Ux): 830 pp = "UNIX"; 831 break; 832 default: 833 return(1); 834 } 835 836 PAIR_CLASS_INIT(&tag, "unix"); 837 print_otag(h, TAG_SPAN, 1, &tag); 838 print_text(h, pp); 839 return(1); 840 } 841 842 843 /* ARGSUSED */ 844 static int 845 mdoc_bx_pre(MDOC_ARGS) 846 { 847 const struct mdoc_node *nn; 848 struct htmlpair tag; 849 850 PAIR_CLASS_INIT(&tag, "unix"); 851 print_otag(h, TAG_SPAN, 1, &tag); 852 853 for (nn = n->child; nn; nn = nn->next) 854 print_mdoc_node(m, nn, h); 855 856 if (n->child) 857 h->flags |= HTML_NOSPACE; 858 859 print_text(h, "BSD"); 860 return(0); 861 } 862 863 864 /* ARGSUSED */ 865 static int 866 mdoc_it_block_pre(MDOC_ARGS, int type, int comp, 867 struct roffsu *offs, struct roffsu *width) 868 { 869 struct htmlpair tag; 870 const struct mdoc_node *nn; 871 struct roffsu su; 872 873 nn = n->parent->parent; 874 assert(nn->args); 875 876 /* XXX: see notes in mdoc_it_pre(). */ 877 878 if (MDOC_Column == type) { 879 /* Don't width-pad on the left. */ 880 SCALE_HS_INIT(width, 0); 881 /* Also disallow non-compact. */ 882 comp = 1; 883 } 884 if (MDOC_Diag == type) 885 /* Mandate non-compact with empty prior. */ 886 if (n->prev && NULL == n->prev->body->child) 887 comp = 1; 888 889 bufcat_style(h, "clear", "both"); 890 if (offs->scale > 0) 891 bufcat_su(h, "margin-left", offs); 892 if (width->scale > 0) 893 bufcat_su(h, "padding-left", width); 894 895 PAIR_STYLE_INIT(&tag, h); 896 897 /* Mandate compact following `Ss' and `Sh' starts. */ 898 899 for (nn = n; nn && ! comp; nn = nn->parent) { 900 if (MDOC_BLOCK != nn->type) 901 continue; 902 if (MDOC_Ss == nn->tok || MDOC_Sh == nn->tok) 903 comp = 1; 904 if (nn->prev) 905 break; 906 } 907 908 if ( ! comp) { 909 SCALE_VS_INIT(&su, 1); 910 bufcat_su(h, "padding-top", &su); 911 } 912 913 PAIR_STYLE_INIT(&tag, h); 914 print_otag(h, TAG_DIV, 1, &tag); 915 return(1); 916 } 917 918 919 /* ARGSUSED */ 920 static int 921 mdoc_it_body_pre(MDOC_ARGS, int type) 922 { 923 struct htmlpair tag; 924 struct roffsu su; 925 926 switch (type) { 927 case (MDOC_Item): 928 /* FALLTHROUGH */ 929 case (MDOC_Ohang): 930 /* FALLTHROUGH */ 931 case (MDOC_Column): 932 break; 933 default: 934 /* 935 * XXX: this tricks CSS into aligning the bodies with 936 * the right-padding in the head. 937 */ 938 SCALE_HS_INIT(&su, 2); 939 bufcat_su(h, "margin-left", &su); 940 PAIR_STYLE_INIT(&tag, h); 941 print_otag(h, TAG_DIV, 1, &tag); 942 break; 943 } 944 945 return(1); 946 } 947 948 949 /* ARGSUSED */ 950 static int 951 mdoc_it_head_pre(MDOC_ARGS, int type, struct roffsu *width) 952 { 953 struct htmlpair tag; 954 struct ord *ord; 955 char nbuf[BUFSIZ]; 956 957 switch (type) { 958 case (MDOC_Item): 959 return(0); 960 case (MDOC_Ohang): 961 print_otag(h, TAG_DIV, 0, &tag); 962 return(1); 963 case (MDOC_Column): 964 bufcat_su(h, "min-width", width); 965 bufcat_style(h, "clear", "none"); 966 if (n->next && MDOC_HEAD == n->next->type) 967 bufcat_style(h, "float", "left"); 968 PAIR_STYLE_INIT(&tag, h); 969 print_otag(h, TAG_DIV, 1, &tag); 970 break; 971 default: 972 bufcat_su(h, "min-width", width); 973 SCALE_INVERT(width); 974 bufcat_su(h, "margin-left", width); 975 if (n->next && n->next->child) 976 bufcat_style(h, "float", "left"); 977 978 /* XXX: buffer if we run into body. */ 979 SCALE_HS_INIT(width, 1); 980 bufcat_su(h, "margin-right", width); 981 PAIR_STYLE_INIT(&tag, h); 982 print_otag(h, TAG_DIV, 1, &tag); 983 break; 984 } 985 986 switch (type) { 987 case (MDOC_Diag): 988 PAIR_CLASS_INIT(&tag, "diag"); 989 print_otag(h, TAG_SPAN, 1, &tag); 990 break; 991 case (MDOC_Enum): 992 ord = h->ords.head; 993 assert(ord); 994 nbuf[BUFSIZ - 1] = 0; 995 (void)snprintf(nbuf, BUFSIZ - 1, "%d.", ord->pos++); 996 print_text(h, nbuf); 997 return(0); 998 case (MDOC_Dash): 999 print_text(h, "\\(en"); 1000 return(0); 1001 case (MDOC_Hyphen): 1002 print_text(h, "\\(hy"); 1003 return(0); 1004 case (MDOC_Bullet): 1005 print_text(h, "\\(bu"); 1006 return(0); 1007 default: 1008 break; 1009 } 1010 1011 return(1); 1012 } 1013 1014 1015 static int 1016 mdoc_it_pre(MDOC_ARGS) 1017 { 1018 int i, type, wp, comp; 1019 const struct mdoc_node *bl, *nn; 1020 struct roffsu width, offs; 1021 1022 /* 1023 * XXX: be very careful in changing anything, here. Lists in 1024 * mandoc have many peculiarities; furthermore, they don't 1025 * translate well into HTML and require a bit of mangling. 1026 */ 1027 1028 bl = n->parent->parent; 1029 if (MDOC_BLOCK != n->type) 1030 bl = bl->parent; 1031 1032 type = a2list(bl); 1033 1034 /* Set default width and offset. */ 1035 1036 SCALE_HS_INIT(&offs, 0); 1037 1038 switch (type) { 1039 case (MDOC_Enum): 1040 /* FALLTHROUGH */ 1041 case (MDOC_Dash): 1042 /* FALLTHROUGH */ 1043 case (MDOC_Hyphen): 1044 /* FALLTHROUGH */ 1045 case (MDOC_Bullet): 1046 SCALE_HS_INIT(&width, 2); 1047 break; 1048 default: 1049 SCALE_HS_INIT(&width, INDENT); 1050 break; 1051 } 1052 1053 /* Get width, offset, and compact arguments. */ 1054 1055 for (wp = -1, comp = i = 0; i < (int)bl->args->argc; i++) 1056 switch (bl->args->argv[i].arg) { 1057 case (MDOC_Column): 1058 wp = i; /* Save for later. */ 1059 break; 1060 case (MDOC_Width): 1061 a2width(bl->args->argv[i].value[0], &width); 1062 break; 1063 case (MDOC_Offset): 1064 a2offs(bl->args->argv[i].value[0], &offs); 1065 break; 1066 case (MDOC_Compact): 1067 comp = 1; 1068 break; 1069 default: 1070 break; 1071 } 1072 1073 /* Override width in some cases. */ 1074 1075 switch (type) { 1076 case (MDOC_Ohang): 1077 /* FALLTHROUGH */ 1078 case (MDOC_Item): 1079 /* FALLTHROUGH */ 1080 case (MDOC_Inset): 1081 /* FALLTHROUGH */ 1082 case (MDOC_Diag): 1083 SCALE_HS_INIT(&width, 0); 1084 break; 1085 default: 1086 if (0 == width.scale) 1087 SCALE_HS_INIT(&width, INDENT); 1088 break; 1089 } 1090 1091 /* Flip to body/block processing. */ 1092 1093 if (MDOC_BODY == n->type) 1094 return(mdoc_it_body_pre(m, n, h, type)); 1095 if (MDOC_BLOCK == n->type) 1096 return(mdoc_it_block_pre(m, n, h, type, comp, 1097 &offs, &width)); 1098 1099 /* Override column widths. */ 1100 1101 if (MDOC_Column == type) { 1102 nn = n->parent->child; 1103 for (i = 0; nn && nn != n; nn = nn->next, i++) 1104 /* Counter... */ ; 1105 if (i < (int)bl->args->argv[wp].sz) 1106 a2width(bl->args->argv[wp].value[i], &width); 1107 } 1108 1109 return(mdoc_it_head_pre(m, n, h, type, &width)); 1110 } 1111 1112 1113 /* ARGSUSED */ 1114 static int 1115 mdoc_bl_pre(MDOC_ARGS) 1116 { 1117 struct ord *ord; 1118 1119 if (MDOC_HEAD == n->type) 1120 return(0); 1121 if (MDOC_BLOCK != n->type) 1122 return(1); 1123 if (MDOC_Enum != a2list(n)) 1124 return(1); 1125 1126 ord = malloc(sizeof(struct ord)); 1127 if (NULL == ord) { 1128 perror(NULL); 1129 exit(EXIT_FAILURE); 1130 } 1131 ord->cookie = n; 1132 ord->pos = 1; 1133 ord->next = h->ords.head; 1134 h->ords.head = ord; 1135 return(1); 1136 } 1137 1138 1139 /* ARGSUSED */ 1140 static void 1141 mdoc_bl_post(MDOC_ARGS) 1142 { 1143 struct ord *ord; 1144 1145 if (MDOC_BLOCK != n->type) 1146 return; 1147 if (MDOC_Enum != a2list(n)) 1148 return; 1149 1150 ord = h->ords.head; 1151 assert(ord); 1152 h->ords.head = ord->next; 1153 free(ord); 1154 } 1155 1156 1157 /* ARGSUSED */ 1158 static int 1159 mdoc_ex_pre(MDOC_ARGS) 1160 { 1161 const struct mdoc_node *nn; 1162 struct tag *t; 1163 struct htmlpair tag; 1164 1165 PAIR_CLASS_INIT(&tag, "utility"); 1166 1167 print_text(h, "The"); 1168 for (nn = n->child; nn; nn = nn->next) { 1169 t = print_otag(h, TAG_SPAN, 1, &tag); 1170 print_text(h, nn->string); 1171 print_tagq(h, t); 1172 1173 h->flags |= HTML_NOSPACE; 1174 1175 if (nn->next && NULL == nn->next->next) 1176 print_text(h, ", and"); 1177 else if (nn->next) 1178 print_text(h, ","); 1179 else 1180 h->flags &= ~HTML_NOSPACE; 1181 } 1182 1183 if (n->child->next) 1184 print_text(h, "utilities exit"); 1185 else 1186 print_text(h, "utility exits"); 1187 1188 print_text(h, "0 on success, and >0 if an error occurs."); 1189 return(0); 1190 } 1191 1192 1193 /* ARGSUSED */ 1194 static int 1195 mdoc_dq_pre(MDOC_ARGS) 1196 { 1197 1198 if (MDOC_BODY != n->type) 1199 return(1); 1200 print_text(h, "\\(lq"); 1201 h->flags |= HTML_NOSPACE; 1202 return(1); 1203 } 1204 1205 1206 /* ARGSUSED */ 1207 static void 1208 mdoc_dq_post(MDOC_ARGS) 1209 { 1210 1211 if (MDOC_BODY != n->type) 1212 return; 1213 h->flags |= HTML_NOSPACE; 1214 print_text(h, "\\(rq"); 1215 } 1216 1217 1218 /* ARGSUSED */ 1219 static int 1220 mdoc_pq_pre(MDOC_ARGS) 1221 { 1222 1223 if (MDOC_BODY != n->type) 1224 return(1); 1225 print_text(h, "\\&("); 1226 h->flags |= HTML_NOSPACE; 1227 return(1); 1228 } 1229 1230 1231 /* ARGSUSED */ 1232 static void 1233 mdoc_pq_post(MDOC_ARGS) 1234 { 1235 1236 if (MDOC_BODY != n->type) 1237 return; 1238 print_text(h, ")"); 1239 } 1240 1241 1242 /* ARGSUSED */ 1243 static int 1244 mdoc_sq_pre(MDOC_ARGS) 1245 { 1246 1247 if (MDOC_BODY != n->type) 1248 return(1); 1249 print_text(h, "\\(oq"); 1250 h->flags |= HTML_NOSPACE; 1251 return(1); 1252 } 1253 1254 1255 /* ARGSUSED */ 1256 static void 1257 mdoc_sq_post(MDOC_ARGS) 1258 { 1259 1260 if (MDOC_BODY != n->type) 1261 return; 1262 h->flags |= HTML_NOSPACE; 1263 print_text(h, "\\(aq"); 1264 } 1265 1266 1267 /* ARGSUSED */ 1268 static int 1269 mdoc_em_pre(MDOC_ARGS) 1270 { 1271 struct htmlpair tag; 1272 1273 PAIR_CLASS_INIT(&tag, "emph"); 1274 print_otag(h, TAG_SPAN, 1, &tag); 1275 return(1); 1276 } 1277 1278 1279 /* ARGSUSED */ 1280 static int 1281 mdoc_d1_pre(MDOC_ARGS) 1282 { 1283 struct htmlpair tag[2]; 1284 struct roffsu su; 1285 1286 if (MDOC_BLOCK != n->type) 1287 return(1); 1288 1289 /* FIXME: D1 shouldn't be literal. */ 1290 1291 SCALE_VS_INIT(&su, INDENT - 2); 1292 bufcat_su(h, "margin-left", &su); 1293 PAIR_CLASS_INIT(&tag[0], "lit"); 1294 PAIR_STYLE_INIT(&tag[1], h); 1295 print_otag(h, TAG_DIV, 2, tag); 1296 return(1); 1297 } 1298 1299 1300 /* ARGSUSED */ 1301 static int 1302 mdoc_sx_pre(MDOC_ARGS) 1303 { 1304 struct htmlpair tag[2]; 1305 const struct mdoc_node *nn; 1306 char buf[BUFSIZ]; 1307 1308 strlcpy(buf, "#", BUFSIZ); 1309 for (nn = n->child; nn; nn = nn->next) { 1310 html_idcat(buf, nn->string, BUFSIZ); 1311 if (nn->next) 1312 html_idcat(buf, " ", BUFSIZ); 1313 } 1314 1315 PAIR_CLASS_INIT(&tag[0], "link-sec"); 1316 PAIR_HREF_INIT(&tag[1], buf); 1317 1318 print_otag(h, TAG_A, 2, tag); 1319 return(1); 1320 } 1321 1322 1323 /* ARGSUSED */ 1324 static int 1325 mdoc_aq_pre(MDOC_ARGS) 1326 { 1327 1328 if (MDOC_BODY != n->type) 1329 return(1); 1330 print_text(h, "\\(la"); 1331 h->flags |= HTML_NOSPACE; 1332 return(1); 1333 } 1334 1335 1336 /* ARGSUSED */ 1337 static void 1338 mdoc_aq_post(MDOC_ARGS) 1339 { 1340 1341 if (MDOC_BODY != n->type) 1342 return; 1343 h->flags |= HTML_NOSPACE; 1344 print_text(h, "\\(ra"); 1345 } 1346 1347 1348 /* ARGSUSED */ 1349 static int 1350 mdoc_bd_pre(MDOC_ARGS) 1351 { 1352 struct htmlpair tag[2]; 1353 int type, comp, i; 1354 const struct mdoc_node *bl, *nn; 1355 struct roffsu su; 1356 1357 if (MDOC_BLOCK == n->type) 1358 bl = n; 1359 else if (MDOC_HEAD == n->type) 1360 return(0); 1361 else 1362 bl = n->parent; 1363 1364 SCALE_VS_INIT(&su, 0); 1365 1366 type = comp = 0; 1367 for (i = 0; i < (int)bl->args->argc; i++) 1368 switch (bl->args->argv[i].arg) { 1369 case (MDOC_Offset): 1370 a2offs(bl->args->argv[i].value[0], &su); 1371 break; 1372 case (MDOC_Compact): 1373 comp = 1; 1374 break; 1375 case (MDOC_Centred): 1376 /* FALLTHROUGH */ 1377 case (MDOC_Ragged): 1378 /* FALLTHROUGH */ 1379 case (MDOC_Filled): 1380 /* FALLTHROUGH */ 1381 case (MDOC_Unfilled): 1382 /* FALLTHROUGH */ 1383 case (MDOC_Literal): 1384 type = bl->args->argv[i].arg; 1385 break; 1386 default: 1387 break; 1388 } 1389 1390 /* FIXME: -centered, etc. formatting. */ 1391 /* FIXME: does not respect -offset ??? */ 1392 1393 if (MDOC_BLOCK == n->type) { 1394 bufcat_su(h, "margin-left", &su); 1395 for (nn = n; nn && ! comp; nn = nn->parent) { 1396 if (MDOC_BLOCK != nn->type) 1397 continue; 1398 if (MDOC_Ss == nn->tok || MDOC_Sh == nn->tok) 1399 comp = 1; 1400 if (nn->prev) 1401 break; 1402 } 1403 if (comp) { 1404 print_otag(h, TAG_DIV, 0, tag); 1405 return(1); 1406 } 1407 SCALE_VS_INIT(&su, 1); 1408 bufcat_su(h, "margin-top", &su); 1409 PAIR_STYLE_INIT(&tag[0], h); 1410 print_otag(h, TAG_DIV, 1, tag); 1411 return(1); 1412 } 1413 1414 if (MDOC_Unfilled != type && MDOC_Literal != type) 1415 return(1); 1416 1417 PAIR_CLASS_INIT(&tag[0], "lit"); 1418 bufcat_style(h, "white-space", "pre"); 1419 PAIR_STYLE_INIT(&tag[1], h); 1420 print_otag(h, TAG_DIV, 2, tag); 1421 1422 for (nn = n->child; nn; nn = nn->next) { 1423 h->flags |= HTML_NOSPACE; 1424 print_mdoc_node(m, nn, h); 1425 if (NULL == nn->next) 1426 continue; 1427 if (nn->prev && nn->prev->line < nn->line) 1428 print_text(h, "\n"); 1429 else if (NULL == nn->prev) 1430 print_text(h, "\n"); 1431 } 1432 1433 return(0); 1434 } 1435 1436 1437 /* ARGSUSED */ 1438 static int 1439 mdoc_pa_pre(MDOC_ARGS) 1440 { 1441 struct htmlpair tag; 1442 1443 PAIR_CLASS_INIT(&tag, "file"); 1444 print_otag(h, TAG_SPAN, 1, &tag); 1445 return(1); 1446 } 1447 1448 1449 /* ARGSUSED */ 1450 static int 1451 mdoc_ad_pre(MDOC_ARGS) 1452 { 1453 struct htmlpair tag; 1454 1455 PAIR_CLASS_INIT(&tag, "addr"); 1456 print_otag(h, TAG_SPAN, 1, &tag); 1457 return(1); 1458 } 1459 1460 1461 /* ARGSUSED */ 1462 static int 1463 mdoc_an_pre(MDOC_ARGS) 1464 { 1465 struct htmlpair tag; 1466 1467 /* TODO: -split and -nosplit (see termp_an_pre()). */ 1468 1469 PAIR_CLASS_INIT(&tag, "author"); 1470 print_otag(h, TAG_SPAN, 1, &tag); 1471 return(1); 1472 } 1473 1474 1475 /* ARGSUSED */ 1476 static int 1477 mdoc_cd_pre(MDOC_ARGS) 1478 { 1479 struct htmlpair tag; 1480 1481 print_otag(h, TAG_DIV, 0, NULL); 1482 PAIR_CLASS_INIT(&tag, "config"); 1483 print_otag(h, TAG_SPAN, 1, &tag); 1484 return(1); 1485 } 1486 1487 1488 /* ARGSUSED */ 1489 static int 1490 mdoc_dv_pre(MDOC_ARGS) 1491 { 1492 struct htmlpair tag; 1493 1494 PAIR_CLASS_INIT(&tag, "define"); 1495 print_otag(h, TAG_SPAN, 1, &tag); 1496 return(1); 1497 } 1498 1499 1500 /* ARGSUSED */ 1501 static int 1502 mdoc_ev_pre(MDOC_ARGS) 1503 { 1504 struct htmlpair tag; 1505 1506 PAIR_CLASS_INIT(&tag, "env"); 1507 print_otag(h, TAG_SPAN, 1, &tag); 1508 return(1); 1509 } 1510 1511 1512 /* ARGSUSED */ 1513 static int 1514 mdoc_er_pre(MDOC_ARGS) 1515 { 1516 struct htmlpair tag; 1517 1518 PAIR_CLASS_INIT(&tag, "errno"); 1519 print_otag(h, TAG_SPAN, 1, &tag); 1520 return(1); 1521 } 1522 1523 1524 /* ARGSUSED */ 1525 static int 1526 mdoc_fa_pre(MDOC_ARGS) 1527 { 1528 const struct mdoc_node *nn; 1529 struct htmlpair tag; 1530 struct tag *t; 1531 1532 PAIR_CLASS_INIT(&tag, "farg"); 1533 if (n->parent->tok != MDOC_Fo) { 1534 print_otag(h, TAG_SPAN, 1, &tag); 1535 return(1); 1536 } 1537 1538 for (nn = n->child; nn; nn = nn->next) { 1539 t = print_otag(h, TAG_SPAN, 1, &tag); 1540 print_text(h, nn->string); 1541 print_tagq(h, t); 1542 if (nn->next) 1543 print_text(h, ","); 1544 } 1545 1546 if (n->child && n->next && n->next->tok == MDOC_Fa) 1547 print_text(h, ","); 1548 1549 return(0); 1550 } 1551 1552 1553 /* ARGSUSED */ 1554 static int 1555 mdoc_fd_pre(MDOC_ARGS) 1556 { 1557 struct htmlpair tag; 1558 struct roffsu su; 1559 1560 if (SEC_SYNOPSIS == n->sec) { 1561 if (n->next && MDOC_Fd != n->next->tok) { 1562 SCALE_VS_INIT(&su, 1); 1563 bufcat_su(h, "margin-bottom", &su); 1564 PAIR_STYLE_INIT(&tag, h); 1565 print_otag(h, TAG_DIV, 1, &tag); 1566 } else 1567 print_otag(h, TAG_DIV, 0, NULL); 1568 } 1569 1570 PAIR_CLASS_INIT(&tag, "macro"); 1571 print_otag(h, TAG_SPAN, 1, &tag); 1572 return(1); 1573 } 1574 1575 1576 /* ARGSUSED */ 1577 static int 1578 mdoc_vt_pre(MDOC_ARGS) 1579 { 1580 struct htmlpair tag; 1581 struct roffsu su; 1582 1583 if (SEC_SYNOPSIS == n->sec && MDOC_BLOCK == n->type) { 1584 if (n->next && MDOC_Vt != n->next->tok) { 1585 SCALE_VS_INIT(&su, 1); 1586 bufcat_su(h, "margin-bottom", &su); 1587 PAIR_STYLE_INIT(&tag, h); 1588 print_otag(h, TAG_DIV, 1, &tag); 1589 } else 1590 print_otag(h, TAG_DIV, 0, NULL); 1591 1592 return(1); 1593 } else if (MDOC_HEAD == n->type) 1594 return(0); 1595 1596 PAIR_CLASS_INIT(&tag, "type"); 1597 print_otag(h, TAG_SPAN, 1, &tag); 1598 return(1); 1599 } 1600 1601 1602 /* ARGSUSED */ 1603 static int 1604 mdoc_ft_pre(MDOC_ARGS) 1605 { 1606 struct htmlpair tag; 1607 1608 if (SEC_SYNOPSIS == n->sec) 1609 print_otag(h, TAG_DIV, 0, NULL); 1610 1611 PAIR_CLASS_INIT(&tag, "ftype"); 1612 print_otag(h, TAG_SPAN, 1, &tag); 1613 return(1); 1614 } 1615 1616 1617 /* ARGSUSED */ 1618 static int 1619 mdoc_fn_pre(MDOC_ARGS) 1620 { 1621 struct tag *t; 1622 struct htmlpair tag[2]; 1623 const struct mdoc_node *nn; 1624 char nbuf[BUFSIZ]; 1625 const char *sp, *ep; 1626 int sz, i; 1627 struct roffsu su; 1628 1629 if (SEC_SYNOPSIS == n->sec) { 1630 SCALE_HS_INIT(&su, INDENT); 1631 bufcat_su(h, "margin-left", &su); 1632 su.scale = -su.scale; 1633 bufcat_su(h, "text-indent", &su); 1634 if (n->next) { 1635 SCALE_VS_INIT(&su, 1); 1636 bufcat_su(h, "margin-bottom", &su); 1637 } 1638 PAIR_STYLE_INIT(&tag[0], h); 1639 print_otag(h, TAG_DIV, 1, tag); 1640 } 1641 1642 /* Split apart into type and name. */ 1643 assert(n->child->string); 1644 sp = n->child->string; 1645 1646 ep = strchr(sp, ' '); 1647 if (NULL != ep) { 1648 PAIR_CLASS_INIT(&tag[0], "ftype"); 1649 t = print_otag(h, TAG_SPAN, 1, tag); 1650 1651 while (ep) { 1652 sz = MIN((int)(ep - sp), BUFSIZ - 1); 1653 (void)memcpy(nbuf, sp, (size_t)sz); 1654 nbuf[sz] = '\0'; 1655 print_text(h, nbuf); 1656 sp = ++ep; 1657 ep = strchr(sp, ' '); 1658 } 1659 print_tagq(h, t); 1660 } 1661 1662 PAIR_CLASS_INIT(&tag[0], "fname"); 1663 1664 /* 1665 * FIXME: only refer to IDs that we know exist. 1666 */ 1667 1668 #if 0 1669 if (SEC_SYNOPSIS == n->sec) { 1670 nbuf[0] = '\0'; 1671 html_idcat(nbuf, sp, BUFSIZ); 1672 PAIR_ID_INIT(&tag[1], nbuf); 1673 } else { 1674 strlcpy(nbuf, "#", BUFSIZ); 1675 html_idcat(nbuf, sp, BUFSIZ); 1676 PAIR_HREF_INIT(&tag[1], nbuf); 1677 } 1678 #endif 1679 1680 t = print_otag(h, TAG_SPAN, 1, tag); 1681 1682 if (sp) { 1683 strlcpy(nbuf, sp, BUFSIZ); 1684 print_text(h, nbuf); 1685 } 1686 1687 print_tagq(h, t); 1688 1689 h->flags |= HTML_NOSPACE; 1690 print_text(h, "("); 1691 1692 bufinit(h); 1693 PAIR_CLASS_INIT(&tag[0], "farg"); 1694 bufcat_style(h, "white-space", "nowrap"); 1695 PAIR_STYLE_INIT(&tag[1], h); 1696 1697 for (nn = n->child->next; nn; nn = nn->next) { 1698 i = 1; 1699 if (SEC_SYNOPSIS == n->sec) 1700 i = 2; 1701 t = print_otag(h, TAG_SPAN, i, tag); 1702 print_text(h, nn->string); 1703 print_tagq(h, t); 1704 if (nn->next) 1705 print_text(h, ","); 1706 } 1707 1708 print_text(h, ")"); 1709 if (SEC_SYNOPSIS == n->sec) 1710 print_text(h, ";"); 1711 1712 return(0); 1713 } 1714 1715 1716 /* ARGSUSED */ 1717 static int 1718 mdoc_sp_pre(MDOC_ARGS) 1719 { 1720 int len; 1721 struct htmlpair tag; 1722 struct roffsu su; 1723 1724 switch (n->tok) { 1725 case (MDOC_sp): 1726 /* FIXME: can this have a scaling indicator? */ 1727 len = n->child ? atoi(n->child->string) : 1; 1728 break; 1729 case (MDOC_br): 1730 len = 0; 1731 break; 1732 default: 1733 len = 1; 1734 break; 1735 } 1736 1737 SCALE_VS_INIT(&su, len); 1738 bufcat_su(h, "height", &su); 1739 PAIR_STYLE_INIT(&tag, h); 1740 print_otag(h, TAG_DIV, 1, &tag); 1741 /* So the div isn't empty: */ 1742 print_text(h, "\\~"); 1743 1744 return(0); 1745 1746 } 1747 1748 1749 /* ARGSUSED */ 1750 static int 1751 mdoc_brq_pre(MDOC_ARGS) 1752 { 1753 1754 if (MDOC_BODY != n->type) 1755 return(1); 1756 print_text(h, "\\(lC"); 1757 h->flags |= HTML_NOSPACE; 1758 return(1); 1759 } 1760 1761 1762 /* ARGSUSED */ 1763 static void 1764 mdoc_brq_post(MDOC_ARGS) 1765 { 1766 1767 if (MDOC_BODY != n->type) 1768 return; 1769 h->flags |= HTML_NOSPACE; 1770 print_text(h, "\\(rC"); 1771 } 1772 1773 1774 /* ARGSUSED */ 1775 static int 1776 mdoc_lk_pre(MDOC_ARGS) 1777 { 1778 const struct mdoc_node *nn; 1779 struct htmlpair tag[2]; 1780 1781 nn = n->child; 1782 1783 PAIR_CLASS_INIT(&tag[0], "link-ext"); 1784 PAIR_HREF_INIT(&tag[1], nn->string); 1785 print_otag(h, TAG_A, 2, tag); 1786 1787 if (NULL == nn->next) 1788 return(1); 1789 1790 for (nn = nn->next; nn; nn = nn->next) 1791 print_text(h, nn->string); 1792 1793 return(0); 1794 } 1795 1796 1797 /* ARGSUSED */ 1798 static int 1799 mdoc_mt_pre(MDOC_ARGS) 1800 { 1801 struct htmlpair tag[2]; 1802 struct tag *t; 1803 const struct mdoc_node *nn; 1804 1805 PAIR_CLASS_INIT(&tag[0], "link-mail"); 1806 1807 for (nn = n->child; nn; nn = nn->next) { 1808 bufinit(h); 1809 bufcat(h, "mailto:"); 1810 bufcat(h, nn->string); 1811 PAIR_HREF_INIT(&tag[1], h->buf); 1812 t = print_otag(h, TAG_A, 2, tag); 1813 print_text(h, nn->string); 1814 print_tagq(h, t); 1815 } 1816 1817 return(0); 1818 } 1819 1820 1821 /* ARGSUSED */ 1822 static int 1823 mdoc_fo_pre(MDOC_ARGS) 1824 { 1825 struct htmlpair tag; 1826 struct roffsu su; 1827 1828 if (MDOC_BODY == n->type) { 1829 h->flags |= HTML_NOSPACE; 1830 print_text(h, "("); 1831 h->flags |= HTML_NOSPACE; 1832 return(1); 1833 } else if (MDOC_BLOCK == n->type && n->next) { 1834 SCALE_VS_INIT(&su, 1); 1835 bufcat_su(h, "margin-bottom", &su); 1836 PAIR_STYLE_INIT(&tag, h); 1837 print_otag(h, TAG_DIV, 1, &tag); 1838 return(1); 1839 } 1840 1841 PAIR_CLASS_INIT(&tag, "fname"); 1842 print_otag(h, TAG_SPAN, 1, &tag); 1843 return(1); 1844 } 1845 1846 1847 /* ARGSUSED */ 1848 static void 1849 mdoc_fo_post(MDOC_ARGS) 1850 { 1851 if (MDOC_BODY != n->type) 1852 return; 1853 h->flags |= HTML_NOSPACE; 1854 print_text(h, ")"); 1855 h->flags |= HTML_NOSPACE; 1856 print_text(h, ";"); 1857 } 1858 1859 1860 /* ARGSUSED */ 1861 static int 1862 mdoc_in_pre(MDOC_ARGS) 1863 { 1864 const struct mdoc_node *nn; 1865 struct tag *t; 1866 struct htmlpair tag[2]; 1867 int i; 1868 struct roffsu su; 1869 1870 if (SEC_SYNOPSIS == n->sec) { 1871 if (n->next && MDOC_In != n->next->tok) { 1872 SCALE_VS_INIT(&su, 1); 1873 bufcat_su(h, "margin-bottom", &su); 1874 PAIR_STYLE_INIT(&tag[0], h); 1875 print_otag(h, TAG_DIV, 1, tag); 1876 } else 1877 print_otag(h, TAG_DIV, 0, NULL); 1878 } 1879 1880 /* FIXME: there's a buffer bug in here somewhere. */ 1881 1882 PAIR_CLASS_INIT(&tag[0], "includes"); 1883 print_otag(h, TAG_SPAN, 1, tag); 1884 1885 if (SEC_SYNOPSIS == n->sec) 1886 print_text(h, "#include"); 1887 1888 print_text(h, "<"); 1889 h->flags |= HTML_NOSPACE; 1890 1891 /* XXX -- see warning in termp_in_post(). */ 1892 1893 for (nn = n->child; nn; nn = nn->next) { 1894 PAIR_CLASS_INIT(&tag[0], "link-includes"); 1895 i = 1; 1896 bufinit(h); 1897 if (h->base_includes) { 1898 buffmt_includes(h, nn->string); 1899 PAIR_HREF_INIT(&tag[i], h->buf); 1900 i++; 1901 } 1902 t = print_otag(h, TAG_A, i, tag); 1903 print_mdoc_node(m, nn, h); 1904 print_tagq(h, t); 1905 } 1906 1907 h->flags |= HTML_NOSPACE; 1908 print_text(h, ">"); 1909 1910 return(0); 1911 } 1912 1913 1914 /* ARGSUSED */ 1915 static int 1916 mdoc_ic_pre(MDOC_ARGS) 1917 { 1918 struct htmlpair tag; 1919 1920 PAIR_CLASS_INIT(&tag, "cmd"); 1921 print_otag(h, TAG_SPAN, 1, &tag); 1922 return(1); 1923 } 1924 1925 1926 /* ARGSUSED */ 1927 static int 1928 mdoc_rv_pre(MDOC_ARGS) 1929 { 1930 const struct mdoc_node *nn; 1931 struct htmlpair tag; 1932 struct tag *t; 1933 1934 print_otag(h, TAG_DIV, 0, NULL); 1935 print_text(h, "The"); 1936 1937 for (nn = n->child; nn; nn = nn->next) { 1938 PAIR_CLASS_INIT(&tag, "fname"); 1939 t = print_otag(h, TAG_SPAN, 1, &tag); 1940 print_text(h, nn->string); 1941 print_tagq(h, t); 1942 1943 h->flags |= HTML_NOSPACE; 1944 if (nn->next && NULL == nn->next->next) 1945 print_text(h, "(), and"); 1946 else if (nn->next) 1947 print_text(h, "(),"); 1948 else 1949 print_text(h, "()"); 1950 } 1951 1952 if (n->child->next) 1953 print_text(h, "functions return"); 1954 else 1955 print_text(h, "function returns"); 1956 1957 print_text(h, "the value 0 if successful; otherwise the value " 1958 "-1 is returned and the global variable"); 1959 1960 PAIR_CLASS_INIT(&tag, "var"); 1961 t = print_otag(h, TAG_SPAN, 1, &tag); 1962 print_text(h, "errno"); 1963 print_tagq(h, t); 1964 print_text(h, "is set to indicate the error."); 1965 return(0); 1966 } 1967 1968 1969 /* ARGSUSED */ 1970 static int 1971 mdoc_va_pre(MDOC_ARGS) 1972 { 1973 struct htmlpair tag; 1974 1975 PAIR_CLASS_INIT(&tag, "var"); 1976 print_otag(h, TAG_SPAN, 1, &tag); 1977 return(1); 1978 } 1979 1980 1981 /* ARGSUSED */ 1982 static int 1983 mdoc_bq_pre(MDOC_ARGS) 1984 { 1985 1986 if (MDOC_BODY != n->type) 1987 return(1); 1988 print_text(h, "\\(lB"); 1989 h->flags |= HTML_NOSPACE; 1990 return(1); 1991 } 1992 1993 1994 /* ARGSUSED */ 1995 static void 1996 mdoc_bq_post(MDOC_ARGS) 1997 { 1998 1999 if (MDOC_BODY != n->type) 2000 return; 2001 h->flags |= HTML_NOSPACE; 2002 print_text(h, "\\(rB"); 2003 } 2004 2005 2006 /* ARGSUSED */ 2007 static int 2008 mdoc_ap_pre(MDOC_ARGS) 2009 { 2010 2011 h->flags |= HTML_NOSPACE; 2012 print_text(h, "\\(aq"); 2013 h->flags |= HTML_NOSPACE; 2014 return(1); 2015 } 2016 2017 2018 /* ARGSUSED */ 2019 static int 2020 mdoc_bf_pre(MDOC_ARGS) 2021 { 2022 int i; 2023 struct htmlpair tag[2]; 2024 struct roffsu su; 2025 2026 if (MDOC_HEAD == n->type) 2027 return(0); 2028 else if (MDOC_BLOCK != n->type) 2029 return(1); 2030 2031 PAIR_CLASS_INIT(&tag[0], "lit"); 2032 2033 if (n->head->child) { 2034 if ( ! strcmp("Em", n->head->child->string)) 2035 PAIR_CLASS_INIT(&tag[0], "emph"); 2036 else if ( ! strcmp("Sy", n->head->child->string)) 2037 PAIR_CLASS_INIT(&tag[0], "symb"); 2038 else if ( ! strcmp("Li", n->head->child->string)) 2039 PAIR_CLASS_INIT(&tag[0], "lit"); 2040 } else { 2041 assert(n->args); 2042 for (i = 0; i < (int)n->args->argc; i++) 2043 switch (n->args->argv[i].arg) { 2044 case (MDOC_Symbolic): 2045 PAIR_CLASS_INIT(&tag[0], "symb"); 2046 break; 2047 case (MDOC_Literal): 2048 PAIR_CLASS_INIT(&tag[0], "lit"); 2049 break; 2050 case (MDOC_Emphasis): 2051 PAIR_CLASS_INIT(&tag[0], "emph"); 2052 break; 2053 default: 2054 break; 2055 } 2056 } 2057 2058 /* FIXME: div's have spaces stripped--we want them. */ 2059 2060 bufcat_style(h, "display", "inline"); 2061 SCALE_HS_INIT(&su, 1); 2062 bufcat_su(h, "margin-right", &su); 2063 PAIR_STYLE_INIT(&tag[1], h); 2064 print_otag(h, TAG_DIV, 2, tag); 2065 return(1); 2066 } 2067 2068 2069 /* ARGSUSED */ 2070 static int 2071 mdoc_ms_pre(MDOC_ARGS) 2072 { 2073 struct htmlpair tag; 2074 2075 PAIR_CLASS_INIT(&tag, "symb"); 2076 print_otag(h, TAG_SPAN, 1, &tag); 2077 return(1); 2078 } 2079 2080 2081 /* ARGSUSED */ 2082 static int 2083 mdoc_pf_pre(MDOC_ARGS) 2084 { 2085 2086 h->flags |= HTML_IGNDELIM; 2087 return(1); 2088 } 2089 2090 2091 /* ARGSUSED */ 2092 static void 2093 mdoc_pf_post(MDOC_ARGS) 2094 { 2095 2096 h->flags &= ~HTML_IGNDELIM; 2097 h->flags |= HTML_NOSPACE; 2098 } 2099 2100 2101 /* ARGSUSED */ 2102 static int 2103 mdoc_rs_pre(MDOC_ARGS) 2104 { 2105 struct htmlpair tag; 2106 struct roffsu su; 2107 2108 if (MDOC_BLOCK != n->type) 2109 return(1); 2110 2111 if (n->prev && SEC_SEE_ALSO == n->sec) { 2112 SCALE_VS_INIT(&su, 1); 2113 bufcat_su(h, "margin-top", &su); 2114 PAIR_STYLE_INIT(&tag, h); 2115 print_otag(h, TAG_DIV, 1, &tag); 2116 } 2117 2118 PAIR_CLASS_INIT(&tag, "ref"); 2119 print_otag(h, TAG_SPAN, 1, &tag); 2120 return(1); 2121 } 2122 2123 2124 2125 /* ARGSUSED */ 2126 static int 2127 mdoc_li_pre(MDOC_ARGS) 2128 { 2129 struct htmlpair tag; 2130 2131 PAIR_CLASS_INIT(&tag, "lit"); 2132 print_otag(h, TAG_SPAN, 1, &tag); 2133 return(1); 2134 } 2135 2136 2137 /* ARGSUSED */ 2138 static int 2139 mdoc_sy_pre(MDOC_ARGS) 2140 { 2141 struct htmlpair tag; 2142 2143 PAIR_CLASS_INIT(&tag, "symb"); 2144 print_otag(h, TAG_SPAN, 1, &tag); 2145 return(1); 2146 } 2147 2148 2149 /* ARGSUSED */ 2150 static int 2151 mdoc_bt_pre(MDOC_ARGS) 2152 { 2153 2154 print_text(h, "is currently in beta test."); 2155 return(0); 2156 } 2157 2158 2159 /* ARGSUSED */ 2160 static int 2161 mdoc_ud_pre(MDOC_ARGS) 2162 { 2163 2164 print_text(h, "currently under development."); 2165 return(0); 2166 } 2167 2168 2169 /* ARGSUSED */ 2170 static int 2171 mdoc_lb_pre(MDOC_ARGS) 2172 { 2173 struct htmlpair tag; 2174 2175 if (SEC_SYNOPSIS == n->sec) 2176 print_otag(h, TAG_DIV, 0, NULL); 2177 PAIR_CLASS_INIT(&tag, "lib"); 2178 print_otag(h, TAG_SPAN, 1, &tag); 2179 return(1); 2180 } 2181 2182 2183 /* ARGSUSED */ 2184 static int 2185 mdoc__x_pre(MDOC_ARGS) 2186 { 2187 struct htmlpair tag[2]; 2188 2189 switch (n->tok) { 2190 case(MDOC__A): 2191 PAIR_CLASS_INIT(&tag[0], "ref-auth"); 2192 break; 2193 case(MDOC__B): 2194 PAIR_CLASS_INIT(&tag[0], "ref-book"); 2195 break; 2196 case(MDOC__C): 2197 PAIR_CLASS_INIT(&tag[0], "ref-city"); 2198 break; 2199 case(MDOC__D): 2200 PAIR_CLASS_INIT(&tag[0], "ref-date"); 2201 break; 2202 case(MDOC__I): 2203 PAIR_CLASS_INIT(&tag[0], "ref-issue"); 2204 break; 2205 case(MDOC__J): 2206 PAIR_CLASS_INIT(&tag[0], "ref-jrnl"); 2207 break; 2208 case(MDOC__N): 2209 PAIR_CLASS_INIT(&tag[0], "ref-num"); 2210 break; 2211 case(MDOC__O): 2212 PAIR_CLASS_INIT(&tag[0], "ref-opt"); 2213 break; 2214 case(MDOC__P): 2215 PAIR_CLASS_INIT(&tag[0], "ref-page"); 2216 break; 2217 case(MDOC__Q): 2218 PAIR_CLASS_INIT(&tag[0], "ref-corp"); 2219 break; 2220 case(MDOC__R): 2221 PAIR_CLASS_INIT(&tag[0], "ref-rep"); 2222 break; 2223 case(MDOC__T): 2224 PAIR_CLASS_INIT(&tag[0], "ref-title"); 2225 print_text(h, "\\(lq"); 2226 h->flags |= HTML_NOSPACE; 2227 break; 2228 case(MDOC__U): 2229 PAIR_CLASS_INIT(&tag[0], "link-ref"); 2230 break; 2231 case(MDOC__V): 2232 PAIR_CLASS_INIT(&tag[0], "ref-vol"); 2233 break; 2234 default: 2235 abort(); 2236 /* NOTREACHED */ 2237 } 2238 2239 if (MDOC__U != n->tok) { 2240 print_otag(h, TAG_SPAN, 1, tag); 2241 return(1); 2242 } 2243 2244 PAIR_HREF_INIT(&tag[1], n->child->string); 2245 print_otag(h, TAG_A, 2, tag); 2246 return(1); 2247 } 2248 2249 2250 /* ARGSUSED */ 2251 static void 2252 mdoc__x_post(MDOC_ARGS) 2253 { 2254 2255 h->flags |= HTML_NOSPACE; 2256 switch (n->tok) { 2257 case (MDOC__T): 2258 print_text(h, "\\(rq"); 2259 h->flags |= HTML_NOSPACE; 2260 break; 2261 default: 2262 break; 2263 } 2264 print_text(h, n->next ? "," : "."); 2265 } 2266