From 5a5eb2619fed6b37178d3b2c58970788c55cb529 Mon Sep 17 00:00:00 2001 From: Dmitri Pal Date: Thu, 15 Apr 2010 17:27:04 -0400 Subject: Code restructuring Time came to split ini_config.c into many much smaller pieces. 1) ini_parse.c - will have parsing functions 2) ini_get_value.c - will have single value interpretation functions 3) ini_get_array.c - will have array interpretation functions. 4) ini_print.c - error printing 5) ini_defines.h - common constants 6) ini_parse.h header for parsing functions 7) ini_list.c - will have list processing functions --- common/ini/ini_get_array.c | 354 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 354 insertions(+) create mode 100644 common/ini/ini_get_array.c (limited to 'common/ini/ini_get_array.c') diff --git a/common/ini/ini_get_array.c b/common/ini/ini_get_array.c new file mode 100644 index 00000000..c2c6362a --- /dev/null +++ b/common/ini/ini_get_array.c @@ -0,0 +1,354 @@ +/* + INI LIBRARY + + Value interpretation functions for arrays of values + and corresponding memory cleanup functions. + + Copyright (C) Dmitri Pal 2010 + + 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 . +*/ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include "config.h" +#include "trace.h" +#include "collection.h" +#include "collection_tools.h" +#include "ini_defines.h" +#include "ini_config.h" + +/* + * Internal contants to indicate how + * to process the lists of strings. + */ +#define EXCLUDE_EMPTY 0 +#define INCLUDE_EMPTY 1 + +/* 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); +} -- cgit