LCOV - code coverage report
Current view: top level - ini - ini_get_array_valueobj.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 122 141 86.5 %
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> 2012
       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_configobj.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             : /* Maximum number of separators supported. Do not make it less than 3. */
      44             : #define MAX_SEP_LEN     3
      45             : 
      46             : /* Arrays of stings */
      47          20 : static char **get_str_cfg_array(struct value_obj *vo,
      48             :                                 int include,
      49             :                                 const char *sep,
      50             :                                 int *size,
      51             :                                 int *error)
      52             : {
      53          20 :     char *copy = NULL;
      54          20 :     char *dest = NULL;
      55             :     char locsep[MAX_SEP_LEN + 1];
      56             :     uint32_t lensep;
      57             :     const char *buff;
      58          20 :     uint32_t count = 0;
      59          20 :     uint32_t len = 0;
      60             :     uint32_t resume_len;
      61             :     char **array;
      62             :     const char *start;
      63             :     char *start_array;
      64             :     uint32_t i, j;
      65             :     uint32_t dlen;
      66             : 
      67             :     TRACE_FLOW_ENTRY();
      68             : 
      69             :     /* Do we have the vo ? */
      70          20 :     if (vo == NULL) {
      71             :         TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
      72           0 :         if (error) *error = EINVAL;
      73             :         return NULL;
      74             :     }
      75             : 
      76             :     /* Get value and length - no error checking as we checked it above
      77             :      * and there is no other reson the function could to fail.
      78             :      */
      79          20 :     value_get_concatenated(vo, &buff);
      80          20 :     value_get_concatenated_len(vo, &dlen);
      81             : 
      82             :     /* Handle the separators */
      83          20 :     if (sep == NULL) {
      84           0 :         locsep[0] = ',';
      85           0 :         locsep[1] = '\0';
      86           0 :         lensep = 2;
      87             :     }
      88             :     else {
      89          20 :         strncpy(locsep, sep, MAX_SEP_LEN);
      90          20 :         locsep[MAX_SEP_LEN] = '\0';
      91          20 :         lensep = strlen(locsep) + 1;
      92             :     }
      93             : 
      94             :     /* Allocate memory for the copy of the string */
      95             :     TRACE_INFO_NUMBER("Length to allocate is :", dlen);
      96             :     /* Always reserve one more byte 
      97             :      * for the case when the string consist of delimeters */
      98          20 :     copy = malloc(dlen + 1);
      99          20 :     if (copy == NULL) {
     100             :         TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM);
     101           0 :         if (error) *error = ENOMEM;
     102             :         return NULL;
     103             :     }
     104             : 
     105             :     /* Suppress warning */
     106          20 :     start = buff;
     107             : 
     108             :     /* Loop through the string */
     109          20 :     dest = copy;
     110         319 :     for(i = 0; i < dlen; i++) {
     111         638 :         for(j = 0; j < lensep; j++) {
     112         715 :             if(buff[i] == locsep[j]) {
     113             :                 /* If we found one of the separators trim spaces around */
     114             :                 resume_len = len;
     115         101 :                 while (len > 0) {
     116          48 :                     if (isspace(start[len - 1])) len--;
     117             :                     else break;
     118             :                 }
     119             :                 TRACE_INFO_STRING("Current:", start);
     120             :                 TRACE_INFO_NUMBER("Length:", len);
     121          77 :                 if (len > 0) {
     122             :                     /* Save block aside */
     123          24 :                     memcpy(dest, start, len);
     124          24 :                     count++;
     125          24 :                     dest += len;
     126          24 :                     *dest = '\0';
     127          24 :                     dest++;
     128             :                 }
     129          53 :                 else if(include) {
     130          24 :                     count++;
     131          24 :                     *dest = '\0';
     132          24 :                     dest++;
     133             :                 }
     134             : 
     135             :                 /* Move forward and trim spaces if any */
     136          77 :                 start += resume_len + 1;
     137          77 :                 i++;
     138             :                 TRACE_INFO_STRING("Other pointer :", buff + i);
     139         327 :                 while ((i < dlen) && (isspace(*start))) {
     140         173 :                     i++;
     141         173 :                     start++;
     142             :                 }
     143          77 :                 len = -1; /* Len will be increased in the loop */
     144          77 :                 i--; /* i will be increased so we need to step back */
     145             :                 TRACE_INFO_STRING("Remaining buffer after triming spaces:",
     146             :                                   start);
     147          77 :                 break;
     148             :             }
     149             :         }
     150         299 :         len++;
     151             :     }
     152             : 
     153             :     /* Save last segment */
     154             :     TRACE_INFO_STRING("Current:", start);
     155             :     TRACE_INFO_NUMBER("Length:", len);
     156          20 :     if (len > 0) {
     157             :         /* Save block aside */
     158           2 :         memcpy(dest, start, len);
     159           2 :         count++;
     160           2 :         dest += len;
     161           2 :         *dest = '\0';
     162             :     }
     163          18 :     else if(include && dlen && count) {
     164             :         TRACE_INFO_NUMBER("Include :", include);
     165             :         TRACE_INFO_NUMBER("dlen :", dlen);
     166             :         TRACE_INFO_NUMBER("Count :", count);
     167           7 :         count++;
     168           7 :         *dest = '\0';
     169             :     }
     170             : 
     171             :     /* Now we know how many items are there in the list */
     172          20 :     array = malloc((count + 1) * sizeof(char *));
     173          20 :     if (array == NULL) {
     174           0 :         free(copy);
     175             :         TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM);
     176           0 :         if (error) *error = ENOMEM;
     177             :         return NULL;
     178             :     }
     179             : 
     180             :     /* Loop again to fill in the pointers */
     181             :     start_array = copy;
     182          57 :     for (i = 0; i < count; i++) {
     183             :         TRACE_INFO_STRING("Token :", start_array);
     184             :         TRACE_INFO_NUMBER("Item :", i);
     185          57 :         array[i] = start_array;
     186             :         /* Move to next item */
     187          57 :         while(*start_array) start_array++;
     188          57 :         start_array++;
     189             :     }
     190          20 :     array[count] = NULL;
     191             : 
     192          20 :     if (error) *error = EOK;
     193          20 :     if (size) *size = count;
     194             :     /* If count is 0 the copy needs to be freed */
     195          20 :     if (count == 0) free(copy);
     196             : 
     197             :     TRACE_FLOW_EXIT();
     198          20 :     return array;
     199             : }
     200             : 
     201             : /* Get array of strings from item eliminating empty tokens */
     202          11 : char **ini_get_string_config_array(struct value_obj *vo,
     203             :                                    const char *sep, int *size, int *error)
     204             : {
     205             :     TRACE_FLOW_ENTRY();
     206          11 :     return get_str_cfg_array(vo, EXCLUDE_EMPTY, sep, size, error);
     207             : }
     208             : /* Get array of strings from item preserving empty tokens */
     209           9 : char **ini_get_raw_string_config_array(struct value_obj *vo,
     210             :                                        const char *sep, int *size, int *error)
     211             : {
     212             :     TRACE_FLOW_ENTRY();
     213           9 :     return get_str_cfg_array(vo, INCLUDE_EMPTY, sep, size, error);
     214             : }
     215             : 
     216             : /* Special function to free string config array */
     217          20 : void ini_free_string_config_array(char **str_config)
     218             : {
     219             :     TRACE_FLOW_ENTRY();
     220             : 
     221          20 :     if (str_config != NULL) {
     222          20 :         if (*str_config != NULL) free(*str_config);
     223          20 :         free(str_config);
     224             :     }
     225             : 
     226             :     TRACE_FLOW_EXIT();
     227          20 : }
     228             : 
     229             : /* Get an array of long values.
     230             :  * NOTE: For now I leave just one function that returns numeric arrays.
     231             :  * In future if we need other numeric types we can change it to do strtoll
     232             :  * internally and wrap it for backward compatibility.
     233             :  */
     234           1 : long *ini_get_long_config_array(struct value_obj *vo, int *size, int *error)
     235             : {
     236             :     const char *str;
     237             :     char *endptr;
     238           1 :     long val = 0;
     239             :     long *array;
     240           1 :     uint32_t count = 0;
     241             :     int err;
     242             :     uint32_t dlen;
     243             : 
     244             :     TRACE_FLOW_ENTRY();
     245             : 
     246             :     /* Do we have the vo ? */
     247           1 :     if (vo == NULL) {
     248             :         TRACE_ERROR_NUMBER("Invalid value object argument.", EINVAL);
     249           0 :         if (error) *error = EINVAL;
     250             :         return NULL;
     251             :     }
     252             : 
     253             :     /* Do we have the size ? */
     254           1 :     if (size == NULL) {
     255             :         TRACE_ERROR_NUMBER("Invalid size argument.", EINVAL);
     256           0 :         if (error) *error = EINVAL;
     257             :         return NULL;
     258             :     }
     259             : 
     260             :     /* Get value and length - no error checking as we checked it above
     261             :      * and there is no other reson the function could to fail.
     262             :      */
     263           1 :     value_get_concatenated(vo, &str);
     264           1 :     value_get_concatenated_len(vo, &dlen);
     265             : 
     266             :     /* Assume that we have maximum number of different numbers */
     267           1 :     array = (long *)malloc(sizeof(long) * dlen/2);
     268           1 :     if (array == NULL) {
     269             :         TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM);
     270           0 :         if (error) *error = ENOMEM;
     271             :         return NULL;
     272             :     }
     273             : 
     274             :     /* Now parse the string */
     275           7 :     while (*str) {
     276             : 
     277           6 :         errno = 0;
     278           6 :         val = strtol(str, &endptr, 10);
     279           6 :         err = errno;
     280             : 
     281           6 :         if (err) {
     282             :             TRACE_ERROR_NUMBER("Conversion failed", err);
     283           0 :             free(array);
     284           0 :             if (error) *error = err;
     285             :             return NULL;
     286             :         }
     287             : 
     288           6 :         if (endptr == str) {
     289             :             TRACE_ERROR_NUMBER("Nothing processed", EIO);
     290           0 :             free(array);
     291           0 :             if (error) *error = EIO;
     292             :             return NULL;
     293             :         }
     294             : 
     295             :         /* Save value */
     296           6 :         array[count] = val;
     297           6 :         count++;
     298             :         /* Are we done? */
     299           6 :         if (*endptr == 0) break;
     300             :         /* Advance to the next valid number */
     301          19 :         for (str = endptr; *str; str++) {
     302          18 :             if (isdigit(*str) || (*str == '-') || (*str == '+')) break;
     303             :         }
     304             :     }
     305             : 
     306           1 :     *size = count;
     307           1 :     if (error) *error = EOK;
     308             : 
     309             :     TRACE_FLOW_EXIT();
     310           1 :     return array;
     311             : 
     312             : }
     313             : 
     314             : /* Get an array of double values */
     315           1 : double *ini_get_double_config_array(struct value_obj *vo, int *size, int *error)
     316             : {
     317             :     const char *str;
     318             :     char *endptr;
     319           1 :     double val = 0;
     320             :     double *array;
     321           1 :     int count = 0;
     322             :     struct lconv *loc;
     323             :     uint32_t dlen;
     324             : 
     325             :     TRACE_FLOW_ENTRY();
     326             : 
     327             :     /* Do we have the vo ? */
     328           1 :     if (vo == NULL) {
     329             :         TRACE_ERROR_NUMBER("Invalid value object argument.", EINVAL);
     330           0 :         if (error) *error = EINVAL;
     331             :         return NULL;
     332             :     }
     333             : 
     334             :     /* Do we have the size ? */
     335           1 :     if (size == NULL) {
     336             :         TRACE_ERROR_NUMBER("Invalid size argument.", EINVAL);
     337           0 :         if (error) *error = EINVAL;
     338             :         return NULL;
     339             :     }
     340             : 
     341             :     /* Get value and length - no error checking as we checked it above
     342             :      * and there is no other reson the function could to fail.
     343             :      */
     344           1 :     value_get_concatenated(vo, &str);
     345           1 :     value_get_concatenated_len(vo, &dlen);
     346             : 
     347             : 
     348             :     /* Assume that we have maximum number of different numbers */
     349           1 :     array = (double *)malloc(sizeof(double) * dlen/2);
     350           1 :     if (array == NULL) {
     351             :         TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM);
     352           0 :         if (error) *error = ENOMEM;
     353             :         return NULL;
     354             :     }
     355             : 
     356             :     /* Get locale information so that we can check for decimal point character.
     357             :      * Based on the man pages it is unclear if this is an allocated memory or not.
     358             :      * Seems like it is a static thread or process local structure so
     359             :      * I will not try to free it after use.
     360             :      */
     361           1 :     loc = localeconv();
     362             : 
     363             :     /* Now parse the string */
     364           8 :     while (*str) {
     365             :         TRACE_INFO_STRING("String to convert",str);
     366           6 :         errno = 0;
     367           6 :         val = strtod(str, &endptr);
     368           6 :         if ((errno == ERANGE) ||
     369           6 :             ((errno != 0) && (val == 0)) ||
     370           6 :             (endptr == str)) {
     371             :             TRACE_ERROR_NUMBER("Conversion failed", EIO);
     372           0 :             free(array);
     373           0 :             if (error) *error = EIO;
     374             :             return NULL;
     375             :         }
     376             :         /* Save value */
     377           6 :         array[count] = val;
     378           6 :         count++;
     379             :         /* Are we done? */
     380           6 :         if (*endptr == 0) break;
     381             :         TRACE_INFO_STRING("End pointer after conversion",endptr);
     382             :         /* Advance to the next valid number */
     383          20 :         for (str = endptr; *str; str++) {
     384          35 :             if (isdigit(*str) || (*str == '-') || (*str == '+') ||
     385             :                /* It is ok to do this since the string is null terminated */
     386          19 :                ((*str == *(loc->decimal_point)) && isdigit(str[1]))) break;
     387             :         }
     388             :     }
     389             : 
     390           1 :     *size = count;
     391           1 :     if (error) *error = EOK;
     392             : 
     393             :     TRACE_FLOW_EXIT();
     394           1 :     return array;
     395             : 
     396             : }
     397             : 
     398             : /* Special function to free long config array */
     399           1 : void ini_free_long_config_array(long *array)
     400             : {
     401           1 :     free(array);
     402           1 : }
     403             : 
     404             : /* Special function to free double config array */
     405           1 : void ini_free_double_config_array(double *array)
     406             : {
     407           1 :     free(array);
     408           1 : }

Generated by: LCOV version 1.10