From ae6fd476d75f2faedcac1ce67914a3ef005fec72 Mon Sep 17 00:00:00 2001
From: Dmitri Pal <dpal@redhat.com>
Date: Fri, 25 Dec 2009 18:54:56 -0500
Subject: [PATCH] INI: Added method to get string list with empty values

The original implementation was compressing the list,
throwing away empty strings.
The function that did that was pretty brain damaging.
I cleaned it up and adjusted so that it could return
list with empty values and without them.
The old function was turned into a wrapper and a new
high level function was intorduced to provide
ability to get both empty and non empty strings.
---
 common/ini/ini_config.c    |  104 +++++++++++++++++++++++---------------------
 common/ini/ini_config.h    |   32 +++++++++++--
 common/ini/ini_config_ut.c |   35 +++++++++++++++
 3 files changed, 117 insertions(+), 54 deletions(-)

diff --git a/common/ini/ini_config.c b/common/ini/ini_config.c
index 17cb53b..67af11b 100644
--- a/common/ini/ini_config.c
+++ b/common/ini/ini_config.c
@@ -42,6 +42,9 @@
 
 #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"
 
@@ -1569,13 +1572,16 @@ void free_bin_config_value(char *value)
     if (value) free(value);
 }
 
-/* Arrays of stings and integers */
-char **get_string_config_array(struct collection_item *item,
-                               const char *sep, int *size, int *error)
+/* Arrays of stings */
+static char **get_str_cfg_array(struct collection_item *item,
+                                int include,
+                                const char *sep,
+                                int *size,
+                                int *error)
 {
-    const char *defsep = ",";
     char *copy = NULL;
     char *dest = NULL;
+    char locsep[4];
     int lensep;
     char *buff;
     int count = 0;
@@ -1583,11 +1589,10 @@ char **get_string_config_array(struct collection_item *item,
     int resume_len;
     char **array;
     char *start;
-    int i, j, k;
-    int growlen = 0;
+    int i, j;
     int dlen;
 
-    TRACE_FLOW_STRING("get_string_config_array", "Entry");
+    TRACE_FLOW_STRING("get_str_cfg_array", "Entry");
 
     /* Do we have the item ? */
     if ((item == NULL) ||
@@ -1598,8 +1603,16 @@ char **get_string_config_array(struct collection_item *item,
     }
 
     /* Handle the separators */
-    if (sep == NULL) sep = defsep;
-    lensep = strnlen(sep, 3);
+    if (sep == NULL) {
+        locsep[0] = ',';
+        locsep[1] = '\0';
+        lensep = 2;
+    }
+    else {
+        strncpy(locsep, sep, 3);
+        locsep[4] = '\0';
+        lensep = strlen(locsep) + 1;
+    }
 
     /* Allocate memory for the copy of the string */
     copy = malloc(col_get_item_length(item));
@@ -1613,17 +1626,18 @@ char **get_string_config_array(struct collection_item *item,
     dest = copy;
     buff = col_get_item_data(item);
     start = buff;
-    dlen = col_get_item_length(item) - 1;
+    dlen = col_get_item_length(item);
     for(i = 0; i < dlen; i++) {
-        growlen = 1;
         for(j = 0; j < lensep; j++) {
-            if(buff[i] == sep[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);
@@ -1631,52 +1645,29 @@ char **get_string_config_array(struct collection_item *item,
                     dest += len;
                     *dest = '\0';
                     dest++;
-                    len = 0;
                 }
+                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);
-                k = 0;
-                while(1) {
-                    TRACE_INFO_STRING("Remaining buffer :", start);
-                    while (((i + k) < dlen) && (isspace(*start))) {
-                        k++;
-                        start++;
-                    }
-                    /* May be we have another separator */
-                    TRACE_INFO_STRING("Remaining before sep check :", start);
-                    if(*start && strchr(sep, *start)) {
-                        TRACE_INFO_NUMBER("Found separator:", *start);
-                        start++;
-                        k++;
-                    }
-                    else {
-                        break;
-                    }
+                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);
-
-                if (k) i += k - 1;
-                /* Next iteration of the loop will add 1 */
-                /* Break out of the inner loop */
-                growlen = 0;
                 break;
             }
         }
-        if (growlen) len++;
-    }
-
-    TRACE_INFO_STRING("Last part :", start);
-    TRACE_INFO_NUMBER("Length :", len);
-    if(len) {
-        /* Copy the remaining piece */
-        memcpy(dest, start, len);
-        count++;
-        dest += len;
-        *dest = '\0';
-        dest++;
+        len++;
     }
 
     /* Now we know how many items are there in the list */
@@ -1702,10 +1693,25 @@ char **get_string_config_array(struct collection_item *item,
 
     if (error) *error = EOK;
     if (size) *size = count;
-    TRACE_FLOW_STRING("get_string_config_array", "Exit");
+    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)
 {
diff --git a/common/ini/ini_config.h b/common/ini/ini_config.h
index 12d4a80..2c906e4 100644
--- a/common/ini/ini_config.h
+++ b/common/ini/ini_config.h
@@ -226,15 +226,37 @@ const char *get_const_string_config_value(struct collection_item *item, int *err
 char *get_bin_config_value(struct collection_item *item, int *length, int *error);
 void free_bin_config_value(char *);
 
-/* Array of stings */
-/* Separator string includes up to three different separators. If NULL comma is assumed. */
-/* The spaces are trimmed automatically around separators in the string. */
-char **get_string_config_array(struct collection_item *item, const char *sep, int *size, int *error);
+/* Array of stings.
+ * Separator string includes up to three different separators. If NULL comma is assumed.
+ * The spaces are trimmed automatically around separators in the string.
+ * The function drops empty tokens from the list.
+ * This means that the string like this: "apple, ,banana, ,orange ,"
+ * will be translated into the list of three items: "apple","banana" and "orange".
+ *
+ * The length of the allocated array is returned in "size".
+ * Size and error parameters can be NULL.
+ * Use free_string_config_array() to free the array after use.
+ */
+char **get_string_config_array(struct collection_item *item,
+                               const char *sep, int *size, int *error);
+
+/* This function is same as above but does not omit empty tokens.
+ * This means that the string like this: "apple, ,banana, ,orange ,"
+ * will be translated into the items: "apple", "", "banana", "", "orange", "".
+ * This function is useful when the configuration parameter
+ * holds a positionally sensitive list.
+ * Use free_string_config_array() to free the array after use.
+ */
+char **get_raw_string_config_array(struct collection_item *item,
+                                   const char *sep, int *size, int *error);
+
 /* Array of long values - separators are detected automatically. */
-/* The length of the allocated array is returned in "size" */
+/* The length of the allocated array is returned in "size". */
+/* Size and error parameters can be NULL. */
 long *get_long_config_array(struct collection_item *item, int *size, int *error);
 /* Array of double values - separators are detected automatically. */
 /* The length of the allocated array is returned in "size" */
+/* Size and error parameters can be NULL. */
 double *get_double_config_array(struct collection_item *item, int *size, int *error);
 
 /* Special function to free string config array */
diff --git a/common/ini/ini_config_ut.c b/common/ini/ini_config_ut.c
index 52e89cb..fabc088 100644
--- a/common/ini/ini_config_ut.c
+++ b/common/ini/ini_config_ut.c
@@ -755,6 +755,25 @@ int get_test(void)
 
     free_string_config_array(strarray);
 
+    printf("Get raw str array without size.\n");
+
+    error = 0;
+    strarray = get_raw_string_config_array(item, ",", NULL, &error);
+    if (error) {
+        printf("Expect success got error %d.\n", error);
+        free_ini_config(ini_config);
+        return error;
+    }
+
+    /* Can be used with this cycle */
+    strptr = strarray;
+    while (*strptr != NULL) {
+        printf("[%s]\n",*strptr);
+        strptr++;
+    }
+
+    free_string_config_array(strarray);
+
     printf("Get str array with size.\n");
 
     error = 0;
@@ -771,6 +790,22 @@ int get_test(void)
 
     free_string_config_array(strarray);
 
+    printf("Get raw str array with size.\n");
+
+    error = 0;
+    size = 0;
+    strarray = get_raw_string_config_array(item, ",", &size, &error);
+    if (error) {
+        printf("Expect success got error %d.\n", error);
+        free_ini_config(ini_config);
+        return error;
+    }
+
+    /* Can be used with this cycle */
+    for (i=0;i<size;i++) printf("[%s]\n",*(strarray + i));
+
+    free_string_config_array(strarray);
+
     printf("Get long array item\n");
 
     item = NULL;
-- 
1.5.5.6

