Home | History | Annotate | Line # | Download | only in dist
man_validate.c revision 1.1.1.10
      1  1.1.1.10  joerg /*	$Vendor-Id: man_validate.c,v 1.47 2010/07/22 23:03:15 kristaps Exp $ */
      2       1.1  joerg /*
      3   1.1.1.8  joerg  * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps (at) bsd.lv>
      4       1.1  joerg  *
      5       1.1  joerg  * Permission to use, copy, modify, and distribute this software for any
      6       1.1  joerg  * purpose with or without fee is hereby granted, provided that the above
      7       1.1  joerg  * copyright notice and this permission notice appear in all copies.
      8       1.1  joerg  *
      9       1.1  joerg  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     10       1.1  joerg  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     11       1.1  joerg  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     12       1.1  joerg  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     13       1.1  joerg  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     14       1.1  joerg  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     15       1.1  joerg  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     16       1.1  joerg  */
     17   1.1.1.4  joerg #ifdef HAVE_CONFIG_H
     18   1.1.1.4  joerg #include "config.h"
     19   1.1.1.4  joerg #endif
     20   1.1.1.4  joerg 
     21       1.1  joerg #include <sys/types.h>
     22       1.1  joerg 
     23       1.1  joerg #include <assert.h>
     24       1.1  joerg #include <ctype.h>
     25       1.1  joerg #include <errno.h>
     26       1.1  joerg #include <limits.h>
     27       1.1  joerg #include <stdarg.h>
     28       1.1  joerg #include <stdlib.h>
     29  1.1.1.10  joerg #include <string.h>
     30       1.1  joerg 
     31   1.1.1.7  joerg #include "mandoc.h"
     32       1.1  joerg #include "libman.h"
     33       1.1  joerg #include "libmandoc.h"
     34       1.1  joerg 
     35   1.1.1.8  joerg #define	CHKARGS	  struct man *m, struct man_node *n
     36       1.1  joerg 
     37       1.1  joerg typedef	int	(*v_check)(CHKARGS);
     38       1.1  joerg 
     39       1.1  joerg struct	man_valid {
     40       1.1  joerg 	v_check	 *pres;
     41       1.1  joerg 	v_check	 *posts;
     42       1.1  joerg };
     43       1.1  joerg 
     44       1.1  joerg static	int	  check_bline(CHKARGS);
     45       1.1  joerg static	int	  check_eq0(CHKARGS);
     46       1.1  joerg static	int	  check_le1(CHKARGS);
     47       1.1  joerg static	int	  check_ge2(CHKARGS);
     48       1.1  joerg static	int	  check_le5(CHKARGS);
     49       1.1  joerg static	int	  check_par(CHKARGS);
     50       1.1  joerg static	int	  check_part(CHKARGS);
     51       1.1  joerg static	int	  check_root(CHKARGS);
     52       1.1  joerg static	int	  check_sec(CHKARGS);
     53       1.1  joerg static	int	  check_text(CHKARGS);
     54   1.1.1.5  joerg static	int	  check_title(CHKARGS);
     55       1.1  joerg 
     56       1.1  joerg static	v_check	  posts_eq0[] = { check_eq0, NULL };
     57   1.1.1.5  joerg static	v_check	  posts_th[] = { check_ge2, check_le5, check_title, NULL };
     58       1.1  joerg static	v_check	  posts_par[] = { check_par, NULL };
     59       1.1  joerg static	v_check	  posts_part[] = { check_part, NULL };
     60       1.1  joerg static	v_check	  posts_sec[] = { check_sec, NULL };
     61   1.1.1.5  joerg static	v_check	  posts_le1[] = { check_le1, NULL };
     62       1.1  joerg static	v_check	  pres_bline[] = { check_bline, NULL };
     63       1.1  joerg 
     64       1.1  joerg static	const struct man_valid man_valids[MAN_MAX] = {
     65   1.1.1.5  joerg 	{ NULL, posts_eq0 }, /* br */
     66   1.1.1.5  joerg 	{ pres_bline, posts_th }, /* TH */
     67       1.1  joerg 	{ pres_bline, posts_sec }, /* SH */
     68       1.1  joerg 	{ pres_bline, posts_sec }, /* SS */
     69       1.1  joerg 	{ pres_bline, posts_par }, /* TP */
     70       1.1  joerg 	{ pres_bline, posts_par }, /* LP */
     71       1.1  joerg 	{ pres_bline, posts_par }, /* PP */
     72       1.1  joerg 	{ pres_bline, posts_par }, /* P */
     73       1.1  joerg 	{ pres_bline, posts_par }, /* IP */
     74       1.1  joerg 	{ pres_bline, posts_par }, /* HP */
     75       1.1  joerg 	{ NULL, NULL }, /* SM */
     76       1.1  joerg 	{ NULL, NULL }, /* SB */
     77       1.1  joerg 	{ NULL, NULL }, /* BI */
     78       1.1  joerg 	{ NULL, NULL }, /* IB */
     79       1.1  joerg 	{ NULL, NULL }, /* BR */
     80       1.1  joerg 	{ NULL, NULL }, /* RB */
     81       1.1  joerg 	{ NULL, NULL }, /* R */
     82       1.1  joerg 	{ NULL, NULL }, /* B */
     83       1.1  joerg 	{ NULL, NULL }, /* I */
     84       1.1  joerg 	{ NULL, NULL }, /* IR */
     85       1.1  joerg 	{ NULL, NULL }, /* RI */
     86  1.1.1.10  joerg 	{ NULL, posts_eq0 }, /* na */ /* FIXME: should warn only. */
     87       1.1  joerg 	{ NULL, NULL }, /* i */
     88  1.1.1.10  joerg 	{ NULL, posts_le1 }, /* sp */ /* FIXME: should warn only. */
     89       1.1  joerg 	{ pres_bline, posts_eq0 }, /* nf */
     90       1.1  joerg 	{ pres_bline, posts_eq0 }, /* fi */
     91       1.1  joerg 	{ NULL, NULL }, /* r */
     92       1.1  joerg 	{ NULL, NULL }, /* RE */
     93       1.1  joerg 	{ NULL, posts_part }, /* RS */
     94       1.1  joerg 	{ NULL, NULL }, /* DT */
     95       1.1  joerg 	{ NULL, NULL }, /* UC */
     96   1.1.1.2  joerg 	{ NULL, NULL }, /* PD */
     97  1.1.1.10  joerg 	{ NULL, posts_le1 }, /* Sp */ /* FIXME: should warn only. */
     98  1.1.1.10  joerg 	{ pres_bline, posts_le1 }, /* Vb */ /* FIXME: should warn only. */
     99   1.1.1.5  joerg 	{ pres_bline, posts_eq0 }, /* Ve */
    100   1.1.1.7  joerg 	{ NULL, NULL }, /* AT */
    101  1.1.1.10  joerg 	{ NULL, NULL }, /* in */
    102       1.1  joerg };
    103       1.1  joerg 
    104       1.1  joerg 
    105       1.1  joerg int
    106   1.1.1.8  joerg man_valid_pre(struct man *m, struct man_node *n)
    107       1.1  joerg {
    108       1.1  joerg 	v_check		*cp;
    109       1.1  joerg 
    110       1.1  joerg 	if (MAN_TEXT == n->type)
    111       1.1  joerg 		return(1);
    112       1.1  joerg 	if (MAN_ROOT == n->type)
    113       1.1  joerg 		return(1);
    114       1.1  joerg 
    115       1.1  joerg 	if (NULL == (cp = man_valids[n->tok].pres))
    116       1.1  joerg 		return(1);
    117       1.1  joerg 	for ( ; *cp; cp++)
    118       1.1  joerg 		if ( ! (*cp)(m, n))
    119       1.1  joerg 			return(0);
    120       1.1  joerg 	return(1);
    121       1.1  joerg }
    122       1.1  joerg 
    123       1.1  joerg 
    124       1.1  joerg int
    125       1.1  joerg man_valid_post(struct man *m)
    126       1.1  joerg {
    127       1.1  joerg 	v_check		*cp;
    128       1.1  joerg 
    129       1.1  joerg 	if (MAN_VALID & m->last->flags)
    130       1.1  joerg 		return(1);
    131       1.1  joerg 	m->last->flags |= MAN_VALID;
    132       1.1  joerg 
    133       1.1  joerg 	switch (m->last->type) {
    134       1.1  joerg 	case (MAN_TEXT):
    135       1.1  joerg 		return(check_text(m, m->last));
    136       1.1  joerg 	case (MAN_ROOT):
    137       1.1  joerg 		return(check_root(m, m->last));
    138       1.1  joerg 	default:
    139       1.1  joerg 		break;
    140       1.1  joerg 	}
    141       1.1  joerg 
    142       1.1  joerg 	if (NULL == (cp = man_valids[m->last->tok].posts))
    143       1.1  joerg 		return(1);
    144       1.1  joerg 	for ( ; *cp; cp++)
    145       1.1  joerg 		if ( ! (*cp)(m, m->last))
    146       1.1  joerg 			return(0);
    147       1.1  joerg 
    148       1.1  joerg 	return(1);
    149       1.1  joerg }
    150       1.1  joerg 
    151       1.1  joerg 
    152       1.1  joerg static int
    153       1.1  joerg check_root(CHKARGS)
    154       1.1  joerg {
    155       1.1  joerg 
    156       1.1  joerg 	if (MAN_BLINE & m->flags)
    157   1.1.1.7  joerg 		return(man_nmsg(m, n, MANDOCERR_SCOPEEXIT));
    158       1.1  joerg 	if (MAN_ELINE & m->flags)
    159   1.1.1.7  joerg 		return(man_nmsg(m, n, MANDOCERR_SCOPEEXIT));
    160       1.1  joerg 
    161       1.1  joerg 	m->flags &= ~MAN_BLINE;
    162       1.1  joerg 	m->flags &= ~MAN_ELINE;
    163       1.1  joerg 
    164   1.1.1.7  joerg 	if (NULL == m->first->child) {
    165   1.1.1.7  joerg 		man_nmsg(m, n, MANDOCERR_NODOCBODY);
    166   1.1.1.7  joerg 		return(0);
    167   1.1.1.7  joerg 	} else if (NULL == m->meta.title) {
    168   1.1.1.7  joerg 		if ( ! man_nmsg(m, n, MANDOCERR_NOTITLE))
    169   1.1.1.6  joerg 			return(0);
    170   1.1.1.6  joerg 		/*
    171   1.1.1.6  joerg 		 * If a title hasn't been set, do so now (by
    172   1.1.1.6  joerg 		 * implication, date and section also aren't set).
    173   1.1.1.6  joerg 		 *
    174   1.1.1.6  joerg 		 * FIXME: this should be in man_action.c.
    175   1.1.1.6  joerg 		 */
    176   1.1.1.6  joerg 	        m->meta.title = mandoc_strdup("unknown");
    177   1.1.1.6  joerg 		m->meta.date = time(NULL);
    178   1.1.1.7  joerg 		m->meta.msec = mandoc_strdup("1");
    179   1.1.1.6  joerg 	}
    180       1.1  joerg 
    181       1.1  joerg 	return(1);
    182       1.1  joerg }
    183       1.1  joerg 
    184       1.1  joerg 
    185       1.1  joerg static int
    186   1.1.1.5  joerg check_title(CHKARGS)
    187   1.1.1.5  joerg {
    188   1.1.1.5  joerg 	const char	*p;
    189   1.1.1.5  joerg 
    190   1.1.1.5  joerg 	assert(n->child);
    191   1.1.1.7  joerg 	/* FIXME: is this sufficient? */
    192   1.1.1.7  joerg 	if ('\0' == *n->child->string) {
    193   1.1.1.7  joerg 		man_nmsg(m, n, MANDOCERR_SYNTARGCOUNT);
    194   1.1.1.7  joerg 		return(0);
    195   1.1.1.7  joerg 	}
    196   1.1.1.5  joerg 
    197   1.1.1.5  joerg 	for (p = n->child->string; '\0' != *p; p++)
    198   1.1.1.5  joerg 		if (isalpha((u_char)*p) && ! isupper((u_char)*p))
    199   1.1.1.7  joerg 			if ( ! man_nmsg(m, n, MANDOCERR_UPPERCASE))
    200   1.1.1.5  joerg 				return(0);
    201   1.1.1.5  joerg 
    202   1.1.1.5  joerg 	return(1);
    203   1.1.1.5  joerg }
    204   1.1.1.5  joerg 
    205   1.1.1.5  joerg 
    206   1.1.1.5  joerg static int
    207       1.1  joerg check_text(CHKARGS)
    208       1.1  joerg {
    209   1.1.1.8  joerg 	char		*p;
    210       1.1  joerg 	int		 pos, c;
    211  1.1.1.10  joerg 	size_t		 sz;
    212       1.1  joerg 
    213       1.1  joerg 	for (p = n->string, pos = n->pos + 1; *p; p++, pos++) {
    214  1.1.1.10  joerg 		sz = strcspn(p, "\t\\");
    215  1.1.1.10  joerg 		p += (int)sz;
    216  1.1.1.10  joerg 
    217  1.1.1.10  joerg 		if ('\0' == *p)
    218  1.1.1.10  joerg 			break;
    219  1.1.1.10  joerg 
    220  1.1.1.10  joerg 		pos += (int)sz;
    221   1.1.1.7  joerg 
    222  1.1.1.10  joerg 		if ('\t' == *p) {
    223  1.1.1.10  joerg 			if (MAN_LITERAL & m->flags)
    224  1.1.1.10  joerg 				continue;
    225  1.1.1.10  joerg 			if (man_pmsg(m, n->line, pos, MANDOCERR_BADTAB))
    226  1.1.1.10  joerg 				continue;
    227  1.1.1.10  joerg 			return(0);
    228       1.1  joerg 		}
    229       1.1  joerg 
    230  1.1.1.10  joerg 		/* Check the special character. */
    231   1.1.1.9  joerg 
    232  1.1.1.10  joerg 		c = mandoc_special(p);
    233  1.1.1.10  joerg 		if (c) {
    234  1.1.1.10  joerg 			p += c - 1;
    235  1.1.1.10  joerg 			pos += c - 1;
    236       1.1  joerg 			continue;
    237  1.1.1.10  joerg 		}
    238  1.1.1.10  joerg 
    239  1.1.1.10  joerg 		c = man_pmsg(m, n->line, pos, MANDOCERR_BADESCAPE);
    240  1.1.1.10  joerg 		if ( ! (MAN_IGN_ESCAPE & m->pflags) && ! c)
    241  1.1.1.10  joerg 			return(c);
    242       1.1  joerg 	}
    243       1.1  joerg 
    244       1.1  joerg 	return(1);
    245       1.1  joerg }
    246       1.1  joerg 
    247       1.1  joerg 
    248       1.1  joerg #define	INEQ_DEFINE(x, ineq, name) \
    249       1.1  joerg static int \
    250       1.1  joerg check_##name(CHKARGS) \
    251       1.1  joerg { \
    252       1.1  joerg 	if (n->nchild ineq (x)) \
    253       1.1  joerg 		return(1); \
    254   1.1.1.7  joerg 	man_vmsg(m, MANDOCERR_SYNTARGCOUNT, n->line, n->pos, \
    255   1.1.1.7  joerg 			"line arguments %s %d (have %d)", \
    256   1.1.1.7  joerg 			#ineq, (x), n->nchild); \
    257   1.1.1.7  joerg 	return(0); \
    258       1.1  joerg }
    259       1.1  joerg 
    260       1.1  joerg INEQ_DEFINE(0, ==, eq0)
    261       1.1  joerg INEQ_DEFINE(1, <=, le1)
    262       1.1  joerg INEQ_DEFINE(2, >=, ge2)
    263       1.1  joerg INEQ_DEFINE(5, <=, le5)
    264       1.1  joerg 
    265       1.1  joerg 
    266       1.1  joerg static int
    267       1.1  joerg check_sec(CHKARGS)
    268       1.1  joerg {
    269       1.1  joerg 
    270   1.1.1.7  joerg 	if (MAN_HEAD == n->type && 0 == n->nchild) {
    271   1.1.1.7  joerg 		man_nmsg(m, n, MANDOCERR_SYNTARGCOUNT);
    272   1.1.1.7  joerg 		return(0);
    273   1.1.1.7  joerg 	} else if (MAN_BODY == n->type && 0 == n->nchild)
    274   1.1.1.7  joerg 		return(man_nmsg(m, n, MANDOCERR_NOBODY));
    275   1.1.1.7  joerg 
    276       1.1  joerg 	return(1);
    277       1.1  joerg }
    278       1.1  joerg 
    279       1.1  joerg 
    280       1.1  joerg static int
    281       1.1  joerg check_part(CHKARGS)
    282       1.1  joerg {
    283       1.1  joerg 
    284       1.1  joerg 	if (MAN_BODY == n->type && 0 == n->nchild)
    285   1.1.1.7  joerg 		return(man_nmsg(m, n, MANDOCERR_NOBODY));
    286       1.1  joerg 	return(1);
    287       1.1  joerg }
    288       1.1  joerg 
    289       1.1  joerg 
    290       1.1  joerg static int
    291       1.1  joerg check_par(CHKARGS)
    292       1.1  joerg {
    293       1.1  joerg 
    294       1.1  joerg 	if (MAN_BODY == n->type)
    295       1.1  joerg 		switch (n->tok) {
    296       1.1  joerg 		case (MAN_IP):
    297       1.1  joerg 			/* FALLTHROUGH */
    298       1.1  joerg 		case (MAN_HP):
    299       1.1  joerg 			/* FALLTHROUGH */
    300       1.1  joerg 		case (MAN_TP):
    301       1.1  joerg 			/* Body-less lists are ok. */
    302       1.1  joerg 			break;
    303       1.1  joerg 		default:
    304       1.1  joerg 			if (n->nchild)
    305       1.1  joerg 				break;
    306   1.1.1.7  joerg 			return(man_nmsg(m, n, MANDOCERR_NOBODY));
    307       1.1  joerg 		}
    308       1.1  joerg 	if (MAN_HEAD == n->type)
    309       1.1  joerg 		switch (n->tok) {
    310       1.1  joerg 		case (MAN_PP):
    311       1.1  joerg 			/* FALLTHROUGH */
    312       1.1  joerg 		case (MAN_P):
    313       1.1  joerg 			/* FALLTHROUGH */
    314       1.1  joerg 		case (MAN_LP):
    315       1.1  joerg 			if (0 == n->nchild)
    316       1.1  joerg 				break;
    317   1.1.1.7  joerg 			return(man_nmsg(m, n, MANDOCERR_ARGSLOST));
    318       1.1  joerg 		default:
    319       1.1  joerg 			if (n->nchild)
    320       1.1  joerg 				break;
    321   1.1.1.7  joerg 			return(man_nmsg(m, n, MANDOCERR_NOARGS));
    322       1.1  joerg 		}
    323       1.1  joerg 
    324       1.1  joerg 	return(1);
    325       1.1  joerg }
    326       1.1  joerg 
    327       1.1  joerg 
    328       1.1  joerg static int
    329       1.1  joerg check_bline(CHKARGS)
    330       1.1  joerg {
    331       1.1  joerg 
    332       1.1  joerg 	assert( ! (MAN_ELINE & m->flags));
    333   1.1.1.7  joerg 	if (MAN_BLINE & m->flags) {
    334   1.1.1.7  joerg 		man_nmsg(m, n, MANDOCERR_SYNTLINESCOPE);
    335   1.1.1.7  joerg 		return(0);
    336   1.1.1.7  joerg 	}
    337   1.1.1.5  joerg 
    338       1.1  joerg 	return(1);
    339       1.1  joerg }
    340       1.1  joerg 
    341