1 /* $Id: man_validate.c,v 1.1 2009/04/06 20:30:40 kristaps Exp $ */ 2 /* 3 * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@openbsd.org> 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 7 * above copyright notice and this permission notice appear in all 8 * copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 #include <sys/types.h> 20 21 #include <assert.h> 22 #include <ctype.h> 23 #include <stdarg.h> 24 #include <stdlib.h> 25 26 #include "libman.h" 27 28 /* FIXME: validate text. */ 29 30 #define POSTARGS struct man *m, const struct man_node *n 31 32 typedef int (*v_post)(POSTARGS); 33 34 struct man_valid { 35 v_post *posts; 36 }; 37 38 static int count(const struct man_node *); 39 static int check_eq0(POSTARGS); 40 static int check_ge1(POSTARGS); 41 static int check_ge2(POSTARGS); 42 static int check_le1(POSTARGS); 43 static int check_le2(POSTARGS); 44 static int check_le5(POSTARGS); 45 46 static v_post posts_le1[] = { check_le1, NULL }; 47 static v_post posts_le2[] = { check_le2, NULL }; 48 static v_post posts_ge1[] = { check_ge1, NULL }; 49 static v_post posts_eq0[] = { check_eq0, NULL }; 50 static v_post posts_ge2_le5[] = { check_ge2, check_le5, NULL }; 51 52 static const struct man_valid man_valids[MAN_MAX] = { 53 { NULL }, /* __ */ 54 { posts_ge2_le5 }, /* TH */ 55 { posts_ge1 }, /* SH */ 56 { posts_ge1 }, /* SS */ 57 { NULL }, /* TP */ 58 { posts_eq0 }, /* LP */ 59 { posts_eq0 }, /* PP */ 60 { posts_eq0 }, /* P */ 61 { posts_le2 }, /* IP */ 62 { posts_le1 }, /* HP */ 63 { NULL }, /* SM */ 64 { NULL }, /* SB */ 65 { NULL }, /* BI */ 66 { NULL }, /* IB */ 67 { NULL }, /* BR */ 68 { NULL }, /* RB */ 69 { NULL }, /* R */ 70 { NULL }, /* B */ 71 { NULL }, /* I */ 72 { NULL }, /* IR */ 73 { NULL }, /* RI */ 74 { posts_eq0 }, /* br */ 75 { posts_eq0 }, /* na */ 76 { NULL }, /* i */ 77 }; 78 79 80 int 81 man_valid_post(struct man *m) 82 { 83 v_post *cp; 84 85 if (MAN_VALID & m->last->flags) 86 return(1); 87 m->last->flags |= MAN_VALID; 88 89 switch (m->last->type) { 90 case (MAN_TEXT): 91 /* FALLTHROUGH */ 92 case (MAN_ROOT): 93 return(1); 94 default: 95 break; 96 } 97 98 if (NULL == (cp = man_valids[m->last->tok].posts)) 99 return(1); 100 for ( ; *cp; cp++) 101 if ( ! (*cp)(m, m->last)) 102 return(0); 103 104 return(1); 105 } 106 107 108 static inline int 109 count(const struct man_node *n) 110 { 111 int i; 112 113 for (i = 0; n; n = n->next, i++) 114 /* Loop. */ ; 115 return(i); 116 } 117 118 119 #define INEQ_DEFINE(x, ineq, name) \ 120 static int \ 121 check_##name(POSTARGS) \ 122 { \ 123 int c; \ 124 if ((c = count(n->child)) ineq (x)) \ 125 return(1); \ 126 return(man_verr(m, n->line, n->pos, \ 127 "expected line arguments %s %d, have %d", \ 128 #ineq, (x), c)); \ 129 } 130 131 INEQ_DEFINE(0, ==, eq0) 132 INEQ_DEFINE(1, >=, ge1) 133 INEQ_DEFINE(2, >=, ge2) 134 INEQ_DEFINE(1, <=, le1) 135 INEQ_DEFINE(2, <=, le2) 136 INEQ_DEFINE(5, <=, le5) 137 138