diff --git a/.bzrignore b/.bzrignore index 900e90d..4adeb9a 100644 --- a/.bzrignore +++ b/.bzrignore @@ -38,3 +38,4 @@ demo/isogrow doc/html doc/doxygen.conf libisofs-1.pc +demo/find diff --git a/Makefile.am b/Makefile.am index b4f7137..f992d25 100644 --- a/Makefile.am +++ b/Makefile.am @@ -16,6 +16,7 @@ libisofs_libisofs_la_SOURCES = \ libisofs/node.c \ libisofs/tree.h \ libisofs/tree.c \ + libisofs/find.c \ libisofs/image.h \ libisofs/image.c \ libisofs/fsource.h \ @@ -65,6 +66,7 @@ noinst_PROGRAMS = \ demo/cat \ demo/catbuffer \ demo/tree \ + demo/find \ demo/ecma119tree \ demo/iso \ demo/isoread \ @@ -89,6 +91,10 @@ demo_tree_CPPFLAGS = -Ilibisofs demo_tree_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS) demo_tree_SOURCES = demo/tree.c +demo_find_CPPFLAGS = -Ilibisofs +demo_find_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS) +demo_find_SOURCES = demo/find.c + demo_ecma119tree_CPPFLAGS = -Ilibisofs demo_ecma119tree_LDADD = $(libisofs_libisofs_la_OBJECTS) $(THREAD_LIBS) demo_ecma119tree_SOURCES = demo/ecma119_tree.c diff --git a/demo/find.c b/demo/find.c new file mode 100644 index 0000000..abae63d --- /dev/null +++ b/demo/find.c @@ -0,0 +1,59 @@ +/* + * Little program that import a directory, find matching nodes and prints the + * resulting iso tree. + */ + +#include "libisofs.h" +#include +#include +#include +#include +#include +#include + +static void +print_dir(IsoDir *dir) +{ + IsoDirIter *iter; + IsoNode *node; + IsoFindCondition *cond; + + cond = iso_new_find_conditions_name("*a*"); + iso_dir_find_children(dir, cond, &iter); + while (iso_dir_iter_next(iter, &node) == 1) { + printf(" %s\n", iso_node_get_name(node)); + } + iso_dir_iter_free(iter); +} + +int main(int argc, char **argv) +{ + int result; + IsoImage *image; + + if (argc != 2) { + printf ("You need to specify a valid path\n"); + return 1; + } + + iso_init(); + iso_set_msgs_severities("NEVER", "ALL", ""); + + result = iso_image_new("volume_id", &image); + if (result < 0) { + printf ("Error creating image\n"); + return 1; + } + + result = iso_tree_add_dir_rec(image, iso_image_get_root(image), argv[1]); + if (result < 0) { + printf ("Error adding directory %d\n", result); + return 1; + } + + print_dir(iso_image_get_root(image)); + + iso_image_unref(image); + iso_finish(); + return 0; +} diff --git a/libisofs/find.c b/libisofs/find.c new file mode 100644 index 0000000..57fbb4c --- /dev/null +++ b/libisofs/find.c @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2008 Vreixo Formoso + * + * This file is part of the libisofs project; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. See COPYING file for details. + */ + +#include "libisofs.h" +#include "node.h" + +#include +#include + +struct iso_find_condition +{ + /* + * Check whether the given node matches this condition. + * + * @param cond + * The condition to check + * @param node + * The node that should be checked + * @return + * 1 if the node matches the condition, 0 if not + */ + int (*matches)(IsoFindCondition *cond, IsoNode *node); + + /** + * Free condition specific data + */ + void (*free)(IsoFindCondition*); + + /** condition specific data */ + void *data; +}; + +struct find_iter_data +{ + IsoDirIter *iter; + IsoFindCondition *cond; +}; + +static +int find_iter_next(IsoDirIter *iter, IsoNode **node) +{ + int ret; + IsoNode *n; + struct find_iter_data *data = iter->data; + + while ((ret = iso_dir_iter_next(data->iter, &n)) == 1) { + if (data->cond->matches(data->cond, n)) { + *node = n; + break; + } + } + return ret; +} + +static +int find_iter_has_next(IsoDirIter *iter) +{ + struct find_iter_data *data = iter->data; + + /* + * FIXME wrong implementation!!!! the underlying iter may have more nodes, + * but they may not match find conditions + */ + return iso_dir_iter_has_next(data->iter); +} + +static +void find_iter_free(IsoDirIter *iter) +{ + struct find_iter_data *data = iter->data; + data->cond->free(data->cond); + free(data->cond); + iso_dir_iter_free(data->iter); + free(iter->data); +} + +static +int find_iter_take(IsoDirIter *iter) +{ + struct find_iter_data *data = iter->data; + return iso_dir_iter_take(data->iter); +} + +static +int find_iter_remove(IsoDirIter *iter) +{ + struct find_iter_data *data = iter->data; + return iso_dir_iter_remove(data->iter); +} + +static +struct iso_dir_iter_iface find_iter_class = { + find_iter_next, + find_iter_has_next, + find_iter_free, + find_iter_take, + find_iter_remove +}; + +int iso_dir_find_children(IsoDir* dir, IsoFindCondition *cond, + IsoDirIter **iter) +{ + int ret; + IsoDirIter *children; + IsoDirIter *it; + struct find_iter_data *data; + + if (dir == NULL || cond == NULL || iter == NULL) { + return ISO_NULL_POINTER; + } + it = malloc(sizeof(IsoDirIter)); + if (it == NULL) { + return ISO_OUT_OF_MEM; + } + data = malloc(sizeof(struct find_iter_data)); + if (data == NULL) { + free(it); + return ISO_OUT_OF_MEM; + } + ret = iso_dir_get_children(dir, &children); + if (ret < 0) { + free(it); + free(data); + return ret; + } + + it->class = &find_iter_class; + it->dir = (IsoDir*)dir; + data->iter = children; + data->cond = cond; + it->data = data; + + *iter = it; + return ISO_SUCCESS; +} + +/*************** find by name wildcard condition *****************/ + +static +int cond_name_matches(IsoFindCondition *cond, IsoNode *node) +{ + char *pattern = (char*) cond->data; + int ret = fnmatch(pattern, node->name, 0); + return ret == 0 ? 1 : 0; +} + +static +void cond_name_free(IsoFindCondition *cond) +{ + free(cond->data); +} + +/** + * Create a new condition that checks if a the node name matches the given + * wildcard. + * + * @param wildcard + * @result + * The created IsoFindCondition, NULL on error. + * + * @since 0.6.4 + */ +IsoFindCondition *iso_new_find_conditions_name(const char *wildcard) +{ + IsoFindCondition *cond; + if (wildcard == NULL) { + return NULL; + } + cond = malloc(sizeof(IsoFindCondition)); + if (cond == NULL) { + return NULL; + } + cond->data = strdup(wildcard); + cond->free = cond_name_free; + cond->matches = cond_name_matches; + return cond; +} diff --git a/libisofs/libisofs.h b/libisofs/libisofs.h index ee80fd5..7ffd308 100644 --- a/libisofs/libisofs.h +++ b/libisofs/libisofs.h @@ -2164,6 +2164,43 @@ int iso_dir_iter_take(IsoDirIter *iter); */ int iso_dir_iter_remove(IsoDirIter *iter); + +/** + * @since 0.6.4 + */ +typedef struct iso_find_condition IsoFindCondition; + +/** + * Create a new condition that checks if a the node name matches the given + * wildcard. + * + * @param wildcard + * @result + * The created IsoFindCondition, NULL on error. + * + * @since 0.6.4 + */ +IsoFindCondition *iso_new_find_conditions_name(const char *wildcard); + +/** + * Find all directory children that match the given condition. + * + * @param dir + * Directory where we will search children. + * @param cond + * Condition that the children must match in order to be returned. + * It will be free together with the iterator. Remember to delete it + * if this function return error. + * @param iter + * Iterator that returns only the children that match condition. + * @return + * 1 on success, < 0 on error + * + * @since 0.6.4 + */ +int iso_dir_find_children(IsoDir* dir, IsoFindCondition *cond, + IsoDirIter **iter); + /** * Get the destination of a node. * The returned string belongs to the node and should not be modified nor diff --git a/libisofs/node.c b/libisofs/node.c index 9276ef8..22f46d7 100644 --- a/libisofs/node.c +++ b/libisofs/node.c @@ -616,7 +616,6 @@ struct iso_dir_iter_iface iter_class = { iter_remove }; - int iso_dir_get_children(const IsoDir *dir, IsoDirIter **iter) { IsoDirIter *it;