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