]> git.cameronkatri.com Git - mandoc.git/blob - mdoc_validate.c
Removed MDOC___: moved MDOC_Ap to its index (comments not passed into mdoc parser).
[mandoc.git] / mdoc_validate.c
1 /* $Id: mdoc_validate.c,v 1.10 2009/06/16 19:45:51 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 }, /* Ap */
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, posts_pp }, /* Lp */
302 { NULL, NULL }, /* Lk */
303 { NULL, posts_text }, /* Mt */
304 { NULL, posts_wline }, /* Brq */
305 { NULL, NULL }, /* Bro */
306 { NULL, NULL }, /* Brc */
307 { NULL, posts_text }, /* %C */
308 { NULL, NULL }, /* Es */
309 { NULL, NULL }, /* En */
310 { NULL, NULL }, /* Dx */
311 { NULL, posts_text }, /* %Q */
312 };
313
314
315 #ifdef __linux__
316 extern size_t strlcat(char *, const char *, size_t);
317 #endif
318
319
320 int
321 mdoc_valid_pre(struct mdoc *mdoc,
322 const struct mdoc_node *n)
323 {
324 v_pre *p;
325 int line, pos;
326 const char *tp;
327
328 if (MDOC_TEXT == n->type) {
329 tp = n->string;
330 line = n->line;
331 pos = n->pos;
332 return(check_text(mdoc, line, pos, tp));
333 }
334
335 if ( ! check_args(mdoc, n))
336 return(0);
337 if (NULL == mdoc_valids[n->tok].pre)
338 return(1);
339 for (p = mdoc_valids[n->tok].pre; *p; p++)
340 if ( ! (*p)(mdoc, n))
341 return(0);
342 return(1);
343 }
344
345
346 int
347 mdoc_valid_post(struct mdoc *mdoc)
348 {
349 v_post *p;
350
351 /*
352 * This check occurs after the macro's children have been filled
353 * in: postfix validation. Since this happens when we're
354 * rewinding the scope tree, it's possible to have multiple
355 * invocations (as by design, for now), we set bit MDOC_VALID to
356 * indicate that we've validated.
357 */
358
359 if (MDOC_VALID & mdoc->last->flags)
360 return(1);
361 mdoc->last->flags |= MDOC_VALID;
362
363 if (MDOC_TEXT == mdoc->last->type)
364 return(1);
365 if (MDOC_ROOT == mdoc->last->type)
366 return(post_root(mdoc));
367
368 if (NULL == mdoc_valids[mdoc->last->tok].post)
369 return(1);
370 for (p = mdoc_valids[mdoc->last->tok].post; *p; p++)
371 if ( ! (*p)(mdoc))
372 return(0);
373
374 return(1);
375 }
376
377
378 static int
379 perr(struct mdoc *m, int line, int pos, enum merr type)
380 {
381 char *p;
382
383 p = NULL;
384 switch (type) {
385 case (ETOOLONG):
386 p = "text argument too long";
387 break;
388 case (EESCAPE):
389 p = "invalid escape sequence";
390 break;
391 case (EPRINT):
392 p = "invalid character";
393 break;
394 case (ENESTDISP):
395 p = "displays may not be nested";
396 break;
397 case (EBOOL):
398 p = "expected boolean value";
399 break;
400 case (EARGREP):
401 p = "argument repeated";
402 break;
403 case (EMULTIDISP):
404 p = "multiple display types specified";
405 break;
406 case (EMULTILIST):
407 p = "multiple list types specified";
408 break;
409 case (ELISTTYPE):
410 p = "missing list type";
411 break;
412 case (EDISPTYPE):
413 p = "missing display type";
414 break;
415 case (ELINE):
416 p = "expected line arguments";
417 break;
418 case (ENOPROLOGUE):
419 p = "document has no prologue";
420 break;
421 case (ENODATA):
422 p = "document has no data";
423 break;
424 case (EATT):
425 p = "expected valid AT&T symbol";
426 break;
427 case (ENAME):
428 p = "default name not yet set";
429 break;
430 }
431 assert(p);
432 return(mdoc_perr(m, line, pos, p));
433 }
434
435
436 static int
437 pwarn(struct mdoc *m, int line, int pos, enum mwarn type)
438 {
439 char *p;
440 enum mdoc_warn c;
441
442 c = WARN_SYNTAX;
443 p = NULL;
444 switch (type) {
445 case (WBADMSEC):
446 p = "inappropriate manual section";
447 c = WARN_COMPAT;
448 break;
449 case (WBADSEC):
450 p = "inappropriate document section";
451 c = WARN_COMPAT;
452 break;
453 case (WARGVAL):
454 p = "argument value suggested";
455 c = WARN_COMPAT;
456 break;
457 case (WPROLREP):
458 p = "prologue macros repeated";
459 c = WARN_COMPAT;
460 break;
461 case (WPROLOOO):
462 p = "prologue macros out-of-order";
463 c = WARN_COMPAT;
464 break;
465 case (WDEPCOL):
466 p = "deprecated column argument syntax";
467 c = WARN_COMPAT;
468 break;
469 case (WNOWIDTH):
470 p = "superfluous width argument";
471 break;
472 case (WMISSWIDTH):
473 p = "missing width argument";
474 break;
475 case (WPRINT):
476 p = "invalid character";
477 break;
478 case (WESCAPE):
479 p = "invalid escape sequence";
480 break;
481 case (WNOLINE):
482 p = "suggested no line arguments";
483 break;
484 case (WLINE):
485 p = "suggested line arguments";
486 break;
487 case (WMULTILINE):
488 p = "suggested multi-line arguments";
489 break;
490 case (WNOMULTILINE):
491 p = "suggested no multi-line arguments";
492 break;
493 case (WWRONGMSEC):
494 p = "document section in wrong manual section";
495 c = WARN_COMPAT;
496 break;
497 case (WSECOOO):
498 p = "document section out of conventional order";
499 break;
500 case (WSECREP):
501 p = "document section repeated";
502 break;
503 case (WBADSTAND):
504 p = "unknown standard";
505 break;
506 case (WNAMESECINC):
507 p = "NAME section contents incomplete/badly-ordered";
508 break;
509 }
510 assert(p);
511 return(mdoc_pwarn(m, line, pos, c, p));
512 }
513
514
515 static int
516 warn_print(struct mdoc *m, int ln, int pos)
517 {
518 if (MDOC_IGN_CHARS & m->pflags)
519 return(pwarn(m, ln, pos, WPRINT));
520 return(perr(m, ln, pos, EPRINT));
521 }
522
523
524 static inline int
525 warn_count(struct mdoc *m, const char *k,
526 int want, const char *v, int has)
527 {
528
529 return(mdoc_warn(m, WARN_SYNTAX,
530 "suggests %s %s %d (has %d)", v, k, want, has));
531 }
532
533
534 static inline int
535 err_count(struct mdoc *m, const char *k,
536 int want, const char *v, int has)
537 {
538
539 return(mdoc_err(m,
540 "requires %s %s %d (has %d)", v, k, want, has));
541 }
542
543
544 static inline int
545 count_child(struct mdoc *mdoc)
546 {
547 int i;
548 struct mdoc_node *n;
549
550 for (i = 0, n = mdoc->last->child; n; n = n->next, i++)
551 /* Do nothing */ ;
552
553 return(i);
554 }
555
556
557 /*
558 * Build these up with macros because they're basically the same check
559 * for different inequalities. Yes, this could be done with functions,
560 * but this is reasonable for now.
561 */
562
563 #define CHECK_CHILD_DEFN(lvl, name, ineq) \
564 static int \
565 lvl##_child_##name(struct mdoc *mdoc, const char *p, int sz) \
566 { \
567 int i; \
568 if ((i = count_child(mdoc)) ineq sz) \
569 return(1); \
570 return(lvl##_count(mdoc, #ineq, sz, p, i)); \
571 }
572
573 #define CHECK_BODY_DEFN(name, lvl, func, num) \
574 static int \
575 b##lvl##_##name(POST_ARGS) \
576 { \
577 if (MDOC_BODY != mdoc->last->type) \
578 return(1); \
579 return(func(mdoc, "multi-line arguments", (num))); \
580 }
581
582 #define CHECK_ELEM_DEFN(name, lvl, func, num) \
583 static int \
584 e##lvl##_##name(POST_ARGS) \
585 { \
586 assert(MDOC_ELEM == mdoc->last->type); \
587 return(func(mdoc, "line arguments", (num))); \
588 }
589
590 #define CHECK_HEAD_DEFN(name, lvl, func, num) \
591 static int \
592 h##lvl##_##name(POST_ARGS) \
593 { \
594 if (MDOC_HEAD != mdoc->last->type) \
595 return(1); \
596 return(func(mdoc, "line arguments", (num))); \
597 }
598
599
600 CHECK_CHILD_DEFN(warn, gt, >) /* warn_child_gt() */
601 CHECK_CHILD_DEFN(err, gt, >) /* err_child_gt() */
602 CHECK_CHILD_DEFN(warn, eq, ==) /* warn_child_eq() */
603 CHECK_CHILD_DEFN(err, eq, ==) /* err_child_eq() */
604 CHECK_CHILD_DEFN(err, lt, <) /* err_child_lt() */
605 CHECK_CHILD_DEFN(warn, lt, <) /* warn_child_lt() */
606 CHECK_BODY_DEFN(ge1, warn, warn_child_gt, 0) /* bwarn_ge1() */
607 CHECK_ELEM_DEFN(eq1, warn, warn_child_eq, 1) /* ewarn_eq1() */
608 CHECK_ELEM_DEFN(eq0, warn, warn_child_eq, 0) /* ewarn_eq0() */
609 CHECK_ELEM_DEFN(ge1, warn, warn_child_gt, 0) /* ewarn_gt1() */
610 CHECK_ELEM_DEFN(eq1, err, err_child_eq, 1) /* eerr_eq1() */
611 CHECK_ELEM_DEFN(le2, err, err_child_lt, 3) /* eerr_le2() */
612 CHECK_ELEM_DEFN(eq0, err, err_child_eq, 0) /* eerr_eq0() */
613 CHECK_ELEM_DEFN(ge1, err, err_child_gt, 0) /* eerr_ge1() */
614 CHECK_HEAD_DEFN(eq0, err, err_child_eq, 0) /* herr_eq0() */
615 CHECK_HEAD_DEFN(le1, warn, warn_child_lt, 2) /* hwarn_le1() */
616 CHECK_HEAD_DEFN(ge1, err, err_child_gt, 0) /* herr_ge1() */
617 CHECK_HEAD_DEFN(eq1, warn, warn_child_eq, 1) /* hwarn_eq1() */
618
619
620 static int
621 check_stdarg(PRE_ARGS)
622 {
623
624 if (n->args && 1 == n->args->argc)
625 if (MDOC_Std == n->args->argv[0].arg)
626 return(1);
627 return(nwarn(mdoc, n, WARGVAL));
628 }
629
630
631 static int
632 check_sec(PRE_ARGS, ...)
633 {
634 enum mdoc_sec sec;
635 va_list ap;
636
637 va_start(ap, n);
638
639 for (;;) {
640 /* LINTED */
641 sec = (enum mdoc_sec)va_arg(ap, int);
642 if (SEC_CUSTOM == sec)
643 break;
644 if (sec != mdoc->lastsec)
645 continue;
646 va_end(ap);
647 return(1);
648 }
649
650 va_end(ap);
651 return(nwarn(mdoc, n, WBADSEC));
652 }
653
654
655 static int
656 check_msec(PRE_ARGS, ...)
657 {
658 va_list ap;
659 int msec;
660
661 va_start(ap, n);
662 for (;;) {
663 /* LINTED */
664 if (0 == (msec = va_arg(ap, int)))
665 break;
666 if (msec != mdoc->meta.msec)
667 continue;
668 va_end(ap);
669 return(1);
670 }
671
672 va_end(ap);
673 return(nwarn(mdoc, n, WBADMSEC));
674 }
675
676
677 static int
678 check_args(struct mdoc *m, const struct mdoc_node *n)
679 {
680 int i;
681
682 if (NULL == n->args)
683 return(1);
684
685 assert(n->args->argc);
686 for (i = 0; i < (int)n->args->argc; i++)
687 if ( ! check_argv(m, n, &n->args->argv[i]))
688 return(0);
689
690 return(1);
691 }
692
693
694 static int
695 check_argv(struct mdoc *m, const struct mdoc_node *n,
696 const struct mdoc_argv *v)
697 {
698 int i;
699
700 for (i = 0; i < (int)v->sz; i++)
701 if ( ! check_text(m, v->line, v->pos, v->value[i]))
702 return(0);
703
704 if (MDOC_Std == v->arg) {
705 /* `Nm' name must be set. */
706 if (v->sz || m->meta.name)
707 return(1);
708 return(nerr(m, n, ENAME));
709 }
710
711 return(1);
712 }
713
714
715 static int
716 check_text(struct mdoc *mdoc, int line, int pos, const char *p)
717 {
718 size_t c;
719
720 /* FIXME: indicate deprecated escapes \*(xx and \*x. */
721
722 for ( ; *p; p++) {
723 if ('\t' == *p) {
724 if ( ! (MDOC_LITERAL & mdoc->flags))
725 if ( ! warn_print(mdoc, line, pos))
726 return(0);
727 } else if ( ! isprint((u_char)*p))
728 if ( ! warn_print(mdoc, line, pos))
729 return(0);
730
731 if ('\\' != *p)
732 continue;
733
734 c = mdoc_isescape(p);
735 if (c) {
736 p += (int)c - 1;
737 continue;
738 }
739 if ( ! (MDOC_IGN_ESCAPE & mdoc->pflags))
740 return(perr(mdoc, line, pos, EESCAPE));
741 if ( ! pwarn(mdoc, line, pos, WESCAPE))
742 return(0);
743 }
744
745 return(1);
746 }
747
748
749
750
751 static int
752 check_parent(PRE_ARGS, int tok, enum mdoc_type t)
753 {
754
755 assert(n->parent);
756 if ((MDOC_ROOT == t || tok == n->parent->tok) &&
757 (t == n->parent->type))
758 return(1);
759
760 return(mdoc_nerr(mdoc, n, "require parent %s",
761 MDOC_ROOT == t ? "<root>" : mdoc_macronames[tok]));
762 }
763
764
765
766 static int
767 pre_display(PRE_ARGS)
768 {
769 struct mdoc_node *node;
770
771 /* Display elements (`Bd', `D1'...) cannot be nested. */
772
773 if (MDOC_BLOCK != n->type)
774 return(1);
775
776 /* LINTED */
777 for (node = mdoc->last->parent; node; node = node->parent)
778 if (MDOC_BLOCK == node->type)
779 if (MDOC_Bd == node->tok)
780 break;
781 if (NULL == node)
782 return(1);
783
784 return(nerr(mdoc, n, ENESTDISP));
785 }
786
787
788 static int
789 pre_bl(PRE_ARGS)
790 {
791 int pos, col, type, width, offset;
792
793 if (MDOC_BLOCK != n->type)
794 return(1);
795 if (NULL == n->args)
796 return(nerr(mdoc, n, ELISTTYPE));
797
798 /* Make sure that only one type of list is specified. */
799
800 type = offset = width = col = -1;
801
802 /* LINTED */
803 for (pos = 0; pos < (int)n->args->argc; pos++)
804 switch (n->args->argv[pos].arg) {
805 case (MDOC_Bullet):
806 /* FALLTHROUGH */
807 case (MDOC_Dash):
808 /* FALLTHROUGH */
809 case (MDOC_Enum):
810 /* FALLTHROUGH */
811 case (MDOC_Hyphen):
812 /* FALLTHROUGH */
813 case (MDOC_Item):
814 /* FALLTHROUGH */
815 case (MDOC_Tag):
816 /* FALLTHROUGH */
817 case (MDOC_Diag):
818 /* FALLTHROUGH */
819 case (MDOC_Hang):
820 /* FALLTHROUGH */
821 case (MDOC_Ohang):
822 /* FALLTHROUGH */
823 case (MDOC_Inset):
824 /* FALLTHROUGH */
825 case (MDOC_Column):
826 if (-1 != type)
827 return(nerr(mdoc, n, EMULTILIST));
828 type = n->args->argv[pos].arg;
829 col = pos;
830 break;
831 case (MDOC_Width):
832 if (-1 != width)
833 return(nerr(mdoc, n, EARGREP));
834 width = n->args->argv[pos].arg;
835 break;
836 case (MDOC_Offset):
837 if (-1 != offset)
838 return(nerr(mdoc, n, EARGREP));
839 offset = n->args->argv[pos].arg;
840 break;
841 default:
842 break;
843 }
844
845 if (-1 == type)
846 return(nerr(mdoc, n, ELISTTYPE));
847
848 /*
849 * Validate the width field. Some list types don't need width
850 * types and should be warned about them. Others should have it
851 * and must also be warned.
852 */
853
854 switch (type) {
855 case (MDOC_Tag):
856 if (-1 == width && ! nwarn(mdoc, n, WMISSWIDTH))
857 return(0);
858 break;
859 case (MDOC_Column):
860 /* FALLTHROUGH */
861 case (MDOC_Diag):
862 /* FALLTHROUGH */
863 case (MDOC_Inset):
864 /* FALLTHROUGH */
865 case (MDOC_Item):
866 if (-1 != width && ! nwarn(mdoc, n, WNOWIDTH))
867 return(0);
868 break;
869 default:
870 break;
871 }
872
873 /*
874 * General validation of fields.
875 */
876
877 switch (type) {
878 case (MDOC_Column):
879 assert(col >= 0);
880 if (0 == n->args->argv[col].sz)
881 break;
882 if ( ! nwarn(mdoc, n, WDEPCOL))
883 return(0);
884 break;
885 default:
886 break;
887 }
888
889 return(1);
890 }
891
892
893 static int
894 pre_bd(PRE_ARGS)
895 {
896 int i, type, err;
897
898 if (MDOC_BLOCK != n->type)
899 return(1);
900 if (NULL == n->args)
901 return(nerr(mdoc, n, EDISPTYPE));
902
903 /* Make sure that only one type of display is specified. */
904
905 /* LINTED */
906 for (i = 0, err = type = 0; ! err &&
907 i < (int)n->args->argc; i++)
908 switch (n->args->argv[i].arg) {
909 case (MDOC_Ragged):
910 /* FALLTHROUGH */
911 case (MDOC_Unfilled):
912 /* FALLTHROUGH */
913 case (MDOC_Filled):
914 /* FALLTHROUGH */
915 case (MDOC_Literal):
916 /* FALLTHROUGH */
917 case (MDOC_File):
918 if (0 == type++)
919 break;
920 return(nerr(mdoc, n, EMULTIDISP));
921 default:
922 break;
923 }
924
925 if (type)
926 return(1);
927 return(nerr(mdoc, n, EDISPTYPE));
928 }
929
930
931 static int
932 pre_ss(PRE_ARGS)
933 {
934
935 if (MDOC_BLOCK != n->type)
936 return(1);
937 return(check_parent(mdoc, n, MDOC_Sh, MDOC_BODY));
938 }
939
940
941 static int
942 pre_sh(PRE_ARGS)
943 {
944
945 if (MDOC_BLOCK != n->type)
946 return(1);
947 return(check_parent(mdoc, n, -1, MDOC_ROOT));
948 }
949
950
951 static int
952 pre_it(PRE_ARGS)
953 {
954
955 if (MDOC_BLOCK != n->type)
956 return(1);
957 return(check_parent(mdoc, n, MDOC_Bl, MDOC_BODY));
958 }
959
960
961 static int
962 pre_an(PRE_ARGS)
963 {
964
965 if (NULL == n->args || 1 == n->args->argc)
966 return(1);
967 return(mdoc_nerr(mdoc, n, "only one argument allowed"));
968 }
969
970
971 static int
972 pre_lb(PRE_ARGS)
973 {
974
975 return(check_sec(mdoc, n, SEC_LIBRARY, SEC_CUSTOM));
976 }
977
978
979 static int
980 pre_rv(PRE_ARGS)
981 {
982
983 if ( ! check_msec(mdoc, n, 2, 3, 0))
984 return(0);
985 return(check_stdarg(mdoc, n));
986 }
987
988
989 static int
990 pre_ex(PRE_ARGS)
991 {
992
993 if ( ! check_msec(mdoc, n, 1, 6, 8, 0))
994 return(0);
995 return(check_stdarg(mdoc, n));
996 }
997
998
999 static int
1000 pre_er(PRE_ARGS)
1001 {
1002
1003 return(check_msec(mdoc, n, 2, 3, 9, 0));
1004 }
1005
1006
1007 static int
1008 pre_cd(PRE_ARGS)
1009 {
1010
1011 return(check_msec(mdoc, n, 4, 0));
1012 }
1013
1014
1015 static int
1016 pre_prologue(PRE_ARGS)
1017 {
1018
1019 return(check_sec(mdoc, n, SEC_PROLOGUE, SEC_CUSTOM));
1020 }
1021
1022
1023 static int
1024 pre_dt(PRE_ARGS)
1025 {
1026
1027 if (0 == mdoc->meta.date || mdoc->meta.os)
1028 if ( ! nwarn(mdoc, n, WPROLOOO))
1029 return(0);
1030 if (mdoc->meta.title)
1031 if ( ! nwarn(mdoc, n, WPROLREP))
1032 return(0);
1033 return(1);
1034 }
1035
1036
1037 static int
1038 pre_os(PRE_ARGS)
1039 {
1040
1041 if (NULL == mdoc->meta.title || 0 == mdoc->meta.date)
1042 if ( ! nwarn(mdoc, n, WPROLOOO))
1043 return(0);
1044 if (mdoc->meta.os)
1045 if ( ! nwarn(mdoc, n, WPROLREP))
1046 return(0);
1047 return(1);
1048 }
1049
1050
1051 static int
1052 pre_dd(PRE_ARGS)
1053 {
1054
1055 if (mdoc->meta.title || mdoc->meta.os)
1056 if ( ! nwarn(mdoc, n, WPROLOOO))
1057 return(0);
1058 if (mdoc->meta.date)
1059 if ( ! nwarn(mdoc, n, WPROLREP))
1060 return(0);
1061 return(1);
1062 }
1063
1064
1065 static int
1066 post_bf(POST_ARGS)
1067 {
1068 char *p;
1069 struct mdoc_node *head;
1070
1071 if (MDOC_BLOCK != mdoc->last->type)
1072 return(1);
1073
1074 head = mdoc->last->head;
1075
1076 if (NULL == mdoc->last->args) {
1077 if (NULL == head->child ||
1078 MDOC_TEXT != head->child->type)
1079 return(mdoc_err(mdoc, "text argument expected"));
1080
1081 p = head->child->string;
1082 if (0 == strcmp(p, "Em"))
1083 return(1);
1084 else if (0 == strcmp(p, "Li"))
1085 return(1);
1086 else if (0 == strcmp(p, "Sm"))
1087 return(1);
1088 return(mdoc_nerr(mdoc, head->child, "invalid font"));
1089 }
1090
1091 if (head->child)
1092 return(mdoc_err(mdoc, "one argument expected"));
1093
1094 return(1);
1095 }
1096
1097
1098 static int
1099 post_nm(POST_ARGS)
1100 {
1101
1102 if (mdoc->last->child)
1103 return(1);
1104 if (mdoc->meta.name)
1105 return(1);
1106 return(verr(mdoc, ENAME));
1107 }
1108
1109
1110 static int
1111 post_at(POST_ARGS)
1112 {
1113
1114 if (NULL == mdoc->last->child)
1115 return(1);
1116 if (MDOC_TEXT != mdoc->last->child->type)
1117 return(verr(mdoc, EATT));
1118 if (mdoc_a2att(mdoc->last->child->string))
1119 return(1);
1120 return(verr(mdoc, EATT));
1121 }
1122
1123
1124 static int
1125 post_an(POST_ARGS)
1126 {
1127
1128 if (mdoc->last->args) {
1129 if (NULL == mdoc->last->child)
1130 return(1);
1131 return(verr(mdoc, ELINE));
1132 }
1133
1134 if (mdoc->last->child)
1135 return(1);
1136 return(verr(mdoc, ELINE));
1137 }
1138
1139
1140 static int
1141 post_args(POST_ARGS)
1142 {
1143
1144 if (mdoc->last->args)
1145 return(1);
1146 return(verr(mdoc, ELINE));
1147 }
1148
1149
1150 static int
1151 post_it(POST_ARGS)
1152 {
1153 int type, i, cols;
1154 struct mdoc_node *n, *c;
1155
1156 if (MDOC_BLOCK != mdoc->last->type)
1157 return(1);
1158
1159 n = mdoc->last->parent->parent;
1160 if (NULL == n->args)
1161 return(verr(mdoc, ELISTTYPE));
1162
1163 /* Some types require block-head, some not. */
1164
1165 /* LINTED */
1166 for (cols = type = -1, i = 0; -1 == type &&
1167 i < (int)n->args->argc; i++)
1168 switch (n->args->argv[i].arg) {
1169 case (MDOC_Tag):
1170 /* FALLTHROUGH */
1171 case (MDOC_Diag):
1172 /* FALLTHROUGH */
1173 case (MDOC_Hang):
1174 /* FALLTHROUGH */
1175 case (MDOC_Ohang):
1176 /* FALLTHROUGH */
1177 case (MDOC_Inset):
1178 /* FALLTHROUGH */
1179 case (MDOC_Bullet):
1180 /* FALLTHROUGH */
1181 case (MDOC_Dash):
1182 /* FALLTHROUGH */
1183 case (MDOC_Enum):
1184 /* FALLTHROUGH */
1185 case (MDOC_Hyphen):
1186 /* FALLTHROUGH */
1187 case (MDOC_Item):
1188 type = n->args->argv[i].arg;
1189 break;
1190 case (MDOC_Column):
1191 type = n->args->argv[i].arg;
1192 cols = (int)n->args->argv[i].sz;
1193 break;
1194 default:
1195 break;
1196 }
1197
1198 if (-1 == type)
1199 return(verr(mdoc, ELISTTYPE));
1200
1201 switch (type) {
1202 case (MDOC_Tag):
1203 if (NULL == mdoc->last->head->child)
1204 if ( ! vwarn(mdoc, WLINE))
1205 return(0);
1206 break;
1207 case (MDOC_Hang):
1208 /* FALLTHROUGH */
1209 case (MDOC_Ohang):
1210 /* FALLTHROUGH */
1211 case (MDOC_Inset):
1212 /* FALLTHROUGH */
1213 case (MDOC_Diag):
1214 if (NULL == mdoc->last->head->child)
1215 if ( ! vwarn(mdoc, WLINE))
1216 return(0);
1217 if (NULL == mdoc->last->body->child)
1218 if ( ! vwarn(mdoc, WMULTILINE))
1219 return(0);
1220 break;
1221 case (MDOC_Bullet):
1222 /* FALLTHROUGH */
1223 case (MDOC_Dash):
1224 /* FALLTHROUGH */
1225 case (MDOC_Enum):
1226 /* FALLTHROUGH */
1227 case (MDOC_Hyphen):
1228 /* FALLTHROUGH */
1229 case (MDOC_Item):
1230 if (mdoc->last->head->child)
1231 if ( ! vwarn(mdoc, WNOLINE))
1232 return(0);
1233 if (NULL == mdoc->last->body->child)
1234 if ( ! vwarn(mdoc, WMULTILINE))
1235 return(0);
1236 break;
1237 case (MDOC_Column):
1238 if (NULL == mdoc->last->head->child)
1239 if ( ! vwarn(mdoc, WLINE))
1240 return(0);
1241 if (mdoc->last->body->child)
1242 if ( ! vwarn(mdoc, WNOMULTILINE))
1243 return(0);
1244 c = mdoc->last->child;
1245 for (i = 0; c && MDOC_HEAD == c->type; c = c->next)
1246 i++;
1247 if (i == cols)
1248 break;
1249 return(mdoc_err(mdoc, "column mismatch (have "
1250 "%d, want %d)", i, cols));
1251 default:
1252 break;
1253 }
1254
1255 return(1);
1256 }
1257
1258
1259 static int
1260 post_bl(POST_ARGS)
1261 {
1262 struct mdoc_node *n;
1263
1264 if (MDOC_BODY != mdoc->last->type)
1265 return(1);
1266 if (NULL == mdoc->last->child)
1267 return(1);
1268
1269 /* LINTED */
1270 for (n = mdoc->last->child; n; n = n->next) {
1271 if (MDOC_BLOCK == n->type)
1272 if (MDOC_It == n->tok)
1273 continue;
1274 return(mdoc_nerr(mdoc, n, "bad child of parent %s",
1275 mdoc_macronames[mdoc->last->tok]));
1276 }
1277
1278 return(1);
1279 }
1280
1281
1282 static int
1283 ebool(struct mdoc *mdoc)
1284 {
1285 struct mdoc_node *n;
1286
1287 /* LINTED */
1288 for (n = mdoc->last->child; n; n = n->next) {
1289 if (MDOC_TEXT != n->type)
1290 break;
1291 if (0 == strcmp(n->string, "on"))
1292 continue;
1293 if (0 == strcmp(n->string, "off"))
1294 continue;
1295 break;
1296 }
1297
1298 if (NULL == n)
1299 return(1);
1300 return(nerr(mdoc, n, EBOOL));
1301 }
1302
1303
1304 static int
1305 post_root(POST_ARGS)
1306 {
1307
1308 if (NULL == mdoc->first->child)
1309 return(verr(mdoc, ENODATA));
1310 if (SEC_PROLOGUE == mdoc->lastnamed)
1311 return(verr(mdoc, ENOPROLOGUE));
1312
1313 if (MDOC_BLOCK != mdoc->first->child->type)
1314 return(verr(mdoc, ENODATA));
1315 if (MDOC_Sh != mdoc->first->child->tok)
1316 return(verr(mdoc, ENODATA));
1317
1318 return(1);
1319 }
1320
1321
1322 static int
1323 post_st(POST_ARGS)
1324 {
1325
1326 if (mdoc_a2st(mdoc->last->child->string))
1327 return(1);
1328 return(vwarn(mdoc, WBADSTAND));
1329 }
1330
1331
1332 static int
1333 post_sh(POST_ARGS)
1334 {
1335
1336 if (MDOC_HEAD == mdoc->last->type)
1337 return(post_sh_head(mdoc));
1338 if (MDOC_BODY == mdoc->last->type)
1339 return(post_sh_body(mdoc));
1340
1341 return(1);
1342 }
1343
1344
1345 static int
1346 post_sh_body(POST_ARGS)
1347 {
1348 struct mdoc_node *n;
1349
1350 if (SEC_NAME != mdoc->lastnamed)
1351 return(1);
1352
1353 /*
1354 * Warn if the NAME section doesn't contain the `Nm' and `Nd'
1355 * macros (can have multiple `Nm' and one `Nd'). Note that the
1356 * children of the BODY declaration can also be "text".
1357 */
1358
1359 if (NULL == (n = mdoc->last->child))
1360 return(vwarn(mdoc, WNAMESECINC));
1361
1362 for ( ; n && n->next; n = n->next) {
1363 if (MDOC_ELEM == n->type && MDOC_Nm == n->tok)
1364 continue;
1365 if (MDOC_TEXT == n->type)
1366 continue;
1367 if ( ! vwarn(mdoc, WNAMESECINC))
1368 return(0);
1369 }
1370
1371 if (MDOC_ELEM == n->type && MDOC_Nd == n->tok)
1372 return(1);
1373 return(vwarn(mdoc, WNAMESECINC));
1374 }
1375
1376
1377 static int
1378 post_sh_head(POST_ARGS)
1379 {
1380 char buf[64];
1381 enum mdoc_sec sec;
1382 const struct mdoc_node *n;
1383
1384 /*
1385 * Process a new section. Sections are either "named" or
1386 * "custom"; custom sections are user-defined, while named ones
1387 * usually follow a conventional order and may only appear in
1388 * certain manual sections.
1389 */
1390
1391 assert(MDOC_Sh == mdoc->last->tok);
1392
1393 /* This is just concat() inlined, which is irritating. */
1394
1395 buf[0] = 0;
1396 for (n = mdoc->last->child; n; n = n->next) {
1397 assert(MDOC_TEXT == n->type);
1398 if (strlcat(buf, n->string, 64) >= 64)
1399 return(nerr(mdoc, n, ETOOLONG));
1400 if (NULL == n->next)
1401 continue;
1402 if (strlcat(buf, " ", 64) >= 64)
1403 return(nerr(mdoc, n, ETOOLONG));
1404 }
1405
1406 sec = mdoc_atosec(buf);
1407
1408 /* The NAME section should always be first. */
1409
1410 if (SEC_BODY == mdoc->lastnamed && SEC_NAME != sec)
1411 return(vwarn(mdoc, WSECOOO));
1412 if (SEC_CUSTOM == sec)
1413 return(1);
1414
1415 /* Check for repeated or out-of-order sections. */
1416
1417 if (sec == mdoc->lastnamed)
1418 return(vwarn(mdoc, WSECREP));
1419 if (sec < mdoc->lastnamed)
1420 return(vwarn(mdoc, WSECOOO));
1421
1422 /* Check particular section/manual section conventions. */
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 }