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