summaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/Makefile.am11
-rw-r--r--common/array.c119
-rw-r--r--common/array.h66
-rw-r--r--common/compat.c95
-rw-r--r--common/compat.h123
-rw-r--r--common/debug.c151
-rw-r--r--common/debug.h129
-rw-r--r--common/dict.c391
-rw-r--r--common/dict.h178
-rw-r--r--common/library.c286
-rw-r--r--common/library.h80
-rw-r--r--common/tests/Makefile.am32
-rw-r--r--common/tests/test-array.c194
-rw-r--r--common/tests/test-dict.c465
14 files changed, 2320 insertions, 0 deletions
diff --git a/common/Makefile.am b/common/Makefile.am
new file mode 100644
index 0000000..f37a501
--- /dev/null
+++ b/common/Makefile.am
@@ -0,0 +1,11 @@
+NULL =
+
+SUBDIRS = . tests
+
+EXTRA_DIST = \
+ array.c array.h \
+ compat.c compat.h \
+ debug.c debug.h \
+ dict.c dict.h \
+ library.c library.h \
+ $(NULL)
diff --git a/common/array.c b/common/array.c
new file mode 100644
index 0000000..f645fd1
--- /dev/null
+++ b/common/array.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2011 Collabora Ltd.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * The names of contributors to this software may not be
+ * used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+
+#include "config.h"
+
+#include "array.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+static int
+maybe_expand_array (p11_array *array,
+ unsigned int length)
+{
+ unsigned int new_allocated;
+ void **new_memory;
+
+ if (length <= array->allocated)
+ return 1;
+
+ new_allocated = array->allocated + 16;
+ if (new_allocated < length)
+ new_allocated = length;
+
+ new_memory = realloc (array->elem, new_allocated * sizeof (void*));
+ if (new_memory == NULL)
+ return 0;
+
+ array->elem = new_memory;
+ array->allocated = new_allocated;
+ return 1;
+}
+
+p11_array *
+p11_array_new (p11_destroyer destroyer)
+{
+ p11_array *array;
+
+ array = calloc (1, sizeof (p11_array));
+ if (array == NULL)
+ return NULL;
+
+ if (!maybe_expand_array (array, 2)) {
+ p11_array_free (array);
+ return NULL;
+ }
+
+ array->destroyer = destroyer;
+ return array;
+}
+
+void
+p11_array_free (p11_array *array)
+{
+ unsigned int i;
+
+ if (array == NULL)
+ return;
+
+ if (array->destroyer) {
+ for (i = 0; i < array->num; i++)
+ (array->destroyer) (array->elem[i]);
+ }
+
+ free (array->elem);
+ free (array);
+}
+
+int
+p11_array_push (p11_array *array,
+ void *value)
+{
+ if (!maybe_expand_array (array, array->num + 1))
+ return 0;
+
+ array->elem[array->num] = value;
+ array->num++;
+ return 1;
+}
+
+void
+p11_array_remove (p11_array *array,
+ unsigned int index)
+{
+ if (array->destroyer)
+ (array->destroyer) (array->elem[index]);
+ memmove (array->elem + index, array->elem + index + 1,
+ (array->num - (index + 1)) * sizeof (void*));
+ array->num--;
+}
diff --git a/common/array.h b/common/array.h
new file mode 100644
index 0000000..6ed7866
--- /dev/null
+++ b/common/array.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2011 Collabora Ltd.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * The names of contributors to this software may not be
+ * used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Author: Stef Waler <stefw@collabora.co.uk>
+ */
+
+#ifndef __P11_ARRAY_H__
+#define __P11_ARRAY_H__
+
+#include <sys/types.h>
+
+#ifndef P11_DESTROYER_DEFINED
+#define P11_DESTROYER_DEFINED
+
+typedef void (*p11_destroyer) (void *data);
+
+#endif
+
+typedef struct _p11_array {
+ void **elem;
+ unsigned int num;
+
+ /* private */
+ unsigned int allocated;
+ p11_destroyer destroyer;
+} p11_array;
+
+p11_array * p11_array_new (p11_destroyer destroyer);
+
+void p11_array_free (p11_array *array);
+
+int p11_array_push (p11_array *array,
+ void *value);
+
+void p11_array_remove (p11_array *array,
+ unsigned int index);
+
+#endif /* __P11_ARRAY_H__ */
diff --git a/common/compat.c b/common/compat.c
index 0f7cb78..fe16e07 100644
--- a/common/compat.c
+++ b/common/compat.c
@@ -36,6 +36,7 @@
#include "compat.h"
+#include <assert.h>
#include <stdlib.h>
#include <string.h>
@@ -110,6 +111,80 @@ getprogname (void)
#endif /* HAVE_GETPROGNAME */
+#ifdef OS_UNIX
+
+void
+p11_mutex_init (p11_mutex_t *mutex)
+{
+ pthread_mutexattr_t attr;
+ int ret;
+
+ pthread_mutexattr_init (&attr);
+ pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
+ ret = pthread_mutex_init (mutex, &attr);
+ assert (ret == 0);
+ pthread_mutexattr_destroy (&attr);
+}
+
+#endif /* OS_UNIX */
+
+#ifdef OS_WIN32
+
+const char *
+p11_module_error (void)
+{
+ DWORD code = GetLastError();
+ p11_local *local;
+ LPVOID msg_buf;
+
+ local = p11_library_get_thread_local ();
+
+ FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, code,
+ MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPSTR)&msg_buf, 0, NULL);
+
+ if (local->last_error)
+ LocalFree (local->last_error);
+ local->last_error = msg_buf;
+
+ return msg_buf;
+}
+
+int
+p11_thread_create (p11_thread_t *thread,
+ p11_thread_routine routine,
+ void *arg)
+{
+ assert (thread);
+
+ *thread = CreateThread (NULL, 0,
+ (LPTHREAD_START_ROUTINE)routine,
+ arg, 0, NULL);
+
+ if (*thread == NULL)
+ return GetLastError ();
+
+ return 0;
+}
+
+int
+p11_thread_join (p11_thread_t thread)
+{
+ DWORD res;
+
+ res = WaitForSingleObject (thread, INFINITE);
+ if (res == WAIT_FAILED)
+ return GetLastError ();
+
+ CloseHandle (thread);
+ return 0;
+}
+
+#endif /* OS_WIN32 */
+
#ifndef HAVE_ERR_H
#include <stdlib.h>
@@ -273,3 +348,23 @@ vwarnx (const char *fmt,
}
#endif /* HAVE_ERR_H */
+
+#ifndef HAVE_MEMDUP
+
+void *
+memdup (void *data,
+ size_t length)
+{
+ void *dup;
+
+ if (!data)
+ return NULL;
+
+ dup = malloc (length);
+ if (dup != NULL)
+ memcpy (dup, data, length);
+
+ return dup;
+}
+
+#endif /* HAVE_MEMDUP */
diff --git a/common/compat.h b/common/compat.h
index 8b3ac21..5061b9f 100644
--- a/common/compat.h
+++ b/common/compat.h
@@ -37,6 +37,8 @@
#include "config.h"
+#include <sys/types.h>
+
#if !defined(__cplusplus) && (__GNUC__ > 2)
#define GNUC_PRINTF(x, y) __attribute__((__format__(__printf__, x, y)))
#else
@@ -53,6 +55,120 @@
const char * getprogname (void);
#endif
+/* -----------------------------------------------------------------------------
+ * WIN32
+ */
+
+#ifdef OS_WIN32
+
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x500
+#endif
+
+#ifndef _WIN32_IE
+#define _WIN32_IE 0x500
+#endif
+
+#define WIN32_LEAN_AND_MEAN 1
+#include <windows.h>
+
+/* Oh ... my ... god */
+#undef CreateMutex
+
+typedef CRITICAL_SECTION p11_mutex_t;
+
+typedef HANDLE p11_thread_t;
+
+typedef DWORD p11_thread_id_t;
+
+#define p11_mutex_init(m) \
+ (InitializeCriticalSection (m))
+#define p11_mutex_lock(m) \
+ (EnterCriticalSection (m))
+#define p11_mutex_unlock(m) \
+ (LeaveCriticalSection (m))
+#define p11_mutex_uninit(m) \
+ (DeleteCriticalSection (m))
+
+typedef void * (*p11_thread_routine) (void *arg);
+
+int p11_thread_create (thread_t *thread, thread_routine, void *arg);
+
+int p11_thread_join (thread_t thread);
+
+/* Returns a thread_id_t */
+#define p11_thread_id_self() \
+ (GetCurrentThreadId ())
+
+typedef HMODULE dl_module_t;
+
+#define p11_module_open(f) \
+ (LoadLibrary (f))
+#define p11_module_close(d) \
+ (FreeLibrary (d))
+#define p11_module_symbol(d, s) \
+ ((void *)GetProcAddress ((d), (s)))
+
+const char * p11_module_error (void);
+
+#define p11_sleep_ms(ms) \
+ (Sleep (ms))
+
+#endif /* OS_WIN32 */
+
+/* ----------------------------------------------------------------------------
+ * UNIX
+ */
+
+#ifdef OS_UNIX
+
+#include <pthread.h>
+#include <dlfcn.h>
+#include <time.h>
+
+typedef pthread_mutex_t p11_mutex_t;
+
+void p11_mutex_init (p11_mutex_t *mutex);
+
+#define p11_mutex_lock(m) \
+ (pthread_mutex_lock (m))
+#define p11_mutex_unlock(m) \
+ (pthread_mutex_unlock (m))
+#define p11_mutex_uninit(m) \
+ (pthread_mutex_destroy(m))
+
+typedef pthread_t p11_thread_t;
+
+typedef pthread_t p11_thread_id_t;
+
+typedef void * (*p11_thread_routine) (void *arg);
+
+#define p11_thread_create(t, r, a) \
+ (pthread_create ((t), NULL, (r), (a)))
+#define p11_thread_join(t) \
+ (pthread_join ((t), NULL))
+#define p11_thread_id_self(m) \
+ (pthread_self ())
+
+typedef void * dl_module_t;
+
+#define p11_module_open(f) \
+ (dlopen ((f), RTLD_LOCAL | RTLD_NOW))
+#define p11_module_close(d) \
+ (dlclose(d))
+#define p11_module_error() \
+ (dlerror ())
+#define p11_module_symbol(d, s) \
+ (dlsym ((d), (s)))
+
+#define p11_sleep_ms(ms) \
+ do { int _ms = (ms); \
+ struct timespec _ts = { _ms / 1000, (_ms % 1000) * 1000 * 1000 }; \
+ nanosleep (&_ts, NULL); \
+ } while(0)
+
+#endif /* OS_UNIX */
+
#ifdef HAVE_ERR_H
#include <err.h>
@@ -80,4 +196,11 @@ void vwarnx (const char *fmt, va_list ap);
#include <errno.h>
#endif /* HAVE_ERRNO_H */
+#ifndef HAVE_MEMDUP
+
+void * memdup (void *data,
+ size_t length);
+
+#endif /* HAVE_MEMDUP */
+
#endif /* __COMPAT_H__ */
diff --git a/common/debug.c b/common/debug.c
new file mode 100644
index 0000000..cca9aaf
--- /dev/null
+++ b/common/debug.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2011 Collabora Ltd.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * The names of contributors to this software may not be
+ * used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ *
+ * CONTRIBUTORS
+ * Stef Walter <stef@memberwebs.com>
+ */
+
+#include "config.h"
+
+#include "debug.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+struct DebugKey {
+ const char *name;
+ int value;
+};
+
+static struct DebugKey debug_keys[] = {
+ { "lib", P11_DEBUG_LIB },
+ { "conf", P11_DEBUG_CONF },
+ { "uri", P11_DEBUG_URI },
+ { "proxy", P11_DEBUG_PROXY },
+ { 0, }
+};
+
+static int debug_inited = 0;
+static int debug_strict = 0;
+
+/* global variable exported in debug.h */
+int p11_debug_current_flags = ~0;
+
+static int
+parse_environ_flags (void)
+{
+ const char *env;
+ int result = 0;
+ const char *p;
+ const char *q;
+ int i;
+
+ env = getenv ("P11_KIT_STRICT");
+ if (env && env[0] != '\0')
+ debug_strict = 1;
+
+ env = getenv ("P11_KIT_DEBUG");
+ if (!env)
+ return 0;
+
+ if (strcmp (env, "all") == 0) {
+ for (i = 0; debug_keys[i].name; i++)
+ result |= debug_keys[i].value;
+
+ } else if (strcmp (env, "help") == 0) {
+ fprintf (stderr, "Supported debug values:");
+ for (i = 0; debug_keys[i].name; i++)
+ fprintf (stderr, " %s", debug_keys[i].name);
+ fprintf (stderr, "\n");
+
+ } else {
+ p = env;
+ while (*p) {
+ q = strpbrk (p, ":;, \t");
+ if (!q)
+ q = p + strlen (p);
+
+ for (i = 0; debug_keys[i].name; i++) {
+ if (q - p == strlen (debug_keys[i].name) &&
+ strncmp (debug_keys[i].name, p, q - p) == 0)
+ result |= debug_keys[i].value;
+ }
+
+ p = q;
+ if (*p)
+ p++;
+ }
+ }
+
+ return result;
+}
+
+void
+p11_debug_init (void)
+{
+ p11_debug_current_flags = parse_environ_flags ();
+ debug_inited = 1;
+}
+
+void
+p11_debug_message (int flag,
+ const char *format, ...)
+{
+ char buffer[512];
+ va_list args;
+
+ if (flag & p11_debug_current_flags) {
+ va_start (args, format);
+ vsnprintf (buffer, sizeof (buffer), format, args);
+ buffer[sizeof (buffer) -1] = 0;
+ va_end (args);
+ fprintf (stderr, "(p11-kit:%d) %s\n", getpid(), buffer);
+ }
+}
+
+void
+p11_debug_precond (const char *format,
+ ...)
+{
+ va_list va;
+
+ va_start (va, format);
+ vfprintf (stderr, format, va);
+ va_end (va);
+
+ if (debug_strict)
+ abort ();
+}
diff --git a/common/debug.h b/common/debug.h
new file mode 100644
index 0000000..e4759d4
--- /dev/null
+++ b/common/debug.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2011 Collabora Ltd.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * The names of contributors to this software may not be
+ * used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Author: Stef Walter <stefw@collabora.co.uk>
+ */
+
+#ifndef P11_DEBUG_H
+#define P11_DEBUG_H
+
+#include "compat.h"
+
+/* Please keep this enum in sync with keys in debug.c */
+enum {
+ P11_DEBUG_LIB = 1 << 1,
+ P11_DEBUG_CONF = 1 << 2,
+ P11_DEBUG_URI = 1 << 3,
+ P11_DEBUG_PROXY = 1 << 4,
+};
+
+extern int p11_debug_current_flags;
+
+void p11_debug_init (void);
+
+void p11_debug_message (int flag,
+ const char *format,
+ ...) GNUC_PRINTF (2, 3);
+
+void p11_debug_precond (const char *format,
+ ...) GNUC_PRINTF (1, 2);
+
+#define assert_not_reached() \
+ (assert (0 && "this code should not be reached"))
+
+#define return_val_if_fail(x, v) \
+ do { if (!(x)) { \
+ p11_debug_precond ("p11-kit: '%s' not true at %s\n", #x, __func__); \
+ return v; \
+ } } while (0)
+
+#define return_if_fail(x) \
+ do { if (!(x)) { \
+ p11_debug_precond ("p11-kit: '%s' not true at %s\n", #x, __func__); \
+ return; \
+ } } while (0)
+
+#define return_if_reached() \
+ do { \
+ p11_debug_precond ("p11-kit: shouldn't be reached at %s\n", __func__); \
+ return; \
+ } while (0)
+
+#define return_val_if_reached(v) \
+ do { \
+ p11_debug_precond ("p11-kit: shouldn't be reached at %s\n", __func__); \
+ return v; \
+ } while (0)
+
+#endif /* DEBUG_H */
+
+/* -----------------------------------------------------------------------------
+ * Below this point is outside the DEBUG_H guard - so it can take effect
+ * more than once. So you can do:
+ *
+ * #define P11_DEBUG_FLAG P11_DEBUG_ONE_THING
+ * #include "debug.h"
+ * ...
+ * p11_debug ("if we're debugging one thing");
+ * ...
+ * #undef P11_DEBUG_FLAG
+ * #define P11_DEBUG_FLAG DEBUG_OTHER_THING
+ * #include "debug.h"
+ * ...
+ * p11_debug ("if we're debugging the other thing");
+ * ...
+ */
+
+#ifdef P11_DEBUG_FLAG
+#ifdef WITH_DEBUG
+
+#undef p11_debug
+#define p11_debug(format, ...) do { \
+ if (P11_DEBUG_FLAG & p11_debug_current_flags) \
+ p11_debug_message (P11_DEBUG_FLAG, "%s: " format, __PRETTY_FUNCTION__, ##__VA_ARGS__); \
+ } while (0)
+
+#undef p11_debugging
+#define p11_debugging \
+ (P11_DEBUG_FLAG & p11_debug_current_flags)
+
+#else /* !defined (WITH_DEBUG) */
+
+#undef p11_debug
+#define p11_debug(format, ...) \
+ do {} while (0)
+
+#undef p11_debugging
+#define p11_debugging 0
+
+#endif /* !defined (WITH_DEBUG) */
+
+#endif /* defined (P11_DEBUG_FLAG) */
diff --git a/common/dict.c b/common/dict.c
new file mode 100644
index 0000000..2f976c1
--- /dev/null
+++ b/common/dict.c
@@ -0,0 +1,391 @@
+/*
+ * Copyright (c) 2004 Stefan Walter
+ * Copyright (c) 2011 Collabora Ltd.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * The names of contributors to this software may not be
+ * used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ */
+
+#include "config.h"
+
+#include "dict.h"
+
+#include <sys/types.h>
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct _p11_dict {
+ p11_dict_hasher hash_func;
+ p11_dict_equals equal_func;
+ p11_destroyer key_destroy_func;
+ p11_destroyer value_destroy_func;
+
+ struct _p11_dictbucket **buckets;
+ unsigned int num_items;
+ unsigned int num_buckets;
+};
+
+typedef struct _p11_dictbucket {
+ void *key;
+ unsigned int hashed;
+ void *value;
+ struct _p11_dictbucket *next;
+} dictbucket;
+
+static dictbucket *
+next_entry (p11_dictiter *iter)
+{
+ dictbucket *bucket = iter->next;
+ while (!bucket) {
+ if (iter->index >= iter->dict->num_buckets)
+ return NULL;
+ bucket = iter->dict->buckets[iter->index++];
+ }
+ iter->next = bucket->next;
+ return bucket;
+}
+
+
+int
+p11_dict_next (p11_dictiter *iter,
+ void **key,
+ void **value)
+{
+ dictbucket *bucket = next_entry (iter);
+ if (bucket == NULL)
+ return 0;
+ if (key)
+ *key = bucket->key;
+ if (value)
+ *value = bucket->value;
+ return 1;
+}
+
+void
+p11_dict_iterate (p11_dict *dict,
+ p11_dictiter *iter)
+{
+ iter->dict = dict;
+ iter->index = 0;
+ iter->next = NULL;
+}
+
+static dictbucket **
+lookup_or_create_bucket (p11_dict *dict,
+ const void *key,
+ int create)
+{
+ dictbucket **bucketp;
+ unsigned int hash;
+
+ /* Perform the hashing */
+ hash = dict->hash_func (key);
+
+ /* scan linked list */
+ for (bucketp = &dict->buckets[hash % dict->num_buckets];
+ *bucketp != NULL; bucketp = &(*bucketp)->next) {
+ if((*bucketp)->hashed == hash && dict->equal_func ((*bucketp)->key, key))
+ break;
+ }
+
+ if ((*bucketp) != NULL || !create)
+ return bucketp;
+
+ /* add a new entry for non-NULL val */
+ (*bucketp) = calloc (sizeof (dictbucket), 1);
+
+ if (*bucketp != NULL) {
+ (*bucketp)->key = (void*)key;
+ (*bucketp)->hashed = hash;
+ dict->num_items++;
+ }
+
+ return bucketp;
+}
+
+void *
+p11_dict_get (p11_dict *dict,
+ const void *key)
+{
+ dictbucket **bucketp;
+
+ bucketp = lookup_or_create_bucket (dict, key, 0);
+ if (bucketp && *bucketp)
+ return (void*)((*bucketp)->value);
+ else
+ return NULL;
+}
+
+int
+p11_dict_set (p11_dict *dict,
+ void *key,
+ void *val)
+{
+ dictbucket **bucketp;
+ p11_dictiter iter;
+ dictbucket *bucket;
+ dictbucket **new_buckets;
+ unsigned int num_buckets;
+
+ bucketp = lookup_or_create_bucket (dict, key, 1);
+ if(bucketp && *bucketp) {
+
+ /* Destroy the previous key */
+ if ((*bucketp)->key && (*bucketp)->key != key && dict->key_destroy_func)
+ dict->key_destroy_func ((*bucketp)->key);
+
+ /* Destroy the previous value */
+ if ((*bucketp)->value && (*bucketp)->value != val && dict->value_destroy_func)
+ dict->value_destroy_func ((*bucketp)->value);
+
+ /* replace entry */
+ (*bucketp)->key = key;
+ (*bucketp)->value = val;
+
+ /* check that the collision rate isn't too high */
+ if (dict->num_items > dict->num_buckets) {
+ num_buckets = dict->num_buckets * 2 + 1;
+ new_buckets = (dictbucket **)calloc (sizeof (dictbucket *), num_buckets);
+
+ /* Ignore failures, maybe we can expand later */
+ if(new_buckets) {
+ p11_dict_iterate (dict, &iter);
+ while ((bucket = next_entry (&iter)) != NULL) {
+ unsigned int i = bucket->hashed % num_buckets;
+ bucket->next = new_buckets[i];
+ new_buckets[i] = bucket;
+ }
+
+ free (dict->buckets);
+ dict->buckets = new_buckets;
+ dict->num_buckets = num_buckets;
+ }
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+int
+p11_dict_steal (p11_dict *dict,
+ const void *key,
+ void **stolen_key,
+ void **stolen_value)
+{
+ dictbucket **bucketp;
+
+ bucketp = lookup_or_create_bucket (dict, key, 0);
+ if (bucketp && *bucketp) {
+ dictbucket *old = *bucketp;
+ *bucketp = (*bucketp)->next;
+ --dict->num_items;
+ if (stolen_key)
+ *stolen_key = old->key;
+ if (stolen_value)
+ *stolen_value = old->value;
+ free (old);
+ return 1;
+ }
+
+ return 0;
+
+}
+
+int
+p11_dict_remove (p11_dict *dict,
+ const void *key)
+{
+ void *old_key;
+ void *old_value;
+
+ if (!p11_dict_steal (dict, key, &old_key, &old_value))
+ return 0;
+
+ if (dict->key_destroy_func)
+ dict->key_destroy_func (old_key);
+ if (dict->value_destroy_func)
+ dict->value_destroy_func (old_value);
+ return 1;
+}
+
+void
+p11_dict_clear (p11_dict *dict)
+{
+ dictbucket *bucket, *next;
+ int i;
+
+ /* Free all entries in the array */
+ for (i = 0; i < dict->num_buckets; ++i) {
+ bucket = dict->buckets[i];
+ while (bucket != NULL) {
+ next = bucket->next;
+ if (dict->key_destroy_func)
+ dict->key_destroy_func (bucket->key);
+ if (dict->value_destroy_func)
+ dict->value_destroy_func (bucket->value);
+ free (bucket);
+ bucket = next;
+ }
+ }
+
+ memset (dict->buckets, 0, dict->num_buckets * sizeof (dictbucket *));
+ dict->num_items = 0;
+}
+
+p11_dict *
+p11_dict_new (p11_dict_hasher hash_func,
+ p11_dict_equals equal_func,
+ p11_destroyer key_destroy_func,
+ p11_destroyer value_destroy_func)
+{
+ p11_dict *dict;
+
+ assert (hash_func);
+ assert (equal_func);
+
+ dict = malloc (sizeof (p11_dict));
+ if (dict) {
+ dict->hash_func = hash_func;
+ dict->equal_func = equal_func;
+ dict->key_destroy_func = key_destroy_func;
+ dict->value_destroy_func = value_destroy_func;
+
+ dict->num_buckets = 9;
+ dict->buckets = (dictbucket **)calloc (sizeof (dictbucket *), dict->num_buckets);
+ if (!dict->buckets) {
+ free (dict);
+ return NULL;
+ }
+
+ dict->num_items = 0;
+ }
+
+ return dict;
+}
+
+void
+p11_dict_free (p11_dict *dict)
+{
+ dictbucket *bucket;
+ p11_dictiter iter;
+
+ if (!dict)
+ return;
+
+ p11_dict_iterate (dict, &iter);
+ while ((bucket = next_entry (&iter)) != NULL) {
+ if (dict->key_destroy_func)
+ dict->key_destroy_func (bucket->key);
+ if (dict->value_destroy_func)
+ dict->value_destroy_func (bucket->value);
+ free (bucket);
+ }
+
+ if (dict->buckets)
+ free (dict->buckets);
+
+ free (dict);
+}
+
+unsigned int
+p11_dict_size (p11_dict *dict)
+{
+ return dict->num_items;
+}
+
+unsigned int
+p11_dict_str_hash (const void *string)
+{
+ const char *p = string;
+ unsigned int hash = *p;
+
+ if (hash)
+ for (p += 1; *p != '\0'; p++)
+ hash = (hash << 5) - hash + *p;
+
+ return hash;
+}
+
+int
+p11_dict_str_equal (const void *string_one,
+ const void *string_two)
+{
+ assert (string_one);
+ assert (string_two);
+
+ return strcmp (string_one, string_two) == 0;
+}
+
+unsigned int
+p11_dict_ulongptr_hash (const void *to_ulong)
+{
+ assert (to_ulong);
+ return (unsigned int)*((unsigned long*)to_ulong);
+}
+
+int
+p11_dict_ulongptr_equal (const void *ulong_one,
+ const void *ulong_two)
+{
+ assert (ulong_one);
+ assert (ulong_two);
+ return *((unsigned long*)ulong_one) == *((unsigned long*)ulong_two);
+}
+
+unsigned int
+p11_dict_intptr_hash (const void *to_int)
+{
+ assert (to_int);
+ return (unsigned int)*((int*)to_int);
+}
+
+int
+p11_dict_intptr_equal (const void *int_one,
+ const void *int_two)
+{
+ assert (int_one);
+ assert (int_two);
+ return *((int*)int_one) == *((int*)int_two);
+}
+
+unsigned int
+p11_dict_direct_hash (const void *ptr)
+{
+ return (unsigned int)(size_t)ptr;
+}
+
+int
+p11_dict_direct_equal (const void *ptr_one,
+ const void *ptr_two)
+{
+ return ptr_one == ptr_two;
+}
diff --git a/common/dict.h b/common/dict.h
new file mode 100644
index 0000000..1ba7185
--- /dev/null
+++ b/common/dict.h
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2004 Stefan Walter
+ * Copyright (c) 2011 Collabora Ltd.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * The names of contributors to this software may not be
+ * used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Author: Stef Waler <stefw@collabora.co.uk>
+ */
+
+#ifndef P11_DICT_H_
+#define P11_DICT_H_
+
+#include <sys/types.h>
+
+/*
+ * ARGUMENT DOCUMENTATION
+ *
+ * dict: The dict
+ * key: Pointer to the key value
+ * val: Pointer to the value
+ * iter: A dict iterator
+ */
+
+
+/* ----------------------------------------------------------------------------------
+ * TYPES
+ */
+
+/* Abstract type for dicts. */
+typedef struct _p11_dict p11_dict;
+
+/* Type for scanning hash tables. */
+typedef struct _p11_dictiter {
+ p11_dict *dict;
+ struct _p11_dictbucket *next;
+ unsigned int index;
+} p11_dictiter;
+
+typedef unsigned int (*p11_dict_hasher) (const void *data);
+
+typedef int (*p11_dict_equals) (const void *one,
+ const void *two);
+
+#ifndef P11_DESTROYER_DEFINED
+#define P11_DESTROYER_DEFINED
+
+typedef void (*p11_destroyer) (void *data);
+
+#endif
+
+/* -----------------------------------------------------------------------------
+ * MAIN
+ */
+
+/*
+ * p11_dict_create : Create a hash table
+ * - returns an allocated hashtable
+ */
+p11_dict * p11_dict_new (p11_dict_hasher hasher,
+ p11_dict_equals equals,
+ p11_destroyer key_destroyer,
+ p11_destroyer value_destroyer);
+
+/*
+ * p11_dict_free : Free a hash table
+ */
+void p11_dict_free (p11_dict *dict);
+
+/*
+ * p11_dict_size: Number of values in hash table
+ * - returns the number of entries in hash table
+ */
+unsigned int p11_dict_size (p11_dict *dict);
+
+/*
+ * p11_dict_get: Retrieves a value from the hash table
+ * - returns the value of the entry
+ */
+void* p11_dict_get (p11_dict *dict,
+ const void *key);
+
+/*
+ * p11_dict_set: Set a value in the hash table
+ * - returns 1 if the entry was added properly
+ */
+int p11_dict_set (p11_dict *dict,
+ void *key,
+ void *value);
+
+/*
+ * p11_dict_remove: Remove a value from the hash table
+ * - returns 1 if the entry was found
+ */
+int p11_dict_remove (p11_dict *dict,
+ const void *key);
+
+/*
+ * p11_dict_steal: Remove a value from the hash table without calling
+ * destroy funcs
+ * - returns 1 if the entry was found
+ */
+int p11_dict_steal (p11_dict *dict,
+ const void *key,
+ void **stolen_key,
+ void **stolen_value);
+
+/*
+ * p11_dict_iterate: Start enumerating through the hash table
+ * - returns a hash iterator
+ */
+void p11_dict_iterate (p11_dict *dict,
+ p11_dictiter *iter);
+
+/*
+ * p11_dict_next: Enumerate through hash table
+ * - sets key and value to key and/or value
+ * - returns whether there was another entry
+ */
+int p11_dict_next (p11_dictiter *iter,
+ void **key,
+ void **value);
+
+/*
+ * p11_dict_clear: Clear all values from has htable.
+ */
+void p11_dict_clear (p11_dict *dict);
+
+/* -----------------------------------------------------------------------------
+ * KEY FUNCTIONS
+ */
+
+unsigned int p11_dict_str_hash (const void *string);
+
+int p11_dict_str_equal (const void *string_one,
+ const void *string_two);
+
+unsigned int p11_dict_ulongptr_hash (const void *to_ulong);
+
+int p11_dict_ulongptr_equal (const void *ulong_one,
+ const void *ulong_two);
+
+unsigned int p11_dict_intptr_hash (const void *to_int);
+
+int p11_dict_intptr_equal (const void *int_one,
+ const void *int_two);
+
+unsigned int p11_dict_direct_hash (const void *ptr);
+
+int p11_dict_direct_equal (const void *ptr_one,
+ const void *ptr_two);
+
+#endif /* __P11_DICT_H__ */
diff --git a/common/library.c b/common/library.c
new file mode 100644
index 0000000..e8547b3
--- /dev/null
+++ b/common/library.c
@@ -0,0 +1,286 @@
+/*
+ * Copyright (c) 2011 Collabora Ltd
+ * Copyright (c) 2012 Stef Walter
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * The names of contributors to this software may not be
+ * used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ *
+ * CONTRIBUTORS
+ * Stef Walter <stef@thewalter.net>
+ */
+
+#include "config.h"
+
+#include "compat.h"
+#define P11_DEBUG_FLAG P11_DEBUG_LIB
+#include "debug.h"
+#include "library.h"
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#define P11_MAX_MESSAGE 512
+
+typedef struct {
+ char message[P11_MAX_MESSAGE];
+#ifdef OS_WIN32
+ void *last_error;
+#endif
+} p11_local;
+
+static p11_local * _p11_library_get_thread_local (void);
+
+p11_mutex_t p11_library_mutex;
+
+#ifdef OS_UNIX
+pthread_once_t p11_library_once;
+#endif
+
+static int print_messages = 1;
+
+void
+p11_message_store (const char* msg,
+ size_t length)
+{
+ p11_local *local;
+
+ if (length > P11_MAX_MESSAGE - 1)
+ length = P11_MAX_MESSAGE - 1;
+
+ local = _p11_library_get_thread_local ();
+ if (local != NULL) {
+ memcpy (local->message, msg, length);
+ local->message[length] = 0;
+ }
+}
+
+void
+p11_message (const char* msg,
+ ...)
+{
+ char buffer[P11_MAX_MESSAGE];
+ va_list va;
+ size_t length;
+
+ va_start (va, msg);
+ length = vsnprintf (buffer, P11_MAX_MESSAGE - 1, msg, va);
+ va_end (va);
+
+ /* Was it truncated? */
+ if (length > P11_MAX_MESSAGE - 1)
+ length = P11_MAX_MESSAGE - 1;
+ buffer[length] = 0;
+
+ /* If printing is not disabled, just print out */
+ if (print_messages)
+ fprintf (stderr, "p11-kit: %s\n", buffer);
+
+ p11_debug_message (P11_DEBUG_LIB, "message: %s", buffer);
+ p11_message_store (buffer, length);
+}
+
+void
+p11_message_quiet (void)
+{
+ p11_lock ();
+ print_messages = 0;
+ p11_unlock ();
+}
+
+const char*
+p11_message_last (void)
+{
+ p11_local *local;
+ local = _p11_library_get_thread_local ();
+ return local && local->message[0] ? local->message : NULL;
+}
+
+void
+p11_message_clear (void)
+{
+ p11_local *local;
+ local = _p11_library_get_thread_local ();
+ if (local != NULL)
+ local->message[0] = 0;
+}
+
+static void
+uninit_common (void)
+{
+ p11_debug ("uninitializing library");
+}
+
+#ifdef OS_UNIX
+
+static pthread_key_t thread_local = 0;
+
+static p11_local *
+_p11_library_get_thread_local (void)
+{
+ p11_local *local;
+
+ p11_library_init_once ();
+
+ local = pthread_getspecific (thread_local);
+ if (local == NULL) {
+ local = calloc (1, sizeof (p11_local));
+ pthread_setspecific (thread_local, local);
+ }
+
+ return local;
+}
+
+#ifdef __GNUC__
+__attribute__((constructor))
+#endif
+void
+p11_library_init (void)
+{
+ p11_debug_init ();
+ p11_debug ("initializing library");
+ p11_mutex_init (&p11_library_mutex);
+ pthread_key_create (&thread_local, free);
+}
+
+#ifdef __GNUC__
+__attribute__((destructor))
+#endif
+void
+p11_library_uninit (void)
+{
+ uninit_common ();
+
+ /* Some cleanup to pacify valgrind */
+ free (pthread_getspecific (thread_local));
+ pthread_setspecific (thread_local, NULL);
+
+ pthread_key_delete (thread_local);
+ p11_mutex_uninit (&p11_library_mutex);
+}
+
+#endif /* OS_UNIX */
+
+#ifdef OS_WIN32
+
+static DWORD thread_local = TLS_OUT_OF_INDEXES;
+
+BOOL WINAPI DllMain (HINSTANCE, DWORD, LPVOID);
+
+static p11_local *
+_p11_library_get_thread_local (void)
+{
+ LPVOID data;
+
+ if (thread_local == TLS_OUT_OF_INDEXES)
+ return NULL;
+
+ data = TlsGetValue (thread_local);
+ if (data == NULL) {
+ data = LocalAlloc (LPTR, sizeof (p11_local));
+ TlsSetValue (thread_local, data);
+ }
+
+ return (p11_local *)data;
+}
+
+void
+p11_library_init (void)
+{
+ p11_debug_init ();
+ p11_debug ("initializing library");
+ p11_mutex_init (&p11_library_mutex);
+ thread_local = TlsAlloc ();
+}
+
+static void
+free_tls_value (LPVOID data)
+{
+ p11_local *local = data;
+ if (local == NULL)
+ return;
+ if (local->last_error)
+ LocalFree (local->last_error);
+ LocalFree (data);
+}
+
+void
+p11_library_uninit (void)
+{
+ LPVOID data;
+
+ uninit_common ();
+
+ if (thread_local != TLS_OUT_OF_INDEXES) {
+ data = TlsGetValue (thread_local);
+ free_tls_value (data);
+ TlsFree (thread_local);
+ }
+ _p11_mutex_uninit (&p11_library_mutex);
+}
+
+
+BOOL WINAPI
+DllMain (HINSTANCE instance,
+ DWORD reason,
+ LPVOID reserved)
+{
+ LPVOID data;
+
+ switch (reason) {
+ case DLL_PROCESS_ATTACH:
+ p11_library_init ();
+ if (thread_local == TLS_OUT_OF_INDEXES) {
+ p11_debug ("couldn't setup tls");
+ return FALSE;
+ }
+ break;
+
+ case DLL_THREAD_DETACH:
+ if (thread_local != TLS_OUT_OF_INDEXES) {
+ p11_debug ("thread stopped, freeing tls");
+ data = TlsGetValue (thread_local);
+ free_tls_value (data);
+ }
+ break;
+
+ case DLL_PROCESS_DETACH:
+ p11_library_uninit ();
+ break;
+
+ default:
+ break;
+ }
+
+ return TRUE;
+}
+
+#endif /* OS_WIN32 */
diff --git a/common/library.h b/common/library.h
new file mode 100644
index 0000000..00e9c2c
--- /dev/null
+++ b/common/library.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2011 Collabora Ltd
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * The names of contributors to this software may not be
+ * used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ *
+ * CONTRIBUTORS
+ * Stef Walter <stef@memberwebs.com>
+ */
+
+#ifndef P11_LIBRARY_H_
+#define P11_LIBRARY_H_
+
+#include "config.h"
+#include "compat.h"
+
+#include <sys/types.h>
+
+extern p11_mutex_t p11_library_mutex;
+
+#define p11_lock() p11_mutex_lock (&p11_library_mutex);
+
+#define p11_unlock() p11_mutex_unlock (&p11_library_mutex);
+
+void p11_message (const char* msg,
+ ...) GNUC_PRINTF (1, 2);
+
+void p11_message_store (const char* msg,
+ size_t length);
+
+const char * p11_message_last (void);
+
+void p11_message_clear (void);
+
+void p11_message_quiet (void);
+
+#ifdef OS_WIN32
+
+/* No implementation, because done by DllMain */
+#define p11_library_init_once()
+
+#else /* !OS_WIN32 */
+extern pthread_once_t p11_library_once;
+
+#define p11_library_init_once() \
+ pthread_once (&p11_library_once, p11_library_init);
+
+#endif /* !OS_WIN32 */
+
+void p11_library_init (void);
+
+void p11_library_uninit (void);
+
+#endif /* P11_LIBRARY_H_ */
diff --git a/common/tests/Makefile.am b/common/tests/Makefile.am
new file mode 100644
index 0000000..11f2369
--- /dev/null
+++ b/common/tests/Makefile.am
@@ -0,0 +1,32 @@
+
+include $(top_srcdir)/build/Makefile.tests
+
+NULL =
+
+COMMON = $(top_srcdir)/common
+
+INCLUDES = \
+ -I$(top_srcdir) \
+ -I$(srcdir)/.. \
+ -I$(COMMON) \
+ $(CUTEST_CFLAGS)
+
+LDADD = $(CUTEST_LIBS)
+
+CHECK_PROGS = \
+ test-dict \
+ test-array \
+ $(NULL)
+
+test_dict_SOURCES = \
+ test-dict.c \
+ $(COMMON)/dict.c
+
+test_array_SOURCES = \
+ test-array.c \
+ $(COMMON)/array.c
+
+noinst_PROGRAMS = \
+ $(CHECK_PROGS)
+
+TESTS = $(CHECK_PROGS:=$(EXEEXT))
diff --git a/common/tests/test-array.c b/common/tests/test-array.c
new file mode 100644
index 0000000..a52f3b5
--- /dev/null
+++ b/common/tests/test-array.c
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2011, Collabora Ltd.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * The names of contributors to this software may not be
+ * used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Author: Stef Walter <stefw@collabora.co.uk>
+ */
+
+#include "config.h"
+#include "CuTest.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "array.h"
+
+static void
+test_p11_array_create (CuTest *tc)
+{
+ p11_array *array;
+
+ array = p11_array_new (NULL);
+ CuAssertPtrNotNull (tc, array);
+ p11_array_free (array);
+}
+
+static void
+test_p11_array_free_null (CuTest *tc)
+{
+ p11_array_free (NULL);
+}
+
+static void
+destroy_value (void *data)
+{
+ int *value = data;
+ *value = 2;
+}
+
+static void
+test_p11_array_free_destroys (CuTest *tc)
+{
+ p11_array *array;
+ int value = 0;
+
+ array = p11_array_new (destroy_value);
+ CuAssertPtrNotNull (tc, array);
+ if (!p11_array_push (array, &value))
+ CuFail (tc, "should not be reached");
+ p11_array_free (array);
+
+ CuAssertIntEquals (tc, 2, value);
+}
+
+static void
+test_p11_array_add (CuTest *tc)
+{
+ char *value = "VALUE";
+ p11_array *array;
+
+ array = p11_array_new (NULL);
+ if (!p11_array_push (array, value))
+ CuFail (tc, "should not be reached");
+
+ CuAssertIntEquals (tc, 1, array->num);
+ CuAssertPtrEquals (tc, array->elem[0], value);
+
+ p11_array_free (array);
+}
+
+static void
+test_p11_array_add_remove (CuTest *tc)
+{
+ char *value = "VALUE";
+ p11_array *array;
+
+ array = p11_array_new (NULL);
+ if (!p11_array_push (array, value))
+ CuFail (tc, "should not be reached");
+
+ CuAssertIntEquals (tc, 1, array->num);
+
+ CuAssertPtrEquals (tc, array->elem[0], value);
+
+ p11_array_remove (array, 0);
+
+ CuAssertIntEquals (tc, 0, array->num);
+
+ p11_array_free (array);
+}
+
+static void
+test_p11_array_remove_destroys (CuTest *tc)
+{
+ p11_array *array;
+ int value = 0;
+
+ array = p11_array_new (destroy_value);
+ if (!p11_array_push (array, &value))
+ CuFail (tc, "should not be reached");
+
+ p11_array_remove (array, 0);
+
+ CuAssertIntEquals (tc, 2, value);
+
+ /* should not be destroyed again */
+ value = 0;
+
+ p11_array_free (array);
+
+ CuAssertIntEquals (tc, 0, value);
+}
+
+static void
+test_p11_array_remove_and_count (CuTest *tc)
+{
+ p11_array *array;
+ int *value;
+ int i;
+
+ array = p11_array_new (free);
+
+ CuAssertIntEquals (tc, 0, array->num);
+
+ for (i = 0; i < 20000; ++i) {
+ value = malloc (sizeof (int));
+ *value = i;
+ if (!p11_array_push (array, value))
+ CuFail (tc, "should not be reached");
+ CuAssertIntEquals (tc, i + 1, array->num);
+ }
+
+ for (i = 10; i < 20000; ++i) {
+ p11_array_remove (array, 10);
+ CuAssertIntEquals (tc, 20010 - (i + 1), array->num);
+ }
+
+ CuAssertIntEquals (tc, 10, array->num);
+
+ p11_array_free (array);
+}
+
+int
+main (void)
+{
+ CuString *output = CuStringNew ();
+ CuSuite* suite = CuSuiteNew ();
+ int ret;
+
+ SUITE_ADD_TEST (suite, test_p11_array_create);
+ SUITE_ADD_TEST (suite, test_p11_array_add);
+ SUITE_ADD_TEST (suite, test_p11_array_add_remove);
+ SUITE_ADD_TEST (suite, test_p11_array_remove_destroys);
+ SUITE_ADD_TEST (suite, test_p11_array_remove_and_count);
+ SUITE_ADD_TEST (suite, test_p11_array_free_null);
+ SUITE_ADD_TEST (suite, test_p11_array_free_destroys);
+
+ CuSuiteRun (suite);
+ CuSuiteSummary (suite, output);
+ CuSuiteDetails (suite, output);
+ printf ("%s\n", output->buffer);
+ ret = suite->failCount;
+ CuSuiteDelete (suite);
+ CuStringDelete (output);
+
+ return ret;
+}
diff --git a/common/tests/test-dict.c b/common/tests/test-dict.c
new file mode 100644
index 0000000..3af3daa
--- /dev/null
+++ b/common/tests/test-dict.c
@@ -0,0 +1,465 @@
+/*
+ * Copyright (c) 2011, Collabora Ltd.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the
+ * above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * The names of contributors to this software may not be
+ * used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Author: Stef Walter <stefw@collabora.co.uk>
+ */
+
+#include "config.h"
+#include "CuTest.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "dict.h"
+
+static void
+test_create (CuTest *tc)
+{
+ p11_dict *map;
+
+ map = p11_dict_new (p11_dict_direct_hash, p11_dict_direct_equal, NULL, NULL);
+ CuAssertPtrNotNull (tc, map);
+ p11_dict_free (map);
+}
+
+static void
+test_free_null (CuTest *tc)
+{
+ p11_dict_free (NULL);
+}
+
+typedef struct {
+ int value;
+ int freed;
+} Key;
+
+static unsigned int
+key_hash (const void *ptr)
+{
+ const Key *k = ptr;
+ assert (!k->freed);
+ return p11_dict_intptr_hash (&k->value);
+}
+
+static int
+key_equal (const void *one,
+ const void *two)
+{
+ const Key *k1 = one;
+ const Key *k2 = two;
+ assert (!k1->freed);
+ assert (!k2->freed);
+ return p11_dict_intptr_equal (&k1->value, &k2->value);
+}
+
+static void
+key_destroy (void *data)
+{
+ Key *k = data;
+ assert (!k->freed);
+ k->freed = 1;
+}
+
+static void
+value_destroy (void *data)
+{
+ int *value = data;
+ *value = 2;
+}
+
+static void
+test_free_destroys (CuTest *tc)
+{
+ p11_dict *map;
+ Key key = { 8, 0 };
+ int value = 0;
+
+ map = p11_dict_new (key_hash, key_equal, key_destroy, value_destroy);
+ CuAssertPtrNotNull (tc, map);
+ if (!p11_dict_set (map, &key, &value))
+ CuFail (tc, "should not be reached");
+ p11_dict_free (map);
+
+ CuAssertIntEquals (tc, 1, key.freed);
+ CuAssertIntEquals (tc, 2, value);
+}
+
+static void
+test_iterate (CuTest *tc)
+{
+ p11_dict *map;
+ p11_dictiter iter;
+ int key = 1;
+ int value = 2;
+ void *pkey;
+ void *pvalue;
+ int ret;
+
+ map = p11_dict_new (p11_dict_direct_hash, p11_dict_direct_equal, NULL, NULL);
+ CuAssertPtrNotNull (tc, map);
+ if (!p11_dict_set (map, &key, &value))
+ CuFail (tc, "should not be reached");
+
+ p11_dict_iterate (map, &iter);
+
+ ret = p11_dict_next (&iter, &pkey, &pvalue);
+ CuAssertIntEquals (tc, 1, ret);
+ CuAssertPtrEquals (tc, pkey, &key);
+ CuAssertPtrEquals (tc, pvalue, &value);
+
+ ret = p11_dict_next (&iter, &pkey, &pvalue);
+ CuAssertIntEquals (tc, 0, ret);
+
+ p11_dict_free (map);
+}
+
+static void
+test_set_get (CuTest *tc)
+{
+ char *key = "KEY";
+ char *value = "VALUE";
+ char *check;
+ p11_dict *map;
+
+ map = p11_dict_new (p11_dict_str_hash, p11_dict_str_equal, NULL, NULL);
+ p11_dict_set (map, key, value);
+ check = p11_dict_get (map, key);
+ CuAssertPtrEquals (tc, check, value);
+
+ p11_dict_free (map);
+}
+
+static void
+test_set_get_remove (CuTest *tc)
+{
+ char *key = "KEY";
+ char *value = "VALUE";
+ char *check;
+ p11_dict *map;
+ int ret;
+
+ map = p11_dict_new (p11_dict_str_hash, p11_dict_str_equal, NULL, NULL);
+
+ if (!p11_dict_set (map, key, value))
+ CuFail (tc, "should not be reached");
+
+ check = p11_dict_get (map, key);
+ CuAssertPtrEquals (tc, check, value);
+
+ ret = p11_dict_remove (map, key);
+ CuAssertIntEquals (tc, ret, 1);
+ ret = p11_dict_remove (map, key);
+ CuAssertIntEquals (tc, ret, 0);
+
+ check = p11_dict_get (map, key);
+ CuAssert (tc, "should be null", check == NULL);
+
+ p11_dict_free (map);
+}
+
+static void
+test_set_clear (CuTest *tc)
+{
+ char *key = "KEY";
+ char *value = "VALUE";
+ char *check;
+ p11_dict *map;
+
+ map = p11_dict_new (p11_dict_direct_hash, p11_dict_direct_equal, NULL, NULL);
+
+ if (!p11_dict_set (map, key, value))
+ CuFail (tc, "should not be reached");
+
+ p11_dict_clear (map);
+
+ check = p11_dict_get (map, key);
+ CuAssert (tc, "should be null", check == NULL);
+
+ p11_dict_free (map);
+}
+
+static void
+test_remove_destroys (CuTest *tc)
+{
+ p11_dict *map;
+ Key key = { 8, 0 };
+ int value = 0;
+ int ret;
+
+ map = p11_dict_new (key_hash, key_equal, key_destroy, value_destroy);
+ CuAssertPtrNotNull (tc, map);
+ if (!p11_dict_set (map, &key, &value))
+ CuFail (tc, "should not be reached");
+
+ ret = p11_dict_remove (map, &key);
+ CuAssertIntEquals (tc, ret, 1);
+ CuAssertIntEquals (tc, 1, key.freed);
+ CuAssertIntEquals (tc, 2, value);
+
+ /* should not be destroyed again */
+ key.freed = 0;
+ value = 0;
+
+ ret = p11_dict_remove (map, &key);
+ CuAssertIntEquals (tc, ret, 0);
+ CuAssertIntEquals (tc, 0, key.freed);
+ CuAssertIntEquals (tc, 0, value);
+
+ /* should not be destroyed again */
+ key.freed = 0;
+ value = 0;
+
+ p11_dict_free (map);
+
+ CuAssertIntEquals (tc, 0, key.freed);
+ CuAssertIntEquals (tc, 0, value);
+}
+
+static void
+test_set_destroys (CuTest *tc)
+{
+ p11_dict *map;
+ Key key = { 8, 0 };
+ Key key2 = { 8, 0 };
+ int value, value2;
+ int ret;
+
+ map = p11_dict_new (key_hash, key_equal, key_destroy, value_destroy);
+ CuAssertPtrNotNull (tc, map);
+ if (!p11_dict_set (map, &key, &value))
+ CuFail (tc, "should not be reached");
+
+ key.freed = key2.freed = value = value2 = 0;
+
+ /* Setting same key and value, should not be destroyed */
+ ret = p11_dict_set (map, &key, &value);
+ CuAssertIntEquals (tc, ret, 1);
+ CuAssertIntEquals (tc, 0, key.freed);
+ CuAssertIntEquals (tc, 0, key2.freed);
+ CuAssertIntEquals (tc, 0, value);
+ CuAssertIntEquals (tc, 0, value2);
+
+ key.freed = key2.freed = value = value2 = 0;
+
+ /* Setting a new key same value, key should be destroyed */
+ ret = p11_dict_set (map, &key2, &value);
+ CuAssertIntEquals (tc, ret, 1);
+ CuAssertIntEquals (tc, 1, key.freed);
+ CuAssertIntEquals (tc, 0, key2.freed);
+ CuAssertIntEquals (tc, 0, value);
+ CuAssertIntEquals (tc, 0, value2);
+
+ key.freed = key2.freed = value = value2 = 0;
+
+ /* Setting same key, new value, value should be destroyed */
+ ret = p11_dict_set (map, &key2, &value2);
+ CuAssertIntEquals (tc, ret, 1);
+ CuAssertIntEquals (tc, 0, key.freed);
+ CuAssertIntEquals (tc, 0, key2.freed);
+ CuAssertIntEquals (tc, 2, value);
+ CuAssertIntEquals (tc, 0, value2);
+
+ key.freed = key2.freed = value = value2 = 0;
+
+ /* Setting new key new value, both should be destroyed */
+ ret = p11_dict_set (map, &key, &value);
+ CuAssertIntEquals (tc, ret, 1);
+ CuAssertIntEquals (tc, 0, key.freed);
+ CuAssertIntEquals (tc, 1, key2.freed);
+ CuAssertIntEquals (tc, 0, value);
+ CuAssertIntEquals (tc, 2, value2);
+
+ key.freed = key2.freed = value = value2 = 0;
+
+ p11_dict_free (map);
+ CuAssertIntEquals (tc, 1, key.freed);
+ CuAssertIntEquals (tc, 2, value);
+ CuAssertIntEquals (tc, 0, key2.freed);
+ CuAssertIntEquals (tc, 0, value2);
+}
+
+
+static void
+test_clear_destroys (CuTest *tc)
+{
+ p11_dict *map;
+ Key key = { 18, 0 };
+ int value = 0;
+
+ map = p11_dict_new (key_hash, key_equal, key_destroy, value_destroy);
+ CuAssertPtrNotNull (tc, map);
+ if (!p11_dict_set (map, &key, &value))
+ CuFail (tc, "should not be reached");
+
+ p11_dict_clear (map);
+ CuAssertIntEquals (tc, 1, key.freed);
+ CuAssertIntEquals (tc, 2, value);
+
+ /* should not be destroyed again */
+ key.freed = 0;
+ value = 0;
+
+ p11_dict_clear (map);
+ CuAssertIntEquals (tc, 0, key.freed);
+ CuAssertIntEquals (tc, 0, value);
+
+ /* should not be destroyed again */
+ key.freed = 0;
+ value = 0;
+
+ p11_dict_free (map);
+
+ CuAssertIntEquals (tc, 0, key.freed);
+ CuAssertIntEquals (tc, 0, value);
+}
+
+static unsigned int
+test_hash_intptr_with_collisions (const void *data)
+{
+ /* lots and lots of collisions, only returns 100 values */
+ return (unsigned int)(*((int*)data) % 100);
+}
+
+static void
+test_hash_add_check_lots_and_collisions (CuTest *tc)
+{
+ p11_dict *map;
+ int *value;
+ int i;
+
+ map = p11_dict_new (test_hash_intptr_with_collisions,
+ p11_dict_intptr_equal, NULL, free);
+
+ for (i = 0; i < 20000; ++i) {
+ value = malloc (sizeof (int));
+ *value = i;
+ if (!p11_dict_set (map, value, value))
+ CuFail (tc, "should not be reached");
+ }
+
+ for (i = 0; i < 20000; ++i) {
+ value = p11_dict_get (map, &i);
+ CuAssertPtrNotNull (tc, value);
+ CuAssertIntEquals (tc, i, *value);
+ }
+
+ p11_dict_free (map);
+}
+
+static void
+test_hash_count (CuTest *tc)
+{
+ p11_dict *map;
+ int *value;
+ int i, ret;
+
+ map = p11_dict_new (p11_dict_intptr_hash, p11_dict_intptr_equal, NULL, free);
+
+ CuAssertIntEquals (tc, 0, p11_dict_size (map));
+
+ for (i = 0; i < 20000; ++i) {
+ value = malloc (sizeof (int));
+ *value = i;
+ if (!p11_dict_set (map, value, value))
+ CuFail (tc, "should not be reached");
+ CuAssertIntEquals (tc, i + 1, p11_dict_size (map));
+ }
+
+ for (i = 0; i < 20000; ++i) {
+ ret = p11_dict_remove (map, &i);
+ CuAssertIntEquals (tc, 1, ret);
+ CuAssertIntEquals (tc, 20000 - (i + 1), p11_dict_size (map));
+ }
+
+ p11_dict_clear (map);
+ CuAssertIntEquals (tc, 0, p11_dict_size (map));
+
+ p11_dict_free (map);
+}
+
+static void
+test_hash_ulongptr (CuTest *tc)
+{
+ p11_dict *map;
+ unsigned long *value;
+ unsigned long i;
+
+ map = p11_dict_new (p11_dict_ulongptr_hash, p11_dict_ulongptr_equal, NULL, free);
+
+ for (i = 0; i < 20000; ++i) {
+ value = malloc (sizeof (unsigned long));
+ *value = i;
+ if (!p11_dict_set (map, value, value))
+ CuFail (tc, "should not be reached");
+ }
+
+ for (i = 0; i < 20000; ++i) {
+ value = p11_dict_get (map, &i);
+ CuAssertPtrNotNull (tc, value);
+ CuAssertIntEquals (tc, i, *value);
+ }
+
+ p11_dict_free (map);
+}
+
+int
+main (void)
+{
+ CuString *output = CuStringNew ();
+ CuSuite* suite = CuSuiteNew ();
+ int ret;
+
+ SUITE_ADD_TEST (suite, test_create);
+ SUITE_ADD_TEST (suite, test_set_get);
+ SUITE_ADD_TEST (suite, test_set_get_remove);
+ SUITE_ADD_TEST (suite, test_remove_destroys);
+ SUITE_ADD_TEST (suite, test_set_clear);
+ SUITE_ADD_TEST (suite, test_set_destroys);
+ SUITE_ADD_TEST (suite, test_clear_destroys);
+ SUITE_ADD_TEST (suite, test_free_null);
+ SUITE_ADD_TEST (suite, test_free_destroys);
+ SUITE_ADD_TEST (suite, test_iterate);
+ SUITE_ADD_TEST (suite, test_hash_add_check_lots_and_collisions);
+ SUITE_ADD_TEST (suite, test_hash_count);
+ SUITE_ADD_TEST (suite, test_hash_ulongptr);
+
+ CuSuiteRun (suite);
+ CuSuiteSummary (suite, output);
+ CuSuiteDetails (suite, output);
+ printf ("%s\n", output->buffer);
+ ret = suite->failCount;
+ CuSuiteDelete (suite);
+ CuStringDelete (output);
+
+ return ret;
+}