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