1#include "builtin.h"
2#include "cache.h"
3
4static 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";
6
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;
15static enum { T_RAW, T_INT, T_BOOL } type = T_RAW;
16
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
26static int show_config(const char* key_, const char* value_)
27{
28 char value[256];
29 const char *vptr = value;
30 int dup_error = 0;
31
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;
40
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);
62
63 return 0;
64}
65
66static 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;
72
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 }
83
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);
89
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 }
97
98 if (regex_) {
99 if (regex_[0] == '!') {
100 do_not_match = 1;
101 regex_++;
102 }
103
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 }
110
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);
120
121 free(key);
122 if (regexp) {
123 regfree(regexp);
124 free(regexp);
125 }
126
127 if (do_all)
128 ret = !seen;
129 else
130 ret = (seen == 1) ? 0 : seen > 1 ? 2 : 1;
131
132free_strings:
133 free(repo_config);
134 free(global);
135 return ret;
136}
137
138int cmd_config(int argc, const char **argv, const char *prefix)
139{
140 int nongit = 0;
141 setup_git_directory_gently(&nongit);
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;
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 }
193
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
213
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"))
233
234 return git_config_set_multivar(argv[2], argv[3], NULL, 1);
235 else
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:
242 default:
243 usage(git_config_set_usage);
244 }
245 return 0;
246}