GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/mandoc/mdoc_man.c Lines: 700 742 94.3 %
Date: 2017-11-07 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
927
	for (;;) {
300
945
		rsz = strcspn(cp, "\\");
301
945
		if (rsz) {
302
945
			cp += rsz;
303
945
			if (skip) {
304
				skip = 0;
305
				rsz--;
306
			}
307
945
			sz += rsz;
308
945
		}
309
945
		if ('\0' == *cp)
310
			break;
311
18
		cp++;
312

18
		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
927
	return sz;
332
927
}
333
334
static void
335
font_push(char newfont)
336
{
337
338
24228
	if (fontqueue.head + fontqueue.size <= ++fontqueue.tail) {
339
		fontqueue.size += 8;
340
		fontqueue.head = mandoc_realloc(fontqueue.head,
341
		    fontqueue.size);
342
	}
343
12114
	*fontqueue.tail = newfont;
344
12114
	print_word("");
345
12114
	printf("\\f");
346
24228
	putchar(newfont);
347
12114
	outflags &= ~MMAN_spc;
348
12114
}
349
350
static void
351
font_pop(void)
352
{
353
354
24228
	if (fontqueue.tail > fontqueue.head)
355
12114
		fontqueue.tail--;
356
12114
	outflags &= ~MMAN_spc;
357
12114
	print_word("");
358
12114
	printf("\\f");
359
24228
	putchar(*fontqueue.tail);
360
12114
}
361
362
static void
363
print_word(const char *s)
364
{
365
366
195894
	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
34371
		if (MMAN_PP & outflags) {
371
2673
			if (MMAN_sp & outflags) {
372
2187
				if (MMAN_PD & outflags) {
373
126
					printf("\n.PD");
374
126
					outflags &= ~MMAN_PD;
375
126
				}
376
486
			} else if ( ! (MMAN_PD & outflags)) {
377
216
				printf("\n.PD 0");
378
216
				outflags |= MMAN_PD;
379
216
			}
380
2673
			printf("\n.PP\n");
381
34371
		} else if (MMAN_sp & outflags)
382
378
			printf("\n.sp\n");
383
31320
		else if (MMAN_br & outflags)
384
738
			printf("\n.br\n");
385
30582
		else if (MMAN_nl & outflags)
386
61164
			putchar('\n');
387
34371
		outflags &= ~(MMAN_PP|MMAN_sp|MMAN_br|MMAN_nl|MMAN_spc);
388
34371
		if (1 == TPremain)
389
			printf(".br\n");
390
34371
		TPremain = 0;
391
97947
	} 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

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

19512
			if (MMAN_Bk & outflags &&
401
3177
			    ! (MMAN_Bk_susp & outflags))
402
6336
				putchar('\\');
403
32670
			putchar(' ');
404
16335
			if (TPremain)
405
9
				TPremain--;
406
		}
407
	}
408
409
	/*
410
	 * Reassign needing space if we're not following opening
411
	 * punctuation.
412
	 */
413

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

130014
	    (('(' != s[0] && '[' != s[0]) || '\0' != s[1])))
415
93897
		outflags |= MMAN_spc;
416
	else
417
4050
		outflags &= ~MMAN_spc;
418
97947
	outflags &= ~(MMAN_spc_force | MMAN_Bk_susp);
419
420
1171908
	for ( ; *s; s++) {
421

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


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

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

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

639
		if (end == NULL || *end != '\0')
494
99
			sz = man_strlen(v);
495
270
		else if (SCALE_EN == su.unit)
496
234
			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
36
			print_word(v);
506
36
			outflags |= MMAN_nl;
507
36
			return;
508
		}
509
	}
510
511
	/*
512
	 * We are inside an enclosing list.
513
	 * Add the two indentations.
514
	 */
515
594
	if (Bl_stack_len)
516
54
		sz += Bl_stack[Bl_stack_len - 1];
