t4200: use cut instead of sed
[git/peff.git] / builtin-config.c
blobed318dc46506af9339d522eb149117f4c3000ead
1 #include "builtin.h"
2 #include "cache.h"
3 #include "color.h"
5 static const char git_config_set_usage[] =
6 "git-config [ --global | --system | [ -f | --file ] config-file ] [ --bool | --int ] [ -z | --null ] [--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 | --get-color var [default] | --get-colorbool name [stdout-is-tty]";
8 static char *key;
9 static regex_t *key_regexp;
10 static regex_t *regexp;
11 const char *value_match;
12 static int show_keys;
13 static int use_key_regexp;
14 static int do_all;
15 static int do_not_match;
16 static int seen;
17 static char delim = '=';
18 static char key_delim = ' ';
19 static char term = '\n';
20 static enum { T_RAW, T_INT, T_BOOL } type = T_RAW;
21 static int literal_match = 0;
23 static int show_all_config(const char *key_, const char *value_)
25 if (value_)
26 printf("%s%c%s%c", key_, delim, value_, term);
27 else
28 printf("%s%c", key_, term);
29 return 0;
32 static int show_config(const char* key_, const char* value_)
34 char value[256];
35 const char *vptr = value;
36 int dup_error = 0;
38 if (!use_key_regexp && strcmp(key_, key))
39 return 0;
40 if (use_key_regexp && regexec(key_regexp, key_, 0, NULL, 0))
41 return 0;
42 if (regexp != NULL &&
43 (do_not_match ^ !!regexec(regexp, (value_?value_:""), 0, NULL, 0)))
44 return 0;
45 if (value_match != NULL &&
46 do_not_match ^ !!strcmp(value_match, (value_ ? value_ : "")))
47 return 0;
49 if (show_keys) {
50 if (value_)
51 printf("%s%c", key_, key_delim);
52 else
53 printf("%s", key_);
55 if (seen && !do_all)
56 dup_error = 1;
57 if (type == T_INT)
58 sprintf(value, "%d", git_config_int(key_, value_?value_:""));
59 else if (type == T_BOOL)
60 vptr = git_config_bool(key_, value_) ? "true" : "false";
61 else
62 vptr = value_?value_:"";
63 seen++;
64 if (dup_error) {
65 error("More than one value for the key %s: %s",
66 key_, vptr);
68 else
69 printf("%s%c", vptr, term);
71 return 0;
74 static int get_value(const char* key_, const char* match_)
76 int ret = -1;
77 char *tl;
78 char *global = NULL, *repo_config = NULL;
79 const char *system_wide = NULL, *local;
81 local = getenv(CONFIG_ENVIRONMENT);
82 if (!local) {
83 const char *home = getenv("HOME");
84 local = getenv(CONFIG_LOCAL_ENVIRONMENT);
85 if (!local)
86 local = repo_config = xstrdup(git_path("config"));
87 if (git_config_global() && home)
88 global = xstrdup(mkpath("%s/.gitconfig", home));
89 if (git_config_system())
90 system_wide = git_etc_gitconfig();
93 key = xstrdup(key_);
94 for (tl=key+strlen(key)-1; tl >= key && *tl != '.'; --tl)
95 *tl = tolower(*tl);
96 for (tl=key; *tl && *tl != '.'; ++tl)
97 *tl = tolower(*tl);
99 if (use_key_regexp) {
100 key_regexp = (regex_t*)xmalloc(sizeof(regex_t));
101 if (regcomp(key_regexp, key, REG_EXTENDED)) {
102 fprintf(stderr, "Invalid key pattern: %s\n", key_);
103 goto free_strings;
107 if (match_ && literal_match) {
108 value_match = match_;
109 do_not_match = 0;
110 regexp = NULL;
112 else if(match_) {
113 value_match = NULL;
114 if (match_[0] == '!') {
115 do_not_match = 1;
116 match_++;
119 regexp = (regex_t*)xmalloc(sizeof(regex_t));
120 if (regcomp(regexp, match_, REG_EXTENDED)) {
121 fprintf(stderr, "Invalid pattern: %s\n", match_);
122 goto free_strings;
125 else {
126 value_match = NULL;
127 regexp = NULL;
130 if (do_all && system_wide)
131 git_config_from_file(show_config, system_wide);
132 if (do_all && global)
133 git_config_from_file(show_config, global);
134 git_config_from_file(show_config, local);
135 if (!do_all && !seen && global)
136 git_config_from_file(show_config, global);
137 if (!do_all && !seen && system_wide)
138 git_config_from_file(show_config, system_wide);
140 free(key);
141 if (regexp) {
142 regfree(regexp);
143 free(regexp);
146 if (do_all)
147 ret = !seen;
148 else
149 ret = (seen == 1) ? 0 : seen > 1 ? 2 : 1;
151 free_strings:
152 free(repo_config);
153 free(global);
154 return ret;
157 char *normalize_value(const char *key, const char *value)
159 char *normalized;
161 if (!value)
162 return NULL;
164 if (type == T_RAW)
165 normalized = xstrdup(value);
166 else {
167 normalized = xmalloc(64);
168 if (type == T_INT) {
169 int v = git_config_int(key, value);
170 sprintf(normalized, "%d", v);
172 else if (type == T_BOOL)
173 sprintf(normalized, "%s",
174 git_config_bool(key, value) ? "true" : "false");
177 return normalized;
180 static int get_color_found;
181 static const char *get_color_slot;
182 static char parsed_color[COLOR_MAXLEN];
184 static int git_get_color_config(const char *var, const char *value)
186 if (!strcmp(var, get_color_slot)) {
187 if (!value)
188 config_error_nonbool(var);
189 color_parse(value, var, parsed_color);
190 get_color_found = 1;
192 return 0;
195 static int get_color(int argc, const char **argv)
198 * grab the color setting for the given slot from the configuration,
199 * or parse the default value if missing, and return ANSI color
200 * escape sequence.
202 * e.g.
203 * git config --get-color color.diff.whitespace "blue reverse"
205 const char *def_color = NULL;
207 switch (argc) {
208 default:
209 usage(git_config_set_usage);
210 case 2:
211 def_color = argv[1];
212 /* fallthru */
213 case 1:
214 get_color_slot = argv[0];
215 break;
218 get_color_found = 0;
219 parsed_color[0] = '\0';
220 git_config(git_get_color_config);
222 if (!get_color_found && def_color)
223 color_parse(def_color, "command line", parsed_color);
225 fputs(parsed_color, stdout);
226 return 0;
229 static int stdout_is_tty;
230 static int get_colorbool_found;
231 static int get_diff_color_found;
232 static int git_get_colorbool_config(const char *var, const char *value)
234 if (!strcmp(var, get_color_slot)) {
235 get_colorbool_found =
236 git_config_colorbool(var, value, stdout_is_tty);
238 if (!strcmp(var, "diff.color")) {
239 get_diff_color_found =
240 git_config_colorbool(var, value, stdout_is_tty);
242 return 0;
245 static int get_colorbool(int argc, const char **argv)
248 * git config --get-colorbool <slot> [<stdout-is-tty>]
250 * returns "true" or "false" depending on how <slot>
251 * is configured.
254 if (argc == 2)
255 stdout_is_tty = git_config_bool("command line", argv[1]);
256 else if (argc == 1)
257 stdout_is_tty = isatty(1);
258 else
259 usage(git_config_set_usage);
260 get_colorbool_found = -1;
261 get_diff_color_found = -1;
262 get_color_slot = argv[0];
263 git_config(git_get_colorbool_config);
265 if (get_colorbool_found < 0) {
266 if (!strcmp(get_color_slot, "color.diff"))
267 get_colorbool_found = get_diff_color_found;
268 if (get_colorbool_found < 0)
269 get_colorbool_found = 0;
272 if (argc == 1) {
273 return get_colorbool_found ? 0 : 1;
274 } else {
275 printf("%s\n", get_colorbool_found ? "true" : "false");
276 return 0;
280 int cmd_config(int argc, const char **argv, const char *prefix)
282 int nongit = 0;
283 char* value;
284 const char *file = setup_git_directory_gently(&nongit);
286 while (1 < argc) {
287 if (!strcmp(argv[1], "--int"))
288 type = T_INT;
289 else if (!strcmp(argv[1], "--bool"))
290 type = T_BOOL;
291 else if (!strcmp(argv[1], "--list") || !strcmp(argv[1], "-l")) {
292 if (argc != 2)
293 usage(git_config_set_usage);
294 if (git_config(show_all_config) < 0 && file && errno)
295 die("unable to read config file %s: %s", file,
296 strerror(errno));
297 return 0;
299 else if (!strcmp(argv[1], "--global")) {
300 char *home = getenv("HOME");
301 if (home) {
302 char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
303 setenv(CONFIG_ENVIRONMENT, user_config, 1);
304 free(user_config);
305 } else {
306 die("$HOME not set");
309 else if (!strcmp(argv[1], "--system"))
310 setenv(CONFIG_ENVIRONMENT, git_etc_gitconfig(), 1);
311 else if (!strcmp(argv[1], "--file") || !strcmp(argv[1], "-f")) {
312 if (argc < 3)
313 usage(git_config_set_usage);
314 if (!is_absolute_path(argv[2]) && file)
315 file = prefix_filename(file, strlen(file),
316 argv[2]);
317 else
318 file = argv[2];
319 setenv(CONFIG_ENVIRONMENT, file, 1);
320 argc--;
321 argv++;
323 else if (!strcmp(argv[1], "--null") || !strcmp(argv[1], "-z")) {
324 term = '\0';
325 delim = '\n';
326 key_delim = '\n';
328 else if (!strcmp(argv[1], "--rename-section")) {
329 int ret;
330 if (argc != 4)
331 usage(git_config_set_usage);
332 ret = git_config_rename_section(argv[2], argv[3]);
333 if (ret < 0)
334 return ret;
335 if (ret == 0) {
336 fprintf(stderr, "No such section!\n");
337 return 1;
339 return 0;
341 else if (!strcmp(argv[1], "--remove-section")) {
342 int ret;
343 if (argc != 3)
344 usage(git_config_set_usage);
345 ret = git_config_rename_section(argv[2], NULL);
346 if (ret < 0)
347 return ret;
348 if (ret == 0) {
349 fprintf(stderr, "No such section!\n");
350 return 1;
352 return 0;
353 } else if (!strcmp(argv[1], "--get-color")) {
354 return get_color(argc-2, argv+2);
355 } else if (!strcmp(argv[1], "--get-colorbool")) {
356 return get_colorbool(argc-2, argv+2);
357 } else if (!strcmp(argv[1], "--literal-match")) {
358 literal_match = 1;
359 } else
360 break;
361 argc--;
362 argv++;
365 switch (argc) {
366 case 2:
367 return get_value(argv[1], NULL);
368 case 3:
369 if (!strcmp(argv[1], "--unset"))
370 return git_config_set(argv[2], NULL);
371 else if (!strcmp(argv[1], "--unset-all"))
372 return git_config_set_multivar(argv[2], NULL, NULL,
373 literal_match, 1);
374 else if (!strcmp(argv[1], "--get"))
375 return get_value(argv[2], NULL);
376 else if (!strcmp(argv[1], "--get-all")) {
377 do_all = 1;
378 return get_value(argv[2], NULL);
379 } else if (!strcmp(argv[1], "--get-regexp")) {
380 show_keys = 1;
381 use_key_regexp = 1;
382 do_all = 1;
383 return get_value(argv[2], NULL);
384 } else {
385 value = normalize_value(argv[1], argv[2]);
386 return git_config_set(argv[1], value);
388 case 4:
389 if (!strcmp(argv[1], "--unset"))
390 return git_config_set_multivar(argv[2], NULL, argv[3],
391 literal_match, 0);
392 else if (!strcmp(argv[1], "--unset-all"))
393 return git_config_set_multivar(argv[2], NULL, argv[3],
394 literal_match, 1);
395 else if (!strcmp(argv[1], "--get"))
396 return get_value(argv[2], argv[3]);
397 else if (!strcmp(argv[1], "--get-all")) {
398 do_all = 1;
399 return get_value(argv[2], argv[3]);
400 } else if (!strcmp(argv[1], "--get-regexp")) {
401 show_keys = 1;
402 use_key_regexp = 1;
403 do_all = 1;
404 return get_value(argv[2], argv[3]);
405 } else if (!strcmp(argv[1], "--add")) {
406 value = normalize_value(argv[2], argv[3]);
407 return git_config_set_multivar(argv[2], value, "^$",
408 0, 0);
409 } else if (!strcmp(argv[1], "--replace-all")) {
410 value = normalize_value(argv[2], argv[3]);
411 return git_config_set_multivar(argv[2], value, NULL,
412 0, 1);
413 } else {
414 value = normalize_value(argv[1], argv[2]);
415 return git_config_set_multivar(argv[1], value, argv[3],
416 literal_match, 0);
418 case 5:
419 if (!strcmp(argv[1], "--replace-all")) {
420 value = normalize_value(argv[2], argv[3]);
421 return git_config_set_multivar(argv[2], value, argv[4],
422 literal_match, 1);
424 case 1:
425 default:
426 usage(git_config_set_usage);
428 return 0;