Home | History | Annotate | Line # | Download | only in dist
man_validate.c revision 1.1.1.15
      1  1.1.1.15  joerg /*	Id: man_validate.c,v 1.87 2013/12/31 18:07:42 schwarze Exp  */
      2       1.1  joerg /*
      3  1.1.1.12  joerg  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps (at) bsd.lv>
      4  1.1.1.15  joerg  * Copyright (c) 2010, 2012, 2013 Ingo Schwarze <schwarze (at) openbsd.org>
      5       1.1  joerg  *
      6       1.1  joerg  * Permission to use, copy, modify, and distribute this software for any
      7       1.1  joerg  * purpose with or without fee is hereby granted, provided that the above
      8       1.1  joerg  * copyright notice and this permission notice appear in all copies.
      9       1.1  joerg  *
     10       1.1  joerg  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     11       1.1  joerg  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     12       1.1  joerg  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     13       1.1  joerg  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     14       1.1  joerg  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     15       1.1  joerg  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     16       1.1  joerg  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     17       1.1  joerg  */
     18   1.1.1.4  joerg #ifdef HAVE_CONFIG_H
     19   1.1.1.4  joerg #include "config.h"
     20   1.1.1.4  joerg #endif
     21   1.1.1.4  joerg 
     22       1.1  joerg #include <sys/types.h>
     23       1.1  joerg 
     24       1.1  joerg #include <assert.h>
     25       1.1  joerg #include <ctype.h>
     26       1.1  joerg #include <errno.h>
     27       1.1  joerg #include <limits.h>
     28       1.1  joerg #include <stdarg.h>
     29       1.1  joerg #include <stdlib.h>
     30  1.1.1.10  joerg #include <string.h>
     31  1.1.1.11  joerg #include <time.h>
     32       1.1  joerg 
     33  1.1.1.12  joerg #include "man.h"
     34   1.1.1.7  joerg #include "mandoc.h"
     35       1.1  joerg #include "libman.h"
     36       1.1  joerg #include "libmandoc.h"
     37       1.1  joerg 
     38  1.1.1.15  joerg #define	CHKARGS	  struct man *man, struct man_node *n
     39       1.1  joerg 
     40       1.1  joerg typedef	int	(*v_check)(CHKARGS);
     41       1.1  joerg 
     42       1.1  joerg struct	man_valid {
     43       1.1  joerg 	v_check	 *pres;
     44       1.1  joerg 	v_check	 *posts;
     45       1.1  joerg };
     46       1.1  joerg 
     47       1.1  joerg static	int	  check_eq0(CHKARGS);
     48  1.1.1.14  joerg static	int	  check_eq2(CHKARGS);
     49       1.1  joerg static	int	  check_le1(CHKARGS);
     50       1.1  joerg static	int	  check_ge2(CHKARGS);
     51       1.1  joerg static	int	  check_le5(CHKARGS);
     52  1.1.1.15  joerg static	int	  check_head1(CHKARGS);
     53       1.1  joerg static	int	  check_par(CHKARGS);
     54       1.1  joerg static	int	  check_part(CHKARGS);
     55       1.1  joerg static	int	  check_root(CHKARGS);
     56  1.1.1.13  joerg static	void	  check_text(CHKARGS);
     57       1.1  joerg 
     58  1.1.1.11  joerg static	int	  post_AT(CHKARGS);
     59  1.1.1.15  joerg static	int	  post_IP(CHKARGS);
     60  1.1.1.13  joerg static	int	  post_vs(CHKARGS);
     61  1.1.1.11  joerg static	int	  post_fi(CHKARGS);
     62  1.1.1.13  joerg static	int	  post_ft(CHKARGS);
     63  1.1.1.11  joerg static	int	  post_nf(CHKARGS);
     64  1.1.1.13  joerg static	int	  post_sec(CHKARGS);
     65  1.1.1.11  joerg static	int	  post_TH(CHKARGS);
     66  1.1.1.11  joerg static	int	  post_UC(CHKARGS);
     67  1.1.1.13  joerg static	int	  pre_sec(CHKARGS);
     68  1.1.1.11  joerg 
     69  1.1.1.11  joerg static	v_check	  posts_at[] = { post_AT, NULL };
     70  1.1.1.13  joerg static	v_check	  posts_br[] = { post_vs, check_eq0, NULL };
     71       1.1  joerg static	v_check	  posts_eq0[] = { check_eq0, NULL };
     72  1.1.1.14  joerg static	v_check	  posts_eq2[] = { check_eq2, NULL };
     73  1.1.1.11  joerg static	v_check	  posts_fi[] = { check_eq0, post_fi, NULL };
     74  1.1.1.13  joerg static	v_check	  posts_ft[] = { post_ft, NULL };
     75  1.1.1.15  joerg static	v_check	  posts_ip[] = { post_IP, NULL };
     76  1.1.1.15  joerg static	v_check	  posts_le1[] = { check_le1, NULL };
     77  1.1.1.11  joerg static	v_check	  posts_nf[] = { check_eq0, post_nf, NULL };
     78       1.1  joerg static	v_check	  posts_par[] = { check_par, NULL };
     79       1.1  joerg static	v_check	  posts_part[] = { check_part, NULL };
     80  1.1.1.13  joerg static	v_check	  posts_sec[] = { post_sec, NULL };
     81  1.1.1.13  joerg static	v_check	  posts_sp[] = { post_vs, check_le1, NULL };
     82  1.1.1.12  joerg static	v_check	  posts_th[] = { check_ge2, check_le5, post_TH, NULL };
     83  1.1.1.11  joerg static	v_check	  posts_uc[] = { post_UC, NULL };
     84  1.1.1.15  joerg static	v_check	  posts_ur[] = { check_head1, check_part, NULL };
     85  1.1.1.14  joerg static	v_check	  pres_sec[] = { pre_sec, NULL };
     86  1.1.1.11  joerg 
     87       1.1  joerg static	const struct man_valid man_valids[MAN_MAX] = {
     88  1.1.1.13  joerg 	{ NULL, posts_br }, /* br */
     89  1.1.1.14  joerg 	{ NULL, posts_th }, /* TH */
     90  1.1.1.13  joerg 	{ pres_sec, posts_sec }, /* SH */
     91  1.1.1.13  joerg 	{ pres_sec, posts_sec }, /* SS */
     92  1.1.1.14  joerg 	{ NULL, NULL }, /* TP */
     93  1.1.1.14  joerg 	{ NULL, posts_par }, /* LP */
     94  1.1.1.14  joerg 	{ NULL, posts_par }, /* PP */
     95  1.1.1.14  joerg 	{ NULL, posts_par }, /* P */
     96  1.1.1.15  joerg 	{ NULL, posts_ip }, /* IP */
     97  1.1.1.14  joerg 	{ NULL, NULL }, /* HP */
     98       1.1  joerg 	{ NULL, NULL }, /* SM */
     99       1.1  joerg 	{ NULL, NULL }, /* SB */
    100       1.1  joerg 	{ NULL, NULL }, /* BI */
    101       1.1  joerg 	{ NULL, NULL }, /* IB */
    102       1.1  joerg 	{ NULL, NULL }, /* BR */
    103       1.1  joerg 	{ NULL, NULL }, /* RB */
    104       1.1  joerg 	{ NULL, NULL }, /* R */
    105       1.1  joerg 	{ NULL, NULL }, /* B */
    106       1.1  joerg 	{ NULL, NULL }, /* I */
    107       1.1  joerg 	{ NULL, NULL }, /* IR */
    108       1.1  joerg 	{ NULL, NULL }, /* RI */
    109  1.1.1.14  joerg 	{ NULL, posts_eq0 }, /* na */
    110  1.1.1.14  joerg 	{ NULL, posts_sp }, /* sp */
    111  1.1.1.14  joerg 	{ NULL, posts_nf }, /* nf */
    112  1.1.1.14  joerg 	{ NULL, posts_fi }, /* fi */
    113       1.1  joerg 	{ NULL, NULL }, /* RE */
    114       1.1  joerg 	{ NULL, posts_part }, /* RS */
    115       1.1  joerg 	{ NULL, NULL }, /* DT */
    116  1.1.1.11  joerg 	{ NULL, posts_uc }, /* UC */
    117  1.1.1.15  joerg 	{ NULL, posts_le1 }, /* PD */
    118  1.1.1.11  joerg 	{ NULL, posts_at }, /* AT */
    119  1.1.1.10  joerg 	{ NULL, NULL }, /* in */
    120  1.1.1.11  joerg 	{ NULL, posts_ft }, /* ft */
    121  1.1.1.14  joerg 	{ NULL, posts_eq2 }, /* OP */
    122  1.1.1.15  joerg 	{ NULL, posts_nf }, /* EX */
    123  1.1.1.15  joerg 	{ NULL, posts_fi }, /* EE */
    124  1.1.1.15  joerg 	{ NULL, posts_ur }, /* UR */
    125  1.1.1.15  joerg 	{ NULL, NULL }, /* UE */
    126       1.1  joerg };
    127       1.1  joerg 
    128       1.1  joerg 
    129       1.1  joerg int
    130  1.1.1.15  joerg man_valid_pre(struct man *man, struct man_node *n)
    131       1.1  joerg {
    132       1.1  joerg 	v_check		*cp;
    133       1.1  joerg 
    134  1.1.1.11  joerg 	switch (n->type) {
    135  1.1.1.11  joerg 	case (MAN_TEXT):
    136  1.1.1.11  joerg 		/* FALLTHROUGH */
    137  1.1.1.11  joerg 	case (MAN_ROOT):
    138  1.1.1.11  joerg 		/* FALLTHROUGH */
    139  1.1.1.12  joerg 	case (MAN_EQN):
    140  1.1.1.12  joerg 		/* FALLTHROUGH */
    141  1.1.1.11  joerg 	case (MAN_TBL):
    142       1.1  joerg 		return(1);
    143  1.1.1.11  joerg 	default:
    144  1.1.1.11  joerg 		break;
    145  1.1.1.11  joerg 	}
    146       1.1  joerg 
    147       1.1  joerg 	if (NULL == (cp = man_valids[n->tok].pres))
    148       1.1  joerg 		return(1);
    149       1.1  joerg 	for ( ; *cp; cp++)
    150  1.1.1.15  joerg 		if ( ! (*cp)(man, n))
    151       1.1  joerg 			return(0);
    152       1.1  joerg 	return(1);
    153       1.1  joerg }
    154       1.1  joerg 
    155       1.1  joerg 
    156       1.1  joerg int
    157  1.1.1.15  joerg man_valid_post(struct man *man)
    158       1.1  joerg {
    159       1.1  joerg 	v_check		*cp;
    160       1.1  joerg 
    161  1.1.1.15  joerg 	if (MAN_VALID & man->last->flags)
    162       1.1  joerg 		return(1);
    163  1.1.1.15  joerg 	man->last->flags |= MAN_VALID;
    164       1.1  joerg 
    165  1.1.1.15  joerg 	switch (man->last->type) {
    166       1.1  joerg 	case (MAN_TEXT):
    167  1.1.1.15  joerg 		check_text(man, man->last);
    168  1.1.1.13  joerg 		return(1);
    169       1.1  joerg 	case (MAN_ROOT):
    170  1.1.1.15  joerg 		return(check_root(man, man->last));
    171  1.1.1.12  joerg 	case (MAN_EQN):
    172  1.1.1.12  joerg 		/* FALLTHROUGH */
    173  1.1.1.11  joerg 	case (MAN_TBL):
    174  1.1.1.11  joerg 		return(1);
    175       1.1  joerg 	default:
    176       1.1  joerg 		break;
    177       1.1  joerg 	}
    178       1.1  joerg 
    179  1.1.1.15  joerg 	if (NULL == (cp = man_valids[man->last->tok].posts))
    180       1.1  joerg 		return(1);
    181       1.1  joerg 	for ( ; *cp; cp++)
    182  1.1.1.15  joerg 		if ( ! (*cp)(man, man->last))
    183       1.1  joerg 			return(0);
    184       1.1  joerg 
    185       1.1  joerg 	return(1);
    186       1.1  joerg }
    187       1.1  joerg 
    188       1.1  joerg 
    189       1.1  joerg static int
    190       1.1  joerg check_root(CHKARGS)
    191       1.1  joerg {
    192       1.1  joerg 
    193  1.1.1.15  joerg 	if (MAN_BLINE & man->flags)
    194  1.1.1.15  joerg 		man_nmsg(man, n, MANDOCERR_SCOPEEXIT);
    195  1.1.1.15  joerg 	else if (MAN_ELINE & man->flags)
    196  1.1.1.15  joerg 		man_nmsg(man, n, MANDOCERR_SCOPEEXIT);
    197       1.1  joerg 
    198  1.1.1.15  joerg 	man->flags &= ~MAN_BLINE;
    199  1.1.1.15  joerg 	man->flags &= ~MAN_ELINE;
    200       1.1  joerg 
    201  1.1.1.15  joerg 	if (NULL == man->first->child) {
    202  1.1.1.15  joerg 		man_nmsg(man, n, MANDOCERR_NODOCBODY);
    203   1.1.1.7  joerg 		return(0);
    204  1.1.1.15  joerg 	} else if (NULL == man->meta.title) {
    205  1.1.1.15  joerg 		man_nmsg(man, n, MANDOCERR_NOTITLE);
    206  1.1.1.11  joerg 
    207   1.1.1.6  joerg 		/*
    208   1.1.1.6  joerg 		 * If a title hasn't been set, do so now (by
    209   1.1.1.6  joerg 		 * implication, date and section also aren't set).
    210   1.1.1.6  joerg 		 */
    211  1.1.1.11  joerg 
    212  1.1.1.15  joerg 	        man->meta.title = mandoc_strdup("unknown");
    213  1.1.1.15  joerg 		man->meta.msec = mandoc_strdup("1");
    214  1.1.1.15  joerg 		man->meta.date = mandoc_normdate
    215  1.1.1.15  joerg 			(man->parse, NULL, n->line, n->pos);
    216   1.1.1.6  joerg 	}
    217       1.1  joerg 
    218       1.1  joerg 	return(1);
    219       1.1  joerg }
    220       1.1  joerg 
    221  1.1.1.13  joerg static void
    222  1.1.1.13  joerg check_text(CHKARGS)
    223       1.1  joerg {
    224  1.1.1.13  joerg 	char		*cp, *p;
    225       1.1  joerg 
    226  1.1.1.15  joerg 	if (MAN_LITERAL & man->flags)
    227  1.1.1.14  joerg 		return;
    228  1.1.1.14  joerg 
    229  1.1.1.14  joerg 	cp = n->string;
    230  1.1.1.14  joerg 	for (p = cp; NULL != (p = strchr(p, '\t')); p++)
    231  1.1.1.15  joerg 		man_pmsg(man, n->line, (int)(p - cp), MANDOCERR_BADTAB);
    232       1.1  joerg }
    233       1.1  joerg 
    234       1.1  joerg #define	INEQ_DEFINE(x, ineq, name) \
    235       1.1  joerg static int \
    236       1.1  joerg check_##name(CHKARGS) \
    237       1.1  joerg { \
    238       1.1  joerg 	if (n->nchild ineq (x)) \
    239       1.1  joerg 		return(1); \
    240  1.1.1.15  joerg 	mandoc_vmsg(MANDOCERR_ARGCOUNT, man->parse, n->line, n->pos, \
    241   1.1.1.7  joerg 			"line arguments %s %d (have %d)", \
    242   1.1.1.7  joerg 			#ineq, (x), n->nchild); \
    243  1.1.1.12  joerg 	return(1); \
    244       1.1  joerg }
    245       1.1  joerg 
    246       1.1  joerg INEQ_DEFINE(0, ==, eq0)
    247  1.1.1.14  joerg INEQ_DEFINE(2, ==, eq2)
    248       1.1  joerg INEQ_DEFINE(1, <=, le1)
    249       1.1  joerg INEQ_DEFINE(2, >=, ge2)
    250       1.1  joerg INEQ_DEFINE(5, <=, le5)
    251       1.1  joerg 
    252  1.1.1.11  joerg static int
    253  1.1.1.15  joerg check_head1(CHKARGS)
    254  1.1.1.15  joerg {
    255  1.1.1.15  joerg 
    256  1.1.1.15  joerg 	if (MAN_HEAD == n->type && 1 != n->nchild)
    257  1.1.1.15  joerg 		mandoc_vmsg(MANDOCERR_ARGCOUNT, man->parse, n->line,
    258  1.1.1.15  joerg 		    n->pos, "line arguments eq 1 (have %d)", n->nchild);
    259  1.1.1.15  joerg 
    260  1.1.1.15  joerg 	return(1);
    261  1.1.1.15  joerg }
    262  1.1.1.15  joerg 
    263  1.1.1.15  joerg static int
    264  1.1.1.13  joerg post_ft(CHKARGS)
    265  1.1.1.11  joerg {
    266  1.1.1.11  joerg 	char	*cp;
    267  1.1.1.11  joerg 	int	 ok;
    268  1.1.1.11  joerg 
    269  1.1.1.11  joerg 	if (0 == n->nchild)
    270  1.1.1.11  joerg 		return(1);
    271  1.1.1.11  joerg 
    272  1.1.1.11  joerg 	ok = 0;
    273  1.1.1.11  joerg 	cp = n->child->string;
    274  1.1.1.11  joerg 	switch (*cp) {
    275  1.1.1.11  joerg 	case ('1'):
    276  1.1.1.11  joerg 		/* FALLTHROUGH */
    277  1.1.1.11  joerg 	case ('2'):
    278  1.1.1.11  joerg 		/* FALLTHROUGH */
    279  1.1.1.11  joerg 	case ('3'):
    280  1.1.1.11  joerg 		/* FALLTHROUGH */
    281  1.1.1.11  joerg 	case ('4'):
    282  1.1.1.11  joerg 		/* FALLTHROUGH */
    283  1.1.1.11  joerg 	case ('I'):
    284  1.1.1.11  joerg 		/* FALLTHROUGH */
    285  1.1.1.11  joerg 	case ('P'):
    286  1.1.1.11  joerg 		/* FALLTHROUGH */
    287  1.1.1.11  joerg 	case ('R'):
    288  1.1.1.11  joerg 		if ('\0' == cp[1])
    289  1.1.1.11  joerg 			ok = 1;
    290  1.1.1.11  joerg 		break;
    291  1.1.1.11  joerg 	case ('B'):
    292  1.1.1.11  joerg 		if ('\0' == cp[1] || ('I' == cp[1] && '\0' == cp[2]))
    293  1.1.1.11  joerg 			ok = 1;
    294  1.1.1.11  joerg 		break;
    295  1.1.1.11  joerg 	case ('C'):
    296  1.1.1.11  joerg 		if ('W' == cp[1] && '\0' == cp[2])
    297  1.1.1.11  joerg 			ok = 1;
    298  1.1.1.11  joerg 		break;
    299  1.1.1.11  joerg 	default:
    300  1.1.1.11  joerg 		break;
    301  1.1.1.11  joerg 	}
    302  1.1.1.11  joerg 
    303  1.1.1.11  joerg 	if (0 == ok) {
    304  1.1.1.12  joerg 		mandoc_vmsg
    305  1.1.1.15  joerg 			(MANDOCERR_BADFONT, man->parse,
    306  1.1.1.12  joerg 			 n->line, n->pos, "%s", cp);
    307  1.1.1.11  joerg 		*cp = '\0';
    308  1.1.1.11  joerg 	}
    309  1.1.1.11  joerg 
    310  1.1.1.11  joerg 	if (1 < n->nchild)
    311  1.1.1.12  joerg 		mandoc_vmsg
    312  1.1.1.15  joerg 			(MANDOCERR_ARGCOUNT, man->parse, n->line,
    313  1.1.1.12  joerg 			 n->pos, "want one child (have %d)",
    314  1.1.1.12  joerg 			 n->nchild);
    315  1.1.1.11  joerg 
    316  1.1.1.11  joerg 	return(1);
    317  1.1.1.11  joerg }
    318       1.1  joerg 
    319       1.1  joerg static int
    320  1.1.1.13  joerg pre_sec(CHKARGS)
    321       1.1  joerg {
    322       1.1  joerg 
    323  1.1.1.13  joerg 	if (MAN_BLOCK == n->type)
    324  1.1.1.15  joerg 		man->flags &= ~MAN_LITERAL;
    325       1.1  joerg 	return(1);
    326       1.1  joerg }
    327       1.1  joerg 
    328  1.1.1.13  joerg static int
    329  1.1.1.13  joerg post_sec(CHKARGS)
    330  1.1.1.13  joerg {
    331  1.1.1.13  joerg 
    332  1.1.1.13  joerg 	if ( ! (MAN_HEAD == n->type && 0 == n->nchild))
    333  1.1.1.13  joerg 		return(1);
    334  1.1.1.13  joerg 
    335  1.1.1.15  joerg 	man_nmsg(man, n, MANDOCERR_SYNTARGCOUNT);
    336  1.1.1.13  joerg 	return(0);
    337  1.1.1.13  joerg }
    338       1.1  joerg 
    339       1.1  joerg static int
    340       1.1  joerg check_part(CHKARGS)
    341       1.1  joerg {
    342       1.1  joerg 
    343       1.1  joerg 	if (MAN_BODY == n->type && 0 == n->nchild)
    344  1.1.1.15  joerg 		mandoc_msg(MANDOCERR_ARGCWARN, man->parse, n->line,
    345  1.1.1.12  joerg 				n->pos, "want children (have none)");
    346  1.1.1.11  joerg 
    347       1.1  joerg 	return(1);
    348       1.1  joerg }
    349       1.1  joerg 
    350       1.1  joerg 
    351       1.1  joerg static int
    352       1.1  joerg check_par(CHKARGS)
    353       1.1  joerg {
    354       1.1  joerg 
    355  1.1.1.12  joerg 	switch (n->type) {
    356  1.1.1.12  joerg 	case (MAN_BLOCK):
    357  1.1.1.12  joerg 		if (0 == n->body->nchild)
    358  1.1.1.15  joerg 			man_node_delete(man, n);
    359  1.1.1.12  joerg 		break;
    360  1.1.1.12  joerg 	case (MAN_BODY):
    361  1.1.1.12  joerg 		if (0 == n->nchild)
    362  1.1.1.15  joerg 			man_nmsg(man, n, MANDOCERR_IGNPAR);
    363  1.1.1.12  joerg 		break;
    364  1.1.1.12  joerg 	case (MAN_HEAD):
    365  1.1.1.12  joerg 		if (n->nchild)
    366  1.1.1.15  joerg 			man_nmsg(man, n, MANDOCERR_ARGSLOST);
    367  1.1.1.12  joerg 		break;
    368  1.1.1.12  joerg 	default:
    369  1.1.1.12  joerg 		break;
    370  1.1.1.12  joerg 	}
    371       1.1  joerg 
    372       1.1  joerg 	return(1);
    373       1.1  joerg }
    374       1.1  joerg 
    375  1.1.1.15  joerg static int
    376  1.1.1.15  joerg post_IP(CHKARGS)
    377  1.1.1.15  joerg {
    378  1.1.1.15  joerg 
    379  1.1.1.15  joerg 	switch (n->type) {
    380  1.1.1.15  joerg 	case (MAN_BLOCK):
    381  1.1.1.15  joerg 		if (0 == n->head->nchild && 0 == n->body->nchild)
    382  1.1.1.15  joerg 			man_node_delete(man, n);
    383  1.1.1.15  joerg 		break;
    384  1.1.1.15  joerg 	case (MAN_BODY):
    385  1.1.1.15  joerg 		if (0 == n->parent->head->nchild && 0 == n->nchild)
    386  1.1.1.15  joerg 			man_nmsg(man, n, MANDOCERR_IGNPAR);
    387  1.1.1.15  joerg 		break;
    388  1.1.1.15  joerg 	default:
    389  1.1.1.15  joerg 		break;
    390  1.1.1.15  joerg 	}
    391  1.1.1.15  joerg 	return(1);
    392  1.1.1.15  joerg }
    393       1.1  joerg 
    394       1.1  joerg static int
    395  1.1.1.11  joerg post_TH(CHKARGS)
    396  1.1.1.11  joerg {
    397  1.1.1.12  joerg 	const char	*p;
    398  1.1.1.11  joerg 
    399  1.1.1.15  joerg 	free(man->meta.title);
    400  1.1.1.15  joerg 	free(man->meta.vol);
    401  1.1.1.15  joerg 	free(man->meta.source);
    402  1.1.1.15  joerg 	free(man->meta.msec);
    403  1.1.1.15  joerg 	free(man->meta.date);
    404  1.1.1.15  joerg 
    405  1.1.1.15  joerg 	man->meta.title = man->meta.vol = man->meta.date =
    406  1.1.1.15  joerg 		man->meta.msec = man->meta.source = NULL;
    407  1.1.1.11  joerg 
    408  1.1.1.11  joerg 	/* ->TITLE<- MSEC DATE SOURCE VOL */
    409  1.1.1.11  joerg 
    410  1.1.1.11  joerg 	n = n->child;
    411  1.1.1.12  joerg 	if (n && n->string) {
    412  1.1.1.12  joerg 		for (p = n->string; '\0' != *p; p++) {
    413  1.1.1.12  joerg 			/* Only warn about this once... */
    414  1.1.1.13  joerg 			if (isalpha((unsigned char)*p) &&
    415  1.1.1.13  joerg 					! isupper((unsigned char)*p)) {
    416  1.1.1.15  joerg 				man_nmsg(man, n, MANDOCERR_UPPERCASE);
    417  1.1.1.12  joerg 				break;
    418  1.1.1.12  joerg 			}
    419  1.1.1.12  joerg 		}
    420  1.1.1.15  joerg 		man->meta.title = mandoc_strdup(n->string);
    421  1.1.1.12  joerg 	} else
    422  1.1.1.15  joerg 		man->meta.title = mandoc_strdup("");
    423  1.1.1.11  joerg 
    424  1.1.1.11  joerg 	/* TITLE ->MSEC<- DATE SOURCE VOL */
    425  1.1.1.11  joerg 
    426  1.1.1.12  joerg 	if (n)
    427  1.1.1.12  joerg 		n = n->next;
    428  1.1.1.12  joerg 	if (n && n->string)
    429  1.1.1.15  joerg 		man->meta.msec = mandoc_strdup(n->string);
    430  1.1.1.12  joerg 	else
    431  1.1.1.15  joerg 		man->meta.msec = mandoc_strdup("");
    432  1.1.1.11  joerg 
    433  1.1.1.11  joerg 	/* TITLE MSEC ->DATE<- SOURCE VOL */
    434  1.1.1.11  joerg 
    435  1.1.1.12  joerg 	if (n)
    436  1.1.1.12  joerg 		n = n->next;
    437  1.1.1.14  joerg 	if (n && n->string && '\0' != n->string[0]) {
    438  1.1.1.15  joerg 		man->meta.date = mandoc_normdate
    439  1.1.1.15  joerg 		    (man->parse, n->string, n->line, n->pos);
    440  1.1.1.14  joerg 	} else
    441  1.1.1.15  joerg 		man->meta.date = mandoc_strdup("");
    442  1.1.1.11  joerg 
    443  1.1.1.11  joerg 	/* TITLE MSEC DATE ->SOURCE<- VOL */
    444  1.1.1.11  joerg 
    445  1.1.1.11  joerg 	if (n && (n = n->next))
    446  1.1.1.15  joerg 		man->meta.source = mandoc_strdup(n->string);
    447  1.1.1.11  joerg 
    448  1.1.1.11  joerg 	/* TITLE MSEC DATE SOURCE ->VOL<- */
    449  1.1.1.14  joerg 	/* If missing, use the default VOL name for MSEC. */
    450  1.1.1.11  joerg 
    451  1.1.1.11  joerg 	if (n && (n = n->next))
    452  1.1.1.15  joerg 		man->meta.vol = mandoc_strdup(n->string);
    453  1.1.1.15  joerg 	else if ('\0' != man->meta.msec[0] &&
    454  1.1.1.15  joerg 	    (NULL != (p = mandoc_a2msec(man->meta.msec))))
    455  1.1.1.15  joerg 		man->meta.vol = mandoc_strdup(p);
    456  1.1.1.11  joerg 
    457  1.1.1.11  joerg 	/*
    458  1.1.1.11  joerg 	 * Remove the `TH' node after we've processed it for our
    459  1.1.1.11  joerg 	 * meta-data.
    460  1.1.1.11  joerg 	 */
    461  1.1.1.15  joerg 	man_node_delete(man, man->last);
    462  1.1.1.11  joerg 	return(1);
    463  1.1.1.11  joerg }
    464  1.1.1.11  joerg 
    465  1.1.1.11  joerg static int
    466  1.1.1.11  joerg post_nf(CHKARGS)
    467  1.1.1.11  joerg {
    468  1.1.1.11  joerg 
    469  1.1.1.15  joerg 	if (MAN_LITERAL & man->flags)
    470  1.1.1.15  joerg 		man_nmsg(man, n, MANDOCERR_SCOPEREP);
    471  1.1.1.11  joerg 
    472  1.1.1.15  joerg 	man->flags |= MAN_LITERAL;
    473  1.1.1.11  joerg 	return(1);
    474  1.1.1.11  joerg }
    475  1.1.1.11  joerg 
    476  1.1.1.11  joerg static int
    477  1.1.1.11  joerg post_fi(CHKARGS)
    478  1.1.1.11  joerg {
    479  1.1.1.11  joerg 
    480  1.1.1.15  joerg 	if ( ! (MAN_LITERAL & man->flags))
    481  1.1.1.15  joerg 		man_nmsg(man, n, MANDOCERR_WNOSCOPE);
    482  1.1.1.11  joerg 
    483  1.1.1.15  joerg 	man->flags &= ~MAN_LITERAL;
    484  1.1.1.11  joerg 	return(1);
    485  1.1.1.11  joerg }
    486  1.1.1.11  joerg 
    487  1.1.1.11  joerg static int
    488  1.1.1.11  joerg post_UC(CHKARGS)
    489  1.1.1.11  joerg {
    490  1.1.1.11  joerg 	static const char * const bsd_versions[] = {
    491  1.1.1.11  joerg 	    "3rd Berkeley Distribution",
    492  1.1.1.11  joerg 	    "4th Berkeley Distribution",
    493  1.1.1.11  joerg 	    "4.2 Berkeley Distribution",
    494  1.1.1.11  joerg 	    "4.3 Berkeley Distribution",
    495  1.1.1.11  joerg 	    "4.4 Berkeley Distribution",
    496  1.1.1.11  joerg 	};
    497  1.1.1.11  joerg 
    498  1.1.1.11  joerg 	const char	*p, *s;
    499  1.1.1.11  joerg 
    500  1.1.1.11  joerg 	n = n->child;
    501  1.1.1.11  joerg 
    502  1.1.1.11  joerg 	if (NULL == n || MAN_TEXT != n->type)
    503  1.1.1.11  joerg 		p = bsd_versions[0];
    504  1.1.1.11  joerg 	else {
    505  1.1.1.11  joerg 		s = n->string;
    506  1.1.1.11  joerg 		if (0 == strcmp(s, "3"))
    507  1.1.1.11  joerg 			p = bsd_versions[0];
    508  1.1.1.11  joerg 		else if (0 == strcmp(s, "4"))
    509  1.1.1.11  joerg 			p = bsd_versions[1];
    510  1.1.1.11  joerg 		else if (0 == strcmp(s, "5"))
    511  1.1.1.11  joerg 			p = bsd_versions[2];
    512  1.1.1.11  joerg 		else if (0 == strcmp(s, "6"))
    513  1.1.1.11  joerg 			p = bsd_versions[3];
    514  1.1.1.11  joerg 		else if (0 == strcmp(s, "7"))
    515  1.1.1.11  joerg 			p = bsd_versions[4];
    516  1.1.1.11  joerg 		else
    517  1.1.1.11  joerg 			p = bsd_versions[0];
    518  1.1.1.11  joerg 	}
    519  1.1.1.11  joerg 
    520  1.1.1.15  joerg 	free(man->meta.source);
    521  1.1.1.15  joerg 	man->meta.source = mandoc_strdup(p);
    522  1.1.1.11  joerg 	return(1);
    523  1.1.1.11  joerg }
    524  1.1.1.11  joerg 
    525  1.1.1.11  joerg static int
    526  1.1.1.11  joerg post_AT(CHKARGS)
    527  1.1.1.11  joerg {
    528  1.1.1.11  joerg 	static const char * const unix_versions[] = {
    529  1.1.1.11  joerg 	    "7th Edition",
    530  1.1.1.11  joerg 	    "System III",
    531  1.1.1.11  joerg 	    "System V",
    532  1.1.1.11  joerg 	    "System V Release 2",
    533  1.1.1.11  joerg 	};
    534  1.1.1.11  joerg 
    535  1.1.1.11  joerg 	const char	*p, *s;
    536  1.1.1.11  joerg 	struct man_node	*nn;
    537  1.1.1.11  joerg 
    538  1.1.1.11  joerg 	n = n->child;
    539  1.1.1.11  joerg 
    540  1.1.1.11  joerg 	if (NULL == n || MAN_TEXT != n->type)
    541  1.1.1.11  joerg 		p = unix_versions[0];
    542  1.1.1.11  joerg 	else {
    543  1.1.1.11  joerg 		s = n->string;
    544  1.1.1.11  joerg 		if (0 == strcmp(s, "3"))
    545  1.1.1.11  joerg 			p = unix_versions[0];
    546  1.1.1.11  joerg 		else if (0 == strcmp(s, "4"))
    547  1.1.1.11  joerg 			p = unix_versions[1];
    548  1.1.1.11  joerg 		else if (0 == strcmp(s, "5")) {
    549  1.1.1.11  joerg 			nn = n->next;
    550  1.1.1.11  joerg 			if (nn && MAN_TEXT == nn->type && nn->string[0])
    551  1.1.1.11  joerg 				p = unix_versions[3];
    552  1.1.1.11  joerg 			else
    553  1.1.1.11  joerg 				p = unix_versions[2];
    554  1.1.1.11  joerg 		} else
    555  1.1.1.11  joerg 			p = unix_versions[0];
    556  1.1.1.11  joerg 	}
    557  1.1.1.11  joerg 
    558  1.1.1.15  joerg 	free(man->meta.source);
    559  1.1.1.15  joerg 	man->meta.source = mandoc_strdup(p);
    560  1.1.1.11  joerg 	return(1);
    561  1.1.1.11  joerg }
    562  1.1.1.13  joerg 
    563  1.1.1.13  joerg static int
    564  1.1.1.13  joerg post_vs(CHKARGS)
    565  1.1.1.13  joerg {
    566  1.1.1.13  joerg 
    567  1.1.1.15  joerg 	if (NULL != n->prev)
    568  1.1.1.15  joerg 		return(1);
    569  1.1.1.15  joerg 
    570  1.1.1.15  joerg 	switch (n->parent->tok) {
    571  1.1.1.15  joerg 	case (MAN_SH):
    572  1.1.1.15  joerg 		/* FALLTHROUGH */
    573  1.1.1.15  joerg 	case (MAN_SS):
    574  1.1.1.15  joerg 		man_nmsg(man, n, MANDOCERR_IGNPAR);
    575  1.1.1.15  joerg 		/* FALLTHROUGH */
    576  1.1.1.15  joerg 	case (MAN_MAX):
    577  1.1.1.15  joerg 		/*
    578  1.1.1.15  joerg 		 * Don't warn about this because it occurs in pod2man
    579  1.1.1.15  joerg 		 * and would cause considerable (unfixable) warnage.
    580  1.1.1.15  joerg 		 */
    581  1.1.1.15  joerg 		man_node_delete(man, n);
    582  1.1.1.15  joerg 		break;
    583  1.1.1.15  joerg 	default:
    584  1.1.1.15  joerg 		break;
    585  1.1.1.15  joerg 	}
    586  1.1.1.13  joerg 
    587  1.1.1.13  joerg 	return(1);
    588  1.1.1.13  joerg }
    589