1 /*
2     INI LIBRARY
3 
4     Object to handle comments
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 <string.h>
25 #include <ctype.h>
26 #include "trace.h"
27 #include "ref_array.h"
28 #include "simplebuffer.h"
29 #include "ini_comment.h"
30 #include "ini_defines.h"
31 
32 /* The lines will increment in this number */
33 #define INI_COMMENT_BLOCK 10
34 /* Default comment length */
35 #define INI_COMMENT_LEN 100
36 
37 
38 /***************************/
39 /* Internal comment states */
40 /***************************/
41 /* Empty - initial */
42 #define INI_COMMENT_EMPTY   0
43 /* Read - read from file */
44 #define INI_COMMENT_READ    1
45 /* Comment was altered */
46 #define INI_COMMENT_CHANGED 2
47 
48 
49 /*********************************/
50 /* Modes to wrap ref array calls */
51 /*********************************/
52 #define INI_COMMENT_MODE_BUILD      1
53 #define INI_COMMENT_MODE_APPEND     2
54 #define INI_COMMENT_MODE_INSERT     3
55 #define INI_COMMENT_MODE_REPLACE    4
56 #define INI_COMMENT_MODE_REMOVE     5
57 #define INI_COMMENT_MODE_CLEAR      6
58 
59 /****************************************/
60 /* Internal structure to hold a comment */
61 /****************************************/
62 struct ini_comment {
63     struct ref_array *ra;
64     uint32_t state;
65 };
66 
67 
68 /****************************************/
69 
70 /* Destroy the comment object */
ini_comment_destroy(struct ini_comment * ic)71 void ini_comment_destroy(struct ini_comment *ic)
72 {
73 
74     TRACE_FLOW_ENTRY();
75     if (ic) {
76         /* Function will check for NULL */
77         ref_array_destroy(ic->ra);
78         free(ic);
79     }
80     TRACE_FLOW_EXIT();
81 }
82 
83 
84 /* Cleanup callback */
ini_comment_cb(void * elem,ref_array_del_enum type,void * data)85 static void ini_comment_cb(void *elem,
86                            ref_array_del_enum type,
87                            void *data)
88 {
89 
90     TRACE_FLOW_ENTRY();
91     simplebuffer_free(*((struct simplebuffer **)elem));
92     TRACE_FLOW_EXIT();
93 }
94 
95 
96 /* Create a comment object */
ini_comment_create(struct ini_comment ** ic)97 int ini_comment_create(struct ini_comment **ic)
98 {
99     int error = EOK;
100     struct ref_array *ra = NULL;
101     struct ini_comment *ic_new = NULL;
102 
103     TRACE_FLOW_ENTRY();
104 
105     error = ref_array_create(&ra,
106                              sizeof(struct simplebuffer *),
107                              INI_COMMENT_BLOCK,
108                              ini_comment_cb,
109                              NULL);
110     if (error) {
111         TRACE_ERROR_NUMBER("Error creating ref array", error);
112         return error;
113     }
114 
115     ic_new = malloc(sizeof(struct ini_comment));
116     if (!ic_new) {
117         TRACE_ERROR_NUMBER("Memory allocation error", ENOMEM);
118         ref_array_destroy(ra);
119         return ENOMEM;
120     }
121 
122     /* Initialize members here */
123     ic_new->ra = ra;
124     ic_new->state = INI_COMMENT_EMPTY;
125 
126     *ic = ic_new;
127 
128     TRACE_FLOW_EXIT();
129     return error;
130 }
131 
132 /* Callback to copy comment */
ini_comment_copy_cb(void * elem,void * new_elem)133 static int ini_comment_copy_cb(void *elem,
134                                void *new_elem)
135 {
136     int error = EOK;
137     struct simplebuffer *sb = NULL;
138     struct simplebuffer *sb_new = NULL;
139 
140     TRACE_FLOW_ENTRY();
141 
142     error = simplebuffer_alloc(&sb_new);
143     if (error) {
144         TRACE_ERROR_NUMBER("Failed to allocate buffer", error);
145         return error;
146     }
147 
148     sb = *((struct simplebuffer **)elem);
149     error = simplebuffer_add_str(sb_new,
150                                  (const char *)simplebuffer_get_buf(sb),
151                                  simplebuffer_get_len(sb),
152                                  INI_COMMENT_LEN);
153     if (error) {
154         TRACE_ERROR_NUMBER("Failed to allocate buffer", error);
155         simplebuffer_free(sb_new);
156         return error;
157     }
158 
159     *((struct simplebuffer **)new_elem) = sb_new;
160 
161     TRACE_FLOW_EXIT();
162     return error;
163 }
164 
165 
166 /* Create a copy of the comment object */
ini_comment_copy(struct ini_comment * ic,struct ini_comment ** ic_copy)167 int ini_comment_copy(struct ini_comment *ic,
168                      struct ini_comment **ic_copy)
169 {
170     int error = EOK;
171     struct ref_array *ra = NULL;
172     struct ini_comment *ic_new = NULL;
173 
174     TRACE_FLOW_ENTRY();
175 
176     error = ref_array_copy(ic->ra,
177                            ini_comment_copy_cb,
178                            ini_comment_cb,
179                            NULL,
180                            &ra);
181     if (error) {
182         TRACE_ERROR_NUMBER("Error creating a copy of ref array", error);
183         return error;
184     }
185 
186     ic_new = malloc(sizeof(struct ini_comment));
187     if (!ic_new) {
188         TRACE_ERROR_NUMBER("Memory allocation error", ENOMEM);
189         ref_array_destroy(ra);
190         return ENOMEM;
191     }
192 
193     /* Initialize members here */
194     ic_new->ra = ra;
195     ic_new->state = ic->state;
196 
197     *ic_copy = ic_new;
198 
199     TRACE_FLOW_EXIT();
200     return error;
201 }
202 
203 /*
204  * Modify the comment object
205  */
ini_comment_modify(struct ini_comment * ic,int mode,uint32_t idx,const char * line,uint32_t length)206 static int ini_comment_modify(struct ini_comment *ic,
207                               int mode,
208                               uint32_t idx,
209                               const char *line,
210                               uint32_t length)
211 {
212     int error = EOK;
213     struct simplebuffer *elem = NULL;
214     struct simplebuffer *empty = NULL;
215     char *input = NULL;
216 
217     uint32_t i, len = 0;
218     uint32_t input_len = 0;
219 
220     TRACE_FLOW_ENTRY();
221 
222     if (!ic) {
223         TRACE_ERROR_NUMBER("Invalid comment object", EINVAL);
224         return EINVAL;
225     }
226 
227 
228     if (mode == INI_COMMENT_MODE_BUILD) {
229         /*
230          * Can use this function only if object is empty or
231          * reading from the file.
232          */
233         if ((ic->state != INI_COMMENT_EMPTY) &&
234             (ic->state != INI_COMMENT_READ)) {
235             TRACE_ERROR_NUMBER("Invalid use of the function", EINVAL);
236             return EINVAL;
237         }
238     }
239 
240     /* Make sure that we ignore "line" in reset case */
241     if (mode != INI_COMMENT_MODE_CLEAR)
242         memcpy(&input, &line, sizeof(char *));
243 
244     if (mode != INI_COMMENT_MODE_REMOVE) {
245 
246         error = simplebuffer_alloc(&elem);
247         if (error) {
248             TRACE_ERROR_NUMBER("Allocate buffer for the comment", error);
249             return error;
250         }
251 
252         if (input) {
253             if (length == 0) input_len = strlen(input);
254             else input_len = length;
255 
256             error = simplebuffer_add_str(elem,
257                                          input,
258                                          input_len,
259                                          INI_COMMENT_LEN);
260         }
261         else {
262             error = simplebuffer_add_str(elem,
263                                          "",
264                                          0,
265                                          INI_COMMENT_LEN);
266         }
267 
268         if (error) {
269             TRACE_ERROR_NUMBER("Allocate buffer for the comment", error);
270             simplebuffer_free(elem);
271             return error;
272         }
273     }
274 
275     /* Do action depending on mode */
276     switch (mode) {
277     case INI_COMMENT_MODE_BUILD:
278 
279         TRACE_INFO_STRING("BUILD mode", "");
280         error = ref_array_append(ic->ra, (void *)&elem);
281         if (error) {
282             TRACE_ERROR_NUMBER("Failed to append line to an array", error);
283             simplebuffer_free(elem);
284             return error;
285         }
286 
287         break;
288 
289     case INI_COMMENT_MODE_APPEND:
290 
291         TRACE_INFO_STRING("Append mode", "");
292         error = ref_array_append(ic->ra, (void *)&elem);
293         if (error) {
294             TRACE_ERROR_NUMBER("Failed to append line to an array", error);
295             simplebuffer_free(elem);
296             return error;
297         }
298 
299         break;
300 
301     case INI_COMMENT_MODE_INSERT:
302 
303         TRACE_INFO_STRING("Insert mode", "");
304         len = ref_array_len(ic->ra);
305         if (idx > len) {
306             /* Fill in empty lines */
307             for (i = 0; i < (idx-len); i++) {
308                 error = simplebuffer_alloc(&empty);
309                 if (error) {
310                     TRACE_ERROR_NUMBER("Allocate buffer for the comment", error);
311                     simplebuffer_free(elem);
312                     return error;
313                 }
314                 error = simplebuffer_add_str(elem,
315                                              NULL,
316                                              0,
317                                              INI_COMMENT_LEN);
318                 if (error) {
319                     TRACE_ERROR_NUMBER("Make comment empty", error);
320                     simplebuffer_free(empty);
321                     simplebuffer_free(elem);
322                     return error;
323                 }
324                 error = ref_array_append(ic->ra, (void *)&empty);
325                 if (error) {
326                     TRACE_ERROR_NUMBER("Append problem", error);
327                     simplebuffer_free(empty);
328                     simplebuffer_free(elem);
329                     return error;
330                 }
331             }
332             /* Append last line */
333             error = ref_array_append(ic->ra, (void *)&elem);
334             if (error) {
335                 TRACE_ERROR_NUMBER("Failed to append last line", error);
336                 simplebuffer_free(elem);
337                 return error;
338             }
339         }
340         else {
341             /* Insert inside the array */
342             error = ref_array_insert(ic->ra, idx, (void *)&elem);
343             if (error) {
344                 TRACE_ERROR_NUMBER("Failed to append last line", error);
345                 simplebuffer_free(elem);
346                 return error;
347             }
348 
349         }
350         break;
351 
352 
353     case INI_COMMENT_MODE_REPLACE:
354 
355         TRACE_INFO_STRING("Replace mode", "");
356         error = ref_array_replace(ic->ra, idx, (void *)&elem);
357         if (error) {
358             TRACE_ERROR_NUMBER("Failed to replace", error);
359             simplebuffer_free(elem);
360             return error;
361         }
362         break;
363 
364     case INI_COMMENT_MODE_REMOVE:
365 
366         TRACE_INFO_STRING("Remove mode", "");
367         error = ref_array_remove(ic->ra, idx);
368         if (error) {
369             TRACE_ERROR_NUMBER("Failed to remove", error);
370             return error;
371         }
372 
373         break;
374 
375     case INI_COMMENT_MODE_CLEAR:
376 
377         TRACE_INFO_STRING("Clear mode", "");
378         error = ref_array_replace(ic->ra, idx, (void *)&elem);
379         if (error) {
380             TRACE_ERROR_NUMBER("Failed to replace", error);
381             simplebuffer_free(elem);
382             return error;
383         }
384         break;
385 
386     default :
387 
388         TRACE_ERROR_STRING("Coding error", "");
389         simplebuffer_free(elem);
390         return EINVAL;
391 
392     }
393 
394 
395     /* Change state */
396     if (INI_COMMENT_MODE_BUILD) ic->state = INI_COMMENT_READ;
397     else ic->state = INI_COMMENT_CHANGED;
398 
399 
400     TRACE_FLOW_EXIT();
401     return error;
402 }
403 
404 /*
405  * Build up a comment object - use this when reading
406  * comments from a file.
407  */
ini_comment_build(struct ini_comment * ic,const char * line)408 int ini_comment_build(struct ini_comment *ic, const char *line)
409 {
410     int error = EOK;
411 
412     TRACE_FLOW_ENTRY();
413 
414     error = ini_comment_modify(ic, INI_COMMENT_MODE_BUILD, 0, line, 0);
415 
416     TRACE_FLOW_NUMBER("ini_comment_build - Returning", error);
417     return error;
418 }
419 
420 /*
421  * Build up a comment object - use this when reading
422  * comments from a file.
423  */
ini_comment_build_wl(struct ini_comment * ic,const char * line,uint32_t length)424 int ini_comment_build_wl(struct ini_comment *ic,
425                          const char *line,
426                          uint32_t length)
427 {
428     int error = EOK;
429 
430     TRACE_FLOW_ENTRY();
431 
432     error = ini_comment_modify(ic, INI_COMMENT_MODE_BUILD, 0, line, length);
433 
434     TRACE_FLOW_NUMBER("ini_comment_build - Returning", error);
435     return error;
436 }
437 
438 /*
439  * Modify comment by instering a line.
440  */
ini_comment_insert(struct ini_comment * ic,uint32_t idx,const char * line)441 int ini_comment_insert(struct ini_comment *ic,
442                        uint32_t idx,
443                        const char *line)
444 {
445     int error = EOK;
446 
447     TRACE_FLOW_ENTRY();
448 
449     error = ini_comment_modify(ic, INI_COMMENT_MODE_INSERT, idx, line, 0);
450 
451     TRACE_FLOW_NUMBER("ini_comment_insert - Returning", error);
452     return error;
453 }
454 
455 /* Modify comment by appending a line. */
ini_comment_append(struct ini_comment * ic,const char * line)456 int ini_comment_append(struct ini_comment *ic, const char *line)
457 {
458     int error = EOK;
459 
460     TRACE_FLOW_ENTRY();
461 
462     error = ini_comment_modify(ic, INI_COMMENT_MODE_APPEND, 0, line, 0);
463 
464     TRACE_FLOW_NUMBER("ini_comment_append - Returning", error);
465     return error;
466 }
467 
468 /* Remove line from the comment.*/
ini_comment_remove(struct ini_comment * ic,uint32_t idx)469 int ini_comment_remove(struct ini_comment *ic, uint32_t idx)
470 {
471     int error = EOK;
472 
473     TRACE_FLOW_ENTRY();
474 
475     error = ini_comment_modify(ic, INI_COMMENT_MODE_REMOVE, idx, NULL, 0);
476 
477     TRACE_FLOW_NUMBER("ini_comment_remove - Returning", error);
478     return error;
479 }
480 
481 /* Clear line in the comment. Line is replaced with an empty line */
ini_comment_clear(struct ini_comment * ic,uint32_t idx)482 int ini_comment_clear(struct ini_comment *ic, uint32_t idx)
483 {
484     int error = EOK;
485 
486     TRACE_FLOW_ENTRY();
487 
488     error = ini_comment_modify(ic, INI_COMMENT_MODE_CLEAR, idx, NULL, 0);
489 
490     TRACE_FLOW_NUMBER("ini_comment_clear - Returning", error);
491     return error;
492 
493 }
494 
495 /* Replace a line in the comment */
ini_comment_replace(struct ini_comment * ic,uint32_t idx,const char * line)496 int ini_comment_replace(struct ini_comment *ic,
497                         uint32_t idx,
498                         const char *line)
499 {
500     int error = EOK;
501 
502     TRACE_FLOW_ENTRY();
503 
504     error = ini_comment_modify(ic, INI_COMMENT_MODE_REPLACE, idx, line, 0);
505 
506     TRACE_FLOW_NUMBER("ini_comment_replace - Returning", error);
507     return error;
508 }
509 
510 
511 /* Reset the comment - clean all lines.*/
ini_comment_reset(struct ini_comment * ic)512 int ini_comment_reset(struct ini_comment *ic)
513 {
514     int error = EOK;
515 
516     TRACE_FLOW_ENTRY();
517 
518     if (!ic) {
519         TRACE_ERROR_NUMBER("Invalid comment object", EINVAL);
520         return EINVAL;
521     }
522 
523     /* Reset comment if it is not empty */
524     if (ic->state != INI_COMMENT_EMPTY) {
525         ref_array_reset(ic->ra);
526         ic->state = INI_COMMENT_CHANGED;
527     }
528 
529     TRACE_FLOW_EXIT();
530     return error;
531 }
532 
533 /* Get number of lines */
ini_comment_get_numlines(struct ini_comment * ic,uint32_t * num)534 int ini_comment_get_numlines(struct ini_comment *ic, uint32_t *num)
535 {
536     int error = EOK;
537 
538     TRACE_FLOW_ENTRY();
539 
540     if ((!ic) || (!num)) {
541         TRACE_ERROR_NUMBER("Invalid argument", EINVAL);
542         return EINVAL;
543     }
544 
545     error = ref_array_getlen(ic->ra, num);
546 
547     TRACE_FLOW_NUMBER("ini_comment_get_numlines - Returning", error);
548     return error;
549 
550 }
551 
552 /* Get line */
ini_comment_get_line(struct ini_comment * ic,uint32_t idx,char ** line,uint32_t * line_len)553 int ini_comment_get_line(struct ini_comment *ic, uint32_t idx,
554                          char **line, uint32_t *line_len)
555 {
556     int error = EOK;
557     void *res = NULL;
558     struct simplebuffer *sb = NULL;
559     const unsigned char *ln;
560 
561     TRACE_FLOW_ENTRY();
562 
563     if ((!ic) || (!line)) {
564         TRACE_ERROR_NUMBER("Invalid argument", EINVAL);
565         return EINVAL;
566     }
567 
568     res = ref_array_get(ic->ra, idx, (void *)&sb);
569     if (!res) {
570         error = EINVAL;
571         *line = NULL;
572         if (line_len) line_len = 0;
573     }
574     else {
575         ln = simplebuffer_get_buf(sb);
576         memcpy(line, &ln, sizeof(char *));
577         if (line_len) *line_len = simplebuffer_get_len(sb);
578     }
579 
580     TRACE_FLOW_NUMBER("ini_comment_get_line - Returning", error);
581     return error;
582 }
583 
584 /* Swap lines */
ini_comment_swap(struct ini_comment * ic,uint32_t idx1,uint32_t idx2)585 int ini_comment_swap(struct ini_comment *ic,
586                      uint32_t idx1,
587                      uint32_t idx2)
588 {
589     int error = EOK;
590 
591     TRACE_FLOW_ENTRY();
592 
593     if (!ic) {
594         TRACE_ERROR_NUMBER("Invalid argument", EINVAL);
595         return EINVAL;
596     }
597 
598     if (idx1 != idx2) {
599         if ((error = ref_array_swap(ic->ra, idx1, idx2))) {
600             TRACE_ERROR_NUMBER("Failed to swap", error);
601             return error;
602         }
603         ic->state = INI_COMMENT_CHANGED;
604     }
605 
606     TRACE_FLOW_EXIT();
607     return error;
608 }
609 
610 /* Add one comment to another */
ini_comment_add(struct ini_comment * ic_to_add,struct ini_comment * ic)611 int ini_comment_add(struct ini_comment *ic_to_add,
612                     struct ini_comment *ic)
613 {
614     int error = EOK;
615     struct simplebuffer *sb = NULL;
616     struct simplebuffer *sb_new = NULL;
617     void *res = NULL;
618     uint32_t len = 0;
619     int i;
620 
621     TRACE_FLOW_ENTRY();
622 
623     len = ref_array_len(ic_to_add->ra);
624 
625     for (i = 0; i< len; i++) {
626 
627         /* Get data element */
628         res = ref_array_get(ic_to_add->ra, i, (void *)(&sb));
629         if (!res) {
630             TRACE_ERROR_NUMBER("Failed to get comment element", error);
631             return error;
632         }
633 
634         /* Create a storage a for a copy */
635         error = simplebuffer_alloc(&sb_new);
636         if (error) {
637             TRACE_ERROR_NUMBER("Allocate buffer for the comment", error);
638             return error;
639         }
640 
641         /* Copy actual data */
642         error = simplebuffer_add_str(sb_new,
643                                      (const char *)simplebuffer_get_buf(sb),
644                                      simplebuffer_get_len(sb),
645                                      INI_COMMENT_LEN);
646         if (error) {
647             TRACE_ERROR_NUMBER("Failed to append line to an array", error);
648             simplebuffer_free(sb_new);
649             return error;
650         }
651 
652         /* Append it to the array */
653         error = ref_array_append(ic->ra, (void *)&sb_new);
654         if (error) {
655             TRACE_ERROR_NUMBER("Failed to append element to an array", error);
656             simplebuffer_free(sb_new);
657             return error;
658         }
659     }
660 
661     TRACE_FLOW_EXIT();
662     return error;
663 }
664 
665 /* Serialize comment */
ini_comment_serialize(struct ini_comment * ic,struct simplebuffer * sbobj)666 int ini_comment_serialize (struct ini_comment *ic,
667                            struct simplebuffer *sbobj)
668 {
669     int error = EOK;
670     uint32_t num = 0;
671     uint32_t i = 0;
672     uint32_t len = 0;
673     char *commentline = NULL;
674 
675     TRACE_FLOW_ENTRY();
676 
677     /* Get number of lines in the comment */
678     error = ini_comment_get_numlines(ic, &num);
679     if (error) {
680         TRACE_ERROR_NUMBER("Failed to get number of lines", error);
681         return error;
682     }
683 
684     for (i = 0; i < num; i++) {
685 
686         len = 0;
687         commentline = NULL;
688 
689         error = ini_comment_get_line(ic, i, &commentline, &len);
690         if (error) {
691             TRACE_ERROR_NUMBER("Failed to get line", error);
692             return error;
693         }
694 
695         error = simplebuffer_add_raw(sbobj,
696                                      commentline,
697                                      len,
698                                      INI_VALUE_BLOCK);
699         if (error) {
700             TRACE_ERROR_NUMBER("Failed to add comment", error);
701             return error;
702         }
703 
704         error = simplebuffer_add_cr(sbobj);
705         if (error) {
706             TRACE_ERROR_NUMBER("Failed to add CR", error);
707             return error;
708         }
709     }
710 
711     TRACE_FLOW_EXIT();
712     return error;
713 }
714 
715 /* Internal function to print comment */
ini_comment_print(struct ini_comment * ic,FILE * file)716 void ini_comment_print(struct ini_comment *ic, FILE *file)
717 {
718     int len;
719     int i;
720     struct simplebuffer *sb = NULL;
721 
722     TRACE_FLOW_ENTRY();
723 
724     if (!file) {
725         TRACE_ERROR_NUMBER("Invalid file argument", EINVAL);
726         return;
727     }
728 
729     if (ic) {
730         len = ref_array_len(ic->ra);
731         for (i = 0; i < len; i++) {
732             ref_array_get(ic->ra, i, (void *)(&sb));
733             fprintf(file, "%s\n", simplebuffer_get_buf(sb));
734         }
735     }
736 
737     TRACE_FLOW_EXIT();
738 }
739 
740 /* Construct a comment out of array or strings. */
ini_comment_construct(const char * comments[],size_t count_comment,struct ini_comment ** ic)741 int ini_comment_construct(const char *comments[],
742                           size_t count_comment,
743                           struct ini_comment **ic)
744 {
745     int error = EOK;
746     size_t cnt = 0;
747     struct ini_comment *new_ic = NULL;
748 
749     TRACE_FLOW_ENTRY();
750     if (!ic) {
751         TRACE_ERROR_STRING("Invalid argument","comment object");
752         return EINVAL;
753     }
754 
755     if (comments) {
756         error =  ini_comment_create(&new_ic);
757         if (error) {
758             TRACE_ERROR_NUMBER("Failed to create comment object",
759                                error);
760             return error;
761         }
762 
763         if (count_comment) {
764             /* Base the number of lines on count */
765             for (cnt = 0; cnt < count_comment; cnt++) {
766                 error = ini_comment_append(new_ic, comments[cnt]);
767                 if (error) {
768                     TRACE_ERROR_NUMBER("Failed to append comment in for loop.",
769                                        error);
770                     ini_comment_destroy(new_ic);
771                     return error;
772                 }
773             }
774         }
775         else {
776             /* Assume that the list is NULL terminated */
777             while (comments[cnt]) {
778                 error = ini_comment_append(new_ic, comments[cnt]);
779                 if (error) {
780                     TRACE_ERROR_NUMBER("Failed to append comment in for loop.",
781                                        error);
782                     ini_comment_destroy(new_ic);
783                     return error;
784                 }
785                 cnt++;
786             }
787         }
788         *ic = new_ic;
789     }
790     else {
791         /* No comments! */
792         *ic = NULL;
793     }
794 
795     TRACE_FLOW_EXIT();
796     return EOK;
797 }
798