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