config.c 62.0 KB
Newer Older
1 2 3 4 5 6 7
/*
 * GIT - The information manager from hell
 *
 * Copyright (C) Linus Torvalds, 2005
 * Copyright (C) Johannes Schindelin, 2005
 *
 */
L
Linus Torvalds 已提交
8
#include "cache.h"
9
#include "lockfile.h"
10
#include "exec_cmd.h"
11
#include "strbuf.h"
12
#include "quote.h"
13 14
#include "hashmap.h"
#include "string-list.h"
15
#include "utf8.h"
L
Linus Torvalds 已提交
16

17 18 19 20
struct config_source {
	struct config_source *prev;
	union {
		FILE *file;
21 22 23 24 25
		struct config_buf {
			const char *buf;
			size_t len;
			size_t pos;
		} buf;
26
	} u;
27
	enum config_origin_type origin_type;
28
	const char *name;
29
	const char *path;
30
	int die_on_error;
31 32 33
	int linenr;
	int eof;
	struct strbuf value;
34
	struct strbuf var;
35

36 37 38
	int (*do_fgetc)(struct config_source *c);
	int (*do_ungetc)(int c, struct config_source *conf);
	long (*do_ftell)(struct config_source *c);
39 40
};

41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
/*
 * These variables record the "current" config source, which
 * can be accessed by parsing callbacks.
 *
 * The "cf" variable will be non-NULL only when we are actually parsing a real
 * config source (file, blob, cmdline, etc).
 *
 * The "current_config_kvi" variable will be non-NULL only when we are feeding
 * cached config from a configset into a callback.
 *
 * They should generally never be non-NULL at the same time. If they are both
 * NULL, then we aren't parsing anything (and depending on the function looking
 * at the variables, it's either a bug for it to be called in the first place,
 * or it's a function which can be reused for non-config purposes, and should
 * fall back to some sane behavior).
 */
57
static struct config_source *cf;
58
static struct key_value_info *current_config_kvi;
59

J
Jeff King 已提交
60 61 62 63 64 65 66 67
/*
 * Similar to the variables above, this gives access to the "scope" of the
 * current value (repo, global, etc). For cached values, it can be found via
 * the current_config_kvi as above. During parsing, the current value can be
 * found in this variable. It's not part of "cf" because it transcends a single
 * file (i.e., a file included from .git/config is still in "repo" scope).
 */
static enum config_scope current_parsing_scope;
68

69 70
static int core_compression_seen;
static int pack_compression_seen;
71 72
static int zlib_compression_seen;

73 74 75 76 77 78 79
/*
 * Default config_set that contains key-value pairs from the usual set of config
 * config files (i.e repo specific .git/config, user wide ~/.gitconfig, XDG
 * config file and the global /etc/gitconfig)
 */
static struct config_set the_config_set;

80 81
static int config_file_fgetc(struct config_source *conf)
{
82
	return getc_unlocked(conf->u.file);
83 84 85 86 87 88 89 90 91 92 93 94
}

static int config_file_ungetc(int c, struct config_source *conf)
{
	return ungetc(c, conf->u.file);
}

static long config_file_ftell(struct config_source *conf)
{
	return ftell(conf->u.file);
}

95 96 97 98 99 100 101 102 103 104 105

static int config_buf_fgetc(struct config_source *conf)
{
	if (conf->u.buf.pos < conf->u.buf.len)
		return conf->u.buf.buf[conf->u.buf.pos++];

	return EOF;
}

static int config_buf_ungetc(int c, struct config_source *conf)
{
106 107 108 109 110 111
	if (conf->u.buf.pos > 0) {
		conf->u.buf.pos--;
		if (conf->u.buf.buf[conf->u.buf.pos] != c)
			die("BUG: config_buf can only ungetc the same character");
		return c;
	}
112 113 114 115 116 117 118 119 120

	return EOF;
}

static long config_buf_ftell(struct config_source *conf)
{
	return conf->u.buf.pos;
}

J
Jeff King 已提交
121 122 123 124 125 126 127 128 129 130 131
#define MAX_INCLUDE_DEPTH 10
static const char include_depth_advice[] =
"exceeded maximum include depth (%d) while including\n"
"	%s\n"
"from\n"
"	%s\n"
"Do you have circular includes?";
static int handle_path_include(const char *path, struct config_include_data *inc)
{
	int ret = 0;
	struct strbuf buf = STRBUF_INIT;
132
	char *expanded;
133

134 135 136 137
	if (!path)
		return config_error_nonbool("include.path");

	expanded = expand_user_path(path);
138
	if (!expanded)
139
		return error("could not expand include path '%s'", path);
140
	path = expanded;
J
Jeff King 已提交
141 142 143 144 145 146 147 148

	/*
	 * Use an absolute path as-is, but interpret relative paths
	 * based on the including config file.
	 */
	if (!is_absolute_path(path)) {
		char *slash;

149
		if (!cf || !cf->path)
J
Jeff King 已提交
150 151
			return error("relative config includes must come from files");

152
		slash = find_last_dir_sep(cf->path);
J
Jeff King 已提交
153
		if (slash)
154
			strbuf_add(&buf, cf->path, slash - cf->path + 1);
J
Jeff King 已提交
155 156 157 158
		strbuf_addstr(&buf, path);
		path = buf.buf;
	}

159
	if (!access_or_die(path, R_OK, 0)) {
J
Jeff King 已提交
160 161
		if (++inc->depth > MAX_INCLUDE_DEPTH)
			die(include_depth_advice, MAX_INCLUDE_DEPTH, path,
162 163 164
			    !cf ? "<unknown>" :
			    cf->name ? cf->name :
			    "the command line");
J
Jeff King 已提交
165 166 167 168
		ret = git_config_from_file(git_config_include, path, inc);
		inc->depth--;
	}
	strbuf_release(&buf);
169
	free(expanded);
J
Jeff King 已提交
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
	return ret;
}

int git_config_include(const char *var, const char *value, void *data)
{
	struct config_include_data *inc = data;
	int ret;

	/*
	 * Pass along all values, including "include" directives; this makes it
	 * possible to query information on the includes themselves.
	 */
	ret = inc->fn(var, value, inc->data);
	if (ret < 0)
		return ret;

186
	if (!strcmp(var, "include.path"))
J
Jeff King 已提交
187 188 189 190
		ret = handle_path_include(value, inc);
	return ret;
}

191 192 193 194
void git_config_push_parameter(const char *text)
{
	struct strbuf env = STRBUF_INIT;
	const char *old = getenv(CONFIG_DATA_ENVIRONMENT);
195
	if (old && *old) {
196 197 198 199 200 201 202 203
		strbuf_addstr(&env, old);
		strbuf_addch(&env, ' ');
	}
	sq_quote_buf(&env, text);
	setenv(CONFIG_DATA_ENVIRONMENT, env.buf, 1);
	strbuf_release(&env);
}

204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
static inline int iskeychar(int c)
{
	return isalnum(c) || c == '-';
}

/*
 * Auxiliary function to sanity-check and split the key into the section
 * identifier and variable name.
 *
 * Returns 0 on success, -1 when there is an invalid character in the key and
 * -2 if there is no section name in the key.
 *
 * store_key - pointer to char* which will hold a copy of the key with
 *             lowercase section and variable name
 * baselen - pointer to int which will hold the length of the
 *           section + subsection part, can be NULL
 */
static int git_config_parse_key_1(const char *key, char **store_key, int *baselen_, int quiet)
{
	int i, dot, baselen;
	const char *last_dot = strrchr(key, '.');

	/*
	 * Since "key" actually contains the section name and the real
	 * key name separated by a dot, we have to know where the dot is.
	 */

	if (last_dot == NULL || last_dot == key) {
		if (!quiet)
			error("key does not contain a section: %s", key);
		return -CONFIG_NO_SECTION_OR_NAME;
	}

	if (!last_dot[1]) {
		if (!quiet)
			error("key does not contain variable name: %s", key);
		return -CONFIG_NO_SECTION_OR_NAME;
	}

	baselen = last_dot - key;
	if (baselen_)
		*baselen_ = baselen;

	/*
	 * Validate the key and while at it, lower case it for matching.
	 */
	if (store_key)
		*store_key = xmallocz(strlen(key));

	dot = 0;
	for (i = 0; key[i]; i++) {
		unsigned char c = key[i];
		if (c == '.')
			dot = 1;
		/* Leave the extended basename untouched.. */
		if (!dot || i > baselen) {
			if (!iskeychar(c) ||
			    (i == baselen + 1 && !isalpha(c))) {
				if (!quiet)
					error("invalid key: %s", key);
				goto out_free_ret_1;
			}
			c = tolower(c);
		} else if (c == '\n') {
			if (!quiet)
				error("invalid key (newline): %s", key);
			goto out_free_ret_1;
		}
		if (store_key)
			(*store_key)[i] = c;
	}

	return 0;

out_free_ret_1:
	if (store_key) {
		free(*store_key);
		*store_key = NULL;
	}
	return -CONFIG_INVALID_KEY;
}

int git_config_parse_key(const char *key, char **store_key, int *baselen)
{
	return git_config_parse_key_1(key, store_key, baselen, 0);
}

int git_config_key_is_valid(const char *key)
{
	return !git_config_parse_key_1(key, NULL, NULL, 1);
}

296 297
int git_config_parse_parameter(const char *text,
			       config_fn_t fn, void *data)
298
{
299
	const char *value;
300
	char *canonical_name;
301
	struct strbuf **pair;
302
	int ret;
303

304
	pair = strbuf_split_str(text, '=', 2);
305 306
	if (!pair[0])
		return error("bogus config parameter: %s", text);
307 308

	if (pair[0]->len && pair[0]->buf[pair[0]->len - 1] == '=') {
309
		strbuf_setlen(pair[0], pair[0]->len - 1);
310 311 312 313 314
		value = pair[1] ? pair[1]->buf : "";
	} else {
		value = NULL;
	}

315 316 317
	strbuf_trim(pair[0]);
	if (!pair[0]->len) {
		strbuf_list_free(pair);
318
		return error("bogus config parameter: %s", text);
319
	}
320 321 322 323 324 325

	if (git_config_parse_key(pair[0]->buf, &canonical_name, NULL)) {
		ret = -1;
	} else {
		ret = (fn(canonical_name, value, data) < 0) ? -1 : 0;
		free(canonical_name);
326 327
	}
	strbuf_list_free(pair);
328
	return ret;
329 330
}

331 332
int git_config_from_parameters(config_fn_t fn, void *data)
{
333
	const char *env = getenv(CONFIG_DATA_ENVIRONMENT);
334
	int ret = 0;
335 336 337 338
	char *envw;
	const char **argv = NULL;
	int nr = 0, alloc = 0;
	int i;
339
	struct config_source source;
340 341 342

	if (!env)
		return 0;
343 344 345

	memset(&source, 0, sizeof(source));
	source.prev = cf;
346
	source.origin_type = CONFIG_ORIGIN_CMDLINE;
347 348
	cf = &source;

349 350 351 352
	/* sq_dequote will write over it */
	envw = xstrdup(env);

	if (sq_dequote_to_argv(envw, &argv, &nr, &alloc) < 0) {
353 354
		ret = error("bogus format in " CONFIG_DATA_ENVIRONMENT);
		goto out;
355 356 357
	}

	for (i = 0; i < nr; i++) {
358
		if (git_config_parse_parameter(argv[i], fn, data) < 0) {
359 360
			ret = -1;
			goto out;
361 362 363
		}
	}

364
out:
365 366
	free(argv);
	free(envw);
367
	cf = source.prev;
368
	return ret;
369 370
}

