config.c 26.6 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 "exec_cmd.h"
L
Linus Torvalds 已提交
10 11 12 13

#define MAXNAME (256)

static FILE *config_file;
14
static const char *config_file_name;
L
Linus Torvalds 已提交
15
static int config_linenr;
16
static int config_file_eof;
17 18
static int zlib_compression_seen;

19 20
const char *config_exclusive_filename = NULL;

L
Linus Torvalds 已提交
21 22 23 24 25 26 27 28
static int get_next_char(void)
{
	int c;
	FILE *f;

	c = '\n';
	if ((f = config_file) != NULL) {
		c = fgetc(f);
29 30 31 32 33 34 35 36
		if (c == '\r') {
			/* DOS like systems */
			c = fgetc(f);
			if (c != '\n') {
				ungetc(c, f);
				c = '\r';
			}
		}
L
Linus Torvalds 已提交
37 38 39
		if (c == '\n')
			config_linenr++;
		if (c == EOF) {
40
			config_file_eof = 1;
L
Linus Torvalds 已提交
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
			c = '\n';
		}
	}
	return c;
}

static char *parse_value(void)
{
	static char value[1024];
	int quote = 0, comment = 0, len = 0, space = 0;

	for (;;) {
		int c = get_next_char();
		if (len >= sizeof(value))
			return NULL;
		if (c == '\n') {
			if (quote)
				return NULL;
			value[len] = 0;
			return value;
		}
		if (comment)
			continue;
		if (isspace(c) && !quote) {
			space = 1;
			continue;
		}
68 69 70 71 72 73
		if (!quote) {
			if (c == ';' || c == '#') {
				comment = 1;
				continue;
			}
		}
L
Linus Torvalds 已提交
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
		if (space) {
			if (len)
				value[len++] = ' ';
			space = 0;
		}
		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;
93 94 95 96 97 98
			/* Some characters escape as themselves */
			case '\\': case '"':
				break;
			/* Reject unknown escape sequences */
			default:
				return NULL;
L
Linus Torvalds 已提交
99 100 101 102 103 104 105 106 107 108 109 110
			}
			value[len++] = c;
			continue;
		}
		if (c == '"') {
			quote = 1-quote;
			continue;
		}
		value[len++] = c;
	}
}

111 112 113 114 115
static inline int iskeychar(int c)
{
	return isalnum(c) || c == '-';
}

116
static int get_value(config_fn_t fn, void *data, char *name, unsigned int len)
L
Linus Torvalds 已提交
117 118 119 120 121 122 123
{
	int c;
	char *value;

	/* Get the full name */
	for (;;) {
		c = get_next_char();
124
		if (config_file_eof)
L
Linus Torvalds 已提交
125
			break;
126
		if (!iskeychar(c))
L
Linus Torvalds 已提交
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
			break;
		name[len++] = tolower(c);
		if (len >= MAXNAME)
			return -1;
	}
	name[len] = 0;
	while (c == ' ' || c == '\t')
		c = get_next_char();

	value = NULL;
	if (c != '\n') {
		if (c != '=')
			return -1;
		value = parse_value();
		if (!value)
			return -1;
	}
144
	return fn(name, value, data);
L
Linus Torvalds 已提交
145 146
}

L
Linus Torvalds 已提交
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
static int get_extended_base_var(char *name, int baselen, int c)
{
	do {
		if (c == '\n')
			return -1;
		c = get_next_char();
	} while (isspace(c));

	/* We require the format to be '[base "extension"]' */
	if (c != '"')
		return -1;
	name[baselen++] = '.';

	for (;;) {
		int c = get_next_char();
		if (c == '\n')
			return -1;
		if (c == '"')
			break;
		if (c == '\\') {
			c = get_next_char();
			if (c == '\n')
				return -1;
		}
		name[baselen++] = c;
		if (baselen > MAXNAME / 2)
			return -1;
	}

	/* Final ']' */
	if (get_next_char() != ']')
		return -1;
	return baselen;
}

