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