mirror of
				https://git.proxmox.com/git/libgit2
				synced 2025-11-04 13:35:31 +00:00 
			
		
		
		
	config: Refactor & add git_config_get_mapped
				
					
				
			Sane API for real-world usage.
This commit is contained in:
		
							parent
							
								
									27950fa3f4
								
							
						
					
					
						commit
						c5e944820a
					
				@ -37,6 +37,19 @@ struct git_config_file {
 | 
			
		||||
	void (*free)(struct git_config_file *);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
	GIT_CVAR_FALSE = 0,
 | 
			
		||||
	GIT_CVAR_TRUE = 1,
 | 
			
		||||
	GIT_CVAR_INT32,
 | 
			
		||||
	GIT_CVAR_STRING
 | 
			
		||||
} git_cvar_t;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
	git_cvar_t cvar_type;
 | 
			
		||||
	const char *str_match;
 | 
			
		||||
	int map_value;
 | 
			
		||||
} git_cvar_map;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Locate the path to the global configuration file
 | 
			
		||||
 *
 | 
			
		||||
@ -301,6 +314,43 @@ GIT_EXTERN(int) git_config_foreach(
 | 
			
		||||
	int (*callback)(const char *var_name, const char *value, void *payload),
 | 
			
		||||
	void *payload);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Query the value of a config variable and return it mapped to
 | 
			
		||||
 * an integer constant.
 | 
			
		||||
 *
 | 
			
		||||
 * This is a helper method to easily map different possible values
 | 
			
		||||
 * to a variable to integer constants that easily identify them.
 | 
			
		||||
 *
 | 
			
		||||
 * A mapping array looks as follows:
 | 
			
		||||
 *
 | 
			
		||||
 *	git_cvar_map autocrlf_mapping[3] = {
 | 
			
		||||
 *		{GIT_CVAR_FALSE, NULL, GIT_AUTO_CRLF_FALSE},
 | 
			
		||||
 *		{GIT_CVAR_TRUE, NULL, GIT_AUTO_CRLF_TRUE},
 | 
			
		||||
 *		{GIT_CVAR_STRING, "input", GIT_AUTO_CRLF_INPUT},
 | 
			
		||||
 *		{GIT_CVAR_STRING, "default", GIT_AUTO_CRLF_DEFAULT}};
 | 
			
		||||
 *
 | 
			
		||||
 * On any "false" value for the variable (e.g. "false", "FALSE", "no"), the
 | 
			
		||||
 * mapping will store `GIT_AUTO_CRLF_FALSE` in the `out` parameter.
 | 
			
		||||
 *
 | 
			
		||||
 * The same thing applies for any "true" value such as "true", "yes" or "1", storing
 | 
			
		||||
 * the `GIT_AUTO_CRLF_TRUE` variable.
 | 
			
		||||
 *
 | 
			
		||||
 * Otherwise, if the value matches the string "input" (with case insensitive comparison),
 | 
			
		||||
 * the given constant will be stored in `out`, and likewise for "default".
 | 
			
		||||
 *
 | 
			
		||||
 * If not a single match can be made to store in `out`, an error code will be
 | 
			
		||||
 * returned.
 | 
			
		||||
 *
 | 
			
		||||
 * @param cfg config file to get the variables from
 | 
			
		||||
 * @param name name of the config variable to lookup
 | 
			
		||||
 * @param maps array of `git_cvar_map` objects specifying the possible mappings
 | 
			
		||||
 * @param map_n number of mapping objects in `maps`
 | 
			
		||||
 * @param out place to store the result of the mapping
 | 
			
		||||
 * @return GIT_SUCCESS on success, error code otherwise
 | 
			
		||||
 */
 | 
			
		||||
GIT_EXTERN(int) git_config_get_mapped(git_config *cfg, const char *name, git_cvar_map *maps, size_t map_n, int *out);
 | 
			
		||||
 | 
			
		||||
/** @} */
 | 
			
		||||
