diff options
author | Dmitri Pal <dpal@redhat.com> | 2012-07-19 18:14:37 -0400 |
---|---|---|
committer | Jakub Hrozek <jhrozek@redhat.com> | 2012-10-17 14:02:52 +0200 |
commit | aa65942aa19e6aea576c71fff9e3e385e2e15cc7 (patch) | |
tree | dec33cad6644c0d9d4ed969854101a66d7388084 /ini/ini_get_array_valueobj.c | |
parent | d18cb68d460e377716e9cc510ce6802403f933a5 (diff) | |
download | ding-libs-aa65942aa19e6aea576c71fff9e3e385e2e15cc7.tar.gz ding-libs-aa65942aa19e6aea576c71fff9e3e385e2e15cc7.tar.xz ding-libs-aa65942aa19e6aea576c71fff9e3e385e2e15cc7.zip |
The implementation of the new interface
The three files in the patch implement the functions
of the new interface. It is mostly inspired by the old
interface except that the string value is replaced with
the value object that hides all the metadata about
the value itself. The main function to get value
now allows more than one value per key.
Diffstat (limited to 'ini/ini_get_array_valueobj.c')
-rw-r--r-- | ini/ini_get_array_valueobj.c | 389 |
1 files changed, 389 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); +} |