Browse Source

check-bolt: handle references to early-drafts too.

Particularly for the onchain.md draft.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ppa-0.6.1
Rusty Russell 9 years ago
parent
commit
3f374d8d8b
  1. 2
      Makefile
  2. 183
      check-bolt.c

2
Makefile

@ -8,7 +8,7 @@ PROTOCC:=protoc-c
CCANDIR := ccan CCANDIR := ccan
# Where we keep the BOLT RFCs # 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 uses DER for signatures (Add BIP68 & HAS_CSV if it's supported)
BITCOIN_FEATURES := \ BITCOIN_FEATURES := \

183
check-bolt.c

@ -12,6 +12,11 @@
static bool verbose = false; static bool verbose = false;
struct bolt_file {
const char *prefix;
const char *contents;
};
/* Turn any whitespace into a single space. */ /* Turn any whitespace into a single space. */
static char *canonicalize(char *str) static char *canonicalize(char *str)
{ {
@ -36,71 +41,91 @@ static char *canonicalize(char *str)
return 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; struct dirent *e;
char **bolts = tal_arr(NULL, char *, 0);
DIR *d = opendir(dir);
if (!d) if (!d)
err(1, "Opening BOLT dir %s", dir); err(1, "Opening BOLT dir %s", path);
while ((e = readdir(d)) != NULL) { while ((e = readdir(d)) != NULL) {
char *endp; int preflen;
unsigned long l;
/* Must start with the bold number. */
l = strtoul(e->d_name, &endp, 10);
if (endp == e->d_name)
continue;
/* Must end in .md */ /* Must end in .md */
if (!strends(e->d_name, ".md")) if (!strends(e->d_name, ".md"))
continue; continue;
if (l >= tal_count(bolts)) /* Prefix is anything up to - */
tal_resizez(&bolts, l+1); 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) 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, tal_resize(files, n+1);
path_join(NULL, dir, (*files)[n].prefix = tal_strndup(*files,
e->d_name, preflen);
(*files)[n].contents
= canonicalize(grab_file(*files,
path_join(path, path,
e->d_name))); 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; 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 (;;) { for (;;) {
char *end; char *bolt, *end;
size_t preflen;
/* BOLT #X: */ /* BOLT #X: */
p = strstr(p, "BOLT"); *p = strstr(*p, "BOLT");
if (!p) if (!*p)
return NULL; return NULL;
p += 4; *p += 4;
while (cisspace(*p)) while (cisspace(**p))
p++; (*p)++;
if (*p != '#') if (**p != '#')
continue; continue;
p++; (*p)++;
*bolt = strtoul(p, &end, 10);
if (!*bolt || p == end) preflen = strcspn(*p, " :");
continue; bolt = tal_strndup(NULL, *p, preflen);
p = end;
while (cisspace(*p)) (*p) += preflen;
p++; while (cisspace(**p))
if (*p != ':') (*p)++;
if (**p != ':')
continue; continue;
p++; (*p)++;
end = strstr(p, "*/"); end = strstr(*p, "*/");
if (!end) if (!end)
*len = strlen(p); *len = strlen(*p);
else else
*len = end - p; *len = end - *p;
return 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; char *pattern = tal_arr(NULL, char, len*2 + 1), *p;
size_t i; size_t i;
bool after_nl = false; bool after_nl = true;
/* We swallow '*' if first in line: block comments */ /* We swallow '*' if first in line: block comments */
p = pattern; p = pattern;
@ -153,30 +178,36 @@ static char *code_to_regex(const char *code, size_t len, bool escape)
return canonicalize(pattern); return canonicalize(pattern);
} }
static void fail(const char *filename, const char *raw, const char *pos, /* Moves *pos to start of line. */
size_t len, const char *bolt) static unsigned linenum(const char *raw, const char **pos)
{ {
unsigned line = 0; /* Out-by-one below */ 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'); l = strchr(l, '\n');
line++; line++;
if (!l) if (!l)
l = pos + strlen(pos); break;
else
l++; l++;
} }
return line;
}
if (bolt) { 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; char *try;
fprintf(stderr, "%s:%u:%.*s\n", filename, line, fprintf(stderr, "%s:%u:mismatch:%.*s\n",
(int)(l - pos), pos); filename, line, (int)strcspn(pos, "\n"), pos);
/* Try to find longest match, as a hint. */ /* Try to find longest match, as a hint. */
try = code_to_regex(pos, len, false); try = code_to_regex(pos + strcspn(pos, "\n"), len, false);
while (strlen(try)) { while (strlen(try)) {
const char *p = strstr(bolt, try); const char *p = strstr(bolt->contents, try);
if (p) { if (p) {
fprintf(stderr, "Closest match: %s...[%.20s]\n", fprintf(stderr, "Closest match: %s...[%.20s]\n",
try, p + strlen(try)); try, p + strlen(try));
@ -184,15 +215,44 @@ static void fail(const char *filename, const char *raw, const char *pos,
} }
try[strlen(try)-1] = '\0'; try[strlen(try)-1] = '\0';
} }
} else { exit(1);
fprintf(stderr, "%s:%u:Unknown bolt\n", filename, line);
} }
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); 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[]) int main(int argc, char *argv[])
{ {
char **bolts; struct bolt_file *bolts;
int i; int i;
err_set_progname(argv[0]); err_set_progname(argv[0]);
@ -211,8 +271,8 @@ int main(int argc, char *argv[])
bolts = get_bolt_files(argv[1]); bolts = get_bolt_files(argv[1]);
for (i = 2; i < argc; i++) { for (i = 2; i < argc; i++) {
char *f = grab_file(NULL, argv[i]), *p; char *f = grab_file(NULL, argv[i]), *p, *bolt;
size_t len, bolt; size_t len;
if (!f) if (!f)
err(1, "Loading %s", argv[i]); err(1, "Loading %s", argv[i]);
@ -220,16 +280,17 @@ int main(int argc, char *argv[])
printf("Checking %s...\n", argv[i]); printf("Checking %s...\n", argv[i]);
p = f; 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); char *pattern = code_to_regex(p, len, true);
if (bolt >= tal_count(bolts) || !bolts[bolt]) struct bolt_file *b = find_bolt(bolt, bolts);
fail(argv[i], f, p, len, NULL); if (!b)
if (!tal_strreg(f, bolts[bolt], pattern, NULL)) fail_nobolt(argv[i], f, p, bolt);
fail(argv[i], f, p, len, bolts[bolt]); if (!tal_strreg(f, b->contents, pattern, NULL))
fail_mismatch(argv[i], f, p, len, b);
if (verbose) if (verbose)
printf(" Found %.10s... in %zu\n", printf(" Found %.10s... in %s\n",
p, bolt); p, b->prefix);
p += len; p += len;
} }
tal_free(f); tal_free(f);

Loading…
Cancel
Save