Home | History | Annotate | Line # | Download | only in dist
man_validate.c revision 1.1.1.4
      1 /*	$Vendor-Id: man_validate.c,v 1.28 2010/01/01 17:14:28 kristaps Exp $ */
      2 /*
      3  * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps (at) kth.se>
      4  *
      5  * Permission to use, copy, modify, and distribute this software for any
      6  * purpose with or without fee is hereby granted, provided that the above
      7  * copyright notice and this permission notice appear in all copies.
      8  *
      9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     16  */
     17 #ifdef HAVE_CONFIG_H
     18 #include "config.h"
     19 #endif
     20 
     21 #include <sys/types.h>
     22 
     23 #include <assert.h>
     24 #include <ctype.h>
     25 #include <errno.h>
     26 #include <limits.h>
     27 #include <stdarg.h>
     28 #include <stdlib.h>
     29 
     30 #include "libman.h"
     31 #include "libmandoc.h"
     32 
     33 #define	CHKARGS	  struct man *m, const struct man_node *n
     34 
     35 typedef	int	(*v_check)(CHKARGS);
     36 
     37 struct	man_valid {
     38 	v_check	 *pres;
     39 	v_check	 *posts;
     40 };
     41 
     42 static	int	  check_bline(CHKARGS);
     43 static	int	  check_eq0(CHKARGS);
     44 static	int	  check_le1(CHKARGS);
     45 static	int	  check_ge2(CHKARGS);
     46 static	int	  check_le5(CHKARGS);
     47 static	int	  check_par(CHKARGS);
     48 static	int	  check_part(CHKARGS);
     49 static	int	  check_root(CHKARGS);
     50 static	int	  check_sec(CHKARGS);
     51 static	int	  check_text(CHKARGS);
     52 
     53 static	v_check	  posts_eq0[] = { check_eq0, NULL };
     54 static	v_check	  posts_ge2_le5[] = { check_ge2, check_le5, NULL };
     55 static	v_check	  posts_par[] = { check_par, NULL };
     56 static	v_check	  posts_part[] = { check_part, NULL };
     57 static	v_check	  posts_sec[] = { check_sec, NULL };
     58 static	v_check	  posts_sp[] = { check_le1, NULL };
     59 static	v_check	  pres_bline[] = { check_bline, NULL };
     60 
     61 static	const struct man_valid man_valids[MAN_MAX] = {
     62 	{ pres_bline, posts_eq0 }, /* br */
     63 	{ pres_bline, posts_ge2_le5 }, /* TH */ /* FIXME: make sure capitalised. */
     64 	{ pres_bline, posts_sec }, /* SH */
     65 	{ pres_bline, posts_sec }, /* SS */
     66 	{ pres_bline, posts_par }, /* TP */
     67 	{ pres_bline, posts_par }, /* LP */
     68 	{ pres_bline, posts_par }, /* PP */
     69 	{ pres_bline, posts_par }, /* P */
     70 	{ pres_bline, posts_par }, /* IP */
     71 	{ pres_bline, posts_par }, /* HP */
     72 	{ NULL, NULL }, /* SM */
     73 	{ NULL, NULL }, /* SB */
     74 	{ NULL, NULL }, /* BI */
     75 	{ NULL, NULL }, /* IB */
     76 	{ NULL, NULL }, /* BR */
     77 	{ NULL, NULL }, /* RB */
     78 	{ NULL, NULL }, /* R */
     79 	{ NULL, NULL }, /* B */
     80 	{ NULL, NULL }, /* I */
     81 	{ NULL, NULL }, /* IR */
     82 	{ NULL, NULL }, /* RI */
     83 	{ pres_bline, posts_eq0 }, /* na */
     84 	{ NULL, NULL }, /* i */
     85 	{ pres_bline, posts_sp }, /* sp */
     86 	{ pres_bline, posts_eq0 }, /* nf */
     87 	{ pres_bline, posts_eq0 }, /* fi */
     88 	{ NULL, NULL }, /* r */
     89 	{ NULL, NULL }, /* RE */
     90 	{ NULL, posts_part }, /* RS */
     91 	{ NULL, NULL }, /* DT */
     92 	{ NULL, NULL }, /* UC */
     93 	{ NULL, NULL }, /* PD */
     94 };
     95 
     96 
     97 int
     98 man_valid_pre(struct man *m, const struct man_node *n)
     99 {
    100 	v_check		*cp;
    101 
    102 	if (MAN_TEXT == n->type)
    103 		return(1);
    104 	if (MAN_ROOT == n->type)
    105 		return(1);
    106 
    107 	if (NULL == (cp = man_valids[n->tok].pres))
    108 		return(1);
    109 	for ( ; *cp; cp++)
    110 		if ( ! (*cp)(m, n))
    111 			return(0);
    112 	return(1);
    113 }
    114 
    115 
    116 int
    117 man_valid_post(struct man *m)
    118 {
    119 	v_check		*cp;
    120 
    121 	if (MAN_VALID & m->last->flags)
    122 		return(1);
    123 	m->last->flags |= MAN_VALID;
    124 
    125 	switch (m->last->type) {
    126 	case (MAN_TEXT):
    127 		return(check_text(m, m->last));
    128 	case (MAN_ROOT):
    129 		return(check_root(m, m->last));
    130 	default:
    131 		break;
    132 	}
    133 
    134 	if (NULL == (cp = man_valids[m->last->tok].posts))
    135 		return(1);
    136 	for ( ; *cp; cp++)
    137 		if ( ! (*cp)(m, m->last))
    138 			return(0);
    139 
    140 	return(1);
    141 }
    142 
    143 
    144 static int
    145 check_root(CHKARGS)
    146 {
    147 
    148 	if (MAN_BLINE & m->flags)
    149 		return(man_nwarn(m, n, WEXITSCOPE));
    150 	if (MAN_ELINE & m->flags)
    151 		return(man_nwarn(m, n, WEXITSCOPE));
    152 
    153 	m->flags &= ~MAN_BLINE;
    154 	m->flags &= ~MAN_ELINE;
    155 
    156 	if (NULL == m->first->child)
    157 		return(man_nerr(m, n, WNODATA));
    158 	if (NULL == m->meta.title)
    159 		return(man_nerr(m, n, WNOTITLE));
    160 
    161 	return(1);
    162 }
    163 
    164 
    165 static int
    166 check_text(CHKARGS)
    167 {
    168 	const char	*p;
    169 	int		 pos, c;
    170 
    171 	assert(n->string);
    172 
    173 	for (p = n->string, pos = n->pos + 1; *p; p++, pos++) {
    174 		if ('\\' == *p) {
    175 			c = mandoc_special(p);
    176 			if (c) {
    177 				p += c - 1;
    178 				pos += c - 1;
    179 				continue;
    180 			}
    181 			if ( ! (MAN_IGN_ESCAPE & m->pflags))
    182 				return(man_perr(m, n->line, pos, WESCAPE));
    183 			if ( ! man_pwarn(m, n->line, pos, WESCAPE))
    184 				return(0);
    185 			continue;
    186 		}
    187 
    188 		if ('\t' == *p || isprint((u_char)*p))
    189 			continue;
    190 
    191 		if (MAN_IGN_CHARS & m->pflags)
    192 			return(man_pwarn(m, n->line, pos, WNPRINT));
    193 		return(man_perr(m, n->line, pos, WNPRINT));
    194 	}
    195 
    196 	return(1);
    197 }
    198 
    199 
    200 #define	INEQ_DEFINE(x, ineq, name) \
    201 static int \
    202 check_##name(CHKARGS) \
    203 { \
    204 	if (n->nchild ineq (x)) \
    205 		return(1); \
    206 	return(man_verr(m, n->line, n->pos, \
    207 			"expected line arguments %s %d, have %d", \
    208 			#ineq, (x), n->nchild)); \
    209 }
    210 
    211 INEQ_DEFINE(0, ==, eq0)
    212 INEQ_DEFINE(1, <=, le1)
    213 INEQ_DEFINE(2, >=, ge2)
    214 INEQ_DEFINE(5, <=, le5)
    215 
    216 
    217 static int
    218 check_sec(CHKARGS)
    219 {
    220 
    221 	if (MAN_BODY == n->type && 0 == n->nchild)
    222 		return(man_nwarn(m, n, WBODYARGS));
    223 	if (MAN_HEAD == n->type && 0 == n->nchild)
    224 		return(man_nerr(m, n, WHEADARGS));
    225 	return(1);
    226 }
    227 
    228 
    229 static int
    230 check_part(CHKARGS)
    231 {
    232 
    233 	if (MAN_BODY == n->type && 0 == n->nchild)
    234 		return(man_nwarn(m, n, WBODYARGS));
    235 	return(1);
    236 }
    237 
    238 
    239 static int
    240 check_par(CHKARGS)
    241 {
    242 
    243 	if (MAN_BODY == n->type)
    244 		switch (n->tok) {
    245 		case (MAN_IP):
    246 			/* FALLTHROUGH */
    247 		case (MAN_HP):
    248 			/* FALLTHROUGH */
    249 		case (MAN_TP):
    250 			/* Body-less lists are ok. */
    251 			break;
    252 		default:
    253 			if (n->nchild)
    254 				break;
    255 			return(man_nwarn(m, n, WBODYARGS));
    256 		}
    257 	if (MAN_HEAD == n->type)
    258 		switch (n->tok) {
    259 		case (MAN_PP):
    260 			/* FALLTHROUGH */
    261 		case (MAN_P):
    262 			/* FALLTHROUGH */
    263 		case (MAN_LP):
    264 			if (0 == n->nchild)
    265 				break;
    266 			return(man_nwarn(m, n, WNHEADARGS));
    267 		default:
    268 			if (n->nchild)
    269 				break;
    270 			return(man_nwarn(m, n, WHEADARGS));
    271 		}
    272 
    273 	return(1);
    274 }
    275 
    276 
    277 static int
    278 check_bline(CHKARGS)
    279 {
    280 
    281 	assert( ! (MAN_ELINE & m->flags));
    282 	if (MAN_BLINE & m->flags)
    283 		return(man_nerr(m, n, WLNSCOPE));
    284 	return(1);
    285 }
    286 
    287