=================================================================== RCS file: /cvs/mandoc/mdoc_validate.c,v retrieving revision 1.13 retrieving revision 1.22 diff -u -p -r1.13 -r1.22 --- mandoc/mdoc_validate.c 2009/06/17 11:02:06 1.13 +++ mandoc/mdoc_validate.c 2009/07/06 11:05:29 1.22 @@ -1,4 +1,4 @@ -/* $Id: mdoc_validate.c,v 1.13 2009/06/17 11:02:06 kristaps Exp $ */ +/* $Id: mdoc_validate.c,v 1.22 2009/07/06 11:05:29 kristaps Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons * @@ -23,6 +23,7 @@ #include #include "libmdoc.h" +#include "libmandoc.h" /* FIXME: .Bl -diag can't have non-text children in HEAD. */ /* TODO: ignoring Pp (it's superfluous in some invocations). */ @@ -46,32 +47,25 @@ enum merr { EMULTILIST, EARGREP, EBOOL, - ENESTDISP + ECOLMIS, + ENESTDISP, + ENOWIDTH, + EMISSWIDTH, + EWRONGMSEC, + ESECOOO, + ESECREP, + EBADSTAND, + ENAMESECINC, + ENOMULTILINE, + EMULTILINE, + ENOLINE, + EPROLOOO, + EPROLREP, + EARGVAL, + EBADSEC, + EBADMSEC }; -enum mwarn { - WPRINT, - WNOWIDTH, - WMISSWIDTH, - WESCAPE, - WDEPESC, - WDEPCOL, - WWRONGMSEC, - WSECOOO, - WSECREP, - WBADSTAND, - WNAMESECINC, - WNOMULTILINE, - WMULTILINE, - WLINE, - WNOLINE, - WPROLOOO, - WPROLREP, - WARGVAL, - WBADSEC, - WBADMSEC -}; - typedef int (*v_pre)(PRE_ARGS); typedef int (*v_post)(POST_ARGS); @@ -80,8 +74,7 @@ struct valids { v_post *post; }; -static int pwarn(struct mdoc *, int, int, enum mwarn); -static int perr(struct mdoc *, int, int, enum merr); +static int perr(struct mdoc *, int, int, enum merr, int); static int check_parent(PRE_ARGS, int, enum mdoc_type); static int check_msec(PRE_ARGS, ...); static int check_sec(PRE_ARGS, ...); @@ -98,7 +91,6 @@ static int err_child_gt(struct mdoc *, const char *, i static int warn_child_gt(struct mdoc *, const char *, int); static int err_child_eq(struct mdoc *, const char *, int); static int warn_child_eq(struct mdoc *, const char *, int); -static int count_child(struct mdoc *); static int warn_print(struct mdoc *, int, int); static int warn_count(struct mdoc *, const char *, int, const char *, int); @@ -138,6 +130,7 @@ static int post_args(POST_ARGS); static int post_at(POST_ARGS); static int post_bf(POST_ARGS); static int post_bl(POST_ARGS); +static int post_bl_head(POST_ARGS); static int post_it(POST_ARGS); static int post_nm(POST_ARGS); static int post_root(POST_ARGS); @@ -148,8 +141,8 @@ static int post_st(POST_ARGS); #define vwarn(m, t) nwarn((m), (m)->last, (t)) #define verr(m, t) nerr((m), (m)->last, (t)) -#define nwarn(m, n, t) pwarn((m), (n)->line, (n)->pos, (t)) -#define nerr(m, n, t) perr((m), (n)->line, (n)->pos, (t)) +#define nwarn(m, n, t) perr((m), (n)->line, (n)->pos, (t), 0) +#define nerr(m, n, t) perr((m), (n)->line, (n)->pos, (t), 1) static v_pre pres_an[] = { pre_an, NULL }; static v_pre pres_bd[] = { pre_display, pre_bd, NULL }; @@ -174,7 +167,7 @@ static v_post posts_wtext[] = { ewarn_ge1, NULL }; static v_post posts_notext[] = { eerr_eq0, NULL }; static v_post posts_wline[] = { bwarn_ge1, herr_eq0, NULL }; static v_post posts_sh[] = { herr_ge1, bwarn_ge1, post_sh, NULL }; -static v_post posts_bl[] = { herr_eq0, bwarn_ge1, post_bl, NULL }; +static v_post posts_bl[] = { bwarn_ge1, post_bl, NULL }; static v_post posts_it[] = { post_it, NULL }; static v_post posts_in[] = { ewarn_eq1, NULL }; static v_post posts_ss[] = { herr_ge1, NULL }; @@ -377,11 +370,12 @@ mdoc_valid_post(struct mdoc *mdoc) static int -perr(struct mdoc *m, int line, int pos, enum merr type) +perr(struct mdoc *m, int line, int pos, enum merr type, int iserr) { char *p; p = NULL; + switch (type) { case (ETOOLONG): p = "text argument too long"; @@ -425,106 +419,76 @@ perr(struct mdoc *m, int line, int pos, enum merr type case (ENODATA): p = "document has no data"; break; + case (ECOLMIS): + p = "column syntax style mismatch"; + break; case (EATT): p = "expected valid AT&T symbol"; break; case (ENAME): p = "default name not yet set"; break; - } - assert(p); - return(mdoc_perr(m, line, pos, p)); -} - - -static int -pwarn(struct mdoc *m, int line, int pos, enum mwarn type) -{ - char *p; - enum mdoc_warn c; - - c = WARN_SYNTAX; - p = NULL; - switch (type) { - case (WBADMSEC): - p = "inappropriate manual section"; - c = WARN_COMPAT; - break; - case (WBADSEC): - p = "inappropriate document section"; - c = WARN_COMPAT; - break; - case (WARGVAL): - p = "argument value suggested"; - c = WARN_COMPAT; - break; - case (WPROLREP): - p = "prologue macros repeated"; - c = WARN_COMPAT; - break; - case (WPROLOOO): - p = "prologue macros out-of-order"; - c = WARN_COMPAT; - break; - case (WDEPCOL): - p = "deprecated column argument syntax"; - c = WARN_COMPAT; - break; - case (WNOWIDTH): + case (ENOWIDTH): p = "superfluous width argument"; break; - case (WMISSWIDTH): + case (EMISSWIDTH): p = "missing width argument"; break; - case (WPRINT): - p = "invalid character"; + case (EWRONGMSEC): + p = "document section in wrong manual section"; break; - case (WESCAPE): - p = "invalid escape sequence"; + case (ESECOOO): + p = "document section out of conventional order"; break; - case (WDEPESC): - p = "deprecated special-character escape"; + case (ESECREP): + p = "document section repeated"; break; - case (WNOLINE): - p = "suggested no line arguments"; + case (EBADSTAND): + p = "unknown standard"; break; - case (WLINE): - p = "suggested line arguments"; + case (ENAMESECINC): + p = "NAME section contents incomplete/badly-ordered"; break; - case (WMULTILINE): + case (ENOMULTILINE): + p = "suggested no multi-line arguments"; + break; + case (EMULTILINE): p = "suggested multi-line arguments"; break; - case (WNOMULTILINE): - p = "suggested no multi-line arguments"; + case (ENOLINE): + p = "suggested no line arguments"; break; - case (WWRONGMSEC): - p = "document section in wrong manual section"; - c = WARN_COMPAT; + case (EPROLOOO): + p = "prologue macros out-of-order"; break; - case (WSECOOO): - p = "document section out of conventional order"; + case (EPROLREP): + p = "prologue macros repeated"; break; - case (WSECREP): - p = "document section repeated"; + case (EARGVAL): + p = "argument value suggested"; break; - case (WBADSTAND): - p = "unknown standard"; + case (EBADMSEC): + p = "inappropriate manual section"; break; - case (WNAMESECINC): - p = "NAME section contents incomplete/badly-ordered"; + case (EBADSEC): + p = "inappropriate document section"; break; } + assert(p); - return(mdoc_pwarn(m, line, pos, c, p)); + + if (iserr) + return(mdoc_perr(m, line, pos, p)); + + return(mdoc_pwarn(m, line, pos, p)); } static int warn_print(struct mdoc *m, int ln, int pos) { - if (MDOC_IGN_CHARS & m->pflags) - return(pwarn(m, ln, pos, WPRINT)); - return(perr(m, ln, pos, EPRINT)); + + return(perr(m, ln, pos, EPRINT, ! (MDOC_IGN_CHARS & m->pflags))); } @@ -533,8 +497,8 @@ warn_count(struct mdoc *m, const char *k, int want, const char *v, int has) { - return(mdoc_warn(m, WARN_SYNTAX, - "suggests %s %s %d (has %d)", v, k, want, has)); + return(mdoc_warn(m, "suggests %s %s %d (has %d)", + v, k, want, has)); } @@ -548,19 +512,6 @@ err_count(struct mdoc *m, const char *k, } -static inline int -count_child(struct mdoc *mdoc) -{ - int i; - struct mdoc_node *n; - - for (i = 0, n = mdoc->last->child; n; n = n->next, i++) - /* Do nothing */ ; - - return(i); -} - - /* * Build these up with macros because they're basically the same check * for different inequalities. Yes, this could be done with functions, @@ -571,10 +522,9 @@ count_child(struct mdoc *mdoc) static int \ lvl##_child_##name(struct mdoc *mdoc, const char *p, int sz) \ { \ - int i; \ - if ((i = count_child(mdoc)) ineq sz) \ + if (mdoc->last->nchild ineq sz) \ return(1); \ - return(lvl##_count(mdoc, #ineq, sz, p, i)); \ + return(lvl##_count(mdoc, #ineq, sz, p, mdoc->last->nchild)); \ } #define CHECK_BODY_DEFN(name, lvl, func, num) \ @@ -631,7 +581,7 @@ check_stdarg(PRE_ARGS) if (n->args && 1 == n->args->argc) if (MDOC_Std == n->args->argv[0].arg) return(1); - return(nwarn(mdoc, n, WARGVAL)); + return(nwarn(mdoc, n, EARGVAL)); } @@ -655,7 +605,7 @@ check_sec(PRE_ARGS, ...) } va_end(ap); - return(nwarn(mdoc, n, WBADSEC)); + return(nwarn(mdoc, n, EBADSEC)); } @@ -677,7 +627,7 @@ check_msec(PRE_ARGS, ...) } va_end(ap); - return(nwarn(mdoc, n, WBADMSEC)); + return(nwarn(mdoc, n, EBADMSEC)); } @@ -722,9 +672,9 @@ check_argv(struct mdoc *m, const struct mdoc_node *n, static int check_text(struct mdoc *mdoc, int line, int pos, const char *p) { - size_t c; + int c; - for ( ; *p; p++) { + for ( ; *p; p++, pos++) { if ('\t' == *p) { if ( ! (MDOC_LITERAL & mdoc->flags)) if ( ! warn_print(mdoc, line, pos)) @@ -736,18 +686,15 @@ check_text(struct mdoc *mdoc, int line, int pos, const if ('\\' != *p) continue; - c = mdoc_isescape(p); + c = mandoc_special(p); if (c) { - /* See if form is deprecated. */ - if ('*' == p[1]) - if ( ! pwarn(mdoc, line, pos, WDEPESC)) - return(0); - p += (int)c - 1; + p += c - 1; + pos += c - 1; continue; } if ( ! (MDOC_IGN_ESCAPE & mdoc->pflags)) - return(perr(mdoc, line, pos, EESCAPE)); - if ( ! pwarn(mdoc, line, pos, WESCAPE)) + return(perr(mdoc, line, pos, EESCAPE, 1)); + if ( ! perr(mdoc, line, pos, EESCAPE, 0)) return(0); } @@ -797,7 +744,7 @@ pre_display(PRE_ARGS) static int pre_bl(PRE_ARGS) { - int pos, col, type, width, offset; + int pos, type, width, offset; if (MDOC_BLOCK != n->type) return(1); @@ -806,7 +753,7 @@ pre_bl(PRE_ARGS) /* Make sure that only one type of list is specified. */ - type = offset = width = col = -1; + type = offset = width = -1; /* LINTED */ for (pos = 0; pos < (int)n->args->argc; pos++) @@ -835,7 +782,6 @@ pre_bl(PRE_ARGS) if (-1 != type) return(nerr(mdoc, n, EMULTILIST)); type = n->args->argv[pos].arg; - col = pos; break; case (MDOC_Width): if (-1 != width) @@ -862,7 +808,7 @@ pre_bl(PRE_ARGS) switch (type) { case (MDOC_Tag): - if (-1 == width && ! nwarn(mdoc, n, WMISSWIDTH)) + if (-1 == width && ! nwarn(mdoc, n, EMISSWIDTH)) return(0); break; case (MDOC_Column): @@ -872,29 +818,13 @@ pre_bl(PRE_ARGS) case (MDOC_Inset): /* FALLTHROUGH */ case (MDOC_Item): - if (-1 != width && ! nwarn(mdoc, n, WNOWIDTH)) + if (-1 != width && ! nwarn(mdoc, n, ENOWIDTH)) return(0); break; default: break; } - /* - * General validation of fields. - */ - - switch (type) { - case (MDOC_Column): - assert(col >= 0); - if (0 == n->args->argv[col].sz) - break; - if ( ! nwarn(mdoc, n, WDEPCOL)) - return(0); - break; - default: - break; - } - return(1); } @@ -1026,10 +956,10 @@ pre_dt(PRE_ARGS) { if (0 == mdoc->meta.date || mdoc->meta.os) - if ( ! nwarn(mdoc, n, WPROLOOO)) + if ( ! nwarn(mdoc, n, EPROLOOO)) return(0); if (mdoc->meta.title) - if ( ! nwarn(mdoc, n, WPROLREP)) + if ( ! nwarn(mdoc, n, EPROLREP)) return(0); return(1); } @@ -1040,10 +970,10 @@ pre_os(PRE_ARGS) { if (NULL == mdoc->meta.title || 0 == mdoc->meta.date) - if ( ! nwarn(mdoc, n, WPROLOOO)) + if ( ! nwarn(mdoc, n, EPROLOOO)) return(0); if (mdoc->meta.os) - if ( ! nwarn(mdoc, n, WPROLREP)) + if ( ! nwarn(mdoc, n, EPROLREP)) return(0); return(1); } @@ -1054,10 +984,10 @@ pre_dd(PRE_ARGS) { if (mdoc->meta.title || mdoc->meta.os) - if ( ! nwarn(mdoc, n, WPROLOOO)) + if ( ! nwarn(mdoc, n, EPROLOOO)) return(0); if (mdoc->meta.date) - if ( ! nwarn(mdoc, n, WPROLREP)) + if ( ! nwarn(mdoc, n, EPROLREP)) return(0); return(1); } @@ -1201,7 +1131,7 @@ post_it(POST_ARGS) switch (type) { case (MDOC_Tag): if (NULL == mdoc->last->head->child) - if ( ! vwarn(mdoc, WLINE)) + if ( ! vwarn(mdoc, ELINE)) return(0); break; case (MDOC_Hang): @@ -1212,10 +1142,10 @@ post_it(POST_ARGS) /* FALLTHROUGH */ case (MDOC_Diag): if (NULL == mdoc->last->head->child) - if ( ! vwarn(mdoc, WLINE)) + if ( ! vwarn(mdoc, ELINE)) return(0); if (NULL == mdoc->last->body->child) - if ( ! vwarn(mdoc, WMULTILINE)) + if ( ! vwarn(mdoc, EMULTILINE)) return(0); break; case (MDOC_Bullet): @@ -1228,18 +1158,18 @@ post_it(POST_ARGS) /* FALLTHROUGH */ case (MDOC_Item): if (mdoc->last->head->child) - if ( ! vwarn(mdoc, WNOLINE)) + if ( ! vwarn(mdoc, ENOLINE)) return(0); if (NULL == mdoc->last->body->child) - if ( ! vwarn(mdoc, WMULTILINE)) + if ( ! vwarn(mdoc, EMULTILINE)) return(0); break; case (MDOC_Column): if (NULL == mdoc->last->head->child) - if ( ! vwarn(mdoc, WLINE)) + if ( ! vwarn(mdoc, ELINE)) return(0); if (mdoc->last->body->child) - if ( ! vwarn(mdoc, WNOMULTILINE)) + if ( ! vwarn(mdoc, ENOMULTILINE)) return(0); c = mdoc->last->child; for (i = 0; c && MDOC_HEAD == c->type; c = c->next) @@ -1257,10 +1187,35 @@ post_it(POST_ARGS) static int +post_bl_head(POST_ARGS) +{ + int i; + const struct mdoc_node *n; + + n = mdoc->last->parent; + assert(n->args); + + for (i = 0; i < (int)n->args->argc; i++) + if (n->args->argv[i].arg == MDOC_Column) + break; + + if (i == (int)n->args->argc) + return(1); + + if (n->args->argv[i].sz && mdoc->last->child) + return(nerr(mdoc, n, ECOLMIS)); + + return(1); +} + + +static int post_bl(POST_ARGS) { struct mdoc_node *n; + if (MDOC_HEAD == mdoc->last->type) + return(post_bl_head(mdoc)); if (MDOC_BODY != mdoc->last->type) return(1); if (NULL == mdoc->last->child) @@ -1325,7 +1280,7 @@ post_st(POST_ARGS) if (mdoc_a2st(mdoc->last->child->string)) return(1); - return(vwarn(mdoc, WBADSTAND)); + return(vwarn(mdoc, EBADSTAND)); } @@ -1357,20 +1312,20 @@ post_sh_body(POST_ARGS) */ if (NULL == (n = mdoc->last->child)) - return(vwarn(mdoc, WNAMESECINC)); + return(vwarn(mdoc, ENAMESECINC)); for ( ; n && n->next; n = n->next) { if (MDOC_ELEM == n->type && MDOC_Nm == n->tok) continue; if (MDOC_TEXT == n->type) continue; - if ( ! vwarn(mdoc, WNAMESECINC)) + if ( ! vwarn(mdoc, ENAMESECINC)) return(0); } if (MDOC_ELEM == n->type && MDOC_Nd == n->tok) return(1); - return(vwarn(mdoc, WNAMESECINC)); + return(vwarn(mdoc, ENAMESECINC)); } @@ -1414,9 +1369,9 @@ post_sh_head(POST_ARGS) if (SEC_CUSTOM == sec) return(1); if (sec == mdoc->lastnamed) - return(vwarn(mdoc, WSECREP)); + return(vwarn(mdoc, ESECREP)); if (sec < mdoc->lastnamed) - return(vwarn(mdoc, WSECOOO)); + return(vwarn(mdoc, ESECOOO)); /* * Check particular section/manual conventions. LIBRARY can @@ -1431,7 +1386,7 @@ post_sh_head(POST_ARGS) case (3): break; default: - return(vwarn(mdoc, WWRONGMSEC)); + return(vwarn(mdoc, EWRONGMSEC)); } break; default: