Annotation of mandoc/validate.c, Revision 1.16
1.16 ! kristaps 1: /* $Id: validate.c,v 1.15 2009/01/03 22:10:22 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 */
1.15 kristaps 79: { want_ge1, args_sh, NULL, NULL }, /* Sh */ /* FIXME: preceding Pp. */
80: { want_ge1, NULL, NULL, NULL }, /* Ss */ /* FIXME: preceding Pp. */
1.14 kristaps 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 */
1.15 kristaps 84: { want_eq0, NULL, tree_pre_display, tree_post_warnemptybody }, /* Bd */ /* FIXME: preceding Pp. */
1.14 kristaps 85: { assert_eq0, NULL, NULL, tree_post_onlybody }, /* Ed */
1.15 kristaps 86: { want_eq0, NULL, NULL, NULL }, /* Bl */ /* FIXME: preceding Pp. */
1.14 kristaps 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 */
1.15 kristaps 130: { need_le2, args_nopunct, NULL, NULL }, /* At */ /* FIXME */
1.14 kristaps 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 */
1.15 kristaps 154: { NULL, NULL, NULL, NULL }, /* Pq */ /* FIXME: ignore following Sh/Ss */
1.14 kristaps 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: if (0 != argc && 0 != sz)
326: return(mdoc_warn(mdoc, tok, pos, WARN_ARGS_EQ0));
327: return(1);
1.11 kristaps 328: }
329:
330:
331: static int
1.14 kristaps 332: args_sh(struct mdoc *mdoc, int tok, int pos,
333: int sz, const char *args[],
1.9 kristaps 334: int argc, const struct mdoc_arg *argv)
1.1 kristaps 335: {
1.9 kristaps 336: enum mdoc_sec sec;
1.2 kristaps 337:
1.9 kristaps 338: sec = mdoc_atosec((size_t)sz, args);
339: if (SEC_CUSTOM != sec && sec < mdoc->sec_lastn)
340: if ( ! mdoc_warn(mdoc, tok, pos, WARN_SEC_OO))
1.8 kristaps 341: return(0);
1.9 kristaps 342: if (SEC_BODY == mdoc->sec_last && SEC_NAME != sec)
343: return(mdoc_err(mdoc, tok, pos, ERR_SEC_NAME));
1.2 kristaps 344:
1.9 kristaps 345: return(1);
1.1 kristaps 346: }
347:
348:
1.9 kristaps 349: static int
1.11 kristaps 350: args_bool(struct mdoc *mdoc, int tok, int pos,
1.14 kristaps 351: int sz, const char *args[],
1.11 kristaps 352: int argc, const struct mdoc_arg *argv)
353: {
1.14 kristaps 354: int i;
1.11 kristaps 355:
1.14 kristaps 356: for (i = 0; i < sz; i++) {
357: if (xstrcmp(args[i], "on"))
358: continue;
359: if (xstrcmp(args[i], "off"))
360: continue;
361: return(mdoc_err(mdoc, tok, pos, ERR_SYNTAX_ARGBAD));
362: }
363: return(1);
1.11 kristaps 364: }
365:
366:
367: static int
1.14 kristaps 368: tree_pre_ref(struct mdoc *mdoc, int tok, int pos)
1.11 kristaps 369: {
370: struct mdoc_node *n;
371:
372: assert(mdoc->last);
373: for (n = mdoc->last ; n; n = n->parent) {
374: if (MDOC_BLOCK != n->type)
375: continue;
376: if (MDOC_Rs != n->data.block.tok)
377: break;
378: return(1);
379: }
380:
381: return(mdoc_err(mdoc, tok, pos, ERR_SCOPE_NOCTX));
382: }
383:
384:
385: static int
1.14 kristaps 386: args_xr(struct mdoc *mdoc, int tok, int pos,
387: int sz, const char *args[],
1.11 kristaps 388: int argc, const struct mdoc_arg *argv)
389: {
390:
391: if (1 == sz)
392: return(1);
393: if (0 == sz)
394: return(mdoc_err(mdoc, tok, pos, ERR_ARGS_GE1));
395: if (MSEC_DEFAULT == mdoc_atomsec(args[1]))
396: return(mdoc_err(mdoc, tok, pos, ERR_SYNTAX_ARGFORM));
397: return(1);
398: }
399:
400:
401: static int
1.14 kristaps 402: args_nopunct(struct mdoc *mdoc, int tok, int pos,
403: int sz, const char *args[],
1.9 kristaps 404: int argc, const struct mdoc_arg *argv)
1.1 kristaps 405: {
1.9 kristaps 406: int i;
1.1 kristaps 407:
1.9 kristaps 408: if (0 == sz)
1.8 kristaps 409: return(1);
1.6 kristaps 410:
1.9 kristaps 411: i = 0;
412: if (ATT_DEFAULT == mdoc_atoatt(args[i]))
413: i++;
414: for ( ; i < sz; i++) {
415: if ( ! mdoc_isdelim(args[i]))
416: continue;
417: return(mdoc_err(mdoc, tok, pos, ERR_SYNTAX_NOPUNCT));
1.8 kristaps 418: }
1.9 kristaps 419: return(1);
1.1 kristaps 420: }
421:
422:
1.9 kristaps 423: static int
1.14 kristaps 424: tree_pre_display(struct mdoc *mdoc, int tok, int pos)
1.1 kristaps 425: {
1.9 kristaps 426: struct mdoc_node *node;
1.8 kristaps 427:
1.9 kristaps 428: assert(mdoc->last);
1.8 kristaps 429:
1.14 kristaps 430: /* Displays may not be nested in other displays. */
431:
1.9 kristaps 432: /* LINTED */
1.11 kristaps 433: for (node = mdoc->last; node; node = node->parent) {
1.9 kristaps 434: if (node->type != MDOC_BLOCK)
435: continue;
436: if (node->data.block.tok != MDOC_Bd)
1.8 kristaps 437: continue;
438: break;
439: }
1.9 kristaps 440: if (NULL == node)
441: return(1);
442: return(mdoc_err(mdoc, tok, pos, ERR_SCOPE_NONEST));
1.8 kristaps 443: }
444:
445:
446: int
1.11 kristaps 447: mdoc_valid_pre(struct mdoc *mdoc, int tok, int pos,
1.9 kristaps 448: int argc, const struct mdoc_arg *argv)
1.8 kristaps 449: {
450:
1.14 kristaps 451: return(1);
1.1 kristaps 452: }
453:
1.11 kristaps 454:
455: int
1.16 ! kristaps 456: mdoc_valid_post(struct mdoc *mdoc, int tok, int pos)
1.11 kristaps 457: {
458:
1.14 kristaps 459: return(1);
1.11 kristaps 460: }
1.14 kristaps 461:
CVSweb