[Ltrace-devel] [PATCH 2/2] Add a way to force a line to be interpreted as a function prototype

Роман Донченко dpb at corrigendum.ru
Sun May 10 16:08:18 UTC 2015


Since "import" is not a keyword in C, it might be used as a type name.
However, a function prototype with "import" as the return type would
be interpreted as an import directive. So provide a new keyword,
"function", that can be used to force a line to be interpreted as a
prototype.

Naturally, the new keyword will also work if the return type is
"function" or "typedef".
---
 ltrace.conf.5                         |  9 +++-
 read_config_file.c                    | 87 ++++++++++++++++++++---------------
 testsuite/ltrace.main/parameters2.exp | 22 +++++++++
 3 files changed, 79 insertions(+), 39 deletions(-)

diff --git a/ltrace.conf.5 b/ltrace.conf.5
index a0579dc..cca35a5 100644
--- a/ltrace.conf.5
+++ b/ltrace.conf.5
@@ -40,12 +40,17 @@ A prototype describes return type and parameter types of a single
 function.  The syntax is as follows:
 
 .RS
-\fILENS\fR \fINAME\fR \fB(\fR[\fILENS\fR{,\fILENS\fR}]\fB);\fR
+[\fBfunction\fR] \fILENS\fR \fINAME\fR \fB(\fR[\fILENS\fR{,\fILENS\fR}]\fB);\fR
 .RE
 
 \fINAME\fR is the (mangled) name of a symbol.  In the elementary case,
 \fILENS\fR is simply a type.  Both lenses and types are described
-below.  For example, a simple function prototype might look like this:
+below.  The \fBfunction\fR keyword, if present, has no effect.  It can be
+used to force a line to be interpreted as a function prototype when the
+return type is a keyword that would start a different type of line
+(such as \fBimport\fR).
+
+For example, a simple function prototype might look like this:
 
 .RS
 .B int\fR kill\fB(int,int);
diff --git a/read_config_file.c b/read_config_file.c
index 336268a..1f1e948 100644
--- a/read_config_file.c
+++ b/read_config_file.c
@@ -1112,27 +1112,9 @@ parse_import(struct protolib_cache *cache, struct protolib *plib,
 }
 
 static void