517
518
594
	(void)snprintf(buf, sizeof(buf), "%dn", sz);
519
594
	print_word(buf);
520
594
	outflags |= MMAN_nl;
521
1224
}
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
3024
	char		  buf[24];
530
1512
	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
1512
	if (bl->width == NULL)
539
9
		sz = (bl->type == LIST_hang) ? 6 : 0;
540
	else {
541
1503
		end = a2roffsu(bl->width, &su, SCALE_MAX);
542

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

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

1890
	if (chsz > sz && bl->type != LIST_tag)
571
252
		print_block(".HP", 0);
572
	else {
573
1260
		print_block(".TP", 0);
574
		remain = sz + 2;
575
	}
576
1512
	if (numeric) {
577
1512
		(void)snprintf(buf, sizeof(buf), "%dn", sz + 2);
578
1512
		print_word(buf);
579
1512
	} else
580
		print_word(bl->width);
581
1512
	TPremain = remain;
582
1512
}
583
584
static void
585
print_count(int *count)
586
{
587
522
	char		  buf[24];
588
589
261
	(void)snprintf(buf, sizeof(buf), "%d.\\&", ++*count);
590
261
	print_word(buf);
591
261
}
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
1899
	printf(".TH \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"\n",
612
3798
	    mdoc->meta.title,
613
5697
	    (mdoc->meta.msec == NULL ? "" : mdoc->meta.msec),
614
1899
	    mdoc->meta.date, mdoc->meta.os, mdoc->meta.vol);
615
616
	/* Disable hyphenation and if nroff, disable justification. */
617
1899
	printf(".nh\n.if n .ad l");
618
619
1899
	outflags = MMAN_nl | MMAN_Sm;
620
1899
	if (0 == fontqueue.size) {
621
1899
		fontqueue.size = 8;
622
1899
		fontqueue.head = fontqueue.tail = mandoc_malloc(8);
623
1899
		*fontqueue.tail = 'R';
624
1899
	}
625
23616
	for (n = mdoc->first->child; n != NULL; n = n->next)
626
9909
		print_node(&mdoc->meta, n);
627
3798
	putchar('\n');
628
1899
}
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
207648
	if (n->flags & NODE_NOPRT)
638
5778
		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

167895
	if (MMAN_spc & outflags && NODE_LINE & n->flags)
645
33453
		outflags |= MMAN_nl;
646
647
	act = NULL;
648
	cond = 0;
649
	do_sub = 1;
650
98046
	n->flags &= ~NODE_ENDED;
651
652
98046
	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

57033
		if (MMAN_nl & outflags &&
658
28269
		    ('.' == *n->string || '\'' == *n->string)) {
659
171
			print_word("");
660
171
			printf("\\&");
661
171
			outflags &= ~MMAN_spc;
662
171
		}
663
42984
		if (n->flags & NODE_DELIMC)
664
2250
			outflags &= ~(MMAN_spc | MMAN_spc_force);
665
40734
		else if (outflags & MMAN_Sm)
666
40302
			outflags |= MMAN_spc_force;
667
85536
		print_word(n->string);
668
42984
		if (n->flags & NODE_DELIMO)
669
792
			outflags &= ~(MMAN_spc | MMAN_spc_force);
670
42192
		else if (outflags & MMAN_Sm)
671
41751
			outflags |= MMAN_spc;
