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