threads / patch / 4023

patchrepo-config: support --get-regexp and fix crash

Subject: [PATCH] repo-config: support --get-regexp and fix crash

## tl;dr

5 messages between May 2, 2006 and May 3, 2006. Diffs are folded; open one to read it.

replies: 4people: 2as markdown or json

Johannes Schindelin· May 2, 2006, 12:22 UTC · lore

With --get-regexp, output all key/value pairs where the key matches a regexp. Example:

	git-repo-config --get-regexp remote.*.url
will output something like
	remote.junio.url git://git.kernel.org/pub/scm/git/git.git
	remote.gitk.url git://git.kernel.org/pub/scm/gitk/gitk.git

This also fixes a crash when no arguments are given, which was introduced with the "-l" and "--list" handling.

Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
---
	Junio made me aware of a crash, a fix for which was too easy to
	merit a separate patch.
	Strange thing I realized: A value is white-space-trimmed at the end
	only if the line does not end with a comment. This fact is accounted
	for in the new tests.
 Documentation/git-repo-config.txt |    5 +++-
 repo-config.c                     |   45 +++++++++++++++++++++++++++++--------
 t/t1300-repo-config.sh            |   23 +++++++++++++++++++
 3 files changed, 62 insertions(+), 11 deletions(-)
Show changes to 3 files +62 −11

Documentation/git-repo-config.txt, repo-config.c, t/t1300-repo-config.sh

diff --git a/Documentation/git-repo-config.txt b/Documentation/git-repo-config.txt
index 566cfa1..ddcf523 100644
--- a/Documentation/git-repo-config.txt
+++ b/Documentation/git-repo-config.txt
@@ -49,7 +49,7 @@ OPTIONS
 
 --replace-all::
 	Default behaviour is to replace at most one line. This replaces
