config.c 33.5 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"
10
#include "strbuf.h"
11
#include "quote.h"
L
Linus Torvalds 已提交
12 13 14 15

#define MAXNAME (256)

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

21 22
const char *config_exclusive_filename = NULL;

23 24 25
struct config_item
{
	struct config_item *next;
26
	char *name;
27 28 29 30 31 32 33 34 35 36 37
	char *value;
};
static struct config_item *config_parameters;
static struct config_item **config_parameters_tail = &config_parameters;

static void lowercase(char *p)
{
	for (; *p; p++)
		*p = tolower(*p);
}

38 39 40 41 42 43 44 45 46 47 48 49 50
void git_config_push_parameter(const char *text)
{
	struct strbuf env = STRBUF_INIT;
	const char *old = getenv(CONFIG_DATA_ENVIRONMENT);
	if (old) {
		strbuf_addstr(&env, old);
		strbuf_addch(&env, ' ');
	}
	sq_quote_buf(&env, text);
	setenv(CONFIG_DATA_ENVIRONMENT, env.buf, 1);
	strbuf_release(&env);
}

51 52 53
int git_config_parse_parameter(const char *text)
{
	struct config_item *ct;
54 55 56 57 58 59 60 61 62
	struct strbuf tmp = STRBUF_INIT;
	struct strbuf **pair;
	strbuf_addstr(&tmp, text);
	pair = strbuf_split(&tmp, '=');
	if (pair[0]->len && pair[0]->buf[pair[0]->len - 1] == '=')
		strbuf_setlen(pair[0], pair[0]->len - 1);
	strbuf_trim(pair[0]);
	if (!pair[0]->len) {
		strbuf_list_free(pair);
63 64
		return -1;
	}
65 66 67 68 69 70 71 72
	ct = xcalloc(1, sizeof(struct config_item));
	ct->name = strbuf_detach(pair[0], NULL);
	if (pair[1]) {
		strbuf_trim(pair[1]);
		ct->value = strbuf_detach(pair[1], NULL);
	}
	strbuf_list_free(pair);
	lowercase(ct->name);
73 74 75 76 77
	*config_parameters_tail = ct;
	config_parameters_tail = &ct->next;
	return 0;
}

78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
int git_config_parse_environment(void) {
	const char *env = getenv(CONFIG_DATA_ENVIRONMENT);
	char *envw;
	const char **argv = NULL;
	int nr = 0, alloc = 0;
	int i;

	if (!env)
		return 0;
	/* sq_dequote will write over it */
	envw = xstrdup(env);

	if (sq_dequote_to_argv(envw, &argv, &nr, &alloc) < 0) {
		free(envw);
		return error("bogus format in " CONFIG_DATA_ENVIRONMENT);
	}

	for (i = 0; i < nr; i++) {
		if (git_config_parse_parameter(argv[i]) < 0) {
			error("bogus config parameter: %s", argv[i]);
			free(argv);
			free(envw);
			return -1;
		}
	}

	free(argv);
	free(envw);
	return 0;
}

L
Linus Torvalds 已提交
109 110 111 112 113 114 115 116
static int get_next_char(void)
{
	int c;
	FILE *f;

	c = '\n';
	if ((f = config_file) != NULL) {
		c = fgetc(f);
117 118 119 120 121 122 123 124
		if (c == '\r') {
			/* DOS like systems */
			c = fgetc(f);
			if (c != '\n') {
				ungetc(c, f);
				c = '\r';
			}
		}
L
Linus Torvalds 已提交
125 126 127
		if (c == '\n')
			config_linenr++;
		if (c == EOF) {
128
			config_file_eof = 1;
L
Linus Torvalds 已提交
129 130 131 132 133 134 135 136 137 138 139 140 141
			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();
142
		if (len >= sizeof(value) - 1)
L
Linus Torvalds 已提交
143 144 145 146 147 148 149 150 151 152
			return NULL;
		if (c == '\n') {
			if (quote)
				return NULL;
			value[len] = 0;
			return value;
		}
		if (comment)
			continue;
		if (isspace(c) && !quote) {
153 154
			if (len)
				space++;
L
Linus Torvalds 已提交
155 156
			continue;
		}
157 158 159 160 161 162
		if (!quote) {
			if (c == ';' || c == '#') {
				comment = 1;
				continue;
			}
		}
163 164
		for (; space; space--)
			value[len++] = ' ';
L
Linus Torvalds 已提交
165 166 167 168 169 170 171 172 173 174 175 176 177 178
		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;
179 180 181 182 183 184
			/* Some characters escape as themselves */
			case '\\': case '"':
				break;
			/* Reject unknown escape sequences */
			default:
				return NULL;
L
Linus Torvalds 已提交
185 186 187 188 189 190 191 192 193 194 195 196
			}
			value[len++] = c;
			continue;
		}
		if (c == '"') {
			quote = 1-quote;
			continue;
		}
		value[len++] = c;
	}
}

