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