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