L
Linus Torvalds 已提交
371 372
static int get_next_char(void)
{
373
	int c = cf->do_fgetc(cf);
L
Linus Torvalds 已提交
374

375 376
	if (c == '\r') {
		/* DOS like systems */
377
		c = cf->do_fgetc(cf);
378
		if (c != '\n') {
J
Jeff King 已提交
379 380
			if (c != EOF)
				cf->do_ungetc(c, cf);
381
			c = '\r';
L
Linus Torvalds 已提交
382 383
		}
	}
384 385 386 387
	if (c == '\n')
		cf->linenr++;
	if (c == EOF) {
		cf->eof = 1;
388
		cf->linenr++;
389 390
		c = '\n';
	}
L
Linus Torvalds 已提交
391 392 393 394 395
	return c;
}

static char *parse_value(void)
{
396
	int quote = 0, comment = 0, space = 0;
L
Linus Torvalds 已提交
397

398
	strbuf_reset(&cf->value);
L
Linus Torvalds 已提交
399 400 401
	for (;;) {
		int c = get_next_char();
		if (c == '\n') {
402 403
			if (quote) {
				cf->linenr--;
L
Linus Torvalds 已提交
404
				return NULL;
405
			}
406
			return cf->value.buf;
L
Linus Torvalds 已提交
407 408 409 410
		}
		if (comment)
			continue;
		if (isspace(c) && !quote) {
411
			if (cf->value.len)
412
				space++;
L
Linus Torvalds 已提交
413 414
			continue;
		}
415 416 417 418 419 420
		if (!quote) {
			if (c == ';' || c == '#') {
				comment = 1;
				continue;
			}
		}
421
		for (; space; space--)
422
			strbuf_addch(&cf->value, ' ');
L
Linus Torvalds 已提交
423 424 425 426 427 428 429 430 431 432 433 434 435 436
		if (c == '\\') {
			c = get_next_char();
			switch (c) {
			case '\n':
				continue;
			case 't':
				c = '\t';
				break;
			case 'b':
				c = '\b';
				break;
			case 'n':
				c = '\n';
				break;
437 438 439 440 441 442
			/* Some characters escape as themselves */
			case '\\': case '"':
				break;
			/* Reject unknown escape sequences */
			default:
				return NULL;
L
Linus Torvalds 已提交
443
			}
444
			strbuf_addch(&cf->value, c);
L
Linus Torvalds 已提交
445 446 447 448 449 450
			continue;
		}
		if (c == '"') {
			quote = 1-quote;
			continue;
		}
451
		strbuf_addch(&cf->value, c);
L
Linus Torvalds 已提交
452 453 454
	}
}

455
static int get_value(config_fn_t fn, void *data, struct strbuf *name)
L
Linus Torvalds 已提交
456 457 458
{
	int c;
	char *value;
459
	int ret;
L
Linus Torvalds 已提交
460 461 462 463

	/* Get the full name */
	for (;;) {
		c = get_next_char();
464
		if (cf->eof)
L
Linus Torvalds 已提交
465
			break;
466
		if (!iskeychar(c))
L
Linus Torvalds 已提交
467
			break;
468
		strbuf_addch(name, tolower(c));
L
Linus Torvalds 已提交
469
	}
470

L
Linus Torvalds 已提交
471 472 473 474 475 476 477 478 479 480 481
	while (c == ' ' || c == '\t')
		c = get_next_char();

	value = NULL;
	if (c != '\n') {
		if (c != '=')
			return -1;
		value = parse_value();
		if (!value)
			return -1;
	}
482 483 484 485 486 487 488 489 490
	/*
	 * We already consumed the \n, but we need linenr to point to
	 * the line we just parsed during the call to fn to get
	 * accurate line number in error messages.
	 */
	cf->linenr--;
	ret = fn(name->buf, value, data);
	cf->linenr++;
	return ret;
L
Linus Torvalds 已提交
491 492
}

493
static int get_extended_base_var(struct strbuf *name, int c)
L
Linus Torvalds 已提交
494 495 496
{
	do {
		if (c == '\n')
497
			goto error_incomplete_line;
L
Linus Torvalds 已提交
498 499 500 501 502 503
		c = get_next_char();
	} while (isspace(c));

	/* We require the format to be '[base "extension"]' */
	if (c != '"')
		return -1;
504
	strbuf_addch(name, '.');
L
Linus Torvalds 已提交
505 506 507 508

	for (;;) {
		int c = get_next_char();
		if (c == '\n')
509
			goto error_incomplete_line;
L
Linus Torvalds 已提交
510 511 512 513 514
		if (c == '"')
			break;
		if (c == '\\') {
			c = get_next_char();
			if (c == '\n')
515
				goto error_incomplete_line;
L
Linus Torvalds 已提交
516
		}
517
		strbuf_addch(name, c);
L
Linus Torvalds 已提交
518 519 520 521 522
	}

	/* Final ']' */
	if (get_next_char() != ']')
		return -1;
523
	return 0;
524 525 526
error_incomplete_line:
	cf->linenr--;
	return -1;
L
Linus Torvalds 已提交
527 528
}

529
static int get_base_var(struct strbuf *name)
L
Linus Torvalds 已提交
530 531 532
{
	for (;;) {
		int c = get_next_char();
533
		if (cf->eof)
L
Linus Torvalds 已提交
534 535
			return -1;
		if (c == ']')
536
			return 0;
L
Linus Torvalds 已提交
537
		if (isspace(c))
538
			return get_extended_base_var(name, c);
539
		if (!iskeychar(c) && c != '.')
L
Linus Torvalds 已提交
540
			return -1;
541
		strbuf_addch(name, tolower(c));
L
Linus Torvalds 已提交
542 543 544
	}
}

545
static int git_parse_source(config_fn_t fn, void *data)
L
Linus Torvalds 已提交
546 547 548
{
	int comment = 0;
	int baselen = 0;
549
	struct strbuf *var = &cf->var;
550 551
	int error_return = 0;
	char *error_msg = NULL;
L
Linus Torvalds 已提交
552

553
	/* U+FEFF Byte Order Mark in UTF8 */
554
	const char *bomptr = utf8_bom;
555

L
Linus Torvalds 已提交
556 557
	for (;;) {
		int c = get_next_char();
558 559 560 561
		if (bomptr && *bomptr) {
			/* We are at the file beginning; skip UTF8-encoded BOM
			 * if present. Sane editors won't put this in on their
			 * own, but e.g. Windows Notepad will do it happily. */
562
			if (c == (*bomptr & 0377)) {
563 564 565 566 567 568 569 570 571 572
				bomptr++;
				continue;
			} else {
				/* Do not tolerate partial BOM. */
				if (bomptr != utf8_bom)
					break;
				/* No BOM at file beginning. Cool. */
				bomptr = NULL;
			}
		}
L
Linus Torvalds 已提交
573
		if (c == '\n') {
574
			if (cf->eof)
L
Linus Torvalds 已提交
575 576 577 578 579 580 581 582 583 584 585
				return 0;
			comment = 0;
			continue;
		}
		if (comment || isspace(c))
			continue;
		if (c == '#' || c == ';') {
			comment = 1;
			continue;
		}
		if (c == '[') {
586 587 588
			/* Reset prior to determining a new stem */
			strbuf_reset(var);
			if (get_base_var(var) < 0 || var->len < 1)
L
Linus Torvalds 已提交
589
				break;
590 591
			strbuf_addch(var, '.');
			baselen = var->len;
L
Linus Torvalds 已提交
592 593 594 595
			continue;
		}
		if (!isalpha(c))
			break;
596 597 598 599 600 601 602 603
		/*
		 * Truncate the var name back to the section header
		 * stem prior to grabbing the suffix part of the name
		 * and the value.
		 */
		strbuf_setlen(var, baselen);
		strbuf_addch(var, tolower(c));
		if (get_value(fn, data, var) < 0)
L
Linus Torvalds 已提交
604 605
			break;
	}
606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632

	switch (cf->origin_type) {
	case CONFIG_ORIGIN_BLOB:
		error_msg = xstrfmt(_("bad config line %d in blob %s"),
				      cf->linenr, cf->name);
		break;
	case CONFIG_ORIGIN_FILE:
		error_msg = xstrfmt(_("bad config line %d in file %s"),
				      cf->linenr, cf->name);
		break;
	case CONFIG_ORIGIN_STDIN:
		error_msg = xstrfmt(_("bad config line %d in standard input"),
				      cf->linenr);
		break;
	case CONFIG_ORIGIN_SUBMODULE_BLOB:
		error_msg = xstrfmt(_("bad config line %d in submodule-blob %s"),
				       cf->linenr, cf->name);
		break;
	case CONFIG_ORIGIN_CMDLINE:
		error_msg = xstrfmt(_("bad config line %d in command line %s"),
				       cf->linenr, cf->name);
		break;
	default:
		error_msg = xstrfmt(_("bad config line %d in %s"),
				      cf->linenr, cf->name);
	}

633
	if (cf->die_on_error)
634
		die("%s", error_msg);
635
	else
636 637 638 639
		error_return = error("%s", error_msg);

	free(error_msg);
	return error_return;
L
Linus Torvalds 已提交
640 641
}

642
static int parse_unit_factor(const char *end, uintmax_t *val)
643 644 645
{
	if (!*end)
		return 1;
646 647 648 649 650 651 652 653 654 655 656 657 658
	else if (!strcasecmp(end, "k")) {
		*val *= 1024;
		return 1;
	}
	else if (!strcasecmp(end, "m")) {
		*val *= 1024 * 1024;
		return 1;
	}
	else if (!strcasecmp(end, "g")) {
		*val *= 1024 * 1024 * 1024;
		return 1;
	}
	return 0;
659 660
}

661
static int git_parse_signed(const char *value, intmax_t *ret, intmax_t max)
662 663 664
{
	if (value && *value) {
		char *end;
665 666 667 668 669 670 671 672
		intmax_t val;
		uintmax_t uval;
		uintmax_t factor = 1;

		errno = 0;
		val = strtoimax(value, &end, 0);
		if (errno == ERANGE)
			return 0;
673 674
		if (!parse_unit_factor(end, &factor)) {
			errno = EINVAL;
675
			return 0;
676
		}
677
		uval = labs(val);
678
		uval *= factor;
679
		if (uval > max || labs(val) > uval) {
680
			errno = ERANGE;
681
			return 0;
682
		}
683 684
		val *= factor;
		*ret = val;
685 686
		return 1;
	}
687
	errno = EINVAL;
688 689 690
	return 0;
}

