Annotation of mandoc/validate.c, Revision 1.52
1.52 ! kristaps 1: /* $Id: validate.c,v 1.51 2009/02/22 14:31:08 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.44 kristaps 24: /*
25: * Pre- and post-validate macros as they're parsed. Pre-validation
26: * occurs when the macro has been detected and its arguments parsed.
27: * Post-validation occurs when all child macros have also been parsed.
28: * In the ELEMENT case, this is simply the parameters of the macro; in
29: * the BLOCK case, this is the HEAD, BODY, TAIL and so on.
30: */
31:
1.18 kristaps 32: typedef int (*v_pre)(struct mdoc *, struct mdoc_node *);
33: typedef int (*v_post)(struct mdoc *);
1.14 kristaps 34:
1.36 kristaps 35: /* FIXME: some sections should only occur in specific msecs. */
36: /* FIXME: ignoring Pp. */
1.51 kristaps 37: /* FIXME: .Ef arguments */
1.36 kristaps 38: /* FIXME: math symbols. */
1.51 kristaps 39: /* FIXME: valid character-escape checks. */
40: /* FIXME: .Fd only in synopsis section. */
1.36 kristaps 41:
1.14 kristaps 42: struct valids {
1.24 kristaps 43: v_pre *pre;
1.17 kristaps 44: v_post *post;
1.14 kristaps 45: };
1.1 kristaps 46:
1.37 kristaps 47: /* Utility checks. */
48:
1.51 kristaps 49: static int check_parent(struct mdoc *, struct mdoc_node *,
1.33 kristaps 50: int, enum mdoc_type);
1.51 kristaps 51: static int check_msec(struct mdoc *, struct mdoc_node *,
1.33 kristaps 52: int, enum mdoc_msec *);
1.51 kristaps 53: static int check_stdarg(struct mdoc *, struct mdoc_node *);
54: static int err_child_lt(struct mdoc *, const char *, int);
55: static int err_child_gt(struct mdoc *, const char *, int);
56: static int warn_child_gt(struct mdoc *, const char *, int);
57: static int err_child_eq(struct mdoc *, const char *, int);
58: static int warn_child_eq(struct mdoc *, const char *, int);
59:
60: /* Utility auxiliaries. */
61:
62: static inline int count_child(struct mdoc *);
63: static inline int warn_count(struct mdoc *, const char *,
64: int, const char *, int);
65: static inline int err_count(struct mdoc *, const char *,
66: int, const char *, int);
1.11 kristaps 67:
1.37 kristaps 68: /* Specific pre-child-parse routines. */
69:
1.23 kristaps 70: static int pre_display(struct mdoc *, struct mdoc_node *);
1.33 kristaps 71: static int pre_sh(struct mdoc *, struct mdoc_node *);
72: static int pre_ss(struct mdoc *, struct mdoc_node *);
1.24 kristaps 73: static int pre_bd(struct mdoc *, struct mdoc_node *);
74: static int pre_bl(struct mdoc *, struct mdoc_node *);
1.25 kristaps 75: static int pre_it(struct mdoc *, struct mdoc_node *);
1.33 kristaps 76: static int pre_cd(struct mdoc *, struct mdoc_node *);
77: static int pre_er(struct mdoc *, struct mdoc_node *);
78: static int pre_ex(struct mdoc *, struct mdoc_node *);
1.36 kristaps 79: static int pre_rv(struct mdoc *, struct mdoc_node *);
1.35 kristaps 80: static int pre_an(struct mdoc *, struct mdoc_node *);
1.36 kristaps 81: static int pre_st(struct mdoc *, struct mdoc_node *);
1.20 kristaps 82: static int pre_prologue(struct mdoc *, struct mdoc_node *);
83: static int pre_prologue(struct mdoc *, struct mdoc_node *);
84: static int pre_prologue(struct mdoc *, struct mdoc_node *);
1.24 kristaps 85:
1.37 kristaps 86: /* Specific post-child-parse routines. */
87:
88: static int herr_ge1(struct mdoc *);
1.41 kristaps 89: static int herr_le1(struct mdoc *);
1.37 kristaps 90: static int herr_eq0(struct mdoc *);
91: static int eerr_eq0(struct mdoc *);
92: static int eerr_le1(struct mdoc *);
93: static int eerr_le2(struct mdoc *);
94: static int eerr_eq1(struct mdoc *);
95: static int eerr_ge1(struct mdoc *);
96: static int ewarn_eq0(struct mdoc *);
1.39 kristaps 97: static int ewarn_eq1(struct mdoc *);
1.37 kristaps 98: static int bwarn_ge1(struct mdoc *);
99: static int ewarn_ge1(struct mdoc *);
100: static int ebool(struct mdoc *);
1.21 kristaps 101: static int post_sh(struct mdoc *);
1.46 kristaps 102: static int post_sh_body(struct mdoc *);
103: static int post_sh_head(struct mdoc *);
1.24 kristaps 104: static int post_bl(struct mdoc *);
1.25 kristaps 105: static int post_it(struct mdoc *);
1.35 kristaps 106: static int post_ex(struct mdoc *);
107: static int post_an(struct mdoc *);
1.36 kristaps 108: static int post_at(struct mdoc *);
109: static int post_xr(struct mdoc *);
1.37 kristaps 110: static int post_nm(struct mdoc *);
1.41 kristaps 111: static int post_bf(struct mdoc *);
1.37 kristaps 112: static int post_root(struct mdoc *);
113:
114: /* Collections of pre-child-parse routines. */
1.17 kristaps 115:
1.24 kristaps 116: static v_pre pres_prologue[] = { pre_prologue, NULL };
117: static v_pre pres_d1[] = { pre_display, NULL };
118: static v_pre pres_bd[] = { pre_display, pre_bd, NULL };
119: static v_pre pres_bl[] = { pre_bl, NULL };
1.25 kristaps 120: static v_pre pres_it[] = { pre_it, NULL };
1.33 kristaps 121: static v_pre pres_ss[] = { pre_ss, NULL };
122: static v_pre pres_sh[] = { pre_sh, NULL };
123: static v_pre pres_cd[] = { pre_cd, NULL };
124: static v_pre pres_er[] = { pre_er, NULL };
125: static v_pre pres_ex[] = { pre_ex, NULL };
1.36 kristaps 126: static v_pre pres_rv[] = { pre_rv, NULL };
1.35 kristaps 127: static v_pre pres_an[] = { pre_an, NULL };
1.36 kristaps 128: static v_pre pres_st[] = { pre_st, NULL };
1.24 kristaps 129:
1.37 kristaps 130: /* Collections of post-child-parse routines. */
131:
132: static v_post posts_bool[] = { eerr_eq1, ebool, NULL };
133: static v_post posts_bd[] = { herr_eq0, bwarn_ge1, NULL };
134: static v_post posts_text[] = { eerr_ge1, NULL };
135: static v_post posts_wtext[] = { ewarn_ge1, NULL };
136: static v_post posts_notext[] = { eerr_eq0, NULL };
1.43 kristaps 137: static v_post posts_wline[] = { bwarn_ge1, herr_eq0, NULL };
1.37 kristaps 138: static v_post posts_sh[] = { herr_ge1, bwarn_ge1, post_sh, NULL };
139: static v_post posts_bl[] = { herr_eq0, bwarn_ge1, post_bl, NULL };
1.25 kristaps 140: static v_post posts_it[] = { post_it, NULL };
1.39 kristaps 141: static v_post posts_in[] = { ewarn_eq1, NULL };
1.37 kristaps 142: static v_post posts_ss[] = { herr_ge1, NULL };
1.52 ! kristaps 143: static v_post posts_pf[] = { eerr_eq1, NULL };
1.37 kristaps 144: static v_post posts_pp[] = { ewarn_eq0, NULL };
145: static v_post posts_ex[] = { eerr_le1, post_ex, NULL };
1.35 kristaps 146: static v_post posts_an[] = { post_an, NULL };
1.37 kristaps 147: static v_post posts_at[] = { post_at, NULL };
148: static v_post posts_xr[] = { eerr_ge1, eerr_le2, post_xr, NULL };
149: static v_post posts_nm[] = { post_nm, NULL };
1.41 kristaps 150: static v_post posts_bf[] = { herr_le1, post_bf, NULL };
1.45 kristaps 151: static v_post posts_rs[] = { herr_eq0, bwarn_ge1, NULL };
152: static v_post posts_fo[] = { bwarn_ge1, NULL };
153: static v_post posts_bk[] = { herr_eq0, bwarn_ge1, NULL };
1.9 kristaps 154:
1.37 kristaps 155: /* Per-macro pre- and post-child-check routine collections. */
1.12 kristaps 156:
1.9 kristaps 157: const struct valids mdoc_valids[MDOC_MAX] = {
1.51 kristaps 158: { NULL, NULL }, /* \" */
159: { pres_prologue, posts_text }, /* Dd */
160: { pres_prologue, NULL }, /* Dt */
161: { pres_prologue, NULL }, /* Os */
162: { pres_sh, posts_sh }, /* Sh */
163: { pres_ss, posts_ss }, /* Ss */
164: { NULL, posts_pp }, /* Pp */
165: { pres_d1, posts_wline }, /* D1 */
166: { pres_d1, posts_wline }, /* Dl */
167: { pres_bd, posts_bd }, /* Bd */
168: { NULL, NULL }, /* Ed */
169: { pres_bl, posts_bl }, /* Bl */
170: { NULL, NULL }, /* El */
171: { pres_it, posts_it }, /* It */
172: { NULL, posts_text }, /* Ad */
173: { pres_an, posts_an }, /* An */
174: { NULL, NULL }, /* Ar */
175: { pres_cd, posts_text }, /* Cd */
176: { NULL, NULL }, /* Cm */
177: { NULL, posts_text }, /* Dv */
178: { pres_er, posts_text }, /* Er */
179: { NULL, posts_text }, /* Ev */
180: { pres_ex, posts_ex }, /* Ex */
181: { NULL, posts_text }, /* Fa */
182: { NULL, posts_wtext }, /* Fd */
183: { NULL, NULL }, /* Fl */
184: { NULL, posts_text }, /* Fn */
185: { NULL, posts_wtext }, /* Ft */
186: { NULL, posts_text }, /* Ic */
187: { NULL, posts_in }, /* In */
188: { NULL, posts_text }, /* Li */
189: { NULL, posts_wtext }, /* Nd */
190: { NULL, posts_nm }, /* Nm */
191: { NULL, posts_wline }, /* Op */
192: { NULL, NULL }, /* Ot */
193: { NULL, NULL }, /* Pa */
194: { pres_rv, posts_notext }, /* Rv */
195: { pres_st, posts_notext }, /* St */
196: { NULL, posts_text }, /* Va */
197: { NULL, posts_text }, /* Vt */
198: { NULL, posts_xr }, /* Xr */
199: { NULL, posts_text }, /* %A */
200: { NULL, posts_text }, /* %B */
201: { NULL, posts_text }, /* %D */
202: { NULL, posts_text }, /* %I */
203: { NULL, posts_text }, /* %J */
204: { NULL, posts_text }, /* %N */
205: { NULL, posts_text }, /* %O */
206: { NULL, posts_text }, /* %P */
207: { NULL, posts_text }, /* %R */
208: { NULL, posts_text }, /* %T */
209: { NULL, posts_text }, /* %V */
210: { NULL, NULL }, /* Ac */
211: { NULL, NULL }, /* Ao */
212: { NULL, posts_wline }, /* Aq */
213: { NULL, posts_at }, /* At */
214: { NULL, NULL }, /* Bc */
215: { NULL, posts_bf }, /* Bf */
216: { NULL, NULL }, /* Bo */
217: { NULL, posts_wline }, /* Bq */
218: { NULL, NULL }, /* Bsx */
219: { NULL, NULL }, /* Bx */
220: { NULL, posts_bool }, /* Db */
221: { NULL, NULL }, /* Dc */
222: { NULL, NULL }, /* Do */
223: { NULL, posts_wline }, /* Dq */
224: { NULL, NULL }, /* Ec */
225: { NULL, NULL }, /* Ef */
226: { NULL, posts_text }, /* Em */
227: { NULL, NULL }, /* Eo */
228: { NULL, NULL }, /* Fx */
229: { NULL, posts_text }, /* Ms */
230: { NULL, posts_notext }, /* No */
231: { NULL, posts_notext }, /* Ns */
232: { NULL, NULL }, /* Nx */
233: { NULL, NULL }, /* Ox */
234: { NULL, NULL }, /* Pc */
1.52 ! kristaps 235: { NULL, posts_pf }, /* Pf */
1.51 kristaps 236: { NULL, NULL }, /* Po */
237: { NULL, posts_wline }, /* Pq */
238: { NULL, NULL }, /* Qc */
239: { NULL, posts_wline }, /* Ql */
240: { NULL, NULL }, /* Qo */
241: { NULL, posts_wline }, /* Qq */
242: { NULL, NULL }, /* Re */
243: { NULL, posts_rs }, /* Rs */
244: { NULL, NULL }, /* Sc */
245: { NULL, NULL }, /* So */
246: { NULL, posts_wline }, /* Sq */
247: { NULL, posts_bool }, /* Sm */
248: { NULL, posts_text }, /* Sx */
249: { NULL, posts_text }, /* Sy */
250: { NULL, posts_text }, /* Tn */
251: { NULL, NULL }, /* Ux */
252: { NULL, NULL }, /* Xc */
253: { NULL, NULL }, /* Xo */
254: { NULL, posts_fo }, /* Fo */
255: { NULL, NULL }, /* Fc */
256: { NULL, NULL }, /* Oo */
257: { NULL, NULL }, /* Oc */
258: { NULL, posts_bk }, /* Bk */
259: { NULL, NULL }, /* Ek */
260: { NULL, posts_notext }, /* Bt */
261: { NULL, NULL }, /* Hf */
262: { NULL, NULL }, /* Fr */
263: { NULL, posts_notext }, /* Ud */
1.9 kristaps 264: };
1.6 kristaps 265:
266:
1.51 kristaps 267: static inline int
268: warn_count(struct mdoc *m, const char *k,
269: int want, const char *v, int has)
270: {
271:
272: return(mdoc_warn(m, WARN_SYNTAX, "suggests %s %d %s "
273: "(has %d)", v, want, k, has));
274: }
275:
276:
277: static inline int
278: err_count(struct mdoc *m, const char *k,
279: int want, const char *v, int has)
280: {
281:
282: return(mdoc_err(m, "requires %s %d %s (has %d)",
283: v, want, k, has));
284: }
285:
286:
287: static inline int
288: count_child(struct mdoc *mdoc)
1.36 kristaps 289: {
1.51 kristaps 290: int i;
1.36 kristaps 291: struct mdoc_node *n;
292:
293: for (i = 0, n = mdoc->last->child; n; n = n->next, i++)
294: /* Do nothing */ ;
295: return(i);
296: }
297:
298:
299: static int
1.51 kristaps 300: warn_child_gt(struct mdoc *mdoc, const char *p, int sz)
1.39 kristaps 301: {
302: int i;
303:
1.51 kristaps 304: if ((i = count_child(mdoc)) > sz)
1.39 kristaps 305: return(1);
1.51 kristaps 306: return(warn_count(mdoc, ">", sz, p, i));
1.39 kristaps 307: }
308:
309:
310: static int
1.51 kristaps 311: err_child_gt(struct mdoc *mdoc, const char *p, int sz)
1.36 kristaps 312: {
313: int i;
314:
1.51 kristaps 315: if ((i = count_child(mdoc)) > sz)
1.36 kristaps 316: return(1);
1.51 kristaps 317: return(err_count(mdoc, ">", sz, p, i));
1.39 kristaps 318: }
319:
320:
321: static int
1.51 kristaps 322: warn_child_eq(struct mdoc *mdoc, const char *p, int sz)
1.39 kristaps 323: {
324: int i;
325:
1.51 kristaps 326: if ((i = count_child(mdoc)) == sz)
1.39 kristaps 327: return(1);
1.51 kristaps 328: return(warn_count(mdoc, "==", sz, p, i));
1.36 kristaps 329: }
330:
331:
332: static int
1.51 kristaps 333: err_child_eq(struct mdoc *mdoc, const char *p, int sz)
1.36 kristaps 334: {
335: int i;
336:
1.51 kristaps 337: if ((i = count_child(mdoc)) == sz)
1.36 kristaps 338: return(1);
1.51 kristaps 339: return(err_count(mdoc, "==", sz, p, i));
1.36 kristaps 340: }
341:
342:
343: static int
1.51 kristaps 344: err_child_lt(struct mdoc *mdoc, const char *p, int sz)
1.36 kristaps 345: {
346: int i;
347:
1.51 kristaps 348: if ((i = count_child(mdoc)) < sz)
1.36 kristaps 349: return(1);
1.51 kristaps 350: return(err_count(mdoc, "<", sz, p, i));
1.36 kristaps 351: }
352:
353:
354: static int
1.51 kristaps 355: check_stdarg(struct mdoc *mdoc, struct mdoc_node *node)
1.36 kristaps 356: {
357:
1.51 kristaps 358: if (MDOC_Std == node->data.elem.argv[0].arg &&
359: 1 == node->data.elem.argc)
1.36 kristaps 360: return(1);
1.51 kristaps 361:
1.36 kristaps 362: return(mdoc_nwarn(mdoc, node, WARN_COMPAT,
363: "macro suggests single `%s' argument",
364: mdoc_argnames[MDOC_Std]));
365: }
366:
367:
368: static int
1.51 kristaps 369: check_msec(struct mdoc *mdoc, struct mdoc_node *node,
1.33 kristaps 370: int sz, enum mdoc_msec *msecs)
371: {
372: int i;
373:
374: for (i = 0; i < sz; i++)
375: if (msecs[i] == mdoc->meta.msec)
376: return(1);
1.37 kristaps 377: return(mdoc_nwarn(mdoc, node, WARN_COMPAT, "macro not "
378: "appropriate for manual section"));
1.33 kristaps 379: }
380:
381:
382: static int
1.51 kristaps 383: check_parent(struct mdoc *mdoc, struct mdoc_node *n,
384: int tok, enum mdoc_type t)
1.33 kristaps 385: {
386:
1.51 kristaps 387: assert(n->parent);
388: if ((MDOC_ROOT == t || tok == n->parent->tok) &&
389: (t == n->parent->type))
390: return(1);
391:
392: return(mdoc_nerr(mdoc, n, "require parent %s (have %s)",
393: MDOC_ROOT == t ? "<root>" :
394: mdoc_macronames[tok],
395: MDOC_ROOT == n->parent->type ? "<root>" :
396: mdoc_macronames[n->parent->type]));
1.33 kristaps 397: }
398:
399:
400: static int
1.37 kristaps 401: bwarn_ge1(struct mdoc *mdoc)
1.6 kristaps 402: {
403:
1.17 kristaps 404: if (MDOC_BODY != mdoc->last->type)
1.8 kristaps 405: return(1);
1.51 kristaps 406: return(warn_child_gt(mdoc, "multi-line parameters", 0));
1.39 kristaps 407: }
408:
409:
410: static int
411: ewarn_eq1(struct mdoc *mdoc)
412: {
413:
414: assert(MDOC_ELEM == mdoc->last->type);
1.51 kristaps 415: return(warn_child_eq(mdoc, "line parameters", 1));
1.8 kristaps 416: }
1.1 kristaps 417:
418:
1.8 kristaps 419: static int
1.37 kristaps 420: ewarn_eq0(struct mdoc *mdoc)
1.22 kristaps 421: {
422:
423: assert(MDOC_ELEM == mdoc->last->type);
1.51 kristaps 424: return(warn_child_eq(mdoc, "line parameters", 0));
1.22 kristaps 425: }
426:
427:
428: static int
1.37 kristaps 429: ewarn_ge1(struct mdoc *mdoc)
1.26 kristaps 430: {
431:
432: assert(MDOC_ELEM == mdoc->last->type);
1.51 kristaps 433: return(warn_child_gt(mdoc, "line parameters", 0));
1.26 kristaps 434: }
435:
436:
437: static int
1.37 kristaps 438: eerr_eq1(struct mdoc *mdoc)
1.34 kristaps 439: {
440:
441: assert(MDOC_ELEM == mdoc->last->type);
1.51 kristaps 442: return(err_child_eq(mdoc, "line parameters", 1));
1.36 kristaps 443: }
444:
445:
446: static int
1.37 kristaps 447: eerr_le2(struct mdoc *mdoc)
1.36 kristaps 448: {
449:
450: assert(MDOC_ELEM == mdoc->last->type);
1.51 kristaps 451: return(err_child_lt(mdoc, "line parameters", 3));
1.34 kristaps 452: }
453:
454:
455: static int
1.37 kristaps 456: eerr_le1(struct mdoc *mdoc)
1.35 kristaps 457: {
458:
459: assert(MDOC_ELEM == mdoc->last->type);
1.51 kristaps 460: return(err_child_lt(mdoc, "line parameters", 2));
1.35 kristaps 461: }
462:
463:
464: static int
1.37 kristaps 465: eerr_eq0(struct mdoc *mdoc)
1.26 kristaps 466: {
467:
468: assert(MDOC_ELEM == mdoc->last->type);
1.51 kristaps 469: return(err_child_eq(mdoc, "line parameters", 0));
1.26 kristaps 470: }
471:
472:
473: static int
1.37 kristaps 474: eerr_ge1(struct mdoc *mdoc)
1.8 kristaps 475: {
1.1 kristaps 476:
1.21 kristaps 477: assert(MDOC_ELEM == mdoc->last->type);
1.51 kristaps 478: return(err_child_gt(mdoc, "line parameters", 0));
1.1 kristaps 479: }
480:
481:
1.9 kristaps 482: static int
1.37 kristaps 483: herr_eq0(struct mdoc *mdoc)
1.24 kristaps 484: {
485:
486: if (MDOC_HEAD != mdoc->last->type)
487: return(1);
1.51 kristaps 488: return(err_child_eq(mdoc, "line parameters", 0));
1.24 kristaps 489: }
490:
491:
492: static int
1.41 kristaps 493: herr_le1(struct mdoc *mdoc)
494: {
495: if (MDOC_HEAD != mdoc->last->type)
496: return(1);
1.51 kristaps 497: return(err_child_lt(mdoc, "line parameters", 2));
1.41 kristaps 498: }
499:
500:
501: static int
1.37 kristaps 502: herr_ge1(struct mdoc *mdoc)
1.14 kristaps 503: {
504:
1.17 kristaps 505: if (MDOC_HEAD != mdoc->last->type)
1.14 kristaps 506: return(1);
1.51 kristaps 507: return(err_child_gt(mdoc, "line parameters", 0));
1.14 kristaps 508: }
509:
510:
511: static int
1.23 kristaps 512: pre_display(struct mdoc *mdoc, struct mdoc_node *node)
513: {
514: struct mdoc_node *n;
515:
1.24 kristaps 516: if (MDOC_BLOCK != node->type)
517: return(1);
518:
1.32 kristaps 519: assert(mdoc->last);
1.38 kristaps 520: /* LINTED */
1.32 kristaps 521: for (n = mdoc->last->parent; n; n = n->parent)
1.23 kristaps 522: if (MDOC_BLOCK == n->type)
1.25 kristaps 523: if (MDOC_Bd == n->tok)
1.23 kristaps 524: break;
525: if (NULL == n)
526: return(1);
1.31 kristaps 527: return(mdoc_nerr(mdoc, node, "displays may not be nested"));
1.23 kristaps 528: }
529:
530:
531: static int
1.24 kristaps 532: pre_bl(struct mdoc *mdoc, struct mdoc_node *node)
533: {
534: int type, err;
535: struct mdoc_arg *argv;
536: size_t i, argc;
537:
538: if (MDOC_BLOCK != node->type)
539: return(1);
1.25 kristaps 540: assert(MDOC_Bl == node->tok);
1.24 kristaps 541:
542: argv = NULL;
543: argc = node->data.block.argc;
544:
1.38 kristaps 545: /* LINTED */
1.24 kristaps 546: for (i = type = err = 0; i < argc; i++) {
547: argv = &node->data.block.argv[(int)i];
548: assert(argv);
549: switch (argv->arg) {
550: case (MDOC_Bullet):
551: /* FALLTHROUGH */
552: case (MDOC_Dash):
553: /* FALLTHROUGH */
554: case (MDOC_Enum):
555: /* FALLTHROUGH */
556: case (MDOC_Hyphen):
557: /* FALLTHROUGH */
558: case (MDOC_Item):
559: /* FALLTHROUGH */
560: case (MDOC_Tag):
561: /* FALLTHROUGH */
562: case (MDOC_Diag):
563: /* FALLTHROUGH */
564: case (MDOC_Hang):
565: /* FALLTHROUGH */
566: case (MDOC_Ohang):
567: /* FALLTHROUGH */
568: case (MDOC_Inset):
1.26 kristaps 569: /* FALLTHROUGH */
570: case (MDOC_Column):
1.24 kristaps 571: if (type)
572: err++;
573: type++;
574: break;
575: default:
576: break;
577: }
578: }
579: if (0 == type)
1.31 kristaps 580: return(mdoc_err(mdoc, "no list type specified"));
1.24 kristaps 581: if (0 == err)
582: return(1);
583: assert(argv);
584: return(mdoc_perr(mdoc, argv->line,
1.31 kristaps 585: argv->pos, "only one list type possible"));
1.24 kristaps 586: }
587:
588:
589: static int
590: pre_bd(struct mdoc *mdoc, struct mdoc_node *node)
591: {
592: int type, err;
593: struct mdoc_arg *argv;
594: size_t i, argc;
595:
596: if (MDOC_BLOCK != node->type)
597: return(1);
1.25 kristaps 598: assert(MDOC_Bd == node->tok);
1.24 kristaps 599:
600: argv = NULL;
601: argc = node->data.block.argc;
602:
1.38 kristaps 603: /* LINTED */
1.24 kristaps 604: for (err = i = type = 0; 0 == err && i < argc; i++) {
605: argv = &node->data.block.argv[(int)i];
606: assert(argv);
607: switch (argv->arg) {
608: case (MDOC_Ragged):
609: /* FALLTHROUGH */
610: case (MDOC_Unfilled):
611: /* FALLTHROUGH */
1.29 kristaps 612: case (MDOC_Filled):
613: /* FALLTHROUGH */
1.24 kristaps 614: case (MDOC_Literal):
615: /* FALLTHROUGH */
616: case (MDOC_File):
617: if (type)
618: err++;
619: type++;
620: break;
621: default:
622: break;
623: }
624: }
625: if (0 == type)
1.31 kristaps 626: return(mdoc_err(mdoc, "no display type specified"));
1.24 kristaps 627: if (0 == err)
628: return(1);
629: assert(argv);
630: return(mdoc_perr(mdoc, argv->line,
1.31 kristaps 631: argv->pos, "only one display type possible"));
1.24 kristaps 632: }
633:
634:
635: static int
1.33 kristaps 636: pre_ss(struct mdoc *mdoc, struct mdoc_node *node)
637: {
638:
1.35 kristaps 639: if (MDOC_BLOCK != node->type)
1.33 kristaps 640: return(1);
1.51 kristaps 641: return(check_parent(mdoc, node, MDOC_Sh, MDOC_BODY));
1.33 kristaps 642: }
643:
644:
645: static int
646: pre_sh(struct mdoc *mdoc, struct mdoc_node *node)
647: {
648:
1.35 kristaps 649: if (MDOC_BLOCK != node->type)
1.33 kristaps 650: return(1);
1.51 kristaps 651: return(check_parent(mdoc, node, -1, MDOC_ROOT));
1.33 kristaps 652: }
653:
654:
655: static int
1.36 kristaps 656: pre_st(struct mdoc *mdoc, struct mdoc_node *node)
657: {
658:
659: assert(MDOC_ELEM == node->type);
660: assert(MDOC_St == node->tok);
661: if (1 == node->data.elem.argc)
662: return(1);
663: return(mdoc_nerr(mdoc, node, "macro must have one argument"));
664: }
665:
666:
667: static int
1.35 kristaps 668: pre_an(struct mdoc *mdoc, struct mdoc_node *node)
669: {
1.36 kristaps 670:
1.35 kristaps 671: assert(MDOC_ELEM == node->type);
672: assert(MDOC_An == node->tok);
673: if (1 >= node->data.elem.argc)
674: return(1);
675: return(mdoc_nerr(mdoc, node, "macro may only have one argument"));
676: }
677:
678:
679: static int
1.36 kristaps 680: pre_rv(struct mdoc *mdoc, struct mdoc_node *node)
681: {
682: enum mdoc_msec msecs[2];
683:
684: assert(MDOC_ELEM == node->type);
685: assert(MDOC_Rv == node->tok);
686:
687: msecs[0] = MSEC_2;
688: msecs[1] = MSEC_3;
1.51 kristaps 689: if ( ! check_msec(mdoc, node, 2, msecs))
1.36 kristaps 690: return(0);
1.51 kristaps 691: return(check_stdarg(mdoc, node));
1.36 kristaps 692: }
693:
694:
695: static int
1.33 kristaps 696: pre_ex(struct mdoc *mdoc, struct mdoc_node *node)
697: {
698: enum mdoc_msec msecs[3];
699:
1.35 kristaps 700: assert(MDOC_ELEM == node->type);
1.36 kristaps 701: assert(MDOC_Ex == node->tok);
1.35 kristaps 702:
1.33 kristaps 703: msecs[0] = MSEC_1;
704: msecs[1] = MSEC_6;
705: msecs[2] = MSEC_8;
1.51 kristaps 706: if ( ! check_msec(mdoc, node, 3, msecs))
1.35 kristaps 707: return(0);
1.51 kristaps 708: return(check_stdarg(mdoc, node));
1.33 kristaps 709: }
710:
711:
712: static int
713: pre_er(struct mdoc *mdoc, struct mdoc_node *node)
714: {
715: enum mdoc_msec msecs[1];
716:
717: msecs[0] = MSEC_2;
1.51 kristaps 718: return(check_msec(mdoc, node, 1, msecs));
1.33 kristaps 719: }
720:
721:
722: static int
723: pre_cd(struct mdoc *mdoc, struct mdoc_node *node)
724: {
725: enum mdoc_msec msecs[1];
726:
727: msecs[0] = MSEC_4;
1.51 kristaps 728: return(check_msec(mdoc, node, 1, msecs));
1.33 kristaps 729: }
730:
731:
732: static int
1.25 kristaps 733: pre_it(struct mdoc *mdoc, struct mdoc_node *node)
734: {
735:
1.48 kristaps 736: /* TODO: -width attribute must be specified for -tag. */
1.49 kristaps 737: /* TODO: children too big for -width? */
1.48 kristaps 738:
1.35 kristaps 739: if (MDOC_BLOCK != node->type)
1.25 kristaps 740: return(1);
1.51 kristaps 741: return(check_parent(mdoc, node, MDOC_Bl, MDOC_BODY));
1.25 kristaps 742: }
743:
744:
745: static int
1.20 kristaps 746: pre_prologue(struct mdoc *mdoc, struct mdoc_node *node)
747: {
748:
1.46 kristaps 749: if (SEC_PROLOGUE != mdoc->lastnamed)
1.31 kristaps 750: return(mdoc_nerr(mdoc, node, "macro may only be invoked in the prologue"));
1.20 kristaps 751: assert(MDOC_ELEM == node->type);
752:
753: /* Check for ordering. */
754:
1.25 kristaps 755: switch (node->tok) {
1.20 kristaps 756: case (MDOC_Os):
1.36 kristaps 757: if (mdoc->meta.title && mdoc->meta.date)
1.20 kristaps 758: break;
1.31 kristaps 759: return(mdoc_nerr(mdoc, node, "prologue macro out-of-order"));
1.20 kristaps 760: case (MDOC_Dt):
1.36 kristaps 761: if (NULL == mdoc->meta.title && mdoc->meta.date)
1.20 kristaps 762: break;
1.31 kristaps 763: return(mdoc_nerr(mdoc, node, "prologue macro out-of-order"));
1.20 kristaps 764: case (MDOC_Dd):
1.36 kristaps 765: if (NULL == mdoc->meta.title && 0 == mdoc->meta.date)
1.20 kristaps 766: break;
1.31 kristaps 767: return(mdoc_nerr(mdoc, node, "prologue macro out-of-order"));
1.20 kristaps 768: default:
769: abort();
770: /* NOTREACHED */
771: }
772:
773: /* Check for repetition. */
774:
1.25 kristaps 775: switch (node->tok) {
1.20 kristaps 776: case (MDOC_Os):
1.36 kristaps 777: if (NULL == mdoc->meta.os)
1.20 kristaps 778: return(1);
779: break;
780: case (MDOC_Dd):
781: if (0 == mdoc->meta.date)
782: return(1);
783: break;
784: case (MDOC_Dt):
1.36 kristaps 785: if (NULL == mdoc->meta.title)
1.20 kristaps 786: return(1);
787: break;
788: default:
789: abort();
790: /* NOTREACHED */
791: }
792:
1.31 kristaps 793: return(mdoc_nerr(mdoc, node, "prologue macro repeated"));
1.20 kristaps 794: }
795:
796:
1.35 kristaps 797: static int
1.41 kristaps 798: post_bf(struct mdoc *mdoc)
799: {
800: char *p;
801: struct mdoc_node *head;
802:
803: if (MDOC_BLOCK != mdoc->last->type)
804: return(1);
805: assert(MDOC_Bf == mdoc->last->tok);
806: head = mdoc->last->data.block.head;
807: assert(head);
808:
809: if (0 == mdoc->last->data.block.argc) {
810: if (head->child) {
811: assert(MDOC_TEXT == head->child->type);
812: p = head->child->data.text.string;
813: if (xstrcmp(p, "Em"))
814: return(1);
815: else if (xstrcmp(p, "Li"))
816: return(1);
817: else if (xstrcmp(p, "Sm"))
818: return(1);
819: return(mdoc_nerr(mdoc, head->child, "invalid font mode"));
820: }
821: return(mdoc_err(mdoc, "macro expects an argument or parameter"));
822: }
823: if (head->child)
824: return(mdoc_err(mdoc, "macro expects an argument or parameter"));
825: if (1 == mdoc->last->data.block.argc)
826: return(1);
827: return(mdoc_err(mdoc, "macro expects an argument or parameter"));
828: }
829:
830:
831: static int
1.37 kristaps 832: post_nm(struct mdoc *mdoc)
833: {
834:
835: assert(MDOC_ELEM == mdoc->last->type);
836: assert(MDOC_Nm == mdoc->last->tok);
837: if (mdoc->last->child)
838: return(1);
839: if (mdoc->meta.name)
840: return(1);
841: return(mdoc_err(mdoc, "macro `%s' has not been invoked with a name",
842: mdoc_macronames[MDOC_Nm]));
843: }
844:
845:
846: static int
1.36 kristaps 847: post_xr(struct mdoc *mdoc)
848: {
849: struct mdoc_node *n;
850:
851: assert(MDOC_ELEM == mdoc->last->type);
852: assert(MDOC_Xr == mdoc->last->tok);
853: assert(mdoc->last->child);
854: assert(MDOC_TEXT == mdoc->last->child->type);
855:
856: if (NULL == (n = mdoc->last->child->next))
857: return(1);
858: assert(MDOC_TEXT == n->type);
859: if (MSEC_DEFAULT != mdoc_atomsec(n->data.text.string))
860: return(1);
861: return(mdoc_nerr(mdoc, n, "invalid manual section"));
862: }
863:
864:
865: static int
866: post_at(struct mdoc *mdoc)
867: {
868:
869: assert(MDOC_ELEM == mdoc->last->type);
870: assert(MDOC_At == mdoc->last->tok);
1.37 kristaps 871:
872: if (NULL == mdoc->last->child)
873: return(1);
1.36 kristaps 874: assert(MDOC_TEXT == mdoc->last->child->type);
875:
876: if (ATT_DEFAULT != mdoc_atoatt(mdoc->last->child->data.text.string))
877: return(1);
878: return(mdoc_err(mdoc, "macro expects a valid AT&T version symbol"));
879: }
880:
881:
882: static int
1.35 kristaps 883: post_an(struct mdoc *mdoc)
884: {
885:
886: assert(MDOC_ELEM == mdoc->last->type);
887: assert(MDOC_An == mdoc->last->tok);
888:
889: if (0 != mdoc->last->data.elem.argc) {
890: if (NULL == mdoc->last->child)
891: return(1);
892: return(mdoc_err(mdoc, "macro expects either argument or parameters"));
893: }
894:
895: if (mdoc->last->child)
896: return(1);
897: return(mdoc_err(mdoc, "macro expects either argument or parameters"));
898: }
899:
900:
901: static int
902: post_ex(struct mdoc *mdoc)
903: {
904:
905: assert(MDOC_ELEM == mdoc->last->type);
906: assert(MDOC_Ex == mdoc->last->tok);
907:
908: if (0 == mdoc->last->data.elem.argc) {
909: if (mdoc->last->child)
910: return(1);
911: return(mdoc_err(mdoc, "macro expects `%s' or a single child",
912: mdoc_argnames[MDOC_Std]));
913: }
914: if (mdoc->last->child)
915: return(mdoc_err(mdoc, "macro expects `%s' or a single child",
916: mdoc_argnames[MDOC_Std]));
917: if (1 != mdoc->last->data.elem.argc)
918: return(mdoc_err(mdoc, "macro expects `%s' or a single child",
919: mdoc_argnames[MDOC_Std]));
920: if (MDOC_Std != mdoc->last->data.elem.argv[0].arg)
921: return(mdoc_err(mdoc, "macro expects `%s' or a single child",
922: mdoc_argnames[MDOC_Std]));
923: return(1);
924: }
925:
926:
1.25 kristaps 927: /* Warn if `Bl' type-specific syntax isn't reflected in items. */
928: static int
929: post_it(struct mdoc *mdoc)
930: {
931: int type, sv;
932: #define TYPE_NONE (0)
933: #define TYPE_BODY (1)
934: #define TYPE_HEAD (2)
1.47 kristaps 935: #define TYPE_OHEAD (3)
1.25 kristaps 936: size_t i, argc;
937: struct mdoc_node *n;
938:
939: if (MDOC_BLOCK != mdoc->last->type)
940: return(1);
941:
942: assert(MDOC_It == mdoc->last->tok);
943:
944: n = mdoc->last->parent;
945: assert(n);
946: assert(MDOC_Bl == n->tok);
947:
948: n = n->parent;
949: assert(MDOC_BLOCK == n->type);
950: assert(MDOC_Bl == n->tok);
951:
952: argc = n->data.block.argc;
953: type = TYPE_NONE;
1.38 kristaps 954: sv = -1;
1.26 kristaps 955:
956: /* Some types require block-head, some not. */
1.25 kristaps 957:
1.38 kristaps 958: /* LINTED */
1.25 kristaps 959: for (i = 0; TYPE_NONE == type && i < argc; i++)
960: switch (n->data.block.argv[(int)i].arg) {
961: case (MDOC_Tag):
962: /* FALLTHROUGH */
963: case (MDOC_Diag):
964: /* FALLTHROUGH */
965: case (MDOC_Hang):
966: /* FALLTHROUGH */
967: case (MDOC_Ohang):
968: /* FALLTHROUGH */
969: case (MDOC_Inset):
970: type = TYPE_HEAD;
971: sv = n->data.block.argv[(int)i].arg;
972: break;
973: case (MDOC_Bullet):
974: /* FALLTHROUGH */
975: case (MDOC_Dash):
976: /* FALLTHROUGH */
977: case (MDOC_Enum):
978: /* FALLTHROUGH */
979: case (MDOC_Hyphen):
980: /* FALLTHROUGH */
981: case (MDOC_Item):
1.47 kristaps 982: type = TYPE_BODY;
983: sv = n->data.block.argv[(int)i].arg;
984: break;
1.25 kristaps 985: case (MDOC_Column):
1.47 kristaps 986: type = TYPE_OHEAD;
1.25 kristaps 987: sv = n->data.block.argv[(int)i].arg;
988: break;
989: default:
990: break;
991: }
992:
993: assert(TYPE_NONE != type);
994:
1.47 kristaps 995: n = mdoc->last->data.block.head;
996: assert(n);
997:
1.25 kristaps 998: if (TYPE_HEAD == type) {
1.33 kristaps 999: if (NULL == n->child)
1.31 kristaps 1000: if ( ! mdoc_warn(mdoc, WARN_SYNTAX, "macro suggests line parameters"))
1.25 kristaps 1001: return(0);
1002:
1.33 kristaps 1003: n = mdoc->last->data.block.body;
1004: assert(n);
1005: if (NULL == n->child)
1.31 kristaps 1006: if ( ! mdoc_warn(mdoc, WARN_SYNTAX, "macro suggests body children"))
1.25 kristaps 1007: return(0);
1008:
1.47 kristaps 1009: } else if (TYPE_BODY == type) {
1010: if (n->child)
1011: if ( ! mdoc_warn(mdoc, WARN_SYNTAX, "macro suggests no line parameters"))
1012: return(0);
1013:
1014: n = mdoc->last->data.block.body;
1015: assert(n);
1016: if (NULL == n->child)
1017: if ( ! mdoc_warn(mdoc, WARN_SYNTAX, "macro suggests body children"))
1018: return(0);
1019: } else {
1020: if (NULL == n->child)
1021: if ( ! mdoc_warn(mdoc, WARN_SYNTAX, "macro suggests line parameters"))
1022: return(0);
1023:
1024: n = mdoc->last->data.block.body;
1025: assert(n);
1026: if (n->child)
1027: if ( ! mdoc_warn(mdoc, WARN_SYNTAX, "macro suggests no body children"))
1028: return(0);
1.25 kristaps 1029: }
1030:
1.47 kristaps 1031: if (MDOC_Column != sv)
1.26 kristaps 1032: return(1);
1033:
1034: /* Make sure the number of columns is sane. */
1035:
1.38 kristaps 1036: argc = mdoc->last->parent->parent->data.block.argv->sz;
1.26 kristaps 1037: n = mdoc->last->data.block.head->child;
1.25 kristaps 1038:
1.26 kristaps 1039: for (i = 0; n; n = n->next)
1040: i++;
1041:
1.38 kristaps 1042: if (i == argc)
1.26 kristaps 1043: return(1);
1.38 kristaps 1044: return(mdoc_err(mdoc, "expected %zu list columns, have %zu", argc, i));
1.25 kristaps 1045: #undef TYPE_NONE
1046: #undef TYPE_BODY
1047: #undef TYPE_HEAD
1.47 kristaps 1048: #undef TYPE_OHEAD
1.25 kristaps 1049: }
1050:
1051:
1.24 kristaps 1052: static int
1053: post_bl(struct mdoc *mdoc)
1054: {
1055: struct mdoc_node *n;
1056:
1057: if (MDOC_BODY != mdoc->last->type)
1058: return(1);
1.25 kristaps 1059: assert(MDOC_Bl == mdoc->last->tok);
1.24 kristaps 1060:
1.38 kristaps 1061: /* LINTED */
1.24 kristaps 1062: for (n = mdoc->last->child; n; n = n->next) {
1063: if (MDOC_BLOCK == n->type)
1.25 kristaps 1064: if (MDOC_It == n->tok)
1.24 kristaps 1065: continue;
1066: break;
1067: }
1068: if (NULL == n)
1069: return(1);
1.31 kristaps 1070: return(mdoc_nerr(mdoc, n, "invalid child of parent macro `Bl'"));
1.24 kristaps 1071: }
1072:
1073:
1.34 kristaps 1074: static int
1.37 kristaps 1075: ebool(struct mdoc *mdoc)
1.34 kristaps 1076: {
1077: struct mdoc_node *n;
1078:
1079: assert(MDOC_ELEM == mdoc->last->type);
1.38 kristaps 1080: /* LINTED */
1.34 kristaps 1081: for (n = mdoc->last->child; n; n = n->next) {
1082: if (MDOC_TEXT != n->type)
1083: break;
1084: if (xstrcmp(n->data.text.string, "on"))
1085: continue;
1086: if (xstrcmp(n->data.text.string, "off"))
1087: continue;
1088: break;
1089: }
1090: if (NULL == n)
1091: return(1);
1.37 kristaps 1092: return(mdoc_nerr(mdoc, n, "expected boolean value"));
1093: }
1094:
1095:
1096: static int
1097: post_root(struct mdoc *mdoc)
1098: {
1099:
1.46 kristaps 1100: if (NULL == mdoc->first->child)
1.37 kristaps 1101: return(mdoc_err(mdoc, "document has no data"));
1.46 kristaps 1102: if (SEC_PROLOGUE == mdoc->lastnamed)
1.39 kristaps 1103: return(mdoc_err(mdoc, "document has incomplete prologue"));
1.46 kristaps 1104: if (MDOC_BLOCK != mdoc->first->child->type)
1105: return(mdoc_err(mdoc, "document expects `%s' macro after prologue", mdoc_macronames[MDOC_Sh]));
1106: if (MDOC_Sh != mdoc->first->child->tok)
1107: return(mdoc_err(mdoc, "document expects `%s' macro after prologue", mdoc_macronames[MDOC_Sh]));
1.37 kristaps 1108: return(1);
1.34 kristaps 1109: }
1110:
1111:
1.20 kristaps 1112: static int
1.21 kristaps 1113: post_sh(struct mdoc *mdoc)
1.14 kristaps 1114: {
1.46 kristaps 1115:
1116: if (MDOC_HEAD == mdoc->last->type)
1117: return(post_sh_head(mdoc));
1118: if (MDOC_BODY == mdoc->last->type)
1119: return(post_sh_body(mdoc));
1120: return(1);
1121: }
1122:
1123:
1124: static int
1125: post_sh_body(struct mdoc *mdoc)
1126: {
1127: struct mdoc_node *n;
1128:
1129: assert(MDOC_Sh == mdoc->last->tok);
1.51 kristaps 1130: assert(MDOC_BODY == mdoc->last->type);
1.46 kristaps 1131: if (SEC_NAME != mdoc->lastnamed)
1132: return(1);
1133:
1.51 kristaps 1134: /*
1135: * Warn if the NAME section doesn't contain the `Nm' and `Nd'
1136: * macros (can have multiple `Nm' and one `Nd'). Note that the
1137: * children of the BODY declaration can also be "text".
1138: */
1139:
1.46 kristaps 1140: if (NULL == (n = mdoc->last->child))
1.51 kristaps 1141: return(mdoc_warn(mdoc, WARN_COMPAT, "section NAME "
1142: "should contain %s and %s",
1143: mdoc_macronames[MDOC_Nm],
1144: mdoc_macronames[MDOC_Nd]));
1145:
1146: for ( ; n && n->next; n = n->next) {
1147: if (MDOC_ELEM == n->type && MDOC_Nm == n->tok)
1148: continue;
1149: if (MDOC_TEXT == n->type)
1150: continue;
1151: if ( ! (mdoc_nwarn(mdoc, n, WARN_COMPAT, "section "
1152: "NAME should contain %s as "
1153: "initial body child",
1154: mdoc_macronames[MDOC_Nm])))
1155: return(0);
1156: }
1157:
1158: if (MDOC_ELEM == n->type && MDOC_Nd == n->tok)
1.46 kristaps 1159: return(1);
1160:
1.51 kristaps 1161: return(mdoc_warn(mdoc, WARN_COMPAT, "section NAME should "
1162: "contain %s as the last child",
1163: mdoc_macronames[MDOC_Nd]));
1.46 kristaps 1164: }
1165:
1166:
1167: static int
1168: post_sh_head(struct mdoc *mdoc)
1169: {
1.36 kristaps 1170: char buf[64];
1.21 kristaps 1171: enum mdoc_sec sec;
1172:
1.25 kristaps 1173: assert(MDOC_Sh == mdoc->last->tok);
1.21 kristaps 1174:
1.36 kristaps 1175: if ( ! xstrlcats(buf, mdoc->last->child, 64))
1176: return(mdoc_err(mdoc, "macro parameters too long"));
1.14 kristaps 1177:
1.46 kristaps 1178: sec = mdoc_atosec(buf);
1179:
1180: if (SEC_BODY == mdoc->lastnamed && SEC_NAME != sec)
1181: return(mdoc_err(mdoc, "section NAME must be first"));
1182: if (SEC_CUSTOM == sec)
1.21 kristaps 1183: return(1);
1.46 kristaps 1184: if (sec == mdoc->lastnamed)
1.31 kristaps 1185: return(mdoc_warn(mdoc, WARN_SYNTAX, "section repeated"));
1.46 kristaps 1186: if (sec < mdoc->lastnamed)
1187: return(mdoc_warn(mdoc, WARN_SYNTAX, "section out of conventional order"));
1188:
1189: return(1);
1.11 kristaps 1190: }
1191:
1192:
1.17 kristaps 1193: int
1.18 kristaps 1194: mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *node)
1.11 kristaps 1195: {
1.24 kristaps 1196: v_pre *p;
1.18 kristaps 1197:
1.25 kristaps 1198: if (MDOC_TEXT == node->type)
1.18 kristaps 1199: return(1);
1.25 kristaps 1200: assert(MDOC_ROOT != node->type);
1.11 kristaps 1201:
1.25 kristaps 1202: if (NULL == mdoc_valids[node->tok].pre)
1.11 kristaps 1203: return(1);
1.25 kristaps 1204: for (p = mdoc_valids[node->tok].pre; *p; p++)
1.24 kristaps 1205: if ( ! (*p)(mdoc, node))
1206: return(0);
1207: return(1);
1.11 kristaps 1208: }
1209:
1210:
1.17 kristaps 1211: int
1.18 kristaps 1212: mdoc_valid_post(struct mdoc *mdoc)
1.11 kristaps 1213: {
1.17 kristaps 1214: v_post *p;
1.11 kristaps 1215:
1.39 kristaps 1216: if (MDOC_VALID & mdoc->last->flags)
1217: return(1);
1218: mdoc->last->flags |= MDOC_VALID;
1219:
1.25 kristaps 1220: if (MDOC_TEXT == mdoc->last->type)
1221: return(1);
1.37 kristaps 1222: if (MDOC_ROOT == mdoc->last->type)
1223: return(post_root(mdoc));
1.14 kristaps 1224:
1.25 kristaps 1225: if (NULL == mdoc_valids[mdoc->last->tok].post)
1.9 kristaps 1226: return(1);
1.25 kristaps 1227: for (p = mdoc_valids[mdoc->last->tok].post; *p; p++)
1.18 kristaps 1228: if ( ! (*p)(mdoc))
1.17 kristaps 1229: return(0);
1.11 kristaps 1230:
1.14 kristaps 1231: return(1);
1.11 kristaps 1232: }
1.14 kristaps 1233:
CVSweb