Commit 2974aa94 by Carlos Martín Nieto

Determine variable type at runtime

Config variables should be interpreted at run-time, as we don't know if a
zero means false or zero, or if yes means true or "yes".

As a variable has no intrinsic type, git_cvtype is gone and the public
API takes care of enforcing a few rules.

Signed-off-by: Carlos Martín Nieto <cmn@elego.de>
parent 2e445cac
...@@ -53,20 +53,6 @@ GIT_EXTERN(int) git_config_open(git_config **cfg_out, const char *path); ...@@ -53,20 +53,6 @@ GIT_EXTERN(int) git_config_open(git_config **cfg_out, const char *path);
GIT_EXTERN(void) git_config_free(git_config *cfg); GIT_EXTERN(void) git_config_free(git_config *cfg);
/** /**
* Get the value of an integer or boolean config variable.
*
* This is a more general function to retrieve the value of a integer
* or boolean variable.
*
* @param cfg where to look for the variable
* @param name the variable's name
* @param out pointer to the variable where the value should be stored
* @param type either GIT_VAR_INT or GIT_VAR_BOOL
* @return GIT_SUCCESS on success; error code otherwise
*/
GIT_EXTERN(int) git_config_get(git_config *cfg, const char *name, int *out, git_cvar_type type);
/**
* Get the value of an integer config variable. * Get the value of an integer config variable.
* *
* @param cfg where to look for the variable * @param cfg where to look for the variable
...@@ -74,23 +60,20 @@ GIT_EXTERN(int) git_config_get(git_config *cfg, const char *name, int *out, git_ ...@@ -74,23 +60,20 @@ GIT_EXTERN(int) git_config_get(git_config *cfg, const char *name, int *out, git_
* @param out pointer to the variable where the value should be stored * @param out pointer to the variable where the value should be stored
* @return GIT_SUCCESS on success; error code otherwise * @return GIT_SUCCESS on success; error code otherwise
*/ */
GIT_INLINE(int) git_config_get_int(git_config *cfg, const char *name, int *out) GIT_EXTERN(int) git_config_get_int(git_config *cfg, const char *name, int *out);
{
return git_config_get(cfg, name, out, GIT_VAR_INT);
}
/** /**
* Get the value of a boolean config variable. * Get the value of a boolean config variable.
* *
* This function uses the usual C convention of 0 being false and
* anything else true.
*
* @param cfg where to look for the variable * @param cfg where to look for the variable
* @param name the variable's name * @param name the variable's name
* @param out pointer to the variable where the value should be stored * @param out pointer to the variable where the value should be stored
* @return GIT_SUCCESS on success; error code otherwise * @return GIT_SUCCESS on success; error code otherwise
*/ */
GIT_INLINE(int) git_config_get_bool(git_config *cfg, const char *name, int *out) GIT_EXTERN(int) git_config_get_bool(git_config *cfg, const char *name, int *out);
{
return git_config_get(cfg, name, out, GIT_VAR_BOOL);
}
/** /**
* Get the value of a string config variable. * Get the value of a string config variable.
...@@ -104,19 +87,6 @@ GIT_INLINE(int) git_config_get_bool(git_config *cfg, const char *name, int *out) ...@@ -104,19 +87,6 @@ GIT_INLINE(int) git_config_get_bool(git_config *cfg, const char *name, int *out)
* @return GIT_SUCCESS on success; error code otherwise * @return GIT_SUCCESS on success; error code otherwise
*/ */
GIT_EXTERN(int) git_config_get_string(git_config *cfg, const char *name, const char **out); GIT_EXTERN(int) git_config_get_string(git_config *cfg, const char *name, const char **out);
/**
* Set the value of an integer or boolean config variable.
*
* This is a more general function to set the value of a integer or
* boolean variable.
*
* @param cfg where to look for the variable
* @param name the variable's name
* @param value the value to store
* @param type either GIT_VAR_INT or GIT_VAR_BOOL
* @return GIT_SUCCESS on success; error code otherwise
*/
GIT_EXTERN(int) git_config_set(git_config *cfg, const char *name, int value, git_cvar_type type);
/** /**
* Set the value of an integer config variable. * Set the value of an integer config variable.
...@@ -126,10 +96,7 @@ GIT_EXTERN(int) git_config_set(git_config *cfg, const char *name, int value, git ...@@ -126,10 +96,7 @@ GIT_EXTERN(int) git_config_set(git_config *cfg, const char *name, int value, git
* @param out pointer to the variable where the value should be stored * @param out pointer to the variable where the value should be stored
* @return GIT_SUCCESS on success; error code otherwise * @return GIT_SUCCESS on success; error code otherwise
*/ */
GIT_INLINE(int) git_config_set_int(git_config *cfg, const char *name, int value) GIT_EXTERN(int) git_config_set_int(git_config *cfg, const char *name, int value);
{
return git_config_set(cfg, name, value, GIT_VAR_INT);
}
/** /**
* Set the value of a boolean config variable. * Set the value of a boolean config variable.
...@@ -139,10 +106,7 @@ GIT_INLINE(int) git_config_set_int(git_config *cfg, const char *name, int value) ...@@ -139,10 +106,7 @@ GIT_INLINE(int) git_config_set_int(git_config *cfg, const char *name, int value)
* @param value the value to store * @param value the value to store
* @return GIT_SUCCESS on success; error code otherwise * @return GIT_SUCCESS on success; error code otherwise
*/ */
GIT_INLINE(int) git_config_set_bool(git_config *cfg, const char *name, int value) GIT_EXTERN(int) git_config_set_bool(git_config *cfg, const char *name, int value);
{
return git_config_set(cfg, name, value, GIT_VAR_BOOL);
}
/** /**
* Set the value of a string config variable. * Set the value of a string config variable.
...@@ -160,17 +124,17 @@ GIT_EXTERN(int) git_config_set_string(git_config *cfg, const char *name, const c ...@@ -160,17 +124,17 @@ GIT_EXTERN(int) git_config_set_string(git_config *cfg, const char *name, const c
/** /**
* Perform an operation on each config variable. * Perform an operation on each config variable.
* *
* The callback is passed a pointer to a config variable and the data * The callback is passed a pointer to a config variable name and the
* pointer passed to this function. As soon as one of the callback * data pointer passed to this function. As soon as one of the
* functions returns something other than 0, this function returns * callback functions returns something other than 0, this function
* that value. * returns that value.
* *
* @param cfg where to get the variables from * @param cfg where to get the variables from
* @param callback the function to call on each variable * @param callback the function to call on each variable
* @param data the data to pass to the callback * @param data the data to pass to the callback
* @return GIT_SUCCESS or the return value of the callback which didn't return 0 * @return GIT_SUCCESS or the return value of the callback which didn't return 0
*/ */
GIT_EXTERN(int) git_config_foreach(git_config *cfg, int (*callback)(git_cvar *, void *data), void *data); GIT_EXTERN(int) git_config_foreach(git_config *cfg, int (*callback)(const char *, void *data), void *data);
/** @} */ /** @} */
GIT_END_DECL GIT_END_DECL
......
...@@ -153,13 +153,6 @@ typedef enum { ...@@ -153,13 +153,6 @@ typedef enum {
GIT_REF_HAS_PEEL = 8, GIT_REF_HAS_PEEL = 8,
} git_rtype; } git_rtype;
/** Config variable type */
typedef enum {
GIT_VAR_INT, /** Stores an integer value */
GIT_VAR_BOOL, /** Stores a boolean value */
GIT_VAR_STR /** Stores a string */
} git_cvar_type;
/** @} */ /** @} */
GIT_END_DECL GIT_END_DECL
......
...@@ -39,10 +39,8 @@ void git_config_free(git_config *cfg); ...@@ -39,10 +39,8 @@ void git_config_free(git_config *cfg);
static void cvar_free(git_cvar *var) static void cvar_free(git_cvar *var)
{ {
if(var->type == GIT_VAR_STR)
free(var->value.string);
free(var->name); free(var->name);
free(var->value);
free(var); free(var);
} }
...@@ -133,26 +131,28 @@ void git_config_free(git_config *cfg) ...@@ -133,26 +131,28 @@ void git_config_free(git_config *cfg)
* Loop over all the variables * Loop over all the variables
*/ */
int git_config_foreach(git_config *cfg, int (*fn)(git_cvar *, void *), void *data) int git_config_foreach(git_config *cfg, int (*fn)(const char *, void *), void *data)
{ {
int ret = GIT_SUCCESS; int ret = GIT_SUCCESS;
git_cvar *var; git_cvar *var;
void *_unused; const void *_unused;
GIT_HASHTABLE_FOREACH(cfg->vars, _unused, var, GIT_HASHTABLE_FOREACH(cfg->vars, _unused, var,
ret = fn(var, data); ret = fn(var->name, data);
if(ret) break; if(ret) break;
); );
return ret; return ret;
} }
/* /**************
* Setters * Setters
*/ **************/
int git_config_set(git_config *cfg, const char *name, /*
int value, git_cvar_type type) * Internal function to actually set the string value of a variable
*/
static int config_set(git_config *cfg, const char *name, const char *value)
{ {
git_cvar *var = NULL; git_cvar *var = NULL;
int error = GIT_SUCCESS; int error = GIT_SUCCESS;
...@@ -170,11 +170,12 @@ int git_config_set(git_config *cfg, const char *name, ...@@ -170,11 +170,12 @@ int git_config_set(git_config *cfg, const char *name,
goto out; goto out;
} }
var->type = type; var->value = git__strdup(value);
if(type == GIT_VAR_BOOL) if(var->value == NULL){
var->value.boolean = value; error = GIT_ENOMEM;
else cvar_free(var);
var->value.integer = value; goto out;
}
error = git_hashtable_insert(cfg->vars, var->name, var); error = git_hashtable_insert(cfg->vars, var->name, var);
if(error < GIT_SUCCESS) if(error < GIT_SUCCESS)
...@@ -184,84 +185,123 @@ int git_config_set(git_config *cfg, const char *name, ...@@ -184,84 +185,123 @@ int git_config_set(git_config *cfg, const char *name,
return error; return error;
} }
int git_config_set_string(git_config *cfg, const char *name, const char *value) int git_config_set_int(git_config *cfg, const char *name, int value)
{ {
git_cvar *var = NULL; char str_value[5]; /* Most numbers should fit in here */
int error = GIT_SUCCESS; int buf_len = sizeof(str_value), ret;
char *help_buf;
var = git__malloc(sizeof(git_cvar));
if(var == NULL){ if((ret = snprintf(str_value, buf_len, "%d", value)) >= buf_len - 1){
error = GIT_ENOMEM; /* The number is too large, we need to allocate more memory */
goto out; buf_len = ret + 1;
help_buf = git__malloc(buf_len);
snprintf(help_buf, buf_len, "%d", value);
} }
var->name = git__strdup(name); return config_set(cfg, name, str_value);
if(var->name == NULL){ }
error = GIT_ENOMEM;
free(var);
goto out;
}
var->value.string = git__strdup(value); int git_config_set_bool(git_config *cfg, const char *name, int value)
if(var->value.string == NULL){ {
error = GIT_ENOMEM; const char *str_value;
cvar_free(var);
goto out;
}
var->type = GIT_VAR_STR; if(value == 0)
str_value = "false";
else
str_value = "true";
error = git_hashtable_insert(cfg->vars, var->name, var); return config_set(cfg, name, str_value);
if(error < GIT_SUCCESS) }
cvar_free(var);
out: int git_config_set_string(git_config *cfg, const char *name, const char *value)
return error; {
return config_set(cfg, name, value);
} }
/***********
* Getters
***********/
/* /*
* Get a config variable's data. * Internal function that actually gets the value in string form
*/ */
int git_config_get(git_config *cfg, const char *name, static int config_get(git_config *cfg, const char *name, const char **out)
int *out, git_cvar_type type)
{ {
git_cvar *var; git_cvar *var;
int error = GIT_SUCCESS; int error = GIT_SUCCESS;
var = git_hashtable_lookup(cfg->vars, name); var = git_hashtable_lookup(cfg->vars, name);
if (var == NULL) { if (var == NULL)
error = GIT_ENOTFOUND; return GIT_ENOTFOUND;
} else {
if (var->type == type) *out = var->value;
*out = type == GIT_VAR_INT ?
var->value.integer : var->value.boolean; return error;
}
int git_config_get_int(git_config *cfg, const char *name, int *out)
{
const char *value;
int ret;
ret = config_get(cfg, name, &value);
if(ret < GIT_SUCCESS)
return ret;
ret = sscanf(value, "%d", out);
if (ret == 0) /* No items were matched i.e. value isn't a number */
return GIT_EINVALIDTYPE;
if (ret < 0) {
if (errno == EINVAL) /* Format was NULL */
return GIT_EINVALIDTYPE;
else else
error = GIT_EINVALIDTYPE; return GIT_EOSERR;
} }
return error;
return GIT_SUCCESS;
} }
int git_config_get_string(git_config *cfg, const char *name, const char **out) int git_config_get_bool(git_config *cfg, const char *name, int *out)
{ {
git_cvar *var; const char *value;
int error = GIT_SUCCESS; int error = GIT_SUCCESS;
var = git_hashtable_lookup(cfg->vars, name); error = config_get(cfg, name, &value);
if (var == NULL) { if (error < GIT_SUCCESS)
error = GIT_ENOTFOUND; return error;
goto out;
} else if (var->type != GIT_VAR_STR) { /* A missing value means true */
error = GIT_EINVALIDTYPE; if (value == NULL) {
goto out; *out = 1;
return GIT_SUCCESS;
} }
*out = var->value.string; if (!strcasecmp(value, "true") ||
!strcasecmp(value, "yes") ||
!strcasecmp(value, "on")){
*out = 1;
return GIT_SUCCESS;
}
if (!strcasecmp(value, "false") ||
!strcasecmp(value, "no") ||
!strcasecmp(value, "off")){
*out = 0;
return GIT_SUCCESS;
}
/* Try to parse it as an integer */
error = git_config_get_int(cfg, name, out);
if (error == GIT_SUCCESS)
*out = !!(*out);
out:
return error; return error;
} }
int git_config_get_string(git_config *cfg, const char *name, const char **out)
{
return config_get(cfg, name, out);
}
static int cfg_getchar_raw(git_config *cfg) static int cfg_getchar_raw(git_config *cfg)
{ {
int c; int c;
......
...@@ -17,13 +17,8 @@ struct git_config { ...@@ -17,13 +17,8 @@ struct git_config {
}; };
struct git_cvar { struct git_cvar {
git_cvar_type type;
char *name; char *name;
union { char *value;
unsigned char boolean;
long integer;
char *string;
} value;
}; };
#endif #endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment