xref: /openbsd-src/usr.bin/mandoc/mdoc_validate.c (revision 5054e3e78af0749a9bb00ba9a024b3ee2d90290f)
1 /*	$Id: mdoc_validate.c,v 1.38 2009/10/27 21:40:07 schwarze Exp $ */
2 /*
3  * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 #include <sys/types.h>
18 
19 #include <assert.h>
20 #include <ctype.h>
21 #include <errno.h>
22 #include <limits.h>
23 #include <stdarg.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include "libmdoc.h"
28 #include "libmandoc.h"
29 
30 /* FIXME: .Bl -diag can't have non-text children in HEAD. */
31 /* TODO: ignoring Pp (it's superfluous in some invocations). */
32 
33 #define	PRE_ARGS  struct mdoc *mdoc, const struct mdoc_node *n
34 #define	POST_ARGS struct mdoc *mdoc
35 
36 typedef	int	(*v_pre)(PRE_ARGS);
37 typedef	int	(*v_post)(POST_ARGS);
38 
39 struct	valids {
40 	v_pre	*pre;
41 	v_post	*post;
42 };
43 
44 static	int	 check_parent(PRE_ARGS, int, enum mdoc_type);
45 static	int	 check_msec(PRE_ARGS, ...);
46 static	int	 check_sec(PRE_ARGS, ...);
47 static	int	 check_stdarg(PRE_ARGS);
48 static	int	 check_text(struct mdoc *, int, int, const char *);
49 static	int	 check_argv(struct mdoc *,
50 			const struct mdoc_node *,
51 			const struct mdoc_argv *);
52 static	int	 check_args(struct mdoc *,
53 			const struct mdoc_node *);
54 static	int	 err_child_lt(struct mdoc *, const char *, int);
55 static	int	 warn_child_lt(struct mdoc *, const char *, int);
56 static	int	 err_child_gt(struct mdoc *, const char *, int);
57 static	int	 warn_child_gt(struct mdoc *, const char *, int);
58 static	int	 err_child_eq(struct mdoc *, const char *, int);
59 static	int	 warn_child_eq(struct mdoc *, const char *, int);
60 static	int	 warn_print(struct mdoc *, int, int);
61 static	int	 warn_count(struct mdoc *, const char *,
62 			int, const char *, int);
63 static	int	 err_count(struct mdoc *, const char *,
64 			int, const char *, int);
65 
66 static	int	 berr_ge1(POST_ARGS);
67 static	int	 bwarn_ge1(POST_ARGS);
68 static	int	 ebool(POST_ARGS);
69 static	int	 eerr_eq0(POST_ARGS);
70 static	int	 eerr_eq1(POST_ARGS);
71 static	int	 eerr_ge1(POST_ARGS);
72 static	int	 eerr_le2(POST_ARGS);
73 static	int	 eerr_le1(POST_ARGS);
74 static	int	 ewarn_ge1(POST_ARGS);
75 static	int	 herr_eq0(POST_ARGS);
76 static	int	 herr_ge1(POST_ARGS);
77 static	int	 hwarn_eq1(POST_ARGS);
78 static	int	 hwarn_le1(POST_ARGS);
79 
80 static	int	 post_an(POST_ARGS);
81 static	int	 post_at(POST_ARGS);
82 static	int	 post_bf(POST_ARGS);
83 static	int	 post_bl(POST_ARGS);
84 static	int	 post_bl_head(POST_ARGS);
85 static	int	 post_it(POST_ARGS);
86 static	int	 post_lb(POST_ARGS);
87 static	int	 post_nm(POST_ARGS);
88 static	int	 post_root(POST_ARGS);
89 static	int	 post_rs(POST_ARGS);
90 static	int	 post_sh(POST_ARGS);
91 static	int	 post_sh_body(POST_ARGS);
92 static	int	 post_sh_head(POST_ARGS);
93 static	int	 post_st(POST_ARGS);
94 static	int	 pre_an(PRE_ARGS);
95 static	int	 pre_bd(PRE_ARGS);
96 static	int	 pre_bl(PRE_ARGS);
97 static	int	 pre_cd(PRE_ARGS);
98 static	int	 pre_dd(PRE_ARGS);
99 static	int	 pre_display(PRE_ARGS);
100 static	int	 pre_dt(PRE_ARGS);
101 static	int	 pre_er(PRE_ARGS);
102 static	int	 pre_ex(PRE_ARGS);
103 static	int	 pre_fd(PRE_ARGS);
104 static	int	 pre_it(PRE_ARGS);
105 static	int	 pre_lb(PRE_ARGS);
106 static	int	 pre_os(PRE_ARGS);
107 static	int	 pre_rv(PRE_ARGS);
108 static	int	 pre_sh(PRE_ARGS);
109 static	int	 pre_ss(PRE_ARGS);
110 
111 static	v_post	 posts_an[] = { post_an, NULL };
112 static	v_post	 posts_at[] = { post_at, NULL };
113 static	v_post	 posts_bd[] = { herr_eq0, bwarn_ge1, NULL };
114 static	v_post	 posts_bf[] = { hwarn_le1, post_bf, NULL };
115 static	v_post	 posts_bl[] = { bwarn_ge1, post_bl, NULL };
116 static	v_post	 posts_bool[] = { eerr_eq1, ebool, NULL };
117 static	v_post	 posts_fo[] = { hwarn_eq1, bwarn_ge1, NULL };
118 static	v_post	 posts_it[] = { post_it, NULL };
119 static	v_post	 posts_lb[] = { eerr_eq1, post_lb, NULL };
120 static	v_post	 posts_nd[] = { berr_ge1, NULL };
121 static	v_post	 posts_nm[] = { post_nm, NULL };
122 static	v_post	 posts_notext[] = { eerr_eq0, NULL };
123 static	v_post	 posts_rs[] = { berr_ge1, herr_eq0, post_rs, NULL };
124 static	v_post	 posts_sh[] = { herr_ge1, bwarn_ge1, post_sh, NULL };
125 static	v_post	 posts_sp[] = { eerr_le1, NULL };
126 static	v_post	 posts_ss[] = { herr_ge1, NULL };
127 static	v_post	 posts_st[] = { eerr_eq1, post_st, NULL };
128 static	v_post	 posts_text[] = { eerr_ge1, NULL };
129 static	v_post	 posts_text1[] = { eerr_eq1, NULL };
130 static	v_post	 posts_wline[] = { bwarn_ge1, herr_eq0, NULL };
131 static	v_post	 posts_wtext[] = { ewarn_ge1, NULL };
132 static	v_post	 posts_xr[] = { eerr_ge1, eerr_le2, NULL };
133 static	v_pre	 pres_an[] = { pre_an, NULL };
134 static	v_pre	 pres_bd[] = { pre_display, pre_bd, NULL };
135 static	v_pre	 pres_bl[] = { pre_bl, NULL };
136 static	v_pre	 pres_cd[] = { pre_cd, NULL };
137 static	v_pre	 pres_d1[] = { pre_display, NULL };
138 static	v_pre	 pres_dd[] = { pre_dd, NULL };
139 static	v_pre	 pres_dt[] = { pre_dt, NULL };
140 static	v_pre	 pres_er[] = { pre_er, NULL };
141 static	v_pre	 pres_ex[] = { pre_ex, NULL };
142 static	v_pre	 pres_fd[] = { pre_fd, NULL };
143 static	v_pre	 pres_it[] = { pre_it, NULL };
144 static	v_pre	 pres_lb[] = { pre_lb, NULL };
145 static	v_pre	 pres_os[] = { pre_os, NULL };
146 static	v_pre	 pres_rv[] = { pre_rv, NULL };
147 static	v_pre	 pres_sh[] = { pre_sh, NULL };
148 static	v_pre	 pres_ss[] = { pre_ss, NULL };
149 
150 const	struct valids mdoc_valids[MDOC_MAX] = {
151 	{ NULL, NULL },				/* Ap */
152 	{ pres_dd, posts_text },		/* Dd */
153 	{ pres_dt, NULL },			/* Dt */
154 	{ pres_os, NULL },			/* Os */
155 	{ pres_sh, posts_sh },			/* Sh */
156 	{ pres_ss, posts_ss },			/* Ss */
157 	{ NULL, posts_notext },			/* Pp */
158 	{ pres_d1, posts_wline },		/* D1 */
159 	{ pres_d1, posts_wline },		/* Dl */
160 	{ pres_bd, posts_bd },			/* Bd */
161 	{ NULL, NULL },				/* Ed */
162 	{ pres_bl, posts_bl },			/* Bl */
163 	{ NULL, NULL },				/* El */
164 	{ pres_it, posts_it },			/* It */
165 	{ NULL, posts_text },			/* Ad */
166 	{ pres_an, posts_an },			/* An */
167 	{ NULL, NULL },				/* Ar */
168 	{ pres_cd, posts_text },		/* Cd */
169 	{ NULL, NULL },				/* Cm */
170 	{ NULL, NULL },				/* Dv */
171 	{ pres_er, posts_text },		/* Er */
172 	{ NULL, NULL },				/* Ev */
173 	{ pres_ex, NULL },			/* Ex */
174 	{ NULL, NULL },				/* Fa */
175 	{ pres_fd, posts_wtext },		/* Fd */
176 	{ NULL, NULL },				/* Fl */
177 	{ NULL, posts_text },			/* Fn */
178 	{ NULL, posts_wtext },			/* Ft */
179 	{ NULL, posts_text },			/* Ic */
180 	{ NULL, posts_text1 },			/* In */
181 	{ NULL, NULL },				/* Li */
182 	{ NULL, posts_nd },			/* Nd */
183 	{ NULL, posts_nm },			/* Nm */
184 	{ NULL, posts_wline },			/* Op */
185 	{ NULL, NULL },				/* Ot */
186 	{ NULL, NULL },				/* Pa */
187 	{ pres_rv, NULL },			/* Rv */
188 	{ NULL, posts_st },			/* St */
189 	{ NULL, NULL },				/* Va */
190 	{ NULL, posts_text },			/* Vt */
191 	{ NULL, posts_xr },			/* Xr */
192 	{ NULL, posts_text },			/* %A */
193 	{ NULL, posts_text },			/* %B */ /* FIXME: can be used outside Rs/Re. */
194 	{ NULL, posts_text },			/* %D */
195 	{ NULL, posts_text },			/* %I */
196 	{ NULL, posts_text },			/* %J */
197 	{ NULL, posts_text },			/* %N */
198 	{ NULL, posts_text },			/* %O */
199 	{ NULL, posts_text },			/* %P */
200 	{ NULL, posts_text },			/* %R */
201 	{ NULL, posts_text },			/* %T */ /* FIXME: can be used outside Rs/Re. */
202 	{ NULL, posts_text },			/* %V */
203 	{ NULL, NULL },				/* Ac */
204 	{ NULL, NULL },				/* Ao */
205 	{ NULL, posts_wline },			/* Aq */
206 	{ NULL, posts_at },			/* At */
207 	{ NULL, NULL },				/* Bc */
208 	{ NULL, posts_bf },			/* Bf */
209 	{ NULL, NULL },				/* Bo */
210 	{ NULL, posts_wline },			/* Bq */
211 	{ NULL, NULL },				/* Bsx */
212 	{ NULL, NULL },				/* Bx */
213 	{ NULL, posts_bool },			/* Db */
214 	{ NULL, NULL },				/* Dc */
215 	{ NULL, NULL },				/* Do */
216 	{ NULL, posts_wline },			/* Dq */
217 	{ NULL, NULL },				/* Ec */
218 	{ NULL, NULL },				/* Ef */
219 	{ NULL, NULL },				/* Em */
220 	{ NULL, NULL },				/* Eo */
221 	{ NULL, NULL },				/* Fx */
222 	{ NULL, posts_text },			/* Ms */
223 	{ NULL, posts_notext },			/* No */
224 	{ NULL, posts_notext },			/* Ns */
225 	{ NULL, NULL },				/* Nx */
226 	{ NULL, NULL },				/* Ox */
227 	{ NULL, NULL },				/* Pc */
228 	{ NULL, posts_text1 },			/* Pf */
229 	{ NULL, NULL },				/* Po */
230 	{ NULL, posts_wline },			/* Pq */
231 	{ NULL, NULL },				/* Qc */
232 	{ NULL, posts_wline },			/* Ql */
233 	{ NULL, NULL },				/* Qo */
234 	{ NULL, posts_wline },			/* Qq */
235 	{ NULL, NULL },				/* Re */
236 	{ NULL, posts_rs },			/* Rs */
237 	{ NULL, NULL },				/* Sc */
238 	{ NULL, NULL },				/* So */
239 	{ NULL, posts_wline },			/* Sq */
240 	{ NULL, posts_bool },			/* Sm */
241 	{ NULL, posts_text },			/* Sx */
242 	{ NULL, posts_text },			/* Sy */
243 	{ NULL, posts_text },			/* Tn */
244 	{ NULL, NULL },				/* Ux */
245 	{ NULL, NULL },				/* Xc */
246 	{ NULL, NULL },				/* Xo */
247 	{ NULL, posts_fo },			/* Fo */
248 	{ NULL, NULL },				/* Fc */
249 	{ NULL, NULL },				/* Oo */
250 	{ NULL, NULL },				/* Oc */
251 	{ NULL, posts_wline },			/* Bk */
252 	{ NULL, NULL },				/* Ek */
253 	{ NULL, posts_notext },			/* Bt */
254 	{ NULL, NULL },				/* Hf */
255 	{ NULL, NULL },				/* Fr */
256 	{ NULL, posts_notext },			/* Ud */
257 	{ pres_lb, posts_lb },			/* Lb */
258 	{ NULL, posts_notext },			/* Lp */
259 	{ NULL, posts_text },			/* Lk */
260 	{ NULL, posts_text },			/* Mt */
261 	{ NULL, posts_wline },			/* Brq */
262 	{ NULL, NULL },				/* Bro */
263 	{ NULL, NULL },				/* Brc */
264 	{ NULL, posts_text },			/* %C */
265 	{ NULL, NULL },				/* Es */
266 	{ NULL, NULL },				/* En */
267 	{ NULL, NULL },				/* Dx */
268 	{ NULL, posts_text },			/* %Q */
269 	{ NULL, posts_notext },			/* br */
270 	{ NULL, posts_sp },			/* sp */
271 	{ NULL, posts_text1 },			/* %U */
272 };
273 
274 
275 int
276 mdoc_valid_pre(struct mdoc *mdoc, const struct mdoc_node *n)
277 {
278 	v_pre		*p;
279 	int		 line, pos;
280 	const char	*tp;
281 
282 	if (MDOC_TEXT == n->type) {
283 		tp = n->string;
284 		line = n->line;
285 		pos = n->pos;
286 		return(check_text(mdoc, line, pos, tp));
287 	}
288 
289 	if ( ! check_args(mdoc, n))
290 		return(0);
291 	if (NULL == mdoc_valids[n->tok].pre)
292 		return(1);
293 	for (p = mdoc_valids[n->tok].pre; *p; p++)
294 		if ( ! (*p)(mdoc, n))
295 			return(0);
296 	return(1);
297 }
298 
299 
300 int
301 mdoc_valid_post(struct mdoc *mdoc)
302 {
303 	v_post		*p;
304 
305 	if (MDOC_VALID & mdoc->last->flags)
306 		return(1);
307 	mdoc->last->flags |= MDOC_VALID;
308 
309 	if (MDOC_TEXT == mdoc->last->type)
310 		return(1);
311 	if (MDOC_ROOT == mdoc->last->type)
312 		return(post_root(mdoc));
313 
314 	if (NULL == mdoc_valids[mdoc->last->tok].post)
315 		return(1);
316 	for (p = mdoc_valids[mdoc->last->tok].post; *p; p++)
317 		if ( ! (*p)(mdoc))
318 			return(0);
319 
320 	return(1);
321 }
322 
323 
324 static int
325 warn_print(struct mdoc *m, int ln, int pos)
326 {
327 
328 	if (MDOC_IGN_CHARS & m->pflags)
329 		return(mdoc_pwarn(m, ln, pos, EPRINT));
330 	return(mdoc_perr(m, ln, pos, EPRINT));
331 }
332 
333 
334 static inline int
335 warn_count(struct mdoc *m, const char *k,
336 		int want, const char *v, int has)
337 {
338 
339 	return(mdoc_vwarn(m, m->last->line, m->last->pos,
340 		"suggests %s %s %d (has %d)", v, k, want, has));
341 }
342 
343 
344 static inline int
345 err_count(struct mdoc *m, const char *k,
346 		int want, const char *v, int has)
347 {
348 
349 	return(mdoc_verr(m, m->last->line, m->last->pos,
350 		"requires %s %s %d (has %d)", v, k, want, has));
351 }
352 
353 
354 /*
355  * Build these up with macros because they're basically the same check
356  * for different inequalities.  Yes, this could be done with functions,
357  * but this is reasonable for now.
358  */
359 
360 #define CHECK_CHILD_DEFN(lvl, name, ineq) 			\
361 static int 							\
362 lvl##_child_##name(struct mdoc *mdoc, const char *p, int sz) 	\
363 { 								\
364 	if (mdoc->last->nchild ineq sz)				\
365 		return(1); 					\
366 	return(lvl##_count(mdoc, #ineq, sz, p, mdoc->last->nchild)); \
367 }
368 
369 #define CHECK_BODY_DEFN(name, lvl, func, num) 			\
370 static int 							\
371 b##lvl##_##name(POST_ARGS) 					\
372 { 								\
373 	if (MDOC_BODY != mdoc->last->type) 			\
374 		return(1); 					\
375 	return(func(mdoc, "multi-line arguments", (num))); 	\
376 }
377 
378 #define CHECK_ELEM_DEFN(name, lvl, func, num) 			\
379 static int							\
380 e##lvl##_##name(POST_ARGS) 					\
381 { 								\
382 	assert(MDOC_ELEM == mdoc->last->type); 			\
383 	return(func(mdoc, "line arguments", (num))); 		\
384 }
385 
386 #define CHECK_HEAD_DEFN(name, lvl, func, num)			\
387 static int 							\
388 h##lvl##_##name(POST_ARGS) 					\
389 { 								\
390 	if (MDOC_HEAD != mdoc->last->type) 			\
391 		return(1); 					\
392 	return(func(mdoc, "line arguments", (num)));	 	\
393 }
394 
395 
396 CHECK_CHILD_DEFN(warn, gt, >)			/* warn_child_gt() */
397 CHECK_CHILD_DEFN(err, gt, >)			/* err_child_gt() */
398 CHECK_CHILD_DEFN(warn, eq, ==)			/* warn_child_eq() */
399 CHECK_CHILD_DEFN(err, eq, ==)			/* err_child_eq() */
400 CHECK_CHILD_DEFN(err, lt, <)			/* err_child_lt() */
401 CHECK_CHILD_DEFN(warn, lt, <)			/* warn_child_lt() */
402 CHECK_BODY_DEFN(ge1, warn, warn_child_gt, 0)	/* bwarn_ge1() */
403 CHECK_BODY_DEFN(ge1, err, err_child_gt, 0)	/* berr_ge1() */
404 CHECK_ELEM_DEFN(ge1, warn, warn_child_gt, 0)	/* ewarn_gt1() */
405 CHECK_ELEM_DEFN(eq1, err, err_child_eq, 1)	/* eerr_eq1() */
406 CHECK_ELEM_DEFN(le2, err, err_child_lt, 3)	/* eerr_le2() */
407 CHECK_ELEM_DEFN(le1, err, err_child_lt, 2)	/* eerr_le1() */
408 CHECK_ELEM_DEFN(eq0, err, err_child_eq, 0)	/* eerr_eq0() */
409 CHECK_ELEM_DEFN(ge1, err, err_child_gt, 0)	/* eerr_ge1() */
410 CHECK_HEAD_DEFN(eq0, err, err_child_eq, 0)	/* herr_eq0() */
411 CHECK_HEAD_DEFN(le1, warn, warn_child_lt, 2)	/* hwarn_le1() */
412 CHECK_HEAD_DEFN(ge1, err, err_child_gt, 0)	/* herr_ge1() */
413 CHECK_HEAD_DEFN(eq1, warn, warn_child_eq, 1)	/* hwarn_eq1() */
414 
415 
416 static int
417 check_stdarg(PRE_ARGS)
418 {
419 
420 	if (n->args && 1 == n->args->argc)
421 		if (MDOC_Std == n->args->argv[0].arg)
422 			return(1);
423 	return(mdoc_nwarn(mdoc, n, EARGVAL));
424 }
425 
426 
427 static int
428 check_sec(PRE_ARGS, ...)
429 {
430 	enum mdoc_sec	 sec;
431 	va_list		 ap;
432 
433 	va_start(ap, n);
434 
435 	for (;;) {
436 		/* LINTED */
437 		sec = (enum mdoc_sec)va_arg(ap, int);
438 		if (SEC_CUSTOM == sec)
439 			break;
440 		if (sec != mdoc->lastsec)
441 			continue;
442 		va_end(ap);
443 		return(1);
444 	}
445 
446 	va_end(ap);
447 	return(mdoc_nwarn(mdoc, n, EBADSEC));
448 }
449 
450 
451 static int
452 check_msec(PRE_ARGS, ...)
453 {
454 	va_list		 ap;
455 	int		 msec;
456 
457 	va_start(ap, n);
458 	for (;;) {
459 		/* LINTED */
460 		if (0 == (msec = va_arg(ap, int)))
461 			break;
462 		if (msec != mdoc->meta.msec)
463 			continue;
464 		va_end(ap);
465 		return(1);
466 	}
467 
468 	va_end(ap);
469 	return(mdoc_nwarn(mdoc, n, EBADMSEC));
470 }
471 
472 
473 static int
474 check_args(struct mdoc *m, const struct mdoc_node *n)
475 {
476 	int		 i;
477 
478 	if (NULL == n->args)
479 		return(1);
480 
481 	assert(n->args->argc);
482 	for (i = 0; i < (int)n->args->argc; i++)
483 		if ( ! check_argv(m, n, &n->args->argv[i]))
484 			return(0);
485 
486 	return(1);
487 }
488 
489 
490 static int
491 check_argv(struct mdoc *m, const struct mdoc_node *n,
492 		const struct mdoc_argv *v)
493 {
494 	int		 i;
495 
496 	for (i = 0; i < (int)v->sz; i++)
497 		if ( ! check_text(m, v->line, v->pos, v->value[i]))
498 			return(0);
499 
500 	if (MDOC_Std == v->arg) {
501 		/* `Nm' name must be set. */
502 		if (v->sz || m->meta.name)
503 			return(1);
504 		return(mdoc_nerr(m, n, ENAME));
505 	}
506 
507 	return(1);
508 }
509 
510 
511 static int
512 check_text(struct mdoc *mdoc, int line, int pos, const char *p)
513 {
514 	int		 c;
515 
516 	for ( ; *p; p++, pos++) {
517 		if ('\t' == *p) {
518 			if ( ! (MDOC_LITERAL & mdoc->flags))
519 				if ( ! warn_print(mdoc, line, pos))
520 					return(0);
521 		} else if ( ! isprint((u_char)*p))
522 			if ( ! warn_print(mdoc, line, pos))
523 				return(0);
524 
525 		if ('\\' != *p)
526 			continue;
527 
528 		c = mandoc_special(p);
529 		if (c) {
530 			p += c - 1;
531 			pos += c - 1;
532 			continue;
533 		}
534 		if ( ! (MDOC_IGN_ESCAPE & mdoc->pflags))
535 			return(mdoc_perr(mdoc, line, pos, EESCAPE));
536 		if ( ! mdoc_pwarn(mdoc, line, pos, EESCAPE))
537 			return(0);
538 	}
539 
540 	return(1);
541 }
542 
543 
544 
545 
546 static int
547 check_parent(PRE_ARGS, int tok, enum mdoc_type t)
548 {
549 
550 	assert(n->parent);
551 	if ((MDOC_ROOT == t || tok == n->parent->tok) &&
552 			(t == n->parent->type))
553 		return(1);
554 
555 	return(mdoc_verr(mdoc, n->line, n->pos, "require parent %s",
556 		MDOC_ROOT == t ? "<root>" : mdoc_macronames[tok]));
557 }
558 
559 
560 
561 static int
562 pre_display(PRE_ARGS)
563 {
564 	struct mdoc_node *node;
565 
566 	/* Display elements (`Bd', `D1'...) cannot be nested. */
567 
568 	if (MDOC_BLOCK != n->type)
569 		return(1);
570 
571 	/* LINTED */
572 	for (node = mdoc->last->parent; node; node = node->parent)
573 		if (MDOC_BLOCK == node->type)
574 			if (MDOC_Bd == node->tok)
575 				break;
576 	if (NULL == node)
577 		return(1);
578 
579 	return(mdoc_nerr(mdoc, n, ENESTDISP));
580 }
581 
582 
583 static int
584 pre_bl(PRE_ARGS)
585 {
586 	int		 pos, type, width, offset;
587 
588 	if (MDOC_BLOCK != n->type)
589 		return(1);
590 	if (NULL == n->args)
591 		return(mdoc_nerr(mdoc, n, ELISTTYPE));
592 
593 	/* Make sure that only one type of list is specified.  */
594 
595 	type = offset = width = -1;
596 
597 	/* LINTED */
598 	for (pos = 0; pos < (int)n->args->argc; pos++)
599 		switch (n->args->argv[pos].arg) {
600 		case (MDOC_Bullet):
601 			/* FALLTHROUGH */
602 		case (MDOC_Dash):
603 			/* FALLTHROUGH */
604 		case (MDOC_Enum):
605 			/* FALLTHROUGH */
606 		case (MDOC_Hyphen):
607 			/* FALLTHROUGH */
608 		case (MDOC_Item):
609 			/* FALLTHROUGH */
610 		case (MDOC_Tag):
611 			/* FALLTHROUGH */
612 		case (MDOC_Diag):
613 			/* FALLTHROUGH */
614 		case (MDOC_Hang):
615 			/* FALLTHROUGH */
616 		case (MDOC_Ohang):
617 			/* FALLTHROUGH */
618 		case (MDOC_Inset):
619 			/* FALLTHROUGH */
620 		case (MDOC_Column):
621 			if (type >= 0)
622 				return(mdoc_nerr(mdoc, n, EMULTILIST));
623 			type = n->args->argv[pos].arg;
624 			break;
625 		case (MDOC_Compact):
626 			if (type < 0 && ! mdoc_nwarn(mdoc, n, ENOTYPE))
627 				return(0);
628 			break;
629 		case (MDOC_Width):
630 			if (width >= 0)
631 				return(mdoc_nerr(mdoc, n, EARGREP));
632 			if (type < 0 && ! mdoc_nwarn(mdoc, n, ENOTYPE))
633 				return(0);
634 			width = n->args->argv[pos].arg;
635 			break;
636 		case (MDOC_Offset):
637 			if (offset >= 0)
638 				return(mdoc_nerr(mdoc, n, EARGREP));
639 			if (type < 0 && ! mdoc_nwarn(mdoc, n, ENOTYPE))
640 				return(0);
641 			offset = n->args->argv[pos].arg;
642 			break;
643 		default:
644 			break;
645 		}
646 
647 	if (type < 0)
648 		return(mdoc_nerr(mdoc, n, ELISTTYPE));
649 
650 	/*
651 	 * Validate the width field.  Some list types don't need width
652 	 * types and should be warned about them.  Others should have it
653 	 * and must also be warned.
654 	 */
655 
656 	switch (type) {
657 	case (MDOC_Tag):
658 		if (width < 0 && ! mdoc_nwarn(mdoc, n, EMISSWIDTH))
659 			return(0);
660 		break;
661 	case (MDOC_Column):
662 		/* FALLTHROUGH */
663 	case (MDOC_Diag):
664 		/* FALLTHROUGH */
665 	case (MDOC_Inset):
666 		/* FALLTHROUGH */
667 	case (MDOC_Item):
668 		if (width >= 0 && ! mdoc_nwarn(mdoc, n, ENOWIDTH))
669 			return(0);
670 		break;
671 	default:
672 		break;
673 	}
674 
675 	return(1);
676 }
677 
678 
679 static int
680 pre_bd(PRE_ARGS)
681 {
682 	int		 i, type, err;
683 
684 	if (MDOC_BLOCK != n->type)
685 		return(1);
686 	if (NULL == n->args)
687 		return(mdoc_nerr(mdoc, n, EDISPTYPE));
688 
689 	/* Make sure that only one type of display is specified.  */
690 
691 	/* LINTED */
692 	for (i = 0, err = type = 0; ! err &&
693 			i < (int)n->args->argc; i++)
694 		switch (n->args->argv[i].arg) {
695 		case (MDOC_Centred):
696 			/* FALLTHROUGH */
697 		case (MDOC_Ragged):
698 			/* FALLTHROUGH */
699 		case (MDOC_Unfilled):
700 			/* FALLTHROUGH */
701 		case (MDOC_Filled):
702 			/* FALLTHROUGH */
703 		case (MDOC_Literal):
704 			if (0 == type++)
705 				break;
706 			return(mdoc_nerr(mdoc, n, EMULTIDISP));
707 		default:
708 			break;
709 		}
710 
711 	if (type)
712 		return(1);
713 	return(mdoc_nerr(mdoc, n, EDISPTYPE));
714 }
715 
716 
717 static int
718 pre_ss(PRE_ARGS)
719 {
720 
721 	if (MDOC_BLOCK != n->type)
722 		return(1);
723 	return(check_parent(mdoc, n, MDOC_Sh, MDOC_BODY));
724 }
725 
726 
727 static int
728 pre_sh(PRE_ARGS)
729 {
730 
731 	if (MDOC_BLOCK != n->type)
732 		return(1);
733 	return(check_parent(mdoc, n, -1, MDOC_ROOT));
734 }
735 
736 
737 static int
738 pre_it(PRE_ARGS)
739 {
740 
741 	if (MDOC_BLOCK != n->type)
742 		return(1);
743 	return(check_parent(mdoc, n, MDOC_Bl, MDOC_BODY));
744 }
745 
746 
747 static int
748 pre_an(PRE_ARGS)
749 {
750 
751 	if (NULL == n->args || 1 == n->args->argc)
752 		return(1);
753 	return(mdoc_verr(mdoc, n->line, n->pos,
754 				"only one argument allowed"));
755 }
756 
757 
758 static int
759 pre_lb(PRE_ARGS)
760 {
761 
762 	return(check_sec(mdoc, n, SEC_LIBRARY, SEC_CUSTOM));
763 }
764 
765 
766 static int
767 pre_rv(PRE_ARGS)
768 {
769 
770 	if ( ! check_msec(mdoc, n, 2, 3, 0))
771 		return(0);
772 	return(check_stdarg(mdoc, n));
773 }
774 
775 
776 static int
777 pre_ex(PRE_ARGS)
778 {
779 
780 	if ( ! check_msec(mdoc, n, 1, 6, 8, 0))
781 		return(0);
782 	return(check_stdarg(mdoc, n));
783 }
784 
785 
786 static int
787 pre_er(PRE_ARGS)
788 {
789 
790 	return(check_msec(mdoc, n, 2, 3, 9, 0));
791 }
792 
793 
794 static int
795 pre_cd(PRE_ARGS)
796 {
797 
798 	return(check_msec(mdoc, n, 4, 0));
799 }
800 
801 
802 static int
803 pre_dt(PRE_ARGS)
804 {
805 
806 	if (0 == mdoc->meta.date || mdoc->meta.os)
807 		if ( ! mdoc_nwarn(mdoc, n, EPROLOOO))
808 			return(0);
809 	if (mdoc->meta.title)
810 		if ( ! mdoc_nwarn(mdoc, n, EPROLREP))
811 			return(0);
812 	return(1);
813 }
814 
815 
816 static int
817 pre_os(PRE_ARGS)
818 {
819 
820 	if (NULL == mdoc->meta.title || 0 == mdoc->meta.date)
821 		if ( ! mdoc_nwarn(mdoc, n, EPROLOOO))
822 			return(0);
823 	if (mdoc->meta.os)
824 		if ( ! mdoc_nwarn(mdoc, n, EPROLREP))
825 			return(0);
826 	return(1);
827 }
828 
829 
830 static int
831 pre_dd(PRE_ARGS)
832 {
833 
834 	if (mdoc->meta.title || mdoc->meta.os)
835 		if ( ! mdoc_nwarn(mdoc, n, EPROLOOO))
836 			return(0);
837 	if (mdoc->meta.date)
838 		if ( ! mdoc_nwarn(mdoc, n, EPROLREP))
839 			return(0);
840 	return(1);
841 }
842 
843 
844 static int
845 post_bf(POST_ARGS)
846 {
847 	char		 *p;
848 	struct mdoc_node *head;
849 
850 	if (MDOC_BLOCK != mdoc->last->type)
851 		return(1);
852 
853 	head = mdoc->last->head;
854 
855 	if (mdoc->last->args && head->child)
856 		return(mdoc_nerr(mdoc, mdoc->last, ELINE));
857 	else if (mdoc->last->args)
858 		return(1);
859 
860 	if (NULL == head->child || MDOC_TEXT != head->child->type)
861 		return(mdoc_nerr(mdoc, mdoc->last, ELINE));
862 
863 	p = head->child->string;
864 
865 	if (0 == strcmp(p, "Em"))
866 		return(1);
867 	else if (0 == strcmp(p, "Li"))
868 		return(1);
869 	else if (0 == strcmp(p, "Sy"))
870 		return(1);
871 
872 	return(mdoc_nerr(mdoc, head, EFONT));
873 }
874 
875 
876 static int
877 post_lb(POST_ARGS)
878 {
879 
880 	if (mdoc_a2lib(mdoc->last->child->string))
881 		return(1);
882 	return(mdoc_nwarn(mdoc, mdoc->last, ELIB));
883 }
884 
885 
886 static int
887 post_nm(POST_ARGS)
888 {
889 
890 	if (mdoc->last->child)
891 		return(1);
892 	if (mdoc->meta.name)
893 		return(1);
894 	return(mdoc_nerr(mdoc, mdoc->last, ENAME));
895 }
896 
897 
898 static int
899 post_at(POST_ARGS)
900 {
901 
902 	if (NULL == mdoc->last->child)
903 		return(1);
904 	if (MDOC_TEXT != mdoc->last->child->type)
905 		return(mdoc_nerr(mdoc, mdoc->last, EATT));
906 	if (mdoc_a2att(mdoc->last->child->string))
907 		return(1);
908 	return(mdoc_nerr(mdoc, mdoc->last, EATT));
909 }
910 
911 
912 static int
913 post_an(POST_ARGS)
914 {
915 
916 	if (mdoc->last->args) {
917 		if (NULL == mdoc->last->child)
918 			return(1);
919 		return(mdoc_nerr(mdoc, mdoc->last, ENOLINE));
920 	}
921 
922 	if (mdoc->last->child)
923 		return(1);
924 	return(mdoc_nerr(mdoc, mdoc->last, ELINE));
925 }
926 
927 
928 static int
929 post_it(POST_ARGS)
930 {
931 	int		  type, i, cols;
932 	struct mdoc_node *n, *c;
933 
934 	if (MDOC_BLOCK != mdoc->last->type)
935 		return(1);
936 
937 	n = mdoc->last->parent->parent;
938 	if (NULL == n->args)
939 		return(mdoc_nerr(mdoc, mdoc->last, ELISTTYPE));
940 
941 	/* Some types require block-head, some not. */
942 
943 	/* LINTED */
944 	for (cols = type = -1, i = 0; -1 == type &&
945 			i < (int)n->args->argc; i++)
946 		switch (n->args->argv[i].arg) {
947 		case (MDOC_Tag):
948 			/* FALLTHROUGH */
949 		case (MDOC_Diag):
950 			/* FALLTHROUGH */
951 		case (MDOC_Hang):
952 			/* FALLTHROUGH */
953 		case (MDOC_Ohang):
954 			/* FALLTHROUGH */
955 		case (MDOC_Inset):
956 			/* FALLTHROUGH */
957 		case (MDOC_Bullet):
958 			/* FALLTHROUGH */
959 		case (MDOC_Dash):
960 			/* FALLTHROUGH */
961 		case (MDOC_Enum):
962 			/* FALLTHROUGH */
963 		case (MDOC_Hyphen):
964 			/* FALLTHROUGH */
965 		case (MDOC_Item):
966 			type = n->args->argv[i].arg;
967 			break;
968 		case (MDOC_Column):
969 			type = n->args->argv[i].arg;
970 			cols = (int)n->args->argv[i].sz;
971 			break;
972 		default:
973 			break;
974 		}
975 
976 	if (-1 == type)
977 		return(mdoc_nerr(mdoc, mdoc->last, ELISTTYPE));
978 
979 	switch (type) {
980 	case (MDOC_Tag):
981 		if (NULL == mdoc->last->head->child)
982 			if ( ! mdoc_nwarn(mdoc, mdoc->last, ELINE))
983 				return(0);
984 		break;
985 	case (MDOC_Hang):
986 		/* FALLTHROUGH */
987 	case (MDOC_Ohang):
988 		/* FALLTHROUGH */
989 	case (MDOC_Inset):
990 		/* FALLTHROUGH */
991 	case (MDOC_Diag):
992 		if (NULL == mdoc->last->head->child)
993 			if ( ! mdoc_nwarn(mdoc, mdoc->last, ELINE))
994 				return(0);
995 		if (NULL == mdoc->last->body->child)
996 			if ( ! mdoc_nwarn(mdoc, mdoc->last, EMULTILINE))
997 				return(0);
998 		break;
999 	case (MDOC_Bullet):
1000 		/* FALLTHROUGH */
1001 	case (MDOC_Dash):
1002 		/* FALLTHROUGH */
1003 	case (MDOC_Enum):
1004 		/* FALLTHROUGH */
1005 	case (MDOC_Hyphen):
1006 		/* FALLTHROUGH */
1007 	case (MDOC_Item):
1008 		if (mdoc->last->head->child)
1009 			if ( ! mdoc_nwarn(mdoc, mdoc->last, ENOLINE))
1010 				return(0);
1011 		if (NULL == mdoc->last->body->child)
1012 			if ( ! mdoc_nwarn(mdoc, mdoc->last, EMULTILINE))
1013 				return(0);
1014 		break;
1015 	case (MDOC_Column):
1016 		if (NULL == mdoc->last->head->child)
1017 			if ( ! mdoc_nwarn(mdoc, mdoc->last, ELINE))
1018 				return(0);
1019 		if (mdoc->last->body->child)
1020 			if ( ! mdoc_nwarn(mdoc, mdoc->last, ENOMULTILINE))
1021 				return(0);
1022 		c = mdoc->last->child;
1023 		for (i = 0; c && MDOC_HEAD == c->type; c = c->next)
1024 			i++;
1025 
1026 		if (i < cols || i == (cols + 1)) {
1027 			if ( ! mdoc_vwarn(mdoc, mdoc->last->line,
1028 					mdoc->last->pos, "column "
1029 					"mismatch: have %d, want %d",
1030 					i, cols))
1031 				return(0);
1032 			break;
1033 		} else if (i == cols)
1034 			break;
1035 
1036 		return(mdoc_verr(mdoc, mdoc->last->line,
1037 				mdoc->last->pos, "column mismatch: "
1038 				"have %d, want %d", i, cols));
1039 	default:
1040 		break;
1041 	}
1042 
1043 	return(1);
1044 }
1045 
1046 
1047 static int
1048 post_bl_head(POST_ARGS)
1049 {
1050 	int			i;
1051 	const struct mdoc_node *n;
1052 
1053 	n = mdoc->last->parent;
1054 	assert(n->args);
1055 
1056 	for (i = 0; i < (int)n->args->argc; i++)
1057 		if (n->args->argv[i].arg == MDOC_Column)
1058 			break;
1059 
1060 	if (i == (int)n->args->argc)
1061 		return(1);
1062 
1063 	if (n->args->argv[i].sz && mdoc->last->child)
1064 		return(mdoc_nerr(mdoc, n, ECOLMIS));
1065 
1066 	return(1);
1067 }
1068 
1069 
1070 static int
1071 post_bl(POST_ARGS)
1072 {
1073 	struct mdoc_node	*n;
1074 
1075 	if (MDOC_HEAD == mdoc->last->type)
1076 		return(post_bl_head(mdoc));
1077 	if (MDOC_BODY != mdoc->last->type)
1078 		return(1);
1079 	if (NULL == mdoc->last->child)
1080 		return(1);
1081 
1082 	/* LINTED */
1083 	for (n = mdoc->last->child; n; n = n->next) {
1084 		if (MDOC_BLOCK == n->type)
1085 			if (MDOC_It == n->tok)
1086 				continue;
1087 		return(mdoc_nerr(mdoc, n, EBADCHILD));
1088 	}
1089 
1090 	return(1);
1091 }
1092 
1093 
1094 static int
1095 ebool(struct mdoc *mdoc)
1096 {
1097 	struct mdoc_node *n;
1098 
1099 	/* LINTED */
1100 	for (n = mdoc->last->child; n; n = n->next) {
1101 		if (MDOC_TEXT != n->type)
1102 			break;
1103 		if (0 == strcmp(n->string, "on"))
1104 			continue;
1105 		if (0 == strcmp(n->string, "off"))
1106 			continue;
1107 		break;
1108 	}
1109 
1110 	if (NULL == n)
1111 		return(1);
1112 	return(mdoc_nerr(mdoc, n, EBOOL));
1113 }
1114 
1115 
1116 static int
1117 post_root(POST_ARGS)
1118 {
1119 
1120 	if (NULL == mdoc->first->child)
1121 		return(mdoc_nerr(mdoc, mdoc->first, ENODAT));
1122 	if ( ! (MDOC_PBODY & mdoc->flags))
1123 		return(mdoc_nerr(mdoc, mdoc->first, ENOPROLOGUE));
1124 
1125 	if (MDOC_BLOCK != mdoc->first->child->type)
1126 		return(mdoc_nerr(mdoc, mdoc->first, ENODAT));
1127 	if (MDOC_Sh != mdoc->first->child->tok)
1128 		return(mdoc_nerr(mdoc, mdoc->first, ENODAT));
1129 
1130 	return(1);
1131 }
1132 
1133 
1134 static int
1135 post_st(POST_ARGS)
1136 {
1137 
1138 	if (mdoc_a2st(mdoc->last->child->string))
1139 		return(1);
1140 	return(mdoc_nerr(mdoc, mdoc->last, EBADSTAND));
1141 }
1142 
1143 
1144 static int
1145 post_rs(POST_ARGS)
1146 {
1147 	struct mdoc_node	*nn;
1148 
1149 	if (MDOC_BODY != mdoc->last->type)
1150 		return(1);
1151 
1152 	for (nn = mdoc->last->child; nn; nn = nn->next)
1153 		switch (nn->tok) {
1154 		case(MDOC__U):
1155 			/* FALLTHROUGH */
1156 		case(MDOC__Q):
1157 			/* FALLTHROUGH */
1158 		case(MDOC__C):
1159 			/* FALLTHROUGH */
1160 		case(MDOC__A):
1161 			/* FALLTHROUGH */
1162 		case(MDOC__B):
1163 			/* FALLTHROUGH */
1164 		case(MDOC__D):
1165 			/* FALLTHROUGH */
1166 		case(MDOC__I):
1167 			/* FALLTHROUGH */
1168 		case(MDOC__J):
1169 			/* FALLTHROUGH */
1170 		case(MDOC__N):
1171 			/* FALLTHROUGH */
1172 		case(MDOC__O):
1173 			/* FALLTHROUGH */
1174 		case(MDOC__P):
1175 			/* FALLTHROUGH */
1176 		case(MDOC__R):
1177 			/* FALLTHROUGH */
1178 		case(MDOC__T):
1179 			/* FALLTHROUGH */
1180 		case(MDOC__V):
1181 			break;
1182 		default:
1183 			return(mdoc_nerr(mdoc, nn, EBADCHILD));
1184 		}
1185 
1186 	return(1);
1187 }
1188 
1189 
1190 static int
1191 post_sh(POST_ARGS)
1192 {
1193 
1194 	if (MDOC_HEAD == mdoc->last->type)
1195 		return(post_sh_head(mdoc));
1196 	if (MDOC_BODY == mdoc->last->type)
1197 		return(post_sh_body(mdoc));
1198 
1199 	return(1);
1200 }
1201 
1202 
1203 static int
1204 post_sh_body(POST_ARGS)
1205 {
1206 	struct mdoc_node *n;
1207 
1208 	if (SEC_NAME != mdoc->lastsec)
1209 		return(1);
1210 
1211 	/*
1212 	 * Warn if the NAME section doesn't contain the `Nm' and `Nd'
1213 	 * macros (can have multiple `Nm' and one `Nd').  Note that the
1214 	 * children of the BODY declaration can also be "text".
1215 	 */
1216 
1217 	if (NULL == (n = mdoc->last->child))
1218 		return(mdoc_nwarn(mdoc, mdoc->last, ENAMESECINC));
1219 
1220 	for ( ; n && n->next; n = n->next) {
1221 		if (MDOC_ELEM == n->type && MDOC_Nm == n->tok)
1222 			continue;
1223 		if (MDOC_TEXT == n->type)
1224 			continue;
1225 		if ( ! mdoc_nwarn(mdoc, mdoc->last, ENAMESECINC))
1226 			return(0);
1227 	}
1228 
1229 	assert(n);
1230 	if (MDOC_BLOCK == n->type && MDOC_Nd == n->tok)
1231 		return(1);
1232 	return(mdoc_nwarn(mdoc, mdoc->last, ENAMESECINC));
1233 }
1234 
1235 
1236 static int
1237 post_sh_head(POST_ARGS)
1238 {
1239 	char		        buf[64];
1240 	enum mdoc_sec	        sec;
1241 	const struct mdoc_node *n;
1242 
1243 	/*
1244 	 * Process a new section.  Sections are either "named" or
1245 	 * "custom"; custom sections are user-defined, while named ones
1246 	 * usually follow a conventional order and may only appear in
1247 	 * certain manual sections.
1248 	 */
1249 
1250 	buf[0] = 0;
1251 
1252 	for (n = mdoc->last->child; n; n = n->next) {
1253 		/* XXX - copied from compact(). */
1254 		assert(MDOC_TEXT == n->type);
1255 
1256 		if (strlcat(buf, n->string, 64) >= 64)
1257 			return(mdoc_nerr(mdoc, n, ETOOLONG));
1258 		if (NULL == n->next)
1259 			continue;
1260 		if (strlcat(buf, " ", 64) >= 64)
1261 			return(mdoc_nerr(mdoc, n, ETOOLONG));
1262 	}
1263 
1264 	sec = mdoc_atosec(buf);
1265 
1266 	/*
1267 	 * Check: NAME should always be first, CUSTOM has no roles,
1268 	 * non-CUSTOM has a conventional order to be followed.
1269 	 */
1270 
1271 	if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed)
1272 		return(mdoc_nerr(mdoc, mdoc->last, ESECNAME));
1273 	if (SEC_CUSTOM == sec)
1274 		return(1);
1275 	if (sec == mdoc->lastnamed)
1276 		if ( ! mdoc_nwarn(mdoc, mdoc->last, ESECREP))
1277 			return(0);
1278 	if (sec < mdoc->lastnamed)
1279 		if ( ! mdoc_nwarn(mdoc, mdoc->last, ESECOOO))
1280 			return(0);
1281 
1282 	/*
1283 	 * Check particular section/manual conventions.  LIBRARY can
1284 	 * only occur in msec 2, 3 (TODO: are there more of these?).
1285 	 */
1286 
1287 	switch (sec) {
1288 	case (SEC_LIBRARY):
1289 		switch (mdoc->meta.msec) {
1290 		case (2):
1291 			/* FALLTHROUGH */
1292 		case (3):
1293 			break;
1294 		default:
1295 			return(mdoc_nwarn(mdoc, mdoc->last, EWRONGMSEC));
1296 		}
1297 		break;
1298 	default:
1299 		break;
1300 	}
1301 
1302 	return(1);
1303 }
1304 
1305 
1306 static int
1307 pre_fd(PRE_ARGS)
1308 {
1309 
1310 	return(check_sec(mdoc, n, SEC_SYNOPSIS, SEC_CUSTOM));
1311 }
1312