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 *)(©));
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