check-bolt: handle references to early-drafts too.
Particularly for the onchain.md draft. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
1245ffaae3
commit
3f374d8d8b
2
Makefile
2
Makefile
|
@ -8,7 +8,7 @@ PROTOCC:=protoc-c
|
|||
CCANDIR := ccan
|
||||
|
||||
# Where we keep the BOLT RFCs
|
||||
BOLTDIR := ../lightning-rfc/bolts/
|
||||
BOLTDIR := ../lightning-rfc/
|
||||
|
||||
# Bitcoin uses DER for signatures (Add BIP68 & HAS_CSV if it's supported)
|
||||
BITCOIN_FEATURES := \
|
||||
|
|
209
check-bolt.c
209
check-bolt.c
|
@ -12,6 +12,11 @@
|
|||
|
||||
static bool verbose = false;
|
||||
|
||||
struct bolt_file {
|
||||
const char *prefix;
|
||||
const char *contents;
|
||||
};
|
||||
|
||||
/* Turn any whitespace into a single space. */
|
||||
static char *canonicalize(char *str)
|
||||
{
|
||||
|
@ -36,71 +41,91 @@ static char *canonicalize(char *str)
|
|||
return str;
|
||||
}
|
||||
|
||||
static char **get_bolt_files(const char *dir)
|
||||
static void get_files(const char *dir, const char *subdir,
|
||||
struct bolt_file **files)
|
||||
{
|
||||
char *path = path_join(NULL, dir, subdir);
|
||||
DIR *d = opendir(path);
|
||||
size_t n = tal_count(*files);
|
||||
struct dirent *e;
|
||||
char **bolts = tal_arr(NULL, char *, 0);
|
||||
DIR *d = opendir(dir);
|
||||
|
||||
if (!d)
|
||||
err(1, "Opening BOLT dir %s", dir);
|
||||
err(1, "Opening BOLT dir %s", path);
|
||||
|
||||
while ((e = readdir(d)) != NULL) {
|
||||
char *endp;
|
||||
unsigned long l;
|
||||
|
||||
/* Must start with the bold number. */
|
||||
l = strtoul(e->d_name, &endp, 10);
|
||||
if (endp == e->d_name)
|
||||
continue;
|
||||
int preflen;
|
||||
|
||||
/* Must end in .md */
|
||||
if (!strends(e->d_name, ".md"))
|
||||
continue;
|
||||
|
||||
if (l >= tal_count(bolts))
|
||||
tal_resizez(&bolts, l+1);
|
||||
/* Prefix is anything up to - */
|
||||
preflen = strspn(e->d_name,
|
||||
"0123456789"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ");
|
||||
if (!preflen)
|
||||
continue;
|
||||
if (preflen + strlen(".md") != strlen(e->d_name)
|
||||
&& e->d_name[preflen] != '-')
|
||||
continue;
|
||||
|
||||
if (verbose)
|
||||
printf("Found bolt %s: #%lu\n", e->d_name, l);
|
||||
printf("Found bolt %.*s\n", preflen, e->d_name);
|
||||
|
||||
bolts[l] = canonicalize(grab_file(NULL,
|
||||
path_join(NULL, dir,
|
||||
e->d_name)));
|
||||
tal_resize(files, n+1);
|
||||
(*files)[n].prefix = tal_strndup(*files,
|
||||
e->d_name, preflen);
|
||||
(*files)[n].contents
|
||||
= canonicalize(grab_file(*files,
|
||||
path_join(path, path,
|
||||
e->d_name)));
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
static struct bolt_file *get_bolt_files(const char *dir)
|
||||
{
|
||||
struct bolt_file *bolts = tal_arr(NULL, struct bolt_file, 0);
|
||||
|
||||
get_files(dir, "bolts", &bolts);
|
||||
get_files(dir, "early-drafts", &bolts);
|
||||
return bolts;
|
||||
}
|
||||
|
||||
static char *find_bolt_ref(char *p, size_t *len, size_t *bolt)
|
||||
static char *find_bolt_ref(char **p, size_t *len)
|
||||
{
|
||||
for (;;) {
|
||||
char *end;
|
||||
char *bolt, *end;
|
||||
size_t preflen;
|
||||
|
||||
/* BOLT #X: */
|
||||
p = strstr(p, "BOLT");
|
||||
if (!p)
|
||||
*p = strstr(*p, "BOLT");
|
||||
if (!*p)
|
||||
return NULL;
|
||||
p += 4;
|
||||
while (cisspace(*p))
|
||||
p++;
|
||||
if (*p != '#')
|
||||
*p += 4;
|
||||
while (cisspace(**p))
|
||||
(*p)++;
|
||||
if (**p != '#')
|
||||
continue;
|
||||
p++;
|
||||
*bolt = strtoul(p, &end, 10);
|
||||
if (!*bolt || p == end)
|
||||
continue;
|
||||
p = end;
|
||||
while (cisspace(*p))
|
||||
p++;
|
||||
if (*p != ':')
|
||||
continue;
|
||||
p++;
|
||||
(*p)++;
|
||||
|
||||
end = strstr(p, "*/");
|
||||
preflen = strcspn(*p, " :");
|
||||
bolt = tal_strndup(NULL, *p, preflen);
|
||||
|
||||
(*p) += preflen;
|
||||
while (cisspace(**p))
|
||||
(*p)++;
|
||||
if (**p != ':')
|
||||
continue;
|
||||
(*p)++;
|
||||
|
||||
end = strstr(*p, "*/");
|
||||
if (!end)
|
||||
*len = strlen(p);
|
||||
*len = strlen(*p);
|
||||
else
|
||||
*len = end - p;
|
||||
return p;
|
||||
*len = end - *p;
|
||||
return bolt;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,7 +133,7 @@ static char *code_to_regex(const char *code, size_t len, bool escape)
|
|||
{
|
||||
char *pattern = tal_arr(NULL, char, len*2 + 1), *p;
|
||||
size_t i;
|
||||
bool after_nl = false;
|
||||
bool after_nl = true;
|
||||
|
||||
/* We swallow '*' if first in line: block comments */
|
||||
p = pattern;
|
||||
|
@ -153,46 +178,81 @@ static char *code_to_regex(const char *code, size_t len, bool escape)
|
|||
return canonicalize(pattern);
|
||||
}
|
||||
|
||||
static void fail(const char *filename, const char *raw, const char *pos,
|
||||
size_t len, const char *bolt)
|
||||
/* Moves *pos to start of line. */
|
||||
static unsigned linenum(const char *raw, const char **pos)
|
||||
{
|
||||
unsigned line = 0; /* Out-by-one below */
|
||||
const char *l = raw;
|
||||
const char *l = raw, *point = *pos;
|
||||
|
||||
while (l < pos) {
|
||||
while (l < point) {
|
||||
*pos = l;
|
||||
l = strchr(l, '\n');
|
||||
line++;
|
||||
if (!l)
|
||||
l = pos + strlen(pos);
|
||||
else
|
||||
l++;
|
||||
break;
|
||||
l++;
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
if (bolt) {
|
||||
char *try;
|
||||
static void fail_mismatch(const char *filename,
|
||||
const char *raw, const char *pos,
|
||||
size_t len, struct bolt_file *bolt)
|
||||
{
|
||||
unsigned line = linenum(raw, &pos);
|
||||
char *try;
|
||||
|
||||
fprintf(stderr, "%s:%u:%.*s\n", filename, line,
|
||||
(int)(l - pos), pos);
|
||||
/* Try to find longest match, as a hint. */
|
||||
try = code_to_regex(pos, len, false);
|
||||
while (strlen(try)) {
|
||||
const char *p = strstr(bolt, try);
|
||||
if (p) {
|
||||
fprintf(stderr, "Closest match: %s...[%.20s]\n",
|
||||
try, p + strlen(try));
|
||||
break;
|
||||
}
|
||||
try[strlen(try)-1] = '\0';
|
||||
fprintf(stderr, "%s:%u:mismatch:%.*s\n",
|
||||
filename, line, (int)strcspn(pos, "\n"), pos);
|
||||
/* Try to find longest match, as a hint. */
|
||||
try = code_to_regex(pos + strcspn(pos, "\n"), len, false);
|
||||
while (strlen(try)) {
|
||||
const char *p = strstr(bolt->contents, try);
|
||||
if (p) {
|
||||
fprintf(stderr, "Closest match: %s...[%.20s]\n",
|
||||
try, p + strlen(try));
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "%s:%u:Unknown bolt\n", filename, line);
|
||||
}
|
||||
try[strlen(try)-1] = '\0';
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void fail_nobolt(const char *filename,
|
||||
const char *raw, const char *pos,
|
||||
const char *bolt_prefix)
|
||||
{
|
||||
unsigned line = linenum(raw, &pos);
|
||||
|
||||
fprintf(stderr, "%s:%u:unknown bolt %s\n",
|
||||
filename, line, bolt_prefix);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static struct bolt_file *find_bolt(const char *bolt_prefix,
|
||||
struct bolt_file *bolts)
|
||||
{
|
||||
size_t i, n = tal_count(bolts);
|
||||
size_t boltnum;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
if (streq(bolts[i].prefix, bolt_prefix))
|
||||
return bolts+i;
|
||||
|
||||
/* Now search for numerical match. */
|
||||
boltnum = atoi(bolt_prefix);
|
||||
if (boltnum) {
|
||||
for (i = 0; i < n; i++)
|
||||
if (atoi(bolts[i].prefix) == boltnum)
|
||||
return bolts+i;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char **bolts;
|
||||
struct bolt_file *bolts;
|
||||
int i;
|
||||
|
||||
err_set_progname(argv[0]);
|
||||
|
@ -211,8 +271,8 @@ int main(int argc, char *argv[])
|
|||
bolts = get_bolt_files(argv[1]);
|
||||
|
||||
for (i = 2; i < argc; i++) {
|
||||
char *f = grab_file(NULL, argv[i]), *p;
|
||||
size_t len, bolt;
|
||||
char *f = grab_file(NULL, argv[i]), *p, *bolt;
|
||||
size_t len;
|
||||
if (!f)
|
||||
err(1, "Loading %s", argv[i]);
|
||||
|
||||
|
@ -220,16 +280,17 @@ int main(int argc, char *argv[])
|
|||
printf("Checking %s...\n", argv[i]);
|
||||
|
||||
p = f;
|
||||
while ((p = find_bolt_ref(p, &len, &bolt)) != NULL) {
|
||||
while ((bolt = find_bolt_ref(&p, &len)) != NULL) {
|
||||
char *pattern = code_to_regex(p, len, true);
|
||||
if (bolt >= tal_count(bolts) || !bolts[bolt])
|
||||
fail(argv[i], f, p, len, NULL);
|
||||
if (!tal_strreg(f, bolts[bolt], pattern, NULL))
|
||||
fail(argv[i], f, p, len, bolts[bolt]);
|
||||
struct bolt_file *b = find_bolt(bolt, bolts);
|
||||
if (!b)
|
||||
fail_nobolt(argv[i], f, p, bolt);
|
||||
if (!tal_strreg(f, b->contents, pattern, NULL))
|
||||
fail_mismatch(argv[i], f, p, len, b);
|
||||
|
||||
if (verbose)
|
||||
printf(" Found %.10s... in %zu\n",
|
||||
p, bolt);
|
||||
printf(" Found %.10s... in %s\n",
|
||||
p, b->prefix);
|
||||
p += len;
|
||||
}
|
||||
tal_free(f);
|
||||
|
|
Loading…
Reference in New Issue