Annotation of mandoc/validate.c, Revision 1.14
1.14 ! kristaps 1: /* $Id: validate.c,v 1.13 2009/01/02 14:06:16 kristaps Exp $ */
1.1 kristaps 2: /*
3: * Copyright (c) 2008 Kristaps Dzonsons <kristaps@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
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 <assert.h>
1.8 kristaps 20: #include <stdlib.h>
1.1 kristaps 21:
22: #include "private.h"
23:
1.11 kristaps 24: /* FIXME: `.St' can only have one argument set. */
1.2 kristaps 25:
1.11 kristaps 26: typedef int (*v_args_sz)(struct mdoc *, int, int, int);
1.14 ! kristaps 27: typedef int (*v_args)(struct mdoc *, int, int,
! 28: int, const char *[],
! 29: int, const struct mdoc_arg *);
! 30: typedef int (*v_tree)(struct mdoc *, int, int);
! 31:
! 32:
! 33: struct valids {
! 34: v_args_sz sz;
! 35: v_args args;
! 36: v_tree tree_pre;
! 37: v_tree tree_post;
! 38: };
1.1 kristaps 39:
1.11 kristaps 40:
41: static int assert_eq0(struct mdoc *, int, int, int);
42: static int assert_le1(struct mdoc *, int, int, int);
43: static int need_eq0(struct mdoc *, int, int, int);
44: static int need_eq1(struct mdoc *, int, int, int);
45: static int need_ge1(struct mdoc *, int, int, int);
46: static int need_le2(struct mdoc *, int, int, int);
47: static int want_eq0(struct mdoc *, int, int, int);
48: static int want_ge1(struct mdoc *, int, int, int);
49:
1.14 ! kristaps 50: static int tree_pre_ref(struct mdoc *, int, int);
! 51: static int tree_pre_display(struct mdoc *, int, int);
1.9 kristaps 52:
1.14 ! kristaps 53: static int tree_post_onlyhead(struct mdoc *, int, int);
! 54: static int tree_post_onlybody(struct mdoc *, int, int);
! 55: static int tree_post_warnemptybody(struct mdoc *, int, int);
! 56:
! 57: static int args_bool(struct mdoc *, int, int,
! 58: int, const char *[],
! 59: int, const struct mdoc_arg *);
! 60: static int args_sh(struct mdoc *, int, int,
! 61: int, const char *[],
! 62: int, const struct mdoc_arg *);
! 63: static int args_an(struct mdoc *, int, int,
! 64: int, const char *[],
! 65: int, const struct mdoc_arg *);
! 66: static int args_nopunct(struct mdoc *, int, int,
! 67: int, const char *[],
! 68: int, const struct mdoc_arg *);
! 69: static int args_xr(struct mdoc *, int, int,
! 70: int, const char *[],
! 71: int, const struct mdoc_arg *);
1.9 kristaps 72:
1.12 kristaps 73:
1.9 kristaps 74: const struct valids mdoc_valids[MDOC_MAX] = {
1.14 ! kristaps 75: { NULL, NULL, NULL, NULL }, /* \" */
! 76: { NULL, NULL, NULL, NULL }, /* Dd */ /* TODO */
! 77: { NULL, NULL, NULL, NULL }, /* Dt */ /* TODO */
! 78: { NULL, NULL, NULL, NULL }, /* Os */ /* TODO */
! 79: { want_ge1, args_sh, NULL, NULL }, /* Sh */
! 80: { want_ge1, NULL, NULL, NULL }, /* Ss */
! 81: { want_eq0, NULL, NULL, NULL }, /* Pp */
! 82: { assert_eq0, NULL, tree_pre_display, tree_post_onlyhead }, /* D1 */
! 83: { assert_eq0, NULL, tree_pre_display, tree_post_onlyhead }, /* Dl */
! 84: { want_eq0, NULL, tree_pre_display, tree_post_warnemptybody }, /* Bd */
! 85: { assert_eq0, NULL, NULL, tree_post_onlybody }, /* Ed */
! 86: { want_eq0, NULL, NULL, NULL }, /* Bl */
! 87: { assert_eq0, NULL, NULL, tree_post_onlybody }, /* El */
! 88: { NULL, NULL, NULL, NULL }, /* It */
! 89: { need_ge1, NULL, NULL, NULL }, /* Ad */
! 90: { NULL, args_an, NULL, NULL }, /* An */
! 91: { NULL, NULL, NULL, NULL }, /* Ar */
! 92: { need_ge1, NULL, NULL, NULL }, /* Cd */
! 93: { NULL, NULL, NULL, NULL }, /* Cm */
! 94: { need_ge1, NULL, NULL, NULL }, /* Dv */
! 95: { need_ge1, NULL, NULL, NULL }, /* Er */
! 96: { need_ge1, NULL, NULL, NULL }, /* Ev */
! 97: { NULL, NULL, NULL, NULL }, /* Ex */
! 98: { need_ge1, NULL, NULL, NULL }, /* Fa */
! 99: { NULL, NULL, NULL, NULL }, /* Fd */
! 100: { NULL, NULL, NULL, NULL }, /* Fl */
! 101: { need_ge1, NULL, NULL, NULL }, /* Fn */
! 102: { want_ge1, NULL, NULL, NULL }, /* Ft */
! 103: { need_ge1, NULL, NULL, NULL }, /* Ic */
! 104: { need_eq1, NULL, NULL, NULL }, /* In */
! 105: { want_ge1, NULL, NULL, NULL }, /* Li */
! 106: { want_ge1, NULL, NULL, NULL }, /* Nd */
! 107: { NULL, NULL, NULL, NULL }, /* Nm */
! 108: { NULL, NULL, NULL, NULL }, /* Op */
! 109: { NULL, NULL, NULL, NULL }, /* Ot */
! 110: { want_ge1, NULL, NULL, NULL }, /* Pa */
! 111: { NULL, NULL, NULL, NULL }, /* Rv */
! 112: { NULL, NULL, NULL, NULL }, /* St */
! 113: { need_ge1, NULL, NULL, NULL }, /* Va */
! 114: { need_ge1, NULL, NULL, NULL }, /* Vt */
! 115: { need_le2, args_xr, NULL, NULL }, /* Xr */
! 116: { need_ge1, NULL, tree_pre_ref, NULL }, /* %A */
! 117: { need_ge1, NULL, tree_pre_ref, NULL }, /* %B */
! 118: { need_ge1, NULL, tree_pre_ref, NULL }, /* %D */
! 119: { need_ge1, NULL, tree_pre_ref, NULL }, /* %I */
! 120: { need_ge1, NULL, tree_pre_ref, NULL }, /* %J */
! 121: { need_ge1, NULL, tree_pre_ref, NULL }, /* %N */
! 122: { need_ge1, NULL, tree_pre_ref, NULL }, /* %O */
! 123: { need_ge1, NULL, tree_pre_ref, NULL }, /* %P */
! 124: { need_ge1, NULL, tree_pre_ref, NULL }, /* %R */
! 125: { need_ge1, NULL, tree_pre_ref, NULL }, /* %T */
! 126: { need_ge1, NULL, tree_pre_ref, NULL }, /* %V */
! 127: { NULL, NULL, NULL, NULL }, /* Ac */
! 128: { NULL, NULL, NULL, NULL }, /* Ao */
! 129: { NULL, NULL, NULL, NULL }, /* Aq */
! 130: { need_le2, args_nopunct, NULL, NULL }, /* At */
! 131: { NULL, NULL, NULL, NULL }, /* Bc */
! 132: { NULL, NULL, NULL, NULL }, /* Bf */
! 133: { NULL, NULL, NULL, NULL }, /* Bo */
! 134: { NULL, NULL, NULL, NULL }, /* Bq */
! 135: { assert_le1, NULL, NULL, NULL }, /* Bsx */
! 136: { assert_le1, NULL, NULL, NULL }, /* Bx */
! 137: { need_eq1, args_bool, NULL, NULL }, /* Db */
! 138: { NULL, NULL, NULL, NULL }, /* Dc */
! 139: { NULL, NULL, NULL, NULL }, /* Do */
! 140: { NULL, NULL, NULL, NULL }, /* Dq */
! 141: { NULL, NULL, NULL, NULL }, /* Ec */
! 142: { NULL, NULL, NULL, NULL }, /* Ef */ /* -symbolic, etc. */
! 143: { need_ge1, NULL, NULL, NULL }, /* Em */
! 144: { NULL, NULL, NULL, NULL }, /* Eo */
! 145: { assert_le1, NULL, NULL, NULL }, /* Fx */
! 146: { want_ge1, NULL, NULL, NULL }, /* Ms */
! 147: { NULL, NULL, NULL, NULL }, /* No */
! 148: { NULL, NULL, NULL, NULL }, /* Ns */
! 149: { assert_le1, NULL, NULL, NULL }, /* Nx */
! 150: { assert_le1, NULL, NULL, NULL }, /* Ox */
! 151: { NULL, NULL, NULL, NULL }, /* Pc */
! 152: { NULL, NULL, NULL, NULL }, /* Pf */ /* 2 or more arguments */
! 153: { NULL, NULL, NULL, NULL }, /* Po */
! 154: { NULL, NULL, NULL, NULL }, /* Pq */
! 155: { NULL, NULL, NULL, NULL }, /* Qc */
! 156: { NULL, NULL, NULL, NULL }, /* Ql */
! 157: { NULL, NULL, NULL, NULL }, /* Qo */
! 158: { NULL, NULL, NULL, NULL }, /* Qq */
! 159: { NULL, NULL, NULL, NULL }, /* Re */
! 160: { NULL, NULL, NULL, NULL }, /* Rs */
! 161: { NULL, NULL, NULL, NULL }, /* Sc */
! 162: { NULL, NULL, NULL, NULL }, /* So */
! 163: { NULL, NULL, NULL, NULL }, /* Sq */
! 164: { need_eq1, args_bool, NULL, NULL }, /* Sm */
! 165: { need_ge1, NULL, NULL, NULL }, /* Sx */
! 166: { need_ge1, NULL, NULL, NULL }, /* Sy */
! 167: { want_ge1, NULL, NULL, NULL }, /* Tn */
! 168: { assert_eq0, NULL, NULL, NULL }, /* Ux */
! 169: { NULL, NULL, NULL, NULL }, /* Xc */
! 170: { NULL, NULL, NULL, NULL }, /* Xo */
! 171: { NULL, NULL, NULL, NULL }, /* Fo */
! 172: { NULL, NULL, NULL, NULL }, /* Fc */
! 173: { NULL, NULL, NULL, NULL }, /* Oo */
! 174: { NULL, NULL, NULL, NULL }, /* Oc */
! 175: { NULL, NULL, NULL, NULL }, /* Bk */
! 176: { NULL, NULL, NULL, NULL }, /* Ek */
! 177: { need_eq0, NULL, NULL, NULL }, /* Bt */
! 178: { need_eq1, NULL, NULL, NULL }, /* Hf */
! 179: { NULL, NULL, NULL, NULL }, /* Fr */
! 180: { need_eq0, NULL, NULL, NULL }, /* Ud */
1.9 kristaps 181: };
1.6 kristaps 182:
183:
184: static int
1.9 kristaps 185: need_le2(struct mdoc *mdoc, int tok, int pos, int sz)
1.6 kristaps 186: {
1.11 kristaps 187: if (sz <= 2)
1.8 kristaps 188: return(1);
1.9 kristaps 189: return(mdoc_err(mdoc, tok, pos, ERR_ARGS_LE2));
1.6 kristaps 190: }
191:
192:
193: static int
1.9 kristaps 194: want_ge1(struct mdoc *mdoc, int tok, int pos, int sz)
1.6 kristaps 195: {
1.9 kristaps 196: if (sz > 0)
1.8 kristaps 197: return(1);
1.9 kristaps 198: return(mdoc_warn(mdoc, tok, pos, WARN_ARGS_GE1));
1.6 kristaps 199: }
1.1 kristaps 200:
201:
202: static int
1.9 kristaps 203: want_eq0(struct mdoc *mdoc, int tok, int pos, int sz)
1.1 kristaps 204: {
1.9 kristaps 205: if (sz == 0)
206: return(1);
207: return(mdoc_warn(mdoc, tok, pos, WARN_ARGS_EQ0));
1.1 kristaps 208: }
209:
210:
211: static int
1.9 kristaps 212: need_eq0(struct mdoc *mdoc, int tok, int pos, int sz)
1.1 kristaps 213: {
1.9 kristaps 214: if (sz == 0)
215: return(1);
216: return(mdoc_err(mdoc, tok, pos, ERR_ARGS_EQ0));
1.1 kristaps 217: }
218:
219:
220: static int
1.9 kristaps 221: assert_le1(struct mdoc *mdoc, int tok, int pos, int sz)
1.1 kristaps 222: {
1.8 kristaps 223:
1.9 kristaps 224: assert(sz <= 1);
1.8 kristaps 225: return(1);
226: }
1.1 kristaps 227:
228:
1.8 kristaps 229: static int
1.9 kristaps 230: assert_eq0(struct mdoc *mdoc, int tok, int pos, int sz)
1.8 kristaps 231: {
1.1 kristaps 232:
1.9 kristaps 233: assert(sz == 0);
1.1 kristaps 234: return(1);
235: }
236:
237:
1.8 kristaps 238: static int
1.9 kristaps 239: need_eq1(struct mdoc *mdoc, int tok, int pos, int sz)
1.1 kristaps 240: {
1.9 kristaps 241: if (sz == 1)
242: return(1);
243: return(mdoc_err(mdoc, tok, pos, ERR_ARGS_EQ1));
1.1 kristaps 244: }
245:
246:
1.9 kristaps 247: static int
248: need_ge1(struct mdoc *mdoc, int tok, int pos, int sz)
1.1 kristaps 249: {
1.9 kristaps 250: if (sz > 0)
251: return(1);
252: return(mdoc_err(mdoc, tok, pos, ERR_ARGS_GE1));
1.1 kristaps 253: }
254:
255:
1.9 kristaps 256: static int
1.14 ! kristaps 257: tree_post_onlybody(struct mdoc *mdoc, int tok, int pos)
1.12 kristaps 258: {
1.14 ! kristaps 259: struct mdoc_node *n;
! 260:
! 261: assert(mdoc->last);
! 262: n = mdoc->last;
! 263:
! 264: assert(MDOC_BLOCK == n->type);
! 265: assert(n->child);
! 266:
! 267: if (MDOC_BODY == n->child->type) {
! 268: if (n->child->child)
! 269: return(1);
! 270: return(mdoc_err(mdoc, tok, pos, ERR_SYNTAX_EMPTYBODY));
! 271: }
! 272:
! 273: return(mdoc_err(mdoc, tok, pos, ERR_SYNTAX_CHILDBODY));
! 274: }
! 275:
! 276:
! 277: static int
! 278: tree_post_warnemptybody(struct mdoc *mdoc, int tok, int pos)
! 279: {
! 280: struct mdoc_node *n;
! 281:
! 282: assert(mdoc->last);
! 283: n = mdoc->last;
! 284:
! 285: assert(MDOC_BLOCK == n->type);
! 286: assert(n->child);
! 287:
! 288: for (n = n->child; n; n = n->next)
! 289: if (MDOC_BODY == n->type)
! 290: break;
1.12 kristaps 291:
1.14 ! kristaps 292: if (n && n->child)
! 293: return(1);
! 294: return(mdoc_warn(mdoc, tok, pos, WARN_SYNTAX_EMPTYBODY));
1.12 kristaps 295: }
296:
297:
298: static int
1.14 ! kristaps 299: tree_post_onlyhead(struct mdoc *mdoc, int tok, int pos)
1.11 kristaps 300: {
301: struct mdoc_node *n;
302:
303: assert(mdoc->last);
304: n = mdoc->last;
305:
306: assert(MDOC_BLOCK == n->type);
307: assert(n->child);
308:
309: n = n->child;
310:
311: if (MDOC_HEAD != n->type)
1.14 ! kristaps 312: return(mdoc_err(mdoc, tok, pos, ERR_SYNTAX_CHILDHEAD));
1.11 kristaps 313: if (n->child)
314: return(1);
1.14 ! kristaps 315: return(mdoc_err(mdoc, tok, pos, ERR_SYNTAX_EMPTYHEAD));
! 316: }
! 317:
! 318:
! 319: static int
! 320: args_an(struct mdoc *mdoc, int tok, int pos,
! 321: int sz, const char *args[],
! 322: int argc, const struct mdoc_arg *argv)
! 323: {
! 324:
! 325: printf("argc=%d, sz=%d\n", argc, sz);
! 326: if (0 != argc && 0 != sz)
! 327: return(mdoc_warn(mdoc, tok, pos, WARN_ARGS_EQ0));
! 328: return(1);
1.11 kristaps 329: }
330:
331:
332: static int
1.14 ! kristaps 333: args_sh(struct mdoc *mdoc, int tok, int pos,
! 334: int sz, const char *args[],
1.9 kristaps 335: int argc, const struct mdoc_arg *argv)
1.1 kristaps 336: {
1.9 kristaps 337: enum mdoc_sec sec;
1.2 kristaps 338:
1.9 kristaps 339: sec = mdoc_atosec((size_t)sz, args);
340: if (SEC_CUSTOM != sec && sec < mdoc->sec_lastn)
341: if ( ! mdoc_warn(mdoc, tok, pos, WARN_SEC_OO))
1.8 kristaps 342: return(0);
1.9 kristaps 343: if (SEC_BODY == mdoc->sec_last && SEC_NAME != sec)
344: return(mdoc_err(mdoc, tok, pos, ERR_SEC_NAME));
1.2 kristaps 345:
1.9 kristaps 346: return(1);
1.1 kristaps 347: }
348:
349:
1.9 kristaps 350: static int
1.11 kristaps 351: args_bool(struct mdoc *mdoc, int tok, int pos,
1.14 ! kristaps 352: int sz, const char *args[],
1.11 kristaps 353: int argc, const struct mdoc_arg *argv)
354: {
1.14 ! kristaps 355: int i;
1.11 kristaps 356:
1.14 ! kristaps 357: for (i = 0; i < sz; i++) {
! 358: if (xstrcmp(args[i], "on"))
! 359: continue;
! 360: if (xstrcmp(args[i], "off"))
! 361: continue;
! 362: return(mdoc_err(mdoc, tok, pos, ERR_SYNTAX_ARGBAD));
! 363: }
! 364: return(1);
1.11 kristaps 365: }
366:
367:
368: static int
1.14 ! kristaps 369: tree_pre_ref(struct mdoc *mdoc, int tok, int pos)
1.11 kristaps 370: {
371: struct mdoc_node *n;
372:
373: assert(mdoc->last);
374: for (n = mdoc->last ; n; n = n->parent) {
375: if (MDOC_BLOCK != n->type)
376: continue;
377: if (MDOC_Rs != n->data.block.tok)
378: break;
379: return(1);
380: }
381:
382: return(mdoc_err(mdoc, tok, pos, ERR_SCOPE_NOCTX));
383: }
384:
385:
386: static int
1.14 ! kristaps 387: args_xr(struct mdoc *mdoc, int tok, int pos,
! 388: int sz, const char *args[],
1.11 kristaps 389: int argc, const struct mdoc_arg *argv)
390: {
391:
392: if (1 == sz)
393: return(1);
394: if (0 == sz)
395: return(mdoc_err(mdoc, tok, pos, ERR_ARGS_GE1));
396: if (MSEC_DEFAULT == mdoc_atomsec(args[1]))
397: return(mdoc_err(mdoc, tok, pos, ERR_SYNTAX_ARGFORM));
398: return(1);
399: }
400:
401:
402: static int
1.14 ! kristaps 403: args_nopunct(struct mdoc *mdoc, int tok, int pos,
! 404: int sz, const char *args[],
1.9 kristaps 405: int argc, const struct mdoc_arg *argv)
1.1 kristaps 406: {
1.9 kristaps 407: int i;
1.1 kristaps 408:
1.9 kristaps 409: if (0 == sz)
1.8 kristaps 410: return(1);
1.6 kristaps 411:
1.9 kristaps 412: i = 0;
413: if (ATT_DEFAULT == mdoc_atoatt(args[i]))
414: i++;
415: for ( ; i < sz; i++) {
416: if ( ! mdoc_isdelim(args[i]))
417: continue;
418: return(mdoc_err(mdoc, tok, pos, ERR_SYNTAX_NOPUNCT));
1.8 kristaps 419: }
1.9 kristaps 420: return(1);
1.1 kristaps 421: }
422:
423:
1.9 kristaps 424: static int
1.14 ! kristaps 425: tree_pre_display(struct mdoc *mdoc, int tok, int pos)
1.1 kristaps 426: {
1.9 kristaps 427: struct mdoc_node *node;
1.8 kristaps 428:
1.9 kristaps 429: assert(mdoc->last);
1.8 kristaps 430:
1.14 ! kristaps 431: /* Displays may not be nested in other displays. */
! 432:
1.9 kristaps 433: /* LINTED */
1.11 kristaps 434: for (node = mdoc->last; node; node = node->parent) {
1.9 kristaps 435: if (node->type != MDOC_BLOCK)
436: continue;
437: if (node->data.block.tok != MDOC_Bd)
1.8 kristaps 438: continue;
439: break;
440: }
1.9 kristaps 441: if (NULL == node)
442: return(1);
443: return(mdoc_err(mdoc, tok, pos, ERR_SCOPE_NONEST));
1.8 kristaps 444: }
445:
446:
447: int
1.11 kristaps 448: mdoc_valid_pre(struct mdoc *mdoc, int tok, int pos,
1.9 kristaps 449: int sz, const char *args[],
450: int argc, const struct mdoc_arg *argv)
1.8 kristaps 451: {
452:
1.9 kristaps 453: assert(tok < MDOC_MAX);
454: if (mdoc_valids[tok].sz)
455: if ( ! (*mdoc_valids[tok].sz)(mdoc, tok, pos, sz))
1.5 kristaps 456: return(0);
1.14 ! kristaps 457: if (mdoc_valids[tok].args)
! 458: if ( ! (*mdoc_valids[tok].args)(mdoc, tok, pos,
! 459: sz, args, argc, argv))
! 460: return(0);
! 461: if (mdoc_valids[tok].tree_pre)
! 462: if ( ! (*mdoc_valids[tok].tree_pre)(mdoc, tok, pos))
! 463: return(0);
! 464: return(1);
1.1 kristaps 465: }
466:
1.11 kristaps 467:
468: int
469: mdoc_valid_post(struct mdoc *mdoc, int tok, int pos)
470: {
471:
1.14 ! kristaps 472: if (mdoc_valids[tok].tree_post)
! 473: return((*mdoc_valids[tok].tree_post)(mdoc, tok, pos));
! 474: return(1);
1.11 kristaps 475: }
1.14 ! kristaps 476:
CVSweb