Browse Source

cdump: handle multi-line preprocessor directives.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Rusty Russell 11 years ago
parent
commit
3d6fe8391a
2 changed files with 87 additions and 2 deletions
  1. 12 2
      ccan/cdump/cdump.c
  2. 75 0
      ccan/cdump/test/run-multiline.c

+ 12 - 2
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;

+ 75 - 0
ccan/cdump/test/run-multiline.c

@@ -0,0 +1,75 @@
+#include <ccan/cdump/cdump.h>
+/* Include the C files directly. */
+#include <ccan/cdump/cdump.c>
+#include <ccan/tap/tap.h>
+
+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();
+}