]>
git.cameronkatri.com Git - mandoc.git/blob - validate.c
1 /* $Id: validate.c,v 1.51 2009/02/22 14:31:08 kristaps Exp $ */
3 * Copyright (c) 2008 Kristaps Dzonsons <kristaps@kth.se>
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the
7 * above copyright notice and this permission notice appear in all
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
25 * Pre- and post-validate macros as they're parsed. Pre-validation
26 * occurs when the macro has been detected and its arguments parsed.
27 * Post-validation occurs when all child macros have also been parsed.
28 * In the ELEMENT case, this is simply the parameters of the macro; in
29 * the BLOCK case, this is the HEAD, BODY, TAIL and so on.
32 typedef int (*v_pre
)(struct mdoc
*, struct mdoc_node
*);
33 typedef int (*v_post
)(struct mdoc
*);
35 /* FIXME: some sections should only occur in specific msecs. */
36 /* FIXME: ignoring Pp. */
37 /* FIXME: .Ef arguments */
38 /* FIXME: math symbols. */
39 /* FIXME: valid character-escape checks. */
40 /* FIXME: .Fd only in synopsis section. */
49 static int check_parent(struct mdoc
*, struct mdoc_node
*,
51 static int check_msec(struct mdoc
*, struct mdoc_node
*,
52 int, enum mdoc_msec
*);
53 static int check_stdarg(struct mdoc
*, struct mdoc_node
*);
54 static int err_child_lt(struct mdoc
*, const char *, int);
55 static int err_child_gt(struct mdoc
*, const char *, int);
56 static int warn_child_gt(struct mdoc
*, const char *, int);
57 static int err_child_eq(struct mdoc
*, const char *, int);
58 static int warn_child_eq(struct mdoc
*, const char *, int);
60 /* Utility auxiliaries. */
62 static inline int count_child(struct mdoc
*);
63 static inline int warn_count(struct mdoc
*, const char *,
64 int, const char *, int);
65 static inline int err_count(struct mdoc
*, const char *,
66 int, const char *, int);
68 /* Specific pre-child-parse routines. */
70 static int pre_display(struct mdoc
*, struct mdoc_node
*);
71 static int pre_sh(struct mdoc
*, struct mdoc_node
*);
72 static int pre_ss(struct mdoc
*, struct mdoc_node
*);
73 static int pre_bd(struct mdoc
*, struct mdoc_node
*);
74 static int pre_bl(struct mdoc
*, struct mdoc_node
*);
75 static int pre_it(struct mdoc
*, struct mdoc_node
*);
76 static int pre_cd(struct mdoc
*, struct mdoc_node
*);
77 static int pre_er(struct mdoc
*, struct mdoc_node
*);
78 static int pre_ex(struct mdoc
*, struct mdoc_node
*);
79 static int pre_rv(struct mdoc
*, struct mdoc_node
*);
80 static int pre_an(struct mdoc
*, struct mdoc_node
*);
81 static int pre_st(struct mdoc
*, struct mdoc_node
*);
82 static int pre_prologue(struct mdoc
*, struct mdoc_node
*);
83 static int pre_prologue(struct mdoc
*, struct mdoc_node
*);
84 static int pre_prologue(struct mdoc
*, struct mdoc_node
*);
86 /* Specific post-child-parse routines. */
88 static int herr_ge1(struct mdoc
*);
89 static int herr_le1(struct mdoc
*);
90 static int herr_eq0(struct mdoc
*);
91 static int eerr_eq0(struct mdoc
*);
92 static int eerr_le1(struct mdoc
*);
93 static int eerr_le2(struct mdoc
*);
94 static int eerr_eq1(struct mdoc
*);
95 static int eerr_ge1(struct mdoc
*);
96 static int ewarn_eq0(struct mdoc
*);
97 static int ewarn_eq1(struct mdoc
*);
98 static int bwarn_ge1(struct mdoc
*);
99 static int ewarn_ge1(struct mdoc
*);
100 static int ebool(struct mdoc
*);
101 static int post_sh(struct mdoc
*);
102 static int post_sh_body(struct mdoc
*);
103 static int post_sh_head(struct mdoc
*);
104 static int post_bl(struct mdoc
*);
105 static int post_it(struct mdoc
*);
106 static int post_ex(struct mdoc
*);
107 static int post_an(struct mdoc
*);
108 static int post_at(struct mdoc
*);
109 static int post_xr(struct mdoc
*);
110 static int post_nm(struct mdoc
*);
111 static int post_bf(struct mdoc
*);
112 static int post_root(struct mdoc
*);
114 /* Collections of pre-child-parse routines. */
116 static v_pre pres_prologue
[] = { pre_prologue
, NULL
};
117 static v_pre pres_d1
[] = { pre_display
, NULL
};
118 static v_pre pres_bd
[] = { pre_display
, pre_bd
, NULL
};
119 static v_pre pres_bl
[] = { pre_bl
, NULL
};
120 static v_pre pres_it
[] = { pre_it
, NULL
};
121 static v_pre pres_ss
[] = { pre_ss
, NULL
};
122 static v_pre pres_sh
[] = { pre_sh
, NULL
};
123 static v_pre pres_cd
[] = { pre_cd
, NULL
};
124 static v_pre pres_er
[] = { pre_er
, NULL
};
125 static v_pre pres_ex
[] = { pre_ex
, NULL
};
126 static v_pre pres_rv
[] = { pre_rv
, NULL
};
127 static v_pre pres_an
[] = { pre_an
, NULL
};
128 static v_pre pres_st
[] = { pre_st
, NULL
};
130 /* Collections of post-child-parse routines. */
132 static v_post posts_bool
[] = { eerr_eq1
, ebool
, NULL
};
133 static v_post posts_bd
[] = { herr_eq0
, bwarn_ge1
, NULL
};
134 static v_post posts_text
[] = { eerr_ge1
, NULL
};
135 static v_post posts_wtext
[] = { ewarn_ge1
, NULL
};
136 static v_post posts_notext
[] = { eerr_eq0
, NULL
};
137 static v_post posts_wline
[] = { bwarn_ge1
, herr_eq0
, NULL
};
138 static v_post posts_sh
[] = { herr_ge1
, bwarn_ge1
, post_sh
, NULL
};
139 static v_post posts_bl
[] = { herr_eq0
, bwarn_ge1
, post_bl
, NULL
};
140 static v_post posts_it
[] = { post_it
, NULL
};
141 static v_post posts_in
[] = { ewarn_eq1
, NULL
};
142 static v_post posts_ss
[] = { herr_ge1
, NULL
};
143 static v_post posts_pp
[] = { ewarn_eq0
, NULL
};
144 static v_post posts_ex
[] = { eerr_le1
, post_ex
, NULL
};
145 static v_post posts_an
[] = { post_an
, NULL
};
146 static v_post posts_at
[] = { post_at
, NULL
};
147 static v_post posts_xr
[] = { eerr_ge1
, eerr_le2
, post_xr
, NULL
};
148 static v_post posts_nm
[] = { post_nm
, NULL
};
149 static v_post posts_bf
[] = { herr_le1
, post_bf
, NULL
};
150 static v_post posts_rs
[] = { herr_eq0
, bwarn_ge1
, NULL
};
151 static v_post posts_fo
[] = { bwarn_ge1
, NULL
};
152 static v_post posts_bk
[] = { herr_eq0
, bwarn_ge1
, NULL
};
154 /* Per-macro pre- and post-child-check routine collections. */
156 const struct valids mdoc_valids
[MDOC_MAX
] = {
157 { NULL
, NULL
}, /* \" */
158 { pres_prologue
, posts_text
}, /* Dd */
159 { pres_prologue
, NULL
}, /* Dt */
160 { pres_prologue
, NULL
}, /* Os */
161 { pres_sh
, posts_sh
}, /* Sh */
162 { pres_ss
, posts_ss
}, /* Ss */
163 { NULL
, posts_pp
}, /* Pp */
164 { pres_d1
, posts_wline
}, /* D1 */
165 { pres_d1
, posts_wline
}, /* Dl */
166 { pres_bd
, posts_bd
}, /* Bd */
167 { NULL
, NULL
}, /* Ed */
168 { pres_bl
, posts_bl
}, /* Bl */
169 { NULL
, NULL
}, /* El */
170 { pres_it
, posts_it
}, /* It */
171 { NULL
, posts_text
}, /* Ad */
172 { pres_an
, posts_an
}, /* An */
173 { NULL
, NULL
}, /* Ar */
174 { pres_cd
, posts_text
}, /* Cd */
175 { NULL
, NULL
}, /* Cm */
176 { NULL
, posts_text
}, /* Dv */
177 { pres_er
, posts_text
}, /* Er */
178 { NULL
, posts_text
}, /* Ev */
179 { pres_ex
, posts_ex
}, /* Ex */
180 { NULL
, posts_text
}, /* Fa */
181 { NULL
, posts_wtext
}, /* Fd */
182 { NULL
, NULL
}, /* Fl */
183 { NULL
, posts_text
}, /* Fn */
184 { NULL
, posts_wtext
}, /* Ft */
185 { NULL
, posts_text
}, /* Ic */
186 { NULL
, posts_in
}, /* In */
187 { NULL
, posts_text
}, /* Li */
188 { NULL
, posts_wtext
}, /* Nd */
189 { NULL
, posts_nm
}, /* Nm */
190 { NULL
, posts_wline
}, /* Op */
191 { NULL
, NULL
}, /* Ot */
192 { NULL
, NULL
}, /* Pa */
193 { pres_rv
, posts_notext
}, /* Rv */
194 { pres_st
, posts_notext
}, /* St */
195 { NULL
, posts_text
}, /* Va */
196 { NULL
, posts_text
}, /* Vt */
197 { NULL
, posts_xr
}, /* Xr */
198 { NULL
, posts_text
}, /* %A */
199 { NULL
, posts_text
}, /* %B */
200 { NULL
, posts_text
}, /* %D */
201 { NULL
, posts_text
}, /* %I */
202 { NULL
, posts_text
}, /* %J */
203 { NULL
, posts_text
}, /* %N */
204 { NULL
, posts_text
}, /* %O */
205 { NULL
, posts_text
}, /* %P */
206 { NULL
, posts_text
}, /* %R */
207 { NULL
, posts_text
}, /* %T */
208 { NULL
, posts_text
}, /* %V */
209 { NULL
, NULL
}, /* Ac */
210 { NULL
, NULL
}, /* Ao */
211 { NULL
, posts_wline
}, /* Aq */
212 { NULL
, posts_at
}, /* At */
213 { NULL
, NULL
}, /* Bc */
214 { NULL
, posts_bf
}, /* Bf */
215 { NULL
, NULL
}, /* Bo */
216 { NULL
, posts_wline
}, /* Bq */
217 { NULL
, NULL
}, /* Bsx */
218 { NULL
, NULL
}, /* Bx */
219 { NULL
, posts_bool
}, /* Db */
220 { NULL
, NULL
}, /* Dc */
221 { NULL
, NULL
}, /* Do */
222 { NULL
, posts_wline
}, /* Dq */
223 { NULL
, NULL
}, /* Ec */
224 { NULL
, NULL
}, /* Ef */
225 { NULL
, posts_text
}, /* Em */
226 { NULL
, NULL
}, /* Eo */
227 { NULL
, NULL
}, /* Fx */
228 { NULL
, posts_text
}, /* Ms */
229 { NULL
, posts_notext
}, /* No */
230 { NULL
, posts_notext
}, /* Ns */
231 { NULL
, NULL
}, /* Nx */
232 { NULL
, NULL
}, /* Ox */
233 { NULL
, NULL
}, /* Pc */
234 { NULL
, NULL
}, /* Pf */
235 { NULL
, NULL
}, /* Po */
236 { NULL
, posts_wline
}, /* Pq */
237 { NULL
, NULL
}, /* Qc */
238 { NULL
, posts_wline
}, /* Ql */
239 { NULL
, NULL
}, /* Qo */
240 { NULL
, posts_wline
}, /* Qq */
241 { NULL
, NULL
}, /* Re */
242 { NULL
, posts_rs
}, /* Rs */
243 { NULL
, NULL
}, /* Sc */
244 { NULL
, NULL
}, /* So */
245 { NULL
, posts_wline
}, /* Sq */
246 { NULL
, posts_bool
}, /* Sm */
247 { NULL
, posts_text
}, /* Sx */
248 { NULL
, posts_text
}, /* Sy */
249 { NULL
, posts_text
}, /* Tn */
250 { NULL
, NULL
}, /* Ux */
251 { NULL
, NULL
}, /* Xc */
252 { NULL
, NULL
}, /* Xo */
253 { NULL
, posts_fo
}, /* Fo */
254 { NULL
, NULL
}, /* Fc */
255 { NULL
, NULL
}, /* Oo */
256 { NULL
, NULL
}, /* Oc */
257 { NULL
, posts_bk
}, /* Bk */
258 { NULL
, NULL
}, /* Ek */
259 { NULL
, posts_notext
}, /* Bt */
260 { NULL
, NULL
}, /* Hf */
261 { NULL
, NULL
}, /* Fr */
262 { NULL
, posts_notext
}, /* Ud */
267 warn_count(struct mdoc
*m
, const char *k
,
268 int want
, const char *v
, int has
)
271 return(mdoc_warn(m
, WARN_SYNTAX
, "suggests %s %d %s "
272 "(has %d)", v
, want
, k
, has
));
277 err_count(struct mdoc
*m
, const char *k
,
278 int want
, const char *v
, int has
)
281 return(mdoc_err(m
, "requires %s %d %s (has %d)",
287 count_child(struct mdoc
*mdoc
)
292 for (i
= 0, n
= mdoc
->last
->child
; n
; n
= n
->next
, i
++)
299 warn_child_gt(struct mdoc
*mdoc
, const char *p
, int sz
)
303 if ((i
= count_child(mdoc
)) > sz
)
305 return(warn_count(mdoc
, ">", sz
, p
, i
));
310 err_child_gt(struct mdoc
*mdoc
, const char *p
, int sz
)
314 if ((i
= count_child(mdoc
)) > sz
)
316 return(err_count(mdoc
, ">", sz
, p
, i
));
321 warn_child_eq(struct mdoc
*mdoc
, const char *p
, int sz
)
325 if ((i
= count_child(mdoc
)) == sz
)
327 return(warn_count(mdoc
, "==", sz
, p
, i
));
332 err_child_eq(struct mdoc
*mdoc
, const char *p
, int sz
)
336 if ((i
= count_child(mdoc
)) == sz
)
338 return(err_count(mdoc
, "==", sz
, p
, i
));
343 err_child_lt(struct mdoc
*mdoc
, const char *p
, int sz
)
347 if ((i
= count_child(mdoc
)) < sz
)
349 return(err_count(mdoc
, "<", sz
, p
, i
));
354 check_stdarg(struct mdoc
*mdoc
, struct mdoc_node
*node
)
357 if (MDOC_Std
== node
->data
.elem
.argv
[0].arg
&&
358 1 == node
->data
.elem
.argc
)
361 return(mdoc_nwarn(mdoc
, node
, WARN_COMPAT
,
362 "macro suggests single `%s' argument",
363 mdoc_argnames
[MDOC_Std
]));
368 check_msec(struct mdoc
*mdoc
, struct mdoc_node
*node
,
369 int sz
, enum mdoc_msec
*msecs
)
373 for (i
= 0; i
< sz
; i
++)
374 if (msecs
[i
] == mdoc
->meta
.msec
)
376 return(mdoc_nwarn(mdoc
, node
, WARN_COMPAT
, "macro not "
377 "appropriate for manual section"));
382 check_parent(struct mdoc
*mdoc
, struct mdoc_node
*n
,
383 int tok
, enum mdoc_type t
)
387 if ((MDOC_ROOT
== t
|| tok
== n
->parent
->tok
) &&
388 (t
== n
->parent
->type
))
391 return(mdoc_nerr(mdoc
, n
, "require parent %s (have %s)",
392 MDOC_ROOT
== t
? "<root>" :
393 mdoc_macronames
[tok
],
394 MDOC_ROOT
== n
->parent
->type
? "<root>" :
395 mdoc_macronames
[n
->parent
->type
]));
400 bwarn_ge1(struct mdoc
*mdoc
)
403 if (MDOC_BODY
!= mdoc
->last
->type
)
405 return(warn_child_gt(mdoc
, "multi-line parameters", 0));
410 ewarn_eq1(struct mdoc
*mdoc
)
413 assert(MDOC_ELEM
== mdoc
->last
->type
);
414 return(warn_child_eq(mdoc
, "line parameters", 1));
419 ewarn_eq0(struct mdoc
*mdoc
)
422 assert(MDOC_ELEM
== mdoc
->last
->type
);
423 return(warn_child_eq(mdoc
, "line parameters", 0));
428 ewarn_ge1(struct mdoc
*mdoc
)
431 assert(MDOC_ELEM
== mdoc
->last
->type
);
432 return(warn_child_gt(mdoc
, "line parameters", 0));
437 eerr_eq1(struct mdoc
*mdoc
)
440 assert(MDOC_ELEM
== mdoc
->last
->type
);
441 return(err_child_eq(mdoc
, "line parameters", 1));
446 eerr_le2(struct mdoc
*mdoc
)
449 assert(MDOC_ELEM
== mdoc
->last
->type
);
450 return(err_child_lt(mdoc
, "line parameters", 3));
455 eerr_le1(struct mdoc
*mdoc
)
458 assert(MDOC_ELEM
== mdoc
->last
->type
);
459 return(err_child_lt(mdoc
, "line parameters", 2));
464 eerr_eq0(struct mdoc
*mdoc
)
467 assert(MDOC_ELEM
== mdoc
->last
->type
);
468 return(err_child_eq(mdoc
, "line parameters", 0));
473 eerr_ge1(struct mdoc
*mdoc
)
476 assert(MDOC_ELEM
== mdoc
->last
->type
);
477 return(err_child_gt(mdoc
, "line parameters", 0));
482 herr_eq0(struct mdoc
*mdoc
)
485 if (MDOC_HEAD
!= mdoc
->last
->type
)
487 return(err_child_eq(mdoc
, "line parameters", 0));
492 herr_le1(struct mdoc
*mdoc
)
494 if (MDOC_HEAD
!= mdoc
->last
->type
)
496 return(err_child_lt(mdoc
, "line parameters", 2));
501 herr_ge1(struct mdoc
*mdoc
)
504 if (MDOC_HEAD
!= mdoc
->last
->type
)
506 return(err_child_gt(mdoc
, "line parameters", 0));
511 pre_display(struct mdoc
*mdoc
, struct mdoc_node
*node
)
515 if (MDOC_BLOCK
!= node
->type
)
520 for (n
= mdoc
->last
->parent
; n
; n
= n
->parent
)
521 if (MDOC_BLOCK
== n
->type
)
522 if (MDOC_Bd
== n
->tok
)
526 return(mdoc_nerr(mdoc
, node
, "displays may not be nested"));
531 pre_bl(struct mdoc
*mdoc
, struct mdoc_node
*node
)
534 struct mdoc_arg
*argv
;
537 if (MDOC_BLOCK
!= node
->type
)
539 assert(MDOC_Bl
== node
->tok
);
542 argc
= node
->data
.block
.argc
;
545 for (i
= type
= err
= 0; i
< argc
; i
++) {
546 argv
= &node
->data
.block
.argv
[(int)i
];
579 return(mdoc_err(mdoc
, "no list type specified"));
583 return(mdoc_perr(mdoc
, argv
->line
,
584 argv
->pos
, "only one list type possible"));
589 pre_bd(struct mdoc
*mdoc
, struct mdoc_node
*node
)
592 struct mdoc_arg
*argv
;
595 if (MDOC_BLOCK
!= node
->type
)
597 assert(MDOC_Bd
== node
->tok
);
600 argc
= node
->data
.block
.argc
;
603 for (err
= i
= type
= 0; 0 == err
&& i
< argc
; i
++) {
604 argv
= &node
->data
.block
.argv
[(int)i
];
609 case (MDOC_Unfilled
):
625 return(mdoc_err(mdoc
, "no display type specified"));
629 return(mdoc_perr(mdoc
, argv
->line
,
630 argv
->pos
, "only one display type possible"));
635 pre_ss(struct mdoc
*mdoc
, struct mdoc_node
*node
)
638 if (MDOC_BLOCK
!= node
->type
)
640 return(check_parent(mdoc
, node
, MDOC_Sh
, MDOC_BODY
));
645 pre_sh(struct mdoc
*mdoc
, struct mdoc_node
*node
)
648 if (MDOC_BLOCK
!= node
->type
)
650 return(check_parent(mdoc
, node
, -1, MDOC_ROOT
));
655 pre_st(struct mdoc
*mdoc
, struct mdoc_node
*node
)
658 assert(MDOC_ELEM
== node
->type
);
659 assert(MDOC_St
== node
->tok
);
660 if (1 == node
->data
.elem
.argc
)
662 return(mdoc_nerr(mdoc
, node
, "macro must have one argument"));
667 pre_an(struct mdoc
*mdoc
, struct mdoc_node
*node
)
670 assert(MDOC_ELEM
== node
->type
);
671 assert(MDOC_An
== node
->tok
);
672 if (1 >= node
->data
.elem
.argc
)
674 return(mdoc_nerr(mdoc
, node
, "macro may only have one argument"));
679 pre_rv(struct mdoc
*mdoc
, struct mdoc_node
*node
)
681 enum mdoc_msec msecs
[2];
683 assert(MDOC_ELEM
== node
->type
);
684 assert(MDOC_Rv
== node
->tok
);
688 if ( ! check_msec(mdoc
, node
, 2, msecs
))
690 return(check_stdarg(mdoc
, node
));
695 pre_ex(struct mdoc
*mdoc
, struct mdoc_node
*node
)
697 enum mdoc_msec msecs
[3];
699 assert(MDOC_ELEM
== node
->type
);
700 assert(MDOC_Ex
== node
->tok
);
705 if ( ! check_msec(mdoc
, node
, 3, msecs
))
707 return(check_stdarg(mdoc
, node
));
712 pre_er(struct mdoc
*mdoc
, struct mdoc_node
*node
)
714 enum mdoc_msec msecs
[1];
717 return(check_msec(mdoc
, node
, 1, msecs
));
722 pre_cd(struct mdoc
*mdoc
, struct mdoc_node
*node
)
724 enum mdoc_msec msecs
[1];
727 return(check_msec(mdoc
, node
, 1, msecs
));
732 pre_it(struct mdoc
*mdoc
, struct mdoc_node
*node
)
735 /* TODO: -width attribute must be specified for -tag. */
736 /* TODO: children too big for -width? */
738 if (MDOC_BLOCK
!= node
->type
)
740 return(check_parent(mdoc
, node
, MDOC_Bl
, MDOC_BODY
));
745 pre_prologue(struct mdoc
*mdoc
, struct mdoc_node
*node
)
748 if (SEC_PROLOGUE
!= mdoc
->lastnamed
)
749 return(mdoc_nerr(mdoc
, node
, "macro may only be invoked in the prologue"));
750 assert(MDOC_ELEM
== node
->type
);
752 /* Check for ordering. */
756 if (mdoc
->meta
.title
&& mdoc
->meta
.date
)
758 return(mdoc_nerr(mdoc
, node
, "prologue macro out-of-order"));
760 if (NULL
== mdoc
->meta
.title
&& mdoc
->meta
.date
)
762 return(mdoc_nerr(mdoc
, node
, "prologue macro out-of-order"));
764 if (NULL
== mdoc
->meta
.title
&& 0 == mdoc
->meta
.date
)
766 return(mdoc_nerr(mdoc
, node
, "prologue macro out-of-order"));
772 /* Check for repetition. */
776 if (NULL
== mdoc
->meta
.os
)
780 if (0 == mdoc
->meta
.date
)
784 if (NULL
== mdoc
->meta
.title
)
792 return(mdoc_nerr(mdoc
, node
, "prologue macro repeated"));
797 post_bf(struct mdoc
*mdoc
)
800 struct mdoc_node
*head
;
802 if (MDOC_BLOCK
!= mdoc
->last
->type
)
804 assert(MDOC_Bf
== mdoc
->last
->tok
);
805 head
= mdoc
->last
->data
.block
.head
;
808 if (0 == mdoc
->last
->data
.block
.argc
) {
810 assert(MDOC_TEXT
== head
->child
->type
);
811 p
= head
->child
->data
.text
.string
;
812 if (xstrcmp(p
, "Em"))
814 else if (xstrcmp(p
, "Li"))
816 else if (xstrcmp(p
, "Sm"))
818 return(mdoc_nerr(mdoc
, head
->child
, "invalid font mode"));
820 return(mdoc_err(mdoc
, "macro expects an argument or parameter"));
823 return(mdoc_err(mdoc
, "macro expects an argument or parameter"));
824 if (1 == mdoc
->last
->data
.block
.argc
)
826 return(mdoc_err(mdoc
, "macro expects an argument or parameter"));
831 post_nm(struct mdoc
*mdoc
)
834 assert(MDOC_ELEM
== mdoc
->last
->type
);
835 assert(MDOC_Nm
== mdoc
->last
->tok
);
836 if (mdoc
->last
->child
)
840 return(mdoc_err(mdoc
, "macro `%s' has not been invoked with a name",
841 mdoc_macronames
[MDOC_Nm
]));
846 post_xr(struct mdoc
*mdoc
)
850 assert(MDOC_ELEM
== mdoc
->last
->type
);
851 assert(MDOC_Xr
== mdoc
->last
->tok
);
852 assert(mdoc
->last
->child
);
853 assert(MDOC_TEXT
== mdoc
->last
->child
->type
);
855 if (NULL
== (n
= mdoc
->last
->child
->next
))
857 assert(MDOC_TEXT
== n
->type
);
858 if (MSEC_DEFAULT
!= mdoc_atomsec(n
->data
.text
.string
))
860 return(mdoc_nerr(mdoc
, n
, "invalid manual section"));
865 post_at(struct mdoc
*mdoc
)
868 assert(MDOC_ELEM
== mdoc
->last
->type
);
869 assert(MDOC_At
== mdoc
->last
->tok
);
871 if (NULL
== mdoc
->last
->child
)
873 assert(MDOC_TEXT
== mdoc
->last
->child
->type
);
875 if (ATT_DEFAULT
!= mdoc_atoatt(mdoc
->last
->child
->data
.text
.string
))
877 return(mdoc_err(mdoc
, "macro expects a valid AT&T version symbol"));
882 post_an(struct mdoc
*mdoc
)
885 assert(MDOC_ELEM
== mdoc
->last
->type
);
886 assert(MDOC_An
== mdoc
->last
->tok
);
888 if (0 != mdoc
->last
->data
.elem
.argc
) {
889 if (NULL
== mdoc
->last
->child
)
891 return(mdoc_err(mdoc
, "macro expects either argument or parameters"));
894 if (mdoc
->last
->child
)
896 return(mdoc_err(mdoc
, "macro expects either argument or parameters"));
901 post_ex(struct mdoc
*mdoc
)
904 assert(MDOC_ELEM
== mdoc
->last
->type
);
905 assert(MDOC_Ex
== mdoc
->last
->tok
);
907 if (0 == mdoc
->last
->data
.elem
.argc
) {
908 if (mdoc
->last
->child
)
910 return(mdoc_err(mdoc
, "macro expects `%s' or a single child",
911 mdoc_argnames
[MDOC_Std
]));
913 if (mdoc
->last
->child
)
914 return(mdoc_err(mdoc
, "macro expects `%s' or a single child",
915 mdoc_argnames
[MDOC_Std
]));
916 if (1 != mdoc
->last
->data
.elem
.argc
)
917 return(mdoc_err(mdoc
, "macro expects `%s' or a single child",
918 mdoc_argnames
[MDOC_Std
]));
919 if (MDOC_Std
!= mdoc
->last
->data
.elem
.argv
[0].arg
)
920 return(mdoc_err(mdoc
, "macro expects `%s' or a single child",
921 mdoc_argnames
[MDOC_Std
]));
926 /* Warn if `Bl' type-specific syntax isn't reflected in items. */
928 post_it(struct mdoc
*mdoc
)
931 #define TYPE_NONE (0)
932 #define TYPE_BODY (1)
933 #define TYPE_HEAD (2)
934 #define TYPE_OHEAD (3)
938 if (MDOC_BLOCK
!= mdoc
->last
->type
)
941 assert(MDOC_It
== mdoc
->last
->tok
);
943 n
= mdoc
->last
->parent
;
945 assert(MDOC_Bl
== n
->tok
);
948 assert(MDOC_BLOCK
== n
->type
);
949 assert(MDOC_Bl
== n
->tok
);
951 argc
= n
->data
.block
.argc
;
955 /* Some types require block-head, some not. */
958 for (i
= 0; TYPE_NONE
== type
&& i
< argc
; i
++)
959 switch (n
->data
.block
.argv
[(int)i
].arg
) {
970 sv
= n
->data
.block
.argv
[(int)i
].arg
;
982 sv
= n
->data
.block
.argv
[(int)i
].arg
;
986 sv
= n
->data
.block
.argv
[(int)i
].arg
;
992 assert(TYPE_NONE
!= type
);
994 n
= mdoc
->last
->data
.block
.head
;
997 if (TYPE_HEAD
== type
) {
998 if (NULL
== n
->child
)
999 if ( ! mdoc_warn(mdoc
, WARN_SYNTAX
, "macro suggests line parameters"))
1002 n
= mdoc
->last
->data
.block
.body
;
1004 if (NULL
== n
->child
)
1005 if ( ! mdoc_warn(mdoc
, WARN_SYNTAX
, "macro suggests body children"))
1008 } else if (TYPE_BODY
== type
) {
1010 if ( ! mdoc_warn(mdoc
, WARN_SYNTAX
, "macro suggests no line parameters"))
1013 n
= mdoc
->last
->data
.block
.body
;
1015 if (NULL
== n
->child
)
1016 if ( ! mdoc_warn(mdoc
, WARN_SYNTAX
, "macro suggests body children"))
1019 if (NULL
== n
->child
)
1020 if ( ! mdoc_warn(mdoc
, WARN_SYNTAX
, "macro suggests line parameters"))
1023 n
= mdoc
->last
->data
.block
.body
;
1026 if ( ! mdoc_warn(mdoc
, WARN_SYNTAX
, "macro suggests no body children"))
1030 if (MDOC_Column
!= sv
)
1033 /* Make sure the number of columns is sane. */
1035 argc
= mdoc
->last
->parent
->parent
->data
.block
.argv
->sz
;
1036 n
= mdoc
->last
->data
.block
.head
->child
;
1038 for (i
= 0; n
; n
= n
->next
)
1043 return(mdoc_err(mdoc
, "expected %zu list columns, have %zu", argc
, i
));
1052 post_bl(struct mdoc
*mdoc
)
1054 struct mdoc_node
*n
;
1056 if (MDOC_BODY
!= mdoc
->last
->type
)
1058 assert(MDOC_Bl
== mdoc
->last
->tok
);
1061 for (n
= mdoc
->last
->child
; n
; n
= n
->next
) {
1062 if (MDOC_BLOCK
== n
->type
)
1063 if (MDOC_It
== n
->tok
)
1069 return(mdoc_nerr(mdoc
, n
, "invalid child of parent macro `Bl'"));
1074 ebool(struct mdoc
*mdoc
)
1076 struct mdoc_node
*n
;
1078 assert(MDOC_ELEM
== mdoc
->last
->type
);
1080 for (n
= mdoc
->last
->child
; n
; n
= n
->next
) {
1081 if (MDOC_TEXT
!= n
->type
)
1083 if (xstrcmp(n
->data
.text
.string
, "on"))
1085 if (xstrcmp(n
->data
.text
.string
, "off"))
1091 return(mdoc_nerr(mdoc
, n
, "expected boolean value"));
1096 post_root(struct mdoc
*mdoc
)
1099 if (NULL
== mdoc
->first
->child
)
1100 return(mdoc_err(mdoc
, "document has no data"));
1101 if (SEC_PROLOGUE
== mdoc
->lastnamed
)
1102 return(mdoc_err(mdoc
, "document has incomplete prologue"));
1103 if (MDOC_BLOCK
!= mdoc
->first
->child
->type
)
1104 return(mdoc_err(mdoc
, "document expects `%s' macro after prologue", mdoc_macronames
[MDOC_Sh
]));
1105 if (MDOC_Sh
!= mdoc
->first
->child
->tok
)
1106 return(mdoc_err(mdoc
, "document expects `%s' macro after prologue", mdoc_macronames
[MDOC_Sh
]));
1112 post_sh(struct mdoc
*mdoc
)
1115 if (MDOC_HEAD
== mdoc
->last
->type
)
1116 return(post_sh_head(mdoc
));
1117 if (MDOC_BODY
== mdoc
->last
->type
)
1118 return(post_sh_body(mdoc
));
1124 post_sh_body(struct mdoc
*mdoc
)
1126 struct mdoc_node
*n
;
1128 assert(MDOC_Sh
== mdoc
->last
->tok
);
1129 assert(MDOC_BODY
== mdoc
->last
->type
);
1130 if (SEC_NAME
!= mdoc
->lastnamed
)
1134 * Warn if the NAME section doesn't contain the `Nm' and `Nd'
1135 * macros (can have multiple `Nm' and one `Nd'). Note that the
1136 * children of the BODY declaration can also be "text".
1139 if (NULL
== (n
= mdoc
->last
->child
))
1140 return(mdoc_warn(mdoc
, WARN_COMPAT
, "section NAME "
1141 "should contain %s and %s",
1142 mdoc_macronames
[MDOC_Nm
],
1143 mdoc_macronames
[MDOC_Nd
]));
1145 for ( ; n
&& n
->next
; n
= n
->next
) {
1146 if (MDOC_ELEM
== n
->type
&& MDOC_Nm
== n
->tok
)
1148 if (MDOC_TEXT
== n
->type
)
1150 if ( ! (mdoc_nwarn(mdoc
, n
, WARN_COMPAT
, "section "
1151 "NAME should contain %s as "
1152 "initial body child",
1153 mdoc_macronames
[MDOC_Nm
])))
1157 if (MDOC_ELEM
== n
->type
&& MDOC_Nd
== n
->tok
)
1160 return(mdoc_warn(mdoc
, WARN_COMPAT
, "section NAME should "
1161 "contain %s as the last child",
1162 mdoc_macronames
[MDOC_Nd
]));
1167 post_sh_head(struct mdoc
*mdoc
)
1172 assert(MDOC_Sh
== mdoc
->last
->tok
);
1174 if ( ! xstrlcats(buf
, mdoc
->last
->child
, 64))
1175 return(mdoc_err(mdoc
, "macro parameters too long"));
1177 sec
= mdoc_atosec(buf
);
1179 if (SEC_BODY
== mdoc
->lastnamed
&& SEC_NAME
!= sec
)
1180 return(mdoc_err(mdoc
, "section NAME must be first"));
1181 if (SEC_CUSTOM
== sec
)
1183 if (sec
== mdoc
->lastnamed
)
1184 return(mdoc_warn(mdoc
, WARN_SYNTAX
, "section repeated"));
1185 if (sec
< mdoc
->lastnamed
)
1186 return(mdoc_warn(mdoc
, WARN_SYNTAX
, "section out of conventional order"));
1193 mdoc_valid_pre(struct mdoc
*mdoc
, struct mdoc_node
*node
)
1197 if (MDOC_TEXT
== node
->type
)
1199 assert(MDOC_ROOT
!= node
->type
);
1201 if (NULL
== mdoc_valids
[node
->tok
].pre
)
1203 for (p
= mdoc_valids
[node
->tok
].pre
; *p
; p
++)
1204 if ( ! (*p
)(mdoc
, node
))
1211 mdoc_valid_post(struct mdoc
*mdoc
)
1215 if (MDOC_VALID
& mdoc
->last
->flags
)
1217 mdoc
->last
->flags
|= MDOC_VALID
;
1219 if (MDOC_TEXT
== mdoc
->last
->type
)
1221 if (MDOC_ROOT
== mdoc
->last
->type
)
1222 return(post_root(mdoc
));
1224 if (NULL
== mdoc_valids
[mdoc
->last
->tok
].post
)
1226 for (p
= mdoc_valids
[mdoc
->last
->tok
].post
; *p
; p
++)