From 024570d0b7dd5024bf89fb61b9f53c4b7d145eb6 Mon Sep 17 00:00:00 2001
From: Dmitri Pal <dpal@redhat.com>
Date: Thu, 25 Nov 2010 23:38:47 -0500
Subject: [PATCH] [INI] Enhancements to value object

* Added capability to copy value.
* Added function to set alternative wrapping boundary
  of the value.
* Created a unit test for both new functions.
---
 ini/ini_valueobj.c    |  122 +++++++++++++++++++++++++++++++++++++++++
 ini/ini_valueobj.h    |    7 +++
 ini/ini_valueobj_ut.c |  144 ++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 272 insertions(+), 1 deletions(-)

diff --git a/ini/ini_valueobj.c b/ini/ini_valueobj.c
index 02b9732f490d23d196f68ee2070a8d6ae56d9a05..5ad8e97d0a684114147ef02a3a2770d8cdc9dd1a 100644
--- a/ini/ini_valueobj.c
+++ b/ini/ini_valueobj.c
@@ -195,8 +195,15 @@ static int value_fold(struct simplebuffer *unfolded,
 
     /* Get the buffer info */
     len = simplebuffer_get_len(unfolded);
+    if (!len) {
+        /* Nothing to fold */
+        TRACE_FLOW_EXIT();
+        return EOK;
+    }
+
     buf = (const char *)simplebuffer_get_buf(unfolded);
 
+
     /* Make sure that we have at least one character to fold */
     if (fold_bound == 0) fold_bound++;
 
@@ -564,6 +571,92 @@ int value_create_new(const char *strvalue,
     return error;
 }
 
+/* Create a copy of the value */
+int value_copy(struct value_obj *vo,
+               struct value_obj **copy_vo)
+{
+
+    int error = EOK;
+    struct value_obj *new_vo = NULL;
+    struct simplebuffer *oneline = NULL;
+
+    TRACE_FLOW_ENTRY();
+
+    if ((!copy_vo) || (!vo)) {
+        TRACE_ERROR_NUMBER("Invalid argument", EINVAL);
+        return EINVAL;
+    }
+
+    /* Create buffer to hold the value */
+    error = simplebuffer_alloc(&oneline);
+    if (error) {
+        TRACE_ERROR_NUMBER("Failed to allocate dynamic string.", error);
+        return error;
+    }
+
+    /* Put value into the buffer */
+    error = simplebuffer_add_str(oneline,
+                                 (const char *)simplebuffer_get_buf(vo->unfolded),
+                                 simplebuffer_get_len(vo->unfolded),
+                                 INI_VALUE_BLOCK);
+    if (error) {
+        TRACE_ERROR_NUMBER("Failed to add string", error);
+        simplebuffer_free(oneline);
+        return error;
+    }
+
+    /* Acllocate new INI value structure */
+    new_vo = malloc(sizeof(struct value_obj));
+    if (!new_vo) {
+        TRACE_ERROR_NUMBER("No memory", ENOMEM);
+        simplebuffer_free(oneline);
+        return ENOMEM;
+    }
+
+    new_vo->origin = vo->origin;
+    new_vo->line = vo->line;
+    new_vo->unfolded = oneline;
+    new_vo->keylen = vo->keylen;
+    new_vo->boundary = vo->boundary;
+    new_vo->raw_lines = NULL;
+    new_vo->raw_lengths = NULL;
+
+    error = value_create_arrays(&(new_vo->raw_lines),
+                                &(new_vo->raw_lengths));
+
+    if (error) {
+        TRACE_ERROR_NUMBER("Failed to fold", error);
+        value_destroy(new_vo);
+        return error;
+    }
+
+    /* Create arrays by folding the value */
+    error = value_fold(new_vo->unfolded,
+                       new_vo->keylen,
+                       new_vo->boundary,
+                       new_vo->raw_lines,
+                       new_vo->raw_lengths);
+    if (error) {
+        TRACE_ERROR_NUMBER("Failed to fold", error);
+        value_destroy(new_vo);
+        return error;
+    }
+
+    /* Copy commetn */
+    error = ini_comment_copy(vo->ic, &new_vo->ic);
+    if (error) {
+        TRACE_ERROR_NUMBER("Failed to copy comment", error);
+        value_destroy(new_vo);
+        return error;
+    }
+
+    *copy_vo = new_vo;
+
+    TRACE_FLOW_EXIT();
+
+    return error;
+}
+
 /* Get concatenated value */
 int value_get_concatenated(struct value_obj *vo,
                            const char **fullstr)
@@ -643,6 +736,35 @@ int value_set_keylen(struct value_obj *vo, uint32_t key_len)
     return EOK;
 }
 