197 198 199 200 201
static inline int iskeychar(int c)
{
	return isalnum(c) || c == '-';
}

202
static int get_value(config_fn_t fn, void *data, char *name, unsigned int len)
L
Linus Torvalds 已提交
203 204 205 206 207 208 209
{
	int c;
	char *value;

	/* Get the full name */
	for (;;) {
		c = get_next_char();
210
		if (config_file_eof)
L
Linus Torvalds 已提交
211
			break;
212
		if (!iskeychar(c))
L
Linus Torvalds 已提交
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
			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;
	}
230
	return fn(name, value, data);
L
Linus Torvalds 已提交
231 232
}

L
Linus Torvalds 已提交
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
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 已提交
268 269 270 271 272 273
static int get_base_var(char *name)
{
	int baselen = 0;

	for (;;) {
		int c = get_next_char();
274
		if (config_file_eof)
L
Linus Torvalds 已提交
275 276 277
			return -1;
		if (c == ']')
			return baselen;
L
Linus Torvalds 已提交
278 279
		if (isspace(c))
			return get_extended_base_var(name, baselen, c);
280
		if (!iskeychar(c) && c != '.')
L
Linus Torvalds 已提交
281 282 283 284 285 286 287
			return -1;
		if (baselen > MAXNAME / 2)
			return -1;
		name[baselen++] = tolower(c);
	}
}

288
static int git_parse_file(config_fn_t fn, void *data)
L
Linus Torvalds 已提交
289 290 291 292 293
{
	int comment = 0;
	int baselen = 0;
	static char var[MAXNAME];

294 295 296 297
	/* U+FEFF Byte Order Mark in UTF8 */
	static const unsigned char *utf8_bom = (unsigned char *) "\xef\xbb\xbf";
	const unsigned char *bomptr = utf8_bom;

L
Linus Torvalds 已提交
298 299
	for (;;) {
		int c = get_next_char();
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314
		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. */
			if ((unsigned char) c == *bomptr) {
				bomptr++;
				continue;
			} else {
				/* Do not tolerate partial BOM. */
				if (bomptr != utf8_bom)
					break;
				/* No BOM at file beginning. Cool. */
				bomptr = NULL;
			}
		}
L
Linus Torvalds 已提交
315
		if (c == '\n') {
316
			if (config_file_eof)
L
Linus Torvalds 已提交
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336
				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;
337
		var[baselen] = tolower(c);
338
		if (get_value(fn, data, var, baselen+1) < 0)
L
Linus Torvalds 已提交
339 340
			break;
	}
341
	die("bad config file line %d in %s", config_linenr, config_file_name);
L
Linus Torvalds 已提交
342 343
}

344
static int parse_unit_factor(const char *end, unsigned long *val)
345 346 347
{
	if (!*end)
		return 1;
348 349 350 351 352 353 354 355 356 357 358 359 360
	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;
361 362
}

363
static int git_parse_long(const char *value, long *ret)
364 365 366 367
{
	if (value && *value) {
		char *end;
		long val = strtol(value, &end, 0);
368 369 370 371
		unsigned long factor = 1;
		if (!parse_unit_factor(end, &factor))
			return 0;
		*ret = val * factor;
372 373 374 375 376 377
		return 1;
	}
	return 0;
}

int git_parse_ulong(const char *value, unsigned long *ret)
L
Linus Torvalds 已提交
378 379 380
{
	if (value && *value) {
		char *end;
381
		unsigned long val = strtoul(value, &end, 0);
382 383 384
		if (!parse_unit_factor(end, &val))
			return 0;
		*ret = val;
385
		return 1;
L
Linus Torvalds 已提交
386
	}
387 388 389
	return 0;
}

390 391 392 393 394 395 396
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);
}

397 398
int git_config_int(const char *name, const char *value)
{
399
	long ret = 0;
400
	if (!git_parse_long(value, &ret))
401
		die_bad_config(name);
402 403 404 405 406 407 408
	return ret;
}

unsigned long git_config_ulong(const char *name, const char *value)
{
	unsigned long ret;
	if (!git_parse_ulong(value, &ret))
409
		die_bad_config(name);
410
	return ret;
L
Linus Torvalds 已提交
411 412
}

J
Jeff King 已提交
413
static int git_config_maybe_bool_text(const char *name, const char *value)
L
Linus Torvalds 已提交
414 415 416 417 418
{
	if (!value)
		return 1;
	if (!*value)
		return 0;
J
Junio C Hamano 已提交
419 420 421
	if (!strcasecmp(value, "true")
	    || !strcasecmp(value, "yes")
	    || !strcasecmp(value, "on"))
L
Linus Torvalds 已提交
422
		return 1;
J
Junio C Hamano 已提交
423 424 425
	if (!strcasecmp(value, "false")
	    || !strcasecmp(value, "no")
	    || !strcasecmp(value, "off"))
L
Linus Torvalds 已提交
426
		return 0;
J
Junio C Hamano 已提交
427 428 429
	return -1;
}

