Annotation of mandoc/validate.c, Revision 1.49
1.49 ! kristaps 1: /* $Id: validate.c,v 1.48 2009/02/21 14:56: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.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.48 kristaps 711: /* TODO: -width attribute must be specified for -tag. */
1.49 ! kristaps 712: /* TODO: children too big for -width? */
1.48 kristaps 713:
1.35 kristaps 714: if (MDOC_BLOCK != node->type)
1.25 kristaps 715: return(1);
1.33 kristaps 716: return(pre_check_parent(mdoc, node, MDOC_Bl, MDOC_BODY));
1.25 kristaps 717: }
718:
719:
720: static int
1.20 kristaps 721: pre_prologue(struct mdoc *mdoc, struct mdoc_node *node)
722: {
723:
1.46 kristaps 724: if (SEC_PROLOGUE != mdoc->lastnamed)
1.31 kristaps 725: return(mdoc_nerr(mdoc, node, "macro may only be invoked in the prologue"));
1.20 kristaps 726: assert(MDOC_ELEM == node->type);
727:
728: /* Check for ordering. */
729:
1.25 kristaps 730: switch (node->tok) {
1.20 kristaps 731: case (MDOC_Os):
1.36 kristaps 732: if (mdoc->meta.title && mdoc->meta.date)
1.20 kristaps 733: break;
1.31 kristaps 734: return(mdoc_nerr(mdoc, node, "prologue macro out-of-order"));
1.20 kristaps 735: case (MDOC_Dt):
1.36 kristaps 736: if (NULL == mdoc->meta.title && mdoc->meta.date)
1.20 kristaps 737: break;
1.31 kristaps 738: return(mdoc_nerr(mdoc, node, "prologue macro out-of-order"));
1.20 kristaps 739: case (MDOC_Dd):
1.36 kristaps 740: if (NULL == mdoc->meta.title && 0 == mdoc->meta.date)
1.20 kristaps 741: break;
1.31 kristaps 742: return(mdoc_nerr(mdoc, node, "prologue macro out-of-order"));
1.20 kristaps 743: default:
744: abort();
745: /* NOTREACHED */
746: }
747:
748: /* Check for repetition. */
749:
1.25 kristaps 750: switch (node->tok) {
1.20 kristaps 751: case (MDOC_Os):
1.36 kristaps 752: if (NULL == mdoc->meta.os)
1.20 kristaps 753: return(1);
754: break;
755: case (MDOC_Dd):
756: if (0 == mdoc->meta.date)
757: return(1);
758: break;
759: case (MDOC_Dt):
1.36 kristaps 760: if (NULL == mdoc->meta.title)
1.20 kristaps 761: return(1);
762: break;
763: default:
764: abort();
765: /* NOTREACHED */
766: }
767:
1.31 kristaps 768: return(mdoc_nerr(mdoc, node, "prologue macro repeated"));
1.20 kristaps 769: }
770:
771:
1.35 kristaps 772: static int
1.41 kristaps 773: post_bf(struct mdoc *mdoc)
774: {
775: char *p;
776: struct mdoc_node *head;
777:
778: if (MDOC_BLOCK != mdoc->last->type)
779: return(1);
780: assert(MDOC_Bf == mdoc->last->tok);
781: head = mdoc->last->data.block.head;
782: assert(head);
783:
784: if (0 == mdoc->last->data.block.argc) {
785: if (head->child) {
786: assert(MDOC_TEXT == head->child->type);
787: p = head->child->data.text.string;
788: if (xstrcmp(p, "Em"))
789: return(1);
790: else if (xstrcmp(p, "Li"))
791: return(1);
792: else if (xstrcmp(p, "Sm"))
793: return(1);
794: return(mdoc_nerr(mdoc, head->child, "invalid font mode"));
795: }
796: return(mdoc_err(mdoc, "macro expects an argument or parameter"));
797: }
798: if (head->child)
799: return(mdoc_err(mdoc, "macro expects an argument or parameter"));
800: if (1 == mdoc->last->data.block.argc)
801: return(1);
802: return(mdoc_err(mdoc, "macro expects an argument or parameter"));
803: }
804:
805:
806: static int
1.37 kristaps 807: post_nm(struct mdoc *mdoc)
808: {
809:
810: assert(MDOC_ELEM == mdoc->last->type);
811: assert(MDOC_Nm == mdoc->last->tok);
812: if (mdoc->last->child)
813: return(1);
814: if (mdoc->meta.name)
815: return(1);
816: return(mdoc_err(mdoc, "macro `%s' has not been invoked with a name",
817: mdoc_macronames[MDOC_Nm]));
818: }
819:
820:
821: static int
1.36 kristaps 822: post_xr(struct mdoc *mdoc)
823: {
824: struct mdoc_node *n;
825:
826: assert(MDOC_ELEM == mdoc->last->type);
827: assert(MDOC_Xr == mdoc->last->tok);
828: assert(mdoc->last->child);
829: assert(MDOC_TEXT == mdoc->last->child->type);
830:
831: if (NULL == (n = mdoc->last->child->next))
832: return(1);
833: assert(MDOC_TEXT == n->type);
834: if (MSEC_DEFAULT != mdoc_atomsec(n->data.text.string))
835: return(1);
836: return(mdoc_nerr(mdoc, n, "invalid manual section"));
837: }
838:
839:
840: static int
841: post_at(struct mdoc *mdoc)
842: {
843:
844: assert(MDOC_ELEM == mdoc->last->type);
845: assert(MDOC_At == mdoc->last->tok);
1.37 kristaps 846:
847: if (NULL == mdoc->last->child)
848: return(1);
1.36 kristaps 849: assert(MDOC_TEXT == mdoc->last->child->type);
850:
851: if (ATT_DEFAULT != mdoc_atoatt(mdoc->last->child->data.text.string))
852: return(1);
853: return(mdoc_err(mdoc, "macro expects a valid AT&T version symbol"));
854: }
855:
856:
857: static int
1.35 kristaps 858: post_an(struct mdoc *mdoc)
859: {
860:
861: assert(MDOC_ELEM == mdoc->last->type);
862: assert(MDOC_An == mdoc->last->tok);
863:
864: if (0 != mdoc->last->data.elem.argc) {
865: if (NULL == mdoc->last->child)
866: return(1);
867: return(mdoc_err(mdoc, "macro expects either argument or parameters"));
868: }
869:
870: if (mdoc->last->child)
871: return(1);
872: return(mdoc_err(mdoc, "macro expects either argument or parameters"));
873: }
874:
875:
876: static int
877: post_ex(struct mdoc *mdoc)
878: {
879:
880: assert(MDOC_ELEM == mdoc->last->type);
881: assert(MDOC_Ex == mdoc->last->tok);
882:
883: if (0 == mdoc->last->data.elem.argc) {
884: if (mdoc->last->child)
885: return(1);
886: return(mdoc_err(mdoc, "macro expects `%s' or a single child",
887: mdoc_argnames[MDOC_Std]));
888: }
889: if (mdoc->last->child)
890: return(mdoc_err(mdoc, "macro expects `%s' or a single child",
891: mdoc_argnames[MDOC_Std]));
892: if (1 != mdoc->last->data.elem.argc)
893: return(mdoc_err(mdoc, "macro expects `%s' or a single child",
894: mdoc_argnames[MDOC_Std]));
895: if (MDOC_Std != mdoc->last->data.elem.argv[0].arg)
896: return(mdoc_err(mdoc, "macro expects `%s' or a single child",
897: mdoc_argnames[MDOC_Std]));
898: return(1);
899: }
900:
901:
1.25 kristaps 902: /* Warn if `Bl' type-specific syntax isn't reflected in items. */
903: static int
904: post_it(struct mdoc *mdoc)
905: {
906: int type, sv;
907: #define TYPE_NONE (0)
908: #define TYPE_BODY (1)
909: #define TYPE_HEAD (2)
1.47 kristaps 910: #define TYPE_OHEAD (3)
1.25 kristaps 911: size_t i, argc;
912: struct mdoc_node *n;
913:
914: if (MDOC_BLOCK != mdoc->last->type)
915: return(1);
916:
917: assert(MDOC_It == mdoc->last->tok);
918:
919: n = mdoc->last->parent;
920: assert(n);
921: assert(MDOC_Bl == n->tok);
922:
923: n = n->parent;
924: assert(MDOC_BLOCK == n->type);
925: assert(MDOC_Bl == n->tok);
926:
927: argc = n->data.block.argc;
928: type = TYPE_NONE;
1.38 kristaps 929: sv = -1;
1.26 kristaps 930:
931: /* Some types require block-head, some not. */
1.25 kristaps 932:
1.38 kristaps 933: /* LINTED */
1.25 kristaps 934: for (i = 0; TYPE_NONE == type && i < argc; i++)
935: switch (n->data.block.argv[(int)i].arg) {
936: case (MDOC_Tag):
937: /* FALLTHROUGH */
938: case (MDOC_Diag):
939: /* FALLTHROUGH */
940: case (MDOC_Hang):
941: /* FALLTHROUGH */
942: case (MDOC_Ohang):
943: /* FALLTHROUGH */
944: case (MDOC_Inset):
945: type = TYPE_HEAD;
946: sv = n->data.block.argv[(int)i].arg;
947: break;
948: case (MDOC_Bullet):
949: /* FALLTHROUGH */
950: case (MDOC_Dash):
951: /* FALLTHROUGH */
952: case (MDOC_Enum):
953: /* FALLTHROUGH */
954: case (MDOC_Hyphen):
955: /* FALLTHROUGH */
956: case (MDOC_Item):
1.47 kristaps 957: type = TYPE_BODY;
958: sv = n->data.block.argv[(int)i].arg;
959: break;
1.25 kristaps 960: case (MDOC_Column):
1.47 kristaps 961: type = TYPE_OHEAD;
1.25 kristaps 962: sv = n->data.block.argv[(int)i].arg;
963: break;
964: default:
965: break;
966: }
967:
968: assert(TYPE_NONE != type);
969:
1.47 kristaps 970: n = mdoc->last->data.block.head;
971: assert(n);
972:
1.25 kristaps 973: if (TYPE_HEAD == type) {
1.33 kristaps 974: if (NULL == n->child)
1.31 kristaps 975: if ( ! mdoc_warn(mdoc, WARN_SYNTAX, "macro suggests line parameters"))
1.25 kristaps 976: return(0);
977:
1.33 kristaps 978: n = mdoc->last->data.block.body;
979: assert(n);
980: if (NULL == n->child)
1.31 kristaps 981: if ( ! mdoc_warn(mdoc, WARN_SYNTAX, "macro suggests body children"))
1.25 kristaps 982: return(0);
983:
1.47 kristaps 984: } else if (TYPE_BODY == type) {
985: if (n->child)
986: if ( ! mdoc_warn(mdoc, WARN_SYNTAX, "macro suggests no line parameters"))
987: return(0);
988:
989: n = mdoc->last->data.block.body;
990: assert(n);
991: if (NULL == n->child)
992: if ( ! mdoc_warn(mdoc, WARN_SYNTAX, "macro suggests body children"))
993: return(0);
994: } else {
995: if (NULL == n->child)
996: if ( ! mdoc_warn(mdoc, WARN_SYNTAX, "macro suggests line parameters"))
997: return(0);
998:
999: n = mdoc->last->data.block.body;
1000: assert(n);
1001: if (n->child)
1002: if ( ! mdoc_warn(mdoc, WARN_SYNTAX, "macro suggests no body children"))
1003: return(0);
1.25 kristaps 1004: }
1005:
1.47 kristaps 1006: if (MDOC_Column != sv)
1.26 kristaps 1007: return(1);
1008:
1009: /* Make sure the number of columns is sane. */
1010:
1.38 kristaps 1011: argc = mdoc->last->parent->parent->data.block.argv->sz;
1.26 kristaps 1012: n = mdoc->last->data.block.head->child;
1.25 kristaps 1013:
1.26 kristaps 1014: for (i = 0; n; n = n->next)
1015: i++;
1016:
1.38 kristaps 1017: if (i == argc)
1.26 kristaps 1018: return(1);
1.38 kristaps 1019: return(mdoc_err(mdoc, "expected %zu list columns, have %zu", argc, i));
1.25 kristaps 1020: #undef TYPE_NONE
1021: #undef TYPE_BODY
1022: #undef TYPE_HEAD
1.47 kristaps 1023: #undef TYPE_OHEAD
1.25 kristaps 1024: }
1025:
1026:
1.24 kristaps 1027: static int
1028: post_bl(struct mdoc *mdoc)
1029: {
1030: struct mdoc_node *n;
1031:
1032: if (MDOC_BODY != mdoc->last->type)
1033: return(1);
1.25 kristaps 1034: assert(MDOC_Bl == mdoc->last->tok);
1.24 kristaps 1035:
1.38 kristaps 1036: /* LINTED */
1.24 kristaps 1037: for (n = mdoc->last->child; n; n = n->next) {
1038: if (MDOC_BLOCK == n->type)
1.25 kristaps 1039: if (MDOC_It == n->tok)
1.24 kristaps 1040: continue;
1041: break;
1042: }
1043: if (NULL == n)
1044: return(1);
1.31 kristaps 1045: return(mdoc_nerr(mdoc, n, "invalid child of parent macro `Bl'"));
1.24 kristaps 1046: }
1047:
1048:
1.34 kristaps 1049: static int
1.37 kristaps 1050: ebool(struct mdoc *mdoc)
1.34 kristaps 1051: {
1052: struct mdoc_node *n;
1053:
1054: assert(MDOC_ELEM == mdoc->last->type);
1.38 kristaps 1055: /* LINTED */
1.34 kristaps 1056: for (n = mdoc->last->child; n; n = n->next) {
1057: if (MDOC_TEXT != n->type)
1058: break;
1059: if (xstrcmp(n->data.text.string, "on"))
1060: continue;
1061: if (xstrcmp(n->data.text.string, "off"))
1062: continue;
1063: break;
1064: }
1065: if (NULL == n)
1066: return(1);
1.37 kristaps 1067: return(mdoc_nerr(mdoc, n, "expected boolean value"));
1068: }
1069:
1070:
1071: static int
1072: post_root(struct mdoc *mdoc)
1073: {
1074:
1.46 kristaps 1075: if (NULL == mdoc->first->child)
1.37 kristaps 1076: return(mdoc_err(mdoc, "document has no data"));
1.46 kristaps 1077: if (SEC_PROLOGUE == mdoc->lastnamed)
1.39 kristaps 1078: return(mdoc_err(mdoc, "document has incomplete prologue"));
1.46 kristaps 1079: if (MDOC_BLOCK != mdoc->first->child->type)
1080: return(mdoc_err(mdoc, "document expects `%s' macro after prologue", mdoc_macronames[MDOC_Sh]));
1081: if (MDOC_Sh != mdoc->first->child->tok)
1082: return(mdoc_err(mdoc, "document expects `%s' macro after prologue", mdoc_macronames[MDOC_Sh]));
1.37 kristaps 1083: return(1);
1.34 kristaps 1084: }
1085:
1086:
1.20 kristaps 1087: static int
1.21 kristaps 1088: post_sh(struct mdoc *mdoc)
1.14 kristaps 1089: {
1.46 kristaps 1090:
1091: if (MDOC_HEAD == mdoc->last->type)
1092: return(post_sh_head(mdoc));
1093: if (MDOC_BODY == mdoc->last->type)
1094: return(post_sh_body(mdoc));
1095: return(1);
1096: }
1097:
1098:
1099: static int
1100: post_sh_body(struct mdoc *mdoc)
1101: {
1102: struct mdoc_node *n;
1103:
1104: assert(MDOC_Sh == mdoc->last->tok);
1105: if (SEC_NAME != mdoc->lastnamed)
1106: return(1);
1107:
1108: if (NULL == (n = mdoc->last->child))
1109: return(mdoc_err(mdoc, "section NAME must contain %s as the first body child", mdoc_macronames[MDOC_Nm]));
1110: if (MDOC_ELEM != n->type || MDOC_Nm != n->tok)
1111: return(mdoc_err(mdoc, "section NAME must contain %s as the first body child", mdoc_macronames[MDOC_Nm]));
1112: if (NULL == (n = n->next))
1113: return(mdoc_err(mdoc, "section NAME must contain %s as the second body child", mdoc_macronames[MDOC_Nd]));
1114: if (MDOC_ELEM != n->type || MDOC_Nd != n->tok)
1115: return(mdoc_err(mdoc, "section NAME must contain %s as the second body child", mdoc_macronames[MDOC_Nd]));
1116: if (NULL == (n = n->next))
1117: return(1);
1118:
1119: return(mdoc_warn(mdoc, WARN_SYNTAX, "section NAME usually limited to %s and %s body children",
1120: mdoc_macronames[MDOC_Nm], mdoc_macronames[MDOC_Nd]));
1121: }
1122:
1123:
1124: static int
1125: post_sh_head(struct mdoc *mdoc)
1126: {
1.36 kristaps 1127: char buf[64];
1.21 kristaps 1128: enum mdoc_sec sec;
1129:
1.25 kristaps 1130: assert(MDOC_Sh == mdoc->last->tok);
1.21 kristaps 1131:
1.36 kristaps 1132: if ( ! xstrlcats(buf, mdoc->last->child, 64))
1133: return(mdoc_err(mdoc, "macro parameters too long"));
1.14 kristaps 1134:
1.46 kristaps 1135: sec = mdoc_atosec(buf);
1136:
1137: if (SEC_BODY == mdoc->lastnamed && SEC_NAME != sec)
1138: return(mdoc_err(mdoc, "section NAME must be first"));
1139: if (SEC_CUSTOM == sec)
1.21 kristaps 1140: return(1);
1.46 kristaps 1141: if (sec == mdoc->lastnamed)
1.31 kristaps 1142: return(mdoc_warn(mdoc, WARN_SYNTAX, "section repeated"));
1.46 kristaps 1143: if (sec < mdoc->lastnamed)
1144: return(mdoc_warn(mdoc, WARN_SYNTAX, "section out of conventional order"));
1145:
1146: return(1);
1.11 kristaps 1147: }
1148:
1149:
1.17 kristaps 1150: int
1.18 kristaps 1151: mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *node)
1.11 kristaps 1152: {
1.24 kristaps 1153: v_pre *p;
1.18 kristaps 1154:
1.25 kristaps 1155: if (MDOC_TEXT == node->type)
1.18 kristaps 1156: return(1);
1.25 kristaps 1157: assert(MDOC_ROOT != node->type);
1.11 kristaps 1158:
1.25 kristaps 1159: if (NULL == mdoc_valids[node->tok].pre)
1.11 kristaps 1160: return(1);
1.25 kristaps 1161: for (p = mdoc_valids[node->tok].pre; *p; p++)
1.24 kristaps 1162: if ( ! (*p)(mdoc, node))
1163: return(0);
1164: return(1);
1.11 kristaps 1165: }
1166:
1167:
1.17 kristaps 1168: int
1.18 kristaps 1169: mdoc_valid_post(struct mdoc *mdoc)
1.11 kristaps 1170: {
1.17 kristaps 1171: v_post *p;
1.11 kristaps 1172:
1.39 kristaps 1173: if (MDOC_VALID & mdoc->last->flags)
1174: return(1);
1175: mdoc->last->flags |= MDOC_VALID;
1176:
1.25 kristaps 1177: if (MDOC_TEXT == mdoc->last->type)
1178: return(1);
1.37 kristaps 1179: if (MDOC_ROOT == mdoc->last->type)
1180: return(post_root(mdoc));
1.14 kristaps 1181:
1.25 kristaps 1182: if (NULL == mdoc_valids[mdoc->last->tok].post)
1.9 kristaps 1183: return(1);
1.25 kristaps 1184: for (p = mdoc_valids[mdoc->last->tok].post; *p; p++)
1.18 kristaps 1185: if ( ! (*p)(mdoc))
1.17 kristaps 1186: return(0);
1.11 kristaps 1187:
1.14 kristaps 1188: return(1);
1.11 kristaps 1189: }
1.14 kristaps 1190:
CVSweb