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