+/* Change boundary */
+int value_set_boundary(struct value_obj *vo, uint32_t boundary)
+{
+    int error = EOK;
+    TRACE_FLOW_ENTRY();
+
+    if (!vo) {
+        TRACE_ERROR_NUMBER("Invalid object", EINVAL);
+        return EINVAL;
+    }
+
+    vo->boundary = boundary;
+
+    /* Fold in new value */
+    error = value_fold(vo->unfolded,
+                       vo->keylen,
+                       vo->boundary,
+                       vo->raw_lines,
+                       vo->raw_lengths);
+    if (error) {
+        TRACE_ERROR_NUMBER("Failed to fold", error);
+        /* In this case nothing to free here but
+         * the object might be unusable */
+        return error;
+    }
+
+    TRACE_FLOW_EXIT();
+    return EOK;
+}
 
 /* Update value */
 int value_update(struct value_obj *vo,
diff --git a/ini/ini_valueobj.h b/ini/ini_valueobj.h
index 2e13c0da24a63444f5b49a23ee311fd8bbadbefd..3267bcc6e737a3197b9d62b905d174f403f47db1 100644
--- a/ini/ini_valueobj.h
+++ b/ini/ini_valueobj.h
@@ -87,6 +87,10 @@ int value_create_new(const char *strvalue,
                      struct ini_comment *ic,
                      struct value_obj **vo);
 
+/* Create a copy of the value */
+int value_copy(struct value_obj *vo,
+               struct value_obj **copy_vo);
+
 /* Destroy a value object */
 void value_destroy(struct value_obj *vo);
 
@@ -105,6 +109,9 @@ int value_get_line(struct value_obj *vo,
 /* Update key length */
 int value_set_keylen(struct value_obj *vo,
                      uint32_t key_len);
+/* Change boundary */
+int value_set_boundary(struct value_obj *vo,
+                       uint32_t boundary);
 
 /* Update value */
 int value_update(struct value_obj *vo,
diff --git a/ini/ini_valueobj_ut.c b/ini/ini_valueobj_ut.c
index 3def3f7b312537f7a1bcdd27cad26545b5262c4d..e307ba221e72ca43a07390f702f2851eb236b541 100644
--- a/ini/ini_valueobj_ut.c
+++ b/ini/ini_valueobj_ut.c
@@ -214,7 +214,7 @@ int other_create_test(FILE *ff, struct value_obj **vo)
 
     /* Now do assertions and modifications to the object */
 
-    /* NOTE: Below this line do need to free arrays or comment
+    /* NOTE: Below this line do not need to free arrays or comment
      * they became internal parts of the value object
      * and will be freed as a part of it.
      */
@@ -420,6 +420,7 @@ int vo_basic_test(void)
         if (error) {
             printf("Failed to save value to file %d.\n", error);
             value_destroy(vo);
+            fclose(ff);
             return error;
         }
 
@@ -464,12 +465,153 @@ int vo_basic_test(void)
     return EOK;
 }
 
+int vo_copy_test(void)
+{
+    int error = EOK;
+    const char *strvalue = "Test multi word value that "
+                           "will be split between several lines";
+
+    struct value_obj *vo = NULL;
+    struct value_obj *vo_copy = NULL;
+    uint32_t wrap = 0;
+    struct ini_comment *ic = NULL;
+    FILE *ff = NULL;
+    char comment[100];
+
+    TRACE_FLOW_ENTRY();
+
+    VOOUT(printf("Copy test\n"));
+
+    errno = 0;
+    ff = fopen("test.ini","a");
+    if (ff == NULL) {
+        error = errno;
+        printf("Failed to open file. Error %d.\n", error);
+        return error;
+    }
+
+    error = ini_comment_create(&ic);
+    if (error) {
+        printf("Failed to create comment object\n");
+        fclose(ff);
+        return -1;
+    }
+
+    error = ini_comment_append(ic, "#This is a copy test!");
+    if (error) {
+        printf("Failed to add a line to the comment %d.\n", error);
+        ini_comment_destroy(ic);
+        fclose(ff);
+        return error;
+    }
+
+    error = ini_comment_append(ic, "#Replacable comment line");
+    if (error) {
+        printf("Failed to add a line to the comment %d.\n", error);
+        ini_comment_destroy(ic);
+        fclose(ff);
+        return error;
+    }
+
+    error = value_create_new(strvalue,
+                             strlen(strvalue),
+                             INI_VALUE_CREATED,
+                             3,
+                             20,
+                             ic,
+                             &vo);
+    if (error) {
+        printf("Failed to create a new value object %d.\n", error);
+        ini_comment_destroy(ic);
+        fclose(ff);
+        return error;
+    }
+
+    error = save_value(ff, "key", vo);
+    if (error) {
+        printf("Failed to save value to file %d.\n", error);
+        value_destroy(vo);
+        return error;
+    }
+
+    for (wrap = 0; wrap < 80; wrap++) {
+
+        TRACE_INFO_NUMBER("Iteration:", wrap);
+
+        error = value_copy(vo, &vo_copy);
+        if (error) {
+            printf("Failed to create a new value object %d.\n", error);
+            value_destroy(vo);
+            fclose(ff);
+            return error;
+        }
+
+        error = value_set_boundary(vo_copy, wrap);
+        if (error) {
+            printf("Failed to set boundary %d.\n", error);
+            value_destroy(vo);
+            value_destroy(vo_copy);
+            fclose(ff);
+            return error;
+        }
+
+        /* Get comment from the value */
+        error = value_extract_comment(vo_copy, &ic);
+        if (error) {
+            printf("Failed to extract comment %d.\n", error);
+            value_destroy(vo);
+            value_destroy(vo_copy);
+            fclose(ff);
+            return error;
+        }
+
+        /* Replace comment in the value */
+        sprintf(comment, ";This is value with boundary %d", wrap);
+        VOOUT(printf("Comment: %s\n", comment));
+        error = ini_comment_replace(ic, 1, comment);
+        if (error) {
+            printf("Failed to replace comment %d.\n", error);
+            value_destroy(vo);
+            value_destroy(vo_copy);
+            fclose(ff);
+            return error;
+        }
+
+        /* Set comment into the value */
+        error = value_put_comment(vo_copy, ic);
+        if (error) {
+            printf("Failed to set comment %d.\n", error);
+            value_destroy(vo);
+            value_destroy(vo_copy);
+            fclose(ff);
+            return error;
+        }
+
+        error = save_value(ff, "key", vo_copy);
+        if (error) {
+            printf("Failed to save value to file %d.\n", error);
+            value_destroy(vo);
+            value_destroy(vo_copy);
+            fclose(ff);
+            return error;
+        }
+
+        value_destroy(vo_copy);
+    }
+
+    value_destroy(vo);
+    TRACE_FLOW_EXIT();
+    return EOK;
+}
+
+
 
 /* Main function of the unit test */
 int main(int argc, char *argv[])
 {
     int error = 0;
     test_fn tests[] = { vo_basic_test,
+                        vo_copy_test,
                         NULL };
     test_fn t;
     int i = 0;
-- 
1.5.5.6

