=================================================================== RCS file: /cvs/mandoc/mdoc_validate.c,v retrieving revision 1.41 retrieving revision 1.58 diff -u -p -r1.41 -r1.58 --- mandoc/mdoc_validate.c 2009/07/25 16:03:03 1.41 +++ mandoc/mdoc_validate.c 2010/02/17 19:28:11 1.58 @@ -1,4 +1,4 @@ -/* $Id: mdoc_validate.c,v 1.41 2009/07/25 16:03:03 kristaps Exp $ */ +/* $Id: mdoc_validate.c,v 1.58 2010/02/17 19:28:11 kristaps Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons * @@ -14,11 +14,14 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #include #include -#include #include #include #include @@ -63,17 +66,13 @@ static int warn_count(struct mdoc *, const char *, static int err_count(struct mdoc *, const char *, int, const char *, int); -#ifdef __linux__ -extern size_t strlcat(char *, const char *, size_t); -#endif - static int berr_ge1(POST_ARGS); static int bwarn_ge1(POST_ARGS); static int ebool(POST_ARGS); static int eerr_eq0(POST_ARGS); static int eerr_eq1(POST_ARGS); static int eerr_ge1(POST_ARGS); -static int eerr_le2(POST_ARGS); +static int eerr_le1(POST_ARGS); static int ewarn_ge1(POST_ARGS); static int herr_eq0(POST_ARGS); static int herr_ge1(POST_ARGS); @@ -81,7 +80,6 @@ static int hwarn_eq1(POST_ARGS); static int hwarn_le1(POST_ARGS); static int post_an(POST_ARGS); -static int post_args(POST_ARGS); static int post_at(POST_ARGS); static int post_bf(POST_ARGS); static int post_bl(POST_ARGS); @@ -90,11 +88,12 @@ static int post_it(POST_ARGS); static int post_lb(POST_ARGS); static int post_nm(POST_ARGS); static int post_root(POST_ARGS); +static int post_rs(POST_ARGS); static int post_sh(POST_ARGS); static int post_sh_body(POST_ARGS); static int post_sh_head(POST_ARGS); -static int post_sp(POST_ARGS); static int post_st(POST_ARGS); +static int post_vt(POST_ARGS); static int pre_an(PRE_ARGS); static int pre_bd(PRE_ARGS); static int pre_bl(PRE_ARGS); @@ -118,24 +117,23 @@ static v_post posts_bd[] = { herr_eq0, bwarn_ge1, NUL static v_post posts_bf[] = { hwarn_le1, post_bf, NULL }; static v_post posts_bl[] = { bwarn_ge1, post_bl, NULL }; static v_post posts_bool[] = { eerr_eq1, ebool, NULL }; -static v_post posts_ex[] = { eerr_eq0, post_args, NULL }; static v_post posts_fo[] = { hwarn_eq1, bwarn_ge1, NULL }; -static v_post posts_in[] = { eerr_eq1, NULL }; static v_post posts_it[] = { post_it, NULL }; static v_post posts_lb[] = { eerr_eq1, post_lb, NULL }; static v_post posts_nd[] = { berr_ge1, NULL }; static v_post posts_nm[] = { post_nm, NULL }; static v_post posts_notext[] = { eerr_eq0, NULL }; -static v_post posts_pf[] = { eerr_eq1, NULL }; -static v_post posts_rv[] = { eerr_eq0, post_args, NULL }; +static v_post posts_rs[] = { berr_ge1, herr_eq0, post_rs, NULL }; static v_post posts_sh[] = { herr_ge1, bwarn_ge1, post_sh, NULL }; -static v_post posts_sp[] = { post_sp, NULL }; +static v_post posts_sp[] = { eerr_le1, NULL }; static v_post posts_ss[] = { herr_ge1, NULL }; static v_post posts_st[] = { eerr_eq1, post_st, NULL }; static v_post posts_text[] = { eerr_ge1, NULL }; +static v_post posts_text1[] = { eerr_eq1, NULL }; +static v_post posts_vt[] = { post_vt, NULL }; static v_post posts_wline[] = { bwarn_ge1, herr_eq0, NULL }; static v_post posts_wtext[] = { ewarn_ge1, NULL }; -static v_post posts_xr[] = { eerr_ge1, eerr_le2, NULL }; +static v_post posts_xr[] = { eerr_ge1, NULL }; static v_pre pres_an[] = { pre_an, NULL }; static v_pre pres_bd[] = { pre_display, pre_bd, NULL }; static v_pre pres_bl[] = { pre_bl, NULL }; @@ -176,35 +174,35 @@ const struct valids mdoc_valids[MDOC_MAX] = { { NULL, NULL }, /* Dv */ { pres_er, posts_text }, /* Er */ { NULL, NULL }, /* Ev */ - { pres_ex, posts_ex }, /* Ex */ + { pres_ex, NULL }, /* Ex */ { NULL, NULL }, /* Fa */ { pres_fd, posts_wtext }, /* Fd */ { NULL, NULL }, /* Fl */ { NULL, posts_text }, /* Fn */ { NULL, posts_wtext }, /* Ft */ { NULL, posts_text }, /* Ic */ - { NULL, posts_in }, /* In */ + { NULL, posts_text1 }, /* In */ { NULL, NULL }, /* Li */ { NULL, posts_nd }, /* Nd */ { NULL, posts_nm }, /* Nm */ { NULL, posts_wline }, /* Op */ { NULL, NULL }, /* Ot */ { NULL, NULL }, /* Pa */ - { pres_rv, posts_rv }, /* Rv */ + { pres_rv, NULL }, /* Rv */ { NULL, posts_st }, /* St */ { NULL, NULL }, /* Va */ - { NULL, posts_text }, /* Vt */ + { NULL, posts_vt }, /* Vt */ { NULL, posts_xr }, /* Xr */ { NULL, posts_text }, /* %A */ - { NULL, posts_text }, /* %B */ - { NULL, posts_text }, /* %D */ + { NULL, posts_text }, /* %B */ /* FIXME: can be used outside Rs/Re. */ + { NULL, posts_text }, /* %D */ /* FIXME: check date with mandoc_a2time(). */ { NULL, posts_text }, /* %I */ { NULL, posts_text }, /* %J */ { NULL, posts_text }, /* %N */ { NULL, posts_text }, /* %O */ { NULL, posts_text }, /* %P */ { NULL, posts_text }, /* %R */ - { NULL, posts_text }, /* %T */ + { NULL, posts_text }, /* %T */ /* FIXME: can be used outside Rs/Re. */ { NULL, posts_text }, /* %V */ { NULL, NULL }, /* Ac */ { NULL, NULL }, /* Ao */ @@ -231,7 +229,7 @@ const struct valids mdoc_valids[MDOC_MAX] = { { NULL, NULL }, /* Nx */ { NULL, NULL }, /* Ox */ { NULL, NULL }, /* Pc */ - { NULL, posts_pf }, /* Pf */ + { NULL, posts_text1 }, /* Pf */ { NULL, NULL }, /* Po */ { NULL, posts_wline }, /* Pq */ { NULL, NULL }, /* Qc */ @@ -239,7 +237,7 @@ const struct valids mdoc_valids[MDOC_MAX] = { { NULL, NULL }, /* Qo */ { NULL, posts_wline }, /* Qq */ { NULL, NULL }, /* Re */ - { NULL, posts_wline }, /* Rs */ + { NULL, posts_rs }, /* Rs */ { NULL, NULL }, /* Sc */ { NULL, NULL }, /* So */ { NULL, posts_wline }, /* Sq */ @@ -262,7 +260,7 @@ const struct valids mdoc_valids[MDOC_MAX] = { { NULL, posts_notext }, /* Ud */ { pres_lb, posts_lb }, /* Lb */ { NULL, posts_notext }, /* Lp */ - { NULL, NULL }, /* Lk */ + { NULL, posts_text }, /* Lk */ { NULL, posts_text }, /* Mt */ { NULL, posts_wline }, /* Brq */ { NULL, NULL }, /* Bro */ @@ -274,6 +272,7 @@ const struct valids mdoc_valids[MDOC_MAX] = { { NULL, posts_text }, /* %Q */ { NULL, posts_notext }, /* br */ { NULL, posts_sp }, /* sp */ + { NULL, posts_text1 }, /* %U */ }; @@ -408,7 +407,7 @@ CHECK_BODY_DEFN(ge1, warn, warn_child_gt, 0) /* bwarn_ CHECK_BODY_DEFN(ge1, err, err_child_gt, 0) /* berr_ge1() */ CHECK_ELEM_DEFN(ge1, warn, warn_child_gt, 0) /* ewarn_gt1() */ CHECK_ELEM_DEFN(eq1, err, err_child_eq, 1) /* eerr_eq1() */ -CHECK_ELEM_DEFN(le2, err, err_child_lt, 3) /* eerr_le2() */ +CHECK_ELEM_DEFN(le1, err, err_child_lt, 2) /* eerr_le1() */ CHECK_ELEM_DEFN(eq0, err, err_child_eq, 0) /* eerr_eq0() */ CHECK_ELEM_DEFN(ge1, err, err_child_gt, 0) /* eerr_ge1() */ CHECK_HEAD_DEFN(eq0, err, err_child_eq, 0) /* herr_eq0() */ @@ -622,25 +621,33 @@ pre_bl(PRE_ARGS) case (MDOC_Inset): /* FALLTHROUGH */ case (MDOC_Column): - if (-1 != type) + if (type >= 0) return(mdoc_nerr(mdoc, n, EMULTILIST)); type = n->args->argv[pos].arg; break; + case (MDOC_Compact): + if (type < 0 && ! mdoc_nwarn(mdoc, n, ENOTYPE)) + return(0); + break; case (MDOC_Width): - if (-1 != width) + if (width >= 0) return(mdoc_nerr(mdoc, n, EARGREP)); + if (type < 0 && ! mdoc_nwarn(mdoc, n, ENOTYPE)) + return(0); width = n->args->argv[pos].arg; break; case (MDOC_Offset): - if (-1 != offset) + if (offset >= 0) return(mdoc_nerr(mdoc, n, EARGREP)); + if (type < 0 && ! mdoc_nwarn(mdoc, n, ENOTYPE)) + return(0); offset = n->args->argv[pos].arg; break; default: break; } - if (-1 == type) + if (type < 0) return(mdoc_nerr(mdoc, n, ELISTTYPE)); /* @@ -651,17 +658,19 @@ pre_bl(PRE_ARGS) switch (type) { case (MDOC_Tag): - if (-1 == width && ! mdoc_nwarn(mdoc, n, EMISSWIDTH)) + if (width < 0 && ! mdoc_nwarn(mdoc, n, EMISSWIDTH)) return(0); break; case (MDOC_Column): /* FALLTHROUGH */ case (MDOC_Diag): /* FALLTHROUGH */ + case (MDOC_Ohang): + /* FALLTHROUGH */ case (MDOC_Inset): /* FALLTHROUGH */ case (MDOC_Item): - if (-1 != width && ! mdoc_nwarn(mdoc, n, ENOWIDTH)) + if (width >= 0 && ! mdoc_nwarn(mdoc, n, ENOWIDTH)) return(0); break; default: @@ -688,6 +697,8 @@ pre_bd(PRE_ARGS) for (i = 0, err = type = 0; ! err && i < (int)n->args->argc; i++) switch (n->args->argv[i].arg) { + case (MDOC_Centred): + /* FALLTHROUGH */ case (MDOC_Ragged): /* FALLTHROUGH */ case (MDOC_Unfilled): @@ -695,8 +706,6 @@ pre_bd(PRE_ARGS) case (MDOC_Filled): /* FALLTHROUGH */ case (MDOC_Literal): - /* FALLTHROUGH */ - case (MDOC_File): if (0 == type++) break; return(mdoc_nerr(mdoc, n, EMULTIDISP)); @@ -799,6 +808,8 @@ static int pre_dt(PRE_ARGS) { + /* FIXME: make sure is capitalised. */ + if (0 == mdoc->meta.date || mdoc->meta.os) if ( ! mdoc_nwarn(mdoc, n, EPROLOOO)) return(0); @@ -880,6 +891,32 @@ post_lb(POST_ARGS) static int +post_vt(POST_ARGS) +{ + const struct mdoc_node *n; + + /* + * The Vt macro comes in both ELEM and BLOCK form, both of which + * have different syntaxes (yet more context-sensitive + * behaviour). ELEM types must have a child; BLOCK types, + * specifically the BODY, should only have TEXT children. + */ + + if (MDOC_ELEM == mdoc->last->type) + return(eerr_ge1(mdoc)); + if (MDOC_BODY != mdoc->last->type) + return(1); + + for (n = mdoc->last->child; n; n = n->next) + if (MDOC_TEXT != n->type) + if ( ! mdoc_nwarn(mdoc, n, EBADCHILD)) + return(0); + + return(1); +} + + +static int post_nm(POST_ARGS) { @@ -922,16 +959,6 @@ post_an(POST_ARGS) static int -post_args(POST_ARGS) -{ - - if (mdoc->last->args) - return(1); - return(mdoc_nerr(mdoc, mdoc->last, ELINE)); -} - - -static int post_it(POST_ARGS) { int type, i, cols; @@ -1085,14 +1112,19 @@ post_bl(POST_ARGS) if (NULL == mdoc->last->child) return(1); + /* + * We only allow certain children of `Bl'. This is usually on + * `It', but apparently `Sm' occurs here and there, so we let + * that one through, too. + */ + /* LINTED */ for (n = mdoc->last->child; n; n = n->next) { - if (MDOC_BLOCK == n->type) - if (MDOC_It == n->tok) - continue; - return(mdoc_verr(mdoc, n->line, n->pos, - "bad child of parent %s", - mdoc_macronames[mdoc->last->tok])); + if (MDOC_BLOCK == n->type && MDOC_It == n->tok) + continue; + if (MDOC_Sm == n->tok) + continue; + return(mdoc_nerr(mdoc, n, EBADCHILD)); } return(1); @@ -1140,43 +1172,58 @@ post_root(POST_ARGS) static int -post_sp(POST_ARGS) +post_st(POST_ARGS) { - long lval; - char *ep, *buf; - if (NULL == mdoc->last->child) + if (mdoc_a2st(mdoc->last->child->string)) return(1); - else if ( ! eerr_eq1(mdoc)) - return(0); - - assert(MDOC_TEXT == mdoc->last->child->type); - buf = mdoc->last->child->string; - assert(buf); - - /* From OpenBSD's strtol(3). */ - errno = 0; - lval = strtol(buf, &ep, 10); - if (buf[0] == '\0' || *ep != '\0') - return(mdoc_nerr(mdoc, mdoc->last->child, ENUMFMT)); - - if ((errno == ERANGE && (lval == LONG_MAX || lval == LONG_MIN)) || - (lval > INT_MAX || lval < 0)) - return(mdoc_nerr(mdoc, mdoc->last->child, ENUMFMT)); - - return(1); + return(mdoc_nerr(mdoc, mdoc->last, EBADSTAND)); } - - static int -post_st(POST_ARGS) +post_rs(POST_ARGS) { + struct mdoc_node *nn; - if (mdoc_a2st(mdoc->last->child->string)) + if (MDOC_BODY != mdoc->last->type) return(1); - return(mdoc_nerr(mdoc, mdoc->last, EBADSTAND)); + + for (nn = mdoc->last->child; nn; nn = nn->next) + switch (nn->tok) { + case(MDOC__U): + /* FALLTHROUGH */ + case(MDOC__Q): + /* FALLTHROUGH */ + case(MDOC__C): + /* FALLTHROUGH */ + case(MDOC__A): + /* FALLTHROUGH */ + case(MDOC__B): + /* FALLTHROUGH */ + case(MDOC__D): + /* FALLTHROUGH */ + case(MDOC__I): + /* FALLTHROUGH */ + case(MDOC__J): + /* FALLTHROUGH */ + case(MDOC__N): + /* FALLTHROUGH */ + case(MDOC__O): + /* FALLTHROUGH */ + case(MDOC__P): + /* FALLTHROUGH */ + case(MDOC__R): + /* FALLTHROUGH */ + case(MDOC__T): + /* FALLTHROUGH */ + case(MDOC__V): + break; + default: + return(mdoc_nerr(mdoc, nn, EBADCHILD)); + } + + return(1); }