4
Additional functions for printing and debugging collections.
6
Copyright (C) Dmitri Pal <dpal@redhat.com> 2009
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.
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.
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/>.
28
#include "collection_priv.h"
29
#include "collection.h"
30
#include "collection_tools.h"
33
int col_debug_handle(const char *property,
45
TRACE_FLOW_STRING("col_debug_handle", "Entry.");
48
nest_level = *(int *)(custom_data);
49
if (nest_level == -1) {
54
TRACE_INFO_NUMBER("We are getting this pointer:", custom_data);
55
TRACE_INFO_NUMBER("Nest level:", nest_level);
59
printf(">%*s%s[%d] str: %s (%d)\n",
60
(nest_level -1) * 4, "",
67
printf(">%*s%s[%d] bin: ",
68
(nest_level -1) * 4, "",
71
for (i = 0; i < length; i++)
72
printf("%02X", ((unsigned char *)(data))[i]);
73
printf(" (%d)\n", nest_level);
75
case COL_TYPE_INTEGER:
76
printf(">%*s%s[%d] int: %d (%d)\n",
77
(nest_level -1) * 4, "",
83
case COL_TYPE_UNSIGNED:
84
printf(">%*s%s[%d] uint: %u (%d)\n",
85
(nest_level -1) * 4, "",
88
*((unsigned int *)(data)),
92
printf(">%*s%s[%d] long: %ld (%d)\n",
93
(nest_level -1) * 4, "",
100
printf(">%*s%s[%d] ulong: %lu (%d)\n",
101
(nest_level -1) * 4, "",
104
*((unsigned long *)(data)),
107
case COL_TYPE_DOUBLE:
108
printf(">%*s%s[%d] double: %.4f (%d)\n",
109
(nest_level -1) * 4, "",
116
printf(">%*s%s[%d] bool: %s (%d)\n",
117
(nest_level -1) * 4, "",
120
(*((unsigned char *)(data)) == '\0') ? "false" : "true",
123
case COL_TYPE_COLLECTION:
124
if (!ignore) nest_level++;
125
printf(">%*s%s[%d] header: count %d, ref_count %d class %d data: ",
126
(nest_level -1) * 4, "",
129
((struct collection_header *)(data))->count,
130
((struct collection_header *)(data))->reference_count,
131
((struct collection_header *)(data))->cclass);
132
for (i = 0; i < length; i++)
133
printf("%02X", ((unsigned char *)(data))[i]);
134
printf(" (%d)\n", nest_level);
136
case COL_TYPE_COLLECTIONREF:
137
printf(">%*s%s[%d] external link: ",
138
(nest_level -1) * 4, "",
141
for (i = 0; i < length; i++)
142
printf("%02X", ((unsigned char *)(data))[i]);
143
printf(" (%d)\n", nest_level);
146
printf(">%*sEND[N/A] (%d)\n",
147
(nest_level -1) * 4, "",
149
if (!ignore) nest_level--;
152
printf("Not implemented yet.\n");
155
*(int *)(custom_data) = nest_level;
156
TRACE_INFO_NUMBER("Nest level at the end:", nest_level);
157
TRACE_FLOW_STRING("col_debug_handle", "Success exit.");
161
/* Convenience function to debug an item */
162
inline int col_debug_item(struct collection_item *item)
166
return col_debug_handle(item->property,
171
(void *)(&nest_level),
176
/* Print collection for debugging purposes */
177
int col_debug_collection(struct collection_item *handle, int flag)
182
TRACE_FLOW_STRING("col_debug_collection", "Entry.");
184
printf("DEBUG COLLECTION %s\n", handle->property);
186
flag |= COL_TRAVERSE_END;
188
printf("Traverse flags %d\n", flag);
190
/* Traverse collection */
191
error = col_traverse_collection(handle, flag,
193
(void *)(&nest_level));
194
if (error) printf("Error debuging collection %d\n", error);
196
TRACE_FLOW_STRING("col_debug_collection", "Exit.");
201
/* Return a static string based on type of the element */
202
static inline const char *col_get_type(int type)
205
case COL_TYPE_STRING:
206
return COL_TYPE_NAME_STRING;
208
case COL_TYPE_INTEGER:
209
return COL_TYPE_NAME_INTEGER;
211
case COL_TYPE_UNSIGNED:
212
return COL_TYPE_NAME_UNSIGNED;
215
return COL_TYPE_NAME_LONG;
218
return COL_TYPE_NAME_ULONG;
220
case COL_TYPE_BINARY:
221
return COL_TYPE_NAME_BINARY;
223
case COL_TYPE_DOUBLE:
224
return COL_TYPE_NAME_DOUBLE;
227
return COL_TYPE_NAME_BOOL;
230
return COL_TYPE_NAME_UNKNOWN;
235
/* Calculate the potential size of the item */
236
int col_get_data_len(int type, int length)
240
TRACE_FLOW_STRING("col_get_data_len", "Entry point");
243
case COL_TYPE_INTEGER:
244
case COL_TYPE_UNSIGNED:
250
case COL_TYPE_STRING:
251
case COL_TYPE_BINARY:
252
len = length * 2 + 2;
255
case COL_TYPE_DOUBLE:
268
TRACE_FLOW_STRING("col_get_data_len","Exit point");
273
/* Copy data escaping characters */
274
static int col_copy_esc(char *dest, const char *source, char esc)
283
if ((source[i] == '\\') ||
284
(source[i] == esc)) {
300
/* Grow buffer to accomodate more space */
301
int col_grow_buffer(struct col_serial_data *buf_data, int len)
305
TRACE_FLOW_STRING("col_grow_buffer", "Entry point");
306
TRACE_INFO_NUMBER("Current length: ", buf_data->length);
307
TRACE_INFO_NUMBER("Increment length: ", len);
308
TRACE_INFO_NUMBER("Expected length: ", buf_data->length+len);
309
TRACE_INFO_NUMBER("Current size: ", buf_data->size);
311
/* Grow buffer if needed */
312
while (buf_data->length+len >= buf_data->size) {
313
tmp = realloc(buf_data->buffer, buf_data->size + BLOCK_SIZE);
315
TRACE_ERROR_NUMBER("Error. Failed to allocate memory.", ENOMEM);
318
buf_data->buffer = tmp;
319
buf_data->size += BLOCK_SIZE;
320
TRACE_INFO_NUMBER("New size: ", buf_data->size);
324
TRACE_INFO_NUMBER("Final size: ", buf_data->size);
325
TRACE_FLOW_STRING("col_grow_buffer", "Success Exit.");
329
/* Specail function to add different formatting symbols to the output */
330
int col_put_marker(struct col_serial_data *buf_data, const void *data, int len)
334
TRACE_FLOW_STRING("col_put_marker", "Entry point");
335
TRACE_INFO_NUMBER("Marker length: ", len);
337
error = col_grow_buffer(buf_data, len);
339
TRACE_ERROR_NUMBER("col_grow_buffer failed with: ", error);
342
memcpy(buf_data->buffer + buf_data->length, data, len);
343
buf_data->length += len;
344
buf_data->buffer[buf_data->length] = '\0';
346
TRACE_FLOW_STRING("col_put_marker","Success exit");
350
/* Add item's data */
351
int col_serialize(const char *property_in,
360
struct col_serial_data *buf_data;
361
const char *property;
368
TRACE_FLOW_STRING("col_serialize","Entry point");
372
/* Check is there is buffer. If not allocate */
373
buf_data = (struct col_serial_data *)custom_data;
374
if (buf_data == NULL) {
375
TRACE_ERROR_STRING("Error.", "Storage data is not passed in!");
378
if (buf_data->buffer == NULL) {
379
TRACE_INFO_STRING("First time use.", "Allocating buffer.");
380
buf_data->buffer = malloc(BLOCK_SIZE);
381
if (buf_data->buffer == NULL) {
382
TRACE_ERROR_NUMBER("Error. Failed to allocate memory.", ENOMEM);
385
buf_data->buffer[0] = '\0';
386
buf_data->length = 0;
387
buf_data->size = BLOCK_SIZE;
390
TRACE_INFO_NUMBER("Buffer len: ", buf_data->length);
391
TRACE_INFO_NUMBER("Buffer size: ", buf_data->size);
392
TRACE_INFO_STRING("Buffer: ", buf_data->buffer);
394
/* Check the beginning of the collection */
395
if (type == COL_TYPE_COLLECTION) {
396
TRACE_INFO_STRING("Serializing collection: ", property_in);
397
TRACE_INFO_STRING("First header. ", "");
398
error = col_put_marker(buf_data, "(", 1);
399
if (error != EOK) return error;
400
property = TEXT_COLLECTION;
401
property_len = TEXT_COLLEN;
403
length = property_len_in + 1;
404
type = COL_TYPE_STRING;
405
buf_data->nest_level++;
407
/* Check for subcollections */
408
else if (type == COL_TYPE_COLLECTIONREF) {
410
TRACE_FLOW_STRING("col_serialize", "skip reference return");
413
/* Check for the end of the collection */
414
else if (type == COL_TYPE_END) {
415
if ((buf_data->length > 0) &&
416
(buf_data->buffer[buf_data->length-1] == ',')) {
418
buf_data->buffer[buf_data->length] = '\0';
420
if (buf_data->nest_level > 0) {
421
buf_data->nest_level--;
422
error = col_put_marker(buf_data, ")", 1);
423
if (error != EOK) return error;
425
TRACE_FLOW_STRING("col_serialize", "end collection item processed returning");
429
property = property_in;
430
property_len = property_len_in;
435
TRACE_INFO_STRING("Property: ", property);
436
TRACE_INFO_NUMBER("Property length: ", property_len);
438
/* Start with property and "=" */
439
if ((error = col_put_marker(buf_data, property, property_len)) ||
440
(error = col_put_marker(buf_data, "=", 1))) {
441
TRACE_ERROR_NUMBER("put_marker returned error: ", error);
444
/* Get projected length of the item */
445
len = col_get_data_len(type,length);
446
TRACE_INFO_NUMBER("Expected data length: ",len);
447
TRACE_INFO_STRING("Buffer so far: ", buf_data->buffer);
449
/* Make sure we have enough space */
450
if ((error = col_grow_buffer(buf_data, len))) {
451
TRACE_ERROR_NUMBER("grow_buffer returned error: ", error);
457
case COL_TYPE_STRING:
458
/* Escape double quotes */
459
len = col_copy_esc(&buf_data->buffer[buf_data->length],
460
(const char *)(data), '"');
463
case COL_TYPE_BINARY:
464
buf_data->buffer[buf_data->length] = '\'';
465
for (i = 0; i < length; i++)
466
sprintf(&buf_data->buffer[buf_data->length + i *2] + 1,
467
"%02X", (unsigned int)(((const unsigned char *)(data))[i]));
468
len = length * 2 + 1;
469
buf_data->buffer[buf_data->length + len] = '\'';
473
case COL_TYPE_INTEGER:
474
len = sprintf(&buf_data->buffer[buf_data->length],
475
"%d", *((const int *)(data)));
478
case COL_TYPE_UNSIGNED:
479
len = sprintf(&buf_data->buffer[buf_data->length],
480
"%u", *((const unsigned int *)(data)));
484
len = sprintf(&buf_data->buffer[buf_data->length],
485
"%ld", *((const long *)(data)));
489
len = sprintf(&buf_data->buffer[buf_data->length],
490
"%lu", *((const unsigned long *)(data)));
493
case COL_TYPE_DOUBLE:
494
len = sprintf(&buf_data->buffer[buf_data->length],
495
"%.4f", *((const double *)(data)));
499
len = sprintf(&buf_data->buffer[buf_data->length],
500
"%s", (*((const unsigned char *)(data))) ? "true" : "false");
504
buf_data->buffer[buf_data->length] = '\0';
510
buf_data->length += len;
511
buf_data->buffer[buf_data->length] = '\0';
513
/* Always put a comma at the end */
514
error = col_put_marker(buf_data, ",", 1);
516
TRACE_ERROR_NUMBER("put_marker returned error: ", error);
520
TRACE_INFO_STRING("Data: ", buf_data->buffer);
521
TRACE_FLOW_STRING("col_serialize", "Exit point");
526
/* Print the collection using default serialization */
527
int col_print_collection(struct collection_item *handle)
529
struct col_serial_data buf_data;
532
TRACE_FLOW_STRING("col_print_collection", "Entry");
534
printf("COLLECTION:\n");
536
buf_data.buffer = NULL;
539
buf_data.nest_level = 0;
541
/* Traverse collection */
542
error = col_traverse_collection(handle,
543
COL_TRAVERSE_DEFAULT | COL_TRAVERSE_END ,
544
col_serialize, (void *)(&buf_data));
546
printf("Error traversing collection %d\n", error);
548
printf("%s\n", buf_data.buffer);
550
free(buf_data.buffer);
552
TRACE_FLOW_NUMBER("col_print_collection returning", error);
556
/* Print the collection using iterator */
557
int col_print_collection2(struct collection_item *handle)
559
struct collection_iterator *iterator = NULL;
561
struct collection_item *item = NULL;
566
TRACE_FLOW_STRING("col_print_collection2", "Entry");
568
/* If we have something to print print it */
569
if (handle == NULL) {
570
TRACE_ERROR_STRING("No error list", "");
575
error = col_bind_iterator(&iterator, handle,
576
COL_TRAVERSE_DEFAULT |
578
COL_TRAVERSE_SHOWSUB);
580
TRACE_ERROR_NUMBER("Error (bind):", error);
585
/* Loop through a collection */
586
error = col_iterate_collection(iterator, &item);
588
TRACE_ERROR_NUMBER("Error (iterate):", error);
589
col_unbind_iterator(iterator);
594
if (item == NULL) break;
596
if (item->type != COL_TYPE_END) printf("%05d", line);
598
col_debug_handle(item->property,
603
(void *)(&nest_level),
609
/* Do not forget to unbind iterator - otherwise there will be a leak */
610
col_unbind_iterator(iterator);
612
TRACE_INFO_STRING("col_print_collection2", "Exit");
616
/* Find and print one item using default serialization */
617
int col_print_item(struct collection_item *handle, const char *name)
619
struct col_serial_data buf_data;
622
TRACE_FLOW_STRING("col_print_item", "Entry");
624
printf("PRINT ITEM:\n");
626
buf_data.buffer = NULL;
629
buf_data.nest_level = 0;
631
error = col_get_item_and_do(handle, name, COL_TYPE_ANY,
632
COL_TRAVERSE_DEFAULT,
633
col_serialize, &buf_data);
634
if(error) printf("Error searching collection %d\n", error);
636
if (buf_data.buffer != NULL) {
637
if (buf_data.length > 0) buf_data.length--;
638
buf_data.buffer[buf_data.length] = '\0',
639
printf("%s\n", buf_data.buffer);
640
free(buf_data.buffer);
643
printf("Name %s is not found in the collection %s.\n",
644
name, handle->property);
648
TRACE_FLOW_NUMBER("col_print_item returning", error);
652
/* Function to free the list of properties. */
653
void col_free_property_list(char **str_list)
657
TRACE_FLOW_STRING("col_free_property_list","Entry");
659
if (str_list != NULL) {
660
while(str_list[current]) {
661
free(str_list[current]);
667
TRACE_FLOW_STRING("col_free_property_list","Exit");
671
/* Convert collection to list of properties */
672
char **col_collection_to_list(struct collection_item *handle, int *size, int *error)
674
struct collection_iterator *iterator;
675
struct collection_item *item = NULL;
681
TRACE_FLOW_STRING("col_collection_to_list","Entry");
683
/* Get number of the subsections */
684
err = col_get_collection_count(handle, &count);
686
TRACE_ERROR_NUMBER("Failed to get count of items from collection.", err);
687
if (error) *error = err;
691
/* Allocate memory for the sections */
692
list = (char **)malloc(count * sizeof(char *));
694
TRACE_ERROR_NUMBER("Failed to get allocate memory.", ENOMEM);
695
if (error) *error = ENOMEM;
699
/* Now iterate to fill in the sections */
701
err = col_bind_iterator(&iterator, handle, COL_TRAVERSE_ONELEVEL);
703
TRACE_ERROR_NUMBER("Failed to bind.", err);
704
if (error) *error = err;
710
/* Loop through a collection */
711
err = col_iterate_collection(iterator, &item);
713
TRACE_ERROR_NUMBER("Failed to iterate collection", err);
714
if (error) *error = err;
715
col_free_property_list(list);
716
col_unbind_iterator(iterator);
721
if (item == NULL) break;
723
TRACE_INFO_STRING("Property:", col_get_item_property(item, NULL));
726
if(col_get_item_type(item) == COL_TYPE_COLLECTION) continue;
729
/* Allocate memory for the new string */
730
list[current] = strdup(col_get_item_property(item, NULL));
731
if (list[current] == NULL) {
732
TRACE_ERROR_NUMBER("Failed to dup string.", ENOMEM);
733
if (error) *error = ENOMEM;
734
col_free_property_list(list);
740
list[current] = NULL;
742
/* Do not forget to unbind iterator - otherwise there will be a leak */
743
col_unbind_iterator(iterator);
745
if (size) *size = (int)(count - 1);
746
if (error) *error = EOK;
748
TRACE_FLOW_STRING("col_collection_to_list returning", ((list == NULL) ? "NULL" : list[0]));