diff options
author | Dmitri Pal <dpal@redhat.com> | 2009-06-11 10:24:25 -0400 |
---|---|---|
committer | Stephen Gallagher <sgallagh@redhat.com> | 2009-07-01 09:17:39 -0400 |
commit | 77c350b05bf4a2ec35512699d3450490ba9d6aff (patch) | |
tree | 0de356caacdb1e55de01b8f62ed0f859bd924b7d | |
parent | f89f2f91cc3ff455041b1ca887904e860de6c896 (diff) | |
download | sssd-77c350b05bf4a2ec35512699d3450490ba9d6aff.tar.gz sssd-77c350b05bf4a2ec35512699d3450490ba9d6aff.tar.bz2 sssd-77c350b05bf4a2ec35512699d3450490ba9d6aff.zip |
Adding INSERT into collection functionality.
Add was always insterting at the end of the collection.
With this change one can control where the item is
inserted and deal with the duplicates too.
Also one now can extract items from collection
using absolute and relative disposition.
Using more advanced hashing function.
-rw-r--r-- | common/collection/Makefile.am | 1 | ||||
-rw-r--r-- | common/collection/collection.c | 1810 | ||||
-rw-r--r-- | common/collection/collection.h | 388 | ||||
-rw-r--r-- | common/collection/collection_cnv.c | 1266 | ||||
-rw-r--r-- | common/collection/collection_priv.h | 4 | ||||
-rw-r--r-- | common/collection/collection_ut.c | 169 | ||||
-rw-r--r-- | common/collection/configure.ac | 3 |
7 files changed, 2791 insertions, 850 deletions
diff --git a/common/collection/Makefile.am b/common/collection/Makefile.am index 0b8d0d03..8df9fc6b 100644 --- a/common/collection/Makefile.am +++ b/common/collection/Makefile.am @@ -14,6 +14,7 @@ noinst_LTLIBRARIES = libcollection.la libcollection_la_SOURCES = \ collection.c \ collection_tools.c \ + collection_cnv.c \ collection.h \ collection_tools.h \ collection_priv.h \ diff --git a/common/collection/collection.c b/common/collection/collection.c index e2816e63..f7918879 100644 --- a/common/collection/collection.c +++ b/common/collection/collection.c @@ -1,7 +1,7 @@ /* COLLECTION LIBRARY - Implemenation of the collection library interface. + Implementation of the collection library interface. Copyright (C) Dmitri Pal <dpal@redhat.com> 2009 @@ -25,6 +25,7 @@ #include <errno.h> #include <ctype.h> #include <time.h> +#include "config.h" #include "trace.h" /* The collection should use the teal structures */ @@ -43,11 +44,21 @@ #define EINTR_INTERNAL 10000 -/* Potential subjest for management with libtools */ +/* Potential subject for management with libtools */ #define DATE_FORMAT "%c" #define TIME_ARRAY_SIZE 100 +/* Magic numbers for hashing */ +#if SIZEOF_LONG == 8 + #define FNV1a_prime 1099511628211ul + #define FNV1a_base 14695981039346656037ul +#elif SIZEOF_LONG_LONG == 8 + #define FNV1a_prime 1099511628211ull + #define FNV1a_base 14695981039346656037ull +#else + #error "Platform cannot support 64-bit constant integers" +#endif /* Struct used for passing parameter for update operation */ struct update_property { @@ -80,6 +91,15 @@ static int act_traverse_handler(struct collection_item *head, void *custom_data, int *stop); +/* Traverse handler to find parent of the item */ +static int parent_traverse_handler(struct collection_item *head, + struct collection_item *previous, + struct collection_item *current, + void *traverse_data, + item_fn user_item_handler, + void *custom_data, + int *stop); + /* Traverse callback signature */ typedef int (*internal_item_fn)(struct collection_item *head, struct collection_item *previous, @@ -88,11 +108,29 @@ typedef int (*internal_item_fn)(struct collection_item *head, item_fn user_item_handler, void *custom_data, int *stop); +/* Function to walk_items */ +static int walk_items(struct collection_item *ci, + int mode_flags, + internal_item_fn traverse_handler, + void *traverse_data, + item_fn user_item_handler, + void *custom_data); -/******************** SUPPLEMENTARY FUNCTIONS ****************************/ +/* Function to get sub collection */ +static int get_subcollection(const char *property, + int property_len, + int type, + void *data, + int length, + void *found, + int *dummy); +/* Function to destroy collection */ +void destroy_collection(struct collection_item *ci); +/******************** SUPPLEMENTARY FUNCTIONS ****************************/ /* BASIC OPERATIONS */ + /* Function that checks if property can be added */ static int validate_property(const char *property) { @@ -113,14 +151,28 @@ static int validate_property(const char *property) return invalid; } - - /* Function that cleans the item */ -static void delete_item(struct collection_item *item) +void delete_item(struct collection_item *item) { + struct collection_item *other_collection; + TRACE_FLOW_STRING("delete_item","Entry point."); - if (item == NULL) return; + if (item == NULL) { + TRACE_FLOW_STRING("delete_item","Nothing to delete!"); + return; + } + + /* Handle external or embedded collection */ + if(item->type == COL_TYPE_COLLECTIONREF) { + /* Our data is a pointer to a whole external collection so dereference + * it or delete */ + other_collection = *((struct collection_item **)(item->data)); + destroy_collection(other_collection); + } + + TRACE_INFO_STRING("Deleting property:", item->property); + TRACE_INFO_NUMBER("Type:", item->type); if (item->property != NULL) free(item->property); if (item->data != NULL) free(item->data); @@ -172,7 +224,18 @@ static int allocate_item(struct collection_item **ci, const char *property, return error; } - item->property_len = strlen(item->property); + item->phash = FNV1a_base; + item->property_len = 0; + + while (property[item->property_len] != 0) { + item->phash = item->phash ^ property[item->property_len]; + item->phash *= FNV1a_prime; + item->property_len++; + } + + TRACE_INFO_NUMBER("Item hash", item->phash); + TRACE_INFO_NUMBER("Item property length", item->property_len); + TRACE_INFO_NUMBER("Item property strlen", strlen(item->property)); /* Deal with data */ item->data = malloc(length); @@ -200,126 +263,585 @@ static int allocate_item(struct collection_item **ci, const char *property, return 0; } -/* Add item to the end of collection */ -/* Can add itself to itself - nice...*/ -static int add_item_to_collection(struct collection_item *collection, - struct collection_item *item) +/* Structure used to find things in collection */ +struct property_search { + const char *property; + uint64_t hash; + struct collection_item *parent; + int index; + int count; + int found; + int use_type; + int type; +}; + +/* Find the parent of the item with given name */ +static int find_property(struct collection_item *collection, + const char *refprop, + int index, + int use_type, + int type, + struct collection_item **parent) +{ + TRACE_FLOW_STRING("find_property", "Entry."); + struct property_search ps; + int i = 0; + + *parent = NULL; + + ps.property = refprop; + ps.hash = FNV1a_base; + ps.parent = NULL; + ps.index = index; + ps.count = 0; + ps.found = 0; + ps.use_type = use_type; + ps.type = type; + + /* Create hash of the string to search */ + while(refprop[i] != 0) { + ps.hash = ps.hash ^ refprop[i]; + ps.hash *= FNV1a_prime; + i++; + } + + /* We do not care about error here */ + (void)walk_items(collection, COL_TRAVERSE_ONELEVEL, parent_traverse_handler, + (void *)parent, NULL, (void *)&ps); + + if (*parent) { + /* Item is found in the collection */ + TRACE_FLOW_STRING("find_property", "Exit - item found"); + return 1; + } + + /* Item is not found */ + TRACE_FLOW_STRING("find_property", "Exit - item NOT found"); + return 0; +} + + + +/* Insert item into the current collection */ +int insert_item_into_current(struct collection_item *collection, + struct collection_item *item, + int disposition, + const char *refprop, + int index, + unsigned flags) { - struct collection_header *header; + struct collection_header *header = NULL; + struct collection_item *parent = NULL; + struct collection_item *current = NULL; + int refindex = 0; - TRACE_FLOW_STRING("add_item_to_collection", "Entry point."); + TRACE_FLOW_STRING("insert_item_into_current", "Entry point"); + + /* Do best effort on the item */ + if ((!item) || (item->next)) { + TRACE_ERROR_STRING("Passed in item is invalid", ""); + return EINVAL; + } if (collection == NULL) { - TRACE_INFO_STRING("add_item_to_collection", + TRACE_INFO_STRING("insert_item_into_current", "Collection accepting is NULL"); - if ((item != NULL) && (item->type == COL_TYPE_COLLECTION)) { + if (item->type == COL_TYPE_COLLECTION) { /* This is a special case of self creation */ - TRACE_INFO_STRING("add_item_to_collection", + TRACE_INFO_STRING("insert_item_into_current", "Adding header item to new collection."); collection = item; } } - - /* We can add items only to collections */ - if (collection->type != COL_TYPE_COLLECTION) { - TRACE_ERROR_STRING("add_item_to_collection", - "Attempt to add item to non collection."); - TRACE_ERROR_STRING("Collection name:", collection->property); - TRACE_ERROR_NUMBER("Collection type:", collection->type); - return EINVAL; + else { + /* We can add items only to collections */ + if (collection->type != COL_TYPE_COLLECTION) { + TRACE_ERROR_STRING("Attempt to add item to non collection.",""); + TRACE_ERROR_STRING("Collection name:", collection->property); + TRACE_ERROR_NUMBER("Collection type:", collection->type); + return EINVAL; + } } + /* After processing flags we can process disposition */ + header = (struct collection_header *)collection->data; - /* Link new item to the last item in the list if there any */ - if (header->last != NULL) header->last->next = item; + /* Check flags first */ + switch(flags) { + case COL_INSERT_NOCHECK: /* No check - good just fall through */ + TRACE_INFO_STRING("Insert without check", ""); + break; + case COL_INSERT_DUPOVER: /* Find item and overwrite - ignore disposition */ + if (find_property(collection, item->property, 0, 0, 0, &parent)) { + current = parent->next; + item->next = current->next; + parent->next = item; + delete_item(current); + header->count--; + TRACE_FLOW_STRING("insert_item_into_current", "Dup overwrite exit"); + return EOK; + } + /* Not found so we fall thorough and add as requested */ + break; + + case COL_INSERT_DUPOVERT: /* Find item by name and type and overwrite - ignore disposition */ + if (find_property(collection, item->property, 0, 1, item->type, &parent)) { + current = parent->next; + item->next = current->next; + parent->next = item; + delete_item(current); + header->count--; + TRACE_FLOW_STRING("insert_item_into_current", "Dup overwrite exit"); + return EOK; + } + /* Not found so we fall thorough and add as requested */ + break; + + case COL_INSERT_DUPERROR: if (find_property(collection, item->property, 0, 0, 0, &parent)) { + /* Return error */ + TRACE_ERROR_NUMBER("Duplicate property", EEXIST); + return EEXIST; + } + break; + + case COL_INSERT_DUPERRORT: if (find_property(collection, item->property, 0, 1, item->type, &parent)) { + /* Return error */ + TRACE_ERROR_NUMBER("Duplicate property of the same type", EEXIST); + return EEXIST; + } + break; + + case COL_INSERT_DUPMOVE: /* Find item and delete */ + if (find_property(collection, item->property, 0, 0, 0, &parent)) { + current = parent->next; + parent->next = current->next; + delete_item(current); + header->count--; + } + /* Now add item according to the disposition */ + break; + + case COL_INSERT_DUPMOVET: /* Find item and delete */ + TRACE_INFO_STRING("Property:", item->property); + TRACE_INFO_NUMBER("Type:", item->type); + if (find_property(collection, item->property, 0, 1, item->type, &parent)) { + TRACE_INFO_NUMBER("Current:", (unsigned)(parent->next)); + current = parent->next; + parent->next = current->next; + delete_item(current); + header->count--; + } + /* Now add item according to the disposition */ + break; + + default: /* The new ones should be added here */ + TRACE_ERROR_NUMBER("Flag is not implemented", ENOSYS); + return ENOSYS; + } + + + switch (disposition) { + case COL_DSP_END: /* Link new item to the last item in the list if there any */ + if (header->last != NULL) header->last->next = item; + /* Make sure we save a new last element */ + header->last = item; + header->count++; + break; + + case COL_DSP_FRONT: /* Same as above if there is header only */ + if (header->count == 1) { + header->last->next = item; + header->last = item; + } + else { + item->next = collection->next; + collection->next = item; + } + header->count++; + break; + + case COL_DSP_BEFORE: /* Check argument */ + if (!refprop) { + TRACE_ERROR_STRING("In this case property is required", ""); + return EINVAL; + } + + /* We need to find property */ + if (find_property(collection, refprop, 0, 0, 0, &parent)) { + item->next = parent->next; + parent->next = item; + header->count++; + } + else { + TRACE_ERROR_STRING("Property not found", refprop); + return ENOENT; + } + break; + + case COL_DSP_AFTER: /* Check argument */ + if (!refprop) { + TRACE_ERROR_STRING("In this case property is required", ""); + return EINVAL; + } + + /* We need to find property */ + if (find_property(collection, refprop, 0, 0, 0, &parent)) { + parent = parent->next; + if (parent->next) { + /* It is not the last item */ + item->next = parent->next; + parent->next = item; + } + else { + /* It is the last item */ + header->last->next = item; + header->last = item; + } + header->count++; + } + else { + TRACE_ERROR_STRING("Property not found", refprop); + return ENOENT; + } + break; + + case COL_DSP_INDEX: if(index == 0) { + /* Same is first */ + if (header->count == 1) { + header->last->next = item; + header->last = item; + } + else { + item->next = collection->next; + collection->next = item; + } + } + else if(index >= header->count - 1) { + /* In this case add to the end */ + if (header->last != NULL) header->last->next = item; + /* Make sure we save a new last element */ + header->last = item; + } + else { + /* In the middle */ + parent = collection; + /* Move to the right position counting */ + while (index > 0) { + index--; + parent = parent->next; + } + item->next = parent->next; + parent->next = item; + } + header->count++; + break; + + case COL_DSP_FIRSTDUP: + case COL_DSP_LASTDUP: + case COL_DSP_NDUP: + + if (disposition == COL_DSP_FIRSTDUP) refindex = 0; + else if (disposition == COL_DSP_LASTDUP) refindex = -1; + else refindex = index; + + /* We need to find property based on index */ + if (find_property(collection, item->property, refindex, 0, 0, &parent)) { + item->next = parent->next; + parent->next = item; + header->count++; + if(header->last == parent) header->last = item; + } + else { + TRACE_ERROR_STRING("Property not found", refprop); + return ENOENT; + } + break; + + default: + TRACE_ERROR_STRING("Disposition is not implemented", ""); + return ENOSYS; + + } - /* Make sure we save a new last element */ - header->last = item; - header->count++; TRACE_INFO_STRING("Collection:", collection->property); TRACE_INFO_STRING("Just added item is:", item->property); TRACE_INFO_NUMBER("Item type.", item->type); TRACE_INFO_NUMBER("Number of items in collection now is.", header->count); - TRACE_FLOW_STRING("add_item_to_collection", "Success exit."); + TRACE_FLOW_STRING("insert_item_into_current", "Exit"); return EOK; } +/* Extract item from the current collection */ +int extract_item_from_current(struct collection_item *collection, + int disposition, + const char *refprop, + int index, + int type, + struct collection_item **ret_ref) +{ + struct collection_header *header = NULL; + struct collection_item *parent = NULL; + struct collection_item *current = NULL; + struct collection_item *found = NULL; + int refindex = 0; + int use_type = 0; -/* TRAVERSE HANDLERS */ + TRACE_FLOW_STRING("extract_item_current", "Entry point"); -/* Special handler to just set a flag if the item is found */ -inline static int is_in_item_handler(const char *property, - int property_len, - int type, - void *data, - int length, - void *found, - int *dummy) -{ - TRACE_FLOW_STRING("is_in_item_handler", "Entry."); - TRACE_INFO_STRING("Property:", property); - TRACE_INFO_NUMBER("Property length:", property_len); - TRACE_INFO_NUMBER("Type:", type); - TRACE_INFO_NUMBER("Length:", length); + /* Check that collection is not empty */ + if ((collection == NULL) || (collection->type != COL_TYPE_COLLECTION)) { + TRACE_ERROR_STRING("Collection can't be NULL", ""); + return EINVAL; + } - *((int *)(found)) = COL_MATCH; + header = (struct collection_header *)collection->data; - TRACE_FLOW_STRING("is_in_item_handler", "Success Exit."); + /* Before moving forward we need to check if there is anything to extract */ + if (header->count <= 1) { + TRACE_ERROR_STRING("Collection is empty.", "Nothing to extract."); + return ENOENT; + } + + if (type != 0) use_type = 1; + + switch (disposition) { + case COL_DSP_END: /* Extract last item in the list. */ + parent = collection; + current = collection->next; + while (current->next != NULL) { + parent = current; + current = current->next; + } + *ret_ref = parent->next; + parent->next = NULL; + /* Special case - one data element */ + if (header->count == 2) header->last = NULL; + else header->last = parent; + break; + + case COL_DSP_FRONT: /* Extract first item in the list */ + *ret_ref = collection->next; + collection->next = (*ret_ref)->next; + /* Special case - one data element */ + if (header->count == 2) header->last = NULL; + break; + + case COL_DSP_BEFORE: /* Check argument */ + if (!refprop) { + TRACE_ERROR_STRING("In this case property is required", ""); + return EINVAL; + } + + /* We have to do it in two steps */ + /* First find the property that is mentioned */ + if (find_property(collection, refprop, 0, use_type, type, &found)) { + /* We found the requested property */ + if (found->next == collection->next) { + /* The referenced property is the first in the list */ + TRACE_ERROR_STRING("Nothing to extract. Lists starts with property", refprop); + return ENOENT; + } + /* Get to the parent of the item that is before the one that is found */ + parent = collection; + current = collection->next; + while (current != found) { + parent = current; + current = current->next; + } + *ret_ref = current; + parent->next = current->next; + + } + else { + TRACE_ERROR_STRING("Property not found", refprop); + return ENOENT; + } + break; + + case COL_DSP_AFTER: /* Check argument */ + if (!refprop) { + TRACE_ERROR_STRING("In this case property is required", ""); + return EINVAL; + } + + /* We need to find property */ + if (find_property(collection, refprop, 0, use_type, type, &parent)) { + current = parent->next; + if (current->next) { + *ret_ref = current->next; + current->next = (*ret_ref)->next; + /* If we removed the last element adjust header */ + if(current->next == NULL) header->last = parent; + } + else { + TRACE_ERROR_STRING("Property is last in the list", refprop); + return ENOENT; + } + } + else { + TRACE_ERROR_STRING("Property not found", refprop); + return ENOENT; + } + break; + + case COL_DSP_INDEX: if (index == 0) { + *ret_ref = collection->next; + collection->next = (*ret_ref)->next; + /* Special case - one data element */ + if (header->count == 2) header->last = NULL; + } + /* Index 0 stands for the first data element. + * Count includes header element. + */ + else if (index >= (header->count - 1)) { + TRACE_ERROR_STRING("Index is out of boundaries", refprop); + return ENOENT; + } + else { + /* Loop till the element with right index */ + refindex = 0; + parent = collection; + current = collection->next; + while (refindex < index) { + parent = current; + current = current->next; + refindex++; + } + *ret_ref = parent->next; + parent->next = (*ret_ref)->next; + /* If we removed the last element adjust header */ + if (parent->next == NULL) header->last = parent; + } + break; + + case COL_DSP_FIRSTDUP: + case COL_DSP_LASTDUP: + case COL_DSP_NDUP: + + if (disposition == COL_DSP_FIRSTDUP) refindex = 0; + else if (disposition == COL_DSP_LASTDUP) refindex = -2; + else refindex = index; + + /* We need to find property based on index */ + if (find_property(collection, refprop, refindex, use_type, type, &parent)) { + *ret_ref = parent->next; + parent->next = (*ret_ref)->next; + /* If we removed the last element adjust header */ + if(parent->next == NULL) header->last = parent; + } + else { + TRACE_ERROR_STRING("Property not found", refprop); + return ENOENT; + } + break; + + default: + TRACE_ERROR_STRING("Disposition is not implemented", ""); + return ENOSYS; + + } + + + /* Clear item and reduce count */ + (*ret_ref)->next = NULL; + header->count--; + TRACE_INFO_STRING("Collection:", (*ret_ref)->property); + TRACE_INFO_NUMBER("Item type.", (*ret_ref)->type); + TRACE_INFO_NUMBER("Number of items in collection now is.", header->count); + + TRACE_FLOW_STRING("extract_item_from_current", "Exit"); return EOK; } -/* Special handler to retrieve the sub collection */ -inline static int get_subcollection(const char *property, - int property_len, - int type, - void *data, - int length, - void *found, - int *dummy) +/* Extract item from the collection */ +int extract_item(struct collection_item *collection, + const char *subcollection, + int disposition, + const char *refprop, + int index, + int type, + struct collection_item **ret_ref) { - TRACE_FLOW_STRING("get_subcollection", "Entry."); - TRACE_INFO_STRING("Property:", property); - TRACE_INFO_NUMBER("Property length:", property_len); - TRACE_INFO_NUMBER("Type:", type); - TRACE_INFO_NUMBER("Length:", length); + struct collection_item *col = NULL; + int error = 0; - *((struct collection_item **)(found)) = *((struct collection_item **)(data)); + TRACE_FLOW_STRING("extract_item", "Entry point"); - TRACE_FLOW_STRING("get_subcollection","Success Exit."); + /* Check that collection is not empty */ + if ((collection == NULL) || (collection->type != COL_TYPE_COLLECTION)) { + TRACE_ERROR_STRING("Collection can't be NULL", ""); + return EINVAL; + } - return EOK; + /* Get subcollection if needed */ + if (subcollection == NULL) { + col = collection; + } + else { + TRACE_INFO_STRING("Subcollection id not null, searching", subcollection); + error = find_item_and_do(collection, subcollection, + COL_TYPE_COLLECTIONREF, + COL_TRAVERSE_DEFAULT, + get_subcollection, (void *)(&col), + COLLECTION_ACTION_FIND); + if (error) { + TRACE_ERROR_NUMBER("Search for subcollection returned error:", error); + return error; + } -} + if (col == NULL) { + TRACE_ERROR_STRING("Search for subcollection returned NULL pointer", ""); + return ENOENT; + } + } -/* ADD PROPERTY */ + /* Extract from the current collection */ + error = extract_item_from_current(col, + disposition, + refprop, + index, + type, + ret_ref); + if (error) { + TRACE_ERROR_NUMBER("Failed extract item into current collection", error); + return error; + } -/* Add a single property to a collection. - * Returns a pointer to a newly allocated property */ -static struct collection_item *add_property(struct collection_item *collection, - const char *subcollection, - const char *property, - void *item_data, - int length, - int type, - int *error) + TRACE_FLOW_STRING("extract_item", "Exit"); + return EOK; +} + + +/* Insert the item into the collection or subcollection */ +int insert_item(struct collection_item *collection, + const char *subcollection, + struct collection_item *item, + int disposition, + const char *refprop, + int index, + unsigned flags) { - struct collection_item *item = NULL; + int error; struct collection_item *acceptor = NULL; - TRACE_FLOW_STRING("add_property", "Entry."); - /* Allocate item */ + TRACE_FLOW_STRING("insert_item", "Entry point."); - TRACE_INFO_NUMBER("Property type to add", type); - *error = allocate_item(&item, property, item_data, length, type); - if (*error) return NULL; + /* Do best effort on the item */ + if ((!item) || (item->next)) { + TRACE_ERROR_STRING("Passed in item is invalid", ""); + return EINVAL; + } - TRACE_INFO_STRING("Created item:", item->property); - TRACE_INFO_NUMBER("Item has type:", item->type); + /* Check that collection is not empty */ + if ((collection == NULL) && (item->type != COL_TYPE_COLLECTION)) { + TRACE_ERROR_STRING("Collection can't be NULL", ""); + return EINVAL; + } /* Add item to collection */ if (subcollection == NULL) { @@ -327,35 +849,177 @@ static struct collection_item *add_property(struct collection_item *collection, } else { TRACE_INFO_STRING("Subcollection id not null, searching", subcollection); - *error = find_item_and_do(collection, subcollection, - COL_TYPE_COLLECTIONREF, - COL_TRAVERSE_DEFAULT, - get_subcollection, (void *)(&acceptor), - COLLECTION_ACTION_FIND); - if (*error) { - TRACE_ERROR_NUMBER("Search for subcollection returned error:", *error); - delete_item(item); - return NULL; + error = find_item_and_do(collection, subcollection, + COL_TYPE_COLLECTIONREF, + COL_TRAVERSE_DEFAULT, + get_subcollection, (void *)(&acceptor), + COLLECTION_ACTION_FIND); + if (error) { + TRACE_ERROR_NUMBER("Search for subcollection returned error:", error); + return error; } if (acceptor == NULL) { TRACE_ERROR_STRING("Search for subcollection returned NULL pointer", ""); - delete_item(item); - *error = ENOENT; - return NULL; + return ENOENT; } } - *error = add_item_to_collection(acceptor, item); - if (*error) { - TRACE_ERROR_NUMBER("Failed to add item to collection error:", *error); + + /* Instert item to the current collection */ + error = insert_item_into_current(acceptor, + item, + disposition, + refprop, + index, + flags); + + if (error) { + TRACE_ERROR_NUMBER("Failed to insert item into current collection", error); + return error; + } + + TRACE_FLOW_STRING("insert_item", "Exit"); + return EOK; +} + + +/* Insert property with reference. + * This is internal function so we do not check parameters. + * See external wrapper below. + */ +static int insert_property_with_ref_int(struct collection_item *collection, + const char *subcollection, + int disposition, + const char *refprop, + int index, + unsigned flags, + const char *property, + int type, + void *data, + int length, + struct collection_item **ret_ref) +{ + struct collection_item *item = NULL; + int error; + + TRACE_FLOW_STRING("insert_property_with_ref_int", "Entry point."); + + /* Create a new property out of the given parameters */ + error = allocate_item(&item, property, data, length, type); + if (error) { + TRACE_ERROR_NUMBER("Failed to allocate item", error); + return error; + } + + /* Send the property to the insert_item function */ + error = insert_item(collection, + subcollection, + item, + disposition, + refprop, + index, + flags); + if (error) { + TRACE_ERROR_NUMBER("Failed to insert item", error); delete_item(item); - return NULL; + return error; + } + + if (ret_ref) *ret_ref = item; + + TRACE_FLOW_STRING("insert_property_with_ref_int", "Exit"); + return EOK; +} + +/* This is public function so we need to check the validity + * of the arguments. + */ +int insert_property_with_ref(struct collection_item *collection, + const char *subcollection, + int disposition, + const char *refprop, + int index, + unsigned flags, + const char *property, + int type, + void *data, + int length, + struct collection_item **ret_ref) +{ + int error; + + TRACE_FLOW_STRING("insert_property_with_ref", "Entry point."); + + /* Check that collection is not empty */ + if (collection == NULL) { + TRACE_ERROR_STRING("Collection cant be NULL", ""); + return EINVAL; } - TRACE_FLOW_STRING("add_property", "Success Exit."); - return item; + error = insert_property_with_ref_int(collection, + subcollection, + disposition, + refprop, + index, + flags, + property, + type, + data, + length, + ret_ref); + + TRACE_FLOW_NUMBER("insert_property_with_ref_int Returning:", error); + return error; } +/* TRAVERSE HANDLERS */ + +/* Special handler to just set a flag if the item is found */ +static int is_in_item_handler(const char *property, + int property_len, + int type, + void *data, + int length, + void *found, + int *dummy) +{ + TRACE_FLOW_STRING("is_in_item_handler", "Entry."); + TRACE_INFO_STRING("Property:", property); + TRACE_INFO_NUMBER("Property length:", property_len); + TRACE_INFO_NUMBER("Type:", type); + TRACE_INFO_NUMBER("Length:", length); + + *((int *)(found)) = COL_MATCH; + + TRACE_FLOW_STRING("is_in_item_handler", "Success Exit."); + + return EOK; +} + +/* Special handler to retrieve the sub collection */ +static int get_subcollection(const char *property, + int property_len, + int type, + void *data, + int length, + void *found, + int *dummy) +{ + TRACE_FLOW_STRING("get_subcollection", "Entry."); + TRACE_INFO_STRING("Property:", property); + TRACE_INFO_NUMBER("Property length:", property_len); + TRACE_INFO_NUMBER("Type:", type); + TRACE_INFO_NUMBER("Length:", length); + + *((struct collection_item **)(found)) = *((struct collection_item **)(data)); + + TRACE_FLOW_STRING("get_subcollection","Success Exit."); + + return EOK; + +} + + /* CLEANUP */ @@ -364,8 +1028,6 @@ static struct collection_item *add_property(struct collection_item *collection, * as memory is freed!!! */ static void delete_collection(struct collection_item *ci) { - struct collection_item *other_collection; - TRACE_FLOW_STRING("delete_collection", "Entry."); if (ci == NULL) { @@ -377,14 +1039,6 @@ static void delete_collection(struct collection_item *ci) delete_collection(ci->next); - /* Handle external or embedded collection */ - if(ci->type == COL_TYPE_COLLECTIONREF) { - /* Our data is a pointer to a whole external collection so dereference - * it or delete */ - other_collection = *((struct collection_item **)(ci->data)); - destroy_collection(other_collection); - } - /* Delete this item */ delete_item(ci); TRACE_FLOW_STRING("delete_collection", "Exit."); @@ -790,13 +1444,13 @@ static int update_current_item(struct collection_item *current, /* Traverse handler for simple traverse function */ /* Handler must be able to deal with NULL current item */ -inline static int simple_traverse_handler(struct collection_item *head, - struct collection_item *previous, - struct collection_item *current, - void *traverse_data, - item_fn user_item_handler, - void *custom_data, - int *stop) +static int simple_traverse_handler(struct collection_item *head, + struct collection_item *previous, + struct collection_item *current, + void *traverse_data, + item_fn user_item_handler, + void *custom_data, + int *stop) { int error = EOK; @@ -816,6 +1470,80 @@ inline static int simple_traverse_handler(struct collection_item *head, return error; } +/* Traverse handler for to find parent */ +static int parent_traverse_handler(struct collection_item *head, + struct collection_item *previous, + struct collection_item *current, + void *traverse_data, + item_fn user_item_handler, + void *custom_data, + int *stop) +{ + struct property_search *to_find; + int done = 0; + int match = 0; + + TRACE_FLOW_STRING("parent_traverse_handler", "Entry."); + + to_find = (struct property_search *)custom_data; + + /* Check hashes first */ + if(to_find->hash == current->phash) { + + TRACE_INFO_NUMBER("Looking for HASH:", (unsigned)(to_find->hash)); + TRACE_INFO_NUMBER("Current HASH:", (unsigned)(current->phash)); + + /* Check type if we are asked to use type */ + if ((to_find->use_type) && (!(to_find->type & current->type))) { + TRACE_FLOW_STRING("parent_traverse_handler. Returning:","Exit. Hash is Ok, type is not"); + return EOK; + } + + /* Validate property. Make sure we include terminating 0 in the comparison */ + if (strncasecmp(current->property, to_find->property, current->property_len + 1) == 0) { + + match = 1; + to_find->found = 1; + + /* Do the right thing based on index */ + /* If index is 0 we are looking for the first value in the list of duplicate properties */ + if (to_find->index == 0) done = 1; + /* If index is non zero we are looking for N-th instance of the dup property */ + else if (to_find->index > 0) { + if (to_find->count == to_find->index) done = 1; + else { + /* Record found instance and move on */ + to_find->parent = previous; + (to_find->count)++; + } + } + /* If we are looking for last instance just record it */ + else to_find->parent = previous; + } + } + + if (done) { + *stop = 1; + *((struct collection_item **)traverse_data) = previous; + } + else { + /* As soon as we found first non matching one but there was a match + * return the parent of the last found item. + */ + if (((!match) || (current->next == NULL)) && (to_find->index != 0) && (to_find->found)) { + *stop = 1; + if (to_find->index == -2) + *((struct collection_item **)traverse_data) = to_find->parent; + else + *((struct collection_item **)traverse_data) = to_find->parent->next; + } + } + + + TRACE_FLOW_STRING("parent_traverse_handler. Returning:","Exit"); + return EOK; +} + /* Traverse callback for find & delete function */ static int act_traverse_handler(struct collection_item *head, @@ -832,7 +1560,6 @@ static int act_traverse_handler(struct collection_item *head, int length; struct path_data *temp; struct collection_header *header; - struct collection_item *other; char *property; int property_len; struct update_property *update_data; @@ -934,13 +1661,6 @@ static int act_traverse_handler(struct collection_item *head, /* Make sure we tell the caller we found a match */ if (custom_data != NULL) *(int *)custom_data = COL_MATCH; - /* Dereference external collections */ - if (current->type == COL_TYPE_COLLECTIONREF) { - TRACE_INFO_STRING("Dereferencing a referenced collection.", ""); - other = *((struct collection_item **)current->data); - header = (struct collection_header *)other->data; - destroy_collection(other); - } /* Adjust header of the collection */ header = (struct collection_header *)head->data; @@ -1027,18 +1747,35 @@ static int copy_traverse_handler(struct collection_item *head, /* Add new item to a collection * all references are now sub collections */ - add_property(parent, NULL, item->property, - (void *)(&new_collection), - sizeof(struct collection_item **), - COL_TYPE_COLLECTIONREF, &error); + error = insert_property_with_ref_int(parent, + NULL, + COL_DSP_END, + NULL, + 0, + 0, + item->property, + COL_TYPE_COLLECTIONREF, + (void *)(&new_collection), + sizeof(struct collection_item **), + NULL); if (error) { TRACE_ERROR_NUMBER("Add property returned error:", error); return error; } } else { - add_property(parent, NULL, item->property, - item->data, item->length, item->type, &error); + + error = insert_property_with_ref_int(parent, + NULL, + COL_DSP_END, + NULL, + 0, + 0, + item->property, + item->type, + item->data, + item->length, + NULL); if (error) { TRACE_ERROR_NUMBER("Add property returned error:", error); return error; @@ -1073,9 +1810,19 @@ int create_collection(struct collection_item **ci, const char *name, header.cclass = cclass; /* Create a collection type property */ - handle = add_property(NULL, NULL, name, - &header, sizeof(header), - COL_TYPE_COLLECTION, &error); + error = insert_property_with_ref_int(NULL, + NULL, + COL_DSP_END, + NULL, + 0, + 0, + name, + COL_TYPE_COLLECTION, + &header, + sizeof(header), + &handle); + + if (error) return error; *ci = handle; @@ -1120,361 +1867,6 @@ void destroy_collection(struct collection_item *ci) } -/* PROPERTIES */ - -/* Add a string property. - If length equals 0, the length is determined based on the string. - Lenght INCLUDES the terminating 0 */ -inline int add_str_property(struct collection_item *ci, - const char *subcollection, - const char *property, - char *string, int length) -{ - int error = EOK; - - TRACE_FLOW_STRING("add_str_property", "Entry."); - - if (length == 0) - length = strlen(string) + 1; - - add_property(ci, subcollection, property, - (void *)(string), length, COL_TYPE_STRING, &error); - - TRACE_FLOW_NUMBER("add_str_property returning", error); - return error; -} - -/* Add a binary property. */ -inline int add_binary_property(struct collection_item *ci, - const char *subcollection, - const char *property, - void *binary_data, int length) -{ - int error = EOK; - - TRACE_FLOW_STRING("add_binary_property", "Entry."); - - add_property(ci, subcollection, property, - binary_data, length, COL_TYPE_BINARY, &error); - - TRACE_FLOW_NUMBER("add_binary_property returning", error); - return error; -} - -/* Add an int property. */ -inline int add_int_property(struct collection_item *ci, - const char *subcollection, - const char *property, int number) -{ - int error = EOK; - - TRACE_FLOW_STRING("add_int_property", "Entry."); - - add_property(ci, subcollection, property, - (void *)(&number), sizeof(int), - COL_TYPE_INTEGER, &error); - - TRACE_FLOW_NUMBER("add_int_property returning", error); - return error; -} - -/* Add an unsigned int property. */ -inline int add_unsigned_property(struct collection_item *ci, - const char *subcollection, - const char *property, unsigned int number) -{ - int error = EOK; - - TRACE_FLOW_STRING("add_unsigned_property", "Entry."); - - add_property(ci, subcollection, property, - (void *)(&number), sizeof(int), COL_TYPE_UNSIGNED, &error); - - TRACE_FLOW_NUMBER("add_unsigned_property returning", error); - return error; -} - -/* Add an long property. */ -inline int add_long_property(struct collection_item *ci, - const char *subcollection, - const char *property, long number) -{ - int error = EOK; - - TRACE_FLOW_STRING("add_long_property", "Entry."); - - add_property(ci, subcollection, property, - (void *)(&number), sizeof(long), COL_TYPE_LONG, &error); - - TRACE_FLOW_NUMBER("add_long_property returning", error); - return error; -} - -/* Add an unsigned long property. */ -inline int add_ulong_property(struct collection_item *ci, - const char *subcollection, - const char *property, unsigned long number) -{ - int error = EOK; - - TRACE_FLOW_STRING("add_ulong_property", "Entry."); - - add_property(ci, subcollection, property, - (void *)(&number), sizeof(long), - COL_TYPE_ULONG, &error); - - TRACE_FLOW_NUMBER("add_ulong_property returning", error); - return error; -} - -/* Add a double property. */ -inline int add_double_property(struct collection_item *ci, - const char *subcollection, - const char *property, double number) -{ - int error = EOK; - - TRACE_FLOW_STRING("add_double_property", "Entry."); - - add_property(ci, subcollection, property, - (void *)(&number), sizeof(double), COL_TYPE_DOUBLE, &error); - - TRACE_FLOW_NUMBER("add_double_property returning", error); - return error; -} - -/* Add a bool property. */ -inline int add_bool_property(struct collection_item *ci, - const char *subcollection, - const char *property, unsigned char logical) -{ - int error = EOK; - - TRACE_FLOW_STRING("add_bool_property", "Entry."); - - add_property(ci, subcollection, property, - (void *)(&logical), sizeof(unsigned char), - COL_TYPE_BOOL, &error); - - TRACE_FLOW_NUMBER("add_bool_property returning", error); - return error; -} - -/* A function to add a property */ -inline int add_any_property(struct collection_item *ci, - const char *subcollection, - const char *property, - int type, void *data, int length) -{ - int error = EOK; - - TRACE_FLOW_STRING("add_any_property", "Entry."); - - add_property(ci, subcollection, property, data, length, type, &error); - - TRACE_FLOW_NUMBER("add_any_property returning", error); - return error; -} - -/* Add a string property. - If length equals 0, the length is determined based on the string. - Lenght INCLUDES the terminating 0 */ -inline int add_str_property_with_ref(struct collection_item *ci, - const char *subcollection, - const char *property, - char *string, int length, - struct collection_item **ref_ret) -{ - int error = EOK; - struct collection_item *item; - - TRACE_FLOW_STRING("add_str_property_with_ref", "Entry."); - - if (length == 0) length = strlen(string) + 1; - - item = add_property(ci, subcollection, property, - (void *)(string), length, COL_TYPE_STRING, &error); - - if (ref_ret != NULL) *ref_ret = item; - - TRACE_FLOW_NUMBER("add_str_property_with_ref returning", error); - return error; -} - -/* Add a binary property. */ -inline int add_binary_property_with_ref(struct collection_item *ci, - const char *subcollection, - const char *property, - void *binary_data, int length, - struct collection_item **ref_ret) -{ - int error = EOK; - struct collection_item *item; - - TRACE_FLOW_STRING("add_binary_property_with_ref", "Entry."); - - item = add_property(ci, subcollection, property, - binary_data, length, COL_TYPE_BINARY, &error); - - if (ref_ret != NULL) *ref_ret = item; - - TRACE_FLOW_NUMBER("add_binary_property_with_ref returning", error); - return error; -} - -/* Add an int property. */ -inline int add_int_property_with_ref(struct collection_item *ci, - const char *subcollection, - const char *property, - int number, - struct collection_item **ref_ret) -{ - int error = EOK; - struct collection_item *item; - - TRACE_FLOW_STRING("add_int_property_with_ref", "Entry."); - - item = add_property(ci, subcollection, property, - (void *)(&number), sizeof(int), - COL_TYPE_INTEGER, &error); - - if (ref_ret != NULL) *ref_ret = item; - - TRACE_FLOW_NUMBER("add_int_property_with_ref returning", error); - return error; -} - -/* Add an unsigned int property. */ -inline int add_unsigned_property_with_ref(struct collection_item *ci, - const char *subcollection, - const char *property, - unsigned int number, - struct collection_item **ref_ret) -{ - int error = EOK; - struct collection_item *item; - - TRACE_FLOW_STRING("add_unsigned_property_with_ref", "Entry."); - - item = add_property(ci, subcollection, property, - (void *)(&number), sizeof(int), - COL_TYPE_UNSIGNED, &error); - - if (ref_ret != NULL) *ref_ret = item; - - TRACE_FLOW_NUMBER("add_unsigned_property_with_ref returning", error); - return error; -} - -/* Add an long property. */ -inline int add_long_property_with_ref(struct collection_item *ci, - const char *subcollection, - const char *property, - long number, - struct collection_item **ref_ret) -{ - int error = EOK; - struct collection_item *item; - - TRACE_FLOW_STRING("add_long_property_with_ref", "Entry."); - - item = add_property(ci, subcollection, property, - (void *)(&number), sizeof(long), COL_TYPE_LONG, &error); - - if (ref_ret != NULL) *ref_ret = item; - - TRACE_FLOW_NUMBER("add_long_property_with_ref returning", error); - return error; -} - -/* Add an unsigned long property. */ -inline int add_ulong_property_with_ref(struct collection_item *ci, - const char *subcollection, - const char *property, - unsigned long number, - struct collection_item **ref_ret) -{ - int error = EOK; - struct collection_item *item; - - TRACE_FLOW_STRING("add_ulong_property_with_ref", "Entry."); - - item = add_property(ci, subcollection, property, - (void *)(&number), sizeof(long), - COL_TYPE_ULONG, &error); - - if (ref_ret != NULL) *ref_ret = item; - - TRACE_FLOW_NUMBER("add_ulong_property_with_ref returning", error); - return error; -} - -/* Add a double property. */ -inline int add_double_property_with_ref(struct collection_item *ci, - const char *subcollection, - const char *property, - double number, - struct collection_item **ref_ret) -{ - int error = EOK; - struct collection_item *item; - - TRACE_FLOW_STRING("add_double_property_with_ref", "Entry."); - - item = add_property(ci, subcollection, property, - (void *)(&number), sizeof(double), - COL_TYPE_DOUBLE, &error); - - if (ref_ret != NULL) *ref_ret = item; - - TRACE_FLOW_NUMBER("add_double_property_with_ref returning", error); - return error; -} - -/* Add a bool property. */ -inline int add_bool_property_with_ref(struct collection_item *ci, - const char *subcollection, - const char *property, - unsigned char logical, - struct collection_item **ref_ret) -{ - int error = EOK; - struct collection_item *item; - - TRACE_FLOW_STRING("add_bool_property_with_ref", "Entry."); - - item = add_property(ci, subcollection, property, - (void *)(&logical), sizeof(unsigned char), - COL_TYPE_BOOL, &error); - - if (ref_ret != NULL) *ref_ret = item; - - TRACE_FLOW_NUMBER("add_bool_property_with_ref returning", error); - return error; -} - -/* A function to add a property */ -inline int add_any_property_with_ref(struct collection_item *ci, - const char *subcollection, - const char *property, - int type, - void *data, - int length, - struct collection_item **ref_ret) -{ - int error = EOK; - struct collection_item *item; - - TRACE_FLOW_STRING("add_any_property_with_ref", "Entry."); - - item = add_property(ci, subcollection, property, - data, length, type, &error); - - if (ref_ret != NULL) *ref_ret = item; - - TRACE_FLOW_NUMBER("add_any_property_with_ref returning", error); - return error; -} @@ -1602,6 +1994,7 @@ int get_reference_from_item(struct collection_item *ci, /* ADDITION */ /* Add collection to collection */ +/* FIXME - allow to add collection to a collection with disposition */ int add_collection_to_collection( struct collection_item *ci, /* Collection handle to with we add another collection */ const char *sub_collection_name, /* Name of the sub collection to which @@ -1673,12 +2066,19 @@ int add_collection_to_collection( collection_to_add->property); /* Create a pointer to external collection */ /* For future thread safety: Transaction start -> */ - add_property(acceptor, NULL, name_to_use, - (void *)(&collection_to_add), - sizeof(struct collection_item **), - COL_TYPE_COLLECTIONREF, &error); - - TRACE_INFO_NUMBER("Type of the header element after add_property:", + error = insert_property_with_ref_int(acceptor, + NULL, + COL_DSP_END, + NULL, + 0, + 0, + name_to_use, + COL_TYPE_COLLECTIONREF, + (void *)(&collection_to_add), + sizeof(struct collection_item **), + NULL); + + TRACE_INFO_NUMBER("Type of the header element after adding property:", collection_to_add->type); TRACE_INFO_STRING("Header name we just added.", collection_to_add->property); @@ -1707,10 +2107,18 @@ int add_collection_to_collection( TRACE_INFO_STRING("Header name we are adding to.", acceptor->property); - add_property(acceptor, NULL, name_to_use, - (void *)(&collection_to_add), - sizeof(struct collection_item **), - COL_TYPE_COLLECTIONREF, &error); + error = insert_property_with_ref_int(acceptor, + NULL, + COL_DSP_END, + NULL, + 0, + 0, + name_to_use, + COL_TYPE_COLLECTIONREF, + (void *)(&collection_to_add), + sizeof(struct collection_item **), + NULL); + TRACE_INFO_NUMBER("Adding property returned:", error); break; @@ -1729,10 +2137,17 @@ int add_collection_to_collection( TRACE_INFO_STRING("Acceptor collection.", acceptor->property); TRACE_INFO_NUMBER("Acceptor collection type.", acceptor->type); - add_property(acceptor, NULL, name_to_use, - (void *)(&collection_copy), - sizeof(struct collection_item **), - COL_TYPE_COLLECTIONREF, &error); + error = insert_property_with_ref_int(acceptor, + NULL, + COL_DSP_END, + NULL, + 0, + 0, + name_to_use, + COL_TYPE_COLLECTIONREF, + (void *)(&collection_copy), + sizeof(struct collection_item **), + NULL); /* -> Transaction end */ TRACE_INFO_NUMBER("Adding property returned:", error); @@ -1750,10 +2165,10 @@ int add_collection_to_collection( /* Function to traverse the entire collection including optionally * sub collections */ -inline int traverse_collection(struct collection_item *ci, - int mode_flags, - item_fn item_handler, - void *custom_data) +int traverse_collection(struct collection_item *ci, + int mode_flags, + item_fn item_handler, + void *custom_data) { int error = EOK; @@ -1774,11 +2189,11 @@ inline int traverse_collection(struct collection_item *ci, /* CHECK */ /* Convenience function to check if specific property is in the collection */ -inline int is_item_in_collection(struct collection_item *ci, - const char *property_to_find, - int type, - int mode_flags, - int *found) +int is_item_in_collection(struct collection_item *ci, + const char *property_to_find, + int type, + int mode_flags, + int *found) { int error; @@ -1799,12 +2214,12 @@ inline int is_item_in_collection(struct collection_item *ci, /* Search function. Looks up an item in the collection based on the property. Essentually it is a traverse function with spacial traversing logic. */ -inline int get_item_and_do(struct collection_item *ci, /* Collection to find things in */ - const char *property_to_find, /* Name to match */ - int type, /* Type filter */ - int mode_flags, /* How to traverse the collection */ - item_fn item_handler, /* Function to call when the item is found */ - void *custom_data) /* Custom data passed around */ +int get_item_and_do(struct collection_item *ci, /* Collection to find things in */ + const char *property_to_find, /* Name to match */ + int type, /* Type filter */ + int mode_flags, /* How to traverse the collection */ + item_fn item_handler, /* Function to call when the item is found */ + void *custom_data) /* Custom data passed around */ { int error = EOK; @@ -1822,11 +2237,11 @@ inline int get_item_and_do(struct collection_item *ci, /* Collection to fi /* Get raw item */ -inline int get_item(struct collection_item *ci, /* Collection to find things in */ - const char *property_to_find, /* Name to match */ - int type, /* Type filter */ - int mode_flags, /* How to traverse the collection */ - struct collection_item **item) /* Found item */ +int get_item(struct collection_item *ci, /* Collection to find things in */ + const char *property_to_find, /* Name to match */ + int type, /* Type filter */ + int mode_flags, /* How to traverse the collection */ + struct collection_item **item) /* Found item */ { int error = EOK; @@ -1844,10 +2259,10 @@ inline int get_item(struct collection_item *ci, /* Collection to find thin /* DELETE */ /* Delete property from the collection */ -inline int delete_property(struct collection_item *ci, /* Collection to find things in */ - const char *property_to_find, /* Name to match */ - int type, /* Type filter */ - int mode_flags) /* How to traverse the collection */ +int delete_property(struct collection_item *ci, /* Collection to find things in */ + const char *property_to_find, /* Name to match */ + int type, /* Type filter */ + int mode_flags) /* How to traverse the collection */ { int error = EOK; int found; @@ -1898,140 +2313,6 @@ int update_property(struct collection_item *ci, /* Collection to find things return error; } -/* Update a string property in the collection. - * Length should include the terminating 0 */ -inline int update_str_property(struct collection_item *ci, - const char *property, - int mode_flags, - char *string, - int length) -{ - int error = EOK; - TRACE_FLOW_STRING("update_str_property", "Entry."); - - if (length == 0) length = strlen(string) + 1; - error = update_property(ci, property, COL_TYPE_STRING, - (void *)string, length, mode_flags); - - TRACE_FLOW_NUMBER("update_str_property Returning", error); - return error; -} - -/* Update a binary property in the collection. */ -inline int update_binary_property(struct collection_item *ci, - const char *property, - int mode_flags, - void *binary_data, - int length) -{ - int error = EOK; - TRACE_FLOW_STRING("update_binary_property", "Entry."); - - error = update_property(ci, property, COL_TYPE_BINARY, - binary_data, length, mode_flags); - - TRACE_FLOW_NUMBER("update_binary_property Returning", error); - return error; -} - -/* Update an int property in the collection. */ -inline int update_int_property(struct collection_item *ci, - const char *property, - int mode_flags, - int number) -{ - int error = EOK; - TRACE_FLOW_STRING("update_int_property", "Entry."); - - error = update_property(ci, property, COL_TYPE_INTEGER, - (void *)(&number), sizeof(int), mode_flags); - - TRACE_FLOW_NUMBER("update_int_property Returning", error); - return error; -} - -/* Update an unsigned int property. */ -inline int update_unsigned_property(struct collection_item *ci, - const char *property, - int mode_flags, - unsigned int number) -{ - int error = EOK; - TRACE_FLOW_STRING("update_unsigned_property", "Entry."); - - error = update_property(ci, property, COL_TYPE_UNSIGNED, - (void *)(&number), sizeof(unsigned int), - mode_flags); - - TRACE_FLOW_NUMBER("update_unsigned_property Returning", error); - return error; -} -/* Update a long property. */ -inline int update_long_property(struct collection_item *ci, - const char *property, - int mode_flags, - long number) -{ - int error = EOK; - TRACE_FLOW_STRING("update_long_property", "Entry."); - - error = update_property(ci, property, COL_TYPE_LONG, - (void *)(&number), sizeof(long), mode_flags); - - TRACE_FLOW_NUMBER("update_long_property Returning", error); - return error; - -} - -/* Update an unsigned long property. */ -inline int update_ulong_property(struct collection_item *ci, - const char *property, - int mode_flags, - unsigned long number) -{ - int error = EOK; - TRACE_FLOW_STRING("update_ulong_property", "Entry."); - - error = update_property(ci, property, COL_TYPE_ULONG, - (void *)(&number), sizeof(unsigned long), - mode_flags); - - TRACE_FLOW_NUMBER("update_ulong_property Returning", error); - return error; -} - -/* Update a double property. */ -inline int update_double_property(struct collection_item *ci, - const char *property, - int mode_flags, - double number) -{ - int error = EOK; - TRACE_FLOW_STRING("update_double_property", "Entry."); - - error = update_property(ci, property, COL_TYPE_DOUBLE, - (void *)(&number), sizeof(double), mode_flags); - - TRACE_FLOW_NUMBER("update_double_property Returning", error); - return error; -} - -/* Update a bool property. */ -inline int update_bool_property(struct collection_item *ci, - const char *property, - int mode_flags, - unsigned char logical) -{ - int error = EOK; - TRACE_FLOW_STRING("update_bool_property", "Entry."); - - error = update_property(ci, property, COL_TYPE_BOOL, - (void *)(&logical), sizeof(unsigned char), - mode_flags); - - TRACE_FLOW_NUMBER("update_bool_property Returning", error); - return error; -} /* Function to modify the item */ int modify_item(struct collection_item *item, @@ -2050,6 +2331,10 @@ int modify_item(struct collection_item *item, } if (property != NULL) { + if (validate_property(property)) { + TRACE_ERROR_STRING("Invalid chracters in the property name", property); + return EINVAL; + } free(item->property); item->property = strdup(property); if (item->property == NULL) { @@ -2058,166 +2343,38 @@ int modify_item(struct collection_item *item, } } - /* If type is different or same but it is string or binary we need to - * replace the storage */ - if ((item->type != type) || - ((item->type == type) && - ((item->type == COL_TYPE_STRING) || (item->type == COL_TYPE_BINARY)))) { - TRACE_INFO_STRING("Replacing item data buffer", ""); - free(item->data); - item->data = malloc(length); - if (item->data == NULL) { - TRACE_ERROR_STRING("Failed to allocate memory", ""); - item->length = 0; - return ENOMEM; + /* We need to change data ? */ + if(length) { + + /* If type is different or same but it is string or binary we need to + * replace the storage */ + if ((item->type != type) || + ((item->type == type) && + ((item->type == COL_TYPE_STRING) || (item->type == COL_TYPE_BINARY)))) { + TRACE_INFO_STRING("Replacing item data buffer", ""); + free(item->data); + item->data = malloc(length); + if (item->data == NULL) { + TRACE_ERROR_STRING("Failed to allocate memory", ""); + item->length = 0; + return ENOMEM; + } + item->length = length; } - item->length = length; - } + TRACE_INFO_STRING("Overwriting item data", ""); + memcpy(item->data, data, item->length); + item->type = type; - TRACE_INFO_STRING("Overwriting item data", ""); - memcpy(item->data, data, item->length); - item->type = type; - - if (item->type == COL_TYPE_STRING) - ((char *)(item->data))[item->length - 1] = '\0'; + if (item->type == COL_TYPE_STRING) + ((char *)(item->data))[item->length - 1] = '\0'; + } TRACE_FLOW_STRING("modify_item", "Exit"); return EOK; } -/* Convinience functions that wrap modify_item(). */ -/* Modify item data to be str */ -inline int modify_str_item(struct collection_item *item, - const char *property, - char *string, - int length) -{ - int len; - int error; - - TRACE_FLOW_STRING("modify_str_item", "Entry"); - - if (length != 0) - len = length; - else - len = strlen(string) + 1; - - error = modify_item(item, property, COL_TYPE_STRING, (void *)string, len); - - TRACE_FLOW_STRING("modify_str_item", "Exit"); - return error; -} - -/* Modify item data to be binary */ -inline int modify_binary_item(struct collection_item *item, - const char *property, - void *binary_data, - int length) -{ - int error; - - TRACE_FLOW_STRING("modify_binary_item", "Entry"); - - error = modify_item(item, property, COL_TYPE_BINARY, binary_data, length); - - TRACE_FLOW_STRING("modify_binary_item", "Exit"); - return error; -} - -/* Modify item data to be bool */ -inline int modify_bool_item(struct collection_item *item, - const char *property, - unsigned char logical) -{ - int error; - - TRACE_FLOW_STRING("modify_bool_item", "Entry"); - - error = modify_item(item, property, COL_TYPE_BOOL, (void *)(&logical), 1); - - TRACE_FLOW_STRING("modify_bool_item", "Exit"); - return error; -} - -/* Modify item data to be int */ -inline int modify_int_item(struct collection_item *item, - const char *property, - int number) -{ - int error; - - TRACE_FLOW_STRING("modify_int_item","Entry"); - - error = modify_item(item, property, COL_TYPE_INTEGER, - (void *)(&number), sizeof(int)); - - TRACE_FLOW_STRING("modify_int_item", "Exit"); - return error; -} - -/* Modify item data to be long */ -inline int modify_long_item(struct collection_item *item, - const char *property, - long number) -{ - int error; - - TRACE_FLOW_STRING("modify_long_item", "Entry"); - - error = modify_item(item, property, COL_TYPE_LONG, - (void *)(&number), sizeof(long)); - - TRACE_FLOW_STRING("modify_long_item", "Exit"); - return error; -} - -/* Modify item data to be unigned long */ -inline int modify_ulong_item(struct collection_item *item, - const char *property, - unsigned long number) -{ - int error; - - TRACE_FLOW_STRING("modify_ulong_item", "Entry"); - - error = modify_item(item, property, COL_TYPE_ULONG, - (void *)(&number), sizeof(unsigned long)); - - TRACE_FLOW_STRING("modify_ulong_item", "Exit"); - return error; -} - -inline int modify_unsigned_item(struct collection_item *item, - const char *property, - unsigned number) -{ - int error; - - TRACE_FLOW_STRING("modify_unsigned_item", "Entry"); - - error = modify_item(item, property, COL_TYPE_UNSIGNED, - (void *)(&number), sizeof(unsigned)); - - TRACE_FLOW_STRING("modify_unsigned_item", "Exit"); - return error; -} - -inline int modify_double_item(struct collection_item *item, - const char *property, - double number) -{ - int error; - - TRACE_FLOW_STRING("modify_double_item", "Entry"); - - error = modify_item(item, property, COL_TYPE_DOUBLE, - (void *)(&number), sizeof(double)); - - TRACE_FLOW_STRING("modify_double_item", "Exit"); - return error; -} /* Grow iteration stack */ @@ -2297,7 +2454,7 @@ int bind_iterator(struct collection_iterator **iterator, /* Stop processing this subcollection and move to the next item in the * collection 'level' levels up.*/ -inline int iterate_up(struct collection_iterator *iterator, int level) +int iterate_up(struct collection_iterator *iterator, int level) { TRACE_FLOW_STRING("iterate_up", "Entry"); @@ -2314,8 +2471,9 @@ inline int iterate_up(struct collection_iterator *iterator, int level) TRACE_FLOW_STRING("iterate_up", "Exit"); return EOK; } + /* How deep are we relative to the top level.*/ -inline int get_iterator_depth(struct collection_iterator *iterator, int *depth) +int get_iterator_depth(struct collection_iterator *iterator, int *depth) { TRACE_FLOW_STRING("iterate_up", "Entry"); @@ -2333,7 +2491,7 @@ inline int get_iterator_depth(struct collection_iterator *iterator, int *depth) /* Unbind the iterator from the collection */ -inline void unbind_iterator(struct collection_iterator *iterator) +void unbind_iterator(struct collection_iterator *iterator) { TRACE_FLOW_STRING("unbind_iterator", "Entry."); if (iterator != NULL) { @@ -2477,7 +2635,7 @@ int iterate_collection(struct collection_iterator *iterator, } /* Set collection class */ -inline int set_collection_class(struct collection_item *item, unsigned cclass) +int set_collection_class(struct collection_item *item, unsigned cclass) { struct collection_header *header; @@ -2495,8 +2653,8 @@ inline int set_collection_class(struct collection_item *item, unsigned cclass) } /* Get collection class */ -inline int get_collection_class(struct collection_item *item, - unsigned *cclass) +int get_collection_class(struct collection_item *item, + unsigned *cclass) { struct collection_header *header; @@ -2514,8 +2672,8 @@ inline int get_collection_class(struct collection_item *item, } /* Get collection count */ -inline int get_collection_count(struct collection_item *item, - unsigned *count) +int get_collection_count(struct collection_item *item, + unsigned *count) { struct collection_header *header; @@ -2535,7 +2693,7 @@ inline int get_collection_count(struct collection_item *item, /* Convinience function to check if the collection is of the specific class */ /* In case of internal error assumes that collection is not of the right class */ -inline int is_of_class(struct collection_item *item, unsigned cclass) +int is_of_class(struct collection_item *item, unsigned cclass) { int error = EOK; unsigned ret_class = 0; @@ -2550,26 +2708,26 @@ inline int is_of_class(struct collection_item *item, unsigned cclass) } /* Get propery */ -inline const char *get_item_property(struct collection_item *ci,int *property_len) +const char *get_item_property(struct collection_item *ci,int *property_len) { if (property_len != NULL) *property_len = ci->property_len; return ci->property; } /* Get type */ -inline int get_item_type(struct collection_item *ci) +int get_item_type(struct collection_item *ci) { return ci->type; } /* Get length */ -inline int get_item_length(struct collection_item *ci) +int get_item_length(struct collection_item *ci) { return ci->length; } /* Get data */ -inline const void *get_item_data(struct collection_item *ci) +const void *get_item_data(struct collection_item *ci) { return ci->data; } diff --git a/common/collection/collection.h b/common/collection/collection.h index 687f468d..28622a50 100644 --- a/common/collection/collection.h +++ b/common/collection/collection.h @@ -48,6 +48,7 @@ Useful when traversing collections */ + /* Any data we deal with can't be longer than this */ /* FIXME - make it compile time option */ #define COL_MAX_DATA 65535 @@ -151,11 +152,11 @@ struct collection_iterator; * empty. * When you put items into a bag you do not see the contents of the bag. * You just hold the bag. How many other bags inside this bag you do not know. - * But you might know that you put a "valet" somewhere there. - * You ask the bag you hold: "find my valet and give it to me". - * get_item function will return you the item that is you "valet". + * But you might know that you put a "wallet" somewhere there. + * You ask the bag you hold: "find my wallet and give it to me". + * get_item function will return you the item that is your "wallet". * You can then change something or just get information about the item you - * retrieved. But in most cases you do not the valet itself. You want to get + * retrieved. But in most cases you do not the wallet itself. You want to get * something from the vallet or put something into it. IMO money would be an * obvious choice. To do this you use update_xxx_property functions. * There might be a bag somewhere deep and you might want to add something to @@ -163,13 +164,13 @@ struct collection_iterator; * want the item to be added to. If this sub collection argument is NULL top * level collection is assumed. * The search in the collections users a dotted notation to refer to an item (or - * property). You can search for "valet" and it will find any first instance of - * the "valet" in your luggage. But you might have two valets. One is yours and - * another is your significant other's. So you might say find "my.valet". - * It will find valet in your bad (collection) named "my". This collection can + * property). You can search for "wallet" and it will find any first instance of + * the "wallet" in your luggage. But you might have two wallets. One is yours and + * another is your significant other's. So you might say find "my.wallet". + * It will find wallet in your bad (collection) named "my". This collection can * be many levels deep inside other collections. You do not need to know the * full path to get to it. But if you have the full path you can use the fill - * path like this "luggage.newbags.my.valet". + * path like this "luggage.newbags.my.wallet". * It is useful to be able to put bags into bags as well as get them out of each * other. When the collection is created the header keeps a reference count on * how many copies of the collection are known to the world. So one can put a @@ -181,14 +182,27 @@ struct collection_iterator; * use. */ -/* Function that creates an named collection */ +/* Function that creates a named collection */ int create_collection(struct collection_item **ci, const char *name, unsigned cclass); +/* Function that creates a named collection using a memory descriptor */ +/* FIXME - function is a placeholder. It is not implemented yet. + * will be added in future together with the definition of the + * descriptor structure. + * The purpose is to control the internal implementation of the collection + * a) Use hash table for faster searches if the collection is expected to be large. + * b) Define memory functions to use. + */ +/* +int create_collection_ex(struct collection_item **ci, const char *name, + unsigned cclass, struct cdescriptor *descrptor); +*/ + /* Function that destroys a collection */ void destroy_collection(struct collection_item *ci); -/* Family of functions that add properties to an event */ +/* Family of functions that add properties to a collection */ /* See details about subcollection argument above. */ /* Family includes the following convinience functions: */ /* Add a string property to collection. The length should include the @@ -397,7 +411,7 @@ const void *get_item_data(struct collection_item *ci); /* If you want to modify the item that you got as a result of iterating through collection * or by calling get_item(). If you want to rename item provide a new name in the property - * argument. If you want the data to remain unchanged use NULL as data parameter. + * argument. If you want the data to remain unchanged use 0 as length parameter. * If item is a reference or collection the call will return error. * Previous type and data of the item is destroyed. */ @@ -407,7 +421,14 @@ int modify_item(struct collection_item *item, void *data, int length); -/* Convenience functions that wrap modify_tem(). */ +/* Rename the item */ +int modify_item_property(struct collection_item *item, + const char *property); + +/* Convenience functions that wrap modify_item(). + * They always assign new value. + * To rename the property just use modify_item_property(); + */ int modify_str_item(struct collection_item *item, const char *property, char *string, @@ -499,9 +520,10 @@ int get_collection_class(struct collection_item *item, /* Collection */ /* Get collection count */ int get_collection_count(struct collection_item *item, /* Collection */ unsigned *count); /* Number of elements in - this collection. - Each subcollection is - counted as 1 element. + * this collection. + * Each subcollection is + * counted as 1 element. + * Header is also counted. */ /* Convenience function to check if the collection is of the specific class */ @@ -510,5 +532,339 @@ int is_of_class(struct collection_item *item, /* Collection */ unsigned cclass); /* Class of the collection */ +/* + * Series of collection functions that allow using collection as a stack or a FIFO + */ + + +/* Extract the item from the collection */ +/* The header will not be considered for extraction. */ +int extract_item(struct collection_item *ci, /* Top collection */ + const char *subcollection, /* Sub collection */ + int disposition, /* Which to extract */ + const char *refprop, /* Property to relate to */ + int index, /* Index of the property to extract. See notes. */ + int type, /* Type filter */ + struct collection_item **ret_ref); /* Returns the reference back */ + +/* Similar extraction function as above just considers only one level. */ +int extract_item_from_current(struct collection_item *ci, /* Top collection */ + int disposition, /* Which to extract */ + const char *refprop, /* Property to relate to */ + int index, /* Index of the property to extract. See notes. */ + int type, /* Type filter */ + struct collection_item **ret_ref); /* Returns the reference back */ + +/* Insert item to the collection */ +/* WARNING: Only use this function to insert items + * that were extracted using extract_item(). + * NEVER use it with items that were returned + * by get_item() or add_xxx_property_with_ref() or + * with insert_xxx_property_with_ref(). + * The fundamental difference is that when you extracted item + * using extract_item() it stops to be managed by a collection. + * With such item you can: + * a) Insert this item into another (or same) collection + * b) Get item information using get_item_xxx() functions. + * c) Destroy item using delete_item(). + * You are required to do either a) or c) with such item. + */ +int insert_item(struct collection_item *collection, /* Top collection */ + const char *subcollection, /* Sub collection */ + struct collection_item *item, /* Item to insert */ + int disposition, /* What should be the position of the item */ + const char *refprop, /* Property to relate to */ + int index, /* Index of the property to extract. See notes. */ + unsigned flags); /* Flags that control naming issues */ + +/* Insert the item into the top level collection (similar to the function above) + * but does not provide access to the sub collection. + */ +int insert_item_into_current(struct collection_item *collection, + struct collection_item *item, + int disposition, + const char *refprop, + int index, + unsigned flags); + + + +/* Function to delete the item */ +void delete_item(struct collection_item *item); + +/* Possible dispositions for insert, extract and delete function(s). + * Not all of these dispositions are implemented day one. + * If disposition is not implemented the function + * will return error ENOSYS. + */ +#define COL_DSP_END 0 /* Add property to the end of the collection */ + /* Extract or delete last property in collection */ +#define COL_DSP_FRONT 1 /* Add property to the top of the collection */ + /* Extract or delete firat property in collection */ +#define COL_DSP_BEFORE 2 /* Add property before other named property */ + /* Extract or delete property that is before given + * property. If the given property is first + * in the list ENOENT is returned. + */ +#define COL_DSP_AFTER 3 /* Add property immediately after other named property */ + /* Delete or extract property immediately after given + * property. If the given property is last in the list + * ENOENT is returned. + */ +#define COL_DSP_INDEX 4 /* Add, extract or delete property using index. + * See notes below. + */ +/* NOTE ABOUT USING: COL_DSP_INDEX. */ +/* The COL_DSP_INDEX adds the item as N-th item after header in the list. + * Index is zero based. + * If there are less than N items in the list the item is added to the end. + * The index value of 0 means that the item will be added immediately + * after the header. Index of 1 will mean that it is added after first data item and so on. + * + * In case of extraction or deletion the N-th item of the collection + * will be extracted or deleted. + * Index is zero based. + * If there are less than N+1 items in the list the function will return ENOENT. + */ + +/* The following three dispositions operate only with list of duplicate + * properties that are going one after another. + * In case of addition the property name is taken from the item + * and the value refprop is ignored. + * In case of extraction or deletion the property name is taken + * from the refprop. + */ +#define COL_DSP_FIRSTDUP 5 /* Add property as a first dup of the given property */ + /* In case of extraction or deletion extracts or deletes + * given property. + */ +#define COL_DSP_LASTDUP 6 /* Add property as a last dup of the given property */ + /* In case of extraction or deletion extracts or deletes + * last duplicate property in the uninterrupted sequence of + * properties with the same name. + */ +#define COL_DSP_NDUP 7 /* Add property as a N-th dup (0- based) of the given property. */ + /* In case of extraction or deletion extracts or deletes + * N-th (0-based) duplicate of the given property. + * If index is greater than number of duplicate + * properties in sequence ENOENT is returned. + * See more details below. + */ + +/* Other dispositions might be possible in future. */ + +/* The COL_DSP_NDUP is used in case of the multi value property + * to add a new property with the same name into specific place + * in the list of properties with the same name. + * The index of 0 will mean to add the property before the first instance of the property with the same name. + * If the property does not exist ENOENT will be returned. + * If the index is greater than the last property with the same name the item will be added + * immediately after last property with the same name. + */ + +/* Flags that can be used with insert functions */ +#define COL_INSERT_NOCHECK 0 /* This is the default mode - no dup checks on insert */ +#define COL_INSERT_DUPOVER 1 /* Check for dup name and overwrite - position ignored */ +#define COL_INSERT_DUPOVERT 2 /* Check for dup name and type and overwrite - position ignored */ +#define COL_INSERT_DUPERROR 3 /* Return error EEXIST if the entry with the same name exists */ +#define COL_INSERT_DUPERRORT 4 /* Return error EEXIST if the entry with the same name and type exists */ +#define COL_INSERT_DUPMOVE 5 /* Check for dups, overwrite, extracts and + * then move to the position requested */ +#define COL_INSERT_DUPMOVET 6 /* Check for dup name and type, overwrite, extracts + * and then move to the position requested */ + +/* In future can be made more complex */ + +/* NOTE ABOUT FLAGS: Use of the DUP checking flags is costly since it requires a forward look up of the whole + * collection before the item is inserted. Do not use it until it is absolutely necessary. + */ + + + +/* The attributes in the collection are always added to the end. + * The family of the insert_xxx(functions) provides + * much more flexibility than add_xxx_property_xxx() functions. + */ + +/* Insert property with reference */ +int insert_property_with_ref(struct collection_item *ci, /* A collection of items */ + const char *subcollection, /* Sub collection */ + int disposition, /* Where to insert */ + const char *refprop, /* Property to relate to */ + int index, /* Index of the property to add */ + unsigned flags, /* Flags that control naming issues */ + const char *property, /* Name */ + int type, /* Data type */ + void *data, /* Pointer to the data */ + int length, /* Length of the data. For + * strings it includes the + * trailing 0 + */ + struct collection_item **ret_ref); /* Returns the reference back */ + + +int insert_str_property(struct collection_item *ci, /* A collection of items */ + const char *subcollection, /* Sub collection */ + int disposition, /* Where to insert */ + const char *refprop, /* Property to relate to */ + int index, /* Index of the property to add */ + unsigned flags, /* Flags that control naming issues */ + const char *property, /* Name */ + char *string, /* String */ + int length); /* Length */ + +int insert_binary_property(struct collection_item *ci, /* A collection of items */ + const char *subcollection, /* Sub collection */ + int disposition, /* Where to insert */ + const char *refprop, /* Property to relate to */ + int index, /* Index of the property to add */ + unsigned flags, /* Flags that control naming issues */ + const char *property, /* Name */ + void *binary_data, /* Binary data */ + int length); /* Length */ + + +int insert_int_property(struct collection_item *ci, /* A collection of items */ + const char *subcollection, /* Sub collection */ + int disposition, /* Where to insert */ + const char *refprop, /* Property to relate to */ + int index, /* Index of the property to add */ + unsigned flags, /* Flags that control naming issues */ + const char *property, /* Name */ + int number); /* Integer */ + + +int insert_unsinged_property(struct collection_item *ci, /* A collection of items */ + const char *subcollection, /* Sub collection */ + int disposition, /* Where to insert */ + const char *refprop, /* Property to relate to */ + int index, /* Index of the property to add */ + unsigned flags, /* Flags that control naming issues */ + const char *property, /* Name */ + unsigned number); /* Unsigned */ + + +int insert_long_property(struct collection_item *ci, /* A collection of items */ + const char *subcollection, /* Sub collection */ + int disposition, /* Where to insert */ + const char *refprop, /* Property to relate to */ + int index, /* Index of the property to add */ + unsigned flags, /* Flags that control naming issues */ + const char *property, /* Name */ + long number); /* Long */ + +int insert_ulong_property(struct collection_item *ci, /* A collection of items */ + const char *subcollection, /* Sub collection */ + int disposition, /* Where to insert */ + const char *refprop, /* Property to relate to */ + int index, /* Index of the property to add */ + unsigned flags, /* Flags that control naming issues */ + const char *property, /* Name */ + unsigned long number); /* Unsigned long */ + +int insert_double_property(struct collection_item *ci, /* A collection of items */ + const char *subcollection, /* Sub collection */ + int disposition, /* Where to insert */ + const char *refprop, /* Property to relate to */ + int index, /* Index of the property to add */ + unsigned flags, /* Flags that control naming issues */ + const char *property, /* Name */ + double number); /* Double */ + +int insert_bool_property(struct collection_item *ci, /* A collection of items */ + const char *subcollection, /* Sub collection */ + int disposition, /* Where to insert */ + const char *refprop, /* Property to relate to */ + int index, /* Index of the property to add */ + unsigned flags, /* Flags that control naming issues */ + const char *property, /* Name */ + unsigned char logical); /* Bool */ + + + +int insert_str_property_with_ref(struct collection_item *ci, /* A collection of items */ + const char *subcollection, /* Sub collection */ + int disposition, /* Where to insert */ + const char *refprop, /* Property to relate to */ + int index, /* Index of the property to add */ + unsigned flags, /* Flags that control naming issues */ + const char *property, /* Name */ + char *string, /* String */ + int length, /* Length */ + struct collection_item **ret_ref); /* Returns the reference back */ + +int insert_binary_property_with_ref(struct collection_item *ci, /* A collection of items */ + const char *subcollection, /* Sub collection */ + int disposition, /* Where to insert */ + const char *refprop, /* Property to relate to */ + int index, /* Index of the property to add */ + unsigned flags, /* Flags that control naming issues */ + const char *property, /* Name */ + void *binary_data, /* Binary data */ + int length, /* Length */ + struct collection_item **ret_ref); /* Returns the reference back */ + + +int insert_int_property_with_ref(struct collection_item *ci, /* A collection of items */ + const char *subcollection, /* Sub collection */ + int disposition, /* Where to insert */ + const char *refprop, /* Property to relate to */ + int index, /* Index of the property to add */ + unsigned flags, /* Flags that control naming issues */ + const char *property, /* Name */ + int number, /* Integer */ + struct collection_item **ret_ref); /* Returns the reference back */ + + +int insert_unsinged_property_with_ref(struct collection_item *ci, /* A collection of items */ + const char *subcollection, /* Sub collection */ + int disposition, /* Where to insert */ + const char *refprop, /* Property to relate to */ + int index, /* Index of the property to add */ + unsigned flags, /* Flags that control naming issues */ + const char *property, /* Name */ + unsigned number, /* Unsigned */ + struct collection_item **ret_ref); /* Returns the reference back */ + +int insert_long_property_with_ref(struct collection_item *ci, /* A collection of items */ + const char *subcollection, /* Sub collection */ + int disposition, /* Where to insert */ + const char *refprop, /* Property to relate to */ + int index, /* Index of the property to add */ + unsigned flags, /* Flags that control naming issues */ + const char *property, /* Name */ + long number, /* Long */ + struct collection_item **ret_ref); /* Returns the reference back */ + +int insert_ulong_property_with_ref(struct collection_item *ci, /* A collection of items */ + const char *subcollection, /* Sub collection */ + int disposition, /* Where to insert */ + const char *refprop, /* Property to relate to */ + int index, /* Index of the property to add */ + unsigned flags, /* Flags that control naming issues */ + const char *property, /* Name */ + unsigned long number, /* Unsigned long */ + struct collection_item **ret_ref); /* Returns the reference back */ + +int insert_double_property_with_ref(struct collection_item *ci, /* A collection of items */ + const char *subcollection, /* Sub collection */ + int disposition, /* Where to insert */ + const char *refprop, /* Property to relate to */ + int index, /* Index of the property to add */ + unsigned flags, /* Flags that control naming issues */ + const char *property, /* Name */ + double number, /* Double */ + struct collection_item **ret_ref); /* Returns the reference back */ + +int insert_bool_property_with_ref(struct collection_item *ci, /* A collection of items */ + const char *subcollection, /* Sub collection */ + int disposition, /* Where to insert */ + const char *refprop, /* Property to relate to */ + int index, /* Index of the property to add */ + unsigned flags, /* Flags that control naming issues */ + const char *property, /* Name */ + unsigned char logical, /* Bool */ + struct collection_item **ret_ref); /* Returns the reference back */ + #endif diff --git a/common/collection/collection_cnv.c b/common/collection/collection_cnv.c new file mode 100644 index 00000000..ca9c483e --- /dev/null +++ b/common/collection/collection_cnv.c @@ -0,0 +1,1266 @@ +/* + COLLECTION LIBRARY + + Convenience wrapper functions are implemented here. + They take a lot of space but pretty simple so they + are separated from the core logic. + + Copyright (C) Dmitri Pal <dpal@redhat.com> 2009 + + Collection Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Collection Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Collection Library. If not, see <http://www.gnu.org/licenses/>. +*/ + +#define _GNU_SOURCE +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <ctype.h> +#include <time.h> +#include "trace.h" + +/* The collection should use the teal structures */ +#include "collection_priv.h" +#include "collection.h" + +/* PROPERTIES */ +/* Insert string property with positioning */ +int insert_str_property(struct collection_item *ci, + const char *subcollection, + int disposition, + const char *refprop, + int index, + unsigned flags, + const char *property, + char *string, + int length) +{ + int error = EOK; + + TRACE_FLOW_STRING("insert_string_property", "Entry."); + + if (length == 0) length = strlen(string) + 1; + + error = insert_property_with_ref(ci, + subcollection, + disposition, + refprop, + index, + flags, + property, + COL_TYPE_STRING, + (void *)string, + length, + NULL); + + TRACE_FLOW_NUMBER("insert_string_property returning", error); + return error; +} + +/* Insert binary property with positioning */ +int insert_binary_property(struct collection_item *ci, + const char *subcollection, + int disposition, + const char *refprop, + int index, + unsigned flags, + const char *property, + void *binary_data, + int length) +{ + int error = EOK; + + TRACE_FLOW_STRING("insert_binary_property", "Entry."); + + error = insert_property_with_ref(ci, + subcollection, + disposition, + refprop, + index, + flags, + property, + COL_TYPE_BINARY, + binary_data, + length, + NULL); + + TRACE_FLOW_NUMBER("insert_binary_property returning", error); + return error; +} + + +/* Insert integer property with positioning */ +int insert_int_property(struct collection_item *ci, + const char *subcollection, + int disposition, + const char *refprop, + int index, + unsigned flags, + const char *property, + int number) +{ + int error = EOK; + + TRACE_FLOW_STRING("insert_int_property", "Entry."); + + error = insert_property_with_ref(ci, + subcollection, + disposition, + refprop, + index, + flags, + property, + COL_TYPE_INTEGER, + (void *)&number, + sizeof(int), + NULL); + + TRACE_FLOW_NUMBER("insert_int_property returning", error); + return error; +} + + +/* Insert unsigned property with positioning */ +int insert_unsigned_property(struct collection_item *ci, + const char *subcollection, + int disposition, + const char *refprop, + int index, + unsigned flags, + const char *property, + unsigned number) +{ + int error = EOK; + + TRACE_FLOW_STRING("insert_unsigned_property", "Entry."); + + error = insert_property_with_ref(ci, + subcollection, + disposition, + refprop, + index, + flags, + property, + COL_TYPE_LONG, + (void *)&number, + sizeof(unsigned), + NULL); + + TRACE_FLOW_NUMBER("insert_unsigned_property returning", error); + return error; +} + + +/* Insert long property with positioning */ +int insert_long_property(struct collection_item *ci, + const char *subcollection, + int disposition, + const char *refprop, + int index, + unsigned flags, + const char *property, + long number) +{ + int error = EOK; + + TRACE_FLOW_STRING("insert_long_property", "Entry."); + + error = insert_property_with_ref(ci, + subcollection, + disposition, + refprop, + index, + flags, + property, + COL_TYPE_LONG, + (void *)&number, + sizeof(long), + NULL); + + TRACE_FLOW_NUMBER("insert_long_property returning", error); + return error; +} + +/* Insert unsigned long property with positioning */ +int insert_ulong_property(struct collection_item *ci, + const char *subcollection, + int disposition, + const char *refprop, + int index, + unsigned flags, + const char *property, + unsigned long number) +{ + int error = EOK; + + TRACE_FLOW_STRING("insert_ulong_property", "Entry."); + + error = insert_property_with_ref(ci, + subcollection, + disposition, + refprop, + index, + flags, + property, + COL_TYPE_ULONG, + (void *)&number, + sizeof(unsigned long), + NULL); + + TRACE_FLOW_NUMBER("insert_ulong_property returning", error); + return error; +} + +/* Insert double property with positioning */ +int insert_double_property(struct collection_item *ci, + const char *subcollection, + int disposition, + const char *refprop, + int index, + unsigned flags, + const char *property, + double number) +{ + int error = EOK; + + TRACE_FLOW_STRING("insert_double_property", "Entry."); + + error = insert_property_with_ref(ci, + subcollection, + disposition, + refprop, + index, + flags, + property, + COL_TYPE_DOUBLE, + (void *)&number, + sizeof(double), + NULL); + + TRACE_FLOW_NUMBER("insert_double_property returning", error); + return error; +} + +/* Insert bool property with positioning */ +int insert_bool_property(struct collection_item *ci, + const char *subcollection, + int disposition, + const char *refprop, + int index, + unsigned flags, + const char *property, + unsigned char logical) +{ + int error = EOK; + + TRACE_FLOW_STRING("insert_bool_property", "Entry."); + + error = insert_property_with_ref(ci, + subcollection, + disposition, + refprop, + index, + flags, + property, + COL_TYPE_BOOL, + (void *)&logical, + sizeof(unsigned char), + NULL); + + TRACE_FLOW_NUMBER("insert_bool_property returning", error); + return error; +} + + +/* Insert string property with positioning and reference. */ +int insert_str_property_with_ref(struct collection_item *ci, + const char *subcollection, + int disposition, + const char *refprop, + int index, + unsigned flags, + const char *property, + char *string, + int length, + struct collection_item **ret_ref) +{ + int error = EOK; + + TRACE_FLOW_STRING("insert_string_property_with_ref", "Entry."); + + if (length == 0) length = strlen(string) + 1; + + error = insert_property_with_ref(ci, + subcollection, + disposition, + refprop, + index, + flags, + property, + COL_TYPE_STRING, + (void *)string, + length, + ret_ref); + + TRACE_FLOW_NUMBER("insert_string_property_with_ref returning", error); + return error; +} + +/* Insert binary property with positioning and reference. */ +int insert_binary_property_with_ref(struct collection_item *ci, + const char *subcollection, + int disposition, + const char *refprop, + int index, + unsigned flags, + const char *property, + void *binary_data, + int length, + struct collection_item **ret_ref) +{ + int error = EOK; + + TRACE_FLOW_STRING("insert_binary_property_with_ref", "Entry."); + + error = insert_property_with_ref(ci, + subcollection, + disposition, + refprop, + index, + flags, + property, + COL_TYPE_BINARY, + (void *)binary_data, + length, + ret_ref); + + TRACE_FLOW_NUMBER("insert_binary_property_with_ref returning", error); + return error; +} + +/* Insert int property with positioning and reference. */ +int insert_int_property_with_ref(struct collection_item *ci, + const char *subcollection, + int disposition, + const char *refprop, + int index, + unsigned flags, + const char *property, + int number, + struct collection_item **ret_ref) +{ + int error = EOK; + + TRACE_FLOW_STRING("insert_int_property_with_ref", "Entry."); + + error = insert_property_with_ref(ci, + subcollection, + disposition, + refprop, + index, + flags, + property, + COL_TYPE_INTEGER, + (void *)&number, + sizeof(int), + ret_ref); + + TRACE_FLOW_NUMBER("insert_int_property_with_ref returning", error); + return error; +} + + +/* Insert unsigned property with positioning and reference. */ +int insert_unsigned_property_with_ref(struct collection_item *ci, + const char *subcollection, + int disposition, + const char *refprop, + int index, + unsigned flags, + const char *property, + unsigned number, + struct collection_item **ret_ref) +{ + int error = EOK; + + TRACE_FLOW_STRING("insert_unsigned_property_with_ref", "Entry."); + + error = insert_property_with_ref(ci, + subcollection, + disposition, + refprop, + index, + flags, + property, + COL_TYPE_UNSIGNED, + (void *)&number, + sizeof(unsigned), + ret_ref); + + TRACE_FLOW_NUMBER("insert_unsigned_property_with_ref returning", error); + return error; +} + +/* Insert long property with positioning and reference. */ +int insert_long_property_with_ref(struct collection_item *ci, + const char *subcollection, + int disposition, + const char *refprop, + int index, + unsigned flags, + const char *property, + long number, + struct collection_item **ret_ref) +{ + int error = EOK; + + TRACE_FLOW_STRING("insert_long_property_with_ref", "Entry."); + + error = insert_property_with_ref(ci, + subcollection, + disposition, + refprop, + index, + flags, + property, + COL_TYPE_LONG, + (void *)&number, + sizeof(long), + ret_ref); + + TRACE_FLOW_NUMBER("insert_long_property_with_ref returning", error); + return error; +} + +/* Insert unsigned long property with positioning and reference. */ +int insert_ulong_property_with_ref(struct collection_item *ci, + const char *subcollection, + int disposition, + const char *refprop, + int index, + unsigned flags, + const char *property, + unsigned long number, + struct collection_item **ret_ref) +{ + int error = EOK; + + TRACE_FLOW_STRING("insert_ulong_property_with_ref", "Entry."); + + error = insert_property_with_ref(ci, + subcollection, + disposition, + refprop, + index, + flags, + property, + COL_TYPE_ULONG, + (void *)&number, + sizeof(unsigned long), + ret_ref); + + TRACE_FLOW_NUMBER("insert_ulong_property_with_ref returning", error); + return error; +} + +/* Insert double property with positioning and reference. */ +int insert_double_property_with_ref(struct collection_item *ci, + const char *subcollection, + int disposition, + const char *refprop, + int index, + unsigned flags, + const char *property, + double number, + struct collection_item **ret_ref) +{ + int error = EOK; + + TRACE_FLOW_STRING("insert_double_property_with_ref", "Entry."); + + error = insert_property_with_ref(ci, + subcollection, + disposition, + refprop, + index, + flags, + property, + COL_TYPE_DOUBLE, + (void *)&number, + sizeof(double), + ret_ref); + + TRACE_FLOW_NUMBER("insert_double_property_with_ref returning", error); + return error; +} + +/* Insert bool property with positioning and reference. */ +int insert_bool_property_with_ref(struct collection_item *ci, + const char *subcollection, + int disposition, + const char *refprop, + int index, + unsigned flags, + const char *property, + unsigned char logical, + struct collection_item **ret_ref) +{ + int error = EOK; + + TRACE_FLOW_STRING("insert_bool_property_with_ref", "Entry."); + + error = insert_property_with_ref(ci, + subcollection, + disposition, + refprop, + index, + flags, + property, + COL_TYPE_BOOL, + (void *)&logical, + sizeof(unsigned char), + ret_ref); + + TRACE_FLOW_NUMBER("insert_bool_property_with_ref returning", error); + return error; +} + + +/* Add a string property. */ +int add_str_property(struct collection_item *ci, + const char *subcollection, + const char *property, + char *string, + int length) +{ + int error = EOK; + + TRACE_FLOW_STRING("add_str_property", "Entry."); + + error = insert_str_property(ci, + subcollection, + COL_DSP_END, + NULL, + 0, + 0, + property, + string, + length); + + TRACE_FLOW_NUMBER("add_str_property returning", error); + return error; +} + +/* Add a binary property. */ +int add_binary_property(struct collection_item *ci, + const char *subcollection, + const char *property, + void *binary_data, + int length) +{ + int error = EOK; + + TRACE_FLOW_STRING("add_binary_property", "Entry."); + + error = insert_binary_property(ci, + subcollection, + COL_DSP_END, + NULL, + 0, + 0, + property, + binary_data, + length); + + TRACE_FLOW_NUMBER("add_binary_property returning", error); + return error; +} + +/* Add an int property. */ +int add_int_property(struct collection_item *ci, + const char *subcollection, + const char *property, + int number) +{ + int error = EOK; + + TRACE_FLOW_STRING("add_int_property", "Entry."); + + error = insert_int_property(ci, + subcollection, + COL_DSP_END, + NULL, + 0, + 0, + property, + number); + + TRACE_FLOW_NUMBER("add_int_property returning", error); + return error; +} + +/* Add an unsigned int property. */ +int add_unsigned_property(struct collection_item *ci, + const char *subcollection, + const char *property, + unsigned int number) +{ + int error = EOK; + + TRACE_FLOW_STRING("add_unsigned_property", "Entry."); + + error = insert_unsigned_property(ci, + subcollection, + COL_DSP_END, + NULL, + 0, + 0, + property, + number); + + TRACE_FLOW_NUMBER("add_unsigned_property returning", error); + return error; +} + +/* Add an long property. */ +int add_long_property(struct collection_item *ci, + const char *subcollection, + const char *property, + long number) +{ + int error = EOK; + + TRACE_FLOW_STRING("add_long_property", "Entry."); + + + error = insert_long_property(ci, + subcollection, + COL_DSP_END, + NULL, + 0, + 0, + property, + number); + + TRACE_FLOW_NUMBER("add_long_property returning", error); + return error; +} + +/* Add an unsigned long property. */ +int add_ulong_property(struct collection_item *ci, + const char *subcollection, + const char *property, + unsigned long number) +{ + int error = EOK; + + TRACE_FLOW_STRING("add_ulong_property", "Entry."); + + error = insert_ulong_property(ci, + subcollection, + COL_DSP_END, + NULL, + 0, + 0, + property, + number); + + TRACE_FLOW_NUMBER("add_ulong_property returning", error); + return error; +} + +/* Add a double property. */ +int add_double_property(struct collection_item *ci, + const char *subcollection, + const char *property, + double number) +{ + int error = EOK; + + TRACE_FLOW_STRING("add_double_property", "Entry."); + + error = insert_double_property(ci, + subcollection, + COL_DSP_END, + NULL, + 0, + 0, + property, + number); + + TRACE_FLOW_NUMBER("add_double_property returning", error); + return error; +} + +/* Add a bool property. */ +int add_bool_property(struct collection_item *ci, + const char *subcollection, + const char *property, + unsigned char logical) +{ + int error = EOK; + + TRACE_FLOW_STRING("add_bool_property", "Entry."); + + error = insert_bool_property(ci, + subcollection, + COL_DSP_END, + NULL, + 0, + 0, + property, + logical); + + TRACE_FLOW_NUMBER("add_bool_property returning", error); + return error; +} + +/* A function to add a property */ +int add_any_property(struct collection_item *ci, + const char *subcollection, + const char *property, + int type, + void *data, + int length) +{ + int error = EOK; + + TRACE_FLOW_STRING("add_any_property", "Entry."); + + error = insert_property_with_ref(ci, + subcollection, + COL_DSP_END, + NULL, + 0, + 0, + property, + type, + data, + length, + NULL); + + TRACE_FLOW_NUMBER("add_any_property returning", error); + return error; +} + +/* Add a string property with reference */ +inline int add_str_property_with_ref(struct collection_item *ci, + const char *subcollection, + const char *property, + char *string, int length, + struct collection_item **ref_ret) +{ + int error = EOK; + + TRACE_FLOW_STRING("add_str_property_with_ref", "Entry."); + + error = insert_str_property_with_ref(ci, + subcollection, + COL_DSP_END, + NULL, + 0, + 0, + property, + string, + length, + ref_ret); + + TRACE_FLOW_NUMBER("add_str_property_with_ref returning", error); + return error; +} + +/* Add a binary property with reference. */ +int add_binary_property_with_ref(struct collection_item *ci, + const char *subcollection, + const char *property, + void *binary_data, int length, + struct collection_item **ref_ret) +{ + int error = EOK; + + TRACE_FLOW_STRING("add_binary_property_with_ref", "Entry."); + + error = insert_binary_property_with_ref(ci, + subcollection, + COL_DSP_END, + NULL, + 0, + 0, + property, + binary_data, + length, + ref_ret); + + TRACE_FLOW_NUMBER("add_binary_property_with_ref returning", error); + return error; +} + +/* Add an int property with reference. */ +int add_int_property_with_ref(struct collection_item *ci, + const char *subcollection, + const char *property, + int number, + struct collection_item **ref_ret) +{ + int error = EOK; + + TRACE_FLOW_STRING("add_int_property_with_ref", "Entry."); + + error = insert_int_property_with_ref(ci, + subcollection, + COL_DSP_END, + NULL, + 0, + 0, + property, + number, + ref_ret); + + TRACE_FLOW_NUMBER("add_int_property_with_ref returning", error); + return error; +} + +/* Add an unsigned int property with reference. */ +int add_unsigned_property_with_ref(struct collection_item *ci, + const char *subcollection, + const char *property, + unsigned int number, + struct collection_item **ref_ret) +{ + int error = EOK; + + TRACE_FLOW_STRING("add_unsigned_property_with_ref", "Entry."); + + error = insert_unsigned_property_with_ref(ci, + subcollection, + COL_DSP_END, + NULL, + 0, + 0, + property, + number, + ref_ret); + + TRACE_FLOW_NUMBER("add_unsigned_property_with_ref returning", error); + return error; +} + +/* Add an long property with reference. */ +int add_long_property_with_ref(struct collection_item *ci, + const char *subcollection, + const char *property, + long number, + struct collection_item **ref_ret) +{ + int error = EOK; + + TRACE_FLOW_STRING("add_long_property_with_ref", "Entry."); + + error = insert_long_property_with_ref(ci, + subcollection, + COL_DSP_END, + NULL, + 0, + 0, + property, + number, + ref_ret); + + TRACE_FLOW_NUMBER("add_long_property_with_ref returning", error); + return error; +} + +/* Add an unsigned long property with reference. */ +int add_ulong_property_with_ref(struct collection_item *ci, + const char *subcollection, + const char *property, + unsigned long number, + struct collection_item **ref_ret) +{ + int error = EOK; + + TRACE_FLOW_STRING("add_ulong_property_with_ref", "Entry."); + + error = insert_ulong_property_with_ref(ci, + subcollection, + COL_DSP_END, + NULL, + 0, + 0, + property, + number, + ref_ret); + + TRACE_FLOW_NUMBER("add_ulong_property_with_ref returning", error); + return error; +} + +/* Add a double property with reference. */ +int add_double_property_with_ref(struct collection_item *ci, + const char *subcollection, + const char *property, + double number, + struct collection_item **ref_ret) +{ + int error = EOK; + + TRACE_FLOW_STRING("add_double_property_with_ref", "Entry."); + + error = insert_double_property_with_ref(ci, + subcollection, + COL_DSP_END, + NULL, + 0, + 0, + property, + number, + ref_ret); + + TRACE_FLOW_NUMBER("add_double_property_with_ref returning", error); + return error; +} + +/* Add a bool property with reference. */ +int add_bool_property_with_ref(struct collection_item *ci, + const char *subcollection, + const char *property, + unsigned char logical, + struct collection_item **ref_ret) +{ + int error = EOK; + + TRACE_FLOW_STRING("add_bool_property_with_ref", "Entry."); + + error = insert_bool_property_with_ref(ci, + subcollection, + COL_DSP_END, + NULL, + 0, + 0, + property, + logical, + ref_ret); + + TRACE_FLOW_NUMBER("add_bool_property_with_ref returning", error); + return error; +} + +/* A function to add a property with reference. */ +int add_any_property_with_ref(struct collection_item *ci, + const char *subcollection, + const char *property, + int type, + void *data, + int length, + struct collection_item **ref_ret) +{ + int error = EOK; + + TRACE_FLOW_STRING("add_any_property_with_ref", "Entry."); + + error = insert_property_with_ref(ci, + subcollection, + COL_DSP_END, + NULL, + 0, + 0, + property, + type, + data, + length, + ref_ret); + + TRACE_FLOW_NUMBER("add_any_property_with_ref returning", error); + return error; +} + + +/* Update a string property in the collection. + * Length should include the terminating 0 */ +int update_str_property(struct collection_item *ci, + const char *property, + int mode_flags, + char *string, + int length) +{ + int error = EOK; + TRACE_FLOW_STRING("update_str_property", "Entry."); + + if (length == 0) length = strlen(string) + 1; + error = update_property(ci, property, COL_TYPE_STRING, + (void *)string, length, mode_flags); + + TRACE_FLOW_NUMBER("update_str_property Returning", error); + return error; +} + +/* Update a binary property in the collection. */ +int update_binary_property(struct collection_item *ci, + const char *property, + int mode_flags, + void *binary_data, + int length) +{ + int error = EOK; + TRACE_FLOW_STRING("update_binary_property", "Entry."); + + error = update_property(ci, property, COL_TYPE_BINARY, + binary_data, length, mode_flags); + + TRACE_FLOW_NUMBER("update_binary_property Returning", error); + return error; +} + +/* Update an int property in the collection. */ +int update_int_property(struct collection_item *ci, + const char *property, + int mode_flags, + int number) +{ + int error = EOK; + TRACE_FLOW_STRING("update_int_property", "Entry."); + + error = update_property(ci, property, COL_TYPE_INTEGER, + (void *)(&number), sizeof(int), mode_flags); + + TRACE_FLOW_NUMBER("update_int_property Returning", error); + return error; +} + +/* Update an unsigned int property. */ +int update_unsigned_property(struct collection_item *ci, + const char *property, + int mode_flags, + unsigned int number) +{ + int error = EOK; + TRACE_FLOW_STRING("update_unsigned_property", "Entry."); + + error = update_property(ci, property, COL_TYPE_UNSIGNED, + (void *)(&number), sizeof(unsigned int), + mode_flags); + + TRACE_FLOW_NUMBER("update_unsigned_property Returning", error); + return error; +} + +/* Update a long property. */ +int update_long_property(struct collection_item *ci, + const char *property, + int mode_flags, + long number) +{ + int error = EOK; + TRACE_FLOW_STRING("update_long_property", "Entry."); + + error = update_property(ci, property, COL_TYPE_LONG, + (void *)(&number), sizeof(long), mode_flags); + + TRACE_FLOW_NUMBER("update_long_property Returning", error); + return error; + +} + +/* Update an unsigned long property. */ +int update_ulong_property(struct collection_item *ci, + const char *property, + int mode_flags, + unsigned long number) +{ + int error = EOK; + TRACE_FLOW_STRING("update_ulong_property", "Entry."); + + error = update_property(ci, property, COL_TYPE_ULONG, + (void *)(&number), sizeof(unsigned long), + mode_flags); + + TRACE_FLOW_NUMBER("update_ulong_property Returning", error); + return error; +} + +/* Update a double property. */ +int update_double_property(struct collection_item *ci, + const char *property, + int mode_flags, + double number) +{ + int error = EOK; + TRACE_FLOW_STRING("update_double_property", "Entry."); + + error = update_property(ci, property, COL_TYPE_DOUBLE, + (void *)(&number), sizeof(double), mode_flags); + + TRACE_FLOW_NUMBER("update_double_property Returning", error); + return error; +} + +/* Update a bool property. */ +int update_bool_property(struct collection_item *ci, + const char *property, + int mode_flags, + unsigned char logical) +{ + int error = EOK; + TRACE_FLOW_STRING("update_bool_property", "Entry."); + + error = update_property(ci, property, COL_TYPE_BOOL, + (void *)(&logical), sizeof(unsigned char), + mode_flags); + + TRACE_FLOW_NUMBER("update_bool_property Returning", error); + return error; +} + +/* Rename item */ +int modify_item_property(struct collection_item *item, + const char *property) +{ + int error; + + TRACE_FLOW_STRING("modify_item_property", "Entry"); + + error = modify_item(item, property, 0, NULL, 0); + + TRACE_FLOW_STRING("modify_item_property", "Exit"); + return error; +} + +/* Convenience functions that wrap modify_item(). */ +/* Modify item data to be str */ +int modify_str_item(struct collection_item *item, + const char *property, + char *string, + int length) +{ + int len; + int error; + + TRACE_FLOW_STRING("modify_str_item", "Entry"); + + if (length != 0) len = length; + else len = strlen(string) + 1; + + error = modify_item(item, property, COL_TYPE_STRING, (void *)string, len); + + TRACE_FLOW_STRING("modify_str_item", "Exit"); + return error; +} + +/* Modify item data to be binary */ +int modify_binary_item(struct collection_item *item, + const char *property, + void *binary_data, + int length) +{ + int error; + + TRACE_FLOW_STRING("modify_binary_item", "Entry"); + + error = modify_item(item, property, COL_TYPE_BINARY, binary_data, length); + + TRACE_FLOW_STRING("modify_binary_item", "Exit"); + return error; +} + +/* Modify item data to be bool */ +int modify_bool_item(struct collection_item *item, + const char *property, + unsigned char logical) +{ + int error; + + TRACE_FLOW_STRING("modify_bool_item", "Entry"); + + error = modify_item(item, property, COL_TYPE_BOOL, (void *)(&logical), 1); + + TRACE_FLOW_STRING("modify_bool_item", "Exit"); + return error; +} + +/* Modify item data to be int */ +int modify_int_item(struct collection_item *item, + const char *property, + int number) +{ + int error; + + TRACE_FLOW_STRING("modify_int_item","Entry"); + + error = modify_item(item, property, COL_TYPE_INTEGER, + (void *)(&number), sizeof(int)); + + TRACE_FLOW_STRING("modify_int_item", "Exit"); + return error; +} + +/* Modify item data to be long */ +int modify_long_item(struct collection_item *item, + const char *property, + long number) +{ + int error; + + TRACE_FLOW_STRING("modify_long_item", "Entry"); + + error = modify_item(item, property, COL_TYPE_LONG, + (void *)(&number), sizeof(long)); + + TRACE_FLOW_STRING("modify_long_item", "Exit"); + return error; +} + +/* Modify item data to be unigned long */ +int modify_ulong_item(struct collection_item *item, + const char *property, + unsigned long number) +{ + int error; + + TRACE_FLOW_STRING("modify_ulong_item", "Entry"); + + error = modify_item(item, property, COL_TYPE_ULONG, + (void *)(&number), sizeof(unsigned long)); + + TRACE_FLOW_STRING("modify_ulong_item", "Exit"); + return error; +} + +int modify_unsigned_item(struct collection_item *item, + const char *property, + unsigned number) +{ + int error; + + TRACE_FLOW_STRING("modify_unsigned_item", "Entry"); + + error = modify_item(item, property, COL_TYPE_UNSIGNED, + (void *)(&number), sizeof(unsigned)); + + TRACE_FLOW_STRING("modify_unsigned_item", "Exit"); + return error; +} + +int modify_double_item(struct collection_item *item, + const char *property, + double number) +{ + int error; + + TRACE_FLOW_STRING("modify_double_item", "Entry"); + + error = modify_item(item, property, COL_TYPE_DOUBLE, + (void *)(&number), sizeof(double)); + + TRACE_FLOW_STRING("modify_double_item", "Exit"); + return error; +} diff --git a/common/collection/collection_priv.h b/common/collection/collection_priv.h index 38d9012a..18688f9d 100644 --- a/common/collection/collection_priv.h +++ b/common/collection/collection_priv.h @@ -22,6 +22,8 @@ #ifndef COLLECTION_PRIV_H #define COLLECTION_PRIV_H +#include <stdint.h> + /* Define real strcutures */ /* Structure that holds one property. * This structure should never be assumed and used directly other than @@ -43,6 +45,7 @@ struct collection_item { int type; int length; void *data; + uint64_t phash; }; @@ -67,4 +70,3 @@ struct collection_header { }; #endif - diff --git a/common/collection/collection_ut.c b/common/collection/collection_ut.c index eabf5222..21f768be 100644 --- a/common/collection/collection_ut.c +++ b/common/collection/collection_ut.c @@ -31,8 +31,8 @@ int ref_collection_test() { - struct collection_item *peer; - struct collection_item *socket; + struct collection_item *peer = NULL; + struct collection_item *socket = NULL; char binary_dump[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 }; int error = EOK; @@ -46,7 +46,7 @@ int ref_collection_test() (error=add_str_property(peer,NULL,"hostname","peerhost.mytest.com",0)) || (error=add_str_property(peer,NULL,"IPv4","10.10.10.10",12)) || /* Expect trailing zero to be truncated */ (error=add_str_property(peer,NULL,"IPv6","bla:bla:bla:bla:bla:bla",0))) { - printf("Failed to add property. Error %d",error); + printf("Failed to add property. Error %d\n",error); destroy_collection(peer); return error; } @@ -109,7 +109,7 @@ int ref_collection_test() int single_collection_test() { - struct collection_item *handle; + struct collection_item *handle = NULL; int error = EOK; TRACE_FLOW_STRING("single_collection_test","Entry."); @@ -165,8 +165,8 @@ int single_collection_test() int add_collection_test() { - struct collection_item *peer; - struct collection_item *socket; + struct collection_item *peer = NULL; + struct collection_item *socket = NULL; char binary_dump[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 }; int error = EOK; @@ -692,6 +692,160 @@ int iterator_test() } +int insert_extract_test() +{ + struct collection_item *col; + struct collection_item *col2; + int error = EOK; + struct collection_item *item = (struct collection_item *)(NULL); + + printf("\n\n==== INSERTION TEST ====\n\n"); + + if ((error = create_collection(&col, "insertion", 0)) || + (error = insert_str_property(col, NULL, COL_DSP_END, + NULL, 0, COL_INSERT_NOCHECK, + "property1", "value1", 0)) || + (error = insert_str_property(col, NULL, COL_DSP_END, + NULL, 0, COL_INSERT_NOCHECK, + "property2", "value2", 0)) || + (error = insert_str_property(col, NULL, COL_DSP_FRONT, + NULL, 0, COL_INSERT_NOCHECK, + "property0", "value0", 0)) || + (error = insert_str_property(col, NULL, COL_DSP_BEFORE, + "property0", 0, COL_INSERT_NOCHECK, + "property_-1", "value_-1", 0)) || + (error = insert_str_property(col, NULL, COL_DSP_BEFORE, + "property1", 0, COL_INSERT_NOCHECK, + "property0_5", "value0_5", 0)) || + (error = insert_str_property(col, NULL, COL_DSP_BEFORE, + "property2", 0, COL_INSERT_NOCHECK, + "property1_5", "value1_5", 0)) || + (error = insert_str_property(col, NULL, COL_DSP_AFTER, + "property_-1", 0, COL_INSERT_NOCHECK, + "property_-0_5", "value_-0_5", 0)) || + (error = insert_str_property(col, NULL, COL_DSP_AFTER, + "property1_5", 0, COL_INSERT_NOCHECK, + "property1_6", "value1_6", 0)) || + (error = insert_str_property(col, NULL, COL_DSP_INDEX, + NULL, 10, COL_INSERT_NOCHECK, + "property10", "value10", 0)) || + (error = insert_str_property(col, NULL, COL_DSP_INDEX, + NULL, 0, COL_INSERT_NOCHECK, + "property_-2", "value_-2", 0)) || + (error = insert_str_property(col, NULL, COL_DSP_INDEX, + NULL, 1, COL_INSERT_NOCHECK, + "property_-1_5", "value_-1_5", 0)) || + (error = insert_str_property(col, NULL, COL_DSP_FIRSTDUP, + NULL, 0, COL_INSERT_NOCHECK, + "property0", "value0firstdup", 0)) || + (error = insert_str_property(col, NULL, COL_DSP_LASTDUP, + NULL, 0, COL_INSERT_NOCHECK, + "property0", "value0lastdup", 0)) || + (error = insert_str_property(col, NULL, COL_DSP_NDUP, + NULL, 1, COL_INSERT_NOCHECK, + "property0", "value0middledup", 0)) || + (error = insert_str_property(col, NULL, 0, + NULL, 0, COL_INSERT_DUPOVER , + "property0", "value0firstdupupdate", 0)) || + (error = insert_str_property(col, NULL, 0, + NULL, 0, COL_INSERT_DUPOVERT, + "property1", "value1update", 0)) || + ((error = insert_str_property(col, NULL, 0, + NULL, 0, COL_INSERT_DUPERROR, + "property0", "does not matter", 0)) != EEXIST) || + (error = insert_str_property(col, NULL, COL_DSP_NDUP, + NULL, 5, COL_INSERT_NOCHECK, + "property10", "value10dup", 0)) || + (error = insert_str_property(col, NULL, COL_DSP_LASTDUP, + NULL, 0, COL_INSERT_NOCHECK, + "property10", "value10lastdup", 0)) || + (error = insert_str_property(col, NULL, COL_DSP_END, + NULL, 0, COL_INSERT_DUPMOVET, + "property_-2", "value-2moved_to_bottom", 0)) || + (error = insert_str_property(col, NULL, COL_DSP_FRONT, + NULL, 0, COL_INSERT_DUPMOVE, + "property1_6", "value_1_6_moved_moved_to_front", 0))) { + + printf("ERROR in the ITERATION TEST\n"); + debug_collection(col,COL_TRAVERSE_DEFAULT); + destroy_collection(col); + return error; + } + + printf("\n\nCollection:\n\n"); + debug_collection(col,COL_TRAVERSE_DEFAULT); + + + printf("\n\n==== EXTRACTION TEST ====\n\n"); + + if ((error = create_collection(&col2, "extraction", 0)) || + (error = extract_item(col, NULL, COL_DSP_FRONT, + NULL, 0, 0, &item)) || + (error = insert_item(col2, NULL, item, COL_DSP_FRONT, + NULL, 0, COL_INSERT_NOCHECK)) || + (debug_collection(col2,COL_TRAVERSE_DEFAULT)) || + (error = extract_item(col, NULL, COL_DSP_END, + NULL, 0, 0, &item)) || + (error = insert_item(col2, NULL, item, COL_DSP_END, + NULL, 0, COL_INSERT_NOCHECK)) || + (debug_collection(col2,COL_TRAVERSE_DEFAULT)) || + (error = insert_str_property(col, NULL, COL_DSP_INDEX, + NULL, 100, COL_INSERT_NOCHECK, + "property100", "value100", 0)) || + (error = extract_item(col, NULL, COL_DSP_AFTER, + "property10", 0, COL_TYPE_STRING, &item)) || + (error = insert_item(col2, NULL, item, COL_DSP_END, + NULL, 0, COL_INSERT_NOCHECK)) || + (debug_collection(col2,COL_TRAVERSE_DEFAULT)) || + (error = extract_item(col, NULL, COL_DSP_BEFORE, + "property0", 0, COL_TYPE_STRING, &item)) || + (error = insert_item(col2, NULL, item, COL_DSP_END, + NULL, 0, COL_INSERT_NOCHECK)) || + (debug_collection(col2,COL_TRAVERSE_DEFAULT)) || + (error = extract_item(col, NULL, COL_DSP_INDEX, + NULL, 1, 0, &item)) || + (error = insert_item(col2, NULL, item, COL_DSP_END, + NULL, 0, COL_INSERT_NOCHECK)) || + (debug_collection(col2,COL_TRAVERSE_DEFAULT)) || + (error = extract_item(col, NULL, COL_DSP_NDUP, + "property0", 1, 0, &item)) || + (error = insert_item(col2, NULL, item, COL_DSP_END, + NULL, 0, COL_INSERT_NOCHECK)) || + (debug_collection(col2,COL_TRAVERSE_DEFAULT)) || + (error = extract_item(col, NULL, COL_DSP_LASTDUP, + "property0", 0, 0, &item)) || + (error = insert_item(col2, NULL, item, COL_DSP_END, + NULL, 0, COL_INSERT_NOCHECK)) || + (debug_collection(col2,COL_TRAVERSE_DEFAULT)) || + (error = extract_item(col, NULL, COL_DSP_FIRSTDUP, + "property0", 0, 0, &item)) || + (error = insert_item(col2, NULL, item, COL_DSP_END, + NULL, 0, COL_INSERT_NOCHECK)) || + (debug_collection(col2,COL_TRAVERSE_DEFAULT))) { + + printf("ERROR in the EXTRACTION TEST\n"); + printf("Collection 1\n"); + debug_collection(col,COL_TRAVERSE_DEFAULT); + printf("Collection 2\n"); + debug_collection(col2,COL_TRAVERSE_DEFAULT); + destroy_collection(col); + destroy_collection(col2); + return error; + } + + printf("Collection 1\n"); + debug_collection(col,COL_TRAVERSE_DEFAULT); + printf("Collection 2\n"); + debug_collection(col2,COL_TRAVERSE_DEFAULT); + + destroy_collection(col2); + destroy_collection(col); + + + return EOK; +} + + /* Main function of the unit test */ int main() @@ -703,7 +857,8 @@ int main() (error=single_collection_test()) || (error=add_collection_test()) || (error=mixed_collection_test()) || - (error=iterator_test())) { + (error=iterator_test()) || + (error=insert_extract_test())) { printf("Failed!\n"); } else printf("Success!\n"); diff --git a/common/collection/configure.ac b/common/collection/configure.ac index da34da0a..504cd4d5 100644 --- a/common/collection/configure.ac +++ b/common/collection/configure.ac @@ -19,5 +19,8 @@ AC_ARG_ENABLE([trace], [trace_level="0"]) AS_IF([test ["$trace_level" -gt "0"] -a ["$trace_level" -lt "8"] ],[AC_SUBST([TRACE_VAR],["-DTRACE_LEVEL=$trace_level"])]) +AC_CHECK_SIZEOF([long]) +AC_CHECK_SIZEOF([long long]) + AC_CONFIG_FILES([Makefile collection.pc]) AC_OUTPUT |