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