From: Rusty Russell Date: Fri, 14 Nov 2014 02:28:58 +0000 (+1030) Subject: cdump: handle multi-line preprocessor directives. X-Git-Url: https://git.ozlabs.org/?p=ccan;a=commitdiff_plain;h=3d6fe8391ab0b6e6b9da0a715a4a8308303fc72e;hp=1e5f5ecc5f6e75ac28c9b03f10837a7231dbca8e cdump: handle multi-line preprocessor directives. Signed-off-by: Rusty Russell --- 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(); +}