672
55062
	} else if (n->tok < ROFF_MAX) {
673
369
		(*roff_manacts[n->tok])(meta, n);
674
369
		return;
675
	} else {
676

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

97515
		if (cond && act->pre != NULL &&
684
42219
		    (n->end == ENDBODY_NOT || n->child != NULL))
685
41643
			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
97677
	if (do_sub)
694
369648
		for (sub = n->child; sub; sub = sub->next)
695
92169
			print_node(meta, sub);
696
697
	/*
698
	 * Lastly, conditionally run the post-node handler.
699
	 */
700
97677
	if (NODE_ENDED & n->flags)
701
297
		return;
702
703

139608
	if (cond && act->post)
704
35766
		(*act->post)(meta, n);
705
706
97380
	if (ENDBODY_NOT != n->end)
707
297
		n->body->flags |= NODE_ENDED;
708
201204
}
709
710
static int
711
cond_head(DECL_ARGS)
712
{
713
714
11340
	return n->type == ROFFT_HEAD;
715
}
716
717
static int
718
cond_body(DECL_ARGS)
719
{
720
721
25614
	return n->type == ROFFT_BODY;
722
}
723
724
static int
725
pre_enc(DECL_ARGS)
726
{
727
	const char	*prefix;
728
729
6822
	prefix = manacts[n->tok].prefix;
730
3411
	if (NULL == prefix)
731
		return 1;
732
3411
	print_word(prefix);
733
3411
	outflags &= ~MMAN_spc;
734
3411
	return 1;
735
3411
}
736
737
static void
738
post_enc(DECL_ARGS)
739
{
740
	const char *suffix;
741
742
3042
	suffix = manacts[n->tok].suffix;
743
1521
	if (NULL == suffix)
744
		return;
745
1521
	outflags &= ~(MMAN_spc | MMAN_nl);
746
1521
	print_word(suffix);
747
3042
}
748
749
static int
750
pre_ex(DECL_ARGS)
751
{
752
324
	outflags |= MMAN_br | MMAN_nl;
753
162
	return 1;
754
}
755
756
static void
757
post_font(DECL_ARGS)
758
{
759
760
11484
	font_pop();
761
5742
}
762
763
static void
764
post_percent(DECL_ARGS)
765
{
766
767
810
	if (pre_em == manacts[n->tok].pre)
768
99
		font_pop();
769
405
	if (n->next) {
770
333
		print_word(",");
771

630
		if (n->prev &&	n->prev->tok == n->tok &&
772
18
				n->next->tok == n->tok)
773
9
			print_word("and");
774
	} else {
775
72
		print_word(".");
776
72
		outflags |= MMAN_nl;
777
	}
778
405
}
779
780
static int
781
pre__t(DECL_ARGS)
782
{
783
784

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

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

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

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

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

675
	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
198
		outflags |= MMAN_sp;
861
198
		break;
862
	case MDOC_Ft:
863

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

207
		else if (SEC_AUTHORS == n->sec &&
891
63
		    ! (MMAN_An_nosplit & outflags))
892
18
			outflags |= MMAN_An_split;
893
234
		return 1;
894
	}
895
261
}
896
897
static int
898
pre_ap(DECL_ARGS)
899
{
900
901
72
	outflags &= ~MMAN_spc;
902
36
	print_word("'");
903
36
	outflags &= ~MMAN_spc;
904
36
	return 0;
905
}
906
907
static int
908
pre_aq(DECL_ARGS)
909
{
910
911

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

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

756
	if (DISP_unfilled == n->norm->Bd.type ||
933
369
	    DISP_literal  == n->norm->Bd.type)
934
126
		print_line(".nf", 0);
935

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

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

1476
	switch (n->type) {
994
	case ROFFT_BLOCK:
995
162
		return 1;
996
	case ROFFT_BODY:
997
	case ROFFT_ELEM:
998
414
		outflags |= MMAN_Bk;
999
414
		return 1;
1000
	default:
1001
162
		return 0;
1002
	}
1003
738
}
1004
1005
static void
1006
post_bk(DECL_ARGS)
1007
{
1008
2970
	switch (n->type) {
1009
	case ROFFT_ELEM:
1010
1089
		while ((n = n->parent) != NULL)
1011
846
			 if (n->tok == MDOC_Bk)
1012
				return;
1013
		/* FALLTHROUGH */
1014
	case ROFFT_BODY:
1015
405
		outflags &= ~MMAN_Bk;
1016
405
		break;
1017
	default:
1018
		break;
1019
	}
1020
738
}
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
3186
	if (n->norm->Bl.offs) {
1033
189
		print_offs(n->norm->Bl.offs, 0);
1034
189
		Bl_stack[Bl_stack_len++] = 0;
1035
189
	}
