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