Annotation of mandoc/mdoc_man.c, Revision 1.26
1.26 ! schwarze 1: /* $Id: mdoc_man.c,v 1.25 2012/07/09 09:31:48 schwarze Exp $ */
1.1 schwarze 2: /*
1.11 schwarze 3: * Copyright (c) 2011, 2012 Ingo Schwarze <schwarze@openbsd.org>
1.1 schwarze 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: */
1.7 kristaps 17: #ifdef HAVE_CONFIG_H
18: #include "config.h"
19: #endif
20:
1.12 schwarze 21: #include <assert.h>
1.1 schwarze 22: #include <stdio.h>
23: #include <string.h>
24:
25: #include "mandoc.h"
1.11 schwarze 26: #include "out.h"
1.4 kristaps 27: #include "man.h"
1.1 schwarze 28: #include "mdoc.h"
29: #include "main.h"
30:
1.5 kristaps 31: #define DECL_ARGS const struct mdoc_meta *m, \
1.20 schwarze 32: const struct mdoc_node *n
1.1 schwarze 33:
34: struct manact {
1.5 kristaps 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 */
1.1 schwarze 40: };
41:
1.5 kristaps 42: static int cond_body(DECL_ARGS);
1.1 schwarze 43: static int cond_head(DECL_ARGS);
1.26 ! schwarze 44: static void font_push(char);
! 45: static void font_pop(void);
1.5 kristaps 46: static void post_bd(DECL_ARGS);
1.13 schwarze 47: static void post_bk(DECL_ARGS);
1.5 kristaps 48: static void post_dl(DECL_ARGS);
1.1 schwarze 49: static void post_enc(DECL_ARGS);
1.17 schwarze 50: static void post_fa(DECL_ARGS);
1.26 ! schwarze 51: static void post_fl(DECL_ARGS);
1.16 schwarze 52: static void post_fn(DECL_ARGS);
1.17 schwarze 53: static void post_fo(DECL_ARGS);
1.26 ! schwarze 54: static void post_font(DECL_ARGS);
1.15 schwarze 55: static void post_in(DECL_ARGS);
1.14 schwarze 56: static void post_lb(DECL_ARGS);
1.5 kristaps 57: static void post_nm(DECL_ARGS);
1.1 schwarze 58: static void post_percent(DECL_ARGS);
1.5 kristaps 59: static void post_pf(DECL_ARGS);
1.3 schwarze 60: static void post_sect(DECL_ARGS);
1.5 kristaps 61: static void post_sp(DECL_ARGS);
1.18 schwarze 62: static void post_vt(DECL_ARGS);
1.22 schwarze 63: static int pre_an(DECL_ARGS);
1.3 schwarze 64: static int pre_ap(DECL_ARGS);
65: static int pre_bd(DECL_ARGS);
1.13 schwarze 66: static int pre_bk(DECL_ARGS);
1.3 schwarze 67: static int pre_br(DECL_ARGS);
1.8 schwarze 68: static int pre_bx(DECL_ARGS);
1.1 schwarze 69: static int pre_dl(DECL_ARGS);
1.5 kristaps 70: static int pre_enc(DECL_ARGS);
1.26 ! schwarze 71: static int pre_em(DECL_ARGS);
1.17 schwarze 72: static int pre_fa(DECL_ARGS);
1.26 ! schwarze 73: static int pre_fl(DECL_ARGS);
1.16 schwarze 74: static int pre_fn(DECL_ARGS);
1.17 schwarze 75: static int pre_fo(DECL_ARGS);
1.23 schwarze 76: static int pre_ft(DECL_ARGS);
1.15 schwarze 77: static int pre_in(DECL_ARGS);
1.1 schwarze 78: static int pre_it(DECL_ARGS);
1.24 schwarze 79: static int pre_lk(DECL_ARGS);
1.26 ! schwarze 80: static int pre_li(DECL_ARGS);
1.1 schwarze 81: static int pre_nm(DECL_ARGS);
1.25 schwarze 82: static int pre_no(DECL_ARGS);
1.1 schwarze 83: static int pre_ns(DECL_ARGS);
84: static int pre_pp(DECL_ARGS);
1.12 schwarze 85: static int pre_sm(DECL_ARGS);
1.3 schwarze 86: static int pre_sp(DECL_ARGS);
1.5 kristaps 87: static int pre_sect(DECL_ARGS);
1.26 ! schwarze 88: static int pre_sy(DECL_ARGS);
1.23 schwarze 89: static void pre_syn(const struct mdoc_node *);
1.18 schwarze 90: static int pre_vt(DECL_ARGS);
1.8 schwarze 91: static int pre_ux(DECL_ARGS);
1.1 schwarze 92: static int pre_xr(DECL_ARGS);
1.20 schwarze 93: static void print_word(const char *);
94: static void print_offs(const char *);
1.5 kristaps 95: static void print_node(DECL_ARGS);
1.1 schwarze 96:
1.3 schwarze 97: static const struct manact manacts[MDOC_MAX + 1] = {
98: { NULL, pre_ap, NULL, NULL, NULL }, /* Ap */
99: { NULL, NULL, NULL, NULL, NULL }, /* Dd */
100: { NULL, NULL, NULL, NULL, NULL }, /* Dt */
1.8 schwarze 101: { NULL, NULL, NULL, NULL, NULL }, /* Os */
1.3 schwarze 102: { NULL, pre_sect, post_sect, ".SH", NULL }, /* Sh */
103: { NULL, pre_sect, post_sect, ".SS", NULL }, /* Ss */
1.1 schwarze 104: { NULL, pre_pp, NULL, NULL, NULL }, /* Pp */
1.3 schwarze 105: { cond_body, pre_dl, post_dl, NULL, NULL }, /* D1 */
1.1 schwarze 106: { cond_body, pre_dl, post_dl, NULL, NULL }, /* Dl */
1.3 schwarze 107: { cond_body, pre_bd, post_bd, NULL, NULL }, /* Bd */
108: { NULL, NULL, NULL, NULL, NULL }, /* Ed */
109: { NULL, NULL, NULL, NULL, NULL }, /* Bl */
110: { NULL, NULL, NULL, NULL, NULL }, /* El */
1.1 schwarze 111: { NULL, pre_it, NULL, NULL, NULL }, /* _It */
1.26 ! schwarze 112: { NULL, pre_em, post_font, NULL, NULL }, /* Ad */
1.22 schwarze 113: { NULL, pre_an, NULL, NULL, NULL }, /* An */
1.26 ! schwarze 114: { NULL, pre_em, post_font, NULL, NULL }, /* Ar */
! 115: { NULL, pre_sy, post_font, NULL, NULL }, /* Cd */
! 116: { NULL, pre_sy, post_font, NULL, NULL }, /* Cm */
! 117: { NULL, pre_li, post_font, NULL, NULL }, /* Dv */
! 118: { NULL, pre_li, post_font, NULL, NULL }, /* Er */
! 119: { NULL, pre_li, post_font, NULL, NULL }, /* Ev */
1.1 schwarze 120: { NULL, pre_enc, post_enc, "The \\fB",
121: "\\fP\nutility exits 0 on success, and >0 if an error occurs."
122: }, /* Ex */
1.17 schwarze 123: { NULL, pre_fa, post_fa, NULL, NULL }, /* Fa */
1.1 schwarze 124: { NULL, NULL, NULL, NULL, NULL }, /* _Fd */
1.26 ! schwarze 125: { NULL, pre_fl, post_fl, NULL, NULL }, /* Fl */
1.16 schwarze 126: { NULL, pre_fn, post_fn, NULL, NULL }, /* Fn */
1.26 ! schwarze 127: { NULL, pre_ft, post_font, NULL, NULL }, /* Ft */
! 128: { NULL, pre_sy, post_font, NULL, NULL }, /* Ic */
1.15 schwarze 129: { NULL, pre_in, post_in, NULL, NULL }, /* In */
1.26 ! schwarze 130: { NULL, pre_li, post_font, NULL, NULL }, /* Li */
1.1 schwarze 131: { cond_head, pre_enc, NULL, "\\- ", NULL }, /* Nd */
132: { NULL, pre_nm, post_nm, NULL, NULL }, /* Nm */
133: { cond_body, pre_enc, post_enc, "[", "]" }, /* Op */
1.8 schwarze 134: { NULL, NULL, NULL, NULL, NULL }, /* Ot */
1.26 ! schwarze 135: { NULL, pre_em, post_font, NULL, NULL }, /* Pa */
1.6 kristaps 136: { NULL, pre_enc, post_enc, "The \\fB",
137: "\\fP\nfunction returns the value 0 if successful;\n"
138: "otherwise the value -1 is returned and the global\n"
139: "variable \\fIerrno\\fP is set to indicate the error."
140: }, /* Rv */
1.8 schwarze 141: { NULL, NULL, NULL, NULL, NULL }, /* St */
1.26 ! schwarze 142: { NULL, pre_em, post_font, NULL, NULL }, /* Va */
1.18 schwarze 143: { NULL, pre_vt, post_vt, NULL, NULL }, /* Vt */
1.8 schwarze 144: { NULL, pre_xr, NULL, NULL, NULL }, /* Xr */
1.1 schwarze 145: { NULL, NULL, post_percent, NULL, NULL }, /* _%A */
146: { NULL, NULL, NULL, NULL, NULL }, /* _%B */
147: { NULL, NULL, post_percent, NULL, NULL }, /* _%D */
148: { NULL, NULL, NULL, NULL, NULL }, /* _%I */
149: { NULL, pre_enc, post_percent, "\\fI", "\\fP" }, /* %J */
150: { NULL, NULL, NULL, NULL, NULL }, /* _%N */
151: { NULL, NULL, NULL, NULL, NULL }, /* _%O */
152: { NULL, NULL, NULL, NULL, NULL }, /* _%P */
153: { NULL, NULL, NULL, NULL, NULL }, /* _%R */
154: { NULL, pre_enc, post_percent, "\"", "\"" }, /* %T */
155: { NULL, NULL, NULL, NULL, NULL }, /* _%V */
1.9 schwarze 156: { NULL, NULL, NULL, NULL, NULL }, /* Ac */
157: { cond_body, pre_enc, post_enc, "<", ">" }, /* Ao */
1.1 schwarze 158: { cond_body, pre_enc, post_enc, "<", ">" }, /* Aq */
1.8 schwarze 159: { NULL, NULL, NULL, NULL, NULL }, /* At */
1.3 schwarze 160: { NULL, NULL, NULL, NULL, NULL }, /* Bc */
1.1 schwarze 161: { NULL, NULL, NULL, NULL, NULL }, /* _Bf */
1.3 schwarze 162: { cond_body, pre_enc, post_enc, "[", "]" }, /* Bo */
163: { cond_body, pre_enc, post_enc, "[", "]" }, /* Bq */
1.8 schwarze 164: { NULL, pre_ux, NULL, "BSD/OS", NULL }, /* Bsx */
165: { NULL, pre_bx, NULL, NULL, NULL }, /* Bx */
166: { NULL, NULL, NULL, NULL, NULL }, /* Db */
1.9 schwarze 167: { NULL, NULL, NULL, NULL, NULL }, /* Dc */
168: { cond_body, pre_enc, post_enc, "``", "''" }, /* Do */
1.1 schwarze 169: { cond_body, pre_enc, post_enc, "``", "''" }, /* Dq */
170: { NULL, NULL, NULL, NULL, NULL }, /* _Ec */
171: { NULL, NULL, NULL, NULL, NULL }, /* _Ef */
1.26 ! schwarze 172: { NULL, pre_em, post_font, NULL, NULL }, /* Em */
1.1 schwarze 173: { NULL, NULL, NULL, NULL, NULL }, /* _Eo */
1.8 schwarze 174: { NULL, pre_ux, NULL, "FreeBSD", NULL }, /* Fx */
1.26 ! schwarze 175: { NULL, pre_sy, post_font, NULL, NULL }, /* Ms */
1.25 schwarze 176: { NULL, pre_no, NULL, NULL, NULL }, /* No */
1.1 schwarze 177: { NULL, pre_ns, NULL, NULL, NULL }, /* Ns */
1.8 schwarze 178: { NULL, pre_ux, NULL, "NetBSD", NULL }, /* Nx */
179: { NULL, pre_ux, NULL, "OpenBSD", NULL }, /* Ox */
1.3 schwarze 180: { NULL, NULL, NULL, NULL, NULL }, /* Pc */
181: { NULL, NULL, post_pf, NULL, NULL }, /* Pf */
182: { cond_body, pre_enc, post_enc, "(", ")" }, /* Po */
183: { cond_body, pre_enc, post_enc, "(", ")" }, /* Pq */
1.9 schwarze 184: { NULL, NULL, NULL, NULL, NULL }, /* Qc */
1.1 schwarze 185: { cond_body, pre_enc, post_enc, "`", "'" }, /* Ql */
1.9 schwarze 186: { cond_body, pre_enc, post_enc, "\"", "\"" }, /* Qo */
187: { cond_body, pre_enc, post_enc, "\"", "\"" }, /* Qq */
188: { NULL, NULL, NULL, NULL, NULL }, /* Re */
1.1 schwarze 189: { cond_body, pre_pp, NULL, NULL, NULL }, /* Rs */
1.9 schwarze 190: { NULL, NULL, NULL, NULL, NULL }, /* Sc */
191: { cond_body, pre_enc, post_enc, "`", "'" }, /* So */
1.1 schwarze 192: { cond_body, pre_enc, post_enc, "`", "'" }, /* Sq */
1.12 schwarze 193: { NULL, pre_sm, NULL, NULL, NULL }, /* Sm */
1.26 ! schwarze 194: { NULL, pre_em, post_font, NULL, NULL }, /* Sx */
! 195: { NULL, pre_sy, post_font, NULL, NULL }, /* Sy */
! 196: { NULL, pre_li, post_font, NULL, NULL }, /* Tn */
1.8 schwarze 197: { NULL, pre_ux, NULL, "UNIX", NULL }, /* Ux */
1.1 schwarze 198: { NULL, NULL, NULL, NULL, NULL }, /* _Xc */
199: { NULL, NULL, NULL, NULL, NULL }, /* _Xo */
1.17 schwarze 200: { NULL, pre_fo, post_fo, NULL, NULL }, /* Fo */
201: { NULL, NULL, NULL, NULL, NULL }, /* Fc */
1.3 schwarze 202: { cond_body, pre_enc, post_enc, "[", "]" }, /* Oo */
1.9 schwarze 203: { NULL, NULL, NULL, NULL, NULL }, /* Oc */
1.13 schwarze 204: { NULL, pre_bk, post_bk, NULL, NULL }, /* Bk */
205: { NULL, NULL, NULL, NULL, NULL }, /* Ek */
1.8 schwarze 206: { NULL, pre_ux, NULL, "is currently in beta test.", NULL }, /* Bt */
207: { NULL, NULL, NULL, NULL, NULL }, /* Hf */
208: { NULL, NULL, NULL, NULL, NULL }, /* Fr */
209: { NULL, pre_ux, NULL, "currently under development.", NULL }, /* Ud */
1.14 schwarze 210: { NULL, NULL, post_lb, NULL, NULL }, /* Lb */
1.3 schwarze 211: { NULL, pre_pp, NULL, NULL, NULL }, /* Lp */
1.24 schwarze 212: { NULL, pre_lk, NULL, NULL, NULL }, /* Lk */
1.26 ! schwarze 213: { NULL, pre_em, post_font, NULL, NULL }, /* Mt */
1.9 schwarze 214: { cond_body, pre_enc, post_enc, "{", "}" }, /* Brq */
215: { cond_body, pre_enc, post_enc, "{", "}" }, /* Bro */
216: { NULL, NULL, NULL, NULL, NULL }, /* Brc */
1.1 schwarze 217: { NULL, NULL, NULL, NULL, NULL }, /* _%C */
218: { NULL, NULL, NULL, NULL, NULL }, /* _Es */
219: { NULL, NULL, NULL, NULL, NULL }, /* _En */
1.8 schwarze 220: { NULL, pre_ux, NULL, "DragonFly", NULL }, /* Dx */
1.1 schwarze 221: { NULL, NULL, NULL, NULL, NULL }, /* _%Q */
1.3 schwarze 222: { NULL, pre_br, NULL, NULL, NULL }, /* br */
223: { NULL, pre_sp, post_sp, NULL, NULL }, /* sp */
1.1 schwarze 224: { NULL, NULL, NULL, NULL, NULL }, /* _%U */
225: { NULL, NULL, NULL, NULL, NULL }, /* _Ta */
1.3 schwarze 226: { NULL, NULL, NULL, NULL, NULL }, /* ROOT */
1.1 schwarze 227: };
228:
1.20 schwarze 229: static int outflags;
230: #define MMAN_spc (1 << 0)
1.25 schwarze 231: #define MMAN_spc_force (1 << 1)
232: #define MMAN_nl (1 << 2)
233: #define MMAN_br (1 << 3)
234: #define MMAN_sp (1 << 4)
235: #define MMAN_Sm (1 << 5)
236: #define MMAN_Bk (1 << 6)
237: #define MMAN_An_split (1 << 7)
238: #define MMAN_An_nosplit (1 << 8)
1.20 schwarze 239:
1.26 ! schwarze 240: static struct {
! 241: char *head;
! 242: char *tail;
! 243: size_t size;
! 244: } fontqueue;
! 245:
! 246: static void
! 247: font_push(char newfont)
! 248: {
! 249:
! 250: if (fontqueue.head + fontqueue.size <= ++fontqueue.tail) {
! 251: fontqueue.size += 8;
! 252: fontqueue.head = mandoc_realloc(fontqueue.head,
! 253: fontqueue.size);
! 254: }
! 255: *fontqueue.tail = newfont;
! 256: print_word("\\f");
! 257: putchar(newfont);
! 258: outflags &= ~MMAN_spc;
! 259: }
! 260:
! 261: static void
! 262: font_pop(void)
! 263: {
! 264:
! 265: if (fontqueue.tail > fontqueue.head)
! 266: fontqueue.tail--;
! 267: outflags &= ~MMAN_spc;
! 268: print_word("\\f");
! 269: putchar(*fontqueue.tail);
! 270: }
! 271:
1.1 schwarze 272: static void
1.20 schwarze 273: print_word(const char *s)
1.1 schwarze 274: {
1.5 kristaps 275:
1.21 schwarze 276: if ((MMAN_sp | MMAN_br | MMAN_nl) & outflags) {
1.5 kristaps 277: /*
278: * If we need a newline, print it now and start afresh.
279: */
1.21 schwarze 280: if (MMAN_sp & outflags)
281: printf("\n.sp\n");
282: else if (MMAN_br & outflags)
283: printf("\n.br\n");
284: else if (MMAN_nl & outflags)
285: putchar('\n');
286: outflags &= ~(MMAN_sp|MMAN_br|MMAN_nl|MMAN_spc);
1.20 schwarze 287: } else if (MMAN_spc & outflags && '\0' != s[0])
1.5 kristaps 288: /*
1.25 schwarze 289: * If we need a space, only print it if
290: * (1) it is forced by `No' or
291: * (2) what follows is not terminating punctuation or
292: * (3) what follows is longer than one character.
1.5 kristaps 293: */
1.25 schwarze 294: if (MMAN_spc_force & outflags ||
295: NULL == strchr(".,:;)]?!", s[0]) || '\0' != s[1]) {
1.20 schwarze 296: if (MMAN_Bk & outflags) {
1.13 schwarze 297: putchar('\\');
298: putchar('~');
299: } else
300: putchar(' ');
301: }
1.5 kristaps 302:
303: /*
304: * Reassign needing space if we're not following opening
305: * punctuation.
306: */
1.20 schwarze 307: if (MMAN_Sm & outflags &&
308: (('(' != s[0] && '[' != s[0]) || '\0' != s[1]))
309: outflags |= MMAN_spc;
310: else
311: outflags &= ~MMAN_spc;
1.25 schwarze 312: outflags &= ~MMAN_spc_force;
1.5 kristaps 313:
1.1 schwarze 314: for ( ; *s; s++) {
315: switch (*s) {
316: case (ASCII_NBRSP):
317: printf("\\~");
318: break;
319: case (ASCII_HYPH):
320: putchar('-');
321: break;
322: default:
1.5 kristaps 323: putchar((unsigned char)*s);
1.1 schwarze 324: break;
325: }
326: }
1.4 kristaps 327: }
328:
1.11 schwarze 329: static void
1.20 schwarze 330: print_offs(const char *v)
1.11 schwarze 331: {
332: char buf[24];
333: struct roffsu su;
334: size_t sz;
335:
336: if (NULL == v || '\0' == *v || 0 == strcmp(v, "left"))
337: sz = 0;
338: else if (0 == strcmp(v, "indent"))
339: sz = 6;
340: else if (0 == strcmp(v, "indent-two"))
341: sz = 12;
342: else if (a2roffsu(v, &su, SCALE_MAX)) {
1.20 schwarze 343: print_word(v);
1.11 schwarze 344: return;
345: } else
346: sz = strlen(v);
347:
348: snprintf(buf, sizeof(buf), "%ldn", sz);
1.20 schwarze 349: print_word(buf);
1.11 schwarze 350: }
351:
1.4 kristaps 352: void
353: man_man(void *arg, const struct man *man)
354: {
355:
1.5 kristaps 356: /*
357: * Dump the keep buffer.
358: * We're guaranteed by now that this exists (is non-NULL).
359: * Flush stdout afterward, just in case.
360: */
1.4 kristaps 361: fputs(mparse_getkeep(man_mparse(man)), stdout);
1.5 kristaps 362: fflush(stdout);
1.1 schwarze 363: }
364:
365: void
366: man_mdoc(void *arg, const struct mdoc *mdoc)
367: {
368: const struct mdoc_meta *m;
369: const struct mdoc_node *n;
370:
371: m = mdoc_meta(mdoc);
372: n = mdoc_node(mdoc);
373:
1.3 schwarze 374: printf(".TH \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"",
1.5 kristaps 375: m->title, m->msec, m->date, m->os, m->vol);
1.1 schwarze 376:
1.20 schwarze 377: outflags = MMAN_nl | MMAN_Sm;
1.26 ! schwarze 378: if (0 == fontqueue.size) {
! 379: fontqueue.size = 8;
! 380: fontqueue.head = fontqueue.tail = mandoc_malloc(8);
! 381: *fontqueue.tail = 'R';
! 382: }
1.20 schwarze 383: print_node(m, n);
1.3 schwarze 384: putchar('\n');
1.1 schwarze 385: }
386:
387: static void
388: print_node(DECL_ARGS)
389: {
390: const struct mdoc_node *prev, *sub;
1.5 kristaps 391: const struct manact *act;
1.1 schwarze 392: int cond, do_sub;
1.5 kristaps 393:
394: /*
395: * Break the line if we were parsed subsequent the current node.
396: * This makes the page structure be more consistent.
397: */
1.1 schwarze 398: prev = n->prev ? n->prev : n->parent;
1.17 schwarze 399: if (prev && prev->line < n->line &&
400: MDOC_Fo != prev->tok && MDOC_Ns != prev->tok)
1.20 schwarze 401: outflags |= MMAN_nl;
1.1 schwarze 402:
1.5 kristaps 403: act = NULL;
1.1 schwarze 404: cond = 0;
405: do_sub = 1;
1.5 kristaps 406:
1.1 schwarze 407: if (MDOC_TEXT == n->type) {
1.5 kristaps 408: /*
409: * Make sure that we don't happen to start with a
410: * control character at the start of a line.
411: */
1.20 schwarze 412: if (MMAN_nl & outflags && ('.' == *n->string ||
1.5 kristaps 413: '\'' == *n->string)) {
1.20 schwarze 414: print_word("\\&");
415: outflags &= ~MMAN_spc;
1.3 schwarze 416: }
1.20 schwarze 417: print_word(n->string);
1.1 schwarze 418: } else {
1.5 kristaps 419: /*
420: * Conditionally run the pre-node action handler for a
421: * node.
422: */
1.1 schwarze 423: act = manacts + n->tok;
1.20 schwarze 424: cond = NULL == act->cond || (*act->cond)(m, n);
1.1 schwarze 425: if (cond && act->pre)
1.20 schwarze 426: do_sub = (*act->pre)(m, n);
1.1 schwarze 427: }
428:
1.5 kristaps 429: /*
430: * Conditionally run all child nodes.
431: * Note that this iterates over children instead of using
432: * recursion. This prevents unnecessary depth in the stack.
433: */
1.1 schwarze 434: if (do_sub)
435: for (sub = n->child; sub; sub = sub->next)
1.20 schwarze 436: print_node(m, sub);
1.1 schwarze 437:
1.5 kristaps 438: /*
439: * Lastly, conditionally run the post-node handler.
440: */
1.1 schwarze 441: if (cond && act->post)
1.20 schwarze 442: (*act->post)(m, n);
1.1 schwarze 443: }
444:
445: static int
446: cond_head(DECL_ARGS)
447: {
1.5 kristaps 448:
1.1 schwarze 449: return(MDOC_HEAD == n->type);
450: }
451:
452: static int
453: cond_body(DECL_ARGS)
454: {
1.5 kristaps 455:
1.1 schwarze 456: return(MDOC_BODY == n->type);
457: }
458:
459: static int
460: pre_enc(DECL_ARGS)
461: {
1.5 kristaps 462: const char *prefix;
1.1 schwarze 463:
464: prefix = manacts[n->tok].prefix;
465: if (NULL == prefix)
466: return(1);
1.20 schwarze 467: print_word(prefix);
468: outflags &= ~MMAN_spc;
1.1 schwarze 469: return(1);
470: }
471:
472: static void
473: post_enc(DECL_ARGS)
474: {
475: const char *suffix;
476:
477: suffix = manacts[n->tok].suffix;
478: if (NULL == suffix)
479: return;
1.20 schwarze 480: outflags &= ~MMAN_spc;
481: print_word(suffix);
1.26 ! schwarze 482: }
! 483:
! 484: static void
! 485: post_font(DECL_ARGS)
! 486: {
! 487:
! 488: font_pop();
1.1 schwarze 489: }
490:
1.5 kristaps 491: /*
492: * Used in listings (percent = %A, e.g.).
493: * FIXME: this is incomplete.
494: * It doesn't print a nice ", and" for lists.
495: */
1.1 schwarze 496: static void
497: post_percent(DECL_ARGS)
498: {
499:
1.20 schwarze 500: post_enc(m, n);
1.1 schwarze 501: if (n->next)
1.20 schwarze 502: print_word(",");
1.1 schwarze 503: else {
1.20 schwarze 504: print_word(".");
505: outflags |= MMAN_nl;
1.1 schwarze 506: }
507: }
508:
1.5 kristaps 509: /*
510: * Print before a section header.
511: */
1.1 schwarze 512: static int
1.3 schwarze 513: pre_sect(DECL_ARGS)
514: {
515:
516: if (MDOC_HEAD != n->type)
517: return(1);
1.20 schwarze 518: outflags |= MMAN_nl;
519: print_word(manacts[n->tok].prefix);
520: print_word("\"");
521: outflags &= ~MMAN_spc;
1.3 schwarze 522: return(1);
523: }
524:
1.5 kristaps 525: /*
526: * Print subsequent a section header.
527: */
1.3 schwarze 528: static void
529: post_sect(DECL_ARGS)
530: {
531:
532: if (MDOC_HEAD != n->type)
533: return;
1.20 schwarze 534: outflags &= ~MMAN_spc;
535: print_word("\"");
536: outflags |= MMAN_nl;
1.22 schwarze 537: if (MDOC_Sh == n->tok && SEC_AUTHORS == n->sec)
538: outflags &= ~(MMAN_An_split | MMAN_An_nosplit);
539: }
540:
1.23 schwarze 541: /* See mdoc_term.c, synopsis_pre() for comments. */
542: static void
543: pre_syn(const struct mdoc_node *n)
544: {
545:
546: if (NULL == n->prev || ! (MDOC_SYNPRETTY & n->flags))
547: return;
548:
549: if (n->prev->tok == n->tok &&
550: MDOC_Ft != n->tok &&
551: MDOC_Fo != n->tok &&
552: MDOC_Fn != n->tok) {
553: outflags |= MMAN_br;
554: return;
555: }
556:
557: switch (n->prev->tok) {
558: case (MDOC_Fd):
559: /* FALLTHROUGH */
560: case (MDOC_Fn):
561: /* FALLTHROUGH */
562: case (MDOC_Fo):
563: /* FALLTHROUGH */
564: case (MDOC_In):
565: /* FALLTHROUGH */
566: case (MDOC_Vt):
567: outflags |= MMAN_sp;
568: break;
569: case (MDOC_Ft):
570: if (MDOC_Fn != n->tok && MDOC_Fo != n->tok) {
571: outflags |= MMAN_sp;
572: break;
573: }
574: /* FALLTHROUGH */
575: default:
576: outflags |= MMAN_br;
577: break;
578: }
579: }
580:
1.22 schwarze 581: static int
582: pre_an(DECL_ARGS)
583: {
584:
585: switch (n->norm->An.auth) {
586: case (AUTH_split):
587: outflags &= ~MMAN_An_nosplit;
588: outflags |= MMAN_An_split;
589: return(0);
590: case (AUTH_nosplit):
591: outflags &= ~MMAN_An_split;
592: outflags |= MMAN_An_nosplit;
593: return(0);
594: default:
595: if (MMAN_An_split & outflags)
596: outflags |= MMAN_br;
597: else if (SEC_AUTHORS == n->sec &&
598: ! (MMAN_An_nosplit & outflags))
599: outflags |= MMAN_An_split;
600: return(1);
601: }
1.3 schwarze 602: }
603:
604: static int
605: pre_ap(DECL_ARGS)
606: {
607:
1.20 schwarze 608: outflags &= ~MMAN_spc;
609: print_word("'");
610: outflags &= ~MMAN_spc;
1.3 schwarze 611: return(0);
612: }
613:
614: static int
615: pre_bd(DECL_ARGS)
616: {
617:
1.21 schwarze 618: if (0 == n->norm->Bd.comp)
619: outflags |= MMAN_sp;
1.3 schwarze 620: if (DISP_unfilled == n->norm->Bd.type ||
621: DISP_literal == n->norm->Bd.type) {
1.20 schwarze 622: outflags |= MMAN_nl;
623: print_word(".nf");
1.3 schwarze 624: }
1.20 schwarze 625: outflags |= MMAN_nl;
626: print_word(".RS");
627: print_offs(n->norm->Bd.offs);
628: outflags |= MMAN_nl;
1.3 schwarze 629: return(1);
630: }
631:
632: static void
633: post_bd(DECL_ARGS)
634: {
635:
1.20 schwarze 636: outflags |= MMAN_nl;
637: print_word(".RE");
1.3 schwarze 638: if (DISP_unfilled == n->norm->Bd.type ||
639: DISP_literal == n->norm->Bd.type) {
1.20 schwarze 640: outflags |= MMAN_nl;
641: print_word(".fi");
1.3 schwarze 642: }
1.20 schwarze 643: outflags |= MMAN_nl;
1.13 schwarze 644: }
645:
646: static int
647: pre_bk(DECL_ARGS)
648: {
649:
650: switch (n->type) {
651: case (MDOC_BLOCK):
652: return(1);
653: case (MDOC_BODY):
1.20 schwarze 654: outflags |= MMAN_Bk;
1.13 schwarze 655: return(1);
656: default:
657: return(0);
658: }
659: }
660:
661: static void
662: post_bk(DECL_ARGS)
663: {
664:
665: if (MDOC_BODY == n->type)
1.20 schwarze 666: outflags &= ~MMAN_Bk;
1.3 schwarze 667: }
668:
669: static int
670: pre_br(DECL_ARGS)
671: {
672:
1.21 schwarze 673: outflags |= MMAN_br;
1.3 schwarze 674: return(0);
675: }
676:
677: static int
1.8 schwarze 678: pre_bx(DECL_ARGS)
679: {
680:
681: n = n->child;
682: if (n) {
1.20 schwarze 683: print_word(n->string);
684: outflags &= ~MMAN_spc;
1.8 schwarze 685: n = n->next;
686: }
1.20 schwarze 687: print_word("BSD");
1.8 schwarze 688: if (NULL == n)
689: return(0);
1.20 schwarze 690: outflags &= ~MMAN_spc;
691: print_word("-");
692: outflags &= ~MMAN_spc;
693: print_word(n->string);
1.8 schwarze 694: return(0);
695: }
696:
697: static int
1.1 schwarze 698: pre_dl(DECL_ARGS)
699: {
700:
1.20 schwarze 701: outflags |= MMAN_nl;
702: print_word(".RS 6n");
703: outflags |= MMAN_nl;
1.1 schwarze 704: return(1);
705: }
706:
707: static void
708: post_dl(DECL_ARGS)
709: {
710:
1.20 schwarze 711: outflags |= MMAN_nl;
712: print_word(".RE");
713: outflags |= MMAN_nl;
1.16 schwarze 714: }
715:
716: static int
1.26 ! schwarze 717: pre_em(DECL_ARGS)
! 718: {
! 719:
! 720: font_push('I');
! 721: return(1);
! 722: }
! 723:
! 724: static int
1.17 schwarze 725: pre_fa(DECL_ARGS)
726: {
727:
728: if (MDOC_Fa == n->tok)
729: n = n->child;
730:
731: while (NULL != n) {
1.26 ! schwarze 732: font_push('I');
1.20 schwarze 733: print_node(m, n);
1.26 ! schwarze 734: font_pop();
1.17 schwarze 735: if (NULL != (n = n->next))
1.20 schwarze 736: print_word(",");
1.17 schwarze 737: }
738: return(0);
739: }
740:
741: static void
742: post_fa(DECL_ARGS)
743: {
744:
745: if (NULL != n->next && MDOC_Fa == n->next->tok)
1.20 schwarze 746: print_word(",");
1.17 schwarze 747: }
748:
749: static int
1.26 ! schwarze 750: pre_fl(DECL_ARGS)
! 751: {
! 752:
! 753: font_push('B');
! 754: print_word("-");
! 755: outflags &= ~MMAN_spc;
! 756: return(1);
! 757: }
! 758:
! 759: static void
! 760: post_fl(DECL_ARGS)
! 761: {
! 762:
! 763: font_pop();
! 764: if (0 == n->nchild)
! 765: outflags &= ~MMAN_spc;
! 766: }
! 767:
! 768: static int
1.16 schwarze 769: pre_fn(DECL_ARGS)
770: {
771:
1.23 schwarze 772: pre_syn(n);
773:
1.16 schwarze 774: n = n->child;
775: if (NULL == n)
776: return(0);
777:
1.26 ! schwarze 778: font_push('B');
1.20 schwarze 779: print_node(m, n);
1.26 ! schwarze 780: font_pop();
1.20 schwarze 781: outflags &= ~MMAN_spc;
1.26 ! schwarze 782: print_word("(");
1.20 schwarze 783: outflags &= ~MMAN_spc;
784: return(pre_fa(m, n->next));
1.16 schwarze 785: }
786:
787: static void
788: post_fn(DECL_ARGS)
789: {
790:
1.20 schwarze 791: print_word(")");
1.16 schwarze 792: if (MDOC_SYNPRETTY & n->flags) {
1.20 schwarze 793: print_word(";");
1.21 schwarze 794: outflags |= MMAN_br;
1.17 schwarze 795: }
796: }
797:
798: static int
799: pre_fo(DECL_ARGS)
800: {
801:
802: switch (n->type) {
1.23 schwarze 803: case (MDOC_BLOCK):
804: pre_syn(n);
805: break;
1.17 schwarze 806: case (MDOC_HEAD):
1.26 ! schwarze 807: font_push('B');
1.17 schwarze 808: break;
809: case (MDOC_BODY):
1.20 schwarze 810: outflags &= ~MMAN_spc;
811: print_word("(");
812: outflags &= ~MMAN_spc;
1.17 schwarze 813: break;
814: default:
815: break;
816: }
817: return(1);
818: }
819:
820: static void
821: post_fo(DECL_ARGS)
822: {
823:
824: switch (n->type) {
825: case (MDOC_HEAD):
1.26 ! schwarze 826: font_pop();
1.17 schwarze 827: break;
828: case (MDOC_BODY):
1.20 schwarze 829: post_fn(m, n);
1.17 schwarze 830: break;
831: default:
832: break;
1.16 schwarze 833: }
1.15 schwarze 834: }
835:
836: static int
1.23 schwarze 837: pre_ft(DECL_ARGS)
838: {
839:
840: pre_syn(n);
1.26 ! schwarze 841: font_push('I');
1.23 schwarze 842: return(1);
843: }
844:
845: static int
1.15 schwarze 846: pre_in(DECL_ARGS)
847: {
848:
849: if (MDOC_SYNPRETTY & n->flags) {
1.23 schwarze 850: pre_syn(n);
1.26 ! schwarze 851: font_push('B');
! 852: print_word("#include <");
! 853: outflags &= ~MMAN_spc;
! 854: } else {
! 855: print_word("<");
! 856: outflags &= ~MMAN_spc;
! 857: font_push('I');
! 858: }
1.15 schwarze 859: return(1);
860: }
861:
862: static void
863: post_in(DECL_ARGS)
864: {
865:
866: if (MDOC_SYNPRETTY & n->flags) {
1.26 ! schwarze 867: outflags &= ~MMAN_spc;
! 868: print_word(">");
! 869: font_pop();
1.21 schwarze 870: outflags |= MMAN_br;
1.26 ! schwarze 871: } else {
! 872: font_pop();
! 873: outflags &= ~MMAN_spc;
! 874: print_word(">");
! 875: }
1.1 schwarze 876: }
877:
878: static int
879: pre_it(DECL_ARGS)
880: {
881: const struct mdoc_node *bln;
882:
883: if (MDOC_HEAD == n->type) {
1.20 schwarze 884: outflags |= MMAN_nl;
885: print_word(".TP");
1.1 schwarze 886: bln = n->parent->parent->prev;
1.3 schwarze 887: switch (bln->norm->Bl.type) {
888: case (LIST_bullet):
1.20 schwarze 889: print_word("4n");
890: outflags |= MMAN_nl;
891: print_word("\\fBo\\fP");
1.3 schwarze 892: break;
893: default:
894: if (bln->norm->Bl.width)
1.20 schwarze 895: print_word(bln->norm->Bl.width);
1.3 schwarze 896: break;
897: }
1.20 schwarze 898: outflags |= MMAN_nl;
1.1 schwarze 899: }
900: return(1);
1.14 schwarze 901: }
902:
903: static void
904: post_lb(DECL_ARGS)
905: {
906:
1.21 schwarze 907: if (SEC_LIBRARY == n->sec)
908: outflags |= MMAN_br;
1.24 schwarze 909: }
910:
911: static int
912: pre_lk(DECL_ARGS)
913: {
914: const struct mdoc_node *link, *descr;
915:
916: if (NULL == (link = n->child))
917: return(0);
918:
919: if (NULL != (descr = link->next)) {
1.26 ! schwarze 920: font_push('I');
1.24 schwarze 921: while (NULL != descr) {
922: print_word(descr->string);
923: descr = descr->next;
924: }
925: print_word(":");
1.26 ! schwarze 926: font_pop();
1.24 schwarze 927: }
928:
1.26 ! schwarze 929: font_push('B');
1.24 schwarze 930: print_word(link->string);
1.26 ! schwarze 931: font_pop();
1.24 schwarze 932: return(0);
1.1 schwarze 933: }
934:
935: static int
1.26 ! schwarze 936: pre_li(DECL_ARGS)
! 937: {
! 938:
! 939: font_push('R');
! 940: return(1);
! 941: }
! 942:
! 943: static int
1.1 schwarze 944: pre_nm(DECL_ARGS)
945: {
946:
1.23 schwarze 947: if (MDOC_BLOCK == n->type)
948: pre_syn(n);
1.1 schwarze 949: if (MDOC_ELEM != n->type && MDOC_HEAD != n->type)
950: return(1);
1.23 schwarze 951: if (NULL == n->child && NULL == m->name)
952: return(0);
1.26 ! schwarze 953: font_push('B');
1.1 schwarze 954: if (NULL == n->child)
1.20 schwarze 955: print_word(m->name);
1.1 schwarze 956: return(1);
957: }
958:
959: static void
960: post_nm(DECL_ARGS)
961: {
962:
963: if (MDOC_ELEM != n->type && MDOC_HEAD != n->type)
964: return;
1.26 ! schwarze 965: font_pop();
1.25 schwarze 966: }
967:
968: static int
969: pre_no(DECL_ARGS)
970: {
971:
972: outflags |= MMAN_spc_force;
973: return(1);
1.1 schwarze 974: }
975:
976: static int
977: pre_ns(DECL_ARGS)
978: {
979:
1.20 schwarze 980: outflags &= ~MMAN_spc;
1.1 schwarze 981: return(0);
982: }
983:
1.3 schwarze 984: static void
985: post_pf(DECL_ARGS)
986: {
987:
1.20 schwarze 988: outflags &= ~MMAN_spc;
1.3 schwarze 989: }
990:
1.1 schwarze 991: static int
992: pre_pp(DECL_ARGS)
993: {
994:
1.20 schwarze 995: outflags |= MMAN_nl;
1.1 schwarze 996: if (MDOC_It == n->parent->tok)
1.20 schwarze 997: print_word(".sp");
1.1 schwarze 998: else
1.20 schwarze 999: print_word(".PP");
1000: outflags |= MMAN_nl;
1.10 schwarze 1001: return(MDOC_Rs == n->tok);
1.12 schwarze 1002: }
1003:
1004: static int
1005: pre_sm(DECL_ARGS)
1006: {
1007:
1008: assert(n->child && MDOC_TEXT == n->child->type);
1009: if (0 == strcmp("on", n->child->string))
1.20 schwarze 1010: outflags |= MMAN_Sm;
1.12 schwarze 1011: else
1.20 schwarze 1012: outflags &= ~MMAN_Sm;
1.12 schwarze 1013: return(0);
1.1 schwarze 1014: }
1015:
1016: static int
1.3 schwarze 1017: pre_sp(DECL_ARGS)
1.1 schwarze 1018: {
1019:
1.20 schwarze 1020: outflags |= MMAN_nl;
1021: print_word(".sp");
1.1 schwarze 1022: return(1);
1023: }
1024:
1025: static void
1.3 schwarze 1026: post_sp(DECL_ARGS)
1.1 schwarze 1027: {
1028:
1.20 schwarze 1029: outflags |= MMAN_nl;
1.18 schwarze 1030: }
1031:
1032: static int
1.26 ! schwarze 1033: pre_sy(DECL_ARGS)
! 1034: {
! 1035:
! 1036: font_push('B');
! 1037: return(1);
! 1038: }
! 1039:
! 1040: static int
1.18 schwarze 1041: pre_vt(DECL_ARGS)
1042: {
1043:
1044: if (MDOC_SYNPRETTY & n->flags) {
1045: switch (n->type) {
1046: case (MDOC_BLOCK):
1.23 schwarze 1047: pre_syn(n);
1.18 schwarze 1048: return(1);
1049: case (MDOC_BODY):
1050: break;
1051: default:
1052: return(0);
1053: }
1054: }
1.26 ! schwarze 1055: font_push('I');
1.18 schwarze 1056: return(1);
1057: }
1058:
1059: static void
1060: post_vt(DECL_ARGS)
1061: {
1062:
1.19 schwarze 1063: if (MDOC_SYNPRETTY & n->flags && MDOC_BODY != n->type)
1.18 schwarze 1064: return;
1.26 ! schwarze 1065: font_pop();
1.1 schwarze 1066: }
1067:
1068: static int
1069: pre_xr(DECL_ARGS)
1070: {
1071:
1072: n = n->child;
1073: if (NULL == n)
1074: return(0);
1.20 schwarze 1075: print_node(m, n);
1.1 schwarze 1076: n = n->next;
1077: if (NULL == n)
1078: return(0);
1.20 schwarze 1079: outflags &= ~MMAN_spc;
1080: print_word("(");
1081: print_node(m, n);
1082: print_word(")");
1.1 schwarze 1083: return(0);
1.8 schwarze 1084: }
1085:
1086: static int
1087: pre_ux(DECL_ARGS)
1088: {
1089:
1.20 schwarze 1090: print_word(manacts[n->tok].prefix);
1.8 schwarze 1091: if (NULL == n->child)
1092: return(0);
1.20 schwarze 1093: outflags &= ~MMAN_spc;
1094: print_word("\\~");
1095: outflags &= ~MMAN_spc;
1.8 schwarze 1096: return(1);
1.1 schwarze 1097: }
CVSweb