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