L
Linus Torvalds 已提交
182 183 184 185 186 187
static int get_base_var(char *name)
{
	int baselen = 0;

	for (;;) {
		int c = get_next_char();
188
		if (config_file_eof)
L
Linus Torvalds 已提交
189 190 191
			return -1;
		if (c == ']')
			return baselen;
L
Linus Torvalds 已提交
192 193
		if (isspace(c))
			return get_extended_base_var(name, baselen, c);
194
		if (!iskeychar(c) && c != '.')
L
Linus Torvalds 已提交
195 196 197 198 199 200 201
			return -1;
		if (baselen > MAXNAME / 2)
			return -1;
		name[baselen++] = tolower(c);
	}
}

202
static int git_parse_file(config_fn_t fn, void *data)
L
Linus Torvalds 已提交
203 204 205 206 207 208 209 210
{
	int comment = 0;
	int baselen = 0;
	static char var[MAXNAME];

	for (;;) {
		int c = get_next_char();
		if (c == '\n') {
211
			if (config_file_eof)
L
Linus Torvalds 已提交
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
				return 0;
			comment = 0;
			continue;
		}
		if (comment || isspace(c))
			continue;
		if (c == '#' || c == ';') {
			comment = 1;
			continue;
		}
		if (c == '[') {
			baselen = get_base_var(var);
			if (baselen <= 0)
				break;
			var[baselen++] = '.';
			var[baselen] = 0;
			continue;
		}
		if (!isalpha(c))
			break;
232
		var[baselen] = tolower(c);
233
		if (get_value(fn, data, var, baselen+1) < 0)
L
Linus Torvalds 已提交
234 235
			break;
	}
236
	die("bad config file line %d in %s", config_linenr, config_file_name);
L
Linus Torvalds 已提交
237 238
}

239
static int parse_unit_factor(const char *end, unsigned long *val)
240 241 242
{
	if (!*end)
		return 1;
243 244 245 246 247 248 249 250 251 252 253 254 255
	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;
256 257 258 259 260 261 262
}

int git_parse_long(const char *value, long *ret)
{
	if (value && *value) {
		char *end;
		long val = strtol(value, &end, 0);
263 264 265 266
		unsigned long factor = 1;
		if (!parse_unit_factor(end, &factor))
			return 0;
		*ret = val * factor;
267 268 269 270 271 272
		return 1;
	}
	return 0;
}

int git_parse_ulong(const char *value, unsigned long *ret)
L
Linus Torvalds 已提交
273 274 275
{
	if (value && *value) {
		char *end;
276
		unsigned long val = strtoul(value, &end, 0);
277 278 279
		if (!parse_unit_factor(end, &val))
			return 0;
		*ret = val;
280
		return 1;
L
Linus Torvalds 已提交
281
	}
282 283 284
	return 0;
}

285 286 287 288 289 290 291
static void die_bad_config(const char *name)
{
	if (config_file_name)
		die("bad config value for '%s' in %s", name, config_file_name);
	die("bad config value for '%s'", name);
}

292 293 294 295
int git_config_int(const char *name, const char *value)
{
	long ret;
	if (!git_parse_long(value, &ret))
296
		die_bad_config(name);
297 298 299 300 301 302 303
	return ret;
}

unsigned long git_config_ulong(const char *name, const char *value)
{
	unsigned long ret;
	if (!git_parse_ulong(value, &ret))
304
		die_bad_config(name);
305
	return ret;
L
Linus Torvalds 已提交
306 307
}

J
Junio C Hamano 已提交
308
int git_config_bool_or_int(const char *name, const char *value, int *is_bool)
L
Linus Torvalds 已提交
309
{
J
Junio C Hamano 已提交
310
	*is_bool = 1;
L
Linus Torvalds 已提交
311 312 313 314
	if (!value)
		return 1;
	if (!*value)
		return 0;
315
	if (!strcasecmp(value, "true") || !strcasecmp(value, "yes"))
L
Linus Torvalds 已提交
316
		return 1;
317
	if (!strcasecmp(value, "false") || !strcasecmp(value, "no"))
L
Linus Torvalds 已提交
318
		return 0;
J
Junio C Hamano 已提交
319
	*is_bool = 0;
J
Junio C Hamano 已提交
320
	return git_config_int(name, value);
L
Linus Torvalds 已提交
321 322
}

J
Junio C Hamano 已提交
323 324 325
int git_config_bool(const char *name, const char *value)
{
	int discard;
J
Junio C Hamano 已提交
326
	return !!git_config_bool_or_int(name, value, &discard);
J
Junio C Hamano 已提交
327 328
}