-process_line(struct protolib_cache *cache, struct protolib *plib,
-             struct locus *loc, char *buf)
+parse_prototype(struct protolib *plib, struct locus *loc, char **str)
 {
-	char *str = buf;
-
-	debug(3, "Reading line %d of `%s'", loc->line_no, loc->filename);
-	skip_whitespace(&str);
-
-	/* A comment or empty line.  */
-	if (*str == ';' || *str == 0 || *str == '\n' || *str == '#')
-		return;
-
-	if (try_parse_kwd(&str, "import") >= 0) {
-		parse_import(cache, plib, loc, &str);
-		return;
-	}
-
-	if (try_parse_kwd(&str, "typedef") >= 0) {
-		parse_typedef(plib, loc, &str);
-		return;
-	}
+	skip_whitespace(str);
 
 	struct prototype fun;
 	prototype_init(&fun);
@@ -1140,7 +1122,7 @@ process_line(struct protolib_cache *cache, struct protolib *plib,
 	struct param *extra_param = NULL;
 	char *proto_name = NULL;
 	int own;
-	fun.return_info = parse_lens(plib, loc, &str, NULL, 0, &own, NULL);
+	fun.return_info = parse_lens(plib, loc, str, NULL, 0, &own, NULL);
 	if (fun.return_info == NULL) {
 	err:
 		debug(3, " Skipping line %d", loc->line_no);
@@ -1157,24 +1139,24 @@ process_line(struct protolib_cache *cache, struct protolib *plib,
 	fun.own_return_info = own;
 	debug(4, " return_type = %d", fun.return_info->type);
 
-	skip_whitespace(&str);
-	proto_name = parse_ident(loc, &str);
+	skip_whitespace(str);
+	proto_name = parse_ident(loc, str);
 	if (proto_name == NULL)
 		goto err;
 
-	skip_whitespace(&str);
-	if (parse_char(loc, &str, '(') < 0)
+	skip_whitespace(str);
+	if (parse_char(loc, str, '(') < 0)
 		goto err;
 	debug(3, " name = %s", proto_name);
 
 	int have_stop = 0;
 
 	while (1) {
-		skip_whitespace(&str);
-		if (*str == ')')
+		skip_whitespace(str);
+		if (**str == ')')
 			break;
 
-		if (str[0] == '+') {
+		if (**str == '+') {
 			if (have_stop == 0) {
 				struct param param;
 				param_init_stop(&param);
@@ -1187,13 +1169,13 @@ process_line(struct protolib_cache *cache, struct protolib *plib,
 				}
 				have_stop = 1;
 			}
-			str++;
+			(*str)++;
 		}
 
 		int own;
 		size_t param_num = prototype_num_params(&fun) - have_stop;
 		struct arg_type_info *type
-			= parse_lens(plib, loc, &str, &extra_param,
+			= parse_lens(plib, loc, str, &extra_param,
 				     param_num, &own, NULL);
 		if (type == NULL) {
 			report_error(loc->filename, loc->line_no,
@@ -1206,17 +1188,17 @@ process_line(struct protolib_cache *cache, struct protolib *plib,
 		if (prototype_push_param(&fun, &param) < 0)
 			goto oom;
 
-		skip_whitespace(&str);
-		if (*str == ',') {
-			str++;
+		skip_whitespace(str);
+		if (**str == ',') {
+			(*str)++;
 			continue;
-		} else if (*str == ')') {
+		} else if (**str == ')') {
 			continue;
 		} else {
-			if (str[strlen(str) - 1] == '\n')
-				str[strlen(str) - 1] = '\0';
+			if ((*str)[strlen(*str) - 1] == '\n')
+				(*str)[strlen(*str) - 1] = '\0';
 			report_error(loc->filename, loc->line_no,
-				     "syntax error around \"%s\"", str);
+				     "syntax error around \"%s\"", *str);
 			goto err;
 		}
 	}
@@ -1260,6 +1242,37 @@ process_line(struct protolib_cache *cache, struct protolib *plib,
 	}
 }
 
+static void
+process_line(struct protolib_cache *cache, struct protolib *plib,
+             struct locus *loc, char *buf)
+{
+	char *str = buf;
+
+	debug(3, "Reading line %d of `%s'", loc->line_no, loc->filename);
+	skip_whitespace(&str);
+
+	/* A comment or empty line.  */
+	if (*str == ';' || *str == 0 || *str == '\n' || *str == '#')
+		return;
+
+	if (try_parse_kwd(&str, "function") >= 0) {
+		parse_prototype(plib, loc, &str);
+		return;
+	}
+
+	if (try_parse_kwd(&str, "import") >= 0) {
+		parse_import(cache, plib, loc, &str);
+		return;
+	}
+
+	if (try_parse_kwd(&str, "typedef") >= 0) {
+		parse_typedef(plib, loc, &str);
+		return;
+	}
+
+	parse_prototype(plib, loc, &str);
+}
+
 int
 read_config_file(FILE *stream, const char *path,
                  struct protolib_cache *cache, struct protolib *plib)
diff --git a/testsuite/ltrace.main/parameters2.exp b/testsuite/ltrace.main/parameters2.exp
index 29b332a..dadddc6 100644
--- a/testsuite/ltrace.main/parameters2.exp
+++ b/testsuite/ltrace.main/parameters2.exp
@@ -296,4 +296,26 @@ ltraceMatch1 [ltraceLibTest {
  somefunc();
 }] {somefunc\(\)} == 1
 
+# Test that the function keyword works
+
+ltraceMatch [ltraceLibTest {
+    typedef function = int;
+    typedef import = int;
+    typedef typedef = int;
+
+    function function f();
+    function import i();
+    function typedef t();
+} {
+    int f(void);
+    int i(void);
+    int t(void);
+} {
+    int f(void) { return 1; }
+    int i(void) { return 2; }
+    int t(void) { return 3; }
+} {
+    f(); i(); t();
+}] [list [list {f\(\)}] [list {i\(\)}] [list {t\(\)}]]
+
 ltraceDone
-- 
1.8.5.6




More information about the Ltrace-devel mailing list