version 1.340, 2017/06/24 14:38:33 |
version 1.347, 2017/07/02 15:31:59 |
|
|
|
|
#include "mandoc_aux.h" |
#include "mandoc_aux.h" |
#include "mandoc.h" |
#include "mandoc.h" |
|
#include "mandoc_xr.h" |
#include "roff.h" |
#include "roff.h" |
#include "mdoc.h" |
#include "mdoc.h" |
#include "libmandoc.h" |
#include "libmandoc.h" |
Line 60 static void check_toptext(struct roff_man *, int, int |
|
Line 61 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 1102 post_fname(POST_ARGS) |
|
Line 1104 post_fname(POST_ARGS) |
|
if ( ! (cp[0] == '\0' || (cp[0] == '(' && cp[1] == '*'))) |
if ( ! (cp[0] == '\0' || (cp[0] == '(' && cp[1] == '*'))) |
mandoc_msg(MANDOCERR_FN_PAREN, mdoc->parse, |
mandoc_msg(MANDOCERR_FN_PAREN, mdoc->parse, |
n->line, n->pos + pos, n->string); |
n->line, n->pos + pos, n->string); |
|
if (n->sec == SEC_SYNOPSIS && mdoc->meta.msec != NULL) |
|
mandoc_xr_add(mdoc->meta.msec, n->string, -1, -1); |
} |
} |
|
|
static void |
static void |
Line 1167 post_nm(POST_ARGS) |
|
Line 1171 post_nm(POST_ARGS) |
|
|
|
n = mdoc->last; |
n = mdoc->last; |
|
|
|
if ((n->sec == SEC_NAME || n->sec == SEC_SYNOPSIS) && |
|
n->child != NULL && n->child->type == ROFFT_TEXT && |
|
mdoc->meta.msec != NULL) |
|
mandoc_xr_add(mdoc->meta.msec, n->child->string, -1, -1); |
|
|
if (n->last != NULL && |
if (n->last != NULL && |
(n->last->tok == MDOC_Pp || |
(n->last->tok == MDOC_Pp || |
n->last->tok == MDOC_Lp)) |
n->last->tok == MDOC_Lp)) |
Line 1459 post_it(POST_ARGS) |
|
Line 1468 post_it(POST_ARGS) |
|
|
|
assert(nit->head->child == NULL); |
assert(nit->head->child == NULL); |
|
|
i = 0; |
if (nit->head->next->child == NULL && |
for (nch = nit->child; nch != NULL; nch = nch->next) |
nit->head->next->next == NULL) { |
if (nch->type == ROFFT_BODY) |
mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse, |
i++; |
nit->line, nit->pos, "It"); |
|
roff_node_delete(mdoc, nit); |
|
break; |
|
} |
|
|
|
i = 0; |
|
for (nch = nit->child; nch != NULL; nch = nch->next) { |
|
if (nch->type != ROFFT_BODY) |
|
continue; |
|
if (i++ && nch->flags & NODE_LINE) |
|
mandoc_msg(MANDOCERR_TA_LINE, mdoc->parse, |
|
nch->line, nch->pos, "Ta"); |
|
} |
if (i < cols || i > cols + 1) |
if (i < cols || i > cols + 1) |
mandoc_vmsg(MANDOCERR_BL_COL, |
mandoc_vmsg(MANDOCERR_BL_COL, |
mdoc->parse, nit->line, nit->pos, |
mdoc->parse, nit->line, nit->pos, |
"%d columns, %d cells", cols, i); |
"%d columns, %d cells", cols, i); |
|
else if (nit->head->next->child != NULL && |
|
nit->head->next->child->line > nit->line) |
|
mandoc_msg(MANDOCERR_IT_NOARG, mdoc->parse, |
|
nit->line, nit->pos, "Bl -column It"); |
break; |
break; |
default: |
default: |
abort(); |
abort(); |
Line 1786 post_sm(POST_ARGS) |
|
Line 1810 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. */ |
|
|
Line 1813 post_root(POST_ARGS) |
|
Line 1859 post_root(POST_ARGS) |
|
mdoc->meta.os_e == MANDOC_OS_OPENBSD ? |
mdoc->meta.os_e == MANDOC_OS_OPENBSD ? |
"(OpenBSD)" : "(NetBSD)"); |
"(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'. */ |
|
|
n = mdoc->first->child; |
n = mdoc->first->child; |
Line 1943 post_hyph(POST_ARGS) |
|
Line 2006 post_hyph(POST_ARGS) |
|
static void |
static void |
post_ns(POST_ARGS) |
post_ns(POST_ARGS) |
{ |
{ |
|
struct roff_node *n; |
|
|
if (mdoc->last->flags & NODE_LINE) |
n = mdoc->last; |
|
if (n->flags & NODE_LINE || |
|
(n->next != NULL && n->next->flags & NODE_DELIMC)) |
mandoc_msg(MANDOCERR_NS_SKIP, mdoc->parse, |
mandoc_msg(MANDOCERR_NS_SKIP, mdoc->parse, |
mdoc->last->line, mdoc->last->pos, NULL); |
n->line, n->pos, NULL); |
} |
} |
|
|
static void |
static void |
Line 2109 post_sh_authors(POST_ARGS) |
|
Line 2175 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 2151 post_sh_head(POST_ARGS) |
|
Line 2260 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 2218 post_xr(POST_ARGS) |
|
Line 2344 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); |
} else |
} else { |
assert(nch->next == n->last); |
assert(nch->next == n->last); |
|
if(mandoc_xr_add(nch->next->string, nch->string, |
|
nch->line, nch->pos)) |
|
mandoc_vmsg(MANDOCERR_XR_SELF, mdoc->parse, |
|
nch->line, nch->pos, "Xr %s %s", |
|
nch->string, nch->next->string); |
|
} |
post_delim(mdoc); |
post_delim(mdoc); |
} |
} |
|
|
|
|
* Mdocdate conventions because we don't know |
* Mdocdate conventions because we don't know |
* the operating system earlier. |
* 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) |
while (n->tok != MDOC_Dd) |
if ((n = n->prev) == NULL) |
if ((n = n->prev) == NULL) |