git-config-set: support selecting values by non-matching regex
authorJohannes Schindelin <Johannes.Schindelin@gmx.de>
Sun, 20 Nov 2005 12:24:18 +0000 (13:24 +0100)
committerJunio C Hamano <junkio@cox.net>
Sun, 20 Nov 2005 18:53:06 +0000 (10:53 -0800)
Extend the regex syntax of value_regex so that prepending an exclamation
mark means non-match:

[core]
quetzal = "Dodo" for Brainf*ck
quetzal = "T. Rex" for Malbolge
quetzal = "cat"

You can match the third line with

git-config-set --get quetzal '! for '

Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Signed-off-by: Junio C Hamano <junkio@cox.net>
Documentation/git-config-set.txt
config-set.c
config.c
t/t1300-config-set.sh
index c707fbcf99dd385112f910c235738dac42bd679d..bfbd42147ae9bfef01e9320340336a9ed8794aee 100644 (file)
@@ -22,7 +22,9 @@ actually the section and the key separated by a dot, and the value will be
 escaped.
 
 If you want to set/unset an option which can occor on multiple lines, you
 escaped.
 
 If you want to set/unset an option which can occor on multiple lines, you
-should provide a POSIX regex for the value.
+should provide a POSIX regex for the value. If you want to handle the lines
+*not* matching the regex, just prepend a single exlamation mark in front
+(see EXAMPLES).
 
 This command will fail if
 
 
 This command will fail if
 
@@ -82,6 +84,7 @@ Given a .git/config like this:
                command="ssh" for "ssh://kernel.org/"
                command="proxy-command" for kernel.org
                command="myprotocol-command" for "my://"
                command="ssh" for "ssh://kernel.org/"
                command="proxy-command" for kernel.org
                command="myprotocol-command" for "my://"
+               command=default-proxy ; for all the rest
 
 you can set the filemode to true with
 
 
 you can set the filemode to true with
 
@@ -139,6 +142,19 @@ new one with
 % git config-set --replace-all proxy.command ssh
 ------------
 
 % git config-set --replace-all proxy.command ssh
 ------------
 
+However, if you really only want to replace the line for the default proxy,
+i.e. the one without a "for ..." postfix, do something like this:
+
+------------
+% git config-set proxy.command ssh '! for '
+------------
+
+To actually match only values with an exclamation mark, you have to
+
+------------
+% git config-set section.key value '[!]'
+------------
+
 
 Author
 ------
 
 Author
 ------
index 90a28b381ff8bb25e148f3e81f9a57a46ab0c962..5f654f7aff1cfa4cdbe5400d328363d4a91d490c 100644 (file)
@@ -8,13 +8,15 @@ static char* key = NULL;
 static char* value = NULL;
 static regex_t* regex = NULL;
 static int do_all = 0;
 static char* value = NULL;
 static regex_t* regex = NULL;
 static int do_all = 0;
