Merge branch 'maint'
[git/git.git] / builtin-config.c
CommitLineData
e12c095a 1#include "builtin.h"
1b1e59c5
JS
2#include "cache.h"
3
4static const char git_config_set_usage[] =
9bc20aa7 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";
4ddba79d 6
96f1e58f
DR
7static char *key;
8static regex_t *key_regexp;
9static regex_t *regexp;
10static int show_keys;
11static int use_key_regexp;
12static int do_all;
13static int do_not_match;
14static int seen;
7162dff3 15static enum { T_RAW, T_INT, T_BOOL } type = T_RAW;
4ddba79d 16
de791f15
PB
17static 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}
25
4ddba79d
JS
26static int show_config(const char* key_, const char* value_)
27{
e098c6f8
JH
28 char value[256];
29 const char *vptr = value;
8f5ff31f 30 int dup_error = 0;
e098c6f8 31
8f5ff31f
JS
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 &&
f98d863d 37 (do_not_match ^
acb70149 38 regexec(regexp, (value_?value_:""), 0, NULL, 0)))
8f5ff31f
JS
39 return 0;
40
b69ba460
FL
41 if (show_keys) {
42 if (value_)
43 printf("%s ", key_);
44 else
45 printf("%s", key_);
46 }
8f5ff31f
JS
47 if (seen && !do_all)
48 dup_error = 1;
49 if (type == T_INT)
acb70149 50 sprintf(value, "%d", git_config_int(key_, value_?value_:""));
8f5ff31f
JS
51 else if (type == T_BOOL)
52 vptr = git_config_bool(key_, value_) ? "true" : "false";
53 else
acb70149 54 vptr = value_?value_:"";
8f5ff31f
JS
55 seen++;
56 if (dup_error) {
57 error("More than one value for the key %s: %s",
58 key_, vptr);
4ddba79d 59 }
8f5ff31f
JS
60 else
61 printf("%s\n", vptr);
62
4ddba79d
JS
63 return 0;
64}
65
66static int get_value(const char* key_, const char* regex_)
67{
5f1a63e0 68 int ret = -1;
d14f7764 69 char *tl;
5f1a63e0 70 char *global = NULL, *repo_config = NULL;
32043c9f 71 const char *system_wide = NULL, *local;
5f1a63e0 72
d4ebc36c 73 local = getenv(CONFIG_ENVIRONMENT);
5f1a63e0
JS
74 if (!local) {
75 const char *home = getenv("HOME");
d4ebc36c 76 local = getenv(CONFIG_LOCAL_ENVIRONMENT);
5f1a63e0 77 if (!local)
9befac47 78 local = repo_config = xstrdup(git_path("config"));
5f1a63e0 79 if (home)
9befac47 80 global = xstrdup(mkpath("%s/.gitconfig", home));
32043c9f 81 system_wide = ETC_GITCONFIG;
5f1a63e0 82 }
4ddba79d 83
9befac47 84 key = xstrdup(key_);
d14f7764
LT
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);
4ddba79d 89
2fa9a0fb 90 if (use_key_regexp) {
2d7320d0 91 key_regexp = (regex_t*)xmalloc(sizeof(regex_t));
2fa9a0fb 92 if (regcomp(key_regexp, key, REG_EXTENDED)) {
e098c6f8 93 fprintf(stderr, "Invalid key pattern: %s\n", key_);
5f1a63e0 94 goto free_strings;
2fa9a0fb
JS
95 }
96 }
97
4ddba79d 98 if (regex_) {
f98d863d
JS
99 if (regex_[0] == '!') {
100 do_not_match = 1;
101 regex_++;
102 }
103
2d7320d0 104 regexp = (regex_t*)xmalloc(sizeof(regex_t));
0a152171 105 if (regcomp(regexp, regex_, REG_EXTENDED)) {
4ddba79d 106 fprintf(stderr, "Invalid pattern: %s\n", regex_);
5f1a63e0 107 goto free_strings;
4ddba79d
JS
108 }
109 }
110
32043c9f
JS
111 if (do_all && system_wide)
112 git_config_from_file(show_config, system_wide);
5f1a63e0
JS
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);
32043c9f
JS
118 if (!do_all && !seen && system_wide)
119 git_config_from_file(show_config, system_wide);
5f1a63e0 120
4ddba79d 121 free(key);
0a152171
AW
122 if (regexp) {
123 regfree(regexp);
124 free(regexp);
4ddba79d
JS
125 }
126
127 if (do_all)
5f1a63e0
JS
128 ret = !seen;
129 else
dc2613de 130 ret = (seen == 1) ? 0 : seen > 1 ? 2 : 1;
5f1a63e0
JS
131
132free_strings:
4cac42b1
JH
133 free(repo_config);
134 free(global);
5f1a63e0 135 return ret;
4ddba79d 136}
1b1e59c5 137
e0d10e1c 138int cmd_config(int argc, const char **argv, const char *prefix)
1b1e59c5 139{
4d599e6b
LT
140 int nongit = 0;
141 setup_git_directory_gently(&nongit);
7162dff3
PB
142
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;
cfa24e18
JS
148 else if (!strcmp(argv[1], "--list") || !strcmp(argv[1], "-l"))
149 return git_config(show_all_config);
34eb3340
SE
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 }
32043c9f
JS
159 }
160 else if (!strcmp(argv[1], "--system"))
161 setenv("GIT_CONFIG", ETC_GITCONFIG, 1);
162 else if (!strcmp(argv[1], "--rename-section")) {
0667fcfb
JS
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;
32043c9f 174 }
118f8b24
PB
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 }
32043c9f 188 else
7162dff3
PB
189 break;
190 argc--;
191 argv++;
192 }
193
1b1e59c5
JS
194 switch (argc) {
195 case 2:
4ddba79d 196 return get_value(argv[1], NULL);
1b1e59c5
JS
197 case 3:
198 if (!strcmp(argv[1], "--unset"))
199 return git_config_set(argv[2], NULL);
4ddba79d
JS
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);
2fa9a0fb
JS
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);
4ddba79d
JS
212 } else
213
1b1e59c5
JS
214 return git_config_set(argv[1], argv[2]);
215 case 4:
216 if (!strcmp(argv[1], "--unset"))
4ddba79d
JS
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]);
2fa9a0fb
JS
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]);
89c4afe0
BG
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"))
4ddba79d
JS
233
234 return git_config_set_multivar(argv[2], argv[3], NULL, 1);
1b1e59c5 235 else
4ddba79d
JS
236
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:
1b1e59c5
JS
242 default:
243 usage(git_config_set_usage);
244 }
245 return 0;
246}