GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/mandoc/mdoc_man.c Lines: 700 742 94.3 %
Date: 2017-11-13 Branches: 456 550 82.9 %

Line Branch Exec Source
1
/*	$OpenBSD: mdoc_man.c,v 1.120 2017/06/14 22:50:37 schwarze Exp $ */
2
/*
3
 * Copyright (c) 2011-2017 Ingo Schwarze <schwarze@openbsd.org>
4
 *
5
 * Permission to use, copy, modify, and distribute this software for any
6
 * purpose with or without fee is hereby granted, provided that the above
7
 * copyright notice and this permission notice appear in all copies.
8
 *
9
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
 */
17
#include <sys/types.h>
18
19
#include <assert.h>
20
#include <stdio.h>
21
#include <stdlib.h>
22
#include <string.h>
23
24
#include "mandoc_aux.h"
25
#include "mandoc.h"
26
#include "roff.h"
27
#include "mdoc.h"
28
#include "man.h"
29
#include "out.h"
30
#include "main.h"
31
32
#define	DECL_ARGS const struct roff_meta *meta, struct roff_node *n
33
34
typedef	int	(*int_fp)(DECL_ARGS);
35
typedef	void	(*void_fp)(DECL_ARGS);
36
37
struct	manact {
38
	int_fp		  cond; /* DON'T run actions */
39
	int_fp		  pre; /* pre-node action */
40
	void_fp		  post; /* post-node action */
41
	const char	 *prefix; /* pre-node string constant */
42
	const char	 *suffix; /* post-node string constant */
43
};
44
45
static	int	  cond_body(DECL_ARGS);
46
static	int	  cond_head(DECL_ARGS);
47
static  void	  font_push(char);
48
static	void	  font_pop(void);
49
static	int	  man_strlen(const char *);
50
static	void	  mid_it(void);
51
static	void	  post__t(DECL_ARGS);
52
static	void	  post_aq(DECL_ARGS);
53
static	void	  post_bd(DECL_ARGS);
54
static	void	  post_bf(DECL_ARGS);
55
static	void	  post_bk(DECL_ARGS);
56
static	void	  post_bl(DECL_ARGS);
57
static	void	  post_dl(DECL_ARGS);
58
static	void	  post_en(DECL_ARGS);
59
static	void	  post_enc(DECL_ARGS);
60
static	void	  post_eo(DECL_ARGS);
61
static	void	  post_fa(DECL_ARGS);
62
static	void	  post_fd(DECL_ARGS);
63
static	void	  post_fl(DECL_ARGS);
64
static	void	  post_fn(DECL_ARGS);
65
static	void	  post_fo(DECL_ARGS);
66
static	void	  post_font(DECL_ARGS);
67
static	void	  post_in(DECL_ARGS);
68
static	void	  post_it(DECL_ARGS);
69
static	void	  post_lb(DECL_ARGS);
70
static	void	  post_nm(DECL_ARGS);
71
static	void	  post_percent(DECL_ARGS);
72
static	void	  post_pf(DECL_ARGS);
73
static	void	  post_sect(DECL_ARGS);
74
static	void	  post_vt(DECL_ARGS);
75
static	int	  pre__t(DECL_ARGS);
76
static	int	  pre_an(DECL_ARGS);
77
static	int	  pre_ap(DECL_ARGS);
78
static	int	  pre_aq(DECL_ARGS);
79
static	int	  pre_bd(DECL_ARGS);
80
static	int	  pre_bf(DECL_ARGS);
81
static	int	  pre_bk(DECL_ARGS);
82
static	int	  pre_bl(DECL_ARGS);
83
static	void	  pre_br(DECL_ARGS);
84
static	int	  pre_dl(DECL_ARGS);
85
static	int	  pre_en(DECL_ARGS);
86
static	int	  pre_enc(DECL_ARGS);
87
static	int	  pre_em(DECL_ARGS);
88
static	int	  pre_skip(DECL_ARGS);
89
static	int	  pre_eo(DECL_ARGS);
90
static	int	  pre_ex(DECL_ARGS);
91
static	int	  pre_fa(DECL_ARGS);
92
static	int	  pre_fd(DECL_ARGS);
93
static	int	  pre_fl(DECL_ARGS);
94
static	int	  pre_fn(DECL_ARGS);
95
static	int	  pre_fo(DECL_ARGS);
96
static	void	  pre_ft(DECL_ARGS);
97
static	int	  pre_Ft(DECL_ARGS);
98
static	int	  pre_in(DECL_ARGS);
99
static	int	  pre_it(DECL_ARGS);
100
static	int	  pre_lk(DECL_ARGS);
101
static	int	  pre_li(DECL_ARGS);
102
static	int	  pre_nm(DECL_ARGS);
103
static	int	  pre_no(DECL_ARGS);
104
static	int	  pre_ns(DECL_ARGS);
105
static	void	  pre_onearg(DECL_ARGS);
106
static	int	  pre_pp(DECL_ARGS);
107
static	int	  pre_rs(DECL_ARGS);
108
static	int	  pre_sm(DECL_ARGS);
109
static	void	  pre_sp(DECL_ARGS);
110
static	int	  pre_sect(DECL_ARGS);
111
static	int	  pre_sy(DECL_ARGS);
112
static	void	  pre_syn(const struct roff_node *);
113
static	void	  pre_ta(DECL_ARGS);
114
static	int	  pre_vt(DECL_ARGS);
115
static	int	  pre_xr(DECL_ARGS);
116
static	void	  print_word(const char *);
117
static	void	  print_line(const char *, int);
118
static	void	  print_block(const char *, int);
119
static	void	  print_offs(const char *, int);
120
static	void	  print_width(const struct mdoc_bl *,
121
			const struct roff_node *);