691
static int git_parse_unsigned(const char *value, uintmax_t *ret, uintmax_t max)
L
Linus Torvalds 已提交
692 693 694
{
	if (value && *value) {
		char *end;
695 696 697 698 699 700 701 702
		uintmax_t val;
		uintmax_t oldval;

		errno = 0;
		val = strtoumax(value, &end, 0);
		if (errno == ERANGE)
			return 0;
		oldval = val;
703 704
		if (!parse_unit_factor(end, &val)) {
			errno = EINVAL;
705
			return 0;
706 707 708
		}
		if (val > max || oldval > val) {
			errno = ERANGE;
709
			return 0;
710
		}
711
		*ret = val;
712
		return 1;
L
Linus Torvalds 已提交
713
	}
714
	errno = EINVAL;
715 716 717
	return 0;
}

718
static int git_parse_int(const char *value, int *ret)
719
{
720
	intmax_t tmp;
721
	if (!git_parse_signed(value, &tmp, maximum_signed_value_of_type(int)))
722 723 724 725 726
		return 0;
	*ret = tmp;
	return 1;
}

727 728 729 730 731 732 733 734 735
static int git_parse_int64(const char *value, int64_t *ret)
{
	intmax_t tmp;
	if (!git_parse_signed(value, &tmp, maximum_signed_value_of_type(int64_t)))
		return 0;
	*ret = tmp;
	return 1;
}

736 737 738 739 740 741 742 743 744
int git_parse_ulong(const char *value, unsigned long *ret)
{
	uintmax_t tmp;
	if (!git_parse_unsigned(value, &tmp, maximum_unsigned_value_of_type(long)))
		return 0;
	*ret = tmp;
	return 1;
}

745
NORETURN
746
static void die_bad_number(const char *name, const char *value)
747
{
748 749
	const char * error_type = (errno == ERANGE)? _("out of range"):_("invalid unit");

750 751 752
	if (!value)
		value = "";

753
	if (!(cf && cf->name))
754 755
		die(_("bad numeric config value '%s' for '%s': %s"),
		    value, name, error_type);
756 757 758

	switch (cf->origin_type) {
	case CONFIG_ORIGIN_BLOB:
759 760
		die(_("bad numeric config value '%s' for '%s' in blob %s: %s"),
		    value, name, cf->name, error_type);
761
	case CONFIG_ORIGIN_FILE:
762 763
		die(_("bad numeric config value '%s' for '%s' in file %s: %s"),
		    value, name, cf->name, error_type);
764
	case CONFIG_ORIGIN_STDIN:
765 766
		die(_("bad numeric config value '%s' for '%s' in standard input: %s"),
		    value, name, error_type);
767
	case CONFIG_ORIGIN_SUBMODULE_BLOB:
768 769
		die(_("bad numeric config value '%s' for '%s' in submodule-blob %s: %s"),
		    value, name, cf->name, error_type);
770
	case CONFIG_ORIGIN_CMDLINE:
771 772
		die(_("bad numeric config value '%s' for '%s' in command line %s: %s"),
		    value, name, cf->name, error_type);
773
	default:
774 775
		die(_("bad numeric config value '%s' for '%s' in %s: %s"),
		    value, name, cf->name, error_type);
776
	}
777 778
}

779 780
int git_config_int(const char *name, const char *value)
{
781 782
	int ret;
	if (!git_parse_int(value, &ret))
783
		die_bad_number(name, value);
784 785 786
	return ret;
}

787 788 789 790 791
int64_t git_config_int64(const char *name, const char *value)
{
	int64_t ret;
	if (!git_parse_int64(value, &ret))
		die_bad_number(name, value);
792 793 794 795 796 797 798
	return ret;
}

unsigned long git_config_ulong(const char *name, const char *value)
{
	unsigned long ret;
	if (!git_parse_ulong(value, &ret))
799
		die_bad_number(name, value);
800
	return ret;
L
Linus Torvalds 已提交
801 802
}

803
int git_parse_maybe_bool(const char *value)
L
Linus Torvalds 已提交
804 805 806 807 808
{
	if (!value)
		return 1;
	if (!*value)
		return 0;
J
Junio C Hamano 已提交
809 810 811
	if (!strcasecmp(value, "true")
	    || !strcasecmp(value, "yes")
	    || !strcasecmp(value, "on"))
L
Linus Torvalds 已提交
812
		return 1;
J
Junio C Hamano 已提交
813 814 815
	if (!strcasecmp(value, "false")
	    || !strcasecmp(value, "no")
	    || !strcasecmp(value, "off"))
L
Linus Torvalds 已提交
816
		return 0;
J
Junio C Hamano 已提交
817 818 819
	return -1;
}

J
Jeff King 已提交
820 821
int git_config_maybe_bool(const char *name, const char *value)
{
822
	int v = git_parse_maybe_bool(value);
J
Jeff King 已提交
823 824
	if (0 <= v)
		return v;
825
	if (git_parse_int(value, &v))
826
		return !!v;
J
Jeff King 已提交
827 828 829
	return -1;
}

J
Junio C Hamano 已提交
830 831
int git_config_bool_or_int(const char *name, const char *value, int *is_bool)
{
832
	int v = git_parse_maybe_bool(value);
J
Junio C Hamano 已提交
833 834 835 836
	if (0 <= v) {
		*is_bool = 1;
		return v;
	}
J
Junio C Hamano 已提交
837
	*is_bool = 0;
J
Junio C Hamano 已提交
838
	return git_config_int(name, value);
L
Linus Torvalds 已提交
839 840
}

J
Junio C Hamano 已提交
841 842 843
int git_config_bool(const char *name, const char *value)
{
	int discard;
J
Junio C Hamano 已提交
844
	return !!git_config_bool_or_int(name, value, &discard);
J
Junio C Hamano 已提交
845 846
}

847 848 849 850 851 852 853 854
int git_config_string(const char **dest, const char *var, const char *value)
{
	if (!value)
		return config_error_nonbool(var);
	*dest = xstrdup(value);
	return 0;
}

855 856 857 858 859 860
int git_config_pathname(const char **dest, const char *var, const char *value)
{
	if (!value)
		return config_error_nonbool(var);
	*dest = expand_user_path(value);
	if (!*dest)
861
		die(_("failed to expand user dir in: '%s'"), value);
862 863 864
	return 0;
}

865
static int git_default_core_config(const char *var, const char *value)
L
Linus Torvalds 已提交
866 867 868 869 870 871
{
	/* This needs a better name */
	if (!strcmp(var, "core.filemode")) {
		trust_executable_bit = git_config_bool(var, value);
		return 0;
	}
872 873 874 875
	if (!strcmp(var, "core.trustctime")) {
		trust_ctime = git_config_bool(var, value);
		return 0;
	}
876
	if (!strcmp(var, "core.checkstat")) {
R
Robin Rosenberg 已提交
877 878 879 880 881
		if (!strcasecmp(value, "default"))
			check_stat = 1;
		else if (!strcasecmp(value, "minimal"))
			check_stat = 0;
	}
L
Linus Torvalds 已提交
882

883 884 885 886 887
	if (!strcmp(var, "core.quotepath")) {
		quote_path_fully = git_config_bool(var, value);
		return 0;
	}

888 889 890 891 892
	if (!strcmp(var, "core.symlinks")) {
		has_symlinks = git_config_bool(var, value);
		return 0;
	}

L
Linus Torvalds 已提交
893 894 895 896 897
	if (!strcmp(var, "core.ignorecase")) {
		ignore_case = git_config_bool(var, value);
		return 0;
	}

898 899 900
	if (!strcmp(var, "core.attributesfile"))
		return git_config_pathname(&git_attributes_file, var, value);

901 902 903
	if (!strcmp(var, "core.hookspath"))
		return git_config_pathname(&git_hooks_path, var, value);

904 905 906 907 908
	if (!strcmp(var, "core.bare")) {
		is_bare_repository_cfg = git_config_bool(var, value);
		return 0;
	}

J
Junio C Hamano 已提交
909 910 911 912 913
	if (!strcmp(var, "core.ignorestat")) {
		assume_unchanged = git_config_bool(var, value);
		return 0;
	}

914 915
	if (!strcmp(var, "core.prefersymlinkrefs")) {
		prefer_symlink_refs = git_config_bool(var, value);
916 917 918
		return 0;
	}

919
	if (!strcmp(var, "core.logallrefupdates")) {
920 921 922 923 924 925
		if (value && !strcasecmp(value, "always"))
			log_all_ref_updates = LOG_REFS_ALWAYS;
		else if (git_config_bool(var, value))
			log_all_ref_updates = LOG_REFS_NORMAL;
		else
			log_all_ref_updates = LOG_REFS_NONE;
926 927 928
		return 0;
	}

929 930 931 932 933
	if (!strcmp(var, "core.warnambiguousrefs")) {
		warn_ambiguous_refs = git_config_bool(var, value);
		return 0;
	}

934
	if (!strcmp(var, "core.abbrev")) {
935 936 937 938 939 940 941 942 943 944
		if (!value)
			return config_error_nonbool(var);
		if (!strcasecmp(value, "auto"))
			default_abbrev = -1;
		else {
			int abbrev = git_config_int(var, value);
			if (abbrev < minimum_abbrev || abbrev > 40)
				return error("abbrev length out of range: %d", abbrev);
			default_abbrev = abbrev;
		}
945 946 947
		return 0;
	}

948 949 950
	if (!strcmp(var, "core.disambiguate"))
		return set_disambiguate_hint_config(var, value);

951
	if (!strcmp(var, "core.loosecompression")) {
952 953 954 955
		int level = git_config_int(var, value);
		if (level == -1)
			level = Z_DEFAULT_COMPRESSION;
		else if (level < 0 || level > Z_BEST_COMPRESSION)
956
			die(_("bad zlib compression level %d"), level);
957
		zlib_compression_level = level;
958 959 960 961 962 963 964 965 966
		zlib_compression_seen = 1;
		return 0;
	}

	if (!strcmp(var, "core.compression")) {
		int level = git_config_int(var, value);
		if (level == -1)
			level = Z_DEFAULT_COMPRESSION;
		else if (level < 0 || level > Z_BEST_COMPRESSION)
967
			die(_("bad zlib compression level %d"), level);
968 969 970 971
		core_compression_level = level;
		core_compression_seen = 1;
		if (!zlib_compression_seen)
			zlib_compression_level = level;
972 973
		if (!pack_compression_seen)
			pack_compression_level = level;
974 975 976
		return 0;
	}

977
	if (!strcmp(var, "core.packedgitwindowsize")) {
978
		int pgsz_x2 = getpagesize() * 2;
979
		packed_git_window_size = git_config_ulong(var, value);
980 981 982 983 984 985

		/* This value must be multiple of (pagesize * 2) */
		packed_git_window_size /= pgsz_x2;
		if (packed_git_window_size < 1)
			packed_git_window_size = 1;
		packed_git_window_size *= pgsz_x2;
986 987 988
		return 0;
	}

989
	if (!strcmp(var, "core.bigfilethreshold")) {
990
		big_file_threshold = git_config_ulong(var, value);
991 992 993
		return 0;
	}

994
	if (!strcmp(var, "core.packedgitlimit")) {
995
		packed_git_limit = git_config_ulong(var, value);
996 997 998
		return 0;
	}

999
	if (!strcmp(var, "core.deltabasecachelimit")) {
1000
		delta_base_cache_limit = git_config_ulong(var, value);
1001 1002 1003
		return 0;
	}

L
Linus Torvalds 已提交
1004
	if (!strcmp(var, "core.autocrlf")) {
L
Linus Torvalds 已提交
1005
		if (value && !strcasecmp(value, "input")) {
1006
			auto_crlf = AUTO_CRLF_INPUT;
L
Linus Torvalds 已提交
1007 1008
			return 0;
		}
L
Linus Torvalds 已提交
1009 1010 1011 1012
		auto_crlf = git_config_bool(var, value);
		return 0;
	}

1013 1014 1015 1016 1017 1018 1019 1020 1021
	if (!strcmp(var, "core.safecrlf")) {
		if (value && !strcasecmp(value, "warn")) {
			safe_crlf = SAFE_CRLF_WARN;
			return 0;
		}
		safe_crlf = git_config_bool(var, value);
		return 0;
	}

1022 1023
	if (!strcmp(var, "core.eol")) {
		if (value && !strcasecmp(value, "lf"))
1024
			core_eol = EOL_LF;
1025
		else if (value && !strcasecmp(value, "crlf"))
1026
			core_eol = EOL_CRLF;
1027
		else if (value && !strcasecmp(value, "native"))
1028
			core_eol = EOL_NATIVE;
1029
		else
1030
			core_eol = EOL_UNSET;
1031 1032 1033
		return 0;
	}

J
Johannes Schindelin 已提交
1034 1035 1036 1037 1038
	if (!strcmp(var, "core.notesref")) {
		notes_ref_name = xstrdup(value);
		return 0;
	}

1039 1040 1041
	if (!strcmp(var, "core.editor"))
		return git_config_string(&editor_program, var, value);

J
Junio C Hamano 已提交
1042
	if (!strcmp(var, "core.commentchar")) {
1043 1044
		if (!value)
			return config_error_nonbool(var);
1045
		else if (!strcasecmp(value, "auto"))
1046
			auto_comment_line_char = 1;
1047
		else if (value[0] && !value[1]) {
1048
			comment_line_char = value[0];
1049
			auto_comment_line_char = 0;
1050 1051 1052
		} else
			return error("core.commentChar should only be one character");
		return 0;
J
Junio C Hamano 已提交
1053 1054
	}

A
Anselm Kruis 已提交
1055 1056 1057
	if (!strcmp(var, "core.askpass"))
		return git_config_string(&askpass_program, var, value);

1058
	if (!strcmp(var, "core.excludesfile"))
1059
		return git_config_pathname(&excludes_file, var, value);
1060 1061 1062 1063 1064 1065 1066 1067

	if (!strcmp(var, "core.whitespace")) {
		if (!value)
			return config_error_nonbool(var);
		whitespace_rule_cfg = parse_whitespace_rule(value);
		return 0;
	}

1068 1069 1070 1071 1072
	if (!strcmp(var, "core.fsyncobjectfiles")) {
		fsync_object_files = git_config_bool(var, value);
		return 0;
	}

L
Linus Torvalds 已提交
1073 1074 1075 1076 1077
	if (!strcmp(var, "core.preloadindex")) {
		core_preload_index = git_config_bool(var, value);
		return 0;
	}

1078 1079 1080 1081 1082 1083
	if (!strcmp(var, "core.createobject")) {
		if (!strcmp(value, "rename"))
			object_creation_mode = OBJECT_CREATION_USES_RENAMES;
		else if (!strcmp(value, "link"))
			object_creation_mode = OBJECT_CREATION_USES_HARDLINKS;
		else
1084
			die(_("invalid mode for object creation: %s"), value);
1085 1086 1087
		return 0;
	}

1088 1089 1090 1091 1092
	if (!strcmp(var, "core.sparsecheckout")) {
		core_apply_sparse_checkout = git_config_bool(var, value);
		return 0;
	}

1093 1094 1095 1096 1097
	if (!strcmp(var, "core.precomposeunicode")) {
		precomposed_unicode = git_config_bool(var, value);
		return 0;
	}

1098 1099 1100 1101 1102
	if (!strcmp(var, "core.protecthfs")) {
		protect_hfs = git_config_bool(var, value);
		return 0;
	}

1103 1104 1105
	if (!strcmp(var, "core.protectntfs")) {
		protect_ntfs = git_config_bool(var, value);
		return 0;
1106 1107
	}

1108 1109 1110 1111 1112 1113 1114 1115
	if (!strcmp(var, "core.hidedotfiles")) {
		if (value && !strcasecmp(value, "dotgitonly"))
			hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
		else
			hide_dotfiles = git_config_bool(var, value);
		return 0;
	}

1116 1117 1118 1119
	/* Add other config variables here and to Documentation/config.txt. */
	return 0;
}

