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