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