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