329 330 331 332 333 334 335 336
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;
}

337
static int git_default_core_config(const char *var, const char *value)
L
Linus Torvalds 已提交
338 339 340 341 342 343 344
{
	/* This needs a better name */
	if (!strcmp(var, "core.filemode")) {
		trust_executable_bit = git_config_bool(var, value);
		return 0;
	}

345 346 347 348 349
	if (!strcmp(var, "core.quotepath")) {
		quote_path_fully = git_config_bool(var, value);
		return 0;
	}

350 351 352 353 354
	if (!strcmp(var, "core.symlinks")) {
		has_symlinks = git_config_bool(var, value);
		return 0;
	}

L
Linus Torvalds 已提交
355 356 357 358 359
	if (!strcmp(var, "core.ignorecase")) {
		ignore_case = git_config_bool(var, value);
		return 0;
	}

360 361 362 363 364
	if (!strcmp(var, "core.bare")) {
		is_bare_repository_cfg = git_config_bool(var, value);
		return 0;
	}

J
Junio C Hamano 已提交
365 366 367 368 369
	if (!strcmp(var, "core.ignorestat")) {
		assume_unchanged = git_config_bool(var, value);
		return 0;
	}

370 371
	if (!strcmp(var, "core.prefersymlinkrefs")) {
		prefer_symlink_refs = git_config_bool(var, value);
372 373 374
		return 0;
	}

375 376 377 378 379
	if (!strcmp(var, "core.logallrefupdates")) {
		log_all_ref_updates = git_config_bool(var, value);
		return 0;
	}

380 381 382 383 384
	if (!strcmp(var, "core.warnambiguousrefs")) {
		warn_ambiguous_refs = git_config_bool(var, value);
		return 0;
	}

385
	if (!strcmp(var, "core.loosecompression")) {
386 387 388 389 390 391
		int level = git_config_int(var, value);
		if (level == -1)
			level = Z_DEFAULT_COMPRESSION;
		else if (level < 0 || level > Z_BEST_COMPRESSION)
			die("bad zlib compression level %d", level);
		zlib_compression_level = level;
392 393 394 395 396 397 398 399 400 401 402 403 404 405
		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)
			die("bad zlib compression level %d", level);
		core_compression_level = level;
		core_compression_seen = 1;
		if (!zlib_compression_seen)
			zlib_compression_level = level;
406 407 408
		return 0;
	}

409
	if (!strcmp(var, "core.packedgitwindowsize")) {
410
		int pgsz_x2 = getpagesize() * 2;
411
		packed_git_window_size = git_config_int(var, value);
412 413 414 415 416 417

		/* 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;
418 419 420
		return 0;
	}

421 422 423 424 425
	if (!strcmp(var, "core.packedgitlimit")) {
		packed_git_limit = git_config_int(var, value);
		return 0;
	}

426 427 428 429 430
	if (!strcmp(var, "core.deltabasecachelimit")) {
		delta_base_cache_limit = git_config_int(var, value);
		return 0;
	}

L
Linus Torvalds 已提交
431
	if (!strcmp(var, "core.autocrlf")) {
L
Linus Torvalds 已提交
432 433 434 435
		if (value && !strcasecmp(value, "input")) {
			auto_crlf = -1;
			return 0;
		}
L
Linus Torvalds 已提交
436 437 438 439
		auto_crlf = git_config_bool(var, value);
		return 0;
	}

440 441 442 443 444 445 446 447 448
	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;
	}

449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464
	if (!strcmp(var, "core.pager"))
		return git_config_string(&pager_program, var, value);

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

	if (!strcmp(var, "core.excludesfile"))
		return git_config_string(&excludes_file, var, value);

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

465 466 467 468 469
	if (!strcmp(var, "core.fsyncobjectfiles")) {
		fsync_object_files = git_config_bool(var, value);
		return 0;
	}

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

474
static int git_default_user_config(const char *var, const char *value)
475
{
476
	if (!strcmp(var, "user.name")) {
477 478
		if (!value)
			return config_error_nonbool(var);
479
		strlcpy(git_default_name, value, sizeof(git_default_name));
480 481
		if (git_default_email[0])
			user_ident_explicitly_given = 1;
482 483 484 485
		return 0;
	}

	if (!strcmp(var, "user.email")) {
486 487
		if (!value)
			return config_error_nonbool(var);
488
		strlcpy(git_default_email, value, sizeof(git_default_email));
489 490
		if (git_default_name[0])
			user_ident_explicitly_given = 1;
491 492 493
		return 0;
	}

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

498
static int git_default_i18n_config(const char *var, const char *value)
499
{
500 501
	if (!strcmp(var, "i18n.commitencoding"))
		return git_config_string(&git_commit_encoding, var, value);
502

503 504
	if (!strcmp(var, "i18n.logoutputencoding"))
		return git_config_string(&git_log_output_encoding, var, value);
505

506 507 508
	/* Add other config variables here and to Documentation/config.txt. */
	return 0;
}
J
Junio C Hamano 已提交
509

