diff options
Diffstat (limited to 'ini')
-rw-r--r-- | ini/ini_get_array_valueobj.c | 389 | ||||
-rw-r--r-- | ini/ini_get_valueobj.c | 794 | ||||
-rw-r--r-- | ini/ini_list_valueobj.c | 136 |
3 files changed, 1319 insertions, 0 deletions
diff --git a/ini/ini_get_array_valueobj.c b/ini/ini_get_array_valueobj.c new file mode 100644 index 0000000..03fdd60 --- /dev/null +++ b/ini/ini_get_array_valueobj.c @@ -0,0 +1,389 @@ +/* + INI LIBRARY + + Value interpretation functions for arrays of values + and corresponding memory cleanup functions. + + Copyright (C) Dmitri Pal <dpal@redhat.com> 2012 + + INI Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + INI Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with INI Library. If not, see <http://www.gnu.org/licenses/>. +*/ + +#define _GNU_SOURCE +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include <locale.h> +#include "config.h" +#include "trace.h" +#include "collection.h" +#include "collection_tools.h" +#include "ini_defines.h" +#include "ini_configobj.h" + +/* + * Internal contants to indicate how + * to process the lists of strings. + */ +#define EXCLUDE_EMPTY 0 +#define INCLUDE_EMPTY 1 + +/* Maximum number of separators supported. Do not make it less than 3. */ +#define MAX_SEP_LEN 3 + +/* Arrays of stings */ +static char **get_str_cfg_array(struct value_obj *vo, + int include, + const char *sep, + int *size, + int *error) +{ + char *copy = NULL; + char *dest = NULL; + char locsep[MAX_SEP_LEN + 1]; + uint32_t lensep; + const char *buff; + uint32_t count = 0; + uint32_t len = 0; + uint32_t resume_len; + char **array; + const char *start; + char *start_array; + uint32_t i, j; + uint32_t dlen; + + TRACE_FLOW_ENTRY(); + + /* Do we have the vo ? */ + if (vo == NULL) { + TRACE_ERROR_NUMBER("Invalid argument.", EINVAL); + if (error) *error = EINVAL; + return NULL; + } + + /* Get value and length - no error checking as we checked it above + * and there is no other reson the function could to fail. + */ + value_get_concatenated(vo, &buff); + value_get_concatenated_len(vo, &dlen); + + /* Handle the separators */ + if (sep == NULL) { + locsep[0] = ','; + locsep[1] = '\0'; + lensep = 2; + } + else { + strncpy(locsep, sep, MAX_SEP_LEN); + locsep[MAX_SEP_LEN] = '\0'; + lensep = strlen(locsep) + 1; + } + + /* Allocate memory for the copy of the string */ + copy = malloc(dlen); + if (copy == NULL) { + TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM); + if (error) *error = ENOMEM; + return NULL; + } + + /* Suppress warning */ + start = buff; + + /* Loop through the string */ + dest = copy; + for(i = 0; i < dlen; i++) { + for(j = 0; j < lensep; j++) { + if(buff[i] == locsep[j]) { + /* If we found one of the separators trim spaces around */ + resume_len = len; + while (len > 0) { + if (isspace(start[len - 1])) len--; + else break; + } + TRACE_INFO_STRING("Current:", start); + TRACE_INFO_NUMBER("Length:", len); + if (len > 0) { + /* Save block aside */ + memcpy(dest, start, len); + count++; + dest += len; + *dest = '\0'; + dest++; + } + else if(include) { + count++; + *dest = '\0'; + dest++; + } + if (locsep[j] == '\0') break; /* We are done */ + + /* Move forward and trim spaces if any */ + start += resume_len + 1; + i++; + TRACE_INFO_STRING("Other pointer :", buff + i); + while ((i < dlen) && (isspace(*start))) { + i++; + start++; + } + len = -1; /* Len will be increased in the loop */ + i--; /* i will be increased so we need to step back */ + TRACE_INFO_STRING("Remaining buffer after triming spaces:", + start); + break; + } + } + len++; + } + + /* Now we know how many items are there in the list */ + array = malloc((count + 1) * sizeof(char *)); + if (array == NULL) { + free(copy); + TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM); + if (error) *error = ENOMEM; + return NULL; + } + + /* Loop again to fill in the pointers */ + start_array = copy; + for (i = 0; i < count; i++) { + TRACE_INFO_STRING("Token :", start_array); + TRACE_INFO_NUMBER("Item :", i); + array[i] = start_array; + /* Move to next item */ + while(*start_array) start_array++; + start_array++; + } + array[count] = NULL; + + if (error) *error = EOK; + if (size) *size = count; + /* If count is 0 the copy needs to be freed */ + if (count == 0) free(copy); + + TRACE_FLOW_EXIT(); + return array; +} + +/* Get array of strings from item eliminating empty tokens */ +char **ini_get_string_config_array(struct value_obj *vo, + const char *sep, int *size, int *error) +{ + TRACE_FLOW_ENTRY(); + return get_str_cfg_array(vo, EXCLUDE_EMPTY, sep, size, error); +} +/* Get array of strings from item preserving empty tokens */ +char **ini_get_raw_string_config_array(struct value_obj *vo, + const char *sep, int *size, int *error) +{ + TRACE_FLOW_ENTRY(); + return get_str_cfg_array(vo, INCLUDE_EMPTY, sep, size, error); +} + +/* Special function to free string config array */ +void ini_free_string_config_array(char **str_config) +{ + TRACE_FLOW_ENTRY(); + + if (str_config != NULL) { + if (*str_config != NULL) free(*str_config); + free(str_config); + } + + TRACE_FLOW_EXIT(); +} + +/* 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 *ini_get_long_config_array(struct value_obj *vo, int *size, int *error) +{ + const char *str; + char *endptr; + long val = 0; + long *array; + uint32_t count = 0; + int err; + uint32_t dlen; + + TRACE_FLOW_ENTRY(); + + /* Do we have the vo ? */ + if (vo == NULL) { + TRACE_ERROR_NUMBER("Invalid value object argument.", EINVAL); + if (error) *error = EINVAL; + return NULL; + } + + /* Do we have the size ? */ + if (size == NULL) { + TRACE_ERROR_NUMBER("Invalid size argument.", EINVAL); + if (error) *error = EINVAL; + return NULL; + } + + /* Get value and length - no error checking as we checked it above + * and there is no other reson the function could to fail. + */ + value_get_concatenated(vo, &str); + value_get_concatenated_len(vo, &dlen); + + /* Assume that we have maximum number of different numbers */ + array = (long *)malloc(sizeof(long) * dlen/2); + if (array == NULL) { + TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM); + if (error) *error = ENOMEM; + return NULL; + } + + /* Now parse the string */ + while (*str) { + + errno = 0; + val = strtol(str, &endptr, 10); + 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++; + /* Are we done? */ + if (*endptr == 0) break; + /* Advance to the next valid number */ + for (str = endptr; *str; str++) { + if (isdigit(*str) || (*str == '-') || (*str == '+')) break; + } + } + + *size = count; + if (error) *error = EOK; + + TRACE_FLOW_EXIT(); + return array; + +} + +/* Get an array of double values */ +double *ini_get_double_config_array(struct value_obj *vo, int *size, int *error) +{ + const char *str; + char *endptr; + double val = 0; + double *array; + int count = 0; + struct lconv *loc; + uint32_t dlen; + + TRACE_FLOW_ENTRY(); + + /* Do we have the vo ? */ + if (vo == NULL) { + TRACE_ERROR_NUMBER("Invalid value object argument.", EINVAL); + if (error) *error = EINVAL; + return NULL; + } + + /* Do we have the size ? */ + if (size == NULL) { + TRACE_ERROR_NUMBER("Invalid size argument.", EINVAL); + if (error) *error = EINVAL; + return NULL; + } + + /* Get value and length - no error checking as we checked it above + * and there is no other reson the function could to fail. + */ + value_get_concatenated(vo, &str); + value_get_concatenated_len(vo, &dlen); + + + /* Assume that we have maximum number of different numbers */ + array = (double *)malloc(sizeof(double) * dlen/2); + if (array == NULL) { + TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM); + if (error) *error = ENOMEM; + return NULL; + } + + /* Get locale information so that we can check for decimal point character. + * Based on the man pages it is unclear if this is an allocated memory or not. + * Seems like it is a static thread or process local structure so + * I will not try to free it after use. + */ + loc = localeconv(); + + /* Now parse the string */ + while (*str) { + TRACE_INFO_STRING("String to convert",str); + errno = 0; + val = strtod(str, &endptr); + if ((errno == ERANGE) || + ((errno != 0) && (val == 0)) || + (endptr == str)) { + TRACE_ERROR_NUMBER("Conversion failed", EIO); + free(array); + if (error) *error = EIO; + return NULL; + } + /* Save value */ + array[count] = val; + count++; + /* Are we done? */ + if (*endptr == 0) break; + TRACE_INFO_STRING("End pointer after conversion",endptr); + /* Advance to the next valid number */ + for (str = endptr; *str; str++) { + if (isdigit(*str) || (*str == '-') || (*str == '+') || + /* It is ok to do this since the string is null terminated */ + ((*str == *(loc->decimal_point)) && isdigit(str[1]))) break; + } + } + + *size = count; + if (error) *error = EOK; + + TRACE_FLOW_EXIT(); + return array; + +} + +/* Special function to free long config array */ +void ini_free_long_config_array(long *array) +{ + free(array); +} + +/* Special function to free double config array */ +void ini_free_double_config_array(double *array) +{ + free(array); +} diff --git a/ini/ini_get_valueobj.c b/ini/ini_get_valueobj.c new file mode 100644 index 0000000..3b7785e --- /dev/null +++ b/ini/ini_get_valueobj.c @@ -0,0 +1,794 @@ +/* + INI LIBRARY + + Value interpretation functions for single values + and corresponding memory cleanup functions. + + Copyright (C) Dmitri Pal <dpal@redhat.com> 2012 + + INI Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + INI Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with INI Library. If not, see <http://www.gnu.org/licenses/>. +*/ + +#define _GNU_SOURCE +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include "config.h" +#include "trace.h" +#include "collection.h" +#include "collection_tools.h" +#include "ini_defines.h" +#include "ini_config_priv.h" +#include "ini_configobj.h" +#include "ini_valueobj.h" + +/* Macro co convert to HEX value */ +#define HEXVAL(c) (isdigit(c) ? (c - '0') : (tolower(c) - 'a') + 10) + +static int is_same_section(struct ini_cfgobj *ini_config, + const char *section) +{ + int len = 0; + + TRACE_FLOW_ENTRY(); + + /* If section is not defined it is different */ + if (ini_config->section == NULL) { + TRACE_FLOW_RETURN(0); + return 0; + } + + len = strlen(section); + + /* If values are same this is the same section */ + if ((strncasecmp(ini_config->section, section, ini_config->section_len) == 0) && + (ini_config->section_len == len)) { + TRACE_FLOW_RETURN(1); + return 1; + } + + /* Otherwise the values are different */ + TRACE_FLOW_RETURN(0); + return 0; +} + +static int is_same_name(struct ini_cfgobj *ini_config, + const char *name, + int name_len) +{ + TRACE_FLOW_ENTRY(); + + /* If name is not defined it is different */ + if (ini_config->name == NULL) { + TRACE_FLOW_RETURN(0); + return 0; + } + + /* If values are same this is the same value */ + if ((strncasecmp(ini_config->name, name, ini_config->name_len) == 0) && + (ini_config->name_len == name_len)) { + TRACE_FLOW_RETURN(1); + return 1; + } + + /* Otherwise the values are different */ + TRACE_FLOW_RETURN(0); + return 0; +} + + +/* Function to get value object from the configuration handle */ +int ini_get_config_valueobj(const char *section, + const char *name, + struct ini_cfgobj *ini_config, + int mode, + struct value_obj **vo) +{ + int error = EOK; + struct collection_item *section_handle = NULL; + struct collection_item *item = NULL; + const char *to_find; + char default_section[] = INI_DEFAULT_SECTION; + uint64_t hash = 0; + int len = 0, name_len = 0; + + TRACE_FLOW_ENTRY(); + + /* Do we have the accepting memory ? */ + if (vo == NULL) { + TRACE_ERROR_NUMBER("Invalid argument vo.", EINVAL); + return EINVAL; + } + + *vo = NULL; + + if (ini_config == NULL) { + TRACE_ERROR_NUMBER("Invalid argument ini_config.", EINVAL); + return EINVAL; + } + + if ((mode < INI_GET_FIRST_VALUE) || + (mode > INI_GET_NEXT_VALUE)) { + TRACE_ERROR_NUMBER("Invalid argument mode:", mode); + return EINVAL; + } + + /* Do we have a name ? */ + if (name == NULL) { + TRACE_ERROR_NUMBER("Name is NULL it will not be found.", EINVAL); + return EINVAL; + } + + /* Empty section means look for the default one */ + if (section == NULL) to_find = default_section; + else to_find = section; + + TRACE_INFO_STRING("Getting Name:", name); + TRACE_INFO_STRING("In Section:", section); + + /* Make sure we start over if this is the first value */ + if (mode == INI_GET_FIRST_VALUE) ini_config_clean_state(ini_config); + + /* Are we looking in the same section ? */ + if (!is_same_section(ini_config, section)) { + + /* This is a different section */ + ini_config_clean_state(ini_config); + + /* Get Subcollection */ + error = col_get_collection_reference(ini_config->cfg, §ion_handle, to_find); + /* Check error */ + if (error && (error != ENOENT)) { + TRACE_ERROR_NUMBER("Failed to get section", error); + return error; + } + + /* Did we find a section */ + if ((error == ENOENT) || (section_handle == NULL)) { + /* We have not found section - return success */ + TRACE_FLOW_EXIT(); + return EOK; + } + + /* Create an iterator */ + error = col_bind_iterator(&(ini_config->iterator), + section_handle, + COL_TRAVERSE_ONELEVEL); + /* Make sure we free the section we found */ + col_destroy_collection(section_handle); + /* Check error */ + if (error) { + TRACE_ERROR_NUMBER("Failed to bind to section", error); + return error; + } + + /* Save section */ + ini_config->section_len = strlen(to_find); + ini_config->section = strndup(to_find, ini_config->section_len); + /* Check error */ + if (ini_config->section == NULL) { + TRACE_ERROR_NUMBER("Failed to save section name ", ENOMEM); + ini_config_clean_state(ini_config); + return ENOMEM; + } + } + + hash = col_make_hash(name, 0, &name_len); + + /* Check if this is the same name */ + if (!is_same_name(ini_config, name, name_len)) { + TRACE_INFO_STRING("Saved name:", ini_config->name); + TRACE_INFO_STRING("Passed name:", name); + TRACE_INFO_NUMBER("Length of the saved name", ini_config->name_len); + TRACE_INFO_NUMBER("Length of the passed name", name_len); + col_rewind_iterator(ini_config->iterator); + free(ini_config->name); + ini_config->name = NULL; + ini_config->name_len = 0; + } + + /* Iterate through the section */ + do { + + /* Loop through a collection */ + error = col_iterate_collection(ini_config->iterator, &item); + if (error) { + TRACE_ERROR_NUMBER("Failed to iterate", error); + ini_config_clean_state(ini_config); + return error; + } + + /* Are we done ? */ + if (item == NULL) { + /* There is nothing left to look for */ + ini_config_clean_state(ini_config); + TRACE_FLOW_EXIT(); + return EOK; + } + + if ((hash == (unsigned long int)col_get_item_hash(item)) && + (strncasecmp(col_get_item_property(item, &len), name, name_len) == 0) && + (len == name_len)) { + TRACE_INFO_STRING("Item is found", name); + break; + } + } + while(1); + + if (!is_same_name(ini_config, name, name_len)) { + /* Save name */ + ini_config->name_len = name_len; + ini_config->name = strndup(name, name_len); + /* Check error */ + if (ini_config->name == NULL) { + TRACE_ERROR_NUMBER("Failed to save key name ", ENOMEM); + ini_config_clean_state(ini_config); + return ENOMEM; + } + } + + *vo = *((struct value_obj **)(col_get_item_data(item))); + + TRACE_FLOW_EXIT(); + return error; +} + +/* Get long long value from config value object */ +static long long ini_get_llong_config_value(struct value_obj *vo, + int strict, + long long def, + int *error) +{ + int err; + const char *str; + char *endptr; + long long val = 0; + + TRACE_FLOW_ENTRY(); + + /* Do we have the vo ? */ + if (vo == NULL) { + TRACE_ERROR_NUMBER("Invalid argument.", EINVAL); + if (error) *error = EINVAL; + return def; + } + + if (error) *error = EOK; + + /* Get value - no error checking as we checked it above + * and there is no other reson the function could fail. + */ + value_get_concatenated(vo, &str); + + /* Try to parse the value */ + errno = 0; + val = strtoll(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; + return def; + } + + TRACE_FLOW_NUMBER("ini_get_llong_config_value returning", (long)val); + return val; +} + +/* Get unsigned long long value from config value object */ +static unsigned long long ini_get_ullong_config_value(struct value_obj *vo, + int strict, + unsigned long long def, + int *error) +{ + int err; + const char *str; + char *endptr; + unsigned long long val = 0; + + TRACE_FLOW_ENTRY(); + + /* Do we have the vo ? */ + if (vo == NULL) { + TRACE_ERROR_NUMBER("Invalid argument.", EINVAL); + if (error) *error = EINVAL; + return def; + } + + if (error) *error = EOK; + + /* Get value - no error checking as we checked it above + * and there is no other reson the function could fail. + */ + value_get_concatenated(vo, &str); + + 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; + return def; + } + + TRACE_FLOW_NUMBER("ini_get_ullong_config_value returning", val); + return val; +} + + +/* Get integer value from config value */ +int ini_get_int_config_value(struct value_obj *vo, + int strict, + int def, + int *error) +{ + long long val = 0; + int err = 0; + + TRACE_FLOW_ENTRY(); + + val = ini_get_llong_config_value(vo, strict, def, &err); + if (err == 0) { + if ((val > INT_MAX) || (val < INT_MIN)) { + TRACE_ERROR_NUMBER("Value is out of range", ERANGE); + val = def; + err = ERANGE; + } + } + + if (error) *error = err; + + TRACE_FLOW_NUMBER("ini_get_int_config_value returning", (int)val); + return (int)val; +} + +/* Get unsigned integer value from config value object */ +unsigned ini_get_unsigned_config_value(struct value_obj *vo, + int strict, + unsigned def, + int *error) +{ + unsigned long long val = 0; + int err = 0; + + TRACE_FLOW_ENTRY(); + + val = ini_get_ullong_config_value(vo, strict, def, &err); + if (err == 0) { + if (val > UINT_MAX) { + TRACE_ERROR_NUMBER("Value is out of range", ERANGE); + val = def; + err = ERANGE; + } + } + + if (error) *error = err; + + TRACE_FLOW_NUMBER("ini_get_unsigned_config_value returning", + (unsigned)val); + return (unsigned)val; +} + +/* Get long value from config value object */ +long ini_get_long_config_value(struct value_obj *vo, + int strict, + long def, + int *error) +{ + long long val = 0; + int err = 0; + + TRACE_FLOW_ENTRY(); + + val = ini_get_llong_config_value(vo, strict, def, &err); + if (err == 0) { + if ((val > LONG_MAX) || (val < LONG_MIN)) { + TRACE_ERROR_NUMBER("Value is out of range", ERANGE); + val = def; + err = ERANGE; + } + } + + if (error) *error = err; + + TRACE_FLOW_NUMBER("ini_get_long_config_value returning", + (long)val); + return (long)val; +} + +/* Get unsigned long value from config value object */ +unsigned long ini_get_ulong_config_value(struct value_obj *vo, + int strict, + unsigned long def, + int *error) +{ + unsigned long long val = 0; + int err = 0; + + TRACE_FLOW_ENTRY(); + + val = ini_get_ullong_config_value(vo, strict, def, &err); + if (err == 0) { + if (val > ULONG_MAX) { + TRACE_ERROR_NUMBER("Value is out of range", ERANGE); + val = def; + err = ERANGE; + } + } + + if (error) *error = err; + + TRACE_FLOW_NUMBER("ini_get_ulong_config_value returning", + (unsigned long)val); + return (unsigned long)val; +} + +/* Get int32_t value from config value object */ +int32_t ini_get_int32_config_value(struct value_obj *vo, + int strict, + int32_t def, + int *error) +{ + long long val = 0; + int err = 0; + + TRACE_FLOW_ENTRY(); + + val = ini_get_llong_config_value(vo, strict, def, &err); + if (err == 0) { + if ((val > INT32_MAX) || (val < INT32_MIN)) { + TRACE_ERROR_NUMBER("Value is out of range", ERANGE); + val = def; + err = ERANGE; + } + } + + if (error) *error = err; + + TRACE_FLOW_NUMBER("ini_get_int32_config_value returning", + (int32_t)val); + return (int32_t)val; +} + +/* Get uint32_t value from config value object */ +uint32_t ini_get_uint32_config_value(struct value_obj *vo, + int strict, + uint32_t def, + int *error) +{ + unsigned long long val = 0; + int err = 0; + + TRACE_FLOW_ENTRY(); + + val = ini_get_ullong_config_value(vo, strict, def, &err); + if (err == 0) { + if (val > UINT32_MAX) { + TRACE_ERROR_NUMBER("Value is out of range", ERANGE); + val = def; + err = ERANGE; + } + } + + if (error) *error = err; + + TRACE_FLOW_NUMBER("ini_get_uint32_config_value returning", + (uint32_t)val); + return (uint32_t)val; +} + +/* Get int64_t value from config value ovject */ +int64_t ini_get_int64_config_value(struct value_obj *vo, + int strict, + int64_t def, + int *error) +{ + long long val = 0; + int err = 0; + + TRACE_FLOW_ENTRY(); + + val = ini_get_llong_config_value(vo, strict, def, &err); + if (err == 0) { + if ((val > INT64_MAX) || (val < INT64_MIN)) { + TRACE_ERROR_NUMBER("Value is out of range", ERANGE); + val = def; + err = ERANGE; + } + } + + if (error) *error = err; + + TRACE_FLOW_NUMBER("ini_get_int64_config_value returning", + (int64_t)val); + return (int64_t)val; +} + +/* Get uint64_t value from config value object */ +uint64_t ini_get_uint64_config_value(struct value_obj *vo, + int strict, + uint64_t def, + int *error) +{ + unsigned long long val = 0; + int err = 0; + + TRACE_FLOW_ENTRY(); + + val = ini_get_ullong_config_value(vo, strict, def, &err); + if (err == 0) { + if (val > UINT64_MAX) { + TRACE_ERROR_NUMBER("Value is out of range", ERANGE); + val = def; + err = ERANGE; + } + } + + if (error) *error = err; + + TRACE_FLOW_NUMBER("ini_get_uint64_config_value returning", + (uint64_t)val); + return (uint64_t)val; +} + +/* Get double value */ +double ini_get_double_config_value(struct value_obj *vo, + int strict, double def, int *error) +{ + const char *str; + char *endptr; + double val = 0; + + TRACE_FLOW_ENTRY(); + + /* Do we have the vo ? */ + if (vo == NULL) { + TRACE_ERROR_NUMBER("Invalid argument.", EINVAL); + if (error) *error = EINVAL; + return def; + } + + if (error) *error = EOK; + + /* Get value - no error checking as we checked it above + * and there is no other reason the function could fail. + */ + value_get_concatenated(vo, &str); + + errno = 0; + val = strtod(str, &endptr); + + /* Check for various possible errors */ + if ((errno == ERANGE) || + ((errno != 0) && (val == 0)) || + (endptr == str)) { + TRACE_ERROR_NUMBER("Conversion failed", EIO); + if (error) *error = EIO; + return def; + } + + if (strict && (*endptr != '\0')) { + TRACE_ERROR_NUMBER("More characters than expected", EIO); + if (error) *error = EIO; + val = def; + } + + TRACE_FLOW_DOUBLE("ini_get_double_config_value returning", val); + return val; +} + +/* Get boolean value */ +unsigned char ini_get_bool_config_value(struct value_obj *vo, + unsigned char def, int *error) +{ + const char *str; + uint32_t len = 0; + + TRACE_FLOW_ENTRY(); + + /* Do we have the vo ? */ + if (vo == NULL) { + TRACE_ERROR_NUMBER("Invalid argument.", EINVAL); + if (error) *error = EINVAL; + return def; + } + + if (error) *error = EOK; + + /* Get value - no error checking as we checked it above + * and there is no other reson the function could fail. + */ + value_get_concatenated(vo, &str); + value_get_concatenated_len(vo, &len); + + /* Try to parse the value */ + if ((strncasecmp(str, "true", len) == 0) || + (strncasecmp(str, "yes", len) == 0)) { + TRACE_FLOW_STRING("Returning", "true"); + return '\1'; + } + else if ((strncasecmp(str, "false", len) == 0) || + (strncasecmp(str, "no", len) == 0)) { + TRACE_FLOW_STRING("Returning", "false"); + return '\0'; + } + + TRACE_ERROR_STRING("Returning", "error"); + if (error) *error = EIO; + return def; +} + +/* Return a string out of the value */ +char *ini_get_string_config_value(struct value_obj *vo, + int *error) +{ + const char *str = NULL; + char *ret_str = NULL; + + TRACE_FLOW_ENTRY(); + + /* Do we have the vo ? */ + if (vo == NULL) { + TRACE_ERROR_NUMBER("Invalid argument.", EINVAL); + if (error) *error = EINVAL; + return NULL; + } + + /* Get value - no error checking as we checked it above + * and there is no other reson the function could fail. + */ + value_get_concatenated(vo, &str); + + ret_str = strdup(str); + if (ret_str == NULL) { + TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM); + if (error) *error = ENOMEM; + return NULL; + } + + if (error) *error = EOK; + + TRACE_FLOW_STRING("ini_get_string_config_value returning", str); + return ret_str; +} + +/* Get string from the value object */ +const char *ini_get_const_string_config_value(struct value_obj *vo, + int *error) +{ + const char *str; + + TRACE_FLOW_ENTRY(); + + /* Do we have the vo ? */ + if (vo == NULL) { + TRACE_ERROR_NUMBER("Invalid argument.", EINVAL); + if (error) *error = EINVAL; + return NULL; + } + + /* Get value - no error checking as we checked it above + * and there is no other reson the function could fail. + */ + value_get_concatenated(vo, &str); + + if (error) *error = EOK; + + TRACE_FLOW_STRING("ini_get_const_string_config_value returning", str); + return str; +} + +/* A special hex format is assumed. + * The string should be taken in single quotes + * and consist of hex encoded value two hex digits per byte. + * Example: '0A2BFECC' + * Case does not matter. + */ +char *ini_get_bin_config_value(struct value_obj *vo, + int *length, int *error) +{ + int i; + char *value = NULL; + const char *buff; + int size = 0; + uint32_t len = 0; + const char *str; + + TRACE_FLOW_ENTRY(); + + /* Do we have the vo ? */ + if (vo == NULL) { + TRACE_ERROR_NUMBER("Invalid argument.", EINVAL); + if (error) *error = EINVAL; + return NULL; + } + + if (error) *error = EOK; + + /* Get value - no error checking as we checked it above + * and there is no other reson the function could fail. + */ + value_get_concatenated(vo, &str); + + /* Check the length */ + value_get_concatenated_len(vo, &len); + if ((len%2) != 0) { + TRACE_ERROR_STRING("Invalid length for binary data", ""); + if (error) *error = EINVAL; + return NULL; + } + + /* Is the format correct ? */ + if ((*str != '\'') || + (str[len -1] != '\'')) { + TRACE_ERROR_STRING("String is not escaped",""); + if (error) *error = EIO; + return NULL; + } + + /* Check that all the symbols are ok */ + buff = str + 1; + len -= 2; + for (i = 0; i < len; i++) { + if (!isxdigit(buff[i])) { + TRACE_ERROR_STRING("Invalid encoding for binary data", buff[i]); + if (error) *error = EIO; + return NULL; + } + } + + /* The value is good so we can allocate memory for it */ + value = malloc(len / 2); + if (value == NULL) { + TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM); + if (error) *error = ENOMEM; + return NULL; + } + + /* Convert the value */ + for (i = 0; i < len; i += 2) { + value[size] = (char)(16 * HEXVAL(buff[i]) + HEXVAL(buff[i+1])); + size++; + } + + if (error) *error = EOK; + if (length) *length = size; + TRACE_FLOW_STRING("ini_get_bin_config_value", "Exit"); + return value; +} + +/* Function to free binary configuration value */ +void ini_free_bin_config_value(char *value) +{ + free(value); +} diff --git a/ini/ini_list_valueobj.c b/ini/ini_list_valueobj.c new file mode 100644 index 0000000..8df6a18 --- /dev/null +++ b/ini/ini_list_valueobj.c @@ -0,0 +1,136 @@ +/* + INI LIBRARY + + Value interpretation functions for single values + and corresponding memory cleanup functions. + + Copyright (C) Dmitri Pal <dpal@redhat.com> 2012 + + INI Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + INI Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with INI Library. If not, see <http://www.gnu.org/licenses/>. +*/ + +#define _GNU_SOURCE +#include <stdio.h> +#include <errno.h> +#include "config.h" +#include "trace.h" +#include "collection.h" +#include "collection_tools.h" +#include "ini_configobj.h" +#include "ini_config_priv.h" + + +/* The section array should be freed using this function */ +void ini_free_section_list(char **section_list) +{ + TRACE_FLOW_ENTRY(); + + col_free_property_list(section_list); + + TRACE_FLOW_EXIT(); +} + +/* The section array should be freed using this function */ +void ini_free_attribute_list(char **section_list) +{ + TRACE_FLOW_ENTRY(); + + col_free_property_list(section_list); + + TRACE_FLOW_EXIT(); +} + + +/* Get list of sections as an array of strings. + * Function allocates memory for the array of the sections. + */ +char **ini_get_section_list(struct ini_cfgobj *ini_config, int *size, int *error) +{ + char **list; + + TRACE_FLOW_ENTRY(); + + /* Do we have the configuration object ? */ + if (ini_config == NULL) { + TRACE_ERROR_NUMBER("Invalid argument.", EINVAL); + if (error) *error = EINVAL; + return NULL; + } + + /* Pass it to the function from collection API */ + list = col_collection_to_list(ini_config->cfg, size, error); + + TRACE_FLOW_STRING("ini_get_section_list returning", + ((list == NULL) ? "NULL" : list[0])); + return list; +} + +/* Get list of attributes in a section as an array of strings. + * Function allocates memory for the array of the strings. + */ +char **ini_get_attribute_list(struct ini_cfgobj *ini_config, + const char *section, + int *size, + int *error) +{ + struct collection_item *subcollection = NULL; + char **list; + int err; + int i = 0; + + TRACE_FLOW_ENTRY(); + + /* Do we have the configuration object ? */ + if (ini_config == NULL) { + TRACE_ERROR_NUMBER("Invalid configuration object argument.", EINVAL); + if (error) *error = EINVAL; + return NULL; + } + + /* Do we have the section ? */ + if (section == NULL) { + TRACE_ERROR_NUMBER("Invalid section argument.", EINVAL); + if (error) *error = EINVAL; + return NULL; + } + + /* Fetch section */ + err = col_get_collection_reference(ini_config->cfg, &subcollection, section); + /* Check error */ + if (err && (subcollection == NULL)) { + TRACE_ERROR_NUMBER("Failed to get section", err); + if (error) *error = EINVAL; + return NULL; + } + + /* Pass it to the function from collection API */ + list = col_collection_to_list(subcollection, size, error); + + col_destroy_collection(subcollection); + + /* Our list of attributes has a special extra attribute - remove it */ + if ((list != NULL) && (list[0] != NULL)) { + free(list[0]); + while(list[i + 1] != NULL) { + list[i] = list[i + 1]; + i++; + } + list[i] = NULL; + } + + if (size) (*size)--; + + TRACE_FLOW_STRING("ini_get_attribute_list returning", ((list == NULL) ? "NULL" : list[0])); + return list; +} |