1036
1037
1593
	switch (n->norm->Bl.type) {
1038
	case LIST_enum:
1039
153
		n->norm->Bl.count = 0;
1040
153
		return 1;
1041
	case LIST_column:
1042
		break;
1043
	default:
1044
1431
		return 1;
1045
	}
1046
1047
9
	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
9
	outflags |= MMAN_nl;
1054
9
	return 1;
1055
1593
}
1056
1057
static void
1058
post_bl(DECL_ARGS)
1059
{
1060
1061
3348
	switch (n->norm->Bl.type) {
1062
	case LIST_column:
1063
9
		if (n->child != NULL)
1064
			print_line(".TE", 0);
1065
		break;
1066
	case LIST_enum:
1067
153
		n->norm->Bl.count = 0;
1068
153
		break;
1069
	default:
1070
		break;
1071
	}
1072
1073
1593
	if (n->norm->Bl.offs) {
1074
189
		print_line(".RE", MMAN_nl);
1075
189
		assert(Bl_stack_len);
1076
189
		Bl_stack_len--;
1077
189
		assert(0 == Bl_stack[Bl_stack_len]);
1078
	} else {
1079
1404
		outflags |= MMAN_PP | MMAN_nl;
1080
1404
		outflags &= ~(MMAN_sp | MMAN_br);
1081
	}
1082
1083
	/* Maybe we are inside an enclosing list? */
1084
1593
	if (NULL != n->parent->next)
1085
1323
		mid_it();
1086
1087
1593
}
1088
1089
static void
1090
pre_br(DECL_ARGS)
1091
{
1092
234
	outflags |= MMAN_br;
1093
117
}
1094
1095
static int
1096
pre_dl(DECL_ARGS)
1097
{
1098
1099
108
	print_offs("6n", 0);
1100
54
	return 1;
1101
}
1102
1103
static void
1104
post_dl(DECL_ARGS)
1105
{
1106
1107
108
	print_line(".RE", MMAN_nl);
1108
1109
	/* Maybe we are inside an enclosing list? */
1110
54
	if (NULL != n->parent->next)
1111
54
		mid_it();
1112
54
}
1113
1114
static int
1115
pre_em(DECL_ARGS)
1116
{
1117
1118
5184
	font_push('I');
1119
2592
	return 1;
1120
}
1121
1122
static int
1123
pre_en(DECL_ARGS)
1124
{
1125
1126

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

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

459
	if (n->end == ENDBODY_NOT &&
1154
189
	    n->parent->head->child == NULL &&
1155
81
	    n->child != NULL &&
1156
45
	    n->child->end != ENDBODY_NOT)
1157
9
		print_word("\\&");
1158

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

288
	    n->parent->head->child != NULL && (n->child != NULL ||
1160
45
	    (n->parent->tail != NULL && n->parent->tail->child != NULL)))
1161
108
		outflags &= ~(MMAN_spc | MMAN_nl);
1162
207
	return 1;