122
static	void	  print_count(int *);
123
static	void	  print_node(DECL_ARGS);
124
125
static	const void_fp roff_manacts[ROFF_MAX] = {
126
	pre_br,		/* br */
127
	pre_onearg,	/* ce */
128
	pre_ft,		/* ft */
129
	pre_onearg,	/* ll */
130
	pre_onearg,	/* mc */
131
	pre_onearg,	/* po */
132
	pre_onearg,	/* rj */
133
	pre_sp,		/* sp */
134
	pre_ta,		/* ta */
135
	pre_onearg,	/* ti */
136
};
137
138
static	const struct manact __manacts[MDOC_MAX - MDOC_Dd] = {
139
	{ NULL, NULL, NULL, NULL, NULL }, /* Dd */
140
	{ NULL, NULL, NULL, NULL, NULL }, /* Dt */
141
	{ NULL, NULL, NULL, NULL, NULL }, /* Os */
142
	{ NULL, pre_sect, post_sect, ".SH", NULL }, /* Sh */
143
	{ NULL, pre_sect, post_sect, ".SS", NULL }, /* Ss */
144
	{ NULL, pre_pp, NULL, NULL, NULL }, /* Pp */
145
	{ cond_body, pre_dl, post_dl, NULL, NULL }, /* D1 */
146
	{ cond_body, pre_dl, post_dl, NULL, NULL }, /* Dl */
147
	{ cond_body, pre_bd, post_bd, NULL, NULL }, /* Bd */
148
	{ NULL, NULL, NULL, NULL, NULL }, /* Ed */
149
	{ cond_body, pre_bl, post_bl, NULL, NULL }, /* Bl */
150
	{ NULL, NULL, NULL, NULL, NULL }, /* El */
151
	{ NULL, pre_it, post_it, NULL, NULL }, /* It */
152
	{ NULL, pre_em, post_font, NULL, NULL }, /* Ad */
153
	{ NULL, pre_an, NULL, NULL, NULL }, /* An */
154
	{ NULL, pre_ap, NULL, NULL, NULL }, /* Ap */
155
	{ NULL, pre_em, post_font, NULL, NULL }, /* Ar */
156
	{ NULL, pre_sy, post_font, NULL, NULL }, /* Cd */
157
	{ NULL, pre_sy, post_font, NULL, NULL }, /* Cm */
158
	{ NULL, pre_li, post_font, NULL, NULL }, /* Dv */
159
	{ NULL, pre_li, post_font, NULL, NULL }, /* Er */
160
	{ NULL, pre_li, post_font, NULL, NULL }, /* Ev */
161
	{ NULL, pre_ex, NULL, NULL, NULL }, /* Ex */
162
	{ NULL, pre_fa, post_fa, NULL, NULL }, /* Fa */
163
	{ NULL, pre_fd, post_fd, NULL, NULL }, /* Fd */
164
	{ NULL, pre_fl, post_fl, NULL, NULL }, /* Fl */
165
	{ NULL, pre_fn, post_fn, NULL, NULL }, /* Fn */
166
	{ NULL, pre_Ft, post_font, NULL, NULL }, /* Ft */
167
	{ NULL, pre_sy, post_font, NULL, NULL }, /* Ic */
168
	{ NULL, pre_in, post_in, NULL, NULL }, /* In */
169
	{ NULL, pre_li, post_font, NULL, NULL }, /* Li */
170
	{ cond_head, pre_enc, NULL, "\\- ", NULL }, /* Nd */
171
	{ NULL, pre_nm, post_nm, NULL, NULL }, /* Nm */
172
	{ cond_body, pre_enc, post_enc, "[", "]" }, /* Op */
173
	{ NULL, pre_Ft, post_font, NULL, NULL }, /* Ot */
174
	{ NULL, pre_em, post_font, NULL, NULL }, /* Pa */
175
	{ NULL, pre_ex, NULL, NULL, NULL }, /* Rv */
176
	{ NULL, NULL, NULL, NULL, NULL }, /* St */
177
	{ NULL, pre_em, post_font, NULL, NULL }, /* Va */
178
	{ NULL, pre_vt, post_vt, NULL, NULL }, /* Vt */
179
	{ NULL, pre_xr, NULL, NULL, NULL }, /* Xr */
180
	{ NULL, NULL, post_percent, NULL, NULL }, /* %A */
181
	{ NULL, pre_em, post_percent, NULL, NULL }, /* %B */
182
	{ NULL, NULL, post_percent, NULL, NULL }, /* %D */
183
	{ NULL, pre_em, post_percent, NULL, NULL }, /* %I */
184
	{ NULL, pre_em, post_percent, NULL, NULL }, /* %J */
185
	{ NULL, NULL, post_percent, NULL, NULL }, /* %N */
186
	{ NULL, NULL, post_percent, NULL, NULL }, /* %O */
187
	{ NULL, NULL, post_percent, NULL, NULL }, /* %P */
188
	{ NULL, NULL, post_percent, NULL, NULL }, /* %R */
189
	{ NULL, pre__t, post__t, NULL, NULL }, /* %T */
190
	{ NULL, NULL, post_percent, NULL, NULL }, /* %V */
191
	{ NULL, NULL, NULL, NULL, NULL }, /* Ac */
192
	{ cond_body, pre_aq, post_aq, NULL, NULL }, /* Ao */
193
	{ cond_body, pre_aq, post_aq, NULL, NULL }, /* Aq */
194
	{ NULL, NULL, NULL, NULL, NULL }, /* At */
195
	{ NULL, NULL, NULL, NULL, NULL }, /* Bc */
196
	{ NULL, pre_bf, post_bf, NULL, NULL }, /* Bf */
197
	{ cond_body, pre_enc, post_enc, "[", "]" }, /* Bo */
198
	{ cond_body, pre_enc, post_enc, "[", "]" }, /* Bq */
199
	{ NULL, pre_bk, post_bk, NULL, NULL }, /* Bsx */
200
	{ NULL, pre_bk, post_bk, NULL, NULL }, /* Bx */
201
	{ NULL, pre_skip, NULL, NULL, NULL }, /* Db */
202
	{ NULL, NULL, NULL, NULL, NULL }, /* Dc */
203
	{ cond_body, pre_enc, post_enc, "\\(Lq", "\\(Rq" }, /* Do */
204
	{ cond_body, pre_enc, post_enc, "\\(Lq", "\\(Rq" }, /* Dq */
205
	{ NULL, NULL, NULL, NULL, NULL }, /* Ec */
206
	{ NULL, NULL, NULL, NULL, NULL }, /* Ef */
207
	{ NULL, pre_em, post_font, NULL, NULL }, /* Em */
208
	{ cond_body, pre_eo, post_eo, NULL, NULL }, /* Eo */
209
	{ NULL, pre_bk, post_bk, NULL, NULL }, /* Fx */
210
	{ NULL, pre_sy, post_font, NULL, NULL }, /* Ms */
211
	{ NULL, pre_no, NULL, NULL, NULL }, /* No */
212
	{ NULL, pre_ns, NULL, NULL, NULL }, /* Ns */
213
	{ NULL, pre_bk, post_bk, NULL, NULL }, /* Nx */
214
	{ NULL, pre_bk, post_bk, NULL, NULL }, /* Ox */
215
	{ NULL, NULL, NULL, NULL, NULL }, /* Pc */
216
	{ NULL, NULL, post_pf, NULL, NULL }, /* Pf */
217
	{ cond_body, pre_enc, post_enc, "(", ")" }, /* Po */
218
	{ cond_body, pre_enc, post_enc, "(", ")" }, /* Pq */
219
	{ NULL, NULL, NULL, NULL, NULL }, /* Qc */
220
	{ cond_body, pre_enc, post_enc, "\\(oq", "\\(cq" }, /* Ql */
221
	{ cond_body, pre_enc, post_enc, "\"", "\"" }, /* Qo */
222
	{ cond_body, pre_enc, post_enc, "\"", "\"" }, /* Qq */
223
	{ NULL, NULL, NULL, NULL, NULL }, /* Re */
224
	{ cond_body, pre_rs, NULL, NULL, NULL }, /* Rs */
225
	{ NULL, NULL, NULL, NULL, NULL }, /* Sc */
226
	{ cond_body, pre_enc, post_enc, "\\(oq", "\\(cq" }, /* So */
227
	{ cond_body, pre_enc, post_enc, "\\(oq", "\\(cq" }, /* Sq */
228
	{ NULL, pre_sm, NULL, NULL, NULL }, /* Sm */
229
	{ NULL, pre_em, post_font, NULL, NULL }, /* Sx */
230
	{ NULL, pre_sy, post_font, NULL, NULL }, /* Sy */
231
	{ NULL, pre_li, post_font, NULL, NULL }, /* Tn */
232
	{ NULL, NULL, NULL, NULL, NULL }, /* Ux */
233
	{ NULL, NULL, NULL, NULL, NULL }, /* Xc */
234
	{ NULL, NULL, NULL, NULL, NULL }, /* Xo */
235
	{ NULL, pre_fo, post_fo, NULL, NULL }, /* Fo */
236
	{ NULL, NULL, NULL, NULL, NULL }, /* Fc */
237
	{ cond_body, pre_enc, post_enc, "[", "]" }, /* Oo */
238
	{ NULL, NULL, NULL, NULL, NULL }, /* Oc */
239
	{ NULL, pre_bk, post_bk, NULL, NULL }, /* Bk */
240
	{ NULL, NULL, NULL, NULL, NULL }, /* Ek */
241
	{ NULL, NULL, NULL, NULL, NULL }, /* Bt */
242
	{ NULL, NULL, NULL, NULL, NULL }, /* Hf */
243
	{ NULL, pre_em, post_font, NULL, NULL }, /* Fr */
244
	{ NULL, NULL, NULL, NULL, NULL }, /* Ud */
245
	{ NULL, NULL, post_lb, NULL, NULL }, /* Lb */
246
	{ NULL, pre_pp, NULL, NULL, NULL }, /* Lp */
247
	{ NULL, pre_lk, NULL, NULL, NULL }, /* Lk */
248
	{ NULL, pre_em, post_font, NULL, NULL }, /* Mt */
249
	{ cond_body, pre_enc, post_enc, "{", "}" }, /* Brq */
250
	{ cond_body, pre_enc, post_enc, "{", "}" }, /* Bro */
251
	{ NULL, NULL, NULL, NULL, NULL }, /* Brc */
252
	{ NULL, NULL, post_percent, NULL, NULL }, /* %C */
253
	{ NULL, pre_skip, NULL, NULL, NULL }, /* Es */
254
	{ cond_body, pre_en, post_en, NULL, NULL }, /* En */
255
	{ NULL, pre_bk, post_bk, NULL, NULL }, /* Dx */
256
	{ NULL, NULL, post_percent, NULL, NULL }, /* %Q */
257
	{ NULL, NULL, post_percent, NULL, NULL }, /* %U */
258
	{ NULL, NULL, NULL, NULL, NULL }, /* Ta */
259
};
260
static	const struct manact *const manacts = __manacts - MDOC_Dd;
261
262
static	int		outflags;
263
#define	MMAN_spc	(1 << 0)  /* blank character before next word */
264
#define	MMAN_spc_force	(1 << 1)  /* even before trailing punctuation */
265
#define	MMAN_nl		(1 << 2)  /* break man(7) code line */
266
#define	MMAN_br		(1 << 3)  /* break output line */
267
#define	MMAN_sp		(1 << 4)  /* insert a blank output line */
268
#define	MMAN_PP		(1 << 5)  /* reset indentation etc. */
269
#define	MMAN_Sm		(1 << 6)  /* horizontal spacing mode */
270
#define	MMAN_Bk		(1 << 7)  /* word keep mode */
271
#define	MMAN_Bk_susp	(1 << 8)  /* suspend this (after a macro) */
272
#define	MMAN_An_split	(1 << 9)  /* author mode is "split" */
273
#define	MMAN_An_nosplit	(1 << 10) /* author mode is "nosplit" */
274
#define	MMAN_PD		(1 << 11) /* inter-paragraph spacing disabled */
275
#define	MMAN_nbrword	(1 << 12) /* do not break the next word */
276
277
#define	BL_STACK_MAX	32
278
279
static	int		Bl_stack[BL_STACK_MAX];  /* offsets [chars] */
280
static	int		Bl_stack_post[BL_STACK_MAX];  /* add final .RE */
281
static	int		Bl_stack_len;  /* number of nested Bl blocks */
282
static	int		TPremain;  /* characters before tag is full */
283
284
static	struct {
285
	char	*head;
286
	char	*tail;
287
	size_t	 size;
288
}	fontqueue;
289
290
291
static int
292
man_strlen(const char *cp)
293
{
294
	size_t	 rsz;
295
	int	 skip, sz;
296
297
	sz = 0;
298
	skip = 0;
299
315
	for (;;) {
300
315
		rsz = strcspn(cp, "\\");
301
315
		if (rsz) {
302
315
			cp += rsz;
303
315
			if (skip) {
304
				skip = 0;
305
				rsz--;
306
			}
307
315
			sz += rsz;
308
315
		}
309
315
		if ('\0' == *cp)
310
			break;
311
6
		cp++;
312

6
		switch (mandoc_escape(&cp, NULL, NULL)) {
313
		case ESCAPE_ERROR:
314
			return sz;
315
		case ESCAPE_UNICODE:
316
		case ESCAPE_NUMBERED:
317
		case ESCAPE_SPECIAL:
318
		case ESCAPE_OVERSTRIKE:
319
			if (skip)
320
				skip = 0;
321
			else
322
				sz++;
323
			break;
324
		case ESCAPE_SKIPCHAR:
325
			skip = 1;
326
			break;
327
		default:
328
			break;
329
		}
330
	}
331
309
	return sz;
332
309
}
333
334
static void
335
font_push(char newfont)
336
{
337
338
8076
	if (fontqueue.head + fontqueue.size <= ++fontqueue.tail) {
339
		fontqueue.size += 8;
340
		fontqueue.head = mandoc_realloc(fontqueue.head,
341
		    fontqueue.size);
342
	}
343
4038
	*fontqueue.tail = newfont;
344
4038
	print_word("");
345
4038
	printf("\\f");
346
8076
	putchar(newfont);
347
4038
	outflags &= ~MMAN_spc;
348
4038
}
349
350
static void
351
font_pop(void)
352
{
353
354
8076
	if (fontqueue.tail > fontqueue.head)
355
4038
		fontqueue.tail--;
356
4038
	outflags &= ~MMAN_spc;
357
4038
	print_word("");
358
4038
	printf("\\f");
359
8076
	putchar(*fontqueue.tail);
360
4038
}
361
362
static void
363
print_word(const char *s)
364
{
365
366
65298
	if ((MMAN_PP | MMAN_sp | MMAN_br | MMAN_nl) & outflags) {
367
		/*
368
		 * If we need a newline, print it now and start afresh.
369
		 */
370
11457
		if (MMAN_PP & outflags) {
371
891
			if (MMAN_sp & outflags) {
372
729
				if (MMAN_PD & outflags) {
373
42
					printf("\n.PD");
374
42
					outflags &= ~MMAN_PD;
375
42
				}
376
162
			} else if ( ! (MMAN_PD & outflags)) {
377
72
				printf("\n.PD 0");
378
72
				outflags |= MMAN_PD;
379
72
			}
380
891
			printf("\n.PP\n");
381
11457
		} else if (MMAN_sp & outflags)
382
126
			printf("\n.sp\n");
383
10440
		else if (MMAN_br & outflags)
384
246
			printf("\n.br\n");
385
10194
		else if (MMAN_nl & outflags)
386
20388
			putchar('\n');
387
11457
		outflags &= ~(MMAN_PP|MMAN_sp|MMAN_br|MMAN_nl|MMAN_spc);
388
11457
		if (1 == TPremain)
389
			printf(".br\n");
390
11457
		TPremain = 0;
391
32649
	} else if (MMAN_spc & outflags) {
392
		/*
393
		 * If we need a space, only print it if
394
		 * (1) it is forced by `No' or
395
		 * (2) what follows is not terminating punctuation or
396
		 * (3) what follows is longer than one character.
397
		 */
398

10485
		if (MMAN_spc_force & outflags || '\0' == s[0] ||
399
2046
		    NULL == strchr(".,:;)]?!", s[0]) || '\0' != s[1]) {
400

6504
			if (MMAN_Bk & outflags &&
401
1059
			    ! (MMAN_Bk_susp & outflags))
402
2112
				putchar('\\');
403
10890
			putchar(' ');
404
5445
			if (TPremain)
405
3
				TPremain--;
406
		}
407
	}
408
409
	/*
410
	 * Reassign needing space if we're not following opening
411
	 * punctuation.
412
	 */
413

65988
	if (MMAN_Sm & outflags && ('\0' == s[0] ||
414

43338
	    (('(' != s[0] && '[' != s[0]) || '\0' != s[1])))
415
31299
		outflags |= MMAN_spc;
416
	else
417
1350
		outflags &= ~MMAN_spc;
418
32649
	outflags &= ~(MMAN_spc_force | MMAN_Bk_susp);
419
420
390636
	for ( ; *s; s++) {
421

186966
		switch (*s) {
422
		case ASCII_NBRSP:
423
			printf("\\ ");
424
			break;
425
		case ASCII_HYPH:
426
120
			putchar('-');
427
			break;
428
		case ASCII_BREAK:
429
			printf("\\:");
430
			break;
431
		case ' ':
432
24462
			if (MMAN_nbrword & outflags) {
433
165
				printf("\\ ");
434
165
				break;
435
			}
436
			/* FALLTHROUGH */
437
		default:
438
324888
			putchar((unsigned char)*s);
439
			break;
440
		}
441
162669
		if (TPremain)
442
501
			TPremain--;
443
	}
444
32649
	outflags &= ~MMAN_nbrword;
445
32649
}
446
447
static void
448
print_line(const char *s, int newflags)
449
{
450
451
1848
	outflags |= MMAN_nl;
452
924
	print_word(s);
453
924
	outflags |= newflags;
454
924
}
455
456
static void
457
print_block(const char *s, int newflags)
458
{
459
460
4134
	outflags &= ~MMAN_PP;
461
2067
	if (MMAN_sp & outflags) {
462
1848
		outflags &= ~(MMAN_sp | MMAN_br);
463
1848
		if (MMAN_PD & outflags) {
464
81
			print_line(".PD", 0);
465
81
			outflags &= ~MMAN_PD;
466
81
		}
467
219
	} else if (! (MMAN_PD & outflags))
468
96
		print_line(".PD 0", MMAN_PD);
469
2067
	outflags |= MMAN_nl;
470
2067
	print_word(s);
471
2067
	outflags |= MMAN_Bk_susp | newflags;
472
2067
}
473
474
static void
475
print_offs(const char *v, int keywords)
476
{
477
420
	char		  buf[24];
478
210
	struct roffsu	  su;
479
	const char	 *end;
480
	int		  sz;
481
482
210
	print_line(".RS", MMAN_Bk_susp);
483
484
	/* Convert v into a number (of characters). */
485


651
	if (NULL == v || '\0' == *v || (keywords && !strcmp(v, "left")))
486
39
		sz = 0;
487

261
	else if (keywords && !strcmp(v, "indent"))
488
45
		sz = 6;
489

171
	else if (keywords && !strcmp(v, "indent-two"))
490
3
		sz = 12;
491
	else {
492
123
		end = a2roffsu(v, &su, SCALE_EN);
493

213
		if (end == NULL || *end != '\0')
494
33
			sz = man_strlen(v);
495
90
		else if (SCALE_EN == su.unit)
496
78
			sz = su.scale;
497
		else {
498
			/*
499
			 * XXX
500
			 * If we are inside an enclosing list,
501
			 * there is no easy way to add the two
502
			 * indentations because they are provided
503
			 * in terms of different units.
504
			 */
505
12
			print_word(v);
506
12
			outflags |= MMAN_nl;
507
12
			return;
508
		}
509
	}
510
511
	/*
512
	 * We are inside an enclosing list.
513
	 * Add the two indentations.
514
	 */
515
198
	if (Bl_stack_len)
516
18
		sz += Bl_stack[Bl_stack_len - 1];
517
518
198
	(void)snprintf(buf, sizeof(buf), "%dn", sz);
519
198
	print_word(buf);
520
198
	outflags |= MMAN_nl;
521
408
}
522
523
/*
524
 * Set up the indentation for a list item; used from pre_it().
525
 */
