mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-29 13:52:17 +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 *);
|
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
|
* 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),
|
int (*callback)(const char *var_name, const char *value, void *payload),
|
||||||
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
|
GIT_END_DECL
|
||||||
#endif
|
#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);
|
return file->set(file, name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********
|
static int parse_bool(int *out, const char *value)
|
||||||
* Getters
|
|
||||||
***********/
|
|
||||||
|
|
||||||
int git_config_get_int64(git_config *cfg, const char *name, int64_t *out)
|
|
||||||
{
|
{
|
||||||
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 */
|
/* A missing value means true */
|
||||||
if (value == NULL) {
|
if (value == NULL) {
|
||||||
*out = 1;
|
*out = 1;
|
||||||
@ -307,14 +230,161 @@ int git_config_get_bool(git_config *cfg, const char *name, int *out)
|
|||||||
return GIT_SUCCESS;
|
return GIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Try to parse it as an integer */
|
return GIT_EINVALIDTYPE;
|
||||||
error = git_config_get_int32(cfg, name, out);
|
}
|
||||||
if (error == GIT_SUCCESS)
|
|
||||||
*out = !!(*out);
|
|
||||||
|
|
||||||
|
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)
|
if (error < GIT_SUCCESS)
|
||||||
return git__rethrow(error, "Failed to get value for %s", name);
|
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)
|
int git_config_get_string(git_config *cfg, const char *name, const char **out)
|
||||||
|
Loading…
Reference in New Issue
Block a user