diff options
Diffstat (limited to 'common/ini/ini_config.c')
-rw-r--r-- | common/ini/ini_config.c | 1476 |
1 files changed, 5 insertions, 1471 deletions
diff --git a/common/ini/ini_config.c b/common/ini/ini_config.c index 1c8e4aef3..b9cd6eb06 100644 --- a/common/ini/ini_config.c +++ b/common/ini/ini_config.c @@ -21,220 +21,19 @@ */ #define _GNU_SOURCE -#include <stdio.h> #include <errno.h> #include <string.h> -#include <ctype.h> #include <stdlib.h> -#include <locale.h> -#include <fcntl.h> -#include <unistd.h> -#include <limits.h> #include "config.h" -/* For error text */ -#include <libintl.h> -#define _(String) gettext (String) -/* INI file is used as a collection */ +#include "trace.h" #include "collection.h" #include "collection_tools.h" -#include "trace.h" -#include "ini_config.h" -#include "ini_metadata.h" #include "path_utils.h" +#include "ini_defines.h" +#include "ini_parse.h" +#include "ini_metadata.h" +#include "ini_config.h" -#define NAME_OVERHEAD 10 - -#define SLASH "/" - -#define EXCLUDE_EMPTY 0 -#define INCLUDE_EMPTY 1 - -/* Name of the special collection used to store parsing errors */ -#define FILE_ERROR_SET "ini_file_error_set" - -/* Text error strings used when errors are printed out */ -#define WARNING_TXT _("Warning") -#define ERROR_TXT _("Error") -/* For parse errors */ -#define WRONG_COLLECTION _("Passed in list is not a list of parse errors.\n") -#define FAILED_TO_PROCCESS _("Internal Error. Failed to process error list.\n") -#define ERROR_HEADER _("Parsing errors and warnings in file: %s\n") -/* For grammar errors */ -#define WRONG_GRAMMAR _("Passed in list is not a list of grammar errors.\n") -#define FAILED_TO_PROC_G _("Internal Error. Failed to process list of grammar errors.\n") -#define ERROR_HEADER_G _("Logical errors and warnings in file: %s\n") -/* For validation errors */ -#define WRONG_VALIDATION _("Passed in list is not a list of validation errors.\n") -#define FAILED_TO_PROC_V _("Internal Error. Failed to process list of validation errors.\n") -#define ERROR_HEADER_V _("Validation errors and warnings in file: %s\n") - -#define LINE_FORMAT _("%s (%d) on line %d: %s\n") - - -/* Codes that parsing function can return */ -#define RET_PAIR 0 -#define RET_COMMENT 1 -#define RET_SECTION 2 -#define RET_INVALID 3 -#define RET_EMPTY 4 -#define RET_EOF 5 -#define RET_ERROR 6 - -#define INI_ERROR "errors" -#define INI_ERROR_NAME "errname" - -/* Internal sizes. MAX_KEY is defined in config.h */ -#define MAX_VALUE PATH_MAX -#define BUFFER_SIZE MAX_KEY + MAX_VALUE + 3 - -/* Beffer length used for int to string conversions */ -#define CONVERSION_BUFFER 80 - -/*============================================================*/ -/* The following classes moved here from the public header - * They are reserved for future use. - * - * NOTE: before exposing these constants again in the common header - * check that the class IDs did not get reused over time by - * other classes. - */ -/** @brief Collection of grammar errors. - * - * Reserved for future use. - */ -#define COL_CLASS_INI_GERROR COL_CLASS_INI_BASE + 5 -/** @brief Collection of validation errors. - * - * Reserved for future use. - */ -#define COL_CLASS_INI_VERROR COL_CLASS_INI_BASE + 6 - -#ifdef HAVE_VALIDATION - -/** @brief Collection of lines from the INI file. - * - * Reserved for future use - */ -#define COL_CLASS_INI_LINES COL_CLASS_INI_BASE + 7 - -#endif /* HAVE_VALIDATION */ -/*============================================================*/ - - -/* Different error string functions can be passed as callbacks */ -typedef const char * (*error_fn)(int error); - -/* Function to return parsing error */ -const char *parsing_error_str(int parsing_error) -{ - const char *placeholder= _("Unknown pasing error."); - const char *str_error[] = { _("Data is too long."), - _("No closing bracket."), - _("Section name is missing."), - _("Section name is too long."), - _("Equal sign is missing."), - _("Property name is missing."), - _("Property name is too long.") - }; - - /* Check the range */ - if ((parsing_error < 1) || (parsing_error > ERR_MAXPARSE)) - return placeholder; - else - return str_error[parsing_error-1]; -} - -/* Function to return grammar error. - * This function is currently not used. - * It is planned to be used by the INI - * file grammar parser. - * - * The following doxygen description is moved here. - * When the function gets exposed move it into - * the header file. - */ -/** @brief Function to return a grammar error in template. - * - * EXPERIMENTAL. Reserved for future use. - * - * This error is returned when the template - * is translated into the grammar object. - * - * @param[in] parsing_error Error code for the grammar error. - * - * @return Error string. - */ - -const char *grammar_error_str(int grammar_error) -{ - const char *placeholder= _("Unknown grammar error."); - /* THIS IS A TEMPORARY PLACEHOLDER !!!! */ - const char *str_error[] = { _(""), - _(""), - _(""), - _(""), - _(""), - _(""), - _("") - }; - - /* Check the range */ - if ((grammar_error < 1) || (grammar_error > ERR_MAXGRAMMAR)) - return placeholder; - else - return str_error[grammar_error-1]; -} - -/* Function to return validation error. - * This function is currently not used. - * It is planned to be used by the INI - * file grammar validator. - * - * The following doxygen description is moved here. - * When the function gets exposed move it into - * the header file. - */ -/** @brief Function to return a validation error. - * - * EXPERIMENTAL. Reserved for future use. - * - * This is the error that it is returned when - * the INI file is validated against the - * grammar object. - * - * @param[in] parsing_error Error code for the validation error. - * - * @return Error string. - */ -const char *validation_error_str(int validation_error) -{ - const char *placeholder= _("Unknown validation error."); - /* THIS IS A TEMPORARY PLACEHOLDER !!!! */ - const char *str_error[] = { _(""), - _(""), - _(""), - _(""), - _(""), - _(""), - _("") - }; - - /* Check the range */ - if ((validation_error < 1) || (validation_error > ERR_MAXVALID)) - return placeholder; - else - return str_error[validation_error-1]; -} - - -/* Internal function to read line from INI file */ -int read_line(FILE *file, - char *buf, - int read_size, - char **key, - char **value, - int *length, - int *ext_error); /***************************************************************************/ /* Function to read single ini file and pupulate @@ -1035,1268 +834,3 @@ int config_for_app(const char *application, TRACE_FLOW_NUMBER("config_for_app. Returning", error); return error; } - - - -/* Reads a line from the file */ -int read_line(FILE *file, - char *buf, - int read_size, - char **key, char **value, - int *length, - int *ext_error) -{ - - char *res; - int len; - char *buffer; - int i; - char *eq; - - TRACE_FLOW_STRING("read_line", "Entry"); - - *ext_error = 0; - - buffer = buf; - - /* Get data from file */ - res = fgets(buffer, read_size - 1, file); - if (res == NULL) { - TRACE_ERROR_STRING("Read nothing", ""); - return RET_EOF; - } - - /* Make sure the buffer is NULL terminated */ - buffer[read_size - 1] = '\0'; - - len = strlen(buffer); - if (len == 0) { - TRACE_ERROR_STRING("Nothing was read.", ""); - return RET_EMPTY; - } - - /* Added \r just in case we deal with Windows in future */ - if ((buffer[len - 1] != '\n') && (buffer[len - 1] != '\r')) { - TRACE_ERROR_STRING("String it too big!", ""); - *ext_error = ERR_LONGDATA; - return RET_ERROR; - } - - /* Ingnore comments */ - if ((*buffer == ';') || (*buffer == '#')) { - TRACE_FLOW_STRING("Comment", buf); - return RET_COMMENT; - } - - TRACE_INFO_STRING("BUFFER before trimming:", buffer); - - /* Trucate trailing spaces and CRs */ - /* Make sure not to step before the beginning */ - while (len && isspace(buffer[len - 1])) { - buffer[len - 1] = '\0'; - len--; - } - - TRACE_INFO_STRING("BUFFER after trimming trailing spaces:", buffer); - - /* Trucate leading spaces */ - while (isspace(*buffer)) { - buffer++; - len--; - } - - TRACE_INFO_STRING("BUFFER after trimming leading spaces:", buffer); - TRACE_INFO_NUMBER("BUFFER length:", len); - - /* Empty line */ - if (len == 0) { - TRACE_FLOW_STRING("Empty line", buf); - return RET_EMPTY; - } - - /* Section */ - if (*buffer == '[') { - if (buffer[len-1] != ']') { - TRACE_ERROR_STRING("Invalid format for section", buf); - *ext_error = ERR_NOCLOSESEC; - return RET_ERROR; - } - buffer++; - len--; - while (isspace(*buffer)) { - buffer++; - len--; - } - if (len == 0) { - TRACE_ERROR_STRING("Invalid format for section", buf); - *ext_error = ERR_NOSECTION; - return RET_ERROR; - } - - buffer[len - 1] = '\0'; - len--; - while (isspace(buffer[len - 1])) { - buffer[len - 1] = '\0'; - len--; - } - if (len >= MAX_KEY) { - TRACE_ERROR_STRING("Section name is too long", buf); - *ext_error = ERR_SECTIONLONG; - return RET_ERROR; - } - - *key = buffer; - return RET_SECTION; - } - - /* Assume we are dealing with the K-V here */ - /* Find "=" */ - eq = strchr(buffer, '='); - if (eq == NULL) { - TRACE_ERROR_STRING("No equal sign", buf); - *ext_error = ERR_NOEQUAL; - return RET_INVALID; - } - - len -= eq-buffer; - - /* Strip spaces around "=" */ - i = eq - buffer - 1; - while ((i >= 0) && isspace(buffer[i])) i--; - if (i < 0) { - TRACE_ERROR_STRING("No key", buf); - *ext_error = ERR_NOKEY; - return RET_INVALID; - } - - /* Copy key into provided buffer */ - if(i >= MAX_KEY) { - TRACE_ERROR_STRING("Section name is too long", buf); - *ext_error = ERR_LONGKEY; - return RET_INVALID; - } - *key = buffer; - buffer[i + 1] = '\0'; - TRACE_INFO_STRING("KEY:", *key); - - eq++; - len--; - while (isspace(*eq)) { - eq++; - len--; - } - - *value = eq; - /* Make sure we include trailing 0 into data */ - *length = len + 1; - - TRACE_INFO_STRING("VALUE:", *value); - TRACE_INFO_NUMBER("LENGTH:", *length); - - TRACE_FLOW_STRING("read_line", "Exit"); - return RET_PAIR; -} - - - -/* Internal function that prints errors */ -static void print_error_list(FILE *file, - struct collection_item *error_list, - int cclass, - char *wrong_col_error, - char *failed_to_process, - char *error_header, - char *line_format, - error_fn error_function) -{ - struct collection_iterator *iterator; - int error; - struct collection_item *item = NULL; - struct parse_error *pe; - unsigned int count; - - TRACE_FLOW_STRING("print_error_list", "Entry"); - - /* If we have something to print print it */ - if (error_list == NULL) { - TRACE_ERROR_STRING("No error list",""); - return; - } - - /* Make sure we go the right collection */ - if (!col_is_of_class(error_list, cclass)) { - TRACE_ERROR_STRING("Wrong collection class:", wrong_col_error); - fprintf(file,"%s\n", wrong_col_error); - return; - } - - /* Bind iterator */ - error = col_bind_iterator(&iterator, error_list, COL_TRAVERSE_DEFAULT); - if (error) { - TRACE_ERROR_STRING("Error (bind):", failed_to_process); - fprintf(file, "%s\n", failed_to_process); - return; - } - - while(1) { - /* Loop through a collection */ - error = col_iterate_collection(iterator, &item); - if (error) { - TRACE_ERROR_STRING("Error (iterate):", failed_to_process); - fprintf(file, "%s\n", failed_to_process); - col_unbind_iterator(iterator); - return; - } - - /* Are we done ? */ - if (item == NULL) break; - - /* Process collection header */ - if (col_get_item_type(item) == COL_TYPE_COLLECTION) { - col_get_collection_count(item, &count); - if (count <= 2) break; - } else if (col_get_item_type(item) == COL_TYPE_STRING) { - fprintf(file, error_header, (char *)col_get_item_data(item)); - } - else { - /* Put error into provided format */ - pe = (struct parse_error *)(col_get_item_data(item)); - fprintf(file, line_format, - col_get_item_property(item, NULL), /* Error or warning */ - pe->error, /* Error */ - pe->line, /* Line */ - error_function(pe->error)); /* Error str */ - } - - } - - /* Do not forget to unbind iterator - otherwise there will be a leak */ - col_unbind_iterator(iterator); - - TRACE_FLOW_STRING("print_error_list", "Exit"); -} - -/* Print errors and warnings that were detected while parsing one file */ -void print_file_parsing_errors(FILE *file, - struct collection_item *error_list) -{ - print_error_list(file, - error_list, - COL_CLASS_INI_PERROR, - WRONG_COLLECTION, - FAILED_TO_PROCCESS, - ERROR_HEADER, - LINE_FORMAT, - parsing_error_str); -} - - -/* Print errors and warnings that were detected while processing grammar. - * - * The following doxygen description is moved here. - * When the function gets exposed move it into - * the header file. - */ -/** - * @brief Print errors and warnings that were detected while - * checking grammar of the template. - * - * EXPERIMENTAL. Reserved for future use. - * - * @param[in] file File descriptor. - * @param[in] error_list List of the parsing errors. - * - */ -void print_grammar_errors(FILE *file, - struct collection_item *error_list) -{ - print_error_list(file, - error_list, - COL_CLASS_INI_GERROR, - WRONG_GRAMMAR, - FAILED_TO_PROC_G, - ERROR_HEADER_G, - LINE_FORMAT, - grammar_error_str); -} - -/* Print errors and warnings that were detected while validating INI file. - * - * The following doxygen description is moved here. - * When the function gets exposed move it into - * the header file. - */ -/** - * @brief Print errors and warnings that were detected while - * checking INI file against the grammar object. - * - * EXPERIMENTAL. Reserved for future use. - * - * @param[in] file File descriptor. - * @param[in] error_list List of the parsing errors. - * - */ -void print_validation_errors(FILE *file, - struct collection_item *error_list) -{ - print_error_list(file, - error_list, - COL_CLASS_INI_VERROR, - WRONG_VALIDATION, - FAILED_TO_PROC_V, - ERROR_HEADER_V, - LINE_FORMAT, - validation_error_str); -} - -/* Print errors and warnings that were detected while parsing - * the whole configuration */ -void print_config_parsing_errors(FILE *file, - struct collection_item *error_list) -{ - struct collection_iterator *iterator; - int error; - struct collection_item *item = NULL; - struct collection_item *file_errors = NULL; - - TRACE_FLOW_STRING("print_config_parsing_errors", "Entry"); - - /* If we have something to print print it */ - if (error_list == NULL) { - TRACE_ERROR_STRING("No error list", ""); - return; - } - - /* Make sure we go the right collection */ - if (!col_is_of_class(error_list, COL_CLASS_INI_PESET)) { - TRACE_ERROR_STRING("Wrong collection class:", WRONG_COLLECTION); - fprintf(file, "%s\n", WRONG_COLLECTION); - return; - } - - /* Bind iterator */ - error = col_bind_iterator(&iterator, error_list, COL_TRAVERSE_DEFAULT); - if (error) { - TRACE_ERROR_STRING("Error (bind):", FAILED_TO_PROCCESS); - fprintf(file,"%s\n", FAILED_TO_PROCCESS); - return; - } - - while(1) { - /* Loop through a collection */ - error = col_iterate_collection(iterator, &item); - if (error) { - TRACE_ERROR_STRING("Error (iterate):", FAILED_TO_PROCCESS); - fprintf(file, "%s\n", FAILED_TO_PROCCESS); - col_unbind_iterator(iterator); - return; - } - - /* Are we done ? */ - if (item == NULL) break; - - /* Print per file sets of errors */ - if (col_get_item_type(item) == COL_TYPE_COLLECTIONREF) { - /* Extract a sub collection */ - error = col_get_reference_from_item(item, &file_errors); - if (error) { - TRACE_ERROR_STRING("Error (extract):", FAILED_TO_PROCCESS); - fprintf(file, "%s\n", FAILED_TO_PROCCESS); - col_unbind_iterator(iterator); - return; - } - print_file_parsing_errors(file, file_errors); - col_destroy_collection(file_errors); - } - } - - /* Do not forget to unbind iterator - otherwise there will be a leak */ - col_unbind_iterator(iterator); - - TRACE_FLOW_STRING("print_config_parsing_errors", "Exit"); -} - - -/* Function to get value from the configration handle */ -int get_config_item(const char *section, - const char *name, - struct collection_item *ini_config, - struct collection_item **item) -{ - int error = EOK; - struct collection_item *section_handle = NULL; - const char *to_find; - char default_section[] = INI_DEFAULT_SECTION; - - TRACE_FLOW_STRING("get_config_item", "Entry"); - - /* Do we have the accepting memory ? */ - if (item == NULL) { - TRACE_ERROR_NUMBER("No buffer - invalid argument.", EINVAL); - return EINVAL; - } - - /* Is the collection of a right type */ - if ((col_is_of_class(ini_config, COL_CLASS_INI_CONFIG) == 0) && - (col_is_of_class(ini_config, COL_CLASS_INI_META) == 0)) { - TRACE_ERROR_NUMBER("Wrong collection type", EINVAL); - return EINVAL; - } - - *item = NULL; - - if (section == NULL) to_find = default_section; - else to_find = section; - - TRACE_INFO_STRING("Getting Name:", name); - TRACE_INFO_STRING("In Section:", section); - - /* Get Subcollection */ - error = col_get_collection_reference(ini_config, §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_STRING("get_value_from_config", "No such section"); - return EOK; - } - - /* Get item */ - error = col_get_item(section_handle, name, - COL_TYPE_STRING, COL_TRAVERSE_ONELEVEL, item); - - /* Make sure we free the section we found */ - col_destroy_collection(section_handle); - - TRACE_FLOW_NUMBER("get_config_item returning", error); - return 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 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 = 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("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_ullong_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; - return def; - } - - TRACE_FLOW_NUMBER("get_ullong_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) -{ - 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) -{ - 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) -{ - 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) -{ - const char *str; - char *endptr; - double val = 0; - - TRACE_FLOW_STRING("get_double_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 = 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_NUMBER("get_double_config_value returning", val); - return val; -} - -/* Get boolean value */ -unsigned char get_bool_config_value(struct collection_item *item, - unsigned char def, int *error) -{ - const char *str; - int len; - - TRACE_FLOW_STRING("get_bool_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; - - str = (const char *)col_get_item_data(item); - len = col_get_item_length(item); - - /* 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 *get_string_config_value(struct collection_item *item, - int *error) -{ - char *str = NULL; - - TRACE_FLOW_STRING("get_string_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 NULL; - } - - str = strdup((const char *)col_get_item_data(item)); - if (str == NULL) { - TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM); - if (error) *error = ENOMEM; - return NULL; - } - - if (error) *error = EOK; - - TRACE_FLOW_STRING("get_string_config_value returning", str); - return str; -} - -/* Get string from item */ -const char *get_const_string_config_value(struct collection_item *item, int *error) -{ - const char *str; - - TRACE_FLOW_STRING("get_const_string_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 NULL; - } - - str = (const char *)col_get_item_data(item); - - if (error) *error = EOK; - - TRACE_FLOW_STRING("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 *get_bin_config_value(struct collection_item *item, - int *length, int *error) -{ - int i; - char *value = NULL; - const char *buff; - int size = 0; - unsigned char hex; - int len; - const char *str; - - TRACE_FLOW_STRING("get_bin_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 NULL; - } - - /* Check the length */ - len = col_get_item_length(item)-1; - if ((len%2) != 0) { - TRACE_ERROR_STRING("Invalid length for binary data", ""); - if (error) *error = EINVAL; - return NULL; - } - - str = (const char *)col_get_item_data(item); - - /* 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 += 2) { - if (!isxdigit(buff[i]) || !isxdigit(buff[i + 1])) { - 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) { - if (isdigit(buff[i])) { - if (isdigit(buff[i+1])) - hex = 16 * (buff[i] - '0') + (buff[i+1] - '0'); - else - hex = 16 * (buff[i] - '0') + (tolower(buff[i+1]) - 'a' + 10); - } - else { - if (isdigit(buff[i+1])) - hex = 16 * (tolower(buff[i]) - 'a') + (buff[i+1] - '0'); - else - hex = 16 * (tolower(buff[i]) - 'a' + 10) + (tolower(buff[i+1]) - 'a' + 10); - } - - value[size] = (char)(hex); - size++; - } - - if (error) *error = EOK; - if (length) *length = size; - TRACE_FLOW_STRING("get_bin_config_value", "Exit"); - return value; -} - -/* Function to free binary configuration value */ -void free_bin_config_value(char *value) -{ - if (value) free(value); -} - -/* Arrays of stings */ -static char **get_str_cfg_array(struct collection_item *item, - int include, - const char *sep, - int *size, - int *error) -{ - char *copy = NULL; - char *dest = NULL; - char locsep[4]; - int lensep; - char *buff; - int count = 0; - int len = 0; - int resume_len; - char **array; - char *start; - int i, j; - int dlen; - - TRACE_FLOW_STRING("get_str_cfg_array", "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 NULL; - } - - /* Handle the separators */ - if (sep == NULL) { - locsep[0] = ','; - locsep[1] = '\0'; - lensep = 2; - } - else { - strncpy(locsep, sep, 3); - locsep[3] = '\0'; - lensep = strlen(locsep) + 1; - } - - /* Allocate memory for the copy of the string */ - copy = malloc(col_get_item_length(item)); - if (copy == NULL) { - TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM); - if (error) *error = ENOMEM; - return NULL; - } - - /* Loop through the string */ - dest = copy; - buff = col_get_item_data(item); - start = buff; - dlen = col_get_item_length(item); - 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 increas 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 = copy; - for (i = 0; i < count; i++) { - TRACE_INFO_STRING("Token :", start); - TRACE_INFO_NUMBER("Item :", i); - array[i] = start; - /* Move to next item */ - while(*start) start++; - start++; - } - array[count] = NULL; - - if (error) *error = EOK; - if (size) *size = count; - TRACE_FLOW_STRING("get_str_cfg_array", "Exit"); - return array; -} - -/* Get array of strings from item eliminating empty tokens */ -char **get_string_config_array(struct collection_item *item, - const char *sep, int *size, int *error) -{ - TRACE_FLOW_STRING("get_string_config_array", "Called."); - return get_str_cfg_array(item, EXCLUDE_EMPTY, sep, size, error); -} -/* Get array of strings from item preserving empty tokens */ -char **get_raw_string_config_array(struct collection_item *item, - const char *sep, int *size, int *error) -{ - TRACE_FLOW_STRING("get_raw_string_config_array", "Called."); - return get_str_cfg_array(item, INCLUDE_EMPTY, sep, size, error); -} - -/* Special function to free string config array */ -void free_string_config_array(char **str_config) -{ - TRACE_FLOW_STRING("free_string_config_array", "Entry"); - - if (str_config != NULL) { - if (*str_config != NULL) free(*str_config); - free(str_config); - } - - TRACE_FLOW_STRING("free_string_config_array", "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 *get_long_config_array(struct collection_item *item, int *size, int *error) -{ - const char *str; - char *endptr; - long val = 0; - long *array; - int count = 0; - int err; - - TRACE_FLOW_STRING("get_long_config_array", "Entry"); - - /* Do we have the item ? */ - if ((item == NULL) || - (col_get_item_type(item) != COL_TYPE_STRING) || - (size == NULL)) { - TRACE_ERROR_NUMBER("Invalid argument.", EINVAL); - if (error) *error = EINVAL; - return NULL; - } - - /* Assume that we have maximum number of different numbers */ - array = (long *)malloc(sizeof(long) * col_get_item_length(item)/2); - if (array == NULL) { - TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM); - if (error) *error = ENOMEM; - return NULL; - } - - /* Now parse the string */ - str = (const char *)col_get_item_data(item); - 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_NUMBER("get_long_config_value returning", val); - return array; - -} - -/* Get an array of double values */ -double *get_double_config_array(struct collection_item *item, int *size, int *error) -{ - const char *str; - char *endptr; - double val = 0; - double *array; - int count = 0; - struct lconv *loc; - - TRACE_FLOW_STRING("get_double_config_array", "Entry"); - - /* Do we have the item ? */ - if ((item == NULL) || - (col_get_item_type(item) != COL_TYPE_STRING) || - (size == NULL)) { - TRACE_ERROR_NUMBER("Invalid argument.", EINVAL); - if (error) *error = EINVAL; - return NULL; - } - - /* Assume that we have maximum number of different numbers */ - array = (double *)malloc(sizeof(double) * col_get_item_length(item)/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 */ - str = (const char *)col_get_item_data(item); - 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_NUMBER("get_double_config_value returning", val); - return array; - -} - - -/* Special function to free long config array */ -void free_long_config_array(long *array) -{ - if (array != NULL) free(array); -} - -/* Special function to free double config array */ -void free_double_config_array(double *array) -{ - if (array != NULL) free(array); -} - -/* The section array should be freed using this function */ -void free_section_list(char **section_list) -{ - TRACE_FLOW_STRING("free_section_list","Entry"); - - col_free_property_list(section_list); - - TRACE_FLOW_STRING("free_section_list","Exit"); -} - -/* The section array should be freed using this function */ -void free_attribute_list(char **section_list) -{ - TRACE_FLOW_STRING("free_section_list","Entry"); - - col_free_property_list(section_list); - - TRACE_FLOW_STRING("free_section_list","Exit"); -} - - -/* Get list of sections as an array of strings. - * Function allocates memory for the array of the sections. - */ -char **get_section_list(struct collection_item *ini_config, int *size, int *error) -{ - char **list; - - TRACE_FLOW_STRING("get_section_list","Entry"); - /* Do we have the item ? */ - if ((ini_config == NULL) || - ((col_is_of_class(ini_config, COL_CLASS_INI_CONFIG) == 0) && - (col_is_of_class(ini_config, COL_CLASS_INI_META) == 0))) { - 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, size, error); - - TRACE_FLOW_STRING("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 **get_attribute_list(struct collection_item *ini_config, const char *section, int *size, int *error) -{ - struct collection_item *subcollection = NULL; - char **list; - int err; - - TRACE_FLOW_STRING("get_attribute_list","Entry"); - /* Do we have the item ? */ - if ((ini_config == NULL) || - ((col_is_of_class(ini_config, COL_CLASS_INI_CONFIG) == 0) && - (col_is_of_class(ini_config, COL_CLASS_INI_META) == 0)) || - (section == NULL)) { - TRACE_ERROR_NUMBER("Invalid argument.", EINVAL); - if (error) *error = EINVAL; - return NULL; - } - - /* Fetch section */ - err = col_get_collection_reference(ini_config, &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); - - TRACE_FLOW_STRING("get_attribute_list returning", ((list == NULL) ? "NULL" : list[0])); - return list; -} |