From 6f8d56130bb3747b1da069db72c726f8e7f5b061 Mon Sep 17 00:00:00 2001
From: Dmitri Pal <dpal@redhat.com>
Date: Thu, 3 Oct 2013 23:19:23 -0400
Subject: [PATCH] [INI] Fix for ini_get_string_config_array

Patch fixes the issue with the string processing.
It addresses the last token problem, adds unit tests
and fixes corner cases when the value consists only
of separators.
---
 ini/ini.d/real.conf          |    4 +
 ini/ini_get_array_valueobj.c |   24 +++++-
 ini/ini_parse_ut.c           |  195 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 221 insertions(+), 2 deletions(-)

diff --git a/ini/ini.d/real.conf b/ini/ini.d/real.conf
index 1e155b8..78b5874 100644
--- a/ini/ini.d/real.conf
+++ b/ini/ini.d/real.conf
@@ -33,6 +33,10 @@ command = ./sbin/sssd_info
 [domains]
 domainsOrder =  , LOCAL,          ,  EXAMPLE.COM, ,     SOMEOTHER.COM    ,  ,
 badarray =    ,   ,    ,   ,   ,
+somearray = ,
+someotherarray = , ;
+justdelim=:;,;
+yetanother = 
 
 [domains/LOCAL]
 description = Reserved domain for local configurations
diff --git a/ini/ini_get_array_valueobj.c b/ini/ini_get_array_valueobj.c
index 5be01aa..cee6bc9 100644
--- a/ini/ini_get_array_valueobj.c
+++ b/ini/ini_get_array_valueobj.c
@@ -92,7 +92,10 @@ static char **get_str_cfg_array(struct value_obj *vo,
     }
 
     /* Allocate memory for the copy of the string */
-    copy = malloc(dlen);
+    TRACE_INFO_NUMBER("Length to allocate is :", dlen);
+    /* Always reserve one more byte 
+     * for the case when the string consist of delimeters */
+    copy = malloc(dlen + 1);
     if (copy == NULL) {
         TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM);
         if (error) *error = ENOMEM;
@@ -128,7 +131,6 @@ static char **get_str_cfg_array(struct value_obj *vo,
                     *dest = '\0';
                     dest++;
                 }
-                if (locsep[j] == '\0') break; /* We are done */
 
                 /* Move forward and trim spaces if any */
                 start += resume_len + 1;
@@ -148,6 +150,24 @@ static char **get_str_cfg_array(struct value_obj *vo,
         len++;
     }
 
+    /* Save last segment */
+    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';
+    }
+    else if(include && dlen && count) {
+        TRACE_INFO_NUMBER("Include :", include);
+        TRACE_INFO_NUMBER("dlen :", dlen);
+        TRACE_INFO_NUMBER("Count :", count);
+        count++;
+        *dest = '\0';
+    }
+
     /* Now we know how many items are there in the list */
     array = malloc((count + 1) * sizeof(char *));
     if (array == NULL) {
diff --git a/ini/ini_parse_ut.c b/ini/ini_parse_ut.c
index 2655d7e..7dd7518 100644
--- a/ini/ini_parse_ut.c
+++ b/ini/ini_parse_ut.c
@@ -38,6 +38,7 @@
 int verbose = 0;
 char *confdir = NULL;
 
+#define NUM_TESTS 14
 #define VAL_SIZE 100
 
 #define INIOUT(foo) \
@@ -1407,6 +1408,74 @@ int reload_test(void)
     return 0;
 }
 
