2011fa8382abead7ae3a49d9959baabf52d0870a
[dragonfly.git] / usr.bin / mandoc / mdoc_validate.c
1 /*      $Id: mdoc_validate.c,v 1.38 2009/10/27 21:40:07 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_it[] = { post_it, NULL };
119 static  v_post   posts_lb[] = { eerr_eq1, post_lb, NULL };
120 static  v_post   posts_nd[] = { berr_ge1, NULL };
121 static  v_post   posts_nm[] = { post_nm, NULL };
122 static  v_post   posts_notext[] = { eerr_eq0, NULL };
123 static  v_post   posts_rs[] = { berr_ge1, herr_eq0, post_rs, NULL };
124 static  v_post   posts_sh[] = { herr_ge1, bwarn_ge1, post_sh, NULL };
125 static  v_post   posts_sp[] = { eerr_le1, NULL };
126 static  v_post   posts_ss[] = { herr_ge1, NULL };
127 static  v_post   posts_st[] = { eerr_eq1, post_st, NULL };
128 static  v_post   posts_text[] = { eerr_ge1, NULL };
129 static  v_post   posts_text1[] = { eerr_eq1, NULL };
130 static  v_post   posts_wline[] = { bwarn_ge1, herr_eq0, NULL };
131 static  v_post   posts_wtext[] = { ewarn_ge1, NULL };
132 static  v_post   posts_xr[] = { eerr_ge1, eerr_le2, NULL };
133 static  v_pre    pres_an[] = { pre_an, NULL };
134 static  v_pre    pres_bd[] = { pre_display, pre_bd, NULL };
135 static  v_pre    pres_bl[] = { pre_bl, NULL };
136 static  v_pre    pres_cd[] = { pre_cd, NULL };
137 static  v_pre    pres_d1[] = { pre_display, NULL };
138 static  v_pre    pres_dd[] = { pre_dd, NULL };
139 static  v_pre    pres_dt[] = { pre_dt, NULL };
140 static  v_pre    pres_er[] = { pre_er, NULL };
141 static  v_pre    pres_ex[] = { pre_ex, NULL };
142 static  v_pre    pres_fd[] = { pre_fd, NULL };
143 static  v_pre    pres_it[] = { pre_it, NULL };
144 static  v_pre    pres_lb[] = { pre_lb, NULL };
145 static  v_pre    pres_os[] = { pre_os, NULL };
146 static  v_pre    pres_rv[] = { pre_rv, NULL };
147 static  v_pre    pres_sh[] = { pre_sh, NULL };
148 static  v_pre    pres_ss[] = { pre_ss, NULL };
149
150 const   struct valids mdoc_valids[MDOC_MAX] = {
151         { NULL, NULL },                         /* Ap */
152         { pres_dd, posts_text },                /* Dd */
153         { pres_dt, NULL },                      /* Dt */
154         { pres_os, NULL },                      /* Os */
155         { pres_sh, posts_sh },                  /* Sh */
156         { pres_ss, posts_ss },                  /* Ss */
157         { NULL, posts_notext },                 /* Pp */
158         { pres_d1, posts_wline },               /* D1 */
159         { pres_d1, posts_wline },               /* Dl */
160         { pres_bd, posts_bd },                  /* Bd */
161         { NULL, NULL },                         /* Ed */
162         { pres_bl, posts_bl },                  /* Bl */
163         { NULL, NULL },                         /* El */
164         { pres_it, posts_it },                  /* It */
165         { NULL, posts_text },                   /* Ad */
166         { pres_an, posts_an },                  /* An */
167         { NULL, NULL },                         /* Ar */
168         { pres_cd, posts_text },                /* Cd */
169         { NULL, NULL },                         /* Cm */
170         { NULL, NULL },                         /* Dv */
171         { pres_er, posts_text },                /* Er */
172         { NULL, NULL },                         /* Ev */
173         { pres_ex, NULL },                      /* Ex */
174         { NULL, NULL },                         /* Fa */
175         { pres_fd, posts_wtext },               /* Fd */
176         { NULL, NULL },                         /* Fl */
177         { NULL, posts_text },                   /* Fn */
178         { NULL, posts_wtext },                  /* Ft */
179         { NULL, posts_text },                   /* Ic */
180         { NULL, posts_text1 },                  /* In */
181         { NULL, NULL },                         /* Li */
182         { NULL, posts_nd },                     /* Nd */
183         { NULL, posts_nm },                     /* Nm */
184         { NULL, posts_wline },                  /* Op */
185         { NULL, NULL },                         /* Ot */
186         { NULL, NULL },                         /* Pa */
187         { pres_rv, NULL },                      /* Rv */
188         { NULL, posts_st },                     /* St */
189         { NULL, NULL },                         /* Va */
190         { NULL, posts_text },                   /* Vt */
191         { NULL, posts_xr },                     /* Xr */
192         { NULL, posts_text },                   /* %A */
193         { NULL, posts_text },                   /* %B */ /* FIXME: can be used outside Rs/Re. */
194         { NULL, posts_text },                   /* %D */
195         { NULL, posts_text },                   /* %I */
196         { NULL, posts_text },                   /* %J */
197         { NULL, posts_text },                   /* %N */
198         { NULL, posts_text },                   /* %O */
199         { NULL, posts_text },                   /* %P */
200         { NULL, posts_text },                   /* %R */
201         { NULL, posts_text },                   /* %T */ /* FIXME: can be used outside Rs/Re. */
202         { NULL, posts_text },                   /* %V */
203         { NULL, NULL },                         /* Ac */
204         { NULL, NULL },                         /* Ao */
205         { NULL, posts_wline },                  /* Aq */
206         { NULL, posts_at },                     /* At */
207         { NULL, NULL },                         /* Bc */
208         { NULL, posts_bf },                     /* Bf */
209         { NULL, NULL },                         /* Bo */
210         { NULL, posts_wline },                  /* Bq */
211         { NULL, NULL },                         /* Bsx */
212         { NULL, NULL },                         /* Bx */
213         { NULL, posts_bool },                   /* Db */
214         { NULL, NULL },                         /* Dc */
215         { NULL, NULL },                         /* Do */
216         { NULL, posts_wline },                  /* Dq */
217         { NULL, NULL },                         /* Ec */
218         { NULL, NULL },                         /* Ef */
219         { NULL, NULL },                         /* Em */
220         { NULL, NULL },                         /* Eo */
221         { NULL, NULL },                         /* Fx */
222         { NULL, posts_text },                   /* Ms */
223         { NULL, posts_notext },                 /* No */
224         { NULL, posts_notext },                 /* Ns */
225         { NULL, NULL },                         /* Nx */
226         { NULL, NULL },                         /* Ox */
227         { NULL, NULL },                         /* Pc */
228         { NULL, posts_text1 },                  /* Pf */
229         { NULL, NULL },                         /* Po */
230         { NULL, posts_wline },                  /* Pq */
231         { NULL, NULL },                         /* Qc */
232         { NULL, posts_wline },                  /* Ql */
233         { NULL, NULL },                         /* Qo */
234         { NULL, posts_wline },                  /* Qq */
235         { NULL, NULL },                         /* Re */
236         { NULL, posts_rs },                     /* Rs */
237         { NULL, NULL },                         /* Sc */
238         { NULL, NULL },                         /* So */
239         { NULL, posts_wline },                  /* Sq */
240         { NULL, posts_bool },                   /* Sm */
241         { NULL, posts_text },                   /* Sx */
242         { NULL, posts_text },                   /* Sy */
243         { NULL, posts_text },                   /* Tn */
244         { NULL, NULL },                         /* Ux */
245         { NULL, NULL },                         /* Xc */
246         { NULL, NULL },                         /* Xo */
247         { NULL, posts_fo },                     /* Fo */
248         { NULL, NULL },                         /* Fc */
249         { NULL, NULL },                         /* Oo */
250         { NULL, NULL },                         /* Oc */
251         { NULL, posts_wline },                  /* Bk */
252         { NULL, NULL },                         /* Ek */
253         { NULL, posts_notext },                 /* Bt */
254         { NULL, NULL },                         /* Hf */
255         { NULL, NULL },                         /* Fr */
256         { NULL, posts_notext },                 /* Ud */
257         { pres_lb, posts_lb },                  /* Lb */
258         { NULL, posts_notext },                 /* Lp */
259         { NULL, posts_text },                   /* Lk */
260         { NULL, posts_text },                   /* Mt */
261         { NULL, posts_wline },                  /* Brq */
262         { NULL, NULL },                         /* Bro */
263         { NULL, NULL },                         /* Brc */
264         { NULL, posts_text },                   /* %C */
265         { NULL, NULL },                         /* Es */
266         { NULL, NULL },                         /* En */
267         { NULL, NULL },                         /* Dx */
268         { NULL, posts_text },                   /* %Q */
269         { NULL, posts_notext },                 /* br */
270         { NULL, posts_sp },                     /* sp */
271         { NULL, posts_text1 },                  /* %U */
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_Centred):
696                         /* FALLTHROUGH */
697                 case (MDOC_Ragged):
698                         /* FALLTHROUGH */
699                 case (MDOC_Unfilled):
700                         /* FALLTHROUGH */
701                 case (MDOC_Filled):
702                         /* FALLTHROUGH */
703                 case (MDOC_Literal):
704                         if (0 == type++)
705                                 break;
706                         return(mdoc_nerr(mdoc, n, EMULTIDISP));
707                 default:
708                         break;
709                 }
710
711         if (type)
712                 return(1);
713         return(mdoc_nerr(mdoc, n, EDISPTYPE));
714 }
715
716
717 static int
718 pre_ss(PRE_ARGS)
719 {
720
721         if (MDOC_BLOCK != n->type)
722                 return(1);
723         return(check_parent(mdoc, n, MDOC_Sh, MDOC_BODY));
724 }
725
726
727 static int
728 pre_sh(PRE_ARGS)
729 {
730
731         if (MDOC_BLOCK != n->type)
732                 return(1);
733         return(check_parent(mdoc, n, -1, MDOC_ROOT));
734 }
735
736
737 static int
738 pre_it(PRE_ARGS)
739 {
740
741         if (MDOC_BLOCK != n->type)
742                 return(1);
743         return(check_parent(mdoc, n, MDOC_Bl, MDOC_BODY));
744 }
745
746
747 static int
748 pre_an(PRE_ARGS)
749 {
750
751         if (NULL == n->args || 1 == n->args->argc)
752                 return(1);
753         return(mdoc_verr(mdoc, n->line, n->pos,
754                                 "only one argument allowed"));
755 }
756
757
758 static int
759 pre_lb(PRE_ARGS)
760 {
761
762         return(check_sec(mdoc, n, SEC_LIBRARY, SEC_CUSTOM));
763 }
764
765
766 static int
767 pre_rv(PRE_ARGS)
768 {
769
770         if ( ! check_msec(mdoc, n, 2, 3, 0))
771                 return(0);
772         return(check_stdarg(mdoc, n));
773 }
774
775
776 static int
777 pre_ex(PRE_ARGS)
778 {
779
780         if ( ! check_msec(mdoc, n, 1, 6, 8, 0))
781                 return(0);
782         return(check_stdarg(mdoc, n));
783 }
784
785
786 static int
787 pre_er(PRE_ARGS)
788 {
789
790         return(check_msec(mdoc, n, 2, 3, 9, 0));
791 }
792
793
794 static int
795 pre_cd(PRE_ARGS)
796 {
797
798         return(check_msec(mdoc, n, 4, 0));
799 }
800
801
802 static int
803 pre_dt(PRE_ARGS)
804 {
805
806         if (0 == mdoc->meta.date || mdoc->meta.os)
807                 if ( ! mdoc_nwarn(mdoc, n, EPROLOOO))
808                         return(0);
809         if (mdoc->meta.title)
810                 if ( ! mdoc_nwarn(mdoc, n, EPROLREP))
811                         return(0);
812         return(1);
813 }
814
815
816 static int
817 pre_os(PRE_ARGS)
818 {
819
820         if (NULL == mdoc->meta.title || 0 == mdoc->meta.date)
821                 if ( ! mdoc_nwarn(mdoc, n, EPROLOOO))
822                         return(0);
823         if (mdoc->meta.os)
824                 if ( ! mdoc_nwarn(mdoc, n, EPROLREP))
825                         return(0);
826         return(1);
827 }
828
829
830 static int
831 pre_dd(PRE_ARGS)
832 {
833
834         if (mdoc->meta.title || mdoc->meta.os)
835                 if ( ! mdoc_nwarn(mdoc, n, EPROLOOO))
836                         return(0);
837         if (mdoc->meta.date)
838                 if ( ! mdoc_nwarn(mdoc, n, EPROLREP))
839                         return(0);
840         return(1);
841 }
842
843
844 static int
845 post_bf(POST_ARGS)
846 {
847         char             *p;
848         struct mdoc_node *head;
849
850         if (MDOC_BLOCK != mdoc->last->type)
851                 return(1);
852
853         head = mdoc->last->head;
854
855         if (mdoc->last->args && head->child)
856                 return(mdoc_nerr(mdoc, mdoc->last, ELINE));
857         else if (mdoc->last->args)
858                 return(1);
859
860         if (NULL == head->child || MDOC_TEXT != head->child->type)
861                 return(mdoc_nerr(mdoc, mdoc->last, ELINE));
862
863         p = head->child->string;
864
865         if (0 == strcmp(p, "Em"))
866                 return(1);
867         else if (0 == strcmp(p, "Li"))
868                 return(1);
869         else if (0 == strcmp(p, "Sy"))
870                 return(1);
871
872         return(mdoc_nerr(mdoc, head, EFONT));
873 }
874
875
876 static int
877 post_lb(POST_ARGS)
878 {
879
880         if (mdoc_a2lib(mdoc->last->child->string))
881                 return(1);
882         return(mdoc_nwarn(mdoc, mdoc->last, ELIB));
883 }
884
885
886 static int
887 post_nm(POST_ARGS)
888 {
889
890         if (mdoc->last->child)
891                 return(1);
892         if (mdoc->meta.name)
893                 return(1);
894         return(mdoc_nerr(mdoc, mdoc->last, ENAME));
895 }
896
897
898 static int
899 post_at(POST_ARGS)
900 {
901
902         if (NULL == mdoc->last->child)
903                 return(1);
904         if (MDOC_TEXT != mdoc->last->child->type)
905                 return(mdoc_nerr(mdoc, mdoc->last, EATT));
906         if (mdoc_a2att(mdoc->last->child->string))
907                 return(1);
908         return(mdoc_nerr(mdoc, mdoc->last, EATT));
909 }
910
911
912 static int
913 post_an(POST_ARGS)
914 {
915
916         if (mdoc->last->args) {
917                 if (NULL == mdoc->last->child)
918                         return(1);
919                 return(mdoc_nerr(mdoc, mdoc->last, ENOLINE));
920         }
921
922         if (mdoc->last->child)
923                 return(1);
924         return(mdoc_nerr(mdoc, mdoc->last, ELINE));
925 }
926
927
928 static int
929 post_it(POST_ARGS)
930 {
931         int               type, i, cols;
932         struct mdoc_node *n, *c;
933
934         if (MDOC_BLOCK != mdoc->last->type)
935                 return(1);
936
937         n = mdoc->last->parent->parent;
938         if (NULL == n->args)
939                 return(mdoc_nerr(mdoc, mdoc->last, ELISTTYPE));
940
941         /* Some types require block-head, some not. */
942
943         /* LINTED */
944         for (cols = type = -1, i = 0; -1 == type &&
945                         i < (int)n->args->argc; i++)
946                 switch (n->args->argv[i].arg) {
947                 case (MDOC_Tag):
948                         /* FALLTHROUGH */
949                 case (MDOC_Diag):
950                         /* FALLTHROUGH */
951                 case (MDOC_Hang):
952                         /* FALLTHROUGH */
953                 case (MDOC_Ohang):
954                         /* FALLTHROUGH */
955                 case (MDOC_Inset):
956                         /* FALLTHROUGH */
957                 case (MDOC_Bullet):
958                         /* FALLTHROUGH */
959                 case (MDOC_Dash):
960                         /* FALLTHROUGH */
961                 case (MDOC_Enum):
962                         /* FALLTHROUGH */
963                 case (MDOC_Hyphen):
964                         /* FALLTHROUGH */
965                 case (MDOC_Item):
966                         type = n->args->argv[i].arg;
967                         break;
968                 case (MDOC_Column):
969                         type = n->args->argv[i].arg;
970                         cols = (int)n->args->argv[i].sz;
971                         break;
972                 default:
973                         break;
974                 }
975
976         if (-1 == type)
977                 return(mdoc_nerr(mdoc, mdoc->last, ELISTTYPE));
978
979         switch (type) {
980         case (MDOC_Tag):
981                 if (NULL == mdoc->last->head->child)
982                         if ( ! mdoc_nwarn(mdoc, mdoc->last, ELINE))
983                                 return(0);
984                 break;
985         case (MDOC_Hang):
986                 /* FALLTHROUGH */
987         case (MDOC_Ohang):
988                 /* FALLTHROUGH */
989         case (MDOC_Inset):
990                 /* FALLTHROUGH */
991         case (MDOC_Diag):
992                 if (NULL == mdoc->last->head->child)
993                         if ( ! mdoc_nwarn(mdoc, mdoc->last, ELINE))
994                                 return(0);
995                 if (NULL == mdoc->last->body->child)
996                         if ( ! mdoc_nwarn(mdoc, mdoc->last, EMULTILINE))
997                                 return(0);
998                 break;
999         case (MDOC_Bullet):
1000                 /* FALLTHROUGH */
1001         case (MDOC_Dash):
1002                 /* FALLTHROUGH */
1003         case (MDOC_Enum):
1004                 /* FALLTHROUGH */
1005         case (MDOC_Hyphen):
1006                 /* FALLTHROUGH */
1007         case (MDOC_Item):
1008                 if (mdoc->last->head->child)
1009                         if ( ! mdoc_nwarn(mdoc, mdoc->last, ENOLINE))
1010                                 return(0);
1011                 if (NULL == mdoc->last->body->child)
1012                         if ( ! mdoc_nwarn(mdoc, mdoc->last, EMULTILINE))
1013                                 return(0);
1014                 break;
1015         case (MDOC_Column):
1016                 if (NULL == mdoc->last->head->child)
1017                         if ( ! mdoc_nwarn(mdoc, mdoc->last, ELINE))
1018                                 return(0);
1019                 if (mdoc->last->body->child)
1020                         if ( ! mdoc_nwarn(mdoc, mdoc->last, ENOMULTILINE))
1021                                 return(0);
1022                 c = mdoc->last->child;
1023                 for (i = 0; c && MDOC_HEAD == c->type; c = c->next)
1024                         i++;
1025
1026                 if (i < cols || i == (cols + 1)) {
1027                         if ( ! mdoc_vwarn(mdoc, mdoc->last->line,
1028                                         mdoc->last->pos, "column "
1029                                         "mismatch: have %d, want %d",
1030                                         i, cols))
1031                                 return(0);
1032                         break;
1033                 } else if (i == cols)
1034                         break;
1035
1036                 return(mdoc_verr(mdoc, mdoc->last->line,
1037                                 mdoc->last->pos, "column mismatch: "
1038                                 "have %d, want %d", i, cols));
1039         default:
1040                 break;
1041         }
1042
1043         return(1);
1044 }
1045
1046
1047 static int
1048 post_bl_head(POST_ARGS)
1049 {
1050         int                     i;
1051         const struct mdoc_node *n;
1052
1053         n = mdoc->last->parent;
1054         assert(n->args);
1055
1056         for (i = 0; i < (int)n->args->argc; i++)
1057                 if (n->args->argv[i].arg == MDOC_Column)
1058                         break;
1059
1060         if (i == (int)n->args->argc)
1061                 return(1);
1062
1063         if (n->args->argv[i].sz && mdoc->last->child)
1064                 return(mdoc_nerr(mdoc, n, ECOLMIS));
1065
1066         return(1);
1067 }
1068
1069
1070 static int
1071 post_bl(POST_ARGS)
1072 {
1073         struct mdoc_node        *n;
1074
1075         if (MDOC_HEAD == mdoc->last->type)
1076                 return(post_bl_head(mdoc));
1077         if (MDOC_BODY != mdoc->last->type)
1078                 return(1);
1079         if (NULL == mdoc->last->child)
1080                 return(1);
1081
1082         /* LINTED */
1083         for (n = mdoc->last->child; n; n = n->next) {
1084                 if (MDOC_BLOCK == n->type)
1085                         if (MDOC_It == n->tok)
1086                                 continue;
1087                 return(mdoc_nerr(mdoc, n, EBADCHILD));
1088         }
1089
1090         return(1);
1091 }
1092
1093
1094 static int
1095 ebool(struct mdoc *mdoc)
1096 {
1097         struct mdoc_node *n;
1098
1099         /* LINTED */
1100         for (n = mdoc->last->child; n; n = n->next) {
1101                 if (MDOC_TEXT != n->type)
1102                         break;
1103                 if (0 == strcmp(n->string, "on"))
1104                         continue;
1105                 if (0 == strcmp(n->string, "off"))
1106                         continue;
1107                 break;
1108         }
1109
1110         if (NULL == n)
1111                 return(1);
1112         return(mdoc_nerr(mdoc, n, EBOOL));
1113 }
1114
1115
1116 static int
1117 post_root(POST_ARGS)
1118 {
1119
1120         if (NULL == mdoc->first->child)
1121                 return(mdoc_nerr(mdoc, mdoc->first, ENODAT));
1122         if ( ! (MDOC_PBODY & mdoc->flags))
1123                 return(mdoc_nerr(mdoc, mdoc->first, ENOPROLOGUE));
1124
1125         if (MDOC_BLOCK != mdoc->first->child->type)
1126                 return(mdoc_nerr(mdoc, mdoc->first, ENODAT));
1127         if (MDOC_Sh != mdoc->first->child->tok)
1128                 return(mdoc_nerr(mdoc, mdoc->first, ENODAT));
1129
1130         return(1);
1131 }
1132
1133
1134 static int
1135 post_st(POST_ARGS)
1136 {
1137
1138         if (mdoc_a2st(mdoc->last->child->string))
1139                 return(1);
1140         return(mdoc_nerr(mdoc, mdoc->last, EBADSTAND));
1141 }
1142
1143
1144 static int
1145 post_rs(POST_ARGS)
1146 {
1147         struct mdoc_node        *nn;
1148
1149         if (MDOC_BODY != mdoc->last->type)
1150                 return(1);
1151
1152         for (nn = mdoc->last->child; nn; nn = nn->next)
1153                 switch (nn->tok) {
1154                 case(MDOC__U):
1155                         /* FALLTHROUGH */
1156                 case(MDOC__Q):
1157                         /* FALLTHROUGH */
1158                 case(MDOC__C):
1159                         /* FALLTHROUGH */
1160                 case(MDOC__A):
1161                         /* FALLTHROUGH */
1162                 case(MDOC__B):
1163                         /* FALLTHROUGH */
1164                 case(MDOC__D):
1165                         /* FALLTHROUGH */
1166                 case(MDOC__I):
1167                         /* FALLTHROUGH */
1168                 case(MDOC__J):
1169                         /* FALLTHROUGH */
1170                 case(MDOC__N):
1171                         /* FALLTHROUGH */
1172                 case(MDOC__O):
1173                         /* FALLTHROUGH */
1174                 case(MDOC__P):
1175                         /* FALLTHROUGH */
1176                 case(MDOC__R):
1177                         /* FALLTHROUGH */
1178                 case(MDOC__T):
1179                         /* FALLTHROUGH */
1180                 case(MDOC__V):
1181                         break;
1182                 default:
1183                         return(mdoc_nerr(mdoc, nn, EBADCHILD));
1184                 }
1185
1186         return(1);
1187 }
1188
1189
1190 static int
1191 post_sh(POST_ARGS)
1192 {
1193
1194         if (MDOC_HEAD == mdoc->last->type)
1195                 return(post_sh_head(mdoc));
1196         if (MDOC_BODY == mdoc->last->type)
1197                 return(post_sh_body(mdoc));
1198
1199         return(1);
1200 }
1201
1202
1203 static int
1204 post_sh_body(POST_ARGS)
1205 {
1206         struct mdoc_node *n;
1207
1208         if (SEC_NAME != mdoc->lastsec)
1209                 return(1);
1210
1211         /*
1212          * Warn if the NAME section doesn't contain the `Nm' and `Nd'
1213          * macros (can have multiple `Nm' and one `Nd').  Note that the
1214          * children of the BODY declaration can also be "text".
1215          */
1216
1217         if (NULL == (n = mdoc->last->child))
1218                 return(mdoc_nwarn(mdoc, mdoc->last, ENAMESECINC));
1219
1220         for ( ; n && n->next; n = n->next) {
1221                 if (MDOC_ELEM == n->type && MDOC_Nm == n->tok)
1222                         continue;
1223                 if (MDOC_TEXT == n->type)
1224                         continue;
1225                 if ( ! mdoc_nwarn(mdoc, mdoc->last, ENAMESECINC))
1226                         return(0);
1227         }
1228
1229         assert(n);
1230         if (MDOC_BLOCK == n->type && MDOC_Nd == n->tok)
1231                 return(1);
1232         return(mdoc_nwarn(mdoc, mdoc->last, ENAMESECINC));
1233 }
1234
1235
1236 static int
1237 post_sh_head(POST_ARGS)
1238 {
1239         char                    buf[64];
1240         enum mdoc_sec           sec;
1241         const struct mdoc_node *n;
1242
1243         /*
1244          * Process a new section.  Sections are either "named" or
1245          * "custom"; custom sections are user-defined, while named ones
1246          * usually follow a conventional order and may only appear in
1247          * certain manual sections.
1248          */
1249
1250         buf[0] = 0;
1251
1252         for (n = mdoc->last->child; n; n = n->next) {
1253                 /* XXX - copied from compact(). */
1254                 assert(MDOC_TEXT == n->type);
1255
1256                 if (strlcat(buf, n->string, 64) >= 64)
1257                         return(mdoc_nerr(mdoc, n, ETOOLONG));
1258                 if (NULL == n->next)
1259                         continue;
1260                 if (strlcat(buf, " ", 64) >= 64)
1261                         return(mdoc_nerr(mdoc, n, ETOOLONG));
1262         }
1263
1264         sec = mdoc_atosec(buf);
1265
1266         /*
1267          * Check: NAME should always be first, CUSTOM has no roles,
1268          * non-CUSTOM has a conventional order to be followed.
1269          */
1270
1271         if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed)
1272                 return(mdoc_nerr(mdoc, mdoc->last, ESECNAME));
1273         if (SEC_CUSTOM == sec)
1274                 return(1);
1275         if (sec == mdoc->lastnamed)
1276                 if ( ! mdoc_nwarn(mdoc, mdoc->last, ESECREP))
1277                         return(0);
1278         if (sec < mdoc->lastnamed)
1279                 if ( ! mdoc_nwarn(mdoc, mdoc->last, ESECOOO))
1280                         return(0);
1281
1282         /*
1283          * Check particular section/manual conventions.  LIBRARY can
1284          * only occur in msec 2, 3 (TODO: are there more of these?).
1285          */
1286
1287         switch (sec) {
1288         case (SEC_LIBRARY):
1289                 switch (mdoc->meta.msec) {
1290                 case (2):
1291                         /* FALLTHROUGH */
1292                 case (3):
1293                         break;
1294                 default:
1295                         return(mdoc_nwarn(mdoc, mdoc->last, EWRONGMSEC));
1296                 }
1297                 break;
1298         default:
1299                 break;
1300         }
1301
1302         return(1);
1303 }
1304
1305
1306 static int
1307 pre_fd(PRE_ARGS)
1308 {
1309
1310         return(check_sec(mdoc, n, SEC_SYNOPSIS, SEC_CUSTOM));
1311 }