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