Skip to content
Browse files

Added more configurable include scanner.

  • Loading branch information...
1 parent 014cd1d commit 9ba4c0da78ecd41f4337dd80f895721eb0884192 @deplinenoise committed Nov 27, 2011
Showing with 264 additions and 30 deletions.
  1. +1 −0 CMakeLists.txt
  2. +4 −2 src/cpp_scanner.c
  3. +9 −24 src/engine.c
  4. +201 −0 src/generic_scanner.c
  5. +4 −3 src/scanner.c
  6. +9 −1 src/scanner.h
  7. +2 −0 src/tundra.c
  8. +29 −0 src/util.c
  9. +4 −0 src/util.h
  10. +1 −0 units.lua
View
1 CMakeLists.txt
@@ -85,6 +85,7 @@ src/exec_unix.c
src/exec_win32.c
src/files.c
src/files.h
+src/generic_scanner.c
src/luafs.c
src/md5.h
src/md5.c
View
6 src/cpp_scanner.c
@@ -34,7 +34,7 @@
/* a simple c preprocessor #include scanner */
static int
-scan_line(td_alloc *scratch, const char *start, td_include_data *dest)
+cpp_scan_line(td_alloc *scratch, const char *start, td_include_data *dest, td_scanner *scanner)
{
char separator;
const char *str_start;
@@ -67,6 +67,8 @@ scan_line(td_alloc *scratch, const char *start, td_include_data *dest)
}
else
dest->is_system_include = 0;
+
+ dest->should_follow = 1;
str_start = start;
for (;;)
@@ -89,7 +91,7 @@ static int make_cpp_scanner(lua_State *L)
td_scanner *self = (td_scanner *) td_alloc_scanner(engine, L, sizeof(td_scanner));
self->ident = "cpp";
- self->scan_fn = &scan_line;
+ self->scan_fn = &cpp_scan_line;
self->include_paths = td_build_file_array(L, engine, 2, &self->path_count);
td_call_cache_hook(L, &td_scanner_hook_key, 2, lua_gettop(L));
View
33 src/engine.c
@@ -299,21 +299,6 @@ td_engine_get_file(td_engine *engine, const char *input_path, td_get_file_mode m
return f;
}
-static int get_int_override(lua_State *L, int index, const char *field_name, int default_value)
-{
- int val = default_value;
- lua_getfield(L, index, field_name);
- if (!lua_isnil(L, -1))
- {
- if (lua_isnumber(L, -1))
- val = (int) lua_tointeger(L, -1);
- else
- luaL_error(L, "%s: expected an integer, found %s", field_name, lua_typename(L, lua_type(L, -1)));
- }
- lua_pop(L, 1);
- return val;
-}
-
static void configure_from_env(td_engine *engine)
{
const char *tmp;
@@ -367,15 +352,15 @@ static int make_engine(lua_State *L)
/* apply optional overrides */
if (1 <= lua_gettop(L) && lua_istable(L, 1))
{
- self->file_hash_size = get_int_override(L, 1, "FileHashSize", self->file_hash_size);
- self->relhash_size = get_int_override(L, 1, "RelationHashSize", self->relhash_size);
- self->settings.debug_flags = get_int_override(L, 1, "DebugFlags", 0);
- self->settings.verbosity = get_int_override(L, 1, "Verbosity", 0);
- self->settings.thread_count = get_int_override(L, 1, "ThreadCount", self->settings.thread_count);
- self->settings.dry_run = get_int_override(L, 1, "DryRun", 0);
- self->settings.continue_on_error = get_int_override(L, 1, "ContinueOnError", 0);
- use_digest_signing = get_int_override(L, 1, "UseDigestSigning", 0);
- debug_signing = get_int_override(L, 1, "DebugSigning", 0);
+ self->file_hash_size = td_get_int_override(L, 1, "FileHashSize", self->file_hash_size);
+ self->relhash_size = td_get_int_override(L, 1, "RelationHashSize", self->relhash_size);
+ self->settings.debug_flags = td_get_int_override(L, 1, "DebugFlags", 0);
+ self->settings.verbosity = td_get_int_override(L, 1, "Verbosity", 0);
+ self->settings.thread_count = td_get_int_override(L, 1, "ThreadCount", self->settings.thread_count);
+ self->settings.dry_run = td_get_int_override(L, 1, "DryRun", 0);
+ self->settings.continue_on_error = td_get_int_override(L, 1, "ContinueOnError", 0);
+ use_digest_signing = td_get_int_override(L, 1, "UseDigestSigning", 0);
+ debug_signing = td_get_int_override(L, 1, "DebugSigning", 0);
}
self->file_hash = (td_file **) calloc(sizeof(td_file*), self->file_hash_size);
View
201 src/generic_scanner.c
@@ -0,0 +1,201 @@
+/*
+ Copyright 2011 Andreas Fredriksson
+
+ This file is part of Tundra.
+
+ Tundra is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Tundra is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Tundra. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "engine.h"
+#include "util.h"
+#include "scanner.h"
+
+#include <ctype.h>
+#include <lua.h>
+#include <lauxlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+/* A scanner that can be configured to handle simple include patterns */
+
+enum {
+ MAX_KEYWORDS = 8,
+ KWSET_FOLLOW = 0, /* for source files */
+ KWSET_NOFOLLOW = 1, /* for binary files */
+ KWSET_COUNT = 2
+};
+
+typedef struct {
+ int keyword_count;
+ const char *keywords[MAX_KEYWORDS];
+ int keyword_lens[MAX_KEYWORDS];
+} keyword_set;
+
+typedef struct {
+ td_scanner base;
+
+ /* if true, line must start with whitespace; required by some assembler syntaxes */
+ int require_whitespace;
+ /* if true, look for " or < separators */
+ int use_separators;
+ /* if true, and use_separators=0, use system include path for everything picked up */
+ int bare_means_system;
+
+ keyword_set kwsets[KWSET_COUNT];
+
+} generic_scanner;
+
+static int
+generic_scan_line(td_alloc *scratch, const char *start_in, td_include_data *dest, td_scanner *scanner_)
+{
+ generic_scanner *scanner = (generic_scanner*) scanner_;
+ char separator;
+ int kw, kwcount, kwset;
+ const char *start = start_in;
+ const char *str_start;
+
+ while (isspace(*start))
+ ++start;
+
+ if (scanner->require_whitespace && start == start_in)
+ return 0;
+
+ for (kwset = 0; kwset < KWSET_COUNT; ++kwset)
+ {
+ const keyword_set *set = &scanner->kwsets[kwset];
+ for (kw = 0, kwcount = set->keyword_count; kw < kwcount; ++kw)
+ {
+ if (0 == strncmp(set->keywords[kw], start, set->keyword_lens[kw]))
+ break;
+ }
+
+ if (kwcount != kw)
+ break;
+ }
+
+ if (kwset == KWSET_COUNT)
+ return 0;
+
+ start += scanner->kwsets[kwset].keyword_lens[kw];
+
+ if (!isspace(*start++))
+ return 0;
+
+ while (isspace(*start))
+ ++start;
+
+ if (scanner->use_separators)
+ {
+ separator = *start++;
+ if ('<' == separator)
+ {
+ dest->is_system_include = 1;
+ separator = '>';
+ }
+ else
+ dest->is_system_include = 0;
+
+ str_start = start;
+ for (;;)
+ {
+ char ch = *start++;
+ if (ch == separator)
+ break;
+ if (!ch)
+ return 0;
+ }
+ }
+ else
+ {
+ const char *p = start;
+
+ /* just grab the next token */
+ while (*start && !isspace(*start))
+ ++start;
+
+ if (p == start)
+ return 0;
+
+ dest->is_system_include = scanner->bare_means_system;
+ }
+
+ dest->string_len = (unsigned short) (start - str_start - 1);
+ dest->string = td_page_strdup(scratch, str_start, dest->string_len);
+ dest->should_follow = kwset == KWSET_FOLLOW;
+ return 1;
+}
+
+static void setup_kwset(lua_State *L, td_engine *engine, const char *key, keyword_set *dest)
+{
+ int i, numkw;
+
+ lua_getfield(L, 3, key);
+ if (lua_isnil(L, -1))
+ luaL_error(L, "expected %s parameter");
+
+ numkw = (int) lua_objlen(L, -1);
+
+ if (numkw <= 0 || numkw > MAX_KEYWORDS)
+ luaL_error(L, "%s: need between 1 and %d keywords, got %d", key, MAX_KEYWORDS, numkw);
+
+ dest->keyword_count = numkw;
+
+ for (i = 0; i < numkw; ++i)
+ {
+ size_t len;
+ const char *txt;
+ lua_rawgeti(L, -1, i + 1);
+ txt = lua_tolstring(L, -1, &len);
+ dest->keywords[i] = td_page_strdup(&engine->alloc, txt, (int)len);
+ dest->keyword_lens[i] = (int) len;
+ lua_pop(L, 1);
+ }
+
+ lua_pop(L, 1);
+}
+
+static int make_generic_scanner(lua_State *L)
+{
+ td_engine *engine = td_check_engine(L, 1);
+ generic_scanner *self = (generic_scanner *) td_alloc_scanner(engine, L, sizeof(generic_scanner));
+
+ self->base.ident = "generic";
+ self->base.scan_fn = &generic_scan_line;
+ self->base.include_paths = td_build_file_array(L, engine, 2, &self->base.path_count);
+
+ setup_kwset(L, engine, "Keywords", &self->kwsets[KWSET_FOLLOW]);
+ setup_kwset(L, engine, "KeywordsNoFollow", &self->kwsets[KWSET_NOFOLLOW]);
+
+ self->require_whitespace = td_get_int_override(L, 3, "RequireWhitespace", 0);
+ self->use_separators = td_get_int_override(L, 3, "UseSeparators", 0);
+ self->bare_means_system = td_get_int_override(L, 3, "BareMeansSystem", 0);
+
+ td_call_cache_hook(L, &td_scanner_hook_key, 2, lua_gettop(L));
+
+ return 1;
+}
+
+static const luaL_Reg generic_scanner_entries[] = {
+ { "make_generic_scanner", make_generic_scanner },
+ { NULL, NULL },
+};
+
+int td_generic_scanner_open(lua_State *L)
+{
+ luaL_newmetatable(L, TUNDRA_ENGINE_MTNAME);
+ luaL_register(L, NULL, generic_scanner_entries);
+ lua_pop(L, 1);
+ return 0;
+}
View
7 src/scanner.c
@@ -117,7 +117,7 @@ find_file(td_file *base_file, td_engine *engine, const td_include_data *inc, con
}
static int
-scan_file_data(td_alloc *scratch, td_file *file, td_include_data *out, int max_count, td_scan_fn *line_scanner)
+scan_file_data(td_alloc *scratch, td_file *file, td_include_data *out, int max_count, td_scanner *scanner)
{
FILE *f;
int file_count = 0;
@@ -126,6 +126,7 @@ scan_file_data(td_alloc *scratch, td_file *file, td_include_data *out, int max_c
char *buffer_start = line_buffer;
int buffer_size = sizeof(line_buffer);
static const unsigned char utf8_mark[] = { 0xef, 0xbb, 0xbf };
+ td_scan_fn *line_scanner = scanner->scan_fn;
if (NULL == (f = fopen(file->path, "r")))
return 0;
@@ -157,7 +158,7 @@ scan_file_data(td_alloc *scratch, td_file *file, td_include_data *out, int max_c
*p = 0;
if (file_count == max_count)
td_croak("%s: too many includes", file->path);
- file_count += (*line_scanner)(scratch, line, &out[file_count]);
+ file_count += (*line_scanner)(scratch, line, &out[file_count], scanner);
line = p+1;
}
}
@@ -206,7 +207,7 @@ scan_file(
if (td_debug_check(engine, TD_DEBUG_SCAN))
printf("%s: scanning\n", file->path);
- count = scan_file_data(scratch, file, &includes[0], sizeof(includes)/sizeof(includes[0]), scanner->scan_fn);
+ count = scan_file_data(scratch, file, &includes[0], sizeof(includes)/sizeof(includes[0]), scanner);
for (i = 0; i < count; ++i)
{
View
10 src/scanner.h
@@ -33,9 +33,17 @@ typedef struct td_include_data_tag {
const char *string;
unsigned short string_len;
unsigned char is_system_include;
+ unsigned char should_follow;
} td_include_data;
-typedef int (td_scan_fn)(struct td_alloc *scratch, const char *start, td_include_data *dest);
+struct td_scanner;
+
+/* Callback to scan each line of the file. */
+typedef int (td_scan_fn)(
+ struct td_alloc *scratch,
+ const char *start,
+ td_include_data *dest,
+ struct td_scanner *scanner);
typedef struct td_scanner {
const char *ident;
View
2 src/tundra.c
@@ -144,6 +144,7 @@ extern int tundra_walk_path(lua_State*);
extern void td_engine_open(lua_State*);
extern int td_scanner_open(lua_State*);
extern int td_cpp_scanner_open(lua_State*);
+extern int td_generic_scanner_open(lua_State*);
extern int td_get_cwd(lua_State*);
extern int td_set_cwd(lua_State*);
extern int td_sanitize_lua_path(lua_State*);
@@ -182,6 +183,7 @@ static int tundra_open(lua_State *L)
td_engine_open(L);
td_scanner_open(L);
td_cpp_scanner_open(L);
+ td_generic_scanner_open(L);
lua_pop(L, 1);
return 0;
}
View
29 src/util.c
@@ -281,3 +281,32 @@ td_sort_file_array(td_file **files, int count)
qsort(files, (size_t) count, sizeof(td_file *), compare_file_paths);
}
+int td_get_int_override(lua_State *L, int index, const char *field_name, int default_value)
+{
+ int val = default_value;
+ lua_getfield(L, index, field_name);
+ if (!lua_isnil(L, -1))
+ {
+ if (lua_isnumber(L, -1))
+ val = (int) lua_tointeger(L, -1);
+ else
+ luaL_error(L, "%s: expected an integer, found %s", field_name, lua_typename(L, lua_type(L, -1)));
+ }
+ lua_pop(L, 1);
+ return val;
+}
+
+const char *td_get_string_override(lua_State *L, int index, const char *field_name, const char *default_value)
+{
+ const char *val = default_value;
+ lua_getfield(L, index, field_name);
+ if (!lua_isnil(L, -1))
+ {
+ if (lua_isstring(L, -1))
+ val = lua_tostring(L, -1);
+ else
+ luaL_error(L, "%s: expected a string, found %s", field_name, lua_typename(L, lua_type(L, -1)));
+ }
+ lua_pop(L, 1);
+ return val;
+}
View
4 src/util.h
@@ -56,6 +56,10 @@ struct td_file **td_build_file_array(struct lua_State* L, struct td_engine *allo
const char *td_spaces(int count);
const char *td_indent(int level);
+/* Get a value called "field_name" from the table at index "index", returning that or the default value. */
+int td_get_int_override(struct lua_State *L, int index, const char *field_name, int default_value);
+const char *td_get_string_override(struct lua_State *L, int index, const char *field_name, const char *default_value);
+
typedef enum {
TD_BUILD_REPLACE_NAME,
TD_BUILD_CONCAT,
View
1 units.lua
@@ -68,6 +68,7 @@ Program {
"src/debug.c",
"src/engine.c",
"src/files.c",
+ "src/generic_scanner.c",
"src/luafs.c",
"src/md5.c",
"src/scanner.c",

0 comments on commit 9ba4c0d

Please sign in to comment.
Something went wrong with that request. Please try again.