xref: /titanic_51/usr/src/cmd/mandoc/man_validate.c (revision 698f87a48e2e945bfe5493ce168e0d0ae1cedd5c)
1*698f87a4SGarrett D'Amore /*	$Id: man_validate.c,v 1.86 2013/10/17 20:54:58 schwarze Exp $ */
295c635efSGarrett D'Amore /*
395c635efSGarrett D'Amore  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4*698f87a4SGarrett D'Amore  * Copyright (c) 2010, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
595c635efSGarrett D'Amore  *
695c635efSGarrett D'Amore  * Permission to use, copy, modify, and distribute this software for any
795c635efSGarrett D'Amore  * purpose with or without fee is hereby granted, provided that the above
895c635efSGarrett D'Amore  * copyright notice and this permission notice appear in all copies.
995c635efSGarrett D'Amore  *
1095c635efSGarrett D'Amore  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1195c635efSGarrett D'Amore  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1295c635efSGarrett D'Amore  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1395c635efSGarrett D'Amore  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1495c635efSGarrett D'Amore  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1595c635efSGarrett D'Amore  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1695c635efSGarrett D'Amore  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1795c635efSGarrett D'Amore  */
1895c635efSGarrett D'Amore #ifdef HAVE_CONFIG_H
1995c635efSGarrett D'Amore #include "config.h"
2095c635efSGarrett D'Amore #endif
2195c635efSGarrett D'Amore 
2295c635efSGarrett D'Amore #include <sys/types.h>
2395c635efSGarrett D'Amore 
2495c635efSGarrett D'Amore #include <assert.h>
2595c635efSGarrett D'Amore #include <ctype.h>
2695c635efSGarrett D'Amore #include <errno.h>
2795c635efSGarrett D'Amore #include <limits.h>
2895c635efSGarrett D'Amore #include <stdarg.h>
2995c635efSGarrett D'Amore #include <stdlib.h>
3095c635efSGarrett D'Amore #include <string.h>
3195c635efSGarrett D'Amore #include <time.h>
3295c635efSGarrett D'Amore 
3395c635efSGarrett D'Amore #include "man.h"
3495c635efSGarrett D'Amore #include "mandoc.h"
3595c635efSGarrett D'Amore #include "libman.h"
3695c635efSGarrett D'Amore #include "libmandoc.h"
3795c635efSGarrett D'Amore 
38*698f87a4SGarrett D'Amore #define	CHKARGS	  struct man *man, struct man_node *n
3995c635efSGarrett D'Amore 
4095c635efSGarrett D'Amore typedef	int	(*v_check)(CHKARGS);
4195c635efSGarrett D'Amore 
4295c635efSGarrett D'Amore struct	man_valid {
4395c635efSGarrett D'Amore 	v_check	 *pres;
4495c635efSGarrett D'Amore 	v_check	 *posts;
4595c635efSGarrett D'Amore };
4695c635efSGarrett D'Amore 
4795c635efSGarrett D'Amore static	int	  check_eq0(CHKARGS);
4895c635efSGarrett D'Amore static	int	  check_eq2(CHKARGS);
4995c635efSGarrett D'Amore static	int	  check_le1(CHKARGS);
5095c635efSGarrett D'Amore static	int	  check_ge2(CHKARGS);
5195c635efSGarrett D'Amore static	int	  check_le5(CHKARGS);
52*698f87a4SGarrett D'Amore static	int	  check_head1(CHKARGS);
5395c635efSGarrett D'Amore static	int	  check_par(CHKARGS);
5495c635efSGarrett D'Amore static	int	  check_part(CHKARGS);
5595c635efSGarrett D'Amore static	int	  check_root(CHKARGS);
5695c635efSGarrett D'Amore static	void	  check_text(CHKARGS);
5795c635efSGarrett D'Amore 
5895c635efSGarrett D'Amore static	int	  post_AT(CHKARGS);
59*698f87a4SGarrett D'Amore static	int	  post_IP(CHKARGS);
6095c635efSGarrett D'Amore static	int	  post_vs(CHKARGS);
6195c635efSGarrett D'Amore static	int	  post_fi(CHKARGS);
6295c635efSGarrett D'Amore static	int	  post_ft(CHKARGS);
6395c635efSGarrett D'Amore static	int	  post_nf(CHKARGS);
6495c635efSGarrett D'Amore static	int	  post_sec(CHKARGS);
6595c635efSGarrett D'Amore static	int	  post_TH(CHKARGS);
6695c635efSGarrett D'Amore static	int	  post_UC(CHKARGS);
6795c635efSGarrett D'Amore static	int	  pre_sec(CHKARGS);
6895c635efSGarrett D'Amore 
6995c635efSGarrett D'Amore static	v_check	  posts_at[] = { post_AT, NULL };
7095c635efSGarrett D'Amore static	v_check	  posts_br[] = { post_vs, check_eq0, NULL };
7195c635efSGarrett D'Amore static	v_check	  posts_eq0[] = { check_eq0, NULL };
7295c635efSGarrett D'Amore static	v_check	  posts_eq2[] = { check_eq2, NULL };
7395c635efSGarrett D'Amore static	v_check	  posts_fi[] = { check_eq0, post_fi, NULL };
7495c635efSGarrett D'Amore static	v_check	  posts_ft[] = { post_ft, NULL };
75*698f87a4SGarrett D'Amore static	v_check	  posts_ip[] = { post_IP, NULL };
76*698f87a4SGarrett D'Amore static	v_check	  posts_le1[] = { check_le1, NULL };
7795c635efSGarrett D'Amore static	v_check	  posts_nf[] = { check_eq0, post_nf, NULL };
7895c635efSGarrett D'Amore static	v_check	  posts_par[] = { check_par, NULL };
7995c635efSGarrett D'Amore static	v_check	  posts_part[] = { check_part, NULL };
8095c635efSGarrett D'Amore static	v_check	  posts_sec[] = { post_sec, NULL };
8195c635efSGarrett D'Amore static	v_check	  posts_sp[] = { post_vs, check_le1, NULL };
8295c635efSGarrett D'Amore static	v_check	  posts_th[] = { check_ge2, check_le5, post_TH, NULL };
8395c635efSGarrett D'Amore static	v_check	  posts_uc[] = { post_UC, NULL };
84*698f87a4SGarrett D'Amore static	v_check	  posts_ur[] = { check_head1, check_part, NULL };
8595c635efSGarrett D'Amore static	v_check	  pres_sec[] = { pre_sec, NULL };
8695c635efSGarrett D'Amore 
8795c635efSGarrett D'Amore static	const struct man_valid man_valids[MAN_MAX] = {
8895c635efSGarrett D'Amore 	{ NULL, posts_br }, /* br */
8995c635efSGarrett D'Amore 	{ NULL, posts_th }, /* TH */
9095c635efSGarrett D'Amore 	{ pres_sec, posts_sec }, /* SH */
9195c635efSGarrett D'Amore 	{ pres_sec, posts_sec }, /* SS */
9295c635efSGarrett D'Amore 	{ NULL, NULL }, /* TP */
9395c635efSGarrett D'Amore 	{ NULL, posts_par }, /* LP */
9495c635efSGarrett D'Amore 	{ NULL, posts_par }, /* PP */
9595c635efSGarrett D'Amore 	{ NULL, posts_par }, /* P */
96*698f87a4SGarrett D'Amore 	{ NULL, posts_ip }, /* IP */
9795c635efSGarrett D'Amore 	{ NULL, NULL }, /* HP */
9895c635efSGarrett D'Amore 	{ NULL, NULL }, /* SM */
9995c635efSGarrett D'Amore 	{ NULL, NULL }, /* SB */
10095c635efSGarrett D'Amore 	{ NULL, NULL }, /* BI */
10195c635efSGarrett D'Amore 	{ NULL, NULL }, /* IB */
10295c635efSGarrett D'Amore 	{ NULL, NULL }, /* BR */
10395c635efSGarrett D'Amore 	{ NULL, NULL }, /* RB */
10495c635efSGarrett D'Amore 	{ NULL, NULL }, /* R */
10595c635efSGarrett D'Amore 	{ NULL, NULL }, /* B */
10695c635efSGarrett D'Amore 	{ NULL, NULL }, /* I */
10795c635efSGarrett D'Amore 	{ NULL, NULL }, /* IR */
10895c635efSGarrett D'Amore 	{ NULL, NULL }, /* RI */
10995c635efSGarrett D'Amore 	{ NULL, posts_eq0 }, /* na */
11095c635efSGarrett D'Amore 	{ NULL, posts_sp }, /* sp */
11195c635efSGarrett D'Amore 	{ NULL, posts_nf }, /* nf */
11295c635efSGarrett D'Amore 	{ NULL, posts_fi }, /* fi */
11395c635efSGarrett D'Amore 	{ NULL, NULL }, /* RE */
11495c635efSGarrett D'Amore 	{ NULL, posts_part }, /* RS */
11595c635efSGarrett D'Amore 	{ NULL, NULL }, /* DT */
11695c635efSGarrett D'Amore 	{ NULL, posts_uc }, /* UC */
117*698f87a4SGarrett D'Amore 	{ NULL, posts_le1 }, /* PD */
11895c635efSGarrett D'Amore 	{ NULL, posts_at }, /* AT */
11995c635efSGarrett D'Amore 	{ NULL, NULL }, /* in */
12095c635efSGarrett D'Amore 	{ NULL, posts_ft }, /* ft */
12195c635efSGarrett D'Amore 	{ NULL, posts_eq2 }, /* OP */
122*698f87a4SGarrett D'Amore 	{ NULL, posts_nf }, /* EX */
123*698f87a4SGarrett D'Amore 	{ NULL, posts_fi }, /* EE */
124*698f87a4SGarrett D'Amore 	{ NULL, posts_ur }, /* UR */
125*698f87a4SGarrett D'Amore 	{ NULL, NULL }, /* UE */
12695c635efSGarrett D'Amore };
12795c635efSGarrett D'Amore 
12895c635efSGarrett D'Amore 
12995c635efSGarrett D'Amore int
130*698f87a4SGarrett D'Amore man_valid_pre(struct man *man, struct man_node *n)
13195c635efSGarrett D'Amore {
13295c635efSGarrett D'Amore 	v_check		*cp;
13395c635efSGarrett D'Amore 
13495c635efSGarrett D'Amore 	switch (n->type) {
13595c635efSGarrett D'Amore 	case (MAN_TEXT):
13695c635efSGarrett D'Amore 		/* FALLTHROUGH */
13795c635efSGarrett D'Amore 	case (MAN_ROOT):
13895c635efSGarrett D'Amore 		/* FALLTHROUGH */
13995c635efSGarrett D'Amore 	case (MAN_EQN):
14095c635efSGarrett D'Amore 		/* FALLTHROUGH */
14195c635efSGarrett D'Amore 	case (MAN_TBL):
14295c635efSGarrett D'Amore 		return(1);
14395c635efSGarrett D'Amore 	default:
14495c635efSGarrett D'Amore 		break;
14595c635efSGarrett D'Amore 	}
14695c635efSGarrett D'Amore 
14795c635efSGarrett D'Amore 	if (NULL == (cp = man_valids[n->tok].pres))
14895c635efSGarrett D'Amore 		return(1);
14995c635efSGarrett D'Amore 	for ( ; *cp; cp++)
150*698f87a4SGarrett D'Amore 		if ( ! (*cp)(man, n))
15195c635efSGarrett D'Amore 			return(0);
15295c635efSGarrett D'Amore 	return(1);
15395c635efSGarrett D'Amore }
15495c635efSGarrett D'Amore 
15595c635efSGarrett D'Amore 
15695c635efSGarrett D'Amore int
157*698f87a4SGarrett D'Amore man_valid_post(struct man *man)
15895c635efSGarrett D'Amore {
15995c635efSGarrett D'Amore 	v_check		*cp;
16095c635efSGarrett D'Amore 
161*698f87a4SGarrett D'Amore 	if (MAN_VALID & man->last->flags)
16295c635efSGarrett D'Amore 		return(1);
163*698f87a4SGarrett D'Amore 	man->last->flags |= MAN_VALID;
16495c635efSGarrett D'Amore 
165*698f87a4SGarrett D'Amore 	switch (man->last->type) {
16695c635efSGarrett D'Amore 	case (MAN_TEXT):
167*698f87a4SGarrett D'Amore 		check_text(man, man->last);
16895c635efSGarrett D'Amore 		return(1);
16995c635efSGarrett D'Amore 	case (MAN_ROOT):
170*698f87a4SGarrett D'Amore 		return(check_root(man, man->last));
17195c635efSGarrett D'Amore 	case (MAN_EQN):
17295c635efSGarrett D'Amore 		/* FALLTHROUGH */
17395c635efSGarrett D'Amore 	case (MAN_TBL):
17495c635efSGarrett D'Amore 		return(1);
17595c635efSGarrett D'Amore 	default:
17695c635efSGarrett D'Amore 		break;
17795c635efSGarrett D'Amore 	}
17895c635efSGarrett D'Amore 
179*698f87a4SGarrett D'Amore 	if (NULL == (cp = man_valids[man->last->tok].posts))
18095c635efSGarrett D'Amore 		return(1);
18195c635efSGarrett D'Amore 	for ( ; *cp; cp++)
182*698f87a4SGarrett D'Amore 		if ( ! (*cp)(man, man->last))
18395c635efSGarrett D'Amore 			return(0);
18495c635efSGarrett D'Amore 
18595c635efSGarrett D'Amore 	return(1);
18695c635efSGarrett D'Amore }
18795c635efSGarrett D'Amore 
18895c635efSGarrett D'Amore 
18995c635efSGarrett D'Amore static int
19095c635efSGarrett D'Amore check_root(CHKARGS)
19195c635efSGarrett D'Amore {
19295c635efSGarrett D'Amore 
193*698f87a4SGarrett D'Amore 	if (MAN_BLINE & man->flags)
194*698f87a4SGarrett D'Amore 		man_nmsg(man, n, MANDOCERR_SCOPEEXIT);
195*698f87a4SGarrett D'Amore 	else if (MAN_ELINE & man->flags)
196*698f87a4SGarrett D'Amore 		man_nmsg(man, n, MANDOCERR_SCOPEEXIT);
19795c635efSGarrett D'Amore 
198*698f87a4SGarrett D'Amore 	man->flags &= ~MAN_BLINE;
199*698f87a4SGarrett D'Amore 	man->flags &= ~MAN_ELINE;
20095c635efSGarrett D'Amore 
201*698f87a4SGarrett D'Amore 	if (NULL == man->first->child) {
202*698f87a4SGarrett D'Amore 		man_nmsg(man, n, MANDOCERR_NODOCBODY);
20395c635efSGarrett D'Amore 		return(0);
204*698f87a4SGarrett D'Amore 	} else if (NULL == man->meta.title) {
205*698f87a4SGarrett D'Amore 		man_nmsg(man, n, MANDOCERR_NOTITLE);
20695c635efSGarrett D'Amore 
20795c635efSGarrett D'Amore 		/*
20895c635efSGarrett D'Amore 		 * If a title hasn't been set, do so now (by
20995c635efSGarrett D'Amore 		 * implication, date and section also aren't set).
21095c635efSGarrett D'Amore 		 */
21195c635efSGarrett D'Amore 
212*698f87a4SGarrett D'Amore 	        man->meta.title = mandoc_strdup("unknown");
213*698f87a4SGarrett D'Amore 		man->meta.msec = mandoc_strdup("1");
214*698f87a4SGarrett D'Amore 		man->meta.date = mandoc_normdate
215*698f87a4SGarrett D'Amore 			(man->parse, NULL, n->line, n->pos);
21695c635efSGarrett D'Amore 	}
21795c635efSGarrett D'Amore 
21895c635efSGarrett D'Amore 	return(1);
21995c635efSGarrett D'Amore }
22095c635efSGarrett D'Amore 
22195c635efSGarrett D'Amore static void
22295c635efSGarrett D'Amore check_text(CHKARGS)
22395c635efSGarrett D'Amore {
22495c635efSGarrett D'Amore 	char		*cp, *p;
22595c635efSGarrett D'Amore 
226*698f87a4SGarrett D'Amore 	if (MAN_LITERAL & man->flags)
22795c635efSGarrett D'Amore 		return;
22895c635efSGarrett D'Amore 
22995c635efSGarrett D'Amore 	cp = n->string;
23095c635efSGarrett D'Amore 	for (p = cp; NULL != (p = strchr(p, '\t')); p++)
231*698f87a4SGarrett D'Amore 		man_pmsg(man, n->line, (int)(p - cp), MANDOCERR_BADTAB);
23295c635efSGarrett D'Amore }
23395c635efSGarrett D'Amore 
23495c635efSGarrett D'Amore #define	INEQ_DEFINE(x, ineq, name) \
23595c635efSGarrett D'Amore static int \
23695c635efSGarrett D'Amore check_##name(CHKARGS) \
23795c635efSGarrett D'Amore { \
23895c635efSGarrett D'Amore 	if (n->nchild ineq (x)) \
23995c635efSGarrett D'Amore 		return(1); \
240*698f87a4SGarrett D'Amore 	mandoc_vmsg(MANDOCERR_ARGCOUNT, man->parse, n->line, n->pos, \
24195c635efSGarrett D'Amore 			"line arguments %s %d (have %d)", \
24295c635efSGarrett D'Amore 			#ineq, (x), n->nchild); \
24395c635efSGarrett D'Amore 	return(1); \
24495c635efSGarrett D'Amore }
24595c635efSGarrett D'Amore 
24695c635efSGarrett D'Amore INEQ_DEFINE(0, ==, eq0)
24795c635efSGarrett D'Amore INEQ_DEFINE(2, ==, eq2)
24895c635efSGarrett D'Amore INEQ_DEFINE(1, <=, le1)
24995c635efSGarrett D'Amore INEQ_DEFINE(2, >=, ge2)
25095c635efSGarrett D'Amore INEQ_DEFINE(5, <=, le5)
25195c635efSGarrett D'Amore 
25295c635efSGarrett D'Amore static int
253*698f87a4SGarrett D'Amore check_head1(CHKARGS)
254*698f87a4SGarrett D'Amore {
255*698f87a4SGarrett D'Amore 
256*698f87a4SGarrett D'Amore 	if (MAN_HEAD == n->type && 1 != n->nchild)
257*698f87a4SGarrett D'Amore 		mandoc_vmsg(MANDOCERR_ARGCOUNT, man->parse, n->line,
258*698f87a4SGarrett D'Amore 		    n->pos, "line arguments eq 1 (have %d)", n->nchild);
259*698f87a4SGarrett D'Amore 
260*698f87a4SGarrett D'Amore 	return(1);
261*698f87a4SGarrett D'Amore }
262*698f87a4SGarrett D'Amore 
263*698f87a4SGarrett D'Amore static int
26495c635efSGarrett D'Amore post_ft(CHKARGS)
26595c635efSGarrett D'Amore {
26695c635efSGarrett D'Amore 	char	*cp;
26795c635efSGarrett D'Amore 	int	 ok;
26895c635efSGarrett D'Amore 
26995c635efSGarrett D'Amore 	if (0 == n->nchild)
27095c635efSGarrett D'Amore 		return(1);
27195c635efSGarrett D'Amore 
27295c635efSGarrett D'Amore 	ok = 0;
27395c635efSGarrett D'Amore 	cp = n->child->string;
27495c635efSGarrett D'Amore 	switch (*cp) {
27595c635efSGarrett D'Amore 	case ('1'):
27695c635efSGarrett D'Amore 		/* FALLTHROUGH */
27795c635efSGarrett D'Amore 	case ('2'):
27895c635efSGarrett D'Amore 		/* FALLTHROUGH */
27995c635efSGarrett D'Amore 	case ('3'):
28095c635efSGarrett D'Amore 		/* FALLTHROUGH */
28195c635efSGarrett D'Amore 	case ('4'):
28295c635efSGarrett D'Amore 		/* FALLTHROUGH */
28395c635efSGarrett D'Amore 	case ('I'):
28495c635efSGarrett D'Amore 		/* FALLTHROUGH */
28595c635efSGarrett D'Amore 	case ('P'):
28695c635efSGarrett D'Amore 		/* FALLTHROUGH */
28795c635efSGarrett D'Amore 	case ('R'):
28895c635efSGarrett D'Amore 		if ('\0' == cp[1])
28995c635efSGarrett D'Amore 			ok = 1;
29095c635efSGarrett D'Amore 		break;
29195c635efSGarrett D'Amore 	case ('B'):
29295c635efSGarrett D'Amore 		if ('\0' == cp[1] || ('I' == cp[1] && '\0' == cp[2]))
29395c635efSGarrett D'Amore 			ok = 1;
29495c635efSGarrett D'Amore 		break;
29595c635efSGarrett D'Amore 	case ('C'):
29695c635efSGarrett D'Amore 		if ('W' == cp[1] && '\0' == cp[2])
29795c635efSGarrett D'Amore 			ok = 1;
29895c635efSGarrett D'Amore 		break;
29995c635efSGarrett D'Amore 	default:
30095c635efSGarrett D'Amore 		break;
30195c635efSGarrett D'Amore 	}
30295c635efSGarrett D'Amore 
30395c635efSGarrett D'Amore 	if (0 == ok) {
30495c635efSGarrett D'Amore 		mandoc_vmsg
305*698f87a4SGarrett D'Amore 			(MANDOCERR_BADFONT, man->parse,
30695c635efSGarrett D'Amore 			 n->line, n->pos, "%s", cp);
30795c635efSGarrett D'Amore 		*cp = '\0';
30895c635efSGarrett D'Amore 	}
30995c635efSGarrett D'Amore 
31095c635efSGarrett D'Amore 	if (1 < n->nchild)
31195c635efSGarrett D'Amore 		mandoc_vmsg
312*698f87a4SGarrett D'Amore 			(MANDOCERR_ARGCOUNT, man->parse, n->line,
31395c635efSGarrett D'Amore 			 n->pos, "want one child (have %d)",
31495c635efSGarrett D'Amore 			 n->nchild);
31595c635efSGarrett D'Amore 
31695c635efSGarrett D'Amore 	return(1);
31795c635efSGarrett D'Amore }
31895c635efSGarrett D'Amore 
31995c635efSGarrett D'Amore static int
32095c635efSGarrett D'Amore pre_sec(CHKARGS)
32195c635efSGarrett D'Amore {
32295c635efSGarrett D'Amore 
32395c635efSGarrett D'Amore 	if (MAN_BLOCK == n->type)
324*698f87a4SGarrett D'Amore 		man->flags &= ~MAN_LITERAL;
32595c635efSGarrett D'Amore 	return(1);
32695c635efSGarrett D'Amore }
32795c635efSGarrett D'Amore 
32895c635efSGarrett D'Amore static int
32995c635efSGarrett D'Amore post_sec(CHKARGS)
33095c635efSGarrett D'Amore {
33195c635efSGarrett D'Amore 
33295c635efSGarrett D'Amore 	if ( ! (MAN_HEAD == n->type && 0 == n->nchild))
33395c635efSGarrett D'Amore 		return(1);
33495c635efSGarrett D'Amore 
335*698f87a4SGarrett D'Amore 	man_nmsg(man, n, MANDOCERR_SYNTARGCOUNT);
33695c635efSGarrett D'Amore 	return(0);
33795c635efSGarrett D'Amore }
33895c635efSGarrett D'Amore 
33995c635efSGarrett D'Amore static int
34095c635efSGarrett D'Amore check_part(CHKARGS)
34195c635efSGarrett D'Amore {
34295c635efSGarrett D'Amore 
34395c635efSGarrett D'Amore 	if (MAN_BODY == n->type && 0 == n->nchild)
344*698f87a4SGarrett D'Amore 		mandoc_msg(MANDOCERR_ARGCWARN, man->parse, n->line,
34595c635efSGarrett D'Amore 				n->pos, "want children (have none)");
34695c635efSGarrett D'Amore 
34795c635efSGarrett D'Amore 	return(1);
34895c635efSGarrett D'Amore }
34995c635efSGarrett D'Amore 
35095c635efSGarrett D'Amore 
35195c635efSGarrett D'Amore static int
35295c635efSGarrett D'Amore check_par(CHKARGS)
35395c635efSGarrett D'Amore {
35495c635efSGarrett D'Amore 
35595c635efSGarrett D'Amore 	switch (n->type) {
35695c635efSGarrett D'Amore 	case (MAN_BLOCK):
35795c635efSGarrett D'Amore 		if (0 == n->body->nchild)
358*698f87a4SGarrett D'Amore 			man_node_delete(man, n);
35995c635efSGarrett D'Amore 		break;
36095c635efSGarrett D'Amore 	case (MAN_BODY):
36195c635efSGarrett D'Amore 		if (0 == n->nchild)
362*698f87a4SGarrett D'Amore 			man_nmsg(man, n, MANDOCERR_IGNPAR);
36395c635efSGarrett D'Amore 		break;
36495c635efSGarrett D'Amore 	case (MAN_HEAD):
36595c635efSGarrett D'Amore 		if (n->nchild)
366*698f87a4SGarrett D'Amore 			man_nmsg(man, n, MANDOCERR_ARGSLOST);
36795c635efSGarrett D'Amore 		break;
36895c635efSGarrett D'Amore 	default:
36995c635efSGarrett D'Amore 		break;
37095c635efSGarrett D'Amore 	}
37195c635efSGarrett D'Amore 
37295c635efSGarrett D'Amore 	return(1);
37395c635efSGarrett D'Amore }
37495c635efSGarrett D'Amore 
375*698f87a4SGarrett D'Amore static int
376*698f87a4SGarrett D'Amore post_IP(CHKARGS)
377*698f87a4SGarrett D'Amore {
378*698f87a4SGarrett D'Amore 
379*698f87a4SGarrett D'Amore 	switch (n->type) {
380*698f87a4SGarrett D'Amore 	case (MAN_BLOCK):
381*698f87a4SGarrett D'Amore 		if (0 == n->head->nchild && 0 == n->body->nchild)
382*698f87a4SGarrett D'Amore 			man_node_delete(man, n);
383*698f87a4SGarrett D'Amore 		break;
384*698f87a4SGarrett D'Amore 	case (MAN_BODY):
385*698f87a4SGarrett D'Amore 		if (0 == n->parent->head->nchild && 0 == n->nchild)
386*698f87a4SGarrett D'Amore 			man_nmsg(man, n, MANDOCERR_IGNPAR);
387*698f87a4SGarrett D'Amore 		break;
388*698f87a4SGarrett D'Amore 	default:
389*698f87a4SGarrett D'Amore 		break;
390*698f87a4SGarrett D'Amore 	}
391*698f87a4SGarrett D'Amore 	return(1);
392*698f87a4SGarrett D'Amore }
39395c635efSGarrett D'Amore 
39495c635efSGarrett D'Amore static int
39595c635efSGarrett D'Amore post_TH(CHKARGS)
39695c635efSGarrett D'Amore {
39795c635efSGarrett D'Amore 	const char	*p;
39895c635efSGarrett D'Amore 	int		 line, pos;
39995c635efSGarrett D'Amore 
400*698f87a4SGarrett D'Amore 	free(man->meta.title);
401*698f87a4SGarrett D'Amore 	free(man->meta.vol);
402*698f87a4SGarrett D'Amore 	free(man->meta.source);
403*698f87a4SGarrett D'Amore 	free(man->meta.msec);
404*698f87a4SGarrett D'Amore 	free(man->meta.date);
40595c635efSGarrett D'Amore 
40695c635efSGarrett D'Amore 	line = n->line;
40795c635efSGarrett D'Amore 	pos = n->pos;
408*698f87a4SGarrett D'Amore 	man->meta.title = man->meta.vol = man->meta.date =
409*698f87a4SGarrett D'Amore 		man->meta.msec = man->meta.source = NULL;
41095c635efSGarrett D'Amore 
41195c635efSGarrett D'Amore 	/* ->TITLE<- MSEC DATE SOURCE VOL */
41295c635efSGarrett D'Amore 
41395c635efSGarrett D'Amore 	n = n->child;
41495c635efSGarrett D'Amore 	if (n && n->string) {
41595c635efSGarrett D'Amore 		for (p = n->string; '\0' != *p; p++) {
41695c635efSGarrett D'Amore 			/* Only warn about this once... */
41795c635efSGarrett D'Amore 			if (isalpha((unsigned char)*p) &&
41895c635efSGarrett D'Amore 					! isupper((unsigned char)*p)) {
419*698f87a4SGarrett D'Amore 				man_nmsg(man, n, MANDOCERR_UPPERCASE);
42095c635efSGarrett D'Amore 				break;
42195c635efSGarrett D'Amore 			}
42295c635efSGarrett D'Amore 		}
423*698f87a4SGarrett D'Amore 		man->meta.title = mandoc_strdup(n->string);
42495c635efSGarrett D'Amore 	} else
425*698f87a4SGarrett D'Amore 		man->meta.title = mandoc_strdup("");
42695c635efSGarrett D'Amore 
42795c635efSGarrett D'Amore 	/* TITLE ->MSEC<- DATE SOURCE VOL */
42895c635efSGarrett D'Amore 
42995c635efSGarrett D'Amore 	if (n)
43095c635efSGarrett D'Amore 		n = n->next;
43195c635efSGarrett D'Amore 	if (n && n->string)
432*698f87a4SGarrett D'Amore 		man->meta.msec = mandoc_strdup(n->string);
43395c635efSGarrett D'Amore 	else
434*698f87a4SGarrett D'Amore 		man->meta.msec = mandoc_strdup("");
43595c635efSGarrett D'Amore 
43695c635efSGarrett D'Amore 	/* TITLE MSEC ->DATE<- SOURCE VOL */
43795c635efSGarrett D'Amore 
43895c635efSGarrett D'Amore 	if (n)
43995c635efSGarrett D'Amore 		n = n->next;
44095c635efSGarrett D'Amore 	if (n && n->string && '\0' != n->string[0]) {
44195c635efSGarrett D'Amore 		pos = n->pos;
442*698f87a4SGarrett D'Amore 		man->meta.date = mandoc_normdate
443*698f87a4SGarrett D'Amore 		    (man->parse, n->string, line, pos);
44495c635efSGarrett D'Amore 	} else
445*698f87a4SGarrett D'Amore 		man->meta.date = mandoc_strdup("");
44695c635efSGarrett D'Amore 
44795c635efSGarrett D'Amore 	/* TITLE MSEC DATE ->SOURCE<- VOL */
44895c635efSGarrett D'Amore 
44995c635efSGarrett D'Amore 	if (n && (n = n->next))
450*698f87a4SGarrett D'Amore 		man->meta.source = mandoc_strdup(n->string);
45195c635efSGarrett D'Amore 
45295c635efSGarrett D'Amore 	/* TITLE MSEC DATE SOURCE ->VOL<- */
45395c635efSGarrett D'Amore 	/* If missing, use the default VOL name for MSEC. */
45495c635efSGarrett D'Amore 
45595c635efSGarrett D'Amore 	if (n && (n = n->next))
456*698f87a4SGarrett D'Amore 		man->meta.vol = mandoc_strdup(n->string);
457*698f87a4SGarrett D'Amore 	else if ('\0' != man->meta.msec[0] &&
458*698f87a4SGarrett D'Amore 	    (NULL != (p = mandoc_a2msec(man->meta.msec))))
459*698f87a4SGarrett D'Amore 		man->meta.vol = mandoc_strdup(p);
46095c635efSGarrett D'Amore 
46195c635efSGarrett D'Amore 	/*
46295c635efSGarrett D'Amore 	 * Remove the `TH' node after we've processed it for our
46395c635efSGarrett D'Amore 	 * meta-data.
46495c635efSGarrett D'Amore 	 */
465*698f87a4SGarrett D'Amore 	man_node_delete(man, man->last);
46695c635efSGarrett D'Amore 	return(1);
46795c635efSGarrett D'Amore }
46895c635efSGarrett D'Amore 
46995c635efSGarrett D'Amore static int
47095c635efSGarrett D'Amore post_nf(CHKARGS)
47195c635efSGarrett D'Amore {
47295c635efSGarrett D'Amore 
473*698f87a4SGarrett D'Amore 	if (MAN_LITERAL & man->flags)
474*698f87a4SGarrett D'Amore 		man_nmsg(man, n, MANDOCERR_SCOPEREP);
47595c635efSGarrett D'Amore 
476*698f87a4SGarrett D'Amore 	man->flags |= MAN_LITERAL;
47795c635efSGarrett D'Amore 	return(1);
47895c635efSGarrett D'Amore }
47995c635efSGarrett D'Amore 
48095c635efSGarrett D'Amore static int
48195c635efSGarrett D'Amore post_fi(CHKARGS)
48295c635efSGarrett D'Amore {
48395c635efSGarrett D'Amore 
484*698f87a4SGarrett D'Amore 	if ( ! (MAN_LITERAL & man->flags))
485*698f87a4SGarrett D'Amore 		man_nmsg(man, n, MANDOCERR_WNOSCOPE);
48695c635efSGarrett D'Amore 
487*698f87a4SGarrett D'Amore 	man->flags &= ~MAN_LITERAL;
48895c635efSGarrett D'Amore 	return(1);
48995c635efSGarrett D'Amore }
49095c635efSGarrett D'Amore 
49195c635efSGarrett D'Amore static int
49295c635efSGarrett D'Amore post_UC(CHKARGS)
49395c635efSGarrett D'Amore {
49495c635efSGarrett D'Amore 	static const char * const bsd_versions[] = {
49595c635efSGarrett D'Amore 	    "3rd Berkeley Distribution",
49695c635efSGarrett D'Amore 	    "4th Berkeley Distribution",
49795c635efSGarrett D'Amore 	    "4.2 Berkeley Distribution",
49895c635efSGarrett D'Amore 	    "4.3 Berkeley Distribution",
49995c635efSGarrett D'Amore 	    "4.4 Berkeley Distribution",
50095c635efSGarrett D'Amore 	};
50195c635efSGarrett D'Amore 
50295c635efSGarrett D'Amore 	const char	*p, *s;
50395c635efSGarrett D'Amore 
50495c635efSGarrett D'Amore 	n = n->child;
50595c635efSGarrett D'Amore 
50695c635efSGarrett D'Amore 	if (NULL == n || MAN_TEXT != n->type)
50795c635efSGarrett D'Amore 		p = bsd_versions[0];
50895c635efSGarrett D'Amore 	else {
50995c635efSGarrett D'Amore 		s = n->string;
51095c635efSGarrett D'Amore 		if (0 == strcmp(s, "3"))
51195c635efSGarrett D'Amore 			p = bsd_versions[0];
51295c635efSGarrett D'Amore 		else if (0 == strcmp(s, "4"))
51395c635efSGarrett D'Amore 			p = bsd_versions[1];
51495c635efSGarrett D'Amore 		else if (0 == strcmp(s, "5"))
51595c635efSGarrett D'Amore 			p = bsd_versions[2];
51695c635efSGarrett D'Amore 		else if (0 == strcmp(s, "6"))
51795c635efSGarrett D'Amore 			p = bsd_versions[3];
51895c635efSGarrett D'Amore 		else if (0 == strcmp(s, "7"))
51995c635efSGarrett D'Amore 			p = bsd_versions[4];
52095c635efSGarrett D'Amore 		else
52195c635efSGarrett D'Amore 			p = bsd_versions[0];
52295c635efSGarrett D'Amore 	}
52395c635efSGarrett D'Amore 
524*698f87a4SGarrett D'Amore 	free(man->meta.source);
525*698f87a4SGarrett D'Amore 	man->meta.source = mandoc_strdup(p);
52695c635efSGarrett D'Amore 	return(1);
52795c635efSGarrett D'Amore }
52895c635efSGarrett D'Amore 
52995c635efSGarrett D'Amore static int
53095c635efSGarrett D'Amore post_AT(CHKARGS)
53195c635efSGarrett D'Amore {
53295c635efSGarrett D'Amore 	static const char * const unix_versions[] = {
53395c635efSGarrett D'Amore 	    "7th Edition",
53495c635efSGarrett D'Amore 	    "System III",
53595c635efSGarrett D'Amore 	    "System V",
53695c635efSGarrett D'Amore 	    "System V Release 2",
53795c635efSGarrett D'Amore 	};
53895c635efSGarrett D'Amore 
53995c635efSGarrett D'Amore 	const char	*p, *s;
54095c635efSGarrett D'Amore 	struct man_node	*nn;
54195c635efSGarrett D'Amore 
54295c635efSGarrett D'Amore 	n = n->child;
54395c635efSGarrett D'Amore 
54495c635efSGarrett D'Amore 	if (NULL == n || MAN_TEXT != n->type)
54595c635efSGarrett D'Amore 		p = unix_versions[0];
54695c635efSGarrett D'Amore 	else {
54795c635efSGarrett D'Amore 		s = n->string;
54895c635efSGarrett D'Amore 		if (0 == strcmp(s, "3"))
54995c635efSGarrett D'Amore 			p = unix_versions[0];
55095c635efSGarrett D'Amore 		else if (0 == strcmp(s, "4"))
55195c635efSGarrett D'Amore 			p = unix_versions[1];
55295c635efSGarrett D'Amore 		else if (0 == strcmp(s, "5")) {
55395c635efSGarrett D'Amore 			nn = n->next;
55495c635efSGarrett D'Amore 			if (nn && MAN_TEXT == nn->type && nn->string[0])
55595c635efSGarrett D'Amore 				p = unix_versions[3];
55695c635efSGarrett D'Amore 			else
55795c635efSGarrett D'Amore 				p = unix_versions[2];
55895c635efSGarrett D'Amore 		} else
55995c635efSGarrett D'Amore 			p = unix_versions[0];
56095c635efSGarrett D'Amore 	}
56195c635efSGarrett D'Amore 
562*698f87a4SGarrett D'Amore 	free(man->meta.source);
563*698f87a4SGarrett D'Amore 	man->meta.source = mandoc_strdup(p);
56495c635efSGarrett D'Amore 	return(1);
56595c635efSGarrett D'Amore }
56695c635efSGarrett D'Amore 
56795c635efSGarrett D'Amore static int
56895c635efSGarrett D'Amore post_vs(CHKARGS)
56995c635efSGarrett D'Amore {
57095c635efSGarrett D'Amore 
571*698f87a4SGarrett D'Amore 	if (NULL != n->prev)
572*698f87a4SGarrett D'Amore 		return(1);
573*698f87a4SGarrett D'Amore 
574*698f87a4SGarrett D'Amore 	switch (n->parent->tok) {
575*698f87a4SGarrett D'Amore 	case (MAN_SH):
576*698f87a4SGarrett D'Amore 		/* FALLTHROUGH */
577*698f87a4SGarrett D'Amore 	case (MAN_SS):
578*698f87a4SGarrett D'Amore 		man_nmsg(man, n, MANDOCERR_IGNPAR);
579*698f87a4SGarrett D'Amore 		/* FALLTHROUGH */
580*698f87a4SGarrett D'Amore 	case (MAN_MAX):
58195c635efSGarrett D'Amore 		/*
582*698f87a4SGarrett D'Amore 		 * Don't warn about this because it occurs in pod2man
583*698f87a4SGarrett D'Amore 		 * and would cause considerable (unfixable) warnage.
58495c635efSGarrett D'Amore 		 */
585*698f87a4SGarrett D'Amore 		man_node_delete(man, n);
586*698f87a4SGarrett D'Amore 		break;
587*698f87a4SGarrett D'Amore 	default:
588*698f87a4SGarrett D'Amore 		break;
589*698f87a4SGarrett D'Amore 	}
59095c635efSGarrett D'Amore 
59195c635efSGarrett D'Amore 	return(1);
59295c635efSGarrett D'Amore }
593