1163
}
1164
1165
static void
1166
post_eo(DECL_ARGS)
1167
{
1168
	int	 body, tail;
1169
1170
378
	if (n->end != ENDBODY_NOT) {
1171
36
		outflags |= MMAN_spc;
1172
36
		return;
1173
	}
1174
1175
369
	body = n->child != NULL || n->parent->head->child != NULL;
1176
450
	tail = n->parent->tail != NULL && n->parent->tail->child != NULL;
1177
1178
153
	if (body && tail)
1179
72
		outflags &= ~MMAN_spc;
1180
81
	else if ( ! (body || tail))
1181
18
		print_word("\\&");
1182
63
	else if ( ! tail)
1183
45
		outflags |= MMAN_spc;
1184
342
}
1185
1186
static int
1187
pre_fa(DECL_ARGS)
1188
{
1189
	int	 am_Fa;
1190
1191
1386
	am_Fa = MDOC_Fa == n->tok;
1192
1193
693
	if (am_Fa)
1194
198
		n = n->child;
1195
1196
1638
	while (NULL != n) {
1197
945
		font_push('I');
1198

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

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

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

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

2160
		if (0 == bln->norm->Bl.comp ||
1396
495
		    (NULL == n->parent->prev &&
1397
126
		     NULL == bln->parent->prev))
1398
1539
			outflags |= MMAN_sp;
1399
2034
		outflags &= ~MMAN_br;
1400


2034
		switch (bln->norm->Bl.type) {
1401
		case LIST_item:
1402
189
			return 0;
1403
		case LIST_inset:
1404
		case LIST_diag:
1405
		case LIST_ohang:
1406
333
			if (bln->norm->Bl.type == LIST_diag)
1407
108
				print_line(".B \"", 0);
1408
			else
1409
225
				print_line(".R \"", 0);
1410
333
			outflags &= ~MMAN_spc;
1411
333
			return 1;
1412
		case LIST_bullet:
1413
		case LIST_dash:
1414
		case LIST_hyphen:
1415
711
			print_width(&bln->norm->Bl, NULL);
1416
711
			TPremain = 0;
1417
711
			outflags |= MMAN_nl;
1418
711
			font_push('B');
1419
711
			if (LIST_bullet == bln->norm->Bl.type)
1420
351
				print_word("\\(bu");
1421
			else
1422
360
				print_word("-");
1423
711
			font_pop();
1424
711
			outflags |= MMAN_nl;
1425
711
			return 0;
1426
		case LIST_enum:
1427
261
			print_width(&bln->norm->Bl, NULL);
1428
261
			TPremain = 0;
1429
261
			outflags |= MMAN_nl;
1430
261
			print_count(&bln->norm->Bl.count);
1431
261
			outflags |= MMAN_nl;
1432
261
			return 0;
1433
		case LIST_hang:
1434
207
			print_width(&bln->norm->Bl, n->child);
1435
207
			TPremain = 0;
1436
207
			outflags |= MMAN_nl;
1437
207
			return 1;
1438
		case LIST_tag:
1439
333
			print_width(&bln->norm->Bl, n->child);
1440
666
			putchar('\n');
1441
333
			outflags &= ~MMAN_spc;
1442
333
			return 1;
1443
		default:
1444
			return 1;
1445
		}
1446
	default:
1447
		break;
1448
	}
1449
4068
	return 1;
1450
6102
}
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
6426
	char		 buf[24];
1460
1461
	/* Nothing to do outside a list. */
1462

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


3546
		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
1512
			assert(Bl_stack_len);
1509
1512
			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