510 511
static int git_default_branch_config(const char *var, const char *value)
{
512 513 514 515 516 517 518 519
	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;
	}
520 521 522 523 524 525 526 527 528 529 530 531 532 533 534
	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
			return error("Malformed value for %s", var);
		return 0;
	}
535

P
Petr Baudis 已提交
536
	/* Add other config variables here and to Documentation/config.txt. */
L
Linus Torvalds 已提交
537 538 539
	return 0;
}

540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562
int git_default_config(const char *var, const char *value, void *dummy)
{
	if (!prefixcmp(var, "core."))
		return git_default_core_config(var, value);

	if (!prefixcmp(var, "user."))
		return git_default_user_config(var, value);

	if (!prefixcmp(var, "i18n."))
		return git_default_i18n_config(var, value);

	if (!prefixcmp(var, "branch."))
		return git_default_branch_config(var, value);

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

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

563
int git_config_from_file(config_fn_t fn, const char *filename, void *data)
L
Linus Torvalds 已提交
564 565
{
	int ret;
566
	FILE *f = fopen(filename, "r");
L
Linus Torvalds 已提交
567 568 569 570

	ret = -1;
	if (f) {
		config_file = f;
571
		config_file_name = filename;
L
Linus Torvalds 已提交
572
		config_linenr = 1;
573
		config_file_eof = 0;
574
		ret = git_parse_file(fn, data);
L
Linus Torvalds 已提交
575
		fclose(f);
576
		config_file_name = NULL;
L
Linus Torvalds 已提交
577 578 579
	}
	return ret;
}
580

581 582
const char *git_etc_gitconfig(void)
{
583 584 585 586 587
	static const char *system_wide;
	if (!system_wide) {
		system_wide = ETC_GITCONFIG;
		if (!is_absolute_path(system_wide)) {
			/* interpret path relative to exec-dir */
J
Johannes Sixt 已提交
588 589 590
			struct strbuf d = STRBUF_INIT;
			strbuf_addf(&d, "%s/%s", git_exec_path(), system_wide);
			system_wide = strbuf_detach(&d, NULL);
591 592 593
		}
	}
	return system_wide;
594 595
}

596
static int git_env_bool(const char *k, int def)
597 598 599 600 601 602 603 604 605 606 607 608 609 610 611
{
	const char *v = getenv(k);
	return v ? git_config_bool(k, v) : def;
}

int git_config_system(void)
{
	return !git_env_bool("GIT_CONFIG_NOSYSTEM", 0);
}

int git_config_global(void)
{
	return !git_env_bool("GIT_CONFIG_NOGLOBAL", 0);
}

612
int git_config(config_fn_t fn, void *data)
613
{
614 615
	int ret = 0;
	char *repo_config = NULL;
616
	const char *home = NULL;
617 618 619 620 621

	/* $GIT_CONFIG makes git read _only_ the given config file,
	 * $GIT_CONFIG_LOCAL will make it process it in addition to the
	 * global config file, the same way it would the per-repository
	 * config file otherwise. */
622 623 624 625 626
	if (config_exclusive_filename)
		return git_config_from_file(fn, config_exclusive_filename, data);
	if (git_config_system() && !access(git_etc_gitconfig(), R_OK))
		ret += git_config_from_file(fn, git_etc_gitconfig(),
					    data);
627

628
	home = getenv("HOME");
629
	if (git_config_global() && home) {
630
		char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
631
		if (!access(user_config, R_OK))
632
			ret += git_config_from_file(fn, user_config, data);
633 634 635
		free(user_config);
	}

636 637
	repo_config = xstrdup(git_path("config"));
	ret += git_config_from_file(fn, repo_config, data);
J
Junio C Hamano 已提交
638
	free(repo_config);
639
	return ret;
640 641
}

642 643 644
/*
 * Find all the stuff for git_config_set() below.
 */
645 646 647

#define MAX_MATCHES 512

648 649 650
static struct {
	int baselen;
	char* key;
651
	int do_not_match;
652
	regex_t* value_regex;
653
	int multi_replace;
654
	size_t offset[MAX_MATCHES];
655 656 657 658
	enum { START, SECTION_SEEN, SECTION_END_SEEN, KEY_SEEN } state;
	int seen;
} store;

659 660 661 662 663 664 665 666
static int matches(const char* key, const char* value)
{
	return !strcmp(key, store.key) &&
		(store.value_regex == NULL ||
		 (store.do_not_match ^
		  !regexec(store.value_regex, value, 0, NULL, 0)));
}

667
static int store_aux(const char* key, const char* value, void *cb)
668
{
669 670 671
	const char *ep;
	size_t section_len;

672 673
	switch (store.state) {
	case KEY_SEEN:
674
		if (matches(key, value)) {
675
			if (store.seen == 1 && store.multi_replace == 0) {
676
				warning("%s has multiple values", key);
677
			} else if (store.seen >= MAX_MATCHES) {
678
				error("too many matches for %s", key);
679
				return 1;
680
			}
681 682

			store.offset[store.seen] = ftell(config_file);
683 684 685 686
			store.seen++;
		}
		break;
	case SECTION_SEEN:
687 688 689 690 691 692 693 694 695 696 697 698 699 700
		/*
		 * 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)) {
701 702
			store.state = SECTION_END_SEEN;
			break;
703 704 705 706 707 708 709
		}

		/*
		 * Do not increment matches: this is no match, but we
		 * just made sure we are in the desired section.
		 */
		store.offset[store.seen] = ftell(config_file);
710 711 712
		/* fallthru */
	case SECTION_END_SEEN:
	case START:
713
		if (matches(key, value)) {
714
			store.offset[store.seen] = ftell(config_file);
715 716
			store.state = KEY_SEEN;
			store.seen++;
L
Linus Torvalds 已提交
717 718
		} else {
			if (strrchr(key, '.') - key == store.baselen &&
S
sean 已提交
719
			      !strncmp(key, store.key, store.baselen)) {
S
sean 已提交
720
					store.state = SECTION_SEEN;
S
sean 已提交
721
					store.offset[store.seen] = ftell(config_file);
L
Linus Torvalds 已提交
722
			}
S
sean 已提交
723
		}
724 725 726 727
	}
	return 0;
}

728
static int write_error(const char *filename)
729
{
730
	error("failed to write new configuration file %s", filename);
731 732 733 734 735 736

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

static int store_write_section(int fd, const char* key)
737
{
738 739 740
	const char *dot;
	int i, success;
	struct strbuf sb;
L
Linus Torvalds 已提交
741

742 743
	strbuf_init(&sb, 0);
	dot = memchr(key, '.', store.baselen);
L
Linus Torvalds 已提交
744
	if (dot) {
745 746
		strbuf_addf(&sb, "[%.*s \"", (int)(dot - key), key);
		for (i = dot - key + 1; i < store.baselen; i++) {
747
			if (key[i] == '"' || key[i] == '\\')
748 749
				strbuf_addch(&sb, '\\');
			strbuf_addch(&sb, key[i]);
L
Linus Torvalds 已提交
750
		}
751 752 753
		strbuf_addstr(&sb, "\"]\n");
	} else {
		strbuf_addf(&sb, "[%.*s]\n", store.baselen, key);
L
Linus Torvalds 已提交
754 755
	}

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

759
	return success;
760 761
}

762
static int store_write_pair(int fd, const char* key, const char* value)
763
{
764 765 766 767
	int i, success;
	int length = strlen(key + store.baselen + 1);
	const char *quote = "";
	struct strbuf sb;
768

769 770 771 772 773 774 775
	/*
	 * 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.
	 */
776
	if (value[0] == ' ')
777
		quote = "\"";
778 779
	for (i = 0; value[i]; i++)
		if (value[i] == ';' || value[i] == '#')
780 781 782 783 784 785 786
			quote = "\"";
	if (i && value[i - 1] == ' ')
		quote = "\"";

	strbuf_init(&sb, 0);
	strbuf_addf(&sb, "\t%.*s = %s",
		    length, key + store.baselen + 1, quote);
787 788 789

	for (i = 0; value[i]; i++)
		switch (value[i]) {
790
		case '\n':
791
			strbuf_addstr(&sb, "\\n");
792 793
			break;
		case '\t':
794
			strbuf_addstr(&sb, "\\t");
795 796 797
			break;
		case '"':
		case '\\':
798
			strbuf_addch(&sb, '\\');
799
		default:
800
			strbuf_addch(&sb, value[i]);
801 802
			break;
		}
803 804 805 806 807 808
	strbuf_addf(&sb, "%s\n", quote);

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

	return success;
809 810
}

811 812
static ssize_t find_beginning_of_line(const char* contents, size_t size,
	size_t offset_, int* found_bracket)
813
{
814 815
	size_t equal_offset = size, bracket_offset = size;
	ssize_t offset;
816

817
contline:
J
Junio C Hamano 已提交
818
	for (offset = offset_-2; offset > 0
819 820 821 822 823
			&& contents[offset] != '\n'; offset--)
		switch (contents[offset]) {
			case '=': equal_offset = offset; break;
			case ']': bracket_offset = offset; break;
		}
824 825 826 827
	if (offset > 0 && contents[offset-1] == '\\') {
		offset_ = offset;
		goto contline;
	}
828 829 830 831 832 833 834 835 836
	if (bracket_offset < equal_offset) {
		*found_bracket = 1;
		offset = bracket_offset+1;
	} else
		offset++;

	return offset;
}

837 838
int git_config_set(const char* key, const char* value)
{
839
	return git_config_set_multivar(key, value, NULL, 0);
840 841 842 843 844
}

/*
 * If value==NULL, unset in (remove from) config,
 * if value_regex!=NULL, disregard key/value pairs where value does not match.
845 846 847
 * 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.
848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865
 *
 * 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.
 *
 */
int git_config_set_multivar(const char* key, const char* value,
866
	const char* value_regex, int multi_replace)
867
{
L
Linus Torvalds 已提交
868
	int i, dot;
869
	int fd = -1, in_fd;
870
	int ret;
871
	char* config_filename;
872
	struct lock_file *lock = NULL;
873
	const char* last_dot = strrchr(key, '.');
874

875 876 877 878
	if (config_exclusive_filename)
		config_filename = xstrdup(config_exclusive_filename);
	else
		config_filename = xstrdup(git_path("config"));
879

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

885
	if (last_dot == NULL) {
886
		error("key does not contain a section: %s", key);
887 888
		ret = 2;
		goto out_free;
889
	}
890 891 892
	store.baselen = last_dot - key;

	store.multi_replace = multi_replace;
893 894 895 896

	/*
	 * Validate the key and while at it, lower case it for matching.
	 */
J
Jonas Fonseca 已提交
897
	store.key = xmalloc(strlen(key) + 1);
L
Linus Torvalds 已提交
898 899 900 901 902 903 904
	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 > store.baselen) {
905
			if (!iskeychar(c) || (i == store.baselen+1 && !isalpha(c))) {
906
				error("invalid key: %s", key);
L
Linus Torvalds 已提交
907 908 909 910 911
				free(store.key);
				ret = 1;
				goto out_free;
			}
			c = tolower(c);
912
		} else if (c == '\n') {
913
			error("invalid key (newline): %s", key);
914 915 916
			free(store.key);
			ret = 1;
			goto out_free;
L
Linus Torvalds 已提交
917 918 919
		}
		store.key[i] = c;
	}
920
	store.key[i] = 0;
921 922

	/*
923
	 * The lock serves a purpose in addition to locking: the new
924 925
	 * contents of .git/config will be written into it.
	 */
926 927 928
	lock = xcalloc(sizeof(struct lock_file), 1);
	fd = hold_lock_file_for_update(lock, config_filename, 0);
	if (fd < 0) {
929
		error("could not lock config file %s", config_filename);
930
		free(store.key);
931 932
		ret = -1;
		goto out_free;
933 934 935 936 937
	}

	/*
	 * If .git/config does not exist yet, write a minimal version.
	 */
938 939
	in_fd = open(config_filename, O_RDONLY);
	if ( in_fd < 0 ) {
940 941
		free(store.key);

942 943 944
		if ( ENOENT != errno ) {
			error("opening %s: %s", config_filename,
			      strerror(errno));
945 946
			ret = 3; /* same as "invalid config file" */
			goto out_free;
947
		}
948 949
		/* if nothing to unset, error out */
		if (value == NULL) {
950 951
			ret = 5;
			goto out_free;
952 953 954
		}

		store.key = (char*)key;
955
		if (!store_write_section(fd, key) ||
956 957 958
		    !store_write_pair(fd, key, value))
			goto write_err_out;
	} else {
959
		struct stat st;
960
		char* contents;
961 962
		size_t contents_sz, copy_begin, copy_end;
		int i, new_line = 0;
963 964 965 966

		if (value_regex == NULL)
			store.value_regex = NULL;
		else {
967 968 969 970 971 972
			if (value_regex[0] == '!') {
				store.do_not_match = 1;
				value_regex++;
			} else
				store.do_not_match = 0;

J
Jonas Fonseca 已提交
973
			store.value_regex = (regex_t*)xmalloc(sizeof(regex_t));
974 975
			if (regcomp(store.value_regex, value_regex,
					REG_EXTENDED)) {
976
				error("invalid pattern: %s", value_regex);
977
				free(store.value_regex);
978 979
				ret = 6;
				goto out_free;
980 981 982
			}
		}

983
		store.offset[0] = 0;
984 985 986 987 988 989 990 991 992
		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.
		 */
993
		if (git_config_from_file(store_aux, config_filename, NULL)) {
994
			error("invalid config file %s", config_filename);
995 996 997 998 999
			free(store.key);
			if (store.value_regex != NULL) {
				regfree(store.value_regex);
				free(store.value_regex);
			}
1000 1001
			ret = 3;
			goto out_free;
1002 1003 1004 1005 1006 1007 1008 1009
		}

		free(store.key);
		if (store.value_regex != NULL) {
			regfree(store.value_regex);
			free(store.value_regex);
		}

1010 1011 1012
		/* if nothing to unset, or too many matches, error out */
		if ((store.seen == 0 && value == NULL) ||
				(store.seen > 1 && multi_replace == 0)) {
1013 1014
			ret = 5;
			goto out_free;
1015 1016
		}

1017
		fstat(in_fd, &st);
1018 1019
		contents_sz = xsize_t(st.st_size);
		contents = xmmap(NULL, contents_sz, PROT_READ,
1020 1021 1022
			MAP_PRIVATE, in_fd, 0);
		close(in_fd);

1023 1024 1025 1026 1027
		if (store.seen == 0)
			store.seen = 1;

		for (i = 0, copy_begin = 0; i < store.seen; i++) {
			if (store.offset[i] == 0) {
1028
				store.offset[i] = copy_end = contents_sz;
1029 1030
			} else if (store.state != KEY_SEEN) {
				copy_end = store.offset[i];
1031
			} else
1032
				copy_end = find_beginning_of_line(
1033
					contents, contents_sz,
1034 1035
					store.offset[i]-2, &new_line);

1036 1037 1038
			if (copy_end > 0 && contents[copy_end-1] != '\n')
				new_line = 1;

1039 1040
			/* write the first part of the config */
			if (copy_end > copy_begin) {
1041 1042 1043 1044 1045 1046 1047
				if (write_in_full(fd, contents + copy_begin,
						  copy_end - copy_begin) <
				    copy_end - copy_begin)
					goto write_err_out;
				if (new_line &&
				    write_in_full(fd, "\n", 1) != 1)
					goto write_err_out;
1048 1049
			}
			copy_begin = store.offset[i];
1050 1051 1052 1053
		}

		/* write the pair (value == NULL means unset) */
		if (value != NULL) {
1054 1055 1056
			if (store.state == START) {
				if (!store_write_section(fd, key))
					goto write_err_out;
1057
			}
1058 1059
			if (!store_write_pair(fd, key, value))
				goto write_err_out;
1060 1061 1062
		}

		/* write the rest of the config */
1063
		if (copy_begin < contents_sz)
1064
			if (write_in_full(fd, contents + copy_begin,
1065 1066
					  contents_sz - copy_begin) <
			    contents_sz - copy_begin)
1067
				goto write_err_out;
1068

1069
		munmap(contents, contents_sz);
1070 1071
	}

B
Brandon Casey 已提交
1072
	if (commit_lock_file(lock) < 0) {
1073
		error("could not commit config file %s", config_filename);
1074 1075
		ret = 4;
		goto out_free;
1076 1077
	}

1078 1079 1080 1081 1082 1083 1084
	/*
	 * lock is committed, so don't try to roll it back below.
	 * NOTE: Since lockfile.c keeps a linked list of all created
	 * lock_file structures, it isn't safe to free(lock).  It's
	 * better to just leave it hanging around.
	 */
	lock = NULL;
1085 1086 1087
	ret = 0;

out_free:
1088 1089
	if (lock)
		rollback_lock_file(lock);
J
Junio C Hamano 已提交
1090
	free(config_filename);
1091
	return ret;
1092 1093

write_err_out:
1094
	ret = write_error(lock->filename);
1095 1096
	goto out_free;

1097 1098
}