J
Jeff King 已提交
430 431
int git_config_maybe_bool(const char *name, const char *value)
{
432
	long v = git_config_maybe_bool_text(name, value);
J
Jeff King 已提交
433 434
	if (0 <= v)
		return v;
435 436
	if (git_parse_long(value, &v))
		return !!v;
J
Jeff King 已提交
437 438 439
	return -1;
}

J
Junio C Hamano 已提交
440 441
int git_config_bool_or_int(const char *name, const char *value, int *is_bool)
{
J
Jeff King 已提交
442
	int v = git_config_maybe_bool_text(name, value);
J
Junio C Hamano 已提交
443 444 445 446
	if (0 <= v) {
		*is_bool = 1;
		return v;
	}
J
Junio C Hamano 已提交
447
	*is_bool = 0;
J
Junio C Hamano 已提交
448
	return git_config_int(name, value);
L
Linus Torvalds 已提交
449 450
}

J
Junio C Hamano 已提交
451 452 453
int git_config_bool(const char *name, const char *value)
{
	int discard;
J
Junio C Hamano 已提交
454
	return !!git_config_bool_or_int(name, value, &discard);
J
Junio C Hamano 已提交
455 456
}

457 458 459 460 461 462 463 464
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;
}

465 466 467 468 469 470 471 472 473 474
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)
		die("Failed to expand user dir in: '%s'", value);
	return 0;
}

475
static int git_default_core_config(const char *var, const char *value)
L
Linus Torvalds 已提交
476 477 478 479 480 481
{
	/* This needs a better name */
	if (!strcmp(var, "core.filemode")) {
		trust_executable_bit = git_config_bool(var, value);
		return 0;
	}
482 483 484 485
	if (!strcmp(var, "core.trustctime")) {
		trust_ctime = git_config_bool(var, value);
		return 0;
	}
L
Linus Torvalds 已提交
486

487 488 489 490 491
	if (!strcmp(var, "core.quotepath")) {
		quote_path_fully = git_config_bool(var, value);
		return 0;
	}

492 493 494 495 496
	if (!strcmp(var, "core.symlinks")) {
		has_symlinks = git_config_bool(var, value);
		return 0;
	}

L
Linus Torvalds 已提交
497 498 499 500 501
	if (!strcmp(var, "core.ignorecase")) {
		ignore_case = git_config_bool(var, value);
		return 0;
	}

502 503 504 505 506 507 508
	if (!strcmp(var, "core.abbrevguard")) {
		unique_abbrev_extra_length = git_config_int(var, value);
		if (unique_abbrev_extra_length < 0)
			unique_abbrev_extra_length = 0;
		return 0;
	}

509 510 511 512 513
	if (!strcmp(var, "core.bare")) {
		is_bare_repository_cfg = git_config_bool(var, value);
		return 0;
	}

J
Junio C Hamano 已提交
514 515 516 517 518
	if (!strcmp(var, "core.ignorestat")) {
		assume_unchanged = git_config_bool(var, value);
		return 0;
	}

519 520
	if (!strcmp(var, "core.prefersymlinkrefs")) {
		prefer_symlink_refs = git_config_bool(var, value);
521 522 523
		return 0;
	}

524 525 526 527 528
	if (!strcmp(var, "core.logallrefupdates")) {
		log_all_ref_updates = git_config_bool(var, value);
		return 0;
	}

529 530 531 532 533
	if (!strcmp(var, "core.warnambiguousrefs")) {
		warn_ambiguous_refs = git_config_bool(var, value);
		return 0;
	}

534 535 536 537 538 539 540 541
	if (!strcmp(var, "core.abbrevlength")) {
		int abbrev = git_config_int(var, value);
		if (abbrev < minimum_abbrev || abbrev > 40)
			return -1;
		default_abbrev = abbrev;
		return 0;
	}

542
	if (!strcmp(var, "core.loosecompression")) {
543 544 545 546 547 548
		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;
549 550 551 552 553 554 555 556 557 558 559 560 561 562
		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;
563 564 565
		return 0;
	}

566
	if (!strcmp(var, "core.packedgitwindowsize")) {
567
		int pgsz_x2 = getpagesize() * 2;
568
		packed_git_window_size = git_config_int(var, value);
569 570 571 572 573 574

		/* 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;
575 576 577
		return 0;
	}

578 579 580 581 582
	if (!strcmp(var, "core.packedgitlimit")) {
		packed_git_limit = git_config_int(var, value);
		return 0;
	}

583 584 585 586 587
	if (!strcmp(var, "core.deltabasecachelimit")) {
		delta_base_cache_limit = git_config_int(var, value);
		return 0;
	}

L
Linus Torvalds 已提交
588
	if (!strcmp(var, "core.autocrlf")) {
L
Linus Torvalds 已提交
589
		if (value && !strcasecmp(value, "input")) {
590 591
			if (eol == EOL_CRLF)
				return error("core.autocrlf=input conflicts with core.eol=crlf");
592
			auto_crlf = AUTO_CRLF_INPUT;
L
Linus Torvalds 已提交
593 594
			return 0;
		}
L
Linus Torvalds 已提交
595 596 597 598
		auto_crlf = git_config_bool(var, value);
		return 0;
	}

599 600 601 602 603 604 605 606 607
	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;
	}

608 609 610 611 612 613 614 615 616 617 618 619 620 621
	if (!strcmp(var, "core.eol")) {
		if (value && !strcasecmp(value, "lf"))
			eol = EOL_LF;
		else if (value && !strcasecmp(value, "crlf"))
			eol = EOL_CRLF;
		else if (value && !strcasecmp(value, "native"))
			eol = EOL_NATIVE;
		else
			eol = EOL_UNSET;
		if (eol == EOL_CRLF && auto_crlf == AUTO_CRLF_INPUT)
			return error("core.autocrlf=input conflicts with core.eol=crlf");
		return 0;
	}

J
Johannes Schindelin 已提交
622 623 624 625 626
	if (!strcmp(var, "core.notesref")) {
		notes_ref_name = xstrdup(value);
		return 0;
	}

627 628 629 630 631 632
	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);

A
Anselm Kruis 已提交
633 634 635
	if (!strcmp(var, "core.askpass"))
		return git_config_string(&askpass_program, var, value);

636
	if (!strcmp(var, "core.excludesfile"))
637
		return git_config_pathname(&excludes_file, var, value);
638 639 640 641 642 643 644 645

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

646 647 648 649 650
	if (!strcmp(var, "core.fsyncobjectfiles")) {
		fsync_object_files = git_config_bool(var, value);
		return 0;
	}

L
Linus Torvalds 已提交
651 652 653 654 655
	if (!strcmp(var, "core.preloadindex")) {
		core_preload_index = git_config_bool(var, value);
		return 0;
	}

656 657 658 659 660 661 662
	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
			die("Invalid mode for object creation: %s", value);
663 664 665
		return 0;
	}

666 667 668 669 670
	if (!strcmp(var, "core.sparsecheckout")) {
		core_apply_sparse_checkout = git_config_bool(var, value);
		return 0;
	}

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

675
static int git_default_user_config(const char *var, const char *value)
676
{
677
	if (!strcmp(var, "user.name")) {
678 679
		if (!value)
			return config_error_nonbool(var);
680
		strlcpy(git_default_name, value, sizeof(git_default_name));
681
		user_ident_explicitly_given |= IDENT_NAME_GIVEN;
682 683 684 685
		return 0;
	}

	if (!strcmp(var, "user.email")) {
686 687
		if (!value)
			return config_error_nonbool(var);
688
		strlcpy(git_default_email, value, sizeof(git_default_email));
689
		user_ident_explicitly_given |= IDENT_MAIL_GIVEN;
690 691 692
		return 0;
	}

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

697
static int git_default_i18n_config(const char *var, const char *value)
698
{
699 700
	if (!strcmp(var, "i18n.commitencoding"))
		return git_config_string(&git_commit_encoding, var, value);
701

702 703
	if (!strcmp(var, "i18n.logoutputencoding"))
		return git_config_string(&git_log_output_encoding, var, value);
704

705 706 707
	/* Add other config variables here and to Documentation/config.txt. */
	return 0;
}
J
Junio C Hamano 已提交
708

709 710
static int git_default_branch_config(const char *var, const char *value)
{
711 712 713 714 715 716 717 718
	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;
	}
719 720 721 722 723 724 725 726 727 728 729 730 731 732 733
	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;
	}
734

P
Petr Baudis 已提交
735
	/* Add other config variables here and to Documentation/config.txt. */
L
Linus Torvalds 已提交
736 737 738
	return 0;
}

739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763
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;
		else if (!strcmp(value, "tracking"))
			push_default = PUSH_DEFAULT_TRACKING;
		else if (!strcmp(value, "current"))
			push_default = PUSH_DEFAULT_CURRENT;
		else {
			error("Malformed value for %s: %s", var, value);
			return error("Must be one of nothing, matching, "
				     "tracking or current.");
		}
		return 0;
	}

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

764 765 766 767 768 769 770 771 772
static int git_default_mailmap_config(const char *var, const char *value)
{
	if (!strcmp(var, "mailmap.file"))
		return git_config_string(&git_mailmap_file, var, value);

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

773 774 775 776 777 778 779 780 781 782 783 784 785 786
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);

787 788 789
	if (!prefixcmp(var, "push."))
		return git_default_push_config(var, value);

790 791 792
	if (!prefixcmp(var, "mailmap."))
		return git_default_mailmap_config(var, value);

793 794 795
	if (!prefixcmp(var, "advice."))
		return git_default_advice_config(var, value);

796 797 798 799 800 801 802 803 804
	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;
}

