From 468ebea67beec7215506125c5a4fbad35e12adc3 Mon Sep 17 00:00:00 2001 From: Dmitri Pal Date: Thu, 11 Mar 2010 12:28:40 -0500 Subject: Fixing type conversion in INI interface. Additional changes. --- ini/ini_config.c | 213 ++++++++++++++++++++++++++++++++++++++++++++-------- ini/ini_config.h | 18 ++++- ini/ini_config_ut.c | 1 + 3 files changed, 197 insertions(+), 35 deletions(-) diff --git a/ini/ini_config.c b/ini/ini_config.c index f9461a7..e87419a 100644 --- a/ini/ini_config.c +++ b/ini/ini_config.c @@ -239,9 +239,13 @@ static int ini_to_collection(FILE *file, switch (status) { case RET_PAIR: - /* Add line to the collection of lines */ + /* Add line to the collection of lines. + * It is pretty safe in this case to just type cast the value to + * int32_t since it is unrealistic that ini file will ever have + * so many lines. + */ if (lines) { - error = col_add_int_property(*lines, NULL, key, line); + error = col_add_int_property(*lines, NULL, key, (int32_t)line); if (error) { TRACE_ERROR_NUMBER("Failed to add line to line collection", error); fclose(file); @@ -308,8 +312,11 @@ static int ini_to_collection(FILE *file, if (lines) { /* For easier search make line numbers for the sections negative. * This would allow differentiating sections and attributes. + * It is pretty safe in this case to just type cast the value to + * int32_t since it is unrealistic that ini file will ever have + * so many lines. */ - error = col_add_int_property(*lines, NULL, key, -1 * line); + error = col_add_int_property(*lines, NULL, key, (int32_t)(-1 * line)); if (error) { TRACE_ERROR_NUMBER("Failed to add line to line collection", error); fclose(file); @@ -1275,13 +1282,16 @@ int get_config_item(const char *section, return error; } -/* Get long value from config item */ -long get_long_config_value(struct collection_item *item, - int strict, long def, int *error) +/* Get long long value from config item */ +static long long get_llong_config_value(struct collection_item *item, + int strict, + long long def, + int *error) { + int err; const char *str; char *endptr; - long val = 0; + long long val = 0; TRACE_FLOW_STRING("get_long_config_value", "Entry"); @@ -1298,50 +1308,179 @@ long get_long_config_value(struct collection_item *item, /* Try to parse the value */ str = (const char *)col_get_item_data(item); errno = 0; - val = strtol(str, &endptr, 10); + val = strtoll(str, &endptr, 10); + err = errno; /* Check for various possible errors */ - if (((errno == ERANGE) && - ((val == LONG_MAX) || - (val == LONG_MIN))) || - ((errno != 0) && (val == 0)) || - (endptr == str)) { - TRACE_ERROR_NUMBER("Conversion failed", EIO); + if (err != 0) { + TRACE_ERROR_NUMBER("Conversion failed", err); + if (error) *error = err; + return def; + } + + /* Other error cases */ + if ((endptr == str) || (strict && (*endptr != '\0'))) { + TRACE_ERROR_NUMBER("More characters or nothing processed", EIO); if (error) *error = EIO; return def; } - if (strict && (*endptr != '\0')) { - TRACE_ERROR_NUMBER("More characters than expected", EIO); + TRACE_FLOW_NUMBER("get_long_config_value returning", (long)val); + return val; +} + +/* Get unsigned long long value from config item */ +static unsigned long long get_ullong_config_value(struct collection_item *item, + int strict, + unsigned long long def, + int *error) +{ + int err; + const char *str; + char *endptr; + unsigned long long val = 0; + + TRACE_FLOW_STRING("get_long_config_value", "Entry"); + + /* Do we have the item ? */ + if ((item == NULL) || + (col_get_item_type(item) != COL_TYPE_STRING)) { + TRACE_ERROR_NUMBER("Invalid argument.", EINVAL); + if (error) *error = EINVAL; + return def; + } + + if (error) *error = EOK; + + /* Try to parse the value */ + str = (const char *)col_get_item_data(item); + errno = 0; + val = strtoull(str, &endptr, 10); + err = errno; + + /* Check for various possible errors */ + if (err != 0) { + TRACE_ERROR_NUMBER("Conversion failed", err); + if (error) *error = err; + return def; + } + + /* Other error cases */ + if ((endptr == str) || (strict && (*endptr != '\0'))) { + TRACE_ERROR_NUMBER("More characters or nothing processed", EIO); if (error) *error = EIO; - val = def; + return def; } - TRACE_FLOW_NUMBER("get_long_config_value returning", val); + TRACE_FLOW_NUMBER("get_long_config_value returning", (long)val); return val; } + /* Get integer value from config item */ int get_int_config_value(struct collection_item *item, - int strict, int def, int *error) + int strict, + int def, + int *error) { - return get_long_config_value(item, strict, def, error); + long long val = 0; + int err = 0; + + TRACE_FLOW_STRING("get_int_config_value", "Entry"); + + val = get_llong_config_value(item, strict, def, &err); + if (err == 0) { + if ((val > INT_MAX) || (val < INT_MIN)) { + val = def; + err = ERANGE; + } + } + + if (error) *error = err; + + TRACE_FLOW_NUMBER("get_int_config_value returning", (int)val); + return (int)val; } /* Get unsigned integer value from config item */ unsigned get_unsigned_config_value(struct collection_item *item, - int strict, unsigned def, int *error) + int strict, + unsigned def, + int *error) { - return get_long_config_value(item, strict, def, error); + unsigned long long val = 0; + int err = 0; + + TRACE_FLOW_STRING("get_unsigned_config_value", "Entry"); + + val = get_ullong_config_value(item, strict, def, &err); + if (err == 0) { + if (val > UINT_MAX) { + val = def; + err = ERANGE; + } + } + + if (error) *error = err; + + TRACE_FLOW_NUMBER("get_unsigned_config_value returning", + (unsigned)val); + return (unsigned)val; +} + +/* Get long value from config item */ +long get_long_config_value(struct collection_item *item, + int strict, + long def, + int *error) +{ + long long val = 0; + int err = 0; + + TRACE_FLOW_STRING("get_long_config_value", "Entry"); + + val = get_llong_config_value(item, strict, def, &err); + if (err == 0) { + if ((val > LONG_MAX) || (val < LONG_MIN)) { + val = def; + err = ERANGE; + } + } + + if (error) *error = err; + + TRACE_FLOW_NUMBER("get_long_config_value returning", + (long)val); + return (long)val; } /* Get unsigned long value from config item */ unsigned long get_ulong_config_value(struct collection_item *item, - int strict, unsigned long def, int *error) + int strict, + unsigned long def, + int *error) { - return get_long_config_value(item, strict, def, error); + unsigned long long val = 0; + int err = 0; + + TRACE_FLOW_STRING("get_ulong_config_value", "Entry"); + + val = get_ullong_config_value(item, strict, def, &err); + if (err == 0) { + if (val > ULONG_MAX) { + val = def; + err = ERANGE; + } + } + + if (error) *error = err; + + TRACE_FLOW_NUMBER("get_ulong_config_value returning", + (unsigned long)val); + return (unsigned long)val; } + /* Get double value */ double get_double_config_value(struct collection_item *item, int strict, double def, int *error) @@ -1725,7 +1864,11 @@ void free_string_config_array(char **str_config) TRACE_FLOW_STRING("free_string_config_array", "Exit"); } -/* Get an array of long values */ +/* Get an array of long values. + * NOTE: For now I leave just one function that returns numeric arrays. + * In future if we need other numeric types we can change it to do strtoll + * internally and wrap it for backward compatibility. + */ long *get_long_config_array(struct collection_item *item, int *size, int *error) { const char *str; @@ -1733,6 +1876,7 @@ long *get_long_config_array(struct collection_item *item, int *size, int *error) long val = 0; long *array; int count = 0; + int err; TRACE_FLOW_STRING("get_long_config_array", "Entry"); @@ -1756,18 +1900,25 @@ long *get_long_config_array(struct collection_item *item, int *size, int *error) /* Now parse the string */ str = (const char *)col_get_item_data(item); while (*str) { + errno = 0; val = strtol(str, &endptr, 10); - if (((errno == ERANGE) && - ((val == LONG_MAX) || - (val == LONG_MIN))) || - ((errno != 0) && (val == 0)) || - (endptr == str)) { - TRACE_ERROR_NUMBER("Conversion failed", EIO); + err = errno; + + if (err) { + TRACE_ERROR_NUMBER("Conversion failed", err); + free(array); + if (error) *error = err; + return NULL; + } + + if (endptr == str) { + TRACE_ERROR_NUMBER("Nothing processed", EIO); free(array); if (error) *error = EIO; return NULL; } + /* Save value */ array[count] = val; count++; diff --git a/ini/ini_config.h b/ini/ini_config.h index 9072203..da8227b 100644 --- a/ini/ini_config.h +++ b/ini/ini_config.h @@ -1040,6 +1040,10 @@ void free_bin_config_value(char *bin); * Size and error parameters can be NULL. * Use \ref free_string_config_array() to free the array after use. * + * The array is always NULL terminated so + * it is safe not to get size and just loop until + * array element is NULL. + * * @param[in] item Item to interpret. * It must be retrieved using * \ref get_config_item(). @@ -1095,6 +1099,10 @@ char **get_string_config_array(struct collection_item *item, * Size and error parameters can be NULL. * Use \ref free_string_config_array() to free the array after use. * + * The array is always NULL terminated so + * it is safe not to get size and just loop until + * array element is NULL. + * * @param[in] item Item to interpret. * It must be retrieved using * \ref get_config_item(). @@ -1142,13 +1150,14 @@ char **get_raw_string_config_array(struct collection_item *item, * in the string. * * The length of the allocated array is returned in "size". - * Size and error parameters can be NULL. + * Size parameter can't be NULL. + * * Use \ref free_long_config_array() to free the array after use. * * @param[in] item Item to interpret. * It must be retrieved using * \ref get_config_item(). - * @param[out] size Variable that optionally receives + * @param[out] size Variable that receives * the size of the array. * @param[out] error Variable will get the value * of the error code if @@ -1187,13 +1196,14 @@ long *get_long_config_array(struct collection_item *item, * in the string. * * The length of the allocated array is returned in "size". - * Size and error parameters can be NULL. + * Size parameter can't be NULL. + * * Use \ref free_double_config_array() to free the array after use. * * @param[in] item Item to interpret. * It must be retrieved using * \ref get_config_item(). - * @param[out] size Variable that optionally receives + * @param[out] size Variable that receives * the size of the array. * @param[out] error Variable will get the value * of the error code if diff --git a/ini/ini_config_ut.c b/ini/ini_config_ut.c index 5731287..1c82a05 100644 --- a/ini/ini_config_ut.c +++ b/ini/ini_config_ut.c @@ -26,6 +26,7 @@ #include #include #define TRACE_HOME +#include "trace.h" #include "ini_config.h" #include "collection.h" #include "collection_tools.h" -- cgit