Annotation of mandoc/validate.c, Revision 1.24
1.24 ! kristaps 1: /* $Id: validate.c,v 1.23 2009/01/09 15:15:31 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.2 kristaps 24:
1.18 kristaps 25: typedef int (*v_pre)(struct mdoc *, struct mdoc_node *);
26: typedef int (*v_post)(struct mdoc *);
1.14 kristaps 27:
28:
29: struct valids {
1.24 ! kristaps 30: v_pre *pre;
1.17 kristaps 31: v_post *post;
1.14 kristaps 32: };
1.1 kristaps 33:
1.11 kristaps 34:
1.23 kristaps 35: static int pre_display(struct mdoc *, struct mdoc_node *);
1.24 ! kristaps 36: static int pre_bd(struct mdoc *, struct mdoc_node *);
! 37: static int pre_bl(struct mdoc *, struct mdoc_node *);
1.20 kristaps 38: static int pre_prologue(struct mdoc *, struct mdoc_node *);
39: static int pre_prologue(struct mdoc *, struct mdoc_node *);
40: static int pre_prologue(struct mdoc *, struct mdoc_node *);
1.24 ! kristaps 41:
! 42: static int headchild_err_ge1(struct mdoc *);
! 43: static int headchild_err_eq0(struct mdoc *);
! 44: static int elemchild_err_ge1(struct mdoc *);
! 45: static int elemchild_warn_eq0(struct mdoc *);
! 46: static int bodychild_warn_ge1(struct mdoc *);
1.21 kristaps 47: static int post_sh(struct mdoc *);
1.24 ! kristaps 48: static int post_bl(struct mdoc *);
1.17 kristaps 49:
1.24 ! kristaps 50: static v_pre pres_prologue[] = { pre_prologue, NULL };
! 51: static v_pre pres_d1[] = { pre_display, NULL };
! 52: static v_pre pres_bd[] = { pre_display, pre_bd, NULL };
! 53: static v_pre pres_bl[] = { pre_bl, NULL };
! 54: static v_post posts_bd[] = { headchild_err_eq0,
! 55: bodychild_warn_ge1, NULL };
! 56:
! 57: static v_post posts_sh[] = { headchild_err_ge1,
! 58: bodychild_warn_ge1, post_sh, NULL };
! 59: static v_post posts_bl[] = { headchild_err_eq0,
! 60: bodychild_warn_ge1, post_bl, NULL };
! 61: static v_post posts_ss[] = { headchild_err_ge1, NULL };
! 62: static v_post posts_pp[] = { elemchild_warn_eq0, NULL };
! 63: static v_post posts_dd[] = { elemchild_err_ge1, NULL };
! 64: static v_post posts_d1[] = { headchild_err_ge1, NULL };
1.9 kristaps 65:
1.12 kristaps 66:
1.9 kristaps 67: const struct valids mdoc_valids[MDOC_MAX] = {
1.17 kristaps 68: { NULL, NULL }, /* \" */
1.24 ! kristaps 69: { pres_prologue, posts_dd }, /* Dd */
! 70: { pres_prologue, NULL }, /* Dt */
! 71: { pres_prologue, NULL }, /* Os */
1.21 kristaps 72: { NULL, posts_sh }, /* Sh */ /* FIXME: preceding Pp. */
1.22 kristaps 73: { NULL, posts_ss }, /* Ss */ /* FIXME: preceding Pp. */
74: { NULL, posts_pp }, /* Pp */ /* FIXME: proceeding... */
1.24 ! kristaps 75: { pres_d1, posts_d1 }, /* D1 */
! 76: { pres_d1, posts_d1 }, /* Dl */
! 77: { pres_bd, posts_bd }, /* Bd */ /* FIXME: preceding Pp. */
1.17 kristaps 78: { NULL, NULL }, /* Ed */
1.24 ! kristaps 79: { pres_bl, posts_bl }, /* Bl */ /* FIXME: preceding Pp. */
1.17 kristaps 80: { NULL, NULL }, /* El */
81: { NULL, NULL }, /* It */
82: { NULL, NULL }, /* Ad */
83: { NULL, NULL }, /* An */
84: { NULL, NULL }, /* Ar */
85: { NULL, NULL }, /* Cd */
86: { NULL, NULL }, /* Cm */
87: { NULL, NULL }, /* Dv */
88: { NULL, NULL }, /* Er */
89: { NULL, NULL }, /* Ev */
90: { NULL, NULL }, /* Ex */
91: { NULL, NULL }, /* Fa */
92: { NULL, NULL }, /* Fd */
93: { NULL, NULL }, /* Fl */
94: { NULL, NULL }, /* Fn */
95: { NULL, NULL }, /* Ft */
96: { NULL, NULL }, /* Ic */
97: { NULL, NULL }, /* In */
98: { NULL, NULL }, /* Li */
99: { NULL, NULL }, /* Nd */
100: { NULL, NULL }, /* Nm */
101: { NULL, NULL }, /* Op */
102: { NULL, NULL }, /* Ot */
103: { NULL, NULL }, /* Pa */
104: { NULL, NULL }, /* Rv */
105: { NULL, NULL }, /* St */
106: { NULL, NULL }, /* Va */
107: { NULL, NULL }, /* Vt */
108: { NULL, NULL }, /* Xr */
109: { NULL, NULL }, /* %A */
110: { NULL, NULL }, /* %B */
111: { NULL, NULL }, /* %D */
112: { NULL, NULL }, /* %I */
113: { NULL, NULL }, /* %J */
114: { NULL, NULL }, /* %N */
115: { NULL, NULL }, /* %O */
116: { NULL, NULL }, /* %P */
117: { NULL, NULL }, /* %R */
118: { NULL, NULL }, /* %T */
119: { NULL, NULL }, /* %V */
120: { NULL, NULL }, /* Ac */
121: { NULL, NULL }, /* Ao */
122: { NULL, NULL }, /* Aq */
123: { NULL, NULL }, /* At */ /* FIXME */
124: { NULL, NULL }, /* Bc */
125: { NULL, NULL }, /* Bf */
126: { NULL, NULL }, /* Bo */
127: { NULL, NULL }, /* Bq */
128: { NULL, NULL }, /* Bsx */
129: { NULL, NULL }, /* Bx */
130: { NULL, NULL }, /* Db */
131: { NULL, NULL }, /* Dc */
132: { NULL, NULL }, /* Do */
133: { NULL, NULL }, /* Dq */
134: { NULL, NULL }, /* Ec */
135: { NULL, NULL }, /* Ef */ /* -symbolic, etc. */
136: { NULL, NULL }, /* Em */
137: { NULL, NULL }, /* Eo */
138: { NULL, NULL }, /* Fx */
139: { NULL, NULL }, /* Ms */
140: { NULL, NULL }, /* No */
141: { NULL, NULL }, /* Ns */
142: { NULL, NULL }, /* Nx */
143: { NULL, NULL }, /* Ox */
144: { NULL, NULL }, /* Pc */
145: { NULL, NULL }, /* Pf */ /* 2 or more arguments */
146: { NULL, NULL }, /* Po */
147: { NULL, NULL }, /* Pq */ /* FIXME: ignore following Sh/Ss */
148: { NULL, NULL }, /* Qc */
149: { NULL, NULL }, /* Ql */
150: { NULL, NULL }, /* Qo */
151: { NULL, NULL }, /* Qq */
152: { NULL, NULL }, /* Re */
153: { NULL, NULL }, /* Rs */
154: { NULL, NULL }, /* Sc */
155: { NULL, NULL }, /* So */
156: { NULL, NULL }, /* Sq */
157: { NULL, NULL }, /* Sm */
158: { NULL, NULL }, /* Sx */
159: { NULL, NULL }, /* Sy */
160: { NULL, NULL }, /* Tn */
161: { NULL, NULL }, /* Ux */
162: { NULL, NULL }, /* Xc */
163: { NULL, NULL }, /* Xo */
164: { NULL, NULL }, /* Fo */
165: { NULL, NULL }, /* Fc */
166: { NULL, NULL }, /* Oo */
167: { NULL, NULL }, /* Oc */
168: { NULL, NULL }, /* Bk */
169: { NULL, NULL }, /* Ek */
170: { NULL, NULL }, /* Bt */
171: { NULL, NULL }, /* Hf */
172: { NULL, NULL }, /* Fr */
173: { NULL, NULL }, /* Ud */
1.9 kristaps 174: };
1.6 kristaps 175:
176:
177: static int
1.24 ! kristaps 178: bodychild_warn_ge1(struct mdoc *mdoc)
1.6 kristaps 179: {
180:
1.17 kristaps 181: if (MDOC_BODY != mdoc->last->type)
1.8 kristaps 182: return(1);
1.17 kristaps 183: if (mdoc->last->child)
1.9 kristaps 184: return(1);
1.18 kristaps 185: return(mdoc_warn(mdoc, WARN_ARGS_GE1));
1.8 kristaps 186: }
1.1 kristaps 187:
188:
1.8 kristaps 189: static int
1.24 ! kristaps 190: elemchild_warn_eq0(struct mdoc *mdoc)
1.22 kristaps 191: {
192:
193: assert(MDOC_ELEM == mdoc->last->type);
194: if (NULL == mdoc->last->child)
195: return(1);
1.24 ! kristaps 196: return(mdoc_pwarn(mdoc, mdoc->last->child->line,
! 197: mdoc->last->child->pos, WARN_ARGS_EQ0));
1.22 kristaps 198: }
199:
200:
201: static int
1.24 ! kristaps 202: elemchild_err_ge1(struct mdoc *mdoc)
1.8 kristaps 203: {
1.1 kristaps 204:
1.21 kristaps 205: assert(MDOC_ELEM == mdoc->last->type);
1.17 kristaps 206: if (mdoc->last->child)
1.9 kristaps 207: return(1);
1.18 kristaps 208: return(mdoc_err(mdoc, ERR_ARGS_GE1));
1.1 kristaps 209: }
210:
211:
1.9 kristaps 212: static int
1.24 ! kristaps 213: headchild_err_eq0(struct mdoc *mdoc)
! 214: {
! 215:
! 216: if (MDOC_HEAD != mdoc->last->type)
! 217: return(1);
! 218: if (NULL == mdoc->last->child)
! 219: return(1);
! 220: return(mdoc_perr(mdoc, mdoc->last->child->line,
! 221: mdoc->last->child->pos, ERR_ARGS_EQ0));
! 222: }
! 223:
! 224:
! 225: static int
! 226: headchild_err_ge1(struct mdoc *mdoc)
1.14 kristaps 227: {
228:
1.17 kristaps 229: if (MDOC_HEAD != mdoc->last->type)
1.14 kristaps 230: return(1);
1.21 kristaps 231: if (mdoc->last->child)
1.11 kristaps 232: return(1);
1.21 kristaps 233: return(mdoc_err(mdoc, ERR_ARGS_GE1));
1.14 kristaps 234: }
235:
236:
237: static int
1.23 kristaps 238: pre_display(struct mdoc *mdoc, struct mdoc_node *node)
239: {
240: struct mdoc_node *n;
241:
1.24 ! kristaps 242: if (MDOC_BLOCK != node->type)
! 243: return(1);
! 244:
1.23 kristaps 245: for (n = mdoc->last; n; n = n->parent)
246: if (MDOC_BLOCK == n->type)
247: if (MDOC_Bd == n->data.block.tok)
248: break;
249: if (NULL == n)
250: return(1);
251: return(mdoc_verr(mdoc, node, ERR_SCOPE_NONEST));
252: }
253:
254:
255: static int
1.24 ! kristaps 256: pre_bl(struct mdoc *mdoc, struct mdoc_node *node)
! 257: {
! 258: int type, err;
! 259: struct mdoc_arg *argv;
! 260: size_t i, argc;
! 261:
! 262: if (MDOC_BLOCK != node->type)
! 263: return(1);
! 264: assert(MDOC_Bl == node->data.block.tok);
! 265:
! 266: argv = NULL;
! 267: argc = node->data.block.argc;
! 268:
! 269: for (i = type = err = 0; i < argc; i++) {
! 270: argv = &node->data.block.argv[(int)i];
! 271: assert(argv);
! 272: switch (argv->arg) {
! 273: case (MDOC_Bullet):
! 274: /* FALLTHROUGH */
! 275: case (MDOC_Dash):
! 276: /* FALLTHROUGH */
! 277: case (MDOC_Enum):
! 278: /* FALLTHROUGH */
! 279: case (MDOC_Hyphen):
! 280: /* FALLTHROUGH */
! 281: case (MDOC_Item):
! 282: /* FALLTHROUGH */
! 283: case (MDOC_Tag):
! 284: /* FALLTHROUGH */
! 285: case (MDOC_Diag):
! 286: /* FALLTHROUGH */
! 287: case (MDOC_Hang):
! 288: /* FALLTHROUGH */
! 289: case (MDOC_Ohang):
! 290: /* FALLTHROUGH */
! 291: case (MDOC_Inset):
! 292: if (type)
! 293: err++;
! 294: type++;
! 295: break;
! 296: default:
! 297: break;
! 298: }
! 299: }
! 300: if (0 == type)
! 301: return(mdoc_err(mdoc, ERR_SYNTAX_ARGMISS));
! 302: if (0 == err)
! 303: return(1);
! 304: assert(argv);
! 305: return(mdoc_perr(mdoc, argv->line,
! 306: argv->pos, ERR_SYNTAX_ARGBAD));
! 307: }
! 308:
! 309:
! 310: static int
! 311: pre_bd(struct mdoc *mdoc, struct mdoc_node *node)
! 312: {
! 313: int type, err;
! 314: struct mdoc_arg *argv;
! 315: size_t i, argc;
! 316:
! 317: if (MDOC_BLOCK != node->type)
! 318: return(1);
! 319: assert(MDOC_Bd == node->data.block.tok);
! 320:
! 321: argv = NULL;
! 322: argc = node->data.block.argc;
! 323:
! 324: for (err = i = type = 0; 0 == err && i < argc; i++) {
! 325: argv = &node->data.block.argv[(int)i];
! 326: assert(argv);
! 327: switch (argv->arg) {
! 328: case (MDOC_Ragged):
! 329: /* FALLTHROUGH */
! 330: case (MDOC_Unfilled):
! 331: /* FALLTHROUGH */
! 332: case (MDOC_Literal):
! 333: /* FALLTHROUGH */
! 334: case (MDOC_File):
! 335: if (type)
! 336: err++;
! 337: type++;
! 338: break;
! 339: default:
! 340: break;
! 341: }
! 342: }
! 343: if (0 == type)
! 344: return(mdoc_err(mdoc, ERR_SYNTAX_ARGMISS));
! 345: if (0 == err)
! 346: return(1);
! 347: assert(argv);
! 348: return(mdoc_perr(mdoc, argv->line,
! 349: argv->pos, ERR_SYNTAX_ARGBAD));
! 350: }
! 351:
! 352:
! 353: static int
1.20 kristaps 354: pre_prologue(struct mdoc *mdoc, struct mdoc_node *node)
355: {
356:
357: if (SEC_PROLOGUE != mdoc->sec_lastn)
358: return(mdoc_verr(mdoc, node, ERR_SEC_NPROLOGUE));
359: assert(MDOC_ELEM == node->type);
360:
361: /* Check for ordering. */
362:
363: switch (node->data.elem.tok) {
364: case (MDOC_Os):
365: if (mdoc->meta.title[0] && mdoc->meta.date)
366: break;
367: return(mdoc_verr(mdoc, node, ERR_SEC_PROLOGUE_OO));
368: case (MDOC_Dt):
369: if (0 == mdoc->meta.title[0] && mdoc->meta.date)
370: break;
371: return(mdoc_verr(mdoc, node, ERR_SEC_PROLOGUE_OO));
372: case (MDOC_Dd):
373: if (0 == mdoc->meta.title[0] && 0 == mdoc->meta.date)
374: break;
375: return(mdoc_verr(mdoc, node, ERR_SEC_PROLOGUE_OO));
376: default:
377: abort();
378: /* NOTREACHED */
379: }
380:
381: /* Check for repetition. */
382:
383: switch (node->data.elem.tok) {
384: case (MDOC_Os):
385: if (0 == mdoc->meta.os[0])
386: return(1);
387: break;
388: case (MDOC_Dd):
389: if (0 == mdoc->meta.date)
390: return(1);
391: break;
392: case (MDOC_Dt):
393: if (0 == mdoc->meta.title[0])
394: return(1);
395: break;
396: default:
397: abort();
398: /* NOTREACHED */
399: }
400:
401: return(mdoc_verr(mdoc, node, ERR_SEC_PROLOGUE_REP));
402: }
403:
404:
1.24 ! kristaps 405: static int
! 406: post_bl(struct mdoc *mdoc)
! 407: {
! 408: struct mdoc_node *n;
! 409:
! 410: if (MDOC_BODY != mdoc->last->type)
! 411: return(1);
! 412: assert(MDOC_Bl == mdoc->last->data.body.tok);
! 413:
! 414: for (n = mdoc->last->child; n; n = n->next) {
! 415: if (MDOC_BLOCK == n->type)
! 416: if (MDOC_It == n->data.block.tok)
! 417: continue;
! 418: break;
! 419: }
! 420: if (NULL == n)
! 421: return(1);
! 422: return(mdoc_verr(mdoc, n, ERR_SYNTAX_CHILDBAD));
! 423: }
! 424:
! 425:
1.21 kristaps 426: /*
427: * Warn if sections (those that are with a known title, such as NAME,
428: * DESCRIPTION, and so forth) are out of the conventional order.
429: */
1.20 kristaps 430: static int
1.21 kristaps 431: post_sh(struct mdoc *mdoc)
1.14 kristaps 432: {
1.21 kristaps 433: enum mdoc_sec sec;
434: int i;
435: struct mdoc_node *n;
436: char *args[MDOC_LINEARG_MAX];
437:
438: if (MDOC_HEAD != mdoc->last->type)
439: return(1);
440:
441: assert(MDOC_Sh == mdoc->last->data.head.tok);
442:
443: n = mdoc->last->child;
444: assert(n);
1.14 kristaps 445:
1.21 kristaps 446: for (i = 0; n && i < MDOC_LINEARG_MAX; n = n->next, i++) {
447: assert(MDOC_TEXT == n->type);
448: assert(NULL == n->child);
449: assert(n->data.text.string);
450: args[i] = n->data.text.string;
451: }
452:
453: sec = mdoc_atosec((size_t)i, (const char **)args);
454: if (SEC_CUSTOM == sec)
455: return(1);
456: if (sec > mdoc->sec_lastn)
457: return(1);
458:
459: if (sec == mdoc->sec_lastn)
460: return(mdoc_warn(mdoc, WARN_SEC_REP));
461: return(mdoc_warn(mdoc, WARN_SEC_OO));
1.11 kristaps 462: }
463:
464:
1.17 kristaps 465: int
1.18 kristaps 466: mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *node)
1.11 kristaps 467: {
1.24 ! kristaps 468: v_pre *p;
1.18 kristaps 469: int t;
470:
471: switch (node->type) {
472: case (MDOC_BODY):
1.20 kristaps 473: t = node->data.body.tok;
1.18 kristaps 474: break;
475: case (MDOC_ELEM):
1.20 kristaps 476: t = node->data.elem.tok;
1.18 kristaps 477: break;
478: case (MDOC_BLOCK):
1.20 kristaps 479: t = node->data.block.tok;
1.18 kristaps 480: break;
481: case (MDOC_HEAD):
1.20 kristaps 482: t = node->data.head.tok;
1.18 kristaps 483: break;
484: default:
485: return(1);
486: }
1.11 kristaps 487:
1.18 kristaps 488: if (NULL == mdoc_valids[t].pre)
1.11 kristaps 489: return(1);
1.24 ! kristaps 490: for (p = mdoc_valids[t].pre; *p; p++)
! 491: if ( ! (*p)(mdoc, node))
! 492: return(0);
! 493: return(1);
1.11 kristaps 494: }
495:
496:
1.17 kristaps 497: int
1.18 kristaps 498: mdoc_valid_post(struct mdoc *mdoc)
1.11 kristaps 499: {
1.17 kristaps 500: v_post *p;
501: int t;
1.11 kristaps 502:
1.17 kristaps 503: switch (mdoc->last->type) {
504: case (MDOC_BODY):
505: t = mdoc->last->data.body.tok;
506: break;
507: case (MDOC_ELEM):
508: t = mdoc->last->data.elem.tok;
509: break;
510: case (MDOC_BLOCK):
511: t = mdoc->last->data.block.tok;
512: break;
513: case (MDOC_HEAD):
514: t = mdoc->last->data.head.tok;
515: break;
516: default:
1.8 kristaps 517: return(1);
518: }
1.14 kristaps 519:
1.17 kristaps 520: if (NULL == mdoc_valids[t].post)
1.9 kristaps 521: return(1);
1.17 kristaps 522: for (p = mdoc_valids[t].post; *p; p++)
1.18 kristaps 523: if ( ! (*p)(mdoc))
1.17 kristaps 524: return(0);
1.11 kristaps 525:
1.14 kristaps 526: return(1);
1.11 kristaps 527: }
1.14 kristaps 528:
CVSweb