a264fe487381537133a187d3f5247bf7a816eb70
[dragonfly.git] / usr.bin / mandoc / mdoc_validate.c
1 /*      $Id: mdoc_validate.c,v 1.54 2009/11/02 06:22:46 kristaps Exp $ */
2 /*
3  * Copyright (c) 2008, 2009 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 above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 #include <sys/types.h>
18
19 #include <assert.h>
20 #include <ctype.h>
21 #include <limits.h>
22 #include <stdarg.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include "libmdoc.h"
27 #include "libmandoc.h"
28
29 /* FIXME: .Bl -diag can't have non-text children in HEAD. */
30 /* TODO: ignoring Pp (it's superfluous in some invocations). */
31
32 #define PRE_ARGS  struct mdoc *mdoc, const struct mdoc_node *n
33 #define POST_ARGS struct mdoc *mdoc
34
35 typedef int     (*v_pre)(PRE_ARGS);
36 typedef int     (*v_post)(POST_ARGS);
37
38 struct  valids {
39         v_pre   *pre;
40         v_post  *post;
41 };
42
43 static  int      check_parent(PRE_ARGS, int, enum mdoc_type);
44 static  int      check_msec(PRE_ARGS, ...);
45 static  int      check_sec(PRE_ARGS, ...);
46 static  int      check_stdarg(PRE_ARGS);
47 static  int      check_text(struct mdoc *, int, int, const char *);
48 static  int      check_argv(struct mdoc *,
49                         const struct mdoc_node *,
50                         const struct mdoc_argv *);
51 static  int      check_args(struct mdoc *,
52                         const struct mdoc_node *);
53 static  int      err_child_lt(struct mdoc *, const char *, int);
54 static  int      warn_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 static  int      warn_print(struct mdoc *, int, int);
60 static  int      warn_count(struct mdoc *, const char *,
61                         int, const char *, int);
62 static  int      err_count(struct mdoc *, const char *,
63                         int, const char *, int);
64
65 #ifdef __linux__
66 extern  size_t   strlcat(char *, const char *, size_t);
67 #endif
68
69 static  int      berr_ge1(POST_ARGS);
70 static  int      bwarn_ge1(POST_ARGS);
71 static  int      ebool(POST_ARGS);
72 static  int      eerr_eq0(POST_ARGS);
73 static  int      eerr_eq1(POST_ARGS);
74 static  int      eerr_ge1(POST_ARGS);
75 static  int      eerr_le2(POST_ARGS);
76 static  int      eerr_le1(POST_ARGS);
77 static  int      ewarn_ge1(POST_ARGS);
78 static  int      herr_eq0(POST_ARGS);
79 static  int      herr_ge1(POST_ARGS);
80 static  int      hwarn_eq1(POST_ARGS);
81 static  int      hwarn_le1(POST_ARGS);
82
83 static  int      post_an(POST_ARGS);
84 static  int      post_at(POST_ARGS);
85 static  int      post_bf(POST_ARGS);
86 static  int      post_bl(POST_ARGS);
87 static  int      post_bl_head(POST_ARGS);
88 static  int      post_it(POST_ARGS);
89 static  int      post_lb(POST_ARGS);
90 static  int      post_nm(POST_ARGS);
91 static  int      post_root(POST_ARGS);
92 static  int      post_rs(POST_ARGS);
93 static  int      post_sh(POST_ARGS);
94 static  int      post_sh_body(POST_ARGS);
95 static  int      post_sh_head(POST_ARGS);
96 static  int      post_st(POST_ARGS);
97 static  int      pre_an(PRE_ARGS);
98 static  int      pre_bd(PRE_ARGS);
99 static  int      pre_bl(PRE_ARGS);
100 static  int      pre_cd(PRE_ARGS);
101 static  int      pre_dd(PRE_ARGS);
102 static  int      pre_display(PRE_ARGS);
103 static  int      pre_dt(PRE_ARGS);
104 static  int      pre_er(PRE_ARGS);
105 static  int      pre_ex(PRE_ARGS);
106 static  int      pre_fd(PRE_ARGS);
107 static  int      pre_it(PRE_ARGS);
108 static  int      pre_lb(PRE_ARGS);
109 static  int      pre_os(PRE_ARGS);
110 static  int      pre_rv(PRE_ARGS);
111 static  int      pre_sh(PRE_ARGS);
112 static  int      pre_ss(PRE_ARGS);
113
114 static  v_post   posts_an[] = { post_an, NULL };
115 static  v_post   posts_at[] = { post_at, NULL };
116 static  v_post   posts_bd[] = { herr_eq0, bwarn_ge1, NULL };
117 static  v_post   posts_bf[] = { hwarn_le1, post_bf, NULL };
118 static  v_post   posts_bl[] = { bwarn_ge1, post_bl, NULL };
119 static  v_post   posts_bool[] = { eerr_eq1, ebool, NULL };
120 static  v_post   posts_fo[] = { hwarn_eq1, bwarn_ge1, NULL };
121 static  v_post   posts_it[] = { post_it, NULL };
122 static  v_post   posts_lb[] = { eerr_eq1, post_lb, NULL };
123 static  v_post   posts_nd[] = { berr_ge1, NULL };
124 static  v_post   posts_nm[] = { post_nm, NULL };
125 static  v_post   posts_notext[] = { eerr_eq0, NULL };
126 static  v_post   posts_rs[] = { berr_ge1, herr_eq0, post_rs, NULL };
127 static  v_post   posts_sh[] = { herr_ge1, bwarn_ge1, post_sh, NULL };
128 static  v_post   posts_sp[] = { eerr_le1, NULL };
129 static  v_post   posts_ss[] = { herr_ge1, NULL };
130 static  v_post   posts_st[] = { eerr_eq1, post_st, NULL };
131 static  v_post   posts_text[] = { eerr_ge1, NULL };
132 static  v_post   posts_text1[] = { eerr_eq1, NULL };
133 static  v_post   posts_wline[] = { bwarn_ge1, herr_eq0, NULL };
134 static  v_post   posts_wtext[] = { ewarn_ge1, NULL };
135 static  v_post   posts_xr[] = { eerr_ge1, eerr_le2, NULL };
136 static  v_pre    pres_an[] = { pre_an, NULL };
137 static  v_pre    pres_bd[] = { pre_display, pre_bd, NULL };
138 static  v_pre    pres_bl[] = { pre_bl, NULL };
139 static  v_pre    pres_cd[] = { pre_cd, NULL };
140 static  v_pre    pres_d1[] = { pre_display, NULL };
141 static  v_pre    pres_dd[] = { pre_dd, NULL };
142 static  v_pre    pres_dt[] = { pre_dt, NULL };
143 static  v_pre    pres_er[] = { pre_er, NULL };
144 static  v_pre    pres_ex[] = { pre_ex, NULL };
145 static  v_pre    pres_fd[] = { pre_fd, NULL };
146 static  v_pre    pres_it[] = { pre_it, NULL };
147 static  v_pre    pres_lb[] = { pre_lb, NULL };
148 static  v_pre    pres_os[] = { pre_os, NULL };
149 static  v_pre    pres_rv[] = { pre_rv, NULL };
150 static  v_pre    pres_sh[] = { pre_sh, NULL };
151 static  v_pre    pres_ss[] = { pre_ss, NULL };
152
153 const   struct valids mdoc_valids[MDOC_MAX] = {
154         { NULL, NULL },                         /* Ap */
155         { pres_dd, posts_text },                /* Dd */
156         { pres_dt, NULL },                      /* Dt */
157         { pres_os, NULL },                      /* Os */
158         { pres_sh, posts_sh },                  /* Sh */
159         { pres_ss, posts_ss },                  /* Ss */
160         { NULL, posts_notext },                 /* Pp */
161         { pres_d1, posts_wline },               /* D1 */
162         { pres_d1, posts_wline },               /* Dl */
163         { pres_bd, posts_bd },                  /* Bd */
164         { NULL, NULL },                         /* Ed */
165         { pres_bl, posts_bl },                  /* Bl */
166         { NULL, NULL },                         /* El */
167         { pres_it, posts_it },                  /* It */
168         { NULL, posts_text },                   /* Ad */
169         { pres_an, posts_an },                  /* An */
170         { NULL, NULL },                         /* Ar */
171         { pres_cd, posts_text },                /* Cd */
172         { NULL, NULL },                         /* Cm */
173         { NULL, NULL },                         /* Dv */
174         { pres_er, posts_text },                /* Er */
175         { NULL, NULL },                         /* Ev */
176         { pres_ex, NULL },                      /* Ex */
177         { NULL, NULL },                         /* Fa */
178         { pres_fd, posts_wtext },               /* Fd */
179         { NULL, NULL },                         /* Fl */
180         { NULL, posts_text },                   /* Fn */
181         { NULL, posts_wtext },                  /* Ft */
182         { NULL, posts_text },                   /* Ic */
183         { NULL, posts_text1 },                  /* In */
184         { NULL, NULL },                         /* Li */
185         { NULL, posts_nd },                     /* Nd */
186         { NULL, posts_nm },                     /* Nm */
187         { NULL, posts_wline },                  /* Op */
188         { NULL, NULL },                         /* Ot */
189         { NULL, NULL },                         /* Pa */
190         { pres_rv, NULL },                      /* Rv */
191         { NULL, posts_st },                     /* St */
192         { NULL, NULL },                         /* Va */
193         { NULL, posts_text },                   /* Vt */
194         { NULL, posts_xr },                     /* Xr */
195         { NULL, posts_text },                   /* %A */
196         { NULL, posts_text },                   /* %B */ /* FIXME: can be used outside Rs/Re. */
197         { NULL, posts_text },                   /* %D */ /* FIXME: check date with mandoc_a2time(). */
198         { NULL, posts_text },                   /* %I */
199         { NULL, posts_text },                   /* %J */
200         { NULL, posts_text },                   /* %N */
201         { NULL, posts_text },                   /* %O */
202         { NULL, posts_text },                   /* %P */
203         { NULL, posts_text },                   /* %R */
204         { NULL, posts_text },                   /* %T */ /* FIXME: can be used outside Rs/Re. */
205         { NULL, posts_text },                   /* %V */
206         { NULL, NULL },                         /* Ac */
207         { NULL, NULL },                         /* Ao */
208         { NULL, posts_wline },                  /* Aq */
209         { NULL, posts_at },                     /* At */
210         { NULL, NULL },                         /* Bc */
211         { NULL, posts_bf },                     /* Bf */
212         { NULL, NULL },                         /* Bo */
213         { NULL, posts_wline },                  /* Bq */
214         { NULL, NULL },                         /* Bsx */
215         { NULL, NULL },                         /* Bx */
216         { NULL, posts_bool },                   /* Db */
217         { NULL, NULL },                         /* Dc */
218         { NULL, NULL },                         /* Do */
219         { NULL, posts_wline },                  /* Dq */
220         { NULL, NULL },                         /* Ec */
221         { NULL, NULL },                         /* Ef */
222         { NULL, NULL },                         /* Em */
223         { NULL, NULL },                         /* Eo */
224         { NULL, NULL },                         /* Fx */
225         { NULL, posts_text },                   /* Ms */
226         { NULL, posts_notext },                 /* No */
227         { NULL, posts_notext },                 /* Ns */
228         { NULL, NULL },                         /* Nx */
229         { NULL, NULL },                         /* Ox */
230         { NULL, NULL },                         /* Pc */
231         { NULL, posts_text1 },                  /* Pf */
232         { NULL, NULL },                         /* Po */
233         { NULL, posts_wline },                  /* Pq */
234         { NULL, NULL },                         /* Qc */
235         { NULL, posts_wline },                  /* Ql */
236         { NULL, NULL },                         /* Qo */
237         { NULL, posts_wline },                  /* Qq */
238         { NULL, NULL },                         /* Re */
239         { NULL, posts_rs },                     /* Rs */
240         { NULL, NULL },                         /* Sc */
241         { NULL, NULL },                         /* So */
242         { NULL, posts_wline },                  /* Sq */
243         { NULL, posts_bool },                   /* Sm */
244         { NULL, posts_text },                   /* Sx */
245         { NULL, posts_text },                   /* Sy */
246         { NULL, posts_text },                   /* Tn */
247         { NULL, NULL },                         /* Ux */
248         { NULL, NULL },                         /* Xc */
249         { NULL, NULL },                         /* Xo */
250         { NULL, posts_fo },                     /* Fo */
251         { NULL, NULL },                         /* Fc */
252         { NULL, NULL },                         /* Oo */
253         { NULL, NULL },                         /* Oc */
254         { NULL, posts_wline },                  /* Bk */
255         { NULL, NULL },                         /* Ek */
256         { NULL, posts_notext },                 /* Bt */
257         { NULL, NULL },                         /* Hf */
258         { NULL, NULL },                         /* Fr */
259         { NULL, posts_notext },                 /* Ud */
260         { pres_lb, posts_lb },                  /* Lb */
261         { NULL, posts_notext },                 /* Lp */
262         { NULL, posts_text },                   /* Lk */
263         { NULL, posts_text },                   /* Mt */
264         { NULL, posts_wline },                  /* Brq */
265         { NULL, NULL },                         /* Bro */
266         { NULL, NULL },                         /* Brc */
267         { NULL, posts_text },                   /* %C */
268         { NULL, NULL },                         /* Es */
269         { NULL, NULL },                         /* En */
270         { NULL, NULL },                         /* Dx */
271         { NULL, posts_text },                   /* %Q */
272         { NULL, posts_notext },                 /* br */
273         { NULL, posts_sp },                     /* sp */
274         { NULL, posts_text1 },                  /* %U */
275 };
276
277
278 int
279 mdoc_valid_pre(struct mdoc *mdoc, const struct mdoc_node *n)
280 {
281         v_pre           *p;
282         int              line, pos;
283         const char      *tp;
284
285         if (MDOC_TEXT == n->type) {
286                 tp = n->string;
287                 line = n->line;
288                 pos = n->pos;
289                 return(check_text(mdoc, line, pos, tp));
290         }
291
292         if ( ! check_args(mdoc, n))
293                 return(0);
294         if (NULL == mdoc_valids[n->tok].pre)
295                 return(1);
296         for (p = mdoc_valids[n->tok].pre; *p; p++)
297                 if ( ! (*p)(mdoc, n))
298                         return(0);
299         return(1);
300 }
301
302
303 int
304 mdoc_valid_post(struct mdoc *mdoc)
305 {
306         v_post          *p;
307
308         if (MDOC_VALID & mdoc->last->flags)
309                 return(1);
310         mdoc->last->flags |= MDOC_VALID;
311
312         if (MDOC_TEXT == mdoc->last->type)
313                 return(1);
314         if (MDOC_ROOT == mdoc->last->type)
315                 return(post_root(mdoc));
316
317         if (NULL == mdoc_valids[mdoc->last->tok].post)
318                 return(1);
319         for (p = mdoc_valids[mdoc->last->tok].post; *p; p++)
320                 if ( ! (*p)(mdoc))
321                         return(0);
322
323         return(1);
324 }
325
326
327 static int
328 warn_print(struct mdoc *m, int ln, int pos)
329 {
330
331         if (MDOC_IGN_CHARS & m->pflags)
332                 return(mdoc_pwarn(m, ln, pos, EPRINT));
333         return(mdoc_perr(m, ln, pos, EPRINT));
334 }
335
336
337 static inline int
338 warn_count(struct mdoc *m, const char *k,
339                 int want, const char *v, int has)
340 {
341
342         return(mdoc_vwarn(m, m->last->line, m->last->pos,
343                 "suggests %s %s %d (has %d)", v, k, want, has));
344 }
345
346
347 static inline int
348 err_count(struct mdoc *m, const char *k,
349                 int want, const char *v, int has)
350 {
351
352         return(mdoc_verr(m, m->last->line, m->last->pos,
353                 "requires %s %s %d (has %d)", v, k, want, has));
354 }
355
356
357 /*
358  * Build these up with macros because they're basically the same check
359  * for different inequalities.  Yes, this could be done with functions,
360  * but this is reasonable for now.
361  */
362
363 #define CHECK_CHILD_DEFN(lvl, name, ineq)                       \
364 static int                                                      \
365 lvl##_child_##name(struct mdoc *mdoc, const char *p, int sz)    \
366 {                                                               \
367         if (mdoc->last->nchild ineq sz)                         \
368                 return(1);                                      \
369         return(lvl##_count(mdoc, #ineq, sz, p, mdoc->last->nchild)); \
370 }
371
372 #define CHECK_BODY_DEFN(name, lvl, func, num)                   \
373 static int                                                      \
374 b##lvl##_##name(POST_ARGS)                                      \
375 {                                                               \
376         if (MDOC_BODY != mdoc->last->type)                      \
377                 return(1);                                      \
378         return(func(mdoc, "multi-line arguments", (num)));      \
379 }
380
381 #define CHECK_ELEM_DEFN(name, lvl, func, num)                   \
382 static int                                                      \
383 e##lvl##_##name(POST_ARGS)                                      \
384 {                                                               \
385         assert(MDOC_ELEM == mdoc->last->type);                  \
386         return(func(mdoc, "line arguments", (num)));            \
387 }
388
389 #define CHECK_HEAD_DEFN(name, lvl, func, num)                   \
390 static int                                                      \
391 h##lvl##_##name(POST_ARGS)                                      \
392 {                                                               \
393         if (MDOC_HEAD != mdoc->last->type)                      \
394                 return(1);                                      \
395         return(func(mdoc, "line arguments", (num)));            \
396 }
397
398
399 CHECK_CHILD_DEFN(warn, gt, >)                   /* warn_child_gt() */
400 CHECK_CHILD_DEFN(err, gt, >)                    /* err_child_gt() */
401 CHECK_CHILD_DEFN(warn, eq, ==)                  /* warn_child_eq() */
402 CHECK_CHILD_DEFN(err, eq, ==)                   /* err_child_eq() */
403 CHECK_CHILD_DEFN(err, lt, <)                    /* err_child_lt() */
404 CHECK_CHILD_DEFN(warn, lt, <)                   /* warn_child_lt() */
405 CHECK_BODY_DEFN(ge1, warn, warn_child_gt, 0)    /* bwarn_ge1() */
406 CHECK_BODY_DEFN(ge1, err, err_child_gt, 0)      /* berr_ge1() */
407 CHECK_ELEM_DEFN(ge1, warn, warn_child_gt, 0)    /* ewarn_gt1() */
408 CHECK_ELEM_DEFN(eq1, err, err_child_eq, 1)      /* eerr_eq1() */
409 CHECK_ELEM_DEFN(le2, err, err_child_lt, 3)      /* eerr_le2() */
410 CHECK_ELEM_DEFN(le1, err, err_child_lt, 2)      /* eerr_le1() */
411 CHECK_ELEM_DEFN(eq0, err, err_child_eq, 0)      /* eerr_eq0() */
412 CHECK_ELEM_DEFN(ge1, err, err_child_gt, 0)      /* eerr_ge1() */
413 CHECK_HEAD_DEFN(eq0, err, err_child_eq, 0)      /* herr_eq0() */
414 CHECK_HEAD_DEFN(le1, warn, warn_child_lt, 2)    /* hwarn_le1() */
415 CHECK_HEAD_DEFN(ge1, err, err_child_gt, 0)      /* herr_ge1() */
416 CHECK_HEAD_DEFN(eq1, warn, warn_child_eq, 1)    /* hwarn_eq1() */
417
418
419 static int
420 check_stdarg(PRE_ARGS)
421 {
422
423         if (n->args && 1 == n->args->argc)
424                 if (MDOC_Std == n->args->argv[0].arg)
425                         return(1);
426         return(mdoc_nwarn(mdoc, n, EARGVAL));
427 }
428
429
430 static int
431 check_sec(PRE_ARGS, ...)
432 {
433         enum mdoc_sec    sec;
434         va_list          ap;
435
436         va_start(ap, n);
437
438         for (;;) {
439                 /* LINTED */
440                 sec = (enum mdoc_sec)va_arg(ap, int);
441                 if (SEC_CUSTOM == sec)
442                         break;
443                 if (sec != mdoc->lastsec)
444                         continue;
445                 va_end(ap);
446                 return(1);
447         }
448
449         va_end(ap);
450         return(mdoc_nwarn(mdoc, n, EBADSEC));
451 }
452
453
454 static int
455 check_msec(PRE_ARGS, ...)
456 {
457         va_list          ap;
458         int              msec;
459
460         va_start(ap, n);
461         for (;;) {
462                 /* LINTED */
463                 if (0 == (msec = va_arg(ap, int)))
464                         break;
465                 if (msec != mdoc->meta.msec)
466                         continue;
467                 va_end(ap);
468                 return(1);
469         }
470
471         va_end(ap);
472         return(mdoc_nwarn(mdoc, n, EBADMSEC));
473 }
474
475
476 static int
477 check_args(struct mdoc *m, const struct mdoc_node *n)
478 {
479         int              i;
480
481         if (NULL == n->args)
482                 return(1);
483
484         assert(n->args->argc);
485         for (i = 0; i < (int)n->args->argc; i++)
486                 if ( ! check_argv(m, n, &n->args->argv[i]))
487                         return(0);
488
489         return(1);
490 }
491
492
493 static int
494 check_argv(struct mdoc *m, const struct mdoc_node *n,
495                 const struct mdoc_argv *v)
496 {
497         int              i;
498
499         for (i = 0; i < (int)v->sz; i++)
500                 if ( ! check_text(m, v->line, v->pos, v->value[i]))
501                         return(0);
502
503         if (MDOC_Std == v->arg) {
504                 /* `Nm' name must be set. */
505                 if (v->sz || m->meta.name)
506                         return(1);
507                 return(mdoc_nerr(m, n, ENAME));
508         }
509
510         return(1);
511 }
512
513
514 static int
515 check_text(struct mdoc *mdoc, int line, int pos, const char *p)
516 {
517         int              c;
518
519         for ( ; *p; p++, pos++) {
520                 if ('\t' == *p) {
521                         if ( ! (MDOC_LITERAL & mdoc->flags))
522                                 if ( ! warn_print(mdoc, line, pos))
523                                         return(0);
524                 } else if ( ! isprint((u_char)*p))
525                         if ( ! warn_print(mdoc, line, pos))
526                                 return(0);
527
528                 if ('\\' != *p)
529                         continue;
530
531                 c = mandoc_special(p);
532                 if (c) {
533                         p += c - 1;
534                         pos += c - 1;
535                         continue;
536                 }
537                 if ( ! (MDOC_IGN_ESCAPE & mdoc->pflags))
538                         return(mdoc_perr(mdoc, line, pos, EESCAPE));
539                 if ( ! mdoc_pwarn(mdoc, line, pos, EESCAPE))
540                         return(0);
541         }
542
543         return(1);
544 }
545
546
547
548
549 static int
550 check_parent(PRE_ARGS, int tok, enum mdoc_type t)
551 {
552
553         assert(n->parent);
554         if ((MDOC_ROOT == t || tok == n->parent->tok) &&
555                         (t == n->parent->type))
556                 return(1);
557
558         return(mdoc_verr(mdoc, n->line, n->pos, "require parent %s",
559                 MDOC_ROOT == t ? "<root>" : mdoc_macronames[tok]));
560 }
561
562
563
564 static int
565 pre_display(PRE_ARGS)
566 {
567         struct mdoc_node *node;
568
569         /* Display elements (`Bd', `D1'...) cannot be nested. */
570
571         if (MDOC_BLOCK != n->type)
572                 return(1);
573
574         /* LINTED */
575         for (node = mdoc->last->parent; node; node = node->parent)
576                 if (MDOC_BLOCK == node->type)
577                         if (MDOC_Bd == node->tok)
578                                 break;
579         if (NULL == node)
580                 return(1);
581
582         return(mdoc_nerr(mdoc, n, ENESTDISP));
583 }
584
585
586 static int
587 pre_bl(PRE_ARGS)
588 {
589         int              pos, type, width, offset;
590
591         if (MDOC_BLOCK != n->type)
592                 return(1);
593         if (NULL == n->args)
594                 return(mdoc_nerr(mdoc, n, ELISTTYPE));
595
596         /* Make sure that only one type of list is specified.  */
597
598         type = offset = width = -1;
599
600         /* LINTED */
601         for (pos = 0; pos < (int)n->args->argc; pos++)
602                 switch (n->args->argv[pos].arg) {
603                 case (MDOC_Bullet):
604                         /* FALLTHROUGH */
605                 case (MDOC_Dash):
606                         /* FALLTHROUGH */
607                 case (MDOC_Enum):
608                         /* FALLTHROUGH */
609                 case (MDOC_Hyphen):
610                         /* FALLTHROUGH */
611                 case (MDOC_Item):
612                         /* FALLTHROUGH */
613                 case (MDOC_Tag):
614                         /* FALLTHROUGH */
615                 case (MDOC_Diag):
616                         /* FALLTHROUGH */
617                 case (MDOC_Hang):
618                         /* FALLTHROUGH */
619                 case (MDOC_Ohang):
620                         /* FALLTHROUGH */
621                 case (MDOC_Inset):
622                         /* FALLTHROUGH */
623                 case (MDOC_Column):
624                         if (type >= 0)
625                                 return(mdoc_nerr(mdoc, n, EMULTILIST));
626                         type = n->args->argv[pos].arg;
627                         break;
628                 case (MDOC_Compact):
629                         if (type < 0 && ! mdoc_nwarn(mdoc, n, ENOTYPE))
630                                 return(0);
631                         break;
632                 case (MDOC_Width):
633                         if (width >= 0)
634                                 return(mdoc_nerr(mdoc, n, EARGREP));
635                         if (type < 0 && ! mdoc_nwarn(mdoc, n, ENOTYPE))
636                                 return(0);
637                         width = n->args->argv[pos].arg;
638                         break;
639                 case (MDOC_Offset):
640                         if (offset >= 0)
641                                 return(mdoc_nerr(mdoc, n, EARGREP));
642                         if (type < 0 && ! mdoc_nwarn(mdoc, n, ENOTYPE))
643                                 return(0);
644                         offset = n->args->argv[pos].arg;
645                         break;
646                 default:
647                         break;
648                 }
649
650         if (type < 0)
651                 return(mdoc_nerr(mdoc, n, ELISTTYPE));
652
653         /*
654          * Validate the width field.  Some list types don't need width
655          * types and should be warned about them.  Others should have it
656          * and must also be warned.
657          */
658
659         switch (type) {
660         case (MDOC_Tag):
661                 if (width < 0 && ! mdoc_nwarn(mdoc, n, EMISSWIDTH))
662                         return(0);
663                 break;
664         case (MDOC_Column):
665                 /* FALLTHROUGH */
666         case (MDOC_Diag):
667                 /* FALLTHROUGH */
668         case (MDOC_Ohang):
669                 /* FALLTHROUGH */
670         case (MDOC_Inset):
671                 /* FALLTHROUGH */
672         case (MDOC_Item):
673                 if (width >= 0 && ! mdoc_nwarn(mdoc, n, ENOWIDTH))
674                         return(0);
675                 break;
676         default:
677                 break;
678         }
679
680         return(1);
681 }
682
683
684 static int
685 pre_bd(PRE_ARGS)
686 {
687         int              i, type, err;
688
689         if (MDOC_BLOCK != n->type)
690                 return(1);
691         if (NULL == n->args)
692                 return(mdoc_nerr(mdoc, n, EDISPTYPE));
693
694         /* Make sure that only one type of display is specified.  */
695
696         /* LINTED */
697         for (i = 0, err = type = 0; ! err &&
698                         i < (int)n->args->argc; i++)
699                 switch (n->args->argv[i].arg) {
700                 case (MDOC_Centred):
701                         /* FALLTHROUGH */
702                 case (MDOC_Ragged):
703                         /* FALLTHROUGH */
704                 case (MDOC_Unfilled):
705                         /* FALLTHROUGH */
706                 case (MDOC_Filled):
707                         /* FALLTHROUGH */
708                 case (MDOC_Literal):
709                         if (0 == type++)
710                                 break;
711                         return(mdoc_nerr(mdoc, n, EMULTIDISP));
712                 default:
713                         break;
714                 }
715
716         if (type)
717                 return(1);
718         return(mdoc_nerr(mdoc, n, EDISPTYPE));
719 }
720
721
722 static int
723 pre_ss(PRE_ARGS)
724 {
725
726         if (MDOC_BLOCK != n->type)
727                 return(1);
728         return(check_parent(mdoc, n, MDOC_Sh, MDOC_BODY));
729 }
730
731
732 static int
733 pre_sh(PRE_ARGS)
734 {
735
736         if (MDOC_BLOCK != n->type)
737                 return(1);
738         return(check_parent(mdoc, n, -1, MDOC_ROOT));
739 }
740
741
742 static int
743 pre_it(PRE_ARGS)
744 {
745
746         if (MDOC_BLOCK != n->type)
747                 return(1);
748         return(check_parent(mdoc, n, MDOC_Bl, MDOC_BODY));
749 }
750
751
752 static int
753 pre_an(PRE_ARGS)
754 {
755
756         if (NULL == n->args || 1 == n->args->argc)
757                 return(1);
758         return(mdoc_verr(mdoc, n->line, n->pos,
759                                 "only one argument allowed"));
760 }
761
762
763 static int
764 pre_lb(PRE_ARGS)
765 {
766
767         return(check_sec(mdoc, n, SEC_LIBRARY, SEC_CUSTOM));
768 }
769
770
771 static int
772 pre_rv(PRE_ARGS)
773 {
774
775         if ( ! check_msec(mdoc, n, 2, 3, 0))
776                 return(0);
777         return(check_stdarg(mdoc, n));
778 }
779
780
781 static int
782 pre_ex(PRE_ARGS)
783 {
784
785         if ( ! check_msec(mdoc, n, 1, 6, 8, 0))
786                 return(0);
787         return(check_stdarg(mdoc, n));
788 }
789
790
791 static int
792 pre_er(PRE_ARGS)
793 {
794
795         return(check_msec(mdoc, n, 2, 3, 9, 0));
796 }
797
798
799 static int
800 pre_cd(PRE_ARGS)
801 {
802
803         return(check_msec(mdoc, n, 4, 0));
804 }
805
806
807 static int
808 pre_dt(PRE_ARGS)
809 {
810
811         /* FIXME: make sure is capitalised. */
812
813         if (0 == mdoc->meta.date || mdoc->meta.os)
814                 if ( ! mdoc_nwarn(mdoc, n, EPROLOOO))
815                         return(0);
816         if (mdoc->meta.title)
817                 if ( ! mdoc_nwarn(mdoc, n, EPROLREP))
818                         return(0);
819         return(1);
820 }
821
822
823 static int
824 pre_os(PRE_ARGS)
825 {
826
827         if (NULL == mdoc->meta.title || 0 == mdoc->meta.date)
828                 if ( ! mdoc_nwarn(mdoc, n, EPROLOOO))
829                         return(0);
830         if (mdoc->meta.os)
831                 if ( ! mdoc_nwarn(mdoc, n, EPROLREP))
832                         return(0);
833         return(1);
834 }
835
836
837 static int
838 pre_dd(PRE_ARGS)
839 {
840
841         if (mdoc->meta.title || mdoc->meta.os)
842                 if ( ! mdoc_nwarn(mdoc, n, EPROLOOO))
843                         return(0);
844         if (mdoc->meta.date)
845                 if ( ! mdoc_nwarn(mdoc, n, EPROLREP))
846                         return(0);
847         return(1);
848 }
849
850
851 static int
852 post_bf(POST_ARGS)
853 {
854         char             *p;
855         struct mdoc_node *head;
856
857         if (MDOC_BLOCK != mdoc->last->type)
858                 return(1);
859
860         head = mdoc->last->head;
861
862         if (mdoc->last->args && head->child)
863                 return(mdoc_nerr(mdoc, mdoc->last, ELINE));
864         else if (mdoc->last->args)
865                 return(1);
866
867         if (NULL == head->child || MDOC_TEXT != head->child->type)
868                 return(mdoc_nerr(mdoc, mdoc->last, ELINE));
869
870         p = head->child->string;
871
872         if (0 == strcmp(p, "Em"))
873                 return(1);
874         else if (0 == strcmp(p, "Li"))
875                 return(1);
876         else if (0 == strcmp(p, "Sy"))
877                 return(1);
878
879         return(mdoc_nerr(mdoc, head, EFONT));
880 }
881
882
883 static int
884 post_lb(POST_ARGS)
885 {
886
887         if (mdoc_a2lib(mdoc->last->child->string))
888                 return(1);
889         return(mdoc_nwarn(mdoc, mdoc->last, ELIB));
890 }
891
892
893 static int
894 post_nm(POST_ARGS)
895 {
896
897         if (mdoc->last->child)
898                 return(1);
899         if (mdoc->meta.name)
900                 return(1);
901         return(mdoc_nerr(mdoc, mdoc->last, ENAME));
902 }
903
904
905 static int
906 post_at(POST_ARGS)
907 {
908
909         if (NULL == mdoc->last->child)
910                 return(1);
911         if (MDOC_TEXT != mdoc->last->child->type)
912                 return(mdoc_nerr(mdoc, mdoc->last, EATT));
913         if (mdoc_a2att(mdoc->last->child->string))
914                 return(1);
915         return(mdoc_nerr(mdoc, mdoc->last, EATT));
916 }
917
918
919 static int
920 post_an(POST_ARGS)
921 {
922
923         if (mdoc->last->args) {
924                 if (NULL == mdoc->last->child)
925                         return(1);
926                 return(mdoc_nerr(mdoc, mdoc->last, ENOLINE));
927         }
928
929         if (mdoc->last->child)
930                 return(1);
931         return(mdoc_nerr(mdoc, mdoc->last, ELINE));
932 }
933
934
935 static int
936 post_it(POST_ARGS)
937 {
938         int               type, i, cols;
939         struct mdoc_node *n, *c;
940
941         if (MDOC_BLOCK != mdoc->last->type)
942                 return(1);
943
944         n = mdoc->last->parent->parent;
945         if (NULL == n->args)
946                 return(mdoc_nerr(mdoc, mdoc->last, ELISTTYPE));
947
948         /* Some types require block-head, some not. */
949
950         /* LINTED */
951         for (cols = type = -1, i = 0; -1 == type &&
952                         i < (int)n->args->argc; i++)
953                 switch (n->args->argv[i].arg) {
954                 case (MDOC_Tag):
955                         /* FALLTHROUGH */
956                 case (MDOC_Diag):
957                         /* FALLTHROUGH */
958                 case (MDOC_Hang):
959                         /* FALLTHROUGH */
960                 case (MDOC_Ohang):
961                         /* FALLTHROUGH */
962                 case (MDOC_Inset):
963                         /* FALLTHROUGH */
964                 case (MDOC_Bullet):
965                         /* FALLTHROUGH */
966                 case (MDOC_Dash):
967                         /* FALLTHROUGH */
968                 case (MDOC_Enum):
969                         /* FALLTHROUGH */
970                 case (MDOC_Hyphen):
971                         /* FALLTHROUGH */
972                 case (MDOC_Item):
973                         type = n->args->argv[i].arg;
974                         break;
975                 case (MDOC_Column):
976                         type = n->args->argv[i].arg;
977                         cols = (int)n->args->argv[i].sz;
978                         break;
979                 default:
980                         break;
981                 }
982
983         if (-1 == type)
984                 return(mdoc_nerr(mdoc, mdoc->last, ELISTTYPE));
985
986         switch (type) {
987         case (MDOC_Tag):
988                 if (NULL == mdoc->last->head->child)
989                         if ( ! mdoc_nwarn(mdoc, mdoc->last, ELINE))
990                                 return(0);
991                 break;
992         case (MDOC_Hang):
993                 /* FALLTHROUGH */
994         case (MDOC_Ohang):
995                 /* FALLTHROUGH */
996         case (MDOC_Inset):
997                 /* FALLTHROUGH */
998         case (MDOC_Diag):
999                 if (NULL == mdoc->last->head->child)
1000                         if ( ! mdoc_nwarn(mdoc, mdoc->last, ELINE))
1001                                 return(0);
1002                 if (NULL == mdoc->last->body->child)
1003                         if ( ! mdoc_nwarn(mdoc, mdoc->last, EMULTILINE))
1004                                 return(0);
1005                 break;
1006         case (MDOC_Bullet):
1007                 /* FALLTHROUGH */
1008         case (MDOC_Dash):
1009                 /* FALLTHROUGH */
1010         case (MDOC_Enum):
1011                 /* FALLTHROUGH */
1012         case (MDOC_Hyphen):
1013                 /* FALLTHROUGH */
1014         case (MDOC_Item):
1015                 if (mdoc->last->head->child)
1016                         if ( ! mdoc_nwarn(mdoc, mdoc->last, ENOLINE))
1017                                 return(0);
1018                 if (NULL == mdoc->last->body->child)
1019                         if ( ! mdoc_nwarn(mdoc, mdoc->last, EMULTILINE))
1020                                 return(0);
1021                 break;
1022         case (MDOC_Column):
1023                 if (NULL == mdoc->last->head->child)
1024                         if ( ! mdoc_nwarn(mdoc, mdoc->last, ELINE))
1025                                 return(0);
1026                 if (mdoc->last->body->child)
1027                         if ( ! mdoc_nwarn(mdoc, mdoc->last, ENOMULTILINE))
1028                                 return(0);
1029                 c = mdoc->last->child;
1030                 for (i = 0; c && MDOC_HEAD == c->type; c = c->next)
1031                         i++;
1032
1033                 if (i < cols || i == (cols + 1)) {
1034                         if ( ! mdoc_vwarn(mdoc, mdoc->last->line,
1035                                         mdoc->last->pos, "column "
1036                                         "mismatch: have %d, want %d",
1037                                         i, cols))
1038                                 return(0);
1039                         break;
1040                 } else if (i == cols)
1041                         break;
1042
1043                 return(mdoc_verr(mdoc, mdoc->last->line,
1044                                 mdoc->last->pos, "column mismatch: "
1045                                 "have %d, want %d", i, cols));
1046         default:
1047                 break;
1048         }
1049
1050         return(1);
1051 }
1052
1053
1054 static int
1055 post_bl_head(POST_ARGS)
1056 {
1057         int                     i;
1058         const struct mdoc_node *n;
1059
1060         n = mdoc->last->parent;
1061         assert(n->args);
1062
1063         for (i = 0; i < (int)n->args->argc; i++)
1064                 if (n->args->argv[i].arg == MDOC_Column)
1065                         break;
1066
1067         if (i == (int)n->args->argc)
1068                 return(1);
1069
1070         if (n->args->argv[i].sz && mdoc->last->child)
1071                 return(mdoc_nerr(mdoc, n, ECOLMIS));
1072
1073         return(1);
1074 }
1075
1076
1077 static int
1078 post_bl(POST_ARGS)
1079 {
1080         struct mdoc_node        *n;
1081
1082         if (MDOC_HEAD == mdoc->last->type)
1083                 return(post_bl_head(mdoc));
1084         if (MDOC_BODY != mdoc->last->type)
1085                 return(1);
1086         if (NULL == mdoc->last->child)
1087                 return(1);
1088
1089         /* LINTED */
1090         for (n = mdoc->last->child; n; n = n->next) {
1091                 if (MDOC_BLOCK == n->type)
1092                         if (MDOC_It == n->tok)
1093                                 continue;
1094                 return(mdoc_nerr(mdoc, n, EBADCHILD));
1095         }
1096
1097         return(1);
1098 }
1099
1100
1101 static int
1102 ebool(struct mdoc *mdoc)
1103 {
1104         struct mdoc_node *n;
1105
1106         /* LINTED */
1107         for (n = mdoc->last->child; n; n = n->next) {
1108                 if (MDOC_TEXT != n->type)
1109                         break;
1110                 if (0 == strcmp(n->string, "on"))
1111                         continue;
1112                 if (0 == strcmp(n->string, "off"))
1113                         continue;
1114                 break;
1115         }
1116
1117         if (NULL == n)
1118                 return(1);
1119         return(mdoc_nerr(mdoc, n, EBOOL));
1120 }
1121
1122
1123 static int
1124 post_root(POST_ARGS)
1125 {
1126
1127         if (NULL == mdoc->first->child)
1128                 return(mdoc_nerr(mdoc, mdoc->first, ENODAT));
1129         if ( ! (MDOC_PBODY & mdoc->flags))
1130                 return(mdoc_nerr(mdoc, mdoc->first, ENOPROLOGUE));
1131
1132         if (MDOC_BLOCK != mdoc->first->child->type)
1133                 return(mdoc_nerr(mdoc, mdoc->first, ENODAT));
1134         if (MDOC_Sh != mdoc->first->child->tok)
1135                 return(mdoc_nerr(mdoc, mdoc->first, ENODAT));
1136
1137         return(1);
1138 }
1139
1140
1141 static int
1142 post_st(POST_ARGS)
1143 {
1144
1145         if (mdoc_a2st(mdoc->last->child->string))
1146                 return(1);
1147         return(mdoc_nerr(mdoc, mdoc->last, EBADSTAND));
1148 }
1149
1150
1151 static int
1152 post_rs(POST_ARGS)
1153 {
1154         struct mdoc_node        *nn;
1155
1156         if (MDOC_BODY != mdoc->last->type)
1157                 return(1);
1158
1159         for (nn = mdoc->last->child; nn; nn = nn->next)
1160                 switch (nn->tok) {
1161                 case(MDOC__U):
1162                         /* FALLTHROUGH */
1163                 case(MDOC__Q):
1164                         /* FALLTHROUGH */
1165                 case(MDOC__C):
1166                         /* FALLTHROUGH */
1167                 case(MDOC__A):
1168                         /* FALLTHROUGH */
1169                 case(MDOC__B):
1170                         /* FALLTHROUGH */
1171                 case(MDOC__D):
1172                         /* FALLTHROUGH */
1173                 case(MDOC__I):
1174                         /* FALLTHROUGH */
1175                 case(MDOC__J):
1176                         /* FALLTHROUGH */
1177                 case(MDOC__N):
1178                         /* FALLTHROUGH */
1179                 case(MDOC__O):
1180                         /* FALLTHROUGH */
1181                 case(MDOC__P):
1182                         /* FALLTHROUGH */
1183                 case(MDOC__R):
1184                         /* FALLTHROUGH */
1185                 case(MDOC__T):
1186                         /* FALLTHROUGH */
1187                 case(MDOC__V):
1188                         break;
1189                 default:
1190                         return(mdoc_nerr(mdoc, nn, EBADCHILD));
1191                 }
1192
1193         return(1);
1194 }
1195
1196
1197 static int
1198 post_sh(POST_ARGS)
1199 {
1200
1201         if (MDOC_HEAD == mdoc->last->type)
1202                 return(post_sh_head(mdoc));
1203         if (MDOC_BODY == mdoc->last->type)
1204                 return(post_sh_body(mdoc));
1205
1206         return(1);
1207 }
1208
1209
1210 static int
1211 post_sh_body(POST_ARGS)
1212 {
1213         struct mdoc_node *n;
1214
1215         if (SEC_NAME != mdoc->lastsec)
1216                 return(1);
1217
1218         /*
1219          * Warn if the NAME section doesn't contain the `Nm' and `Nd'
1220          * macros (can have multiple `Nm' and one `Nd').  Note that the
1221          * children of the BODY declaration can also be "text".
1222          */
1223
1224         if (NULL == (n = mdoc->last->child))
1225                 return(mdoc_nwarn(mdoc, mdoc->last, ENAMESECINC));
1226
1227         for ( ; n && n->next; n = n->next) {
1228                 if (MDOC_ELEM == n->type && MDOC_Nm == n->tok)
1229                         continue;
1230                 if (MDOC_TEXT == n->type)
1231                         continue;
1232                 if ( ! mdoc_nwarn(mdoc, mdoc->last, ENAMESECINC))
1233                         return(0);
1234         }
1235
1236         assert(n);
1237         if (MDOC_BLOCK == n->type && MDOC_Nd == n->tok)
1238                 return(1);
1239         return(mdoc_nwarn(mdoc, mdoc->last, ENAMESECINC));
1240 }
1241
1242
1243 static int
1244 post_sh_head(POST_ARGS)
1245 {
1246         char                    buf[64];
1247         enum mdoc_sec           sec;
1248         const struct mdoc_node *n;
1249
1250         /*
1251          * Process a new section.  Sections are either "named" or
1252          * "custom"; custom sections are user-defined, while named ones
1253          * usually follow a conventional order and may only appear in
1254          * certain manual sections.
1255          */
1256
1257         buf[0] = 0;
1258
1259         for (n = mdoc->last->child; n; n = n->next) {
1260                 /* XXX - copied from compact(). */
1261                 assert(MDOC_TEXT == n->type);
1262
1263                 if (strlcat(buf, n->string, 64) >= 64)
1264                         return(mdoc_nerr(mdoc, n, ETOOLONG));
1265                 if (NULL == n->next)
1266                         continue;
1267                 if (strlcat(buf, " ", 64) >= 64)
1268                         return(mdoc_nerr(mdoc, n, ETOOLONG));
1269         }
1270
1271         sec = mdoc_atosec(buf);
1272
1273         /*
1274          * Check: NAME should always be first, CUSTOM has no roles,
1275          * non-CUSTOM has a conventional order to be followed.
1276          */
1277
1278         if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed)
1279                 return(mdoc_nerr(mdoc, mdoc->last, ESECNAME));
1280         if (SEC_CUSTOM == sec)
1281                 return(1);
1282         if (sec == mdoc->lastnamed)
1283                 if ( ! mdoc_nwarn(mdoc, mdoc->last, ESECREP))
1284                         return(0);
1285         if (sec < mdoc->lastnamed)
1286                 if ( ! mdoc_nwarn(mdoc, mdoc->last, ESECOOO))
1287                         return(0);
1288
1289         /*
1290          * Check particular section/manual conventions.  LIBRARY can
1291          * only occur in msec 2, 3 (TODO: are there more of these?).
1292          */
1293
1294         switch (sec) {
1295         case (SEC_LIBRARY):
1296                 switch (mdoc->meta.msec) {
1297                 case (2):
1298                         /* FALLTHROUGH */
1299                 case (3):
1300                         break;
1301                 default:
1302                         return(mdoc_nwarn(mdoc, mdoc->last, EWRONGMSEC));
1303                 }
1304                 break;
1305         default:
1306                 break;
1307         }
1308
1309         return(1);
1310 }
1311
1312
1313 static int
1314 pre_fd(PRE_ARGS)
1315 {
1316
1317         return(check_sec(mdoc, n, SEC_SYNOPSIS, SEC_CUSTOM));
1318 }