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