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