1120
static int git_default_i18n_config(const char *var, const char *value)
1121
{
1122 1123
	if (!strcmp(var, "i18n.commitencoding"))
		return git_config_string(&git_commit_encoding, var, value);
1124

1125 1126
	if (!strcmp(var, "i18n.logoutputencoding"))
		return git_config_string(&git_log_output_encoding, var, value);
1127

1128 1129 1130
	/* Add other config variables here and to Documentation/config.txt. */
	return 0;
}
J
Junio C Hamano 已提交
1131

1132 1133
static int git_default_branch_config(const char *var, const char *value)
{
1134 1135 1136 1137 1138 1139 1140 1141
	if (!strcmp(var, "branch.autosetupmerge")) {
		if (value && !strcasecmp(value, "always")) {
			git_branch_track = BRANCH_TRACK_ALWAYS;
			return 0;
		}
		git_branch_track = git_config_bool(var, value);
		return 0;
	}
1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153
	if (!strcmp(var, "branch.autosetuprebase")) {
		if (!value)
			return config_error_nonbool(var);
		else if (!strcmp(value, "never"))
			autorebase = AUTOREBASE_NEVER;
		else if (!strcmp(value, "local"))
			autorebase = AUTOREBASE_LOCAL;
		else if (!strcmp(value, "remote"))
			autorebase = AUTOREBASE_REMOTE;
		else if (!strcmp(value, "always"))
			autorebase = AUTOREBASE_ALWAYS;
		else
1154
			return error("malformed value for %s", var);
1155 1156
		return 0;
	}
1157

P
Petr Baudis 已提交
1158
	/* Add other config variables here and to Documentation/config.txt. */
L
Linus Torvalds 已提交
1159 1160 1161
	return 0;
}

1162 1163 1164 1165 1166 1167 1168 1169 1170
static int git_default_push_config(const char *var, const char *value)
{
	if (!strcmp(var, "push.default")) {
		if (!value)
			return config_error_nonbool(var);
		else if (!strcmp(value, "nothing"))
			push_default = PUSH_DEFAULT_NOTHING;
		else if (!strcmp(value, "matching"))
			push_default = PUSH_DEFAULT_MATCHING;
1171 1172
		else if (!strcmp(value, "simple"))
			push_default = PUSH_DEFAULT_SIMPLE;
1173 1174 1175 1176
		else if (!strcmp(value, "upstream"))
			push_default = PUSH_DEFAULT_UPSTREAM;
		else if (!strcmp(value, "tracking")) /* deprecated */
			push_default = PUSH_DEFAULT_UPSTREAM;
1177 1178 1179
		else if (!strcmp(value, "current"))
			push_default = PUSH_DEFAULT_CURRENT;
		else {
1180
			error("malformed value for %s: %s", var, value);
1181 1182
			return error("Must be one of nothing, matching, simple, "
				     "upstream or current.");
1183 1184 1185 1186 1187 1188 1189 1190
		}
		return 0;
	}

	/* Add other config variables here and to Documentation/config.txt. */
	return 0;
}

1191 1192 1193
static int git_default_mailmap_config(const char *var, const char *value)
{
	if (!strcmp(var, "mailmap.file"))
1194
		return git_config_pathname(&git_mailmap_file, var, value);
1195 1196
	if (!strcmp(var, "mailmap.blob"))
		return git_config_string(&git_mailmap_blob, var, value);
1197 1198 1199 1200 1201

	/* Add other config variables here and to Documentation/config.txt. */
	return 0;
}

1202 1203
int git_default_config(const char *var, const char *value, void *dummy)
{
1204
	if (starts_with(var, "core."))
1205 1206
		return git_default_core_config(var, value);

1207
	if (starts_with(var, "user."))
1208
		return git_ident_config(var, value, dummy);
1209

1210
	if (starts_with(var, "i18n."))
1211 1212
		return git_default_i18n_config(var, value);

1213
	if (starts_with(var, "branch."))
1214 1215
		return git_default_branch_config(var, value);

1216
	if (starts_with(var, "push."))
1217 1218
		return git_default_push_config(var, value);

1219
	if (starts_with(var, "mailmap."))
1220 1221
		return git_default_mailmap_config(var, value);

1222
	if (starts_with(var, "advice."))
1223 1224
		return git_default_advice_config(var, value);

1225 1226 1227 1228 1229
	if (!strcmp(var, "pager.color") || !strcmp(var, "color.pager")) {
		pager_use_color = git_config_bool(var,value);
		return 0;
	}

1230 1231 1232 1233
	if (!strcmp(var, "pack.packsizelimit")) {
		pack_size_limit_cfg = git_config_ulong(var, value);
		return 0;
	}
1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245

	if (!strcmp(var, "pack.compression")) {
		int level = git_config_int(var, value);
		if (level == -1)
			level = Z_DEFAULT_COMPRESSION;
		else if (level < 0 || level > Z_BEST_COMPRESSION)
			die(_("bad pack compression level %d"), level);
		pack_compression_level = level;
		pack_compression_seen = 1;
		return 0;
	}

1246 1247 1248 1249
	/* Add other config variables here and to Documentation/config.txt. */
	return 0;
}

1250
/*
1251
 * All source specific fields in the union, die_on_error, name and the callbacks
1252
 * fgetc, ungetc, ftell of top need to be initialized before calling
1253 1254
 * this function.
 */
1255
static int do_config_from(struct config_source *top, config_fn_t fn, void *data)
1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266
{
	int ret;

	/* push config-file parsing state stack */
	top->prev = cf;
	top->linenr = 1;
	top->eof = 0;
	strbuf_init(&top->value, 1024);
	strbuf_init(&top->var, 1024);
	cf = top;

1267
	ret = git_parse_source(fn, data);
1268 1269 1270 1271 1272 1273 1274 1275 1276

	/* pop config-file parsing state stack */
	strbuf_release(&top->value);
	strbuf_release(&top->var);
	cf = top->prev;

	return ret;
}

1277
static int do_config_from_file(config_fn_t fn,
1278 1279
		const enum config_origin_type origin_type,
		const char *name, const char *path, FILE *f,
1280
		void *data)
L
Linus Torvalds 已提交
1281
{
1282
	struct config_source top;
L
Linus Torvalds 已提交
1283

1284
	top.u.file = f;
1285
	top.origin_type = origin_type;
1286 1287 1288 1289 1290 1291
	top.name = name;
	top.path = path;
	top.die_on_error = 1;
	top.do_fgetc = config_file_fgetc;
	top.do_ungetc = config_file_ungetc;
	top.do_ftell = config_file_ftell;
1292

1293 1294
	return do_config_from(&top, fn, data);
}
1295

1296 1297
static int git_config_from_stdin(config_fn_t fn, void *data)
{
1298
	return do_config_from_file(fn, CONFIG_ORIGIN_STDIN, "", NULL, stdin, data);
1299 1300 1301 1302 1303 1304
}

int git_config_from_file(config_fn_t fn, const char *filename, void *data)
{
	int ret = -1;
	FILE *f;
1305

1306 1307
	f = fopen(filename, "r");
	if (f) {
1308
		flockfile(f);
1309
		ret = do_config_from_file(fn, CONFIG_ORIGIN_FILE, filename, filename, f, data);
1310
		funlockfile(f);
L
Linus Torvalds 已提交
1311 1312 1313 1314
		fclose(f);
	}
	return ret;
}
1315

1316
int git_config_from_mem(config_fn_t fn, const enum config_origin_type origin_type,
1317
			const char *name, const char *buf, size_t len, void *data)
1318 1319 1320 1321 1322 1323
{
	struct config_source top;

	top.u.buf.buf = buf;
	top.u.buf.len = len;
	top.u.buf.pos = 0;
1324
	top.origin_type = origin_type;
1325
	top.name = name;
1326
	top.path = NULL;
1327
	top.die_on_error = 0;
1328 1329 1330
	top.do_fgetc = config_buf_fgetc;
	top.do_ungetc = config_buf_ungetc;
	top.do_ftell = config_buf_ftell;
1331 1332 1333 1334

	return do_config_from(&top, fn, data);
}

1335 1336 1337 1338
int git_config_from_blob_sha1(config_fn_t fn,
			      const char *name,
			      const unsigned char *sha1,
			      void *data)
1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352
{
	enum object_type type;
	char *buf;
	unsigned long size;
	int ret;

	buf = read_sha1_file(sha1, &type, &size);
	if (!buf)
		return error("unable to load config blob object '%s'", name);
	if (type != OBJ_BLOB) {
		free(buf);
		return error("reference '%s' does not point to a blob", name);
	}

1353
	ret = git_config_from_mem(fn, CONFIG_ORIGIN_BLOB, name, buf, size, data);
1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369
	free(buf);

	return ret;
}

static int git_config_from_blob_ref(config_fn_t fn,
				    const char *name,
				    void *data)
{
	unsigned char sha1[20];

	if (get_sha1(name, sha1) < 0)
		return error("unable to resolve config blob '%s'", name);
	return git_config_from_blob_sha1(fn, name, sha1, data);
}

1370 1371
const char *git_etc_gitconfig(void)
{
1372
	static const char *system_wide;
1373 1374
	if (!system_wide)
		system_wide = system_path(ETC_GITCONFIG);
1375
	return system_wide;
1376 1377
}

1378 1379 1380 1381
/*
 * Parse environment variable 'k' as a boolean (in various
 * possible spellings); if missing, use the default value 'def'.
 */
1382
int git_env_bool(const char *k, int def)
1383 1384 1385 1386 1387
{
	const char *v = getenv(k);
	return v ? git_config_bool(k, v) : def;
}

1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399
/*
 * Parse environment variable 'k' as ulong with possibly a unit
 * suffix; if missing, use the default value 'val'.
 */
unsigned long git_env_ulong(const char *k, unsigned long val)
{
	const char *v = getenv(k);
	if (v && !git_parse_ulong(v, &val))
		die("failed to parse %s", k);
	return val;
}

1400 1401 1402 1403 1404
int git_config_system(void)
{
	return !git_env_bool("GIT_CONFIG_NOSYSTEM", 0);
}

J
Jeff King 已提交
1405
static int do_git_config_sequence(config_fn_t fn, void *data)
1406
{
1407
	int ret = 0;
1408 1409
	char *xdg_config = xdg_config_home("config");
	char *user_config = expand_user_path("~/.gitconfig");
1410
	char *repo_config = have_git_dir() ? git_pathdup("config") : NULL;
1411

J
Jeff King 已提交
1412
	current_parsing_scope = CONFIG_SCOPE_SYSTEM;
1413
	if (git_config_system() && !access_or_die(git_etc_gitconfig(), R_OK, 0))
1414 1415
		ret += git_config_from_file(fn, git_etc_gitconfig(),
					    data);
1416

J
Jeff King 已提交
1417
	current_parsing_scope = CONFIG_SCOPE_GLOBAL;
1418
	if (xdg_config && !access_or_die(xdg_config, R_OK, ACCESS_EACCES_OK))
1419 1420
		ret += git_config_from_file(fn, xdg_config, data);

1421
	if (user_config && !access_or_die(user_config, R_OK, ACCESS_EACCES_OK))
1422
		ret += git_config_from_file(fn, user_config, data);
1423

J
Jeff King 已提交
1424
	current_parsing_scope = CONFIG_SCOPE_REPO;
1425
	if (repo_config && !access_or_die(repo_config, R_OK, 0))
1426
		ret += git_config_from_file(fn, repo_config, data);
1427

J
Jeff King 已提交
1428
	current_parsing_scope = CONFIG_SCOPE_CMDLINE;
1429
	if (git_config_from_parameters(fn, data) < 0)
1430
		die(_("unable to parse command-line config"));
1431

J
Jeff King 已提交
1432
	current_parsing_scope = CONFIG_SCOPE_UNKNOWN;
1433 1434
	free(xdg_config);
	free(user_config);
J
Jeff King 已提交
1435
	free(repo_config);
1436
	return ret;
1437 1438
}

1439
int git_config_with_options(config_fn_t fn, void *data,
1440
			    struct git_config_source *config_source,
1441
			    int respect_includes)
N
Nguyễn Thái Ngọc Duy 已提交
1442
{
J
Jeff King 已提交
1443 1444 1445 1446 1447 1448 1449 1450
	struct config_include_data inc = CONFIG_INCLUDE_INIT;

	if (respect_includes) {
		inc.fn = fn;
		inc.data = data;
		fn = git_config_include;
		data = &inc;
	}
N
Nguyễn Thái Ngọc Duy 已提交
1451

1452 1453 1454 1455
	/*
	 * If we have a specific filename, use it. Otherwise, follow the
	 * regular lookup sequence.
	 */
1456 1457 1458
	if (config_source && config_source->use_stdin)
		return git_config_from_stdin(fn, data);
	else if (config_source && config_source->file)
1459 1460 1461
		return git_config_from_file(fn, config_source->file, data);
	else if (config_source && config_source->blob)
		return git_config_from_blob_ref(fn, config_source->blob, data);
1462

J
Jeff King 已提交
1463
	return do_git_config_sequence(fn, data);
N
Nguyễn Thái Ngọc Duy 已提交
1464 1465
}

1466
static void git_config_raw(config_fn_t fn, void *data)
1467
{
1468 1469 1470
	if (git_config_with_options(fn, data, NULL, 1) < 0)
		/*
		 * git_config_with_options() normally returns only
1471
		 * zero, as most errors are fatal, and
1472 1473 1474 1475 1476 1477 1478 1479
		 * non-fatal potential errors are guarded by "if"
		 * statements that are entered only when no error is
		 * possible.
		 *
		 * If we ever encounter a non-fatal error, it means
		 * something went really wrong and we should stop
		 * immediately.
		 */
1480
		die(_("unknown error occurred while reading the configuration files"));
1481 1482
}

1483
static void configset_iter(struct config_set *cs, config_fn_t fn, void *data)
1484
{
1485 1486 1487 1488 1489 1490 1491 1492 1493
	int i, value_index;
	struct string_list *values;
	struct config_set_element *entry;
	struct configset_list *list = &cs->list;

	for (i = 0; i < list->nr; i++) {
		entry = list->items[i].e;
		value_index = list->items[i].value_index;
		values = &entry->value_list;
1494 1495 1496 1497 1498 1499 1500 1501 1502

		current_config_kvi = values->items[value_index].util;

		if (fn(entry->key, values->items[value_index].string, data) < 0)
			git_die_config_linenr(entry->key,
					      current_config_kvi->filename,
					      current_config_kvi->linenr);

		current_config_kvi = NULL;
1503 1504 1505 1506 1507 1508 1509 1510 1511
	}
}

static void git_config_check_init(void);

void git_config(config_fn_t fn, void *data)
{
	git_config_check_init();
	configset_iter(&the_config_set, fn, data);
1512 1513
}

1514 1515 1516 1517 1518 1519 1520 1521 1522
static struct config_set_element *configset_find_element(struct config_set *cs, const char *key)
{
	struct config_set_element k;
	struct config_set_element *found_entry;
	char *normalized_key;
	/*
	 * `key` may come from the user, so normalize it before using it
	 * for querying entries from the hashmap.
	 */
S
Stefan Beller 已提交
1523
	if (git_config_parse_key(key, &normalized_key, NULL))
1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535
		return NULL;

	hashmap_entry_init(&k, strhash(normalized_key));
	k.key = normalized_key;
	found_entry = hashmap_get(&cs->config_hash, &k, NULL);
	free(normalized_key);
	return found_entry;
}

static int configset_add_value(struct config_set *cs, const char *key, const char *value)
{
	struct config_set_element *e;
1536
	struct string_list_item *si;
1537
	struct configset_list_item *l_item;
1538 1539
	struct key_value_info *kv_info = xmalloc(sizeof(*kv_info));

1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551
	e = configset_find_element(cs, key);
	/*
	 * Since the keys are being fed by git_config*() callback mechanism, they
	 * are already normalized. So simply add them without any further munging.
	 */
	if (!e) {
		e = xmalloc(sizeof(*e));
		hashmap_entry_init(e, strhash(key));
		e->key = xstrdup(key);
		string_list_init(&e->value_list, 1);
		hashmap_add(&cs->config_hash, e);
	}
1552
	si = string_list_append_nodup(&e->value_list, xstrdup_or_null(value));
1553 1554 1555 1556 1557 1558

	ALLOC_GROW(cs->list.items, cs->list.nr + 1, cs->list.alloc);
	l_item = &cs->list.items[cs->list.nr++];
	l_item->e = e;
	l_item->value_index = e->value_list.nr - 1;

1559 1560 1561
	if (!cf)
		die("BUG: configset_add_value has no source");
	if (cf->name) {
1562 1563
		kv_info->filename = strintern(cf->name);
		kv_info->linenr = cf->linenr;
1564
		kv_info->origin_type = cf->origin_type;
1565 1566 1567 1568
	} else {
		/* for values read from `git_config_from_parameters()` */
		kv_info->filename = NULL;
		kv_info->linenr = -1;
1569
		kv_info->origin_type = CONFIG_ORIGIN_CMDLINE;
1570
	}
J
Jeff King 已提交
1571
	kv_info->scope = current_parsing_scope;
1572
	si->util = kv_info;
1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586

	return 0;
}

static int config_set_element_cmp(const struct config_set_element *e1,
				 const struct config_set_element *e2, const void *unused)
{
	return strcmp(e1->key, e2->key);
}

