summaryrefslogtreecommitdiffstats
path: root/common/ini/ini_config.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/ini/ini_config.c')
-rw-r--r--common/ini/ini_config.c1476
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, &section_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;
-}