805
int git_config_from_file(config_fn_t fn, const char *filename, void *data)
L
Linus Torvalds 已提交
806 807
{
	int ret;
808
	FILE *f = fopen(filename, "r");
L
Linus Torvalds 已提交
809 810 811 812

	ret = -1;
	if (f) {
		config_file = f;
813
		config_file_name = filename;
L
Linus Torvalds 已提交
814
		config_linenr = 1;
815
		config_file_eof = 0;
816
		ret = git_parse_file(fn, data);
L
Linus Torvalds 已提交
817
		fclose(f);
818
		config_file_name = NULL;
L
Linus Torvalds 已提交
819 820 821
	}
	return ret;
}
822

823 824
const char *git_etc_gitconfig(void)
{
825
	static const char *system_wide;
826 827
	if (!system_wide)
		system_wide = system_path(ETC_GITCONFIG);
828
	return system_wide;
829 830
}

831
int git_env_bool(const char *k, int def)
832 833 834 835 836 837 838 839 840 841 842 843 844 845 846
{
	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);
}

847 848
int git_config_from_parameters(config_fn_t fn, void *data)
{
849
	static int loaded_environment;
850
	const struct config_item *ct;
851 852 853 854 855 856

	if (!loaded_environment) {
		if (git_config_parse_environment() < 0)
			return -1;
		loaded_environment = 1;
	}
857 858 859 860 861 862
	for (ct = config_parameters; ct; ct = ct->next)
		if (fn(ct->name, ct->value, data) < 0)
			return -1;
	return 0;
}

N
Nguyễn Thái Ngọc Duy 已提交
863
int git_config_early(config_fn_t fn, void *data, const char *repo_config)
864
{
865
	int ret = 0, found = 0;
866
	const char *home = NULL;
867

868
	/* Setting $GIT_CONFIG makes git read _only_ the given config file. */
869 870
	if (config_exclusive_filename)
		return git_config_from_file(fn, config_exclusive_filename, data);
871
	if (git_config_system() && !access(git_etc_gitconfig(), R_OK)) {
872 873
		ret += git_config_from_file(fn, git_etc_gitconfig(),
					    data);
874 875
		found += 1;
	}
876

877
	home = getenv("HOME");
878
	if (git_config_global() && home) {
879
		char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
880
		if (!access(user_config, R_OK)) {
881
			ret += git_config_from_file(fn, user_config, data);
882 883
			found += 1;
		}
884 885 886
		free(user_config);
	}

N
Nguyễn Thái Ngọc Duy 已提交
887
	if (repo_config && !access(repo_config, R_OK)) {
888 889 890
		ret += git_config_from_file(fn, repo_config, data);
		found += 1;
	}
891

892 893
	ret += git_config_from_parameters(fn, data);
	if (config_parameters)
894 895
		found += 1;

896
	return ret == 0 ? found : ret;
897 898
}

N
Nguyễn Thái Ngọc Duy 已提交
899 900 901 902 903 904 905 906 907 908 909 910
int git_config(config_fn_t fn, void *data)
{
	char *repo_config = NULL;
	int ret;

	repo_config = git_pathdup("config");
	ret = git_config_early(fn, data, repo_config);
	if (repo_config)
		free(repo_config);
	return ret;
}

911 912 913
/*
 * Find all the stuff for git_config_set() below.
 */
914 915 916

#define MAX_MATCHES 512

917 918
static struct {
	int baselen;
919
	char *key;
920
	int do_not_match;
921
	regex_t *value_regex;
922
	int multi_replace;
923
	size_t offset[MAX_MATCHES];
924 925 926 927
	enum { START, SECTION_SEEN, SECTION_END_SEEN, KEY_SEEN } state;
	int seen;
} store;

928
static int matches(const char *key, const char *value)
929 930 931 932 933 934 935
{
	return !strcmp(key, store.key) &&
		(store.value_regex == NULL ||
		 (store.do_not_match ^
		  !regexec(store.value_regex, value, 0, NULL, 0)));
}

936
static int store_aux(const char *key, const char *value, void *cb)
937
{
938 939 940
	const char *ep;
	size_t section_len;

941 942
	switch (store.state) {
	case KEY_SEEN:
943
		if (matches(key, value)) {
944
			if (store.seen == 1 && store.multi_replace == 0) {
945
				warning("%s has multiple values", key);
946
			} else if (store.seen >= MAX_MATCHES) {
947
				error("too many matches for %s", key);
948
				return 1;
949
			}
950 951

			store.offset[store.seen] = ftell(config_file);
952 953 954 955
			store.seen++;
		}
		break;
	case SECTION_SEEN:
956 957 958 959 960 961 962 963 964 965 966 967 968 969
		/*
		 * 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)) {
970 971
			store.state = SECTION_END_SEEN;
			break;
972 973 974 975 976 977 978
		}

		/*
		 * 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);
979 980 981
		/* fallthru */
	case SECTION_END_SEEN:
	case START:
982
		if (matches(key, value)) {
983
			store.offset[store.seen] = ftell(config_file);
984 985
			store.state = KEY_SEEN;
			store.seen++;
L
Linus Torvalds 已提交
986 987
		} else {
			if (strrchr(key, '.') - key == store.baselen &&
S
sean 已提交
988
			      !strncmp(key, store.key, store.baselen)) {
S
sean 已提交
989
					store.state = SECTION_SEEN;
S
sean 已提交
990
					store.offset[store.seen] = ftell(config_file);
L
Linus Torvalds 已提交
991
			}
S
sean 已提交
992
		}
993 994 995 996
	}
	return 0;
}