void git_configset_init(struct config_set *cs)
{
	hashmap_init(&cs->config_hash, (hashmap_cmp_fn)config_set_element_cmp, 0);
	cs->hash_initialized = 1;
1587 1588 1589
	cs->list.nr = 0;
	cs->list.alloc = 0;
	cs->list.items = NULL;
1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601
}

void git_configset_clear(struct config_set *cs)
{
	struct config_set_element *entry;
	struct hashmap_iter iter;
	if (!cs->hash_initialized)
		return;

	hashmap_iter_init(&cs->config_hash, &iter);
	while ((entry = hashmap_iter_next(&iter))) {
		free(entry->key);
1602
		string_list_clear(&entry->value_list, 1);
1603 1604 1605
	}
	hashmap_free(&cs->config_hash, 1);
	cs->hash_initialized = 0;
1606 1607 1608 1609
	free(cs->list.items);
	cs->list.nr = 0;
	cs->list.alloc = 0;
	cs->list.items = NULL;
1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727
}

static int config_set_callback(const char *key, const char *value, void *cb)
{
	struct config_set *cs = cb;
	configset_add_value(cs, key, value);
	return 0;
}

int git_configset_add_file(struct config_set *cs, const char *filename)
{
	return git_config_from_file(config_set_callback, filename, cs);
}

int git_configset_get_value(struct config_set *cs, const char *key, const char **value)
{
	const struct string_list *values = NULL;
	/*
	 * Follows "last one wins" semantic, i.e., if there are multiple matches for the
	 * queried key in the files of the configset, the value returned will be the last
	 * value in the value list for that key.
	 */
	values = git_configset_get_value_multi(cs, key);

	if (!values)
		return 1;
	assert(values->nr > 0);
	*value = values->items[values->nr - 1].string;
	return 0;
}

const struct string_list *git_configset_get_value_multi(struct config_set *cs, const char *key)
{
	struct config_set_element *e = configset_find_element(cs, key);
	return e ? &e->value_list : NULL;
}

int git_configset_get_string_const(struct config_set *cs, const char *key, const char **dest)
{
	const char *value;
	if (!git_configset_get_value(cs, key, &value))
		return git_config_string(dest, key, value);
	else
		return 1;
}

int git_configset_get_string(struct config_set *cs, const char *key, char **dest)
{
	return git_configset_get_string_const(cs, key, (const char **)dest);
}

int git_configset_get_int(struct config_set *cs, const char *key, int *dest)
{
	const char *value;
	if (!git_configset_get_value(cs, key, &value)) {
		*dest = git_config_int(key, value);
		return 0;
	} else
		return 1;
}

int git_configset_get_ulong(struct config_set *cs, const char *key, unsigned long *dest)
{
	const char *value;
	if (!git_configset_get_value(cs, key, &value)) {
		*dest = git_config_ulong(key, value);
		return 0;
	} else
		return 1;
}

int git_configset_get_bool(struct config_set *cs, const char *key, int *dest)
{
	const char *value;
	if (!git_configset_get_value(cs, key, &value)) {
		*dest = git_config_bool(key, value);
		return 0;
	} else
		return 1;
}

int git_configset_get_bool_or_int(struct config_set *cs, const char *key,
				int *is_bool, int *dest)
{
	const char *value;
	if (!git_configset_get_value(cs, key, &value)) {
		*dest = git_config_bool_or_int(key, value, is_bool);
		return 0;
	} else
		return 1;
}

int git_configset_get_maybe_bool(struct config_set *cs, const char *key, int *dest)
{
	const char *value;
	if (!git_configset_get_value(cs, key, &value)) {
		*dest = git_config_maybe_bool(key, value);
		if (*dest == -1)
			return -1;
		return 0;
	} else
		return 1;
}

int git_configset_get_pathname(struct config_set *cs, const char *key, const char **dest)
{
	const char *value;
	if (!git_configset_get_value(cs, key, &value))
		return git_config_pathname(dest, key, value);
	else
		return 1;
}

static void git_config_check_init(void)
{
	if (the_config_set.hash_initialized)
		return;
	git_configset_init(&the_config_set);
1728
	git_config_raw(config_set_callback, &the_config_set);
1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751
}

void git_config_clear(void)
{
	if (!the_config_set.hash_initialized)
		return;
	git_configset_clear(&the_config_set);
}

int git_config_get_value(const char *key, const char **value)
{
	git_config_check_init();
	return git_configset_get_value(&the_config_set, key, value);
}

const struct string_list *git_config_get_value_multi(const char *key)
{
	git_config_check_init();
	return git_configset_get_value_multi(&the_config_set, key);
}

int git_config_get_string_const(const char *key, const char **dest)
{
1752
	int ret;
1753
	git_config_check_init();
1754 1755 1756 1757
	ret = git_configset_get_string_const(&the_config_set, key, dest);
	if (ret < 0)
		git_die_config(key, NULL);
	return ret;
1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797
}

int git_config_get_string(const char *key, char **dest)
{
	git_config_check_init();
	return git_config_get_string_const(key, (const char **)dest);
}

int git_config_get_int(const char *key, int *dest)
{
	git_config_check_init();
	return git_configset_get_int(&the_config_set, key, dest);
}

int git_config_get_ulong(const char *key, unsigned long *dest)
{
	git_config_check_init();
	return git_configset_get_ulong(&the_config_set, key, dest);
}

int git_config_get_bool(const char *key, int *dest)
{
	git_config_check_init();
	return git_configset_get_bool(&the_config_set, key, dest);
}

int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest)
{
	git_config_check_init();
	return git_configset_get_bool_or_int(&the_config_set, key, is_bool, dest);
}

int git_config_get_maybe_bool(const char *key, int *dest)
{
	git_config_check_init();
	return git_configset_get_maybe_bool(&the_config_set, key, dest);
}

int git_config_get_pathname(const char *key, const char **dest)
{
1798
	int ret;
1799
	git_config_check_init();
1800 1801 1802 1803 1804 1805
	ret = git_configset_get_pathname(&the_config_set, key, dest);
	if (ret < 0)
		git_die_config(key, NULL);
	return ret;
}

1806 1807 1808 1809 1810
int git_config_get_untracked_cache(void)
{
	int val = -1;
	const char *v;

1811 1812 1813 1814
	/* Hack for test programs like test-dump-untracked-cache */
	if (ignore_untracked_cache_config)
		return -1;

1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829
	if (!git_config_get_maybe_bool("core.untrackedcache", &val))
		return val;

	if (!git_config_get_value("core.untrackedcache", &v)) {
		if (!strcasecmp(v, "keep"))
			return -1;

		error("unknown core.untrackedCache value '%s'; "
		      "using 'keep' default value", v);
		return -1;
	}

	return -1; /* default value */
}

1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854
NORETURN
void git_die_config_linenr(const char *key, const char *filename, int linenr)
{
	if (!filename)
		die(_("unable to parse '%s' from command-line config"), key);
	else
		die(_("bad config variable '%s' in file '%s' at line %d"),
		    key, filename, linenr);
}

NORETURN __attribute__((format(printf, 2, 3)))
void git_die_config(const char *key, const char *err, ...)
{
	const struct string_list *values;
	struct key_value_info *kv_info;

	if (err) {
		va_list params;
		va_start(params, err);
		vreportf("error: ", err, params);
		va_end(params);
	}
	values = git_config_get_value_multi(key);
	kv_info = values->items[values->nr - 1].util;
	git_die_config_linenr(key, kv_info->filename, kv_info->linenr);
1855 1856
}

1857 1858 1859
/*
 * Find all the stuff for git_config_set() below.
 */
1860

1861 1862
static struct {
	int baselen;
1863
	char *key;
1864
	int do_not_match;
1865
	regex_t *value_regex;
1866
	int multi_replace;
1867 1868
	size_t *offset;
	unsigned int offset_alloc;
1869 1870 1871 1872
	enum { START, SECTION_SEEN, SECTION_END_SEEN, KEY_SEEN } state;
	int seen;
} store;

1873
static int matches(const char *key, const char *value)
1874
{
1875 1876 1877 1878 1879 1880 1881 1882 1883
	if (strcmp(key, store.key))
		return 0; /* not ours */
	if (!store.value_regex)
		return 1; /* always matches */
	if (store.value_regex == CONFIG_REGEX_NONE)
		return 0; /* never matches */

	return store.do_not_match ^
		(value && !regexec(store.value_regex, value, 0, NULL, 0));
1884 1885
}

1886
static int store_aux(const char *key, const char *value, void *cb)
1887
{
1888 1889 1890
	const char *ep;
	size_t section_len;

1891 1892
	switch (store.state) {
	case KEY_SEEN:
1893
		if (matches(key, value)) {
1894
			if (store.seen == 1 && store.multi_replace == 0) {
1895
				warning(_("%s has multiple values"), key);
1896
			}
1897

1898 1899 1900
			ALLOC_GROW(store.offset, store.seen + 1,
				   store.offset_alloc);

1901
			store.offset[store.seen] = cf->do_ftell(cf);
1902 1903 1904 1905
			store.seen++;
		}
		break;
	case SECTION_SEEN:
1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919
		/*
		 * What we are looking for is in store.key (both
		 * section and var), and its section part is baselen
		 * long.  We found key (again, both section and var).
		 * We would want to know if this key is in the same
		 * section as what we are looking for.  We already
		 * know we are in the same section as what should
		 * hold store.key.
		 */
		ep = strrchr(key, '.');
		section_len = ep - key;

		if ((section_len != store.baselen) ||
		    memcmp(key, store.key, section_len+1)) {
1920 1921
			store.state = SECTION_END_SEEN;
			break;
1922 1923 1924 1925 1926 1927
		}

		/*
		 * Do not increment matches: this is no match, but we
		 * just made sure we are in the desired section.
		 */
1928 1929
		ALLOC_GROW(store.offset, store.seen + 1,
			   store.offset_alloc);
1930
		store.offset[store.seen] = cf->do_ftell(cf);
1931 1932 1933
		/* fallthru */
	case SECTION_END_SEEN:
	case START:
1934
		if (matches(key, value)) {
1935 1936
			ALLOC_GROW(store.offset, store.seen + 1,
				   store.offset_alloc);
1937
			store.offset[store.seen] = cf->do_ftell(cf);
1938 1939
			store.state = KEY_SEEN;
			store.seen++;
L
Linus Torvalds 已提交
1940 1941
		} else {
			if (strrchr(key, '.') - key == store.baselen &&
S
sean 已提交
1942
			      !strncmp(key, store.key, store.baselen)) {
S
sean 已提交
1943
					store.state = SECTION_SEEN;
1944 1945 1946
					ALLOC_GROW(store.offset,
						   store.seen + 1,
						   store.offset_alloc);
1947
					store.offset[store.seen] = cf->do_ftell(cf);
L
Linus Torvalds 已提交
1948
			}
S
sean 已提交
1949
		}
1950 1951 1952 1953
	}
	return 0;
}

1954
static int write_error(const char *filename)
1955
{
1956
	error("failed to write new configuration file %s", filename);
1957 1958 1959 1960 1961

	/* Same error code as "failed to rename". */
	return 4;
}

