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