1 /* $Id: mdoc_man.c,v 1.50 2013/06/02 18:16:51 schwarze Exp $ */ 2 /* 3 * Copyright (c) 2011, 2012, 2013 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, "\\(lq", "\\(rq" }, /* Do */ 182 { cond_body, pre_enc, post_enc, "\\(lq", "\\(rq" }, /* 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, "\\(oq", "\\(cq" }, /* 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, "\\(oq", "\\(cq" }, /* So */ 205 { cond_body, pre_enc, post_enc, "\\(oq", "\\(cq" }, /* 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 print_line(".RS", MMAN_Bk_susp); 408 409 /* Convert v into a number (of characters). */ 410 if (NULL == v || '\0' == *v || 0 == strcmp(v, "left")) 411 sz = 0; 412 else if (0 == strcmp(v, "indent")) 413 sz = 6; 414 else if (0 == strcmp(v, "indent-two")) 415 sz = 12; 416 else if (a2roffsu(v, &su, SCALE_MAX)) { 417 if (SCALE_EN == su.unit) 418 sz = su.scale; 419 else { 420 /* 421 * XXX 422 * If we are inside an enclosing list, 423 * there is no easy way to add the two 424 * indentations because they are provided 425 * in terms of different units. 426 */ 427 print_word(v); 428 outflags |= MMAN_nl; 429 return; 430 } 431 } else 432 sz = strlen(v); 433 434 /* 435 * We are inside an enclosing list. 436 * Add the two indentations. 437 */ 438 if (Bl_stack_len) 439 sz += Bl_stack[Bl_stack_len - 1]; 440 441 snprintf(buf, sizeof(buf), "%ldn", sz); 442 print_word(buf); 443 outflags |= MMAN_nl; 444 } 445 446 /* 447 * Set up the indentation for a list item; used from pre_it(). 448 */ 449 void 450 print_width(const char *v, const struct mdoc_node *child, size_t defsz) 451 { 452 char buf[24]; 453 struct roffsu su; 454 size_t sz, chsz; 455 int numeric, remain; 456 457 numeric = 1; 458 remain = 0; 459 460 /* Convert v into a number (of characters). */ 461 if (NULL == v) 462 sz = defsz; 463 else if (a2roffsu(v, &su, SCALE_MAX)) { 464 if (SCALE_EN == su.unit) 465 sz = su.scale; 466 else { 467 sz = 0; 468 numeric = 0; 469 } 470 } else 471 sz = strlen(v); 472 473 /* XXX Rough estimation, might have multiple parts. */ 474 chsz = (NULL != child && MDOC_TEXT == child->type) ? 475 strlen(child->string) : 0; 476 477 /* Maybe we are inside an enclosing list? */ 478 mid_it(); 479 480 /* 481 * Save our own indentation, 482 * such that child lists can use it. 483 */ 484 Bl_stack[Bl_stack_len++] = sz + 2; 485 486 /* Set up the current list. */ 487 if (defsz && chsz > sz) 488 print_block(".HP", 0); 489 else { 490 print_block(".TP", 0); 491 remain = sz + 2; 492 } 493 if (numeric) { 494 snprintf(buf, sizeof(buf), "%ldn", sz + 2); 495 print_word(buf); 496 } else 497 print_word(v); 498 TPremain = remain; 499 } 500 501 void 502 print_count(int *count) 503 { 504 char buf[12]; 505 506 snprintf(buf, sizeof(buf), "%d.", ++*count); 507 print_word(buf); 508 } 509 510 void 511 man_man(void *arg, const struct man *man) 512 { 513 514 /* 515 * Dump the keep buffer. 516 * We're guaranteed by now that this exists (is non-NULL). 517 * Flush stdout afterward, just in case. 518 */ 519 fputs(mparse_getkeep(man_mparse(man)), stdout); 520 fflush(stdout); 521 } 522 523 void 524 man_mdoc(void *arg, const struct mdoc *mdoc) 525 { 526 const struct mdoc_meta *meta; 527 const struct mdoc_node *n; 528 529 meta = mdoc_meta(mdoc); 530 n = mdoc_node(mdoc); 531 532 printf(".TH \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"\n", 533 meta->title, meta->msec, meta->date, 534 meta->os, meta->vol); 535 536 /* Disable hyphenation and if nroff, disable justification. */ 537 printf(".nh\n.if n .ad l"); 538 539 outflags = MMAN_nl | MMAN_Sm; 540 if (0 == fontqueue.size) { 541 fontqueue.size = 8; 542 fontqueue.head = fontqueue.tail = mandoc_malloc(8); 543 *fontqueue.tail = 'R'; 544 } 545 print_node(meta, n); 546 putchar('\n'); 547 } 548 549 static void 550 print_node(DECL_ARGS) 551 { 552 const struct mdoc_node *prev, *sub; 553 const struct manact *act; 554 int cond, do_sub; 555 556 /* 557 * Break the line if we were parsed subsequent the current node. 558 * This makes the page structure be more consistent. 559 */ 560 prev = n->prev ? n->prev : n->parent; 561 if (MMAN_spc & outflags && prev && prev->line < n->line) 562 outflags |= MMAN_nl; 563 564 act = NULL; 565 cond = 0; 566 do_sub = 1; 567 568 if (MDOC_TEXT == n->type) { 569 /* 570 * Make sure that we don't happen to start with a 571 * control character at the start of a line. 572 */ 573 if (MMAN_nl & outflags && ('.' == *n->string || 574 '\'' == *n->string)) { 575 print_word(""); 576 printf("\\&"); 577 outflags &= ~MMAN_spc; 578 } 579 print_word(n->string); 580 } else { 581 /* 582 * Conditionally run the pre-node action handler for a 583 * node. 584 */ 585 act = manacts + n->tok; 586 cond = NULL == act->cond || (*act->cond)(meta, n); 587 if (cond && act->pre) 588 do_sub = (*act->pre)(meta, n); 589 } 590 591 /* 592 * Conditionally run all child nodes. 593 * Note that this iterates over children instead of using 594 * recursion. This prevents unnecessary depth in the stack. 595 */ 596 if (do_sub) 597 for (sub = n->child; sub; sub = sub->next) 598 print_node(meta, sub); 599 600 /* 601 * Lastly, conditionally run the post-node handler. 602 */ 603 if (cond && act->post) 604 (*act->post)(meta, n); 605 } 606 607 static int 608 cond_head(DECL_ARGS) 609 { 610 611 return(MDOC_HEAD == n->type); 612 } 613 614 static int 615 cond_body(DECL_ARGS) 616 { 617 618 return(MDOC_BODY == n->type); 619 } 620 621 static int 622 pre_enc(DECL_ARGS) 623 { 624 const char *prefix; 625 626 prefix = manacts[n->tok].prefix; 627 if (NULL == prefix) 628 return(1); 629 print_word(prefix); 630 outflags &= ~MMAN_spc; 631 return(1); 632 } 633 634 static void 635 post_enc(DECL_ARGS) 636 { 637 const char *suffix; 638 639 suffix = manacts[n->tok].suffix; 640 if (NULL == suffix) 641 return; 642 outflags &= ~MMAN_spc; 643 print_word(suffix); 644 } 645 646 static void 647 post_font(DECL_ARGS) 648 { 649 650 font_pop(); 651 } 652 653 static void 654 post_percent(DECL_ARGS) 655 { 656 657 if (pre_em == manacts[n->tok].pre) 658 font_pop(); 659 if (n->next) { 660 print_word(","); 661 if (n->prev && n->prev->tok == n->tok && 662 n->next->tok == n->tok) 663 print_word("and"); 664 } else { 665 print_word("."); 666 outflags |= MMAN_nl; 667 } 668 } 669 670 static int 671 pre__t(DECL_ARGS) 672 { 673 674 if (n->parent && MDOC_Rs == n->parent->tok && 675 n->parent->norm->Rs.quote_T) { 676 print_word(""); 677 putchar('\"'); 678 outflags &= ~MMAN_spc; 679 } else 680 font_push('I'); 681 return(1); 682 } 683 684 static void 685 post__t(DECL_ARGS) 686 { 687 688 if (n->parent && MDOC_Rs == n->parent->tok && 689 n->parent->norm->Rs.quote_T) { 690 outflags &= ~MMAN_spc; 691 print_word(""); 692 putchar('\"'); 693 } else 694 font_pop(); 695 post_percent(meta, n); 696 } 697 698 /* 699 * Print before a section header. 700 */ 701 static int 702 pre_sect(DECL_ARGS) 703 { 704 705 switch (n->type) { 706 case (MDOC_HEAD): 707 outflags |= MMAN_sp; 708 print_block(manacts[n->tok].prefix, 0); 709 print_word(""); 710 putchar('\"'); 711 outflags &= ~MMAN_spc; 712 break; 713 case (MDOC_BODY): 714 if (MDOC_Sh == n->tok) { 715 if (MDOC_SYNPRETTY & n->flags) 716 outflags |= MMAN_Bk; 717 else 718 outflags &= ~MMAN_Bk; 719 } 720 break; 721 default: 722 break; 723 } 724 return(1); 725 } 726 727 /* 728 * Print subsequent a section header. 729 */ 730 static void 731 post_sect(DECL_ARGS) 732 { 733 734 if (MDOC_HEAD != n->type) 735 return; 736 outflags &= ~MMAN_spc; 737 print_word(""); 738 putchar('\"'); 739 outflags |= MMAN_nl; 740 if (MDOC_Sh == n->tok && SEC_AUTHORS == n->sec) 741 outflags &= ~(MMAN_An_split | MMAN_An_nosplit); 742 } 743 744 /* See mdoc_term.c, synopsis_pre() for comments. */ 745 static void 746 pre_syn(const struct mdoc_node *n) 747 { 748 749 if (NULL == n->prev || ! (MDOC_SYNPRETTY & n->flags)) 750 return; 751 752 if (n->prev->tok == n->tok && 753 MDOC_Ft != n->tok && 754 MDOC_Fo != n->tok && 755 MDOC_Fn != n->tok) { 756 outflags |= MMAN_br; 757 return; 758 } 759 760 switch (n->prev->tok) { 761 case (MDOC_Fd): 762 /* FALLTHROUGH */ 763 case (MDOC_Fn): 764 /* FALLTHROUGH */ 765 case (MDOC_Fo): 766 /* FALLTHROUGH */ 767 case (MDOC_In): 768 /* FALLTHROUGH */ 769 case (MDOC_Vt): 770 outflags |= MMAN_sp; 771 break; 772 case (MDOC_Ft): 773 if (MDOC_Fn != n->tok && MDOC_Fo != n->tok) { 774 outflags |= MMAN_sp; 775 break; 776 } 777 /* FALLTHROUGH */ 778 default: 779 outflags |= MMAN_br; 780 break; 781 } 782 } 783 784 static int 785 pre_an(DECL_ARGS) 786 { 787 788 switch (n->norm->An.auth) { 789 case (AUTH_split): 790 outflags &= ~MMAN_An_nosplit; 791 outflags |= MMAN_An_split; 792 return(0); 793 case (AUTH_nosplit): 794 outflags &= ~MMAN_An_split; 795 outflags |= MMAN_An_nosplit; 796 return(0); 797 default: 798 if (MMAN_An_split & outflags) 799 outflags |= MMAN_br; 800 else if (SEC_AUTHORS == n->sec && 801 ! (MMAN_An_nosplit & outflags)) 802 outflags |= MMAN_An_split; 803 return(1); 804 } 805 } 806 807 static int 808 pre_ap(DECL_ARGS) 809 { 810 811 outflags &= ~MMAN_spc; 812 print_word("'"); 813 outflags &= ~MMAN_spc; 814 return(0); 815 } 816 817 static int 818 pre_bd(DECL_ARGS) 819 { 820 821 outflags &= ~(MMAN_PP | MMAN_sp | MMAN_br); 822 823 if (DISP_unfilled == n->norm->Bd.type || 824 DISP_literal == n->norm->Bd.type) 825 print_line(".nf", 0); 826 if (0 == n->norm->Bd.comp && NULL != n->parent->prev) 827 outflags |= MMAN_sp; 828 print_offs(n->norm->Bd.offs); 829 return(1); 830 } 831 832 static void 833 post_bd(DECL_ARGS) 834 { 835 836 /* Close out this display. */ 837 print_line(".RE", MMAN_nl); 838 if (DISP_unfilled == n->norm->Bd.type || 839 DISP_literal == n->norm->Bd.type) 840 print_line(".fi", MMAN_nl); 841 842 /* Maybe we are inside an enclosing list? */ 843 if (NULL != n->parent->next) 844 mid_it(); 845 } 846 847 static int 848 pre_bf(DECL_ARGS) 849 { 850 851 switch (n->type) { 852 case (MDOC_BLOCK): 853 return(1); 854 case (MDOC_BODY): 855 break; 856 default: 857 return(0); 858 } 859 switch (n->norm->Bf.font) { 860 case (FONT_Em): 861 font_push('I'); 862 break; 863 case (FONT_Sy): 864 font_push('B'); 865 break; 866 default: 867 font_push('R'); 868 break; 869 } 870 return(1); 871 } 872 873 static void 874 post_bf(DECL_ARGS) 875 { 876 877 if (MDOC_BODY == n->type) 878 font_pop(); 879 } 880 881 static int 882 pre_bk(DECL_ARGS) 883 { 884 885 switch (n->type) { 886 case (MDOC_BLOCK): 887 return(1); 888 case (MDOC_BODY): 889 outflags |= MMAN_Bk; 890 return(1); 891 default: 892 return(0); 893 } 894 } 895 896 static void 897 post_bk(DECL_ARGS) 898 { 899 900 if (MDOC_BODY == n->type && ! (MDOC_SYNPRETTY & n->flags)) 901 outflags &= ~MMAN_Bk; 902 } 903 904 static int 905 pre_bl(DECL_ARGS) 906 { 907 size_t icol; 908 909 /* 910 * print_offs() will increase the -offset to account for 911 * a possible enclosing .It, but any enclosed .It blocks 912 * just nest and do not add up their indentation. 913 */ 914 if (n->norm->Bl.offs) { 915 print_offs(n->norm->Bl.offs); 916 Bl_stack[Bl_stack_len++] = 0; 917 } 918 919 switch (n->norm->Bl.type) { 920 case (LIST_enum): 921 n->norm->Bl.count = 0; 922 return(1); 923 case (LIST_column): 924 break; 925 default: 926 return(1); 927 } 928 929 print_line(".TS", MMAN_nl); 930 for (icol = 0; icol < n->norm->Bl.ncols; icol++) 931 print_word("l"); 932 print_word("."); 933 outflags |= MMAN_nl; 934 return(1); 935 } 936 937 static void 938 post_bl(DECL_ARGS) 939 { 940 941 switch (n->norm->Bl.type) { 942 case (LIST_column): 943 print_line(".TE", 0); 944 break; 945 case (LIST_enum): 946 n->norm->Bl.count = 0; 947 break; 948 default: 949 break; 950 } 951 952 if (n->norm->Bl.offs) { 953 print_line(".RE", MMAN_nl); 954 assert(Bl_stack_len); 955 Bl_stack_len--; 956 assert(0 == Bl_stack[Bl_stack_len]); 957 } else { 958 outflags |= MMAN_PP | MMAN_nl; 959 outflags &= ~(MMAN_sp | MMAN_br); 960 } 961 962 /* Maybe we are inside an enclosing list? */ 963 if (NULL != n->parent->next) 964 mid_it(); 965 966 } 967 968 static int 969 pre_br(DECL_ARGS) 970 { 971 972 outflags |= MMAN_br; 973 return(0); 974 } 975 976 static int 977 pre_bx(DECL_ARGS) 978 { 979 980 n = n->child; 981 if (n) { 982 print_word(n->string); 983 outflags &= ~MMAN_spc; 984 n = n->next; 985 } 986 print_word("BSD"); 987 if (NULL == n) 988 return(0); 989 outflags &= ~MMAN_spc; 990 print_word("-"); 991 outflags &= ~MMAN_spc; 992 print_word(n->string); 993 return(0); 994 } 995 996 static int 997 pre_dl(DECL_ARGS) 998 { 999 1000 print_offs("6n"); 1001 return(1); 1002 } 1003 1004 static void 1005 post_dl(DECL_ARGS) 1006 { 1007 1008 print_line(".RE", MMAN_nl); 1009 1010 /* Maybe we are inside an enclosing list? */ 1011 if (NULL != n->parent->next) 1012 mid_it(); 1013 } 1014 1015 static int 1016 pre_em(DECL_ARGS) 1017 { 1018 1019 font_push('I'); 1020 return(1); 1021 } 1022 1023 static void 1024 post_eo(DECL_ARGS) 1025 { 1026 1027 if (MDOC_HEAD == n->type || MDOC_BODY == n->type) 1028 outflags &= ~MMAN_spc; 1029 } 1030 1031 static int 1032 pre_fa(DECL_ARGS) 1033 { 1034 1035 if (MDOC_Fa == n->tok) 1036 n = n->child; 1037 1038 while (NULL != n) { 1039 font_push('I'); 1040 print_node(meta, n); 1041 font_pop(); 1042 if (NULL != (n = n->next)) 1043 print_word(","); 1044 } 1045 return(0); 1046 } 1047 1048 static void 1049 post_fa(DECL_ARGS) 1050 { 1051 1052 if (NULL != n->next && MDOC_Fa == n->next->tok) 1053 print_word(","); 1054 } 1055 1056 static int 1057 pre_fd(DECL_ARGS) 1058 { 1059 1060 pre_syn(n); 1061 font_push('B'); 1062 return(1); 1063 } 1064 1065 static void 1066 post_fd(DECL_ARGS) 1067 { 1068 1069 font_pop(); 1070 outflags |= MMAN_br; 1071 } 1072 1073 static int 1074 pre_fl(DECL_ARGS) 1075 { 1076 1077 font_push('B'); 1078 print_word("\\-"); 1079 outflags &= ~MMAN_spc; 1080 return(1); 1081 } 1082 1083 static void 1084 post_fl(DECL_ARGS) 1085 { 1086 1087 font_pop(); 1088 if (0 == n->nchild && NULL != n->next && 1089 n->next->line == n->line) 1090 outflags &= ~MMAN_spc; 1091 } 1092 1093 static int 1094 pre_fn(DECL_ARGS) 1095 { 1096 1097 pre_syn(n); 1098 1099 n = n->child; 1100 if (NULL == n) 1101 return(0); 1102 1103 font_push('B'); 1104 print_node(meta, n); 1105 font_pop(); 1106 outflags &= ~MMAN_spc; 1107 print_word("("); 1108 outflags &= ~MMAN_spc; 1109 1110 n = n->next; 1111 if (NULL != n) 1112 pre_fa(meta, n); 1113 return(0); 1114 } 1115 1116 static void 1117 post_fn(DECL_ARGS) 1118 { 1119 1120 print_word(")"); 1121 if (MDOC_SYNPRETTY & n->flags) { 1122 print_word(";"); 1123 outflags |= MMAN_br; 1124 } 1125 } 1126 1127 static int 1128 pre_fo(DECL_ARGS) 1129 { 1130 1131 switch (n->type) { 1132 case (MDOC_BLOCK): 1133 pre_syn(n); 1134 break; 1135 case (MDOC_HEAD): 1136 font_push('B'); 1137 break; 1138 case (MDOC_BODY): 1139 outflags &= ~MMAN_spc; 1140 print_word("("); 1141 outflags &= ~MMAN_spc; 1142 break; 1143 default: 1144 break; 1145 } 1146 return(1); 1147 } 1148 1149 static void 1150 post_fo(DECL_ARGS) 1151 { 1152 1153 switch (n->type) { 1154 case (MDOC_HEAD): 1155 font_pop(); 1156 break; 1157 case (MDOC_BODY): 1158 post_fn(meta, n); 1159 break; 1160 default: 1161 break; 1162 } 1163 } 1164 1165 static int 1166 pre_ft(DECL_ARGS) 1167 { 1168 1169 pre_syn(n); 1170 font_push('I'); 1171 return(1); 1172 } 1173 1174 static int 1175 pre_in(DECL_ARGS) 1176 { 1177 1178 if (MDOC_SYNPRETTY & n->flags) { 1179 pre_syn(n); 1180 font_push('B'); 1181 print_word("#include <"); 1182 outflags &= ~MMAN_spc; 1183 } else { 1184 print_word("<"); 1185 outflags &= ~MMAN_spc; 1186 font_push('I'); 1187 } 1188 return(1); 1189 } 1190 1191 static void 1192 post_in(DECL_ARGS) 1193 { 1194 1195 if (MDOC_SYNPRETTY & n->flags) { 1196 outflags &= ~MMAN_spc; 1197 print_word(">"); 1198 font_pop(); 1199 outflags |= MMAN_br; 1200 } else { 1201 font_pop(); 1202 outflags &= ~MMAN_spc; 1203 print_word(">"); 1204 } 1205 } 1206 1207 static int 1208 pre_it(DECL_ARGS) 1209 { 1210 const struct mdoc_node *bln; 1211 1212 switch (n->type) { 1213 case (MDOC_HEAD): 1214 outflags |= MMAN_PP | MMAN_nl; 1215 bln = n->parent->parent; 1216 if (0 == bln->norm->Bl.comp || 1217 (NULL == n->parent->prev && 1218 NULL == bln->parent->prev)) 1219 outflags |= MMAN_sp; 1220 outflags &= ~MMAN_br; 1221 switch (bln->norm->Bl.type) { 1222 case (LIST_item): 1223 return(0); 1224 case (LIST_inset): 1225 /* FALLTHROUGH */ 1226 case (LIST_diag): 1227 /* FALLTHROUGH */ 1228 case (LIST_ohang): 1229 if (bln->norm->Bl.type == LIST_diag) 1230 print_line(".B \"", 0); 1231 else 1232 print_line(".R \"", 0); 1233 outflags &= ~MMAN_spc; 1234 return(1); 1235 case (LIST_bullet): 1236 /* FALLTHROUGH */ 1237 case (LIST_dash): 1238 /* FALLTHROUGH */ 1239 case (LIST_hyphen): 1240 print_width(bln->norm->Bl.width, NULL, 0); 1241 TPremain = 0; 1242 outflags |= MMAN_nl; 1243 font_push('B'); 1244 if (LIST_bullet == bln->norm->Bl.type) 1245 print_word("o"); 1246 else 1247 print_word("-"); 1248 font_pop(); 1249 break; 1250 case (LIST_enum): 1251 print_width(bln->norm->Bl.width, NULL, 0); 1252 TPremain = 0; 1253 outflags |= MMAN_nl; 1254 print_count(&bln->norm->Bl.count); 1255 break; 1256 case (LIST_hang): 1257 print_width(bln->norm->Bl.width, n->child, 6); 1258 TPremain = 0; 1259 break; 1260 case (LIST_tag): 1261 print_width(bln->norm->Bl.width, n->child, 0); 1262 putchar('\n'); 1263 outflags &= ~MMAN_spc; 1264 return(1); 1265 default: 1266 return(1); 1267 } 1268 outflags |= MMAN_nl; 1269 default: 1270 break; 1271 } 1272 return(1); 1273 } 1274 1275 /* 1276 * This function is called after closing out an indented block. 1277 * If we are inside an enclosing list, restore its indentation. 1278 */ 1279 static void 1280 mid_it(void) 1281 { 1282 char buf[24]; 1283 1284 /* Nothing to do outside a list. */ 1285 if (0 == Bl_stack_len || 0 == Bl_stack[Bl_stack_len - 1]) 1286 return; 1287 1288 /* The indentation has already been set up. */ 1289 if (Bl_stack_post[Bl_stack_len - 1]) 1290 return; 1291 1292 /* Restore the indentation of the enclosing list. */ 1293 print_line(".RS", MMAN_Bk_susp); 1294 snprintf(buf, sizeof(buf), "%ldn", Bl_stack[Bl_stack_len - 1]); 1295 print_word(buf); 1296 1297 /* Remeber to close out this .RS block later. */ 1298 Bl_stack_post[Bl_stack_len - 1] = 1; 1299 } 1300 1301 static void 1302 post_it(DECL_ARGS) 1303 { 1304 const struct mdoc_node *bln; 1305 1306 bln = n->parent->parent; 1307 1308 switch (n->type) { 1309 case (MDOC_HEAD): 1310 switch (bln->norm->Bl.type) { 1311 case (LIST_diag): 1312 outflags &= ~MMAN_spc; 1313 print_word("\\ "); 1314 break; 1315 case (LIST_ohang): 1316 outflags |= MMAN_br; 1317 break; 1318 default: 1319 break; 1320 } 1321 break; 1322 case (MDOC_BODY): 1323 switch (bln->norm->Bl.type) { 1324 case (LIST_bullet): 1325 /* FALLTHROUGH */ 1326 case (LIST_dash): 1327 /* FALLTHROUGH */ 1328 case (LIST_hyphen): 1329 /* FALLTHROUGH */ 1330 case (LIST_enum): 1331 /* FALLTHROUGH */ 1332 case (LIST_hang): 1333 /* FALLTHROUGH */ 1334 case (LIST_tag): 1335 assert(Bl_stack_len); 1336 Bl_stack[--Bl_stack_len] = 0; 1337 1338 /* 1339 * Our indentation had to be restored 1340 * after a child display or child list. 1341 * Close out that indentation block now. 1342 */ 1343 if (Bl_stack_post[Bl_stack_len]) { 1344 print_line(".RE", MMAN_nl); 1345 Bl_stack_post[Bl_stack_len] = 0; 1346 } 1347 break; 1348 case (LIST_column): 1349 if (NULL != n->next) { 1350 putchar('\t'); 1351 outflags &= ~MMAN_spc; 1352 } 1353 break; 1354 default: 1355 break; 1356 } 1357 break; 1358 default: 1359 break; 1360 } 1361 } 1362 1363 static void 1364 post_lb(DECL_ARGS) 1365 { 1366 1367 if (SEC_LIBRARY == n->sec) 1368 outflags |= MMAN_br; 1369 } 1370 1371 static int 1372 pre_lk(DECL_ARGS) 1373 { 1374 const struct mdoc_node *link, *descr; 1375 1376 if (NULL == (link = n->child)) 1377 return(0); 1378 1379 if (NULL != (descr = link->next)) { 1380 font_push('I'); 1381 while (NULL != descr) { 1382 print_word(descr->string); 1383 descr = descr->next; 1384 } 1385 print_word(":"); 1386 font_pop(); 1387 } 1388 1389 font_push('B'); 1390 print_word(link->string); 1391 font_pop(); 1392 return(0); 1393 } 1394 1395 static int 1396 pre_li(DECL_ARGS) 1397 { 1398 1399 font_push('R'); 1400 return(1); 1401 } 1402 1403 static int 1404 pre_nm(DECL_ARGS) 1405 { 1406 char *name; 1407 1408 if (MDOC_BLOCK == n->type) 1409 pre_syn(n); 1410 if (MDOC_ELEM != n->type && MDOC_HEAD != n->type) 1411 return(1); 1412 name = n->child ? n->child->string : meta->name; 1413 if (NULL == name) 1414 return(0); 1415 if (MDOC_HEAD == n->type) { 1416 if (NULL == n->parent->prev) 1417 outflags |= MMAN_sp; 1418 print_block(".HP", 0); 1419 printf(" %ldn", strlen(name) + 1); 1420 outflags |= MMAN_nl; 1421 } 1422 font_push('B'); 1423 if (NULL == n->child) 1424 print_word(meta->name); 1425 return(1); 1426 } 1427 1428 static void 1429 post_nm(DECL_ARGS) 1430 { 1431 1432 if (MDOC_ELEM != n->type && MDOC_HEAD != n->type) 1433 return; 1434 font_pop(); 1435 } 1436 1437 static int 1438 pre_no(DECL_ARGS) 1439 { 1440 1441 outflags |= MMAN_spc_force; 1442 return(1); 1443 } 1444 1445 static int 1446 pre_ns(DECL_ARGS) 1447 { 1448 1449 outflags &= ~MMAN_spc; 1450 return(0); 1451 } 1452 1453 static void 1454 post_pf(DECL_ARGS) 1455 { 1456 1457 outflags &= ~MMAN_spc; 1458 } 1459 1460 static int 1461 pre_pp(DECL_ARGS) 1462 { 1463 1464 if (MDOC_It != n->parent->tok) 1465 outflags |= MMAN_PP; 1466 outflags |= MMAN_sp | MMAN_nl; 1467 outflags &= ~MMAN_br; 1468 return(0); 1469 } 1470 1471 static int 1472 pre_rs(DECL_ARGS) 1473 { 1474 1475 if (SEC_SEE_ALSO == n->sec) { 1476 outflags |= MMAN_PP | MMAN_sp | MMAN_nl; 1477 outflags &= ~MMAN_br; 1478 } 1479 return(1); 1480 } 1481 1482 static int 1483 pre_sm(DECL_ARGS) 1484 { 1485 1486 assert(n->child && MDOC_TEXT == n->child->type); 1487 if (0 == strcmp("on", n->child->string)) 1488 outflags |= MMAN_Sm | MMAN_spc; 1489 else 1490 outflags &= ~MMAN_Sm; 1491 return(0); 1492 } 1493 1494 static int 1495 pre_sp(DECL_ARGS) 1496 { 1497 1498 if (MMAN_PP & outflags) { 1499 outflags &= ~MMAN_PP; 1500 print_line(".PP", 0); 1501 } else 1502 print_line(".sp", 0); 1503 return(1); 1504 } 1505 1506 static void 1507 post_sp(DECL_ARGS) 1508 { 1509 1510 outflags |= MMAN_nl; 1511 } 1512 1513 static int 1514 pre_sy(DECL_ARGS) 1515 { 1516 1517 font_push('B'); 1518 return(1); 1519 } 1520 1521 static int 1522 pre_vt(DECL_ARGS) 1523 { 1524 1525 if (MDOC_SYNPRETTY & n->flags) { 1526 switch (n->type) { 1527 case (MDOC_BLOCK): 1528 pre_syn(n); 1529 return(1); 1530 case (MDOC_BODY): 1531 break; 1532 default: 1533 return(0); 1534 } 1535 } 1536 font_push('I'); 1537 return(1); 1538 } 1539 1540 static void 1541 post_vt(DECL_ARGS) 1542 { 1543 1544 if (MDOC_SYNPRETTY & n->flags && MDOC_BODY != n->type) 1545 return; 1546 font_pop(); 1547 } 1548 1549 static int 1550 pre_xr(DECL_ARGS) 1551 { 1552 1553 n = n->child; 1554 if (NULL == n) 1555 return(0); 1556 print_node(meta, n); 1557 n = n->next; 1558 if (NULL == n) 1559 return(0); 1560 outflags &= ~MMAN_spc; 1561 print_word("("); 1562 print_node(meta, n); 1563 print_word(")"); 1564 return(0); 1565 } 1566 1567 static int 1568 pre_ux(DECL_ARGS) 1569 { 1570 1571 print_word(manacts[n->tok].prefix); 1572 if (NULL == n->child) 1573 return(0); 1574 outflags &= ~MMAN_spc; 1575 print_word("\\ "); 1576 outflags &= ~MMAN_spc; 1577 return(1); 1578 } 1579