1 /* $Id: mdoc_man.c,v 1.46 2012/12/31 22:34:01 schwarze Exp $ */ 2 /* 3 * Copyright (c) 2011, 2012 Ingo Schwarze <schwarze@openbsd.org> 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 <assert.h> 18 #include <stdio.h> 19 #include <string.h> 20 21 #include "mandoc.h" 22 #include "out.h" 23 #include "man.h" 24 #include "mdoc.h" 25 #include "main.h" 26 27 #define DECL_ARGS const struct mdoc_meta *meta, \ 28 const struct mdoc_node *n 29 30 struct manact { 31 int (*cond)(DECL_ARGS); /* DON'T run actions */ 32 int (*pre)(DECL_ARGS); /* pre-node action */ 33 void (*post)(DECL_ARGS); /* post-node action */ 34 const char *prefix; /* pre-node string constant */ 35 const char *suffix; /* post-node string constant */ 36 }; 37 38 static int cond_body(DECL_ARGS); 39 static int cond_head(DECL_ARGS); 40 static void font_push(char); 41 static void font_pop(void); 42 static void mid_it(void); 43 static void post__t(DECL_ARGS); 44 static void post_bd(DECL_ARGS); 45 static void post_bf(DECL_ARGS); 46 static void post_bk(DECL_ARGS); 47 static void post_bl(DECL_ARGS); 48 static void post_dl(DECL_ARGS); 49 static void post_enc(DECL_ARGS); 50 static void post_eo(DECL_ARGS); 51 static void post_fa(DECL_ARGS); 52 static void post_fd(DECL_ARGS); 53 static void post_fl(DECL_ARGS); 54 static void post_fn(DECL_ARGS); 55 static void post_fo(DECL_ARGS); 56 static void post_font(DECL_ARGS); 57 static void post_in(DECL_ARGS); 58 static void post_it(DECL_ARGS); 59 static void post_lb(DECL_ARGS); 60 static void post_nm(DECL_ARGS); 61 static void post_percent(DECL_ARGS); 62 static void post_pf(DECL_ARGS); 63 static void post_sect(DECL_ARGS); 64 static void post_sp(DECL_ARGS); 65 static void post_vt(DECL_ARGS); 66 static int pre__t(DECL_ARGS); 67 static int pre_an(DECL_ARGS); 68 static int pre_ap(DECL_ARGS); 69 static int pre_bd(DECL_ARGS); 70 static int pre_bf(DECL_ARGS); 71 static int pre_bk(DECL_ARGS); 72 static int pre_bl(DECL_ARGS); 73 static int pre_br(DECL_ARGS); 74 static int pre_bx(DECL_ARGS); 75 static int pre_dl(DECL_ARGS); 76 static int pre_enc(DECL_ARGS); 77 static int pre_em(DECL_ARGS); 78 static int pre_fa(DECL_ARGS); 79 static int pre_fd(DECL_ARGS); 80 static int pre_fl(DECL_ARGS); 81 static int pre_fn(DECL_ARGS); 82 static int pre_fo(DECL_ARGS); 83 static int pre_ft(DECL_ARGS); 84 static int pre_in(DECL_ARGS); 85 static int pre_it(DECL_ARGS); 86 static int pre_lk(DECL_ARGS); 87 static int pre_li(DECL_ARGS); 88 static int pre_nm(DECL_ARGS); 89 static int pre_no(DECL_ARGS); 90 static int pre_ns(DECL_ARGS); 91 static int pre_pp(DECL_ARGS); 92 static int pre_rs(DECL_ARGS); 93 static int pre_sm(DECL_ARGS); 94 static int pre_sp(DECL_ARGS); 95 static int pre_sect(DECL_ARGS); 96 static int pre_sy(DECL_ARGS); 97 static void pre_syn(const struct mdoc_node *); 98 static int pre_vt(DECL_ARGS); 99 static int pre_ux(DECL_ARGS); 100 static int pre_xr(DECL_ARGS); 101 static void print_word(const char *); 102 static void print_line(const char *, int); 103 static void print_block(const char *, int); 104 static void print_offs(const char *); 105 static void print_width(const char *, 106 const struct mdoc_node *, size_t); 107 static void print_count(int *); 108 static void print_node(DECL_ARGS); 109 110 static const struct manact manacts[MDOC_MAX + 1] = { 111 { NULL, pre_ap, NULL, NULL, NULL }, /* Ap */ 112 { NULL, NULL, NULL, NULL, NULL }, /* Dd */ 113 { NULL, NULL, NULL, NULL, NULL }, /* Dt */ 114 { NULL, NULL, NULL, NULL, NULL }, /* Os */ 115 { NULL, pre_sect, post_sect, ".SH", NULL }, /* Sh */ 116 { NULL, pre_sect, post_sect, ".SS", NULL }, /* Ss */ 117 { NULL, pre_pp, NULL, NULL, NULL }, /* Pp */ 118 { cond_body, pre_dl, post_dl, NULL, NULL }, /* D1 */ 119 { cond_body, pre_dl, post_dl, NULL, NULL }, /* Dl */ 120 { cond_body, pre_bd, post_bd, NULL, NULL }, /* Bd */ 121 { NULL, NULL, NULL, NULL, NULL }, /* Ed */ 122 { cond_body, pre_bl, post_bl, NULL, NULL }, /* Bl */ 123 { NULL, NULL, NULL, NULL, NULL }, /* El */ 124 { NULL, pre_it, post_it, NULL, NULL }, /* It */ 125 { NULL, pre_em, post_font, NULL, NULL }, /* Ad */ 126 { NULL, pre_an, NULL, NULL, NULL }, /* An */ 127 { NULL, pre_em, post_font, NULL, NULL }, /* Ar */ 128 { NULL, pre_sy, post_font, NULL, NULL }, /* Cd */ 129 { NULL, pre_sy, post_font, NULL, NULL }, /* Cm */ 130 { NULL, pre_li, post_font, NULL, NULL }, /* Dv */ 131 { NULL, pre_li, post_font, NULL, NULL }, /* Er */ 132 { NULL, pre_li, post_font, NULL, NULL }, /* Ev */ 133 { NULL, pre_enc, post_enc, "The \\fB", 134 "\\fP\nutility exits 0 on success, and >0 if an error occurs." 135 }, /* Ex */ 136 { NULL, pre_fa, post_fa, NULL, NULL }, /* Fa */ 137 { NULL, pre_fd, post_fd, NULL, NULL }, /* Fd */ 138 { NULL, pre_fl, post_fl, NULL, NULL }, /* Fl */ 139 { NULL, pre_fn, post_fn, NULL, NULL }, /* Fn */ 140 { NULL, pre_ft, post_font, NULL, NULL }, /* Ft */ 141 { NULL, pre_sy, post_font, NULL, NULL }, /* Ic */ 142 { NULL, pre_in, post_in, NULL, NULL }, /* In */ 143 { NULL, pre_li, post_font, NULL, NULL }, /* Li */ 144 { cond_head, pre_enc, NULL, "\\- ", NULL }, /* Nd */ 145 { NULL, pre_nm, post_nm, NULL, NULL }, /* Nm */ 146 { cond_body, pre_enc, post_enc, "[", "]" }, /* Op */ 147 { NULL, NULL, NULL, NULL, NULL }, /* Ot */ 148 { NULL, pre_em, post_font, NULL, NULL }, /* Pa */ 149 { NULL, pre_enc, post_enc, "The \\fB", 150 "\\fP\nfunction returns the value 0 if successful;\n" 151 "otherwise the value -1 is returned and the global\n" 152 "variable \\fIerrno\\fP is set to indicate the error." 153 }, /* Rv */ 154 { NULL, NULL, NULL, NULL, NULL }, /* St */ 155 { NULL, pre_em, post_font, NULL, NULL }, /* Va */ 156 { NULL, pre_vt, post_vt, NULL, NULL }, /* Vt */ 157 { NULL, pre_xr, NULL, NULL, NULL }, /* Xr */ 158 { NULL, NULL, post_percent, NULL, NULL }, /* %A */ 159 { NULL, pre_em, post_percent, NULL, NULL }, /* %B */ 160 { NULL, NULL, post_percent, NULL, NULL }, /* %D */ 161 { NULL, pre_em, post_percent, NULL, NULL }, /* %I */ 162 { NULL, pre_em, post_percent, NULL, NULL }, /* %J */ 163 { NULL, NULL, post_percent, NULL, NULL }, /* %N */ 164 { NULL, NULL, post_percent, NULL, NULL }, /* %O */ 165 { NULL, NULL, post_percent, NULL, NULL }, /* %P */ 166 { NULL, NULL, post_percent, NULL, NULL }, /* %R */ 167 { NULL, pre__t, post__t, NULL, NULL }, /* %T */ 168 { NULL, NULL, post_percent, NULL, NULL }, /* %V */ 169 { NULL, NULL, NULL, NULL, NULL }, /* Ac */ 170 { cond_body, pre_enc, post_enc, "<", ">" }, /* Ao */ 171 { cond_body, pre_enc, post_enc, "<", ">" }, /* Aq */ 172 { NULL, NULL, NULL, NULL, NULL }, /* At */ 173 { NULL, NULL, NULL, NULL, NULL }, /* Bc */ 174 { NULL, pre_bf, post_bf, NULL, NULL }, /* Bf */ 175 { cond_body, pre_enc, post_enc, "[", "]" }, /* Bo */ 176 { cond_body, pre_enc, post_enc, "[", "]" }, /* Bq */ 177 { NULL, pre_ux, NULL, "BSD/OS", NULL }, /* Bsx */ 178 { NULL, pre_bx, NULL, NULL, NULL }, /* Bx */ 179 { NULL, NULL, NULL, NULL, NULL }, /* Db */ 180 { NULL, NULL, NULL, NULL, NULL }, /* Dc */ 181 { cond_body, pre_enc, post_enc, "``", "''" }, /* Do */ 182 { cond_body, pre_enc, post_enc, "``", "''" }, /* Dq */ 183 { NULL, NULL, NULL, NULL, NULL }, /* Ec */ 184 { NULL, NULL, NULL, NULL, NULL }, /* Ef */ 185 { NULL, pre_em, post_font, NULL, NULL }, /* Em */ 186 { NULL, NULL, post_eo, NULL, NULL }, /* Eo */ 187 { NULL, pre_ux, NULL, "FreeBSD", NULL }, /* Fx */ 188 { NULL, pre_sy, post_font, NULL, NULL }, /* Ms */ 189 { NULL, pre_no, NULL, NULL, NULL }, /* No */ 190 { NULL, pre_ns, NULL, NULL, NULL }, /* Ns */ 191 { NULL, pre_ux, NULL, "NetBSD", NULL }, /* Nx */ 192 { NULL, pre_ux, NULL, "OpenBSD", NULL }, /* Ox */ 193 { NULL, NULL, NULL, NULL, NULL }, /* Pc */ 194 { NULL, NULL, post_pf, NULL, NULL }, /* Pf */ 195 { cond_body, pre_enc, post_enc, "(", ")" }, /* Po */ 196 { cond_body, pre_enc, post_enc, "(", ")" }, /* Pq */ 197 { NULL, NULL, NULL, NULL, NULL }, /* Qc */ 198 { cond_body, pre_enc, post_enc, "`", "'" }, /* Ql */ 199 { cond_body, pre_enc, post_enc, "\"", "\"" }, /* Qo */ 200 { cond_body, pre_enc, post_enc, "\"", "\"" }, /* Qq */ 201 { NULL, NULL, NULL, NULL, NULL }, /* Re */ 202 { cond_body, pre_rs, NULL, NULL, NULL }, /* Rs */ 203 { NULL, NULL, NULL, NULL, NULL }, /* Sc */ 204 { cond_body, pre_enc, post_enc, "`", "'" }, /* So */ 205 { cond_body, pre_enc, post_enc, "`", "'" }, /* Sq */ 206 { NULL, pre_sm, NULL, NULL, NULL }, /* Sm */ 207 { NULL, pre_em, post_font, NULL, NULL }, /* Sx */ 208 { NULL, pre_sy, post_font, NULL, NULL }, /* Sy */ 209 { NULL, pre_li, post_font, NULL, NULL }, /* Tn */ 210 { NULL, pre_ux, NULL, "UNIX", NULL }, /* Ux */ 211 { NULL, NULL, NULL, NULL, NULL }, /* Xc */ 212 { NULL, NULL, NULL, NULL, NULL }, /* Xo */ 213 { NULL, pre_fo, post_fo, NULL, NULL }, /* Fo */ 214 { NULL, NULL, NULL, NULL, NULL }, /* Fc */ 215 { cond_body, pre_enc, post_enc, "[", "]" }, /* Oo */ 216 { NULL, NULL, NULL, NULL, NULL }, /* Oc */ 217 { NULL, pre_bk, post_bk, NULL, NULL }, /* Bk */ 218 { NULL, NULL, NULL, NULL, NULL }, /* Ek */ 219 { NULL, pre_ux, NULL, "is currently in beta test.", NULL }, /* Bt */ 220 { NULL, NULL, NULL, NULL, NULL }, /* Hf */ 221 { NULL, NULL, NULL, NULL, NULL }, /* Fr */ 222 { NULL, pre_ux, NULL, "currently under development.", NULL }, /* Ud */ 223 { NULL, NULL, post_lb, NULL, NULL }, /* Lb */ 224 { NULL, pre_pp, NULL, NULL, NULL }, /* Lp */ 225 { NULL, pre_lk, NULL, NULL, NULL }, /* Lk */ 226 { NULL, pre_em, post_font, NULL, NULL }, /* Mt */ 227 { cond_body, pre_enc, post_enc, "{", "}" }, /* Brq */ 228 { cond_body, pre_enc, post_enc, "{", "}" }, /* Bro */ 229 { NULL, NULL, NULL, NULL, NULL }, /* Brc */ 230 { NULL, NULL, post_percent, NULL, NULL }, /* %C */ 231 { NULL, NULL, NULL, NULL, NULL }, /* Es */ 232 { NULL, NULL, NULL, NULL, NULL }, /* En */ 233 { NULL, pre_ux, NULL, "DragonFly", NULL }, /* Dx */ 234 { NULL, NULL, post_percent, NULL, NULL }, /* %Q */ 235 { NULL, pre_br, NULL, NULL, NULL }, /* br */ 236 { NULL, pre_sp, post_sp, NULL, NULL }, /* sp */ 237 { NULL, NULL, post_percent, NULL, NULL }, /* %U */ 238 { NULL, NULL, NULL, NULL, NULL }, /* Ta */ 239 { NULL, NULL, NULL, NULL, NULL }, /* ROOT */ 240 }; 241 242 static int outflags; 243 #define MMAN_spc (1 << 0) /* blank character before next word */ 244 #define MMAN_spc_force (1 << 1) /* even before trailing punctuation */ 245 #define MMAN_nl (1 << 2) /* break man(7) code line */ 246 #define MMAN_br (1 << 3) /* break output line */ 247 #define MMAN_sp (1 << 4) /* insert a blank output line */ 248 #define MMAN_PP (1 << 5) /* reset indentation etc. */ 249 #define MMAN_Sm (1 << 6) /* horizontal spacing mode */ 250 #define MMAN_Bk (1 << 7) /* word keep mode */ 251 #define MMAN_Bk_susp (1 << 8) /* suspend this (after a macro) */ 252 #define MMAN_An_split (1 << 9) /* author mode is "split" */ 253 #define MMAN_An_nosplit (1 << 10) /* author mode is "nosplit" */ 254 #define MMAN_PD (1 << 11) /* inter-paragraph spacing disabled */ 255 256 #define BL_STACK_MAX 32 257 258 static size_t Bl_stack[BL_STACK_MAX]; /* offsets [chars] */ 259 static int Bl_stack_post[BL_STACK_MAX]; /* add final .RE */ 260 static int Bl_stack_len; /* number of nested Bl blocks */ 261 static int TPremain; /* characters before tag is full */ 262 263 static struct { 264 char *head; 265 char *tail; 266 size_t size; 267 } fontqueue; 268 269 static void 270 font_push(char newfont) 271 { 272 273 if (fontqueue.head + fontqueue.size <= ++fontqueue.tail) { 274 fontqueue.size += 8; 275 fontqueue.head = mandoc_realloc(fontqueue.head, 276 fontqueue.size); 277 } 278 *fontqueue.tail = newfont; 279 print_word(""); 280 printf("\\f"); 281 putchar(newfont); 282 outflags &= ~MMAN_spc; 283 } 284 285 static void 286 font_pop(void) 287 { 288 289 if (fontqueue.tail > fontqueue.head) 290 fontqueue.tail--; 291 outflags &= ~MMAN_spc; 292 print_word(""); 293 printf("\\f"); 294 putchar(*fontqueue.tail); 295 } 296 297 static void 298 print_word(const char *s) 299 { 300 301 if ((MMAN_PP | MMAN_sp | MMAN_br | MMAN_nl) & outflags) { 302 /* 303 * If we need a newline, print it now and start afresh. 304 */ 305 if (MMAN_PP & outflags) { 306 if (MMAN_sp & outflags) { 307 if (MMAN_PD & outflags) { 308 printf("\n.PD"); 309 outflags &= ~MMAN_PD; 310 } 311 } else if ( ! (MMAN_PD & outflags)) { 312 printf("\n.PD 0"); 313 outflags |= MMAN_PD; 314 } 315 printf("\n.PP\n"); 316 } else if (MMAN_sp & outflags) 317 printf("\n.sp\n"); 318 else if (MMAN_br & outflags) 319 printf("\n.br\n"); 320 else if (MMAN_nl & outflags) 321 putchar('\n'); 322 outflags &= ~(MMAN_PP|MMAN_sp|MMAN_br|MMAN_nl|MMAN_spc); 323 if (1 == TPremain) 324 printf(".br\n"); 325 TPremain = 0; 326 } else if (MMAN_spc & outflags) { 327 /* 328 * If we need a space, only print it if 329 * (1) it is forced by `No' or 330 * (2) what follows is not terminating punctuation or 331 * (3) what follows is longer than one character. 332 */ 333 if (MMAN_spc_force & outflags || '\0' == s[0] || 334 NULL == strchr(".,:;)]?!", s[0]) || '\0' != s[1]) { 335 if (MMAN_Bk & outflags && 336 ! (MMAN_Bk_susp & outflags)) 337 putchar('\\'); 338 putchar(' '); 339 if (TPremain) 340 TPremain--; 341 } 342 } 343 344 /* 345 * Reassign needing space if we're not following opening 346 * punctuation. 347 */ 348 if (MMAN_Sm & outflags && ('\0' == s[0] || 349 (('(' != s[0] && '[' != s[0]) || '\0' != s[1]))) 350 outflags |= MMAN_spc; 351 else 352 outflags &= ~MMAN_spc; 353 outflags &= ~(MMAN_spc_force | MMAN_Bk_susp); 354 355 for ( ; *s; s++) { 356 switch (*s) { 357 case (ASCII_NBRSP): 358 printf("\\ "); 359 break; 360 case (ASCII_HYPH): 361 putchar('-'); 362 break; 363 default: 364 putchar((unsigned char)*s); 365 break; 366 } 367 if (TPremain) 368 TPremain--; 369 } 370 } 371 372 static void 373 print_line(const char *s, int newflags) 374 { 375 376 outflags &= ~MMAN_br; 377 outflags |= MMAN_nl; 378 print_word(s); 379 outflags |= newflags; 380 } 381 382 static void 383 print_block(const char *s, int newflags) 384 { 385 386 outflags &= ~MMAN_PP; 387 if (MMAN_sp & outflags) { 388 outflags &= ~(MMAN_sp | MMAN_br); 389 if (MMAN_PD & outflags) { 390 print_line(".PD", 0); 391 outflags &= ~MMAN_PD; 392 } 393 } else if (! (MMAN_PD & outflags)) 394 print_line(".PD 0", MMAN_PD); 395 outflags |= MMAN_nl; 396 print_word(s); 397 outflags |= MMAN_Bk_susp | newflags; 398 } 399 400 static void 401 print_offs(const char *v) 402 { 403 char buf[24]; 404 struct roffsu su; 405 size_t sz; 406 407 /* Convert v into a number (of characters). */ 408 if (NULL == v || '\0' == *v || 0 == strcmp(v, "left")) 409 sz = 0; 410 else if (0 == strcmp(v, "indent")) 411 sz = 6; 412 else if (0 == strcmp(v, "indent-two")) 413 sz = 12; 414 else if (a2roffsu(v, &su, SCALE_MAX)) { 415 if (SCALE_EN == su.unit) 416 sz = su.scale; 417 else { 418 /* 419 * XXX 420 * If we are inside an enclosing list, 421 * there is no easy way to add the two 422 * indentations because they are provided 423 * in terms of different units. 424 */ 425 print_word(v); 426 return; 427 } 428 } else 429 sz = strlen(v); 430 431 /* 432 * We are inside an enclosing list. 433 * Add the two indentations. 434 */ 435 if (Bl_stack_len) 436 sz += Bl_stack[Bl_stack_len - 1]; 437 438 snprintf(buf, sizeof(buf), "%ldn", sz); 439 print_word(buf); 440 } 441 442 /* 443 * Set up the indentation for a list item; used from pre_it(). 444 */ 445 void 446 print_width(const char *v, const struct mdoc_node *child, size_t defsz) 447 { 448 char buf[24]; 449 struct roffsu su; 450 size_t sz, chsz; 451 int numeric, remain; 452 453 numeric = 1; 454 remain = 0; 455 456 /* Convert v into a number (of characters). */ 457 if (NULL == v) 458 sz = defsz; 459 else if (a2roffsu(v, &su, SCALE_MAX)) { 460 if (SCALE_EN == su.unit) 461 sz = su.scale; 462 else { 463 sz = 0; 464 numeric = 0; 465 } 466 } else 467 sz = strlen(v); 468 469 /* XXX Rough estimation, might have multiple parts. */ 470 chsz = (NULL != child && MDOC_TEXT == child->type) ? 471 strlen(child->string) : 0; 472 473 /* Maybe we are inside an enclosing list? */ 474 mid_it(); 475 476 /* 477 * Save our own indentation, 478 * such that child lists can use it. 479 */ 480 Bl_stack[Bl_stack_len++] = sz + 2; 481 482 /* Set up the current list. */ 483 if (defsz && chsz > sz) 484 print_block(".HP", 0); 485 else { 486 print_block(".TP", 0); 487 remain = sz + 2; 488 } 489 if (numeric) { 490 snprintf(buf, sizeof(buf), "%ldn", sz + 2); 491 print_word(buf); 492 } else 493 print_word(v); 494 TPremain = remain; 495 } 496 497 void 498 print_count(int *count) 499 { 500 char buf[12]; 501 502 snprintf(buf, sizeof(buf), "%d.", ++*count); 503 print_word(buf); 504 } 505 506 void 507 man_man(void *arg, const struct man *man) 508 { 509 510 /* 511 * Dump the keep buffer. 512 * We're guaranteed by now that this exists (is non-NULL). 513 * Flush stdout afterward, just in case. 514 */ 515 fputs(mparse_getkeep(man_mparse(man)), stdout); 516 fflush(stdout); 517 } 518 519 void 520 man_mdoc(void *arg, const struct mdoc *mdoc) 521 { 522 const struct mdoc_meta *meta; 523 const struct mdoc_node *n; 524 525 meta = mdoc_meta(mdoc); 526 n = mdoc_node(mdoc); 527 528 printf(".TH \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"\n", 529 meta->title, meta->msec, meta->date, 530 meta->os, meta->vol); 531 532 /* Disable hyphenation and if nroff, disable justification. */ 533 printf(".nh\n.if n .ad l"); 534 535 outflags = MMAN_nl | MMAN_Sm; 536 if (0 == fontqueue.size) { 537 fontqueue.size = 8; 538 fontqueue.head = fontqueue.tail = mandoc_malloc(8); 539 *fontqueue.tail = 'R'; 540 } 541 print_node(meta, n); 542 putchar('\n'); 543 } 544 545 static void 546 print_node(DECL_ARGS) 547 { 548 const struct mdoc_node *prev, *sub; 549 const struct manact *act; 550 int cond, do_sub; 551 552 /* 553 * Break the line if we were parsed subsequent the current node. 554 * This makes the page structure be more consistent. 555 */ 556 prev = n->prev ? n->prev : n->parent; 557 if (MMAN_spc & outflags && prev && prev->line < n->line) 558 outflags |= MMAN_nl; 559 560 act = NULL; 561 cond = 0; 562 do_sub = 1; 563 564 if (MDOC_TEXT == n->type) { 565 /* 566 * Make sure that we don't happen to start with a 567 * control character at the start of a line. 568 */ 569 if (MMAN_nl & outflags && ('.' == *n->string || 570 '\'' == *n->string)) { 571 print_word(""); 572 printf("\\&"); 573 outflags &= ~MMAN_spc; 574 } 575 print_word(n->string); 576 } else { 577 /* 578 * Conditionally run the pre-node action handler for a 579 * node. 580 */ 581 act = manacts + n->tok; 582 cond = NULL == act->cond || (*act->cond)(meta, n); 583 if (cond && act->pre) 584 do_sub = (*act->pre)(meta, n); 585 } 586 587 /* 588 * Conditionally run all child nodes. 589 * Note that this iterates over children instead of using 590 * recursion. This prevents unnecessary depth in the stack. 591 */ 592 if (do_sub) 593 for (sub = n->child; sub; sub = sub->next) 594 print_node(meta, sub); 595 596 /* 597 * Lastly, conditionally run the post-node handler. 598 */ 599 if (cond && act->post) 600 (*act->post)(meta, n); 601 } 602 603 static int 604 cond_head(DECL_ARGS) 605 { 606 607 return(MDOC_HEAD == n->type); 608 } 609 610 static int 611 cond_body(DECL_ARGS) 612 { 613 614 return(MDOC_BODY == n->type); 615 } 616 617 static int 618 pre_enc(DECL_ARGS) 619 { 620 const char *prefix; 621 622 prefix = manacts[n->tok].prefix; 623 if (NULL == prefix) 624 return(1); 625 print_word(prefix); 626 outflags &= ~MMAN_spc; 627 return(1); 628 } 629 630 static void 631 post_enc(DECL_ARGS) 632 { 633 const char *suffix; 634 635 suffix = manacts[n->tok].suffix; 636 if (NULL == suffix) 637 return; 638 outflags &= ~MMAN_spc; 639 print_word(suffix); 640 } 641 642 static void 643 post_font(DECL_ARGS) 644 { 645 646 font_pop(); 647 } 648 649 static void 650 post_percent(DECL_ARGS) 651 { 652 653 if (pre_em == manacts[n->tok].pre) 654 font_pop(); 655 if (n->next) { 656 print_word(","); 657 if (n->prev && n->prev->tok == n->tok && 658 n->next->tok == n->tok) 659 print_word("and"); 660 } else { 661 print_word("."); 662 outflags |= MMAN_nl; 663 } 664 } 665 666 static int 667 pre__t(DECL_ARGS) 668 { 669 670 if (n->parent && MDOC_Rs == n->parent->tok && 671 n->parent->norm->Rs.quote_T) { 672 print_word(""); 673 putchar('\"'); 674 outflags &= ~MMAN_spc; 675 } else 676 font_push('I'); 677 return(1); 678 } 679 680 static void 681 post__t(DECL_ARGS) 682 { 683 684 if (n->parent && MDOC_Rs == n->parent->tok && 685 n->parent->norm->Rs.quote_T) { 686 outflags &= ~MMAN_spc; 687 print_word(""); 688 putchar('\"'); 689 } else 690 font_pop(); 691 post_percent(meta, n); 692 } 693 694 /* 695 * Print before a section header. 696 */ 697 static int 698 pre_sect(DECL_ARGS) 699 { 700 701 switch (n->type) { 702 case (MDOC_HEAD): 703 outflags |= MMAN_sp; 704 print_block(manacts[n->tok].prefix, 0); 705 print_word(""); 706 putchar('\"'); 707 outflags &= ~MMAN_spc; 708 break; 709 case (MDOC_BODY): 710 if (MDOC_Sh == n->tok) { 711 if (MDOC_SYNPRETTY & n->flags) 712 outflags |= MMAN_Bk; 713 else 714 outflags &= ~MMAN_Bk; 715 } 716 break; 717 default: 718 break; 719 } 720 return(1); 721 } 722 723 /* 724 * Print subsequent a section header. 725 */ 726 static void 727 post_sect(DECL_ARGS) 728 { 729 730 if (MDOC_HEAD != n->type) 731 return; 732 outflags &= ~MMAN_spc; 733 print_word(""); 734 putchar('\"'); 735 outflags |= MMAN_nl; 736 if (MDOC_Sh == n->tok && SEC_AUTHORS == n->sec) 737 outflags &= ~(MMAN_An_split | MMAN_An_nosplit); 738 } 739 740 /* See mdoc_term.c, synopsis_pre() for comments. */ 741 static void 742 pre_syn(const struct mdoc_node *n) 743 { 744 745 if (NULL == n->prev || ! (MDOC_SYNPRETTY & n->flags)) 746 return; 747 748 if (n->prev->tok == n->tok && 749 MDOC_Ft != n->tok && 750 MDOC_Fo != n->tok && 751 MDOC_Fn != n->tok) { 752 outflags |= MMAN_br; 753 return; 754 } 755 756 switch (n->prev->tok) { 757 case (MDOC_Fd): 758 /* FALLTHROUGH */ 759 case (MDOC_Fn): 760 /* FALLTHROUGH */ 761 case (MDOC_Fo): 762 /* FALLTHROUGH */ 763 case (MDOC_In): 764 /* FALLTHROUGH */ 765 case (MDOC_Vt): 766 outflags |= MMAN_sp; 767 break; 768 case (MDOC_Ft): 769 if (MDOC_Fn != n->tok && MDOC_Fo != n->tok) { 770 outflags |= MMAN_sp; 771 break; 772 } 773 /* FALLTHROUGH */ 774 default: 775 outflags |= MMAN_br; 776 break; 777 } 778 } 779 780 static int 781 pre_an(DECL_ARGS) 782 { 783 784 switch (n->norm->An.auth) { 785 case (AUTH_split): 786 outflags &= ~MMAN_An_nosplit; 787 outflags |= MMAN_An_split; 788 return(0); 789 case (AUTH_nosplit): 790 outflags &= ~MMAN_An_split; 791 outflags |= MMAN_An_nosplit; 792 return(0); 793 default: 794 if (MMAN_An_split & outflags) 795 outflags |= MMAN_br; 796 else if (SEC_AUTHORS == n->sec && 797 ! (MMAN_An_nosplit & outflags)) 798 outflags |= MMAN_An_split; 799 return(1); 800 } 801 } 802 803 static int 804 pre_ap(DECL_ARGS) 805 { 806 807 outflags &= ~MMAN_spc; 808 print_word("'"); 809 outflags &= ~MMAN_spc; 810 return(0); 811 } 812 813 static int 814 pre_bd(DECL_ARGS) 815 { 816 817 outflags &= ~(MMAN_PP | MMAN_sp | MMAN_br); 818 819 if (DISP_unfilled == n->norm->Bd.type || 820 DISP_literal == n->norm->Bd.type) 821 print_line(".nf", 0); 822 if (0 == n->norm->Bd.comp && NULL != n->parent->prev) 823 outflags |= MMAN_sp; 824 print_line(".RS", MMAN_Bk_susp); 825 print_offs(n->norm->Bd.offs); 826 outflags |= MMAN_nl; 827 return(1); 828 } 829 830 static void 831 post_bd(DECL_ARGS) 832 { 833 834 /* Close out this display. */ 835 print_line(".RE", MMAN_nl); 836 if (DISP_unfilled == n->norm->Bd.type || 837 DISP_literal == n->norm->Bd.type) 838 print_line(".fi", MMAN_nl); 839 840 /* Maybe we are inside an enclosing list? */ 841 if (NULL != n->parent->next) 842 mid_it(); 843 } 844 845 static int 846 pre_bf(DECL_ARGS) 847 { 848 849 switch (n->type) { 850 case (MDOC_BLOCK): 851 return(1); 852 case (MDOC_BODY): 853 break; 854 default: 855 return(0); 856 } 857 switch (n->norm->Bf.font) { 858 case (FONT_Em): 859 font_push('I'); 860 break; 861 case (FONT_Sy): 862 font_push('B'); 863 break; 864 default: 865 font_push('R'); 866 break; 867 } 868 return(1); 869 } 870 871 static void 872 post_bf(DECL_ARGS) 873 { 874 875 if (MDOC_BODY == n->type) 876 font_pop(); 877 } 878 879 static int 880 pre_bk(DECL_ARGS) 881 { 882 883 switch (n->type) { 884 case (MDOC_BLOCK): 885 return(1); 886 case (MDOC_BODY): 887 outflags |= MMAN_Bk; 888 return(1); 889 default: 890 return(0); 891 } 892 } 893 894 static void 895 post_bk(DECL_ARGS) 896 { 897 898 if (MDOC_BODY == n->type) 899 outflags &= ~MMAN_Bk; 900 } 901 902 static int 903 pre_bl(DECL_ARGS) 904 { 905 size_t icol; 906 907 switch (n->norm->Bl.type) { 908 case (LIST_enum): 909 n->norm->Bl.count = 0; 910 return(1); 911 case (LIST_column): 912 break; 913 default: 914 return(1); 915 } 916 917 print_line(".TS", MMAN_nl); 918 for (icol = 0; icol < n->norm->Bl.ncols; icol++) 919 print_word("l"); 920 print_word("."); 921 outflags |= MMAN_nl; 922 return(1); 923 } 924 925 static void 926 post_bl(DECL_ARGS) 927 { 928 929 switch (n->norm->Bl.type) { 930 case (LIST_column): 931 print_line(".TE", 0); 932 break; 933 case (LIST_enum): 934 n->norm->Bl.count = 0; 935 break; 936 default: 937 break; 938 } 939 outflags |= MMAN_PP | MMAN_nl; 940 outflags &= ~(MMAN_sp | MMAN_br); 941 942 /* Maybe we are inside an enclosing list? */ 943 if (NULL != n->parent->next) 944 mid_it(); 945 946 } 947 948 static int 949 pre_br(DECL_ARGS) 950 { 951 952 outflags |= MMAN_br; 953 return(0); 954 } 955 956 static int 957 pre_bx(DECL_ARGS) 958 { 959 960 n = n->child; 961 if (n) { 962 print_word(n->string); 963 outflags &= ~MMAN_spc; 964 n = n->next; 965 } 966 print_word("BSD"); 967 if (NULL == n) 968 return(0); 969 outflags &= ~MMAN_spc; 970 print_word("-"); 971 outflags &= ~MMAN_spc; 972 print_word(n->string); 973 return(0); 974 } 975 976 static int 977 pre_dl(DECL_ARGS) 978 { 979 980 print_line(".RS", MMAN_Bk_susp); 981 print_offs("6n"); 982 outflags |= MMAN_nl; 983 return(1); 984 } 985 986 static void 987 post_dl(DECL_ARGS) 988 { 989 990 print_line(".RE", MMAN_nl); 991 992 /* Maybe we are inside an enclosing list? */ 993 if (NULL != n->parent->next) 994 mid_it(); 995 } 996 997 static int 998 pre_em(DECL_ARGS) 999 { 1000 1001 font_push('I'); 1002 return(1); 1003 } 1004 1005 static void 1006 post_eo(DECL_ARGS) 1007 { 1008 1009 if (MDOC_HEAD == n->type || MDOC_BODY == n->type) 1010 outflags &= ~MMAN_spc; 1011 } 1012 1013 static int 1014 pre_fa(DECL_ARGS) 1015 { 1016 1017 if (MDOC_Fa == n->tok) 1018 n = n->child; 1019 1020 while (NULL != n) { 1021 font_push('I'); 1022 print_node(meta, n); 1023 font_pop(); 1024 if (NULL != (n = n->next)) 1025 print_word(","); 1026 } 1027 return(0); 1028 } 1029 1030 static void 1031 post_fa(DECL_ARGS) 1032 { 1033 1034 if (NULL != n->next && MDOC_Fa == n->next->tok) 1035 print_word(","); 1036 } 1037 1038 static int 1039 pre_fd(DECL_ARGS) 1040 { 1041 1042 pre_syn(n); 1043 font_push('B'); 1044 return(1); 1045 } 1046 1047 static void 1048 post_fd(DECL_ARGS) 1049 { 1050 1051 font_pop(); 1052 outflags |= MMAN_br; 1053 } 1054 1055 static int 1056 pre_fl(DECL_ARGS) 1057 { 1058 1059 font_push('B'); 1060 print_word("\\-"); 1061 outflags &= ~MMAN_spc; 1062 return(1); 1063 } 1064 1065 static void 1066 post_fl(DECL_ARGS) 1067 { 1068 1069 font_pop(); 1070 if (0 == n->nchild && NULL != n->next && 1071 n->next->line == n->line) 1072 outflags &= ~MMAN_spc; 1073 } 1074 1075 static int 1076 pre_fn(DECL_ARGS) 1077 { 1078 1079 pre_syn(n); 1080 1081 n = n->child; 1082 if (NULL == n) 1083 return(0); 1084 1085 font_push('B'); 1086 print_node(meta, n); 1087 font_pop(); 1088 outflags &= ~MMAN_spc; 1089 print_word("("); 1090 outflags &= ~MMAN_spc; 1091 1092 n = n->next; 1093 if (NULL != n) 1094 pre_fa(meta, n); 1095 return(0); 1096 } 1097 1098 static void 1099 post_fn(DECL_ARGS) 1100 { 1101 1102 print_word(")"); 1103 if (MDOC_SYNPRETTY & n->flags) { 1104 print_word(";"); 1105 outflags |= MMAN_br; 1106 } 1107 } 1108 1109 static int 1110 pre_fo(DECL_ARGS) 1111 { 1112 1113 switch (n->type) { 1114 case (MDOC_BLOCK): 1115 pre_syn(n); 1116 break; 1117 case (MDOC_HEAD): 1118 font_push('B'); 1119 break; 1120 case (MDOC_BODY): 1121 outflags &= ~MMAN_spc; 1122 print_word("("); 1123 outflags &= ~MMAN_spc; 1124 break; 1125 default: 1126 break; 1127 } 1128 return(1); 1129 } 1130 1131 static void 1132 post_fo(DECL_ARGS) 1133 { 1134 1135 switch (n->type) { 1136 case (MDOC_HEAD): 1137 font_pop(); 1138 break; 1139 case (MDOC_BODY): 1140 post_fn(meta, n); 1141 break; 1142 default: 1143 break; 1144 } 1145 } 1146 1147 static int 1148 pre_ft(DECL_ARGS) 1149 { 1150 1151 pre_syn(n); 1152 font_push('I'); 1153 return(1); 1154 } 1155 1156 static int 1157 pre_in(DECL_ARGS) 1158 { 1159 1160 if (MDOC_SYNPRETTY & n->flags) { 1161 pre_syn(n); 1162 font_push('B'); 1163 print_word("#include <"); 1164 outflags &= ~MMAN_spc; 1165 } else { 1166 print_word("<"); 1167 outflags &= ~MMAN_spc; 1168 font_push('I'); 1169 } 1170 return(1); 1171 } 1172 1173 static void 1174 post_in(DECL_ARGS) 1175 { 1176 1177 if (MDOC_SYNPRETTY & n->flags) { 1178 outflags &= ~MMAN_spc; 1179 print_word(">"); 1180 font_pop(); 1181 outflags |= MMAN_br; 1182 } else { 1183 font_pop(); 1184 outflags &= ~MMAN_spc; 1185 print_word(">"); 1186 } 1187 } 1188 1189 static int 1190 pre_it(DECL_ARGS) 1191 { 1192 const struct mdoc_node *bln; 1193 1194 switch (n->type) { 1195 case (MDOC_HEAD): 1196 outflags |= MMAN_PP | MMAN_nl; 1197 bln = n->parent->parent; 1198 if (0 == bln->norm->Bl.comp || 1199 (NULL == n->parent->prev && 1200 NULL == bln->parent->prev)) 1201 outflags |= MMAN_sp; 1202 outflags &= ~MMAN_br; 1203 switch (bln->norm->Bl.type) { 1204 case (LIST_item): 1205 return(0); 1206 case (LIST_inset): 1207 /* FALLTHROUGH */ 1208 case (LIST_diag): 1209 /* FALLTHROUGH */ 1210 case (LIST_ohang): 1211 if (bln->norm->Bl.type == LIST_diag) 1212 print_line(".B \"", 0); 1213 else 1214 print_line(".R \"", 0); 1215 outflags &= ~MMAN_spc; 1216 return(1); 1217 case (LIST_bullet): 1218 /* FALLTHROUGH */ 1219 case (LIST_dash): 1220 /* FALLTHROUGH */ 1221 case (LIST_hyphen): 1222 print_width(bln->norm->Bl.width, NULL, 0); 1223 TPremain = 0; 1224 outflags |= MMAN_nl; 1225 font_push('B'); 1226 if (LIST_bullet == bln->norm->Bl.type) 1227 print_word("o"); 1228 else 1229 print_word("-"); 1230 font_pop(); 1231 break; 1232 case (LIST_enum): 1233 print_width(bln->norm->Bl.width, NULL, 0); 1234 TPremain = 0; 1235 outflags |= MMAN_nl; 1236 print_count(&bln->norm->Bl.count); 1237 break; 1238 case (LIST_hang): 1239 print_width(bln->norm->Bl.width, n->child, 6); 1240 TPremain = 0; 1241 break; 1242 case (LIST_tag): 1243 print_width(bln->norm->Bl.width, n->child, 0); 1244 putchar('\n'); 1245 outflags &= ~MMAN_spc; 1246 return(1); 1247 default: 1248 return(1); 1249 } 1250 outflags |= MMAN_nl; 1251 default: 1252 break; 1253 } 1254 return(1); 1255 } 1256 1257 /* 1258 * This function is called after closing out an indented block. 1259 * If we are inside an enclosing list, restore its indentation. 1260 */ 1261 static void 1262 mid_it(void) 1263 { 1264 char buf[24]; 1265 1266 /* Nothing to do outside a list. */ 1267 if (0 == Bl_stack_len || 0 == Bl_stack[Bl_stack_len - 1]) 1268 return; 1269 1270 /* The indentation has already been set up. */ 1271 if (Bl_stack_post[Bl_stack_len - 1]) 1272 return; 1273 1274 /* Restore the indentation of the enclosing list. */ 1275 print_line(".RS", MMAN_Bk_susp); 1276 snprintf(buf, sizeof(buf), "%ldn", Bl_stack[Bl_stack_len - 1]); 1277 print_word(buf); 1278 1279 /* Remeber to close out this .RS block later. */ 1280 Bl_stack_post[Bl_stack_len - 1] = 1; 1281 } 1282 1283 static void 1284 post_it(DECL_ARGS) 1285 { 1286 const struct mdoc_node *bln; 1287 1288 bln = n->parent->parent; 1289 1290 switch (n->type) { 1291 case (MDOC_HEAD): 1292 switch (bln->norm->Bl.type) { 1293 case (LIST_diag): 1294 outflags &= ~MMAN_spc; 1295 print_word("\\ "); 1296 break; 1297 case (LIST_ohang): 1298 outflags |= MMAN_br; 1299 break; 1300 default: 1301 break; 1302 } 1303 break; 1304 case (MDOC_BODY): 1305 switch (bln->norm->Bl.type) { 1306 case (LIST_bullet): 1307 /* FALLTHROUGH */ 1308 case (LIST_dash): 1309 /* FALLTHROUGH */ 1310 case (LIST_hyphen): 1311 /* FALLTHROUGH */ 1312 case (LIST_enum): 1313 /* FALLTHROUGH */ 1314 case (LIST_hang): 1315 /* FALLTHROUGH */ 1316 case (LIST_tag): 1317 assert(Bl_stack_len); 1318 Bl_stack[--Bl_stack_len] = 0; 1319 1320 /* 1321 * Our indentation had to be restored 1322 * after a child display or child list. 1323 * Close out that indentation block now. 1324 */ 1325 if (Bl_stack_post[Bl_stack_len]) { 1326 print_line(".RE", MMAN_nl); 1327 Bl_stack_post[Bl_stack_len] = 0; 1328 } 1329 break; 1330 case (LIST_column): 1331 if (NULL != n->next) { 1332 putchar('\t'); 1333 outflags &= ~MMAN_spc; 1334 } 1335 break; 1336 default: 1337 break; 1338 } 1339 break; 1340 default: 1341 break; 1342 } 1343 } 1344 1345 static void 1346 post_lb(DECL_ARGS) 1347 { 1348 1349 if (SEC_LIBRARY == n->sec) 1350 outflags |= MMAN_br; 1351 } 1352 1353 static int 1354 pre_lk(DECL_ARGS) 1355 { 1356 const struct mdoc_node *link, *descr; 1357 1358 if (NULL == (link = n->child)) 1359 return(0); 1360 1361 if (NULL != (descr = link->next)) { 1362 font_push('I'); 1363 while (NULL != descr) { 1364 print_word(descr->string); 1365 descr = descr->next; 1366 } 1367 print_word(":"); 1368 font_pop(); 1369 } 1370 1371 font_push('B'); 1372 print_word(link->string); 1373 font_pop(); 1374 return(0); 1375 } 1376 1377 static int 1378 pre_li(DECL_ARGS) 1379 { 1380 1381 font_push('R'); 1382 return(1); 1383 } 1384 1385 static int 1386 pre_nm(DECL_ARGS) 1387 { 1388 char *name; 1389 1390 if (MDOC_BLOCK == n->type) 1391 pre_syn(n); 1392 if (MDOC_ELEM != n->type && MDOC_HEAD != n->type) 1393 return(1); 1394 name = n->child ? n->child->string : meta->name; 1395 if (NULL == name) 1396 return(0); 1397 if (MDOC_HEAD == n->type) { 1398 if (NULL == n->parent->prev) 1399 outflags |= MMAN_sp; 1400 print_block(".HP", 0); 1401 printf(" %ldn", strlen(name) + 1); 1402 outflags |= MMAN_nl; 1403 } 1404 font_push('B'); 1405 if (NULL == n->child) 1406 print_word(meta->name); 1407 return(1); 1408 } 1409 1410 static void 1411 post_nm(DECL_ARGS) 1412 { 1413 1414 if (MDOC_ELEM != n->type && MDOC_HEAD != n->type) 1415 return; 1416 font_pop(); 1417 } 1418 1419 static int 1420 pre_no(DECL_ARGS) 1421 { 1422 1423 outflags |= MMAN_spc_force; 1424 return(1); 1425 } 1426 1427 static int 1428 pre_ns(DECL_ARGS) 1429 { 1430 1431 outflags &= ~MMAN_spc; 1432 return(0); 1433 } 1434 1435 static void 1436 post_pf(DECL_ARGS) 1437 { 1438 1439 outflags &= ~MMAN_spc; 1440 } 1441 1442 static int 1443 pre_pp(DECL_ARGS) 1444 { 1445 1446 if (MDOC_It != n->parent->tok) 1447 outflags |= MMAN_PP; 1448 outflags |= MMAN_sp | MMAN_nl; 1449 outflags &= ~MMAN_br; 1450 return(0); 1451 } 1452 1453 static int 1454 pre_rs(DECL_ARGS) 1455 { 1456 1457 if (SEC_SEE_ALSO == n->sec) { 1458 outflags |= MMAN_PP | MMAN_sp | MMAN_nl; 1459 outflags &= ~MMAN_br; 1460 } 1461 return(1); 1462 } 1463 1464 static int 1465 pre_sm(DECL_ARGS) 1466 { 1467 1468 assert(n->child && MDOC_TEXT == n->child->type); 1469 if (0 == strcmp("on", n->child->string)) 1470 outflags |= MMAN_Sm | MMAN_spc; 1471 else 1472 outflags &= ~MMAN_Sm; 1473 return(0); 1474 } 1475 1476 static int 1477 pre_sp(DECL_ARGS) 1478 { 1479 1480 if (MMAN_PP & outflags) { 1481 outflags &= ~MMAN_PP; 1482 print_line(".PP", 0); 1483 } else 1484 print_line(".sp", 0); 1485 return(1); 1486 } 1487 1488 static void 1489 post_sp(DECL_ARGS) 1490 { 1491 1492 outflags |= MMAN_nl; 1493 } 1494 1495 static int 1496 pre_sy(DECL_ARGS) 1497 { 1498 1499 font_push('B'); 1500 return(1); 1501 } 1502 1503 static int 1504 pre_vt(DECL_ARGS) 1505 { 1506 1507 if (MDOC_SYNPRETTY & n->flags) { 1508 switch (n->type) { 1509 case (MDOC_BLOCK): 1510 pre_syn(n); 1511 return(1); 1512 case (MDOC_BODY): 1513 break; 1514 default: 1515 return(0); 1516 } 1517 } 1518 font_push('I'); 1519 return(1); 1520 } 1521 1522 static void 1523 post_vt(DECL_ARGS) 1524 { 1525 1526 if (MDOC_SYNPRETTY & n->flags && MDOC_BODY != n->type) 1527 return; 1528 font_pop(); 1529 } 1530 1531 static int 1532 pre_xr(DECL_ARGS) 1533 { 1534 1535 n = n->child; 1536 if (NULL == n) 1537 return(0); 1538 print_node(meta, n); 1539 n = n->next; 1540 if (NULL == n) 1541 return(0); 1542 outflags &= ~MMAN_spc; 1543 print_word("("); 1544 print_node(meta, n); 1545 print_word(")"); 1546 return(0); 1547 } 1548 1549 static int 1550 pre_ux(DECL_ARGS) 1551 { 1552 1553 print_word(manacts[n->tok].prefix); 1554 if (NULL == n->child) 1555 return(0); 1556 outflags &= ~MMAN_spc; 1557 print_word("\\ "); 1558 outflags &= ~MMAN_spc; 1559 return(1); 1560 } 1561