diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/scanner.l | 132 |
1 files changed, 109 insertions, 23 deletions
diff --git a/src/scanner.l b/src/scanner.l index c2c008d6..fe65e0c6 100644 --- a/src/scanner.l +++ b/src/scanner.l @@ -10,6 +10,8 @@ %{ +#include <dirent.h> +#include <libgen.h> #include <limits.h> #include <netinet/in.h> #include <arpa/inet.h> @@ -637,8 +639,8 @@ static struct error_record *scanner_push_file(void *scanner, const char *filenam return NULL; } -int scanner_read_file(void *scanner, const char *filename, - const struct location *loc) +static int include_file(void *scanner, const char *filename, + const struct location *loc) { struct parser_state *state = yyget_extra(scanner); struct error_record *erec; @@ -655,12 +657,94 @@ int scanner_read_file(void *scanner, const char *filename, if (erec != NULL) goto err; return 0; +err: + erec_queue(erec, state->msgs); + return -1; +} +int scanner_read_file(void *scanner, const char *filename, + const struct location *loc) +{ + return include_file(scanner, filename, loc); +} + +static int include_directory(void *scanner, const char *dirname, + DIR *directory, const struct location *loc) +{ + struct parser_state *state = yyget_extra(scanner); + struct error_record *erec; + struct dirent *de; + FILE *f; + int ret; + + if (!dirname[0] || dirname[strlen(dirname)-1] != '/') { + erec = error(loc, "Include directory name \"%s\" does not end in '/'", + dirname); + goto err; + } + + /* If the path is a directory, assume that all files there need + * to be included. + */ + while ((de = readdir(directory))) { + char dirbuf[PATH_MAX]; + + ret = snprintf(dirbuf, sizeof(dirbuf), "%s/%s", dirname, + de->d_name); + if (ret < 0 || ret >= PATH_MAX) { + erec = error(loc, "Too long file path \"%s/%s\"\n", + dirname, de->d_name); + goto err; + } + + if (strcmp(de->d_name, ".") == 0 || + strcmp(de->d_name, "..") == 0) + continue; + + f = fopen(dirbuf, "r"); + if (f == NULL) { + erec = error(loc, "Could not open file \"%s\": %s\n", + dirbuf, strerror(errno)); + goto err; + } + + erec = scanner_push_file(scanner, de->d_name, f, loc); + if (erec != NULL) + goto err; + } + return 0; err: erec_queue(erec, state->msgs); return -1; } +static int include_dentry(void *scanner, const char *filename, + const struct location *loc) +{ + DIR *directory; + int ret; + + /* The file can be either a simple file or a directory which + * contains files. + */ + directory = opendir(filename); + if (directory == NULL && + errno != ENOTDIR) { + /* Could not access the directory or file, keep on searching. + * Return value '1' indicates to the caller that we should still + * search in the next include directory. + */ + ret = 1; + } else if (directory != NULL) { + ret = include_directory(scanner, filename, directory, loc); + closedir(directory); + } else { + ret = include_file(scanner, filename, loc); + } + + return ret; +} + static bool search_in_include_path(const char *filename) { return (strncmp(filename, "./", strlen("./")) != 0 && @@ -674,37 +758,39 @@ int scanner_include_file(void *scanner, const char *filename, struct parser_state *state = yyget_extra(scanner); struct error_record *erec; char buf[PATH_MAX]; - const char *name = buf; unsigned int i; - FILE *f; + int ret; - f = NULL; if (search_in_include_path(filename)) { for (i = 0; i < INCLUDE_PATHS_MAX; i++) { if (include_paths[i] == NULL) break; - snprintf(buf, sizeof(buf), "%s/%s", - include_paths[i], filename); - f = fopen(buf, "r"); - if (f != NULL) - break; + ret = snprintf(buf, sizeof(buf), "%s/%s", + include_paths[i], filename); + if (ret < 0 || ret >= PATH_MAX) { + erec = error(loc, "Too long file path \"%s/%s\"\n", + include_paths[i], filename); + erec_queue(erec, state->msgs); + return -1; + } + + ret = include_dentry(scanner, buf, loc); + if (ret == 0) + return 0; + else if (ret != 1) + /* error has been processed already */ + return -1; } } else { - f = fopen(filename, "r"); - name = filename; - } - if (f == NULL) { - erec = error(loc, "Could not open file \"%s\": %s", - filename, strerror(errno)); - goto err; + ret = include_dentry(scanner, filename, loc); + if (ret == 0) + return 0; + else if (ret != 1) + return -1; + /* else fall through to "not found" processing */ } - erec = scanner_push_file(scanner, name, f, loc); - if (erec != NULL) - goto err; - return 0; - -err: + erec = error(loc, "Did not find \"%s\"\n", filename); erec_queue(erec, state->msgs); return -1; } |