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