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