526
static void
527
print_width(const struct mdoc_bl *bl, const struct roff_node *child)
528
{
529
1008
	char		  buf[24];
530
504
	struct roffsu	  su;
531
	const char	 *end;
532
	int		  numeric, remain, sz, chsz;
533
534
	numeric = 1;
535
	remain = 0;
536
537
	/* Convert the width into a number (of characters). */
538
504
	if (bl->width == NULL)
539
3
		sz = (bl->type == LIST_hang) ? 6 : 0;
540
	else {
541
501
		end = a2roffsu(bl->width, &su, SCALE_MAX);
542

1002
		if (end == NULL || *end != '\0')
543
			sz = man_strlen(bl->width);
544
501
		else if (SCALE_EN == su.unit)
545
501
			sz = su.scale;
546
		else {
547
			sz = 0;
548
			numeric = 0;
549
		}
550
	}
551
552
	/* XXX Rough estimation, might have multiple parts. */
553
504
	if (bl->type == LIST_enum)
554
87
		chsz = (bl->count > 8) + 1;
555

597
	else if (child != NULL && child->type == ROFFT_TEXT)
556
177
		chsz = man_strlen(child->string);
557
	else
558
		chsz = 0;
559
560
	/* Maybe we are inside an enclosing list? */
561
504
	mid_it();
562
563
	/*
564
	 * Save our own indentation,
565
	 * such that child lists can use it.
566
	 */
567
504
	Bl_stack[Bl_stack_len++] = sz + 2;
568
569
	/* Set up the current list. */
570

630
	if (chsz > sz && bl->type != LIST_tag)
571
84
		print_block(".HP", 0);
572
	else {
573
420
		print_block(".TP", 0);
574
		remain = sz + 2;
575
	}
576
504
	if (numeric) {
577
504
		(void)snprintf(buf, sizeof(buf), "%dn", sz + 2);
578
504
		print_word(buf);
579
504
	} else
580
		print_word(bl->width);
581
504
	TPremain = remain;
582
504
}
583
584
static void
585
print_count(int *count)
586
{
587
174
	char		  buf[24];
588
589
87
	(void)snprintf(buf, sizeof(buf), "%d.\\&", ++*count);
590
87
	print_word(buf);
591
87
}
592
593
void
594
man_man(void *arg, const struct roff_man *man)
595
{
596
597
	/*
598
	 * Dump the keep buffer.
599
	 * We're guaranteed by now that this exists (is non-NULL).
600
	 * Flush stdout afterward, just in case.
601
	 */
602
	fputs(mparse_getkeep(man_mparse(man)), stdout);
603
	fflush(stdout);
604
}
605
606
void
607
man_mdoc(void *arg, const struct roff_man *mdoc)
608
{
609
	struct roff_node *n;
610
611
633
	printf(".TH \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"\n",
612
1266
	    mdoc->meta.title,
613
1899
	    (mdoc->meta.msec == NULL ? "" : mdoc->meta.msec),
614
633
	    mdoc->meta.date, mdoc->meta.os, mdoc->meta.vol);
615
616
	/* Disable hyphenation and if nroff, disable justification. */
617
633
	printf(".nh\n.if n .ad l");
618
619
633
	outflags = MMAN_nl | MMAN_Sm;
620
633
	if (0 == fontqueue.size) {
621
633
		fontqueue.size = 8;
622
633
		fontqueue.head = fontqueue.tail = mandoc_malloc(8);
623
633
		*fontqueue.tail = 'R';
624
633
	}
625
7872
	for (n = mdoc->first->child; n != NULL; n = n->next)
626
3303
		print_node(&mdoc->meta, n);
627
1266
	putchar('\n');
628
633
}
629
630
static void
631
print_node(DECL_ARGS)
632
{
633
	const struct manact	*act;
634
	struct roff_node	*sub;
635
	int			 cond, do_sub;
636
637
69216
	if (n->flags & NODE_NOPRT)
638
1926
		return;
639
640
	/*
641
	 * Break the line if we were parsed subsequent the current node.
642
	 * This makes the page structure be more consistent.
643
	 */
644

55965
	if (MMAN_spc & outflags && NODE_LINE & n->flags)
645
11151
		outflags |= MMAN_nl;
646
647
	act = NULL;
648
	cond = 0;
649
	do_sub = 1;
650
32682
	n->flags &= ~NODE_ENDED;
651
652
32682
	if (n->type == ROFFT_TEXT) {
653
		/*
654
		 * Make sure that we don't happen to start with a
655
		 * control character at the start of a line.
656
		 */
657

19011
		if (MMAN_nl & outflags &&
658
9423
		    ('.' == *n->string || '\'' == *n->string)) {
659
57
			print_word("");
660
57
			printf("\\&");
661
57
			outflags &= ~MMAN_spc;
662
57
		}
663
14328
		if (n->flags & NODE_DELIMC)
664
750
			outflags &= ~(MMAN_spc | MMAN_spc_force);
665
13578
		else if (outflags & MMAN_Sm)
666
13434
			outflags |= MMAN_spc_force;
667
28512
		print_word(n->string);
668
14328
		if (n->flags & NODE_DELIMO)
669
264
			outflags &= ~(MMAN_spc | MMAN_spc_force);
670
14064
		else if (outflags & MMAN_Sm)
671
13917
			outflags |= MMAN_spc;
672
18354
	} else if (n->tok < ROFF_MAX) {
673
123
		(*roff_manacts[n->tok])(meta, n);
674
123
		return;
675
	} else {
676

36462
		assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
677
		/*
678
		 * Conditionally run the pre-node action handler for a
679
		 * node.
680
		 */
681
18231
		act = manacts + n->tok;
682
42621
		cond = act->cond == NULL || (*act->cond)(meta, n);
683

32505
		if (cond && act->pre != NULL &&
684
14073
		    (n->end == ENDBODY_NOT || n->child != NULL))
685
13881
			do_sub = (*act->pre)(meta, n);
686
	}
687
688
	/*
689
	 * Conditionally run all child nodes.
690
	 * Note that this iterates over children instead of using
691
	 * recursion.  This prevents unnecessary depth in the stack.
692
	 */
693
32559
	if (do_sub)
694
123216
		for (sub = n->child; sub; sub = sub->next)
695
30723
			print_node(meta, sub);
696
697
	/*
698
	 * Lastly, conditionally run the post-node handler.
699
	 */
700
32559
	if (NODE_ENDED & n->flags)
701
99
		return;
702
703

46536
	if (cond && act->post)
704
11922
		(*act->post)(meta, n);
705
706
32460
	if (ENDBODY_NOT != n->end)
707
99
		n->body->flags |= NODE_ENDED;
708
67068
}
709
710
static int
711
cond_head(DECL_ARGS)
712
{
713
714
3780
	return n->type == ROFFT_HEAD;
715
}
716
717
static int
718
cond_body(DECL_ARGS)
719
{
720
721
8538
	return n->type == ROFFT_BODY;
722
}
723
724
static int
725
pre_enc(DECL_ARGS)
726
{
727
	const char	*prefix;
728
729
2274
	prefix = manacts[n->tok].prefix;
730
1137
	if (NULL == prefix)
731
		return 1;
732
1137
	print_word(prefix);
733
1137
	outflags &= ~MMAN_spc;
734
1137
	return 1;
735
1137
}
736
737
static void
738
post_enc(DECL_ARGS)
739
{
740
	const char *suffix;
741
742
1014
	suffix = manacts[n->tok].suffix;
743
507
	if (NULL == suffix)
744
		return;
745
507
	outflags &= ~(MMAN_spc | MMAN_nl);
746
507
	print_word(suffix);
747
1014
}
748
749
static int
750
pre_ex(DECL_ARGS)
751
{
752
108
	outflags |= MMAN_br | MMAN_nl;
753
54
	return 1;
754
}
755
756
static void
757
post_font(DECL_ARGS)
758
{
759
760
3828
	font_pop();
761
1914
}
762
763
static void
764
post_percent(DECL_ARGS)
765
{
766
767
270
	if (pre_em == manacts[n->tok].pre)
768
33
		font_pop();
769
135
	if (n->next) {
770
111
		print_word(",");
771

210
		if (n->prev &&	n->prev->tok == n->tok &&
772
6
				n->next->tok == n->tok)
773
3
			print_word("and");
774
	} else {
775
24
		print_word(".");
776
24
		outflags |= MMAN_nl;
777
	}
778
135
}
779
780
static int
781
pre__t(DECL_ARGS)
782
{
783
784

27
	if (n->parent->tok == MDOC_Rs && n->parent->norm->Rs.quote_T) {
785
6
		print_word("\\(lq");
786
6
		outflags &= ~MMAN_spc;
787
6
	} else
788
3
		font_push('I');
789
9
	return 1;
790
}
791
792
static void
793
post__t(DECL_ARGS)
794
{
795
796

27
	if (n->parent->tok  == MDOC_Rs && n->parent->norm->Rs.quote_T) {
797
6
		outflags &= ~MMAN_spc;
798
6
		print_word("\\(rq");
799
6
	} else
800
3
		font_pop();
801
9
	post_percent(meta, n);
802
9
}
803
804
/*
805
 * Print before a section header.
806
 */
