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