summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/Makefile.am4
-rw-r--r--common/configure.ac2
-rw-r--r--common/refarray/Makefile.am36
-rw-r--r--common/refarray/configure.ac30
-rw-r--r--common/refarray/m4/.dir0
-rw-r--r--common/refarray/ref_array.c294
-rw-r--r--common/refarray/ref_array.h84
-rw-r--r--common/refarray/ref_array.pc.in11
-rw-r--r--common/refarray/ref_array_ut.c343
9 files changed, 802 insertions, 2 deletions
diff --git a/common/Makefile.am b/common/Makefile.am
index 1659e0d17..29226ea5f 100644
--- a/common/Makefile.am
+++ b/common/Makefile.am
@@ -1,5 +1,5 @@
ACLOCAL_AMFLAGS = -I m4
-SUBDIRS = trace collection ini dhash path_utils elapi
+SUBDIRS = trace collection ini dhash path_utils refarray elapi
dist_noinst_DATA = \
m4
@@ -12,12 +12,14 @@ libsssd_util_la_LIBADD = \
collection/libcollection.la \
ini/libini_config.la \
dhash/libdhash.la \
+ refarray/libref_array.la \
elapi/libelapi.la
libsssd_util_la_CFLAGS = $(AM_CFLAGS) \
-I ./collection \
-I ./ini \
-I ./dhash \
-I ./elapi \
+ -I ./refarray \
-I ./trace
endif
diff --git a/common/configure.ac b/common/configure.ac
index 1df6c2277..a017bcc73 100644
--- a/common/configure.ac
+++ b/common/configure.ac
@@ -24,7 +24,7 @@ AS_IF([test ["$trace_level" -gt "0"] -a ["$trace_level" -lt "8"] ],[AC_SUBST([TR
AC_CONFIG_FILES([Makefile
trace/Makefile])
-AC_CONFIG_SUBDIRS([collection dhash ini path_utils elapi])
+AC_CONFIG_SUBDIRS([collection dhash ini path_utils refarray elapi])
AC_DEFUN([WITH_SINGLELIB],
[ AC_ARG_WITH([singlelib],
diff --git a/common/refarray/Makefile.am b/common/refarray/Makefile.am
new file mode 100644
index 000000000..573173ac3
--- /dev/null
+++ b/common/refarray/Makefile.am
@@ -0,0 +1,36 @@
+TRACE_LEVEL=@TRACE_VAR@
+
+topdir=$(srcdir)/..
+
+AM_CFLAGS =
+
+if HAVE_GCC
+ AM_CFLAGS += \
+ -Wall -Wshadow -Wstrict-prototypes -Wpointer-arith -Wcast-qual \
+ -Wcast-align -Wwrite-strings
+endif
+
+AM_CPPFLAGS = -I$(topdir)/trace -I$(topdir)/elapi/refarray $(TRACE_LEVEL)
+
+ACLOCAL_AMFLAGS = -I m4
+
+# Set up the pkg-config file
+pkgconfigdir = $(libdir)/pkgconfig
+dist_noinst_DATA = \
+ ref_array.pc \
+ m4
+
+# Build library
+noinst_LTLIBRARIES = libref_array.la
+libref_array_la_SOURCES = \
+ ref_array.c \
+ ref_array.h
+
+# Build unit test
+check_PROGRAMS = ref_array_ut
+ref_array_ut_SOURCES = ref_array_ut.c
+ref_array_ut_LDADD = libref_array.la
+
+TESTS = ref_array_ut
+
+tests: all $(check_PROGRAMS)
diff --git a/common/refarray/configure.ac b/common/refarray/configure.ac
new file mode 100644
index 000000000..b220c521f
--- /dev/null
+++ b/common/refarray/configure.ac
@@ -0,0 +1,30 @@
+m4_include([../../version.m4])
+AC_INIT([sssd_libs],
+ VERSION_NUMBER,
+ [sssd-devel@lists.fedorahosted.org])
+AC_CONFIG_SRCDIR([ref_array.c])
+AC_CONFIG_AUX_DIR([build])
+AM_INIT_AUTOMAKE([-Wall -Werror foreign])
+AC_PROG_CC
+AC_PROG_LIBTOOL
+AC_CONFIG_MACRO_DIR([m4])
+AC_PROG_INSTALL
+
+AM_CONDITIONAL([HAVE_GCC], [test "$ac_cv_prog_gcc" = yes])
+
+m4_pattern_allow([AM_SILENT_RULES])
+AM_SILENT_RULES
+
+AC_CONFIG_HEADERS([config.h])
+
+# Enable trace build
+AC_ARG_ENABLE([trace],
+ [AS_HELP_STRING([--enable-trace[=LEVEL]],[build with low level tracing enabled])],
+ [trace_level="$enableval"],
+ [trace_level="0"])
+
+AS_IF([test ["$trace_level" -gt "0"] -a ["$trace_level" -lt "8"] ],[AC_SUBST([TRACE_VAR],["-DTRACE_LEVEL=$trace_level"])])
+
+AC_CONFIG_FILES([Makefile ref_array.pc])
+
+AC_OUTPUT
diff --git a/common/refarray/m4/.dir b/common/refarray/m4/.dir
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/common/refarray/m4/.dir
diff --git a/common/refarray/ref_array.c b/common/refarray/ref_array.c
new file mode 100644
index 000000000..d33a16b4f
--- /dev/null
+++ b/common/refarray/ref_array.c
@@ -0,0 +1,294 @@
+/*
+ REF ARRAY
+
+ Implementation of the dynamic array with reference count.
+
+ Copyright (C) Dmitri Pal <dpal@redhat.com> 2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+ This program 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#define _GNU_SOURCE
+#include <errno.h> /* for errors */
+#include <stdint.h>
+#include <malloc.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "ref_array.h"
+#include "config.h"
+#include "trace.h"
+
+/* The structure used in referenced array */
+struct ref_array {
+ void *storage; /* The storage buffer */
+ size_t elsize; /* Size of one element in the buffer */
+ uint32_t size; /* Size of the storage in items */
+ uint32_t grow_by; /* What increment use to reallocate memory */
+ uint32_t len; /* Number of the elements in the array */
+ uint32_t refcount; /* Reference count */
+ ref_array_fn cb; /* Cleanup callback */
+ void *cb_data; /* Caller's callback data */
+};
+
+/****************************************************/
+/* INTERNAL FUNCTIONS */
+/****************************************************/
+static int ref_array_grow(struct ref_array *ra)
+{
+ int error = EOK;
+ void *newbuf = NULL;
+
+ TRACE_FLOW_STRING("ref_array_grow", "Entry");
+
+ TRACE_INFO_NUMBER("Current length: ", ra->len);
+ TRACE_INFO_NUMBER("Current size: ", ra->size);
+
+ /* Grow buffer if needed */
+ newbuf = realloc(ra->storage, (ra->size + ra->grow_by) * ra->elsize);
+ if (newbuf == NULL) {
+ TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM);
+ return ENOMEM;
+ }
+
+ ra->storage = newbuf;
+ ra->size += ra->grow_by;
+
+ TRACE_INFO_NUMBER("Final size: ", ra->size);
+ TRACE_FLOW_NUMBER("elapi_grow_data. Exit. Returning", error);
+ return error;
+
+}
+
+
+/****************************************************/
+/* PUBLIC FUNCTIONS */
+/****************************************************/
+
+/* Create referenced array */
+int ref_array_create(struct ref_array **ra,
+ size_t elemsz,
+ uint32_t grow_by,
+ ref_array_fn cb,
+ void *data)
+{
+ struct ref_array *new_ra = NULL;
+
+ TRACE_FLOW_STRING("ref_array_create", "Entry");
+
+ if (!ra) {
+ TRACE_ERROR_NUMBER("Uninitialized argument.", EINVAL);
+ return EINVAL;
+ }
+
+ if ((!elemsz) || (!grow_by)) {
+ TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
+ return EINVAL;
+ }
+
+ new_ra = (struct ref_array *)malloc(sizeof(struct ref_array));
+
+ if (!new_ra) {
+ TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM);
+ return ENOMEM;
+ }
+
+ new_ra->storage = NULL;
+ new_ra->elsize = elemsz;
+ new_ra->size = 0;
+ new_ra->grow_by = grow_by;
+ new_ra->len = 0;
+ new_ra->refcount = 1;
+ new_ra->cb = cb;
+ new_ra->cb_data = data;
+
+ *ra = new_ra;
+
+ TRACE_FLOW_STRING("ref_array_create", "Exit");
+ return EOK;
+}
+
+/* Get new reference to an array */
+struct ref_array *ref_array_getref(struct ref_array *ra)
+{
+ TRACE_FLOW_STRING("ref_array_getref", "Entry");
+
+ /* Check if array is not NULL */
+ if (ra) {
+ TRACE_INFO_NUMBER("Increasing reference count. Current: ", ra->refcount);
+ /* Increase reference count */
+ ra->refcount++;
+ TRACE_INFO_NUMBER("Increased reference count. New: ", ra->refcount);
+
+ }
+ else {
+ TRACE_ERROR_STRING("Uninitialized array.", "Returning NULL");
+ }
+
+ TRACE_FLOW_STRING("ref_array_getref", "Exit");
+ return ra;
+}
+
+/* Delete the array */
+void ref_array_destroy(struct ref_array *ra)
+{
+ int idx;
+
+ TRACE_FLOW_STRING("ref_array_destroy", "Entry");
+
+ /* Check if array is not NULL */
+ if (!ra) {
+ TRACE_ERROR_STRING("Uninitialized array.", "Coding error???");
+ return;
+ }
+
+ TRACE_INFO_NUMBER("Current reference count: ", ra->refcount);
+ if (ra->refcount) {
+ /* Decrease reference count */
+ ra->refcount--;
+ if (ra->refcount == 0) {
+ TRACE_INFO_NUMBER("It is time to delete array. Count:", ra->refcount);
+ if (ra->cb) {
+ for (idx = 0; idx < ra->len; idx++) {
+ ra->cb((unsigned char *)(ra->storage) + idx * ra->elsize,
+ REF_ARRAY_DESTROY, ra->cb_data);
+ }
+ }
+ free(ra->storage);
+ free(ra);
+ }
+ }
+ else {
+ /* Should never be here...
+ * This can happen if the caller by mistake would try to
+ * destroy the object from within the callback. Brrr....
+ */
+ TRACE_ERROR_STRING("Reference count is 0.", "Coding error???");
+ }
+
+ TRACE_FLOW_STRING("ref_array_destroy", "Exit");
+}
+
+/* Add new element to the array */
+int ref_array_append(struct ref_array *ra, void *element)
+{
+ int error = EOK;
+
+ TRACE_FLOW_STRING("ref_array_append", "Entry");
+ if ((!ra) || (!element)) {
+ TRACE_ERROR_NUMBER("Uninitialized argument.", EINVAL);
+ return EINVAL;
+ }
+
+ /* Do we have enough room for a new element? */
+ if (ra->size == ra->len) {
+ error = ref_array_grow(ra);
+ if (error) {
+ TRACE_ERROR_NUMBER("Failed to grow array.", error);
+ return EINVAL;
+ }
+ }
+
+ /* Copy element */
+ memcpy((unsigned char *)(ra->storage) + ra->len * ra->elsize,
+ element,
+ ra->elsize);
+
+ ra->len++;
+
+ TRACE_FLOW_STRING("ref_array_append", "Exit");
+ return error;
+}
+
+/* Get element */
+void *ref_array_get(struct ref_array *ra, uint32_t idx, void *acptr)
+{
+ TRACE_FLOW_STRING("ref_array_get", "Entry");
+
+ if (!ra) {
+ TRACE_ERROR_STRING("Uninitialized argument.", "");
+ return NULL;
+ }
+
+ if (idx >= ra->len) {
+ TRACE_ERROR_NUMBER("Invalid idx.", idx);
+ return NULL;
+ }
+
+ TRACE_INFO_NUMBER("Index: ", idx);
+
+ if (acptr) {
+
+ TRACE_INFO_STRING("Copying data.", "");
+ memcpy(acptr,
+ (unsigned char *)(ra->storage) + idx * ra->elsize,
+ ra->elsize);
+
+ }
+
+ TRACE_FLOW_STRING("ref_array_get returning internal storage", "Exit");
+ return (unsigned char *)(ra->storage) + idx * ra->elsize;
+}
+
+
+/* Get length */
+int ref_array_getlen(struct ref_array *ra, uint32_t *len)
+{
+ TRACE_FLOW_STRING("ref_array_getlen", "Entry");
+
+ if ((!ra) || (!len)) {
+ TRACE_ERROR_STRING("Uninitialized argument.", "");
+ return EINVAL;
+ }
+
+ *len = ra->len;
+
+ TRACE_FLOW_STRING("ref_array_getlen", "Exit");
+ return EOK;
+}
+
+/* Alternative function to get length */
+uint32_t ref_array_len(struct ref_array *ra)
+{
+ TRACE_FLOW_STRING("ref_array_len", "Entry");
+
+ if (!ra) {
+ TRACE_ERROR_STRING("Uninitialized argument.", "");
+ errno = EINVAL;
+ return 0;
+ }
+
+ TRACE_FLOW_STRING("ref_array_len", "Exit");
+ return ra->len;
+}
+
+
+/* Debug function */
+void ref_array_debug(struct ref_array *ra)
+{
+ int i,j;
+
+ printf("\nARRAY DUMP START\n");
+ printf("Length = %u\n", ra->len);
+ printf("Size = %u\n", ra->size);
+ printf("Element = %u\n", (unsigned int)(ra->elsize));
+ printf("Grow by = %u\n", ra->grow_by);
+ printf("Count = %u\n", ra->refcount);
+ printf("ARRAY:\n");
+ for (i = 0; i < ra->len; i++) {
+ for (j = 0; j < ra->elsize; j++) {
+ printf("%x", *((unsigned char *)(ra->storage) + i * ra->elsize + j));
+ }
+ printf("\n%s\n", *((char **)((unsigned char *)(ra->storage) + i * ra->elsize)));
+ }
+ printf("\nARRAY DUMP END\n\n");
+}
diff --git a/common/refarray/ref_array.h b/common/refarray/ref_array.h
new file mode 100644
index 000000000..42112907e
--- /dev/null
+++ b/common/refarray/ref_array.h
@@ -0,0 +1,84 @@
+/*
+ REF ARRAY
+
+ Header file for of the dynamic array with reference count.
+
+ Copyright (C) Dmitri Pal <dpal@redhat.com> 2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+ This program 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef REF_ARRAY_H
+#define REF_ARRAY_H
+
+#include <stdint.h>
+#include <stdlib.h>
+
+struct ref_array;
+
+#ifndef EOK
+#define EOK 0
+#endif
+
+/*************************************/
+/* Interface to the referenced array */
+/*************************************/
+
+typedef enum
+{
+ REF_ARRAY_DESTROY,
+ REF_ARRAY_DELETE,
+} ref_array_del_enum;
+
+/* Callback that can be provided by caller
+ * to free data when the storage is actually destroyed
+ */
+typedef void (*ref_array_fn)(void *elem,
+ ref_array_del_enum type,
+ void *data);
+
+
+/* Create referenced array */
+int ref_array_create(struct ref_array **ra,
+ size_t elem,
+ uint32_t grow_by,
+ ref_array_fn cb,
+ void *data);
+
+/* Get new reference to an array */
+struct ref_array *ref_array_getref(struct ref_array *ra);
+
+/* Delete the array */
+void ref_array_destroy(struct ref_array *ra);
+
+/* Add new element to the array */
+int ref_array_append(struct ref_array *ra, void *element);
+
+/* Get element */
+void *ref_array_get(struct ref_array *ra, uint32_t idx, void *acptr);
+
+/* Get array length */
+int ref_array_getlen(struct ref_array *ra, uint32_t *len);
+
+/* Alternative function to get length.
+ * Returns 0 if the array is invalid
+ */
+uint32_t ref_array_len(struct ref_array *ra);
+
+
+/* In future in might make sense to add entry points
+ * to insert and delete elements from the array.
+ * Current use cases do not require this kind of
+ * functionality so it is left out of the implementation
+ */
+
+#endif
diff --git a/common/refarray/ref_array.pc.in b/common/refarray/ref_array.pc.in
new file mode 100644
index 000000000..1fc06f71b
--- /dev/null
+++ b/common/refarray/ref_array.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: @PACKAGE_NAME@
+Description: Reference library
+Version: @PACKAGE_VERSION@
+Libs: -L${libdir} -lref_array
+Cflags: -I${includedir}
+URL: http://fedorahosted.org/sssd/
diff --git a/common/refarray/ref_array_ut.c b/common/refarray/ref_array_ut.c
new file mode 100644
index 000000000..c85b6b26d
--- /dev/null
+++ b/common/refarray/ref_array_ut.c
@@ -0,0 +1,343 @@
+/*
+ REF ARRAY
+
+ Implementation of the dynamic array with reference count.
+
+ Copyright (C) Dmitri Pal <dpal@redhat.com> 2009
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+ This program 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 General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#define _GNU_SOURCE
+#include <errno.h> /* for errors */
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "ref_array.h"
+#include "config.h"
+#define TRACE_HOME
+#include "trace.h"
+
+int verbose = 0;
+
+#define RAOUT(foo) \
+ do { \
+ if (verbose) foo; \
+ } while(0)
+
+extern void ref_array_debug(struct ref_array *ra);
+
+typedef int (*test_fn)(void);
+
+/* Basic test */
+int ref_array_basic_test(void)
+{
+ const char *line1 = "line1";
+ const char *line2 = "line2";
+ const char *line3 = "line3";
+ const char *line4 = "line4";
+ const char *line5 = "line5";
+ const char *line6 = "line6";
+ uint32_t i;
+ struct ref_array *ra;
+ struct ref_array *ra2;
+ int error = EOK;
+ uint32_t len = 0;
+ uint32_t other_len = 0;
+ char *ret;
+ char *elem;
+ void *ptr;
+
+ error = ref_array_create(&ra, sizeof(char *), 1, NULL, NULL);
+ if (error) {
+ printf("Failed to create array %d\n", error);
+ return error;
+ }
+
+ RAOUT(ref_array_debug(ra));
+
+ error = ref_array_append(ra, &line1);
+ if (error) {
+ ref_array_destroy(ra);
+ printf("Failed to append to array line 1 %d\n", error);
+ return error;
+ }
+
+ RAOUT(ref_array_debug(ra));
+
+ error = ref_array_append(ra, &line2);
+ if (error) {
+ ref_array_destroy(ra);
+ printf("Failed to append to array line 2 %d\n", error);
+ return error;
+ }
+
+ RAOUT(ref_array_debug(ra));
+
+ error = ref_array_append(ra, &line3);
+ if (error) {
+ ref_array_destroy(ra);
+ printf("Failed to append to array line 3 %d\n", error);
+ return error;
+ }
+
+ RAOUT(ref_array_debug(ra));
+
+ error = ref_array_append(ra, &line4);
+ if (error) {
+ ref_array_destroy(ra);
+ printf("Failed to append to array line 4 %d\n", error);
+ return error;
+ }
+
+ RAOUT(ref_array_debug(ra));
+
+ error = ref_array_append(ra, &line5);
+ if (error) {
+ ref_array_destroy(ra);
+ printf("Failed to append to array line 5 %d\n", error);
+ return error;
+ }
+
+ RAOUT(ref_array_debug(ra));
+
+ error = ref_array_append(ra, &line6);
+ if (error) {
+ ref_array_destroy(ra);
+ printf("Failed to append to array line 6 %d\n", error);
+ return error;
+ }
+
+ RAOUT(ref_array_debug(ra));
+
+ RAOUT(printf("\n\nTest 1 - Printing lines.\n\n"));
+
+ error = ref_array_getlen(ra, &other_len);
+ if (error) {
+ ref_array_destroy(ra);
+ printf("Failed to get length %d\n", error);
+ return error;
+ }
+
+ len = ref_array_len(ra);
+
+ if (len != other_len) {
+ ref_array_destroy(ra);
+ printf("Lengths do not match:\n");
+ printf("Len : %d\n", len);
+ printf("Get Len: %d\n", other_len);
+ return EFAULT;
+ }
+
+ for (i = 0; i < len; i++) {
+ ref_array_get(ra, i, &ret);
+ RAOUT(printf("%s\n", ret));
+ }
+
+ RAOUT(printf("\n\nTest 2 - Creating reference and then printing lines.\n\n"));
+
+ ra2 = ref_array_getref(ra);
+ ref_array_destroy(ra);
+
+ for (i = 0; i < len; i++) {
+ ret = *((char **)ref_array_get(ra2, i, NULL));
+ RAOUT(printf("%s\n", ret));
+ }
+
+ RAOUT(printf("\n\nTest 3 - Get elements with copying.\n\n"));
+
+ for (i = 0; i < len; i++) {
+ ref_array_get(ra2, i, &ret);
+ RAOUT(printf("%s\n", ret));
+ }
+
+ RAOUT(printf("\n\nTest 4a - Get elements with copying and assignment.\n\n"));
+
+ /* This is a bad practice to use one variable
+ * as a parameter and as an acceptor for the return value.
+ * See next example for a better way to do it.
+ */
+ for (i = 0; i < len; i++) {
+ ret = *((char **)ref_array_get(ra2, i, &ret));
+ RAOUT(printf("%s\n", ret));
+ }
+
+ RAOUT(printf("\n\nTest 4b - Get elements with copying and assignment.\n\n"));
+
+ for (i = 0; i < len; i++) {
+ ret = *((char **)ref_array_get(ra2, i, &elem));
+ RAOUT(printf("%s\n", ret));
+ RAOUT(printf("%s\n", elem));
+ if (strcmp(ret, elem) != 0) {
+ ref_array_destroy(ra2);
+ printf("\nRetrieved strings were expected to be same,\n");
+ printf("but they are not:\n");
+ printf("By pointer:[%s]\nAs element:[%s]\n", ret, elem);
+ return EFAULT;
+ }
+ }
+
+ RAOUT(printf("\n\nTest 5 - While loop up.\n\n"));
+
+ i = 0;
+ for (;;) {
+ ptr = ref_array_get(ra2, i, &ret);
+ if (ptr) {
+ RAOUT(printf("%s\n", ret));
+ i++;
+ }
+ else break;
+ }
+
+ RAOUT(printf("\n\nTest 6 - While loop down.\n\n"));
+
+ i = len - 1;
+ for (;;) {
+ ptr = ref_array_get(ra2, i, &ret);
+ if (ptr) {
+ RAOUT(printf("%s\n", ret));
+ i--;
+ }
+ else break;
+ }
+
+ RAOUT(printf("\n\nDone!!!\n\n"));
+
+ ref_array_destroy(ra2);
+ return EOK;
+}
+
+void array_cleanup(void *elem,
+ ref_array_del_enum type,
+ void *data)
+{
+ RAOUT(printf("%s%s\n", (char *)data, *((char **)elem)));
+ free(*((char **)elem));
+}
+
+/* Free test */
+int ref_array_free_test(void)
+{
+ const char *line1 = "line1";
+ const char *line2 = "line2";
+ const char *line3 = "line3";
+ const char *line4 = "line4";
+ char text[] = "Deleting: ";
+ char *str;
+ uint32_t i;
+ struct ref_array *ra;
+ int error = EOK;
+ char *ret;
+ void *ptr;
+
+ error = ref_array_create(&ra, sizeof(char *), 1, array_cleanup, (char *)text);
+ if (error) {
+ printf("Failed to create array %d\n", error);
+ return error;
+ }
+
+ RAOUT(ref_array_debug(ra));
+
+ str = strdup(line1);
+
+ error = ref_array_append(ra, &str);
+ if (error) {
+ ref_array_destroy(ra);
+ printf("Failed to append to array line 1 %d\n", error);
+ return error;
+ }
+
+ RAOUT(ref_array_debug(ra));
+
+ str = strdup(line2);
+
+ error = ref_array_append(ra, &str);
+ if (error) {
+ ref_array_destroy(ra);
+ printf("Failed to append to array line 2 %d\n", error);
+ return error;
+ }
+
+ RAOUT(ref_array_debug(ra));
+
+ str = strdup(line3);
+
+ error = ref_array_append(ra, &str);
+ if (error) {
+ ref_array_destroy(ra);
+ printf("Failed to append to array line 3 %d\n", error);
+ return error;
+ }
+
+ RAOUT(ref_array_debug(ra));
+
+ str = strdup(line4);
+
+ error = ref_array_append(ra, &str);
+ if (error) {
+ ref_array_destroy(ra);
+ printf("Failed to append to array line 4 %d\n", error);
+ return error;
+ }
+
+ RAOUT(ref_array_debug(ra));
+
+ i = 0;
+ for (;;) {
+ ptr = ref_array_get(ra, i, &ret);
+ if (ptr) {
+ RAOUT(printf("%s\n", ret));
+ i++;
+ }
+ else break;
+ }
+
+ RAOUT(printf("\n\nDone!!!\n\n"));
+
+ ref_array_destroy(ra);
+ return EOK;
+}
+
+
+
+/* Main function of the unit test */
+int main(int argc, char *argv[])
+{
+ int error = 0;
+ test_fn tests[] = { ref_array_basic_test,
+ ref_array_free_test,
+ NULL };
+ test_fn t;
+ int i = 0;
+ char *var;
+
+ if ((argc > 1) && (strcmp(argv[1], "-v") == 0)) verbose = 1;
+ else {
+ var = getenv("COMMON_TEST_VERBOSE");
+ if (var) verbose = 1;
+ }
+
+ RAOUT(printf("Start\n"));
+
+ while ((t = tests[i++])) {
+ error = t();
+ if (error) {
+ RAOUT(printf("Failed with error %d!\n", error));
+ return error;
+ }
+ }
+
+ RAOUT(printf("Success!\n"));
+ return 0;
+}