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