xref: /dragonfly/contrib/mdocml/mdoc_validate.c (revision 31c7ac8b)
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_ERRORS):
2045 		if (*mdoc->meta.msec == '4')
2046 			break;
2047 		/* FALLTHROUGH */
2048 	case (SEC_RETURN_VALUES):
2049 		/* FALLTHROUGH */
2050 	case (SEC_LIBRARY):
2051 		if (*mdoc->meta.msec == '2')
2052 			break;
2053 		if (*mdoc->meta.msec == '3')
2054 			break;
2055 		if (*mdoc->meta.msec == '9')
2056 			break;
2057 		mandoc_msg(MANDOCERR_SECMSEC, mdoc->parse,
2058 				mdoc->last->line, mdoc->last->pos, buf);
2059 		break;
2060 	default:
2061 		break;
2062 	}
2063 
2064 	return(1);
2065 }
2066 
2067 static int
2068 post_ignpar(POST_ARGS)
2069 {
2070 	struct mdoc_node *np;
2071 
2072 	if (MDOC_BODY != mdoc->last->type)
2073 		return(1);
2074 
2075 	if (NULL != (np = mdoc->last->child))
2076 		if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) {
2077 			mdoc_nmsg(mdoc, np, MANDOCERR_IGNPAR);
2078 			mdoc_node_delete(mdoc, np);
2079 		}
2080 
2081 	if (NULL != (np = mdoc->last->last))
2082 		if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) {
2083 			mdoc_nmsg(mdoc, np, MANDOCERR_IGNPAR);
2084 			mdoc_node_delete(mdoc, np);
2085 		}
2086 
2087 	return(1);
2088 }
2089 
2090 static int
2091 pre_par(PRE_ARGS)
2092 {
2093 
2094 	if (NULL == mdoc->last)
2095 		return(1);
2096 	if (MDOC_ELEM != n->type && MDOC_BLOCK != n->type)
2097 		return(1);
2098 
2099 	/*
2100 	 * Don't allow prior `Lp' or `Pp' prior to a paragraph-type
2101 	 * block:  `Lp', `Pp', or non-compact `Bd' or `Bl'.
2102 	 */
2103 
2104 	if (MDOC_Pp != mdoc->last->tok &&
2105 	    MDOC_Lp != mdoc->last->tok &&
2106 	    MDOC_br != mdoc->last->tok)
2107 		return(1);
2108 	if (MDOC_Bl == n->tok && n->norm->Bl.comp)
2109 		return(1);
2110 	if (MDOC_Bd == n->tok && n->norm->Bd.comp)
2111 		return(1);
2112 	if (MDOC_It == n->tok && n->parent->norm->Bl.comp)
2113 		return(1);
2114 
2115 	mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNPAR);
2116 	mdoc_node_delete(mdoc, mdoc->last);
2117 	return(1);
2118 }
2119 
2120 static int
2121 post_par(POST_ARGS)
2122 {
2123 
2124 	if (MDOC_ELEM != mdoc->last->type &&
2125 	    MDOC_BLOCK != mdoc->last->type)
2126 		return(1);
2127 
2128 	if (NULL == mdoc->last->prev) {
2129 		if (MDOC_Sh != mdoc->last->parent->tok &&
2130 		    MDOC_Ss != mdoc->last->parent->tok)
2131 			return(1);
2132 	} else {
2133 		if (MDOC_Pp != mdoc->last->prev->tok &&
2134 		    MDOC_Lp != mdoc->last->prev->tok &&
2135 		    (MDOC_br != mdoc->last->tok ||
2136 		     (MDOC_sp != mdoc->last->prev->tok &&
2137 		      MDOC_br != mdoc->last->prev->tok)))
2138 			return(1);
2139 	}
2140 
2141 	mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNPAR);
2142 	mdoc_node_delete(mdoc, mdoc->last);
2143 	return(1);
2144 }
2145 
2146 static int
2147 pre_literal(PRE_ARGS)
2148 {
2149 
2150 	if (MDOC_BODY != n->type)
2151 		return(1);
2152 
2153 	/*
2154 	 * The `Dl' (note "el" not "one") and `Bd -literal' and `Bd
2155 	 * -unfilled' macros set MDOC_LITERAL on entrance to the body.
2156 	 */
2157 
2158 	switch (n->tok) {
2159 	case (MDOC_Dl):
2160 		mdoc->flags |= MDOC_LITERAL;
2161 		break;
2162 	case (MDOC_Bd):
2163 		if (DISP_literal == n->norm->Bd.type)
2164 			mdoc->flags |= MDOC_LITERAL;
2165 		if (DISP_unfilled == n->norm->Bd.type)
2166 			mdoc->flags |= MDOC_LITERAL;
2167 		break;
2168 	default:
2169 		abort();
2170 		/* NOTREACHED */
2171 	}
2172 
2173 	return(1);
2174 }
2175 
2176 static int
2177 post_dd(POST_ARGS)
2178 {
2179 	char		  buf[DATESIZE];
2180 	struct mdoc_node *n;
2181 	int		  c;
2182 
2183 	if (mdoc->meta.date)
2184 		free(mdoc->meta.date);
2185 
2186 	n = mdoc->last;
2187 	if (NULL == n->child || '\0' == n->child->string[0]) {
2188 		mdoc->meta.date = mandoc_normdate
2189 			(mdoc->parse, NULL, n->line, n->pos);
2190 		return(1);
2191 	}
2192 
2193 	buf[0] = '\0';
2194 	if (-1 == (c = concat(buf, n->child, DATESIZE))) {
2195 		mdoc_nmsg(mdoc, n->child, MANDOCERR_MEM);
2196 		return(0);
2197 	}
2198 
2199 	assert(c);
2200 	mdoc->meta.date = mandoc_normdate
2201 		(mdoc->parse, buf, n->line, n->pos);
2202 
2203 	return(1);
2204 }
2205 
2206 static int
2207 post_dt(POST_ARGS)
2208 {
2209 	struct mdoc_node *nn, *n;
2210 	const char	 *cp;
2211 	char		 *p;
2212 
2213 	n = mdoc->last;
2214 
2215 	if (mdoc->meta.title)
2216 		free(mdoc->meta.title);
2217 	if (mdoc->meta.vol)
2218 		free(mdoc->meta.vol);
2219 	if (mdoc->meta.arch)
2220 		free(mdoc->meta.arch);
2221 
2222 	mdoc->meta.title = mdoc->meta.vol = mdoc->meta.arch = NULL;
2223 
2224 	/* First make all characters uppercase. */
2225 
2226 	if (NULL != (nn = n->child))
2227 		for (p = nn->string; *p; p++) {
2228 			if (toupper((unsigned char)*p) == *p)
2229 				continue;
2230 
2231 			/*
2232 			 * FIXME: don't be lazy: have this make all
2233 			 * characters be uppercase and just warn once.
2234 			 */
2235 			mdoc_nmsg(mdoc, nn, MANDOCERR_UPPERCASE);
2236 			break;
2237 		}
2238 
2239 	/* Handles: `.Dt'
2240 	 *   --> title = unknown, volume = local, msec = 0, arch = NULL
2241 	 */
2242 
2243 	if (NULL == (nn = n->child)) {
2244 		/* XXX: make these macro values. */
2245 		/* FIXME: warn about missing values. */
2246 		mdoc->meta.title = mandoc_strdup("UNKNOWN");
2247 		mdoc->meta.vol = mandoc_strdup("LOCAL");
2248 		mdoc->meta.msec = mandoc_strdup("1");
2249 		return(1);
2250 	}
2251 
2252 	/* Handles: `.Dt TITLE'
2253 	 *   --> title = TITLE, volume = local, msec = 0, arch = NULL
2254 	 */
2255 
2256 	mdoc->meta.title = mandoc_strdup
2257 		('\0' == nn->string[0] ? "UNKNOWN" : nn->string);
2258 
2259 	if (NULL == (nn = nn->next)) {
2260 		/* FIXME: warn about missing msec. */
2261 		/* XXX: make this a macro value. */
2262 		mdoc->meta.vol = mandoc_strdup("LOCAL");
2263 		mdoc->meta.msec = mandoc_strdup("1");
2264 		return(1);
2265 	}
2266 
2267 	/* Handles: `.Dt TITLE SEC'
2268 	 *   --> title = TITLE, volume = SEC is msec ?
2269 	 *           format(msec) : SEC,
2270 	 *       msec = SEC is msec ? atoi(msec) : 0,
2271 	 *       arch = NULL
2272 	 */
2273 
2274 	cp = mandoc_a2msec(nn->string);
2275 	if (cp) {
2276 		mdoc->meta.vol = mandoc_strdup(cp);
2277 		mdoc->meta.msec = mandoc_strdup(nn->string);
2278 	} else {
2279 		mdoc_nmsg(mdoc, n, MANDOCERR_BADMSEC);
2280 		mdoc->meta.vol = mandoc_strdup(nn->string);
2281 		mdoc->meta.msec = mandoc_strdup(nn->string);
2282 	}
2283 
2284 	if (NULL == (nn = nn->next))
2285 		return(1);
2286 
2287 	/* Handles: `.Dt TITLE SEC VOL'
2288 	 *   --> title = TITLE, volume = VOL is vol ?
2289 	 *       format(VOL) :
2290 	 *           VOL is arch ? format(arch) :
2291 	 *               VOL
2292 	 */
2293 
2294 	cp = mdoc_a2vol(nn->string);
2295 	if (cp) {
2296 		free(mdoc->meta.vol);
2297 		mdoc->meta.vol = mandoc_strdup(cp);
2298 	} else {
2299 		cp = mdoc_a2arch(nn->string);
2300 		if (NULL == cp) {
2301 			mdoc_nmsg(mdoc, nn, MANDOCERR_BADVOLARCH);
2302 			free(mdoc->meta.vol);
2303 			mdoc->meta.vol = mandoc_strdup(nn->string);
2304 		} else
2305 			mdoc->meta.arch = mandoc_strdup(cp);
2306 	}
2307 
2308 	/* Ignore any subsequent parameters... */
2309 	/* FIXME: warn about subsequent parameters. */
2310 
2311 	return(1);
2312 }
2313 
2314 static int
2315 post_prol(POST_ARGS)
2316 {
2317 	/*
2318 	 * Remove prologue macros from the document after they're
2319 	 * processed.  The final document uses mdoc_meta for these
2320 	 * values and discards the originals.
2321 	 */
2322 
2323 	mdoc_node_delete(mdoc, mdoc->last);
2324 	if (mdoc->meta.title && mdoc->meta.date && mdoc->meta.os)
2325 		mdoc->flags |= MDOC_PBODY;
2326 
2327 	return(1);
2328 }
2329 
2330 static int
2331 post_bx(POST_ARGS)
2332 {
2333 	struct mdoc_node	*n;
2334 
2335 	/*
2336 	 * Make `Bx's second argument always start with an uppercase
2337 	 * letter.  Groff checks if it's an "accepted" term, but we just
2338 	 * uppercase blindly.
2339 	 */
2340 
2341 	n = mdoc->last->child;
2342 	if (n && NULL != (n = n->next))
2343 		*n->string = (char)toupper
2344 			((unsigned char)*n->string);
2345 
2346 	return(1);
2347 }
2348 
2349 static int
2350 post_os(POST_ARGS)
2351 {
2352 	struct mdoc_node *n;
2353 	char		  buf[BUFSIZ];
2354 	int		  c;
2355 #ifndef OSNAME
2356 	struct utsname	  utsname;
2357 #endif
2358 
2359 	n = mdoc->last;
2360 
2361 	/*
2362 	 * Set the operating system by way of the `Os' macro.
2363 	 * The order of precedence is:
2364 	 * 1. the argument of the `Os' macro, unless empty
2365 	 * 2. the -Ios=foo command line argument, if provided
2366 	 * 3. -DOSNAME="\"foo\"", if provided during compilation
2367 	 * 4. "sysname release" from uname(3)
2368  	 */
2369 
2370 	free(mdoc->meta.os);
2371 
2372 	buf[0] = '\0';
2373 	if (-1 == (c = concat(buf, n->child, BUFSIZ))) {
2374 		mdoc_nmsg(mdoc, n->child, MANDOCERR_MEM);
2375 		return(0);
2376 	}
2377 
2378 	assert(c);
2379 
2380 	if ('\0' == buf[0]) {
2381 		if (mdoc->defos) {
2382 			mdoc->meta.os = mandoc_strdup(mdoc->defos);
2383 			return(1);
2384 		}
2385 #ifdef OSNAME
2386 		if (strlcat(buf, OSNAME, BUFSIZ) >= BUFSIZ) {
2387 			mdoc_nmsg(mdoc, n, MANDOCERR_MEM);
2388 			return(0);
2389 		}
2390 #else /*!OSNAME */
2391 		if (-1 == uname(&utsname)) {
2392 			mdoc_nmsg(mdoc, n, MANDOCERR_UNAME);
2393                         mdoc->meta.os = mandoc_strdup("UNKNOWN");
2394                         return(post_prol(mdoc));
2395                 }
2396 
2397 		if (strlcat(buf, utsname.sysname, BUFSIZ) >= BUFSIZ) {
2398 			mdoc_nmsg(mdoc, n, MANDOCERR_MEM);
2399 			return(0);
2400 		}
2401 		if (strlcat(buf, " ", BUFSIZ) >= BUFSIZ) {
2402 			mdoc_nmsg(mdoc, n, MANDOCERR_MEM);
2403 			return(0);
2404 		}
2405 		if (strlcat(buf, utsname.release, BUFSIZ) >= BUFSIZ) {
2406 			mdoc_nmsg(mdoc, n, MANDOCERR_MEM);
2407 			return(0);
2408 		}
2409 #endif /*!OSNAME*/
2410 	}
2411 
2412 	mdoc->meta.os = mandoc_strdup(buf);
2413 	return(1);
2414 }
2415 
2416 static int
2417 post_std(POST_ARGS)
2418 {
2419 	struct mdoc_node *nn, *n;
2420 
2421 	n = mdoc->last;
2422 
2423 	/*
2424 	 * Macros accepting `-std' as an argument have the name of the
2425 	 * current document (`Nm') filled in as the argument if it's not
2426 	 * provided.
2427 	 */
2428 
2429 	if (n->child)
2430 		return(1);
2431 
2432 	if (NULL == mdoc->meta.name)
2433 		return(1);
2434 
2435 	nn = n;
2436 	mdoc->next = MDOC_NEXT_CHILD;
2437 
2438 	if ( ! mdoc_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name))
2439 		return(0);
2440 
2441 	mdoc->last = nn;
2442 	return(1);
2443 }
2444 
2445 /*
2446  * Concatenate a node, stopping at the first non-text.
2447  * Concatenation is separated by a single whitespace.
2448  * Returns -1 on fatal (string overrun) error, 0 if child nodes were
2449  * encountered, 1 otherwise.
2450  */
2451 static int
2452 concat(char *p, const struct mdoc_node *n, size_t sz)
2453 {
2454 
2455 	for ( ; NULL != n; n = n->next) {
2456 		if (MDOC_TEXT != n->type)
2457 			return(0);
2458 		if ('\0' != p[0] && strlcat(p, " ", sz) >= sz)
2459 			return(-1);
2460 		if (strlcat(p, n->string, sz) >= sz)
2461 			return(-1);
2462 		concat(p, n->child, sz);
2463 	}
2464 
2465 	return(1);
2466 }
2467 
2468 static enum mdoc_sec
2469 a2sec(const char *p)
2470 {
2471 	int		 i;
2472 
2473 	for (i = 0; i < (int)SEC__MAX; i++)
2474 		if (secnames[i] && 0 == strcmp(p, secnames[i]))
2475 			return((enum mdoc_sec)i);
2476 
2477 	return(SEC_CUSTOM);
2478 }
2479 
2480 static size_t
2481 macro2len(enum mdoct macro)
2482 {
2483 
2484 	switch (macro) {
2485 	case(MDOC_Ad):
2486 		return(12);
2487 	case(MDOC_Ao):
2488 		return(12);
2489 	case(MDOC_An):
2490 		return(12);
2491 	case(MDOC_Aq):
2492 		return(12);
2493 	case(MDOC_Ar):
2494 		return(12);
2495 	case(MDOC_Bo):
2496 		return(12);
2497 	case(MDOC_Bq):
2498 		return(12);
2499 	case(MDOC_Cd):
2500 		return(12);
2501 	case(MDOC_Cm):
2502 		return(10);
2503 	case(MDOC_Do):
2504 		return(10);
2505 	case(MDOC_Dq):
2506 		return(12);
2507 	case(MDOC_Dv):
2508 		return(12);
2509 	case(MDOC_Eo):
2510 		return(12);
2511 	case(MDOC_Em):
2512 		return(10);
2513 	case(MDOC_Er):
2514 		return(17);
2515 	case(MDOC_Ev):
2516 		return(15);
2517 	case(MDOC_Fa):
2518 		return(12);
2519 	case(MDOC_Fl):
2520 		return(10);
2521 	case(MDOC_Fo):
2522 		return(16);
2523 	case(MDOC_Fn):
2524 		return(16);
2525 	case(MDOC_Ic):
2526 		return(10);
2527 	case(MDOC_Li):
2528 		return(16);
2529 	case(MDOC_Ms):
2530 		return(6);
2531 	case(MDOC_Nm):
2532 		return(10);
2533 	case(MDOC_No):
2534 		return(12);
2535 	case(MDOC_Oo):
2536 		return(10);
2537 	case(MDOC_Op):
2538 		return(14);
2539 	case(MDOC_Pa):
2540 		return(32);
2541 	case(MDOC_Pf):
2542 		return(12);
2543 	case(MDOC_Po):
2544 		return(12);
2545 	case(MDOC_Pq):
2546 		return(12);
2547 	case(MDOC_Ql):
2548 		return(16);
2549 	case(MDOC_Qo):
2550 		return(12);
2551 	case(MDOC_So):
2552 		return(12);
2553 	case(MDOC_Sq):
2554 		return(12);
2555 	case(MDOC_Sy):
2556 		return(6);
2557 	case(MDOC_Sx):
2558 		return(16);
2559 	case(MDOC_Tn):
2560 		return(10);
2561 	case(MDOC_Va):
2562 		return(12);
2563 	case(MDOC_Vt):
2564 		return(12);
2565 	case(MDOC_Xr):
2566 		return(10);
2567 	default:
2568 		break;
2569 	};
2570 	return(0);
2571 }
2572