997
static int write_error(const char *filename)
998
{
999
	error("failed to write new configuration file %s", filename);
1000 1001 1002 1003 1004

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

1005
static int store_write_section(int fd, const char *key)
1006
{
1007 1008
	const char *dot;
	int i, success;
1009
	struct strbuf sb = STRBUF_INIT;
L
Linus Torvalds 已提交
1010

1011
	dot = memchr(key, '.', store.baselen);
L
Linus Torvalds 已提交
1012
	if (dot) {
1013 1014
		strbuf_addf(&sb, "[%.*s \"", (int)(dot - key), key);
		for (i = dot - key + 1; i < store.baselen; i++) {
1015
			if (key[i] == '"' || key[i] == '\\')
1016 1017
				strbuf_addch(&sb, '\\');
			strbuf_addch(&sb, key[i]);
L
Linus Torvalds 已提交
1018
		}
1019 1020 1021
		strbuf_addstr(&sb, "\"]\n");
	} else {
		strbuf_addf(&sb, "[%.*s]\n", store.baselen, key);
L
Linus Torvalds 已提交
1022 1023
	}

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

1027
	return success;
1028 1029
}

1030
static int store_write_pair(int fd, const char *key, const char *value)
1031
{
1032 1033 1034
	int i, success;
	int length = strlen(key + store.baselen + 1);
	const char *quote = "";
1035
	struct strbuf sb = STRBUF_INIT;
1036

1037 1038 1039 1040 1041 1042 1043
	/*
	 * 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.
	 */
1044
	if (value[0] == ' ')
1045
		quote = "\"";
1046 1047
	for (i = 0; value[i]; i++)
		if (value[i] == ';' || value[i] == '#')
1048 1049 1050 1051 1052 1053
			quote = "\"";
	if (i && value[i - 1] == ' ')
		quote = "\"";

	strbuf_addf(&sb, "\t%.*s = %s",
		    length, key + store.baselen + 1, quote);
1054 1055 1056

	for (i = 0; value[i]; i++)
		switch (value[i]) {
1057
		case '\n':
1058
			strbuf_addstr(&sb, "\\n");
1059 1060
			break;
		case '\t':
1061
			strbuf_addstr(&sb, "\\t");
1062 1063 1064
			break;
		case '"':
		case '\\':
1065
			strbuf_addch(&sb, '\\');
1066
		default:
1067
			strbuf_addch(&sb, value[i]);
1068 1069
			break;
		}
1070 1071 1072 1073 1074 1075
	strbuf_addf(&sb, "%s\n", quote);

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

	return success;
1076 1077
}

1078 1079
static ssize_t find_beginning_of_line(const char *contents, size_t size,
	size_t offset_, int *found_bracket)
1080
{
1081 1082
	size_t equal_offset = size, bracket_offset = size;
	ssize_t offset;
1083

1084
contline:
J
Junio C Hamano 已提交
1085
	for (offset = offset_-2; offset > 0
1086 1087 1088 1089 1090
			&& contents[offset] != '\n'; offset--)
		switch (contents[offset]) {
			case '=': equal_offset = offset; break;
			case ']': bracket_offset = offset; break;
		}
1091 1092 1093 1094
	if (offset > 0 && contents[offset-1] == '\\') {
		offset_ = offset;
		goto contline;
	}
1095 1096 1097 1098 1099 1100 1101 1102 1103
	if (bracket_offset < equal_offset) {
		*found_bracket = 1;
		offset = bracket_offset+1;
	} else
		offset++;

	return offset;
}

1104
int git_config_set(const char *key, const char *value)
1105
{
1106
	return git_config_set_multivar(key, value, NULL, 0);
1107 1108 1109 1110 1111
}

/*
 * If value==NULL, unset in (remove from) config,
 * if value_regex!=NULL, disregard key/value pairs where value does not match.
1112 1113 1114
 * 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.
1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131
 *
 * 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.
 *
 */
1132 1133
int git_config_set_multivar(const char *key, const char *value,
	const char *value_regex, int multi_replace)
1134
{
L
Linus Torvalds 已提交
1135
	int i, dot;
1136
	int fd = -1, in_fd;
1137
	int ret;
1138
	char *config_filename;
1139
	struct lock_file *lock = NULL;
1140
	const char *last_dot = strrchr(key, '.');
1141

1142 1143 1144
	if (config_exclusive_filename)
		config_filename = xstrdup(config_exclusive_filename);
	else
1145
		config_filename = git_pathdup("config");
1146

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

1152
	if (last_dot == NULL) {
1153
		error("key does not contain a section: %s", key);
1154 1155
		ret = 2;
		goto out_free;
1156
	}
1157 1158 1159
	store.baselen = last_dot - key;

	store.multi_replace = multi_replace;
1160 1161 1162 1163

	/*
	 * Validate the key and while at it, lower case it for matching.
	 */
J
Jonas Fonseca 已提交
1164
	store.key = xmalloc(strlen(key) + 1);
L
Linus Torvalds 已提交
1165 1166 1167 1168 1169 1170 1171
	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) {
1172
			if (!iskeychar(c) || (i == store.baselen+1 && !isalpha(c))) {
1173
				error("invalid key: %s", key);
L
Linus Torvalds 已提交
1174 1175 1176 1177 1178
				free(store.key);
				ret = 1;
				goto out_free;
			}
			c = tolower(c);
1179
		} else if (c == '\n') {
1180
			error("invalid key (newline): %s", key);
1181 1182 1183
			free(store.key);
			ret = 1;
			goto out_free;
L
Linus Torvalds 已提交
1184 1185 1186
		}
		store.key[i] = c;
	}
