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