1512
			if (Bl_stack_post[Bl_stack_len]) {
1517
81
				print_line(".RE", MMAN_nl);
1518
81
				Bl_stack_post[Bl_stack_len] = 0;
1519
81
			}
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
6102
}
1535
1536
static void
1537
post_lb(DECL_ARGS)
1538
{
1539
1540
90
	if (SEC_LIBRARY == n->sec)
1541
27
		outflags |= MMAN_br;
1542
45
}
1543
1544
static int
1545
pre_lk(DECL_ARGS)
1546
{
1547
	const struct roff_node *link, *descr, *punct;
1548
	int display;
1549
1550
198
	if ((link = n->child) == NULL)
1551
		return 0;
1552
1553
	/* Find beginning of trailing punctuation. */
1554
99
	punct = n->last;
1555

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

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

3429
	if (n->type != ROFFT_ELEM && n->type != ROFFT_HEAD)
1624
396
		return 1;
1625
7263
	name = n->child == NULL ? NULL : n->child->string;
1626
2439
	if (NULL == name)
1627
54
		return 0;
1628
2385
	if (n->type == ROFFT_HEAD) {
1629
198
		if (NULL == n->parent->prev)
1630
72
			outflags |= MMAN_sp;
1631
198
		print_block(".HP", 0);
1632
198
		printf(" %dn", man_strlen(name) + 1);
1633
198
		outflags |= MMAN_nl;
1634
198
	}
1635
2385
	font_push('B');
1636
2385
	return 1;
1637
2835
}
1638
1639
static void
1640
post_nm(DECL_ARGS)
1641
{
1642
1643

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

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

252
	if ( ! (n->next == NULL || n->next->flags & NODE_LINE))
1678
54
		outflags &= ~MMAN_spc;
1679
90
}
1680
1681
static int
1682
pre_pp(DECL_ARGS)
1683
{
1684
1685
3330
	if (MDOC_It != n->parent->tok)
1686
1665
		outflags |= MMAN_PP;
1687
1665
	outflags |= MMAN_sp | MMAN_nl;
1688
1665
	outflags &= ~MMAN_br;
1689
1665
	return 0;
1690
}
1691
1692
static int
1693
pre_rs(DECL_ARGS)
1694
{
1695
1696
180
	if (SEC_SEE_ALSO == n->sec) {
1697
54
		outflags |= MMAN_PP | MMAN_sp | MMAN_nl;
1698
54
		outflags &= ~MMAN_br;
1699
54
	}
1700
90
	return 1;
1701
}
1702
1703
static int
1704
pre_skip(DECL_ARGS)
1705
{
1706
1707
90
	return 0;
1708
}
1709
1710
static int
1711
pre_sm(DECL_ARGS)
1712
{
1713
1714
900
	if (NULL == n->child)
1715
45
		outflags ^= MMAN_Sm;
1716
810
	else if (0 == strcmp("on", n->child->string))
1717
405
		outflags |= MMAN_Sm;
1718
	else
1719
405
		outflags &= ~MMAN_Sm;
1720
1721
450
	if (MMAN_Sm & outflags)
1722
234
		outflags |= MMAN_spc;
1723
1724
450
	return 0;
1725
}
1726
1727
static void
1728
pre_sp(DECL_ARGS)
1729
{
1730
360
	if (outflags & MMAN_PP) {
1731
		outflags &= ~MMAN_PP;
1732
		print_line(".PP", 0);
1733
	} else {
1734
180
		print_line(".sp", 0);
1735
180
		if (n->child != NULL)
1736
36
			print_word(n->child->string);
1737
	}
1738
180
	outflags |= MMAN_nl;
1739
180
}
1740
1741
static int
1742
pre_sy(DECL_ARGS)
1743
{
1744
1745
3474
	font_push('B');
1746
1737
	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
414
	if (NODE_SYNPRETTY & n->flags) {
1763
153
		switch (n->type) {
1764
		case ROFFT_BLOCK:
1765
27
			pre_syn(n);
1766
27
			return 1;
1767
		case ROFFT_BODY:
1768
			break;
1769
		default:
1770
27
			return 0;
1771
		}
1772
	}
1773
153
	font_push('I');
1774
153
	return 1;
1775
207
}
1776
1777
static void
1778
post_vt(DECL_ARGS)
1779
{
1780
1781

495
	if (n->flags & NODE_SYNPRETTY && n->type != ROFFT_BODY)
1782
		return;
1783
153
	font_pop();
1784
360
}
1785
1786
static int
1787
pre_xr(DECL_ARGS)
1788
{
1789
1790
216
	n = n->child;
1791
108
	if (NULL == n)
1792
		return 0;
1793
108
	print_node(meta, n);
1794
108
	n = n->next;
1795
108
	if (NULL == n)
1796
18
		return 0;
1797
90
	outflags &= ~MMAN_spc;
1798
90
	print_word("(");
1799
90
	print_node(meta, n);
1800
90
	print_word(")");
1801
90
	return 0;
1802
108
}