1187
	store.key[i] = 0;
1188 1189

	/*
1190
	 * The lock serves a purpose in addition to locking: the new
1191 1192
	 * contents of .git/config will be written into it.
	 */
1193 1194 1195
	lock = xcalloc(sizeof(struct lock_file), 1);
	fd = hold_lock_file_for_update(lock, config_filename, 0);
	if (fd < 0) {
A
Alex Riesen 已提交
1196
		error("could not lock config file %s: %s", config_filename, strerror(errno));
1197
		free(store.key);
1198 1199
		ret = -1;
		goto out_free;
1200 1201 1202 1203 1204
	}

	/*
	 * If .git/config does not exist yet, write a minimal version.
	 */
1205 1206
	in_fd = open(config_filename, O_RDONLY);
	if ( in_fd < 0 ) {
1207 1208
		free(store.key);

1209 1210 1211
		if ( ENOENT != errno ) {
			error("opening %s: %s", config_filename,
			      strerror(errno));
1212 1213
			ret = 3; /* same as "invalid config file" */
			goto out_free;
1214
		}
1215 1216
		/* if nothing to unset, error out */
		if (value == NULL) {
1217 1218
			ret = 5;
			goto out_free;
1219 1220
		}

1221
		store.key = (char *)key;
1222
		if (!store_write_section(fd, key) ||
1223 1224 1225
		    !store_write_pair(fd, key, value))
			goto write_err_out;
	} else {
1226
		struct stat st;
1227
		char *contents;
1228 1229
		size_t contents_sz, copy_begin, copy_end;
		int i, new_line = 0;
1230 1231 1232 1233

		if (value_regex == NULL)
			store.value_regex = NULL;
		else {
1234 1235 1236 1237 1238 1239
			if (value_regex[0] == '!') {
				store.do_not_match = 1;
				value_regex++;
			} else
				store.do_not_match = 0;

J
Jonas Fonseca 已提交
1240
			store.value_regex = (regex_t*)xmalloc(sizeof(regex_t));
1241 1242
			if (regcomp(store.value_regex, value_regex,
					REG_EXTENDED)) {
1243
				error("invalid pattern: %s", value_regex);
1244
				free(store.value_regex);
1245 1246
				ret = 6;
				goto out_free;
1247 1248 1249
			}
		}

1250
		store.offset[0] = 0;
1251 1252 1253 1254 1255 1256 1257 1258 1259
		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.
		 */
1260
		if (git_config_from_file(store_aux, config_filename, NULL)) {
1261
			error("invalid config file %s", config_filename);
1262 1263 1264 1265 1266
			free(store.key);
			if (store.value_regex != NULL) {
				regfree(store.value_regex);
				free(store.value_regex);
			}
1267 1268
			ret = 3;
			goto out_free;
1269 1270 1271 1272 1273 1274 1275 1276
		}

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

1277 1278 1279
		/* if nothing to unset, or too many matches, error out */
		if ((store.seen == 0 && value == NULL) ||
				(store.seen > 1 && multi_replace == 0)) {
1280 1281
			ret = 5;
			goto out_free;
1282 1283
		}

1284
		fstat(in_fd, &st);
1285 1286
		contents_sz = xsize_t(st.st_size);
		contents = xmmap(NULL, contents_sz, PROT_READ,
1287 1288 1289
			MAP_PRIVATE, in_fd, 0);
		close(in_fd);

1290 1291 1292 1293 1294
		if (store.seen == 0)
			store.seen = 1;

		for (i = 0, copy_begin = 0; i < store.seen; i++) {
			if (store.offset[i] == 0) {
1295
				store.offset[i] = copy_end = contents_sz;
1296 1297
			} else if (store.state != KEY_SEEN) {
				copy_end = store.offset[i];
1298
			} else
1299
				copy_end = find_beginning_of_line(
1300
					contents, contents_sz,
1301 1302
					store.offset[i]-2, &new_line);

1303 1304 1305
			if (copy_end > 0 && contents[copy_end-1] != '\n')
				new_line = 1;

1306 1307
			/* write the first part of the config */
			if (copy_end > copy_begin) {
1308 1309 1310 1311 1312
				if (write_in_full(fd, contents + copy_begin,
						  copy_end - copy_begin) <
				    copy_end - copy_begin)
					goto write_err_out;
				if (new_line &&
1313
				    write_str_in_full(fd, "\n") != 1)
1314
					goto write_err_out;
1315 1316
			}
			copy_begin = store.offset[i];
1317 1318 1319 1320
		}

		/* write the pair (value == NULL means unset) */
		if (value != NULL) {
1321 1322 1323
			if (store.state == START) {
				if (!store_write_section(fd, key))
					goto write_err_out;
1324
			}
1325 1326
			if (!store_write_pair(fd, key, value))
				goto write_err_out;
1327 1328 1329
		}

		/* write the rest of the config */
1330
		if (copy_begin < contents_sz)
1331
			if (write_in_full(fd, contents + copy_begin,
1332 1333
					  contents_sz - copy_begin) <
			    contents_sz - copy_begin)
1334
				goto write_err_out;
1335

1336
		munmap(contents, contents_sz);
1337 1338
	}