GIT_END_DECL
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										236
									
								
								src/config.c
									
									
									
									
									
								
							
							
						
						
									
										236
									
								
								src/config.c
									
									
									
									
									
								
							@ -209,85 +209,8 @@ int git_config_set_string(git_config *cfg, const char *name, const char *value)
 | 
			
		||||
	return file->set(file, name, value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/***********
 | 
			
		||||
 * Getters
 | 
			
		||||
 ***********/
 | 
			
		||||
 | 
			
		||||
int git_config_get_int64(git_config *cfg, const char *name, int64_t *out)
 | 
			
		||||
static int parse_bool(int *out, const char *value)
 | 
			
		||||
{
 | 
			
		||||
	const char *value, *num_end;
 | 
			
		||||
	int ret;
 | 
			
		||||
	int64_t num;
 | 
			
		||||
 | 
			
		||||
	ret = git_config_get_string(cfg, name, &value);
 | 
			
		||||
	if (ret < GIT_SUCCESS)
 | 
			
		||||
		return git__rethrow(ret, "Failed to retrieve value for '%s'", name);
 | 
			
		||||
 | 
			
		||||
	ret = git__strtol64(&num, value, &num_end, 0);
 | 
			
		||||
	if (ret < GIT_SUCCESS)
 | 
			
		||||
		return git__rethrow(ret, "Failed to convert value for '%s'", name);
 | 
			
		||||
 | 
			
		||||
	switch (*num_end) {
 | 
			
		||||
	case 'g':
 | 
			
		||||
	case 'G':
 | 
			
		||||
		num *= 1024;
 | 
			
		||||
		/* fallthrough */
 | 
			
		||||
 | 
			
		||||
	case 'm':
 | 
			
		||||
	case 'M':
 | 
			
		||||
		num *= 1024;
 | 
			
		||||
		/* fallthrough */
 | 
			
		||||
 | 
			
		||||
	case 'k':
 | 
			
		||||
	case 'K':
 | 
			
		||||
		num *= 1024;
 | 
			
		||||
 | 
			
		||||
		/* check that that there are no more characters after the
 | 
			
		||||
		 * given modifier suffix */
 | 
			
		||||
		if (num_end[1] != '\0')
 | 
			
		||||
			return git__throw(GIT_EINVALIDTYPE,
 | 
			
		||||
				"Failed to get value for '%s'. Invalid type suffix", name);
 | 
			
		||||
 | 
			
		||||
		/* fallthrough */
 | 
			
		||||
 | 
			
		||||
	case '\0':
 | 
			
		||||
		*out = num;
 | 
			
		||||
		return GIT_SUCCESS;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		return git__throw(GIT_EINVALIDTYPE,
 | 
			
		||||
			"Failed to get value for '%s'. Value is of invalid type", name);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int git_config_get_int32(git_config *cfg, const char *name, int32_t *out)
 | 
			
		||||
{
 | 
			
		||||
	int64_t tmp_long;
 | 
			
		||||
	int32_t tmp_int;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	ret = git_config_get_int64(cfg, name, &tmp_long);
 | 
			
		||||
	if (ret < GIT_SUCCESS)
 | 
			
		||||
		return git__rethrow(ret, "Failed to convert value for '%s'", name);
 | 
			
		||||
	
 | 
			
		||||
	tmp_int = tmp_long & 0xFFFFFFFF;
 | 
			
		||||
	if (tmp_int != tmp_long)
 | 
			
		||||
		return git__throw(GIT_EOVERFLOW, "Value for '%s' is too large", name);
 | 
			
		||||
 | 
			
		||||
	*out = tmp_int;
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int git_config_get_bool(git_config *cfg, const char *name, int *out)
 | 
			
		||||
{
 | 
			
		||||
	const char *value;
 | 
			
		||||
	int error = GIT_SUCCESS;
 | 
			
		||||
 | 
			
		||||
	error = git_config_get_string(cfg, name, &value);
 | 
			
		||||
	if (error < GIT_SUCCESS)
 | 
			
		||||
		return git__rethrow(error, "Failed to get value for %s", name);
 | 
			
		||||
 | 
			
		||||
	/* A missing value means true */
 | 
			
		||||
	if (value == NULL) {
 | 
			
		||||
		*out = 1;
 | 
			
		||||
@ -307,14 +230,161 @@ int git_config_get_bool(git_config *cfg, const char *name, int *out)
 | 
			
		||||
		return GIT_SUCCESS;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Try to parse it as an integer */
 | 
			
		||||
	error = git_config_get_int32(cfg, name, out);
 | 
			
		||||
	if (error == GIT_SUCCESS)
 | 
			
		||||
		*out = !!(*out);
 | 
			
		||||
	return GIT_EINVALIDTYPE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int parse_int64(int64_t *out, const char *value)
 | 
			
		||||
{
 | 
			
		||||
	const char *num_end;
 | 
			
		||||
	int64_t num;
 | 
			
		||||
 | 
			
		||||
	if (git__strtol64(&num, value, &num_end, 0) < 0)
 | 
			
		||||
		return GIT_EINVALIDTYPE;
 | 
			
		||||
 | 
			
		||||
	switch (*num_end) {
 | 
			
		||||
	case 'g':
 | 
			
		||||
	case 'G':
 | 
			
		||||
		num *= 1024;
 | 
			
		||||
		/* fallthrough */
 | 
			
		||||
 | 
			
		||||
	case 'm':
 | 
			
		||||
	case 'M':
 | 
			
		||||
		num *= 1024;
 | 
			
		||||
		/* fallthrough */
 | 
			
		||||
 | 
			
		||||
	case 'k':
 | 
			
		||||
	case 'K':
 | 
			
		||||
		num *= 1024;
 | 
			
		||||
 | 
			
		||||
		/* check that that there are no more characters after the
 | 
			
		||||
		 * given modifier suffix */
 | 
			
		||||
		if (num_end[1] != '\0')
 | 
			
		||||
			return GIT_EINVALIDTYPE;
 | 
			
		||||
 | 
			
		||||
		/* fallthrough */
 | 
			
		||||
 | 
			
		||||
	case '\0':
 | 
			
		||||
		*out = num;
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		return GIT_EINVALIDTYPE;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int parse_int32(int32_t *out, const char *value)
 | 
			
		||||
{
 | 
			
		||||
	int64_t tmp;
 | 
			
		||||
	int32_t truncate;
 | 
			
		||||
 | 
			
		||||
	if (parse_int64(&tmp, value) < 0)
 | 
			
		||||
		return GIT_EINVALIDTYPE;
 | 
			
		||||
 | 
			
		||||
	truncate = tmp & 0xFFFFFFFF;
 | 
			
		||||
	if (truncate != tmp)
 | 
			
		||||
		return GIT_EOVERFLOW;
 | 
			
		||||
 | 
			
		||||
	*out = truncate;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/***********
 | 
			
		||||
 * Getters
 | 
			
		||||
 ***********/
 | 
			
		||||
int git_config_get_mapped(git_config *cfg, const char *name, git_cvar_map *maps, size_t map_n, int *out)
 | 
			
		||||
{
 | 
			
		||||
	size_t i;
 | 
			
		||||
	const char *value;
 | 
			
		||||
	int error;
 | 
			
		||||
 | 
			
		||||
	error = git_config_get_string(cfg, name, &value);
 | 
			
		||||
	if (error < GIT_SUCCESS)
 | 
			
		||||
		return error;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < map_n; ++i) {
 | 
			
		||||
		git_cvar_map *m = maps + i;
 | 
			
		||||
 | 
			
		||||
		switch (m->cvar_type) {
 | 
			
		||||
			case GIT_CVAR_FALSE:
 | 
			
		||||
			case GIT_CVAR_TRUE: {
 | 
			
		||||
				int bool_val;
 | 
			
		||||
 | 
			
		||||
				if (parse_bool(&bool_val, value) == 0 && 
 | 
			
		||||
					bool_val == (int)m->cvar_type) {
 | 
			
		||||
					*out = m->map_value;
 | 
			
		||||
					return 0;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			case GIT_CVAR_INT32:
 | 
			
		||||
				if (parse_int32(out, value) == 0)
 | 
			
		||||
					return 0;
 | 
			
		||||
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case GIT_CVAR_STRING:
 | 
			
		||||
				if (strcasecmp(value, m->str_match) == 0) {
 | 
			
		||||
					*out = m->map_value;
 | 
			
		||||
					return 0;
 | 
			
		||||
				}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return git__throw(GIT_ENOTFOUND,
 | 
			
		||||
		"Failed to map the '%s' config variable with a valid value", name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int git_config_get_int64(git_config *cfg, const char *name, int64_t *out)
 | 
			
		||||
{
 | 
			
		||||
	const char *value;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	ret = git_config_get_string(cfg, name, &value);
 | 
			
		||||
	if (ret < GIT_SUCCESS)
 | 
			
		||||
		return git__rethrow(ret, "Failed to retrieve value for '%s'", name);
 | 
			
		||||
 | 
			
		||||
	if (parse_int64(out, value) < 0)
 | 
			
		||||
		return git__throw(GIT_EINVALIDTYPE, "Failed to parse '%s' as an integer", value);
 | 
			
		||||
 | 
			
		||||
	return GIT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int git_config_get_int32(git_config *cfg, const char *name, int32_t *out)
 | 
			
		||||
{
 | 
			
		||||
	const char *value;
 | 
			
		||||
	int error;
 | 
			
		||||
 | 
			
		||||
	error = git_config_get_string(cfg, name, &value);
 | 
			
		||||
	if (error < GIT_SUCCESS)
 | 
			
		||||
		return git__rethrow(error, "Failed to get value for %s", name);
 | 
			
		||||
	return error;
 | 
			
		||||
 | 
			
		||||
	error = parse_int32(out, value);
 | 
			
		||||
	if (error < GIT_SUCCESS)
 | 
			
		||||
		return git__throw(GIT_EINVALIDTYPE, "Failed to parse '%s' as a 32-bit integer", value);
 | 
			
		||||
	
 | 
			
		||||
	return GIT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int git_config_get_bool(git_config *cfg, const char *name, int *out)
 | 
			
		||||
{
 | 
			
		||||
	const char *value;
 | 
			
		||||
	int error = GIT_SUCCESS;
 | 
			
		||||
 | 
			
		||||
	error = git_config_get_string(cfg, name, &value);
 | 
			
		||||
	if (error < GIT_SUCCESS)
 | 
			
		||||
		return git__rethrow(error, "Failed to get value for %s", name);
 | 
			
		||||
 | 
			
		||||
	if (parse_bool(out, value) == 0)
 | 
			
		||||
		return GIT_SUCCESS;
 | 
			
		||||
 | 
			
		||||
	if (parse_int32(out, value) == 0) {
 | 
			
		||||
		*out = !!(*out);
 | 
			
		||||
		return GIT_SUCCESS;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return git__throw(GIT_EINVALIDTYPE, "Failed to parse '%s' as a boolean value", value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int git_config_get_string(git_config *cfg, const char *name, const char **out)
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user