-	all lines matching the key (and optionally the value_regex)
+	all lines matching the key (and optionally the value_regex).
 
 --get::
 	Get the value for a given key (optionally filtered by a regex
@@ -59,6 +59,9 @@ OPTIONS
 	Like get, but does not fail if the number of values for the key
 	is not exactly one.
 
+--get-regexp::
+	Like --get-all, but interprets the name as a regular expression.
+
 --unset::
 	Remove the line matching the key from .git/config.
 
diff --git a/repo-config.c b/repo-config.c
index fa8aba7..722153c 100644
--- a/repo-config.c
+++ b/repo-config.c
@@ -6,7 +6,10 @@ static const char git_config_set_usage[]
 
 static char* key = NULL;
 static char* value = NULL;
+static regex_t* key_regexp = NULL;
 static regex_t* regexp = NULL;
+static int show_keys = 0;
+static int use_key_regexp = 0;
 static int do_all = 0;
 static int do_not_match = 0;
 static int seen = 0;
@@ -26,16 +29,18 @@ static int show_config(const char* key_,
 	if (value_ == NULL)
 		value_ = "";
 
-	if (!strcmp(key_, key) &&
+	if ((use_key_regexp || !strcmp(key_, key)) &&
+			(!use_key_regexp ||
+			 !regexec(key_regexp, key_, 0, NULL, 0)) &&
 			(regexp == NULL ||
 			 (do_not_match ^
 			  !regexec(regexp, value_, 0, NULL, 0)))) {
-		if (do_all) {
-			printf("%s\n", value_);
-			return 0;
-		}
+		if (show_keys)
+			printf("%s ", key_);
 		if (seen > 0) {
-			fprintf(stderr, "More than one value: %s\n", value);
+			if (!do_all)
+				fprintf(stderr, "More than one value: %s\n",
+						value);
 			free(value);
 		}
 
@@ -50,6 +55,8 @@ static int show_config(const char* key_,
 			value = strdup(value_);
 		}
 		seen++;
+		if (do_all)
+			printf("%s\n", value);
 	}
 	return 0;
 }
@@ -63,6 +70,14 @@ static int get_value(const char* key_, c
 		key[i] = tolower(key_[i]);
 	key[i] = 0;
 
+	if (use_key_regexp) {
+		key_regexp = (regex_t*)malloc(sizeof(regex_t));
+		if (regcomp(key_regexp, key, REG_EXTENDED)) {
+			fprintf(stderr, "Invalid key pattern: %s\n", regex_);
+			return -1;
+		}
+	}
+
 	if (regex_) {
 		if (regex_[0] == '!') {
 			do_not_match = 1;
@@ -78,7 +93,8 @@ static int get_value(const char* key_, c
 
 	git_config(show_config);
 	if (value) {
-		printf("%s\n", value);
+		if (!do_all)
+			printf("%s\n", value);
 		free(value);
 	}
 	free(key);
@@ -102,15 +118,14 @@ int main(int argc, const char **argv)
 			type = T_INT;
 		else if (!strcmp(argv[1], "--bool"))
 			type = T_BOOL;
+		else if (!strcmp(argv[1], "--list") || !strcmp(argv[1], "-l"))
+			return git_config(show_all_config);
 		else
 			break;
 		argc--;
 		argv++;
 	}
 
-	if (!strcmp(argv[1], "--list") || !strcmp(argv[1], "-l"))
-		return git_config(show_all_config);
-
 	switch (argc) {
 	case 2:
 		return get_value(argv[1], NULL);
@@ -124,6 +139,11 @@ int main(int argc, const char **argv)
 		else if (!strcmp(argv[1], "--get-all")) {
 			do_all = 1;
 			return get_value(argv[2], NULL);
+		} else if (!strcmp(argv[1], "--get-regexp")) {
+			show_keys = 1;
+			use_key_regexp = 1;
+			do_all = 1;
+			return get_value(argv[2], NULL);
 		} else
 
 			return git_config_set(argv[1], argv[2]);
@@ -137,6 +157,11 @@ int main(int argc, const char **argv)
 		else if (!strcmp(argv[1], "--get-all")) {
 			do_all = 1;
 			return get_value(argv[2], argv[3]);
+		} else if (!strcmp(argv[1], "--get-regexp")) {
+			show_keys = 1;
+			use_key_regexp = 1;
+			do_all = 1;
+			return get_value(argv[2], argv[3]);
 		} else if (!strcmp(argv[1], "--replace-all"))
 
 			return git_config_set_multivar(argv[2], argv[3], NULL, 1);
diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh
index ab4dd5c..52e8e33 100755
--- a/t/t1300-repo-config.sh
+++ b/t/t1300-repo-config.sh
@@ -247,6 +247,24 @@ EOF
 
 test_expect_success 'hierarchical section value' 'cmp .git/config expect'
 
+cat > expect << EOF
+beta.noindent=sillyValue 
+nextsection.nonewline=wow2 for me
+123456.a123=987
+1.2.3.alpha=beta
+EOF
+
+test_expect_success 'working --list' \
+	'git-repo-config --list > output && cmp output expect'
+
+cat > expect << EOF
+beta.noindent sillyValue 
+nextsection.nonewline wow2 for me
+EOF
+
+test_expect_success '--get-regexp' \
+	'git-repo-config --get-regexp in > output && cmp output expect'
+
 cat > .git/config << EOF
 [novalue]
 	variable
@@ -255,5 +273,10 @@ EOF
 test_expect_success 'get variable with no value' \
 	'git-repo-config --get novalue.variable ^$'
 
+git-repo-config > output 2>&1
+
+test_expect_success 'no arguments, but no crash' \
+	"test $? = 129 && grep usage output"
+
 test_done
 
Junio C Hamano· May 2, 2006, 23:30 UTC · re: Johannes Schindelin · lore

Re: [PATCH] repo-config: support --get-regexp and fix crash

Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
> 	Junio made me aware of a crash, a fix for which was too easy to
> 	merit a separate patch.

Not really. The fix is clean-and-obvious, and is readily applicable to "master" without being cooked in "next". On the other hand, --get-regexp may or may not be so; by conflating the two, you are delaying the trivial and useful fix unnecessarily.

I already split the patch and applied the fix on "master", while keeping the rest in "pu" (sorry, I ran out of patience to test everything to put it in "next" -- will do so tomorrow).

It is usually a good idea to avoid making an otherwise good clean patch a hostage to new features (intentionally or accidentally).

> 	Strange thing I realized: A value is white-space-trimmed at the end
> 	only if the line does not end with a comment. This fact is accounted
> 	for in the new tests.

Thanks - a note like this helps me quite a bit, because I usually apply e-mailed patches with --whitespace=strip, which would have destroyed the test, leaving me scratching my head without such a notice.

Johannes Schindelin· May 3, 2006, 11:55 UTC · re: Junio C Hamano · lore

Re: [PATCH] repo-config: support --get-regexp and fix crash

Hi,
On Tue, 2 May 2006, Junio C Hamano wrote:
Show 6 quoted lines
> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
> 
> > 	Junio made me aware of a crash, a fix for which was too easy to
> > 	merit a separate patch.
> 
> Not really.
Right. I was just too lazy.
Show 8 quoted lines
> > 	Strange thing I realized: A value is white-space-trimmed at the end
> > 	only if the line does not end with a comment. This fact is accounted
> > 	for in the new tests.
> 
> Thanks - a note like this helps me quite a bit, because I
> usually apply e-mailed patches with --whitespace=strip, which
> would have destroyed the test, leaving me scratching my head
> without such a notice.

Apparently, I hid that note well: somebody complained privately that my patch is not white-space clean.

As for the --get-regexp part: just take your time. It was easy enough, and I think it is quite cool, but I have to see an application for it yet.

Ciao, Dscho

Junio C Hamano· May 3, 2006, 04:06 UTC · re: Johannes Schindelin · lore

Re: [PATCH] repo-config: support --get-regexp and fix crash

Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
Show 5 quoted lines
> diff --git a/repo-config.c b/repo-config.c
> index fa8aba7..722153c 100644
> --- a/repo-config.c
> +++ b/repo-config.c
> @@ -6,7 +6,10 @@ static const char git_config_set_usage[]
New flag missing from usage.
Show 21 quoted lines
>  
>  static char* key = NULL;
>  static char* value = NULL;
> +static regex_t* key_regexp = NULL;
>  static regex_t* regexp = NULL;
> +static int show_keys = 0;
> +static int use_key_regexp = 0;
>  static int do_all = 0;
>  static int do_not_match = 0;
>  static int seen = 0;
> @@ -26,16 +29,18 @@ static int show_config(const char* key_,
>  	if (value_ == NULL)
>  		value_ = "";
>  
> -	if (!strcmp(key_, key) &&
> +	if ((use_key_regexp || !strcmp(key_, key)) &&
> +			(!use_key_regexp ||
> +			 !regexec(key_regexp, key_, 0, NULL, 0)) &&
>  			(regexp == NULL ||
>  			 (do_not_match ^
>  			  !regexec(regexp, value_, 0, NULL, 0)))) {
That's a convoluted logic.
 (1) Either we are using key-regexp, or otherwise the key has to
     exactly match; and
 (2) Either we are not using key-regexp, or key-regexp must
     match; and
 (3) Either we are not using regexp, or value must match (or
     unmatch) as we are told by do_no_match.

It all makes sense, but I wonder if this is the clearest way to convey what is happening to people. Not that I have a cleaner alternative in mind...

Show 12 quoted lines
> @@ -63,6 +70,14 @@ static int get_value(const char* key_, c
>  		key[i] = tolower(key_[i]);
>  	key[i] = 0;
>  
> +	if (use_key_regexp) {
> +		key_regexp = (regex_t*)malloc(sizeof(regex_t));
> +		if (regcomp(key_regexp, key, REG_EXTENDED)) {
> +			fprintf(stderr, "Invalid key pattern: %s\n", regex_);
> +			return -1;
> +		}
> +	}
> +

Not worrying about leaking on failure path is just fine, since this is not a libified part. Perhaps the free() in get_value() are all like that -- get_value() is called once immediately before exiting the program anyway ;-).

To my deliberately bogus request, I am getting (null); fprintf() should use "key" instead of "regex_", perhaps?

	$ git-repo-config --get-regexp 'core['
        Invalid key pattern: (null)
Show 10 quoted lines
> @@ -78,7 +93,8 @@ static int get_value(const char* key_, c
>  
>  	git_config(show_config);
>  	if (value) {
> -		printf("%s\n", value);
> +		if (!do_all)
> +			printf("%s\n", value);
>  		free(value);
>  	}
>  	free(key);

I wonder if it would make things cleaner if you do not keep the global "value" around. Instead, do all the printing in show_config(), using a static global bool "seen" to control do_all vs get-all request as you already do. Then get_value() does not even need to worry about freeing the value, does it?

Also I am not sure if "say OK if do_all was requested" at the end of get_value(). If a do_all request did not find any match, is it an OK condition? I do not have strong feeling either way, though.

A suggested patch on top of your version that is in "pu".
-- >8 --
Show changes to repo-config.c +20 −26
diff --git a/repo-config.c b/repo-config.c
index 722153c..7e06d1a 100644
--- a/repo-config.c
+++ b/repo-config.c
@@ -2,10 +2,9 @@ #include "cache.h"
 #include <regex.h>
 
 static const char git_config_set_usage[] =
-"git-repo-config [ --bool | --int ] [--get | --get-all | --replace-all | --unset | --unset-all] name [value [value_regex]] | --list";
+"git-repo-config [ --bool | --int ] [--get | --get-all | --get-regexp | --replace-all | --unset | --unset-all] name [value [value_regex]] | --list";
 
 static char* key = NULL;
-static char* value = NULL;
 static regex_t* key_regexp = NULL;
 static regex_t* regexp = NULL;
 static int show_keys = 0;
@@ -26,6 +25,9 @@ static int show_all_config(const char *k
 
 static int show_config(const char* key_, const char* value_)
 {
+	char value[256];
+	const char *vptr = value;
+
 	if (value_ == NULL)
 		value_ = "";
 
@@ -35,28 +37,25 @@ static int show_config(const char* key_,
 			(regexp == NULL ||
 			 (do_not_match ^
 			  !regexec(regexp, value_, 0, NULL, 0)))) {
+		int dup_error = 0;
 		if (show_keys)
 			printf("%s ", key_);
-		if (seen > 0) {
-			if (!do_all)
-				fprintf(stderr, "More than one value: %s\n",
-						value);
-			free(value);
-		}
-
-		if (type == T_INT) {
-			value = malloc(256);
+		if (seen && !do_all)
+			dup_error = 1;
+		if (type == T_INT)
 			sprintf(value, "%d", git_config_int(key_, value_));
-		} else if (type == T_BOOL) {
-			value = malloc(256);
+		else if (type == T_BOOL)
 			sprintf(value, "%s", git_config_bool(key_, value_)
 					     ? "true" : "false");
-		} else {
-			value = strdup(value_);
-		}
+		else
+			vptr = value_;
 		seen++;
-		if (do_all)
-			printf("%s\n", value);
+		if (dup_error) {
+			error("More than one value for the key %s: %s",
+			      key_, vptr);
+		}
+		else
+			printf("%s\n", vptr);
 	}
 	return 0;
 }
@@ -73,7 +72,7 @@ static int get_value(const char* key_, c
 	if (use_key_regexp) {
 		key_regexp = (regex_t*)malloc(sizeof(regex_t));
 		if (regcomp(key_regexp, key, REG_EXTENDED)) {
-			fprintf(stderr, "Invalid key pattern: %s\n", regex_);
+			fprintf(stderr, "Invalid key pattern: %s\n", key_);
 			return -1;
 		}
 	}
@@ -92,11 +91,6 @@ static int get_value(const char* key_, c
 	}
 
 	git_config(show_config);
-	if (value) {
-		if (!do_all)
-			printf("%s\n", value);
-		free(value);
-	}
 	free(key);
 	if (regexp) {
 		regfree(regexp);
@@ -104,9 +98,9 @@ static int get_value(const char* key_, c
 	}
 
 	if (do_all)
-		return 0;
+		return !seen;
 
-	return seen == 1 ? 0 : 1;
+	return (seen == 1) ? 0 : 1;
 }
 
 int main(int argc, const char **argv)
Johannes Schindelin· May 3, 2006, 12:41 UTC · re: Junio C Hamano · lore

Re: [PATCH] repo-config: support --get-regexp and fix crash

Hi,
thanks for your patch.
On Tue, 2 May 2006, Junio C Hamano wrote:
Show 28 quoted lines
> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
> 
> > @@ -26,16 +29,18 @@ static int show_config(const char* key_,
> >  	if (value_ == NULL)
> >  		value_ = "";
> >  
> > -	if (!strcmp(key_, key) &&
> > +	if ((use_key_regexp || !strcmp(key_, key)) &&
> > +			(!use_key_regexp ||
> > +			 !regexec(key_regexp, key_, 0, NULL, 0)) &&
> >  			(regexp == NULL ||
> >  			 (do_not_match ^
> >  			  !regexec(regexp, value_, 0, NULL, 0)))) {
> 
> That's a convoluted logic.
> 
>  (1) Either we are using key-regexp, or otherwise the key has to
>      exactly match; and
> 
>  (2) Either we are not using key-regexp, or key-regexp must
>      match; and
> 
>  (3) Either we are not using regexp, or value must match (or
>      unmatch) as we are told by do_no_match.
> 
> It all makes sense, but I wonder if this is the clearest way to
> convey what is happening to people.  Not that I have a cleaner
> alternative in mind...
How about this (on top of your patch):

--- snip --- [PATCH] repo-config: deconvolute logics

It was rightly noticed that the logic is quite convoluted. Fix that.
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
---
	The real change is very short, but a code block got reindented, 
	too.
 repo-config.c |   50 ++++++++++++++++++++++++++------------------------
 1 files changed, 26 insertions(+), 24 deletions(-)
Show changes to repo-config.c +26 −24
diff --git a/repo-config.c b/repo-config.c
index 7e06d1a..63eda1b 100644
--- a/repo-config.c
+++ b/repo-config.c
@@ -27,36 +27,38 @@ static int show_config(const char* key_,
 {
 	char value[256];
 	const char *vptr = value;
+	int dup_error = 0;
 
 	if (value_ == NULL)
 		value_ = "";
 
-	if ((use_key_regexp || !strcmp(key_, key)) &&
-			(!use_key_regexp ||
-			 !regexec(key_regexp, key_, 0, NULL, 0)) &&
-			(regexp == NULL ||
+	if (!use_key_regexp && strcmp(key_, key))
+		return 0;
+	if (use_key_regexp && regexec(key_regexp, key_, 0, NULL, 0))
+		return 0;
+	if (regexp != NULL &&
 			 (do_not_match ^
-			  !regexec(regexp, value_, 0, NULL, 0)))) {
-		int dup_error = 0;
-		if (show_keys)
-			printf("%s ", key_);
-		if (seen && !do_all)
-			dup_error = 1;
-		if (type == T_INT)
-			sprintf(value, "%d", git_config_int(key_, value_));
-		else if (type == T_BOOL)
-			sprintf(value, "%s", git_config_bool(key_, value_)
-					     ? "true" : "false");
-		else
-			vptr = value_;
-		seen++;
-		if (dup_error) {
-			error("More than one value for the key %s: %s",
-			      key_, vptr);
-		}
-		else
-			printf("%s\n", vptr);
+			  regexec(regexp, value_, 0, NULL, 0)))
+		return 0;
+
+	if (show_keys)
+		printf("%s ", key_);
+	if (seen && !do_all)
+		dup_error = 1;
+	if (type == T_INT)
+		sprintf(value, "%d", git_config_int(key_, value_));
+	else if (type == T_BOOL)
+		vptr = git_config_bool(key_, value_) ? "true" : "false";
+	else
+		vptr = value_;
+	seen++;
+	if (dup_error) {
+		error("More than one value for the key %s: %s",
+				key_, vptr);
 	}
+	else
+		printf("%s\n", vptr);
+
 	return 0;
 }
 

← back to recent threads