Line data Source code
1 : /*
2 : COLLECTION LIBRARY
3 :
4 : Additional functions for printing and debugging collections.
5 :
6 : Copyright (C) Dmitri Pal <dpal@redhat.com> 2009
7 :
8 : Collection 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 : Collection 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 Collection Library. If not, see <http://www.gnu.org/licenses/>.
20 : */
21 :
22 : #include "config.h"
23 : #include <stdio.h>
24 : #include <malloc.h>
25 : #include <errno.h>
26 : #include <string.h>
27 : #include "trace.h"
28 : #include "collection_priv.h"
29 : #include "collection.h"
30 : #include "collection_tools.h"
31 :
32 : /* Debug handle */
33 0 : int col_debug_handle(const char *property,
34 : int property_len,
35 : int type,
36 : void *data,
37 : int length,
38 : void *custom_data,
39 : int *dummy)
40 : {
41 : int i;
42 : int nest_level;
43 0 : int ignore = 0;
44 :
45 : TRACE_FLOW_STRING("col_debug_handle", "Entry.");
46 :
47 :
48 0 : nest_level = *(int *)(custom_data);
49 0 : if (nest_level == -1) {
50 0 : ignore = 1;
51 0 : nest_level = 1;
52 : }
53 :
54 : TRACE_INFO_NUMBER("We are getting this pointer:", custom_data);
55 : TRACE_INFO_NUMBER("Nest level:", nest_level);
56 :
57 0 : switch (type) {
58 : case COL_TYPE_STRING:
59 0 : printf(">%*s%s[%d] str: %s (%d)\n",
60 0 : (nest_level -1) * 4, "",
61 : property,
62 : length,
63 : (char *)(data),
64 : nest_level);
65 0 : break;
66 : case COL_TYPE_BINARY:
67 0 : printf(">%*s%s[%d] bin: ",
68 0 : (nest_level -1) * 4, "",
69 : property,
70 : length);
71 0 : for (i = 0; i < length; i++)
72 0 : printf("%02X", ((unsigned char *)(data))[i]);
73 0 : printf(" (%d)\n", nest_level);
74 0 : break;
75 : case COL_TYPE_INTEGER:
76 0 : printf(">%*s%s[%d] int: %d (%d)\n",
77 0 : (nest_level -1) * 4, "",
78 : property,
79 : length,
80 : *((int32_t *)(data)),
81 : nest_level);
82 0 : break;
83 : case COL_TYPE_UNSIGNED:
84 0 : printf(">%*s%s[%d] uint: %u (%d)\n",
85 0 : (nest_level -1) * 4, "",
86 : property,
87 : length,
88 : *((uint32_t *)(data)),
89 : nest_level);
90 0 : break;
91 : case COL_TYPE_LONG:
92 0 : printf(">%*s%s[%d] long: %lld (%d)\n",
93 0 : (nest_level -1) * 4, "",
94 : property,
95 : length,
96 : (long long int)(*((int64_t *)(data))),
97 : nest_level);
98 0 : break;
99 : case COL_TYPE_ULONG:
100 0 : printf(">%*s%s[%d] ulong: %llu (%d)\n",
101 0 : (nest_level -1) * 4, "",
102 : property,
103 : length,
104 : (long long unsigned)(*((uint64_t *)(data))),
105 : nest_level);
106 0 : break;
107 : case COL_TYPE_DOUBLE:
108 0 : printf(">%*s%s[%d] double: %.4f (%d)\n",
109 0 : (nest_level -1) * 4, "",
110 : property,
111 : length,
112 : *((double *)(data)),
113 : nest_level);
114 0 : break;
115 : case COL_TYPE_BOOL:
116 0 : printf(">%*s%s[%d] bool: %s (%d)\n",
117 0 : (nest_level -1) * 4, "",
118 : property,
119 : length,
120 0 : (*((unsigned char *)(data)) == '\0') ? "false" : "true",
121 : nest_level);
122 0 : break;
123 : case COL_TYPE_COLLECTION:
124 0 : if (!ignore) nest_level++;
125 0 : printf(">%*s%s[%d] header: count %d, ref_count %d class %d data: ",
126 0 : (nest_level -1) * 4, "",
127 : property,
128 : length,
129 : ((struct collection_header *)(data))->count,
130 : ((struct collection_header *)(data))->reference_count,
131 : ((struct collection_header *)(data))->cclass);
132 : /* Due to padding issues this is unsafe so ifdefed for now */
133 : #ifdef COL_PRINT_BINARY_HEADER
134 : for (i = 0; i < length; i++)
135 : printf("%02X", ((unsigned char *)(data))[i]);
136 : #endif
137 0 : printf(" (%d)\n", nest_level);
138 0 : break;
139 : case COL_TYPE_COLLECTIONREF:
140 0 : printf(">%*s%s[%d] external link: ",
141 0 : (nest_level -1) * 4, "",
142 : property,
143 : length);
144 0 : for (i = 0; i < length; i++)
145 0 : printf("%02X", ((unsigned char *)(data))[i]);
146 0 : printf(" (%d)\n", nest_level);
147 0 : break;
148 : case COL_TYPE_END:
149 0 : printf(">%*sEND[N/A] (%d)\n",
150 0 : (nest_level -1) * 4, "",
151 : nest_level);
152 0 : if (!ignore) nest_level--;
153 0 : break;
154 : default:
155 0 : printf("Not implemented yet.\n");
156 0 : break;
157 : }
158 0 : *(int *)(custom_data) = nest_level;
159 : TRACE_INFO_NUMBER("Nest level at the end:", nest_level);
160 : TRACE_FLOW_STRING("col_debug_handle", "Success exit.");
161 0 : return EOK;
162 : }
163 :
164 : /* Convenience function to debug an item */
165 0 : inline int col_debug_item(struct collection_item *item)
166 : {
167 0 : int dummy = 0;
168 0 : int nest_level = -1;
169 0 : return col_debug_handle(item->property,
170 : item->property_len,
171 : item->type,
172 : item->data,
173 : item->length,
174 : (void *)(&nest_level),
175 : &dummy);
176 : }
177 :
178 :
179 : /* Print collection for debugging purposes */
180 0 : int col_debug_collection(struct collection_item *handle, int flag)
181 : {
182 0 : int error = EOK;
183 0 : int nest_level = 0;
184 :
185 : TRACE_FLOW_STRING("col_debug_collection", "Entry.");
186 :
187 0 : printf("DEBUG COLLECTION %s\n", handle->property);
188 :
189 0 : flag |= COL_TRAVERSE_END;
190 :
191 0 : printf("Traverse flags %d\n", flag);
192 :
193 : /* Traverse collection */
194 0 : error = col_traverse_collection(handle, flag,
195 : col_debug_handle,
196 : (void *)(&nest_level));
197 0 : if (error) printf("Error debuging collection %d\n", error);
198 :
199 : TRACE_FLOW_STRING("col_debug_collection", "Exit.");
200 0 : return error;
201 : }
202 :
203 :
204 : /* Return a static string based on type of the element */
205 : static inline const char *col_get_type(int type)
206 : {
207 : switch (type) {
208 : case COL_TYPE_STRING:
209 : return COL_TYPE_NAME_STRING;
210 :
211 : case COL_TYPE_INTEGER:
212 : return COL_TYPE_NAME_INTEGER;
213 :
214 : case COL_TYPE_UNSIGNED:
215 : return COL_TYPE_NAME_UNSIGNED;
216 :
217 : case COL_TYPE_LONG:
218 : return COL_TYPE_NAME_LONG;
219 :
220 : case COL_TYPE_ULONG:
221 : return COL_TYPE_NAME_ULONG;
222 :
223 : case COL_TYPE_BINARY:
224 : return COL_TYPE_NAME_BINARY;
225 :
226 : case COL_TYPE_DOUBLE:
227 : return COL_TYPE_NAME_DOUBLE;
228 :
229 : case COL_TYPE_BOOL:
230 : return COL_TYPE_NAME_BOOL;
231 :
232 : default:
233 : return COL_TYPE_NAME_UNKNOWN;
234 : }
235 :
236 : }
237 :
238 : /* Calculate the potential size of the item */
239 0 : int col_get_data_len(int type, int length)
240 : {
241 0 : int len = 0;
242 :
243 : TRACE_FLOW_STRING("col_get_data_len", "Entry point");
244 :
245 0 : switch (type) {
246 : case COL_TYPE_INTEGER:
247 : case COL_TYPE_UNSIGNED:
248 0 : len = 11;
249 0 : break;
250 : case COL_TYPE_LONG:
251 : case COL_TYPE_ULONG:
252 0 : len = 20;
253 0 : break;
254 :
255 : case COL_TYPE_STRING:
256 : case COL_TYPE_BINARY:
257 0 : len = length * 2 + 2;
258 0 : break;
259 :
260 : case COL_TYPE_DOUBLE:
261 0 : len = 64;
262 0 : break;
263 :
264 : case COL_TYPE_BOOL:
265 0 : len = 6;
266 0 : break;
267 :
268 : default:
269 0 : len = 0;
270 0 : break;
271 : }
272 :
273 : TRACE_FLOW_STRING("col_get_data_len","Exit point");
274 :
275 0 : return len;
276 : }
277 :
278 : /* Copy data escaping characters */
279 0 : static int col_copy_esc(char *dest, const char *source, char esc)
280 : {
281 0 : int i = 0;
282 0 : int j = 0;
283 :
284 0 : dest[j] = esc;
285 0 : j++;
286 :
287 0 : while (source[i]) {
288 0 : if ((source[i] == '\\') ||
289 0 : (source[i] == esc)) {
290 :
291 0 : dest[j] = '\\';
292 0 : j++;
293 :
294 : }
295 0 : dest[j] = source[i];
296 0 : i++;
297 0 : j++;
298 : }
299 0 : dest[j] = esc;
300 0 : j++;
301 :
302 0 : return j;
303 : }
304 :
305 : /* Grow buffer to accomodate more space */
306 0 : int col_grow_buffer(struct col_serial_data *buf_data, int len)
307 : {
308 : char *tmp;
309 :
310 : TRACE_FLOW_STRING("col_grow_buffer", "Entry point");
311 : TRACE_INFO_NUMBER("Current length: ", buf_data->length);
312 : TRACE_INFO_NUMBER("Increment length: ", len);
313 : TRACE_INFO_NUMBER("Expected length: ", buf_data->length+len);
314 : TRACE_INFO_NUMBER("Current size: ", buf_data->size);
315 :
316 : /* Grow buffer if needed */
317 0 : while (buf_data->length+len >= buf_data->size) {
318 0 : tmp = realloc(buf_data->buffer, buf_data->size + BLOCK_SIZE);
319 0 : if (tmp == NULL) {
320 : TRACE_ERROR_NUMBER("Error. Failed to allocate memory.", ENOMEM);
321 0 : return ENOMEM;
322 : }
323 0 : buf_data->buffer = tmp;
324 0 : buf_data->size += BLOCK_SIZE;
325 : TRACE_INFO_NUMBER("New size: ", buf_data->size);
326 :
327 : }
328 :
329 : TRACE_INFO_NUMBER("Final size: ", buf_data->size);
330 : TRACE_FLOW_STRING("col_grow_buffer", "Success Exit.");
331 0 : return EOK;
332 : }
333 :
334 : /* Specail function to add different formatting symbols to the output */
335 0 : int col_put_marker(struct col_serial_data *buf_data, const void *data, int len)
336 : {
337 0 : int error = EOK;
338 :
339 : TRACE_FLOW_STRING("col_put_marker", "Entry point");
340 : TRACE_INFO_NUMBER("Marker length: ", len);
341 :
342 0 : error = col_grow_buffer(buf_data, len);
343 0 : if (error) {
344 : TRACE_ERROR_NUMBER("col_grow_buffer failed with: ", error);
345 0 : return error;
346 : }
347 0 : memcpy(buf_data->buffer + buf_data->length, data, len);
348 0 : buf_data->length += len;
349 0 : buf_data->buffer[buf_data->length] = '\0';
350 :
351 : TRACE_FLOW_STRING("col_put_marker","Success exit");
352 0 : return error;
353 : }
354 :
355 : /* Add item's data */
356 0 : int col_serialize(const char *property_in,
357 : int property_len_in,
358 : int type,
359 : void *data_in,
360 : int length_in,
361 : void *custom_data,
362 : int *dummy)
363 : {
364 : int len;
365 : struct col_serial_data *buf_data;
366 : const char *property;
367 : const void *data;
368 : int property_len;
369 : int length;
370 0 : int error = EOK;
371 : int i;
372 :
373 : TRACE_FLOW_STRING("col_serialize","Entry point");
374 :
375 0 : *dummy = 0;
376 :
377 : /* Check is there is buffer. If not allocate */
378 0 : buf_data = (struct col_serial_data *)custom_data;
379 0 : if (buf_data == NULL) {
380 : TRACE_ERROR_STRING("Error.", "Storage data is not passed in!");
381 0 : return EINVAL;
382 : }
383 0 : if (buf_data->buffer == NULL) {
384 : TRACE_INFO_STRING("First time use.", "Allocating buffer.");
385 0 : buf_data->buffer = malloc(BLOCK_SIZE);
386 0 : if (buf_data->buffer == NULL) {
387 : TRACE_ERROR_NUMBER("Error. Failed to allocate memory.", ENOMEM);
388 0 : return ENOMEM;
389 : }
390 0 : buf_data->buffer[0] = '\0';
391 0 : buf_data->length = 0;
392 0 : buf_data->size = BLOCK_SIZE;
393 : }
394 :
395 : TRACE_INFO_NUMBER("Buffer len: ", buf_data->length);
396 : TRACE_INFO_NUMBER("Buffer size: ", buf_data->size);
397 : TRACE_INFO_STRING("Buffer: ", buf_data->buffer);
398 :
399 : /* Check the beginning of the collection */
400 0 : if (type == COL_TYPE_COLLECTION) {
401 : TRACE_INFO_STRING("Serializing collection: ", property_in);
402 : TRACE_INFO_STRING("First header. ", "");
403 0 : error = col_put_marker(buf_data, "(", 1);
404 0 : if (error != EOK) return error;
405 0 : property = TEXT_COLLECTION;
406 0 : property_len = TEXT_COLLEN;
407 0 : data = property_in;
408 0 : length = property_len_in + 1;
409 0 : type = COL_TYPE_STRING;
410 0 : buf_data->nest_level++;
411 : }
412 : /* Check for subcollections */
413 0 : else if (type == COL_TYPE_COLLECTIONREF) {
414 : /* Skip */
415 : TRACE_FLOW_STRING("col_serialize", "skip reference return");
416 0 : return EOK;
417 : }
418 : /* Check for the end of the collection */
419 0 : else if (type == COL_TYPE_END) {
420 0 : if ((buf_data->length > 0) &&
421 0 : (buf_data->buffer[buf_data->length-1] == ',')) {
422 0 : buf_data->length--;
423 0 : buf_data->buffer[buf_data->length] = '\0';
424 : }
425 0 : if (buf_data->nest_level > 0) {
426 0 : buf_data->nest_level--;
427 0 : error = col_put_marker(buf_data, ")", 1);
428 0 : if (error != EOK) return error;
429 : }
430 : TRACE_FLOW_STRING("col_serialize", "end collection item processed returning");
431 0 : return EOK;
432 : }
433 : else {
434 0 : property = property_in;
435 0 : property_len = property_len_in;
436 0 : data = data_in;
437 0 : length = length_in;
438 : }
439 :
440 : TRACE_INFO_STRING("Property: ", property);
441 : TRACE_INFO_NUMBER("Property length: ", property_len);
442 :
443 : /* Start with property and "=" */
444 0 : if ((error = col_put_marker(buf_data, property, property_len)) ||
445 : (error = col_put_marker(buf_data, "=", 1))) {
446 : TRACE_ERROR_NUMBER("put_marker returned error: ", error);
447 0 : return error;
448 : }
449 : /* Get projected length of the item */
450 0 : len = col_get_data_len(type,length);
451 : TRACE_INFO_NUMBER("Expected data length: ",len);
452 : TRACE_INFO_STRING("Buffer so far: ", buf_data->buffer);
453 :
454 : /* Make sure we have enough space */
455 0 : if ((error = col_grow_buffer(buf_data, len))) {
456 : TRACE_ERROR_NUMBER("grow_buffer returned error: ", error);
457 0 : return error;
458 : }
459 :
460 : /* Add the value */
461 0 : switch (type) {
462 : case COL_TYPE_STRING:
463 : /* Escape double quotes */
464 0 : len = col_copy_esc(&buf_data->buffer[buf_data->length],
465 : (const char *)(data), '"');
466 0 : break;
467 :
468 : /* Here and below it is safe to use sprintf() becuase we
469 : * already pre-calculated the length and allocated buffer
470 : * of the right size.
471 : */
472 :
473 : case COL_TYPE_BINARY:
474 0 : buf_data->buffer[buf_data->length] = '\'';
475 0 : for (i = 0; i < length; i++)
476 0 : sprintf(&buf_data->buffer[buf_data->length + i *2] + 1,
477 0 : "%02X", (unsigned int)(((const unsigned char *)(data))[i]));
478 0 : len = length * 2 + 1;
479 0 : buf_data->buffer[buf_data->length + len] = '\'';
480 0 : len++;
481 0 : break;
482 :
483 : case COL_TYPE_INTEGER:
484 0 : len = sprintf(&buf_data->buffer[buf_data->length],
485 : "%d", *((const int32_t *)(data)));
486 0 : break;
487 :
488 : case COL_TYPE_UNSIGNED:
489 0 : len = sprintf(&buf_data->buffer[buf_data->length],
490 : "%u", *((const uint32_t *)(data)));
491 0 : break;
492 :
493 : case COL_TYPE_LONG:
494 0 : len = sprintf(&buf_data->buffer[buf_data->length],
495 : "%lld",
496 : (long long int)(*((const int64_t *)(data))));
497 0 : break;
498 :
499 : case COL_TYPE_ULONG:
500 0 : len = sprintf(&buf_data->buffer[buf_data->length],
501 : "%llu",
502 : (long long unsigned)(*((const uint64_t *)(data))));
503 0 : break;
504 :
505 : case COL_TYPE_DOUBLE:
506 0 : len = sprintf(&buf_data->buffer[buf_data->length],
507 : "%.4f", *((const double *)(data)));
508 0 : break;
509 :
510 : case COL_TYPE_BOOL:
511 0 : len = sprintf(&buf_data->buffer[buf_data->length],
512 0 : "%s", (*((const unsigned char *)(data))) ? "true" : "false");
513 0 : break;
514 :
515 : default:
516 0 : buf_data->buffer[buf_data->length] = '\0';
517 0 : len = 0;
518 0 : break;
519 : }
520 :
521 : /* Adjust length */
522 0 : buf_data->length += len;
523 0 : buf_data->buffer[buf_data->length] = '\0';
524 :
525 : /* Always put a comma at the end */
526 0 : error = col_put_marker(buf_data, ",", 1);
527 0 : if (error != EOK) {
528 : TRACE_ERROR_NUMBER("put_marker returned error: ", error);
529 0 : return error;
530 : }
531 :
532 : TRACE_INFO_STRING("Data: ", buf_data->buffer);
533 : TRACE_FLOW_STRING("col_serialize", "Exit point");
534 0 : return EOK;
535 :
536 : }
537 :
538 : /* Print the collection using default serialization */
539 0 : int col_print_collection(struct collection_item *handle)
540 : {
541 : struct col_serial_data buf_data;
542 0 : int error = EOK;
543 :
544 : TRACE_FLOW_STRING("col_print_collection", "Entry");
545 :
546 0 : printf("COLLECTION:\n");
547 :
548 0 : buf_data.buffer = NULL;
549 0 : buf_data.length = 0;
550 0 : buf_data.size = 0;
551 0 : buf_data.nest_level = 0;
552 :
553 : /* Traverse collection */
554 0 : error = col_traverse_collection(handle,
555 : COL_TRAVERSE_DEFAULT | COL_TRAVERSE_END ,
556 : col_serialize, (void *)(&buf_data));
557 0 : if (error)
558 0 : printf("Error traversing collection %d\n", error);
559 : else
560 0 : printf("%s\n", buf_data.buffer);
561 :
562 0 : free(buf_data.buffer);
563 :
564 : TRACE_FLOW_NUMBER("col_print_collection returning", error);
565 0 : return error;
566 : }
567 :
568 : /* Print the collection using iterator */
569 0 : int col_print_collection2(struct collection_item *handle)
570 : {
571 0 : struct collection_iterator *iterator = NULL;
572 0 : int error = EOK;
573 0 : struct collection_item *item = NULL;
574 0 : int nest_level = 0;
575 0 : int dummy = 0;
576 0 : int line = 1;
577 :
578 : TRACE_FLOW_STRING("col_print_collection2", "Entry");
579 :
580 : /* If we have something to print print it */
581 0 : if (handle == NULL) {
582 : TRACE_ERROR_STRING("No error list", "");
583 0 : return EINVAL;
584 : }
585 :
586 : /* Bind iterator */
587 0 : error = col_bind_iterator(&iterator, handle,
588 : COL_TRAVERSE_DEFAULT |
589 : COL_TRAVERSE_END |
590 : COL_TRAVERSE_SHOWSUB);
591 0 : if (error) {
592 : TRACE_ERROR_NUMBER("Error (bind):", error);
593 0 : return error;
594 : }
595 :
596 : do {
597 : /* Loop through a collection */
598 0 : error = col_iterate_collection(iterator, &item);
599 0 : if (error) {
600 : TRACE_ERROR_NUMBER("Error (iterate):", error);
601 0 : col_unbind_iterator(iterator);
602 0 : return error;
603 : }
604 :
605 : /* Are we done ? */
606 0 : if (item == NULL) break;
607 :
608 0 : if (item->type != COL_TYPE_END) printf("%05d", line);
609 :
610 0 : col_debug_handle(item->property,
611 0 : item->property_len,
612 0 : item->type,
613 0 : item->data,
614 0 : item->length,
615 : (void *)(&nest_level),
616 : &dummy);
617 0 : line++;
618 : }
619 0 : while(1);
620 :
621 : /* Do not forget to unbind iterator - otherwise there will be a leak */
622 0 : col_unbind_iterator(iterator);
623 :
624 : TRACE_INFO_STRING("col_print_collection2", "Exit");
625 0 : return EOK;
626 : }
627 :
628 : /* Find and print one item using default serialization */
629 0 : int col_print_item(struct collection_item *handle, const char *name)
630 : {
631 : struct col_serial_data buf_data;
632 0 : int error = EOK;
633 :
634 : TRACE_FLOW_STRING("col_print_item", "Entry");
635 :
636 0 : printf("PRINT ITEM:\n");
637 :
638 0 : buf_data.buffer = NULL;
639 0 : buf_data.length = 0;
640 0 : buf_data.size = 0;
641 0 : buf_data.nest_level = 0;
642 :
643 0 : error = col_get_item_and_do(handle, name, COL_TYPE_ANY,
644 : COL_TRAVERSE_DEFAULT,
645 : col_serialize, &buf_data);
646 0 : if(error) printf("Error searching collection %d\n", error);
647 : else {
648 0 : if (buf_data.buffer != NULL) {
649 0 : if (buf_data.length > 0) buf_data.length--;
650 0 : buf_data.buffer[buf_data.length] = '\0',
651 0 : printf("%s\n", buf_data.buffer);
652 0 : free(buf_data.buffer);
653 : }
654 : else {
655 0 : printf("Name %s is not found in the collection %s.\n",
656 : name, handle->property);
657 : }
658 : }
659 :
660 : TRACE_FLOW_NUMBER("col_print_item returning", error);
661 0 : return error;
662 : }
663 :
664 : /* Function to free the list of properties. */
665 32 : void col_free_property_list(char **str_list)
666 : {
667 32 : int current = 0;
668 :
669 : TRACE_FLOW_STRING("col_free_property_list","Entry");
670 :
671 32 : if (str_list != NULL) {
672 228 : while(str_list[current]) {
673 164 : free(str_list[current]);
674 164 : current++;
675 : }
676 32 : free(str_list);
677 : }
678 :
679 : TRACE_FLOW_STRING("col_free_property_list","Exit");
680 32 : }
681 :
682 :
683 : /* Convert collection to list of properties */
684 6 : char **col_collection_to_list(struct collection_item *handle, int *size, int *error)
685 : {
686 : struct collection_iterator *iterator;
687 6 : struct collection_item *item = NULL;
688 : char **list;
689 : unsigned count;
690 : int err;
691 6 : int current = 0;
692 :
693 : TRACE_FLOW_STRING("col_collection_to_list","Entry");
694 :
695 : /* Get number of the subsections */
696 6 : err = col_get_collection_count(handle, &count);
697 6 : if (err) {
698 : TRACE_ERROR_NUMBER("Failed to get count of items from collection.", err);
699 0 : if (error) *error = err;
700 0 : return NULL;
701 : }
702 :
703 : /* Allocate memory for the sections */
704 6 : list = (char **)malloc(count * sizeof(char *));
705 6 : if (list == NULL) {
706 : TRACE_ERROR_NUMBER("Failed to get allocate memory.", ENOMEM);
707 0 : if (error) *error = ENOMEM;
708 0 : return NULL;
709 : }
710 :
711 : /* Now iterate to fill in the sections */
712 : /* Bind iterator */
713 6 : err = col_bind_iterator(&iterator, handle, COL_TRAVERSE_ONELEVEL);
714 6 : if (err) {
715 : TRACE_ERROR_NUMBER("Failed to bind.", err);
716 0 : if (error) *error = err;
717 0 : free(list);
718 0 : return NULL;
719 : }
720 :
721 : while(1) {
722 : /* Loop through a collection */
723 86 : err = col_iterate_collection(iterator, &item);
724 86 : if (err) {
725 : TRACE_ERROR_NUMBER("Failed to iterate collection", err);
726 0 : if (error) *error = err;
727 0 : col_free_property_list(list);
728 0 : col_unbind_iterator(iterator);
729 0 : return NULL;
730 : }
731 :
732 : /* Are we done ? */
733 86 : if (item == NULL) break;
734 :
735 : TRACE_INFO_STRING("Property:", col_get_item_property(item, NULL));
736 :
737 : /* Skip head */
738 80 : if(col_get_item_type(item) == COL_TYPE_COLLECTION) continue;
739 :
740 :
741 : /* Allocate memory for the new string */
742 74 : list[current] = strdup(col_get_item_property(item, NULL));
743 74 : if (list[current] == NULL) {
744 : TRACE_ERROR_NUMBER("Failed to dup string.", ENOMEM);
745 0 : if (error) *error = ENOMEM;
746 0 : col_free_property_list(list);
747 0 : return NULL;
748 : }
749 74 : current++;
750 80 : }
751 :
752 6 : list[current] = NULL;
753 :
754 : /* Do not forget to unbind iterator - otherwise there will be a leak */
755 6 : col_unbind_iterator(iterator);
756 :
757 6 : if (size) *size = (int)(count - 1);
758 6 : if (error) *error = EOK;
759 :
760 : TRACE_FLOW_STRING("col_collection_to_list returning", ((list == NULL) ? "NULL" : list[0]));
761 6 : return list;
762 : }
|