diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index 30338f1..eb7e0af 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -1820,6 +1820,78 @@ void iso_node_unref(IsoNode *node); */ enum IsoNodeType iso_node_get_type(IsoNode *node); +/** + * Function to handle particular extended information. The function + * pointer acts as an identifier for the type of the information. Structs + * with same information type must use the same function. + * + * @param data + * Attached data + * @param flag + * What to do with the data. At this time the following values are + * defined: + * -> 1 the data must be freed + * @return + * 1 in any case. + * + * @since 0.6.4 + */ +typedef int (*iso_node_xinfo_func)(void *data, int flag); + +/** + * Add extended information to the given node. Extended info allows + * applications (and libisofs itself) to add more information to an IsoNode. + * You can use this facilities to associate new information with a given + * node. + * + * Each node keeps a list of added extended info, meaning you can add several + * extended info data to each node. Each extended info you add is identified + * by the proc parameter, a pointer to a function that knows how to manage + * the external info data. Thus, in order to add several types of extended + * info, you need to define a "proc" function for each type. + * + * @param node + * The node where to add the extended info + * @param proc + * A function pointer used to identify the type of the data, and that + * knows how to manage it + * @param data + * Extended info to add. + * @return + * 1 if success, 0 if the given node already has extended info of the + * type defined by the "proc" function, < 0 on error + * + * @since 0.6.4 + */ +int iso_node_add_xinfo(IsoNode *node, iso_node_xinfo_func proc, void *data); + +/** + * Remove the given extended info (defined by the proc function) from the + * given node. + * + * @return + * 1 on success, 0 if node does not have extended info of the requested + * type, < 0 on error + * + * @since 0.6.4 + */ +int iso_node_remove_xinfo(IsoNode *node, iso_node_xinfo_func proc); + +/** + * Get the given extended info (defined by the proc function) from the + * given node. + * + * @param data + * Will be filled with the extended info corresponding to the given proc + * function + * @return + * 1 on success, 0 if node does not have extended info of the requested + * type, < 0 on error + * + * @since 0.6.4 + */ +int iso_node_get_xinfo(IsoNode *node, iso_node_xinfo_func proc, void **data); + /** * Set the name of a node. Note that if the node is already added to a dir * this can fail if dir already contains a node with the new name. diff --git a/libisofs/node.c b/libisofs/node.c index 95a0095..6442473 100644 --- a/libisofs/node.c +++ b/libisofs/node.c @@ -69,19 +69,144 @@ void iso_node_unref(IsoNode *node) /* other kind of nodes does not need to delete anything here */ break; } - -#ifdef LIBISO_EXTENDED_INFORMATION + if (node->xinfo) { - /* free extended info */ - node->xinfo->process(node->xinfo->data, 1); - free(node->xinfo); + IsoExtendedInfo *info = node->xinfo; + while (info != NULL) { + IsoExtendedInfo *tmp = info->next; + + /* free extended info */ + info->process(info->data, 1); + free(info); + info = tmp; + } } -#endif free(node->name); free(node); } } +/** + * Add extended information to the given node. Extended info allows + * applications (and libisofs itself) to add more information to an IsoNode. + * You can use this facilities to associate new information with a given + * node. + * + * Each node keeps a list of added extended info, meaning you can add several + * extended info data to each node. Each extended info you add is identified + * by the proc parameter, a pointer to a function that knows how to manage + * the external info data. Thus, in order to add several types of extended + * info, you need to define a "proc" function for each type. + * + * @param node + * The node where to add the extended info + * @param proc + * A function pointer used to identify the type of the data, and that + * knows how to manage it + * @param data + * Extended info to add. + * @return + * 1 if success, 0 if the given node already has extended info of the + * type defined by the "proc" function, < 0 on error + */ +int iso_node_add_xinfo(IsoNode *node, iso_node_xinfo_func proc, void *data) +{ + IsoExtendedInfo *info; + IsoExtendedInfo *pos; + + if (node == NULL || proc == NULL) { + return ISO_NULL_POINTER; + } + + pos = node->xinfo; + while (pos != NULL) { + if (pos->process == proc) { + return 0; /* extended info already added */ + } + pos = pos->next; + } + + info = malloc(sizeof(IsoExtendedInfo)); + if (info == NULL) { + return ISO_OUT_OF_MEM; + } + info->next = node->xinfo; + info->data = data; + info->process = proc; + node->xinfo = info; + return ISO_SUCCESS; +} + +/** + * Remove the given extended info (defined by the proc function) from the + * given node. + * + * @return + * 1 on success, 0 if node does not have extended info of the requested + * type, < 0 on error + */ +int iso_node_remove_xinfo(IsoNode *node, iso_node_xinfo_func proc) +{ + IsoExtendedInfo *pos, *prev; + + if (node == NULL || proc == NULL) { + return ISO_NULL_POINTER; + } + + prev = NULL; + pos = node->xinfo; + while (pos != NULL) { + if (pos->process == proc) { + /* this is the extended info we want to remove */ + pos->process(pos->data, 1); + + if (prev != NULL) { + prev->next = pos->next; + } else { + node->xinfo = pos->next; + } + free(pos); + return ISO_SUCCESS; + } + prev = pos; + pos = pos->next; + } + /* requested xinfo not found */ + return 0; +} + +/** + * Get the given extended info (defined by the proc function) from the + * given node. + * + * @param data + * Will be filled with the extended info corresponding to the given proc + * function + * @return + * 1 on success, 0 if node does not have extended info of the requested + * type, < 0 on error + */ +int iso_node_get_xinfo(IsoNode *node, iso_node_xinfo_func proc, void **data) +{ + IsoExtendedInfo *pos; + + if (node == NULL || proc == NULL || data == NULL) { + return ISO_NULL_POINTER; + } + + pos = node->xinfo; + while (pos != NULL) { + if (pos->process == proc) { + /* this is the extended info we want */ + *data = pos->data; + return ISO_SUCCESS; + } + pos = pos->next; + } + /* requested xinfo not found */ + return 0; +} + /** * Get the type of an IsoNode. */ diff --git a/libisofs/node.h b/libisofs/node.h index dd13469..993051c 100644 --- a/libisofs/node.h +++ b/libisofs/node.h @@ -20,9 +20,6 @@ #include #include -/* #define LIBISO_EXTENDED_INFORMATION */ -#ifdef LIBISO_EXTENDED_INFORMATION - /** * The extended information is a way to attach additional information to each * IsoNode. External applications may want to use this extension system to @@ -55,7 +52,7 @@ struct iso_extended_info { * @return * 1 */ - int (*process)(void *data, int flag); + iso_node_xinfo_func process; /** * Pointer to information specific data. @@ -63,8 +60,6 @@ struct iso_extended_info { void *data; }; -#endif - /** * */ @@ -102,12 +97,10 @@ struct Iso_Node */ IsoNode *next; -#ifdef LIBISO_EXTENDED_INFORMATION /** * Extended information for the node. */ IsoExtendedInfo *xinfo; -#endif }; struct Iso_Dir diff --git a/test/test_node.c b/test/test_node.c index 1df22b3..2fdcf0c 100644 --- a/test/test_node.c +++ b/test/test_node.c @@ -1106,6 +1106,183 @@ void test_iso_node_set_name() free(dir); } +static +int xinfo_a(void *data, int flag) { + return 1; +} + +static +int xinfo_b(void *data, int flag) { + return 1; +} + +static +void test_iso_node_add_xinfo() +{ + int result; + IsoNode *node; + + /* cretae a node */ + node = calloc(1, sizeof(IsoNode)); + + /* add xinfo data */ + result = iso_node_add_xinfo(node, xinfo_a, NULL); + CU_ASSERT_EQUAL(result, 1); + + /* we can't add again the same xinfo type */ + result = iso_node_add_xinfo(node, xinfo_a, &result); + CU_ASSERT_EQUAL(result, 0); + + result = iso_node_add_xinfo(node, xinfo_b, NULL); + CU_ASSERT_EQUAL(result, 1); + + free(node->xinfo->next); + free(node->xinfo); + free(node); +} + +static +void test_iso_node_get_xinfo() +{ + int result; + IsoNode *node; + char *one_data = "my data"; + char *another_data = "my data 2"; + void *data; + + /* cretae a node */ + node = calloc(1, sizeof(IsoNode)); + + /* at the beginning we have no data */ + result = iso_node_get_xinfo(node, xinfo_b, &data); + CU_ASSERT_EQUAL(result, 0); + result = iso_node_get_xinfo(node, xinfo_a, &data); + CU_ASSERT_EQUAL(result, 0); + + /* add xinfo data */ + result = iso_node_add_xinfo(node, xinfo_a, one_data); + CU_ASSERT_EQUAL(result, 1); + + /* we get the correct data */ + result = iso_node_get_xinfo(node, xinfo_a, &data); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_PTR_EQUAL(data, one_data); + + /* we can't add again the same xinfo type */ + result = iso_node_add_xinfo(node, xinfo_a, &result); + CU_ASSERT_EQUAL(result, 0); + + /* we get the correct data again */ + result = iso_node_get_xinfo(node, xinfo_a, &data); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_PTR_EQUAL(data, one_data); + + /* xinfo_b has no data */ + result = iso_node_get_xinfo(node, xinfo_b, &data); + CU_ASSERT_EQUAL(result, 0); + + /* add another xinfo */ + result = iso_node_add_xinfo(node, xinfo_b, another_data); + CU_ASSERT_EQUAL(result, 1); + + /* test both data is returned propertly */ + result = iso_node_get_xinfo(node, xinfo_a, &data); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_PTR_EQUAL(data, one_data); + + result = iso_node_get_xinfo(node, xinfo_b, &data); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_PTR_EQUAL(data, another_data); + + free(node->xinfo->next); + free(node->xinfo); + free(node); +} + +static +void test_iso_node_remove_xinfo() +{ + int result; + IsoNode *node; + char *one_data = "my data"; + char *another_data = "my data 2"; + void *data; + + /* cretae a node */ + node = calloc(1, sizeof(IsoNode)); + + /* try to remove inexistent data */ + result = iso_node_remove_xinfo(node, xinfo_b); + CU_ASSERT_EQUAL(result, 0); + result = iso_node_remove_xinfo(node, xinfo_a); + CU_ASSERT_EQUAL(result, 0); + + /* add xinfo data */ + result = iso_node_add_xinfo(node, xinfo_a, one_data); + CU_ASSERT_EQUAL(result, 1); + result = iso_node_get_xinfo(node, xinfo_a, &data); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_PTR_EQUAL(data, one_data); + + /* remove it */ + result = iso_node_remove_xinfo(node, xinfo_b); + CU_ASSERT_EQUAL(result, 0); + result = iso_node_remove_xinfo(node, xinfo_a); + CU_ASSERT_EQUAL(result, 1); + + result = iso_node_get_xinfo(node, xinfo_a, &data); + CU_ASSERT_EQUAL(result, 0); + + /* add again the same xinfo type */ + result = iso_node_add_xinfo(node, xinfo_a, one_data); + CU_ASSERT_EQUAL(result, 1); + + /* we get the correct data again */ + result = iso_node_get_xinfo(node, xinfo_a, &data); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_PTR_EQUAL(data, one_data); + + /* add another xinfo */ + result = iso_node_add_xinfo(node, xinfo_b, another_data); + CU_ASSERT_EQUAL(result, 1); + + /* test both data is returned propertly */ + result = iso_node_get_xinfo(node, xinfo_a, &data); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_PTR_EQUAL(data, one_data); + + result = iso_node_get_xinfo(node, xinfo_b, &data); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_PTR_EQUAL(data, another_data); + + /* remove b */ + result = iso_node_remove_xinfo(node, xinfo_b); + CU_ASSERT_EQUAL(result, 1); + + /* only a can be get */ + result = iso_node_get_xinfo(node, xinfo_a, &data); + CU_ASSERT_EQUAL(result, 1); + CU_ASSERT_PTR_EQUAL(data, one_data); + + result = iso_node_get_xinfo(node, xinfo_b, &data); + CU_ASSERT_EQUAL(result, 0); + + /* try to remove b again */ + result = iso_node_remove_xinfo(node, xinfo_b); + CU_ASSERT_EQUAL(result, 0); + + /* remove a */ + result = iso_node_remove_xinfo(node, xinfo_a); + CU_ASSERT_EQUAL(result, 1); + + result = iso_node_get_xinfo(node, xinfo_a, &data); + CU_ASSERT_EQUAL(result, 0); + result = iso_node_get_xinfo(node, xinfo_b, &data); + CU_ASSERT_EQUAL(result, 0); + + free(node); +} + void add_node_suite() { CU_pSuite pSuite = CU_add_suite("Node Test Suite", NULL, NULL); @@ -1128,4 +1305,7 @@ void add_node_suite() CU_add_test(pSuite, "iso_node_take()", test_iso_node_take); CU_add_test(pSuite, "iso_node_take() during iteration", test_iso_dir_iter_when_external_take); CU_add_test(pSuite, "iso_node_set_name()", test_iso_node_set_name); + CU_add_test(pSuite, "iso_node_add_xinfo()", test_iso_node_add_xinfo); + CU_add_test(pSuite, "iso_node_get_xinfo()", test_iso_node_get_xinfo); + CU_add_test(pSuite, "iso_node_remove_xinfo()", test_iso_node_remove_xinfo); }