1962
static int store_write_section(int fd, const char *key)
1963
{
1964 1965
	const char *dot;
	int i, success;
1966
	struct strbuf sb = STRBUF_INIT;
L
Linus Torvalds 已提交
1967

1968
	dot = memchr(key, '.', store.baselen);
L
Linus Torvalds 已提交
1969
	if (dot) {
1970 1971
		strbuf_addf(&sb, "[%.*s \"", (int)(dot - key), key);
		for (i = dot - key + 1; i < store.baselen; i++) {
1972
			if (key[i] == '"' || key[i] == '\\')
1973 1974
				strbuf_addch(&sb, '\\');
			strbuf_addch(&sb, key[i]);
L
Linus Torvalds 已提交
1975
		}
1976 1977 1978
		strbuf_addstr(&sb, "\"]\n");
	} else {
		strbuf_addf(&sb, "[%.*s]\n", store.baselen, key);
L
Linus Torvalds 已提交
1979 1980
	}

1981 1982
	success = write_in_full(fd, sb.buf, sb.len) == sb.len;
	strbuf_release(&sb);
1983

1984
	return success;
1985 1986
}

1987
static int store_write_pair(int fd, const char *key, const char *value)
1988
{
1989 1990 1991
	int i, success;
	int length = strlen(key + store.baselen + 1);
	const char *quote = "";
1992
	struct strbuf sb = STRBUF_INIT;
1993

1994 1995 1996 1997 1998 1999 2000
	/*
	 * Check to see if the value needs to be surrounded with a dq pair.
	 * Note that problematic characters are always backslash-quoted; this
	 * check is about not losing leading or trailing SP and strings that
	 * follow beginning-of-comment characters (i.e. ';' and '#') by the
	 * configuration parser.
	 */
2001
	if (value[0] == ' ')
2002
		quote = "\"";
2003 2004
	for (i = 0; value[i]; i++)
		if (value[i] == ';' || value[i] == '#')
2005 2006 2007 2008 2009 2010
			quote = "\"";
	if (i && value[i - 1] == ' ')
		quote = "\"";

	strbuf_addf(&sb, "\t%.*s = %s",
		    length, key + store.baselen + 1, quote);
2011 2012 2013

	for (i = 0; value[i]; i++)
		switch (value[i]) {
2014
		case '\n':
2015
			strbuf_addstr(&sb, "\\n");
2016 2017
			break;
		case '\t':
2018
			strbuf_addstr(&sb, "\\t");
2019 2020 2021
			break;
		case '"':
		case '\\':
2022
			strbuf_addch(&sb, '\\');
2023
		default:
2024
			strbuf_addch(&sb, value[i]);
2025 2026
			break;
		}
2027 2028 2029 2030 2031 2032
	strbuf_addf(&sb, "%s\n", quote);

	success = write_in_full(fd, sb.buf, sb.len) == sb.len;
	strbuf_release(&sb);

	return success;
2033 2034
}

2035 2036
static ssize_t find_beginning_of_line(const char *contents, size_t size,
	size_t offset_, int *found_bracket)
2037
{
2038 2039
	size_t equal_offset = size, bracket_offset = size;
	ssize_t offset;
2040

2041
contline:
J
Junio C Hamano 已提交
2042
	for (offset = offset_-2; offset > 0
2043 2044 2045 2046 2047
			&& contents[offset] != '\n'; offset--)
		switch (contents[offset]) {
			case '=': equal_offset = offset; break;
			case ']': bracket_offset = offset; break;
		}
2048 2049 2050 2051
	if (offset > 0 && contents[offset-1] == '\\') {
		offset_ = offset;
		goto contline;
	}
2052 2053 2054 2055 2056 2057 2058 2059 2060
	if (bracket_offset < equal_offset) {
		*found_bracket = 1;
		offset = bracket_offset+1;
	} else
		offset++;

	return offset;
}

2061 2062
int git_config_set_in_file_gently(const char *config_filename,
				  const char *key, const char *value)
2063
{
2064
	return git_config_set_multivar_in_file_gently(config_filename, key, value, NULL, 0);
2065 2066
}

2067 2068
void git_config_set_in_file(const char *config_filename,
			    const char *key, const char *value)
2069
{
2070
	git_config_set_multivar_in_file(config_filename, key, value, NULL, 0);
2071 2072
}

2073
int git_config_set_gently(const char *key, const char *value)
2074
{
2075
	return git_config_set_multivar_gently(key, value, NULL, 0);
2076 2077
}

2078
void git_config_set(const char *key, const char *value)
2079
{
2080
	git_config_set_multivar(key, value, NULL, 0);
2081 2082 2083 2084 2085
}

/*
 * If value==NULL, unset in (remove from) config,
 * if value_regex!=NULL, disregard key/value pairs where value does not match.
2086 2087
 * if value_regex==CONFIG_REGEX_NONE, do not match any existing values
 *     (only add a new one)
2088 2089 2090
 * if multi_replace==0, nothing, or only one matching key/value is replaced,
 *     else all matching key/values (regardless how many) are removed,
 *     before the new pair is written.
2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107
 *
 * Returns 0 on success.
 *
 * This function does this:
 *
 * - it locks the config file by creating ".git/config.lock"
 *
 * - it then parses the config using store_aux() as validator to find
 *   the position on the key/value pair to replace. If it is to be unset,
 *   it must be found exactly once.
 *
 * - the config file is mmap()ed and the part before the match (if any) is
 *   written to the lock file, then the changed part and the rest.
 *
 * - the config file is removed and the lock file rename()d to it.
 *
 */
2108 2109 2110 2111
int git_config_set_multivar_in_file_gently(const char *config_filename,
					   const char *key, const char *value,
					   const char *value_regex,
					   int multi_replace)
2112
{
2113
	int fd = -1, in_fd = -1;
2114
	int ret;
2115
	static struct lock_file lock;
2116
	char *filename_buf = NULL;
2117 2118
	char *contents = NULL;
	size_t contents_sz;
2119

2120 2121 2122
	/* parse-key returns negative; flip the sign to feed exit(3) */
	ret = 0 - git_config_parse_key(key, &store.key, &store.baselen);
	if (ret)
2123
		goto out_free;
2124 2125

	store.multi_replace = multi_replace;
2126

2127 2128
	if (!config_filename)
		config_filename = filename_buf = git_pathdup("config");
2129 2130

	/*
2131
	 * The lock serves a purpose in addition to locking: the new
2132 2133
	 * contents of .git/config will be written into it.
	 */
2134
	fd = hold_lock_file_for_update(&lock, config_filename, 0);
2135
	if (fd < 0) {
2136
		error_errno("could not lock config file %s", config_filename);
2137
		free(store.key);
2138
		ret = CONFIG_NO_LOCK;
2139
		goto out_free;
2140 2141 2142 2143 2144
	}

	/*
	 * If .git/config does not exist yet, write a minimal version.
	 */
2145 2146
	in_fd = open(config_filename, O_RDONLY);
	if ( in_fd < 0 ) {
2147 2148
		free(store.key);

2149
		if ( ENOENT != errno ) {
2150
			error_errno("opening %s", config_filename);
2151
			ret = CONFIG_INVALID_FILE; /* same as "invalid config file" */
2152
			goto out_free;
2153
		}
2154 2155
		/* if nothing to unset, error out */
		if (value == NULL) {
2156
			ret = CONFIG_NOTHING_SET;
2157
			goto out_free;
2158 2159
		}

2160
		store.key = (char *)key;
2161
		if (!store_write_section(fd, key) ||
2162 2163 2164
		    !store_write_pair(fd, key, value))
			goto write_err_out;
	} else {
2165
		struct stat st;
2166
		size_t copy_begin, copy_end;
2167
		int i, new_line = 0;
2168 2169 2170

		if (value_regex == NULL)
			store.value_regex = NULL;
2171 2172
		else if (value_regex == CONFIG_REGEX_NONE)
			store.value_regex = CONFIG_REGEX_NONE;
2173
		else {
2174 2175 2176 2177 2178 2179
			if (value_regex[0] == '!') {
				store.do_not_match = 1;
				value_regex++;
			} else
				store.do_not_match = 0;

J
Jonas Fonseca 已提交
2180
			store.value_regex = (regex_t*)xmalloc(sizeof(regex_t));
2181 2182
			if (regcomp(store.value_regex, value_regex,
					REG_EXTENDED)) {
2183
				error("invalid pattern: %s", value_regex);
2184
				free(store.value_regex);
2185
				ret = CONFIG_INVALID_PATTERN;
2186
				goto out_free;
2187 2188 2189
			}
		}

2190
		ALLOC_GROW(store.offset, 1, store.offset_alloc);
2191
		store.offset[0] = 0;
2192 2193 2194 2195 2196 2197 2198 2199 2200
		store.state = START;
		store.seen = 0;

		/*
		 * After this, store.offset will contain the *end* offset
		 * of the last match, or remain at 0 if no match was found.
		 * As a side effect, we make sure to transform only a valid
		 * existing config file.
		 */
2201
		if (git_config_from_file(store_aux, config_filename, NULL)) {
2202
			error("invalid config file %s", config_filename);
2203
			free(store.key);
2204 2205
			if (store.value_regex != NULL &&
			    store.value_regex != CONFIG_REGEX_NONE) {
2206 2207 2208
				regfree(store.value_regex);
				free(store.value_regex);
			}
2209
			ret = CONFIG_INVALID_FILE;
2210
			goto out_free;
2211 2212 2213
		}

		free(store.key);
2214 2215
		if (store.value_regex != NULL &&
		    store.value_regex != CONFIG_REGEX_NONE) {
2216 2217 2218 2219
			regfree(store.value_regex);
			free(store.value_regex);
		}

2220 2221 2222
		/* if nothing to unset, or too many matches, error out */
		if ((store.seen == 0 && value == NULL) ||
				(store.seen > 1 && multi_replace == 0)) {
2223
			ret = CONFIG_NOTHING_SET;
2224
			goto out_free;
2225 2226
		}

2227 2228 2229 2230 2231 2232
		if (fstat(in_fd, &st) == -1) {
			error_errno(_("fstat on %s failed"), config_filename);
			ret = CONFIG_INVALID_FILE;
			goto out_free;
		}

2233
		contents_sz = xsize_t(st.st_size);
J
Jeff King 已提交
2234 2235 2236
		contents = xmmap_gently(NULL, contents_sz, PROT_READ,
					MAP_PRIVATE, in_fd, 0);
		if (contents == MAP_FAILED) {
2237 2238
			if (errno == ENODEV && S_ISDIR(st.st_mode))
				errno = EISDIR;
2239
			error_errno("unable to mmap '%s'", config_filename);
J
Jeff King 已提交
2240 2241 2242 2243
			ret = CONFIG_INVALID_FILE;
			contents = NULL;
			goto out_free;
		}
2244
		close(in_fd);
2245
		in_fd = -1;
2246

2247 2248
		if (chmod(get_lock_file_path(&lock), st.st_mode & 07777) < 0) {
			error_errno("chmod on %s failed", get_lock_file_path(&lock));
2249 2250 2251 2252
			ret = CONFIG_NO_WRITE;
			goto out_free;
		}

2253 2254 2255 2256 2257
		if (store.seen == 0)
			store.seen = 1;

		for (i = 0, copy_begin = 0; i < store.seen; i++) {
			if (store.offset[i] == 0) {
2258
				store.offset[i] = copy_end = contents_sz;
2259 2260
			} else if (store.state != KEY_SEEN) {
				copy_end = store.offset[i];
2261
			} else
2262
				copy_end = find_beginning_of_line(
2263
					contents, contents_sz,
2264 2265
					store.offset[i]-2, &new_line);

2266 2267 2268
			if (copy_end > 0 && contents[copy_end-1] != '\n')
				new_line = 1;

2269 2270
			/* write the first part of the config */
			if (copy_end > copy_begin) {
2271 2272 2273 2274 2275
				if (write_in_full(fd, contents + copy_begin,
						  copy_end - copy_begin) <
				    copy_end - copy_begin)
					goto write_err_out;
				if (new_line &&
2276
				    write_str_in_full(fd, "\n") != 1)
2277
					goto write_err_out;
2278 2279
			}
			copy_begin = store.offset[i];
2280 2281 2282 2283
		}

		/* write the pair (value == NULL means unset) */
		if (value != NULL) {
2284 2285 2286
			if (store.state == START) {
				if (!store_write_section(fd, key))
					goto write_err_out;
2287
			}
2288 2289
			if (!store_write_pair(fd, key, value))
				goto write_err_out;
2290 2291 2292
		}

		/* write the rest of the config */
2293
		if (copy_begin < contents_sz)
2294
			if (write_in_full(fd, contents + copy_begin,
2295 2296
					  contents_sz - copy_begin) <
			    contents_sz - copy_begin)
2297
				goto write_err_out;
2298 2299 2300

		munmap(contents, contents_sz);
		contents = NULL;
2301 2302
	}

2303
	if (commit_lock_file(&lock) < 0) {
2304
		error_errno("could not write config file %s", config_filename);
2305
		ret = CONFIG_NO_WRITE;
2306
		goto out_free;
2307 2308
	}

2309 2310
	ret = 0;

2311 2312 2313
	/* Invalidate the config cache */
	git_config_clear();

2314
out_free:
2315
	rollback_lock_file(&lock);
2316
	free(filename_buf);
2317 2318
	if (contents)
		munmap(contents, contents_sz);
2319 2320
	if (in_fd >= 0)
		close(in_fd);
2321
	return ret;
2322 2323

write_err_out:
2324
	ret = write_error(get_lock_file_path(&lock));
2325 2326
	goto out_free;

2327 2328
}

