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