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