Unfortunate people may have to use $GIT_DIR/config edited on DOSsy machine on UNIXy machine. Ignore '\r' immediately followed by '\n'. Signed-off-by: Junio C Hamano <junkio@cox.net>
		
			
				
	
	
		
			245 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			245 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
 | 
						|
#include "cache.h"
 | 
						|
 | 
						|
#define MAXNAME (256)
 | 
						|
 | 
						|
static FILE *config_file;
 | 
						|
static int config_linenr;
 | 
						|
static int get_next_char(void)
 | 
						|
{
 | 
						|
	int c;
 | 
						|
	FILE *f;
 | 
						|
 | 
						|
	c = '\n';
 | 
						|
	if ((f = config_file) != NULL) {
 | 
						|
		c = fgetc(f);
 | 
						|
		if (c == '\r') {
 | 
						|
			/* DOS like systems */
 | 
						|
			c = fgetc(f);
 | 
						|
			if (c != '\n') {
 | 
						|
				ungetc(c, f);
 | 
						|
				c = '\r';
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if (c == '\n')
 | 
						|
			config_linenr++;
 | 
						|
		if (c == EOF) {
 | 
						|
			config_file = NULL;
 | 
						|
			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;
 | 
						|
		}
 | 
						|
		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;
 | 
						|
			/* Some characters escape as themselves */
 | 
						|
			case '\\': case '"':
 | 
						|
				break;
 | 
						|
			/* Reject unknown escape sequences */
 | 
						|
			default:
 | 
						|
				return NULL;
 | 
						|
			}
 | 
						|
			value[len++] = c;
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
		if (c == '"') {
 | 
						|
			quote = 1-quote;
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
		if (!quote) {
 | 
						|
			if (c == ';' || c == '#') {
 | 
						|
				comment = 1;
 | 
						|
				continue;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		value[len++] = c;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static int get_value(config_fn_t fn, char *name, unsigned int len)
 | 
						|
{
 | 
						|
	int c;
 | 
						|
	char *value;
 | 
						|
 | 
						|
	/* Get the full name */
 | 
						|
	for (;;) {
 | 
						|
		c = get_next_char();
 | 
						|
		if (c == EOF)
 | 
						|
			break;
 | 
						|
		if (!isalnum(c))
 | 
						|
			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;
 | 
						|
	}
 | 
						|
	return fn(name, value);
 | 
						|
}
 | 
						|
 | 
						|
static int get_base_var(char *name)
 | 
						|
{
 | 
						|
	int baselen = 0;
 | 
						|
 | 
						|
	for (;;) {
 | 
						|
		int c = get_next_char();
 | 
						|
		if (c == EOF)
 | 
						|
			return -1;
 | 
						|
		if (c == ']')
 | 
						|
			return baselen;
 | 
						|
		if (!isalnum(c))
 | 
						|
			return -1;
 | 
						|
		if (baselen > MAXNAME / 2)
 | 
						|
			return -1;
 | 
						|
		name[baselen++] = tolower(c);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static int git_parse_file(config_fn_t fn)
 | 
						|
{
 | 
						|
	int comment = 0;
 | 
						|
	int baselen = 0;
 | 
						|
	static char var[MAXNAME];
 | 
						|
 | 
						|
	for (;;) {
 | 
						|
		int c = get_next_char();
 | 
						|
		if (c == '\n') {
 | 
						|
			/* EOF? */
 | 
						|
			if (!config_file)
 | 
						|
				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;
 | 
						|
		var[baselen] = tolower(c);
 | 
						|
		if (get_value(fn, var, baselen+1) < 0)
 | 
						|
			break;
 | 
						|
	}
 | 
						|
	die("bad config file line %d", config_linenr);
 | 
						|
}
 | 
						|
 | 
						|
int git_config_int(const char *name, const char *value)
 | 
						|
{
 | 
						|
	if (value && *value) {
 | 
						|
		char *end;
 | 
						|
		int val = strtol(value, &end, 0);
 | 
						|
		if (!*end)
 | 
						|
			return val;
 | 
						|
	}
 | 
						|
	die("bad config value for '%s'", name);
 | 
						|
}
 | 
						|
 | 
						|
int git_config_bool(const char *name, const char *value)
 | 
						|
{
 | 
						|
	if (!value)
 | 
						|
		return 1;
 | 
						|
	if (!*value)
 | 
						|
		return 0;
 | 
						|
	if (!strcasecmp(value, "true"))
 | 
						|
		return 1;
 | 
						|
	if (!strcasecmp(value, "false"))
 | 
						|
		return 0;
 | 
						|
	return git_config_int(name, value) != 0;
 | 
						|
}
 | 
						|
 | 
						|
int git_default_config(const char *var, const char *value)
 | 
						|
{
 | 
						|
	/* This needs a better name */
 | 
						|
	if (!strcmp(var, "core.filemode")) {
 | 
						|
		trust_executable_bit = git_config_bool(var, value);
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
 | 
						|
	if (!strcmp(var, "user.name")) {
 | 
						|
		strncpy(git_default_name, value, sizeof(git_default_name));
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
 | 
						|
	if (!strcmp(var, "user.email")) {
 | 
						|
		strncpy(git_default_email, value, sizeof(git_default_email));
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
 | 
						|
	/* Add other config variables here.. */
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
int git_config(config_fn_t fn)
 | 
						|
{
 | 
						|
	int ret;
 | 
						|
	FILE *f = fopen(git_path("config"), "r");
 | 
						|
 | 
						|
	ret = -1;
 | 
						|
	if (f) {
 | 
						|
		config_file = f;
 | 
						|
		config_linenr = 1;
 | 
						|
		ret = git_parse_file(fn);
 | 
						|
		fclose(f);
 | 
						|
	}
 | 
						|
	return ret;
 | 
						|
}
 |