* [PATCH - policyrep] Add generic iterators and a linked-list data structure to libsepol
@ 2007-04-18 20:59 Karl MacMillan
0 siblings, 0 replies; 3+ messages in thread
From: Karl MacMillan @ 2007-04-18 20:59 UTC (permalink / raw)
To: SELinux List
Add a generic iterator data structure and a linked-list implementation
based that uses the iterators to libsepol. Includes test cases for the
linked-list implementation.
Signed-off-by: Karl MacMillan <kmacmillan@mentalrootkit.com>
diff -r c0ca24c3e136 libsepol/include/sepol/errcodes.h
--- a/libsepol/include/sepol/errcodes.h Wed Apr 18 11:32:21 2007 -0400
+++ b/libsepol/include/sepol/errcodes.h Wed Apr 18 16:59:11 2007 -0400
@@ -22,4 +22,7 @@
#define SEPOL_EEXIST -EEXIST
#define SEPOL_ENOENT -ENOENT
+/* Custom error codes */
+#define SEPOL_ITERSTOP -500
+
#endif
diff -r c0ca24c3e136 libsepol/include/sepol/iter.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libsepol/include/sepol/iter.h Wed Apr 18 16:59:11 2007 -0400
@@ -0,0 +1,239 @@
+/* Author : Karl MacMillan <kmacmillan@mentalrootkit.com> */
+
+#ifndef __sepol_iter_h__
+#define __sepol_iter_h__
+
+#include <sepol/handle.h>
+
+/**
+ * \defgroup libsepol_iter sepol_iter: generic iterators
+ * Iterators represent a position within a data structure. They are a
+ * generalization of the concept of pointers. Using iterators allows
+ * algorithms to be cleanly separated from data structures by
+ * abstracting the concept of position and movement. Once an iterator
+ * is created and its position initialized in a data structure
+ * specific way, looping and other control flow can be implemented
+ * only using the generic iterator functions.
+ *
+ * For example, consider the code below which loops through a list
+ * (the error handling and some initialization is ommitted for brevity):
+ * \code
+ * int ret;
+ * struct sepol_iter *iter;
+ * struct sepol_handle *h;
+ *
+ * sepol_iter_create(h, &iter);
+ * ret = sepol_list_begin(h, iter);
+ *
+ * while (ret == SEPOL_OK) {
+ * // process the data
+ * data = sepol_iter_get_data(h, iter);
+ * ret = sepol_iter_next(h, iter);
+ * }
+ * if (ret != SEPOL_ITERSTOP)
+ * // handle errors
+ * \endcode
+ */
+
+/**
+ * \ingroup libsepol_iter
+ * \struct sepol_iter
+ *
+ * Iterator data structuer.
+ *
+ * @see libsepol_iter
+ */
+struct sepol_iter;
+
+/**
+ * \ingroup libsepol_iter
+ * Create an iterator. The iterator is not valid
+ * until a data structure specific call has been
+ * made to initiliaze its position (e.g., sepol_list_begin).
+ *
+ * @param h sepol handle (can be NULL)
+ * @param iter pointer to allocated iterator
+ *
+ * \retval SEPOL_OK success
+ * \retval SEPOL_ENOMEM out of memory
+ */
+extern int sepol_iter_create(struct sepol_handle *h, struct sepol_iter **iter);
+
+/**
+ * \ingroup libsepol_iter
+ * Free an iterator. This has no effect on the data structure or items
+ * that the iterator may represent - only the iterator is destroyed.
+ *
+ * @param h sepol handle (can be NULL)
+ * @param iter iterator to destroy
+ *
+ * \retval SEPOL_OK success
+ * \retval <0 other errors specific to the underlying data structure
+ */
+extern int sepol_iter_free(struct sepol_handle *h, struct sepol_iter *iter);
+
+/**
+ * \ingroup libsepol_iter
+ * Make a copy of an iterator. The new iterator will be at the
+ * same position as the old iterator.
+ *
+ * Warning: Not all iterators support copying. See the data structure
+ * documentation for details on whether iterators to a specific
+ * data structure support copying.
+ *
+ * @param h sepol handle (can be NULL)
+ * @param iter iterator to copy
+ * @param new_iter newly created iterator which is a copy of iter
+ *
+ * \retval SEPOL_OK success
+ * \retval SEPOL_ENOMEM out of memory
+ * \retval SEPOL_ENOTSUP iterator copying not supported
+ */
+extern int sepol_iter_clone(struct sepol_handle *h, const struct sepol_iter *iter,
+ struct sepol_iter **new_iter);
+
+/**
+ * \ingroup libsepol_iter
+ * Return the data at this iterator location. The type
+ * of the returned data is data structure specific.
+ *
+ * @param h sepol handle (can be NULL)
+ * @param iter iterator from which to return data
+ * @param data pointer to data returned by iterator
+ *
+ * \retval SEPOL_OK success
+ * \retval <0 other errors specific to the underlying data structure
+ */
+extern int sepol_iter_get_data(struct sepol_handle *h, struct sepol_iter *iter,
+ void **data);
+
+/**
+ * \ingroup libsepol_iter
+ *
+ * Move the iterator to the next position. If SEPOL_ITERSTOP is
+ * returned, one past the end of the data structure has been reached.
+ * After SEPOL_ITERSTOP has been returned No other calls using this
+ * iterator are valid until a data structure specific call has been
+ * made to reset it to a valid position (e.g., sepol_list_begin).
+ *
+ * @param h sepol handle (can be NULL)
+ * @param iter iterator to advance
+ *
+ * \retval SEPOL_OK iterator successfully moved
+ * \retval SEPOL_ITERSTOP iteration should stop
+ * \retval <0 other errors specific to the underlying data structure
+ */
+extern int sepol_iter_next(struct sepol_handle *h, struct sepol_iter *iter);
+
+/**
+ * \ingroup libsepol_iter
+ * Move the iterator to the prev position. If SEPOL_ITERSTOP is
+ * returned, one before the beginning of the data structure has been
+ * reached. No other calls using this iterator are valid until a data
+ * structure specific call has been made to reset it to a valid
+ * position (e.g., sepol_list_end).
+ *
+ * Not all iterators support prev - the data structure specific
+ * iterator documentation should indicate whether prev is supported.
+ *
+ * @param h sepol handle (can be NULL)
+ * @param iter iterator to move to the previous position
+ *
+ * \retval SEPOL_OK iterator successfully moved
+ * \retval SEPOL_ITERSTOP iteration should stop
+ * \retval SEPOL_ENOTSUP previous iterator not supported for this
+ * data structure.
+ * \retval <0: other errors specific to the underlying data structure
+ */
+extern int sepol_iter_prev(struct sepol_handle *h, struct sepol_iter *iter);
+
+/**
+ * \ingroup libsepol_iter
+ * Move the iterator forward by distance. This does _not_ set the
+ * absolute position of the iterator. Rather, it moves in by distance
+ * from the current position. For example, moving an iterator at
+ * position 2 by 3 would put the iterator at position 5.
+ *
+ * @param h sepol handle (can be NULL)
+ * @param iter iterator to move forward
+ * @param distance distance to move iterator forward
+ *
+ * \retval SEPOL_OK iterator successfully moved
+ * \retval SEPOL_ITERSTOP iteration should stop
+ * \retval SEPOL_ENOTSUP previous iterator not supported for this
+ * data structure.
+ * \retval <0: other errors specific to the underlying data structure
+ */
+extern int sepol_iter_forward(struct sepol_handle *h, struct sepol_iter *iter,
+ unsigned int distance);
+
+/**
+ * \ingroup libsepol_iter
+ * Move the iterator backward by distance. This does _not_ set the
+ * absolute position of the iterator. Rather, it moves in by distance
+ * from the current position. For example, moving an iterator at
+ * position 2 by 1 would put the iterator at position 1.
+ *
+ * Iterator must support sepol_iter_prev.
+ *
+ * @param h sepol handle (can be NULL)
+ * @param iter iterator to move backward
+ * @param distance distance to move iterator
+ *
+ * \retval SEPOL_OK iterator successfully moved
+ * \retval SEPOL_ITERSTOP iteration should stop
+ * \retval SEPOL_ENOTSUP previous iterator not supported for this
+ * data structure.
+ * \retval <0: other errors specific to the underlying data structure
+ */
+extern int sepol_iter_backward(struct sepol_handle *h, struct sepol_iter *iter,
+ unsigned int distance);
+
+/**
+ * \ingroup libsepol_iter
+ * \def sepol_foreach
+ * Iterate over a sequence in a for-loop-like manner. This
+ * macro is a convenience wrapper around sepol_iter_next
+ * and sepol_iter_get_state. For example:
+ *
+ * \code
+ * int ret;
+ * struct sepol_iter *iter;
+ * char *name;
+ * // initialization omitted
+ * ret = sepol_list_begin(h, list, iter);
+ * sepol_foreach(h, ret, name, iter) {
+ * printf("%s\n", name);
+ * }
+ * if (ret != SEPOL_ITERSTOP)
+ * // handle error
+ * \endcode
+ *
+ * @param h sepol handle (can be NULL)
+ * @param ret int variable used to hold the return value
+ * of functions called by the macro.
+ * @param cur variable used to hold the results of sepol_iter_get_data.
+ * The type of the variable must be appropriate for the data stored
+ * in the data structure.
+ * @param iter iterator initialized to a valid position (e.g., after
+ * a call to sepol_list_begin).
+ */
+#define sepol_foreach(h, ret, cur, iter) \
+ for (; ret == SEPOL_OK && (sepol_iter_get_data(h, iter, (void**)&cur) == SEPOL_OK); \
+ ret = sepol_iter_next(h, iter)) \
+
+
+/* used by implementations of iterators */
+extern void sepol_iter_set_state(struct sepol_iter *iter, void *state);
+extern void *sepol_iter_get_state(const struct sepol_iter *iter);
+extern void sepol_iter_set_next(struct sepol_iter *iter,
+ int (*next)(struct sepol_handle *, struct sepol_iter *));
+extern void sepol_iter_set_prev(struct sepol_iter *iter,
+ int (*prev)(struct sepol_handle *, struct sepol_iter *));
+extern void sepol_iter_set_get_data(struct sepol_iter *iter,
+ int (*get)(struct sepol_handle *, struct sepol_iter *, void **));
+extern void sepol_iter_set_free(struct sepol_iter *iter, int (*state_free)(struct sepol_handle *, void *data));
+extern void sepol_iter_set_clone(struct sepol_iter *iter,
+ int (*clone)(struct sepol_handle *, const struct sepol_iter *old, struct sepol_iter *new_iter));
+
+#endif
diff -r c0ca24c3e136 libsepol/include/sepol/list.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libsepol/include/sepol/list.h Wed Apr 18 16:59:11 2007 -0400
@@ -0,0 +1,234 @@
+/* Author : Karl MacMillan <kmacmillan@mentalrootkit.com> */
+
+
+#ifndef __sepol_list_h__
+#define __sepol_list_h__
+
+#include <sepol/iter.h>
+
+/**
+ * \defgroup libsepol_list sepol_list: doubly-linked lists
+ * Doubly-linked list data type.
+ *
+ * The sepol_list data type represents a doubly-linked list.
+ * It supports:
+ * - forward and backward iteration using sepol_iter.
+ * - prepending and appending in constant time.
+ * - getting the length in constant time.
+ * - insertion and deletion.
+ * - stack / queue like usage (via sepol_list_pop_front and
+ * sepol_list_pop_back).
+ *
+ * This list implementation is designed to be generic by storing
+ * void pointers as the objects. These pointers are not interpreted
+ * or manipulated in any way. This means that the memory for the
+ * objects is *not* managed with the rest of the list (e.g.,
+ * sepol_list_free only destroys the memory for the list not the
+ * items stored in the list). This also means that the list is not
+ * ideal for storing simple types (like ints) because they need to
+ * be allocated.
+ *
+ * @see sepol_iter
+ */
+
+/**
+ * \ingroup libsepol_list
+ * \struct sepol_list
+ * Doubly-linked list struct type.
+ *
+ * @see libsepol_list
+ */
+struct sepol_list;
+
+/**
+ * \ingroup libsepol_list
+ * Create an sepol_list. On success, SEPOL_OK is returned
+ * and the list pointer passed in is set to an allocated
+ * sepol_list struct that has been initialized.
+ *
+ * @param h sepol handle (may be NULL)
+ * @param list pointer to a list pointer for returning the
+ * newly created list.
+ *
+ * \retval SEPOL_OK list successfully created
+ * \retval SEPOL_ENOMEM out of memory
+ */
+extern int sepol_list_create(struct sepol_handle *h, struct sepol_list **list);
+
+/**
+ * \ingroup libsepol_list
+ * Destroy an sepol_list. This will _not_ free the memory
+ * for the list items, only for the internal list structures.
+ * The list items memory should be freed by the caller.
+ *
+ * @param list list to destroy
+ */
+extern void sepol_list_free(struct sepol_list *list);
+
+/**
+ * \ingroup libsepol_list
+ * Return the lenght of the list. This is a constant time
+ * operation.
+ *
+ * @param list list object
+ *
+ * \returns length of the list
+ */
+extern unsigned int sepol_list_length(struct sepol_list *list);
+
+/**
+ * \ingroup libsepol_list
+ * Append an item to the list. If successful, the item will
+ * become the last item in the list.
+ *
+ * @param h sepol handle (may be NULL)
+ * @param list list to which to append
+ * @param item to append
+ *
+ * \retval SEPOL_OK success
+ * \retval SEPOL_ENOMEM out of memory
+ */
+extern int sepol_list_append(struct sepol_handle *h, struct sepol_list *list,
+ void *item);
+
+/**
+ * \ingroup libsepol_list
+ * Prepend an item to the list. If successful, the item will
+ * become the first item in the list.
+ *
+ * @param h sepol handle (may be NULL)
+ * @param list list to which to prepend
+ * @param item to prepend
+ *
+ * \retval SEPOL_OK success
+ * \retval SEPOL_ENOMEM out of memory
+ */
+extern int sepol_list_prepend(struct sepol_handle *h, struct sepol_list *list,
+ void *item);
+
+/**
+ * \ingroup libsepol_list
+ * Insert an item before the iterator position. The existing item is
+ * shifted to the next position in the list. The iterator continues to
+ * point at the same item, though the position of that item will have
+ * moved forward by one.
+ *
+ * @param h sepol handle (may be NULL)
+ * @param list list to which to insert
+ * @param iter iter representing the insertion position
+ * @param item item to insert
+ *
+ * \retval SEPOL_OK success
+ * \retval SEPOL_ENOMEM out of memory
+ */
+extern int sepol_list_insert(struct sepol_handle *h, struct sepol_list *list,
+ struct sepol_iter *iter, void *item);
+
+/**
+ * \ingroup libsepol_list
+ * Insert into the list all of the items returned by the iter. This method
+ * is useful for inserting all of the items from another data structure
+ * into the list (because a standard iterator is used any data structure that
+ * supports iteratoration can be used).
+ *
+ * @param h sepol handle (may be NULL)
+ * @param list list to extend
+ * @param iter iterator for data to extend
+ *
+ * \retval SEPOL_OK success
+ * \retval SEPOL_ENOMEM out of memory
+ */
+extern int sepol_list_extend(struct sepol_handle *h, struct sepol_list *list,
+ struct sepol_iter *iter);
+
+/**
+ * \ingroup libsepol_list
+ * Convenience function to extend a list with another list. Internally, simply
+ * creates a an iter pointing to the beginning of the list and calls
+ * sepol_list_extend.
+ *
+ * @param h sepol handle (may be NULL)
+ * @param list list to extend
+ * @param other source list
+ *
+ * \retval SEPOL_OK success
+ * \retval SEPOL_ENOMEM out of memory
+ */
+extern int sepol_list_extend_list(struct sepol_handle *h, struct sepol_list *list,
+ struct sepol_list *other);
+
+/**
+ * \ingroup libsepol_list
+ * Remove and return the first item in the list. Item will be set
+ * to the item if the operation was successful.
+ *
+ * @param h sepol handle (may be NULL)
+ * @param list list from which to pop item
+ * @param item pointer that will be set to the popped item
+ *
+ * \retval SEPOL_OK succss
+ * \retval SEPOL_ERANGE empty list
+ */
+extern int sepol_list_pop_front(struct sepol_handle *h, struct sepol_list *list,
+ void **item);
+
+/**
+ * \ingroup libsepol_list
+ * Remove and return the last item in the list. Item will be set
+ * to the item if the operation was successful.
+ *
+ * @param h sepol handle (may be NULL)
+ * @param list list from which to pop item
+ * @param item that will be set to the popped item
+ *
+ * \retval SEPOL_OK succss
+ * \retval SEPOL_ERANGE: empty list
+ */
+extern int sepol_list_pop_back(struct sepol_handle *h, struct sepol_list *list,
+ void **item);
+
+/**
+ * \ingroup libsepol_list
+ * Delete an item at the iterator position. The iterator is no longer
+ * valid after deletion (if continued iteration is needed, the iterator
+ * should be copied and the copy advanced prior to deletion).
+ *
+ * @param h sepol handle (may be NULL)
+ * @param list list from which to delete item
+ * @param iter representing the position of the item to delete
+ *
+ * \retval SEPOL_OK success
+ */
+extern int sepol_list_del(struct sepol_handle *h, struct sepol_list *list,
+ struct sepol_iter *iter);
+
+/**
+ * \ingroup libsepol_list
+ * Position the iterator at the beginning of the list. If the list
+ * is empty SEPOL_ITERSTOP will be returned and the iterator will not
+ * be valid.
+ *
+ * @param h sepol handle (may be NULL)
+ * @param list list to iterate over
+ * @param iter iterator to set to list beginning
+ *
+ * \retval SEPOL_OK success
+ * \retval SEPOL_ITERSTOP empty list
+ */
+extern int sepol_list_begin(struct sepol_handle *h, struct sepol_list *list,
+ struct sepol_iter *iter);
+
+/**
+ * \ingroup libsepol_list
+ * Position the iterator at the end of the list. If the list
+ * is empty SEPOL_ITERSTOP will be returned and the iterator will not
+ * be valid.
+ *
+ * @param h sepol handle (may be NULL)
+ * \retval SEPOL_OK success
+ * \retval SEPOL_ITERSTOP empty list
+ */
+extern int sepol_list_end(struct sepol_handle *h, struct sepol_list *list,
+ struct sepol_iter *iter);
+
+#endif
diff -r c0ca24c3e136 libsepol/src/iter.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libsepol/src/iter.c Wed Apr 18 16:59:11 2007 -0400
@@ -0,0 +1,186 @@
+/*
+ * Author : Karl MacMillan <kmacmillan@mentalrootkit.com>
+ *
+ * Copyright (C) 2006-2007 Red Hat, Inc.
+ *
+ * This 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 2.1 of the License, or (at your option) any later version.
+ *
+ * This 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 this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <sepol/iter.h>
+#include <sepol/errcodes.h>
+
+#include "debug.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+struct sepol_iter
+{
+ void *state;
+ int (*next)(struct sepol_handle *, struct sepol_iter *);
+ int (*prev)(struct sepol_handle *, struct sepol_iter *);
+ int (*get)(struct sepol_handle *, struct sepol_iter *, void **);
+ int (*clone)(struct sepol_handle *, const struct sepol_iter *, struct sepol_iter *);
+ int (*free_fn)(struct sepol_handle *, void *);
+};
+
+int sepol_iter_create(struct sepol_handle *h, struct sepol_iter **iter)
+{
+ *iter = (struct sepol_iter*)calloc(1, sizeof(struct sepol_iter));
+ if (*iter == NULL) {
+ ERR(h, "out of memory");
+ return SEPOL_ENOMEM;
+ }
+
+ return SEPOL_OK;
+}
+
+int sepol_iter_free(struct sepol_handle *h, struct sepol_iter *iter)
+{
+ int ret;
+ if (iter->free_fn != NULL) {
+ ret = iter->free_fn(h, iter->state);
+ }
+ free(iter);
+
+ return ret;
+}
+
+int sepol_iter_clone(struct sepol_handle *h, const struct sepol_iter *iter,
+ struct sepol_iter **new_iter)
+{
+ int ret;
+
+ if (iter->clone == NULL) {
+ ERR(h, "iterator copying not supported");
+ return SEPOL_ENOTSUP;
+ }
+
+ ret = sepol_iter_create(h, new_iter);
+ if (ret < 0)
+ return ret;
+
+ return iter->clone(h, iter, *new_iter);
+}
+
+int sepol_iter_get_data(struct sepol_handle *h, struct sepol_iter *iter, void **data)
+{
+ assert(iter);
+ assert(iter->get);
+
+ return iter->get(h, iter, data);
+}
+
+int sepol_iter_next(struct sepol_handle *h, struct sepol_iter *iter)
+{
+ assert(iter);
+ assert(iter->next);
+
+ return iter->next(h, iter);
+}
+
+int sepol_iter_prev(struct sepol_handle *h, struct sepol_iter *iter)
+{
+ assert(iter);
+
+ if (iter->prev == NULL) {
+ ERR(h, "iterator previous not supported");
+ return SEPOL_ENOTSUP;
+ }
+
+ return iter->prev(h, iter);
+}
+
+/* At some point forward and backward should be overridable by
+ * the data structures. Depending on the data structure there
+ * could be significant performance improvements by directly
+ * implementing forward and backward.
+ */
+int sepol_iter_forward(struct sepol_handle *h, struct sepol_iter *iter,
+ unsigned int distance)
+{
+ unsigned int i = 0;
+ int ret = SEPOL_OK;
+
+ while (i < distance && ret == SEPOL_OK) {
+ ret = sepol_iter_next(h, iter);
+ i++;
+ }
+
+ return ret;
+}
+
+int sepol_iter_backward(struct sepol_handle *h, struct sepol_iter *iter,
+ unsigned int distance)
+{
+ unsigned int i = 0;
+ int ret = SEPOL_OK;
+
+ while (i < distance && ret == SEPOL_OK) {
+ ret = sepol_iter_prev(h, iter);
+ i++;
+ }
+
+ return ret;
+}
+
+void sepol_iter_set_state(struct sepol_iter *iter, void *state)
+{
+ assert(iter);
+ if (iter->state && iter->free_fn)
+ iter->free_fn(NULL, iter->state);
+ iter->state = state;
+}
+
+void *sepol_iter_get_state(const struct sepol_iter *iter)
+{
+ assert(iter);
+ return iter->state;
+}
+
+void sepol_iter_set_next(struct sepol_iter *iter,
+ int (*next)(struct sepol_handle *, struct sepol_iter *))
+{
+ assert(iter);
+ iter->next = next;
+}
+
+void sepol_iter_set_prev(struct sepol_iter *iter,
+ int (*prev)(struct sepol_handle *, struct sepol_iter *))
+{
+ assert(iter);
+ iter->prev = prev;
+}
+
+void sepol_iter_set_get_data(struct sepol_iter *iter,
+ int (*get)(struct sepol_handle *, struct sepol_iter *, void **))
+{
+ assert(iter);
+ iter->get = get;
+}
+
+void sepol_iter_set_free(struct sepol_iter *iter, int (*state_free)(struct sepol_handle *, void *))
+{
+ assert(iter);
+ iter->free_fn = state_free;
+}
+
+void sepol_iter_set_clone(struct sepol_iter *iter,
+ int (*clone)(struct sepol_handle *, const struct sepol_iter *old, struct sepol_iter *new_iter))
+{
+ assert(iter);
+ iter->clone = clone;
+}
diff -r c0ca24c3e136 libsepol/src/list.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libsepol/src/list.c Wed Apr 18 16:59:11 2007 -0400
@@ -0,0 +1,422 @@
+/*
+ * Author : Karl MacMillan <kmacmillan@mentalrootkit.com>
+ *
+ * Copyright (C) 2006-2007 Red Hat, Inc.
+ *
+ * This 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 2.1 of the License, or (at your option) any later version.
+ *
+ * This 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 this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <sepol/errcodes.h>
+
+#include <sepol/list.h>
+#include <sepol/iter.h>
+
+#include "debug.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct sepol_list_item
+{
+ struct sepol_list_item *next;
+ struct sepol_list_item *prev;
+ void *item;
+};
+
+struct sepol_list
+{
+ struct sepol_list_item *head;
+ struct sepol_list_item *tail;
+ unsigned int len;
+};
+
+int sepol_list_create(struct sepol_handle *h, struct sepol_list **list)
+{
+ assert(list);
+
+ *list = (struct sepol_list *)calloc(1, sizeof(struct sepol_list));
+ if (*list == NULL) {
+ ERR(h, "out of memory");
+ return SEPOL_ENOMEM;
+ }
+
+ return SEPOL_OK;
+}
+
+void sepol_list_free(struct sepol_list *list)
+{
+ struct sepol_list_item *cur, *next;
+
+ if (list == NULL)
+ return;
+
+ cur = list->head;
+ while (cur != NULL) {
+ next = cur->next;
+ free(cur);
+ cur = next;
+ }
+
+ free(list);
+}
+
+unsigned int sepol_list_length(struct sepol_list *list)
+{
+ assert(list);
+ return list->len;
+}
+
+static int sepol_list_item_create(struct sepol_handle *h,
+ struct sepol_list_item **x)
+{
+ *x = calloc(1, sizeof(struct sepol_list_item));
+ if (*x == NULL) {
+ ERR(h, "out of memory");
+ return SEPOL_ENOMEM;
+ } else {
+ return SEPOL_OK;
+ }
+}
+
+int sepol_list_append(struct sepol_handle *h, struct sepol_list *list, void *item)
+{
+ int ret;
+ struct sepol_list_item *x;
+
+ assert(list);
+
+ ret = sepol_list_item_create(h, &x);
+ if (ret < 0)
+ return ret;
+ x->item = item;
+
+ /* empty list */
+ if (list->tail == NULL) {
+ list->tail = x;
+ list->head = x;
+ x->prev = NULL;
+ x->next = NULL;
+ } else {
+ /* non-empty list */
+ list->tail->next = x;
+ x->prev = list->tail;
+ x->next = NULL;
+ list->tail = x;
+ }
+
+ list->len++;
+ return SEPOL_OK;
+}
+
+int sepol_list_prepend(struct sepol_handle *h, struct sepol_list *list, void *item)
+{
+ int ret;
+ struct sepol_list_item *x;
+
+ assert(list);
+
+ ret = sepol_list_item_create(h, &x);
+ if (ret < 0)
+ return ret;
+ x->item = item;
+
+ /* empty list */
+ if (list->tail == NULL) {
+ list->tail = x;
+ list->head = x;
+ x->prev = NULL;
+ x->next = NULL;
+ } else {
+ x->next = list->head;
+ list->head->prev = x;
+ x->prev = NULL;
+ list->head = x;
+ }
+
+ list->len++;
+ return SEPOL_OK;
+}
+
+int sepol_list_insert(struct sepol_handle *h, struct sepol_list *list,
+ struct sepol_iter *iter, void *item)
+{
+ int ret;
+ struct sepol_list_item *x, *cur;
+
+ assert(list);
+
+ cur = (struct sepol_list_item*)sepol_iter_get_state(iter);
+ assert(cur);
+
+ /* Short circuit for prepend and append. */
+ if (list->head == cur) {
+ return sepol_list_prepend(h, list, item);
+ } else if (list->tail == cur) {
+ return sepol_list_append(h, list, item);
+ }
+
+ ret = sepol_list_item_create(h, &x);
+ if (ret < 0)
+ return ret;
+ x->item = item;
+
+ x->prev = cur->prev;
+ x->prev->next = x;
+ x->next = cur;
+ cur->prev = x;
+
+ list->len++;
+ return SEPOL_OK;
+}
+
+int sepol_list_extend(struct sepol_handle *h, struct sepol_list *list,
+ struct sepol_iter *iter)
+{
+ int ret = SEPOL_OK;
+ void *data;
+
+ while (ret == SEPOL_OK) {
+ ret = sepol_iter_get_data(h, iter, &data);
+ if (ret < 0)
+ return ret;
+ ret = sepol_list_append(h, list, data);
+ if (ret < 0)
+ return ret;
+
+ ret = sepol_iter_next(h, iter);
+ }
+ if (ret != SEPOL_ITERSTOP)
+ return ret;
+ else
+ return SEPOL_OK;
+}
+
+int sepol_list_extend_list(struct sepol_handle *h, struct sepol_list *list,
+ struct sepol_list *other)
+{
+ int ret;
+ struct sepol_iter *iter;
+
+ if (!other->len)
+ return SEPOL_OK;
+
+ ret = sepol_iter_create(h, &iter);
+ if (ret < 0)
+ return ret;
+
+ ret = sepol_list_begin(h, other, iter);
+ if (ret < 0)
+ goto out;
+ ret = sepol_list_extend(h, list, iter);
+
+out:
+ sepol_iter_free(h, iter);
+ return ret;
+}
+
+
+int sepol_list_pop_front(struct sepol_handle *h, struct sepol_list *list,
+ void **item)
+{
+ struct sepol_list_item *cur;
+
+ if (list->head == NULL)
+ return SEPOL_ERANGE;
+
+ cur = list->head;
+ if (list->head == list->tail) {
+ list->head = NULL;
+ list->tail = NULL;
+ } else {
+ list->head = list->head->next;
+ if (list->head)
+ list->head->prev = NULL;
+ }
+
+ *item = cur->item;
+ free(cur);
+
+ return SEPOL_OK;
+}
+
+int sepol_list_pop_back(struct sepol_handle *h, struct sepol_list *list,
+ void **item)
+{
+ struct sepol_list_item *cur;
+
+ if (list->tail == NULL)
+ return SEPOL_ERANGE;
+
+ cur = list->tail;
+
+ if (list->head == list->tail) {
+ list->head = NULL;
+ list->tail = NULL;
+ } else {
+ list->tail = list->tail->prev;
+ if (list->tail)
+ list->tail->next = NULL;
+ }
+
+ *item = cur->item;
+ free(cur);
+
+ return SEPOL_OK;
+}
+
+
+int sepol_list_del(struct sepol_handle *h, struct sepol_list *list,
+ struct sepol_iter *iter)
+{
+ struct sepol_list_item *cur;
+
+ cur = sepol_iter_get_state(iter);
+ assert(cur);
+
+ if (list->head == cur && list->tail == cur) {
+ list->head = NULL;
+ list->tail = NULL;
+ goto out;
+ }
+
+ if (cur->prev)
+ cur->prev->next = cur->next;
+ else
+ list->head = cur->next;
+
+ if (cur->next)
+ cur->next->prev = cur->prev;
+ else
+ list->tail = cur->prev;
+
+out:
+ free(cur);
+ list->len--;
+ sepol_iter_set_state(iter, NULL);
+ return SEPOL_OK;
+}
+
+static int sepol_list_next(struct sepol_handle *h, struct sepol_iter *iter)
+{
+ struct sepol_list_item *cur;
+
+ assert(iter);
+
+ cur = (struct sepol_list_item*)sepol_iter_get_state(iter);
+ assert(cur);
+
+ if (cur->next == NULL) {
+ /* set the state to NULL to catch using this iterator
+ * after ITERSTOP is returned (which is a bug). */
+ sepol_iter_set_state(iter, NULL);
+ return SEPOL_ITERSTOP;
+ } else {
+ sepol_iter_set_state(iter, cur->next);
+ return SEPOL_OK;
+ }
+}
+
+static int sepol_list_prev(struct sepol_handle *h, struct sepol_iter *iter)
+{
+ struct sepol_list_item *cur;
+
+ assert(iter);
+
+ cur = (struct sepol_list_item*)sepol_iter_get_state(iter);
+ assert(cur);
+
+ if (cur->prev == NULL) {
+ /* set the state to NULL to catch using this iterator
+ * after ITERSTOP is returned (which is a bug). */
+ sepol_iter_set_state(iter, NULL);
+ return SEPOL_ITERSTOP;
+ } else {
+ sepol_iter_set_state(iter, cur->prev);
+ return SEPOL_OK;
+ }
+}
+
+static int sepol_list_iter_get_data(struct sepol_handle *h,
+ struct sepol_iter *iter, void **data)
+{
+ struct sepol_list_item *cur;
+
+ assert(iter);
+
+ cur = (struct sepol_list_item*)sepol_iter_get_state(iter);
+ if (!cur) {
+ return SEPOL_ENOENT;
+ }
+
+ *data = cur->item;
+
+ return SEPOL_OK;
+}
+
+
+static int sepol_list_iter_clone(struct sepol_handle *h, const struct sepol_iter *o,
+ struct sepol_iter *n);
+
+#define ITERSETUP(iter) { sepol_iter_set_next(iter, sepol_list_next); \
+ sepol_iter_set_prev(iter, sepol_list_prev); \
+ sepol_iter_set_clone(iter, sepol_list_iter_clone); \
+ sepol_iter_set_get_data(iter, sepol_list_iter_get_data); }
+
+static int sepol_list_iter_clone(struct sepol_handle *h, const struct sepol_iter *o,
+ struct sepol_iter *n)
+{
+ void *state = sepol_iter_get_state(o);
+ sepol_iter_set_state(n, state);
+
+ ITERSETUP(n);
+
+ return SEPOL_OK;
+}
+
+
+int sepol_list_begin(struct sepol_handle *h, struct sepol_list *list,
+ struct sepol_iter *iter)
+{
+ assert(list);
+ assert(iter);
+
+ if (list->head == NULL)
+ return SEPOL_ITERSTOP;
+
+ sepol_iter_set_state(iter, list->head);
+
+ ITERSETUP(iter);
+
+ return SEPOL_OK;
+}
+
+int sepol_list_end(struct sepol_handle *h, struct sepol_list *list,
+ struct sepol_iter *iter)
+{
+ assert(list);
+ assert(iter);
+
+ if (list->tail == NULL)
+ return SEPOL_ITERSTOP;
+
+ sepol_iter_set_state(iter, list->tail);
+
+ ITERSETUP(iter);
+
+ return SEPOL_OK;
+}
+
+
diff -r c0ca24c3e136 libsepol/tests/libsepol-tests.c
--- a/libsepol/tests/libsepol-tests.c Wed Apr 18 11:32:21 2007 -0400
+++ b/libsepol/tests/libsepol-tests.c Wed Apr 18 16:59:11 2007 -0400
@@ -22,6 +22,7 @@
#include "test-linker.h"
#include "test-expander.h"
#include "test-deps.h"
+#include "test-list.h"
#include <CUnit/Basic.h>
#include <CUnit/Console.h>
@@ -61,6 +62,7 @@ static int do_tests(int interactive, int
DECLARE_SUITE(linker);
DECLARE_SUITE(expander);
DECLARE_SUITE(deps);
+ DECLARE_SUITE(list);
if (verbose)
CU_basic_set_mode(CU_BRM_VERBOSE);
diff -r c0ca24c3e136 libsepol/tests/test-list.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libsepol/tests/test-list.c Wed Apr 18 16:59:11 2007 -0400
@@ -0,0 +1,373 @@
+/*
+ * Author : Karl MacMillan <kmacmillan@mentalrootkit.com>
+ *
+ * Copyright (C) 2006 Red Hat, Inc.
+ *
+ * This 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 2.1 of the License, or (at your option) any later version.
+ *
+ * This 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 this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "test-list.h"
+
+#include <sepol/list.h>
+#include <sepol/iter.h>
+#include <sepol/errcodes.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+int list_test_init(void)
+{
+ return 0;
+}
+
+int list_test_cleanup(void)
+{
+ return 0;
+}
+
+static void test_list_create(void)
+{
+ struct sepol_list *list;
+ int ret;
+
+ ret = sepol_list_create(NULL, &list);
+ CU_ASSERT(ret == 0);
+
+ sepol_list_free(list);
+}
+
+static void test_list(void)
+{
+ struct sepol_list *list;
+ struct sepol_iter *iter, *iter2;
+ struct sepol_handle *h;
+ int ret;
+ int i, *num, nums[6];
+
+ for (i = 0; i < 6; i++)
+ nums[i] = i;
+
+ h = sepol_handle_create();
+ CU_ASSERT(h != NULL);
+
+ ret = sepol_iter_create(h, &iter);
+ CU_ASSERT(ret == 0);
+
+ ret = sepol_list_create(h, &list);
+ CU_ASSERT(ret == 0);
+
+ ret = sepol_list_append(h, list, &nums[4]);
+ CU_ASSERT(ret == 0);
+
+ ret = sepol_list_append(h, list, &nums[5]);
+ CU_ASSERT(ret == 0);
+
+ ret = sepol_list_prepend(h, list, &nums[1]);
+ CU_ASSERT(ret == 0);
+
+ ret = sepol_list_begin(h, list, iter);
+ CU_ASSERT(ret == 0);
+ ret = sepol_iter_forward(h, iter, 1);
+ CU_ASSERT(ret == 0);
+
+ ret = sepol_list_insert(h, list, iter, &nums[2]);
+ CU_ASSERT(ret == 0);
+
+ ret = sepol_list_begin(h, list, iter);
+ CU_ASSERT(ret == 0);
+ ret = sepol_list_insert(h, list, iter, &nums[0]);
+ CU_ASSERT(ret == 0);
+
+ ret = sepol_list_begin(h, list, iter);
+ CU_ASSERT(ret == 0);
+ ret = sepol_iter_forward(h, iter, 3);
+ CU_ASSERT(ret == 0);
+
+ ret = sepol_list_insert(h, list, iter, &nums[3]);
+ CU_ASSERT(ret == 0);
+
+ CU_ASSERT(sepol_list_length(list) == 6);
+
+ ret = sepol_list_begin(h, list, iter);
+ CU_ASSERT(ret == 0);
+ i = 0;
+
+ sepol_foreach(h, ret, num, iter) {
+ CU_ASSERT(*num == i);
+ i++;
+ }
+
+ CU_ASSERT(i == 6);
+ CU_ASSERT(ret == SEPOL_ITERSTOP);
+
+ ret = sepol_list_end(h, list, iter);
+ CU_ASSERT(ret == 0);
+ i = 5;
+ while (ret == SEPOL_OK) {
+ ret = sepol_iter_get_data(h, iter, (void**)&num);
+ CU_ASSERT(ret == SEPOL_OK);
+ CU_ASSERT(*num == i);
+ i--;
+ ret = sepol_iter_prev(h, iter);
+ }
+ CU_ASSERT(i == -1);
+ CU_ASSERT(ret == SEPOL_ITERSTOP);
+
+ ret = sepol_list_end(h, list, iter);
+ CU_ASSERT(ret == 0);
+ ret = sepol_iter_prev(h, iter);
+ CU_ASSERT(ret == 0);
+ ret = sepol_iter_get_data(h, iter, (void**)&num);
+ CU_ASSERT(ret == SEPOL_OK);
+ CU_ASSERT(*num == 4);
+
+
+ ret = sepol_list_begin(h, list, iter);
+ CU_ASSERT(ret == 0);
+ i = 0;
+ while (ret == SEPOL_OK) {
+ if (i == 2) {
+ ret = sepol_iter_clone(h, iter, &iter2);
+ CU_ASSERT(ret == SEPOL_OK);
+ ret = sepol_iter_next(h, iter);
+ CU_ASSERT(ret == SEPOL_OK);
+ ret = sepol_list_del(h, list, iter2);
+ CU_ASSERT(ret == SEPOL_OK);
+ i++;
+ continue;
+ }
+ i++;
+ ret = sepol_iter_next(h, iter);
+ }
+ CU_ASSERT(ret == SEPOL_ITERSTOP);
+ CU_ASSERT(i == 6);
+ CU_ASSERT(sepol_list_length(list) == 5);
+
+ sepol_iter_free(h, iter);
+ sepol_iter_free(h, iter2);
+ sepol_list_free(list);
+ sepol_handle_destroy(h);
+}
+
+static void test_list_pop(void)
+{
+ int ret;
+ struct sepol_list *list;
+ struct sepol_handle *h;
+ void *item;
+
+ h = sepol_handle_create();
+ CU_ASSERT(h != NULL);
+
+ ret = sepol_list_create(h, &list);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_append(h, list, "webern");
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_append(h, list, "berg");
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_append(h, list, "schoenberg");
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_append(h, list, "sessions");
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_pop_back(h, list, &item);
+ CU_ASSERT(ret == SEPOL_OK);
+ CU_ASSERT(strcmp((char*)item, "sessions") == 0);
+
+ ret = sepol_list_pop_back(h, list, &item);
+ CU_ASSERT(ret == SEPOL_OK);
+ CU_ASSERT(strcmp((char*)item, "schoenberg") == 0);
+
+ ret = sepol_list_pop_front(h, list, &item);
+ CU_ASSERT(ret == SEPOL_OK);
+ CU_ASSERT(strcmp((char*)item, "webern") == 0);
+
+ ret = sepol_list_pop_back(h, list, &item);
+ CU_ASSERT(ret == SEPOL_OK);
+ CU_ASSERT(strcmp((char*)item, "berg") == 0);
+
+
+ ret = sepol_list_pop_back(h, list, &item);
+ CU_ASSERT(ret == SEPOL_ERANGE);
+
+ sepol_list_free(list);
+ sepol_handle_destroy(h);
+}
+
+static void test_list_extend(void)
+{
+ int ret, i;
+ struct sepol_list *serialism, *minimalism;
+ struct sepol_iter *iter;
+ struct sepol_handle *h;
+ char *composers[] = {"webern", "berg",
+ "schoenberg", "sessions",
+ "adams", "glass", "reich" };
+ char *composer;
+
+ h = sepol_handle_create();
+ CU_ASSERT(h != NULL);
+
+ ret = sepol_list_create(h, &serialism);
+ CU_ASSERT(ret == SEPOL_OK);
+
+
+ ret = sepol_list_create(h, &minimalism);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_append(h, serialism, composers[0]);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_append(h, serialism, composers[1]);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_append(h, serialism, composers[2]);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_append(h, serialism, composers[3]);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_append(h, minimalism, composers[4]);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_append(h, minimalism, composers[5]);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_append(h, minimalism, composers[6]);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_iter_create(h, &iter);
+ CU_ASSERT(ret == SEPOL_OK);
+ ret = sepol_list_begin(h, minimalism, iter);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_extend(h, serialism, iter);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_begin(h, serialism, iter);
+ CU_ASSERT(ret == SEPOL_OK);
+ i = 0;
+ while (ret == SEPOL_OK) {
+ ret = sepol_iter_get_data(h, iter, (void**)&composer);
+ CU_ASSERT(ret == SEPOL_OK);
+ CU_ASSERT(strcmp(composers[i], composer) == 0);
+ ret = sepol_iter_next(h, iter);
+ i++;
+ }
+ CU_ASSERT(ret == SEPOL_ITERSTOP);
+
+ sepol_iter_free(h, iter);
+ sepol_list_free(serialism);
+ sepol_list_free(minimalism);
+ sepol_handle_destroy(h);
+}
+
+static void test_list_extend_list(void)
+{
+ int ret, i;
+ struct sepol_list *serialism, *minimalism;
+ struct sepol_iter *iter;
+ struct sepol_handle *h;
+ char *composers[] = {"webern", "berg",
+ "schoenberg", "sessions",
+ "adams", "glass", "reich" };
+ char *composer;
+
+
+ h = sepol_handle_create();
+ CU_ASSERT(h != NULL);
+
+ ret = sepol_list_create(h, &serialism);
+ CU_ASSERT(ret == SEPOL_OK);
+
+
+ ret = sepol_list_create(h, &minimalism);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_append(h, serialism, composers[0]);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_append(h, serialism, composers[1]);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_append(h, serialism, composers[2]);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_append(h, serialism, composers[3]);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_append(h, minimalism, composers[4]);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_append(h, minimalism, composers[5]);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_append(h, minimalism, composers[6]);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_extend_list(h, serialism, minimalism);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_iter_create(h, &iter);
+ CU_ASSERT(ret == SEPOL_OK);
+
+
+ ret = sepol_list_begin(h, serialism, iter);
+ CU_ASSERT(ret == SEPOL_OK);
+ i = 0;
+ while (ret == SEPOL_OK) {
+ ret = sepol_iter_get_data(h, iter, (void**)&composer);
+ CU_ASSERT(ret == SEPOL_OK);
+ CU_ASSERT(strcmp(composers[i], composer) == 0);
+ ret = sepol_iter_next(h, iter);
+ i++;
+ }
+ CU_ASSERT(ret == SEPOL_ITERSTOP);
+
+ sepol_iter_free(h, iter);
+ sepol_list_free(serialism);
+ sepol_list_free(minimalism);
+ sepol_handle_destroy(h);
+}
+
+int list_add_tests(CU_pSuite suite)
+{
+ if (NULL == CU_add_test(suite, "test_list_create", test_list_create)) {
+ return -1;
+ }
+
+ if (NULL == CU_add_test(suite, "test_list",
+ test_list)) {
+ return -1;
+ }
+
+ if (NULL == CU_add_test(suite, "test_list_pop", test_list_pop)) {
+ return -1;
+ }
+
+ if (NULL == CU_add_test(suite, "test_list_extend", test_list_extend)) {
+ return -1;
+ }
+
+ if (NULL == CU_add_test(suite, "test_list_extend_list", test_list_extend_list)) {
+ return -1;
+ }
+
+ return 0;
+}
diff -r c0ca24c3e136 libsepol/tests/test-list.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libsepol/tests/test-list.h Wed Apr 18 16:59:11 2007 -0400
@@ -0,0 +1,12 @@
+/* Author : Karl MacMillan <kmacmillan@mentalrootkit.com> */
+
+#ifndef __test_list_h__
+#define __test_list_h__
+
+#include <CUnit/Basic.h>
+
+int list_test_init(void);
+int list_test_cleanup(void);
+int list_add_tests(CU_pSuite suite);
+
+#endif
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH - policyrep] Add generic iterators and a linked-list data structure to libsepol
2007-04-18 20:45 Karl MacMillan
@ 2007-04-18 20:58 ` Karl MacMillan
0 siblings, 0 replies; 3+ messages in thread
From: Karl MacMillan @ 2007-04-18 20:58 UTC (permalink / raw)
To: SELinux List
On Wed, 2007-04-18 at 16:45 -0400, Karl MacMillan wrote:
> Add a generic iterator data structure and a linked-list implementation
> based that uses the iterators to libsepol. Includes test cases for the
> linked-list implementation.
>
> Signed-off-by: Karl MacMillan <kmacmillan@mentalrootkit.com>
>
Actually - this patch is missing extern on most of the function
definitions. Updated patch coming.
Karl
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH - policyrep] Add generic iterators and a linked-list data structure to libsepol
@ 2007-04-18 20:45 Karl MacMillan
2007-04-18 20:58 ` Karl MacMillan
0 siblings, 1 reply; 3+ messages in thread
From: Karl MacMillan @ 2007-04-18 20:45 UTC (permalink / raw)
To: SELinux List
Add a generic iterator data structure and a linked-list implementation
based that uses the iterators to libsepol. Includes test cases for the
linked-list implementation.
Signed-off-by: Karl MacMillan <kmacmillan@mentalrootkit.com>
diff -r c0ca24c3e136 libsepol/include/sepol/errcodes.h
--- a/libsepol/include/sepol/errcodes.h Wed Apr 18 11:32:21 2007 -0400
+++ b/libsepol/include/sepol/errcodes.h Wed Apr 18 16:30:08 2007 -0400
@@ -22,4 +22,7 @@
#define SEPOL_EEXIST -EEXIST
#define SEPOL_ENOENT -ENOENT
+/* Custom error codes */
+#define SEPOL_ITERSTOP -500
+
#endif
diff -r c0ca24c3e136 libsepol/include/sepol/iter.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libsepol/include/sepol/iter.h Wed Apr 18 16:30:08 2007 -0400
@@ -0,0 +1,239 @@
+/* Author : Karl MacMillan <kmacmillan@mentalrootkit.com> */
+
+#ifndef __sepol_iter_h__
+#define __sepol_iter_h__
+
+#include <sepol/handle.h>
+
+/**
+ * \defgroup libsepol_iter sepol_iter: generic iterators
+ * Iterators represent a position within a data structure. They are a
+ * generalization of the concept of pointers. Using iterators allows
+ * algorithms to be cleanly separated from data structures by
+ * abstracting the concept of position and movement. Once an iterator
+ * is created and its position initialized in a data structure
+ * specific way, looping and other control flow can be implemented
+ * only using the generic iterator functions.
+ *
+ * For example, consider the code below which loops through a list
+ * (the error handling and some initialization is ommitted for brevity):
+ * \code
+ * int ret;
+ * struct sepol_iter *iter;
+ * struct sepol_handle *h;
+ *
+ * sepol_iter_create(h, &iter);
+ * ret = sepol_list_begin(h, iter);
+ *
+ * while (ret == SEPOL_OK) {
+ * // process the data
+ * data = sepol_iter_get_data(h, iter);
+ * ret = sepol_iter_next(h, iter);
+ * }
+ * if (ret != SEPOL_ITERSTOP)
+ * // handle errors
+ * \endcode
+ */
+
+/**
+ * \ingroup libsepol_iter
+ * \struct sepol_iter
+ *
+ * Iterator data structuer.
+ *
+ * @see libsepol_iter
+ */
+struct sepol_iter;
+
+/**
+ * \ingroup libsepol_iter
+ * Create an iterator. The iterator is not valid
+ * until a data structure specific call has been
+ * made to initiliaze its position (e.g., sepol_list_begin).
+ *
+ * @param h sepol handle (can be NULL)
+ * @param iter pointer to allocated iterator
+ *
+ * \retval SEPOL_OK success
+ * \retval SEPOL_ENOMEM out of memory
+ */
+extern int sepol_iter_create(struct sepol_handle *h, struct sepol_iter **iter);
+
+/**
+ * \ingroup libsepol_iter
+ * Free an iterator. This has no effect on the data structure or items
+ * that the iterator may represent - only the iterator is destroyed.
+ *
+ * @param h sepol handle (can be NULL)
+ * @param iter iterator to destroy
+ *
+ * \retval SEPOL_OK success
+ * \retval <0 other errors specific to the underlying data structure
+ */
+extern int sepol_iter_free(struct sepol_handle *h, struct sepol_iter *iter);
+
+/**
+ * \ingroup libsepol_iter
+ * Make a copy of an iterator. The new iterator will be at the
+ * same position as the old iterator.
+ *
+ * Warning: Not all iterators support copying. See the data structure
+ * documentation for details on whether iterators to a specific
+ * data structure support copying.
+ *
+ * @param h sepol handle (can be NULL)
+ * @param iter iterator to copy
+ * @param new_iter newly created iterator which is a copy of iter
+ *
+ * \retval SEPOL_OK success
+ * \retval SEPOL_ENOMEM out of memory
+ * \retval SEPOL_ENOTSUP iterator copying not supported
+ */
+extern int sepol_iter_clone(struct sepol_handle *h, const struct sepol_iter *iter,
+ struct sepol_iter **new_iter);
+
+/**
+ * \ingroup libsepol_iter
+ * Return the data at this iterator location. The type
+ * of the returned data is data structure specific.
+ *
+ * @param h sepol handle (can be NULL)
+ * @param iter iterator from which to return data
+ * @param data pointer to data returned by iterator
+ *
+ * \retval SEPOL_OK success
+ * \retval <0 other errors specific to the underlying data structure
+ */
+extern int sepol_iter_get_data(struct sepol_handle *h, struct sepol_iter *iter,
+ void **data);
+
+/**
+ * \ingroup libsepol_iter
+ *
+ * Move the iterator to the next position. If SEPOL_ITERSTOP is
+ * returned, one past the end of the data structure has been reached.
+ * After SEPOL_ITERSTOP has been returned No other calls using this
+ * iterator are valid until a data structure specific call has been
+ * made to reset it to a valid position (e.g., sepol_list_begin).
+ *
+ * @param h sepol handle (can be NULL)
+ * @param iter iterator to advance
+ *
+ * \retval SEPOL_OK iterator successfully moved
+ * \retval SEPOL_ITERSTOP iteration should stop
+ * \retval <0 other errors specific to the underlying data structure
+ */
+int sepol_iter_next(struct sepol_handle *h, struct sepol_iter *iter);
+
+/**
+ * \ingroup libsepol_iter
+ * Move the iterator to the prev position. If SEPOL_ITERSTOP is
+ * returned, one before the beginning of the data structure has been
+ * reached. No other calls using this iterator are valid until a data
+ * structure specific call has been made to reset it to a valid
+ * position (e.g., sepol_list_end).
+ *
+ * Not all iterators support prev - the data structure specific
+ * iterator documentation should indicate whether prev is supported.
+ *
+ * @param h sepol handle (can be NULL)
+ * @param iter iterator to move to the previous position
+ *
+ * \retval SEPOL_OK iterator successfully moved
+ * \retval SEPOL_ITERSTOP iteration should stop
+ * \retval SEPOL_ENOTSUP previous iterator not supported for this
+ * data structure.
+ * \retval <0: other errors specific to the underlying data structure
+ */
+int sepol_iter_prev(struct sepol_handle *h, struct sepol_iter *iter);
+
+/**
+ * \ingroup libsepol_iter
+ * Move the iterator forward by distance. This does _not_ set the
+ * absolute position of the iterator. Rather, it moves in by distance
+ * from the current position. For example, moving an iterator at
+ * position 2 by 3 would put the iterator at position 5.
+ *
+ * @param h sepol handle (can be NULL)
+ * @param iter iterator to move forward
+ * @param distance distance to move iterator forward
+ *
+ * \retval SEPOL_OK iterator successfully moved
+ * \retval SEPOL_ITERSTOP iteration should stop
+ * \retval SEPOL_ENOTSUP previous iterator not supported for this
+ * data structure.
+ * \retval <0: other errors specific to the underlying data structure
+ */
+int sepol_iter_forward(struct sepol_handle *h, struct sepol_iter *iter,
+ unsigned int distance);
+
+/**
+ * \ingroup libsepol_iter
+ * Move the iterator backward by distance. This does _not_ set the
+ * absolute position of the iterator. Rather, it moves in by distance
+ * from the current position. For example, moving an iterator at
+ * position 2 by 1 would put the iterator at position 1.
+ *
+ * Iterator must support sepol_iter_prev.
+ *
+ * @param h sepol handle (can be NULL)
+ * @param iter iterator to move backward
+ * @param distance distance to move iterator
+ *
+ * \retval SEPOL_OK iterator successfully moved
+ * \retval SEPOL_ITERSTOP iteration should stop
+ * \retval SEPOL_ENOTSUP previous iterator not supported for this
+ * data structure.
+ * \retval <0: other errors specific to the underlying data structure
+ */
+int sepol_iter_backward(struct sepol_handle *h, struct sepol_iter *iter,
+ unsigned int distance);
+
+/**
+ * \ingroup libsepol_iter
+ * \def sepol_foreach
+ * Iterate over a sequence in a for-loop-like manner. This
+ * macro is a convenience wrapper around sepol_iter_next
+ * and sepol_iter_get_state. For example:
+ *
+ * \code
+ * int ret;
+ * struct sepol_iter *iter;
+ * char *name;
+ * // initialization omitted
+ * ret = sepol_list_begin(h, list, iter);
+ * sepol_foreach(h, ret, name, iter) {
+ * printf("%s\n", name);
+ * }
+ * if (ret != SEPOL_ITERSTOP)
+ * // handle error
+ * \endcode
+ *
+ * @param h sepol handle (can be NULL)
+ * @param ret int variable used to hold the return value
+ * of functions called by the macro.
+ * @param cur variable used to hold the results of sepol_iter_get_data.
+ * The type of the variable must be appropriate for the data stored
+ * in the data structure.
+ * @param iter iterator initialized to a valid position (e.g., after
+ * a call to sepol_list_begin).
+ */
+#define sepol_foreach(h, ret, cur, iter) \
+ for (; ret == SEPOL_OK && (sepol_iter_get_data(h, iter, (void**)&cur) == SEPOL_OK); \
+ ret = sepol_iter_next(h, iter)) \
+
+
+/* used by implementations of iterators */
+void sepol_iter_set_state(struct sepol_iter *iter, void *state);
+void *sepol_iter_get_state(const struct sepol_iter *iter);
+void sepol_iter_set_next(struct sepol_iter *iter,
+ int (*next)(struct sepol_handle *, struct sepol_iter *));
+void sepol_iter_set_prev(struct sepol_iter *iter,
+ int (*prev)(struct sepol_handle *, struct sepol_iter *));
+void sepol_iter_set_get_data(struct sepol_iter *iter,
+ int (*get)(struct sepol_handle *, struct sepol_iter *, void **));
+void sepol_iter_set_free(struct sepol_iter *iter, int (*state_free)(struct sepol_handle *, void *data));
+void sepol_iter_set_clone(struct sepol_iter *iter,
+ int (*clone)(struct sepol_handle *, const struct sepol_iter *old, struct sepol_iter *new_iter));
+
+#endif
diff -r c0ca24c3e136 libsepol/include/sepol/list.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libsepol/include/sepol/list.h Wed Apr 18 16:30:08 2007 -0400
@@ -0,0 +1,232 @@
+/* Author : Karl MacMillan <kmacmillan@mentalrootkit.com> */
+
+
+#ifndef __sepol_list_h__
+#define __sepol_list_h__
+
+#include <sepol/iter.h>
+
+/**
+ * \defgroup libsepol_list sepol_list: doubly-linked lists
+ * Doubly-linked list data type.
+ *
+ * The sepol_list data type represents a doubly-linked list.
+ * It supports:
+ * - forward and backward iteration using sepol_iter.
+ * - prepending and appending in constant time.
+ * - getting the length in constant time.
+ * - insertion and deletion.
+ * - stack / queue like usage (via sepol_list_pop_front and
+ * sepol_list_pop_back).
+ *
+ * This list implementation is designed to be generic by storing
+ * void pointers as the objects. These pointers are not interpreted
+ * or manipulated in any way. This means that the memory for the
+ * objects is *not* managed with the rest of the list (e.g.,
+ * sepol_list_free only destroys the memory for the list not the
+ * items stored in the list). This also means that the list is not
+ * ideal for storing simple types (like ints) because they need to
+ * be allocated.
+ *
+ * @see sepol_iter
+ */
+
+/**
+ * \ingroup libsepol_list
+ * \struct sepol_list
+ * Doubly-linked list struct type.
+ *
+ * @see libsepol_list
+ */
+struct sepol_list;
+
+/**
+ * \ingroup libsepol_list
+ * Create an sepol_list. On success, SEPOL_OK is returned
+ * and the list pointer passed in is set to an allocated
+ * sepol_list struct that has been initialized.
+ *
+ * @param h sepol handle (may be NULL)
+ * @param list pointer to a list pointer for returning the
+ * newly created list.
+ *
+ * \retval SEPOL_OK list successfully created
+ * \retval SEPOL_ENOMEM out of memory
+ */
+int sepol_list_create(struct sepol_handle *h, struct sepol_list **list);
+
+/**
+ * \ingroup libsepol_list
+ * Destroy an sepol_list. This will _not_ free the memory
+ * for the list items, only for the internal list structures.
+ * The list items memory should be freed by the caller.
+ *
+ * @param list list to destroy
+ */
+void sepol_list_free(struct sepol_list *list);
+
+/**
+ * \ingroup libsepol_list
+ * Return the lenght of the list. This is a constant time
+ * operation.
+ *
+ * @param list list object
+ *
+ * \returns length of the list
+ */
+unsigned int sepol_list_length(struct sepol_list *list);
+
+/**
+ * \ingroup libsepol_list
+ * Append an item to the list. If successful, the item will
+ * become the last item in the list.
+ *
+ * @param h sepol handle (may be NULL)
+ * @param list list to which to append
+ * @param item to append
+ *
+ * \retval SEPOL_OK success
+ * \retval SEPOL_ENOMEM out of memory
+ */
+int sepol_list_append(struct sepol_handle *h, struct sepol_list *list, void *item);
+
+/**
+ * \ingroup libsepol_list
+ * Prepend an item to the list. If successful, the item will
+ * become the first item in the list.
+ *
+ * @param h sepol handle (may be NULL)
+ * @param list list to which to prepend
+ * @param item to prepend
+ *
+ * \retval SEPOL_OK success
+ * \retval SEPOL_ENOMEM out of memory
+ */
+int sepol_list_prepend(struct sepol_handle *h, struct sepol_list *list, void *item);
+
+/**
+ * \ingroup libsepol_list
+ * Insert an item before the iterator position. The existing item is
+ * shifted to the next position in the list. The iterator continues to
+ * point at the same item, though the position of that item will have
+ * moved forward by one.
+ *
+ * @param h sepol handle (may be NULL)
+ * @param list list to which to insert
+ * @param iter iter representing the insertion position
+ * @param item item to insert
+ *
+ * \retval SEPOL_OK success
+ * \retval SEPOL_ENOMEM out of memory
+ */
+int sepol_list_insert(struct sepol_handle *h, struct sepol_list *list,
+ struct sepol_iter *iter, void *item);
+
+/**
+ * \ingroup libsepol_list
+ * Insert into the list all of the items returned by the iter. This method
+ * is useful for inserting all of the items from another data structure
+ * into the list (because a standard iterator is used any data structure that
+ * supports iteratoration can be used).
+ *
+ * @param h sepol handle (may be NULL)
+ * @param list list to extend
+ * @param iter iterator for data to extend
+ *
+ * \retval SEPOL_OK success
+ * \retval SEPOL_ENOMEM out of memory
+ */
+int sepol_list_extend(struct sepol_handle *h, struct sepol_list *list,
+ struct sepol_iter *iter);
+
+/**
+ * \ingroup libsepol_list
+ * Convenience function to extend a list with another list. Internally, simply
+ * creates a an iter pointing to the beginning of the list and calls
+ * sepol_list_extend.
+ *
+ * @param h sepol handle (may be NULL)
+ * @param list list to extend
+ * @param other source list
+ *
+ * \retval SEPOL_OK success
+ * \retval SEPOL_ENOMEM out of memory
+ */
+int sepol_list_extend_list(struct sepol_handle *h, struct sepol_list *list,
+ struct sepol_list *other);
+
+/**
+ * \ingroup libsepol_list
+ * Remove and return the first item in the list. Item will be set
+ * to the item if the operation was successful.
+ *
+ * @param h sepol handle (may be NULL)
+ * @param list list from which to pop item
+ * @param item pointer that will be set to the popped item
+ *
+ * \retval SEPOL_OK succss
+ * \retval SEPOL_ERANGE empty list
+ */
+int sepol_list_pop_front(struct sepol_handle *h, struct sepol_list *list,
+ void **item);
+
+/**
+ * \ingroup libsepol_list
+ * Remove and return the last item in the list. Item will be set
+ * to the item if the operation was successful.
+ *
+ * @param h sepol handle (may be NULL)
+ * @param list list from which to pop item
+ * @param item that will be set to the popped item
+ *
+ * \retval SEPOL_OK succss
+ * \retval SEPOL_ERANGE: empty list
+ */
+int sepol_list_pop_back(struct sepol_handle *h, struct sepol_list *list,
+ void **item);
+
+/**
+ * \ingroup libsepol_list
+ * Delete an item at the iterator position. The iterator is no longer
+ * valid after deletion (if continued iteration is needed, the iterator
+ * should be copied and the copy advanced prior to deletion).
+ *
+ * @param h sepol handle (may be NULL)
+ * @param list list from which to delete item
+ * @param iter representing the position of the item to delete
+ *
+ * \retval SEPOL_OK success
+ */
+int sepol_list_del(struct sepol_handle *h, struct sepol_list *list,
+ struct sepol_iter *iter);
+
+/**
+ * \ingroup libsepol_list
+ * Position the iterator at the beginning of the list. If the list
+ * is empty SEPOL_ITERSTOP will be returned and the iterator will not
+ * be valid.
+ *
+ * @param h sepol handle (may be NULL)
+ * @param list list to iterate over
+ * @param iter iterator to set to list beginning
+ *
+ * \retval SEPOL_OK success
+ * \retval SEPOL_ITERSTOP empty list
+ */
+int sepol_list_begin(struct sepol_handle *h, struct sepol_list *list,
+ struct sepol_iter *iter);
+
+/**
+ * \ingroup libsepol_list
+ * Position the iterator at the end of the list. If the list
+ * is empty SEPOL_ITERSTOP will be returned and the iterator will not
+ * be valid.
+ *
+ * @param h sepol handle (may be NULL)
+ * \retval SEPOL_OK success
+ * \retval SEPOL_ITERSTOP empty list
+ */
+int sepol_list_end(struct sepol_handle *h, struct sepol_list *list,
+ struct sepol_iter *iter);
+
+#endif
diff -r c0ca24c3e136 libsepol/src/iter.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libsepol/src/iter.c Wed Apr 18 16:30:08 2007 -0400
@@ -0,0 +1,186 @@
+/*
+ * Author : Karl MacMillan <kmacmillan@mentalrootkit.com>
+ *
+ * Copyright (C) 2006-2007 Red Hat, Inc.
+ *
+ * This 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 2.1 of the License, or (at your option) any later version.
+ *
+ * This 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 this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <sepol/iter.h>
+#include <sepol/errcodes.h>
+
+#include "debug.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+struct sepol_iter
+{
+ void *state;
+ int (*next)(struct sepol_handle *, struct sepol_iter *);
+ int (*prev)(struct sepol_handle *, struct sepol_iter *);
+ int (*get)(struct sepol_handle *, struct sepol_iter *, void **);
+ int (*clone)(struct sepol_handle *, const struct sepol_iter *, struct sepol_iter *);
+ int (*free_fn)(struct sepol_handle *, void *);
+};
+
+int sepol_iter_create(struct sepol_handle *h, struct sepol_iter **iter)
+{
+ *iter = (struct sepol_iter*)calloc(1, sizeof(struct sepol_iter));
+ if (*iter == NULL) {
+ ERR(h, "out of memory");
+ return SEPOL_ENOMEM;
+ }
+
+ return SEPOL_OK;
+}
+
+int sepol_iter_free(struct sepol_handle *h, struct sepol_iter *iter)
+{
+ int ret;
+ if (iter->free_fn != NULL) {
+ ret = iter->free_fn(h, iter->state);
+ }
+ free(iter);
+
+ return ret;
+}
+
+int sepol_iter_clone(struct sepol_handle *h, const struct sepol_iter *iter,
+ struct sepol_iter **new_iter)
+{
+ int ret;
+
+ if (iter->clone == NULL) {
+ ERR(h, "iterator copying not supported");
+ return SEPOL_ENOTSUP;
+ }
+
+ ret = sepol_iter_create(h, new_iter);
+ if (ret < 0)
+ return ret;
+
+ return iter->clone(h, iter, *new_iter);
+}
+
+int sepol_iter_get_data(struct sepol_handle *h, struct sepol_iter *iter, void **data)
+{
+ assert(iter);
+ assert(iter->get);
+
+ return iter->get(h, iter, data);
+}
+
+int sepol_iter_next(struct sepol_handle *h, struct sepol_iter *iter)
+{
+ assert(iter);
+ assert(iter->next);
+
+ return iter->next(h, iter);
+}
+
+int sepol_iter_prev(struct sepol_handle *h, struct sepol_iter *iter)
+{
+ assert(iter);
+
+ if (iter->prev == NULL) {
+ ERR(h, "iterator previous not supported");
+ return SEPOL_ENOTSUP;
+ }
+
+ return iter->prev(h, iter);
+}
+
+/* At some point forward and backward should be overridable by
+ * the data structures. Depending on the data structure there
+ * could be significant performance improvements by directly
+ * implementing forward and backward.
+ */
+int sepol_iter_forward(struct sepol_handle *h, struct sepol_iter *iter,
+ unsigned int distance)
+{
+ unsigned int i = 0;
+ int ret = SEPOL_OK;
+
+ while (i < distance && ret == SEPOL_OK) {
+ ret = sepol_iter_next(h, iter);
+ i++;
+ }
+
+ return ret;
+}
+
+int sepol_iter_backward(struct sepol_handle *h, struct sepol_iter *iter,
+ unsigned int distance)
+{
+ unsigned int i = 0;
+ int ret = SEPOL_OK;
+
+ while (i < distance && ret == SEPOL_OK) {
+ ret = sepol_iter_prev(h, iter);
+ i++;
+ }
+
+ return ret;
+}
+
+void sepol_iter_set_state(struct sepol_iter *iter, void *state)
+{
+ assert(iter);
+ if (iter->state && iter->free_fn)
+ iter->free_fn(NULL, iter->state);
+ iter->state = state;
+}
+
+void *sepol_iter_get_state(const struct sepol_iter *iter)
+{
+ assert(iter);
+ return iter->state;
+}
+
+void sepol_iter_set_next(struct sepol_iter *iter,
+ int (*next)(struct sepol_handle *, struct sepol_iter *))
+{
+ assert(iter);
+ iter->next = next;
+}
+
+void sepol_iter_set_prev(struct sepol_iter *iter,
+ int (*prev)(struct sepol_handle *, struct sepol_iter *))
+{
+ assert(iter);
+ iter->prev = prev;
+}
+
+void sepol_iter_set_get_data(struct sepol_iter *iter,
+ int (*get)(struct sepol_handle *, struct sepol_iter *, void **))
+{
+ assert(iter);
+ iter->get = get;
+}
+
+void sepol_iter_set_free(struct sepol_iter *iter, int (*state_free)(struct sepol_handle *, void *))
+{
+ assert(iter);
+ iter->free_fn = state_free;
+}
+
+void sepol_iter_set_clone(struct sepol_iter *iter,
+ int (*clone)(struct sepol_handle *, const struct sepol_iter *old, struct sepol_iter *new_iter))
+{
+ assert(iter);
+ iter->clone = clone;
+}
diff -r c0ca24c3e136 libsepol/src/list.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libsepol/src/list.c Wed Apr 18 16:30:08 2007 -0400
@@ -0,0 +1,422 @@
+/*
+ * Author : Karl MacMillan <kmacmillan@mentalrootkit.com>
+ *
+ * Copyright (C) 2006-2007 Red Hat, Inc.
+ *
+ * This 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 2.1 of the License, or (at your option) any later version.
+ *
+ * This 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 this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <sepol/errcodes.h>
+
+#include <sepol/list.h>
+#include <sepol/iter.h>
+
+#include "debug.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct sepol_list_item
+{
+ struct sepol_list_item *next;
+ struct sepol_list_item *prev;
+ void *item;
+};
+
+struct sepol_list
+{
+ struct sepol_list_item *head;
+ struct sepol_list_item *tail;
+ unsigned int len;
+};
+
+int sepol_list_create(struct sepol_handle *h, struct sepol_list **list)
+{
+ assert(list);
+
+ *list = (struct sepol_list *)calloc(1, sizeof(struct sepol_list));
+ if (*list == NULL) {
+ ERR(h, "out of memory");
+ return SEPOL_ENOMEM;
+ }
+
+ return SEPOL_OK;
+}
+
+void sepol_list_free(struct sepol_list *list)
+{
+ struct sepol_list_item *cur, *next;
+
+ if (list == NULL)
+ return;
+
+ cur = list->head;
+ while (cur != NULL) {
+ next = cur->next;
+ free(cur);
+ cur = next;
+ }
+
+ free(list);
+}
+
+unsigned int sepol_list_length(struct sepol_list *list)
+{
+ assert(list);
+ return list->len;
+}
+
+static int sepol_list_item_create(struct sepol_handle *h,
+ struct sepol_list_item **x)
+{
+ *x = calloc(1, sizeof(struct sepol_list_item));
+ if (*x == NULL) {
+ ERR(h, "out of memory");
+ return SEPOL_ENOMEM;
+ } else {
+ return SEPOL_OK;
+ }
+}
+
+int sepol_list_append(struct sepol_handle *h, struct sepol_list *list, void *item)
+{
+ int ret;
+ struct sepol_list_item *x;
+
+ assert(list);
+
+ ret = sepol_list_item_create(h, &x);
+ if (ret < 0)
+ return ret;
+ x->item = item;
+
+ /* empty list */
+ if (list->tail == NULL) {
+ list->tail = x;
+ list->head = x;
+ x->prev = NULL;
+ x->next = NULL;
+ } else {
+ /* non-empty list */
+ list->tail->next = x;
+ x->prev = list->tail;
+ x->next = NULL;
+ list->tail = x;
+ }
+
+ list->len++;
+ return SEPOL_OK;
+}
+
+int sepol_list_prepend(struct sepol_handle *h, struct sepol_list *list, void *item)
+{
+ int ret;
+ struct sepol_list_item *x;
+
+ assert(list);
+
+ ret = sepol_list_item_create(h, &x);
+ if (ret < 0)
+ return ret;
+ x->item = item;
+
+ /* empty list */
+ if (list->tail == NULL) {
+ list->tail = x;
+ list->head = x;
+ x->prev = NULL;
+ x->next = NULL;
+ } else {
+ x->next = list->head;
+ list->head->prev = x;
+ x->prev = NULL;
+ list->head = x;
+ }
+
+ list->len++;
+ return SEPOL_OK;
+}
+
+int sepol_list_insert(struct sepol_handle *h, struct sepol_list *list,
+ struct sepol_iter *iter, void *item)
+{
+ int ret;
+ struct sepol_list_item *x, *cur;
+
+ assert(list);
+
+ cur = (struct sepol_list_item*)sepol_iter_get_state(iter);
+ assert(cur);
+
+ /* Short circuit for prepend and append. */
+ if (list->head == cur) {
+ return sepol_list_prepend(h, list, item);
+ } else if (list->tail == cur) {
+ return sepol_list_append(h, list, item);
+ }
+
+ ret = sepol_list_item_create(h, &x);
+ if (ret < 0)
+ return ret;
+ x->item = item;
+
+ x->prev = cur->prev;
+ x->prev->next = x;
+ x->next = cur;
+ cur->prev = x;
+
+ list->len++;
+ return SEPOL_OK;
+}
+
+int sepol_list_extend(struct sepol_handle *h, struct sepol_list *list,
+ struct sepol_iter *iter)
+{
+ int ret = SEPOL_OK;
+ void *data;
+
+ while (ret == SEPOL_OK) {
+ ret = sepol_iter_get_data(h, iter, &data);
+ if (ret < 0)
+ return ret;
+ ret = sepol_list_append(h, list, data);
+ if (ret < 0)
+ return ret;
+
+ ret = sepol_iter_next(h, iter);
+ }
+ if (ret != SEPOL_ITERSTOP)
+ return ret;
+ else
+ return SEPOL_OK;
+}
+
+int sepol_list_extend_list(struct sepol_handle *h, struct sepol_list *list,
+ struct sepol_list *other)
+{
+ int ret;
+ struct sepol_iter *iter;
+
+ if (!other->len)
+ return SEPOL_OK;
+
+ ret = sepol_iter_create(h, &iter);
+ if (ret < 0)
+ return ret;
+
+ ret = sepol_list_begin(h, other, iter);
+ if (ret < 0)
+ goto out;
+ ret = sepol_list_extend(h, list, iter);
+
+out:
+ sepol_iter_free(h, iter);
+ return ret;
+}
+
+
+int sepol_list_pop_front(struct sepol_handle *h, struct sepol_list *list,
+ void **item)
+{
+ struct sepol_list_item *cur;
+
+ if (list->head == NULL)
+ return SEPOL_ERANGE;
+
+ cur = list->head;
+ if (list->head == list->tail) {
+ list->head = NULL;
+ list->tail = NULL;
+ } else {
+ list->head = list->head->next;
+ if (list->head)
+ list->head->prev = NULL;
+ }
+
+ *item = cur->item;
+ free(cur);
+
+ return SEPOL_OK;
+}
+
+int sepol_list_pop_back(struct sepol_handle *h, struct sepol_list *list,
+ void **item)
+{
+ struct sepol_list_item *cur;
+
+ if (list->tail == NULL)
+ return SEPOL_ERANGE;
+
+ cur = list->tail;
+
+ if (list->head == list->tail) {
+ list->head = NULL;
+ list->tail = NULL;
+ } else {
+ list->tail = list->tail->prev;
+ if (list->tail)
+ list->tail->next = NULL;
+ }
+
+ *item = cur->item;
+ free(cur);
+
+ return SEPOL_OK;
+}
+
+
+int sepol_list_del(struct sepol_handle *h, struct sepol_list *list,
+ struct sepol_iter *iter)
+{
+ struct sepol_list_item *cur;
+
+ cur = sepol_iter_get_state(iter);
+ assert(cur);
+
+ if (list->head == cur && list->tail == cur) {
+ list->head = NULL;
+ list->tail = NULL;
+ goto out;
+ }
+
+ if (cur->prev)
+ cur->prev->next = cur->next;
+ else
+ list->head = cur->next;
+
+ if (cur->next)
+ cur->next->prev = cur->prev;
+ else
+ list->tail = cur->prev;
+
+out:
+ free(cur);
+ list->len--;
+ sepol_iter_set_state(iter, NULL);
+ return SEPOL_OK;
+}
+
+static int sepol_list_next(struct sepol_handle *h, struct sepol_iter *iter)
+{
+ struct sepol_list_item *cur;
+
+ assert(iter);
+
+ cur = (struct sepol_list_item*)sepol_iter_get_state(iter);
+ assert(cur);
+
+ if (cur->next == NULL) {
+ /* set the state to NULL to catch using this iterator
+ * after ITERSTOP is returned (which is a bug). */
+ sepol_iter_set_state(iter, NULL);
+ return SEPOL_ITERSTOP;
+ } else {
+ sepol_iter_set_state(iter, cur->next);
+ return SEPOL_OK;
+ }
+}
+
+static int sepol_list_prev(struct sepol_handle *h, struct sepol_iter *iter)
+{
+ struct sepol_list_item *cur;
+
+ assert(iter);
+
+ cur = (struct sepol_list_item*)sepol_iter_get_state(iter);
+ assert(cur);
+
+ if (cur->prev == NULL) {
+ /* set the state to NULL to catch using this iterator
+ * after ITERSTOP is returned (which is a bug). */
+ sepol_iter_set_state(iter, NULL);
+ return SEPOL_ITERSTOP;
+ } else {
+ sepol_iter_set_state(iter, cur->prev);
+ return SEPOL_OK;
+ }
+}
+
+static int sepol_list_iter_get_data(struct sepol_handle *h,
+ struct sepol_iter *iter, void **data)
+{
+ struct sepol_list_item *cur;
+
+ assert(iter);
+
+ cur = (struct sepol_list_item*)sepol_iter_get_state(iter);
+ if (!cur) {
+ return SEPOL_ENOENT;
+ }
+
+ *data = cur->item;
+
+ return SEPOL_OK;
+}
+
+
+static int sepol_list_iter_clone(struct sepol_handle *h, const struct sepol_iter *o,
+ struct sepol_iter *n);
+
+#define ITERSETUP(iter) { sepol_iter_set_next(iter, sepol_list_next); \
+ sepol_iter_set_prev(iter, sepol_list_prev); \
+ sepol_iter_set_clone(iter, sepol_list_iter_clone); \
+ sepol_iter_set_get_data(iter, sepol_list_iter_get_data); }
+
+static int sepol_list_iter_clone(struct sepol_handle *h, const struct sepol_iter *o,
+ struct sepol_iter *n)
+{
+ void *state = sepol_iter_get_state(o);
+ sepol_iter_set_state(n, state);
+
+ ITERSETUP(n);
+
+ return SEPOL_OK;
+}
+
+
+int sepol_list_begin(struct sepol_handle *h, struct sepol_list *list,
+ struct sepol_iter *iter)
+{
+ assert(list);
+ assert(iter);
+
+ if (list->head == NULL)
+ return SEPOL_ITERSTOP;
+
+ sepol_iter_set_state(iter, list->head);
+
+ ITERSETUP(iter);
+
+ return SEPOL_OK;
+}
+
+int sepol_list_end(struct sepol_handle *h, struct sepol_list *list,
+ struct sepol_iter *iter)
+{
+ assert(list);
+ assert(iter);
+
+ if (list->tail == NULL)
+ return SEPOL_ITERSTOP;
+
+ sepol_iter_set_state(iter, list->tail);
+
+ ITERSETUP(iter);
+
+ return SEPOL_OK;
+}
+
+
diff -r c0ca24c3e136 libsepol/tests/libsepol-tests.c
--- a/libsepol/tests/libsepol-tests.c Wed Apr 18 11:32:21 2007 -0400
+++ b/libsepol/tests/libsepol-tests.c Wed Apr 18 16:30:08 2007 -0400
@@ -22,6 +22,7 @@
#include "test-linker.h"
#include "test-expander.h"
#include "test-deps.h"
+#include "test-list.h"
#include <CUnit/Basic.h>
#include <CUnit/Console.h>
@@ -61,6 +62,7 @@ static int do_tests(int interactive, int
DECLARE_SUITE(linker);
DECLARE_SUITE(expander);
DECLARE_SUITE(deps);
+ DECLARE_SUITE(list);
if (verbose)
CU_basic_set_mode(CU_BRM_VERBOSE);
diff -r c0ca24c3e136 libsepol/tests/test-list.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libsepol/tests/test-list.c Wed Apr 18 16:30:08 2007 -0400
@@ -0,0 +1,373 @@
+/*
+ * Author : Karl MacMillan <kmacmillan@mentalrootkit.com>
+ *
+ * Copyright (C) 2006 Red Hat, Inc.
+ *
+ * This 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 2.1 of the License, or (at your option) any later version.
+ *
+ * This 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 this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "test-list.h"
+
+#include <sepol/list.h>
+#include <sepol/iter.h>
+#include <sepol/errcodes.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+int list_test_init(void)
+{
+ return 0;
+}
+
+int list_test_cleanup(void)
+{
+ return 0;
+}
+
+static void test_list_create(void)
+{
+ struct sepol_list *list;
+ int ret;
+
+ ret = sepol_list_create(NULL, &list);
+ CU_ASSERT(ret == 0);
+
+ sepol_list_free(list);
+}
+
+static void test_list(void)
+{
+ struct sepol_list *list;
+ struct sepol_iter *iter, *iter2;
+ struct sepol_handle *h;
+ int ret;
+ int i, *num, nums[6];
+
+ for (i = 0; i < 6; i++)
+ nums[i] = i;
+
+ h = sepol_handle_create();
+ CU_ASSERT(h != NULL);
+
+ ret = sepol_iter_create(h, &iter);
+ CU_ASSERT(ret == 0);
+
+ ret = sepol_list_create(h, &list);
+ CU_ASSERT(ret == 0);
+
+ ret = sepol_list_append(h, list, &nums[4]);
+ CU_ASSERT(ret == 0);
+
+ ret = sepol_list_append(h, list, &nums[5]);
+ CU_ASSERT(ret == 0);
+
+ ret = sepol_list_prepend(h, list, &nums[1]);
+ CU_ASSERT(ret == 0);
+
+ ret = sepol_list_begin(h, list, iter);
+ CU_ASSERT(ret == 0);
+ ret = sepol_iter_forward(h, iter, 1);
+ CU_ASSERT(ret == 0);
+
+ ret = sepol_list_insert(h, list, iter, &nums[2]);
+ CU_ASSERT(ret == 0);
+
+ ret = sepol_list_begin(h, list, iter);
+ CU_ASSERT(ret == 0);
+ ret = sepol_list_insert(h, list, iter, &nums[0]);
+ CU_ASSERT(ret == 0);
+
+ ret = sepol_list_begin(h, list, iter);
+ CU_ASSERT(ret == 0);
+ ret = sepol_iter_forward(h, iter, 3);
+ CU_ASSERT(ret == 0);
+
+ ret = sepol_list_insert(h, list, iter, &nums[3]);
+ CU_ASSERT(ret == 0);
+
+ CU_ASSERT(sepol_list_length(list) == 6);
+
+ ret = sepol_list_begin(h, list, iter);
+ CU_ASSERT(ret == 0);
+ i = 0;
+
+ sepol_foreach(h, ret, num, iter) {
+ CU_ASSERT(*num == i);
+ i++;
+ }
+
+ CU_ASSERT(i == 6);
+ CU_ASSERT(ret == SEPOL_ITERSTOP);
+
+ ret = sepol_list_end(h, list, iter);
+ CU_ASSERT(ret == 0);
+ i = 5;
+ while (ret == SEPOL_OK) {
+ ret = sepol_iter_get_data(h, iter, (void**)&num);
+ CU_ASSERT(ret == SEPOL_OK);
+ CU_ASSERT(*num == i);
+ i--;
+ ret = sepol_iter_prev(h, iter);
+ }
+ CU_ASSERT(i == -1);
+ CU_ASSERT(ret == SEPOL_ITERSTOP);
+
+ ret = sepol_list_end(h, list, iter);
+ CU_ASSERT(ret == 0);
+ ret = sepol_iter_prev(h, iter);
+ CU_ASSERT(ret == 0);
+ ret = sepol_iter_get_data(h, iter, (void**)&num);
+ CU_ASSERT(ret == SEPOL_OK);
+ CU_ASSERT(*num == 4);
+
+
+ ret = sepol_list_begin(h, list, iter);
+ CU_ASSERT(ret == 0);
+ i = 0;
+ while (ret == SEPOL_OK) {
+ if (i == 2) {
+ ret = sepol_iter_clone(h, iter, &iter2);
+ CU_ASSERT(ret == SEPOL_OK);
+ ret = sepol_iter_next(h, iter);
+ CU_ASSERT(ret == SEPOL_OK);
+ ret = sepol_list_del(h, list, iter2);
+ CU_ASSERT(ret == SEPOL_OK);
+ i++;
+ continue;
+ }
+ i++;
+ ret = sepol_iter_next(h, iter);
+ }
+ CU_ASSERT(ret == SEPOL_ITERSTOP);
+ CU_ASSERT(i == 6);
+ CU_ASSERT(sepol_list_length(list) == 5);
+
+ sepol_iter_free(h, iter);
+ sepol_iter_free(h, iter2);
+ sepol_list_free(list);
+ sepol_handle_destroy(h);
+}
+
+static void test_list_pop(void)
+{
+ int ret;
+ struct sepol_list *list;
+ struct sepol_handle *h;
+ void *item;
+
+ h = sepol_handle_create();
+ CU_ASSERT(h != NULL);
+
+ ret = sepol_list_create(h, &list);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_append(h, list, "webern");
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_append(h, list, "berg");
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_append(h, list, "schoenberg");
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_append(h, list, "sessions");
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_pop_back(h, list, &item);
+ CU_ASSERT(ret == SEPOL_OK);
+ CU_ASSERT(strcmp((char*)item, "sessions") == 0);
+
+ ret = sepol_list_pop_back(h, list, &item);
+ CU_ASSERT(ret == SEPOL_OK);
+ CU_ASSERT(strcmp((char*)item, "schoenberg") == 0);
+
+ ret = sepol_list_pop_front(h, list, &item);
+ CU_ASSERT(ret == SEPOL_OK);
+ CU_ASSERT(strcmp((char*)item, "webern") == 0);
+
+ ret = sepol_list_pop_back(h, list, &item);
+ CU_ASSERT(ret == SEPOL_OK);
+ CU_ASSERT(strcmp((char*)item, "berg") == 0);
+
+
+ ret = sepol_list_pop_back(h, list, &item);
+ CU_ASSERT(ret == SEPOL_ERANGE);
+
+ sepol_list_free(list);
+ sepol_handle_destroy(h);
+}
+
+static void test_list_extend(void)
+{
+ int ret, i;
+ struct sepol_list *serialism, *minimalism;
+ struct sepol_iter *iter;
+ struct sepol_handle *h;
+ char *composers[] = {"webern", "berg",
+ "schoenberg", "sessions",
+ "adams", "glass", "reich" };
+ char *composer;
+
+ h = sepol_handle_create();
+ CU_ASSERT(h != NULL);
+
+ ret = sepol_list_create(h, &serialism);
+ CU_ASSERT(ret == SEPOL_OK);
+
+
+ ret = sepol_list_create(h, &minimalism);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_append(h, serialism, composers[0]);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_append(h, serialism, composers[1]);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_append(h, serialism, composers[2]);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_append(h, serialism, composers[3]);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_append(h, minimalism, composers[4]);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_append(h, minimalism, composers[5]);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_append(h, minimalism, composers[6]);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_iter_create(h, &iter);
+ CU_ASSERT(ret == SEPOL_OK);
+ ret = sepol_list_begin(h, minimalism, iter);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_extend(h, serialism, iter);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_begin(h, serialism, iter);
+ CU_ASSERT(ret == SEPOL_OK);
+ i = 0;
+ while (ret == SEPOL_OK) {
+ ret = sepol_iter_get_data(h, iter, (void**)&composer);
+ CU_ASSERT(ret == SEPOL_OK);
+ CU_ASSERT(strcmp(composers[i], composer) == 0);
+ ret = sepol_iter_next(h, iter);
+ i++;
+ }
+ CU_ASSERT(ret == SEPOL_ITERSTOP);
+
+ sepol_iter_free(h, iter);
+ sepol_list_free(serialism);
+ sepol_list_free(minimalism);
+ sepol_handle_destroy(h);
+}
+
+static void test_list_extend_list(void)
+{
+ int ret, i;
+ struct sepol_list *serialism, *minimalism;
+ struct sepol_iter *iter;
+ struct sepol_handle *h;
+ char *composers[] = {"webern", "berg",
+ "schoenberg", "sessions",
+ "adams", "glass", "reich" };
+ char *composer;
+
+
+ h = sepol_handle_create();
+ CU_ASSERT(h != NULL);
+
+ ret = sepol_list_create(h, &serialism);
+ CU_ASSERT(ret == SEPOL_OK);
+
+
+ ret = sepol_list_create(h, &minimalism);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_append(h, serialism, composers[0]);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_append(h, serialism, composers[1]);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_append(h, serialism, composers[2]);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_append(h, serialism, composers[3]);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_append(h, minimalism, composers[4]);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_append(h, minimalism, composers[5]);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_append(h, minimalism, composers[6]);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_list_extend_list(h, serialism, minimalism);
+ CU_ASSERT(ret == SEPOL_OK);
+
+ ret = sepol_iter_create(h, &iter);
+ CU_ASSERT(ret == SEPOL_OK);
+
+
+ ret = sepol_list_begin(h, serialism, iter);
+ CU_ASSERT(ret == SEPOL_OK);
+ i = 0;
+ while (ret == SEPOL_OK) {
+ ret = sepol_iter_get_data(h, iter, (void**)&composer);
+ CU_ASSERT(ret == SEPOL_OK);
+ CU_ASSERT(strcmp(composers[i], composer) == 0);
+ ret = sepol_iter_next(h, iter);
+ i++;
+ }
+ CU_ASSERT(ret == SEPOL_ITERSTOP);
+
+ sepol_iter_free(h, iter);
+ sepol_list_free(serialism);
+ sepol_list_free(minimalism);
+ sepol_handle_destroy(h);
+}
+
+int list_add_tests(CU_pSuite suite)
+{
+ if (NULL == CU_add_test(suite, "test_list_create", test_list_create)) {
+ return -1;
+ }
+
+ if (NULL == CU_add_test(suite, "test_list",
+ test_list)) {
+ return -1;
+ }
+
+ if (NULL == CU_add_test(suite, "test_list_pop", test_list_pop)) {
+ return -1;
+ }
+
+ if (NULL == CU_add_test(suite, "test_list_extend", test_list_extend)) {
+ return -1;
+ }
+
+ if (NULL == CU_add_test(suite, "test_list_extend_list", test_list_extend_list)) {
+ return -1;
+ }
+
+ return 0;
+}
diff -r c0ca24c3e136 libsepol/tests/test-list.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libsepol/tests/test-list.h Wed Apr 18 16:30:08 2007 -0400
@@ -0,0 +1,12 @@
+/* Author : Karl MacMillan <kmacmillan@mentalrootkit.com> */
+
+#ifndef __test_list_h__
+#define __test_list_h__
+
+#include <CUnit/Basic.h>
+
+int list_test_init(void);
+int list_test_cleanup(void);
+int list_add_tests(CU_pSuite suite);
+
+#endif
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2007-04-18 21:03 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-04-18 20:59 [PATCH - policyrep] Add generic iterators and a linked-list data structure to libsepol Karl MacMillan
-- strict thread matches above, loose matches on Subject: below --
2007-04-18 20:45 Karl MacMillan
2007-04-18 20:58 ` Karl MacMillan
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.