807
static int
808
pre_sect(DECL_ARGS)
809
{
810
811
8568
	if (n->type == ROFFT_HEAD) {
812
1428
		outflags |= MMAN_sp;
813
1428
		print_block(manacts[n->tok].prefix, 0);
814
1428
		print_word("");
815
2856
		putchar('\"');
816
1428
		outflags &= ~MMAN_spc;
817
1428
	}
818
4284
	return 1;
819
}
820
821
/*
822
 * Print subsequent a section header.
823
 */
824
static void
825
post_sect(DECL_ARGS)
826
{
827
828
8568
	if (n->type != ROFFT_HEAD)
829
		return;
830
1428
	outflags &= ~MMAN_spc;
831
1428
	print_word("");
832
2856
	putchar('\"');
833
1428
	outflags |= MMAN_nl;
834

2820
	if (MDOC_Sh == n->tok && SEC_AUTHORS == n->sec)
835
12
		outflags &= ~(MMAN_An_split | MMAN_An_nosplit);
836
4284
}
837
838
/* See mdoc_term.c, synopsis_pre() for comments. */
839
static void
840
pre_syn(const struct roff_node *n)
841
{
842
843

1662
	if (NULL == n->prev || ! (NODE_SYNPRETTY & n->flags))
844
		return;
845
846

210
	if (n->prev->tok == n->tok &&
847
24
	    MDOC_Ft != n->tok &&
848
24
	    MDOC_Fo != n->tok &&
849
24
	    MDOC_Fn != n->tok) {
850
24
		outflags |= MMAN_br;
851
24
		return;
852
	}
853
854

225
	switch (n->prev->tok) {
855
	case MDOC_Fd:
856
	case MDOC_Fn:
857
	case MDOC_Fo:
858
	case MDOC_In:
859
	case MDOC_Vt:
860
66
		outflags |= MMAN_sp;
861
66
		break;
862
	case MDOC_Ft:
863

81
		if (MDOC_Fn != n->tok && MDOC_Fo != n->tok) {
864
			outflags |= MMAN_sp;
865
			break;
866
		}
867
		/* FALLTHROUGH */
868
	default:
869
96
		outflags |= MMAN_br;
870
96
		break;
871
	}
872
591
}
873
874
static int
875
pre_an(DECL_ARGS)
876
{
877
878
174
	switch (n->norm->An.auth) {
879
	case AUTH_split:
880
3
		outflags &= ~MMAN_An_nosplit;
881
3
		outflags |= MMAN_An_split;
882
3
		return 0;
883
	case AUTH_nosplit:
884
6
		outflags &= ~MMAN_An_split;
885
6
		outflags |= MMAN_An_nosplit;
886
6
		return 0;
887
	default:
888
78
		if (MMAN_An_split & outflags)
889
30
			outflags |= MMAN_br;
890

69
		else if (SEC_AUTHORS == n->sec &&
891
21
		    ! (MMAN_An_nosplit & outflags))
892
6
			outflags |= MMAN_An_split;
893
78
		return 1;
894
	}
895
87
}
896
897
static int
898
pre_ap(DECL_ARGS)
899
{
900
901
24
	outflags &= ~MMAN_spc;
902
12
	print_word("'");
903
12
	outflags &= ~MMAN_spc;
904
12
	return 0;
905
}
906
907
static int
908
pre_aq(DECL_ARGS)
909
{
910
911

333
	print_word(n->child != NULL && n->child->next == NULL &&
912
39
	    n->child->tok == MDOC_Mt ?  "<" : "\\(la");
913
84
	outflags &= ~MMAN_spc;
914
84
	return 1;
915
}
916
917
static void
918
post_aq(DECL_ARGS)
919
{
920
921
168
	outflags &= ~(MMAN_spc | MMAN_nl);
922

225
	print_word(n->child != NULL && n->child->next == NULL &&
923
39
	    n->child->tok == MDOC_Mt ?  ">" : "\\(ra");
924
84
}
925
926
static int
927
pre_bd(DECL_ARGS)
928
{
929
930
258
	outflags &= ~(MMAN_PP | MMAN_sp | MMAN_br);
931
932

252
	if (DISP_unfilled == n->norm->Bd.type ||
933
123
	    DISP_literal  == n->norm->Bd.type)
934
42
		print_line(".nf", 0);
935

243
	if (0 == n->norm->Bd.comp && NULL != n->parent->prev)
936
102
		outflags |= MMAN_sp;
937
129
	print_offs(n->norm->Bd.offs, 1);
938
129
	return 1;
939
}
940
941
static void
942
post_bd(DECL_ARGS)
943
{
944
945
	/* Close out this display. */
946
258
	print_line(".RE", MMAN_nl);
947

252
	if (DISP_unfilled == n->norm->Bd.type ||
948
123
	    DISP_literal  == n->norm->Bd.type)
949
42
		print_line(".fi", MMAN_nl);
950
951
	/* Maybe we are inside an enclosing list? */
952
129
	if (NULL != n->parent->next)
953
108
		mid_it();
954
129
}
955
956
static int
957
pre_bf(DECL_ARGS)
958
{
959
960
270
	switch (n->type) {
961
	case ROFFT_BLOCK:
962
45
		return 1;
963
	case ROFFT_BODY:
964
		break;
965
	default:
966
45
		return 0;
967
	}
968
45
	switch (n->norm->Bf.font) {
969
	case FONT_Em:
970
9
		font_push('I');
971
9
		break;
972
	case FONT_Sy:
973
24
		font_push('B');
974
24
		break;
975
	default:
976
12
		font_push('R');
977
12
		break;
978
	}
979
45
	return 1;
980
135
}
981
982
static void
983
post_bf(DECL_ARGS)
984
{
985
986
270
	if (n->type == ROFFT_BODY)
987
45
		font_pop();
988
135
}
989
990
static int
991
pre_bk(DECL_ARGS)
992
{
993

492
	switch (n->type) {
994
	case ROFFT_BLOCK:
995
54
		return 1;
996
	case ROFFT_BODY:
997
	case ROFFT_ELEM:
998
138
		outflags |= MMAN_Bk;
999
138
		return 1;
1000
	default:
1001
54
		return 0;
1002
	}
1003
246
}
1004
1005
static void
1006
post_bk(DECL_ARGS)
1007
{
1008
711
	switch (n->type) {
1009
	case ROFFT_ELEM:
1010
726
		while ((n = n->parent) != NULL)
1011
282
			 if (n->tok == MDOC_Bk)
1012
				return;
1013
		/* FALLTHROUGH */
1014
	case ROFFT_BODY:
1015
135
		outflags &= ~MMAN_Bk;
1016
135
		break;
1017
	default:
1018
		break;
1019
	}
1020
246
}
1021
1022
static int
1023
pre_bl(DECL_ARGS)
1024
{
1025
	size_t		 icol;
1026
1027
	/*
1028
	 * print_offs() will increase the -offset to account for
1029
	 * a possible enclosing .It, but any enclosed .It blocks
1030
	 * just nest and do not add up their indentation.
1031
	 */
1032
1062
	if (n->norm->Bl.offs) {
1033
63
		print_offs(n->norm->Bl.offs, 0);
1034
63
		Bl_stack[Bl_stack_len++] = 0;
1035
63
	}
1036
1037
531
	switch (n->norm->Bl.type) {
1038
	case LIST_enum:
1039
51
		n->norm->Bl.count = 0;
1040
51
		return 1;
1041
	case LIST_column:
1042
		break;
1043
	default:
1044
477
		return 1;
1045
	}
1046
1047
3
	if (n->child != NULL) {
1048
		print_line(".TS", MMAN_nl);
1049
		for (icol = 0; icol < n->norm->Bl.ncols; icol++)
1050
			print_word("l");
1051
		print_word(".");
1052
	}
1053
3
	outflags |= MMAN_nl;
1054
3
	return 1;
1055
531
}
1056
1057
static void
1058
post_bl(DECL_ARGS)
1059
{
1060
1061
1116
	switch (n->norm->Bl.type) {
1062
	case LIST_column:
1063
3
		if (n->child != NULL)
1064
			print_line(".TE", 0);
1065
		break;
1066
	case LIST_enum:
1067
51
		n->norm->Bl.count = 0;
1068
51
		break;
1069
	default:
1070
		break;
1071
	}
1072
1073
531
	if (n->norm->Bl.offs) {
1074
63
		print_line(".RE", MMAN_nl);
1075
63
		assert(Bl_stack_len);
1076
63
		Bl_stack_len--;
1077
63
		assert(0 == Bl_stack[Bl_stack_len]);
1078
	} else {
1079
468
		outflags |= MMAN_PP | MMAN_nl;
1080
468
		outflags &= ~(MMAN_sp | MMAN_br);
1081
	}
1082
1083
	/* Maybe we are inside an enclosing list? */
1084
531
	if (NULL != n->parent->next)
1085
441
		mid_it();
1086
1087
531
}
1088
1089
static void
1090
pre_br(DECL_ARGS)
1091
{
1092
78
	outflags |= MMAN_br;
1093
39
}
1094
1095
static int
1096
pre_dl(DECL_ARGS)
1097
{
1098
1099
36
	print_offs("6n", 0);
1100
18
	return 1;
1101
}
1102
1103
static void
1104
post_dl(DECL_ARGS)
1105
{
1106
1107
36
	print_line(".RE", MMAN_nl);
1108
1109
	/* Maybe we are inside an enclosing list? */
1110
18
	if (NULL != n->parent->next)
1111
18
		mid_it();
1112
18
}
1113
1114
static int
1115
pre_em(DECL_ARGS)
1116
{
1117
1118
1728
	font_push('I');
1119
864
	return 1;
1120
}
1121
1122
static int
1123
pre_en(DECL_ARGS)
1124
{
1125
1126

33
	if (NULL == n->norm->Es ||
1127
9
	    NULL == n->norm->Es->child)
1128
6
		return 1;
1129
1130
6
	print_word(n->norm->Es->child->string);
1131
6
	outflags &= ~MMAN_spc;
1132
6
	return 1;
1133
12
}
1134
1135
static void
1136
post_en(DECL_ARGS)
1137
{
1138
1139

30
	if (NULL == n->norm->Es ||
1140
9
	    NULL == n->norm->Es->child ||
1141
6
	    NULL == n->norm->Es->child->next)
1142
		return;
1143
1144
6
	outflags &= ~MMAN_spc;
1145
6
	print_word(n->norm->Es->child->next->string);
1146
6
	return;
1147
12
}
1148
1149
static int
1150
pre_eo(DECL_ARGS)
1151
{
1152
1153

153
	if (n->end == ENDBODY_NOT &&
1154
63
	    n->parent->head->child == NULL &&
1155
27
	    n->child != NULL &&
1156
15
	    n->child->end != ENDBODY_NOT)
1157
3
		print_word("\\&");
1158

78
	else if (n->end != ENDBODY_NOT ? n->child != NULL :
1159

96
	    n->parent->head->child != NULL && (n->child != NULL ||
1160
15
	    (n->parent->tail != NULL && n->parent->tail->child != NULL)))
1161
36
		outflags &= ~(MMAN_spc | MMAN_nl);
1162
69
	return 1;
1163
}
1164
1165
static void
1166
post_eo(DECL_ARGS)
1167
{
1168
	int	 body, tail;
1169
1170
126
	if (n->end != ENDBODY_NOT) {
1171
12
		outflags |= MMAN_spc;
1172
12
		return;
1173
	}
1174
1175
123
	body = n->child != NULL || n->parent->head->child != NULL;
1176
150
	tail = n->parent->tail != NULL && n->parent->tail->child != NULL;
1177
1178
51
	if (body && tail)
1179
24
		outflags &= ~MMAN_spc;
1180
27
	else if ( ! (body || tail))
1181
6
		print_word("\\&");
1182
21
	else if ( ! tail)
1183
15
		outflags |= MMAN_spc;
1184
114
}
1185
1186
static int
1187
pre_fa(DECL_ARGS)
1188
{
1189
	int	 am_Fa;
1190
1191
462
	am_Fa = MDOC_Fa == n->tok;
1192
1193
231
	if (am_Fa)
1194
66
		n = n->child;
1195
1196
1092
	while (NULL != n) {
1197
315
		font_push('I');
1198

546
		if (am_Fa || NODE_SYNPRETTY & n->flags)
1199
168
			outflags |= MMAN_nbrword;
1200
315
		print_node(meta, n);
1201
315
		font_pop();
1202
315
		if (NULL != (n = n->next))
1203
84
			print_word(",");
1204
	}
1205
231
	return 0;
1206
}
1207
1208
static void
1209
post_fa(DECL_ARGS)
1210
{
1211
1212

150
	if (NULL != n->next && MDOC_Fa == n->next->tok)
1213
12
		print_word(",");
1214
66
}
1215
1216
static int
1217
pre_fd(DECL_ARGS)
1218
{
1219
1220
60
	pre_syn(n);
1221
30
	font_push('B');
1222
30
	return 1;
1223
}
1224
1225
static void
1226
post_fd(DECL_ARGS)
1227
{
1228
1229
60
	font_pop();
1230
30
	outflags |= MMAN_br;
1231
30
}
1232
1233
static int
1234
pre_fl(DECL_ARGS)
1235
{
1236
1237
516
	font_push('B');
1238
258
	print_word("\\-");
1239
258
	if (n->child != NULL)
1240
201
		outflags &= ~MMAN_spc;
1241
258
	return 1;
1242
}
1243
1244
static void
1245
post_fl(DECL_ARGS)
1246
{
1247
1248
516
	font_pop();
1249

270
	if (!(n->child != NULL ||
1250
57
	    n->next == NULL ||
1251
57
	    n->next->type == ROFFT_TEXT ||
1252
12
	    n->next->flags & NODE_LINE))
1253
12
		outflags &= ~MMAN_spc;
1254
258
}
1255
1256
static int
1257
pre_fn(DECL_ARGS)
1258
{
1259
1260
402
	pre_syn(n);
1261
1262
201
	n = n->child;
1263
201
	if (NULL == n)
1264
		return 0;
1265
1266
201
	if (NODE_SYNPRETTY & n->flags)
1267
48
		print_block(".HP 4n", MMAN_nl);
1268
1269
201
	font_push('B');
1270
201
	print_node(meta, n);
1271
201
	font_pop();
1272
201
	outflags &= ~MMAN_spc;
1273
201
	print_word("(");
1274
201
	outflags &= ~MMAN_spc;
1275
1276
201
	n = n->next;
1277
201
	if (NULL != n)
1278
165
		pre_fa(meta, n);
1279
201
	return 0;
1280
201
}
1281
1282
static void
1283
post_fn(DECL_ARGS)
1284
{
1285
1286
522
	print_word(")");
1287
261
	if (NODE_SYNPRETTY & n->flags) {
1288
69
		print_word(";");
1289
69
		outflags |= MMAN_PP;
1290
69
	}
1291
261
}
1292
1293
static int
1294
pre_fo(DECL_ARGS)
1295
{
1296
1297

537
	switch (n->type) {
1298
	case ROFFT_BLOCK:
1299
60
		pre_syn(n);
1300
60
		break;
1301
	case ROFFT_HEAD:
1302
60
		if (n->child == NULL)
1303
3
			return 0;
1304
57
		if (NODE_SYNPRETTY & n->flags)
1305
21
			print_block(".HP 4n", MMAN_nl);
1306
57
		font_push('B');
1307
57
		break;
1308
	case ROFFT_BODY:
1309
60
		outflags &= ~(MMAN_spc | MMAN_nl);
1310
60
		print_word("(");
1311
60
		outflags &= ~MMAN_spc;
1312
60
		break;
1313
	default:
1314
		break;
1315
	}
1316
177
	return 1;
1317
180
}
1318
1319
static void
1320
post_fo(DECL_ARGS)
1321
{
1322
1323
480
	switch (n->type) {
1324
	case ROFFT_HEAD:
1325
60
		if (n->child != NULL)
1326
57
			font_pop();
1327
		break;
1328
	case ROFFT_BODY:
1329
60
		post_fn(meta, n);
1330
60
		break;
1331
	default:
1332
		break;
1333
	}
1334
180
}
1335
1336
static int
1337
pre_Ft(DECL_ARGS)
1338
{
1339
1340
414
	pre_syn(n);
1341
207
	font_push('I');
1342
207
	return 1;
1343
}
1344
1345
static void
1346
pre_ft(DECL_ARGS)
1347
{
1348
24
	print_line(".ft", 0);
1349
12
	print_word(n->child->string);
1350
12
	outflags |= MMAN_nl;
1351
12
}
1352
1353
static int
1354
pre_in(DECL_ARGS)
1355
{
1356
1357
72
	if (NODE_SYNPRETTY & n->flags) {
1358
18
		pre_syn(n);
1359
18
		font_push('B');
1360
18
		print_word("#include <");
1361
18
		outflags &= ~MMAN_spc;
1362
18
	} else {
1363
18
		print_word("<");
1364
18
		outflags &= ~MMAN_spc;
1365
18
		font_push('I');
1366
	}
1367
36
	return 1;
1368
}
1369
1370
static void
1371
post_in(DECL_ARGS)
1372
{
1373
1374
72
	if (NODE_SYNPRETTY & n->flags) {
1375
18
		outflags &= ~MMAN_spc;
1376
18
		print_word(">");
1377
18
		font_pop();
1378
18
		outflags |= MMAN_br;
1379
18
	} else {
1380
18
		font_pop();
1381
18
		outflags &= ~MMAN_spc;
1382
18
		print_word(">");
1383
	}
1384
36
}
1385
1386
static int
1387
pre_it(DECL_ARGS)
1388
{
1389
	const struct roff_node *bln;
1390
1391
4068
	switch (n->type) {
1392
	case ROFFT_HEAD:
1393
678
		outflags |= MMAN_PP | MMAN_nl;
1394
678
		bln = n->parent->parent;
1395

720
		if (0 == bln->norm->Bl.comp ||
1396
165
		    (NULL == n->parent->prev &&
1397
42
		     NULL == bln->parent->prev))
1398
513
			outflags |= MMAN_sp;
1399
678
		outflags &= ~MMAN_br;
1400


678
		switch (bln->norm->Bl.type) {
1401
		case LIST_item:
1402
63
			return 0;
1403
		case LIST_inset:
1404
		case LIST_diag:
1405
		case LIST_ohang:
1406
111
			if (bln->norm->Bl.type == LIST_diag)
1407
36
				print_line(".B \"", 0);
1408
			else
1409
75
				print_line(".R \"", 0);
1410
111
			outflags &= ~MMAN_spc;
1411
111
			return 1;
1412
		case LIST_bullet:
1413
		case LIST_dash:
1414
		case LIST_hyphen:
1415
237
			print_width(&bln->norm->Bl, NULL);
1416
237
			TPremain = 0;
1417
237
			outflags |= MMAN_nl;
1418
237
			font_push('B');
1419
237
			if (LIST_bullet == bln->norm->Bl.type)
1420
117
				print_word("\\(bu");
1421
			else
1422
120
				print_word("-");
1423
237
			font_pop();
1424
237
			outflags |= MMAN_nl;
1425
237
			return 0;
1426
		case LIST_enum:
1427
87
			print_width(&bln->norm->Bl, NULL);
1428
87
			TPremain = 0;
1429
87
			outflags |= MMAN_nl;
1430
87
			print_count(&bln->norm->Bl.count);
1431
87
			outflags |= MMAN_nl;
1432
87
			return 0;
1433
		case LIST_hang:
1434
69
			print_width(&bln->norm->Bl, n->child);
1435
69
			TPremain = 0;
1436
69
			outflags |= MMAN_nl;
1437
69
			return 1;
1438
		case LIST_tag:
1439
111
			print_width(&bln->norm->Bl, n->child);
1440
222
			putchar('\n');
1441
111
			outflags &= ~MMAN_spc;
1442
111
			return 1;
1443
		default:
1444
			return 1;
1445
		}
1446
	default:
1447
		break;
1448
	}
1449
1356
	return 1;
1450
2034
}
1451
1452
/*
1453
 * This function is called after closing out an indented block.
1454
 * If we are inside an enclosing list, restore its indentation.
1455
 */
