]> git.cameronkatri.com Git - mandoc.git/blob - validate.c
Cleaned up validation source a bit.
[mandoc.git] / validate.c
1 /* $Id: validate.c,v 1.51 2009/02/22 14:31:08 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 * Pre- and post-validate macros as they're parsed. Pre-validation
26 * occurs when the macro has been detected and its arguments parsed.
27 * Post-validation occurs when all child macros have also been parsed.
28 * In the ELEMENT case, this is simply the parameters of the macro; in
29 * the BLOCK case, this is the HEAD, BODY, TAIL and so on.
30 */
31
32 typedef int (*v_pre)(struct mdoc *, struct mdoc_node *);
33 typedef int (*v_post)(struct mdoc *);
34
35 /* FIXME: some sections should only occur in specific msecs. */
36 /* FIXME: ignoring Pp. */
37 /* FIXME: .Ef arguments */
38 /* FIXME: math symbols. */
39 /* FIXME: valid character-escape checks. */
40 /* FIXME: .Fd only in synopsis section. */
41
42 struct valids {
43 v_pre *pre;
44 v_post *post;
45 };
46
47 /* Utility checks. */
48
49 static int check_parent(struct mdoc *, struct mdoc_node *,
50 int, enum mdoc_type);
51 static int check_msec(struct mdoc *, struct mdoc_node *,
52 int, enum mdoc_msec *);
53 static int check_stdarg(struct mdoc *, struct mdoc_node *);
54 static int err_child_lt(struct mdoc *, const char *, int);
55 static int err_child_gt(struct mdoc *, const char *, int);
56 static int warn_child_gt(struct mdoc *, const char *, int);
57 static int err_child_eq(struct mdoc *, const char *, int);
58 static int warn_child_eq(struct mdoc *, const char *, int);
59
60 /* Utility auxiliaries. */
61
62 static inline int count_child(struct mdoc *);
63 static inline int warn_count(struct mdoc *, const char *,
64 int, const char *, int);
65 static inline int err_count(struct mdoc *, const char *,
66 int, const char *, int);
67
68 /* Specific pre-child-parse routines. */
69
70 static int pre_display(struct mdoc *, struct mdoc_node *);
71 static int pre_sh(struct mdoc *, struct mdoc_node *);
72 static int pre_ss(struct mdoc *, struct mdoc_node *);
73 static int pre_bd(struct mdoc *, struct mdoc_node *);
74 static int pre_bl(struct mdoc *, struct mdoc_node *);
75 static int pre_it(struct mdoc *, struct mdoc_node *);
76 static int pre_cd(struct mdoc *, struct mdoc_node *);
77 static int pre_er(struct mdoc *, struct mdoc_node *);
78 static int pre_ex(struct mdoc *, struct mdoc_node *);
79 static int pre_rv(struct mdoc *, struct mdoc_node *);
80 static int pre_an(struct mdoc *, struct mdoc_node *);
81 static int pre_st(struct mdoc *, struct mdoc_node *);
82 static int pre_prologue(struct mdoc *, struct mdoc_node *);
83 static int pre_prologue(struct mdoc *, struct mdoc_node *);
84 static int pre_prologue(struct mdoc *, struct mdoc_node *);
85
86 /* Specific post-child-parse routines. */
87
88 static int herr_ge1(struct mdoc *);
89 static int herr_le1(struct mdoc *);
90 static int herr_eq0(struct mdoc *);
91 static int eerr_eq0(struct mdoc *);
92 static int eerr_le1(struct mdoc *);
93 static int eerr_le2(struct mdoc *);
94 static int eerr_eq1(struct mdoc *);
95 static int eerr_ge1(struct mdoc *);
96 static int ewarn_eq0(struct mdoc *);
97 static int ewarn_eq1(struct mdoc *);
98 static int bwarn_ge1(struct mdoc *);
99 static int ewarn_ge1(struct mdoc *);
100 static int ebool(struct mdoc *);
101 static int post_sh(struct mdoc *);
102 static int post_sh_body(struct mdoc *);
103 static int post_sh_head(struct mdoc *);
104 static int post_bl(struct mdoc *);
105 static int post_it(struct mdoc *);
106 static int post_ex(struct mdoc *);
107 static int post_an(struct mdoc *);
108 static int post_at(struct mdoc *);
109 static int post_xr(struct mdoc *);
110 static int post_nm(struct mdoc *);
111 static int post_bf(struct mdoc *);
112 static int post_root(struct mdoc *);
113
114 /* Collections of pre-child-parse routines. */
115
116 static v_pre pres_prologue[] = { pre_prologue, NULL };
117 static v_pre pres_d1[] = { pre_display, NULL };
118 static v_pre pres_bd[] = { pre_display, pre_bd, NULL };
119 static v_pre pres_bl[] = { pre_bl, NULL };
120 static v_pre pres_it[] = { pre_it, NULL };
121 static v_pre pres_ss[] = { pre_ss, NULL };
122 static v_pre pres_sh[] = { pre_sh, NULL };
123 static v_pre pres_cd[] = { pre_cd, NULL };
124 static v_pre pres_er[] = { pre_er, NULL };
125 static v_pre pres_ex[] = { pre_ex, NULL };
126 static v_pre pres_rv[] = { pre_rv, NULL };
127 static v_pre pres_an[] = { pre_an, NULL };
128 static v_pre pres_st[] = { pre_st, NULL };
129
130 /* Collections of post-child-parse routines. */
131
132 static v_post posts_bool[] = { eerr_eq1, ebool, NULL };
133 static v_post posts_bd[] = { herr_eq0, bwarn_ge1, NULL };
134 static v_post posts_text[] = { eerr_ge1, NULL };
135 static v_post posts_wtext[] = { ewarn_ge1, NULL };
136 static v_post posts_notext[] = { eerr_eq0, NULL };
137 static v_post posts_wline[] = { bwarn_ge1, herr_eq0, NULL };
138 static v_post posts_sh[] = { herr_ge1, bwarn_ge1, post_sh, NULL };
139 static v_post posts_bl[] = { herr_eq0, bwarn_ge1, post_bl, NULL };
140 static v_post posts_it[] = { post_it, NULL };
141 static v_post posts_in[] = { ewarn_eq1, NULL };
142 static v_post posts_ss[] = { herr_ge1, NULL };
143 static v_post posts_pp[] = { ewarn_eq0, NULL };
144 static v_post posts_ex[] = { eerr_le1, post_ex, NULL };
145 static v_post posts_an[] = { post_an, NULL };
146 static v_post posts_at[] = { post_at, NULL };
147 static v_post posts_xr[] = { eerr_ge1, eerr_le2, post_xr, NULL };
148 static v_post posts_nm[] = { post_nm, NULL };
149 static v_post posts_bf[] = { herr_le1, post_bf, NULL };
150 static v_post posts_rs[] = { herr_eq0, bwarn_ge1, NULL };
151 static v_post posts_fo[] = { bwarn_ge1, NULL };
152 static v_post posts_bk[] = { herr_eq0, bwarn_ge1, NULL };
153
154 /* Per-macro pre- and post-child-check routine collections. */
155
156 const struct valids mdoc_valids[MDOC_MAX] = {
157 { NULL, NULL }, /* \" */
158 { pres_prologue, posts_text }, /* Dd */
159 { pres_prologue, NULL }, /* Dt */
160 { pres_prologue, NULL }, /* Os */
161 { pres_sh, posts_sh }, /* Sh */
162 { pres_ss, posts_ss }, /* Ss */
163 { NULL, posts_pp }, /* Pp */
164 { pres_d1, posts_wline }, /* D1 */
165 { pres_d1, posts_wline }, /* Dl */
166 { pres_bd, posts_bd }, /* Bd */
167 { NULL, NULL }, /* Ed */
168 { pres_bl, posts_bl }, /* Bl */
169 { NULL, NULL }, /* El */
170 { pres_it, posts_it }, /* It */
171 { NULL, posts_text }, /* Ad */
172 { pres_an, posts_an }, /* An */
173 { NULL, NULL }, /* Ar */
174 { pres_cd, posts_text }, /* Cd */
175 { NULL, NULL }, /* Cm */
176 { NULL, posts_text }, /* Dv */
177 { pres_er, posts_text }, /* Er */
178 { NULL, posts_text }, /* Ev */
179 { pres_ex, posts_ex }, /* Ex */
180 { NULL, posts_text }, /* Fa */
181 { NULL, posts_wtext }, /* Fd */
182 { NULL, NULL }, /* Fl */
183 { NULL, posts_text }, /* Fn */
184 { NULL, posts_wtext }, /* Ft */
185 { NULL, posts_text }, /* Ic */
186 { NULL, posts_in }, /* In */
187 { NULL, posts_text }, /* Li */
188 { NULL, posts_wtext }, /* Nd */
189 { NULL, posts_nm }, /* Nm */
190 { NULL, posts_wline }, /* Op */
191 { NULL, NULL }, /* Ot */
192 { NULL, NULL }, /* Pa */
193 { pres_rv, posts_notext }, /* Rv */
194 { pres_st, posts_notext }, /* St */
195 { NULL, posts_text }, /* Va */
196 { NULL, posts_text }, /* Vt */
197 { NULL, posts_xr }, /* Xr */
198 { NULL, posts_text }, /* %A */
199 { NULL, posts_text }, /* %B */
200 { NULL, posts_text }, /* %D */
201 { NULL, posts_text }, /* %I */
202 { NULL, posts_text }, /* %J */
203 { NULL, posts_text }, /* %N */
204 { NULL, posts_text }, /* %O */
205 { NULL, posts_text }, /* %P */
206 { NULL, posts_text }, /* %R */
207 { NULL, posts_text }, /* %T */
208 { NULL, posts_text }, /* %V */
209 { NULL, NULL }, /* Ac */
210 { NULL, NULL }, /* Ao */
211 { NULL, posts_wline }, /* Aq */
212 { NULL, posts_at }, /* At */
213 { NULL, NULL }, /* Bc */
214 { NULL, posts_bf }, /* Bf */
215 { NULL, NULL }, /* Bo */
216 { NULL, posts_wline }, /* Bq */
217 { NULL, NULL }, /* Bsx */
218 { NULL, NULL }, /* Bx */
219 { NULL, posts_bool }, /* Db */
220 { NULL, NULL }, /* Dc */
221 { NULL, NULL }, /* Do */
222 { NULL, posts_wline }, /* Dq */
223 { NULL, NULL }, /* Ec */
224 { NULL, NULL }, /* Ef */
225 { NULL, posts_text }, /* Em */
226 { NULL, NULL }, /* Eo */
227 { NULL, NULL }, /* Fx */
228 { NULL, posts_text }, /* Ms */
229 { NULL, posts_notext }, /* No */
230 { NULL, posts_notext }, /* Ns */
231 { NULL, NULL }, /* Nx */
232 { NULL, NULL }, /* Ox */
233 { NULL, NULL }, /* Pc */
234 { NULL, NULL }, /* Pf */
235 { NULL, NULL }, /* Po */
236 { NULL, posts_wline }, /* Pq */
237 { NULL, NULL }, /* Qc */
238 { NULL, posts_wline }, /* Ql */
239 { NULL, NULL }, /* Qo */
240 { NULL, posts_wline }, /* Qq */
241 { NULL, NULL }, /* Re */
242 { NULL, posts_rs }, /* Rs */
243 { NULL, NULL }, /* Sc */
244 { NULL, NULL }, /* So */
245 { NULL, posts_wline }, /* Sq */
246 { NULL, posts_bool }, /* Sm */
247 { NULL, posts_text }, /* Sx */
248 { NULL, posts_text }, /* Sy */
249 { NULL, posts_text }, /* Tn */
250 { NULL, NULL }, /* Ux */
251 { NULL, NULL }, /* Xc */
252 { NULL, NULL }, /* Xo */
253 { NULL, posts_fo }, /* Fo */
254 { NULL, NULL }, /* Fc */
255 { NULL, NULL }, /* Oo */
256 { NULL, NULL }, /* Oc */
257 { NULL, posts_bk }, /* Bk */
258 { NULL, NULL }, /* Ek */
259 { NULL, posts_notext }, /* Bt */
260 { NULL, NULL }, /* Hf */
261 { NULL, NULL }, /* Fr */
262 { NULL, posts_notext }, /* Ud */
263 };
264
265
266 static inline int
267 warn_count(struct mdoc *m, const char *k,
268 int want, const char *v, int has)
269 {
270
271 return(mdoc_warn(m, WARN_SYNTAX, "suggests %s %d %s "
272 "(has %d)", v, want, k, has));
273 }
274
275
276 static inline int
277 err_count(struct mdoc *m, const char *k,
278 int want, const char *v, int has)
279 {
280
281 return(mdoc_err(m, "requires %s %d %s (has %d)",
282 v, want, k, has));
283 }
284
285
286 static inline int
287 count_child(struct mdoc *mdoc)
288 {
289 int i;
290 struct mdoc_node *n;
291
292 for (i = 0, n = mdoc->last->child; n; n = n->next, i++)
293 /* Do nothing */ ;
294 return(i);
295 }
296
297
298 static int
299 warn_child_gt(struct mdoc *mdoc, const char *p, int sz)
300 {
301 int i;
302
303 if ((i = count_child(mdoc)) > sz)
304 return(1);
305 return(warn_count(mdoc, ">", sz, p, i));
306 }
307
308
309 static int
310 err_child_gt(struct mdoc *mdoc, const char *p, int sz)
311 {
312 int i;
313
314 if ((i = count_child(mdoc)) > sz)
315 return(1);
316 return(err_count(mdoc, ">", sz, p, i));
317 }
318
319
320 static int
321 warn_child_eq(struct mdoc *mdoc, const char *p, int sz)
322 {
323 int i;
324
325 if ((i = count_child(mdoc)) == sz)
326 return(1);
327 return(warn_count(mdoc, "==", sz, p, i));
328 }
329
330
331 static int
332 err_child_eq(struct mdoc *mdoc, const char *p, int sz)
333 {
334 int i;
335
336 if ((i = count_child(mdoc)) == sz)
337 return(1);
338 return(err_count(mdoc, "==", sz, p, i));
339 }
340
341
342 static int
343 err_child_lt(struct mdoc *mdoc, const char *p, int sz)
344 {
345 int i;
346
347 if ((i = count_child(mdoc)) < sz)
348 return(1);
349 return(err_count(mdoc, "<", sz, p, i));
350 }
351
352
353 static int
354 check_stdarg(struct mdoc *mdoc, struct mdoc_node *node)
355 {
356
357 if (MDOC_Std == node->data.elem.argv[0].arg &&
358 1 == node->data.elem.argc)
359 return(1);
360
361 return(mdoc_nwarn(mdoc, node, WARN_COMPAT,
362 "macro suggests single `%s' argument",
363 mdoc_argnames[MDOC_Std]));
364 }
365
366
367 static int
368 check_msec(struct mdoc *mdoc, struct mdoc_node *node,
369 int sz, enum mdoc_msec *msecs)
370 {
371 int i;
372
373 for (i = 0; i < sz; i++)
374 if (msecs[i] == mdoc->meta.msec)
375 return(1);
376 return(mdoc_nwarn(mdoc, node, WARN_COMPAT, "macro not "
377 "appropriate for manual section"));
378 }
379
380
381 static int
382 check_parent(struct mdoc *mdoc, struct mdoc_node *n,
383 int tok, enum mdoc_type t)
384 {
385
386 assert(n->parent);
387 if ((MDOC_ROOT == t || tok == n->parent->tok) &&
388 (t == n->parent->type))
389 return(1);
390
391 return(mdoc_nerr(mdoc, n, "require parent %s (have %s)",
392 MDOC_ROOT == t ? "<root>" :
393 mdoc_macronames[tok],
394 MDOC_ROOT == n->parent->type ? "<root>" :
395 mdoc_macronames[n->parent->type]));
396 }
397
398
399 static int
400 bwarn_ge1(struct mdoc *mdoc)
401 {
402
403 if (MDOC_BODY != mdoc->last->type)
404 return(1);
405 return(warn_child_gt(mdoc, "multi-line parameters", 0));
406 }
407
408
409 static int
410 ewarn_eq1(struct mdoc *mdoc)
411 {
412
413 assert(MDOC_ELEM == mdoc->last->type);
414 return(warn_child_eq(mdoc, "line parameters", 1));
415 }
416
417
418 static int
419 ewarn_eq0(struct mdoc *mdoc)
420 {
421
422 assert(MDOC_ELEM == mdoc->last->type);
423 return(warn_child_eq(mdoc, "line parameters", 0));
424 }
425
426
427 static int
428 ewarn_ge1(struct mdoc *mdoc)
429 {
430
431 assert(MDOC_ELEM == mdoc->last->type);
432 return(warn_child_gt(mdoc, "line parameters", 0));
433 }
434
435
436 static int
437 eerr_eq1(struct mdoc *mdoc)
438 {
439
440 assert(MDOC_ELEM == mdoc->last->type);
441 return(err_child_eq(mdoc, "line parameters", 1));
442 }
443
444
445 static int
446 eerr_le2(struct mdoc *mdoc)
447 {
448
449 assert(MDOC_ELEM == mdoc->last->type);
450 return(err_child_lt(mdoc, "line parameters", 3));
451 }
452
453
454 static int
455 eerr_le1(struct mdoc *mdoc)
456 {
457
458 assert(MDOC_ELEM == mdoc->last->type);
459 return(err_child_lt(mdoc, "line parameters", 2));
460 }
461
462
463 static int
464 eerr_eq0(struct mdoc *mdoc)
465 {
466
467 assert(MDOC_ELEM == mdoc->last->type);
468 return(err_child_eq(mdoc, "line parameters", 0));
469 }
470
471
472 static int
473 eerr_ge1(struct mdoc *mdoc)
474 {
475
476 assert(MDOC_ELEM == mdoc->last->type);
477 return(err_child_gt(mdoc, "line parameters", 0));
478 }
479
480
481 static int
482 herr_eq0(struct mdoc *mdoc)
483 {
484
485 if (MDOC_HEAD != mdoc->last->type)
486 return(1);
487 return(err_child_eq(mdoc, "line parameters", 0));
488 }
489
490
491 static int
492 herr_le1(struct mdoc *mdoc)
493 {
494 if (MDOC_HEAD != mdoc->last->type)
495 return(1);
496 return(err_child_lt(mdoc, "line parameters", 2));
497 }
498
499
500 static int
501 herr_ge1(struct mdoc *mdoc)
502 {
503
504 if (MDOC_HEAD != mdoc->last->type)
505 return(1);
506 return(err_child_gt(mdoc, "line parameters", 0));
507 }
508
509
510 static int
511 pre_display(struct mdoc *mdoc, struct mdoc_node *node)
512 {
513 struct mdoc_node *n;
514
515 if (MDOC_BLOCK != node->type)
516 return(1);
517
518 assert(mdoc->last);
519 /* LINTED */
520 for (n = mdoc->last->parent; n; n = n->parent)
521 if (MDOC_BLOCK == n->type)
522 if (MDOC_Bd == n->tok)
523 break;
524 if (NULL == n)
525 return(1);
526 return(mdoc_nerr(mdoc, node, "displays may not be nested"));
527 }
528
529
530 static int
531 pre_bl(struct mdoc *mdoc, struct mdoc_node *node)
532 {
533 int type, err;
534 struct mdoc_arg *argv;
535 size_t i, argc;
536
537 if (MDOC_BLOCK != node->type)
538 return(1);
539 assert(MDOC_Bl == node->tok);
540
541 argv = NULL;
542 argc = node->data.block.argc;
543
544 /* LINTED */
545 for (i = type = err = 0; i < argc; i++) {
546 argv = &node->data.block.argv[(int)i];
547 assert(argv);
548 switch (argv->arg) {
549 case (MDOC_Bullet):
550 /* FALLTHROUGH */
551 case (MDOC_Dash):
552 /* FALLTHROUGH */
553 case (MDOC_Enum):
554 /* FALLTHROUGH */
555 case (MDOC_Hyphen):
556 /* FALLTHROUGH */
557 case (MDOC_Item):
558 /* FALLTHROUGH */
559 case (MDOC_Tag):
560 /* FALLTHROUGH */
561 case (MDOC_Diag):
562 /* FALLTHROUGH */
563 case (MDOC_Hang):
564 /* FALLTHROUGH */
565 case (MDOC_Ohang):
566 /* FALLTHROUGH */
567 case (MDOC_Inset):
568 /* FALLTHROUGH */
569 case (MDOC_Column):
570 if (type)
571 err++;
572 type++;
573 break;
574 default:
575 break;
576 }
577 }
578 if (0 == type)
579 return(mdoc_err(mdoc, "no list type specified"));
580 if (0 == err)
581 return(1);
582 assert(argv);
583 return(mdoc_perr(mdoc, argv->line,
584 argv->pos, "only one list type possible"));
585 }
586
587
588 static int
589 pre_bd(struct mdoc *mdoc, struct mdoc_node *node)
590 {
591 int type, err;
592 struct mdoc_arg *argv;
593 size_t i, argc;
594
595 if (MDOC_BLOCK != node->type)
596 return(1);
597 assert(MDOC_Bd == node->tok);
598
599 argv = NULL;
600 argc = node->data.block.argc;
601
602 /* LINTED */
603 for (err = i = type = 0; 0 == err && i < argc; i++) {
604 argv = &node->data.block.argv[(int)i];
605 assert(argv);
606 switch (argv->arg) {
607 case (MDOC_Ragged):
608 /* FALLTHROUGH */
609 case (MDOC_Unfilled):
610 /* FALLTHROUGH */
611 case (MDOC_Filled):
612 /* FALLTHROUGH */
613 case (MDOC_Literal):
614 /* FALLTHROUGH */
615 case (MDOC_File):
616 if (type)
617 err++;
618 type++;
619 break;
620 default:
621 break;
622 }
623 }
624 if (0 == type)
625 return(mdoc_err(mdoc, "no display type specified"));
626 if (0 == err)
627 return(1);
628 assert(argv);
629 return(mdoc_perr(mdoc, argv->line,
630 argv->pos, "only one display type possible"));
631 }
632
633
634 static int
635 pre_ss(struct mdoc *mdoc, struct mdoc_node *node)
636 {
637
638 if (MDOC_BLOCK != node->type)
639 return(1);
640 return(check_parent(mdoc, node, MDOC_Sh, MDOC_BODY));
641 }
642
643
644 static int
645 pre_sh(struct mdoc *mdoc, struct mdoc_node *node)
646 {
647
648 if (MDOC_BLOCK != node->type)
649 return(1);
650 return(check_parent(mdoc, node, -1, MDOC_ROOT));
651 }
652
653
654 static int
655 pre_st(struct mdoc *mdoc, struct mdoc_node *node)
656 {
657
658 assert(MDOC_ELEM == node->type);
659 assert(MDOC_St == node->tok);
660 if (1 == node->data.elem.argc)
661 return(1);
662 return(mdoc_nerr(mdoc, node, "macro must have one argument"));
663 }
664
665
666 static int
667 pre_an(struct mdoc *mdoc, struct mdoc_node *node)
668 {
669
670 assert(MDOC_ELEM == node->type);
671 assert(MDOC_An == node->tok);
672 if (1 >= node->data.elem.argc)
673 return(1);
674 return(mdoc_nerr(mdoc, node, "macro may only have one argument"));
675 }
676
677
678 static int
679 pre_rv(struct mdoc *mdoc, struct mdoc_node *node)
680 {
681 enum mdoc_msec msecs[2];
682
683 assert(MDOC_ELEM == node->type);
684 assert(MDOC_Rv == node->tok);
685
686 msecs[0] = MSEC_2;
687 msecs[1] = MSEC_3;
688 if ( ! check_msec(mdoc, node, 2, msecs))
689 return(0);
690 return(check_stdarg(mdoc, node));
691 }
692
693
694 static int
695 pre_ex(struct mdoc *mdoc, struct mdoc_node *node)
696 {
697 enum mdoc_msec msecs[3];
698
699 assert(MDOC_ELEM == node->type);
700 assert(MDOC_Ex == node->tok);
701
702 msecs[0] = MSEC_1;
703 msecs[1] = MSEC_6;
704 msecs[2] = MSEC_8;
705 if ( ! check_msec(mdoc, node, 3, msecs))
706 return(0);
707 return(check_stdarg(mdoc, node));
708 }
709
710
711 static int
712 pre_er(struct mdoc *mdoc, struct mdoc_node *node)
713 {
714 enum mdoc_msec msecs[1];
715
716 msecs[0] = MSEC_2;
717 return(check_msec(mdoc, node, 1, msecs));
718 }
719
720
721 static int
722 pre_cd(struct mdoc *mdoc, struct mdoc_node *node)
723 {
724 enum mdoc_msec msecs[1];
725
726 msecs[0] = MSEC_4;
727 return(check_msec(mdoc, node, 1, msecs));
728 }
729
730
731 static int
732 pre_it(struct mdoc *mdoc, struct mdoc_node *node)
733 {
734
735 /* TODO: -width attribute must be specified for -tag. */
736 /* TODO: children too big for -width? */
737
738 if (MDOC_BLOCK != node->type)
739 return(1);
740 return(check_parent(mdoc, node, MDOC_Bl, MDOC_BODY));
741 }
742
743
744 static int
745 pre_prologue(struct mdoc *mdoc, struct mdoc_node *node)
746 {
747
748 if (SEC_PROLOGUE != mdoc->lastnamed)
749 return(mdoc_nerr(mdoc, node, "macro may only be invoked in the prologue"));
750 assert(MDOC_ELEM == node->type);
751
752 /* Check for ordering. */
753
754 switch (node->tok) {
755 case (MDOC_Os):
756 if (mdoc->meta.title && mdoc->meta.date)
757 break;
758 return(mdoc_nerr(mdoc, node, "prologue macro out-of-order"));
759 case (MDOC_Dt):
760 if (NULL == mdoc->meta.title && mdoc->meta.date)
761 break;
762 return(mdoc_nerr(mdoc, node, "prologue macro out-of-order"));
763 case (MDOC_Dd):
764 if (NULL == mdoc->meta.title && 0 == mdoc->meta.date)
765 break;
766 return(mdoc_nerr(mdoc, node, "prologue macro out-of-order"));
767 default:
768 abort();
769 /* NOTREACHED */
770 }
771
772 /* Check for repetition. */
773
774 switch (node->tok) {
775 case (MDOC_Os):
776 if (NULL == mdoc->meta.os)
777 return(1);
778 break;
779 case (MDOC_Dd):
780 if (0 == mdoc->meta.date)
781 return(1);
782 break;
783 case (MDOC_Dt):
784 if (NULL == mdoc->meta.title)
785 return(1);
786 break;
787 default:
788 abort();
789 /* NOTREACHED */
790 }
791
792 return(mdoc_nerr(mdoc, node, "prologue macro repeated"));
793 }
794
795
796 static int
797 post_bf(struct mdoc *mdoc)
798 {
799 char *p;
800 struct mdoc_node *head;
801
802 if (MDOC_BLOCK != mdoc->last->type)
803 return(1);
804 assert(MDOC_Bf == mdoc->last->tok);
805 head = mdoc->last->data.block.head;
806 assert(head);
807
808 if (0 == mdoc->last->data.block.argc) {
809 if (head->child) {
810 assert(MDOC_TEXT == head->child->type);
811 p = head->child->data.text.string;
812 if (xstrcmp(p, "Em"))
813 return(1);
814 else if (xstrcmp(p, "Li"))
815 return(1);
816 else if (xstrcmp(p, "Sm"))
817 return(1);
818 return(mdoc_nerr(mdoc, head->child, "invalid font mode"));
819 }
820 return(mdoc_err(mdoc, "macro expects an argument or parameter"));
821 }
822 if (head->child)
823 return(mdoc_err(mdoc, "macro expects an argument or parameter"));
824 if (1 == mdoc->last->data.block.argc)
825 return(1);
826 return(mdoc_err(mdoc, "macro expects an argument or parameter"));
827 }
828
829
830 static int
831 post_nm(struct mdoc *mdoc)
832 {
833
834 assert(MDOC_ELEM == mdoc->last->type);
835 assert(MDOC_Nm == mdoc->last->tok);
836 if (mdoc->last->child)
837 return(1);
838 if (mdoc->meta.name)
839 return(1);
840 return(mdoc_err(mdoc, "macro `%s' has not been invoked with a name",
841 mdoc_macronames[MDOC_Nm]));
842 }
843
844
845 static int
846 post_xr(struct mdoc *mdoc)
847 {
848 struct mdoc_node *n;
849
850 assert(MDOC_ELEM == mdoc->last->type);
851 assert(MDOC_Xr == mdoc->last->tok);
852 assert(mdoc->last->child);
853 assert(MDOC_TEXT == mdoc->last->child->type);
854
855 if (NULL == (n = mdoc->last->child->next))
856 return(1);
857 assert(MDOC_TEXT == n->type);
858 if (MSEC_DEFAULT != mdoc_atomsec(n->data.text.string))
859 return(1);
860 return(mdoc_nerr(mdoc, n, "invalid manual section"));
861 }
862
863
864 static int
865 post_at(struct mdoc *mdoc)
866 {
867
868 assert(MDOC_ELEM == mdoc->last->type);
869 assert(MDOC_At == mdoc->last->tok);
870
871 if (NULL == mdoc->last->child)
872 return(1);
873 assert(MDOC_TEXT == mdoc->last->child->type);
874
875 if (ATT_DEFAULT != mdoc_atoatt(mdoc->last->child->data.text.string))
876 return(1);
877 return(mdoc_err(mdoc, "macro expects a valid AT&T version symbol"));
878 }
879
880
881 static int
882 post_an(struct mdoc *mdoc)
883 {
884
885 assert(MDOC_ELEM == mdoc->last->type);
886 assert(MDOC_An == mdoc->last->tok);
887
888 if (0 != mdoc->last->data.elem.argc) {
889 if (NULL == mdoc->last->child)
890 return(1);
891 return(mdoc_err(mdoc, "macro expects either argument or parameters"));
892 }
893
894 if (mdoc->last->child)
895 return(1);
896 return(mdoc_err(mdoc, "macro expects either argument or parameters"));
897 }
898
899
900 static int
901 post_ex(struct mdoc *mdoc)
902 {
903
904 assert(MDOC_ELEM == mdoc->last->type);
905 assert(MDOC_Ex == mdoc->last->tok);
906
907 if (0 == mdoc->last->data.elem.argc) {
908 if (mdoc->last->child)
909 return(1);
910 return(mdoc_err(mdoc, "macro expects `%s' or a single child",
911 mdoc_argnames[MDOC_Std]));
912 }
913 if (mdoc->last->child)
914 return(mdoc_err(mdoc, "macro expects `%s' or a single child",
915 mdoc_argnames[MDOC_Std]));
916 if (1 != mdoc->last->data.elem.argc)
917 return(mdoc_err(mdoc, "macro expects `%s' or a single child",
918 mdoc_argnames[MDOC_Std]));
919 if (MDOC_Std != mdoc->last->data.elem.argv[0].arg)
920 return(mdoc_err(mdoc, "macro expects `%s' or a single child",
921 mdoc_argnames[MDOC_Std]));
922 return(1);
923 }
924
925
926 /* Warn if `Bl' type-specific syntax isn't reflected in items. */
927 static int
928 post_it(struct mdoc *mdoc)
929 {
930 int type, sv;
931 #define TYPE_NONE (0)
932 #define TYPE_BODY (1)
933 #define TYPE_HEAD (2)
934 #define TYPE_OHEAD (3)
935 size_t i, argc;
936 struct mdoc_node *n;
937
938 if (MDOC_BLOCK != mdoc->last->type)
939 return(1);
940
941 assert(MDOC_It == mdoc->last->tok);
942
943 n = mdoc->last->parent;
944 assert(n);
945 assert(MDOC_Bl == n->tok);
946
947 n = n->parent;
948 assert(MDOC_BLOCK == n->type);
949 assert(MDOC_Bl == n->tok);
950
951 argc = n->data.block.argc;
952 type = TYPE_NONE;
953 sv = -1;
954
955 /* Some types require block-head, some not. */
956
957 /* LINTED */
958 for (i = 0; TYPE_NONE == type && i < argc; i++)
959 switch (n->data.block.argv[(int)i].arg) {
960 case (MDOC_Tag):
961 /* FALLTHROUGH */
962 case (MDOC_Diag):
963 /* FALLTHROUGH */
964 case (MDOC_Hang):
965 /* FALLTHROUGH */
966 case (MDOC_Ohang):
967 /* FALLTHROUGH */
968 case (MDOC_Inset):
969 type = TYPE_HEAD;
970 sv = n->data.block.argv[(int)i].arg;
971 break;
972 case (MDOC_Bullet):
973 /* FALLTHROUGH */
974 case (MDOC_Dash):
975 /* FALLTHROUGH */
976 case (MDOC_Enum):
977 /* FALLTHROUGH */
978 case (MDOC_Hyphen):
979 /* FALLTHROUGH */
980 case (MDOC_Item):
981 type = TYPE_BODY;
982 sv = n->data.block.argv[(int)i].arg;
983 break;
984 case (MDOC_Column):
985 type = TYPE_OHEAD;
986 sv = n->data.block.argv[(int)i].arg;
987 break;
988 default:
989 break;
990 }
991
992 assert(TYPE_NONE != type);
993
994 n = mdoc->last->data.block.head;
995 assert(n);
996
997 if (TYPE_HEAD == type) {
998 if (NULL == n->child)
999 if ( ! mdoc_warn(mdoc, WARN_SYNTAX, "macro suggests line parameters"))
1000 return(0);
1001
1002 n = mdoc->last->data.block.body;
1003 assert(n);
1004 if (NULL == n->child)
1005 if ( ! mdoc_warn(mdoc, WARN_SYNTAX, "macro suggests body children"))
1006 return(0);
1007
1008 } else if (TYPE_BODY == type) {
1009 if (n->child)
1010 if ( ! mdoc_warn(mdoc, WARN_SYNTAX, "macro suggests no line parameters"))
1011 return(0);
1012
1013 n = mdoc->last->data.block.body;
1014 assert(n);
1015 if (NULL == n->child)
1016 if ( ! mdoc_warn(mdoc, WARN_SYNTAX, "macro suggests body children"))
1017 return(0);
1018 } else {
1019 if (NULL == n->child)
1020 if ( ! mdoc_warn(mdoc, WARN_SYNTAX, "macro suggests line parameters"))
1021 return(0);
1022
1023 n = mdoc->last->data.block.body;
1024 assert(n);
1025 if (n->child)
1026 if ( ! mdoc_warn(mdoc, WARN_SYNTAX, "macro suggests no body children"))
1027 return(0);
1028 }
1029
1030 if (MDOC_Column != sv)
1031 return(1);
1032
1033 /* Make sure the number of columns is sane. */
1034
1035 argc = mdoc->last->parent->parent->data.block.argv->sz;
1036 n = mdoc->last->data.block.head->child;
1037
1038 for (i = 0; n; n = n->next)
1039 i++;
1040
1041 if (i == argc)
1042 return(1);
1043 return(mdoc_err(mdoc, "expected %zu list columns, have %zu", argc, i));
1044 #undef TYPE_NONE
1045 #undef TYPE_BODY
1046 #undef TYPE_HEAD
1047 #undef TYPE_OHEAD
1048 }
1049
1050
1051 static int
1052 post_bl(struct mdoc *mdoc)
1053 {
1054 struct mdoc_node *n;
1055
1056 if (MDOC_BODY != mdoc->last->type)
1057 return(1);
1058 assert(MDOC_Bl == mdoc->last->tok);
1059
1060 /* LINTED */
1061 for (n = mdoc->last->child; n; n = n->next) {
1062 if (MDOC_BLOCK == n->type)
1063 if (MDOC_It == n->tok)
1064 continue;
1065 break;
1066 }
1067 if (NULL == n)
1068 return(1);
1069 return(mdoc_nerr(mdoc, n, "invalid child of parent macro `Bl'"));
1070 }
1071
1072
1073 static int
1074 ebool(struct mdoc *mdoc)
1075 {
1076 struct mdoc_node *n;
1077
1078 assert(MDOC_ELEM == mdoc->last->type);
1079 /* LINTED */
1080 for (n = mdoc->last->child; n; n = n->next) {
1081 if (MDOC_TEXT != n->type)
1082 break;
1083 if (xstrcmp(n->data.text.string, "on"))
1084 continue;
1085 if (xstrcmp(n->data.text.string, "off"))
1086 continue;
1087 break;
1088 }
1089 if (NULL == n)
1090 return(1);
1091 return(mdoc_nerr(mdoc, n, "expected boolean value"));
1092 }
1093
1094
1095 static int
1096 post_root(struct mdoc *mdoc)
1097 {
1098
1099 if (NULL == mdoc->first->child)
1100 return(mdoc_err(mdoc, "document has no data"));
1101 if (SEC_PROLOGUE == mdoc->lastnamed)
1102 return(mdoc_err(mdoc, "document has incomplete prologue"));
1103 if (MDOC_BLOCK != mdoc->first->child->type)
1104 return(mdoc_err(mdoc, "document expects `%s' macro after prologue", mdoc_macronames[MDOC_Sh]));
1105 if (MDOC_Sh != mdoc->first->child->tok)
1106 return(mdoc_err(mdoc, "document expects `%s' macro after prologue", mdoc_macronames[MDOC_Sh]));
1107 return(1);
1108 }
1109
1110
1111 static int
1112 post_sh(struct mdoc *mdoc)
1113 {
1114
1115 if (MDOC_HEAD == mdoc->last->type)
1116 return(post_sh_head(mdoc));
1117 if (MDOC_BODY == mdoc->last->type)
1118 return(post_sh_body(mdoc));
1119 return(1);
1120 }
1121
1122
1123 static int
1124 post_sh_body(struct mdoc *mdoc)
1125 {
1126 struct mdoc_node *n;
1127
1128 assert(MDOC_Sh == mdoc->last->tok);
1129 assert(MDOC_BODY == mdoc->last->type);
1130 if (SEC_NAME != mdoc->lastnamed)
1131 return(1);
1132
1133 /*
1134 * Warn if the NAME section doesn't contain the `Nm' and `Nd'
1135 * macros (can have multiple `Nm' and one `Nd'). Note that the
1136 * children of the BODY declaration can also be "text".
1137 */
1138
1139 if (NULL == (n = mdoc->last->child))
1140 return(mdoc_warn(mdoc, WARN_COMPAT, "section NAME "
1141 "should contain %s and %s",
1142 mdoc_macronames[MDOC_Nm],
1143 mdoc_macronames[MDOC_Nd]));
1144
1145 for ( ; n && n->next; n = n->next) {
1146 if (MDOC_ELEM == n->type && MDOC_Nm == n->tok)
1147 continue;
1148 if (MDOC_TEXT == n->type)
1149 continue;
1150 if ( ! (mdoc_nwarn(mdoc, n, WARN_COMPAT, "section "
1151 "NAME should contain %s as "
1152 "initial body child",
1153 mdoc_macronames[MDOC_Nm])))
1154 return(0);
1155 }
1156
1157 if (MDOC_ELEM == n->type && MDOC_Nd == n->tok)
1158 return(1);
1159
1160 return(mdoc_warn(mdoc, WARN_COMPAT, "section NAME should "
1161 "contain %s as the last child",
1162 mdoc_macronames[MDOC_Nd]));
1163 }
1164
1165
1166 static int
1167 post_sh_head(struct mdoc *mdoc)
1168 {
1169 char buf[64];
1170 enum mdoc_sec sec;
1171
1172 assert(MDOC_Sh == mdoc->last->tok);
1173
1174 if ( ! xstrlcats(buf, mdoc->last->child, 64))
1175 return(mdoc_err(mdoc, "macro parameters too long"));
1176
1177 sec = mdoc_atosec(buf);
1178
1179 if (SEC_BODY == mdoc->lastnamed && SEC_NAME != sec)
1180 return(mdoc_err(mdoc, "section NAME must be first"));
1181 if (SEC_CUSTOM == sec)
1182 return(1);
1183 if (sec == mdoc->lastnamed)
1184 return(mdoc_warn(mdoc, WARN_SYNTAX, "section repeated"));
1185 if (sec < mdoc->lastnamed)
1186 return(mdoc_warn(mdoc, WARN_SYNTAX, "section out of conventional order"));
1187
1188 return(1);
1189 }
1190
1191
1192 int
1193 mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *node)
1194 {
1195 v_pre *p;
1196
1197 if (MDOC_TEXT == node->type)
1198 return(1);
1199 assert(MDOC_ROOT != node->type);
1200
1201 if (NULL == mdoc_valids[node->tok].pre)
1202 return(1);
1203 for (p = mdoc_valids[node->tok].pre; *p; p++)
1204 if ( ! (*p)(mdoc, node))
1205 return(0);
1206 return(1);
1207 }
1208
1209
1210 int
1211 mdoc_valid_post(struct mdoc *mdoc)
1212 {
1213 v_post *p;
1214
1215 if (MDOC_VALID & mdoc->last->flags)
1216 return(1);
1217 mdoc->last->flags |= MDOC_VALID;
1218
1219 if (MDOC_TEXT == mdoc->last->type)
1220 return(1);
1221 if (MDOC_ROOT == mdoc->last->type)
1222 return(post_root(mdoc));
1223
1224 if (NULL == mdoc_valids[mdoc->last->tok].post)
1225 return(1);
1226 for (p = mdoc_valids[mdoc->last->tok].post; *p; p++)
1227 if ( ! (*p)(mdoc))
1228 return(0);
1229
1230 return(1);
1231 }
1232