xref: /openbsd-src/usr.bin/mandoc/mdoc_validate.c (revision 4c1e55dc91edd6e69ccc60ce855900fbc12cf34f)
1 /*	$Id: mdoc_validate.c,v 1.105 2012/07/12 15:09:50 schwarze Exp $ */
2 /*
3  * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
4  * Copyright (c) 2010, 2011, 2012 Ingo Schwarze <schwarze@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 #ifndef        OSNAME
19 #include <sys/utsname.h>
20 #endif
21 
22 #include <sys/types.h>
23 
24 #include <assert.h>
25 #include <ctype.h>
26 #include <limits.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <time.h>
31 
32 #include "mdoc.h"
33 #include "mandoc.h"
34 #include "libmdoc.h"
35 #include "libmandoc.h"
36 
37 /* FIXME: .Bl -diag can't have non-text children in HEAD. */
38 
39 #define	PRE_ARGS  struct mdoc *mdoc, struct mdoc_node *n
40 #define	POST_ARGS struct mdoc *mdoc
41 
42 #define	NUMSIZ	  32
43 #define	DATESIZE  32
44 
45 enum	check_ineq {
46 	CHECK_LT,
47 	CHECK_GT,
48 	CHECK_EQ
49 };
50 
51 enum	check_lvl {
52 	CHECK_WARN,
53 	CHECK_ERROR,
54 };
55 
56 typedef	int	(*v_pre)(PRE_ARGS);
57 typedef	int	(*v_post)(POST_ARGS);
58 
59 struct	valids {
60 	v_pre	*pre;
61 	v_post	*post;
62 };
63 
64 static	int	 check_count(struct mdoc *, enum mdoc_type,
65 			enum check_lvl, enum check_ineq, int);
66 static	int	 check_parent(PRE_ARGS, enum mdoct, enum mdoc_type);
67 static	void	 check_text(struct mdoc *, int, int, char *);
68 static	void	 check_argv(struct mdoc *,
69 			struct mdoc_node *, struct mdoc_argv *);
70 static	void	 check_args(struct mdoc *, struct mdoc_node *);
71 static	int	 concat(char *, const struct mdoc_node *, size_t);
72 static	enum mdoc_sec	a2sec(const char *);
73 static	size_t		macro2len(enum mdoct);
74 
75 static	int	 ebool(POST_ARGS);
76 static	int	 berr_ge1(POST_ARGS);
77 static	int	 bwarn_ge1(POST_ARGS);
78 static	int	 ewarn_eq0(POST_ARGS);
79 static	int	 ewarn_eq1(POST_ARGS);
80 static	int	 ewarn_ge1(POST_ARGS);
81 static	int	 ewarn_le1(POST_ARGS);
82 static	int	 hwarn_eq0(POST_ARGS);
83 static	int	 hwarn_eq1(POST_ARGS);
84 static	int	 hwarn_ge1(POST_ARGS);
85 static	int	 hwarn_le1(POST_ARGS);
86 
87 static	int	 post_an(POST_ARGS);
88 static	int	 post_at(POST_ARGS);
89 static	int	 post_bf(POST_ARGS);
90 static	int	 post_bl(POST_ARGS);
91 static	int	 post_bl_block(POST_ARGS);
92 static	int	 post_bl_block_width(POST_ARGS);
93 static	int	 post_bl_block_tag(POST_ARGS);
94 static	int	 post_bl_head(POST_ARGS);
95 static	int	 post_bx(POST_ARGS);
96 static	int	 post_dd(POST_ARGS);
97 static	int	 post_dt(POST_ARGS);
98 static	int	 post_defaults(POST_ARGS);
99 static	int	 post_literal(POST_ARGS);
100 static	int	 post_eoln(POST_ARGS);
101 static	int	 post_it(POST_ARGS);
102 static	int	 post_lb(POST_ARGS);
103 static	int	 post_nm(POST_ARGS);
104 static	int	 post_ns(POST_ARGS);
105 static	int	 post_os(POST_ARGS);
106 static	int	 post_ignpar(POST_ARGS);
107 static	int	 post_prol(POST_ARGS);
108 static	int	 post_root(POST_ARGS);
109 static	int	 post_rs(POST_ARGS);
110 static	int	 post_sh(POST_ARGS);
111 static	int	 post_sh_body(POST_ARGS);
112 static	int	 post_sh_head(POST_ARGS);
113 static	int	 post_st(POST_ARGS);
114 static	int	 post_std(POST_ARGS);
115 static	int	 post_vt(POST_ARGS);
116 static	int	 pre_an(PRE_ARGS);
117 static	int	 pre_bd(PRE_ARGS);
118 static	int	 pre_bl(PRE_ARGS);
119 static	int	 pre_dd(PRE_ARGS);
120 static	int	 pre_display(PRE_ARGS);
121 static	int	 pre_dt(PRE_ARGS);
122 static	int	 pre_it(PRE_ARGS);
123 static	int	 pre_literal(PRE_ARGS);
124 static	int	 pre_os(PRE_ARGS);
125 static	int	 pre_par(PRE_ARGS);
126 static	int	 pre_sh(PRE_ARGS);
127 static	int	 pre_ss(PRE_ARGS);
128 static	int	 pre_std(PRE_ARGS);
129 
130 static	v_post	 posts_an[] = { post_an, NULL };
131 static	v_post	 posts_at[] = { post_at, post_defaults, NULL };
132 static	v_post	 posts_bd[] = { post_literal, hwarn_eq0, bwarn_ge1, NULL };
133 static	v_post	 posts_bf[] = { hwarn_le1, post_bf, NULL };
134 static	v_post	 posts_bk[] = { hwarn_eq0, bwarn_ge1, NULL };
135 static	v_post	 posts_bl[] = { bwarn_ge1, post_bl, NULL };
136 static	v_post	 posts_bx[] = { post_bx, NULL };
137 static	v_post	 posts_bool[] = { ebool, NULL };
138 static	v_post	 posts_eoln[] = { post_eoln, NULL };
139 static	v_post	 posts_defaults[] = { post_defaults, NULL };
140 static	v_post	 posts_dd[] = { post_dd, post_prol, NULL };
141 static	v_post	 posts_dl[] = { post_literal, bwarn_ge1, NULL };
142 static	v_post	 posts_dt[] = { post_dt, post_prol, NULL };
143 static	v_post	 posts_fo[] = { hwarn_eq1, bwarn_ge1, NULL };
144 static	v_post	 posts_it[] = { post_it, NULL };
145 static	v_post	 posts_lb[] = { post_lb, NULL };
146 static	v_post	 posts_nd[] = { berr_ge1, NULL };
147 static	v_post	 posts_nm[] = { post_nm, NULL };
148 static	v_post	 posts_notext[] = { ewarn_eq0, NULL };
149 static	v_post	 posts_ns[] = { post_ns, NULL };
150 static	v_post	 posts_os[] = { post_os, post_prol, NULL };
151 static	v_post	 posts_rs[] = { post_rs, NULL };
152 static	v_post	 posts_sh[] = { post_ignpar, hwarn_ge1, post_sh, NULL };
153 static	v_post	 posts_sp[] = { ewarn_le1, NULL };
154 static	v_post	 posts_ss[] = { post_ignpar, hwarn_ge1, NULL };
155 static	v_post	 posts_st[] = { post_st, NULL };
156 static	v_post	 posts_std[] = { post_std, NULL };
157 static	v_post	 posts_text[] = { ewarn_ge1, NULL };
158 static	v_post	 posts_text1[] = { ewarn_eq1, NULL };
159 static	v_post	 posts_vt[] = { post_vt, NULL };
160 static	v_post	 posts_wline[] = { bwarn_ge1, NULL };
161 static	v_pre	 pres_an[] = { pre_an, NULL };
162 static	v_pre	 pres_bd[] = { pre_display, pre_bd, pre_literal, pre_par, NULL };
163 static	v_pre	 pres_bl[] = { pre_bl, pre_par, NULL };
164 static	v_pre	 pres_d1[] = { pre_display, NULL };
165 static	v_pre	 pres_dl[] = { pre_literal, pre_display, NULL };
166 static	v_pre	 pres_dd[] = { pre_dd, NULL };
167 static	v_pre	 pres_dt[] = { pre_dt, NULL };
168 static	v_pre	 pres_er[] = { NULL, NULL };
169 static	v_pre	 pres_fd[] = { NULL, NULL };
170 static	v_pre	 pres_it[] = { pre_it, pre_par, NULL };
171 static	v_pre	 pres_os[] = { pre_os, NULL };
172 static	v_pre	 pres_pp[] = { pre_par, NULL };
173 static	v_pre	 pres_sh[] = { pre_sh, NULL };
174 static	v_pre	 pres_ss[] = { pre_ss, NULL };
175 static	v_pre	 pres_std[] = { pre_std, NULL };
176 
177 static	const struct valids mdoc_valids[MDOC_MAX] = {
178 	{ NULL, NULL },				/* Ap */
179 	{ pres_dd, posts_dd },			/* Dd */
180 	{ pres_dt, posts_dt },			/* Dt */
181 	{ pres_os, posts_os },			/* Os */
182 	{ pres_sh, posts_sh },			/* Sh */
183 	{ pres_ss, posts_ss },			/* Ss */
184 	{ pres_pp, posts_notext },		/* Pp */
185 	{ pres_d1, posts_wline },		/* D1 */
186 	{ pres_dl, posts_dl },			/* Dl */
187 	{ pres_bd, posts_bd },			/* Bd */
188 	{ NULL, NULL },				/* Ed */
189 	{ pres_bl, posts_bl },			/* Bl */
190 	{ NULL, NULL },				/* El */
191 	{ pres_it, posts_it },			/* It */
192 	{ NULL, NULL },				/* Ad */
193 	{ pres_an, posts_an },			/* An */
194 	{ NULL, posts_defaults },		/* Ar */
195 	{ NULL, NULL },				/* Cd */
196 	{ NULL, NULL },				/* Cm */
197 	{ NULL, NULL },				/* Dv */
198 	{ pres_er, NULL },			/* Er */
199 	{ NULL, NULL },				/* Ev */
200 	{ pres_std, posts_std },		/* Ex */
201 	{ NULL, NULL },				/* Fa */
202 	{ pres_fd, posts_text },		/* Fd */
203 	{ NULL, NULL },				/* Fl */
204 	{ NULL, NULL },				/* Fn */
205 	{ NULL, NULL },				/* Ft */
206 	{ NULL, NULL },				/* Ic */
207 	{ NULL, posts_text1 },			/* In */
208 	{ NULL, posts_defaults },		/* Li */
209 	{ NULL, posts_nd },			/* Nd */
210 	{ NULL, posts_nm },			/* Nm */
211 	{ NULL, NULL },				/* Op */
212 	{ NULL, NULL },				/* Ot */
213 	{ NULL, posts_defaults },		/* Pa */
214 	{ pres_std, posts_std },		/* Rv */
215 	{ NULL, posts_st },			/* St */
216 	{ NULL, NULL },				/* Va */
217 	{ NULL, posts_vt },			/* Vt */
218 	{ NULL, posts_text },			/* Xr */
219 	{ NULL, posts_text },			/* %A */
220 	{ NULL, posts_text },			/* %B */ /* FIXME: can be used outside Rs/Re. */
221 	{ NULL, posts_text },			/* %D */
222 	{ NULL, posts_text },			/* %I */
223 	{ NULL, posts_text },			/* %J */
224 	{ NULL, posts_text },			/* %N */
225 	{ NULL, posts_text },			/* %O */
226 	{ NULL, posts_text },			/* %P */
227 	{ NULL, posts_text },			/* %R */
228 	{ NULL, posts_text },			/* %T */ /* FIXME: can be used outside Rs/Re. */
229 	{ NULL, posts_text },			/* %V */
230 	{ NULL, NULL },				/* Ac */
231 	{ NULL, NULL },				/* Ao */
232 	{ NULL, NULL },				/* Aq */
233 	{ NULL, posts_at },			/* At */
234 	{ NULL, NULL },				/* Bc */
235 	{ NULL, posts_bf },			/* Bf */
236 	{ NULL, NULL },				/* Bo */
237 	{ NULL, NULL },				/* Bq */
238 	{ NULL, NULL },				/* Bsx */
239 	{ NULL, posts_bx },			/* Bx */
240 	{ NULL, posts_bool },			/* Db */
241 	{ NULL, NULL },				/* Dc */
242 	{ NULL, NULL },				/* Do */
243 	{ NULL, NULL },				/* Dq */
244 	{ NULL, NULL },				/* Ec */
245 	{ NULL, NULL },				/* Ef */
246 	{ NULL, NULL },				/* Em */
247 	{ NULL, NULL },				/* Eo */
248 	{ NULL, NULL },				/* Fx */
249 	{ NULL, NULL },				/* Ms */
250 	{ NULL, posts_notext },			/* No */
251 	{ NULL, posts_ns },			/* Ns */
252 	{ NULL, NULL },				/* Nx */
253 	{ NULL, NULL },				/* Ox */
254 	{ NULL, NULL },				/* Pc */
255 	{ NULL, posts_text1 },			/* Pf */
256 	{ NULL, NULL },				/* Po */
257 	{ NULL, NULL },				/* Pq */
258 	{ NULL, NULL },				/* Qc */
259 	{ NULL, NULL },				/* Ql */
260 	{ NULL, NULL },				/* Qo */
261 	{ NULL, NULL },				/* Qq */
262 	{ NULL, NULL },				/* Re */
263 	{ NULL, posts_rs },			/* Rs */
264 	{ NULL, NULL },				/* Sc */
265 	{ NULL, NULL },				/* So */
266 	{ NULL, NULL },				/* Sq */
267 	{ NULL, posts_bool },			/* Sm */
268 	{ NULL, NULL },				/* Sx */
269 	{ NULL, NULL },				/* Sy */
270 	{ NULL, NULL },				/* Tn */
271 	{ NULL, NULL },				/* Ux */
272 	{ NULL, NULL },				/* Xc */
273 	{ NULL, NULL },				/* Xo */
274 	{ NULL, posts_fo },			/* Fo */
275 	{ NULL, NULL },				/* Fc */
276 	{ NULL, NULL },				/* Oo */
277 	{ NULL, NULL },				/* Oc */
278 	{ NULL, posts_bk },			/* Bk */
279 	{ NULL, NULL },				/* Ek */
280 	{ NULL, posts_eoln },			/* Bt */
281 	{ NULL, NULL },				/* Hf */
282 	{ NULL, NULL },				/* Fr */
283 	{ NULL, posts_eoln },			/* Ud */
284 	{ NULL, posts_lb },			/* Lb */
285 	{ NULL, posts_notext },			/* Lp */
286 	{ NULL, NULL },				/* Lk */
287 	{ NULL, posts_defaults },		/* Mt */
288 	{ NULL, NULL },				/* Brq */
289 	{ NULL, NULL },				/* Bro */
290 	{ NULL, NULL },				/* Brc */
291 	{ NULL, posts_text },			/* %C */
292 	{ NULL, NULL },				/* Es */
293 	{ NULL, NULL },				/* En */
294 	{ NULL, NULL },				/* Dx */
295 	{ NULL, posts_text },			/* %Q */
296 	{ NULL, posts_notext },			/* br */
297 	{ pres_pp, posts_sp },			/* sp */
298 	{ NULL, posts_text1 },			/* %U */
299 	{ NULL, NULL },				/* Ta */
300 };
301 
302 #define	RSORD_MAX 14 /* Number of `Rs' blocks. */
303 
304 static	const enum mdoct rsord[RSORD_MAX] = {
305 	MDOC__A,
306 	MDOC__T,
307 	MDOC__B,
308 	MDOC__I,
309 	MDOC__J,
310 	MDOC__R,
311 	MDOC__N,
312 	MDOC__V,
313 	MDOC__U,
314 	MDOC__P,
315 	MDOC__Q,
316 	MDOC__D,
317 	MDOC__O,
318 	MDOC__C
319 };
320 
321 static	const char * const secnames[SEC__MAX] = {
322 	NULL,
323 	"NAME",
324 	"LIBRARY",
325 	"SYNOPSIS",
326 	"DESCRIPTION",
327 	"IMPLEMENTATION NOTES",
328 	"RETURN VALUES",
329 	"ENVIRONMENT",
330 	"FILES",
331 	"EXIT STATUS",
332 	"EXAMPLES",
333 	"DIAGNOSTICS",
334 	"COMPATIBILITY",
335 	"ERRORS",
336 	"SEE ALSO",
337 	"STANDARDS",
338 	"HISTORY",
339 	"AUTHORS",
340 	"CAVEATS",
341 	"BUGS",
342 	"SECURITY CONSIDERATIONS",
343 	NULL
344 };
345 
346 int
347 mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *n)
348 {
349 	v_pre		*p;
350 	int		 line, pos;
351 	char		*tp;
352 
353 	switch (n->type) {
354 	case (MDOC_TEXT):
355 		tp = n->string;
356 		line = n->line;
357 		pos = n->pos;
358 		check_text(mdoc, line, pos, tp);
359 		/* FALLTHROUGH */
360 	case (MDOC_TBL):
361 		/* FALLTHROUGH */
362 	case (MDOC_EQN):
363 		/* FALLTHROUGH */
364 	case (MDOC_ROOT):
365 		return(1);
366 	default:
367 		break;
368 	}
369 
370 	check_args(mdoc, n);
371 
372 	if (NULL == mdoc_valids[n->tok].pre)
373 		return(1);
374 	for (p = mdoc_valids[n->tok].pre; *p; p++)
375 		if ( ! (*p)(mdoc, n))
376 			return(0);
377 	return(1);
378 }
379 
380 
381 int
382 mdoc_valid_post(struct mdoc *mdoc)
383 {
384 	v_post		*p;
385 
386 	if (MDOC_VALID & mdoc->last->flags)
387 		return(1);
388 	mdoc->last->flags |= MDOC_VALID;
389 
390 	switch (mdoc->last->type) {
391 	case (MDOC_TEXT):
392 		/* FALLTHROUGH */
393 	case (MDOC_EQN):
394 		/* FALLTHROUGH */
395 	case (MDOC_TBL):
396 		return(1);
397 	case (MDOC_ROOT):
398 		return(post_root(mdoc));
399 	default:
400 		break;
401 	}
402 
403 	if (NULL == mdoc_valids[mdoc->last->tok].post)
404 		return(1);
405 	for (p = mdoc_valids[mdoc->last->tok].post; *p; p++)
406 		if ( ! (*p)(mdoc))
407 			return(0);
408 
409 	return(1);
410 }
411 
412 static int
413 check_count(struct mdoc *m, enum mdoc_type type,
414 		enum check_lvl lvl, enum check_ineq ineq, int val)
415 {
416 	const char	*p;
417 	enum mandocerr	 t;
418 
419 	if (m->last->type != type)
420 		return(1);
421 
422 	switch (ineq) {
423 	case (CHECK_LT):
424 		p = "less than ";
425 		if (m->last->nchild < val)
426 			return(1);
427 		break;
428 	case (CHECK_GT):
429 		p = "more than ";
430 		if (m->last->nchild > val)
431 			return(1);
432 		break;
433 	case (CHECK_EQ):
434 		p = "";
435 		if (val == m->last->nchild)
436 			return(1);
437 		break;
438 	default:
439 		abort();
440 		/* NOTREACHED */
441 	}
442 
443 	t = lvl == CHECK_WARN ? MANDOCERR_ARGCWARN : MANDOCERR_ARGCOUNT;
444 	mandoc_vmsg(t, m->parse, m->last->line, m->last->pos,
445 			"want %s%d children (have %d)",
446 			p, val, m->last->nchild);
447 	return(1);
448 }
449 
450 static int
451 berr_ge1(POST_ARGS)
452 {
453 
454 	return(check_count(mdoc, MDOC_BODY, CHECK_ERROR, CHECK_GT, 0));
455 }
456 
457 static int
458 bwarn_ge1(POST_ARGS)
459 {
460 	return(check_count(mdoc, MDOC_BODY, CHECK_WARN, CHECK_GT, 0));
461 }
462 
463 static int
464 ewarn_eq0(POST_ARGS)
465 {
466 	return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 0));
467 }
468 
469 static int
470 ewarn_eq1(POST_ARGS)
471 {
472 	return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1));
473 }
474 
475 static int
476 ewarn_ge1(POST_ARGS)
477 {
478 	return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_GT, 0));
479 }
480 
481 static int
482 ewarn_le1(POST_ARGS)
483 {
484 	return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_LT, 2));
485 }
486 
487 static int
488 hwarn_eq0(POST_ARGS)
489 {
490 	return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 0));
491 }
492 
493 static int
494 hwarn_eq1(POST_ARGS)
495 {
496 	return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 1));
497 }
498 
499 static int
500 hwarn_ge1(POST_ARGS)
501 {
502 	return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_GT, 0));
503 }
504 
505 static int
506 hwarn_le1(POST_ARGS)
507 {
508 	return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_LT, 2));
509 }
510 
511 static void
512 check_args(struct mdoc *m, struct mdoc_node *n)
513 {
514 	int		 i;
515 
516 	if (NULL == n->args)
517 		return;
518 
519 	assert(n->args->argc);
520 	for (i = 0; i < (int)n->args->argc; i++)
521 		check_argv(m, n, &n->args->argv[i]);
522 }
523 
524 static void
525 check_argv(struct mdoc *m, struct mdoc_node *n, struct mdoc_argv *v)
526 {
527 	int		 i;
528 
529 	for (i = 0; i < (int)v->sz; i++)
530 		check_text(m, v->line, v->pos, v->value[i]);
531 
532 	/* FIXME: move to post_std(). */
533 
534 	if (MDOC_Std == v->arg)
535 		if ( ! (v->sz || m->meta.name))
536 			mdoc_nmsg(m, n, MANDOCERR_NONAME);
537 }
538 
539 static void
540 check_text(struct mdoc *m, int ln, int pos, char *p)
541 {
542 	char		*cp;
543 
544 	if (MDOC_LITERAL & m->flags)
545 		return;
546 
547 	for (cp = p; NULL != (p = strchr(p, '\t')); p++)
548 		mdoc_pmsg(m, ln, pos + (int)(p - cp), MANDOCERR_BADTAB);
549 }
550 
551 static int
552 check_parent(PRE_ARGS, enum mdoct tok, enum mdoc_type t)
553 {
554 
555 	assert(n->parent);
556 	if ((MDOC_ROOT == t || tok == n->parent->tok) &&
557 			(t == n->parent->type))
558 		return(1);
559 
560 	mandoc_vmsg(MANDOCERR_SYNTCHILD, mdoc->parse, n->line,
561 			n->pos, "want parent %s", MDOC_ROOT == t ?
562 			"<root>" : mdoc_macronames[tok]);
563 	return(0);
564 }
565 
566 
567 static int
568 pre_display(PRE_ARGS)
569 {
570 	struct mdoc_node *node;
571 
572 	if (MDOC_BLOCK != n->type)
573 		return(1);
574 
575 	for (node = mdoc->last->parent; node; node = node->parent)
576 		if (MDOC_BLOCK == node->type)
577 			if (MDOC_Bd == node->tok)
578 				break;
579 
580 	if (node)
581 		mdoc_nmsg(mdoc, n, MANDOCERR_NESTEDDISP);
582 
583 	return(1);
584 }
585 
586 
587 static int
588 pre_bl(PRE_ARGS)
589 {
590 	int		  i, comp, dup;
591 	const char	 *offs, *width;
592 	enum mdoc_list	  lt;
593 	struct mdoc_node *np;
594 
595 	if (MDOC_BLOCK != n->type) {
596 		if (ENDBODY_NOT != n->end) {
597 			assert(n->pending);
598 			np = n->pending->parent;
599 		} else
600 			np = n->parent;
601 
602 		assert(np);
603 		assert(MDOC_BLOCK == np->type);
604 		assert(MDOC_Bl == np->tok);
605 		return(1);
606 	}
607 
608 	/*
609 	 * First figure out which kind of list to use: bind ourselves to
610 	 * the first mentioned list type and warn about any remaining
611 	 * ones.  If we find no list type, we default to LIST_item.
612 	 */
613 
614 	/* LINTED */
615 	for (i = 0; n->args && i < (int)n->args->argc; i++) {
616 		lt = LIST__NONE;
617 		dup = comp = 0;
618 		width = offs = NULL;
619 		switch (n->args->argv[i].arg) {
620 		/* Set list types. */
621 		case (MDOC_Bullet):
622 			lt = LIST_bullet;
623 			break;
624 		case (MDOC_Dash):
625 			lt = LIST_dash;
626 			break;
627 		case (MDOC_Enum):
628 			lt = LIST_enum;
629 			break;
630 		case (MDOC_Hyphen):
631 			lt = LIST_hyphen;
632 			break;
633 		case (MDOC_Item):
634 			lt = LIST_item;
635 			break;
636 		case (MDOC_Tag):
637 			lt = LIST_tag;
638 			break;
639 		case (MDOC_Diag):
640 			lt = LIST_diag;
641 			break;
642 		case (MDOC_Hang):
643 			lt = LIST_hang;
644 			break;
645 		case (MDOC_Ohang):
646 			lt = LIST_ohang;
647 			break;
648 		case (MDOC_Inset):
649 			lt = LIST_inset;
650 			break;
651 		case (MDOC_Column):
652 			lt = LIST_column;
653 			break;
654 		/* Set list arguments. */
655 		case (MDOC_Compact):
656 			dup = n->norm->Bl.comp;
657 			comp = 1;
658 			break;
659 		case (MDOC_Width):
660 			/* NB: this can be empty! */
661 			if (n->args->argv[i].sz) {
662 				width = n->args->argv[i].value[0];
663 				dup = (NULL != n->norm->Bl.width);
664 				break;
665 			}
666 			mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV);
667 			break;
668 		case (MDOC_Offset):
669 			/* NB: this can be empty! */
670 			if (n->args->argv[i].sz) {
671 				offs = n->args->argv[i].value[0];
672 				dup = (NULL != n->norm->Bl.offs);
673 				break;
674 			}
675 			mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV);
676 			break;
677 		default:
678 			continue;
679 		}
680 
681 		/* Check: duplicate auxiliary arguments. */
682 
683 		if (dup)
684 			mdoc_nmsg(mdoc, n, MANDOCERR_ARGVREP);
685 
686 		if (comp && ! dup)
687 			n->norm->Bl.comp = comp;
688 		if (offs && ! dup)
689 			n->norm->Bl.offs = offs;
690 		if (width && ! dup)
691 			n->norm->Bl.width = width;
692 
693 		/* Check: multiple list types. */
694 
695 		if (LIST__NONE != lt && n->norm->Bl.type != LIST__NONE)
696 			mdoc_nmsg(mdoc, n, MANDOCERR_LISTREP);
697 
698 		/* Assign list type. */
699 
700 		if (LIST__NONE != lt && n->norm->Bl.type == LIST__NONE) {
701 			n->norm->Bl.type = lt;
702 			/* Set column information, too. */
703 			if (LIST_column == lt) {
704 				n->norm->Bl.ncols =
705 					n->args->argv[i].sz;
706 				n->norm->Bl.cols = (void *)
707 					n->args->argv[i].value;
708 			}
709 		}
710 
711 		/* The list type should come first. */
712 
713 		if (n->norm->Bl.type == LIST__NONE)
714 			if (n->norm->Bl.width ||
715 					n->norm->Bl.offs ||
716 					n->norm->Bl.comp)
717 				mdoc_nmsg(mdoc, n, MANDOCERR_LISTFIRST);
718 
719 		continue;
720 	}
721 
722 	/* Allow lists to default to LIST_item. */
723 
724 	if (LIST__NONE == n->norm->Bl.type) {
725 		mdoc_nmsg(mdoc, n, MANDOCERR_LISTTYPE);
726 		n->norm->Bl.type = LIST_item;
727 	}
728 
729 	/*
730 	 * Validate the width field.  Some list types don't need width
731 	 * types and should be warned about them.  Others should have it
732 	 * and must also be warned.  Yet others have a default and need
733 	 * no warning.
734 	 */
735 
736 	switch (n->norm->Bl.type) {
737 	case (LIST_tag):
738 		if (NULL == n->norm->Bl.width)
739 			mdoc_nmsg(mdoc, n, MANDOCERR_NOWIDTHARG);
740 		break;
741 	case (LIST_column):
742 		/* FALLTHROUGH */
743 	case (LIST_diag):
744 		/* FALLTHROUGH */
745 	case (LIST_ohang):
746 		/* FALLTHROUGH */
747 	case (LIST_inset):
748 		/* FALLTHROUGH */
749 	case (LIST_item):
750 		if (n->norm->Bl.width)
751 			mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV);
752 		break;
753 	case (LIST_bullet):
754 		/* FALLTHROUGH */
755 	case (LIST_dash):
756 		/* FALLTHROUGH */
757 	case (LIST_hyphen):
758 		if (NULL == n->norm->Bl.width)
759 			n->norm->Bl.width = "2n";
760 		break;
761 	case (LIST_enum):
762 		if (NULL == n->norm->Bl.width)
763 			n->norm->Bl.width = "3n";
764 		break;
765 	default:
766 		break;
767 	}
768 
769 	return(1);
770 }
771 
772 
773 static int
774 pre_bd(PRE_ARGS)
775 {
776 	int		  i, dup, comp;
777 	enum mdoc_disp 	  dt;
778 	const char	 *offs;
779 	struct mdoc_node *np;
780 
781 	if (MDOC_BLOCK != n->type) {
782 		if (ENDBODY_NOT != n->end) {
783 			assert(n->pending);
784 			np = n->pending->parent;
785 		} else
786 			np = n->parent;
787 
788 		assert(np);
789 		assert(MDOC_BLOCK == np->type);
790 		assert(MDOC_Bd == np->tok);
791 		return(1);
792 	}
793 
794 	/* LINTED */
795 	for (i = 0; n->args && i < (int)n->args->argc; i++) {
796 		dt = DISP__NONE;
797 		dup = comp = 0;
798 		offs = NULL;
799 
800 		switch (n->args->argv[i].arg) {
801 		case (MDOC_Centred):
802 			dt = DISP_centred;
803 			break;
804 		case (MDOC_Ragged):
805 			dt = DISP_ragged;
806 			break;
807 		case (MDOC_Unfilled):
808 			dt = DISP_unfilled;
809 			break;
810 		case (MDOC_Filled):
811 			dt = DISP_filled;
812 			break;
813 		case (MDOC_Literal):
814 			dt = DISP_literal;
815 			break;
816 		case (MDOC_File):
817 			mdoc_nmsg(mdoc, n, MANDOCERR_BADDISP);
818 			return(0);
819 		case (MDOC_Offset):
820 			/* NB: this can be empty! */
821 			if (n->args->argv[i].sz) {
822 				offs = n->args->argv[i].value[0];
823 				dup = (NULL != n->norm->Bd.offs);
824 				break;
825 			}
826 			mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV);
827 			break;
828 		case (MDOC_Compact):
829 			comp = 1;
830 			dup = n->norm->Bd.comp;
831 			break;
832 		default:
833 			abort();
834 			/* NOTREACHED */
835 		}
836 
837 		/* Check whether we have duplicates. */
838 
839 		if (dup)
840 			mdoc_nmsg(mdoc, n, MANDOCERR_ARGVREP);
841 
842 		/* Make our auxiliary assignments. */
843 
844 		if (offs && ! dup)
845 			n->norm->Bd.offs = offs;
846 		if (comp && ! dup)
847 			n->norm->Bd.comp = comp;
848 
849 		/* Check whether a type has already been assigned. */
850 
851 		if (DISP__NONE != dt && n->norm->Bd.type != DISP__NONE)
852 			mdoc_nmsg(mdoc, n, MANDOCERR_DISPREP);
853 
854 		/* Make our type assignment. */
855 
856 		if (DISP__NONE != dt && n->norm->Bd.type == DISP__NONE)
857 			n->norm->Bd.type = dt;
858 	}
859 
860 	if (DISP__NONE == n->norm->Bd.type) {
861 		mdoc_nmsg(mdoc, n, MANDOCERR_DISPTYPE);
862 		n->norm->Bd.type = DISP_ragged;
863 	}
864 
865 	return(1);
866 }
867 
868 
869 static int
870 pre_ss(PRE_ARGS)
871 {
872 
873 	if (MDOC_BLOCK != n->type)
874 		return(1);
875 	return(check_parent(mdoc, n, MDOC_Sh, MDOC_BODY));
876 }
877 
878 
879 static int
880 pre_sh(PRE_ARGS)
881 {
882 
883 	if (MDOC_BLOCK != n->type)
884 		return(1);
885 
886 	roff_regunset(mdoc->roff, REG_nS);
887 	return(check_parent(mdoc, n, MDOC_MAX, MDOC_ROOT));
888 }
889 
890 
891 static int
892 pre_it(PRE_ARGS)
893 {
894 
895 	if (MDOC_BLOCK != n->type)
896 		return(1);
897 
898 	return(check_parent(mdoc, n, MDOC_Bl, MDOC_BODY));
899 }
900 
901 
902 static int
903 pre_an(PRE_ARGS)
904 {
905 	int		 i;
906 
907 	if (NULL == n->args)
908 		return(1);
909 
910 	for (i = 1; i < (int)n->args->argc; i++)
911 		mdoc_pmsg(mdoc, n->args->argv[i].line,
912 			n->args->argv[i].pos, MANDOCERR_IGNARGV);
913 
914 	if (MDOC_Split == n->args->argv[0].arg)
915 		n->norm->An.auth = AUTH_split;
916 	else if (MDOC_Nosplit == n->args->argv[0].arg)
917 		n->norm->An.auth = AUTH_nosplit;
918 	else
919 		abort();
920 
921 	return(1);
922 }
923 
924 static int
925 pre_std(PRE_ARGS)
926 {
927 
928 	if (n->args && 1 == n->args->argc)
929 		if (MDOC_Std == n->args->argv[0].arg)
930 			return(1);
931 
932 	mdoc_nmsg(mdoc, n, MANDOCERR_NOARGV);
933 	return(1);
934 }
935 
936 static int
937 pre_dt(PRE_ARGS)
938 {
939 
940 	if (NULL == mdoc->meta.date || mdoc->meta.os)
941 		mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO);
942 
943 	if (mdoc->meta.title)
944 		mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP);
945 
946 	return(1);
947 }
948 
949 static int
950 pre_os(PRE_ARGS)
951 {
952 
953 	if (NULL == mdoc->meta.title || NULL == mdoc->meta.date)
954 		mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO);
955 
956 	if (mdoc->meta.os)
957 		mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP);
958 
959 	return(1);
960 }
961 
962 static int
963 pre_dd(PRE_ARGS)
964 {
965 
966 	if (mdoc->meta.title || mdoc->meta.os)
967 		mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO);
968 
969 	if (mdoc->meta.date)
970 		mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP);
971 
972 	return(1);
973 }
974 
975 
976 static int
977 post_bf(POST_ARGS)
978 {
979 	struct mdoc_node *np;
980 	enum mdocargt	  arg;
981 
982 	/*
983 	 * Unlike other data pointers, these are "housed" by the HEAD
984 	 * element, which contains the goods.
985 	 */
986 
987 	if (MDOC_HEAD != mdoc->last->type) {
988 		if (ENDBODY_NOT != mdoc->last->end) {
989 			assert(mdoc->last->pending);
990 			np = mdoc->last->pending->parent->head;
991 		} else if (MDOC_BLOCK != mdoc->last->type) {
992 			np = mdoc->last->parent->head;
993 		} else
994 			np = mdoc->last->head;
995 
996 		assert(np);
997 		assert(MDOC_HEAD == np->type);
998 		assert(MDOC_Bf == np->tok);
999 		return(1);
1000 	}
1001 
1002 	np = mdoc->last;
1003 	assert(MDOC_BLOCK == np->parent->type);
1004 	assert(MDOC_Bf == np->parent->tok);
1005 
1006 	/*
1007 	 * Cannot have both argument and parameter.
1008 	 * If neither is specified, let it through with a warning.
1009 	 */
1010 
1011 	if (np->parent->args && np->child) {
1012 		mdoc_nmsg(mdoc, np, MANDOCERR_SYNTARGVCOUNT);
1013 		return(0);
1014 	} else if (NULL == np->parent->args && NULL == np->child) {
1015 		mdoc_nmsg(mdoc, np, MANDOCERR_FONTTYPE);
1016 		return(1);
1017 	}
1018 
1019 	/* Extract argument into data. */
1020 
1021 	if (np->parent->args) {
1022 		arg = np->parent->args->argv[0].arg;
1023 		if (MDOC_Emphasis == arg)
1024 			np->norm->Bf.font = FONT_Em;
1025 		else if (MDOC_Literal == arg)
1026 			np->norm->Bf.font = FONT_Li;
1027 		else if (MDOC_Symbolic == arg)
1028 			np->norm->Bf.font = FONT_Sy;
1029 		else
1030 			abort();
1031 		return(1);
1032 	}
1033 
1034 	/* Extract parameter into data. */
1035 
1036 	if (0 == strcmp(np->child->string, "Em"))
1037 		np->norm->Bf.font = FONT_Em;
1038 	else if (0 == strcmp(np->child->string, "Li"))
1039 		np->norm->Bf.font = FONT_Li;
1040 	else if (0 == strcmp(np->child->string, "Sy"))
1041 		np->norm->Bf.font = FONT_Sy;
1042 	else
1043 		mdoc_nmsg(mdoc, np, MANDOCERR_FONTTYPE);
1044 
1045 	return(1);
1046 }
1047 
1048 static int
1049 post_lb(POST_ARGS)
1050 {
1051 	const char	*p;
1052 	char		*buf;
1053 	size_t		 sz;
1054 
1055 	check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1);
1056 
1057 	assert(mdoc->last->child);
1058 	assert(MDOC_TEXT == mdoc->last->child->type);
1059 
1060 	p = mdoc_a2lib(mdoc->last->child->string);
1061 
1062 	/* If lookup ok, replace with table value. */
1063 
1064 	if (p) {
1065 		free(mdoc->last->child->string);
1066 		mdoc->last->child->string = mandoc_strdup(p);
1067 		return(1);
1068 	}
1069 
1070 	/* If not, use "library ``xxxx''. */
1071 
1072 	sz = strlen(mdoc->last->child->string) +
1073 		2 + strlen("\\(lqlibrary\\(rq");
1074 	buf = mandoc_malloc(sz);
1075 	snprintf(buf, sz, "library \\(lq%s\\(rq",
1076 			mdoc->last->child->string);
1077 	free(mdoc->last->child->string);
1078 	mdoc->last->child->string = buf;
1079 	return(1);
1080 }
1081 
1082 static int
1083 post_eoln(POST_ARGS)
1084 {
1085 
1086 	if (mdoc->last->child)
1087 		mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_ARGSLOST);
1088 	return(1);
1089 }
1090 
1091 
1092 static int
1093 post_vt(POST_ARGS)
1094 {
1095 	const struct mdoc_node *n;
1096 
1097 	/*
1098 	 * The Vt macro comes in both ELEM and BLOCK form, both of which
1099 	 * have different syntaxes (yet more context-sensitive
1100 	 * behaviour).  ELEM types must have a child, which is already
1101 	 * guaranteed by the in_line parsing routine; BLOCK types,
1102 	 * specifically the BODY, should only have TEXT children.
1103 	 */
1104 
1105 	if (MDOC_BODY != mdoc->last->type)
1106 		return(1);
1107 
1108 	for (n = mdoc->last->child; n; n = n->next)
1109 		if (MDOC_TEXT != n->type)
1110 			mdoc_nmsg(mdoc, n, MANDOCERR_CHILD);
1111 
1112 	return(1);
1113 }
1114 
1115 
1116 static int
1117 post_nm(POST_ARGS)
1118 {
1119 	char		 buf[BUFSIZ];
1120 	int		 c;
1121 
1122 	if (NULL != mdoc->meta.name)
1123 		return(1);
1124 
1125 	/* Try to use our children for setting the meta name. */
1126 
1127 	if (NULL != mdoc->last->child) {
1128 		buf[0] = '\0';
1129 		c = concat(buf, mdoc->last->child, BUFSIZ);
1130 	} else
1131 		c = 0;
1132 
1133 	switch (c) {
1134 	case (-1):
1135 		mdoc_nmsg(mdoc, mdoc->last->child, MANDOCERR_MEM);
1136 		return(0);
1137 	case (0):
1138 		mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NONAME);
1139 		mdoc->meta.name = mandoc_strdup("UNKNOWN");
1140 		break;
1141 	default:
1142 		mdoc->meta.name = mandoc_strdup(buf);
1143 		break;
1144 	}
1145 	return(1);
1146 }
1147 
1148 static int
1149 post_literal(POST_ARGS)
1150 {
1151 
1152 	/*
1153 	 * The `Dl' (note "el" not "one") and `Bd' macros unset the
1154 	 * MDOC_LITERAL flag as they leave.  Note that `Bd' only sets
1155 	 * this in literal mode, but it doesn't hurt to just switch it
1156 	 * off in general since displays can't be nested.
1157 	 */
1158 
1159 	if (MDOC_BODY == mdoc->last->type)
1160 		mdoc->flags &= ~MDOC_LITERAL;
1161 
1162 	return(1);
1163 }
1164 
1165 static int
1166 post_defaults(POST_ARGS)
1167 {
1168 	struct mdoc_node *nn;
1169 
1170 	/*
1171 	 * The `Ar' defaults to "file ..." if no value is provided as an
1172 	 * argument; the `Mt' and `Pa' macros use "~"; the `Li' just
1173 	 * gets an empty string.
1174 	 */
1175 
1176 	if (mdoc->last->child)
1177 		return(1);
1178 
1179 	nn = mdoc->last;
1180 	mdoc->next = MDOC_NEXT_CHILD;
1181 
1182 	switch (nn->tok) {
1183 	case (MDOC_Ar):
1184 		if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "file"))
1185 			return(0);
1186 		if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "..."))
1187 			return(0);
1188 		break;
1189 	case (MDOC_At):
1190 		if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "AT&T"))
1191 			return(0);
1192 		if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "UNIX"))
1193 			return(0);
1194 		break;
1195 	case (MDOC_Li):
1196 		if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, ""))
1197 			return(0);
1198 		break;
1199 	case (MDOC_Pa):
1200 		/* FALLTHROUGH */
1201 	case (MDOC_Mt):
1202 		if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "~"))
1203 			return(0);
1204 		break;
1205 	default:
1206 		abort();
1207 		/* NOTREACHED */
1208 	}
1209 
1210 	mdoc->last = nn;
1211 	return(1);
1212 }
1213 
1214 static int
1215 post_at(POST_ARGS)
1216 {
1217 	const char	 *p, *q;
1218 	char		 *buf;
1219 	size_t		  sz;
1220 
1221 	/*
1222 	 * If we have a child, look it up in the standard keys.  If a
1223 	 * key exist, use that instead of the child; if it doesn't,
1224 	 * prefix "AT&T UNIX " to the existing data.
1225 	 */
1226 
1227 	if (NULL == mdoc->last->child)
1228 		return(1);
1229 
1230 	assert(MDOC_TEXT == mdoc->last->child->type);
1231 	p = mdoc_a2att(mdoc->last->child->string);
1232 
1233 	if (p) {
1234 		free(mdoc->last->child->string);
1235 		mdoc->last->child->string = mandoc_strdup(p);
1236 	} else {
1237 		mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADATT);
1238 		p = "AT&T UNIX ";
1239 		q = mdoc->last->child->string;
1240 		sz = strlen(p) + strlen(q) + 1;
1241 		buf = mandoc_malloc(sz);
1242 		strlcpy(buf, p, sz);
1243 		strlcat(buf, q, sz);
1244 		free(mdoc->last->child->string);
1245 		mdoc->last->child->string = buf;
1246 	}
1247 
1248 	return(1);
1249 }
1250 
1251 static int
1252 post_an(POST_ARGS)
1253 {
1254 	struct mdoc_node *np;
1255 
1256 	np = mdoc->last;
1257 	if (AUTH__NONE == np->norm->An.auth) {
1258 		if (0 == np->child)
1259 			check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_GT, 0);
1260 	} else if (np->child)
1261 		check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 0);
1262 
1263 	return(1);
1264 }
1265 
1266 
1267 static int
1268 post_it(POST_ARGS)
1269 {
1270 	int		  i, cols;
1271 	enum mdoc_list	  lt;
1272 	struct mdoc_node *n, *c;
1273 	enum mandocerr	  er;
1274 
1275 	if (MDOC_BLOCK != mdoc->last->type)
1276 		return(1);
1277 
1278 	n = mdoc->last->parent->parent;
1279 	lt = n->norm->Bl.type;
1280 
1281 	if (LIST__NONE == lt) {
1282 		mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_LISTTYPE);
1283 		return(1);
1284 	}
1285 
1286 	switch (lt) {
1287 	case (LIST_tag):
1288 		if (mdoc->last->head->child)
1289 			break;
1290 		/* FIXME: give this a dummy value. */
1291 		mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOARGS);
1292 		break;
1293 	case (LIST_hang):
1294 		/* FALLTHROUGH */
1295 	case (LIST_ohang):
1296 		/* FALLTHROUGH */
1297 	case (LIST_inset):
1298 		/* FALLTHROUGH */
1299 	case (LIST_diag):
1300 		if (NULL == mdoc->last->head->child)
1301 			mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOARGS);
1302 		break;
1303 	case (LIST_bullet):
1304 		/* FALLTHROUGH */
1305 	case (LIST_dash):
1306 		/* FALLTHROUGH */
1307 	case (LIST_enum):
1308 		/* FALLTHROUGH */
1309 	case (LIST_hyphen):
1310 		if (NULL == mdoc->last->body->child)
1311 			mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOBODY);
1312 		/* FALLTHROUGH */
1313 	case (LIST_item):
1314 		if (mdoc->last->head->child)
1315 			mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_ARGSLOST);
1316 		break;
1317 	case (LIST_column):
1318 		cols = (int)n->norm->Bl.ncols;
1319 
1320 		assert(NULL == mdoc->last->head->child);
1321 
1322 		if (NULL == mdoc->last->body->child)
1323 			mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOBODY);
1324 
1325 		for (i = 0, c = mdoc->last->child; c; c = c->next)
1326 			if (MDOC_BODY == c->type)
1327 				i++;
1328 
1329 		if (i < cols)
1330 			er = MANDOCERR_ARGCOUNT;
1331 		else if (i == cols || i == cols + 1)
1332 			break;
1333 		else
1334 			er = MANDOCERR_SYNTARGCOUNT;
1335 
1336 		mandoc_vmsg(er, mdoc->parse, mdoc->last->line,
1337 				mdoc->last->pos,
1338 				"columns == %d (have %d)", cols, i);
1339 		return(MANDOCERR_ARGCOUNT == er);
1340 	default:
1341 		break;
1342 	}
1343 
1344 	return(1);
1345 }
1346 
1347 static int
1348 post_bl_block(POST_ARGS)
1349 {
1350 	struct mdoc_node *n;
1351 
1352 	/*
1353 	 * These are fairly complicated, so we've broken them into two
1354 	 * functions.  post_bl_block_tag() is called when a -tag is
1355 	 * specified, but no -width (it must be guessed).  The second
1356 	 * when a -width is specified (macro indicators must be
1357 	 * rewritten into real lengths).
1358 	 */
1359 
1360 	n = mdoc->last;
1361 
1362 	if (LIST_tag == n->norm->Bl.type &&
1363 			NULL == n->norm->Bl.width) {
1364 		if ( ! post_bl_block_tag(mdoc))
1365 			return(0);
1366 	} else if (NULL != n->norm->Bl.width) {
1367 		if ( ! post_bl_block_width(mdoc))
1368 			return(0);
1369 	} else
1370 		return(1);
1371 
1372 	assert(n->norm->Bl.width);
1373 	return(1);
1374 }
1375 
1376 static int
1377 post_bl_block_width(POST_ARGS)
1378 {
1379 	size_t		  width;
1380 	int		  i;
1381 	enum mdoct	  tok;
1382 	struct mdoc_node *n;
1383 	char		  buf[NUMSIZ];
1384 
1385 	n = mdoc->last;
1386 
1387 	/*
1388 	 * Calculate the real width of a list from the -width string,
1389 	 * which may contain a macro (with a known default width), a
1390 	 * literal string, or a scaling width.
1391 	 *
1392 	 * If the value to -width is a macro, then we re-write it to be
1393 	 * the macro's width as set in share/tmac/mdoc/doc-common.
1394 	 */
1395 
1396 	if (0 == strcmp(n->norm->Bl.width, "Ds"))
1397 		width = 6;
1398 	else if (MDOC_MAX == (tok = mdoc_hash_find(n->norm->Bl.width)))
1399 		return(1);
1400 	else if (0 == (width = macro2len(tok)))  {
1401 		mdoc_nmsg(mdoc, n, MANDOCERR_BADWIDTH);
1402 		return(1);
1403 	}
1404 
1405 	/* The value already exists: free and reallocate it. */
1406 
1407 	assert(n->args);
1408 
1409 	for (i = 0; i < (int)n->args->argc; i++)
1410 		if (MDOC_Width == n->args->argv[i].arg)
1411 			break;
1412 
1413 	assert(i < (int)n->args->argc);
1414 
1415 	snprintf(buf, NUMSIZ, "%un", (unsigned int)width);
1416 	free(n->args->argv[i].value[0]);
1417 	n->args->argv[i].value[0] = mandoc_strdup(buf);
1418 
1419 	/* Set our width! */
1420 	n->norm->Bl.width = n->args->argv[i].value[0];
1421 	return(1);
1422 }
1423 
1424 static int
1425 post_bl_block_tag(POST_ARGS)
1426 {
1427 	struct mdoc_node *n, *nn;
1428 	size_t		  sz, ssz;
1429 	int		  i;
1430 	char		  buf[NUMSIZ];
1431 
1432 	/*
1433 	 * Calculate the -width for a `Bl -tag' list if it hasn't been
1434 	 * provided.  Uses the first head macro.  NOTE AGAIN: this is
1435 	 * ONLY if the -width argument has NOT been provided.  See
1436 	 * post_bl_block_width() for converting the -width string.
1437 	 */
1438 
1439 	sz = 10;
1440 	n = mdoc->last;
1441 
1442 	for (nn = n->body->child; nn; nn = nn->next) {
1443 		if (MDOC_It != nn->tok)
1444 			continue;
1445 
1446 		assert(MDOC_BLOCK == nn->type);
1447 		nn = nn->head->child;
1448 
1449 		if (nn == NULL)
1450 			break;
1451 
1452 		if (MDOC_TEXT == nn->type) {
1453 			sz = strlen(nn->string) + 1;
1454 			break;
1455 		}
1456 
1457 		if (0 != (ssz = macro2len(nn->tok)))
1458 			sz = ssz;
1459 
1460 		break;
1461 	}
1462 
1463 	/* Defaults to ten ens. */
1464 
1465 	snprintf(buf, NUMSIZ, "%un", (unsigned int)sz);
1466 
1467 	/*
1468 	 * We have to dynamically add this to the macro's argument list.
1469 	 * We're guaranteed that a MDOC_Width doesn't already exist.
1470 	 */
1471 
1472 	assert(n->args);
1473 	i = (int)(n->args->argc)++;
1474 
1475 	n->args->argv = mandoc_realloc(n->args->argv,
1476 			n->args->argc * sizeof(struct mdoc_argv));
1477 
1478 	n->args->argv[i].arg = MDOC_Width;
1479 	n->args->argv[i].line = n->line;
1480 	n->args->argv[i].pos = n->pos;
1481 	n->args->argv[i].sz = 1;
1482 	n->args->argv[i].value = mandoc_malloc(sizeof(char *));
1483 	n->args->argv[i].value[0] = mandoc_strdup(buf);
1484 
1485 	/* Set our width! */
1486 	n->norm->Bl.width = n->args->argv[i].value[0];
1487 	return(1);
1488 }
1489 
1490 
1491 static int
1492 post_bl_head(POST_ARGS)
1493 {
1494 	struct mdoc_node *np, *nn, *nnp;
1495 	int		  i, j;
1496 
1497 	if (LIST_column != mdoc->last->norm->Bl.type)
1498 		/* FIXME: this should be ERROR class... */
1499 		return(hwarn_eq0(mdoc));
1500 
1501 	/*
1502 	 * Convert old-style lists, where the column width specifiers
1503 	 * trail as macro parameters, to the new-style ("normal-form")
1504 	 * lists where they're argument values following -column.
1505 	 */
1506 
1507 	/* First, disallow both types and allow normal-form. */
1508 
1509 	/*
1510 	 * TODO: technically, we can accept both and just merge the two
1511 	 * lists, but I'll leave that for another day.
1512 	 */
1513 
1514 	if (mdoc->last->norm->Bl.ncols && mdoc->last->nchild) {
1515 		mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_COLUMNS);
1516 		return(0);
1517 	} else if (NULL == mdoc->last->child)
1518 		return(1);
1519 
1520 	np = mdoc->last->parent;
1521 	assert(np->args);
1522 
1523 	for (j = 0; j < (int)np->args->argc; j++)
1524 		if (MDOC_Column == np->args->argv[j].arg)
1525 			break;
1526 
1527 	assert(j < (int)np->args->argc);
1528 	assert(0 == np->args->argv[j].sz);
1529 
1530 	/*
1531 	 * Accommodate for new-style groff column syntax.  Shuffle the
1532 	 * child nodes, all of which must be TEXT, as arguments for the
1533 	 * column field.  Then, delete the head children.
1534 	 */
1535 
1536 	np->args->argv[j].sz = (size_t)mdoc->last->nchild;
1537 	np->args->argv[j].value = mandoc_malloc
1538 		((size_t)mdoc->last->nchild * sizeof(char *));
1539 
1540 	mdoc->last->norm->Bl.ncols = np->args->argv[j].sz;
1541 	mdoc->last->norm->Bl.cols = (void *)np->args->argv[j].value;
1542 
1543 	for (i = 0, nn = mdoc->last->child; nn; i++) {
1544 		np->args->argv[j].value[i] = nn->string;
1545 		nn->string = NULL;
1546 		nnp = nn;
1547 		nn = nn->next;
1548 		mdoc_node_delete(NULL, nnp);
1549 	}
1550 
1551 	mdoc->last->nchild = 0;
1552 	mdoc->last->child = NULL;
1553 
1554 	return(1);
1555 }
1556 
1557 static int
1558 post_bl(POST_ARGS)
1559 {
1560 	struct mdoc_node	*n;
1561 
1562 	if (MDOC_HEAD == mdoc->last->type)
1563 		return(post_bl_head(mdoc));
1564 	if (MDOC_BLOCK == mdoc->last->type)
1565 		return(post_bl_block(mdoc));
1566 	if (MDOC_BODY != mdoc->last->type)
1567 		return(1);
1568 
1569 	for (n = mdoc->last->child; n; n = n->next) {
1570 		switch (n->tok) {
1571 		case (MDOC_Lp):
1572 			/* FALLTHROUGH */
1573 		case (MDOC_Pp):
1574 			mdoc_nmsg(mdoc, n, MANDOCERR_CHILD);
1575 			/* FALLTHROUGH */
1576 		case (MDOC_It):
1577 			/* FALLTHROUGH */
1578 		case (MDOC_Sm):
1579 			continue;
1580 		default:
1581 			break;
1582 		}
1583 
1584 		mdoc_nmsg(mdoc, n, MANDOCERR_SYNTCHILD);
1585 		return(0);
1586 	}
1587 
1588 	return(1);
1589 }
1590 
1591 static int
1592 ebool(struct mdoc *mdoc)
1593 {
1594 
1595 	if (NULL == mdoc->last->child) {
1596 		mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_MACROEMPTY);
1597 		mdoc_node_delete(mdoc, mdoc->last);
1598 		return(1);
1599 	}
1600 	check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1);
1601 
1602 	assert(MDOC_TEXT == mdoc->last->child->type);
1603 
1604 	if (0 == strcmp(mdoc->last->child->string, "on"))
1605 		return(1);
1606 	if (0 == strcmp(mdoc->last->child->string, "off"))
1607 		return(1);
1608 
1609 	mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADBOOL);
1610 	return(1);
1611 }
1612 
1613 static int
1614 post_root(POST_ARGS)
1615 {
1616 	int		  erc;
1617 	struct mdoc_node *n;
1618 
1619 	erc = 0;
1620 
1621 	/* Check that we have a finished prologue. */
1622 
1623 	if ( ! (MDOC_PBODY & mdoc->flags)) {
1624 		erc++;
1625 		mdoc_nmsg(mdoc, mdoc->first, MANDOCERR_NODOCPROLOG);
1626 	}
1627 
1628 	n = mdoc->first;
1629 	assert(n);
1630 
1631 	/* Check that we begin with a proper `Sh'. */
1632 
1633 	if (NULL == n->child) {
1634 		erc++;
1635 		mdoc_nmsg(mdoc, n, MANDOCERR_NODOCBODY);
1636 	} else if (MDOC_BLOCK != n->child->type ||
1637 			MDOC_Sh != n->child->tok) {
1638 		erc++;
1639 		/* Can this be lifted?  See rxdebug.1 for example. */
1640 		mdoc_nmsg(mdoc, n, MANDOCERR_NODOCBODY);
1641 	}
1642 
1643 	return(erc ? 0 : 1);
1644 }
1645 
1646 static int
1647 post_st(POST_ARGS)
1648 {
1649 	struct mdoc_node	 *ch;
1650 	const char		 *p;
1651 
1652 	if (NULL == (ch = mdoc->last->child)) {
1653 		mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_MACROEMPTY);
1654 		mdoc_node_delete(mdoc, mdoc->last);
1655 		return(1);
1656 	}
1657 
1658 	assert(MDOC_TEXT == ch->type);
1659 
1660 	if (NULL == (p = mdoc_a2st(ch->string))) {
1661 		mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADSTANDARD);
1662 		mdoc_node_delete(mdoc, mdoc->last);
1663 	} else {
1664 		free(ch->string);
1665 		ch->string = mandoc_strdup(p);
1666 	}
1667 
1668 	return(1);
1669 }
1670 
1671 static int
1672 post_rs(POST_ARGS)
1673 {
1674 	struct mdoc_node *nn, *next, *prev;
1675 	int		  i, j;
1676 
1677 	switch (mdoc->last->type) {
1678 	case (MDOC_HEAD):
1679 		check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 0);
1680 		return(1);
1681 	case (MDOC_BODY):
1682 		if (mdoc->last->child)
1683 			break;
1684 		check_count(mdoc, MDOC_BODY, CHECK_WARN, CHECK_GT, 0);
1685 		return(1);
1686 	default:
1687 		return(1);
1688 	}
1689 
1690 	/*
1691 	 * Make sure only certain types of nodes are allowed within the
1692 	 * the `Rs' body.  Delete offending nodes and raise a warning.
1693 	 * Do this before re-ordering for the sake of clarity.
1694 	 */
1695 
1696 	next = NULL;
1697 	for (nn = mdoc->last->child; nn; nn = next) {
1698 		for (i = 0; i < RSORD_MAX; i++)
1699 			if (nn->tok == rsord[i])
1700 				break;
1701 
1702 		if (i < RSORD_MAX) {
1703 			if (MDOC__J == rsord[i] || MDOC__B == rsord[i])
1704 				mdoc->last->norm->Rs.quote_T++;
1705 			next = nn->next;
1706 			continue;
1707 		}
1708 
1709 		next = nn->next;
1710 		mdoc_nmsg(mdoc, nn, MANDOCERR_CHILD);
1711 		mdoc_node_delete(mdoc, nn);
1712 	}
1713 
1714 	/*
1715 	 * Nothing to sort if only invalid nodes were found
1716 	 * inside the `Rs' body.
1717 	 */
1718 
1719 	if (NULL == mdoc->last->child)
1720 		return(1);
1721 
1722 	/*
1723 	 * The full `Rs' block needs special handling to order the
1724 	 * sub-elements according to `rsord'.  Pick through each element
1725 	 * and correctly order it.  This is a insertion sort.
1726 	 */
1727 
1728 	next = NULL;
1729 	for (nn = mdoc->last->child->next; nn; nn = next) {
1730 		/* Determine order of `nn'. */
1731 		for (i = 0; i < RSORD_MAX; i++)
1732 			if (rsord[i] == nn->tok)
1733 				break;
1734 
1735 		/*
1736 		 * Remove `nn' from the chain.  This somewhat
1737 		 * repeats mdoc_node_unlink(), but since we're
1738 		 * just re-ordering, there's no need for the
1739 		 * full unlink process.
1740 		 */
1741 
1742 		if (NULL != (next = nn->next))
1743 			next->prev = nn->prev;
1744 
1745 		if (NULL != (prev = nn->prev))
1746 			prev->next = nn->next;
1747 
1748 		nn->prev = nn->next = NULL;
1749 
1750 		/*
1751 		 * Scan back until we reach a node that's
1752 		 * ordered before `nn'.
1753 		 */
1754 
1755 		for ( ; prev ; prev = prev->prev) {
1756 			/* Determine order of `prev'. */
1757 			for (j = 0; j < RSORD_MAX; j++)
1758 				if (rsord[j] == prev->tok)
1759 					break;
1760 
1761 			if (j <= i)
1762 				break;
1763 		}
1764 
1765 		/*
1766 		 * Set `nn' back into its correct place in front
1767 		 * of the `prev' node.
1768 		 */
1769 
1770 		nn->prev = prev;
1771 
1772 		if (prev) {
1773 			if (prev->next)
1774 				prev->next->prev = nn;
1775 			nn->next = prev->next;
1776 			prev->next = nn;
1777 		} else {
1778 			mdoc->last->child->prev = nn;
1779 			nn->next = mdoc->last->child;
1780 			mdoc->last->child = nn;
1781 		}
1782 	}
1783 
1784 	return(1);
1785 }
1786 
1787 static int
1788 post_ns(POST_ARGS)
1789 {
1790 
1791 	if (MDOC_LINE & mdoc->last->flags)
1792 		mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNNS);
1793 	return(1);
1794 }
1795 
1796 static int
1797 post_sh(POST_ARGS)
1798 {
1799 
1800 	if (MDOC_HEAD == mdoc->last->type)
1801 		return(post_sh_head(mdoc));
1802 	if (MDOC_BODY == mdoc->last->type)
1803 		return(post_sh_body(mdoc));
1804 
1805 	return(1);
1806 }
1807 
1808 static int
1809 post_sh_body(POST_ARGS)
1810 {
1811 	struct mdoc_node *n;
1812 
1813 	if (SEC_NAME != mdoc->lastsec)
1814 		return(1);
1815 
1816 	/*
1817 	 * Warn if the NAME section doesn't contain the `Nm' and `Nd'
1818 	 * macros (can have multiple `Nm' and one `Nd').  Note that the
1819 	 * children of the BODY declaration can also be "text".
1820 	 */
1821 
1822 	if (NULL == (n = mdoc->last->child)) {
1823 		mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC);
1824 		return(1);
1825 	}
1826 
1827 	for ( ; n && n->next; n = n->next) {
1828 		if (MDOC_ELEM == n->type && MDOC_Nm == n->tok)
1829 			continue;
1830 		if (MDOC_TEXT == n->type)
1831 			continue;
1832 		mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC);
1833 	}
1834 
1835 	assert(n);
1836 	if (MDOC_BLOCK == n->type && MDOC_Nd == n->tok)
1837 		return(1);
1838 
1839 	mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC);
1840 	return(1);
1841 }
1842 
1843 static int
1844 post_sh_head(POST_ARGS)
1845 {
1846 	char		 buf[BUFSIZ];
1847 	struct mdoc_node *n;
1848 	enum mdoc_sec	 sec;
1849 	int		 c;
1850 
1851 	/*
1852 	 * Process a new section.  Sections are either "named" or
1853 	 * "custom".  Custom sections are user-defined, while named ones
1854 	 * follow a conventional order and may only appear in certain
1855 	 * manual sections.
1856 	 */
1857 
1858 	sec = SEC_CUSTOM;
1859 	buf[0] = '\0';
1860 	if (-1 == (c = concat(buf, mdoc->last->child, BUFSIZ))) {
1861 		mdoc_nmsg(mdoc, mdoc->last->child, MANDOCERR_MEM);
1862 		return(0);
1863 	} else if (1 == c)
1864 		sec = a2sec(buf);
1865 
1866 	/* The NAME should be first. */
1867 
1868 	if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed)
1869 		mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NAMESECFIRST);
1870 
1871 	/* The SYNOPSIS gets special attention in other areas. */
1872 
1873 	if (SEC_SYNOPSIS == sec)
1874 		mdoc->flags |= MDOC_SYNOPSIS;
1875 	else
1876 		mdoc->flags &= ~MDOC_SYNOPSIS;
1877 
1878 	/* Mark our last section. */
1879 
1880 	mdoc->lastsec = sec;
1881 
1882 	/*
1883 	 * Set the section attribute for the current HEAD, for its
1884 	 * parent BLOCK, and for the HEAD children; the latter can
1885 	 * only be TEXT nodes, so no recursion is needed.
1886 	 * For other blocks and elements, including .Sh BODY, this is
1887 	 * done when allocating the node data structures, but for .Sh
1888 	 * BLOCK and HEAD, the section is still unknown at that time.
1889 	 */
1890 
1891 	mdoc->last->parent->sec = sec;
1892 	mdoc->last->sec = sec;
1893 	for (n = mdoc->last->child; n; n = n->next)
1894 		n->sec = sec;
1895 
1896 	/* We don't care about custom sections after this. */
1897 
1898 	if (SEC_CUSTOM == sec)
1899 		return(1);
1900 
1901 	/*
1902 	 * Check whether our non-custom section is being repeated or is
1903 	 * out of order.
1904 	 */
1905 
1906 	if (sec == mdoc->lastnamed)
1907 		mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SECREP);
1908 
1909 	if (sec < mdoc->lastnamed)
1910 		mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SECOOO);
1911 
1912 	/* Mark the last named section. */
1913 
1914 	mdoc->lastnamed = sec;
1915 
1916 	/* Check particular section/manual conventions. */
1917 
1918 	assert(mdoc->meta.msec);
1919 
1920 	switch (sec) {
1921 	case (SEC_RETURN_VALUES):
1922 		/* FALLTHROUGH */
1923 	case (SEC_ERRORS):
1924 		/* FALLTHROUGH */
1925 	case (SEC_LIBRARY):
1926 		if (*mdoc->meta.msec == '2')
1927 			break;
1928 		if (*mdoc->meta.msec == '3')
1929 			break;
1930 		if (*mdoc->meta.msec == '9')
1931 			break;
1932 		mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SECMSEC);
1933 		break;
1934 	default:
1935 		break;
1936 	}
1937 
1938 	return(1);
1939 }
1940 
1941 static int
1942 post_ignpar(POST_ARGS)
1943 {
1944 	struct mdoc_node *np;
1945 
1946 	if (MDOC_BODY != mdoc->last->type)
1947 		return(1);
1948 
1949 	if (NULL != (np = mdoc->last->child))
1950 		if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) {
1951 			mdoc_nmsg(mdoc, np, MANDOCERR_IGNPAR);
1952 			mdoc_node_delete(mdoc, np);
1953 		}
1954 
1955 	if (NULL != (np = mdoc->last->last))
1956 		if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) {
1957 			mdoc_nmsg(mdoc, np, MANDOCERR_IGNPAR);
1958 			mdoc_node_delete(mdoc, np);
1959 		}
1960 
1961 	return(1);
1962 }
1963 
1964 static int
1965 pre_par(PRE_ARGS)
1966 {
1967 
1968 	if (NULL == mdoc->last)
1969 		return(1);
1970 	if (MDOC_ELEM != n->type && MDOC_BLOCK != n->type)
1971 		return(1);
1972 
1973 	/*
1974 	 * Don't allow prior `Lp' or `Pp' prior to a paragraph-type
1975 	 * block:  `Lp', `Pp', or non-compact `Bd' or `Bl'.
1976 	 */
1977 
1978 	if (MDOC_Pp != mdoc->last->tok && MDOC_Lp != mdoc->last->tok)
1979 		return(1);
1980 	if (MDOC_Bl == n->tok && n->norm->Bl.comp)
1981 		return(1);
1982 	if (MDOC_Bd == n->tok && n->norm->Bd.comp)
1983 		return(1);
1984 	if (MDOC_It == n->tok && n->parent->norm->Bl.comp)
1985 		return(1);
1986 
1987 	mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNPAR);
1988 	mdoc_node_delete(mdoc, mdoc->last);
1989 	return(1);
1990 }
1991 
1992 static int
1993 pre_literal(PRE_ARGS)
1994 {
1995 
1996 	if (MDOC_BODY != n->type)
1997 		return(1);
1998 
1999 	/*
2000 	 * The `Dl' (note "el" not "one") and `Bd -literal' and `Bd
2001 	 * -unfilled' macros set MDOC_LITERAL on entrance to the body.
2002 	 */
2003 
2004 	switch (n->tok) {
2005 	case (MDOC_Dl):
2006 		mdoc->flags |= MDOC_LITERAL;
2007 		break;
2008 	case (MDOC_Bd):
2009 		if (DISP_literal == n->norm->Bd.type)
2010 			mdoc->flags |= MDOC_LITERAL;
2011 		if (DISP_unfilled == n->norm->Bd.type)
2012 			mdoc->flags |= MDOC_LITERAL;
2013 		break;
2014 	default:
2015 		abort();
2016 		/* NOTREACHED */
2017 	}
2018 
2019 	return(1);
2020 }
2021 
2022 static int
2023 post_dd(POST_ARGS)
2024 {
2025 	char		  buf[DATESIZE];
2026 	struct mdoc_node *n;
2027 	int		  c;
2028 
2029 	if (mdoc->meta.date)
2030 		free(mdoc->meta.date);
2031 
2032 	n = mdoc->last;
2033 	if (NULL == n->child || '\0' == n->child->string[0]) {
2034 		mdoc->meta.date = mandoc_normdate
2035 			(mdoc->parse, NULL, n->line, n->pos);
2036 		return(1);
2037 	}
2038 
2039 	buf[0] = '\0';
2040 	if (-1 == (c = concat(buf, n->child, DATESIZE))) {
2041 		mdoc_nmsg(mdoc, n->child, MANDOCERR_MEM);
2042 		return(0);
2043 	}
2044 
2045 	assert(c);
2046 	mdoc->meta.date = mandoc_normdate
2047 		(mdoc->parse, buf, n->line, n->pos);
2048 
2049 	return(1);
2050 }
2051 
2052 static int
2053 post_dt(POST_ARGS)
2054 {
2055 	struct mdoc_node *nn, *n;
2056 	const char	 *cp;
2057 	char		 *p;
2058 
2059 	n = mdoc->last;
2060 
2061 	if (mdoc->meta.title)
2062 		free(mdoc->meta.title);
2063 	if (mdoc->meta.vol)
2064 		free(mdoc->meta.vol);
2065 	if (mdoc->meta.arch)
2066 		free(mdoc->meta.arch);
2067 
2068 	mdoc->meta.title = mdoc->meta.vol = mdoc->meta.arch = NULL;
2069 
2070 	/* First make all characters uppercase. */
2071 
2072 	if (NULL != (nn = n->child))
2073 		for (p = nn->string; *p; p++) {
2074 			if (toupper((unsigned char)*p) == *p)
2075 				continue;
2076 
2077 			/*
2078 			 * FIXME: don't be lazy: have this make all
2079 			 * characters be uppercase and just warn once.
2080 			 */
2081 			mdoc_nmsg(mdoc, nn, MANDOCERR_UPPERCASE);
2082 			break;
2083 		}
2084 
2085 	/* Handles: `.Dt'
2086 	 *   --> title = unknown, volume = local, msec = 0, arch = NULL
2087 	 */
2088 
2089 	if (NULL == (nn = n->child)) {
2090 		/* XXX: make these macro values. */
2091 		/* FIXME: warn about missing values. */
2092 		mdoc->meta.title = mandoc_strdup("UNKNOWN");
2093 		mdoc->meta.vol = mandoc_strdup("LOCAL");
2094 		mdoc->meta.msec = mandoc_strdup("1");
2095 		return(1);
2096 	}
2097 
2098 	/* Handles: `.Dt TITLE'
2099 	 *   --> title = TITLE, volume = local, msec = 0, arch = NULL
2100 	 */
2101 
2102 	mdoc->meta.title = mandoc_strdup
2103 		('\0' == nn->string[0] ? "UNKNOWN" : nn->string);
2104 
2105 	if (NULL == (nn = nn->next)) {
2106 		/* FIXME: warn about missing msec. */
2107 		/* XXX: make this a macro value. */
2108 		mdoc->meta.vol = mandoc_strdup("LOCAL");
2109 		mdoc->meta.msec = mandoc_strdup("1");
2110 		return(1);
2111 	}
2112 
2113 	/* Handles: `.Dt TITLE SEC'
2114 	 *   --> title = TITLE, volume = SEC is msec ?
2115 	 *           format(msec) : SEC,
2116 	 *       msec = SEC is msec ? atoi(msec) : 0,
2117 	 *       arch = NULL
2118 	 */
2119 
2120 	cp = mandoc_a2msec(nn->string);
2121 	if (cp) {
2122 		mdoc->meta.vol = mandoc_strdup(cp);
2123 		mdoc->meta.msec = mandoc_strdup(nn->string);
2124 	} else {
2125 		mdoc_nmsg(mdoc, n, MANDOCERR_BADMSEC);
2126 		mdoc->meta.vol = mandoc_strdup(nn->string);
2127 		mdoc->meta.msec = mandoc_strdup(nn->string);
2128 	}
2129 
2130 	if (NULL == (nn = nn->next))
2131 		return(1);
2132 
2133 	/* Handles: `.Dt TITLE SEC VOL'
2134 	 *   --> title = TITLE, volume = VOL is vol ?
2135 	 *       format(VOL) :
2136 	 *           VOL is arch ? format(arch) :
2137 	 *               VOL
2138 	 */
2139 
2140 	cp = mdoc_a2vol(nn->string);
2141 	if (cp) {
2142 		free(mdoc->meta.vol);
2143 		mdoc->meta.vol = mandoc_strdup(cp);
2144 	} else {
2145 		/* FIXME: warn about bad arch. */
2146 		cp = mdoc_a2arch(nn->string);
2147 		if (NULL == cp) {
2148 			free(mdoc->meta.vol);
2149 			mdoc->meta.vol = mandoc_strdup(nn->string);
2150 		} else
2151 			mdoc->meta.arch = mandoc_strdup(cp);
2152 	}
2153 
2154 	/* Ignore any subsequent parameters... */
2155 	/* FIXME: warn about subsequent parameters. */
2156 
2157 	return(1);
2158 }
2159 
2160 static int
2161 post_prol(POST_ARGS)
2162 {
2163 	/*
2164 	 * Remove prologue macros from the document after they're
2165 	 * processed.  The final document uses mdoc_meta for these
2166 	 * values and discards the originals.
2167 	 */
2168 
2169 	mdoc_node_delete(mdoc, mdoc->last);
2170 	if (mdoc->meta.title && mdoc->meta.date && mdoc->meta.os)
2171 		mdoc->flags |= MDOC_PBODY;
2172 
2173 	return(1);
2174 }
2175 
2176 static int
2177 post_bx(POST_ARGS)
2178 {
2179 	struct mdoc_node	*n;
2180 
2181 	/*
2182 	 * Make `Bx's second argument always start with an uppercase
2183 	 * letter.  Groff checks if it's an "accepted" term, but we just
2184 	 * uppercase blindly.
2185 	 */
2186 
2187 	n = mdoc->last->child;
2188 	if (n && NULL != (n = n->next))
2189 		*n->string = (char)toupper
2190 			((unsigned char)*n->string);
2191 
2192 	return(1);
2193 }
2194 
2195 static int
2196 post_os(POST_ARGS)
2197 {
2198 	struct mdoc_node *n;
2199 	char		  buf[BUFSIZ];
2200 	int		  c;
2201 #ifndef OSNAME
2202 	struct utsname	  utsname;
2203 #endif
2204 
2205 	n = mdoc->last;
2206 
2207 	/*
2208 	 * Set the operating system by way of the `Os' macro.
2209 	 * The order of precedence is:
2210 	 * 1. the argument of the `Os' macro, unless empty
2211 	 * 2. the -Ios=foo command line argument, if provided
2212 	 * 3. -DOSNAME="\"foo\"", if provided during compilation
2213 	 * 4. "sysname release" from uname(3)
2214  	 */
2215 
2216 	free(mdoc->meta.os);
2217 
2218 	buf[0] = '\0';
2219 	if (-1 == (c = concat(buf, n->child, BUFSIZ))) {
2220 		mdoc_nmsg(mdoc, n->child, MANDOCERR_MEM);
2221 		return(0);
2222 	}
2223 
2224 	assert(c);
2225 
2226 	if ('\0' == buf[0]) {
2227 		if (mdoc->defos) {
2228 			mdoc->meta.os = mandoc_strdup(mdoc->defos);
2229 			return(1);
2230 		}
2231 #ifdef OSNAME
2232 		if (strlcat(buf, OSNAME, BUFSIZ) >= BUFSIZ) {
2233 			mdoc_nmsg(mdoc, n, MANDOCERR_MEM);
2234 			return(0);
2235 		}
2236 #else /*!OSNAME */
2237 		if (-1 == uname(&utsname)) {
2238 			mdoc_nmsg(mdoc, n, MANDOCERR_UNAME);
2239                         mdoc->meta.os = mandoc_strdup("UNKNOWN");
2240                         return(post_prol(mdoc));
2241                 }
2242 
2243 		if (strlcat(buf, utsname.sysname, BUFSIZ) >= BUFSIZ) {
2244 			mdoc_nmsg(mdoc, n, MANDOCERR_MEM);
2245 			return(0);
2246 		}
2247 		if (strlcat(buf, " ", BUFSIZ) >= BUFSIZ) {
2248 			mdoc_nmsg(mdoc, n, MANDOCERR_MEM);
2249 			return(0);
2250 		}
2251 		if (strlcat(buf, utsname.release, BUFSIZ) >= BUFSIZ) {
2252 			mdoc_nmsg(mdoc, n, MANDOCERR_MEM);
2253 			return(0);
2254 		}
2255 #endif /*!OSNAME*/
2256 	}
2257 
2258 	mdoc->meta.os = mandoc_strdup(buf);
2259 	return(1);
2260 }
2261 
2262 static int
2263 post_std(POST_ARGS)
2264 {
2265 	struct mdoc_node *nn, *n;
2266 
2267 	n = mdoc->last;
2268 
2269 	/*
2270 	 * Macros accepting `-std' as an argument have the name of the
2271 	 * current document (`Nm') filled in as the argument if it's not
2272 	 * provided.
2273 	 */
2274 
2275 	if (n->child)
2276 		return(1);
2277 
2278 	if (NULL == mdoc->meta.name)
2279 		return(1);
2280 
2281 	nn = n;
2282 	mdoc->next = MDOC_NEXT_CHILD;
2283 
2284 	if ( ! mdoc_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name))
2285 		return(0);
2286 
2287 	mdoc->last = nn;
2288 	return(1);
2289 }
2290 
2291 /*
2292  * Concatenate a node, stopping at the first non-text.
2293  * Concatenation is separated by a single whitespace.
2294  * Returns -1 on fatal (string overrun) error, 0 if child nodes were
2295  * encountered, 1 otherwise.
2296  */
2297 static int
2298 concat(char *p, const struct mdoc_node *n, size_t sz)
2299 {
2300 
2301 	for ( ; NULL != n; n = n->next) {
2302 		if (MDOC_TEXT != n->type)
2303 			return(0);
2304 		if ('\0' != p[0] && strlcat(p, " ", sz) >= sz)
2305 			return(-1);
2306 		if (strlcat(p, n->string, sz) >= sz)
2307 			return(-1);
2308 		concat(p, n->child, sz);
2309 	}
2310 
2311 	return(1);
2312 }
2313 
2314 static enum mdoc_sec
2315 a2sec(const char *p)
2316 {
2317 	int		 i;
2318 
2319 	for (i = 0; i < (int)SEC__MAX; i++)
2320 		if (secnames[i] && 0 == strcmp(p, secnames[i]))
2321 			return((enum mdoc_sec)i);
2322 
2323 	return(SEC_CUSTOM);
2324 }
2325 
2326 static size_t
2327 macro2len(enum mdoct macro)
2328 {
2329 
2330 	switch (macro) {
2331 	case(MDOC_Ad):
2332 		return(12);
2333 	case(MDOC_Ao):
2334 		return(12);
2335 	case(MDOC_An):
2336 		return(12);
2337 	case(MDOC_Aq):
2338 		return(12);
2339 	case(MDOC_Ar):
2340 		return(12);
2341 	case(MDOC_Bo):
2342 		return(12);
2343 	case(MDOC_Bq):
2344 		return(12);
2345 	case(MDOC_Cd):
2346 		return(12);
2347 	case(MDOC_Cm):
2348 		return(10);
2349 	case(MDOC_Do):
2350 		return(10);
2351 	case(MDOC_Dq):
2352 		return(12);
2353 	case(MDOC_Dv):
2354 		return(12);
2355 	case(MDOC_Eo):
2356 		return(12);
2357 	case(MDOC_Em):
2358 		return(10);
2359 	case(MDOC_Er):
2360 		return(17);
2361 	case(MDOC_Ev):
2362 		return(15);
2363 	case(MDOC_Fa):
2364 		return(12);
2365 	case(MDOC_Fl):
2366 		return(10);
2367 	case(MDOC_Fo):
2368 		return(16);
2369 	case(MDOC_Fn):
2370 		return(16);
2371 	case(MDOC_Ic):
2372 		return(10);
2373 	case(MDOC_Li):
2374 		return(16);
2375 	case(MDOC_Ms):
2376 		return(6);
2377 	case(MDOC_Nm):
2378 		return(10);
2379 	case(MDOC_No):
2380 		return(12);
2381 	case(MDOC_Oo):
2382 		return(10);
2383 	case(MDOC_Op):
2384 		return(14);
2385 	case(MDOC_Pa):
2386 		return(32);
2387 	case(MDOC_Pf):
2388 		return(12);
2389 	case(MDOC_Po):
2390 		return(12);
2391 	case(MDOC_Pq):
2392 		return(12);
2393 	case(MDOC_Ql):
2394 		return(16);
2395 	case(MDOC_Qo):
2396 		return(12);
2397 	case(MDOC_So):
2398 		return(12);
2399 	case(MDOC_Sq):
2400 		return(12);
2401 	case(MDOC_Sy):
2402 		return(6);
2403 	case(MDOC_Sx):
2404 		return(16);
2405 	case(MDOC_Tn):
2406 		return(10);
2407 	case(MDOC_Va):
2408 		return(12);
2409 	case(MDOC_Vt):
2410 		return(12);
2411 	case(MDOC_Xr):
2412 		return(10);
2413 	default:
2414 		break;
2415 	};
2416 	return(0);
2417 }
2418