1456
static void
1457
mid_it(void)
1458
{
1459
2142
	char		 buf[24];
1460
1461
	/* Nothing to do outside a list. */
1462

1149
	if (0 == Bl_stack_len || 0 == Bl_stack[Bl_stack_len - 1])
1463
1029
		return;
1464
1465
	/* The indentation has already been set up. */
1466
42
	if (Bl_stack_post[Bl_stack_len - 1])
1467
15
		return;
1468
1469
	/* Restore the indentation of the enclosing list. */
1470
27
	print_line(".RS", MMAN_Bk_susp);
1471
54
	(void)snprintf(buf, sizeof(buf), "%dn",
1472
27
	    Bl_stack[Bl_stack_len - 1]);
1473
27
	print_word(buf);
1474
1475
	/* Remeber to close out this .RS block later. */
1476
27
	Bl_stack_post[Bl_stack_len - 1] = 1;
1477
1098
}
1478
1479
static void
1480
post_it(DECL_ARGS)
1481
{
1482
	const struct roff_node *bln;
1483
1484
4068
	bln = n->parent->parent;
1485
1486
2034
	switch (n->type) {
1487
	case ROFFT_HEAD:
1488
735
		switch (bln->norm->Bl.type) {
1489
		case LIST_diag:
1490
36
			outflags &= ~MMAN_spc;
1491
36
			print_word("\\ ");
1492
36
			break;
1493
		case LIST_ohang:
1494
21
			outflags |= MMAN_br;
1495
21
			break;
1496
		default:
1497
			break;
1498
		}
1499
		break;
1500
	case ROFFT_BODY:
1501


1182
		switch (bln->norm->Bl.type) {
1502
		case LIST_bullet:
1503
		case LIST_dash:
1504
		case LIST_hyphen:
1505
		case LIST_enum:
1506
		case LIST_hang:
1507
		case LIST_tag:
1508
504
			assert(Bl_stack_len);
1509
504
			Bl_stack[--Bl_stack_len] = 0;
1510
1511
			/*
1512
			 * Our indentation had to be restored
1513
			 * after a child display or child list.
1514
			 * Close out that indentation block now.
1515
			 */
1516
504
			if (Bl_stack_post[Bl_stack_len]) {
1517
27
				print_line(".RE", MMAN_nl);
1518
27
				Bl_stack_post[Bl_stack_len] = 0;
1519
27
			}
1520
			break;
1521
		case LIST_column:
1522
			if (NULL != n->next) {
1523
				putchar('\t');
1524
				outflags &= ~MMAN_spc;
1525
			}
1526
			break;
1527
		default:
1528
			break;
1529
		}
1530
		break;
1531
	default:
1532
		break;
1533
	}
1534
2034
}
1535
1536
static void
1537
post_lb(DECL_ARGS)
1538
{
1539
1540
30
	if (SEC_LIBRARY == n->sec)
1541
9
		outflags |= MMAN_br;
1542
15
}
1543
1544
static int
1545
pre_lk(DECL_ARGS)
1546
{
1547
	const struct roff_node *link, *descr, *punct;
1548
	int display;
1549
1550
66
	if ((link = n->child) == NULL)
1551
		return 0;
1552
1553
	/* Find beginning of trailing punctuation. */
1554
33
	punct = n->last;
1555

153
	while (punct != link && punct->flags & NODE_DELIMC)
1556
6
		punct = punct->prev;
1557
33
	punct = punct->next;
1558
1559
	/* Link text. */
1560

63
	if ((descr = link->next) != NULL && descr != punct) {
1561
30
		font_push('I');
1562
138
		while (descr != punct) {
1563
39
			print_word(descr->string);
1564
39
			descr = descr->next;
1565
		}
1566
30
		font_pop();
1567
30
		print_word(":");
1568
30
	}
1569
1570
	/* Link target. */
1571
33
	display = man_strlen(link->string) >= 26;
1572
33
	if (display) {
1573
3
		print_line(".RS", MMAN_Bk_susp);
1574
3
		print_word("6n");
1575
3
		outflags |= MMAN_nl;
1576
3
	}
1577
33
	font_push('B');
1578
33
	print_word(link->string);
1579
33
	font_pop();
1580
1581
	/* Trailing punctuation. */
1582
78
	while (punct != NULL) {
1583
6
		print_word(punct->string);
1584
6
		punct = punct->next;
1585
	}
1586
33
	if (display)
1587
3
		print_line(".RE", MMAN_nl);
1588
33
	return 0;
1589
33
}
1590
1591
static void
1592
pre_onearg(DECL_ARGS)
1593
{
1594
24
	outflags |= MMAN_nl;
1595
12
	print_word(".");
1596
12
	outflags &= ~MMAN_spc;
1597
12
	print_word(roff_name[n->tok]);
1598
12
	if (n->child != NULL)
1599
9
		print_word(n->child->string);
1600
12
	outflags |= MMAN_nl;
1601
12
	if (n->tok == ROFF_ce)
1602
		for (n = n->child->next; n != NULL; n = n->next)
1603
			print_node(meta, n);
1604
12
}
1605
1606
static int
1607
pre_li(DECL_ARGS)
1608
{
1609
1610
594
	font_push('R');
1611
297
	return 1;
1612
}
1613
1614
static int
1615
pre_nm(DECL_ARGS)
1616
{
1617
	char	*name;
1618
1619
1890
	if (n->type == ROFFT_BLOCK) {
1620
66
		outflags |= MMAN_Bk;
1621
66
		pre_syn(n);
1622
66
	}
1623

1143
	if (n->type != ROFFT_ELEM && n->type != ROFFT_HEAD)
1624
132
		return 1;
1625
2421
	name = n->child == NULL ? NULL : n->child->string;
1626
813
	if (NULL == name)
1627
18
		return 0;
1628
795
	if (n->type == ROFFT_HEAD) {
1629
66
		if (NULL == n->parent->prev)
1630
24
			outflags |= MMAN_sp;
1631
66
		print_block(".HP", 0);
1632
66
		printf(" %dn", man_strlen(name) + 1);
1633
66
		outflags |= MMAN_nl;
1634
66
	}
1635
795
	font_push('B');
1636
795
	return 1;
1637
945
}
1638
1639
static void
1640
post_nm(DECL_ARGS)
1641
{
1642
1643

2769
	switch (n->type) {
1644
	case ROFFT_BLOCK:
1645
66
		outflags &= ~MMAN_Bk;
1646
66
		break;
1647
	case ROFFT_HEAD:
1648
	case ROFFT_ELEM:
1649

1608
		if (n->child != NULL && n->child->string != NULL)
1650
795
			font_pop();
1651
		break;
1652
	default:
1653
		break;
1654
	}
1655
945
}
1656
1657
static int
1658
pre_no(DECL_ARGS)
1659
{
1660
1661
816
	outflags |= MMAN_spc_force;
1662
408
	return 1;
1663
}
1664
1665
static int
1666
pre_ns(DECL_ARGS)
1667
{
1668
1669
162
	outflags &= ~MMAN_spc;
1670
81
	return 0;
1671
}
1672
1673
static void
1674
post_pf(DECL_ARGS)
1675
{
1676
1677

84
	if ( ! (n->next == NULL || n->next->flags & NODE_LINE))
1678
18
		outflags &= ~MMAN_spc;
1679
30
}
1680
1681
static int
1682
pre_pp(DECL_ARGS)
1683
{
1684
1685
1110
	if (MDOC_It != n->parent->tok)
1686
555
		outflags |= MMAN_PP;
1687
555
	outflags |= MMAN_sp | MMAN_nl;
1688
555
	outflags &= ~MMAN_br;
1689
555
	return 0;
1690
}
1691
1692
static int
1693
pre_rs(DECL_ARGS)
1694
{
1695
1696
60
	if (SEC_SEE_ALSO == n->sec) {
1697
18
		outflags |= MMAN_PP | MMAN_sp | MMAN_nl;
1698
18
		outflags &= ~MMAN_br;
1699
18
	}
1700
30
	return 1;
1701
}
1702
1703
static int
1704
pre_skip(DECL_ARGS)
1705
{
1706
1707
30
	return 0;
1708
}
1709
1710
static int
1711
pre_sm(DECL_ARGS)
1712
{
1713
1714
300
	if (NULL == n->child)
1715
15
		outflags ^= MMAN_Sm;
1716
270
	else if (0 == strcmp("on", n->child->string))
1717
135
		outflags |= MMAN_Sm;
1718
	else
1719
135
		outflags &= ~MMAN_Sm;
1720
1721
150
	if (MMAN_Sm & outflags)
1722
78
		outflags |= MMAN_spc;
1723
1724
150
	return 0;
1725
}
1726
1727
static void
1728
pre_sp(DECL_ARGS)
1729
{
1730
120
	if (outflags & MMAN_PP) {
1731
		outflags &= ~MMAN_PP;
1732
		print_line(".PP", 0);
1733
	} else {
1734
60
		print_line(".sp", 0);
1735
60
		if (n->child != NULL)
1736
12
			print_word(n->child->string);
1737
	}
1738
60
	outflags |= MMAN_nl;
1739
60
}
1740
1741
static int
1742
pre_sy(DECL_ARGS)
1743
{
1744
1745
1158
	font_push('B');
1746
579
	return 1;
1747
}
1748
1749
static void
1750
pre_ta(DECL_ARGS)
1751
{
1752
	print_line(".ta", 0);
1753
	for (n = n->child; n != NULL; n = n->next)
1754
		print_word(n->string);
1755
	outflags |= MMAN_nl;
1756
}
1757
1758
static int
1759
pre_vt(DECL_ARGS)
1760
{
1761
1762
138
	if (NODE_SYNPRETTY & n->flags) {
1763
51
		switch (n->type) {
1764
		case ROFFT_BLOCK:
1765
9
			pre_syn(n);
1766
9
			return 1;
1767
		case ROFFT_BODY:
1768
			break;
1769
		default:
1770
9
			return 0;
1771
		}
1772
	}
1773
51
	font_push('I');
1774
51
	return 1;
1775
69
}
1776
1777
static void
1778
post_vt(DECL_ARGS)
1779
{
1780
1781

165
	if (n->flags & NODE_SYNPRETTY && n->type != ROFFT_BODY)
1782
		return;
1783
51
	font_pop();
1784
120
}
1785
1786
static int
1787
pre_xr(DECL_ARGS)
1788
{
1789
1790
72
	n = n->child;
1791
36
	if (NULL == n)
1792
		return 0;
1793
36
	print_node(meta, n);
1794
36
	n = n->next;
1795
36
	if (NULL == n)
1796
6
		return 0;
1797
30
	outflags &= ~MMAN_spc;
1798
30
	print_word("(");
1799
30
	print_node(meta, n);
1800
30
	print_word(")");
1801
30
	return 0;
1802
36
}