mdoc_validate.c revision 1.45
1/*	$Id: mdoc_validate.c,v 1.45 2010/04/03 16:24:17 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_print(struct mdoc *, int, int);
60static	int	 warn_count(struct mdoc *, const char *,
61			int, const char *, int);
62static	int	 err_count(struct mdoc *, const char *,
63			int, const char *, int);
64
65static	int	 berr_ge1(POST_ARGS);
66static	int	 bwarn_ge1(POST_ARGS);
67static	int	 ebool(POST_ARGS);
68static	int	 eerr_eq0(POST_ARGS);
69static	int	 eerr_eq1(POST_ARGS);
70static	int	 eerr_ge1(POST_ARGS);
71static	int	 eerr_le1(POST_ARGS);
72static	int	 ewarn_ge1(POST_ARGS);
73static	int	 herr_eq0(POST_ARGS);
74static	int	 herr_ge1(POST_ARGS);
75static	int	 hwarn_eq1(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_cd(PRE_ARGS);
97static	int	 pre_dd(PRE_ARGS);
98static	int	 pre_display(PRE_ARGS);
99static	int	 pre_dt(PRE_ARGS);
100static	int	 pre_er(PRE_ARGS);
101static	int	 pre_ex(PRE_ARGS);
102static	int	 pre_fd(PRE_ARGS);
103static	int	 pre_it(PRE_ARGS);
104static	int	 pre_lb(PRE_ARGS);
105static	int	 pre_os(PRE_ARGS);
106static	int	 pre_rv(PRE_ARGS);
107static	int	 pre_sh(PRE_ARGS);
108static	int	 pre_ss(PRE_ARGS);
109
110static	v_post	 posts_an[] = { post_an, NULL };
111static	v_post	 posts_at[] = { post_at, NULL };
112static	v_post	 posts_bd[] = { herr_eq0, bwarn_ge1, NULL };
113static	v_post	 posts_bf[] = { hwarn_le1, post_bf, NULL };
114static	v_post	 posts_bl[] = { bwarn_ge1, post_bl, NULL };
115static	v_post	 posts_bool[] = { eerr_eq1, ebool, NULL };
116static	v_post	 posts_fo[] = { hwarn_eq1, bwarn_ge1, NULL };
117static	v_post	 posts_it[] = { post_it, NULL };
118static	v_post	 posts_lb[] = { eerr_eq1, post_lb, NULL };
119static	v_post	 posts_nd[] = { berr_ge1, NULL };
120static	v_post	 posts_nm[] = { post_nm, NULL };
121static	v_post	 posts_notext[] = { eerr_eq0, NULL };
122static	v_post	 posts_rs[] = { berr_ge1, herr_eq0, post_rs, NULL };
123static	v_post	 posts_sh[] = { herr_ge1, bwarn_ge1, post_sh, NULL };
124static	v_post	 posts_sp[] = { eerr_le1, NULL };
125static	v_post	 posts_ss[] = { herr_ge1, NULL };
126static	v_post	 posts_st[] = { eerr_eq1, post_st, NULL };
127static	v_post	 posts_text[] = { eerr_ge1, NULL };
128static	v_post	 posts_text1[] = { eerr_eq1, NULL };
129static	v_post	 posts_vt[] = { post_vt, NULL };
130static	v_post	 posts_wline[] = { bwarn_ge1, herr_eq0, NULL };
131static	v_post	 posts_wtext[] = { ewarn_ge1, NULL };
132static	v_post	 posts_xr[] = { eerr_ge1, NULL };
133static	v_pre	 pres_an[] = { pre_an, NULL };
134static	v_pre	 pres_bd[] = { pre_display, pre_bd, NULL };
135static	v_pre	 pres_bl[] = { pre_bl, NULL };
136static	v_pre	 pres_cd[] = { pre_cd, NULL };
137static	v_pre	 pres_d1[] = { pre_display, NULL };
138static	v_pre	 pres_dd[] = { pre_dd, NULL };
139static	v_pre	 pres_dt[] = { pre_dt, NULL };
140static	v_pre	 pres_er[] = { pre_er, NULL };
141static	v_pre	 pres_ex[] = { pre_ex, NULL };
142static	v_pre	 pres_fd[] = { pre_fd, NULL };
143static	v_pre	 pres_it[] = { pre_it, NULL };
144static	v_pre	 pres_lb[] = { pre_lb, NULL };
145static	v_pre	 pres_os[] = { pre_os, NULL };
146static	v_pre	 pres_rv[] = { pre_rv, NULL };
147static	v_pre	 pres_sh[] = { pre_sh, NULL };
148static	v_pre	 pres_ss[] = { pre_ss, NULL };
149
150const	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_vt },			/* 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 */ /* FIXME: check date with mandoc_a2time(). */
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	{ NULL, NULL },				/* eos */
273};
274
275
276int
277mdoc_valid_pre(struct mdoc *mdoc, const struct mdoc_node *n)
278{
279	v_pre		*p;
280	int		 line, pos;
281	const char	*tp;
282
283	if (MDOC_TEXT == n->type) {
284		tp = n->string;
285		line = n->line;
286		pos = n->pos;
287		return(check_text(mdoc, line, pos, tp));
288	}
289
290	if ( ! check_args(mdoc, n))
291		return(0);
292	if (NULL == mdoc_valids[n->tok].pre)
293		return(1);
294	for (p = mdoc_valids[n->tok].pre; *p; p++)
295		if ( ! (*p)(mdoc, n))
296			return(0);
297	return(1);
298}
299
300
301int
302mdoc_valid_post(struct mdoc *mdoc)
303{
304	v_post		*p;
305
306	if (MDOC_VALID & mdoc->last->flags)
307		return(1);
308	mdoc->last->flags |= MDOC_VALID;
309
310	if (MDOC_TEXT == mdoc->last->type)
311		return(1);
312	if (MDOC_ROOT == mdoc->last->type)
313		return(post_root(mdoc));
314
315	if (NULL == mdoc_valids[mdoc->last->tok].post)
316		return(1);
317	for (p = mdoc_valids[mdoc->last->tok].post; *p; p++)
318		if ( ! (*p)(mdoc))
319			return(0);
320
321	return(1);
322}
323
324
325static int
326warn_print(struct mdoc *m, int ln, int pos)
327{
328
329	if (MDOC_IGN_CHARS & m->pflags)
330		return(mdoc_pwarn(m, ln, pos, EPRINT));
331	return(mdoc_perr(m, ln, pos, EPRINT));
332}
333
334
335static inline int
336warn_count(struct mdoc *m, const char *k,
337		int want, const char *v, int has)
338{
339
340	return(mdoc_vwarn(m, m->last->line, m->last->pos,
341		"suggests %s %s %d (has %d)", v, k, want, has));
342}
343
344
345static inline int
346err_count(struct mdoc *m, const char *k,
347		int want, const char *v, int has)
348{
349
350	return(mdoc_verr(m, m->last->line, m->last->pos,
351		"requires %s %s %d (has %d)", v, k, want, has));
352}
353
354
355/*
356 * Build these up with macros because they're basically the same check
357 * for different inequalities.  Yes, this could be done with functions,
358 * but this is reasonable for now.
359 */
360
361#define CHECK_CHILD_DEFN(lvl, name, ineq) 			\
362static int 							\
363lvl##_child_##name(struct mdoc *mdoc, const char *p, int sz) 	\
364{ 								\
365	if (mdoc->last->nchild ineq sz)				\
366		return(1); 					\
367	return(lvl##_count(mdoc, #ineq, sz, p, mdoc->last->nchild)); \
368}
369
370#define CHECK_BODY_DEFN(name, lvl, func, num) 			\
371static int 							\
372b##lvl##_##name(POST_ARGS) 					\
373{ 								\
374	if (MDOC_BODY != mdoc->last->type) 			\
375		return(1); 					\
376	return(func(mdoc, "multi-line arguments", (num))); 	\
377}
378
379#define CHECK_ELEM_DEFN(name, lvl, func, num) 			\
380static int							\
381e##lvl##_##name(POST_ARGS) 					\
382{ 								\
383	assert(MDOC_ELEM == mdoc->last->type); 			\
384	return(func(mdoc, "line arguments", (num))); 		\
385}
386
387#define CHECK_HEAD_DEFN(name, lvl, func, num)			\
388static int 							\
389h##lvl##_##name(POST_ARGS) 					\
390{ 								\
391	if (MDOC_HEAD != mdoc->last->type) 			\
392		return(1); 					\
393	return(func(mdoc, "line arguments", (num)));	 	\
394}
395
396
397CHECK_CHILD_DEFN(warn, gt, >)			/* warn_child_gt() */
398CHECK_CHILD_DEFN(err, gt, >)			/* err_child_gt() */
399CHECK_CHILD_DEFN(warn, eq, ==)			/* warn_child_eq() */
400CHECK_CHILD_DEFN(err, eq, ==)			/* err_child_eq() */
401CHECK_CHILD_DEFN(err, lt, <)			/* err_child_lt() */
402CHECK_CHILD_DEFN(warn, lt, <)			/* warn_child_lt() */
403CHECK_BODY_DEFN(ge1, warn, warn_child_gt, 0)	/* bwarn_ge1() */
404CHECK_BODY_DEFN(ge1, err, err_child_gt, 0)	/* berr_ge1() */
405CHECK_ELEM_DEFN(ge1, warn, warn_child_gt, 0)	/* ewarn_gt1() */
406CHECK_ELEM_DEFN(eq1, err, err_child_eq, 1)	/* eerr_eq1() */
407CHECK_ELEM_DEFN(le1, err, err_child_lt, 2)	/* eerr_le1() */
408CHECK_ELEM_DEFN(eq0, err, err_child_eq, 0)	/* eerr_eq0() */
409CHECK_ELEM_DEFN(ge1, err, err_child_gt, 0)	/* eerr_ge1() */
410CHECK_HEAD_DEFN(eq0, err, err_child_eq, 0)	/* herr_eq0() */
411CHECK_HEAD_DEFN(le1, warn, warn_child_lt, 2)	/* hwarn_le1() */
412CHECK_HEAD_DEFN(ge1, err, err_child_gt, 0)	/* herr_ge1() */
413CHECK_HEAD_DEFN(eq1, warn, warn_child_eq, 1)	/* hwarn_eq1() */
414
415
416static int
417check_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
427static int
428check_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
451static int
452check_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
473static int
474check_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
490static int
491check_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
511static int
512check_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
546static int
547check_parent(PRE_ARGS, enum mdoct 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
561static int
562pre_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
583static int
584pre_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_Ohang):
666		/* FALLTHROUGH */
667	case (MDOC_Inset):
668		/* FALLTHROUGH */
669	case (MDOC_Item):
670		if (width >= 0 && ! mdoc_nwarn(mdoc, n, ENOWIDTH))
671			return(0);
672		break;
673	default:
674		break;
675	}
676
677	return(1);
678}
679
680
681static int
682pre_bd(PRE_ARGS)
683{
684	int		 i, type, err;
685
686	if (MDOC_BLOCK != n->type)
687		return(1);
688	if (NULL == n->args)
689		return(mdoc_nerr(mdoc, n, EDISPTYPE));
690
691	/* Make sure that only one type of display is specified.  */
692
693	/* LINTED */
694	for (i = 0, err = type = 0; ! err &&
695			i < (int)n->args->argc; i++)
696		switch (n->args->argv[i].arg) {
697		case (MDOC_Centred):
698			/* FALLTHROUGH */
699		case (MDOC_Ragged):
700			/* FALLTHROUGH */
701		case (MDOC_Unfilled):
702			/* FALLTHROUGH */
703		case (MDOC_Filled):
704			/* FALLTHROUGH */
705		case (MDOC_Literal):
706			if (0 == type++)
707				break;
708			return(mdoc_nerr(mdoc, n, EMULTIDISP));
709		default:
710			break;
711		}
712
713	if (type)
714		return(1);
715	return(mdoc_nerr(mdoc, n, EDISPTYPE));
716}
717
718
719static int
720pre_ss(PRE_ARGS)
721{
722
723	if (MDOC_BLOCK != n->type)
724		return(1);
725	return(check_parent(mdoc, n, MDOC_Sh, MDOC_BODY));
726}
727
728
729static int
730pre_sh(PRE_ARGS)
731{
732
733	if (MDOC_BLOCK != n->type)
734		return(1);
735	return(check_parent(mdoc, n, -1, MDOC_ROOT));
736}
737
738
739static int
740pre_it(PRE_ARGS)
741{
742
743	if (MDOC_BLOCK != n->type)
744		return(1);
745	return(check_parent(mdoc, n, MDOC_Bl, MDOC_BODY));
746}
747
748
749static int
750pre_an(PRE_ARGS)
751{
752
753	if (NULL == n->args || 1 == n->args->argc)
754		return(1);
755	return(mdoc_verr(mdoc, n->line, n->pos,
756				"only one argument allowed"));
757}
758
759
760static int
761pre_lb(PRE_ARGS)
762{
763
764	return(check_sec(mdoc, n, SEC_LIBRARY, SEC_CUSTOM));
765}
766
767
768static int
769pre_rv(PRE_ARGS)
770{
771
772	if ( ! check_msec(mdoc, n, 2, 3, 0))
773		return(0);
774	return(check_stdarg(mdoc, n));
775}
776
777
778static int
779pre_ex(PRE_ARGS)
780{
781
782	if ( ! check_msec(mdoc, n, 1, 6, 8, 0))
783		return(0);
784	return(check_stdarg(mdoc, n));
785}
786
787
788static int
789pre_er(PRE_ARGS)
790{
791
792	return(check_msec(mdoc, n, 2, 3, 9, 0));
793}
794
795
796static int
797pre_cd(PRE_ARGS)
798{
799
800	return(check_msec(mdoc, n, 4, 0));
801}
802
803
804static int
805pre_dt(PRE_ARGS)
806{
807
808	/* FIXME: make sure is capitalised. */
809
810	if (0 == mdoc->meta.date || mdoc->meta.os)
811		if ( ! mdoc_nwarn(mdoc, n, EPROLOOO))
812			return(0);
813	if (mdoc->meta.title)
814		if ( ! mdoc_nwarn(mdoc, n, EPROLREP))
815			return(0);
816	return(1);
817}
818
819
820static int
821pre_os(PRE_ARGS)
822{
823
824	if (NULL == mdoc->meta.title || 0 == mdoc->meta.date)
825		if ( ! mdoc_nwarn(mdoc, n, EPROLOOO))
826			return(0);
827	if (mdoc->meta.os)
828		if ( ! mdoc_nwarn(mdoc, n, EPROLREP))
829			return(0);
830	return(1);
831}
832
833
834static int
835pre_dd(PRE_ARGS)
836{
837
838	if (mdoc->meta.title || mdoc->meta.os)
839		if ( ! mdoc_nwarn(mdoc, n, EPROLOOO))
840			return(0);
841	if (mdoc->meta.date)
842		if ( ! mdoc_nwarn(mdoc, n, EPROLREP))
843			return(0);
844	return(1);
845}
846
847
848static int
849post_bf(POST_ARGS)
850{
851	char		 *p;
852	struct mdoc_node *head;
853
854	if (MDOC_BLOCK != mdoc->last->type)
855		return(1);
856
857	head = mdoc->last->head;
858
859	if (mdoc->last->args && head->child)
860		return(mdoc_nerr(mdoc, mdoc->last, ELINE));
861	else if (mdoc->last->args)
862		return(1);
863
864	if (NULL == head->child || MDOC_TEXT != head->child->type)
865		return(mdoc_nerr(mdoc, mdoc->last, ELINE));
866
867	p = head->child->string;
868
869	if (0 == strcmp(p, "Em"))
870		return(1);
871	else if (0 == strcmp(p, "Li"))
872		return(1);
873	else if (0 == strcmp(p, "Sy"))
874		return(1);
875
876	return(mdoc_nerr(mdoc, head, EFONT));
877}
878
879
880static int
881post_lb(POST_ARGS)
882{
883
884	if (mdoc_a2lib(mdoc->last->child->string))
885		return(1);
886	return(mdoc_nwarn(mdoc, mdoc->last, ELIB));
887}
888
889
890static int
891post_vt(POST_ARGS)
892{
893	const struct mdoc_node *n;
894
895	/*
896	 * The Vt macro comes in both ELEM and BLOCK form, both of which
897	 * have different syntaxes (yet more context-sensitive
898	 * behaviour).  ELEM types must have a child; BLOCK types,
899	 * specifically the BODY, should only have TEXT children.
900	 */
901
902	if (MDOC_ELEM == mdoc->last->type)
903		return(eerr_ge1(mdoc));
904	if (MDOC_BODY != mdoc->last->type)
905		return(1);
906
907	for (n = mdoc->last->child; n; n = n->next)
908		if (MDOC_TEXT != n->type &&
909		    (MDOC_ELEM != n->type || MDOC_eos != n->tok))
910			if ( ! mdoc_nwarn(mdoc, n, EBADCHILD))
911				return(0);
912
913	return(1);
914}
915
916
917static int
918post_nm(POST_ARGS)
919{
920
921	if (mdoc->last->child)
922		return(1);
923	if (mdoc->meta.name)
924		return(1);
925	return(mdoc_nerr(mdoc, mdoc->last, ENAME));
926}
927
928
929static int
930post_at(POST_ARGS)
931{
932
933	if (NULL == mdoc->last->child)
934		return(1);
935	if (MDOC_TEXT != mdoc->last->child->type)
936		return(mdoc_nerr(mdoc, mdoc->last, EATT));
937	if (mdoc_a2att(mdoc->last->child->string))
938		return(1);
939	return(mdoc_nerr(mdoc, mdoc->last, EATT));
940}
941
942
943static int
944post_an(POST_ARGS)
945{
946
947	if (mdoc->last->args) {
948		if (NULL == mdoc->last->child)
949			return(1);
950		return(mdoc_nerr(mdoc, mdoc->last, ENOLINE));
951	}
952
953	if (mdoc->last->child)
954		return(1);
955	return(mdoc_nerr(mdoc, mdoc->last, ELINE));
956}
957
958
959static int
960post_it(POST_ARGS)
961{
962	int		  type, i, cols;
963	struct mdoc_node *n, *c;
964
965	if (MDOC_BLOCK != mdoc->last->type)
966		return(1);
967
968	n = mdoc->last->parent->parent;
969	if (NULL == n->args)
970		return(mdoc_nerr(mdoc, mdoc->last, ELISTTYPE));
971
972	/* Some types require block-head, some not. */
973
974	/* LINTED */
975	for (cols = type = -1, i = 0; -1 == type &&
976			i < (int)n->args->argc; i++)
977		switch (n->args->argv[i].arg) {
978		case (MDOC_Tag):
979			/* FALLTHROUGH */
980		case (MDOC_Diag):
981			/* FALLTHROUGH */
982		case (MDOC_Hang):
983			/* FALLTHROUGH */
984		case (MDOC_Ohang):
985			/* FALLTHROUGH */
986		case (MDOC_Inset):
987			/* FALLTHROUGH */
988		case (MDOC_Bullet):
989			/* FALLTHROUGH */
990		case (MDOC_Dash):
991			/* FALLTHROUGH */
992		case (MDOC_Enum):
993			/* FALLTHROUGH */
994		case (MDOC_Hyphen):
995			/* FALLTHROUGH */
996		case (MDOC_Item):
997			type = n->args->argv[i].arg;
998			break;
999		case (MDOC_Column):
1000			type = n->args->argv[i].arg;
1001			cols = (int)n->args->argv[i].sz;
1002			break;
1003		default:
1004			break;
1005		}
1006
1007	if (-1 == type)
1008		return(mdoc_nerr(mdoc, mdoc->last, ELISTTYPE));
1009
1010	switch (type) {
1011	case (MDOC_Tag):
1012		if (NULL == mdoc->last->head->child)
1013			if ( ! mdoc_nwarn(mdoc, mdoc->last, ELINE))
1014				return(0);
1015		break;
1016	case (MDOC_Hang):
1017		/* FALLTHROUGH */
1018	case (MDOC_Ohang):
1019		/* FALLTHROUGH */
1020	case (MDOC_Inset):
1021		/* FALLTHROUGH */
1022	case (MDOC_Diag):
1023		if (NULL == mdoc->last->head->child)
1024			if ( ! mdoc_nwarn(mdoc, mdoc->last, ELINE))
1025				return(0);
1026		if (NULL == mdoc->last->body->child)
1027			if ( ! mdoc_nwarn(mdoc, mdoc->last, EMULTILINE))
1028				return(0);
1029		break;
1030	case (MDOC_Bullet):
1031		/* FALLTHROUGH */
1032	case (MDOC_Dash):
1033		/* FALLTHROUGH */
1034	case (MDOC_Enum):
1035		/* FALLTHROUGH */
1036	case (MDOC_Hyphen):
1037		/* FALLTHROUGH */
1038	case (MDOC_Item):
1039		if (mdoc->last->head->child)
1040			if ( ! mdoc_nwarn(mdoc, mdoc->last, ENOLINE))
1041				return(0);
1042		if (NULL == mdoc->last->body->child)
1043			if ( ! mdoc_nwarn(mdoc, mdoc->last, EMULTILINE))
1044				return(0);
1045		break;
1046	case (MDOC_Column):
1047		if (NULL == mdoc->last->head->child)
1048			if ( ! mdoc_nwarn(mdoc, mdoc->last, ELINE))
1049				return(0);
1050		if (mdoc->last->body->child)
1051			if ( ! mdoc_nwarn(mdoc, mdoc->last, ENOMULTILINE))
1052				return(0);
1053		c = mdoc->last->child;
1054		for (i = 0; c && MDOC_HEAD == c->type; c = c->next)
1055			i++;
1056
1057		if (i < cols || i == (cols + 1)) {
1058			if ( ! mdoc_vwarn(mdoc, mdoc->last->line,
1059					mdoc->last->pos, "column "
1060					"mismatch: have %d, want %d",
1061					i, cols))
1062				return(0);
1063			break;
1064		} else if (i == cols)
1065			break;
1066
1067		return(mdoc_verr(mdoc, mdoc->last->line,
1068				mdoc->last->pos, "column mismatch: "
1069				"have %d, want %d", i, cols));
1070	default:
1071		break;
1072	}
1073
1074	return(1);
1075}
1076
1077
1078static int
1079post_bl_head(POST_ARGS)
1080{
1081	int			i;
1082	const struct mdoc_node *n;
1083
1084	n = mdoc->last->parent;
1085	assert(n->args);
1086
1087	for (i = 0; i < (int)n->args->argc; i++)
1088		if (n->args->argv[i].arg == MDOC_Column)
1089			break;
1090
1091	if (i == (int)n->args->argc)
1092		return(1);
1093
1094	if (n->args->argv[i].sz && mdoc->last->child)
1095		return(mdoc_nerr(mdoc, n, ECOLMIS));
1096
1097	return(1);
1098}
1099
1100
1101static int
1102post_bl(POST_ARGS)
1103{
1104	struct mdoc_node	*n;
1105
1106	if (MDOC_HEAD == mdoc->last->type)
1107		return(post_bl_head(mdoc));
1108	if (MDOC_BODY != mdoc->last->type)
1109		return(1);
1110	if (NULL == mdoc->last->child)
1111		return(1);
1112
1113	/*
1114	 * We only allow certain children of `Bl'.  This is usually on
1115	 * `It', but apparently `Sm' occurs here and there, so we let
1116	 * that one through, too.
1117	 */
1118
1119	/* LINTED */
1120	for (n = mdoc->last->child; n; n = n->next) {
1121		if (MDOC_BLOCK == n->type && MDOC_It == n->tok)
1122			continue;
1123		if (MDOC_Sm == n->tok)
1124			continue;
1125		return(mdoc_nerr(mdoc, n, EBADCHILD));
1126	}
1127
1128	return(1);
1129}
1130
1131
1132static int
1133ebool(struct mdoc *mdoc)
1134{
1135	struct mdoc_node *n;
1136
1137	/* LINTED */
1138	for (n = mdoc->last->child; n; n = n->next) {
1139		if (MDOC_TEXT != n->type)
1140			break;
1141		if (0 == strcmp(n->string, "on"))
1142			continue;
1143		if (0 == strcmp(n->string, "off"))
1144			continue;
1145		break;
1146	}
1147
1148	if (NULL == n)
1149		return(1);
1150	return(mdoc_nerr(mdoc, n, EBOOL));
1151}
1152
1153
1154static int
1155post_root(POST_ARGS)
1156{
1157
1158	if (NULL == mdoc->first->child)
1159		return(mdoc_nerr(mdoc, mdoc->first, ENODAT));
1160	if ( ! (MDOC_PBODY & mdoc->flags))
1161		return(mdoc_nerr(mdoc, mdoc->first, ENOPROLOGUE));
1162
1163	if (MDOC_BLOCK != mdoc->first->child->type)
1164		return(mdoc_nerr(mdoc, mdoc->first, ENODAT));
1165	if (MDOC_Sh != mdoc->first->child->tok)
1166		return(mdoc_nerr(mdoc, mdoc->first, ENODAT));
1167
1168	return(1);
1169}
1170
1171
1172static int
1173post_st(POST_ARGS)
1174{
1175
1176	if (mdoc_a2st(mdoc->last->child->string))
1177		return(1);
1178	return(mdoc_nerr(mdoc, mdoc->last, EBADSTAND));
1179}
1180
1181
1182static int
1183post_rs(POST_ARGS)
1184{
1185	struct mdoc_node	*nn;
1186
1187	if (MDOC_BODY != mdoc->last->type)
1188		return(1);
1189
1190	for (nn = mdoc->last->child; nn; nn = nn->next)
1191		switch (nn->tok) {
1192		case(MDOC__U):
1193			/* FALLTHROUGH */
1194		case(MDOC__Q):
1195			/* FALLTHROUGH */
1196		case(MDOC__C):
1197			/* FALLTHROUGH */
1198		case(MDOC__A):
1199			/* FALLTHROUGH */
1200		case(MDOC__B):
1201			/* FALLTHROUGH */
1202		case(MDOC__D):
1203			/* FALLTHROUGH */
1204		case(MDOC__I):
1205			/* FALLTHROUGH */
1206		case(MDOC__J):
1207			/* FALLTHROUGH */
1208		case(MDOC__N):
1209			/* FALLTHROUGH */
1210		case(MDOC__O):
1211			/* FALLTHROUGH */
1212		case(MDOC__P):
1213			/* FALLTHROUGH */
1214		case(MDOC__R):
1215			/* FALLTHROUGH */
1216		case(MDOC__T):
1217			/* FALLTHROUGH */
1218		case(MDOC__V):
1219			break;
1220		default:
1221			return(mdoc_nerr(mdoc, nn, EBADCHILD));
1222		}
1223
1224	return(1);
1225}
1226
1227
1228static int
1229post_sh(POST_ARGS)
1230{
1231
1232	if (MDOC_HEAD == mdoc->last->type)
1233		return(post_sh_head(mdoc));
1234	if (MDOC_BODY == mdoc->last->type)
1235		return(post_sh_body(mdoc));
1236
1237	return(1);
1238}
1239
1240
1241static int
1242post_sh_body(POST_ARGS)
1243{
1244	struct mdoc_node *n;
1245
1246	if (SEC_NAME != mdoc->lastsec)
1247		return(1);
1248
1249	/*
1250	 * Warn if the NAME section doesn't contain the `Nm' and `Nd'
1251	 * macros (can have multiple `Nm' and one `Nd').  Note that the
1252	 * children of the BODY declaration can also be "text".
1253	 */
1254
1255	if (NULL == (n = mdoc->last->child))
1256		return(mdoc_nwarn(mdoc, mdoc->last, ENAMESECINC));
1257
1258	for ( ; n && n->next; n = n->next) {
1259		if (MDOC_ELEM == n->type && MDOC_Nm == n->tok)
1260			continue;
1261		if (MDOC_TEXT == n->type)
1262			continue;
1263		if ( ! mdoc_nwarn(mdoc, mdoc->last, ENAMESECINC))
1264			return(0);
1265	}
1266
1267	assert(n);
1268	if (MDOC_BLOCK == n->type && MDOC_Nd == n->tok)
1269		return(1);
1270	return(mdoc_nwarn(mdoc, mdoc->last, ENAMESECINC));
1271}
1272
1273
1274static int
1275post_sh_head(POST_ARGS)
1276{
1277	char		        buf[64];
1278	enum mdoc_sec	        sec;
1279	const struct mdoc_node *n;
1280
1281	/*
1282	 * Process a new section.  Sections are either "named" or
1283	 * "custom"; custom sections are user-defined, while named ones
1284	 * usually follow a conventional order and may only appear in
1285	 * certain manual sections.
1286	 */
1287
1288	buf[0] = 0;
1289
1290	for (n = mdoc->last->child; n; n = n->next) {
1291		/* XXX - copied from compact(). */
1292		assert(MDOC_TEXT == n->type);
1293
1294		if (strlcat(buf, n->string, 64) >= 64)
1295			return(mdoc_nerr(mdoc, n, ETOOLONG));
1296		if (NULL == n->next)
1297			continue;
1298		if (strlcat(buf, " ", 64) >= 64)
1299			return(mdoc_nerr(mdoc, n, ETOOLONG));
1300	}
1301
1302	sec = mdoc_atosec(buf);
1303
1304	/*
1305	 * Check: NAME should always be first, CUSTOM has no roles,
1306	 * non-CUSTOM has a conventional order to be followed.
1307	 */
1308
1309	if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed &&
1310	    ! mdoc_nwarn(mdoc, mdoc->last, ESECNAME))
1311		return(0);
1312	if (SEC_CUSTOM == sec)
1313		return(1);
1314	if (sec == mdoc->lastnamed)
1315		if ( ! mdoc_nwarn(mdoc, mdoc->last, ESECREP))
1316			return(0);
1317	if (sec < mdoc->lastnamed)
1318		if ( ! mdoc_nwarn(mdoc, mdoc->last, ESECOOO))
1319			return(0);
1320
1321	/*
1322	 * Check particular section/manual conventions.  LIBRARY can
1323	 * only occur in msec 2, 3 (TODO: are there more of these?).
1324	 */
1325
1326	switch (sec) {
1327	case (SEC_LIBRARY):
1328		switch (mdoc->meta.msec) {
1329		case (2):
1330			/* FALLTHROUGH */
1331		case (3):
1332			break;
1333		default:
1334			return(mdoc_nwarn(mdoc, mdoc->last, EWRONGMSEC));
1335		}
1336		break;
1337	default:
1338		break;
1339	}
1340
1341	return(1);
1342}
1343
1344
1345static int
1346pre_fd(PRE_ARGS)
1347{
1348
1349	return(check_sec(mdoc, n, SEC_SYNOPSIS, SEC_CUSTOM));
1350}
1351