Annotation of mandoc/validate.c, Revision 1.26
1.26 ! kristaps 1: /* $Id: validate.c,v 1.25 2009/01/12 12:52:21 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 *);
1.26 ! kristaps 45: static int elemchild_err_eq0(struct mdoc *);
1.24 kristaps 46: static int elemchild_err_ge1(struct mdoc *);
47: static int elemchild_warn_eq0(struct mdoc *);
48: static int bodychild_warn_ge1(struct mdoc *);
1.26 ! kristaps 49: static int elemchild_warn_ge1(struct mdoc *);
1.21 kristaps 50: static int post_sh(struct mdoc *);
1.24 kristaps 51: static int post_bl(struct mdoc *);
1.25 kristaps 52: static int post_it(struct mdoc *);
1.17 kristaps 53:
1.24 kristaps 54: static v_pre pres_prologue[] = { pre_prologue, NULL };
55: static v_pre pres_d1[] = { pre_display, NULL };
56: static v_pre pres_bd[] = { pre_display, pre_bd, NULL };
57: static v_pre pres_bl[] = { pre_bl, NULL };
1.25 kristaps 58: static v_pre pres_it[] = { pre_it, NULL };
1.24 kristaps 59: static v_post posts_bd[] = { headchild_err_eq0,
60: bodychild_warn_ge1, NULL };
61:
1.26 ! kristaps 62: static v_post posts_text[] = { elemchild_err_ge1, NULL };
! 63: static v_post posts_wtext[] = { elemchild_warn_ge1, NULL };
! 64: static v_post posts_notext[] = { elemchild_err_eq0, NULL };
1.24 kristaps 65: static v_post posts_sh[] = { headchild_err_ge1,
66: bodychild_warn_ge1, post_sh, NULL };
67: static v_post posts_bl[] = { headchild_err_eq0,
68: 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? */
! 117: { NULL, posts_wtext }, /* 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.26 ! kristaps 138: { NULL, posts_wtext }, /* Aq */
1.17 kristaps 139: { NULL, NULL }, /* At */ /* FIXME */
140: { NULL, NULL }, /* Bc */
141: { NULL, NULL }, /* Bf */
142: { NULL, NULL }, /* Bo */
1.26 ! kristaps 143: { NULL, posts_wtext }, /* 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.26 ! kristaps 149: { NULL, posts_wtext }, /* 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.26 ! kristaps 163: { NULL, posts_wtext }, /* Pq */ /* FIXME: ignore following Sh/Ss */
1.17 kristaps 164: { NULL, NULL }, /* Qc */
1.26 ! kristaps 165: { NULL, posts_wtext }, /* Ql */
1.17 kristaps 166: { NULL, NULL }, /* Qo */
1.26 ! kristaps 167: { NULL, posts_wtext }, /* Qq */
1.17 kristaps 168: { NULL, NULL }, /* Re */
169: { NULL, NULL }, /* Rs */
170: { NULL, NULL }, /* Sc */
171: { NULL, NULL }, /* So */
1.26 ! kristaps 172: { NULL, posts_wtext }, /* Sq */
! 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.24 kristaps 194: bodychild_warn_ge1(struct mdoc *mdoc)
1.6 kristaps 195: {
196:
1.17 kristaps 197: if (MDOC_BODY != mdoc->last->type)
1.8 kristaps 198: return(1);
1.17 kristaps 199: if (mdoc->last->child)
1.9 kristaps 200: return(1);
1.18 kristaps 201: return(mdoc_warn(mdoc, WARN_ARGS_GE1));
1.8 kristaps 202: }
1.1 kristaps 203:
204:
1.8 kristaps 205: static int
1.24 kristaps 206: elemchild_warn_eq0(struct mdoc *mdoc)
1.22 kristaps 207: {
208:
209: assert(MDOC_ELEM == mdoc->last->type);
210: if (NULL == mdoc->last->child)
211: return(1);
1.24 kristaps 212: return(mdoc_pwarn(mdoc, mdoc->last->child->line,
213: mdoc->last->child->pos, WARN_ARGS_EQ0));
1.22 kristaps 214: }
215:
216:
217: static int
1.26 ! kristaps 218: elemchild_warn_ge1(struct mdoc *mdoc)
! 219: {
! 220:
! 221: assert(MDOC_ELEM == mdoc->last->type);
! 222: if (mdoc->last->child)
! 223: return(1);
! 224: return(mdoc_warn(mdoc, WARN_ARGS_GE1));
! 225: }
! 226:
! 227:
! 228: static int
! 229: elemchild_err_eq0(struct mdoc *mdoc)
! 230: {
! 231:
! 232: assert(MDOC_ELEM == mdoc->last->type);
! 233: if (NULL == mdoc->last->child)
! 234: return(1);
! 235: return(mdoc_err(mdoc, ERR_ARGS_EQ0));
! 236: }
! 237:
! 238:
! 239: static int
1.24 kristaps 240: elemchild_err_ge1(struct mdoc *mdoc)
1.8 kristaps 241: {
1.1 kristaps 242:
1.21 kristaps 243: assert(MDOC_ELEM == mdoc->last->type);
1.17 kristaps 244: if (mdoc->last->child)
1.9 kristaps 245: return(1);
1.18 kristaps 246: return(mdoc_err(mdoc, ERR_ARGS_GE1));
1.1 kristaps 247: }
248:
249:
1.9 kristaps 250: static int
1.24 kristaps 251: headchild_err_eq0(struct mdoc *mdoc)
252: {
253:
254: if (MDOC_HEAD != mdoc->last->type)
255: return(1);
256: if (NULL == mdoc->last->child)
257: return(1);
258: return(mdoc_perr(mdoc, mdoc->last->child->line,
259: mdoc->last->child->pos, ERR_ARGS_EQ0));
260: }
261:
262:
263: static int
264: headchild_err_ge1(struct mdoc *mdoc)
1.14 kristaps 265: {
266:
1.17 kristaps 267: if (MDOC_HEAD != mdoc->last->type)
1.14 kristaps 268: return(1);
1.21 kristaps 269: if (mdoc->last->child)
1.11 kristaps 270: return(1);
1.21 kristaps 271: return(mdoc_err(mdoc, ERR_ARGS_GE1));
1.14 kristaps 272: }
273:
274:
275: static int
1.23 kristaps 276: pre_display(struct mdoc *mdoc, struct mdoc_node *node)
277: {
278: struct mdoc_node *n;
279:
1.24 kristaps 280: if (MDOC_BLOCK != node->type)
281: return(1);
282:
1.23 kristaps 283: for (n = mdoc->last; n; n = n->parent)
284: if (MDOC_BLOCK == n->type)
1.25 kristaps 285: if (MDOC_Bd == n->tok)
1.23 kristaps 286: break;
287: if (NULL == n)
288: return(1);
289: return(mdoc_verr(mdoc, node, ERR_SCOPE_NONEST));
290: }
291:
292:
293: static int
1.24 kristaps 294: pre_bl(struct mdoc *mdoc, struct mdoc_node *node)
295: {
296: int type, err;
297: struct mdoc_arg *argv;
298: size_t i, argc;
299:
300: if (MDOC_BLOCK != node->type)
301: return(1);
1.25 kristaps 302: assert(MDOC_Bl == node->tok);
1.24 kristaps 303:
304: argv = NULL;
305: argc = node->data.block.argc;
306:
307: for (i = type = err = 0; i < argc; i++) {
308: argv = &node->data.block.argv[(int)i];
309: assert(argv);
310: switch (argv->arg) {
311: case (MDOC_Bullet):
312: /* FALLTHROUGH */
313: case (MDOC_Dash):
314: /* FALLTHROUGH */
315: case (MDOC_Enum):
316: /* FALLTHROUGH */
317: case (MDOC_Hyphen):
318: /* FALLTHROUGH */
319: case (MDOC_Item):
320: /* FALLTHROUGH */
321: case (MDOC_Tag):
322: /* FALLTHROUGH */
323: case (MDOC_Diag):
324: /* FALLTHROUGH */
325: case (MDOC_Hang):
326: /* FALLTHROUGH */
327: case (MDOC_Ohang):
328: /* FALLTHROUGH */
329: case (MDOC_Inset):
1.26 ! kristaps 330: /* FALLTHROUGH */
! 331: case (MDOC_Column):
1.24 kristaps 332: if (type)
333: err++;
334: type++;
335: break;
336: default:
337: break;
338: }
339: }
340: if (0 == type)
341: return(mdoc_err(mdoc, ERR_SYNTAX_ARGMISS));
342: if (0 == err)
343: return(1);
344: assert(argv);
345: return(mdoc_perr(mdoc, argv->line,
346: argv->pos, ERR_SYNTAX_ARGBAD));
347: }
348:
349:
350: static int
351: pre_bd(struct mdoc *mdoc, struct mdoc_node *node)
352: {
353: int type, err;
354: struct mdoc_arg *argv;
355: size_t i, argc;
356:
357: if (MDOC_BLOCK != node->type)
358: return(1);
1.25 kristaps 359: assert(MDOC_Bd == node->tok);
1.24 kristaps 360:
361: argv = NULL;
362: argc = node->data.block.argc;
363:
364: for (err = i = type = 0; 0 == err && i < argc; i++) {
365: argv = &node->data.block.argv[(int)i];
366: assert(argv);
367: switch (argv->arg) {
368: case (MDOC_Ragged):
369: /* FALLTHROUGH */
370: case (MDOC_Unfilled):
371: /* FALLTHROUGH */
372: case (MDOC_Literal):
373: /* FALLTHROUGH */
374: case (MDOC_File):
375: if (type)
376: err++;
377: type++;
378: break;
379: default:
380: break;
381: }
382: }
383: if (0 == type)
384: return(mdoc_err(mdoc, ERR_SYNTAX_ARGMISS));
385: if (0 == err)
386: return(1);
387: assert(argv);
388: return(mdoc_perr(mdoc, argv->line,
389: argv->pos, ERR_SYNTAX_ARGBAD));
390: }
391:
392:
393: static int
1.25 kristaps 394: pre_it(struct mdoc *mdoc, struct mdoc_node *node)
395: {
396:
397: if (MDOC_BLOCK != mdoc->last->type)
398: return(1);
399: assert(MDOC_It == mdoc->last->tok);
400:
401: if (MDOC_BODY != mdoc->last->parent->type)
402: return(mdoc_verr(mdoc, node, ERR_SYNTAX_PARENTBAD));
403: if (MDOC_Bl != mdoc->last->parent->tok)
404: return(mdoc_verr(mdoc, node, ERR_SYNTAX_PARENTBAD));
405:
406: return(1);
407: }
408:
409:
410: static int
1.20 kristaps 411: pre_prologue(struct mdoc *mdoc, struct mdoc_node *node)
412: {
413:
414: if (SEC_PROLOGUE != mdoc->sec_lastn)
415: return(mdoc_verr(mdoc, node, ERR_SEC_NPROLOGUE));
416: assert(MDOC_ELEM == node->type);
417:
418: /* Check for ordering. */
419:
1.25 kristaps 420: switch (node->tok) {
1.20 kristaps 421: case (MDOC_Os):
422: if (mdoc->meta.title[0] && mdoc->meta.date)
423: break;
424: return(mdoc_verr(mdoc, node, ERR_SEC_PROLOGUE_OO));
425: case (MDOC_Dt):
426: if (0 == mdoc->meta.title[0] && mdoc->meta.date)
427: break;
428: return(mdoc_verr(mdoc, node, ERR_SEC_PROLOGUE_OO));
429: case (MDOC_Dd):
430: if (0 == mdoc->meta.title[0] && 0 == mdoc->meta.date)
431: break;
432: return(mdoc_verr(mdoc, node, ERR_SEC_PROLOGUE_OO));
433: default:
434: abort();
435: /* NOTREACHED */
436: }
437:
438: /* Check for repetition. */
439:
1.25 kristaps 440: switch (node->tok) {
1.20 kristaps 441: case (MDOC_Os):
442: if (0 == mdoc->meta.os[0])
443: return(1);
444: break;
445: case (MDOC_Dd):
446: if (0 == mdoc->meta.date)
447: return(1);
448: break;
449: case (MDOC_Dt):
450: if (0 == mdoc->meta.title[0])
451: return(1);
452: break;
453: default:
454: abort();
455: /* NOTREACHED */
456: }
457:
458: return(mdoc_verr(mdoc, node, ERR_SEC_PROLOGUE_REP));
459: }
460:
461:
1.25 kristaps 462: /* Warn if `Bl' type-specific syntax isn't reflected in items. */
463: static int
464: post_it(struct mdoc *mdoc)
465: {
466: int type, sv;
467: #define TYPE_NONE (0)
468: #define TYPE_BODY (1)
469: #define TYPE_HEAD (2)
470: size_t i, argc;
471: struct mdoc_node *n;
472:
473: if (MDOC_BLOCK != mdoc->last->type)
474: return(1);
475:
476: assert(MDOC_It == mdoc->last->tok);
477:
478: n = mdoc->last->parent;
479: assert(n);
480: assert(MDOC_Bl == n->tok);
481:
482: n = n->parent;
483: assert(MDOC_BLOCK == n->type);
484: assert(MDOC_Bl == n->tok);
485:
486: argc = n->data.block.argc;
487: type = TYPE_NONE;
1.26 ! kristaps 488:
! 489: /* Some types require block-head, some not. */
1.25 kristaps 490:
491: for (i = 0; TYPE_NONE == type && i < argc; i++)
492: switch (n->data.block.argv[(int)i].arg) {
493: case (MDOC_Tag):
494: /* FALLTHROUGH */
495: case (MDOC_Diag):
496: /* FALLTHROUGH */
497: case (MDOC_Hang):
498: /* FALLTHROUGH */
499: case (MDOC_Ohang):
500: /* FALLTHROUGH */
501: case (MDOC_Inset):
502: type = TYPE_HEAD;
503: sv = n->data.block.argv[(int)i].arg;
504: break;
505: case (MDOC_Bullet):
506: /* FALLTHROUGH */
507: case (MDOC_Dash):
508: /* FALLTHROUGH */
509: case (MDOC_Enum):
510: /* FALLTHROUGH */
511: case (MDOC_Hyphen):
512: /* FALLTHROUGH */
513: case (MDOC_Item):
514: /* FALLTHROUGH */
515: case (MDOC_Column):
516: type = TYPE_BODY;
517: sv = n->data.block.argv[(int)i].arg;
518: break;
519: default:
520: break;
521: }
522:
523: assert(TYPE_NONE != type);
524:
525: if (TYPE_HEAD == type) {
526: if (NULL == (n = mdoc->last->data.block.head)) {
527: if ( ! mdoc_warn(mdoc, WARN_SYNTAX_EMPTYHEAD))
528: return(0);
529: } else if (NULL == n->child)
530: if ( ! mdoc_warn(mdoc, WARN_SYNTAX_EMPTYHEAD))
531: return(0);
532:
533: if (NULL == (n = mdoc->last->data.block.body)) {
534: if ( ! mdoc_warn(mdoc, WARN_SYNTAX_EMPTYBODY))
535: return(0);
536: } else if (NULL == n->child)
537: if ( ! mdoc_warn(mdoc, WARN_SYNTAX_EMPTYBODY))
538: return(0);
539:
540: return(1);
541: }
542:
543: if (NULL == (n = mdoc->last->data.block.head)) {
544: if ( ! mdoc_warn(mdoc, WARN_SYNTAX_EMPTYHEAD))
545: return(0);
546: } else if (NULL == n->child)
547: if ( ! mdoc_warn(mdoc, WARN_SYNTAX_EMPTYHEAD))
548: return(0);
549:
550: if ((n = mdoc->last->data.block.body) && n->child)
551: if ( ! mdoc_warn(mdoc, WARN_SYNTAX_NOBODY))
552: return(0);
553:
1.26 ! kristaps 554: if (MDOC_Column != sv)
! 555: return(1);
! 556:
! 557: /* Make sure the number of columns is sane. */
! 558:
! 559: sv = mdoc->last->parent->parent->data.block.argv->sz;
! 560: n = mdoc->last->data.block.head->child;
1.25 kristaps 561:
1.26 ! kristaps 562: for (i = 0; n; n = n->next)
! 563: i++;
! 564:
! 565: if (i == (size_t)sv)
! 566: return(1);
! 567: return(mdoc_err(mdoc, ERR_SYNTAX_ARGFORM));
1.25 kristaps 568:
569: #undef TYPE_NONE
570: #undef TYPE_BODY
571: #undef TYPE_HEAD
572: }
573:
574:
575: /* Make sure that only `It' macros are our body-children. */
1.24 kristaps 576: static int
577: post_bl(struct mdoc *mdoc)
578: {
579: struct mdoc_node *n;
580:
581: if (MDOC_BODY != mdoc->last->type)
582: return(1);
1.25 kristaps 583: assert(MDOC_Bl == mdoc->last->tok);
1.24 kristaps 584:
585: for (n = mdoc->last->child; n; n = n->next) {
586: if (MDOC_BLOCK == n->type)
1.25 kristaps 587: if (MDOC_It == n->tok)
1.24 kristaps 588: continue;
589: break;
590: }
591: if (NULL == n)
592: return(1);
593: return(mdoc_verr(mdoc, n, ERR_SYNTAX_CHILDBAD));
594: }
595:
596:
1.25 kristaps 597: /* Warn if conventional sections are out of order. */
1.20 kristaps 598: static int
1.21 kristaps 599: post_sh(struct mdoc *mdoc)
1.14 kristaps 600: {
1.21 kristaps 601: enum mdoc_sec sec;
602: int i;
603: struct mdoc_node *n;
604: char *args[MDOC_LINEARG_MAX];
605:
606: if (MDOC_HEAD != mdoc->last->type)
607: return(1);
608:
1.25 kristaps 609: assert(MDOC_Sh == mdoc->last->tok);
1.21 kristaps 610:
611: n = mdoc->last->child;
612: assert(n);
1.14 kristaps 613:
1.21 kristaps 614: for (i = 0; n && i < MDOC_LINEARG_MAX; n = n->next, i++) {
615: assert(MDOC_TEXT == n->type);
616: assert(NULL == n->child);
617: assert(n->data.text.string);
618: args[i] = n->data.text.string;
619: }
620:
621: sec = mdoc_atosec((size_t)i, (const char **)args);
622: if (SEC_CUSTOM == sec)
623: return(1);
624: if (sec > mdoc->sec_lastn)
625: return(1);
626:
627: if (sec == mdoc->sec_lastn)
628: return(mdoc_warn(mdoc, WARN_SEC_REP));
629: return(mdoc_warn(mdoc, WARN_SEC_OO));
1.11 kristaps 630: }
631:
632:
1.17 kristaps 633: int
1.18 kristaps 634: mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *node)
1.11 kristaps 635: {
1.24 kristaps 636: v_pre *p;
1.18 kristaps 637:
1.25 kristaps 638: /* TODO: character-escape checks. */
639:
640: if (MDOC_TEXT == node->type)
1.18 kristaps 641: return(1);
1.25 kristaps 642: assert(MDOC_ROOT != node->type);
1.11 kristaps 643:
1.25 kristaps 644: if (NULL == mdoc_valids[node->tok].pre)
1.11 kristaps 645: return(1);
1.25 kristaps 646: for (p = mdoc_valids[node->tok].pre; *p; p++)
1.24 kristaps 647: if ( ! (*p)(mdoc, node))
648: return(0);
649: return(1);
1.11 kristaps 650: }
651:
652:
1.17 kristaps 653: int
1.18 kristaps 654: mdoc_valid_post(struct mdoc *mdoc)
1.11 kristaps 655: {
1.17 kristaps 656: v_post *p;
1.11 kristaps 657:
1.25 kristaps 658: if (MDOC_TEXT == mdoc->last->type)
659: return(1);
660: if (MDOC_ROOT == mdoc->last->type)
1.8 kristaps 661: return(1);
1.14 kristaps 662:
1.25 kristaps 663: if (NULL == mdoc_valids[mdoc->last->tok].post)
1.9 kristaps 664: return(1);
1.25 kristaps 665: for (p = mdoc_valids[mdoc->last->tok].post; *p; p++)
1.18 kristaps 666: if ( ! (*p)(mdoc))
1.17 kristaps 667: return(0);
1.11 kristaps 668:
1.14 kristaps 669: return(1);
1.11 kristaps 670: }
1.14 kristaps 671:
CVSweb