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