+static int do_not_match = 0;
 static int seen = 0;
 
 static int show_config(const char* key_, const char* value_)
 {
        if (!strcmp(key_, key) &&
                        (regex == NULL ||
 static int seen = 0;
 
 static int show_config(const char* key_, const char* value_)
 {
        if (!strcmp(key_, key) &&
                        (regex == NULL ||
-                        !regexec(regex, value_, 0, NULL, 0))) {
+                        (do_not_match ^
+                         !regexec(regex, value_, 0, NULL, 0)))) {
                if (do_all) {
                        printf("%s\n", value_);
                        return 0;
                if (do_all) {
                        printf("%s\n", value_);
                        return 0;
@@ -38,6 +40,11 @@ static int get_value(const char* key_, const char* regex_)
                key[i] = tolower(key_[i]);
 
        if (regex_) {
                key[i] = tolower(key_[i]);
 
        if (regex_) {
+               if (regex_[0] == '!') {
+                       do_not_match = 1;
+                       regex_++;
+               }
+
                regex = (regex_t*)malloc(sizeof(regex_t));
                if (regcomp(regex, regex_, REG_EXTENDED)) {
                        fprintf(stderr, "Invalid pattern: %s\n", regex_);
                regex = (regex_t*)malloc(sizeof(regex_t));
                if (regcomp(regex, regex_, REG_EXTENDED)) {
                        fprintf(stderr, "Invalid pattern: %s\n", regex_);
index 697d79f53698d23503d076c7968c5dc72ea8d40a..5d237c862d4c7d0e3c62565849df7b87e4bf78a6 100644 (file)
--- a/config.c
+++ b/config.c
@@ -269,6 +269,7 @@ int git_config(config_fn_t fn)
 static struct {
        int baselen;
        char* key;
 static struct {
        int baselen;
        char* key;
+       int do_not_match;
        regex_t* value_regex;
        int multi_replace;
        off_t offset[MAX_MATCHES];
        regex_t* value_regex;
        int multi_replace;
        off_t offset[MAX_MATCHES];
@@ -276,13 +277,19 @@ static struct {
        int seen;
 } store;
 
        int seen;
 } store;
 
+static int matches(const char* key, const char* value)
+{
+       return !strcmp(key, store.key) &&
+               (store.value_regex == NULL ||
+                (store.do_not_match ^
+                 !regexec(store.value_regex, value, 0, NULL, 0)));
+}
+
 static int store_aux(const char* key, const char* value)
 {
        switch (store.state) {
        case KEY_SEEN:
 static int store_aux(const char* key, const char* value)
 {
        switch (store.state) {
        case KEY_SEEN:
-               if (!strcmp(key, store.key) &&
-                               (store.value_regex == NULL ||
-                               !regexec(store.value_regex, value, 0, NULL, 0))) {
+               if (matches(key, value)) {
                        if (store.seen == 1 && store.multi_replace == 0) {
                                fprintf(stderr,
                                        "Warning: %s has multiple values\n",
                        if (store.seen == 1 && store.multi_replace == 0) {
                                fprintf(stderr,
                                        "Warning: %s has multiple values\n",
@@ -306,9 +313,7 @@ static int store_aux(const char* key, const char* value)
                /* fallthru */
        case SECTION_END_SEEN:
        case START:
                /* fallthru */
        case SECTION_END_SEEN:
        case START:
-               if (!strcmp(key, store.key) &&
-                               (store.value_regex == NULL ||
-                               !regexec(store.value_regex, value, 0, NULL, 0))) {
+               if (matches(key, value)) {
                        store.offset[store.seen] = ftell(config_file);
                        store.state = KEY_SEEN;
                        store.seen++;
                        store.offset[store.seen] = ftell(config_file);
                        store.state = KEY_SEEN;
                        store.seen++;
@@ -471,6 +476,12 @@ int git_config_set_multivar(const char* key, const char* value,
                if (value_regex == NULL)
                        store.value_regex = NULL;
                else {
                if (value_regex == NULL)
                        store.value_regex = NULL;
                else {
+                       if (value_regex[0] == '!') {
+                               store.do_not_match = 1;
+                               value_regex++;
+                       } else
+                               store.do_not_match = 0;
+
                        store.value_regex = (regex_t*)malloc(sizeof(regex_t));
                        if (regcomp(store.value_regex, value_regex,
                                        REG_EXTENDED)) {
                        store.value_regex = (regex_t*)malloc(sizeof(regex_t));
                        if (regcomp(store.value_regex, value_regex,
                                        REG_EXTENDED)) {
index 717bf4de79518a647d5610e4f5c52d01d29b229a..59b6c4c85d5ff2d0a16437edb016785ce3130818 100644 (file)
@@ -69,6 +69,28 @@ EOF
 
 test_expect_success 'similar section' 'cmp .git/config expect'
 
 
 test_expect_success 'similar section' 'cmp .git/config expect'
 
+test_expect_success 'replace with non-match' \
+       'git-config-set core.penguin kingpin !blue'
+
+test_expect_success 'replace with non-match (actually matching)' \
+       'git-config-set core.penguin "very blue" !kingpin'
+
+cat > expect << EOF
+#
+# This is the config file
+#
+
+[core]
+       penguin = very blue
+       Movie = BadPhysics
+       UPPERCASE = true
+       penguin = kingpin
+[Cores]
+       WhatEver = Second
+EOF
+
+test_expect_success 'non-match result' 'cmp .git/config expect'
+
 cat > .git/config << EOF
 [beta] ; silly comment # another comment
 noIndent= sillyValue ; 'nother silly comment
 cat > .git/config << EOF
 [beta] ; silly comment # another comment
 noIndent= sillyValue ; 'nother silly comment
@@ -173,6 +195,12 @@ EOF
 
 test_expect_success 'multivar' 'cmp .git/config expect'
 
 
 test_expect_success 'multivar' 'cmp .git/config expect'
 
+test_expect_success 'non-match' \
+       'git-config-set --get nextsection.nonewline !for'
+
+test_expect_success 'non-match value' \
+       'test wow = $(git-config-set --get nextsection.nonewline !for)'
+
 test_expect_failure 'ambiguous get' \
        'git-config-set --get nextsection.nonewline'
 
 test_expect_failure 'ambiguous get' \
        'git-config-set --get nextsection.nonewline'