Code

config: Change output of --get-regexp for valueless keys
[git.git] / builtin-config.c
1 #include "builtin.h"
2 #include "cache.h"
4 static const char git_config_set_usage[] =
5 "git-config [ --global | --system ] [ --bool | --int ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --remove-section name | --list";
7 static char *key;
8 static regex_t *key_regexp;
9 static regex_t *regexp;
10 static int show_keys;
11 static int use_key_regexp;
12 static int do_all;
13 static int do_not_match;
14 static int seen;
15 static enum { T_RAW, T_INT, T_BOOL } type = T_RAW;
17 static int show_all_config(const char *key_, const char *value_)
18 {
19         if (value_)
20                 printf("%s=%s\n", key_, value_);
21         else
22                 printf("%s\n", key_);
23         return 0;
24 }
26 static int show_config(const char* key_, const char* value_)
27 {
28         char value[256];
29         const char *vptr = value;
30         int dup_error = 0;
32         if (!use_key_regexp && strcmp(key_, key))
33                 return 0;
34         if (use_key_regexp && regexec(key_regexp, key_, 0, NULL, 0))
35                 return 0;
36         if (regexp != NULL &&
37                          (do_not_match ^
38                           regexec(regexp, (value_?value_:""), 0, NULL, 0)))
39                 return 0;
41         if (show_keys) {
42                 if (value_)
43                         printf("%s ", key_);
44                 else
45                         printf("%s", key_);
46         }
47         if (seen && !do_all)
48                 dup_error = 1;
49         if (type == T_INT)
50                 sprintf(value, "%d", git_config_int(key_, value_?value_:""));
51         else if (type == T_BOOL)
52                 vptr = git_config_bool(key_, value_) ? "true" : "false";
53         else
54                 vptr = value_?value_:"";
55         seen++;
56         if (dup_error) {
57                 error("More than one value for the key %s: %s",
58                                 key_, vptr);
59         }
60         else
61                 printf("%s\n", vptr);
63         return 0;
64 }
66 static int get_value(const char* key_, const char* regex_)
67 {
68         int ret = -1;
69         char *tl;
70         char *global = NULL, *repo_config = NULL;
71         const char *system_wide = NULL, *local;
73         local = getenv(CONFIG_ENVIRONMENT);
74         if (!local) {
75                 const char *home = getenv("HOME");
76                 local = getenv(CONFIG_LOCAL_ENVIRONMENT);
77                 if (!local)
78                         local = repo_config = xstrdup(git_path("config"));
79                 if (home)
80                         global = xstrdup(mkpath("%s/.gitconfig", home));
81                 system_wide = ETC_GITCONFIG;
82         }
84         key = xstrdup(key_);
85         for (tl=key+strlen(key)-1; tl >= key && *tl != '.'; --tl)
86                 *tl = tolower(*tl);
87         for (tl=key; *tl && *tl != '.'; ++tl)
88                 *tl = tolower(*tl);
90         if (use_key_regexp) {
91                 key_regexp = (regex_t*)xmalloc(sizeof(regex_t));
92                 if (regcomp(key_regexp, key, REG_EXTENDED)) {
93                         fprintf(stderr, "Invalid key pattern: %s\n", key_);
94                         goto free_strings;
95                 }
96         }
98         if (regex_) {
99                 if (regex_[0] == '!') {
100                         do_not_match = 1;
101                         regex_++;
102                 }
104                 regexp = (regex_t*)xmalloc(sizeof(regex_t));
105                 if (regcomp(regexp, regex_, REG_EXTENDED)) {
106                         fprintf(stderr, "Invalid pattern: %s\n", regex_);
107                         goto free_strings;
108                 }
109         }
111         if (do_all && system_wide)
112                 git_config_from_file(show_config, system_wide);
113         if (do_all && global)
114                 git_config_from_file(show_config, global);
115         git_config_from_file(show_config, local);
116         if (!do_all && !seen && global)
117                 git_config_from_file(show_config, global);
118         if (!do_all && !seen && system_wide)
119                 git_config_from_file(show_config, system_wide);
121         free(key);
122         if (regexp) {
123                 regfree(regexp);
124                 free(regexp);
125         }
127         if (do_all)
128                 ret = !seen;
129         else
130                 ret = (seen == 1) ? 0 : seen > 1 ? 2 : 1;
132 free_strings:
133         free(repo_config);
134         free(global);
135         return ret;
138 int cmd_config(int argc, const char **argv, const char *prefix)
140         int nongit = 0;
141         setup_git_directory_gently(&nongit);
143         while (1 < argc) {
144                 if (!strcmp(argv[1], "--int"))
145                         type = T_INT;
146                 else if (!strcmp(argv[1], "--bool"))
147                         type = T_BOOL;
148                 else if (!strcmp(argv[1], "--list") || !strcmp(argv[1], "-l"))
149                         return git_config(show_all_config);
150                 else if (!strcmp(argv[1], "--global")) {
151                         char *home = getenv("HOME");
152                         if (home) {
153                                 char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
154                                 setenv("GIT_CONFIG", user_config, 1);
155                                 free(user_config);
156                         } else {
157                                 die("$HOME not set");
158                         }
159                 }
160                 else if (!strcmp(argv[1], "--system"))
161                         setenv("GIT_CONFIG", ETC_GITCONFIG, 1);
162                 else if (!strcmp(argv[1], "--rename-section")) {
163                         int ret;
164                         if (argc != 4)
165                                 usage(git_config_set_usage);
166                         ret = git_config_rename_section(argv[2], argv[3]);
167                         if (ret < 0)
168                                 return ret;
169                         if (ret == 0) {
170                                 fprintf(stderr, "No such section!\n");
171                                 return 1;
172                         }
173                         return 0;
174                 }
175                 else if (!strcmp(argv[1], "--remove-section")) {
176                         int ret;
177                         if (argc != 3)
178                                 usage(git_config_set_usage);
179                         ret = git_config_rename_section(argv[2], NULL);
180                         if (ret < 0)
181                                 return ret;
182                         if (ret == 0) {
183                                 fprintf(stderr, "No such section!\n");
184                                 return 1;
185                         }
186                         return 0;
187                 }
188                 else
189                         break;
190                 argc--;
191                 argv++;
192         }
194         switch (argc) {
195         case 2:
196                 return get_value(argv[1], NULL);
197         case 3:
198                 if (!strcmp(argv[1], "--unset"))
199                         return git_config_set(argv[2], NULL);
200                 else if (!strcmp(argv[1], "--unset-all"))
201                         return git_config_set_multivar(argv[2], NULL, NULL, 1);
202                 else if (!strcmp(argv[1], "--get"))
203                         return get_value(argv[2], NULL);
204                 else if (!strcmp(argv[1], "--get-all")) {
205                         do_all = 1;
206                         return get_value(argv[2], NULL);
207                 } else if (!strcmp(argv[1], "--get-regexp")) {
208                         show_keys = 1;
209                         use_key_regexp = 1;
210                         do_all = 1;
211                         return get_value(argv[2], NULL);
212                 } else
214                         return git_config_set(argv[1], argv[2]);
215         case 4:
216                 if (!strcmp(argv[1], "--unset"))
217                         return git_config_set_multivar(argv[2], NULL, argv[3], 0);
218                 else if (!strcmp(argv[1], "--unset-all"))
219                         return git_config_set_multivar(argv[2], NULL, argv[3], 1);
220                 else if (!strcmp(argv[1], "--get"))
221                         return get_value(argv[2], argv[3]);
222                 else if (!strcmp(argv[1], "--get-all")) {
223                         do_all = 1;
224                         return get_value(argv[2], argv[3]);
225                 } else if (!strcmp(argv[1], "--get-regexp")) {
226                         show_keys = 1;
227                         use_key_regexp = 1;
228                         do_all = 1;
229                         return get_value(argv[2], argv[3]);
230                 } else if (!strcmp(argv[1], "--add"))
231                         return git_config_set_multivar(argv[2], argv[3], "^$", 0);
232                 else if (!strcmp(argv[1], "--replace-all"))
234                         return git_config_set_multivar(argv[2], argv[3], NULL, 1);
235                 else
237                         return git_config_set_multivar(argv[1], argv[2], argv[3], 0);
238         case 5:
239                 if (!strcmp(argv[1], "--replace-all"))
240                         return git_config_set_multivar(argv[2], argv[3], argv[4], 1);
241         case 1:
242         default:
243                 usage(git_config_set_usage);
244         }
245         return 0;