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