version 1.321, 2017/04/28 16:25:11 |
version 1.343, 2017/06/25 17:43:45 |
Line 56 static void check_text(struct roff_man *, int, int, c |
|
Line 56 static void check_text(struct roff_man *, int, int, c |
|
static void check_argv(struct roff_man *, |
static void check_argv(struct roff_man *, |
struct roff_node *, struct mdoc_argv *); |
struct roff_node *, struct mdoc_argv *); |
static void check_args(struct roff_man *, struct roff_node *); |
static void check_args(struct roff_man *, struct roff_node *); |
|
static void check_toptext(struct roff_man *, int, int, const char *); |
static int child_an(const struct roff_node *); |
static int child_an(const struct roff_node *); |
static size_t macro2len(enum roff_tok); |
static size_t macro2len(enum roff_tok); |
static void rewrite_macro2len(char **); |
static void rewrite_macro2len(struct roff_man *, char **); |
|
static int similar(const char *, const char *); |
|
|
static void post_an(POST_ARGS); |
static void post_an(POST_ARGS); |
static void post_an_norm(POST_ARGS); |
static void post_an_norm(POST_ARGS); |
Line 74 static void post_bx(POST_ARGS); |
|
Line 76 static void post_bx(POST_ARGS); |
|
static void post_defaults(POST_ARGS); |
static void post_defaults(POST_ARGS); |
static void post_display(POST_ARGS); |
static void post_display(POST_ARGS); |
static void post_dd(POST_ARGS); |
static void post_dd(POST_ARGS); |
|
static void post_delim(POST_ARGS); |
static void post_dt(POST_ARGS); |
static void post_dt(POST_ARGS); |
static void post_en(POST_ARGS); |
static void post_en(POST_ARGS); |
static void post_es(POST_ARGS); |
static void post_es(POST_ARGS); |
Line 105 static void post_sh_authors(POST_ARGS); |
|
Line 108 static void post_sh_authors(POST_ARGS); |
|
static void post_sm(POST_ARGS); |
static void post_sm(POST_ARGS); |
static void post_st(POST_ARGS); |
static void post_st(POST_ARGS); |
static void post_std(POST_ARGS); |
static void post_std(POST_ARGS); |
|
static void post_useless(POST_ARGS); |
static void post_xr(POST_ARGS); |
static void post_xr(POST_ARGS); |
static void post_xx(POST_ARGS); |
static void post_xx(POST_ARGS); |
|
|
Line 122 static const v_post __mdoc_valids[MDOC_MAX - MDOC_Dd] |
|
Line 126 static const v_post __mdoc_valids[MDOC_MAX - MDOC_Dd] |
|
post_bl, /* Bl */ |
post_bl, /* Bl */ |
NULL, /* El */ |
NULL, /* El */ |
post_it, /* It */ |
post_it, /* It */ |
NULL, /* Ad */ |
post_delim, /* Ad */ |
post_an, /* An */ |
post_an, /* An */ |
NULL, /* Ap */ |
NULL, /* Ap */ |
post_defaults, /* Ar */ |
post_defaults, /* Ar */ |
NULL, /* Cd */ |
NULL, /* Cd */ |
NULL, /* Cm */ |
post_delim, /* Cm */ |
NULL, /* Dv */ |
post_delim, /* Dv */ |
NULL, /* Er */ |
post_delim, /* Er */ |
NULL, /* Ev */ |
post_delim, /* Ev */ |
post_ex, /* Ex */ |
post_ex, /* Ex */ |
post_fa, /* Fa */ |
post_fa, /* Fa */ |
NULL, /* Fd */ |
NULL, /* Fd */ |
NULL, /* Fl */ |
post_delim, /* Fl */ |
post_fn, /* Fn */ |
post_fn, /* Fn */ |
NULL, /* Ft */ |
post_delim, /* Ft */ |
NULL, /* Ic */ |
post_delim, /* Ic */ |
NULL, /* In */ |
post_delim, /* In */ |
post_defaults, /* Li */ |
post_defaults, /* Li */ |
post_nd, /* Nd */ |
post_nd, /* Nd */ |
post_nm, /* Nm */ |
post_nm, /* Nm */ |
NULL, /* Op */ |
post_delim, /* Op */ |
post_obsolete, /* Ot */ |
post_obsolete, /* Ot */ |
post_defaults, /* Pa */ |
post_defaults, /* Pa */ |
post_rv, /* Rv */ |
post_rv, /* Rv */ |
post_st, /* St */ |
post_st, /* St */ |
NULL, /* Va */ |
post_delim, /* Va */ |
NULL, /* Vt */ |
post_delim, /* Vt */ |
post_xr, /* Xr */ |
post_xr, /* Xr */ |
NULL, /* %A */ |
NULL, /* %A */ |
post_hyph, /* %B */ /* FIXME: can be used outside Rs/Re. */ |
post_hyph, /* %B */ /* FIXME: can be used outside Rs/Re. */ |
Line 162 static const v_post __mdoc_valids[MDOC_MAX - MDOC_Dd] |
|
Line 166 static const v_post __mdoc_valids[MDOC_MAX - MDOC_Dd] |
|
post_hyph, /* %T */ /* FIXME: can be used outside Rs/Re. */ |
post_hyph, /* %T */ /* FIXME: can be used outside Rs/Re. */ |
NULL, /* %V */ |
NULL, /* %V */ |
NULL, /* Ac */ |
NULL, /* Ac */ |
NULL, /* Ao */ |
post_delim, /* Ao */ |
NULL, /* Aq */ |
post_delim, /* Aq */ |
post_at, /* At */ |
post_at, /* At */ |
NULL, /* Bc */ |
NULL, /* Bc */ |
post_bf, /* Bf */ |
post_bf, /* Bf */ |
NULL, /* Bo */ |
post_delim, /* Bo */ |
NULL, /* Bq */ |
NULL, /* Bq */ |
post_xx, /* Bsx */ |
post_xx, /* Bsx */ |
post_bx, /* Bx */ |
post_bx, /* Bx */ |
Line 177 static const v_post __mdoc_valids[MDOC_MAX - MDOC_Dd] |
|
Line 181 static const v_post __mdoc_valids[MDOC_MAX - MDOC_Dd] |
|
NULL, /* Dq */ |
NULL, /* Dq */ |
NULL, /* Ec */ |
NULL, /* Ec */ |
NULL, /* Ef */ |
NULL, /* Ef */ |
NULL, /* Em */ |
post_delim, /* Em */ |
NULL, /* Eo */ |
NULL, /* Eo */ |
post_xx, /* Fx */ |
post_xx, /* Fx */ |
NULL, /* Ms */ |
post_delim, /* Ms */ |
NULL, /* No */ |
NULL, /* No */ |
post_ns, /* Ns */ |
post_ns, /* Ns */ |
post_xx, /* Nx */ |
post_xx, /* Nx */ |
post_xx, /* Ox */ |
post_xx, /* Ox */ |
NULL, /* Pc */ |
NULL, /* Pc */ |
NULL, /* Pf */ |
NULL, /* Pf */ |
NULL, /* Po */ |
post_delim, /* Po */ |
NULL, /* Pq */ |
post_delim, /* Pq */ |
NULL, /* Qc */ |
NULL, /* Qc */ |
NULL, /* Ql */ |
post_delim, /* Ql */ |
NULL, /* Qo */ |
post_delim, /* Qo */ |
NULL, /* Qq */ |
post_delim, /* Qq */ |
NULL, /* Re */ |
NULL, /* Re */ |
post_rs, /* Rs */ |
post_rs, /* Rs */ |
NULL, /* Sc */ |
NULL, /* Sc */ |
NULL, /* So */ |
post_delim, /* So */ |
NULL, /* Sq */ |
post_delim, /* Sq */ |
post_sm, /* Sm */ |
post_sm, /* Sm */ |
post_hyph, /* Sx */ |
post_hyph, /* Sx */ |
NULL, /* Sy */ |
post_delim, /* Sy */ |
NULL, /* Tn */ |
post_useless, /* Tn */ |
post_xx, /* Ux */ |
post_xx, /* Ux */ |
NULL, /* Xc */ |
NULL, /* Xc */ |
NULL, /* Xo */ |
NULL, /* Xo */ |
post_fo, /* Fo */ |
post_fo, /* Fo */ |
NULL, /* Fc */ |
NULL, /* Fc */ |
NULL, /* Oo */ |
post_delim, /* Oo */ |
NULL, /* Oc */ |
NULL, /* Oc */ |
post_bk, /* Bk */ |
post_bk, /* Bk */ |
NULL, /* Ek */ |
NULL, /* Ek */ |
post_eoln, /* Bt */ |
post_eoln, /* Bt */ |
NULL, /* Hf */ |
post_obsolete, /* Hf */ |
post_obsolete, /* Fr */ |
post_obsolete, /* Fr */ |
post_eoln, /* Ud */ |
post_eoln, /* Ud */ |
post_lb, /* Lb */ |
post_lb, /* Lb */ |
post_par, /* Lp */ |
post_par, /* Lp */ |
NULL, /* Lk */ |
post_delim, /* Lk */ |
post_defaults, /* Mt */ |
post_defaults, /* Mt */ |
NULL, /* Brq */ |
post_delim, /* Brq */ |
NULL, /* Bro */ |
post_delim, /* Bro */ |
NULL, /* Brc */ |
NULL, /* Brc */ |
NULL, /* %C */ |
NULL, /* %C */ |
post_es, /* Es */ |
post_es, /* Es */ |
post_en, /* En */ |
post_en, /* En */ |
post_xx, /* Dx */ |
post_xx, /* Dx */ |
NULL, /* %Q */ |
NULL, /* %Q */ |
post_par, /* br */ |
|
post_par, /* sp */ |
|
NULL, /* %U */ |
NULL, /* %U */ |
NULL, /* Ta */ |
NULL, /* Ta */ |
NULL, /* ll */ |
|
}; |
}; |
static const v_post *const mdoc_valids = __mdoc_valids - MDOC_Dd; |
static const v_post *const mdoc_valids = __mdoc_valids - MDOC_Dd; |
|
|
Line 304 mdoc_node_validate(struct roff_man *mdoc) |
|
Line 305 mdoc_node_validate(struct roff_man *mdoc) |
|
if (n->sec != SEC_SYNOPSIS || |
if (n->sec != SEC_SYNOPSIS || |
(n->parent->tok != MDOC_Cd && n->parent->tok != MDOC_Fd)) |
(n->parent->tok != MDOC_Cd && n->parent->tok != MDOC_Fd)) |
check_text(mdoc, n->line, n->pos, n->string); |
check_text(mdoc, n->line, n->pos, n->string); |
|
if (n->parent->tok == MDOC_It || |
|
(n->parent->type == ROFFT_BODY && |
|
(n->parent->tok == MDOC_Sh || |
|
n->parent->tok == MDOC_Ss))) |
|
check_toptext(mdoc, n->line, n->pos, n->string); |
break; |
break; |
case ROFFT_EQN: |
case ROFFT_EQN: |
case ROFFT_TBL: |
case ROFFT_TBL: |
Line 327 mdoc_node_validate(struct roff_man *mdoc) |
|
Line 333 mdoc_node_validate(struct roff_man *mdoc) |
|
|
|
/* Call the macro's postprocessor. */ |
/* Call the macro's postprocessor. */ |
|
|
|
if (n->tok < ROFF_MAX) { |
|
switch(n->tok) { |
|
case ROFF_br: |
|
case ROFF_sp: |
|
post_par(mdoc); |
|
break; |
|
default: |
|
roff_validate(mdoc); |
|
break; |
|
} |
|
break; |
|
} |
|
|
|
assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX); |
p = mdoc_valids + n->tok; |
p = mdoc_valids + n->tok; |
if (*p) |
if (*p) |
(*p)(mdoc); |
(*p)(mdoc); |
Line 372 check_text(struct roff_man *mdoc, int ln, int pos, cha |
|
Line 392 check_text(struct roff_man *mdoc, int ln, int pos, cha |
|
} |
} |
|
|
static void |
static void |
|
check_toptext(struct roff_man *mdoc, int ln, int pos, const char *p) |
|
{ |
|
const char *cp, *cpr; |
|
|
|
if (*p == '\0') |
|
return; |
|
|
|
if ((cp = strstr(p, "OpenBSD")) != NULL) |
|
mandoc_msg(MANDOCERR_BX, mdoc->parse, |
|
ln, pos + (cp - p), "Ox"); |
|
if ((cp = strstr(p, "NetBSD")) != NULL) |
|
mandoc_msg(MANDOCERR_BX, mdoc->parse, |
|
ln, pos + (cp - p), "Nx"); |
|
if ((cp = strstr(p, "FreeBSD")) != NULL) |
|
mandoc_msg(MANDOCERR_BX, mdoc->parse, |
|
ln, pos + (cp - p), "Fx"); |
|
if ((cp = strstr(p, "DragonFly")) != NULL) |
|
mandoc_msg(MANDOCERR_BX, mdoc->parse, |
|
ln, pos + (cp - p), "Dx"); |
|
|
|
cp = p; |
|
while ((cp = strstr(cp + 1, "()")) != NULL) { |
|
for (cpr = cp - 1; cpr >= p; cpr--) |
|
if (*cpr != '_' && !isalnum((unsigned char)*cpr)) |
|
break; |
|
if ((cpr < p || *cpr == ' ') && cpr + 1 < cp) { |
|
cpr++; |
|
mandoc_vmsg(MANDOCERR_FUNC, mdoc->parse, |
|
ln, pos + (cpr - p), |
|
"%.*s()", (int)(cp - cpr), cpr); |
|
} |
|
} |
|
} |
|
|
|
static void |
|
post_delim(POST_ARGS) |
|
{ |
|
const struct roff_node *nch; |
|
const char *lc, *cp; |
|
int nw; |
|
enum mdelim delim; |
|
enum roff_tok tok; |
|
|
|
/* |
|
* Find candidates: at least two bytes, |
|
* the last one a closing or middle delimiter. |
|
*/ |
|
|
|
tok = mdoc->last->tok; |
|
nch = mdoc->last->last; |
|
if (nch == NULL || nch->type != ROFFT_TEXT) |
|
return; |
|
lc = strchr(nch->string, '\0') - 1; |
|
if (lc <= nch->string) |
|
return; |
|
delim = mdoc_isdelim(lc); |
|
if (delim == DELIM_NONE || delim == DELIM_OPEN) |
|
return; |
|
|
|
/* |
|
* Reduce false positives by allowing various cases. |
|
*/ |
|
|
|
/* Escaped delimiters. */ |
|
if (lc > nch->string + 1 && lc[-2] == '\\' && |
|
(lc[-1] == '&' || lc[-1] == 'e')) |
|
return; |
|
|
|
/* Specific byte sequences. */ |
|
switch (*lc) { |
|
case ')': |
|
for (cp = lc; cp >= nch->string; cp--) |
|
if (*cp == '(') |
|
return; |
|
break; |
|
case '.': |
|
if (lc > nch->string + 1 && lc[-2] == '.' && lc[-1] == '.') |
|
return; |
|
if (lc[-1] == '.') |
|
return; |
|
break; |
|
case ';': |
|
if (tok == MDOC_Vt) |
|
return; |
|
break; |
|
case '?': |
|
if (lc[-1] == '?') |
|
return; |
|
break; |
|
case ']': |
|
for (cp = lc; cp >= nch->string; cp--) |
|
if (*cp == '[') |
|
return; |
|
break; |
|
case '|': |
|
if (lc == nch->string + 1 && lc[-1] == '|') |
|
return; |
|
default: |
|
break; |
|
} |
|
|
|
/* Exactly two non-alphanumeric bytes. */ |
|
if (lc == nch->string + 1 && !isalnum((unsigned char)lc[-1])) |
|
return; |
|
|
|
/* At least three alphabetic words with a sentence ending. */ |
|
if (strchr("!.:?", *lc) != NULL && (tok == MDOC_Em || |
|
tok == MDOC_Li || tok == MDOC_Po || tok == MDOC_Pq || |
|
tok == MDOC_Sy)) { |
|
nw = 0; |
|
for (cp = lc - 1; cp >= nch->string; cp--) { |
|
if (*cp == ' ') { |
|
nw++; |
|
if (cp > nch->string && cp[-1] == ',') |
|
cp--; |
|
} else if (isalpha((unsigned int)*cp)) { |
|
if (nw > 1) |
|
return; |
|
} else |
|
break; |
|
} |
|
} |
|
|
|
mandoc_vmsg(MANDOCERR_DELIM, mdoc->parse, |
|
nch->line, nch->pos + (lc - nch->string), |
|
"%s%s %s", roff_name[tok], |
|
nch == mdoc->last->child ? "" : " ...", nch->string); |
|
} |
|
|
|
static void |
post_bl_norm(POST_ARGS) |
post_bl_norm(POST_ARGS) |
{ |
{ |
struct roff_node *n; |
struct roff_node *n; |
Line 451 post_bl_norm(POST_ARGS) |
|
Line 601 post_bl_norm(POST_ARGS) |
|
mdoc->parse, argv->line, |
mdoc->parse, argv->line, |
argv->pos, "Bl -width %s", |
argv->pos, "Bl -width %s", |
argv->value[0]); |
argv->value[0]); |
rewrite_macro2len(argv->value); |
rewrite_macro2len(mdoc, argv->value); |
n->norm->Bl.width = argv->value[0]; |
n->norm->Bl.width = argv->value[0]; |
break; |
break; |
case MDOC_Offset: |
case MDOC_Offset: |
Line 466 post_bl_norm(POST_ARGS) |
|
Line 616 post_bl_norm(POST_ARGS) |
|
mdoc->parse, argv->line, |
mdoc->parse, argv->line, |
argv->pos, "Bl -offset %s", |
argv->pos, "Bl -offset %s", |
argv->value[0]); |
argv->value[0]); |
rewrite_macro2len(argv->value); |
rewrite_macro2len(mdoc, argv->value); |
n->norm->Bl.offs = argv->value[0]; |
n->norm->Bl.offs = argv->value[0]; |
break; |
break; |
default: |
default: |
Line 593 post_bd(POST_ARGS) |
|
Line 743 post_bd(POST_ARGS) |
|
mdoc->parse, argv->line, |
mdoc->parse, argv->line, |
argv->pos, "Bd -offset %s", |
argv->pos, "Bd -offset %s", |
argv->value[0]); |
argv->value[0]); |
rewrite_macro2len(argv->value); |
rewrite_macro2len(mdoc, argv->value); |
n->norm->Bd.offs = argv->value[0]; |
n->norm->Bd.offs = argv->value[0]; |
break; |
break; |
case MDOC_Compact: |
case MDOC_Compact: |
Line 660 post_eoln(POST_ARGS) |
|
Line 810 post_eoln(POST_ARGS) |
|
{ |
{ |
struct roff_node *n; |
struct roff_node *n; |
|
|
|
post_useless(mdoc); |
n = mdoc->last; |
n = mdoc->last; |
if (n->child != NULL) |
if (n->child != NULL) |
mandoc_vmsg(MANDOCERR_ARG_SKIP, mdoc->parse, n->line, |
mandoc_vmsg(MANDOCERR_ARG_SKIP, mdoc->parse, n->line, |
Line 745 post_lb(POST_ARGS) |
|
Line 896 post_lb(POST_ARGS) |
|
struct roff_node *n; |
struct roff_node *n; |
const char *p; |
const char *p; |
|
|
|
post_delim(mdoc); |
|
|
n = mdoc->last; |
n = mdoc->last; |
assert(n->child->type == ROFFT_TEXT); |
assert(n->child->type == ROFFT_TEXT); |
mdoc->next = ROFF_NEXT_CHILD; |
mdoc->next = ROFF_NEXT_CHILD; |
Line 757 post_lb(POST_ARGS) |
|
Line 910 post_lb(POST_ARGS) |
|
return; |
return; |
} |
} |
|
|
|
mandoc_vmsg(MANDOCERR_LB_BAD, mdoc->parse, n->child->line, |
|
n->child->pos, "Lb %s", n->child->string); |
|
|
roff_word_alloc(mdoc, n->line, n->pos, "library"); |
roff_word_alloc(mdoc, n->line, n->pos, "library"); |
mdoc->last->flags = NODE_NOSRC; |
mdoc->last->flags = NODE_NOSRC; |
roff_word_alloc(mdoc, n->line, n->pos, "\\(Lq"); |
roff_word_alloc(mdoc, n->line, n->pos, "\\(Lq"); |
Line 855 post_obsolete(POST_ARGS) |
|
Line 1011 post_obsolete(POST_ARGS) |
|
n->line, n->pos, roff_name[n->tok]); |
n->line, n->pos, roff_name[n->tok]); |
} |
} |
|
|
|
static void |
|
post_useless(POST_ARGS) |
|
{ |
|
struct roff_node *n; |
|
|
|
n = mdoc->last; |
|
mandoc_msg(MANDOCERR_MACRO_USELESS, mdoc->parse, |
|
n->line, n->pos, roff_name[n->tok]); |
|
} |
|
|
/* |
/* |
* Block macros. |
* Block macros. |
*/ |
*/ |
Line 992 post_fa(POST_ARGS) |
|
Line 1158 post_fa(POST_ARGS) |
|
break; |
break; |
} |
} |
} |
} |
|
post_delim(mdoc); |
} |
} |
|
|
static void |
static void |
Line 1014 post_nm(POST_ARGS) |
|
Line 1181 post_nm(POST_ARGS) |
|
mandoc_msg(MANDOCERR_NM_NONAME, mdoc->parse, |
mandoc_msg(MANDOCERR_NM_NONAME, mdoc->parse, |
n->line, n->pos, "Nm"); |
n->line, n->pos, "Nm"); |
|
|
|
if (n->type == ROFFT_ELEM) |
|
post_delim(mdoc); |
|
|
if ((n->type != ROFFT_ELEM && n->type != ROFFT_HEAD) || |
if ((n->type != ROFFT_ELEM && n->type != ROFFT_HEAD) || |
(n->child != NULL && n->child->type == ROFFT_TEXT) || |
(n->child != NULL && n->child->type == ROFFT_TEXT) || |
mdoc->meta.name == NULL) |
mdoc->meta.name == NULL) |
|
|
post_nd(POST_ARGS) |
post_nd(POST_ARGS) |
{ |
{ |
struct roff_node *n; |
struct roff_node *n; |
|
size_t sz; |
|
|
n = mdoc->last; |
n = mdoc->last; |
|
|
Line 1042 post_nd(POST_ARGS) |
|
Line 1213 post_nd(POST_ARGS) |
|
if (n->child == NULL) |
if (n->child == NULL) |
mandoc_msg(MANDOCERR_ND_EMPTY, mdoc->parse, |
mandoc_msg(MANDOCERR_ND_EMPTY, mdoc->parse, |
n->line, n->pos, "Nd"); |
n->line, n->pos, "Nd"); |
|
else if (n->last->type == ROFFT_TEXT && |
|
(sz = strlen(n->last->string)) != 0 && |
|
n->last->string[sz - 1] == '.') |
|
mandoc_msg(MANDOCERR_ND_DOT, mdoc->parse, |
|
n->last->line, n->last->pos + sz - 1, NULL); |
|
|
post_hyph(mdoc); |
post_hyph(mdoc); |
} |
} |
Line 1098 post_defaults(POST_ARGS) |
|
Line 1274 post_defaults(POST_ARGS) |
|
{ |
{ |
struct roff_node *nn; |
struct roff_node *nn; |
|
|
|
if (mdoc->last->child != NULL) { |
|
post_delim(mdoc); |
|
return; |
|
} |
|
|
/* |
/* |
* The `Ar' defaults to "file ..." if no value is provided as an |
* The `Ar' defaults to "file ..." if no value is provided as an |
* argument; the `Mt' and `Pa' macros use "~"; the `Li' just |
* argument; the `Mt' and `Pa' macros use "~"; the `Li' just |
* gets an empty string. |
* gets an empty string. |
*/ |
*/ |
|
|
if (mdoc->last->child != NULL) |
|
return; |
|
|
|
nn = mdoc->last; |
nn = mdoc->last; |
|
|
switch (nn->tok) { |
switch (nn->tok) { |
case MDOC_Ar: |
case MDOC_Ar: |
mdoc->next = ROFF_NEXT_CHILD; |
mdoc->next = ROFF_NEXT_CHILD; |
Line 1172 post_an(POST_ARGS) |
|
Line 1349 post_an(POST_ARGS) |
|
if (nch == NULL) |
if (nch == NULL) |
mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, |
mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, |
np->line, np->pos, "An"); |
np->line, np->pos, "An"); |
|
else |
|
post_delim(mdoc); |
} else if (nch != NULL) |
} else if (nch != NULL) |
mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, |
mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, |
nch->line, nch->pos, "An ... %s", nch->string); |
nch->line, nch->pos, "An ... %s", nch->string); |
Line 1200 post_xx(POST_ARGS) |
|
Line 1379 post_xx(POST_ARGS) |
|
struct roff_node *n; |
struct roff_node *n; |
const char *os; |
const char *os; |
|
|
|
post_delim(mdoc); |
|
|
n = mdoc->last; |
n = mdoc->last; |
switch (n->tok) { |
switch (n->tok) { |
case MDOC_Bsx: |
case MDOC_Bsx: |
Line 1310 post_bl_block(POST_ARGS) |
|
Line 1491 post_bl_block(POST_ARGS) |
|
switch (nc->tok) { |
switch (nc->tok) { |
case MDOC_Pp: |
case MDOC_Pp: |
case MDOC_Lp: |
case MDOC_Lp: |
case MDOC_br: |
case ROFF_br: |
break; |
break; |
default: |
default: |
nc = NULL; |
nc = NULL; |
Line 1338 post_bl_block(POST_ARGS) |
|
Line 1519 post_bl_block(POST_ARGS) |
|
* If the argument of -offset or -width is a macro, |
* If the argument of -offset or -width is a macro, |
* replace it with the associated default width. |
* replace it with the associated default width. |
*/ |
*/ |
void |
static void |
rewrite_macro2len(char **arg) |
rewrite_macro2len(struct roff_man *mdoc, char **arg) |
{ |
{ |
size_t width; |
size_t width; |
enum roff_tok tok; |
enum roff_tok tok; |
Line 1348 rewrite_macro2len(char **arg) |
|
Line 1529 rewrite_macro2len(char **arg) |
|
return; |
return; |
else if ( ! strcmp(*arg, "Ds")) |
else if ( ! strcmp(*arg, "Ds")) |
width = 6; |
width = 6; |
else if ((tok = mdoc_hash_find(*arg)) == TOKEN_NONE) |
else if ((tok = roffhash_find(mdoc->mdocmac, *arg, 0)) == TOKEN_NONE) |
return; |
return; |
else |
else |
width = macro2len(tok); |
width = macro2len(tok); |
Line 1426 post_bl(POST_ARGS) |
|
Line 1607 post_bl(POST_ARGS) |
|
struct roff_node *nparent, *nprev; /* of the Bl block */ |
struct roff_node *nparent, *nprev; /* of the Bl block */ |
struct roff_node *nblock, *nbody; /* of the Bl */ |
struct roff_node *nblock, *nbody; /* of the Bl */ |
struct roff_node *nchild, *nnext; /* of the Bl body */ |
struct roff_node *nchild, *nnext; /* of the Bl body */ |
|
const char *prev_Er; |
|
int order; |
|
|
nbody = mdoc->last; |
nbody = mdoc->last; |
switch (nbody->type) { |
switch (nbody->type) { |
Line 1526 post_bl(POST_ARGS) |
|
Line 1709 post_bl(POST_ARGS) |
|
|
|
nchild = nnext; |
nchild = nnext; |
} |
} |
|
|
|
if (mdoc->meta.os_e != MANDOC_OS_NETBSD) |
|
return; |
|
|
|
prev_Er = NULL; |
|
for (nchild = nbody->child; nchild != NULL; nchild = nchild->next) { |
|
if (nchild->tok != MDOC_It) |
|
continue; |
|
if ((nnext = nchild->head->child) == NULL) |
|
continue; |
|
if (nnext->type == ROFFT_BLOCK) |
|
nnext = nnext->body->child; |
|
if (nnext == NULL || nnext->tok != MDOC_Er) |
|
continue; |
|
nnext = nnext->child; |
|
if (prev_Er != NULL) { |
|
order = strcmp(prev_Er, nnext->string); |
|
if (order > 0) |
|
mandoc_vmsg(MANDOCERR_ER_ORDER, |
|
mdoc->parse, nnext->line, nnext->pos, |
|
"Er %s %s (NetBSD)", |
|
prev_Er, nnext->string); |
|
else if (order == 0) |
|
mandoc_vmsg(MANDOCERR_ER_REP, |
|
mdoc->parse, nnext->line, nnext->pos, |
|
"Er %s (NetBSD)", prev_Er); |
|
} |
|
prev_Er = nnext->string; |
|
} |
} |
} |
|
|
static void |
static void |
Line 1575 post_sm(POST_ARGS) |
|
Line 1787 post_sm(POST_ARGS) |
|
static void |
static void |
post_root(POST_ARGS) |
post_root(POST_ARGS) |
{ |
{ |
|
const char *openbsd_arch[] = { |
|
"alpha", "amd64", "arm64", "armv7", "hppa", "i386", |
|
"landisk", "loongson", "luna88k", "macppc", "mips64", |
|
"octeon", "sgi", "socppc", "sparc64", NULL |
|
}; |
|
const char *netbsd_arch[] = { |
|
"acorn26", "acorn32", "algor", "alpha", "amiga", |
|
"arc", "atari", |
|
"bebox", "cats", "cesfic", "cobalt", "dreamcast", |
|
"emips", "evbarm", "evbmips", "evbppc", "evbsh3", "evbsh5", |
|
"hp300", "hpcarm", "hpcmips", "hpcsh", "hppa", |
|
"i386", "ibmnws", "luna68k", |
|
"mac68k", "macppc", "mipsco", "mmeye", "mvme68k", "mvmeppc", |
|
"netwinder", "news68k", "newsmips", "next68k", |
|
"pc532", "playstation2", "pmax", "pmppc", "prep", |
|
"sandpoint", "sbmips", "sgimips", "shark", |
|
"sparc", "sparc64", "sun2", "sun3", |
|
"vax", "walnut", "x68k", "x86", "x86_64", "xen", NULL |
|
}; |
|
const char **arches[] = { NULL, netbsd_arch, openbsd_arch }; |
|
|
struct roff_node *n; |
struct roff_node *n; |
|
const char **arch; |
|
|
/* Add missing prologue data. */ |
/* Add missing prologue data. */ |
|
|
if (mdoc->meta.date == NULL) |
if (mdoc->meta.date == NULL) |
mdoc->meta.date = mdoc->quick ? |
mdoc->meta.date = mdoc->quick ? mandoc_strdup("") : |
mandoc_strdup("") : |
mandoc_normdate(mdoc, NULL, 0, 0); |
mandoc_normdate(mdoc->parse, NULL, 0, 0); |
|
|
|
if (mdoc->meta.title == NULL) { |
if (mdoc->meta.title == NULL) { |
mandoc_msg(MANDOCERR_DT_NOTITLE, |
mandoc_msg(MANDOCERR_DT_NOTITLE, |
Line 1597 post_root(POST_ARGS) |
|
Line 1830 post_root(POST_ARGS) |
|
mandoc_msg(MANDOCERR_OS_MISSING, |
mandoc_msg(MANDOCERR_OS_MISSING, |
mdoc->parse, 0, 0, NULL); |
mdoc->parse, 0, 0, NULL); |
mdoc->meta.os = mandoc_strdup(""); |
mdoc->meta.os = mandoc_strdup(""); |
|
} else if (mdoc->meta.os_e && |
|
(mdoc->meta.rcsids & (1 << mdoc->meta.os_e)) == 0) |
|
mandoc_msg(MANDOCERR_RCS_MISSING, mdoc->parse, 0, 0, |
|
mdoc->meta.os_e == MANDOC_OS_OPENBSD ? |
|
"(OpenBSD)" : "(NetBSD)"); |
|
|
|
if (mdoc->meta.arch != NULL && |
|
(arch = arches[mdoc->meta.os_e]) != NULL) { |
|
while (*arch != NULL && strcmp(*arch, mdoc->meta.arch)) |
|
arch++; |
|
if (*arch == NULL) { |
|
n = mdoc->first->child; |
|
while (n->tok != MDOC_Dt) |
|
n = n->next; |
|
n = n->child->next->next; |
|
mandoc_vmsg(MANDOCERR_ARCH_BAD, |
|
mdoc->parse, n->line, n->pos, |
|
"Dt ... %s %s", mdoc->meta.arch, |
|
mdoc->meta.os_e == MANDOC_OS_OPENBSD ? |
|
"(OpenBSD)" : "(NetBSD)"); |
|
} |
} |
} |
|
|
/* Check that we begin with a proper `Sh'. */ |
/* Check that we begin with a proper `Sh'. */ |
Line 1868 post_sh_see_also(POST_ARGS) |
|
Line 2122 post_sh_see_also(POST_ARGS) |
|
if (isalpha((const unsigned char)*name)) |
if (isalpha((const unsigned char)*name)) |
return; |
return; |
lastpunct = n->string; |
lastpunct = n->string; |
if (n->next == NULL) |
if (n->next == NULL || n->next->tok == MDOC_Rs) |
mandoc_vmsg(MANDOCERR_XR_PUNCT, mdoc->parse, |
mandoc_vmsg(MANDOCERR_XR_PUNCT, mdoc->parse, |
n->line, n->pos, "%s after %s(%s)", |
n->line, n->pos, "%s after %s(%s)", |
lastpunct, lastname, lastsec); |
lastpunct, lastname, lastsec); |
Line 1895 post_sh_authors(POST_ARGS) |
|
Line 2149 post_sh_authors(POST_ARGS) |
|
mdoc->last->line, mdoc->last->pos, NULL); |
mdoc->last->line, mdoc->last->pos, NULL); |
} |
} |
|
|
|
/* |
|
* Return an upper bound for the string distance (allowing |
|
* transpositions). Not a full Levenshtein implementation |
|
* because Levenshtein is quadratic in the string length |
|
* and this function is called for every standard name, |
|
* so the check for each custom name would be cubic. |
|
* The following crude heuristics is linear, resulting |
|
* in quadratic behaviour for checking one custom name, |
|
* which does not cause measurable slowdown. |
|
*/ |
|
static int |
|
similar(const char *s1, const char *s2) |
|
{ |
|
const int maxdist = 3; |
|
int dist = 0; |
|
|
|
while (s1[0] != '\0' && s2[0] != '\0') { |
|
if (s1[0] == s2[0]) { |
|
s1++; |
|
s2++; |
|
continue; |
|
} |
|
if (++dist > maxdist) |
|
return INT_MAX; |
|
if (s1[1] == s2[1]) { /* replacement */ |
|
s1++; |
|
s2++; |
|
} else if (s1[0] == s2[1] && s1[1] == s2[0]) { |
|
s1 += 2; /* transposition */ |
|
s2 += 2; |
|
} else if (s1[0] == s2[1]) /* insertion */ |
|
s2++; |
|
else if (s1[1] == s2[0]) /* deletion */ |
|
s1++; |
|
else |
|
return INT_MAX; |
|
} |
|
dist += strlen(s1) + strlen(s2); |
|
return dist > maxdist ? INT_MAX : dist; |
|
} |
|
|
static void |
static void |
post_sh_head(POST_ARGS) |
post_sh_head(POST_ARGS) |
{ |
{ |
struct roff_node *nch; |
struct roff_node *nch; |
const char *goodsec; |
const char *goodsec; |
|
const char *const *testsec; |
|
int dist, mindist; |
enum roff_sec sec; |
enum roff_sec sec; |
|
|
/* |
/* |
Line 1937 post_sh_head(POST_ARGS) |
|
Line 2234 post_sh_head(POST_ARGS) |
|
|
|
/* We don't care about custom sections after this. */ |
/* We don't care about custom sections after this. */ |
|
|
if (sec == SEC_CUSTOM) |
if (sec == SEC_CUSTOM) { |
|
if ((nch = mdoc->last->child) == NULL || |
|
nch->type != ROFFT_TEXT || nch->next != NULL) |
|
return; |
|
goodsec = NULL; |
|
mindist = INT_MAX; |
|
for (testsec = secnames + 1; *testsec != NULL; testsec++) { |
|
dist = similar(nch->string, *testsec); |
|
if (dist < mindist) { |
|
goodsec = *testsec; |
|
mindist = dist; |
|
} |
|
} |
|
if (goodsec != NULL) |
|
mandoc_vmsg(MANDOCERR_SEC_TYPO, mdoc->parse, |
|
nch->line, nch->pos, "Sh %s instead of %s", |
|
nch->string, goodsec); |
return; |
return; |
|
} |
|
|
/* |
/* |
* Check whether our non-custom section is being repeated or is |
* Check whether our non-custom section is being repeated or is |
Line 2004 post_xr(POST_ARGS) |
|
Line 2318 post_xr(POST_ARGS) |
|
if (nch->next == NULL) { |
if (nch->next == NULL) { |
mandoc_vmsg(MANDOCERR_XR_NOSEC, mdoc->parse, |
mandoc_vmsg(MANDOCERR_XR_NOSEC, mdoc->parse, |
n->line, n->pos, "Xr %s", nch->string); |
n->line, n->pos, "Xr %s", nch->string); |
return; |
} else |
} |
assert(nch->next == n->last); |
assert(nch->next == n->last); |
post_delim(mdoc); |
} |
} |
|
|
static void |
static void |
Line 2064 post_prevpar(POST_ARGS) |
|
Line 2378 post_prevpar(POST_ARGS) |
|
|
|
if (n->prev->tok != MDOC_Pp && |
if (n->prev->tok != MDOC_Pp && |
n->prev->tok != MDOC_Lp && |
n->prev->tok != MDOC_Lp && |
n->prev->tok != MDOC_br) |
n->prev->tok != ROFF_br) |
return; |
return; |
if (n->tok == MDOC_Bl && n->norm->Bl.comp) |
if (n->tok == MDOC_Bl && n->norm->Bl.comp) |
return; |
return; |
Line 2085 post_par(POST_ARGS) |
|
Line 2399 post_par(POST_ARGS) |
|
struct roff_node *np; |
struct roff_node *np; |
|
|
np = mdoc->last; |
np = mdoc->last; |
if (np->tok != MDOC_br && np->tok != MDOC_sp) |
if (np->tok != ROFF_br && np->tok != ROFF_sp) |
post_prevpar(mdoc); |
post_prevpar(mdoc); |
|
|
if (np->tok == MDOC_sp) { |
if (np->tok == ROFF_sp) { |
if (np->child != NULL && np->child->next != NULL) |
if (np->child != NULL && np->child->next != NULL) |
mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, |
mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse, |
np->child->next->line, np->child->next->pos, |
np->child->next->line, np->child->next->pos, |
Line 2103 post_par(POST_ARGS) |
|
Line 2417 post_par(POST_ARGS) |
|
if (np->tok != MDOC_Sh && np->tok != MDOC_Ss) |
if (np->tok != MDOC_Sh && np->tok != MDOC_Ss) |
return; |
return; |
} else if (np->tok != MDOC_Pp && np->tok != MDOC_Lp && |
} else if (np->tok != MDOC_Pp && np->tok != MDOC_Lp && |
(mdoc->last->tok != MDOC_br || |
(mdoc->last->tok != ROFF_br || |
(np->tok != MDOC_sp && np->tok != MDOC_br))) |
(np->tok != ROFF_sp && np->tok != ROFF_br))) |
return; |
return; |
|
|
mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse, |
mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse, |
Line 2138 post_dd(POST_ARGS) |
|
Line 2452 post_dd(POST_ARGS) |
|
|
|
if (n->child == NULL || n->child->string[0] == '\0') { |
if (n->child == NULL || n->child->string[0] == '\0') { |
mdoc->meta.date = mdoc->quick ? mandoc_strdup("") : |
mdoc->meta.date = mdoc->quick ? mandoc_strdup("") : |
mandoc_normdate(mdoc->parse, NULL, n->line, n->pos); |
mandoc_normdate(mdoc, NULL, n->line, n->pos); |
return; |
return; |
} |
} |
|
|
Line 2147 post_dd(POST_ARGS) |
|
Line 2461 post_dd(POST_ARGS) |
|
if (mdoc->quick) |
if (mdoc->quick) |
mdoc->meta.date = datestr; |
mdoc->meta.date = datestr; |
else { |
else { |
mdoc->meta.date = mandoc_normdate(mdoc->parse, |
mdoc->meta.date = mandoc_normdate(mdoc, |
datestr, n->line, n->pos); |
datestr, n->line, n->pos); |
free(datestr); |
free(datestr); |
} |
} |
|
|
post_bx(POST_ARGS) |
post_bx(POST_ARGS) |
{ |
{ |
struct roff_node *n, *nch; |
struct roff_node *n, *nch; |
|
const char *macro; |
|
|
|
post_delim(mdoc); |
|
|
n = mdoc->last; |
n = mdoc->last; |
nch = n->child; |
nch = n->child; |
|
|
if (nch != NULL) { |
if (nch != NULL) { |
|
macro = !strcmp(nch->string, "Open") ? "Ox" : |
|
!strcmp(nch->string, "Net") ? "Nx" : |
|
!strcmp(nch->string, "Free") ? "Fx" : |
|
!strcmp(nch->string, "DragonFly") ? "Dx" : NULL; |
|
if (macro != NULL) |
|
mandoc_msg(MANDOCERR_BX, mdoc->parse, |
|
n->line, n->pos, macro); |
mdoc->last = nch; |
mdoc->last = nch; |
nch = nch->next; |
nch = nch->next; |
mdoc->next = ROFF_NEXT_SIBLING; |
mdoc->next = ROFF_NEXT_SIBLING; |
Line 2324 post_os(POST_ARGS) |
|
Line 2648 post_os(POST_ARGS) |
|
mdoc->meta.os = NULL; |
mdoc->meta.os = NULL; |
deroff(&mdoc->meta.os, n); |
deroff(&mdoc->meta.os, n); |
if (mdoc->meta.os) |
if (mdoc->meta.os) |
return; |
goto out; |
|
|
if (mdoc->defos) { |
if (mdoc->os_s != NULL) { |
mdoc->meta.os = mandoc_strdup(mdoc->defos); |
mdoc->meta.os = mandoc_strdup(mdoc->os_s); |
return; |
goto out; |
} |
} |
|
|
#ifdef OSNAME |
#ifdef OSNAME |
Line 2345 post_os(POST_ARGS) |
|
Line 2669 post_os(POST_ARGS) |
|
} |
} |
mdoc->meta.os = mandoc_strdup(defbuf); |
mdoc->meta.os = mandoc_strdup(defbuf); |
#endif /*!OSNAME*/ |
#endif /*!OSNAME*/ |
|
|
|
out: |
|
if (mdoc->meta.os_e == MANDOC_OS_OTHER) { |
|
if (strstr(mdoc->meta.os, "OpenBSD") != NULL) |
|
mdoc->meta.os_e = MANDOC_OS_OPENBSD; |
|
else if (strstr(mdoc->meta.os, "NetBSD") != NULL) |
|
mdoc->meta.os_e = MANDOC_OS_NETBSD; |
|
} |
|
|
|
/* |
|
* This is the earliest point where we can check |
|
* Mdocdate conventions because we don't know |
|
* the operating system earlier. |
|
*/ |
|
|
|
if (n->child != NULL) |
|
mandoc_vmsg(MANDOCERR_OS_ARG, mdoc->parse, |
|
n->child->line, n->child->pos, |
|
"Os %s (%s)", n->child->string, |
|
mdoc->meta.os_e == MANDOC_OS_OPENBSD ? |
|
"OpenBSD" : "NetBSD"); |
|
|
|
while (n->tok != MDOC_Dd) |
|
if ((n = n->prev) == NULL) |
|
return; |
|
if ((n = n->child) == NULL) |
|
return; |
|
if (strncmp(n->string, "$" "Mdocdate", 9)) { |
|
if (mdoc->meta.os_e == MANDOC_OS_OPENBSD) |
|
mandoc_vmsg(MANDOCERR_MDOCDATE_MISSING, |
|
mdoc->parse, n->line, n->pos, |
|
"Dd %s (OpenBSD)", n->string); |
|
} else { |
|
if (mdoc->meta.os_e == MANDOC_OS_NETBSD) |
|
mandoc_vmsg(MANDOCERR_MDOCDATE, |
|
mdoc->parse, n->line, n->pos, |
|
"Dd %s (NetBSD)", n->string); |
|
} |
} |
} |
|
|
enum roff_sec |
enum roff_sec |