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