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