[Ltrace-devel] [PATCH 3/6] Add an ability to import config files into other config files

Роман Донченко dpb at corrigendum.ru
Mon Apr 20 00:39:24 UTC 2015


Handy for sharing declarations between libraries.
---
 forward.h          |  1 +
 prototype.c        |  2 +-
 read_config_file.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 read_config_file.h |  3 +-
 4 files changed, 87 insertions(+), 5 deletions(-)

diff --git a/forward.h b/forward.h
index 58d8f05..7bdc98c 100644
--- a/forward.h
+++ b/forward.h
@@ -33,6 +33,7 @@ struct param;
 struct param_enum;
 struct process;
 struct protolib;
+struct protolib_cache;
 struct prototype;
 struct timedelta;
 struct value;
diff --git a/prototype.c b/prototype.c
index 22e54c4..b09f945 100644
--- a/prototype.c
+++ b/prototype.c
@@ -639,7 +639,7 @@ protolib_cache_file(struct protolib_cache *cache,
 
 	struct protolib *new_plib = build_default_config(cache, filename);
 	if (new_plib == NULL
-	    || read_config_file(stream, filename, new_plib) < 0) {
+	    || read_config_file(stream, filename, cache, new_plib) < 0) {
 		fclose(stream);
 		if (own_filename)
 			free((char *) filename);
diff --git a/read_config_file.c b/read_config_file.c
index 56e3519..77cf976 100644
--- a/read_config_file.c
+++ b/read_config_file.c
@@ -217,6 +217,42 @@ parse_char(struct locus *loc, char **str, char expected)
 	return 0;
 }
 
+static char *
+parse_string_literal(struct locus *loc, char **str)
+{
+	if (parse_char(loc, str, '"') < 0)
+		return NULL;
+
+	size_t len = strcspn(*str, "\"\n\\");
+	char terminator = (*str)[len];
+
+	if (terminator == '\0' || terminator == '\n') {
+		report_error(loc->filename, loc->line_no, "unmatched quote");
+		return NULL;
+	}
+
+	if (terminator == '\\') {
+		/* Strings are currently only used for filenames, where
+		 * there's usually nothing to escape. Nevertheless, we reserve
+		 * the backslash in case strings become used in other contexts
+		 * where escaping is necessary. */
+		report_error(loc->filename, loc->line_no,
+			     "backslashes in string literals reserved for future use");
+		return NULL;
+	}
+
+	char *result = malloc(len + 1);
+	if (!result) {
+		report_error(loc->filename, loc->line_no,
+			     "malloc: %s", strerror(errno));
+		return NULL;
+	}
+	memcpy(result, *str, len);
+	result[len] = '\0';
+	(*str) += len + 1;
+	return result;
+}
+
 static struct expr_node *parse_argnum(struct locus *loc,
 				      char **str, int *ownp, int zero);
 
@@ -1060,8 +1096,46 @@ void_to_hidden_int(struct prototype *proto, struct param *param, void *data)
 	return CBS_CONT;
 }
 
+static void
+parse_import(struct protolib_cache *cache, struct protolib *plib,
+             struct locus *loc, char **str)
+{
+	(*str) += strlen("import");
+	eat_spaces(str);
+
+	char *file_name = parse_string_literal(loc, str);
+	if (!file_name)
+		return;
+
+	eat_spaces(str);
+	if (parse_char(loc, str, ';') < 0) {
+		free(file_name);
+		return;
+	}
+
+	struct protolib *imported;
+
+	if (protolib_cache_maybe_load(cache, file_name, 1, true, &imported) < 0) {
+		free(file_name);
+		return;
+	}
+
+	if (!imported) {
+		report_error(loc->filename, loc->line_no,
+			     "\"%s.conf\" not found", file_name);
+		free(file_name);
+		return;
+	}
+
+	if (protolib_add_import(plib, imported) < 0) {
+		report_error(loc->filename, loc->line_no,
+			     "import failed");
+	}
+}
+
 static int
-process_line(struct protolib *plib, struct locus *loc, char *buf)
+process_line(struct protolib_cache *cache, struct protolib *plib,
+             struct locus *loc, char *buf)
 {
 	char *str = buf;
 
@@ -1072,6 +1146,11 @@ process_line(struct protolib *plib, struct locus *loc, char *buf)
 	if (*str == ';' || *str == 0 || *str == '\n' || *str == '#')
 		return 0;
 
+	if (strncmp(str, "import ", 7) == 0) {
+		parse_import(cache, plib, loc, &str);
+		return 0;
+	}
+
 	if (strncmp(str, "typedef ", 8) == 0) {
 		parse_typedef(plib, loc, &str);
 		return 0;
@@ -1206,7 +1285,8 @@ process_line(struct protolib *plib, struct locus *loc, char *buf)
 }
 
 int
-read_config_file(FILE *stream, const char *path, struct protolib *plib)
+read_config_file(FILE *stream, const char *path,
+                 struct protolib_cache *cache, struct protolib *plib)
 {
 	debug(DEBUG_FUNCTION, "Reading config file `%s'...", path);
 
@@ -1215,7 +1295,7 @@ read_config_file(FILE *stream, const char *path, struct protolib *plib)
 	size_t len = 0;
 	while (getline(&line, &len, stream) >= 0) {
 		loc.line_no++;
-		process_line(plib, &loc, line);
+		process_line(cache, plib, &loc, line);
 	}
 
 	free(line);
diff --git a/read_config_file.h b/read_config_file.h
index 5a72a05..f5fc738 100644
--- a/read_config_file.h
+++ b/read_config_file.h
@@ -23,6 +23,7 @@
 
 #include "forward.h"
 
-int read_config_file(FILE *stream, const char *name, struct protolib *plib);
+int read_config_file(FILE *stream, const char *name,
+                     struct protolib_cache *cache, struct protolib *plib);
 
 #endif /* READ_CONFIG_FILE_H */
-- 
1.8.5.6




More information about the Ltrace-devel mailing list