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