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