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