diff options
Diffstat (limited to 'common/collection/collection.c')
-rw-r--r-- | common/collection/collection.c | 278 |
1 files changed, 237 insertions, 41 deletions
diff --git a/common/collection/collection.c b/common/collection/collection.c index 298ddf4d8..b4a2c8d5a 100644 --- a/common/collection/collection.c +++ b/common/collection/collection.c @@ -112,7 +112,8 @@ static int col_walk_items(struct collection_item *ci, internal_item_fn traverse_handler, void *traverse_data, col_item_fn user_item_handler, - void *custom_data); + void *custom_data, + unsigned *depth); /* Function to get sub collection */ static int col_get_subcollection(const char *property, @@ -283,6 +284,7 @@ static int col_find_property(struct collection_item *collection, { struct property_search ps; int i = 0; + unsigned depth = 0; TRACE_FLOW_STRING("col_find_property", "Entry."); @@ -307,7 +309,8 @@ static int col_find_property(struct collection_item *collection, /* We do not care about error here */ (void)col_walk_items(collection, COL_TRAVERSE_ONELEVEL, col_parent_traverse_handler, - (void *)parent, NULL, (void *)&ps); + (void *)parent, NULL, (void *)&ps, + &depth); if (*parent) { /* Item is found in the collection */ @@ -1221,13 +1224,14 @@ static void col_delete_path_data(struct path_data *path) /* For each item walked it will call traverse handler. Traverse handler accepts: current item, user provided item handler and user provided custom data. */ -/* See below defferent traverse handlers for different cases */ +/* See below different traverse handlers for different cases */ static int col_walk_items(struct collection_item *ci, int mode_flags, internal_item_fn traverse_handler, void *traverse_data, col_item_fn user_item_handler, - void *custom_data) + void *custom_data, + unsigned *depth) { struct collection_item *current; struct collection_item *parent = NULL; @@ -1238,6 +1242,9 @@ static int col_walk_items(struct collection_item *ci, TRACE_FLOW_STRING("col_walk_items", "Entry."); TRACE_INFO_NUMBER("Mode flags:", mode_flags); + /* Increase depth */ + (*depth)++; + current = ci; while (current) { @@ -1252,22 +1259,34 @@ static int col_walk_items(struct collection_item *ci, if ((mode_flags & COL_TRAVERSE_IGNORE) == 0) { TRACE_INFO_STRING("Subcollection is not ignored.", ""); - /* We are not ignoring sub collections */ - error = traverse_handler(ci, parent, current, traverse_data, - user_item_handler, custom_data, &stop); - if (stop != 0) { - TRACE_INFO_STRING("Traverse handler returned STOP.", ""); - error = EINTR_INTERNAL; - } - /* Check what error we got */ - if (error == EINTR_INTERNAL) { - TRACE_FLOW_NUMBER("Internal error - means we are stopping.", error); - return error; - } - else if (error) { - TRACE_ERROR_NUMBER("Traverse handler returned error.", error); - return error; + + if ((mode_flags & COL_TRAVERSE_FLAT) == 0) { + + TRACE_INFO_STRING("Subcollection is not flattened.", ""); + /* We are not flattening sub collections. + * The flattening means that we are not going + * to return reference and headers for sub collections. + * We will also not do special end collection + * invocation for sub collections. + */ + error = traverse_handler(ci, parent, current, traverse_data, + user_item_handler, custom_data, &stop); + if (stop != 0) { + TRACE_INFO_STRING("Traverse handler returned STOP.", ""); + error = EINTR_INTERNAL; + } + /* Check what error we got */ + if (error == EINTR_INTERNAL) { + TRACE_FLOW_NUMBER("Internal error - means we are stopping.", error); + (*depth)--; + return error; + } + else if (error) { + TRACE_ERROR_NUMBER("Traverse handler returned error.", error); + (*depth)--; + return error; + } } if ((mode_flags & COL_TRAVERSE_ONELEVEL) == 0) { @@ -1278,7 +1297,8 @@ static int col_walk_items(struct collection_item *ci, /* We need to go into sub collections */ error = col_walk_items(sub, mode_flags, traverse_handler, traverse_data, - user_item_handler, custom_data); + user_item_handler, custom_data, + depth); TRACE_INFO_STRING("Returned from sub collection processing", ""); TRACE_INFO_STRING("Done processing item:", current->property); TRACE_INFO_NUMBER("Done processing item type:", current->type); @@ -1286,12 +1306,29 @@ static int col_walk_items(struct collection_item *ci, } } } - else - /* Call handler then move on */ - error = traverse_handler(ci, parent, current, - traverse_data, user_item_handler, - custom_data, &stop); + else { + /* Check if it is a header and we are not on the root level. + * If we are flattening collection we need to skip headers + * for sub collections. + */ + + /* Call handler if: + * a) It is not collection header + * OR + * b) It is header we are flattening but we are on top level + * OR + * c) It is header and we are not flattening. + */ + if ((current->type != COL_TYPE_COLLECTION) || + (((mode_flags & COL_TRAVERSE_FLAT) != 0) && (*depth == 1)) || + ((mode_flags & COL_TRAVERSE_FLAT) == 0)) { + /* Call handler then move on */ + error = traverse_handler(ci, parent, current, + traverse_data, user_item_handler, + custom_data, &stop); + } + } /* If we are stopped - return EINTR_INTERNAL */ if (stop != 0) { TRACE_INFO_STRING("Traverse handler returned STOP.", ""); @@ -1300,10 +1337,12 @@ static int col_walk_items(struct collection_item *ci, /* Check what error we got */ if (error == EINTR_INTERNAL) { TRACE_FLOW_NUMBER("Internal error - means we are stopping.", error); + (*depth)--; return error; } else if (error) { TRACE_ERROR_NUMBER("Traverse handler returned error.", error); + (*depth)--; return error; } @@ -1314,14 +1353,27 @@ static int col_walk_items(struct collection_item *ci, TRACE_INFO_STRING("Out of loop", ""); + /* Check if we need to have a special + * call at the end of the collection. + */ if ((mode_flags & COL_TRAVERSE_END) != 0) { - TRACE_INFO_STRING("About to do the special end collection invocation of handler", ""); - error = traverse_handler(ci, parent, current, - traverse_data, user_item_handler, - custom_data, &stop); + + /* Do this dummy invocation only: + * a) If we are flattening and on the root level + * b) We are not flattening + */ + if ((((mode_flags & COL_TRAVERSE_FLAT) != 0) && (*depth == 1)) || + ((mode_flags & COL_TRAVERSE_FLAT) == 0)) { + + TRACE_INFO_STRING("About to do the special end collection invocation of handler", ""); + error = traverse_handler(ci, parent, current, + traverse_data, user_item_handler, + custom_data, &stop); + } } TRACE_FLOW_NUMBER("col_walk_items. Returns: ", error); + (*depth)--; return error; } @@ -1343,6 +1395,7 @@ static int col_find_item_and_do(struct collection_item *ci, int error = EOK; struct find_name *traverse_data = NULL; + unsigned depth = 0; TRACE_FLOW_STRING("col_find_item_and_do", "Entry."); @@ -1386,7 +1439,8 @@ static int col_find_item_and_do(struct collection_item *ci, TRACE_INFO_NUMBER("Traverse flags", mode_flags); error = col_walk_items(ci, mode_flags, col_act_traverse_handler, - (void *)traverse_data, item_handler, custom_data); + (void *)traverse_data, item_handler, custom_data, + &depth); if (traverse_data->current_path != NULL) { TRACE_INFO_STRING("find_item_and_do", @@ -1793,6 +1847,79 @@ static int col_copy_traverse_handler(struct collection_item *head, return error; } +/* Function to copy collection as flat set */ +static int col_copy_collection_flat(struct collection_item *acceptor, + struct collection_item *donor) +{ + int error = EOK; + struct collection_iterator *iter = NULL; + struct collection_item *item = NULL; + struct collection_item *new_item = NULL; + struct collection_item *current = NULL; + + TRACE_FLOW_STRING("col_copy_collection_flat", "Entry"); + + /* Bind iterator in flat mode */ + error = col_bind_iterator(&iter, donor, COL_TRAVERSE_FLAT); + if (error) { + TRACE_ERROR_NUMBER("Failed to bind iterator:", error); + return error; + } + + /* Skip header */ + error = col_iterate_collection(iter, &item); + if (error) { + TRACE_ERROR_NUMBER("Failed to iterate on header:", error); + col_unbind_iterator(iter); + return error; + } + + current = item->next; + + while (current) { + + /* Loop through a collection */ + error = col_iterate_collection(iter, &item); + if (error) { + TRACE_ERROR_NUMBER("Failed to iterate:", error); + col_unbind_iterator(iter); + return error; + } + + /* Create new item */ + error = col_allocate_item(&new_item, + item->property, + item->data, + item->length, + item->type); + if(error) { + TRACE_ERROR_NUMBER("Error allocating end item.", error); + col_unbind_iterator(iter); + return error; + } + + /* Insert this item into collection */ + error = col_insert_item(acceptor, + NULL, + new_item, + COL_DSP_END, + NULL, + 0, + COL_INSERT_DUPOVER); + if(error) { + TRACE_ERROR_NUMBER("Error allocating end item.", error); + col_unbind_iterator(iter); + col_delete_item(new_item); + return error; + } + + current = item->next; + } + + col_unbind_iterator(iter); + TRACE_FLOW_NUMBER("col_copy_collection_flat Exit returning", error); + return error; +} /********************* MAIN INTERFACE FUNCTIONS *****************************/ @@ -1889,6 +2016,7 @@ int col_copy_collection(struct collection_item **collection_copy, struct collection_item *new_collection = NULL; const char *name; struct collection_header *header; + unsigned depth = 0; TRACE_FLOW_STRING("col_copy_collection", "Entry."); @@ -1909,7 +2037,7 @@ int col_copy_collection(struct collection_item **collection_copy, error = col_walk_items(collection_to_copy, COL_TRAVERSE_ONELEVEL, col_copy_traverse_handler, new_collection, - NULL, NULL); + NULL, NULL, &depth); if (!error) *collection_copy = new_collection; else col_destroy_collection(new_collection); @@ -2156,6 +2284,15 @@ int col_add_collection_to_collection(struct collection_item *ci, TRACE_INFO_NUMBER("Adding property returned:", error); break; + case COL_ADD_MODE_FLAT: + TRACE_INFO_STRING("We are flattening the collection.", ""); + + error = col_copy_collection_flat(acceptor, collection_to_add); + + TRACE_INFO_NUMBER("Copy collection flat returned:", error); + break; + + default: error = EINVAL; } @@ -2175,10 +2312,12 @@ int col_traverse_collection(struct collection_item *ci, { int error = EOK; + unsigned depth = 0; + TRACE_FLOW_STRING("col_traverse_collection", "Entry."); error = col_walk_items(ci, mode_flags, col_simple_traverse_handler, - NULL, item_handler, custom_data); + NULL, item_handler, custom_data, &depth); if ((error != 0) && (error != EINTR_INTERNAL)) { TRACE_ERROR_NUMBER("Error walking tree", error); @@ -2430,8 +2569,11 @@ int col_bind_iterator(struct collection_iterator **iterator, iter->stack = NULL; iter->stack_size = 0; iter->stack_depth = 0; + iter->item_level = 0; iter->flags = mode_flags; + TRACE_INFO_NUMBER("Iterator flags", iter->flags); + /* Allocate memory for stack */ error = col_grow_stack(iter, 1); if(error) { @@ -2491,13 +2633,31 @@ int col_get_iterator_depth(struct collection_iterator *iterator, int *depth) return EINVAL; } - *depth = iterator->stack_depth -1; + *depth = iterator->stack_depth - 1; TRACE_INFO_NUMBER("Stack depth at the end:", iterator->stack_depth); TRACE_FLOW_STRING("col_get_iterator_depth","Exit"); return EOK; } +/* What was the level of the last item we got? */ +int col_get_item_depth(struct collection_iterator *iterator, int *depth) +{ + TRACE_FLOW_STRING("col_get_item_depth", "Entry"); + + if ((iterator == NULL) || (depth == NULL)) { + TRACE_ERROR_NUMBER("Invalid parameter.", EINVAL); + return EINVAL; + } + + *depth = iterator->item_level; + + TRACE_INFO_NUMBER("Item level at the end:", iterator->item_level); + TRACE_FLOW_STRING("col_get_item_depth","Exit"); + return EOK; +} + + /* Unbind the iterator from the collection */ void col_unbind_iterator(struct collection_iterator *iterator) @@ -2505,7 +2665,7 @@ void col_unbind_iterator(struct collection_iterator *iterator) TRACE_FLOW_STRING("col_unbind_iterator", "Entry."); if (iterator != NULL) { col_destroy_collection(iterator->top); - free(iterator->end_item); + col_delete_item(iterator->end_item); free(iterator->stack); free(iterator); } @@ -2541,6 +2701,7 @@ int col_iterate_collection(struct collection_iterator *iterator, /* Is current item available */ current = iterator->stack[iterator->stack_depth - 1]; + iterator->item_level = iterator->stack_depth - 1; /* We are not done so check if we have an item */ if (current != NULL) { @@ -2569,6 +2730,7 @@ int col_iterate_collection(struct collection_iterator *iterator, TRACE_INFO_STRING("Instructed to show header not reference", ""); other = *((struct collection_item **)current->data); iterator->stack[iterator->stack_depth] = other->next; + iterator->item_level = iterator->stack_depth; *item = other; } /* Do we need to show both? */ @@ -2576,6 +2738,17 @@ int col_iterate_collection(struct collection_iterator *iterator, TRACE_INFO_STRING("Instructed to show header and reference",""); iterator->stack[iterator->stack_depth] = *((struct collection_item **)(current->data)); *item = current; + /* Do not need to adjust level here */ + } + /* Do not show either */ + else if ((iterator->flags & COL_TRAVERSE_FLAT) != 0) { + TRACE_INFO_STRING("Instructed not to show header and reference",""); + other = *((struct collection_item **)current->data); + iterator->stack[iterator->stack_depth] = other->next; + iterator->stack[iterator->stack_depth - 1] = current->next; + iterator->stack_depth++; + /* Do not need to adjust level here */ + continue; } /* We need to show reference only */ else { @@ -2589,6 +2762,8 @@ int col_iterate_collection(struct collection_iterator *iterator, TRACE_INFO_NUMBER("Will show this item next time type:", other->next->type); } *item = current; + TRACE_INFO_NUMBER("Level of the reference:", iterator->item_level); + /* Do not need to adjust level here */ } TRACE_INFO_STRING("We return item:", (*item)->property); @@ -2616,9 +2791,18 @@ int col_iterate_collection(struct collection_iterator *iterator, } else { /* Got a normal item - return it and move to the next one */ - TRACE_INFO_STRING("Simple item", ""); - *item = current; - iterator->stack[iterator->stack_depth - 1] = current->next; + if ((current->type == COL_TYPE_COLLECTION) && + ((iterator->flags & COL_TRAVERSE_FLAT) != 0) && + (iterator->stack_depth > 1)) { + TRACE_INFO_STRING("Header of the sub collection in flat case ", ""); + iterator->stack[iterator->stack_depth - 1] = current->next; + continue; + } + else { + TRACE_INFO_STRING("Simple item", ""); + *item = current; + iterator->stack[iterator->stack_depth - 1] = current->next; + } break; } } @@ -2626,12 +2810,24 @@ int col_iterate_collection(struct collection_iterator *iterator, /* Item is NULL */ TRACE_INFO_STRING("Finished level", "moving to upper level"); iterator->stack_depth--; + /* Remember that item_level is zero based while depth is size + * so we decrease and then assign. */ TRACE_INFO_NUMBER("Stack depth at the end:", iterator->stack_depth); if ((iterator->flags & COL_TRAVERSE_END) != 0) { - /* Return dummy entry to indicate the end of the collection */ - TRACE_INFO_STRING("Finished level", "told to return END"); - *item = iterator->end_item; - break; + + /* Show end element + * a) If we are flattening but at the top + * b) We are not flattening + */ + if ((((iterator->flags & COL_TRAVERSE_FLAT) != 0) && + (iterator->stack_depth == 0)) || + ((iterator->flags & COL_TRAVERSE_FLAT) == 0)) { + + /* Return dummy entry to indicate the end of the collection */ + TRACE_INFO_STRING("Finished level", "told to return END"); + *item = iterator->end_item; + break; + } } else { /* Move to next level */ |