summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/scanner.l132
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;
}