]> git.cameronkatri.com Git - mandoc.git/blob - validate.c
Boolean validation.
[mandoc.git] / validate.c
1 /* $Id: validate.c,v 1.34 2009/01/16 14:15:12 kristaps Exp $ */
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>
20 #include <stdlib.h>
21
22 #include "private.h"
23
24
25 typedef int (*v_pre)(struct mdoc *, struct mdoc_node *);
26 typedef int (*v_post)(struct mdoc *);
27
28
29 struct valids {
30 v_pre *pre;
31 v_post *post;
32 };
33
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 *);
38
39 static int pre_display(struct mdoc *, struct mdoc_node *);
40 static int pre_sh(struct mdoc *, struct mdoc_node *);
41 static int pre_ss(struct mdoc *, struct mdoc_node *);
42 static int pre_bd(struct mdoc *, struct mdoc_node *);
43 static int pre_bl(struct mdoc *, struct mdoc_node *);
44 static int pre_it(struct mdoc *, struct mdoc_node *);
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 *);
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 *);
51
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 *);
63 static int post_sh(struct mdoc *);
64 static int post_bl(struct mdoc *);
65 static int post_it(struct mdoc *);
66
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 };
71 static v_pre pres_it[] = { pre_it, NULL };
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 };
77
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 };
88 static v_post posts_it[] = { post_it, NULL };
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 };
92
93
94 const struct valids mdoc_valids[MDOC_MAX] = {
95 { NULL, NULL }, /* \" */
96 { pres_prologue, posts_text }, /* Dd */
97 { pres_prologue, NULL }, /* Dt */
98 { pres_prologue, NULL }, /* Os */
99 /* FIXME: preceding Pp. */
100 /* FIXME: NAME section internal ordering. */
101 { pres_sh, posts_sh }, /* Sh */
102 /* FIXME: preceding Pp. */
103 { pres_ss, posts_ss }, /* Ss */
104 /* FIXME: proceeding... */
105 { NULL, posts_pp }, /* Pp */
106 { pres_d1, posts_d1 }, /* D1 */
107 { pres_d1, posts_d1 }, /* Dl */
108 /* FIXME: preceding Pp. */
109 { pres_bd, posts_bd }, /* Bd */
110 { NULL, NULL }, /* Ed */
111 /* FIXME: preceding Pp. */
112 { pres_bl, posts_bl }, /* Bl */
113 { NULL, NULL }, /* El */
114 { pres_it, posts_it }, /* It */
115 { NULL, posts_text }, /* Ad */
116 /* FIXME: argument OR parameters. */
117 { NULL, NULL }, /* An */
118 { NULL, NULL }, /* Ar */
119 { pres_cd, posts_text }, /* Cd */
120 { NULL, NULL }, /* Cm */
121 { NULL, posts_text }, /* Dv */
122 { pres_er, posts_text }, /* Er */
123 { NULL, posts_text }, /* Ev */
124 { pres_ex, posts_notext }, /* Ex */ /* FIXME: -std required */
125 { NULL, posts_text }, /* Fa */
126 { NULL, NULL }, /* Fd */ /* FIXME: SYNOPSIS section. */
127 { NULL, NULL }, /* Fl */
128 { NULL, posts_text }, /* Fn */
129 { NULL, NULL }, /* Ft */
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? */
135 { NULL, posts_wline }, /* Op */
136 { NULL, NULL }, /* Ot */
137 { NULL, NULL }, /* Pa */
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 */
154 { NULL, NULL }, /* Ac */
155 { NULL, NULL }, /* Ao */
156 { NULL, posts_wline }, /* Aq */
157 { NULL, NULL }, /* At */ /* FIXME */
158 { NULL, NULL }, /* Bc */
159 { NULL, NULL }, /* Bf */
160 { NULL, NULL }, /* Bo */
161 { NULL, posts_wline }, /* Bq */
162 { NULL, NULL }, /* Bsx */
163 { NULL, NULL }, /* Bx */
164 { NULL, posts_bool }, /* Db */
165 { NULL, NULL }, /* Dc */
166 { NULL, NULL }, /* Do */
167 { NULL, posts_wline }, /* Dq */
168 { NULL, NULL }, /* Ec */
169 { NULL, NULL }, /* Ef */ /* -symbolic, etc. */
170 { NULL, posts_text }, /* Em */
171 { NULL, NULL }, /* Eo */
172 { NULL, NULL }, /* Fx */
173 { NULL, posts_text }, /* Ms */ /* FIXME: which symbols? */
174 { NULL, posts_notext }, /* No */
175 { NULL, posts_notext }, /* Ns */
176 { NULL, NULL }, /* Nx */
177 { NULL, NULL }, /* Ox */
178 { NULL, NULL }, /* Pc */
179 { NULL, NULL }, /* Pf */ /* FIXME: 2 or more arguments */ /* First should be text. */
180 { NULL, NULL }, /* Po */
181 { NULL, posts_wline }, /* Pq */ /* FIXME: ignore following Sh/Ss */
182 { NULL, NULL }, /* Qc */
183 { NULL, posts_wline }, /* Ql */
184 { NULL, NULL }, /* Qo */
185 { NULL, posts_wline }, /* Qq */
186 { NULL, NULL }, /* Re */
187 { NULL, NULL }, /* Rs */
188 { NULL, NULL }, /* Sc */
189 { NULL, NULL }, /* So */
190 { NULL, posts_wline }, /* Sq */
191 { NULL, posts_bool }, /* Sm */
192 { NULL, posts_text }, /* Sx */
193 { NULL, posts_text }, /* Sy */
194 { NULL, posts_text }, /* Tn */
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 */
204 { NULL, posts_notext }, /* Bt */
205 { NULL, NULL }, /* Hf */
206 { NULL, NULL }, /* Fr */
207 { NULL, posts_notext }, /* Ud */
208 };
209
210
211 static int
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
243 body_err_eq0(struct mdoc *mdoc)
244 {
245
246 if (MDOC_BODY != mdoc->last->type)
247 return(1);
248 if (NULL == mdoc->last->child)
249 return(1);
250 return(mdoc_warn(mdoc, WARN_SYNTAX, "macro suggests no body children"));
251 }
252
253
254 static int
255 body_warn_ge1(struct mdoc *mdoc)
256 {
257
258 if (MDOC_BODY != mdoc->last->type)
259 return(1);
260 if (mdoc->last->child)
261 return(1);
262 return(mdoc_warn(mdoc, WARN_SYNTAX, "macro suggests one or more body children"));
263 }
264
265
266 static int
267 elem_warn_eq0(struct mdoc *mdoc)
268 {
269
270 assert(MDOC_ELEM == mdoc->last->type);
271 if (NULL == mdoc->last->child)
272 return(1);
273 return(mdoc_pwarn(mdoc, mdoc->last->child->line,
274 mdoc->last->child->pos, WARN_SYNTAX, "macro suggests no parameters"));
275 }
276
277
278 static int
279 elem_warn_ge1(struct mdoc *mdoc)
280 {
281
282 assert(MDOC_ELEM == mdoc->last->type);
283 if (mdoc->last->child)
284 return(1);
285 return(mdoc_warn(mdoc, WARN_SYNTAX, "macro suggests one or more parameters"));
286 }
287
288
289 static int
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)
304 {
305
306 assert(MDOC_ELEM == mdoc->last->type);
307 if (NULL == mdoc->last->child)
308 return(1);
309 return(mdoc_err(mdoc, "macro expects no parameters"));
310 }
311
312
313 static int
314 elem_err_ge1(struct mdoc *mdoc)
315 {
316
317 assert(MDOC_ELEM == mdoc->last->type);
318 if (mdoc->last->child)
319 return(1);
320 return(mdoc_err(mdoc, "macro expects one or more parameters"));
321 }
322
323
324 static int
325 head_err_eq0(struct mdoc *mdoc)
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,
333 mdoc->last->child->pos, "macro expects no parameters"));
334 }
335
336
337 static int
338 head_warn_ge1(struct mdoc *mdoc)
339 {
340
341 if (MDOC_HEAD != mdoc->last->type)
342 return(1);
343 if (mdoc->last->child)
344 return(1);
345 return(mdoc_warn(mdoc, WARN_SYNTAX, "macro suggests one or more parameters"));
346 }
347
348
349 static int
350 head_err_ge1(struct mdoc *mdoc)
351 {
352
353 if (MDOC_HEAD != mdoc->last->type)
354 return(1);
355 if (mdoc->last->child)
356 return(1);
357 return(mdoc_err(mdoc, "macro expects one or more parameters"));
358 }
359
360
361 static int
362 pre_display(struct mdoc *mdoc, struct mdoc_node *node)
363 {
364 struct mdoc_node *n;
365
366 if (MDOC_BLOCK != node->type)
367 return(1);
368
369 assert(mdoc->last);
370 for (n = mdoc->last->parent; n; n = n->parent)
371 if (MDOC_BLOCK == n->type)
372 if (MDOC_Bd == n->tok)
373 break;
374 if (NULL == n)
375 return(1);
376 return(mdoc_nerr(mdoc, node, "displays may not be nested"));
377 }
378
379
380 static int
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);
389 assert(MDOC_Bl == node->tok);
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):
417 /* FALLTHROUGH */
418 case (MDOC_Column):
419 if (type)
420 err++;
421 type++;
422 break;
423 default:
424 break;
425 }
426 }
427 if (0 == type)
428 return(mdoc_err(mdoc, "no list type specified"));
429 if (0 == err)
430 return(1);
431 assert(argv);
432 return(mdoc_perr(mdoc, argv->line,
433 argv->pos, "only one list type possible"));
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);
446 assert(MDOC_Bd == node->tok);
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 */
459 case (MDOC_Filled):
460 /* FALLTHROUGH */
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)
473 return(mdoc_err(mdoc, "no display type specified"));
474 if (0 == err)
475 return(1);
476 assert(argv);
477 return(mdoc_perr(mdoc, argv->line,
478 argv->pos, "only one display type possible"));
479 }
480
481
482 static int
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
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);
543 return(pre_check_parent(mdoc, node, MDOC_Bl, MDOC_BODY));
544 }
545
546
547 static int
548 pre_prologue(struct mdoc *mdoc, struct mdoc_node *node)
549 {
550
551 if (SEC_PROLOGUE != mdoc->sec_lastn)
552 return(mdoc_nerr(mdoc, node, "macro may only be invoked in the prologue"));
553 assert(MDOC_ELEM == node->type);
554
555 /* Check for ordering. */
556
557 switch (node->tok) {
558 case (MDOC_Os):
559 if (mdoc->meta.title[0] && mdoc->meta.date)
560 break;
561 return(mdoc_nerr(mdoc, node, "prologue macro out-of-order"));
562 case (MDOC_Dt):
563 if (0 == mdoc->meta.title[0] && mdoc->meta.date)
564 break;
565 return(mdoc_nerr(mdoc, node, "prologue macro out-of-order"));
566 case (MDOC_Dd):
567 if (0 == mdoc->meta.title[0] && 0 == mdoc->meta.date)
568 break;
569 return(mdoc_nerr(mdoc, node, "prologue macro out-of-order"));
570 default:
571 abort();
572 /* NOTREACHED */
573 }
574
575 /* Check for repetition. */
576
577 switch (node->tok) {
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
595 return(mdoc_nerr(mdoc, node, "prologue macro repeated"));
596 }
597
598
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;
625
626 /* Some types require block-head, some not. */
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) {
663 n = mdoc->last->data.block.head;
664 assert(n);
665 if (NULL == n->child)
666 if ( ! mdoc_warn(mdoc, WARN_SYNTAX, "macro suggests line parameters"))
667 return(0);
668
669 n = mdoc->last->data.block.body;
670 assert(n);
671 if (NULL == n->child)
672 if ( ! mdoc_warn(mdoc, WARN_SYNTAX, "macro suggests body children"))
673 return(0);
674
675 return(1);
676 }
677
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"))
685 return(0);
686
687 n = mdoc->last->data.block.body;
688 assert(n);
689 if (NULL == n->child)
690 if ( ! mdoc_warn(mdoc, WARN_SYNTAX, "macro suggests body children"))
691 return(0);
692
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;
700
701 for (i = 0; n; n = n->next)
702 i++;
703
704 if (i == (size_t)sv)
705 return(1);
706 return(mdoc_err(mdoc, "expected %d list columns, have %d", sv, (int)i));
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. */
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);
722 assert(MDOC_Bl == mdoc->last->tok);
723
724 for (n = mdoc->last->child; n; n = n->next) {
725 if (MDOC_BLOCK == n->type)
726 if (MDOC_It == n->tok)
727 continue;
728 break;
729 }
730 if (NULL == n)
731 return(1);
732 return(mdoc_nerr(mdoc, n, "invalid child of parent macro `Bl'"));
733 }
734
735
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
757 /* Warn if conventional sections are out of order. */
758 static int
759 post_sh(struct mdoc *mdoc)
760 {
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
769 assert(MDOC_Sh == mdoc->last->tok);
770
771 n = mdoc->last->child;
772 assert(n);
773
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)
788 return(mdoc_warn(mdoc, WARN_SYNTAX, "section repeated"));
789 return(mdoc_warn(mdoc, WARN_SYNTAX, "section out of conventional order"));
790 }
791
792
793 int
794 mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *node)
795 {
796 v_pre *p;
797
798 /* TODO: character-escape checks. */
799
800 if (MDOC_TEXT == node->type)
801 return(1);
802 assert(MDOC_ROOT != node->type);
803
804 if (NULL == mdoc_valids[node->tok].pre)
805 return(1);
806 for (p = mdoc_valids[node->tok].pre; *p; p++)
807 if ( ! (*p)(mdoc, node))
808 return(0);
809 return(1);
810 }
811
812
813 int
814 mdoc_valid_post(struct mdoc *mdoc)
815 {
816 v_post *p;
817
818 if (MDOC_TEXT == mdoc->last->type)
819 return(1);
820 if (MDOC_ROOT == mdoc->last->type) {
821 /* TODO: make sure prologue is complete. */
822 return(1);
823 }
824
825 if (NULL == mdoc_valids[mdoc->last->tok].post)
826 return(1);
827 for (p = mdoc_valids[mdoc->last->tok].post; *p; p++)
828 if ( ! (*p)(mdoc))
829 return(0);
830
831 return(1);
832 }
833