LCOV - code coverage report
Current view: top level - ini - ini_get_array.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 114 131 87.0 %
Date: 2014-04-01 Functions: 8 8 100.0 %

          Line data    Source code
       1             : /*
       2             :     INI LIBRARY
       3             : 
       4             :     Value interpretation functions for arrays of values
       5             :     and corresponding memory cleanup functions.
       6             : 
       7             :     Copyright (C) Dmitri Pal <dpal@redhat.com> 2010
       8             : 
       9             :     INI Library is free software: you can redistribute it and/or modify
      10             :     it under the terms of the GNU Lesser General Public License as published by
      11             :     the Free Software Foundation, either version 3 of the License, or
      12             :     (at your option) any later version.
      13             : 
      14             :     INI Library is distributed in the hope that it will be useful,
      15             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :     GNU Lesser General Public License for more details.
      18             : 
      19             :     You should have received a copy of the GNU Lesser General Public License
      20             :     along with INI Library.  If not, see <http://www.gnu.org/licenses/>.
      21             : */
      22             : 
      23             : #include "config.h"
      24             : #include <stdio.h>
      25             : #include <errno.h>
      26             : #include <string.h>
      27             : #include <stdlib.h>
      28             : #include <ctype.h>
      29             : #include <locale.h>
      30             : #include "trace.h"
      31             : #include "collection.h"
      32             : #include "collection_tools.h"
      33             : #include "ini_defines.h"
      34             : #include "ini_config.h"
      35             : 
      36             : /*
      37             :  * Internal contants to indicate how
      38             :  * to process the lists of strings.
      39             :  */
      40             : #define EXCLUDE_EMPTY   0
      41             : #define INCLUDE_EMPTY   1
      42             : 
      43             : /* Arrays of stings */
      44           6 : static char **get_str_cfg_array(struct collection_item *item,
      45             :                                 int include,
      46             :                                 const char *sep,
      47             :                                 int *size,
      48             :                                 int *error)
      49             : {
      50           6 :     char *copy = NULL;
      51           6 :     char *dest = NULL;
      52             :     char locsep[4];
      53             :     int lensep;
      54             :     char *buff;
      55           6 :     int count = 0;
      56           6 :     int len = 0;
      57             :     int resume_len;
      58             :     char **array;
      59             :     char *start;
      60             :     int i, j;
      61             :     int dlen;
      62             : 
      63             :     TRACE_FLOW_STRING("get_str_cfg_array", "Entry");
      64             : 
      65             :     /* Do we have the item ? */
      66          12 :     if ((item == NULL) ||
      67           6 :         (col_get_item_type(item) != COL_TYPE_STRING)) {
      68             :         TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
      69           0 :         if (error) *error = EINVAL;
      70             :         return NULL;
      71             :     }
      72             : 
      73             :     /* Handle the separators */
      74           6 :     if (sep == NULL) {
      75           0 :         locsep[0] = ',';
      76           0 :         locsep[1] = '\0';
      77           0 :         lensep = 2;
      78             :     }
      79             :     else {
      80           6 :         strncpy(locsep, sep, 3);
      81           6 :         locsep[3] = '\0';
      82           6 :         lensep = strlen(locsep) + 1;
      83             :     }
      84             : 
      85             :     /* Allocate memory for the copy of the string */
      86           6 :     copy = malloc(col_get_item_length(item));
      87           6 :     if (copy == NULL) {
      88             :         TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM);
      89           0 :         if (error) *error = ENOMEM;
      90             :         return NULL;
      91             :     }
      92             : 
      93             :     /* Loop through the string */
      94           6 :     dest = copy;
      95           6 :     buff = col_get_item_data(item);
      96           6 :     start = buff;
      97           6 :     dlen = col_get_item_length(item);
      98         177 :     for(i = 0; i < dlen; i++) {
      99         270 :         for(j = 0; j < lensep; j++) {
     100         309 :             if(buff[i] == locsep[j]) {
     101             :                 /* If we found one of the separators trim spaces around */
     102             :                 resume_len = len;
     103          55 :                 while (len > 0) {
     104          28 :                     if (isspace(start[len - 1])) len--;
     105             :                     else break;
     106             :                 }
     107             :                 TRACE_INFO_STRING("Current:", start);
     108             :                 TRACE_INFO_NUMBER("Length:", len);
     109          39 :                 if (len > 0) {
     110             :                     /* Save block aside */
     111          12 :                     memcpy(dest, start, len);
     112          12 :                     count++;
     113          12 :                     dest += len;
     114          12 :                     *dest = '\0';
     115          12 :                     dest++;
     116             :                 }
     117          27 :                 else if(include) {
     118          10 :                     count++;
     119          10 :                     *dest = '\0';
     120          10 :                     dest++;
     121             :                 }
     122          39 :                 if (locsep[j] == '\0') break; /* We are done */
     123             : 
     124             :                 /* Move forward and trim spaces if any */
     125          33 :                 start += resume_len + 1;
     126          33 :                 i++;
     127             :                 TRACE_INFO_STRING("Other pointer :", buff + i);
     128         163 :                 while ((i < dlen) && (isspace(*start))) {
     129          97 :                     i++;
     130          97 :                     start++;
     131             :                 }
     132          33 :                 len = -1; /* Len will be increased in the loop */
     133          33 :                 i--; /* i will be increas so we need to step back */
     134             :                 TRACE_INFO_STRING("Remaining buffer after triming spaces:", start);
     135          33 :                 break;
     136             :             }
     137             :         }
     138         171 :         len++;
     139             :     }
     140             : 
     141             :     /* Now we know how many items are there in the list */
     142           6 :     array = malloc((count + 1) * sizeof(char *));
     143           6 :     if (array == NULL) {
     144           0 :         free(copy);
     145             :         TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM);
     146           0 :         if (error) *error = ENOMEM;
     147             :         return NULL;
     148             :     }
     149             : 
     150             :     /* Loop again to fill in the pointers */
     151             :     start = copy;
     152          22 :     for (i = 0; i < count; i++) {
     153             :         TRACE_INFO_STRING("Token :", start);
     154             :         TRACE_INFO_NUMBER("Item :", i);
     155          22 :         array[i] = start;
     156             :         /* Move to next item */
     157          22 :         while(*start) start++;
     158          22 :         start++;
     159             :     }
     160           6 :     array[count] = NULL;
     161             : 
     162           6 :     if (error) *error = EOK;
     163           6 :     if (size) *size = count;
     164             :     /* If count is 0 the copy needs to be freed */
     165           6 :     if (count == 0) free(copy);
     166             :     TRACE_FLOW_STRING("get_str_cfg_array", "Exit");
     167           6 :     return array;
     168             : }
     169             : 
     170             : /* Get array of strings from item eliminating empty tokens */
     171           4 : char **get_string_config_array(struct collection_item *item,
     172             :                                const char *sep, int *size, int *error)
     173             : {
     174             :     TRACE_FLOW_STRING("get_string_config_array", "Called.");
     175           4 :     return get_str_cfg_array(item, EXCLUDE_EMPTY, sep, size, error);
     176             : }
     177             : /* Get array of strings from item preserving empty tokens */
     178           2 : char **get_raw_string_config_array(struct collection_item *item,
     179             :                                    const char *sep, int *size, int *error)
     180             : {
     181             :     TRACE_FLOW_STRING("get_raw_string_config_array", "Called.");
     182           2 :     return get_str_cfg_array(item, INCLUDE_EMPTY, sep, size, error);
     183             : }
     184             : 
     185             : /* Special function to free string config array */
     186           6 : void free_string_config_array(char **str_config)
     187             : {
     188             :     TRACE_FLOW_STRING("free_string_config_array", "Entry");
     189             : 
     190           6 :     if (str_config != NULL) {
     191           6 :         if (*str_config != NULL) free(*str_config);
     192           6 :         free(str_config);
     193             :     }
     194             : 
     195             :     TRACE_FLOW_STRING("free_string_config_array", "Exit");
     196           6 : }
     197             : 
     198             : /* Get an array of long values.
     199             :  * NOTE: For now I leave just one function that returns numeric arrays.
     200             :  * In future if we need other numeric types we can change it to do strtoll
     201             :  * internally and wrap it for backward compatibility.
     202             :  */
     203           1 : long *get_long_config_array(struct collection_item *item, int *size, int *error)
     204             : {
     205             :     const char *str;
     206             :     char *endptr;
     207           1 :     long val = 0;
     208             :     long *array;
     209           1 :     int count = 0;
     210             :     int err;
     211             : 
     212             :     TRACE_FLOW_STRING("get_long_config_array", "Entry");
     213             : 
     214             :     /* Do we have the item ? */
     215           2 :     if ((item == NULL) ||
     216           2 :         (col_get_item_type(item) != COL_TYPE_STRING) ||
     217             :         (size == NULL)) {
     218             :         TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
     219           0 :         if (error) *error = EINVAL;
     220             :         return NULL;
     221             :     }
     222             : 
     223             :     /* Assume that we have maximum number of different numbers */
     224           1 :     array = (long *)malloc(sizeof(long) * col_get_item_length(item)/2);
     225           1 :     if (array == NULL) {
     226             :         TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM);
     227           0 :         if (error) *error = ENOMEM;
     228             :         return NULL;
     229             :     }
     230             : 
     231             :     /* Now parse the string */
     232           1 :     str = (const char *)col_get_item_data(item);
     233           8 :     while (*str) {
     234             : 
     235           6 :         errno = 0;
     236           6 :         val = strtol(str, &endptr, 10);
     237           6 :         err = errno;
     238             : 
     239           6 :         if (err) {
     240             :             TRACE_ERROR_NUMBER("Conversion failed", err);
     241           0 :             free(array);
     242           0 :             if (error) *error = err;
     243             :             return NULL;
     244             :         }
     245             : 
     246           6 :         if (endptr == str) {
     247             :             TRACE_ERROR_NUMBER("Nothing processed", EIO);
     248           0 :             free(array);
     249           0 :             if (error) *error = EIO;
     250             :             return NULL;
     251             :         }
     252             : 
     253             :         /* Save value */
     254           6 :         array[count] = val;
     255           6 :         count++;
     256             :         /* Are we done? */
     257           6 :         if (*endptr == 0) break;
     258             :         /* Advance to the next valid number */
     259          13 :         for (str = endptr; *str; str++) {
     260          18 :             if (isdigit(*str) || (*str == '-') || (*str == '+')) break;
     261             :         }
     262             :     }
     263             : 
     264           1 :     *size = count;
     265           1 :     if (error) *error = EOK;
     266             : 
     267             :     TRACE_FLOW_NUMBER("get_long_config_value returning", val);
     268           1 :     return array;
     269             : 
     270             : }
     271             : 
     272             : /* Get an array of double values */
     273           1 : double *get_double_config_array(struct collection_item *item, int *size, int *error)
     274             : {
     275             :     const char *str;
     276             :     char *endptr;
     277           1 :     double val = 0;
     278             :     double *array;
     279           1 :     int count = 0;
     280             :     struct lconv *loc;
     281             : 
     282             :     TRACE_FLOW_STRING("get_double_config_array", "Entry");
     283             : 
     284             :     /* Do we have the item ? */
     285           2 :     if ((item == NULL) ||
     286           2 :         (col_get_item_type(item) != COL_TYPE_STRING) ||
     287             :         (size == NULL)) {
     288             :         TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
     289           0 :         if (error) *error = EINVAL;
     290             :         return NULL;
     291             :     }
     292             : 
     293             :     /* Assume that we have maximum number of different numbers */
     294           1 :     array = (double *)malloc(sizeof(double) * col_get_item_length(item)/2);
     295           1 :     if (array == NULL) {
     296             :         TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM);
     297           0 :         if (error) *error = ENOMEM;
     298             :         return NULL;
     299             :     }
     300             : 
     301             :     /* Get locale information so that we can check for decimal point character.
     302             :      * Based on the man pages it is unclear if this is an allocated memory or not.
     303             :      * Seems like it is a static thread or process local structure so
     304             :      * I will not try to free it after use.
     305             :      */
     306           1 :     loc = localeconv();
     307             : 
     308             :     /* Now parse the string */
     309           1 :     str = (const char *)col_get_item_data(item);
     310           8 :     while (*str) {
     311             :         TRACE_INFO_STRING("String to convert",str);
     312           6 :         errno = 0;
     313           6 :         val = strtod(str, &endptr);
     314           6 :         if ((errno == ERANGE) ||
     315           6 :             ((errno != 0) && (val == 0)) ||
     316           6 :             (endptr == str)) {
     317             :             TRACE_ERROR_NUMBER("Conversion failed", EIO);
     318           0 :             free(array);
     319           0 :             if (error) *error = EIO;
     320             :             return NULL;
     321             :         }
     322             :         /* Save value */
     323           6 :         array[count] = val;
     324           6 :         count++;
     325             :         /* Are we done? */
     326           6 :         if (*endptr == 0) break;
     327             :         TRACE_INFO_STRING("End pointer after conversion",endptr);
     328             :         /* Advance to the next valid number */
     329          14 :         for (str = endptr; *str; str++) {
     330          35 :             if (isdigit(*str) || (*str == '-') || (*str == '+') ||
     331             :                /* It is ok to do this since the string is null terminated */
     332          19 :                ((*str == *(loc->decimal_point)) && isdigit(str[1]))) break;
     333             :         }
     334             :     }
     335             : 
     336           1 :     *size = count;
     337           1 :     if (error) *error = EOK;
     338             : 
     339             :     TRACE_FLOW_NUMBER("get_double_config_value returning", val);
     340           1 :     return array;
     341             : 
     342             : }
     343             : 
     344             : 
     345             : /* Special function to free long config array */
     346           1 : void free_long_config_array(long *array)
     347             : {
     348           1 :     if (array != NULL) free(array);
     349           1 : }
     350             : 
     351             : /* Special function to free double config array */
     352           1 : void free_double_config_array(double *array)
     353             : {
     354           1 :     if (array != NULL) free(array);
     355           1 : }

Generated by: LCOV version 1.10