LCOV - code coverage report
Current view: top level - ini - ini_valueobj.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 320 369 86.7 %
Date: 2014-04-01 Functions: 23 24 95.8 %

          Line data    Source code
       1             : /*
       2             :     INI LIBRARY
       3             : 
       4             :     Module represents interface to the value object.
       5             : 
       6             :     Copyright (C) Dmitri Pal <dpal@redhat.com> 2010
       7             : 
       8             :     INI Library is free software: you can redistribute it and/or modify
       9             :     it under the terms of the GNU Lesser General Public License as published by
      10             :     the Free Software Foundation, either version 3 of the License, or
      11             :     (at your option) any later version.
      12             : 
      13             :     INI Library is distributed in the hope that it will be useful,
      14             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :     GNU Lesser General Public License for more details.
      17             : 
      18             :     You should have received a copy of the GNU Lesser General Public License
      19             :     along with INI Library.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include "config.h"
      23             : #include <errno.h>
      24             : #include <stdio.h>
      25             : #include <string.h>
      26             : #include <ctype.h>
      27             : #include "simplebuffer.h"
      28             : #include "ref_array.h"
      29             : #include "ini_comment.h"
      30             : #include "ini_defines.h"
      31             : #include "ini_valueobj.h"
      32             : #include "trace.h"
      33             : 
      34             : struct value_obj {
      35             :     struct ref_array *raw_lines;
      36             :     struct ref_array *raw_lengths;
      37             :     struct simplebuffer *unfolded;
      38             :     uint32_t origin;
      39             :     uint32_t line;
      40             :     uint32_t keylen;
      41             :     uint32_t boundary;
      42             :     struct ini_comment *ic;
      43             : };
      44             : 
      45             : /* The length of " =" which is 3 */
      46             : #define INI_FOLDING_OVERHEAD 3
      47             : 
      48             : /* Array growth */
      49             : #define INI_ARRAY_GROW  2
      50             : 
      51             : /* Equal sign */
      52             : #define INI_EQUAL_SIGN  " = "
      53             : #define INI_OPEN_BR     "["
      54             : #define INI_CLOSE_BR    "]"
      55             : 
      56             : 
      57             : /* Unfold the value represented by the array */
      58       67749 : static int value_unfold(struct ref_array *raw_lines,
      59             :                         struct ref_array *raw_lengths,
      60             :                         struct simplebuffer **unfolded)
      61             : {
      62             :     int error;
      63       67749 :     struct simplebuffer *oneline = NULL;
      64       67749 :     uint32_t len = 0;
      65       67749 :     char *ptr = NULL;
      66       67749 :     uint32_t i = 0;
      67       67749 :     char *part = NULL;
      68             : 
      69             :     TRACE_FLOW_ENTRY();
      70             : 
      71       67749 :     error = simplebuffer_alloc(&oneline);
      72       67749 :     if (error) {
      73             :         TRACE_ERROR_NUMBER("Failed to allocate dynamic string.", error);
      74             :         return error;
      75             :     }
      76             : 
      77             :     for (;;) {
      78             :         /* Get line */
      79      282727 :         ptr = ref_array_get(raw_lines, i, NULL);
      80      282727 :         if (ptr) {
      81             :             /* Get its length */
      82      214978 :             ref_array_get(raw_lengths, i, (void *)&len);
      83             : 
      84      214978 :             part = *((char **)(ptr));
      85             : 
      86             :             TRACE_INFO_STRING("Value:", part);
      87             :             TRACE_INFO_NUMBER("Lenght:", len);
      88             : 
      89      214978 :             error = simplebuffer_add_raw(oneline,
      90             :                                          part,
      91             :                                          len,
      92             :                                          INI_VALUE_BLOCK);
      93      214978 :             if (error) {
      94             :                 TRACE_ERROR_NUMBER("Failed to add string", error);
      95           0 :                 simplebuffer_free(oneline);
      96           0 :                 return error;
      97             :             }
      98             : 
      99      214978 :             i++;
     100             :         }
     101             :         else break;
     102      214978 :     }
     103             : 
     104       67749 :     *unfolded = oneline;
     105             : 
     106             :     TRACE_FLOW_EXIT();
     107       67749 :     return error;
     108             : }
     109             : 
     110             : 
     111      665776 : static int save_portion(struct ref_array *raw_lines,
     112             :                         struct ref_array *raw_lengths,
     113             :                         const char* buf,
     114             :                         uint32_t len)
     115             : {
     116      665776 :     int error = EOK;
     117      665776 :     char *copy = NULL;
     118      665776 :     uint32_t adj = 0;
     119             : 
     120             :     TRACE_FLOW_ENTRY();
     121             : 
     122             :     /* Add leading space only if there is
     123             :      * a) no space
     124             :      * b) it is not an empty line
     125             :      * c) it is now a first line
     126             :      */
     127             : 
     128      665776 :     if ((buf[0] != ' ') &&
     129      128746 :         (buf[0] != '\t') &&
     130      245109 :         (len != 0) &&
     131      128746 :         (ref_array_len(raw_lines) != 0)) adj = 1;
     132             : 
     133      665776 :     copy = malloc(len + adj + 1);
     134      665776 :     if (!copy) {
     135             :         TRACE_ERROR_NUMBER("Failed to allocate memory", ENOMEM);
     136             :         return ENOMEM;
     137             :     }
     138             : 
     139      665776 :     memcpy(copy + adj, buf, len);
     140      665776 :     len += adj;
     141      665776 :     copy[len] = 0;
     142             : 
     143             :     /* If the section being saved is not starting
     144             :      * with space add a space.
     145             :      */
     146      665776 :     if (adj) copy[0] = ' ';
     147             : 
     148      665776 :     error = ref_array_append(raw_lines, (void *)(&copy));
     149      665776 :     if (error) {
     150             :         TRACE_ERROR_NUMBER("Failed to append line",
     151             :                             error);
     152           0 :         free(copy);
     153           0 :         return error;
     154             :     }
     155             : 
     156      665776 :     error = ref_array_append(raw_lengths, (void *)(&len));
     157      665776 :     if (error) {
     158             :         TRACE_ERROR_NUMBER("Failed to append length",
     159             :                             error);
     160           0 :         return error;
     161             :     }
     162             : 
     163             :     TRACE_INFO_STRING("Added string:", (char *)copy);
     164             :     TRACE_INFO_NUMBER("Added number:", len);
     165             : 
     166             : 
     167             :     TRACE_FLOW_EXIT();
     168             :     return EOK;
     169             : }
     170             : 
     171             : /* Function to create a folded value out of the unfolded string */
     172      132357 : static int value_fold(struct simplebuffer *unfolded,
     173             :                       uint32_t key_len,
     174             :                       uint32_t fold_bound,
     175             :                       struct ref_array *raw_lines,
     176             :                       struct ref_array *raw_lengths)
     177             : {
     178      132357 :     int error = EOK;
     179             :     const char *buf;
     180      132357 :     uint32_t len = 0;          /* Full length of the buffer          */
     181      132357 :     uint32_t fold_place = 0;   /* Potential folding place            */
     182      132357 :     uint32_t best_place = 0;   /* Dynamic folding boundary           */
     183      132357 :     uint32_t next_place = 0;   /* Position of the found space        */
     184      132357 :     uint32_t fold_len = 0;     /* Determined length of the substring */
     185      132357 :     uint32_t idx = 0;          /* Counter of lines                   */
     186      132357 :     uint32_t i = 0;            /* Internal counter                   */
     187      132357 :     uint32_t resume_place = 0; /* Place we resume parsing            */
     188      132357 :     uint32_t start_place = 0;  /* Start of the string                */
     189      132357 :     int done = 0;              /* Are we done?                       */
     190             : 
     191             :     TRACE_FLOW_ENTRY();
     192             : 
     193             :     /* Reset arrays */
     194      132357 :     ref_array_reset(raw_lines);
     195      132357 :     ref_array_reset(raw_lengths);
     196             : 
     197             :     /* Get the buffer info */
     198      132357 :     len = simplebuffer_get_len(unfolded);
     199      132357 :     if (!len) {
     200             :         /* Nothing to fold */
     201             :         TRACE_FLOW_EXIT();
     202             :         return EOK;
     203             :     }
     204             : 
     205      132021 :     buf = (const char *)simplebuffer_get_buf(unfolded);
     206             : 
     207             :     TRACE_INFO_STRING("Unfolded value:", buf);
     208             : 
     209             :     /* Make sure that we have at least one character to fold */
     210      132021 :     if (fold_bound == 0) fold_bound++;
     211             : 
     212      770853 :     while (!done) {
     213             :         /* Determine the max length of the line */
     214      638832 :         if (idx == 0) {
     215      132021 :              if (fold_bound > (key_len + INI_FOLDING_OVERHEAD)) {
     216      111809 :                  best_place = fold_bound - key_len - INI_FOLDING_OVERHEAD;
     217             :              }
     218             :              else best_place = 0;
     219             :         }
     220             :         else {
     221      506811 :              best_place = fold_bound;
     222             : 
     223             :              /* Starting with the second line if we plan
     224             :               * to add space ourselves factor it into folding
     225             :               * boadary
     226             :               */
     227      506811 :              if ((buf[start_place] != ' ') &&
     228       12383 :                  (buf[start_place] != '\t')) best_place--;
     229             :         }
     230             : 
     231             :         TRACE_INFO_NUMBER("Best place", best_place);
     232             : 
     233      638832 :         fold_place = start_place;
     234      638832 :         next_place = start_place;
     235      638832 :         best_place += start_place;
     236             : 
     237             : 
     238             :         /* Parse the buffer from the right place */
     239    22814022 :         for (i = resume_place; i <= len; i++) {
     240             : 
     241             :             /* Check for folding opportunity */
     242    22712551 :             if (i == len) {
     243             :                 next_place = i;
     244             :                 done = 1;
     245             :             }
     246             :             /*
     247             :              * Fold if we found the separator or the first line
     248             :              * is too long right away
     249             :              */
     250    42281471 :             else if (((buf[i] == ' ') || (buf[i] == '\t')) ||
     251    19700941 :                      ((best_place == 0) && (i == 0))) {
     252             :                 next_place = i;
     253             :                 TRACE_INFO_NUMBER("Next place:", next_place);
     254             :             }
     255    19688558 :             else continue;
     256             : 
     257     3023993 :             if ((next_place > best_place) || (next_place == 0)) {
     258     1074722 :                 if ((fold_place == start_place) &&
     259      537361 :                     (next_place != 0)) {
     260             :                     /* Our first found folding place
     261             :                      * is already after the preferred
     262             :                      * folding place. Time to fold then...
     263             :                      */
     264       65017 :                     fold_len = next_place - start_place;
     265             : 
     266             :                 }
     267             :                 else {
     268             :                     /* We will use the previous
     269             :                      * folding place.
     270             :                      */
     271      472344 :                     fold_len = fold_place - start_place;
     272             : 
     273             :                 }
     274             : 
     275             :                 TRACE_INFO_NUMBER("Fold len:", fold_len);
     276             : 
     277      537361 :                 error = save_portion(raw_lines,
     278             :                                      raw_lengths,
     279             :                                      buf + start_place,
     280             :                                      fold_len);
     281      537361 :                 if (error) {
     282             :                     TRACE_ERROR_NUMBER("Failed to save", error);
     283             :                     return error;
     284             :                 }
     285             : 
     286      537361 :                 start_place += fold_len;
     287             : 
     288             :                 /*
     289             :                  * This will force the re-processing
     290             :                  * of the same space but it is
     291             :                  * helpful in case the middle portion
     292             :                  * of the value is beyond our folding limit.
     293             :                  */
     294      537361 :                 resume_place = next_place;
     295      537361 :                 if (fold_len == 0) resume_place++;
     296      537361 :                 idx++;
     297      537361 :                 break;
     298             :             }
     299             :             else { /* Case when next_place <= best_place */
     300             :                 fold_place = next_place;
     301             :             }
     302             :         }
     303             : 
     304             :         /* Save last portion */
     305      638832 :         if (done) {
     306      132021 :             if (next_place - start_place) {
     307      128415 :                 error = save_portion(raw_lines,
     308             :                                      raw_lengths,
     309             :                                      buf + start_place,
     310             :                                      next_place - start_place);
     311      128415 :                 if (error) {
     312             :                     TRACE_ERROR_NUMBER("Failed to save last chunk", error);
     313             :                     return error;
     314             :                 }
     315      128415 :                 idx++;
     316             :             }
     317             :         }
     318             :     }
     319             : 
     320             :     TRACE_FLOW_EXIT();
     321             :     return error;
     322             : }
     323             : 
     324       67749 : static int trim_last(struct value_obj *vo)
     325             : {
     326       67749 :     int error = EOK;
     327       67749 :     uint32_t last = 0;
     328       67749 :     uint32_t len = 0;
     329       67749 :     uint32_t idx = 0;
     330       67749 :     char *ptr = NULL;
     331       67749 :     char *part = NULL;
     332             : 
     333             :     TRACE_FLOW_ENTRY();
     334             : 
     335       67749 :     last = ref_array_len(vo->raw_lengths);
     336       67749 :     if (last) {
     337       67749 :         last--;
     338       67749 :         ref_array_get(vo->raw_lengths, last, (void *)&len);
     339       67749 :         if (len) {
     340       67568 :             ptr = ref_array_get(vo->raw_lines, last, NULL);
     341       67568 :             if (ptr) {
     342       67568 :                 part = *((char **)ptr);
     343             : 
     344             :                 TRACE_INFO_STRING("Value", part);
     345             :                 TRACE_INFO_NUMBER("Length", len);
     346             : 
     347       67568 :                 idx = len - 1;
     348             : 
     349             :                 TRACE_INFO_NUMBER("Start index", idx);
     350             : 
     351          59 :                 while((idx) && (isspace(part[idx]))) idx--;
     352       67568 :                 if (idx != len - 1) {
     353             :                     TRACE_INFO_NUMBER("End index", idx);
     354          57 :                     len = idx + 1;
     355          57 :                     error = ref_array_replace(vo->raw_lengths, last, (void *)&len);
     356          57 :                     if (error) {
     357             :                         TRACE_ERROR_NUMBER("Failed to update length", error);
     358             :                         return error;
     359             :                     }
     360             :                 }
     361             :             }
     362             :         }
     363             :     }
     364             :     TRACE_FLOW_EXIT();
     365             :     return error;
     366             : }
     367             : 
     368             : /* Create value from a referenced array */
     369       67749 : int value_create_from_refarray(struct ref_array *raw_lines,
     370             :                                struct ref_array *raw_lengths,
     371             :                                uint32_t line,
     372             :                                uint32_t origin,
     373             :                                uint32_t key_len,
     374             :                                uint32_t boundary,
     375             :                                struct ini_comment *ic,
     376             :                                struct value_obj **vo)
     377             : {
     378       67749 :     int error = EOK;
     379       67749 :     struct value_obj *new_vo = NULL;
     380             : 
     381             :     TRACE_FLOW_ENTRY();
     382             : 
     383       67749 :     if ((!raw_lines) || (!raw_lengths) || (!vo)) {
     384             :         TRACE_ERROR_NUMBER("Invalid argument", EINVAL);
     385             :         return EINVAL;
     386             :     }
     387             : 
     388       67749 :     new_vo = malloc(sizeof(struct value_obj));
     389       67749 :     if (!new_vo) {
     390             :         TRACE_ERROR_NUMBER("No memory", ENOMEM);
     391             :         return ENOMEM;
     392             :     }
     393             : 
     394             :     /* We are not using references here since
     395             :      * it will be inconsistent with the way
     396             :      * how comment is handled.
     397             :      * We could have added references here and make
     398             :      * comment keep references but it seems to be
     399             :      * and overhead in this case.
     400             :      */
     401       67749 :     new_vo->raw_lines = raw_lines;
     402       67749 :     new_vo->raw_lengths = raw_lengths;
     403       67749 :     new_vo->origin = origin;
     404       67749 :     new_vo->line = line;
     405       67749 :     new_vo->keylen = key_len;
     406       67749 :     new_vo->boundary = boundary;
     407       67749 :     new_vo->ic = ic;
     408             : 
     409             :     /* Last line might have spaces at the end, trim them */
     410       67749 :     error = trim_last(new_vo);
     411       67749 :     if (error) {
     412             :         TRACE_ERROR_NUMBER("Failed to trim last", error);
     413           0 :         value_destroy(new_vo);
     414           0 :         return error;
     415             :     }
     416             : 
     417       67749 :     error = value_unfold(new_vo->raw_lines,
     418             :                          new_vo->raw_lengths,
     419             :                          &(new_vo->unfolded));
     420       67749 :     if (error) {
     421             :         TRACE_ERROR_NUMBER("Failed to unfold", error);
     422           0 :         value_destroy(new_vo);
     423           0 :         return error;
     424             :     }
     425             : 
     426             :     TRACE_INFO_STRING("Unfolded:",
     427             :                       (const char *)simplebuffer_get_buf(new_vo->unfolded));
     428       67749 :     *vo = new_vo;
     429             : 
     430             :     TRACE_FLOW_EXIT();
     431             : 
     432       67749 :     return error;
     433             : }
     434             : 
     435             : /* Cleanup callback for lines array */
     436      880754 : void value_lines_cleanup_cb(void *elem,
     437             :                             ref_array_del_enum type,
     438             :                             void *data)
     439             : {
     440             :     char *part;
     441             : 
     442             :     TRACE_FLOW_ENTRY();
     443             : 
     444      880754 :     part = *((char **)(elem));
     445             : 
     446             :     TRACE_INFO_STRING("Freeing:", part);
     447             : 
     448      880754 :     free(part);
     449             : 
     450             :     TRACE_FLOW_EXIT();
     451      880754 : }
     452             : 
     453             : /* Create a pair of arrays */
     454      134280 : int value_create_arrays(struct ref_array **raw_lines,
     455             :                         struct ref_array **raw_lengths)
     456             : {
     457      134280 :     int error = EOK;
     458      134280 :     struct ref_array *new_lines = NULL;
     459      134280 :     struct ref_array *new_lengths = NULL;
     460             : 
     461             :     TRACE_FLOW_ENTRY();
     462             : 
     463      134280 :     error = ref_array_create(&new_lines,
     464             :                              sizeof(char *),
     465             :                              INI_ARRAY_GROW,
     466             :                              value_lines_cleanup_cb,
     467             :                              NULL);
     468      134280 :     if (error) {
     469             :         TRACE_ERROR_NUMBER("Failed to create lines array", error);
     470             :         return error;
     471             : 
     472             :     }
     473             : 
     474      134280 :     error = ref_array_create(&new_lengths,
     475             :                              sizeof(uint32_t),
     476             :                              INI_ARRAY_GROW,
     477             :                              NULL,
     478             :                              NULL);
     479      134280 :     if (error) {
     480             :         TRACE_ERROR_NUMBER("Failed to create lengths array", error);
     481           0 :         ref_array_destroy(new_lines);
     482           0 :         return error;
     483             : 
     484             :     }
     485             : 
     486      134280 :     *raw_lines = new_lines;
     487      134280 :     *raw_lengths = new_lengths;
     488             : 
     489             :     TRACE_FLOW_EXIT();
     490      134280 :     return EOK;
     491             : }
     492             : 
     493             : /* Add a raw string to the arrays */
     494      214978 : int value_add_to_arrays(const char *strvalue,
     495             :                         uint32_t len,
     496             :                         struct ref_array *raw_lines,
     497             :                         struct ref_array *raw_lengths)
     498             : {
     499      214978 :     int error = EOK;
     500             : 
     501             :     TRACE_FLOW_ENTRY();
     502             : 
     503      214978 :     error = ref_array_append(raw_lines, (void *)(&strvalue));
     504      214978 :     if (error) {
     505             :         TRACE_ERROR_NUMBER("Failed to add to lines array", error);
     506             :         return error;
     507             : 
     508             :     }
     509             : 
     510      214978 :     error = ref_array_append(raw_lengths, (void *)(&len));
     511             :     if (error) {
     512             :         TRACE_ERROR_NUMBER("Failed to add to lengths array", error);
     513             :         return error;
     514             : 
     515             :     }
     516             : 
     517             :     TRACE_FLOW_EXIT();
     518             :     return error;
     519             : }
     520             : 
     521             : 
     522             : /* Destroy arrays */
     523      134526 : void value_destroy_arrays(struct ref_array *raw_lines,
     524             :                           struct ref_array *raw_lengths)
     525             : {
     526             :     TRACE_FLOW_ENTRY();
     527             : 
     528             :     /* Function checks validity inside */
     529      134526 :     ref_array_destroy(raw_lines);
     530             :     /* Function checks validity inside */
     531      134526 :     ref_array_destroy(raw_lengths);
     532             : 
     533             :     TRACE_FLOW_EXIT();
     534             : 
     535      134526 : }
     536             : 
     537             : /* Destroy a value object */
     538      134280 : void value_destroy(struct value_obj *vo)
     539             : {
     540             :     TRACE_FLOW_ENTRY();
     541             : 
     542      134280 :     if (vo) {
     543             :         /* Free arrays if any */
     544      134280 :         value_destroy_arrays(vo->raw_lines,
     545             :                              vo->raw_lengths);
     546             :         /* Free the simple buffer if any */
     547      134280 :         simplebuffer_free(vo->unfolded);
     548             :         /* Function checks validity inside */
     549      134280 :         ini_comment_destroy(vo->ic);
     550      134280 :         free(vo);
     551             :     }
     552             : 
     553             :     TRACE_FLOW_EXIT();
     554      134280 : }
     555             : 
     556             : /* Create value object from string buffer */
     557          83 : int value_create_new(const char *strvalue,
     558             :                      uint32_t length,
     559             :                      uint32_t origin,
     560             :                      uint32_t key_len,
     561             :                      uint32_t boundary,
     562             :                      struct ini_comment *ic,
     563             :                      struct value_obj **vo)
     564             : {
     565          83 :     int error = EOK;
     566          83 :     struct value_obj *new_vo = NULL;
     567          83 :     struct simplebuffer *oneline = NULL;
     568             : 
     569             :     TRACE_FLOW_ENTRY();
     570             : 
     571          83 :     if ((!strvalue) || (!vo)) {
     572             :         TRACE_ERROR_NUMBER("Invalid argument", EINVAL);
     573             :         return EINVAL;
     574             :     }
     575             : 
     576             :     /* Create buffer to hold the value */
     577          83 :     error = simplebuffer_alloc(&oneline);
     578          83 :     if (error) {
     579             :         TRACE_ERROR_NUMBER("Failed to allocate dynamic string.", error);
     580             :         return error;
     581             :     }
     582             : 
     583             :     /* Put value into the buffer */
     584          83 :     error = simplebuffer_add_str(oneline,
     585             :                                  strvalue,
     586             :                                  length,
     587             :                                  INI_VALUE_BLOCK);
     588          83 :     if (error) {
     589             :         TRACE_ERROR_NUMBER("Failed to add string", error);
     590           0 :         simplebuffer_free(oneline);
     591           0 :         return error;
     592             :     }
     593             : 
     594             :     /* Acllocate new INI value structure */
     595          83 :     new_vo = malloc(sizeof(struct value_obj));
     596          83 :     if (!new_vo) {
     597             :         TRACE_ERROR_NUMBER("No memory", ENOMEM);
     598           0 :         simplebuffer_free(oneline);
     599           0 :         return ENOMEM;
     600             :     }
     601             : 
     602          83 :     new_vo->origin = origin;
     603             :     /* Line is not known in this case */
     604          83 :     new_vo->line = 0;
     605          83 :     new_vo->ic = ic;
     606          83 :     new_vo->unfolded = oneline;
     607          83 :     new_vo->keylen = key_len;
     608          83 :     new_vo->boundary = boundary;
     609          83 :     new_vo->raw_lines = NULL;
     610          83 :     new_vo->raw_lengths = NULL;
     611             : 
     612          83 :     error = value_create_arrays(&(new_vo->raw_lines),
     613             :                                 &(new_vo->raw_lengths));
     614             : 
     615          83 :     if (error) {
     616             :         TRACE_ERROR_NUMBER("Failed to fold", error);
     617           0 :         value_destroy(new_vo);
     618           0 :         return error;
     619             :     }
     620             : 
     621             :     /* Create arrays by folding the value */
     622          83 :     error = value_fold(new_vo->unfolded,
     623             :                        new_vo->keylen,
     624             :                        new_vo->boundary,
     625             :                        new_vo->raw_lines,
     626             :                        new_vo->raw_lengths);
     627          83 :     if (error) {
     628             :         TRACE_ERROR_NUMBER("Failed to fold", error);
     629           0 :         value_destroy(new_vo);
     630           0 :         return error;
     631             :     }
     632             : 
     633          83 :     *vo = new_vo;
     634             : 
     635             :     TRACE_FLOW_EXIT();
     636             : 
     637          83 :     return error;
     638             : }
     639             : 
     640             : /* Create a copy of the value */
     641       66448 : int value_copy(struct value_obj *vo,
     642             :                struct value_obj **copy_vo)
     643             : {
     644             : 
     645       66448 :     int error = EOK;
     646       66448 :     struct value_obj *new_vo = NULL;
     647       66448 :     struct simplebuffer *oneline = NULL;
     648             : 
     649             :     TRACE_FLOW_ENTRY();
     650             : 
     651       66448 :     if ((!copy_vo) || (!vo)) {
     652             :         TRACE_ERROR_NUMBER("Invalid argument", EINVAL);
     653             :         return EINVAL;
     654             :     }
     655             : 
     656             :     /* Create buffer to hold the value */
     657       66448 :     error = simplebuffer_alloc(&oneline);
     658       66448 :     if (error) {
     659             :         TRACE_ERROR_NUMBER("Failed to allocate dynamic string.", error);
     660             :         return error;
     661             :     }
     662             : 
     663             :     /* Put value into the buffer */
     664      132896 :     error = simplebuffer_add_str(oneline,
     665       66448 :                                  (const char *)simplebuffer_get_buf(vo->unfolded),
     666             :                                  simplebuffer_get_len(vo->unfolded),
     667             :                                  INI_VALUE_BLOCK);
     668       66448 :     if (error) {
     669             :         TRACE_ERROR_NUMBER("Failed to add string", error);
     670           0 :         simplebuffer_free(oneline);
     671           0 :         return error;
     672             :     }
     673             : 
     674             :     /* Acllocate new INI value structure */
     675       66448 :     new_vo = malloc(sizeof(struct value_obj));
     676       66448 :     if (!new_vo) {
     677             :         TRACE_ERROR_NUMBER("No memory", ENOMEM);
     678           0 :         simplebuffer_free(oneline);
     679           0 :         return ENOMEM;
     680             :     }
     681             : 
     682       66448 :     new_vo->origin = vo->origin;
     683       66448 :     new_vo->line = vo->line;
     684       66448 :     new_vo->unfolded = oneline;
     685       66448 :     new_vo->keylen = vo->keylen;
     686       66448 :     new_vo->boundary = vo->boundary;
     687       66448 :     new_vo->raw_lines = NULL;
     688       66448 :     new_vo->raw_lengths = NULL;
     689       66448 :     new_vo->ic = NULL;
     690             : 
     691       66448 :     error = value_create_arrays(&(new_vo->raw_lines),
     692             :                                 &(new_vo->raw_lengths));
     693             : 
     694       66448 :     if (error) {
     695             :         TRACE_ERROR_NUMBER("Failed to fold", error);
     696           0 :         value_destroy(new_vo);
     697           0 :         return error;
     698             :     }
     699             : 
     700             :     /* Create arrays by folding the value */
     701       66448 :     error = value_fold(new_vo->unfolded,
     702             :                        new_vo->keylen,
     703             :                        new_vo->boundary,
     704             :                        new_vo->raw_lines,
     705             :                        new_vo->raw_lengths);
     706       66448 :     if (error) {
     707             :         TRACE_ERROR_NUMBER("Failed to fold", error);
     708           0 :         value_destroy(new_vo);
     709           0 :         return error;
     710             :     }
     711             : 
     712             :     /* Copy comment */
     713       66448 :     if (vo->ic) {
     714       30962 :         error = ini_comment_copy(vo->ic, &new_vo->ic);
     715       30962 :         if (error) {
     716             :             TRACE_ERROR_NUMBER("Failed to copy comment", error);
     717           0 :             value_destroy(new_vo);
     718           0 :             return error;
     719             :         }
     720             :     }
     721             : 
     722       66448 :     *copy_vo = new_vo;
     723             : 
     724             :     TRACE_INFO_STRING("Orig value:",
     725             :                       (const char *)simplebuffer_get_buf(vo->unfolded));
     726             :     TRACE_INFO_STRING("Copy value:",
     727             :                       (const char *)simplebuffer_get_buf(new_vo->unfolded));
     728             : 
     729             :     TRACE_INFO_NUMBER("Orig value num lines:",
     730             :                       ref_array_len(vo->raw_lengths));
     731             :     TRACE_INFO_NUMBER("Copy value num lines:",
     732             :                       ref_array_len(new_vo->raw_lengths));
     733             : 
     734             :     TRACE_FLOW_EXIT();
     735       66448 :     return error;
     736             : }
     737             : 
     738             : /* Get concatenated value */
     739          41 : int value_get_concatenated(struct value_obj *vo,
     740             :                            const char **fullstr)
     741             : {
     742             :     TRACE_FLOW_ENTRY();
     743             : 
     744          41 :     if (!vo) {
     745             :         TRACE_ERROR_NUMBER("Invalid object", EINVAL);
     746             :         return EINVAL;
     747             :     }
     748             : 
     749          41 :     if (!fullstr)
     750             :     {
     751             :         TRACE_ERROR_NUMBER("Invalid output value", EINVAL);
     752             :         return EINVAL;
     753             :     }
     754             : 
     755          41 :     *fullstr = (const char *)simplebuffer_get_buf(vo->unfolded);
     756             : 
     757             :     TRACE_FLOW_EXIT();
     758          41 :     return EOK;
     759             : }
     760             : 
     761             : /* Get length of the concatenated value */
     762          27 : int value_get_concatenated_len(struct value_obj *vo,
     763             :                                uint32_t *len)
     764             : {
     765             :     TRACE_FLOW_ENTRY();
     766             : 
     767          27 :     if (!vo) {
     768             :         TRACE_ERROR_NUMBER("Invalid object", EINVAL);
     769             :         return EINVAL;
     770             :     }
     771             : 
     772          27 :     if (!len)
     773             :     {
     774             :         TRACE_ERROR_NUMBER("Invalid output value", EINVAL);
     775             :         return EINVAL;
     776             :     }
     777             : 
     778          27 :     *len = simplebuffer_get_len(vo->unfolded);
     779             : 
     780             :     TRACE_FLOW_EXIT();
     781          27 :     return EOK;
     782             : }
     783             : 
     784             : 
     785             : /* Get value's origin */
     786           1 : int value_get_origin(struct value_obj *vo, uint32_t *origin)
     787             : {
     788             :     TRACE_FLOW_ENTRY();
     789             : 
     790           1 :     if (!vo) {
     791             :         TRACE_ERROR_NUMBER("Invalid object", EINVAL);
     792             :         return EINVAL;
     793             :     }
     794             : 
     795           1 :     if (!origin)
     796             :     {
     797             :         TRACE_ERROR_NUMBER("Invalid output value", EINVAL);
     798             :         return EINVAL;
     799             :     }
     800             : 
     801           1 :     *origin = vo->origin;
     802             : 
     803             :     TRACE_FLOW_EXIT();
     804           1 :     return EOK;
     805             : }
     806             : 
     807             : /* Get value's line */
     808           1 : int value_get_line(struct value_obj *vo, uint32_t *line)
     809             : {
     810             :     TRACE_FLOW_ENTRY();
     811             : 
     812           1 :     if (!vo) {
     813             :         TRACE_ERROR_NUMBER("Invalid object", EINVAL);
     814             :         return EINVAL;
     815             :     }
     816             : 
     817           1 :     if (!line)
     818             :     {
     819             :         TRACE_ERROR_NUMBER("Invalid output value", EINVAL);
     820             :         return EINVAL;
     821             :     }
     822             : 
     823           1 :     *line = vo->line;
     824             : 
     825             :     TRACE_FLOW_EXIT();
     826           1 :     return EOK;
     827             : }
     828             : 
     829             : /* Update key length */
     830           1 : int value_set_keylen(struct value_obj *vo, uint32_t key_len)
     831             : {
     832           1 :     int error = EOK;
     833             :     TRACE_FLOW_ENTRY();
     834             : 
     835           1 :     if (!vo) {
     836             :         TRACE_ERROR_NUMBER("Invalid object", EINVAL);
     837             :         return EINVAL;
     838             :     }
     839             : 
     840           1 :     vo->keylen = key_len;
     841             : 
     842             :     /* Fold in new value */
     843           1 :     error = value_fold(vo->unfolded,
     844             :                        vo->keylen,
     845             :                        vo->boundary,
     846             :                        vo->raw_lines,
     847             :                        vo->raw_lengths);
     848           1 :     if (error) {
     849             :         TRACE_ERROR_NUMBER("Failed to fold", error);
     850             :         /* In this case nothing to free here but
     851             :          * the object might be unsiable */
     852           0 :         return error;
     853             :     }
     854             : 
     855             :     TRACE_FLOW_EXIT();
     856             :     return EOK;
     857             : }
     858             : 
     859             : /* Change boundary */
     860       65824 : int value_set_boundary(struct value_obj *vo, uint32_t boundary)
     861             : {
     862       65824 :     int error = EOK;
     863             :     TRACE_FLOW_ENTRY();
     864             : 
     865       65824 :     if (!vo) {
     866             :         TRACE_ERROR_NUMBER("Invalid object", EINVAL);
     867             :         return EINVAL;
     868             :     }
     869             : 
     870       65824 :     vo->boundary = boundary;
     871             : 
     872             :     /* Fold in new value */
     873       65824 :     error = value_fold(vo->unfolded,
     874             :                        vo->keylen,
     875             :                        vo->boundary,
     876             :                        vo->raw_lines,
     877             :                        vo->raw_lengths);
     878       65824 :     if (error) {
     879             :         TRACE_ERROR_NUMBER("Failed to fold", error);
     880             :         /* In this case nothing to free here but
     881             :          * the object might be unusable */
     882           0 :         return error;
     883             :     }
     884             : 
     885             :     TRACE_FLOW_EXIT();
     886             :     return EOK;
     887             : }
     888             : 
     889             : /* Update value */
     890           1 : int value_update(struct value_obj *vo,
     891             :                  const char *value,
     892             :                  uint32_t length,
     893             :                  uint32_t origin,
     894             :                  uint32_t boundary)
     895             : {
     896           1 :     int error = EOK;
     897           1 :     struct simplebuffer *oneline = NULL;
     898             : 
     899           1 :     if ((!value) || (!vo)) {
     900             :         TRACE_ERROR_NUMBER("Invalid argument", EINVAL);
     901             :         return EINVAL;
     902             :     }
     903             : 
     904             :     /* Create buffer to hold the value */
     905           1 :     error = simplebuffer_alloc(&oneline);
     906           1 :     if (error) {
     907             :         TRACE_ERROR_NUMBER("Failed to allocate dynamic string.", error);
     908             :         return error;
     909             :     }
     910             : 
     911             :     /* Put value into the buffer */
     912           1 :     error = simplebuffer_add_str(oneline,
     913             :                                  value,
     914             :                                  length,
     915             :                                  INI_VALUE_BLOCK);
     916           1 :     if (error) {
     917             :         TRACE_ERROR_NUMBER("Failed to add string", error);
     918           0 :         simplebuffer_free(oneline);
     919           0 :         return error;
     920             :     }
     921             : 
     922           1 :     simplebuffer_free(vo->unfolded);
     923             : 
     924           1 :     vo->origin = origin;
     925           1 :     vo->unfolded = oneline;
     926           1 :     vo->boundary = boundary;
     927             : 
     928             :     /* Fold in new value */
     929           1 :     error = value_fold(vo->unfolded,
     930             :                        vo->keylen,
     931             :                        vo->boundary,
     932             :                        vo->raw_lines,
     933             :                        vo->raw_lengths);
     934             :     if (error) {
     935             :         TRACE_ERROR_NUMBER("Failed to fold", error);
     936             :         /* In this case nothing to free here but
     937             :          * the object might be unsiable */
     938             :         return error;
     939             :     }
     940             : 
     941             :     TRACE_FLOW_EXIT();
     942             : 
     943             :     return error;
     944             : 
     945             : }
     946             : 
     947             : /* Get comment from the value */
     948          83 : int value_extract_comment(struct value_obj *vo, struct ini_comment **ic)
     949             : {
     950          83 :     int error = EOK;
     951             : 
     952             :     TRACE_FLOW_ENTRY();
     953             : 
     954          83 :     if ((!vo) || (!ic)) {
     955             :         TRACE_ERROR_NUMBER("Invalid input parameter", EINVAL);
     956             :         return EINVAL;
     957             :     }
     958             : 
     959          83 :     *ic = vo->ic;
     960          83 :     vo->ic = NULL;
     961             : 
     962             :     TRACE_FLOW_EXIT();
     963          83 :     return error;
     964             : 
     965             : }
     966             : 
     967             : /* Set comment into the value */
     968          81 : int value_put_comment(struct value_obj *vo, struct ini_comment *ic)
     969             : {
     970          81 :     int error = EOK;
     971             : 
     972             :     TRACE_FLOW_ENTRY();
     973             : 
     974          81 :     if ((!vo) || (!ic)) {
     975             :         TRACE_ERROR_NUMBER("Invalid input parameter", EINVAL);
     976             :         return EINVAL;
     977             :     }
     978             : 
     979          81 :     if (vo->ic != ic) {
     980             :         /* Remove existing comment if any */
     981          81 :         ini_comment_destroy(vo->ic);
     982             :     }
     983             : 
     984          81 :     vo->ic = ic;
     985             : 
     986             :     TRACE_FLOW_EXIT();
     987          81 :     return error;
     988             : 
     989             : }
     990             : 
     991             : /* Serialize value */
     992       66514 : int value_serialize(struct value_obj *vo,
     993             :                     const char *key,
     994             :                     struct simplebuffer *sbobj)
     995             : {
     996       66514 :     int error = EOK;
     997       66514 :     uint32_t i = 0;
     998       66514 :     uint32_t len = 0;
     999       66514 :     char *ptr = NULL;
    1000       66514 :     char *part = NULL;
    1001       66514 :     int sec = 0;
    1002       66514 :     uint32_t vln = 0;
    1003             : 
    1004             :     TRACE_FLOW_ENTRY();
    1005             :     TRACE_INFO_STRING("Serializing key:", key);
    1006             : 
    1007       66514 :     if (!vo) {
    1008             :         TRACE_ERROR_NUMBER("Invalid input parameter", EINVAL);
    1009             :         return EINVAL;
    1010             :     }
    1011             : 
    1012             :     /* Put comment first */
    1013       66514 :     if (vo->ic) {
    1014       31197 :         error = ini_comment_serialize(vo->ic, sbobj);
    1015       31197 :         if (error) {
    1016             :             TRACE_ERROR_NUMBER("Failed serialize comment", error);
    1017             :             return error;
    1018             :         }
    1019             :     }
    1020             : 
    1021             :     /* Handle the case it is a section key */
    1022       66514 :     if (strncmp(key,
    1023             :                 INI_SECTION_KEY,
    1024        1232 :                 sizeof(INI_SECTION_KEY)) == 0) sec = 1;
    1025             : 
    1026       66514 :     if (sec) {
    1027        1232 :         error = simplebuffer_add_str(sbobj,
    1028             :                                      INI_OPEN_BR,
    1029             :                                      sizeof(INI_OPEN_BR) - 1,
    1030             :                                      INI_VALUE_BLOCK);
    1031        1232 :         if (error) {
    1032             :             TRACE_ERROR_NUMBER("Failed to add opening section bracket", error);
    1033             :             return error;
    1034             : 
    1035             :         }
    1036             :     }
    1037             :     else {
    1038             : 
    1039       65282 :         error = simplebuffer_add_str(sbobj,
    1040             :                                      key,
    1041             :                                      vo->keylen,
    1042             :                                      INI_VALUE_BLOCK);
    1043       65282 :         if (error) {
    1044             :             TRACE_ERROR_NUMBER("Failed to add key", error);
    1045             :             return error;
    1046             :         }
    1047             : 
    1048       65282 :         error = simplebuffer_add_str(sbobj,
    1049             :                                      INI_EQUAL_SIGN,
    1050             :                                      sizeof(INI_EQUAL_SIGN) - 1,
    1051             :                                      INI_VALUE_BLOCK);
    1052       65282 :         if (error) {
    1053             :             TRACE_ERROR_NUMBER("Failed to add equal sign", error);
    1054             :             return error;
    1055             :         }
    1056             : 
    1057             :     }
    1058             : 
    1059       66514 :     if (vo->raw_lines) {
    1060             : 
    1061       66514 :         vln = ref_array_len(vo->raw_lines);
    1062             :         TRACE_INFO_NUMBER("Number of lines:", vln);
    1063             : 
    1064             : #ifdef HAVE_TRACE
    1065             : 
    1066             :         ref_array_debug(vo->raw_lines, 0);
    1067             :         ref_array_debug(vo->raw_lengths, 1);
    1068             : #endif
    1069             : 
    1070      530314 :         for (i = 0; i < vln; i++) {
    1071             :             /* Get line */
    1072      463800 :             ptr = ref_array_get(vo->raw_lines, i, NULL);
    1073             : 
    1074      463800 :             if (ptr) {
    1075             :                 /* Get its length */
    1076      463800 :                 len = 0;
    1077      463800 :                 ref_array_get(vo->raw_lengths, i, (void *)&len);
    1078             : 
    1079      463800 :                 part = *((char **)(ptr));
    1080             : 
    1081             :                 TRACE_INFO_STRING("Value:", part);
    1082             :                 TRACE_INFO_NUMBER("Lenght:", len);
    1083             : 
    1084      463800 :                 error = simplebuffer_add_raw(sbobj,
    1085             :                                              part,
    1086             :                                              len,
    1087             :                                              INI_VALUE_BLOCK);
    1088      463800 :                 if (error) {
    1089             :                     TRACE_ERROR_NUMBER("Failed to add value", error);
    1090             :                     return error;
    1091             :                 }
    1092             : 
    1093             :             }
    1094      463800 :             if (!sec) {
    1095      462568 :                 error = simplebuffer_add_cr(sbobj);
    1096      462568 :                 if (error) {
    1097             :                     TRACE_ERROR_NUMBER("Failed to add CR", error);
    1098             :                     return error;
    1099             :                 }
    1100             :             }
    1101             :         }
    1102             : 
    1103       66514 :         if ((!vln) && (!sec)) {
    1104         168 :             error = simplebuffer_add_cr(sbobj);
    1105         168 :             if (error) {
    1106             :                 TRACE_ERROR_NUMBER("Failed to add CR", error);
    1107             :                 return error;
    1108             :             }
    1109             :         }
    1110             :     }
    1111             : 
    1112       66514 :     if (sec) {
    1113        1232 :         error = simplebuffer_add_str(sbobj,
    1114             :                                      INI_CLOSE_BR,
    1115             :                                      sizeof(INI_CLOSE_BR) - 1,
    1116             :                                      INI_VALUE_BLOCK);
    1117        1232 :         if (error) {
    1118             :             TRACE_ERROR_NUMBER("Failed to add closing bracket", error);
    1119             :             return error;
    1120             : 
    1121             :         }
    1122             : 
    1123        1232 :         error = simplebuffer_add_cr(sbobj);
    1124        1232 :         if (error) {
    1125             :             TRACE_ERROR_NUMBER("Failed to add CR", error);
    1126             :             return error;
    1127             :         }
    1128             :     }
    1129             : 
    1130             :     TRACE_INFO_STRING("Buffer:", (const char *)simplebuffer_get_buf(sbobj));
    1131             :     TRACE_FLOW_EXIT();
    1132       66514 :     return error;
    1133             : }
    1134             : 
    1135             : /* Merge comment from one value into another */
    1136           1 : int value_merge_comment(struct value_obj *vo_donor,
    1137             :                         struct value_obj *vo)
    1138             : {
    1139           1 :     int error = EOK;
    1140             : 
    1141             :     TRACE_FLOW_ENTRY();
    1142             : 
    1143           1 :     if ((!vo) || (!vo_donor)) {
    1144             :         TRACE_ERROR_NUMBER("Invalid input parameter", EINVAL);
    1145             :         return EINVAL;
    1146             :     }
    1147             : 
    1148           1 :     if (vo_donor->ic) {
    1149             : 
    1150             :         /* If there is something to add */
    1151             : 
    1152           1 :         if (vo->ic) {
    1153             : 
    1154             :             /* Merge comments if both present */
    1155           1 :             error = ini_comment_add(vo_donor->ic, vo->ic);
    1156           1 :             if (error) {
    1157             :                 TRACE_ERROR_NUMBER("Failed to merge the comment", error);
    1158             :                 return error;
    1159             :             }
    1160             :         }
    1161             :         else {
    1162             : 
    1163             :             /* Copy comment if only donor present */
    1164           0 :             error = ini_comment_copy(vo_donor->ic, &(vo->ic));
    1165           0 :             if (error) {
    1166             :                 TRACE_ERROR_NUMBER("Failed to merge the comment", error);
    1167             :                 return error;
    1168             :             }
    1169             :         }
    1170             :     }
    1171             : 
    1172             :     TRACE_FLOW_EXIT();
    1173           1 :     return error;
    1174             : }
    1175             : 
    1176             : 
    1177             : /* Print value */
    1178           0 : void value_print(const char *key, struct value_obj *vo)
    1179             : {
    1180             : 
    1181           0 :     int error = EOK;
    1182           0 :     struct simplebuffer *sbobj = NULL;
    1183             : 
    1184             :     TRACE_FLOW_ENTRY();
    1185             : 
    1186           0 :     error = simplebuffer_alloc(&sbobj);
    1187           0 :     if (error) {
    1188           0 :         printf("Failed to allocate dynamic string %d.\n", error);
    1189           0 :         return;
    1190             :     }
    1191             : 
    1192             :     /* Serialize */
    1193           0 :     error = value_serialize(vo, key, sbobj);
    1194           0 :     if (error) {
    1195           0 :         printf("Failed to serialize a value object %d.\n", error);
    1196           0 :         simplebuffer_free(sbobj);
    1197           0 :         return;
    1198             :     }
    1199             : 
    1200           0 :     printf("%s", simplebuffer_get_buf(sbobj));
    1201           0 :     simplebuffer_free(sbobj);
    1202             : 
    1203             :     TRACE_FLOW_EXIT();
    1204             : }

Generated by: LCOV version 1.10