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