2329 2330 2331
void git_config_set_multivar_in_file(const char *config_filename,
				     const char *key, const char *value,
				     const char *value_regex, int multi_replace)
2332
{
2333 2334 2335 2336
	if (!git_config_set_multivar_in_file_gently(config_filename, key, value,
						    value_regex, multi_replace))
		return;
	if (value)
2337
		die(_("could not set '%s' to '%s'"), key, value);
2338 2339
	else
		die(_("could not unset '%s'"), key);
2340 2341
}

2342 2343
int git_config_set_multivar_gently(const char *key, const char *value,
				   const char *value_regex, int multi_replace)
2344
{
2345 2346
	return git_config_set_multivar_in_file_gently(NULL, key, value, value_regex,
						      multi_replace);
2347 2348
}

2349 2350
void git_config_set_multivar(const char *key, const char *value,
			     const char *value_regex, int multi_replace)
2351
{
2352 2353
	git_config_set_multivar_in_file(NULL, key, value, value_regex,
					multi_replace);
2354 2355
}

2356 2357 2358
static int section_name_match (const char *buf, const char *name)
{
	int i = 0, j = 0, dot = 0;
2359 2360 2361
	if (buf[i] != '[')
		return 0;
	for (i = 1; buf[i] && buf[i] != ']'; i++) {
2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381
		if (!dot && isspace(buf[i])) {
			dot = 1;
			if (name[j++] != '.')
				break;
			for (i++; isspace(buf[i]); i++)
				; /* do nothing */
			if (buf[i] != '"')
				break;
			continue;
		}
		if (buf[i] == '\\' && dot)
			i++;
		else if (buf[i] == '"' && dot) {
			for (i++; isspace(buf[i]); i++)
				; /* do_nothing */
			break;
		}
		if (buf[i] != name[j++])
			break;
	}
2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392
	if (buf[i] == ']' && name[j] == 0) {
		/*
		 * We match, now just find the right length offset by
		 * gobbling up any whitespace after it, as well
		 */
		i++;
		for (; buf[i] && isspace(buf[i]); i++)
			; /* do nothing */
		return i;
	}
	return 0;
2393 2394
}

2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410
static int section_name_is_ok(const char *name)
{
	/* Empty section names are bogus. */
	if (!*name)
		return 0;

	/*
	 * Before a dot, we must be alphanumeric or dash. After the first dot,
	 * anything goes, so we can stop checking.
	 */
	for (; *name && *name != '.'; name++)
		if (*name != '-' && !isalnum(*name))
			return 0;
	return 1;
}

2411
/* if new_name == NULL, the section is removed instead */
2412 2413
int git_config_rename_section_in_file(const char *config_filename,
				      const char *old_name, const char *new_name)
2414
{
2415
	int ret = 0, remove = 0;
2416
	char *filename_buf = NULL;
2417
	struct lock_file *lock;
2418 2419
	int out_fd;
	char buf[1024];
2420
	FILE *config_file;
2421
	struct stat st;
2422

2423 2424
	if (new_name && !section_name_is_ok(new_name)) {
		ret = error("invalid section name: %s", new_name);
2425
		goto out_no_rollback;
2426 2427
	}

2428 2429 2430
	if (!config_filename)
		config_filename = filename_buf = git_pathdup("config");

2431
	lock = xcalloc(1, sizeof(struct lock_file));
2432
	out_fd = hold_lock_file_for_update(lock, config_filename, 0);
2433
	if (out_fd < 0) {
2434
		ret = error("could not lock config file %s", config_filename);
2435 2436
		goto out;
	}
2437

2438
	if (!(config_file = fopen(config_filename, "rb"))) {
2439
		/* no config file means nothing to rename, no error */
2440
		goto commit_and_out;
2441
	}
2442

2443 2444 2445 2446
	if (fstat(fileno(config_file), &st) == -1) {
		ret = error_errno(_("fstat on %s failed"), config_filename);
		goto out;
	}
2447

2448
	if (chmod(get_lock_file_path(lock), st.st_mode & 07777) < 0) {
2449 2450
		ret = error_errno("chmod on %s failed",
				  get_lock_file_path(lock));
2451 2452 2453
		goto out;
	}

2454 2455
	while (fgets(buf, sizeof(buf), config_file)) {
		int i;
2456
		int length;
2457
		char *output = buf;
2458 2459 2460 2461
		for (i = 0; buf[i] && isspace(buf[i]); i++)
			; /* do nothing */
		if (buf[i] == '[') {
			/* it's a section */
2462 2463
			int offset = section_name_match(&buf[i], old_name);
			if (offset > 0) {
2464 2465 2466
				ret++;
				if (new_name == NULL) {
					remove = 1;
2467 2468 2469
					continue;
				}
				store.baselen = strlen(new_name);
2470
				if (!store_write_section(out_fd, new_name)) {
2471
					ret = write_error(get_lock_file_path(lock));
2472 2473
					goto out;
				}
2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489
				/*
				 * We wrote out the new section, with
				 * a newline, now skip the old
				 * section's length
				 */
				output += offset + i;
				if (strlen(output) > 0) {
					/*
					 * More content means there's
					 * a declaration to put on the
					 * next line; indent with a
					 * tab
					 */
					output -= 1;
					output[0] = '\t';
				}
2490
			}
2491
			remove = 0;
2492
		}
2493 2494
		if (remove)
			continue;
2495 2496
		length = strlen(output);
		if (write_in_full(out_fd, output, length) != length) {
2497
			ret = write_error(get_lock_file_path(lock));
2498 2499
			goto out;
		}
2500
	}
2501
	fclose(config_file);
2502
commit_and_out:
B
Brandon Casey 已提交
2503
	if (commit_lock_file(lock) < 0)
2504 2505
		ret = error_errno("could not write config file %s",
				  config_filename);
2506
out:
2507 2508
	rollback_lock_file(lock);
out_no_rollback:
2509
	free(filename_buf);
2510 2511
	return ret;
}
2512

2513 2514
int git_config_rename_section(const char *old_name, const char *new_name)
{
2515
	return git_config_rename_section_in_file(NULL, old_name, new_name);
2516 2517
}

2518 2519 2520 2521
/*
 * Call this to report error for your variable that should not
 * get a boolean value (i.e. "[my] var" means "true").
 */
2522
#undef config_error_nonbool
2523 2524
int config_error_nonbool(const char *var)
{
2525
	return error("missing value for '%s'", var);
2526
}
2527 2528 2529 2530 2531 2532 2533 2534 2535

int parse_config_key(const char *var,
		     const char *section,
		     const char **subsection, int *subsection_len,
		     const char **key)
{
	const char *dot;

	/* Does it start with "section." ? */
2536
	if (!skip_prefix(var, section, &var) || *var != '.')
2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547
		return -1;

	/*
	 * Find the key; we don't know yet if we have a subsection, but we must
	 * parse backwards from the end, since the subsection may have dots in
	 * it, too.
	 */
	dot = strrchr(var, '.');
	*key = dot + 1;

	/* Did we have a subsection at all? */
2548
	if (dot == var) {
2549 2550 2551 2552
		if (subsection) {
			*subsection = NULL;
			*subsection_len = 0;
		}
2553 2554
	}
	else {
2555 2556
		if (!subsection)
			return -1;
2557
		*subsection = var + 1;
2558 2559 2560 2561 2562
		*subsection_len = dot - *subsection;
	}

	return 0;
}
2563 2564 2565

const char *current_config_origin_type(void)
{
2566
	int type;
2567 2568 2569 2570 2571
	if (current_config_kvi)
		type = current_config_kvi->origin_type;
	else if(cf)
		type = cf->origin_type;
	else
2572
		die("BUG: current_config_origin_type called outside config callback");
2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587

	switch (type) {
	case CONFIG_ORIGIN_BLOB:
		return "blob";
	case CONFIG_ORIGIN_FILE:
		return "file";
	case CONFIG_ORIGIN_STDIN:
		return "standard input";
	case CONFIG_ORIGIN_SUBMODULE_BLOB:
		return "submodule-blob";
	case CONFIG_ORIGIN_CMDLINE:
		return "command line";
	default:
		die("BUG: unknown config origin type");
	}
2588 2589 2590 2591
}

const char *current_config_name(void)
{
2592 2593 2594 2595 2596 2597
	const char *name;
	if (current_config_kvi)
		name = current_config_kvi->filename;
	else if (cf)
		name = cf->name;
	else
2598
		die("BUG: current_config_name called outside config callback");
2599
	return name ? name : "";
2600
}
J
Jeff King 已提交
2601 2602 2603 2604 2605 2606 2607

enum config_scope current_config_scope(void)
{
	if (current_config_kvi)
		return current_config_kvi->scope;
	else
		return current_parsing_scope;
2608
}