xref: /titanic_51/usr/src/cmd/mandoc/man_validate.c (revision 260e9a87725c090ba5835b1f9f0b62fa2f96036f)
1*260e9a87SYuri Pankov /*	$OpenBSD$ */
295c635efSGarrett D'Amore /*
395c635efSGarrett D'Amore  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4*260e9a87SYuri Pankov  * Copyright (c) 2010, 2012-2015 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 #include "config.h"
1995c635efSGarrett D'Amore 
2095c635efSGarrett D'Amore #include <sys/types.h>
2195c635efSGarrett D'Amore 
2295c635efSGarrett D'Amore #include <assert.h>
2395c635efSGarrett D'Amore #include <ctype.h>
2495c635efSGarrett D'Amore #include <errno.h>
2595c635efSGarrett D'Amore #include <limits.h>
2695c635efSGarrett D'Amore #include <stdarg.h>
2795c635efSGarrett D'Amore #include <stdlib.h>
2895c635efSGarrett D'Amore #include <string.h>
2995c635efSGarrett D'Amore #include <time.h>
3095c635efSGarrett D'Amore 
3195c635efSGarrett D'Amore #include "man.h"
3295c635efSGarrett D'Amore #include "mandoc.h"
33*260e9a87SYuri Pankov #include "mandoc_aux.h"
3495c635efSGarrett D'Amore #include "libman.h"
3595c635efSGarrett D'Amore #include "libmandoc.h"
3695c635efSGarrett D'Amore 
37698f87a4SGarrett D'Amore #define	CHKARGS	  struct man *man, struct man_node *n
3895c635efSGarrett D'Amore 
39*260e9a87SYuri Pankov typedef	void	(*v_check)(CHKARGS);
4095c635efSGarrett D'Amore 
41*260e9a87SYuri Pankov static	void	  check_par(CHKARGS);
42*260e9a87SYuri Pankov static	void	  check_part(CHKARGS);
43*260e9a87SYuri Pankov static	void	  check_root(CHKARGS);
4495c635efSGarrett D'Amore static	void	  check_text(CHKARGS);
4595c635efSGarrett D'Amore 
46*260e9a87SYuri Pankov static	void	  post_AT(CHKARGS);
47*260e9a87SYuri Pankov static	void	  post_IP(CHKARGS);
48*260e9a87SYuri Pankov static	void	  post_vs(CHKARGS);
49*260e9a87SYuri Pankov static	void	  post_fi(CHKARGS);
50*260e9a87SYuri Pankov static	void	  post_ft(CHKARGS);
51*260e9a87SYuri Pankov static	void	  post_nf(CHKARGS);
52*260e9a87SYuri Pankov static	void	  post_OP(CHKARGS);
53*260e9a87SYuri Pankov static	void	  post_TH(CHKARGS);
54*260e9a87SYuri Pankov static	void	  post_UC(CHKARGS);
55*260e9a87SYuri Pankov static	void	  post_UR(CHKARGS);
5695c635efSGarrett D'Amore 
57*260e9a87SYuri Pankov static	v_check man_valids[MAN_MAX] = {
58*260e9a87SYuri Pankov 	post_vs,    /* br */
59*260e9a87SYuri Pankov 	post_TH,    /* TH */
60*260e9a87SYuri Pankov 	NULL,       /* SH */
61*260e9a87SYuri Pankov 	NULL,       /* SS */
62*260e9a87SYuri Pankov 	NULL,       /* TP */
63*260e9a87SYuri Pankov 	check_par,  /* LP */
64*260e9a87SYuri Pankov 	check_par,  /* PP */
65*260e9a87SYuri Pankov 	check_par,  /* P */
66*260e9a87SYuri Pankov 	post_IP,    /* IP */
67*260e9a87SYuri Pankov 	NULL,       /* HP */
68*260e9a87SYuri Pankov 	NULL,       /* SM */
69*260e9a87SYuri Pankov 	NULL,       /* SB */
70*260e9a87SYuri Pankov 	NULL,       /* BI */
71*260e9a87SYuri Pankov 	NULL,       /* IB */
72*260e9a87SYuri Pankov 	NULL,       /* BR */
73*260e9a87SYuri Pankov 	NULL,       /* RB */
74*260e9a87SYuri Pankov 	NULL,       /* R */
75*260e9a87SYuri Pankov 	NULL,       /* B */
76*260e9a87SYuri Pankov 	NULL,       /* I */
77*260e9a87SYuri Pankov 	NULL,       /* IR */
78*260e9a87SYuri Pankov 	NULL,       /* RI */
79*260e9a87SYuri Pankov 	post_vs,    /* sp */
80*260e9a87SYuri Pankov 	post_nf,    /* nf */
81*260e9a87SYuri Pankov 	post_fi,    /* fi */
82*260e9a87SYuri Pankov 	NULL,       /* RE */
83*260e9a87SYuri Pankov 	check_part, /* RS */
84*260e9a87SYuri Pankov 	NULL,       /* DT */
85*260e9a87SYuri Pankov 	post_UC,    /* UC */
86*260e9a87SYuri Pankov 	NULL,       /* PD */
87*260e9a87SYuri Pankov 	post_AT,    /* AT */
88*260e9a87SYuri Pankov 	NULL,       /* in */
89*260e9a87SYuri Pankov 	post_ft,    /* ft */
90*260e9a87SYuri Pankov 	post_OP,    /* OP */
91*260e9a87SYuri Pankov 	post_nf,    /* EX */
92*260e9a87SYuri Pankov 	post_fi,    /* EE */
93*260e9a87SYuri Pankov 	post_UR,    /* UR */
94*260e9a87SYuri Pankov 	NULL,       /* UE */
95*260e9a87SYuri Pankov 	NULL,       /* ll */
9695c635efSGarrett D'Amore };
9795c635efSGarrett D'Amore 
9895c635efSGarrett D'Amore 
99*260e9a87SYuri Pankov void
100698f87a4SGarrett D'Amore man_valid_post(struct man *man)
10195c635efSGarrett D'Amore {
102*260e9a87SYuri Pankov 	struct man_node	*n;
10395c635efSGarrett D'Amore 	v_check		*cp;
10495c635efSGarrett D'Amore 
105*260e9a87SYuri Pankov 	n = man->last;
106*260e9a87SYuri Pankov 	if (n->flags & MAN_VALID)
107*260e9a87SYuri Pankov 		return;
108*260e9a87SYuri Pankov 	n->flags |= MAN_VALID;
10995c635efSGarrett D'Amore 
110*260e9a87SYuri Pankov 	switch (n->type) {
111*260e9a87SYuri Pankov 	case MAN_TEXT:
112*260e9a87SYuri Pankov 		check_text(man, n);
113*260e9a87SYuri Pankov 		break;
114*260e9a87SYuri Pankov 	case MAN_ROOT:
115*260e9a87SYuri Pankov 		check_root(man, n);
116*260e9a87SYuri Pankov 		break;
117*260e9a87SYuri Pankov 	case MAN_EQN:
11895c635efSGarrett D'Amore 		/* FALLTHROUGH */
119*260e9a87SYuri Pankov 	case MAN_TBL:
120*260e9a87SYuri Pankov 		break;
12195c635efSGarrett D'Amore 	default:
122*260e9a87SYuri Pankov 		cp = man_valids + n->tok;
123*260e9a87SYuri Pankov 		if (*cp)
124*260e9a87SYuri Pankov 			(*cp)(man, n);
12595c635efSGarrett D'Amore 		break;
12695c635efSGarrett D'Amore 	}
12795c635efSGarrett D'Amore }
12895c635efSGarrett D'Amore 
129*260e9a87SYuri Pankov static void
13095c635efSGarrett D'Amore check_root(CHKARGS)
13195c635efSGarrett D'Amore {
13295c635efSGarrett D'Amore 
133*260e9a87SYuri Pankov 	assert((man->flags & (MAN_BLINE | MAN_ELINE)) == 0);
13495c635efSGarrett D'Amore 
135*260e9a87SYuri Pankov 	if (NULL == man->first->child)
136*260e9a87SYuri Pankov 		mandoc_msg(MANDOCERR_DOC_EMPTY, man->parse,
137*260e9a87SYuri Pankov 		    n->line, n->pos, NULL);
138*260e9a87SYuri Pankov 	else
139*260e9a87SYuri Pankov 		man->meta.hasbody = 1;
14095c635efSGarrett D'Amore 
141*260e9a87SYuri Pankov 	if (NULL == man->meta.title) {
142*260e9a87SYuri Pankov 		mandoc_msg(MANDOCERR_TH_NOTITLE, man->parse,
143*260e9a87SYuri Pankov 		    n->line, n->pos, NULL);
14495c635efSGarrett D'Amore 
14595c635efSGarrett D'Amore 		/*
14695c635efSGarrett D'Amore 		 * If a title hasn't been set, do so now (by
14795c635efSGarrett D'Amore 		 * implication, date and section also aren't set).
14895c635efSGarrett D'Amore 		 */
14995c635efSGarrett D'Amore 
150*260e9a87SYuri Pankov 		man->meta.title = mandoc_strdup("");
151*260e9a87SYuri Pankov 		man->meta.msec = mandoc_strdup("");
152*260e9a87SYuri Pankov 		man->meta.date = man->quick ? mandoc_strdup("") :
153*260e9a87SYuri Pankov 		    mandoc_normdate(man->parse, NULL, n->line, n->pos);
15495c635efSGarrett D'Amore 	}
15595c635efSGarrett D'Amore }
15695c635efSGarrett D'Amore 
15795c635efSGarrett D'Amore static void
15895c635efSGarrett D'Amore check_text(CHKARGS)
15995c635efSGarrett D'Amore {
16095c635efSGarrett D'Amore 	char		*cp, *p;
16195c635efSGarrett D'Amore 
162698f87a4SGarrett D'Amore 	if (MAN_LITERAL & man->flags)
16395c635efSGarrett D'Amore 		return;
16495c635efSGarrett D'Amore 
16595c635efSGarrett D'Amore 	cp = n->string;
16695c635efSGarrett D'Amore 	for (p = cp; NULL != (p = strchr(p, '\t')); p++)
167*260e9a87SYuri Pankov 		mandoc_msg(MANDOCERR_FI_TAB, man->parse,
168*260e9a87SYuri Pankov 		    n->line, n->pos + (p - cp), NULL);
16995c635efSGarrett D'Amore }
17095c635efSGarrett D'Amore 
171*260e9a87SYuri Pankov static void
172*260e9a87SYuri Pankov post_OP(CHKARGS)
173698f87a4SGarrett D'Amore {
174698f87a4SGarrett D'Amore 
175*260e9a87SYuri Pankov 	if (n->nchild == 0)
176*260e9a87SYuri Pankov 		mandoc_msg(MANDOCERR_OP_EMPTY, man->parse,
177*260e9a87SYuri Pankov 		    n->line, n->pos, "OP");
178*260e9a87SYuri Pankov 	else if (n->nchild > 2) {
179*260e9a87SYuri Pankov 		n = n->child->next->next;
180*260e9a87SYuri Pankov 		mandoc_vmsg(MANDOCERR_ARG_EXCESS, man->parse,
181*260e9a87SYuri Pankov 		    n->line, n->pos, "OP ... %s", n->string);
182*260e9a87SYuri Pankov 	}
183698f87a4SGarrett D'Amore }
184698f87a4SGarrett D'Amore 
185*260e9a87SYuri Pankov static void
186*260e9a87SYuri Pankov post_UR(CHKARGS)
187*260e9a87SYuri Pankov {
188*260e9a87SYuri Pankov 
189*260e9a87SYuri Pankov 	if (n->type == MAN_HEAD && n->child == NULL)
190*260e9a87SYuri Pankov 		mandoc_vmsg(MANDOCERR_UR_NOHEAD, man->parse,
191*260e9a87SYuri Pankov 		    n->line, n->pos, "UR");
192*260e9a87SYuri Pankov 	check_part(man, n);
193*260e9a87SYuri Pankov }
194*260e9a87SYuri Pankov 
195*260e9a87SYuri Pankov static void
19695c635efSGarrett D'Amore post_ft(CHKARGS)
19795c635efSGarrett D'Amore {
19895c635efSGarrett D'Amore 	char	*cp;
19995c635efSGarrett D'Amore 	int	 ok;
20095c635efSGarrett D'Amore 
20195c635efSGarrett D'Amore 	if (0 == n->nchild)
202*260e9a87SYuri Pankov 		return;
20395c635efSGarrett D'Amore 
20495c635efSGarrett D'Amore 	ok = 0;
20595c635efSGarrett D'Amore 	cp = n->child->string;
20695c635efSGarrett D'Amore 	switch (*cp) {
207*260e9a87SYuri Pankov 	case '1':
20895c635efSGarrett D'Amore 		/* FALLTHROUGH */
209*260e9a87SYuri Pankov 	case '2':
21095c635efSGarrett D'Amore 		/* FALLTHROUGH */
211*260e9a87SYuri Pankov 	case '3':
21295c635efSGarrett D'Amore 		/* FALLTHROUGH */
213*260e9a87SYuri Pankov 	case '4':
21495c635efSGarrett D'Amore 		/* FALLTHROUGH */
215*260e9a87SYuri Pankov 	case 'I':
21695c635efSGarrett D'Amore 		/* FALLTHROUGH */
217*260e9a87SYuri Pankov 	case 'P':
21895c635efSGarrett D'Amore 		/* FALLTHROUGH */
219*260e9a87SYuri Pankov 	case 'R':
22095c635efSGarrett D'Amore 		if ('\0' == cp[1])
22195c635efSGarrett D'Amore 			ok = 1;
22295c635efSGarrett D'Amore 		break;
223*260e9a87SYuri Pankov 	case 'B':
22495c635efSGarrett D'Amore 		if ('\0' == cp[1] || ('I' == cp[1] && '\0' == cp[2]))
22595c635efSGarrett D'Amore 			ok = 1;
22695c635efSGarrett D'Amore 		break;
227*260e9a87SYuri Pankov 	case 'C':
22895c635efSGarrett D'Amore 		if ('W' == cp[1] && '\0' == cp[2])
22995c635efSGarrett D'Amore 			ok = 1;
23095c635efSGarrett D'Amore 		break;
23195c635efSGarrett D'Amore 	default:
23295c635efSGarrett D'Amore 		break;
23395c635efSGarrett D'Amore 	}
23495c635efSGarrett D'Amore 
23595c635efSGarrett D'Amore 	if (0 == ok) {
236*260e9a87SYuri Pankov 		mandoc_vmsg(MANDOCERR_FT_BAD, man->parse,
237*260e9a87SYuri Pankov 		    n->line, n->pos, "ft %s", cp);
23895c635efSGarrett D'Amore 		*cp = '\0';
23995c635efSGarrett D'Amore 	}
24095c635efSGarrett D'Amore }
24195c635efSGarrett D'Amore 
242*260e9a87SYuri Pankov static void
24395c635efSGarrett D'Amore check_part(CHKARGS)
24495c635efSGarrett D'Amore {
24595c635efSGarrett D'Amore 
246*260e9a87SYuri Pankov 	if (n->type == MAN_BODY && n->child == NULL)
247*260e9a87SYuri Pankov 		mandoc_msg(MANDOCERR_BLK_EMPTY, man->parse,
248*260e9a87SYuri Pankov 		    n->line, n->pos, man_macronames[n->tok]);
24995c635efSGarrett D'Amore }
25095c635efSGarrett D'Amore 
251*260e9a87SYuri Pankov static void
25295c635efSGarrett D'Amore check_par(CHKARGS)
25395c635efSGarrett D'Amore {
25495c635efSGarrett D'Amore 
25595c635efSGarrett D'Amore 	switch (n->type) {
256*260e9a87SYuri Pankov 	case MAN_BLOCK:
25795c635efSGarrett D'Amore 		if (0 == n->body->nchild)
258698f87a4SGarrett D'Amore 			man_node_delete(man, n);
25995c635efSGarrett D'Amore 		break;
260*260e9a87SYuri Pankov 	case MAN_BODY:
26195c635efSGarrett D'Amore 		if (0 == n->nchild)
262*260e9a87SYuri Pankov 			mandoc_vmsg(MANDOCERR_PAR_SKIP,
263*260e9a87SYuri Pankov 			    man->parse, n->line, n->pos,
264*260e9a87SYuri Pankov 			    "%s empty", man_macronames[n->tok]);
26595c635efSGarrett D'Amore 		break;
266*260e9a87SYuri Pankov 	case MAN_HEAD:
26795c635efSGarrett D'Amore 		if (n->nchild)
268*260e9a87SYuri Pankov 			mandoc_vmsg(MANDOCERR_ARG_SKIP,
269*260e9a87SYuri Pankov 			    man->parse, n->line, n->pos,
270*260e9a87SYuri Pankov 			    "%s %s%s", man_macronames[n->tok],
271*260e9a87SYuri Pankov 			    n->child->string,
272*260e9a87SYuri Pankov 			    n->nchild > 1 ? " ..." : "");
27395c635efSGarrett D'Amore 		break;
27495c635efSGarrett D'Amore 	default:
27595c635efSGarrett D'Amore 		break;
27695c635efSGarrett D'Amore 	}
27795c635efSGarrett D'Amore }
27895c635efSGarrett D'Amore 
279*260e9a87SYuri Pankov static void
280698f87a4SGarrett D'Amore post_IP(CHKARGS)
281698f87a4SGarrett D'Amore {
282698f87a4SGarrett D'Amore 
283698f87a4SGarrett D'Amore 	switch (n->type) {
284*260e9a87SYuri Pankov 	case MAN_BLOCK:
285698f87a4SGarrett D'Amore 		if (0 == n->head->nchild && 0 == n->body->nchild)
286698f87a4SGarrett D'Amore 			man_node_delete(man, n);
287698f87a4SGarrett D'Amore 		break;
288*260e9a87SYuri Pankov 	case MAN_BODY:
289698f87a4SGarrett D'Amore 		if (0 == n->parent->head->nchild && 0 == n->nchild)
290*260e9a87SYuri Pankov 			mandoc_vmsg(MANDOCERR_PAR_SKIP,
291*260e9a87SYuri Pankov 			    man->parse, n->line, n->pos,
292*260e9a87SYuri Pankov 			    "%s empty", man_macronames[n->tok]);
293698f87a4SGarrett D'Amore 		break;
294698f87a4SGarrett D'Amore 	default:
295698f87a4SGarrett D'Amore 		break;
296698f87a4SGarrett D'Amore 	}
297698f87a4SGarrett D'Amore }
29895c635efSGarrett D'Amore 
299*260e9a87SYuri Pankov static void
30095c635efSGarrett D'Amore post_TH(CHKARGS)
30195c635efSGarrett D'Amore {
302*260e9a87SYuri Pankov 	struct man_node	*nb;
30395c635efSGarrett D'Amore 	const char	*p;
30495c635efSGarrett D'Amore 
305698f87a4SGarrett D'Amore 	free(man->meta.title);
306698f87a4SGarrett D'Amore 	free(man->meta.vol);
307698f87a4SGarrett D'Amore 	free(man->meta.source);
308698f87a4SGarrett D'Amore 	free(man->meta.msec);
309698f87a4SGarrett D'Amore 	free(man->meta.date);
31095c635efSGarrett D'Amore 
311698f87a4SGarrett D'Amore 	man->meta.title = man->meta.vol = man->meta.date =
312698f87a4SGarrett D'Amore 	    man->meta.msec = man->meta.source = NULL;
31395c635efSGarrett D'Amore 
314*260e9a87SYuri Pankov 	nb = n;
315*260e9a87SYuri Pankov 
31695c635efSGarrett D'Amore 	/* ->TITLE<- MSEC DATE SOURCE VOL */
31795c635efSGarrett D'Amore 
31895c635efSGarrett D'Amore 	n = n->child;
31995c635efSGarrett D'Amore 	if (n && n->string) {
32095c635efSGarrett D'Amore 		for (p = n->string; '\0' != *p; p++) {
32195c635efSGarrett D'Amore 			/* Only warn about this once... */
32295c635efSGarrett D'Amore 			if (isalpha((unsigned char)*p) &&
32395c635efSGarrett D'Amore 			    ! isupper((unsigned char)*p)) {
324*260e9a87SYuri Pankov 				mandoc_vmsg(MANDOCERR_TITLE_CASE,
325*260e9a87SYuri Pankov 				    man->parse, n->line,
326*260e9a87SYuri Pankov 				    n->pos + (p - n->string),
327*260e9a87SYuri Pankov 				    "TH %s", n->string);
32895c635efSGarrett D'Amore 				break;
32995c635efSGarrett D'Amore 			}
33095c635efSGarrett D'Amore 		}
331698f87a4SGarrett D'Amore 		man->meta.title = mandoc_strdup(n->string);
332*260e9a87SYuri Pankov 	} else {
333698f87a4SGarrett D'Amore 		man->meta.title = mandoc_strdup("");
334*260e9a87SYuri Pankov 		mandoc_msg(MANDOCERR_TH_NOTITLE, man->parse,
335*260e9a87SYuri Pankov 		    nb->line, nb->pos, "TH");
336*260e9a87SYuri Pankov 	}
33795c635efSGarrett D'Amore 
33895c635efSGarrett D'Amore 	/* TITLE ->MSEC<- DATE SOURCE VOL */
33995c635efSGarrett D'Amore 
34095c635efSGarrett D'Amore 	if (n)
34195c635efSGarrett D'Amore 		n = n->next;
34295c635efSGarrett D'Amore 	if (n && n->string)
343698f87a4SGarrett D'Amore 		man->meta.msec = mandoc_strdup(n->string);
344*260e9a87SYuri Pankov 	else {
345698f87a4SGarrett D'Amore 		man->meta.msec = mandoc_strdup("");
346*260e9a87SYuri Pankov 		mandoc_vmsg(MANDOCERR_MSEC_MISSING, man->parse,
347*260e9a87SYuri Pankov 		    nb->line, nb->pos, "TH %s", man->meta.title);
348*260e9a87SYuri Pankov 	}
34995c635efSGarrett D'Amore 
35095c635efSGarrett D'Amore 	/* TITLE MSEC ->DATE<- SOURCE VOL */
35195c635efSGarrett D'Amore 
35295c635efSGarrett D'Amore 	if (n)
35395c635efSGarrett D'Amore 		n = n->next;
35495c635efSGarrett D'Amore 	if (n && n->string && '\0' != n->string[0]) {
355*260e9a87SYuri Pankov 		man->meta.date = man->quick ?
356*260e9a87SYuri Pankov 		    mandoc_strdup(n->string) :
357*260e9a87SYuri Pankov 		    mandoc_normdate(man->parse, n->string,
358*260e9a87SYuri Pankov 			n->line, n->pos);
359*260e9a87SYuri Pankov 	} else {
360698f87a4SGarrett D'Amore 		man->meta.date = mandoc_strdup("");
361*260e9a87SYuri Pankov 		mandoc_msg(MANDOCERR_DATE_MISSING, man->parse,
362*260e9a87SYuri Pankov 		    n ? n->line : nb->line,
363*260e9a87SYuri Pankov 		    n ? n->pos : nb->pos, "TH");
364*260e9a87SYuri Pankov 	}
36595c635efSGarrett D'Amore 
36695c635efSGarrett D'Amore 	/* TITLE MSEC DATE ->SOURCE<- VOL */
36795c635efSGarrett D'Amore 
36895c635efSGarrett D'Amore 	if (n && (n = n->next))
369698f87a4SGarrett D'Amore 		man->meta.source = mandoc_strdup(n->string);
370*260e9a87SYuri Pankov 	else if (man->defos != NULL)
371*260e9a87SYuri Pankov 		man->meta.source = mandoc_strdup(man->defos);
37295c635efSGarrett D'Amore 
37395c635efSGarrett D'Amore 	/* TITLE MSEC DATE SOURCE ->VOL<- */
37495c635efSGarrett D'Amore 	/* If missing, use the default VOL name for MSEC. */
37595c635efSGarrett D'Amore 
37695c635efSGarrett D'Amore 	if (n && (n = n->next))
377698f87a4SGarrett D'Amore 		man->meta.vol = mandoc_strdup(n->string);
378698f87a4SGarrett D'Amore 	else if ('\0' != man->meta.msec[0] &&
379698f87a4SGarrett D'Amore 	    (NULL != (p = mandoc_a2msec(man->meta.msec))))
380698f87a4SGarrett D'Amore 		man->meta.vol = mandoc_strdup(p);
38195c635efSGarrett D'Amore 
382*260e9a87SYuri Pankov 	if (n != NULL && (n = n->next) != NULL)
383*260e9a87SYuri Pankov 		mandoc_vmsg(MANDOCERR_ARG_EXCESS, man->parse,
384*260e9a87SYuri Pankov 		    n->line, n->pos, "TH ... %s", n->string);
385*260e9a87SYuri Pankov 
38695c635efSGarrett D'Amore 	/*
38795c635efSGarrett D'Amore 	 * Remove the `TH' node after we've processed it for our
38895c635efSGarrett D'Amore 	 * meta-data.
38995c635efSGarrett D'Amore 	 */
390698f87a4SGarrett D'Amore 	man_node_delete(man, man->last);
39195c635efSGarrett D'Amore }
39295c635efSGarrett D'Amore 
393*260e9a87SYuri Pankov static void
39495c635efSGarrett D'Amore post_nf(CHKARGS)
39595c635efSGarrett D'Amore {
39695c635efSGarrett D'Amore 
397*260e9a87SYuri Pankov 	if (man->flags & MAN_LITERAL)
398*260e9a87SYuri Pankov 		mandoc_msg(MANDOCERR_NF_SKIP, man->parse,
399*260e9a87SYuri Pankov 		    n->line, n->pos, "nf");
40095c635efSGarrett D'Amore 
401698f87a4SGarrett D'Amore 	man->flags |= MAN_LITERAL;
40295c635efSGarrett D'Amore }
40395c635efSGarrett D'Amore 
404*260e9a87SYuri Pankov static void
40595c635efSGarrett D'Amore post_fi(CHKARGS)
40695c635efSGarrett D'Amore {
40795c635efSGarrett D'Amore 
408698f87a4SGarrett D'Amore 	if ( ! (MAN_LITERAL & man->flags))
409*260e9a87SYuri Pankov 		mandoc_msg(MANDOCERR_FI_SKIP, man->parse,
410*260e9a87SYuri Pankov 		    n->line, n->pos, "fi");
41195c635efSGarrett D'Amore 
412698f87a4SGarrett D'Amore 	man->flags &= ~MAN_LITERAL;
41395c635efSGarrett D'Amore }
41495c635efSGarrett D'Amore 
415*260e9a87SYuri Pankov static void
41695c635efSGarrett D'Amore post_UC(CHKARGS)
41795c635efSGarrett D'Amore {
41895c635efSGarrett D'Amore 	static const char * const bsd_versions[] = {
41995c635efSGarrett D'Amore 	    "3rd Berkeley Distribution",
42095c635efSGarrett D'Amore 	    "4th Berkeley Distribution",
42195c635efSGarrett D'Amore 	    "4.2 Berkeley Distribution",
42295c635efSGarrett D'Amore 	    "4.3 Berkeley Distribution",
42395c635efSGarrett D'Amore 	    "4.4 Berkeley Distribution",
42495c635efSGarrett D'Amore 	};
42595c635efSGarrett D'Amore 
42695c635efSGarrett D'Amore 	const char	*p, *s;
42795c635efSGarrett D'Amore 
42895c635efSGarrett D'Amore 	n = n->child;
42995c635efSGarrett D'Amore 
43095c635efSGarrett D'Amore 	if (NULL == n || MAN_TEXT != n->type)
43195c635efSGarrett D'Amore 		p = bsd_versions[0];
43295c635efSGarrett D'Amore 	else {
43395c635efSGarrett D'Amore 		s = n->string;
43495c635efSGarrett D'Amore 		if (0 == strcmp(s, "3"))
43595c635efSGarrett D'Amore 			p = bsd_versions[0];
43695c635efSGarrett D'Amore 		else if (0 == strcmp(s, "4"))
43795c635efSGarrett D'Amore 			p = bsd_versions[1];
43895c635efSGarrett D'Amore 		else if (0 == strcmp(s, "5"))
43995c635efSGarrett D'Amore 			p = bsd_versions[2];
44095c635efSGarrett D'Amore 		else if (0 == strcmp(s, "6"))
44195c635efSGarrett D'Amore 			p = bsd_versions[3];
44295c635efSGarrett D'Amore 		else if (0 == strcmp(s, "7"))
44395c635efSGarrett D'Amore 			p = bsd_versions[4];
44495c635efSGarrett D'Amore 		else
44595c635efSGarrett D'Amore 			p = bsd_versions[0];
44695c635efSGarrett D'Amore 	}
44795c635efSGarrett D'Amore 
448698f87a4SGarrett D'Amore 	free(man->meta.source);
449698f87a4SGarrett D'Amore 	man->meta.source = mandoc_strdup(p);
45095c635efSGarrett D'Amore }
45195c635efSGarrett D'Amore 
452*260e9a87SYuri Pankov static void
45395c635efSGarrett D'Amore post_AT(CHKARGS)
45495c635efSGarrett D'Amore {
45595c635efSGarrett D'Amore 	static const char * const unix_versions[] = {
45695c635efSGarrett D'Amore 	    "7th Edition",
45795c635efSGarrett D'Amore 	    "System III",
45895c635efSGarrett D'Amore 	    "System V",
45995c635efSGarrett D'Amore 	    "System V Release 2",
46095c635efSGarrett D'Amore 	};
46195c635efSGarrett D'Amore 
46295c635efSGarrett D'Amore 	const char	*p, *s;
46395c635efSGarrett D'Amore 	struct man_node	*nn;
46495c635efSGarrett D'Amore 
46595c635efSGarrett D'Amore 	n = n->child;
46695c635efSGarrett D'Amore 
46795c635efSGarrett D'Amore 	if (NULL == n || MAN_TEXT != n->type)
46895c635efSGarrett D'Amore 		p = unix_versions[0];
46995c635efSGarrett D'Amore 	else {
47095c635efSGarrett D'Amore 		s = n->string;
47195c635efSGarrett D'Amore 		if (0 == strcmp(s, "3"))
47295c635efSGarrett D'Amore 			p = unix_versions[0];
47395c635efSGarrett D'Amore 		else if (0 == strcmp(s, "4"))
47495c635efSGarrett D'Amore 			p = unix_versions[1];
47595c635efSGarrett D'Amore 		else if (0 == strcmp(s, "5")) {
47695c635efSGarrett D'Amore 			nn = n->next;
47795c635efSGarrett D'Amore 			if (nn && MAN_TEXT == nn->type && nn->string[0])
47895c635efSGarrett D'Amore 				p = unix_versions[3];
47995c635efSGarrett D'Amore 			else
48095c635efSGarrett D'Amore 				p = unix_versions[2];
48195c635efSGarrett D'Amore 		} else
48295c635efSGarrett D'Amore 			p = unix_versions[0];
48395c635efSGarrett D'Amore 	}
48495c635efSGarrett D'Amore 
485698f87a4SGarrett D'Amore 	free(man->meta.source);
486698f87a4SGarrett D'Amore 	man->meta.source = mandoc_strdup(p);
48795c635efSGarrett D'Amore }
48895c635efSGarrett D'Amore 
489*260e9a87SYuri Pankov static void
49095c635efSGarrett D'Amore post_vs(CHKARGS)
49195c635efSGarrett D'Amore {
49295c635efSGarrett D'Amore 
493698f87a4SGarrett D'Amore 	if (NULL != n->prev)
494*260e9a87SYuri Pankov 		return;
495698f87a4SGarrett D'Amore 
496698f87a4SGarrett D'Amore 	switch (n->parent->tok) {
497*260e9a87SYuri Pankov 	case MAN_SH:
498698f87a4SGarrett D'Amore 		/* FALLTHROUGH */
499*260e9a87SYuri Pankov 	case MAN_SS:
500*260e9a87SYuri Pankov 		mandoc_vmsg(MANDOCERR_PAR_SKIP, man->parse, n->line, n->pos,
501*260e9a87SYuri Pankov 		    "%s after %s", man_macronames[n->tok],
502*260e9a87SYuri Pankov 		    man_macronames[n->parent->tok]);
503698f87a4SGarrett D'Amore 		/* FALLTHROUGH */
504*260e9a87SYuri Pankov 	case MAN_MAX:
50595c635efSGarrett D'Amore 		/*
506698f87a4SGarrett D'Amore 		 * Don't warn about this because it occurs in pod2man
507698f87a4SGarrett D'Amore 		 * and would cause considerable (unfixable) warnage.
50895c635efSGarrett D'Amore 		 */
509698f87a4SGarrett D'Amore 		man_node_delete(man, n);
510698f87a4SGarrett D'Amore 		break;
511698f87a4SGarrett D'Amore 	default:
512698f87a4SGarrett D'Amore 		break;
513698f87a4SGarrett D'Amore 	}
51495c635efSGarrett D'Amore }
515