From f98d863d2122e1b8781dfb9889df98876a26f315 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sun, 20 Nov 2005 13:24:18 +0100 Subject: [PATCH] git-config-set: support selecting values by non-matching regex 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 Signed-off-by: Junio C Hamano --- Documentation/git-config-set.txt | 18 +++++++++++++++++- config-set.c | 9 ++++++++- config.c | 23 +++++++++++++++++------ t/t1300-config-set.sh | 28 ++++++++++++++++++++++++++++ 4 files changed, 70 insertions(+), 8 deletions(-) diff --git a/Documentation/git-config-set.txt b/Documentation/git-config-set.txt index c707fbcf99..bfbd42147a 100644 --- a/Documentation/git-config-set.txt +++ b/Documentation/git-config-set.txt @@ -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 -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 @@ -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=default-proxy ; for all the rest you can set the filemode to true with @@ -139,6 +142,19 @@ new one with % 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 ------ diff --git a/config-set.c b/config-set.c index 90a28b381f..5f654f7aff 100644 --- a/config-set.c +++ b/config-set.c @@ -8,13 +8,15 @@ static char* key = NULL; 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 || - !regexec(regex, value_, 0, NULL, 0))) { + (do_not_match ^ + !regexec(regex, value_, 0, NULL, 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_) { + 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_); diff --git a/config.c b/config.c index 697d79f536..5d237c862d 100644 --- a/config.c +++ b/config.c @@ -269,6 +269,7 @@ int git_config(config_fn_t fn) static struct { int baselen; char* key; + int do_not_match; regex_t* value_regex; int multi_replace; off_t offset[MAX_MATCHES]; @@ -276,13 +277,19 @@ static struct { 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: - 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", @@ -306,9 +313,7 @@ static int store_aux(const char* key, const char* value) /* 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++; @@ -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[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)) { diff --git a/t/t1300-config-set.sh b/t/t1300-config-set.sh index 717bf4de79..59b6c4c85d 100644 --- a/t/t1300-config-set.sh +++ b/t/t1300-config-set.sh @@ -69,6 +69,28 @@ EOF 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 @@ -173,6 +195,12 @@ EOF 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' -- 2.11.4.GIT