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