]>
git.cameronkatri.com Git - mandoc.git/blob - validate.c
1 /* $Id: validate.c,v 1.32 2009/01/16 12:23:25 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 typedef int (*v_pre
)(struct mdoc
*, struct mdoc_node
*);
26 typedef int (*v_post
)(struct mdoc
*);
35 static int pre_display(struct mdoc
*, struct mdoc_node
*);
36 static int pre_bd(struct mdoc
*, struct mdoc_node
*);
37 static int pre_bl(struct mdoc
*, struct mdoc_node
*);
38 static int pre_it(struct mdoc
*, struct mdoc_node
*);
39 static int pre_prologue(struct mdoc
*, struct mdoc_node
*);
40 static int pre_prologue(struct mdoc
*, struct mdoc_node
*);
41 static int pre_prologue(struct mdoc
*, struct mdoc_node
*);
43 static int headchild_err_ge1(struct mdoc
*);
44 static int headchild_warn_ge1(struct mdoc
*);
45 static int headchild_err_eq0(struct mdoc
*);
46 static int elemchild_err_eq0(struct mdoc
*);
47 static int elemchild_err_ge1(struct mdoc
*);
48 static int elemchild_warn_eq0(struct mdoc
*);
49 static int bodychild_warn_ge1(struct mdoc
*);
50 static int bodychild_err_eq0(struct mdoc
*);
51 static int elemchild_warn_ge1(struct mdoc
*);
52 static int post_sh(struct mdoc
*);
53 static int post_bl(struct mdoc
*);
54 static int post_it(struct mdoc
*);
56 static v_pre pres_prologue
[] = { pre_prologue
, NULL
};
57 static v_pre pres_d1
[] = { pre_display
, NULL
};
58 static v_pre pres_bd
[] = { pre_display
, pre_bd
, NULL
};
59 static v_pre pres_bl
[] = { pre_bl
, NULL
};
60 static v_pre pres_it
[] = { pre_it
, NULL
};
62 static v_post posts_bd
[] = { headchild_err_eq0
, bodychild_warn_ge1
, NULL
};
63 static v_post posts_text
[] = { elemchild_err_ge1
, NULL
};
64 static v_post posts_wtext
[] = { elemchild_warn_ge1
, NULL
};
65 static v_post posts_notext
[] = { elemchild_err_eq0
, NULL
};
66 static v_post posts_wline
[] = { headchild_warn_ge1
, bodychild_err_eq0
, NULL
};
67 static v_post posts_sh
[] = { headchild_err_ge1
, bodychild_warn_ge1
, post_sh
, NULL
};
68 static v_post posts_bl
[] = { headchild_err_eq0
, bodychild_warn_ge1
, post_bl
, NULL
};
69 static v_post posts_it
[] = { post_it
, NULL
};
70 static v_post posts_ss
[] = { headchild_err_ge1
, NULL
};
71 static v_post posts_pp
[] = { elemchild_warn_eq0
, NULL
};
72 static v_post posts_d1
[] = { headchild_err_ge1
, NULL
};
75 const struct valids mdoc_valids
[MDOC_MAX
] = {
76 { NULL
, NULL
}, /* \" */
77 { pres_prologue
, posts_text
}, /* Dd */
78 { pres_prologue
, NULL
}, /* Dt */
79 { pres_prologue
, NULL
}, /* Os */
80 /* FIXME: preceding Pp. */
81 /* FIXME: NAME section internal ordering. */
82 /* FIXME: can only be a child of root. */
83 { NULL
, posts_sh
}, /* Sh */
84 /* FIXME: preceding Pp. */
85 /* FIXME: can only be a child of Sh. */
86 { NULL
, posts_ss
}, /* Ss */
87 /* FIXME: proceeding... */
88 { NULL
, posts_pp
}, /* Pp */
89 { pres_d1
, posts_d1
}, /* D1 */
90 { pres_d1
, posts_d1
}, /* Dl */
91 /* FIXME: preceding Pp. */
92 { pres_bd
, posts_bd
}, /* Bd */
93 { NULL
, NULL
}, /* Ed */
94 /* FIXME: preceding Pp. */
95 { pres_bl
, posts_bl
}, /* Bl */
96 { NULL
, NULL
}, /* El */
97 { pres_it
, posts_it
}, /* It */
98 { NULL
, posts_text
}, /* Ad */
100 { NULL
, NULL
}, /* An */
101 { NULL
, NULL
}, /* Ar */
103 { NULL
, posts_text
}, /* Cd */ /* FIXME: section 4 only. */
104 { NULL
, NULL
}, /* Cm */
105 { NULL
, posts_text
}, /* Dv */
106 { NULL
, posts_text
}, /* Er */ /* FIXME: section 2 only. */
107 { NULL
, posts_text
}, /* Ev */
108 { NULL
, posts_notext
}, /* Ex */ /* FIXME: sections 1,6,8 only. */ /* -std required */
109 { NULL
, posts_text
}, /* Fa */
110 { NULL
, NULL
}, /* Fd */ /* FIXME: SYNOPSIS section. */
111 { NULL
, NULL
}, /* Fl */
112 { NULL
, posts_text
}, /* Fn */
113 { NULL
, NULL
}, /* Ft */
114 { NULL
, posts_text
}, /* Ic */
115 { NULL
, posts_wtext
}, /* In */
116 { NULL
, posts_text
}, /* Li */
117 { NULL
, posts_wtext
}, /* Nd */
118 { NULL
, NULL
}, /* Nm */ /* FIXME: If name not set? */
119 { NULL
, posts_wline
}, /* Op */
120 { NULL
, NULL
}, /* Ot */
121 { NULL
, NULL
}, /* Pa */
122 { NULL
, posts_notext
}, /* Rv */ /* -std required */
123 { NULL
, posts_notext
}, /* St */ /* arg required */
124 { NULL
, posts_text
}, /* Va */
125 { NULL
, posts_text
}, /* Vt */
126 { NULL
, NULL
}, /* Xr */ /* FIXME */
127 { NULL
, posts_text
}, /* %A */
128 { NULL
, posts_text
}, /* %B */
129 { NULL
, posts_text
}, /* %D */
130 { NULL
, posts_text
}, /* %I */
131 { NULL
, posts_text
}, /* %J */
132 { NULL
, posts_text
}, /* %N */
133 { NULL
, posts_text
}, /* %O */
134 { NULL
, posts_text
}, /* %P */
135 { NULL
, posts_text
}, /* %R */
136 { NULL
, posts_text
}, /* %T */
137 { NULL
, posts_text
}, /* %V */
138 { NULL
, NULL
}, /* Ac */
139 { NULL
, NULL
}, /* Ao */
140 { NULL
, posts_wline
}, /* Aq */
141 { NULL
, NULL
}, /* At */ /* FIXME */
142 { NULL
, NULL
}, /* Bc */
143 { NULL
, NULL
}, /* Bf */
144 { NULL
, NULL
}, /* Bo */
145 { NULL
, posts_wline
}, /* Bq */
146 { NULL
, NULL
}, /* Bsx */
147 { NULL
, NULL
}, /* Bx */
148 { NULL
, NULL
}, /* Db */ /* FIXME: boolean */
149 { NULL
, NULL
}, /* Dc */
150 { NULL
, NULL
}, /* Do */
151 { NULL
, posts_wline
}, /* Dq */
152 { NULL
, NULL
}, /* Ec */
153 { NULL
, NULL
}, /* Ef */ /* -symbolic, etc. */
154 { NULL
, posts_text
}, /* Em */
155 { NULL
, NULL
}, /* Eo */
156 { NULL
, NULL
}, /* Fx */
157 { NULL
, posts_text
}, /* Ms */ /* FIXME: which symbols? */
158 { NULL
, posts_notext
}, /* No */
159 { NULL
, posts_notext
}, /* Ns */
160 { NULL
, NULL
}, /* Nx */
161 { NULL
, NULL
}, /* Ox */
162 { NULL
, NULL
}, /* Pc */
163 { NULL
, NULL
}, /* Pf */ /* FIXME: 2 or more arguments */
164 { NULL
, NULL
}, /* Po */
165 { NULL
, posts_wline
}, /* Pq */ /* FIXME: ignore following Sh/Ss */
166 { NULL
, NULL
}, /* Qc */
167 { NULL
, posts_wline
}, /* Ql */
168 { NULL
, NULL
}, /* Qo */
169 { NULL
, posts_wline
}, /* Qq */
170 { NULL
, NULL
}, /* Re */
171 { NULL
, NULL
}, /* Rs */
172 { NULL
, NULL
}, /* Sc */
173 { NULL
, NULL
}, /* So */
174 { NULL
, posts_wline
}, /* Sq */
175 { NULL
, NULL
}, /* Sm */ /* FIXME: boolean */
176 { NULL
, posts_text
}, /* Sx */
177 { NULL
, posts_text
}, /* Sy */
178 { NULL
, posts_text
}, /* Tn */
179 { NULL
, NULL
}, /* Ux */
180 { NULL
, NULL
}, /* Xc */
181 { NULL
, NULL
}, /* Xo */
182 { NULL
, NULL
}, /* Fo */
183 { NULL
, NULL
}, /* Fc */
184 { NULL
, NULL
}, /* Oo */
185 { NULL
, NULL
}, /* Oc */
186 { NULL
, NULL
}, /* Bk */
187 { NULL
, NULL
}, /* Ek */
188 { NULL
, posts_notext
}, /* Bt */
189 { NULL
, NULL
}, /* Hf */
190 { NULL
, NULL
}, /* Fr */
191 { NULL
, posts_notext
}, /* Ud */
196 bodychild_err_eq0(struct mdoc
*mdoc
)
199 if (MDOC_BODY
!= mdoc
->last
->type
)
201 if (NULL
== mdoc
->last
->child
)
203 return(mdoc_warn(mdoc
, WARN_SYNTAX
, "macro suggests no body children"));
208 bodychild_warn_ge1(struct mdoc
*mdoc
)
211 if (MDOC_BODY
!= mdoc
->last
->type
)
213 if (mdoc
->last
->child
)
215 return(mdoc_warn(mdoc
, WARN_SYNTAX
, "macro suggests one or more body children"));
220 elemchild_warn_eq0(struct mdoc
*mdoc
)
223 assert(MDOC_ELEM
== mdoc
->last
->type
);
224 if (NULL
== mdoc
->last
->child
)
226 return(mdoc_pwarn(mdoc
, mdoc
->last
->child
->line
,
227 mdoc
->last
->child
->pos
, WARN_SYNTAX
, "macro suggests no parameters"));
232 elemchild_warn_ge1(struct mdoc
*mdoc
)
235 assert(MDOC_ELEM
== mdoc
->last
->type
);
236 if (mdoc
->last
->child
)
238 return(mdoc_warn(mdoc
, WARN_SYNTAX
, "macro suggests one or more parameters"));
243 elemchild_err_eq0(struct mdoc
*mdoc
)
246 assert(MDOC_ELEM
== mdoc
->last
->type
);
247 if (NULL
== mdoc
->last
->child
)
249 return(mdoc_err(mdoc
, "macro expects no parameters"));
254 elemchild_err_ge1(struct mdoc
*mdoc
)
257 assert(MDOC_ELEM
== mdoc
->last
->type
);
258 if (mdoc
->last
->child
)
260 return(mdoc_err(mdoc
, "macro expects one or more parameters"));
265 headchild_err_eq0(struct mdoc
*mdoc
)
268 if (MDOC_HEAD
!= mdoc
->last
->type
)
270 if (NULL
== mdoc
->last
->child
)
272 return(mdoc_perr(mdoc
, mdoc
->last
->child
->line
,
273 mdoc
->last
->child
->pos
, "macro expects no parameters"));
278 headchild_warn_ge1(struct mdoc
*mdoc
)
281 if (MDOC_HEAD
!= mdoc
->last
->type
)
283 if (mdoc
->last
->child
)
285 return(mdoc_warn(mdoc
, WARN_SYNTAX
, "macro suggests one or more parameters"));
290 headchild_err_ge1(struct mdoc
*mdoc
)
293 if (MDOC_HEAD
!= mdoc
->last
->type
)
295 if (mdoc
->last
->child
)
297 return(mdoc_err(mdoc
, "macro expects one or more parameters"));
302 pre_display(struct mdoc
*mdoc
, struct mdoc_node
*node
)
306 if (MDOC_BLOCK
!= node
->type
)
310 for (n
= mdoc
->last
->parent
; n
; n
= n
->parent
)
311 if (MDOC_BLOCK
== n
->type
)
312 if (MDOC_Bd
== n
->tok
)
316 return(mdoc_nerr(mdoc
, node
, "displays may not be nested"));
321 pre_bl(struct mdoc
*mdoc
, struct mdoc_node
*node
)
324 struct mdoc_arg
*argv
;
327 if (MDOC_BLOCK
!= node
->type
)
329 assert(MDOC_Bl
== node
->tok
);
332 argc
= node
->data
.block
.argc
;
334 for (i
= type
= err
= 0; i
< argc
; i
++) {
335 argv
= &node
->data
.block
.argv
[(int)i
];
368 return(mdoc_err(mdoc
, "no list type specified"));
372 return(mdoc_perr(mdoc
, argv
->line
,
373 argv
->pos
, "only one list type possible"));
378 pre_bd(struct mdoc
*mdoc
, struct mdoc_node
*node
)
381 struct mdoc_arg
*argv
;
384 if (MDOC_BLOCK
!= node
->type
)
386 assert(MDOC_Bd
== node
->tok
);
389 argc
= node
->data
.block
.argc
;
391 for (err
= i
= type
= 0; 0 == err
&& i
< argc
; i
++) {
392 argv
= &node
->data
.block
.argv
[(int)i
];
397 case (MDOC_Unfilled
):
413 return(mdoc_err(mdoc
, "no display type specified"));
417 return(mdoc_perr(mdoc
, argv
->line
,
418 argv
->pos
, "only one display type possible"));
423 pre_it(struct mdoc
*mdoc
, struct mdoc_node
*node
)
426 if (MDOC_BLOCK
!= mdoc
->last
->type
)
428 assert(MDOC_It
== mdoc
->last
->tok
);
430 if (MDOC_BODY
!= mdoc
->last
->parent
->type
)
431 return(mdoc_nerr(mdoc
, node
, "invalid macro parent `%s'", mdoc_macronames
[mdoc
->last
->parent
->tok
]));
432 if (MDOC_Bl
!= mdoc
->last
->parent
->tok
)
433 return(mdoc_nerr(mdoc
, node
, "invalid macro parent `%s'", mdoc_macronames
[mdoc
->last
->parent
->tok
]));
440 pre_prologue(struct mdoc
*mdoc
, struct mdoc_node
*node
)
443 if (SEC_PROLOGUE
!= mdoc
->sec_lastn
)
444 return(mdoc_nerr(mdoc
, node
, "macro may only be invoked in the prologue"));
445 assert(MDOC_ELEM
== node
->type
);
447 /* Check for ordering. */
451 if (mdoc
->meta
.title
[0] && mdoc
->meta
.date
)
453 return(mdoc_nerr(mdoc
, node
, "prologue macro out-of-order"));
455 if (0 == mdoc
->meta
.title
[0] && mdoc
->meta
.date
)
457 return(mdoc_nerr(mdoc
, node
, "prologue macro out-of-order"));
459 if (0 == mdoc
->meta
.title
[0] && 0 == mdoc
->meta
.date
)
461 return(mdoc_nerr(mdoc
, node
, "prologue macro out-of-order"));
467 /* Check for repetition. */
471 if (0 == mdoc
->meta
.os
[0])
475 if (0 == mdoc
->meta
.date
)
479 if (0 == mdoc
->meta
.title
[0])
487 return(mdoc_nerr(mdoc
, node
, "prologue macro repeated"));
491 /* Warn if `Bl' type-specific syntax isn't reflected in items. */
493 post_it(struct mdoc
*mdoc
)
496 #define TYPE_NONE (0)
497 #define TYPE_BODY (1)
498 #define TYPE_HEAD (2)
502 if (MDOC_BLOCK
!= mdoc
->last
->type
)
505 assert(MDOC_It
== mdoc
->last
->tok
);
507 n
= mdoc
->last
->parent
;
509 assert(MDOC_Bl
== n
->tok
);
512 assert(MDOC_BLOCK
== n
->type
);
513 assert(MDOC_Bl
== n
->tok
);
515 argc
= n
->data
.block
.argc
;
518 /* Some types require block-head, some not. */
520 for (i
= 0; TYPE_NONE
== type
&& i
< argc
; i
++)
521 switch (n
->data
.block
.argv
[(int)i
].arg
) {
532 sv
= n
->data
.block
.argv
[(int)i
].arg
;
546 sv
= n
->data
.block
.argv
[(int)i
].arg
;
552 assert(TYPE_NONE
!= type
);
554 if (TYPE_HEAD
== type
) {
555 if (NULL
== (n
= mdoc
->last
->data
.block
.head
)) {
556 if ( ! mdoc_warn(mdoc
, WARN_SYNTAX
, "macro suggests line parameters"))
558 } else if (NULL
== n
->child
)
559 if ( ! mdoc_warn(mdoc
, WARN_SYNTAX
, "macro suggests line parameters"))
562 if (NULL
== (n
= mdoc
->last
->data
.block
.body
)) {
563 if ( ! mdoc_warn(mdoc
, WARN_SYNTAX
, "macro suggests body children"))
565 } else if (NULL
== n
->child
)
566 if ( ! mdoc_warn(mdoc
, WARN_SYNTAX
, "macro suggests body children"))
572 if (NULL
== (n
= mdoc
->last
->data
.block
.head
)) {
573 if ( ! mdoc_warn(mdoc
, WARN_SYNTAX
, "macro suggests line parameters"))
575 } else if (NULL
== n
->child
)
576 if ( ! mdoc_warn(mdoc
, WARN_SYNTAX
, "macro suggests line parameters"))
579 if ((n
= mdoc
->last
->data
.block
.body
) && n
->child
)
580 if ( ! mdoc_warn(mdoc
, WARN_SYNTAX
, "macro suggests body children"))
583 if (MDOC_Column
!= sv
)
586 /* Make sure the number of columns is sane. */
588 sv
= mdoc
->last
->parent
->parent
->data
.block
.argv
->sz
;
589 n
= mdoc
->last
->data
.block
.head
->child
;
591 for (i
= 0; n
; n
= n
->next
)
596 return(mdoc_err(mdoc
, "expected %d list columns, have %d", sv
, (int)i
));
604 /* Make sure that only `It' macros are our body-children. */
606 post_bl(struct mdoc
*mdoc
)
610 if (MDOC_BODY
!= mdoc
->last
->type
)
612 assert(MDOC_Bl
== mdoc
->last
->tok
);
614 for (n
= mdoc
->last
->child
; n
; n
= n
->next
) {
615 if (MDOC_BLOCK
== n
->type
)
616 if (MDOC_It
== n
->tok
)
622 return(mdoc_nerr(mdoc
, n
, "invalid child of parent macro `Bl'"));
626 /* Warn if conventional sections are out of order. */
628 post_sh(struct mdoc
*mdoc
)
633 char *args
[MDOC_LINEARG_MAX
];
635 if (MDOC_HEAD
!= mdoc
->last
->type
)
638 assert(MDOC_Sh
== mdoc
->last
->tok
);
640 n
= mdoc
->last
->child
;
643 for (i
= 0; n
&& i
< MDOC_LINEARG_MAX
; n
= n
->next
, i
++) {
644 assert(MDOC_TEXT
== n
->type
);
645 assert(NULL
== n
->child
);
646 assert(n
->data
.text
.string
);
647 args
[i
] = n
->data
.text
.string
;
650 sec
= mdoc_atosec((size_t)i
, (const char **)args
);
651 if (SEC_CUSTOM
== sec
)
653 if (sec
> mdoc
->sec_lastn
)
656 if (sec
== mdoc
->sec_lastn
)
657 return(mdoc_warn(mdoc
, WARN_SYNTAX
, "section repeated"));
658 return(mdoc_warn(mdoc
, WARN_SYNTAX
, "section out of conventional order"));
663 mdoc_valid_pre(struct mdoc
*mdoc
, struct mdoc_node
*node
)
667 /* TODO: character-escape checks. */
669 if (MDOC_TEXT
== node
->type
)
671 assert(MDOC_ROOT
!= node
->type
);
673 if (NULL
== mdoc_valids
[node
->tok
].pre
)
675 for (p
= mdoc_valids
[node
->tok
].pre
; *p
; p
++)
676 if ( ! (*p
)(mdoc
, node
))
683 mdoc_valid_post(struct mdoc
*mdoc
)
687 if (MDOC_TEXT
== mdoc
->last
->type
)
689 if (MDOC_ROOT
== mdoc
->last
->type
)
692 if (NULL
== mdoc_valids
[mdoc
->last
->tok
].post
)
694 for (p
= mdoc_valids
[mdoc
->last
->tok
].post
; *p
; p
++)