From f7315b84a70f81579971d3450a2865fde3b71a7a Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Sat, 29 Dec 2007 21:24:11 +1100 Subject: [PATCH] Avoid hacky recompilation of files to namespacize, use hacky parser instead! --- ccan_tools/namespacize.c | 228 +++++++++++++++++++++++++-------------- 1 file changed, 150 insertions(+), 78 deletions(-) diff --git a/ccan_tools/namespacize.c b/ccan_tools/namespacize.c index a9b67f18..e4a3973f 100644 --- a/ccan_tools/namespacize.c +++ b/ccan_tools/namespacize.c @@ -13,7 +13,10 @@ #include "talloc/talloc.h" #define CFLAGS "-O3 -Wall -Wundef -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes -Wmissing-declarations -Werror -I. -Iccan_tools/libtap/src/" -#define CFLAGS_HDR "-Wall -Wundef -Wstrict-prototypes -Wold-style-definition -Werror -I." + +#define IDENT_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \ + "abcdefghijklmnopqrstuvwxyz" \ + "01234567889_" static bool verbose = false; static int indent = 0; @@ -166,20 +169,6 @@ lines_from_cmd(const void *ctx, char *format, ...) return split(ctx, buffer, "\n", NULL); } -static char *build_obj(const char *cfile) -{ - char *cmd; - char *ofile = talloc_strdup(cfile, cfile); - - ofile[strlen(ofile)-1] = 'c'; - - cmd = talloc_asprintf(ofile, "gcc " CFLAGS " -o %s -c %s", - ofile, cfile); - if (system(cmd) != 0) - errx(1, "Failed to compile %s", cfile); - return ofile; -} - struct replace { struct replace *next; @@ -200,11 +189,12 @@ static void __attribute__((noreturn)) usage(void) static void add_replace(struct replace **repl, const char *str) { - struct replace *new; + struct replace *new, *i; - /* Don't replace things already CCAN-ized (eg. idempotent wrappers) */ - if (strstarts(str, "CCAN_") || strstarts(str, "ccan_")) - return; + /* Avoid duplicates. */ + for (i = *repl; i; i = i->next) + if (streq(i->string, str)) + return; new = talloc(*repl, struct replace); new->next = *repl; @@ -212,6 +202,17 @@ static void add_replace(struct replace **repl, const char *str) *repl = new; } +static void add_replace_tok(struct replace **repl, const char *s) +{ + struct replace *new; + unsigned int len = strspn(s, IDENT_CHARS); + + new = talloc(*repl, struct replace); + new->next = *repl; + new->string = talloc_strndup(new, s, len); + *repl = new; +} + static char *basename(const void *ctx, const char *dir) { char *p = strrchr(dir, '/'); @@ -221,20 +222,11 @@ static char *basename(const void *ctx, const char *dir) return talloc_strdup(ctx, p+1); } -/* FIXME: Only does main header, should chase local includes. */ -static void analyze_headers(const char *dir, struct replace **repl) +static void look_for_macros(char *contents, struct replace **repl) { - char *hdr, *contents, *p; + char *p; enum { LINESTART, HASH, DEFINE, NONE } state = LINESTART; - /* Get hold of header, assume that's it. */ - hdr = talloc_asprintf(dir, "%s/%s.h", dir, basename(dir, dir)); - contents = grab_file(dir, hdr); - if (!contents) - err(1, "Reading %s", hdr); - - verbose("Looking in %s\n", hdr); - verbose_indent(); /* Look for lines of form #define X */ for (p = contents; *p; p++) { if (*p == '\n') @@ -248,79 +240,160 @@ static void analyze_headers(const char *dir, struct replace **repl) } else if (state == DEFINE) { unsigned int len; - len = strspn(p, "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "01234567889_"); + len = strspn(p, IDENT_CHARS); if (len) { char *s; s = talloc_strndup(contents, p, len); - verbose("Found %s\n", s); - add_replace(repl, s); + /* Don't wrap idempotent wrappers */ + if (!strstarts(s, "CCAN_")) { + verbose("Found %s\n", s); + add_replace(repl, s); + } } state = NONE; } else state = NONE; } } - verbose_unindent(); } -static void add_extern_symbols(const char *ofile, struct replace **repl) +/* Blank out preprocessor lines, and eliminate \ */ +static void preprocess(char *p) { - /* Should actually read the elf: this is a hack. */ - char **line; + char *s; - line = lines_from_cmd(ofile, "nm --defined-only --extern %s", ofile); + /* We assume backslashes are only used for macros. */ + while ((s = strstr(p, "\\\n")) != NULL) + s[0] = s[1] = ' '; - /* nm output is of form [hexaddr] [char] [name]\n */ - for (; *line; line++) { - unsigned int cols; - char **names = split(ofile, *line, " \t", &cols); - if (cols != 3) - errx(1, "Unexpected nm line '%s' (%i cols)", *line, cols); + /* Now eliminate # lines. */ + if (p[0] == '#') { + unsigned int i; + for (i = 0; p[i] != '\n'; i++) + p[i] = ' '; + } + while ((s = strstr(p, "\n#")) != NULL) { + unsigned int i; + for (i = 1; s[i] != '\n'; i++) + s[i] = ' '; + } +} - verbose("Found %s\n", names[2]); - add_replace(repl, names[2]); +static char *get_statement(const void *ctx, char **p) +{ + unsigned brackets = 0; + bool seen_brackets = false; + char *answer = talloc_strdup(ctx, ""); + + for (;;) { + if ((*p)[0] == '/' && (*p)[1] == '/') + *p += strcspn(*p, "\n"); + else if ((*p)[0] == '/' && (*p)[1] == '*') + *p = strstr(*p, "*/") + 1; + else { + char c = **p; + if (c == ';' && !brackets) { + (*p)++; + return answer; + } + /* Compress whitespace into a single ' ' */ + if (isspace(c)) { + c = ' '; + while (isspace((*p)[1])) + (*p)++; + } else if (c == '{' || c == '(' || c == '[') { + if (c == '(') + seen_brackets = true; + brackets++; + } else if (c == '}' || c == ')' || c == ']') + brackets--; + + if (answer[0] != '\0' || c != ' ') { + answer = talloc_realloc(NULL, answer, char, + strlen(answer) + 2); + answer[strlen(answer)+1] = '\0'; + answer[strlen(answer)] = c; + } + if (c == '}' && seen_brackets && brackets == 0) { + (*p)++; + return answer; + } + } + (*p)++; + if (**p == '\0') + return NULL; } } -static void get_header_symbols(const char *dir, struct replace **repl) +/* This hack should handle well-formatted code. */ +static void look_for_definitions(char *contents, struct replace **repl) { - char *cmd; - char *hfile = talloc_asprintf(dir, "%s/%s.h", dir, basename(dir, dir)); - char *ofile = talloc_asprintf(dir, "%s.o", hfile); + char *stmt, *p = contents; - /* Horrible hack to get static inlines. */ - cmd = talloc_asprintf(dir, "gcc " CFLAGS_HDR - " -Dstatic= -include %s -o %s -c -x c /dev/null", - hfile, ofile); - if (system(cmd) != 0) - errx(1, "Failed to compile %s", hfile); + preprocess(contents); - add_extern_symbols(ofile, repl); -} + while ((stmt = get_statement(contents, &p)) != NULL) { + int i, len; -/* FIXME: Better to analyse headers in more depth, rather than recompile. */ -static void get_exposed_symbols(const char *dir, struct replace **repl) -{ - char **files; - unsigned int i; + /* Definition of struct/union? */ + if ((strncmp(stmt, "struct", 5) == 0 + || strncmp(stmt, "union", 5) == 0) + && strchr(stmt, '{') && stmt[7] != '{') + add_replace_tok(repl, stmt+7); - files = get_dir(dir); - for (i = 0; files[i]; i++) { - char *ofile; - if (!strends(files[i], ".c") || strends(files[i], "/_info.c")) + /* Definition of var or typedef? */ + for (i = strlen(stmt)-1; i >= 0; i--) + if (strspn(stmt+i, IDENT_CHARS) == 0) + break; + + if (i != strlen(stmt)-1) { + add_replace_tok(repl, stmt+i+1); continue; + } - /* This produces file.c -> file.o */ - ofile = build_obj(files[i]); - verbose("Looking in %s\n", ofile); - verbose_indent(); - add_extern_symbols(ofile, repl); - unlink(ofile); - verbose_unindent(); + /* function or array declaration? */ + len = strspn(stmt, IDENT_CHARS "* "); + if (len > 0 && (stmt[len] == '(' || stmt[len] == '[')) { + if (strspn(stmt + len + 1, IDENT_CHARS) != 0) { + for (i = len-1; i >= 0; i--) + if (strspn(stmt+i, IDENT_CHARS) == 0) + break; + if (i != len-1) { + add_replace_tok(repl, stmt+i+1); + continue; + } + } else { + /* Pointer to function? */ + len++; + len += strspn(stmt + len, " *"); + i = strspn(stmt + len, IDENT_CHARS); + if (i > 0 && stmt[len + i] == ')') + add_replace_tok(repl, stmt+len); + } + } } - get_header_symbols(dir, repl); +} + +/* FIXME: Only does main header, should chase local includes. */ +static void analyze_headers(const char *dir, struct replace **repl) +{ + char *hdr, *contents; + + /* Get hold of header, assume that's it. */ + hdr = talloc_asprintf(dir, "%s/%s.h", dir, basename(dir, dir)); + contents = grab_file(dir, hdr); + if (!contents) + err(1, "Reading %s", hdr); + + verbose("Looking in %s for macros\n", hdr); + verbose_indent(); + look_for_macros(contents, repl); + verbose_unindent(); + + verbose("Looking in %s for symbols\n", hdr); + verbose_indent(); + look_for_definitions(contents, repl); + verbose_unindent(); } static void write_replacement_file(const char *dir, struct replace **repl) @@ -472,7 +545,6 @@ static void convert_dir(const char *dir) name[strlen(name)-1] = '\0'; analyze_headers(name, &replace); - get_exposed_symbols(name, &replace); write_replacement_file(name, &replace); setup_adjust_files(name, replace, &adj); rename_files(adj); -- 2.39.2