B
Brandon Casey 已提交
1339
	if (commit_lock_file(lock) < 0) {
1340
		error("could not commit config file %s", config_filename);
1341 1342
		ret = 4;
		goto out_free;
1343 1344
	}

1345 1346 1347 1348 1349 1350 1351
	/*
	 * 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;
1352 1353 1354
	ret = 0;

out_free:
1355 1356
	if (lock)
		rollback_lock_file(lock);
J
Junio C Hamano 已提交
1357
	free(config_filename);
1358
	return ret;
1359 1360

write_err_out:
1361
	ret = write_error(lock->filename);
1362 1363
	goto out_free;

1364 1365
}

1366 1367 1368
static int section_name_match (const char *buf, const char *name)
{
	int i = 0, j = 0, dot = 0;
1369 1370 1371
	if (buf[i] != '[')
		return 0;
	for (i = 1; buf[i] && buf[i] != ']'; i++) {
1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391
		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;
	}
1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402
	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;
1403 1404 1405
}

/* if new_name == NULL, the section is removed instead */
1406 1407
int git_config_rename_section(const char *old_name, const char *new_name)
{
1408
	int ret = 0, remove = 0;
1409
	char *config_filename;
1410 1411 1412 1413
	struct lock_file *lock = xcalloc(sizeof(struct lock_file), 1);
	int out_fd;
	char buf[1024];

1414 1415 1416
	if (config_exclusive_filename)
		config_filename = xstrdup(config_exclusive_filename);
	else
1417
		config_filename = git_pathdup("config");
1418
	out_fd = hold_lock_file_for_update(lock, config_filename, 0);
1419
	if (out_fd < 0) {
1420
		ret = error("could not lock config file %s", config_filename);
1421 1422
		goto out;
	}
1423

1424
	if (!(config_file = fopen(config_filename, "rb"))) {
1425 1426
		/* no config file means nothing to rename, no error */
		goto unlock_and_out;
1427
	}
1428 1429 1430

	while (fgets(buf, sizeof(buf), config_file)) {
		int i;
1431
		int length;
1432
		char *output = buf;
1433 1434 1435 1436
		for (i = 0; buf[i] && isspace(buf[i]); i++)
			; /* do nothing */
		if (buf[i] == '[') {
			/* it's a section */
1437 1438
			int offset = section_name_match(&buf[i], old_name);
			if (offset > 0) {
1439 1440 1441
				ret++;
				if (new_name == NULL) {
					remove = 1;
1442 1443 1444
					continue;
				}
				store.baselen = strlen(new_name);
1445
				if (!store_write_section(out_fd, new_name)) {
1446
					ret = write_error(lock->filename);
1447 1448
					goto out;
				}
1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464
				/*
				 * 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';
				}
1465
			}
1466
			remove = 0;
1467
		}
1468 1469
		if (remove)
			continue;
1470 1471
		length = strlen(output);
		if (write_in_full(out_fd, output, length) != length) {
1472
			ret = write_error(lock->filename);
1473 1474
			goto out;
		}
1475
	}
1476
	fclose(config_file);
1477
 unlock_and_out:
B
Brandon Casey 已提交
1478
	if (commit_lock_file(lock) < 0)
1479
		ret = error("could not commit config file %s", config_filename);
1480 1481
 out:
	free(config_filename);
1482 1483
	return ret;
}
1484 1485 1486 1487 1488 1489 1490 1491 1492

/*
 * 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);
}