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