1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126
static int section_name_match (const char *buf, const char *name)
{
	int i = 0, j = 0, dot = 0;
	for (; buf[i] && buf[i] != ']'; i++) {
		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;
	}
	return (buf[i] == ']' && name[j] == 0);
}

/* if new_name == NULL, the section is removed instead */
1127 1128
int git_config_rename_section(const char *old_name, const char *new_name)
{
1129
	int ret = 0, remove = 0;
1130
	char *config_filename;
1131 1132 1133 1134
	struct lock_file *lock = xcalloc(sizeof(struct lock_file), 1);
	int out_fd;
	char buf[1024];

1135 1136 1137 1138
	if (config_exclusive_filename)
		config_filename = xstrdup(config_exclusive_filename);
	else
		config_filename = xstrdup(git_path("config"));
1139
	out_fd = hold_lock_file_for_update(lock, config_filename, 0);
1140
	if (out_fd < 0) {
1141
		ret = error("could not lock config file %s", config_filename);
1142 1143
		goto out;
	}
1144

1145
	if (!(config_file = fopen(config_filename, "rb"))) {
1146 1147
		/* no config file means nothing to rename, no error */
		goto unlock_and_out;
1148
	}
1149 1150 1151

	while (fgets(buf, sizeof(buf), config_file)) {
		int i;
1152
		int length;
1153 1154 1155 1156
		for (i = 0; buf[i] && isspace(buf[i]); i++)
			; /* do nothing */
		if (buf[i] == '[') {
			/* it's a section */
1157 1158 1159 1160
			if (section_name_match (&buf[i+1], old_name)) {
				ret++;
				if (new_name == NULL) {
					remove = 1;
1161 1162 1163
					continue;
				}
				store.baselen = strlen(new_name);
1164
				if (!store_write_section(out_fd, new_name)) {
1165
					ret = write_error(lock->filename);
1166 1167
					goto out;
				}
1168 1169
				continue;
			}
1170
			remove = 0;
1171
		}
1172 1173
		if (remove)
			continue;
1174 1175
		length = strlen(buf);
		if (write_in_full(out_fd, buf, length) != length) {
1176
			ret = write_error(lock->filename);
1177 1178
			goto out;
		}
1179
	}
1180
	fclose(config_file);
1181
 unlock_and_out:
B
Brandon Casey 已提交
1182
	if (commit_lock_file(lock) < 0)
1183
		ret = error("could not commit config file %s", config_filename);
1184 1185
 out:
	free(config_filename);
1186 1187
	return ret;
}
1188 1189 1190 1191 1192 1193 1194 1195 1196

/*
 * Call this to report error for your variable that should not
 * get a boolean value (i.e. "[my] var" means "true").
 */
int config_error_nonbool(const char *var)
{
	return error("Missing value for '%s'", var);
}