Home | History | Annotate | Line # | Download | only in dist
man_validate.c revision 1.1.1.16
      1  1.1.1.16  christos /*	$OpenBSD$ */
      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.16  christos  * Copyright (c) 2010, 2012-2015 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 #include "config.h"
     19   1.1.1.4     joerg 
     20       1.1     joerg #include <sys/types.h>
     21       1.1     joerg 
     22       1.1     joerg #include <assert.h>
     23       1.1     joerg #include <ctype.h>
     24       1.1     joerg #include <errno.h>
     25       1.1     joerg #include <limits.h>
     26       1.1     joerg #include <stdarg.h>
     27       1.1     joerg #include <stdlib.h>
     28  1.1.1.10     joerg #include <string.h>
     29  1.1.1.11     joerg #include <time.h>
     30       1.1     joerg 
     31  1.1.1.12     joerg #include "man.h"
     32   1.1.1.7     joerg #include "mandoc.h"
     33  1.1.1.16  christos #include "mandoc_aux.h"
     34       1.1     joerg #include "libman.h"
     35       1.1     joerg #include "libmandoc.h"
     36       1.1     joerg 
     37  1.1.1.15     joerg #define	CHKARGS	  struct man *man, struct man_node *n
     38       1.1     joerg 
     39  1.1.1.16  christos typedef	void	(*v_check)(CHKARGS);
     40       1.1     joerg 
     41  1.1.1.16  christos static	void	  check_par(CHKARGS);
     42  1.1.1.16  christos static	void	  check_part(CHKARGS);
     43  1.1.1.16  christos static	void	  check_root(CHKARGS);
     44  1.1.1.13     joerg static	void	  check_text(CHKARGS);
     45       1.1     joerg 
     46  1.1.1.16  christos static	void	  post_AT(CHKARGS);
     47  1.1.1.16  christos static	void	  post_IP(CHKARGS);
     48  1.1.1.16  christos static	void	  post_vs(CHKARGS);
     49  1.1.1.16  christos static	void	  post_fi(CHKARGS);
     50  1.1.1.16  christos static	void	  post_ft(CHKARGS);
     51  1.1.1.16  christos static	void	  post_nf(CHKARGS);
     52  1.1.1.16  christos static	void	  post_OP(CHKARGS);
     53  1.1.1.16  christos static	void	  post_TH(CHKARGS);
     54  1.1.1.16  christos static	void	  post_UC(CHKARGS);
     55  1.1.1.16  christos static	void	  post_UR(CHKARGS);
     56  1.1.1.16  christos 
     57  1.1.1.16  christos static	v_check man_valids[MAN_MAX] = {
     58  1.1.1.16  christos 	post_vs,    /* br */
     59  1.1.1.16  christos 	post_TH,    /* TH */
     60  1.1.1.16  christos 	NULL,       /* SH */
     61  1.1.1.16  christos 	NULL,       /* SS */
     62  1.1.1.16  christos 	NULL,       /* TP */
     63  1.1.1.16  christos 	check_par,  /* LP */
     64  1.1.1.16  christos 	check_par,  /* PP */
     65  1.1.1.16  christos 	check_par,  /* P */
     66  1.1.1.16  christos 	post_IP,    /* IP */
     67  1.1.1.16  christos 	NULL,       /* HP */
     68  1.1.1.16  christos 	NULL,       /* SM */
     69  1.1.1.16  christos 	NULL,       /* SB */
     70  1.1.1.16  christos 	NULL,       /* BI */
     71  1.1.1.16  christos 	NULL,       /* IB */
     72  1.1.1.16  christos 	NULL,       /* BR */
     73  1.1.1.16  christos 	NULL,       /* RB */
     74  1.1.1.16  christos 	NULL,       /* R */
     75  1.1.1.16  christos 	NULL,       /* B */
     76  1.1.1.16  christos 	NULL,       /* I */
     77  1.1.1.16  christos 	NULL,       /* IR */
     78  1.1.1.16  christos 	NULL,       /* RI */
     79  1.1.1.16  christos 	post_vs,    /* sp */
     80  1.1.1.16  christos 	post_nf,    /* nf */
     81  1.1.1.16  christos 	post_fi,    /* fi */
     82  1.1.1.16  christos 	NULL,       /* RE */
     83  1.1.1.16  christos 	check_part, /* RS */
     84  1.1.1.16  christos 	NULL,       /* DT */
     85  1.1.1.16  christos 	post_UC,    /* UC */
     86  1.1.1.16  christos 	NULL,       /* PD */
     87  1.1.1.16  christos 	post_AT,    /* AT */
     88  1.1.1.16  christos 	NULL,       /* in */
     89  1.1.1.16  christos 	post_ft,    /* ft */
     90  1.1.1.16  christos 	post_OP,    /* OP */
     91  1.1.1.16  christos 	post_nf,    /* EX */
     92  1.1.1.16  christos 	post_fi,    /* EE */
     93  1.1.1.16  christos 	post_UR,    /* UR */
     94  1.1.1.16  christos 	NULL,       /* UE */
     95  1.1.1.16  christos 	NULL,       /* ll */
     96       1.1     joerg };
     97       1.1     joerg 
     98       1.1     joerg 
     99  1.1.1.16  christos void
    100  1.1.1.16  christos man_valid_post(struct man *man)
    101       1.1     joerg {
    102  1.1.1.16  christos 	struct man_node	*n;
    103       1.1     joerg 	v_check		*cp;
    104       1.1     joerg 
    105  1.1.1.16  christos 	n = man->last;
    106  1.1.1.16  christos 	if (n->flags & MAN_VALID)
    107  1.1.1.16  christos 		return;
    108  1.1.1.16  christos 	n->flags |= MAN_VALID;
    109  1.1.1.16  christos 
    110  1.1.1.11     joerg 	switch (n->type) {
    111  1.1.1.16  christos 	case MAN_TEXT:
    112  1.1.1.16  christos 		check_text(man, n);
    113  1.1.1.11     joerg 		break;
    114  1.1.1.16  christos 	case MAN_ROOT:
    115  1.1.1.16  christos 		check_root(man, n);
    116  1.1.1.16  christos 		break;
    117  1.1.1.16  christos 	case MAN_EQN:
    118  1.1.1.12     joerg 		/* FALLTHROUGH */
    119  1.1.1.16  christos 	case MAN_TBL:
    120  1.1.1.16  christos 		break;
    121       1.1     joerg 	default:
    122  1.1.1.16  christos 		cp = man_valids + n->tok;
    123  1.1.1.16  christos 		if (*cp)
    124  1.1.1.16  christos 			(*cp)(man, n);
    125       1.1     joerg 		break;
    126       1.1     joerg 	}
    127       1.1     joerg }
    128       1.1     joerg 
    129  1.1.1.16  christos static void
    130  1.1.1.16  christos check_root(CHKARGS)
    131       1.1     joerg {
    132       1.1     joerg 
    133  1.1.1.16  christos 	assert((man->flags & (MAN_BLINE | MAN_ELINE)) == 0);
    134       1.1     joerg 
    135  1.1.1.16  christos 	if (NULL == man->first->child)
    136  1.1.1.16  christos 		mandoc_msg(MANDOCERR_DOC_EMPTY, man->parse,
    137  1.1.1.16  christos 		    n->line, n->pos, NULL);
    138  1.1.1.16  christos 	else
    139  1.1.1.16  christos 		man->meta.hasbody = 1;
    140       1.1     joerg 
    141  1.1.1.16  christos 	if (NULL == man->meta.title) {
    142  1.1.1.16  christos 		mandoc_msg(MANDOCERR_TH_NOTITLE, man->parse,
    143  1.1.1.16  christos 		    n->line, n->pos, NULL);
    144  1.1.1.11     joerg 
    145   1.1.1.6     joerg 		/*
    146   1.1.1.6     joerg 		 * If a title hasn't been set, do so now (by
    147   1.1.1.6     joerg 		 * implication, date and section also aren't set).
    148   1.1.1.6     joerg 		 */
    149  1.1.1.11     joerg 
    150  1.1.1.16  christos 		man->meta.title = mandoc_strdup("");
    151  1.1.1.16  christos 		man->meta.msec = mandoc_strdup("");
    152  1.1.1.16  christos 		man->meta.date = man->quick ? mandoc_strdup("") :
    153  1.1.1.16  christos 		    mandoc_normdate(man->parse, NULL, n->line, n->pos);
    154   1.1.1.6     joerg 	}
    155       1.1     joerg }
    156       1.1     joerg 
    157  1.1.1.13     joerg static void
    158  1.1.1.13     joerg check_text(CHKARGS)
    159       1.1     joerg {
    160  1.1.1.13     joerg 	char		*cp, *p;
    161       1.1     joerg 
    162  1.1.1.15     joerg 	if (MAN_LITERAL & man->flags)
    163  1.1.1.14     joerg 		return;
    164  1.1.1.14     joerg 
    165  1.1.1.14     joerg 	cp = n->string;
    166  1.1.1.14     joerg 	for (p = cp; NULL != (p = strchr(p, '\t')); p++)
    167  1.1.1.16  christos 		mandoc_msg(MANDOCERR_FI_TAB, man->parse,
    168  1.1.1.16  christos 		    n->line, n->pos + (p - cp), NULL);
    169       1.1     joerg }
    170       1.1     joerg 
    171  1.1.1.16  christos static void
    172  1.1.1.16  christos post_OP(CHKARGS)
    173  1.1.1.16  christos {
    174       1.1     joerg 
    175  1.1.1.16  christos 	if (n->nchild == 0)
    176  1.1.1.16  christos 		mandoc_msg(MANDOCERR_OP_EMPTY, man->parse,
    177  1.1.1.16  christos 		    n->line, n->pos, "OP");
    178  1.1.1.16  christos 	else if (n->nchild > 2) {
    179  1.1.1.16  christos 		n = n->child->next->next;
    180  1.1.1.16  christos 		mandoc_vmsg(MANDOCERR_ARG_EXCESS, man->parse,
    181  1.1.1.16  christos 		    n->line, n->pos, "OP ... %s", n->string);
    182  1.1.1.16  christos 	}
    183  1.1.1.16  christos }
    184       1.1     joerg 
    185  1.1.1.16  christos static void
    186  1.1.1.16  christos post_UR(CHKARGS)
    187  1.1.1.15     joerg {
    188  1.1.1.15     joerg 
    189  1.1.1.16  christos 	if (n->type == MAN_HEAD && n->child == NULL)
    190  1.1.1.16  christos 		mandoc_vmsg(MANDOCERR_UR_NOHEAD, man->parse,
    191  1.1.1.16  christos 		    n->line, n->pos, "UR");
    192  1.1.1.16  christos 	check_part(man, n);
    193  1.1.1.15     joerg }
    194  1.1.1.15     joerg 
    195  1.1.1.16  christos static void
    196  1.1.1.13     joerg post_ft(CHKARGS)
    197  1.1.1.11     joerg {
    198  1.1.1.11     joerg 	char	*cp;
    199  1.1.1.11     joerg 	int	 ok;
    200  1.1.1.11     joerg 
    201  1.1.1.11     joerg 	if (0 == n->nchild)
    202  1.1.1.16  christos 		return;
    203  1.1.1.11     joerg 
    204  1.1.1.11     joerg 	ok = 0;
    205  1.1.1.11     joerg 	cp = n->child->string;
    206  1.1.1.11     joerg 	switch (*cp) {
    207  1.1.1.16  christos 	case '1':
    208  1.1.1.11     joerg 		/* FALLTHROUGH */
    209  1.1.1.16  christos 	case '2':
    210  1.1.1.11     joerg 		/* FALLTHROUGH */
    211  1.1.1.16  christos 	case '3':
    212  1.1.1.11     joerg 		/* FALLTHROUGH */
    213  1.1.1.16  christos 	case '4':
    214  1.1.1.11     joerg 		/* FALLTHROUGH */
    215  1.1.1.16  christos 	case 'I':
    216  1.1.1.11     joerg 		/* FALLTHROUGH */
    217  1.1.1.16  christos 	case 'P':
    218  1.1.1.11     joerg 		/* FALLTHROUGH */
    219  1.1.1.16  christos 	case 'R':
    220  1.1.1.11     joerg 		if ('\0' == cp[1])
    221  1.1.1.11     joerg 			ok = 1;
    222  1.1.1.11     joerg 		break;
    223  1.1.1.16  christos 	case 'B':
    224  1.1.1.11     joerg 		if ('\0' == cp[1] || ('I' == cp[1] && '\0' == cp[2]))
    225  1.1.1.11     joerg 			ok = 1;
    226  1.1.1.11     joerg 		break;
    227  1.1.1.16  christos 	case 'C':
    228  1.1.1.11     joerg 		if ('W' == cp[1] && '\0' == cp[2])
    229  1.1.1.11     joerg 			ok = 1;
    230  1.1.1.11     joerg 		break;
    231  1.1.1.11     joerg 	default:
    232  1.1.1.11     joerg 		break;
    233  1.1.1.11     joerg 	}
    234  1.1.1.11     joerg 
    235  1.1.1.11     joerg 	if (0 == ok) {
    236  1.1.1.16  christos 		mandoc_vmsg(MANDOCERR_FT_BAD, man->parse,
    237  1.1.1.16  christos 		    n->line, n->pos, "ft %s", cp);
    238  1.1.1.11     joerg 		*cp = '\0';
    239  1.1.1.11     joerg 	}
    240  1.1.1.13     joerg }
    241       1.1     joerg 
    242  1.1.1.16  christos static void
    243       1.1     joerg check_part(CHKARGS)
    244       1.1     joerg {
    245       1.1     joerg 
    246  1.1.1.16  christos 	if (n->type == MAN_BODY && n->child == NULL)
    247  1.1.1.16  christos 		mandoc_msg(MANDOCERR_BLK_EMPTY, man->parse,
    248  1.1.1.16  christos 		    n->line, n->pos, man_macronames[n->tok]);
    249       1.1     joerg }
    250       1.1     joerg 
    251  1.1.1.16  christos static void
    252       1.1     joerg check_par(CHKARGS)
    253       1.1     joerg {
    254       1.1     joerg 
    255  1.1.1.12     joerg 	switch (n->type) {
    256  1.1.1.16  christos 	case MAN_BLOCK:
    257  1.1.1.12     joerg 		if (0 == n->body->nchild)
    258  1.1.1.15     joerg 			man_node_delete(man, n);
    259  1.1.1.12     joerg 		break;
    260  1.1.1.16  christos 	case MAN_BODY:
    261  1.1.1.12     joerg 		if (0 == n->nchild)
    262  1.1.1.16  christos 			mandoc_vmsg(MANDOCERR_PAR_SKIP,
    263  1.1.1.16  christos 			    man->parse, n->line, n->pos,
    264  1.1.1.16  christos 			    "%s empty", man_macronames[n->tok]);
    265  1.1.1.12     joerg 		break;
    266  1.1.1.16  christos 	case MAN_HEAD:
    267  1.1.1.12     joerg 		if (n->nchild)
    268  1.1.1.16  christos 			mandoc_vmsg(MANDOCERR_ARG_SKIP,
    269  1.1.1.16  christos 			    man->parse, n->line, n->pos,
    270  1.1.1.16  christos 			    "%s %s%s", man_macronames[n->tok],
    271  1.1.1.16  christos 			    n->child->string,
    272  1.1.1.16  christos 			    n->nchild > 1 ? " ..." : "");
    273  1.1.1.12     joerg 		break;
    274  1.1.1.12     joerg 	default:
    275  1.1.1.12     joerg 		break;
    276  1.1.1.12     joerg 	}
    277       1.1     joerg }
    278       1.1     joerg 
    279  1.1.1.16  christos static void
    280  1.1.1.15     joerg post_IP(CHKARGS)
    281  1.1.1.15     joerg {
    282  1.1.1.15     joerg 
    283  1.1.1.15     joerg 	switch (n->type) {
    284  1.1.1.16  christos 	case MAN_BLOCK:
    285  1.1.1.15     joerg 		if (0 == n->head->nchild && 0 == n->body->nchild)
    286  1.1.1.15     joerg 			man_node_delete(man, n);
    287  1.1.1.15     joerg 		break;
    288  1.1.1.16  christos 	case MAN_BODY:
    289  1.1.1.15     joerg 		if (0 == n->parent->head->nchild && 0 == n->nchild)
    290  1.1.1.16  christos 			mandoc_vmsg(MANDOCERR_PAR_SKIP,
    291  1.1.1.16  christos 			    man->parse, n->line, n->pos,
    292  1.1.1.16  christos 			    "%s empty", man_macronames[n->tok]);
    293  1.1.1.15     joerg 		break;
    294  1.1.1.15     joerg 	default:
    295  1.1.1.15     joerg 		break;
    296  1.1.1.15     joerg 	}
    297  1.1.1.15     joerg }
    298       1.1     joerg 
    299  1.1.1.16  christos static void
    300  1.1.1.11     joerg post_TH(CHKARGS)
    301  1.1.1.11     joerg {
    302  1.1.1.16  christos 	struct man_node	*nb;
    303  1.1.1.12     joerg 	const char	*p;
    304  1.1.1.11     joerg 
    305  1.1.1.15     joerg 	free(man->meta.title);
    306  1.1.1.15     joerg 	free(man->meta.vol);
    307  1.1.1.15     joerg 	free(man->meta.source);
    308  1.1.1.15     joerg 	free(man->meta.msec);
    309  1.1.1.15     joerg 	free(man->meta.date);
    310  1.1.1.15     joerg 
    311  1.1.1.15     joerg 	man->meta.title = man->meta.vol = man->meta.date =
    312  1.1.1.16  christos 	    man->meta.msec = man->meta.source = NULL;
    313  1.1.1.16  christos 
    314  1.1.1.16  christos 	nb = n;
    315  1.1.1.11     joerg 
    316  1.1.1.11     joerg 	/* ->TITLE<- MSEC DATE SOURCE VOL */
    317  1.1.1.11     joerg 
    318  1.1.1.11     joerg 	n = n->child;
    319  1.1.1.12     joerg 	if (n && n->string) {
    320  1.1.1.12     joerg 		for (p = n->string; '\0' != *p; p++) {
    321  1.1.1.12     joerg 			/* Only warn about this once... */
    322  1.1.1.16  christos 			if (isalpha((unsigned char)*p) &&
    323  1.1.1.16  christos 			    ! isupper((unsigned char)*p)) {
    324  1.1.1.16  christos 				mandoc_vmsg(MANDOCERR_TITLE_CASE,
    325  1.1.1.16  christos 				    man->parse, n->line,
    326  1.1.1.16  christos 				    n->pos + (p - n->string),
    327  1.1.1.16  christos 				    "TH %s", n->string);
    328  1.1.1.12     joerg 				break;
    329  1.1.1.12     joerg 			}
    330  1.1.1.12     joerg 		}
    331  1.1.1.15     joerg 		man->meta.title = mandoc_strdup(n->string);
    332  1.1.1.16  christos 	} else {
    333  1.1.1.15     joerg 		man->meta.title = mandoc_strdup("");
    334  1.1.1.16  christos 		mandoc_msg(MANDOCERR_TH_NOTITLE, man->parse,
    335  1.1.1.16  christos 		    nb->line, nb->pos, "TH");
    336  1.1.1.16  christos 	}
    337  1.1.1.11     joerg 
    338  1.1.1.11     joerg 	/* TITLE ->MSEC<- DATE SOURCE VOL */
    339  1.1.1.11     joerg 
    340  1.1.1.12     joerg 	if (n)
    341  1.1.1.12     joerg 		n = n->next;
    342  1.1.1.12     joerg 	if (n && n->string)
    343  1.1.1.15     joerg 		man->meta.msec = mandoc_strdup(n->string);
    344  1.1.1.16  christos 	else {
    345  1.1.1.15     joerg 		man->meta.msec = mandoc_strdup("");
    346  1.1.1.16  christos 		mandoc_vmsg(MANDOCERR_MSEC_MISSING, man->parse,
    347  1.1.1.16  christos 		    nb->line, nb->pos, "TH %s", man->meta.title);
    348  1.1.1.16  christos 	}
    349  1.1.1.11     joerg 
    350  1.1.1.11     joerg 	/* TITLE MSEC ->DATE<- SOURCE VOL */
    351  1.1.1.11     joerg 
    352  1.1.1.12     joerg 	if (n)
    353  1.1.1.12     joerg 		n = n->next;
    354  1.1.1.14     joerg 	if (n && n->string && '\0' != n->string[0]) {
    355  1.1.1.16  christos 		man->meta.date = man->quick ?
    356  1.1.1.16  christos 		    mandoc_strdup(n->string) :
    357  1.1.1.16  christos 		    mandoc_normdate(man->parse, n->string,
    358  1.1.1.16  christos 			n->line, n->pos);
    359  1.1.1.16  christos 	} else {
    360  1.1.1.15     joerg 		man->meta.date = mandoc_strdup("");
    361  1.1.1.16  christos 		mandoc_msg(MANDOCERR_DATE_MISSING, man->parse,
    362  1.1.1.16  christos 		    n ? n->line : nb->line,
    363  1.1.1.16  christos 		    n ? n->pos : nb->pos, "TH");
    364  1.1.1.16  christos 	}
    365  1.1.1.11     joerg 
    366  1.1.1.11     joerg 	/* TITLE MSEC DATE ->SOURCE<- VOL */
    367  1.1.1.11     joerg 
    368  1.1.1.11     joerg 	if (n && (n = n->next))
    369  1.1.1.15     joerg 		man->meta.source = mandoc_strdup(n->string);
    370  1.1.1.16  christos 	else if (man->defos != NULL)
    371  1.1.1.16  christos 		man->meta.source = mandoc_strdup(man->defos);
    372  1.1.1.11     joerg 
    373  1.1.1.11     joerg 	/* TITLE MSEC DATE SOURCE ->VOL<- */
    374  1.1.1.14     joerg 	/* If missing, use the default VOL name for MSEC. */
    375  1.1.1.11     joerg 
    376  1.1.1.11     joerg 	if (n && (n = n->next))
    377  1.1.1.15     joerg 		man->meta.vol = mandoc_strdup(n->string);
    378  1.1.1.15     joerg 	else if ('\0' != man->meta.msec[0] &&
    379  1.1.1.15     joerg 	    (NULL != (p = mandoc_a2msec(man->meta.msec))))
    380  1.1.1.15     joerg 		man->meta.vol = mandoc_strdup(p);
    381  1.1.1.11     joerg 
    382  1.1.1.16  christos 	if (n != NULL && (n = n->next) != NULL)
    383  1.1.1.16  christos 		mandoc_vmsg(MANDOCERR_ARG_EXCESS, man->parse,
    384  1.1.1.16  christos 		    n->line, n->pos, "TH ... %s", n->string);
    385  1.1.1.16  christos 
    386  1.1.1.11     joerg 	/*
    387  1.1.1.11     joerg 	 * Remove the `TH' node after we've processed it for our
    388  1.1.1.11     joerg 	 * meta-data.
    389  1.1.1.11     joerg 	 */
    390  1.1.1.15     joerg 	man_node_delete(man, man->last);
    391  1.1.1.11     joerg }
    392  1.1.1.11     joerg 
    393  1.1.1.16  christos static void
    394  1.1.1.11     joerg post_nf(CHKARGS)
    395  1.1.1.11     joerg {
    396  1.1.1.11     joerg 
    397  1.1.1.16  christos 	if (man->flags & MAN_LITERAL)
    398  1.1.1.16  christos 		mandoc_msg(MANDOCERR_NF_SKIP, man->parse,
    399  1.1.1.16  christos 		    n->line, n->pos, "nf");
    400  1.1.1.11     joerg 
    401  1.1.1.15     joerg 	man->flags |= MAN_LITERAL;
    402  1.1.1.11     joerg }
    403  1.1.1.11     joerg 
    404  1.1.1.16  christos static void
    405  1.1.1.11     joerg post_fi(CHKARGS)
    406  1.1.1.11     joerg {
    407  1.1.1.11     joerg 
    408  1.1.1.15     joerg 	if ( ! (MAN_LITERAL & man->flags))
    409  1.1.1.16  christos 		mandoc_msg(MANDOCERR_FI_SKIP, man->parse,
    410  1.1.1.16  christos 		    n->line, n->pos, "fi");
    411  1.1.1.11     joerg 
    412  1.1.1.15     joerg 	man->flags &= ~MAN_LITERAL;
    413  1.1.1.11     joerg }
    414  1.1.1.11     joerg 
    415  1.1.1.16  christos static void
    416  1.1.1.11     joerg post_UC(CHKARGS)
    417  1.1.1.11     joerg {
    418  1.1.1.11     joerg 	static const char * const bsd_versions[] = {
    419  1.1.1.11     joerg 	    "3rd Berkeley Distribution",
    420  1.1.1.11     joerg 	    "4th Berkeley Distribution",
    421  1.1.1.11     joerg 	    "4.2 Berkeley Distribution",
    422  1.1.1.11     joerg 	    "4.3 Berkeley Distribution",
    423  1.1.1.11     joerg 	    "4.4 Berkeley Distribution",
    424  1.1.1.11     joerg 	};
    425  1.1.1.11     joerg 
    426  1.1.1.11     joerg 	const char	*p, *s;
    427  1.1.1.11     joerg 
    428  1.1.1.11     joerg 	n = n->child;
    429  1.1.1.11     joerg 
    430  1.1.1.11     joerg 	if (NULL == n || MAN_TEXT != n->type)
    431  1.1.1.11     joerg 		p = bsd_versions[0];
    432  1.1.1.11     joerg 	else {
    433  1.1.1.11     joerg 		s = n->string;
    434  1.1.1.11     joerg 		if (0 == strcmp(s, "3"))
    435  1.1.1.11     joerg 			p = bsd_versions[0];
    436  1.1.1.11     joerg 		else if (0 == strcmp(s, "4"))
    437  1.1.1.11     joerg 			p = bsd_versions[1];
    438  1.1.1.11     joerg 		else if (0 == strcmp(s, "5"))
    439  1.1.1.11     joerg 			p = bsd_versions[2];
    440  1.1.1.11     joerg 		else if (0 == strcmp(s, "6"))
    441  1.1.1.11     joerg 			p = bsd_versions[3];
    442  1.1.1.11     joerg 		else if (0 == strcmp(s, "7"))
    443  1.1.1.11     joerg 			p = bsd_versions[4];
    444  1.1.1.11     joerg 		else
    445  1.1.1.11     joerg 			p = bsd_versions[0];
    446  1.1.1.11     joerg 	}
    447  1.1.1.11     joerg 
    448  1.1.1.15     joerg 	free(man->meta.source);
    449  1.1.1.15     joerg 	man->meta.source = mandoc_strdup(p);
    450  1.1.1.11     joerg }
    451  1.1.1.11     joerg 
    452  1.1.1.16  christos static void
    453  1.1.1.11     joerg post_AT(CHKARGS)
    454  1.1.1.11     joerg {
    455  1.1.1.11     joerg 	static const char * const unix_versions[] = {
    456  1.1.1.11     joerg 	    "7th Edition",
    457  1.1.1.11     joerg 	    "System III",
    458  1.1.1.11     joerg 	    "System V",
    459  1.1.1.11     joerg 	    "System V Release 2",
    460  1.1.1.11     joerg 	};
    461  1.1.1.11     joerg 
    462  1.1.1.11     joerg 	const char	*p, *s;
    463  1.1.1.11     joerg 	struct man_node	*nn;
    464  1.1.1.11     joerg 
    465  1.1.1.11     joerg 	n = n->child;
    466  1.1.1.11     joerg 
    467  1.1.1.11     joerg 	if (NULL == n || MAN_TEXT != n->type)
    468  1.1.1.11     joerg 		p = unix_versions[0];
    469  1.1.1.11     joerg 	else {
    470  1.1.1.11     joerg 		s = n->string;
    471  1.1.1.11     joerg 		if (0 == strcmp(s, "3"))
    472  1.1.1.11     joerg 			p = unix_versions[0];
    473  1.1.1.11     joerg 		else if (0 == strcmp(s, "4"))
    474  1.1.1.11     joerg 			p = unix_versions[1];
    475  1.1.1.11     joerg 		else if (0 == strcmp(s, "5")) {
    476  1.1.1.11     joerg 			nn = n->next;
    477  1.1.1.11     joerg 			if (nn && MAN_TEXT == nn->type && nn->string[0])
    478  1.1.1.11     joerg 				p = unix_versions[3];
    479  1.1.1.11     joerg 			else
    480  1.1.1.11     joerg 				p = unix_versions[2];
    481  1.1.1.11     joerg 		} else
    482  1.1.1.11     joerg 			p = unix_versions[0];
    483  1.1.1.11     joerg 	}
    484  1.1.1.11     joerg 
    485  1.1.1.15     joerg 	free(man->meta.source);
    486  1.1.1.15     joerg 	man->meta.source = mandoc_strdup(p);
    487  1.1.1.11     joerg }
    488  1.1.1.13     joerg 
    489  1.1.1.16  christos static void
    490  1.1.1.13     joerg post_vs(CHKARGS)
    491  1.1.1.13     joerg {
    492  1.1.1.13     joerg 
    493  1.1.1.15     joerg 	if (NULL != n->prev)
    494  1.1.1.16  christos 		return;
    495  1.1.1.15     joerg 
    496  1.1.1.15     joerg 	switch (n->parent->tok) {
    497  1.1.1.16  christos 	case MAN_SH:
    498  1.1.1.15     joerg 		/* FALLTHROUGH */
    499  1.1.1.16  christos 	case MAN_SS:
    500  1.1.1.16  christos 		mandoc_vmsg(MANDOCERR_PAR_SKIP, man->parse, n->line, n->pos,
    501  1.1.1.16  christos 		    "%s after %s", man_macronames[n->tok],
    502  1.1.1.16  christos 		    man_macronames[n->parent->tok]);
    503  1.1.1.15     joerg 		/* FALLTHROUGH */
    504  1.1.1.16  christos 	case MAN_MAX:
    505  1.1.1.16  christos 		/*
    506  1.1.1.15     joerg 		 * Don't warn about this because it occurs in pod2man
    507  1.1.1.15     joerg 		 * and would cause considerable (unfixable) warnage.
    508  1.1.1.15     joerg 		 */
    509  1.1.1.15     joerg 		man_node_delete(man, n);
    510  1.1.1.15     joerg 		break;
    511  1.1.1.15     joerg 	default:
    512  1.1.1.15     joerg 		break;
    513  1.1.1.15     joerg 	}
    514  1.1.1.13     joerg }
    515