mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-28 08:58:41 +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