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