version 1.342, 2017/06/24 18:58:33 |
version 1.343, 2017/06/25 17:43:45 |
Line 60 static void check_toptext(struct roff_man *, int, int |
|
Line 60 static void check_toptext(struct roff_man *, int, int |
|
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(struct roff_man *, 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 2148 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 2190 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 |