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