+int test_one_array(struct ini_cfgobj *ini_config,
+                   const char *section,
+                   const char *value,
+                   int raw,
+                   int expect,
+                   const char *sep,
+                   const char *message)
+{
+    struct value_obj *vo = NULL;
+    int error = 0;
+    int size = 0;
+    char **strarray;
+    char **strptr;
+    int i;
+
+    INIOUT(printf(message));
+
+    vo = NULL;
+    error = ini_get_config_valueobj(section,
+                                    value,
+                                    ini_config,
+                                    INI_GET_FIRST_VALUE,
+                                    &vo);
+    if(error) {
+        printf("Expected success but got error! %d\n",error);
+        return error;
+    }
+
+    /* Value should be found */
+    if (vo == NULL) {
+        printf("Expected success but got NULL. Section %s value %s, %s\n", section, value, raw ? "raw" : "interpreted");
+        return -1;
+    }
+
+    INIOUT(value_print(value, vo));
+
+    INIOUT(printf("Get str array with size.\n"));
+
+    error = 0;
+
+    if (raw) strarray = ini_get_raw_string_config_array(vo, sep, &size, &error);
+    else strarray = ini_get_string_config_array(vo, sep, &size, &error);
+    if (error) {
+        printf("Expect success got error %d.\n", error);
+        return error;
+    }
+
+    /* Can be used with this cycle */
+    strptr = strarray;
+    while (*strptr != NULL) {
+        INIOUT(printf("[%s]\n",*strptr));
+        strptr++;
+    }
+
+    if (size != expect) {
+        printf("Expected %d but got %d.\n", expect, size);
+        ini_free_string_config_array(strarray);
+        return -1;
+    }
+
+    /* Can be used with this cycle */
+    INIOUT(for (i=0; i<size; i++) printf("[%s]\n", *(strarray + i)));
+
+    ini_free_string_config_array(strarray);
+
+    return EOK;
+}
+
 int get_test(void)
 {
 
@@ -1441,6 +1510,115 @@ int get_test(void)
     char *srcdir = NULL;
     int bad_val = 0;
 
+    /* Define structure for testing arrays in the loop */
+    struct a_t { char section[100];
+                 char value[100];
+                 int raw;
+                 int expect;
+                 char sep[10];
+                 char message[100]; } array_test[NUM_TESTS] =
+            {
+                { "services",
+                  "activeServices",
+                  0,
+                  4,
+                  ",:;",
+                  "Make sure we parse string array properly\n"},
+
+                { "services",
+                  "activeServices",
+                  1,
+                  4,
+                  ",:;",
+                  "Make sure we parse raw string array properly\n"},
+
+                { "domains",
+                  "domainsOrder",
+                  0,
+                  3,
+                  ",:;",
+                  "Parse string array with comma at the end\n"},
+
+                { "domains",
+                  "domainsOrder",
+                  1,
+                  8,
+                  ",:;",
+                  "Parse raw string array with comma at the end\n"},
+
+                { "domains",
+                  "badarray",
+                  0,
+                  0,
+                  ",:;",
+                  "Bad array should have no tokens\n"},
+
+                { "domains",
+                  "badarray",
+                  1,
+                  6,
+                  ",:;",
+                  "Raw bad array should have right number of tokens.\n"},
+
+                { "domains",
+                  "somearray",
+                  0,
+                  0,
+                  ",:;",
+                  "Bad array should have no tokens\n"},
+
+                { "domains",
+                  "somearray",
+                  1,
+                  2,
+                  ",:;",
+                  "Raw bad array should have right number of tokens.\n"},
+
+                { "domains",
+                  "someotherarray",
+                  0,
+                  0,
+                  ",:;",
+                  "Bad array should have no tokens\n"},
+
+                { "domains",
+                  "someotherarray",
+                  1,
+                  3,
+                  ",:;",
+                  "Raw bad array should have right number of tokens.\n"},
+
+                { "domains",
+                  "justdelim",
+                  0,
+                  0,
+                  ",:;",
+                  "Bad array should have no tokens\n"},
+
+                { "domains",
+                  "justdelim",
+                  1,
+                  5,
+                  ",:;",
+                  "Delimeters only should have right number of tokens.\n"},
+
+                { "domains",
+                  "yetanother",
+                  0,
+                  0,
+                  ",:;",
+                  "Empty array should have no tokens.\n"},
+
+                { "domains",
+                  "yetanother",
+                  1,
+                  0,
+                  ",:;",
+                  "Empty raw array should have no token.\n"}
+            };
+
+    /*****************************************************/
+
     INIOUT(printf("\n\n<==== GET TEST START =====>\n"));
     INIOUT(printf("Creating configuration object\n"));
 
@@ -2063,6 +2241,23 @@ int get_test(void)
 
     /**********************************************************/
 
+    for (i = 0; i< NUM_TESTS; i++) {
+        error = test_one_array(ini_config,
+                               array_test[i].section,
+                               array_test[i].value,
+                               array_test[i].raw,
+                               array_test[i].expect,
+                               array_test[i].sep,
+                               array_test[i].message);
+        if (error) {
+            /* Message is printed inside function */
+            ini_config_destroy(ini_config);
+            return error;
+        }
+    }
+
+    /**********************************************************/
+
     INIOUT(printf("Get long array value\n"));
 
     vo = NULL;
-- 
1.7.1

