From 3d6fe8391ab0b6e6b9da0a715a4a8308303fc72e Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 14 Nov 2014 12:58:58 +1030 Subject: [PATCH] cdump: handle multi-line preprocessor directives. Signed-off-by: Rusty Russell --- ccan/cdump/cdump.c | 14 +++++- ccan/cdump/test/run-multiline.c | 75 +++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 ccan/cdump/test/run-multiline.c diff --git a/ccan/cdump/cdump.c b/ccan/cdump/cdump.c index dad319dc..fb942594 100644 --- a/ccan/cdump/cdump.c +++ b/ccan/cdump/cdump.c @@ -16,6 +16,16 @@ static void add_token(struct token **toks, const char *p, size_t len) (*toks)[n].len = len; } +static size_t to_eol(const char *p) +{ + size_t len = strcspn(p, "\n"); + + /* And any \ continuations. */ + while (p[len] && p[len-1] == '\\') + len += strcspn(p+len+1, "\n") + 1; + return len; +} + /* Simplified tokenizer: comments and preproc directives removed, identifiers are a token, others are single char tokens. */ static struct token *tokenize(const void *ctx, const char *code) @@ -27,10 +37,10 @@ static struct token *tokenize(const void *ctx, const char *code) for (i = 0; code[i]; i += len) { if (code[i] == '#' && start_of_line) { /* Preprocessor line. */ - len = strcspn(code+i, "\n"); + len = to_eol(code + i); } else if (code[i] == '/' && code[i+1] == '/') { /* One line comment. */ - len = strcspn(code+i, "\n"); + len = to_eol(code + i); if (tok_start != -1U) { add_token(&toks, code+tok_start, i - tok_start); tok_start = -1U; diff --git a/ccan/cdump/test/run-multiline.c b/ccan/cdump/test/run-multiline.c new file mode 100644 index 00000000..50f4e75b --- /dev/null +++ b/ccan/cdump/test/run-multiline.c @@ -0,0 +1,75 @@ +#include +/* Include the C files directly. */ +#include +#include + +int main(void) +{ + struct cdump_definitions *defs; + const struct cdump_type *t; + char *ctx = tal(NULL, char), *problems; + + /* This is how many tests you plan to run */ + plan_tests(30); + + /* Multi-line preprocessor statement. */ + defs = cdump_extract(ctx, + "#if \\\n" + "SOME\\\n" + "THING\n" + "enum foo { BAR };", &problems); + ok1(defs); + ok1(tal_parent(defs) == ctx); + + ok1(strmap_empty(&defs->structs)); + ok1(strmap_empty(&defs->unions)); + t = strmap_get(&defs->enums, "foo"); + ok1(t); + ok1(t->kind == CDUMP_ENUM); + ok1(streq(t->name, "foo")); + ok1(tal_count(t->u.enum_vals) == 1); + ok1(streq(t->u.enum_vals[0].name, "BAR")); + ok1(!t->u.enum_vals[0].value); + + defs = cdump_extract(ctx, + "enum foo {\n" + "#if \\\n" + "SOME\\\n" + "THING\n" + " BAR };", &problems); + ok1(defs); + ok1(tal_parent(defs) == ctx); + + ok1(strmap_empty(&defs->structs)); + ok1(strmap_empty(&defs->unions)); + t = strmap_get(&defs->enums, "foo"); + ok1(t); + ok1(t->kind == CDUMP_ENUM); + ok1(streq(t->name, "foo")); + ok1(tal_count(t->u.enum_vals) == 1); + ok1(streq(t->u.enum_vals[0].name, "BAR")); + ok1(!t->u.enum_vals[0].value); + + /* Multi-line "one-line" comment. */ + defs = cdump_extract(ctx, + "enum foo {\n" + "// Comment \\\n" + "SOME\\\n" + "THING\n" + " BAR };", &problems); + ok1(defs); + ok1(tal_parent(defs) == ctx); + + ok1(strmap_empty(&defs->structs)); + ok1(strmap_empty(&defs->unions)); + t = strmap_get(&defs->enums, "foo"); + ok1(t); + ok1(t->kind == CDUMP_ENUM); + ok1(streq(t->name, "foo")); + ok1(tal_count(t->u.enum_vals) == 1); + ok1(streq(t->u.enum_vals[0].name, "BAR")); + ok1(!t->u.enum_vals[0].value); + + /* This exits depending on whether all tests passed */ + return exit_status(); +} -- 2.39.2