Annotation of mandoc/validate.c, Revision 1.37
1.37 ! kristaps 1: /* $Id: validate.c,v 1.36 2009/01/17 16:15:27 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);
468: for (n = mdoc->last->parent; n; n = n->parent)
1.23 kristaps 469: if (MDOC_BLOCK == n->type)
1.25 kristaps 470: if (MDOC_Bd == n->tok)
1.23 kristaps 471: break;
472: if (NULL == n)
473: return(1);
1.31 kristaps 474: return(mdoc_nerr(mdoc, node, "displays may not be nested"));
1.23 kristaps 475: }
476:
477:
478: static int
1.24 kristaps 479: pre_bl(struct mdoc *mdoc, struct mdoc_node *node)
480: {
481: int type, err;
482: struct mdoc_arg *argv;
483: size_t i, argc;
484:
485: if (MDOC_BLOCK != node->type)
486: return(1);
1.25 kristaps 487: assert(MDOC_Bl == node->tok);
1.24 kristaps 488:
489: argv = NULL;
490: argc = node->data.block.argc;
491:
492: for (i = type = err = 0; i < argc; i++) {
493: argv = &node->data.block.argv[(int)i];
494: assert(argv);
495: switch (argv->arg) {
496: case (MDOC_Bullet):
497: /* FALLTHROUGH */
498: case (MDOC_Dash):
499: /* FALLTHROUGH */
500: case (MDOC_Enum):
501: /* FALLTHROUGH */
502: case (MDOC_Hyphen):
503: /* FALLTHROUGH */
504: case (MDOC_Item):
505: /* FALLTHROUGH */
506: case (MDOC_Tag):
507: /* FALLTHROUGH */
508: case (MDOC_Diag):
509: /* FALLTHROUGH */
510: case (MDOC_Hang):
511: /* FALLTHROUGH */
512: case (MDOC_Ohang):
513: /* FALLTHROUGH */
514: case (MDOC_Inset):
1.26 kristaps 515: /* FALLTHROUGH */
516: case (MDOC_Column):
1.24 kristaps 517: if (type)
518: err++;
519: type++;
520: break;
521: default:
522: break;
523: }
524: }
525: if (0 == type)
1.31 kristaps 526: return(mdoc_err(mdoc, "no list type specified"));
1.24 kristaps 527: if (0 == err)
528: return(1);
529: assert(argv);
530: return(mdoc_perr(mdoc, argv->line,
1.31 kristaps 531: argv->pos, "only one list type possible"));
1.24 kristaps 532: }
533:
534:
535: static int
536: pre_bd(struct mdoc *mdoc, struct mdoc_node *node)
537: {
538: int type, err;
539: struct mdoc_arg *argv;
540: size_t i, argc;
541:
542: if (MDOC_BLOCK != node->type)
543: return(1);
1.25 kristaps 544: assert(MDOC_Bd == node->tok);
1.24 kristaps 545:
546: argv = NULL;
547: argc = node->data.block.argc;
548:
549: for (err = i = type = 0; 0 == err && i < argc; i++) {
550: argv = &node->data.block.argv[(int)i];
551: assert(argv);
552: switch (argv->arg) {
553: case (MDOC_Ragged):
554: /* FALLTHROUGH */
555: case (MDOC_Unfilled):
556: /* FALLTHROUGH */
1.29 kristaps 557: case (MDOC_Filled):
558: /* FALLTHROUGH */
1.24 kristaps 559: case (MDOC_Literal):
560: /* FALLTHROUGH */
561: case (MDOC_File):
562: if (type)
563: err++;
564: type++;
565: break;
566: default:
567: break;
568: }
569: }
570: if (0 == type)
1.31 kristaps 571: return(mdoc_err(mdoc, "no display type specified"));
1.24 kristaps 572: if (0 == err)
573: return(1);
574: assert(argv);
575: return(mdoc_perr(mdoc, argv->line,
1.31 kristaps 576: argv->pos, "only one display type possible"));
1.24 kristaps 577: }
578:
579:
580: static int
1.33 kristaps 581: pre_ss(struct mdoc *mdoc, struct mdoc_node *node)
582: {
583:
1.35 kristaps 584: if (MDOC_BLOCK != node->type)
1.33 kristaps 585: return(1);
586: return(pre_check_parent(mdoc, node, MDOC_Sh, MDOC_BODY));
587: }
588:
589:
590: static int
591: pre_sh(struct mdoc *mdoc, struct mdoc_node *node)
592: {
593:
1.35 kristaps 594: if (MDOC_BLOCK != node->type)
1.33 kristaps 595: return(1);
596: return(pre_check_parent(mdoc, node, -1, MDOC_ROOT));
597: }
598:
599:
600: static int
1.36 kristaps 601: pre_st(struct mdoc *mdoc, struct mdoc_node *node)
602: {
603:
604: assert(MDOC_ELEM == node->type);
605: assert(MDOC_St == node->tok);
606: if (1 == node->data.elem.argc)
607: return(1);
608: return(mdoc_nerr(mdoc, node, "macro must have one argument"));
609: }
610:
611:
612: static int
1.35 kristaps 613: pre_an(struct mdoc *mdoc, struct mdoc_node *node)
614: {
1.36 kristaps 615:
1.35 kristaps 616: assert(MDOC_ELEM == node->type);
617: assert(MDOC_An == node->tok);
618: if (1 >= node->data.elem.argc)
619: return(1);
620: return(mdoc_nerr(mdoc, node, "macro may only have one argument"));
621: }
622:
623:
624: static int
1.36 kristaps 625: pre_rv(struct mdoc *mdoc, struct mdoc_node *node)
626: {
627: enum mdoc_msec msecs[2];
628:
629: assert(MDOC_ELEM == node->type);
630: assert(MDOC_Rv == node->tok);
631:
632: msecs[0] = MSEC_2;
633: msecs[1] = MSEC_3;
634: if ( ! pre_check_msecs(mdoc, node, 2, msecs))
635: return(0);
636: return(pre_check_stdarg(mdoc, node));
637: }
638:
639:
640: static int
1.33 kristaps 641: pre_ex(struct mdoc *mdoc, struct mdoc_node *node)
642: {
643: enum mdoc_msec msecs[3];
644:
1.35 kristaps 645: assert(MDOC_ELEM == node->type);
1.36 kristaps 646: assert(MDOC_Ex == node->tok);
1.35 kristaps 647:
1.33 kristaps 648: msecs[0] = MSEC_1;
649: msecs[1] = MSEC_6;
650: msecs[2] = MSEC_8;
1.35 kristaps 651: if ( ! pre_check_msecs(mdoc, node, 3, msecs))
652: return(0);
1.36 kristaps 653: return(pre_check_stdarg(mdoc, node));
1.33 kristaps 654: }
655:
656:
657: static int
658: pre_er(struct mdoc *mdoc, struct mdoc_node *node)
659: {
660: enum mdoc_msec msecs[1];
661:
662: msecs[0] = MSEC_2;
663: return(pre_check_msecs(mdoc, node, 1, msecs));
664: }
665:
666:
667: static int
668: pre_cd(struct mdoc *mdoc, struct mdoc_node *node)
669: {
670: enum mdoc_msec msecs[1];
671:
672: msecs[0] = MSEC_4;
673: return(pre_check_msecs(mdoc, node, 1, msecs));
674: }
675:
676:
677: static int
1.25 kristaps 678: pre_it(struct mdoc *mdoc, struct mdoc_node *node)
679: {
680:
1.35 kristaps 681: if (MDOC_BLOCK != node->type)
1.25 kristaps 682: return(1);
1.33 kristaps 683: return(pre_check_parent(mdoc, node, MDOC_Bl, MDOC_BODY));
1.25 kristaps 684: }
685:
686:
687: static int
1.20 kristaps 688: pre_prologue(struct mdoc *mdoc, struct mdoc_node *node)
689: {
690:
691: if (SEC_PROLOGUE != mdoc->sec_lastn)
1.31 kristaps 692: return(mdoc_nerr(mdoc, node, "macro may only be invoked in the prologue"));
1.20 kristaps 693: assert(MDOC_ELEM == node->type);
694:
695: /* Check for ordering. */
696:
1.25 kristaps 697: switch (node->tok) {
1.20 kristaps 698: case (MDOC_Os):
1.36 kristaps 699: if (mdoc->meta.title && mdoc->meta.date)
1.20 kristaps 700: break;
1.31 kristaps 701: return(mdoc_nerr(mdoc, node, "prologue macro out-of-order"));
1.20 kristaps 702: case (MDOC_Dt):
1.36 kristaps 703: if (NULL == mdoc->meta.title && mdoc->meta.date)
1.20 kristaps 704: break;
1.31 kristaps 705: return(mdoc_nerr(mdoc, node, "prologue macro out-of-order"));
1.20 kristaps 706: case (MDOC_Dd):
1.36 kristaps 707: if (NULL == mdoc->meta.title && 0 == mdoc->meta.date)
1.20 kristaps 708: break;
1.31 kristaps 709: return(mdoc_nerr(mdoc, node, "prologue macro out-of-order"));
1.20 kristaps 710: default:
711: abort();
712: /* NOTREACHED */
713: }
714:
715: /* Check for repetition. */
716:
1.25 kristaps 717: switch (node->tok) {
1.20 kristaps 718: case (MDOC_Os):
1.36 kristaps 719: if (NULL == mdoc->meta.os)
1.20 kristaps 720: return(1);
721: break;
722: case (MDOC_Dd):
723: if (0 == mdoc->meta.date)
724: return(1);
725: break;
726: case (MDOC_Dt):
1.36 kristaps 727: if (NULL == mdoc->meta.title)
1.20 kristaps 728: return(1);
729: break;
730: default:
731: abort();
732: /* NOTREACHED */
733: }
734:
1.31 kristaps 735: return(mdoc_nerr(mdoc, node, "prologue macro repeated"));
1.20 kristaps 736: }
737:
738:
1.35 kristaps 739: static int
1.37 ! kristaps 740: post_nm(struct mdoc *mdoc)
! 741: {
! 742:
! 743: assert(MDOC_ELEM == mdoc->last->type);
! 744: assert(MDOC_Nm == mdoc->last->tok);
! 745: if (mdoc->last->child)
! 746: return(1);
! 747: if (mdoc->meta.name)
! 748: return(1);
! 749: return(mdoc_err(mdoc, "macro `%s' has not been invoked with a name",
! 750: mdoc_macronames[MDOC_Nm]));
! 751: }
! 752:
! 753:
! 754: static int
1.36 kristaps 755: post_xr(struct mdoc *mdoc)
756: {
757: struct mdoc_node *n;
758:
759: assert(MDOC_ELEM == mdoc->last->type);
760: assert(MDOC_Xr == mdoc->last->tok);
761: assert(mdoc->last->child);
762: assert(MDOC_TEXT == mdoc->last->child->type);
763:
764: if (NULL == (n = mdoc->last->child->next))
765: return(1);
766: assert(MDOC_TEXT == n->type);
767: if (MSEC_DEFAULT != mdoc_atomsec(n->data.text.string))
768: return(1);
769: return(mdoc_nerr(mdoc, n, "invalid manual section"));
770: }
771:
772:
773: static int
774: post_at(struct mdoc *mdoc)
775: {
776:
777: assert(MDOC_ELEM == mdoc->last->type);
778: assert(MDOC_At == mdoc->last->tok);
1.37 ! kristaps 779:
! 780: if (NULL == mdoc->last->child)
! 781: return(1);
1.36 kristaps 782: assert(MDOC_TEXT == mdoc->last->child->type);
783:
784: if (ATT_DEFAULT != mdoc_atoatt(mdoc->last->child->data.text.string))
785: return(1);
786: return(mdoc_err(mdoc, "macro expects a valid AT&T version symbol"));
787: }
788:
789:
790: static int
1.35 kristaps 791: post_an(struct mdoc *mdoc)
792: {
793:
794: assert(MDOC_ELEM == mdoc->last->type);
795: assert(MDOC_An == mdoc->last->tok);
796:
797: if (0 != mdoc->last->data.elem.argc) {
798: if (NULL == mdoc->last->child)
799: return(1);
800: return(mdoc_err(mdoc, "macro expects either argument or parameters"));
801: }
802:
803: if (mdoc->last->child)
804: return(1);
805: return(mdoc_err(mdoc, "macro expects either argument or parameters"));
806: }
807:
808:
809: static int
810: post_ex(struct mdoc *mdoc)
811: {
812:
813: assert(MDOC_ELEM == mdoc->last->type);
814: assert(MDOC_Ex == mdoc->last->tok);
815:
816: if (0 == mdoc->last->data.elem.argc) {
817: if (mdoc->last->child)
818: return(1);
819: return(mdoc_err(mdoc, "macro expects `%s' or a single child",
820: mdoc_argnames[MDOC_Std]));
821: }
822: if (mdoc->last->child)
823: return(mdoc_err(mdoc, "macro expects `%s' or a single child",
824: mdoc_argnames[MDOC_Std]));
825: if (1 != mdoc->last->data.elem.argc)
826: return(mdoc_err(mdoc, "macro expects `%s' or a single child",
827: mdoc_argnames[MDOC_Std]));
828: if (MDOC_Std != mdoc->last->data.elem.argv[0].arg)
829: return(mdoc_err(mdoc, "macro expects `%s' or a single child",
830: mdoc_argnames[MDOC_Std]));
831: return(1);
832: }
833:
834:
1.25 kristaps 835: /* Warn if `Bl' type-specific syntax isn't reflected in items. */
836: static int
837: post_it(struct mdoc *mdoc)
838: {
839: int type, sv;
840: #define TYPE_NONE (0)
841: #define TYPE_BODY (1)
842: #define TYPE_HEAD (2)
843: size_t i, argc;
844: struct mdoc_node *n;
845:
846: if (MDOC_BLOCK != mdoc->last->type)
847: return(1);
848:
849: assert(MDOC_It == mdoc->last->tok);
850:
851: n = mdoc->last->parent;
852: assert(n);
853: assert(MDOC_Bl == n->tok);
854:
855: n = n->parent;
856: assert(MDOC_BLOCK == n->type);
857: assert(MDOC_Bl == n->tok);
858:
859: argc = n->data.block.argc;
860: type = TYPE_NONE;
1.26 kristaps 861:
862: /* Some types require block-head, some not. */
1.25 kristaps 863:
864: for (i = 0; TYPE_NONE == type && i < argc; i++)
865: switch (n->data.block.argv[(int)i].arg) {
866: case (MDOC_Tag):
867: /* FALLTHROUGH */
868: case (MDOC_Diag):
869: /* FALLTHROUGH */
870: case (MDOC_Hang):
871: /* FALLTHROUGH */
872: case (MDOC_Ohang):
873: /* FALLTHROUGH */
874: case (MDOC_Inset):
875: type = TYPE_HEAD;
876: sv = n->data.block.argv[(int)i].arg;
877: break;
878: case (MDOC_Bullet):
879: /* FALLTHROUGH */
880: case (MDOC_Dash):
881: /* FALLTHROUGH */
882: case (MDOC_Enum):
883: /* FALLTHROUGH */
884: case (MDOC_Hyphen):
885: /* FALLTHROUGH */
886: case (MDOC_Item):
887: /* FALLTHROUGH */
888: case (MDOC_Column):
889: type = TYPE_BODY;
890: sv = n->data.block.argv[(int)i].arg;
891: break;
892: default:
893: break;
894: }
895:
896: assert(TYPE_NONE != type);
897:
898: if (TYPE_HEAD == type) {
1.33 kristaps 899: n = mdoc->last->data.block.head;
900: assert(n);
901: if (NULL == n->child)
1.31 kristaps 902: if ( ! mdoc_warn(mdoc, WARN_SYNTAX, "macro suggests line parameters"))
1.25 kristaps 903: return(0);
904:
1.33 kristaps 905: n = mdoc->last->data.block.body;
906: assert(n);
907: if (NULL == n->child)
1.31 kristaps 908: if ( ! mdoc_warn(mdoc, WARN_SYNTAX, "macro suggests body children"))
1.25 kristaps 909: return(0);
910:
911: return(1);
912: }
913:
1.33 kristaps 914: assert(TYPE_BODY == type);
915: assert(mdoc->last->data.block.head);
916:
917: n = mdoc->last->data.block.head;
918: assert(n);
919: if (n->child)
920: if ( ! mdoc_warn(mdoc, WARN_SYNTAX, "macro suggests no line parameters"))
1.25 kristaps 921: return(0);
922:
1.33 kristaps 923: n = mdoc->last->data.block.body;
924: assert(n);
925: if (NULL == n->child)
1.31 kristaps 926: if ( ! mdoc_warn(mdoc, WARN_SYNTAX, "macro suggests body children"))
1.25 kristaps 927: return(0);
928:
1.26 kristaps 929: if (MDOC_Column != sv)
930: return(1);
931:
932: /* Make sure the number of columns is sane. */
933:
934: sv = mdoc->last->parent->parent->data.block.argv->sz;
935: n = mdoc->last->data.block.head->child;
1.25 kristaps 936:
1.26 kristaps 937: for (i = 0; n; n = n->next)
938: i++;
939:
940: if (i == (size_t)sv)
941: return(1);
1.31 kristaps 942: return(mdoc_err(mdoc, "expected %d list columns, have %d", sv, (int)i));
1.25 kristaps 943: #undef TYPE_NONE
944: #undef TYPE_BODY
945: #undef TYPE_HEAD
946: }
947:
948:
1.24 kristaps 949: static int
950: post_bl(struct mdoc *mdoc)
951: {
952: struct mdoc_node *n;
953:
954: if (MDOC_BODY != mdoc->last->type)
955: return(1);
1.25 kristaps 956: assert(MDOC_Bl == mdoc->last->tok);
1.24 kristaps 957:
958: for (n = mdoc->last->child; n; n = n->next) {
959: if (MDOC_BLOCK == n->type)
1.25 kristaps 960: if (MDOC_It == n->tok)
1.24 kristaps 961: continue;
962: break;
963: }
964: if (NULL == n)
965: return(1);
1.31 kristaps 966: return(mdoc_nerr(mdoc, n, "invalid child of parent macro `Bl'"));
1.24 kristaps 967: }
968:
969:
1.34 kristaps 970: static int
1.37 ! kristaps 971: ebool(struct mdoc *mdoc)
1.34 kristaps 972: {
973: struct mdoc_node *n;
974:
975: assert(MDOC_ELEM == mdoc->last->type);
976: for (n = mdoc->last->child; n; n = n->next) {
977: if (MDOC_TEXT != n->type)
978: break;
979: if (xstrcmp(n->data.text.string, "on"))
980: continue;
981: if (xstrcmp(n->data.text.string, "off"))
982: continue;
983: break;
984: }
985: if (NULL == n)
986: return(1);
1.37 ! kristaps 987: return(mdoc_nerr(mdoc, n, "expected boolean value"));
! 988: }
! 989:
! 990:
! 991: static int
! 992: post_root(struct mdoc *mdoc)
! 993: {
! 994:
! 995: if (NULL == mdoc->last->child)
! 996: return(mdoc_err(mdoc, "document has no data"));
! 997: if (NULL == mdoc->meta.title)
! 998: return(mdoc_err(mdoc, "document has no incomplete prologue"));
! 999: if (NULL == mdoc->meta.os)
! 1000: return(mdoc_err(mdoc, "document has no incomplete prologue"));
! 1001: if (0 == mdoc->meta.date)
! 1002: return(mdoc_err(mdoc, "document has no incomplete prologue"));
! 1003: return(1);
1.34 kristaps 1004: }
1005:
1006:
1.25 kristaps 1007: /* Warn if conventional sections are out of order. */
1.20 kristaps 1008: static int
1.21 kristaps 1009: post_sh(struct mdoc *mdoc)
1.14 kristaps 1010: {
1.36 kristaps 1011: char buf[64];
1.21 kristaps 1012: enum mdoc_sec sec;
1013:
1014: if (MDOC_HEAD != mdoc->last->type)
1015: return(1);
1.25 kristaps 1016: assert(MDOC_Sh == mdoc->last->tok);
1.21 kristaps 1017:
1.36 kristaps 1018: if ( ! xstrlcats(buf, mdoc->last->child, 64))
1019: return(mdoc_err(mdoc, "macro parameters too long"));
1.14 kristaps 1020:
1.36 kristaps 1021: if (SEC_CUSTOM == (sec = mdoc_atosec(buf)))
1.21 kristaps 1022: return(1);
1023: if (sec > mdoc->sec_lastn)
1024: return(1);
1025: if (sec == mdoc->sec_lastn)
1.31 kristaps 1026: return(mdoc_warn(mdoc, WARN_SYNTAX, "section repeated"));
1027: return(mdoc_warn(mdoc, WARN_SYNTAX, "section out of conventional order"));
1.11 kristaps 1028: }
1029:
1030:
1.17 kristaps 1031: int
1.18 kristaps 1032: mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *node)
1.11 kristaps 1033: {
1.24 kristaps 1034: v_pre *p;
1.18 kristaps 1035:
1.25 kristaps 1036: if (MDOC_TEXT == node->type)
1.18 kristaps 1037: return(1);
1.25 kristaps 1038: assert(MDOC_ROOT != node->type);
1.11 kristaps 1039:
1.25 kristaps 1040: if (NULL == mdoc_valids[node->tok].pre)
1.11 kristaps 1041: return(1);
1.25 kristaps 1042: for (p = mdoc_valids[node->tok].pre; *p; p++)
1.24 kristaps 1043: if ( ! (*p)(mdoc, node))
1044: return(0);
1045: return(1);
1.11 kristaps 1046: }
1047:
1048:
1.17 kristaps 1049: int
1.18 kristaps 1050: mdoc_valid_post(struct mdoc *mdoc)
1.11 kristaps 1051: {
1.17 kristaps 1052: v_post *p;
1.11 kristaps 1053:
1.25 kristaps 1054: if (MDOC_TEXT == mdoc->last->type)
1055: return(1);
1.37 ! kristaps 1056: if (MDOC_ROOT == mdoc->last->type)
! 1057: return(post_root(mdoc));
1.14 kristaps 1058:
1.25 kristaps 1059: if (NULL == mdoc_valids[mdoc->last->tok].post)
1.9 kristaps 1060: return(1);
1.25 kristaps 1061: for (p = mdoc_valids[mdoc->last->tok].post; *p; p++)
1.18 kristaps 1062: if ( ! (*p)(mdoc))
1.17 kristaps 1063: return(0);
1.11 kristaps 1064:
1.14 kristaps 1065: return(1);
1.11 kristaps 1066: }
1.14 kristaps 1067:
CVSweb