diff --git a/.gitignore b/.gitignore
index 69cb7933a..cf7ebb45d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,3 +17,5 @@ configure
config.log
aclocal.m4
semantic.cache
+wiki/backups/*
+doc/devel/draw/*.png
diff --git a/Makefile.am b/Makefile.am
index 8a2bc889f..f3ae3ef41 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -46,6 +46,9 @@ include $(top_srcdir)/src/common/Makefile.am
include $(top_srcdir)/src/lib/Makefile.am
include $(top_srcdir)/src/backend/Makefile.am
+# tools
+include $(top_srcdir)/src/tool/Makefile.am
+
# gui
include $(top_srcdir)/src/gui/Makefile.am
diff --git a/SConstruct b/SConstruct
index 2b3e2cfd0..9c56cece3 100644
--- a/SConstruct
+++ b/SConstruct
@@ -79,7 +79,7 @@ def setupBasicEnvironment():
env.Append(CPPDEFINES = '_GNU_SOURCE')
appendCppDefine(env,'DEBUG','DEBUG', 'NDEBUG')
- appendCppDefine(env,'OPENGL','USE_OPENGL')
+# appendCppDefine(env,'OPENGL','USE_OPENGL')
appendVal(env,'ARCHFLAGS', 'CCFLAGS') # for both C and C++
appendVal(env,'OPTIMIZE', 'CCFLAGS', val=' -O3')
appendVal(env,'DEBUG', 'CCFLAGS', val=' -ggdb')
@@ -128,7 +128,7 @@ def defineCmdlineOptions():
allowed_values=('ALPHA', 'BETA', 'RELEASE'))
,BoolOption('DEBUG', 'Build with debugging information and no optimizations', False)
,BoolOption('OPTIMIZE', 'Build with strong optimization (-O3)', False)
- ,BoolOption('OPENGL', 'Include support for OpenGL preview rendering', False)
+# ,BoolOption('OPENGL', 'Include support for OpenGL preview rendering', False)
# ,EnumOption('DIST_TARGET', 'Build target architecture', 'auto',
# allowed_values=('auto', 'i386', 'i686', 'x86_64' ), ignorecase=2)
,PathOption('DESTDIR', 'Installation dir prefix', '/usr/local')
@@ -337,8 +337,8 @@ def definePostBuildTargets(env, artifacts):
env.Clean ('build', [ '$SRCDIR/pre.gch' ])
doxydoc = artifacts['doxydoc'] = env.Doxygen('doc/devel/Doxyfile')
- env.Alias ('doxydoc', doxydoc)
- env.Clean ('doxydoc', doxydoc + ['doc/devel/,doxylog','doc/devel/warnings.txt'])
+ env.Alias ('doc', doxydoc)
+ env.Clean ('doc', doxydoc + ['doc/devel/,doxylog','doc/devel/warnings.txt'])
def defineInstallTargets(env, artifacts):
diff --git a/doc/devel/Doxyfile b/doc/devel/Doxyfile
index b7c59fa54..f43b69042 100644
--- a/doc/devel/Doxyfile
+++ b/doc/devel/Doxyfile
@@ -1,11 +1,11 @@
-# Doxyfile 1.5.5
+# Doxyfile 1.5.6
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = Lumiera
-PROJECT_NUMBER = 0.1+pre
+PROJECT_NUMBER = 3.0+alpha
OUTPUT_DIRECTORY =
CREATE_SUBDIRS = YES
OUTPUT_LANGUAGE = English
@@ -32,7 +32,7 @@ SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = YES
QT_AUTOBRIEF = NO
MULTILINE_CPP_IS_BRIEF = NO
-DETAILS_AT_TOP = YES
+DETAILS_AT_TOP = NO
INHERIT_DOCS = YES
SEPARATE_MEMBER_PAGES = NO
TAB_SIZE = 4
@@ -44,6 +44,7 @@ OPTIMIZE_OUTPUT_VHDL = NO
BUILTIN_STL_SUPPORT = YES
CPP_CLI_SUPPORT = NO
SIP_SUPPORT = NO
+IDL_PROPERTY_SUPPORT = YES
DISTRIBUTE_GROUP_DOC = NO
SUBGROUPING = YES
TYPEDEF_HIDES_STRUCT = NO
@@ -65,8 +66,8 @@ CASE_SENSE_NAMES = YES
HIDE_SCOPE_NAMES = NO
SHOW_INCLUDE_FILES = YES
INLINE_INFO = YES
-SORT_MEMBER_DOCS = NO
-SORT_BRIEF_DOCS = NO
+SORT_MEMBER_DOCS = YES
+SORT_BRIEF_DOCS = YES
SORT_GROUP_NAMES = NO
SORT_BY_SCOPE_NAME = NO
GENERATE_TODOLIST = YES
@@ -77,6 +78,8 @@ ENABLED_SECTIONS =
MAX_INITIALIZER_LINES = 30
SHOW_USED_FILES = YES
SHOW_DIRECTORIES = NO
+SHOW_FILES = YES
+SHOW_NAMESPACES = YES
FILE_VERSION_FILTER =
#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
@@ -87,7 +90,7 @@ WARN_IF_UNDOCUMENTED = NO
WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = YES
WARN_FORMAT = "$file:$line: $text"
-WARN_LOGFILE = warnings.txt
+WARN_LOGFILE =
#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------
@@ -179,18 +182,20 @@ HTML_STYLESHEET =
HTML_ALIGN_MEMBERS = YES
GENERATE_HTMLHELP = NO
GENERATE_DOCSET = NO
-DOCSET_FEEDNAME = "Lumiera Doxygen docs"
+DOCSET_FEEDNAME = "Doxygen generated docs"
DOCSET_BUNDLE_ID = org.doxygen.Project
HTML_DYNAMIC_SECTIONS = NO
CHM_FILE =
HHC_LOCATION =
GENERATE_CHI = NO
+CHM_INDEX_ENCODING =
BINARY_TOC = NO
TOC_EXPAND = NO
DISABLE_INDEX = NO
ENUM_VALUES_PER_LINE = 4
GENERATE_TREEVIEW = YES
TREEVIEW_WIDTH = 250
+FORMULA_FONTSIZE = 10
#---------------------------------------------------------------------------
# configuration options related to the LaTeX output
#---------------------------------------------------------------------------
@@ -268,6 +273,8 @@ CLASS_DIAGRAMS = YES
MSCGEN_PATH =
HIDE_UNDOC_RELATIONS = YES
HAVE_DOT = YES
+DOT_FONTNAME = FreeSans
+DOT_FONTPATH =
CLASS_GRAPH = YES
COLLABORATION_GRAPH = YES
GROUP_GRAPHS = YES
diff --git a/doc/devel/draw/Lumi.Architecture-1.svg b/doc/devel/draw/Lumi.Architecture-1.svg
index 9df05b7d3..40fab02c7 100644
--- a/doc/devel/draw/Lumi.Architecture-1.svg
+++ b/doc/devel/draw/Lumi.Architecture-1.svg
@@ -14,10 +14,10 @@
sodipodi:version="0.32"
inkscape:version="0.45.1"
version="1.0"
- sodipodi:docbase="/home/hiv/devel/skizzen"
- sodipodi:docname="Cin3.Architecture-1.svg"
+ sodipodi:docbase="/mnt/Lager/heim/devel/lumi/doc/devel/draw"
+ sodipodi:docname="Lumi.Architecture-1.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
- inkscape:export-filename="/home/hiv/devel/skizzen/Cin3.Architecture-1.png"
+ inkscape:export-filename="/home/hiv/devel/skizzen/Lumi.Architecture-1.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90">
+ inkscape:window-y="28"
+ showgrid="true"
+ inkscape:grid-points="true"
+ inkscape:grid-bbox="false"
+ gridspacingx="2px"
+ gridspacingy="2px"
+ objecttolerance="50"
+ gridtolerance="10000" />
@@ -87,7 +94,7 @@
style="opacity:1;color:#000000;fill:#ececec;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect3136"
width="449.55356"
- height="142.91072"
+ height="144.89977"
x="46.375008"
y="369.10715" />
Defaults
+ y="267.42578">SessionDefaults
Cache
+ width="119.99424"
+ height="29.96665"
+ x="159.96713"
+ y="480.03333" />
IO-Handling
Storage Backend(s)
+ x="300"
+ y="480">Storage Backend(s)
Plugins (Codecs, Effects,...)
+ y="355.89285" />
+ y="232.85713" />
-
-
-
-
(re)-Building
+
+ Plugin Loader
+
+
+
+
+
+ Serializer
+
+
+
+
+
+
+ Defaults
+
+
+
+
diff --git a/doc/devel/draw/LumiLogo.svg b/doc/devel/draw/LumiLogo.svg
new file mode 100644
index 000000000..a4d60254d
--- /dev/null
+++ b/doc/devel/draw/LumiLogo.svg
@@ -0,0 +1,118 @@
+
+
+
diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am
index 8ad4cce2b..abb576021 100644
--- a/src/backend/Makefile.am
+++ b/src/backend/Makefile.am
@@ -26,7 +26,12 @@ liblumibackend_a_SOURCES = \
$(liblumibackend_a_srcdir)/file.c \
$(liblumibackend_a_srcdir)/filehandle.c \
$(liblumibackend_a_srcdir)/filedescriptor.c \
- $(liblumibackend_a_srcdir)/filehandlecache.c
+ $(liblumibackend_a_srcdir)/filehandlecache.c \
+ $(liblumibackend_a_srcdir)/config.c \
+ $(liblumibackend_a_srcdir)/config_typed.c \
+ $(liblumibackend_a_srcdir)/configentry.c \
+ $(liblumibackend_a_srcdir)/configitem.c \
+ $(liblumibackend_a_srcdir)/config_lookup.c
noinst_HEADERS += \
@@ -35,5 +40,9 @@ noinst_HEADERS += \
$(liblumibackend_a_srcdir)/file.h \
$(liblumibackend_a_srcdir)/filehandle.h \
$(liblumibackend_a_srcdir)/filedescriptor.h \
- $(liblumibackend_a_srcdir)/filehandlecache.h
+ $(liblumibackend_a_srcdir)/filehandlecache.h \
+ $(liblumibackend_a_srcdir)/config.h \
+ $(liblumibackend_a_srcdir)/configentry.h \
+ $(liblumibackend_a_srcdir)/configitem.h \
+ $(liblumibackend_a_srcdir)/config_lookup.h
diff --git a/src/backend/config.c b/src/backend/config.c
new file mode 100644
index 000000000..276088673
--- /dev/null
+++ b/src/backend/config.c
@@ -0,0 +1,355 @@
+/*
+ config.c - Lumiera configuration system
+
+ Copyright (C) Lumiera.org
+ 2008, Christian Thaeter
+
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+//TODO: Support library includes//
+#include "lib/safeclib.h"
+
+
+//TODO: Lumiera header includes//
+#include "backend/config.h"
+
+//TODO: internal/static forward declarations//
+
+
+//TODO: System includes//
+#include
+#include
+#include
+
+/**
+ * @file
+ *
+ */
+
+NOBUG_DEFINE_FLAG_PARENT (config_all, backend);
+NOBUG_DEFINE_FLAG_PARENT (config, config_all);
+NOBUG_DEFINE_FLAG_PARENT (config_typed, config_all);
+NOBUG_DEFINE_FLAG_PARENT (config_file, config_all);
+NOBUG_DEFINE_FLAG_PARENT (config_item, config_all);
+NOBUG_DEFINE_FLAG_PARENT (config_lookup, config_all);
+
+LUMIERA_ERROR_DEFINE (CONFIG_SYNTAX, "syntax error in configfile");
+LUMIERA_ERROR_DEFINE (CONFIG_SYNTAX_KEY, "syntax error in key");
+LUMIERA_ERROR_DEFINE (CONFIG_SYNTAX_VALUE, "syntax error in value");
+LUMIERA_ERROR_DEFINE (CONFIG_NO_ENTRY, "no configuration entry");
+LUMIERA_ERROR_DEFINE (CONFIG_DEFAULT, "illegal default value");
+
+/**
+ * defaults for the configuraton system itself
+ */
+const char* lumiera_config_defaults[] =
+ {
+ /* Low level formating, don't change these */
+ "config.formatstr.link = '< %s'",
+ "config.formatstr.number.dec = '= %lld'",
+ "config.formatstr.number.hex = '= 0x%llX'",
+ "config.formatstr.number.oct = '= 0%llo'",
+ "config.formatstr.real = '= %Lg'",
+ "config.formatstr.real.dec = '= %Lf'",
+ "config.formatstr.real.sci = '= %Le'",
+ "config.formatstr.string = '=%s'",
+ "config.formatstr.string.dquoted = '= \"%s\"'",
+ "config.formatstr.string.quoted = '= ''%s'''",
+ "config.formatstr.word = '= %s'",
+ "config.formatstr.bool = '= %d'",
+
+ /* default representations per type */
+ "config.formatdef.link < config.formatstr.link",
+ "config.formatdef.number < config.formatstr.number.dec",
+ "config.formatdef.real < config.formatstr.real",
+ "config.formatdef.string < config.formatstr.string",
+ "config.formatdef.word < config.formatstr.word",
+ "config.formatdef.bool < config.formatstr.bool",
+
+ /* per key formatting override stored under */
+ "config.formatkey ='config.format.%s'",
+
+ NULL
+ };
+
+
+/* singleton config */
+LumieraConfig lumiera_global_config = NULL;
+
+
+int
+lumiera_config_init (const char* path)
+{
+ TRACE (config);
+ REQUIRE (!lumiera_global_config, "Configuration subsystem already initialized");
+ REQUIRE (path);
+
+ NOBUG_INIT_FLAG (config_all);
+ NOBUG_INIT_FLAG (config);
+ NOBUG_INIT_FLAG (config_typed);
+ NOBUG_INIT_FLAG (config_file);
+ NOBUG_INIT_FLAG (config_item);
+ NOBUG_INIT_FLAG (config_lookup);
+
+ lumiera_global_config = lumiera_malloc (sizeof (*lumiera_global_config));
+ lumiera_config_lookup_init (&lumiera_global_config->keys);
+
+ lumiera_configitem_init (&lumiera_global_config->defaults);
+ lumiera_configitem_init (&lumiera_global_config->files);
+ lumiera_configitem_init (&lumiera_global_config->TODO_unknown);
+
+ lumiera_rwlock_init (&lumiera_global_config->lock, "config rwlock", &NOBUG_FLAG (config));
+
+ lumiera_config_setdefault (lumiera_tmpbuf_snprintf (SIZE_MAX, "config.path = %s", path));
+
+ for (const char** itr = lumiera_config_defaults; *itr; ++itr)
+ {
+ lumiera_config_setdefault (*itr);
+ }
+
+ return 0;
+}
+
+
+void
+lumiera_config_destroy ()
+{
+ TRACE (config);
+ if (lumiera_global_config)
+ {
+ lumiera_rwlock_destroy (&lumiera_global_config->lock, &NOBUG_FLAG (config));
+ lumiera_configitem_destroy (&lumiera_global_config->defaults, &lumiera_global_config->keys);
+ lumiera_configitem_destroy (&lumiera_global_config->files, &lumiera_global_config->keys);
+ lumiera_configitem_destroy (&lumiera_global_config->TODO_unknown, &lumiera_global_config->keys);
+ lumiera_config_lookup_destroy (&lumiera_global_config->keys);
+ lumiera_free (lumiera_global_config);
+ lumiera_global_config = NULL;
+ }
+ else
+ WARN (config, "Tried to destroy non initialized config subsystem");
+}
+
+
+int
+lumiera_config_load (const char* file)
+{
+ TRACE (config);
+ UNIMPLEMENTED();
+ return -1;
+}
+
+
+int
+lumiera_config_save ()
+{
+ TRACE (config);
+ UNIMPLEMENTED();
+ return -1;
+}
+
+
+int
+lumiera_config_purge (const char* filename)
+{
+ TRACE (config);
+
+ UNIMPLEMENTED();
+ return -1;
+}
+
+
+int
+lumiera_config_get (const char* key, const char** value)
+{
+ TRACE (config);
+ REQUIRE (key);
+ REQUIRE (value);
+
+ int ret = -1;
+
+ /* we translate the key for the env var override by making it uppercase and replace . with _,
+ as side effect, this also checks the key syntax */
+ char* tr_key = lumiera_tmpbuf_tr (key,
+ LUMIERA_CONFIG_KEY_CHARS,
+ LUMIERA_CONFIG_ENV_CHARS,
+ NULL);
+
+ if (tr_key)
+ {
+ char* env = lumiera_tmpbuf_snprintf (2048, "LUMIERA_%s", tr_key);
+
+ *value = getenv(env);
+ if (*value)
+ {
+ ret = 0;
+ NOTICE (config, "envvar override for config %s = %s", env, *value);
+ }
+ else
+ {
+ TODO ("follow '<' delegates?");
+ LumieraConfigitem item = lumiera_config_lookup_item_find (&lumiera_global_config->keys, key);
+
+ if (item)
+ {
+ *value = item->delim+1;
+ ret = 0;
+ }
+ else
+ LUMIERA_ERROR_SET (config, CONFIG_NO_ENTRY);
+ }
+ }
+ else
+ {
+ LUMIERA_ERROR_SET (config, CONFIG_SYNTAX_KEY);
+ }
+
+ return ret;
+}
+
+
+int
+lumiera_config_get_default (const char* key, const char** value)
+{
+ TRACE (config);
+ REQUIRE (key);
+ REQUIRE (value);
+
+ int ret = -1;
+
+ TODO ("follow '<' delegates?");
+ TODO ("refactor _get and get_default to iterator access (return LList or Lookupentry)");
+ LumieraConfigitem item = lumiera_config_lookup_item_tail_find (&lumiera_global_config->keys, key);
+
+ if (item && item->parent == &lumiera_global_config->defaults)
+ {
+ *value = item->delim+1;
+ ret = 0;
+ }
+
+ return ret;
+}
+
+
+int
+lumiera_config_set (const char* key, const char* delim_value)
+{
+ TRACE (config);
+
+ TODO ("if does this item already exist in a user writeable file?");
+ TODO (" replace delim_value");
+
+ TODO ("else");
+ TODO (" find matching prefix");
+ TODO (" find matching suffix");
+ TODO (" find proper prefix indentation, else use config.indent");
+ TODO (" create configitem with prefix/suffix removed");
+
+
+
+// * set a value by key
+// * handles internally everything as string:string key:value pair.
+// * lowlevel function
+// * tag file as dirty
+// * set will create a new user configuration file if it does not exist yet or will append a line to the existing one in RAM. These files, tagged as 'dirty', will be only written if save() is called.
+
+
+
+ UNIMPLEMENTED();
+ return -1;
+}
+
+
+LumieraConfigitem
+lumiera_config_setdefault (const char* line)
+{
+ TRACE (config);
+ REQUIRE (line);
+
+ LumieraConfigitem item = NULL;
+
+ LUMIERA_WRLOCK_SECTION (config, &lumiera_global_config->lock)
+ {
+ const char* key = line;
+ while (*key && isspace (*key))
+ key++;
+
+ key = lumiera_tmpbuf_strndup (line, strspn (line, LUMIERA_CONFIG_KEY_CHARS));
+
+ if (!(item = lumiera_config_lookup_item_find (&lumiera_global_config->keys, key)) || item->parent != &lumiera_global_config->defaults)
+ {
+ item = lumiera_configitem_new (line);
+
+ if (item)
+ {
+ ENSURE (item->delim, "default must be a configentry with key=value or keydelim == '=' || *item->delim == '<', "default must be a configentry with key=value or keyline);
+
+ llist_insert_head (&lumiera_global_config->defaults.childs, &item->link);
+ item->parent = &lumiera_global_config->defaults;
+
+ lumiera_config_lookup_insert_default (&lumiera_global_config->keys, item);
+ }
+ }
+ }
+
+ return item;
+}
+
+
+void
+lumiera_config_dump (FILE* out)
+{
+ fprintf (out, "# registered defaults:\n");
+
+ LLIST_FOREACH (&lumiera_global_config->defaults.childs, node)
+ fprintf (out, "%s\n", ((LumieraConfigitem) node)->line);
+
+ fprintf (out, "# end of defaults\n\n");
+
+#if 0 /*TODO UNIMPLEMENTED */
+ fprintf (out, "# files:\n");
+ lumiera_configitem files;
+ fprintf (out, "# volatiles:")
+ lumiera_configitem TODO_unknown;
+#endif
+}
+
+
+int
+lumiera_config_reset (const char* key)
+{
+ TRACE (config);
+ UNIMPLEMENTED();
+ return -1;
+}
+
+
+int
+lumiera_config_info (const char* key, const char** filename, unsigned* line)
+{
+ TRACE (config);
+ UNIMPLEMENTED();
+ return -1;
+}
+
+/*
+// Local Variables:
+// mode: C
+// c-file-style: "gnu"
+// indent-tabs-mode: nil
+// End:
+*/
diff --git a/src/backend/config.h b/src/backend/config.h
new file mode 100644
index 000000000..7667f26f1
--- /dev/null
+++ b/src/backend/config.h
@@ -0,0 +1,262 @@
+/*
+ config.h - Lumiera configuration system
+
+ Copyright (C) Lumiera.org
+ 2008, Christian Thaeter
+
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef LUMIERA_CONFIG_H
+#define LUMIERA_CONFIG_H
+
+//TODO: Support library includes//
+#include "lib/error.h"
+#include "lib/rwlock.h"
+
+//TODO: Forward declarations//
+struct lumiera_config_struct;
+
+
+/* master config subsystem debug flag */
+NOBUG_DECLARE_FLAG (config_all);
+/* config subsystem internals */
+NOBUG_DECLARE_FLAG (config);
+/* high level typed interface operations */
+NOBUG_DECLARE_FLAG (config_typed);
+/* file operations */
+NOBUG_DECLARE_FLAG (config_file);
+/* single config items */
+NOBUG_DECLARE_FLAG (config_item);
+/* lookup config keys */
+NOBUG_DECLARE_FLAG (config_lookup);
+
+
+LUMIERA_ERROR_DECLARE (CONFIG_SYNTAX);
+LUMIERA_ERROR_DECLARE (CONFIG_SYNTAX_KEY);
+LUMIERA_ERROR_DECLARE (CONFIG_SYNTAX_VALUE);
+LUMIERA_ERROR_DECLARE (CONFIG_NO_ENTRY);
+LUMIERA_ERROR_DECLARE (CONFIG_DEFAULT);
+
+//TODO: Lumiera header includes//
+#include "backend/config_lookup.h"
+
+//TODO: System includes//
+#include
+#include
+
+/**
+ * @file
+ * TODO documentation, http://www.pipapo.org/pipawiki/Lumiera/ConfigLoader
+ */
+
+#define LUMIERA_CONFIG_KEY_CHARS "abcdefghijklmnopqrstuvwxyz0123456789_."
+#define LUMIERA_CONFIG_ENV_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789__"
+
+struct lumiera_config_struct
+{
+ lumiera_config_lookup keys;
+
+ lumiera_configitem defaults; /* registered default values */
+ lumiera_configitem files; /* all loaded files */
+ lumiera_configitem TODO_unknown; /* all values which are not part of a file and not default TODO: this will be removed when file support is finished */
+
+ /*
+ all access is protected with rwlock's.
+ We use rwlocks here since concurrent reads are likely common.
+
+ So far this is a global config lock, if this is a problem we might granularize it by locking on a file level.
+ config access is not planned to be transactional yet, if this is a problem we need to expose the rwlock to a config_acquire/config_release function pair
+ */
+ lumiera_rwlock lock;
+};
+
+typedef struct lumiera_config_struct lumiera_config;
+typedef lumiera_config* LumieraConfig;
+
+/**
+ * Supported high level types: TODO documenting
+ */
+/* TODO: add here as 'LUMIERA_CONFIG_TYPE(name, ctype)' the _get/_set prototypes are declared automatically below, you still have to implement them in config.c */
+#define LUMIERA_CONFIG_TYPES \
+ LUMIERA_CONFIG_TYPE(link, char*) \
+ LUMIERA_CONFIG_TYPE(number, signed long long) \
+ LUMIERA_CONFIG_TYPE(real, long double) \
+ LUMIERA_CONFIG_TYPE(string, char*) \
+ LUMIERA_CONFIG_TYPE(word, char*) \
+ LUMIERA_CONFIG_TYPE(bool, int)
+
+
+// * does only initialize the variables, so that they get valid values, but does not allocate them as they will be allocated before as they are singleton.
+// * lumiera_config_init (const char* searchpath) searchpath is a buildin-default, can be changed via configure and can be appended and overridden by using a flag, e.g. {{{ --config-path-append="" }}} or {{{ --config-path="" }}}
+
+/**
+ * Initialize the configuration subsystem.
+ * @param path search path for config files.
+ * Must be called only once
+ */
+int
+lumiera_config_init (const char* path);
+
+
+// * frees all space allocated by the ConfigLoader.
+
+/**
+ * Destroys the configuration subsystem.
+ * Subsequent calls are no-ops.
+ */
+void
+lumiera_config_destroy ();
+
+
+// * reads '''one''' single configuration file that will include all settings from other files.
+// * does not read itself but give delegates reading. The actual reading and parsing will be done in configfile object. s.later.
+/**
+ *
+ */
+int
+lumiera_config_load (const char* file);
+
+
+//{{{ lumiera_config_save () { LLIST_FOREACH(config_singleton.files, f) { LumieraFile file = (LumieraFile) f; if(lumiera_configfile_isdirty (file)) lumiera_configfile_save(file); } } }}}
+// * saves all the changed settings to user's configuration files, but recognizes where settings came from and will write them to an appropriate named file. Example: '''changed''' values from ''/usr/local/share/lumiera/plugins/blur.conf'' will be saved into ''~/.lumiera/plugins/blur.conf''
+// * finds out which files are dirty and which settings have to be written to user's config files.
+// * does initiate the actual saving procedure by delegating the save to the actual configfile objects, see below.
+// * empty user configuration files in RAM will be deleted from disk on write.
+// * checks whether the file has changed since last read, and will print out an error if necessary instead of overriding it without notification.
+/**
+ *
+ */
+int
+lumiera_config_save ();
+
+
+// * `lumiera_config_purge(const char* filename)` removes all configs loaded from filename
+/**
+ *
+ */
+int
+lumiera_config_purge (const char* filename);
+
+
+/**
+ * Does a diagnostic dump of the whole config database
+ */
+void
+lumiera_config_dump (FILE* out);
+
+
+// * {{{ lumiera_config_get(...) }}}
+// * get a value by key
+// * handles internally everything as string:string key:value pair.
+// * lowlevel function
+// * lumiera_config_integer_get (const char* key, int *value) will return integers instead of strings and return 0 if succeeded and -1 if it failed.
+/**
+ *
+ */
+int
+lumiera_config_get (const char* key, const char** value);
+
+
+int
+lumiera_config_get_default (const char* key, const char** value);
+
+
+// * {{{ lumiera_config_set(...) }}}
+// * set a value by key
+// * handles internally everything as string:string key:value pair.
+// * lowlevel function
+// * tag file as dirty
+// * set will create a new user configuration file if it does not exist yet or will append a line to the existing one in RAM. These files, tagged as 'dirty', will be only written if save() is called.
+
+/**
+ *
+ *
+ * @param key
+ * @param delim_value delimiter (= or <) followed by the value to be set
+ *
+ */
+int
+lumiera_config_set (const char* key, const char* delim_value);
+
+
+/**
+ * Installs a default value for a config key.
+ * Any key might have an associated default value which is used when
+ * no other configuration is available, this can be set once.
+ * Any subsequent call will be a no-op.
+ * @param line line with key, delimiter and value to store as default value
+ * @return NULL in case of an error, else a pointer to the default configitem
+ */
+LumieraConfigitem
+lumiera_config_setdefault (const char* line);
+
+
+
+// * {{{int lumiera_config_TYPE_get(const char* key, TYPE* value, const char* default) }}}
+// High level config interface for different types.
+// if default is given (!NULL) then value is set to default in case key was not found or any other error occured.
+// error code is still set and -1 (fail) is returned in case of an error, but it might be cleared with no ill effects.
+// NOTE: errors are persistent in our error handler, they must still be cleared, even when ignored.
+// if default is given then 'KEY_NOT_FOUND' is not a error here, if default is NULL then it is
+// NOTE2: default values are given as strings, the config loader remembers a given default value and checks if it got changed
+// when it is _set(). Thus a default value can be supressed when set/written
+/**
+ *
+ */
+#define LUMIERA_CONFIG_TYPE(name, type) \
+ int \
+ lumiera_config_##name##_get (const char* key, type* value);
+LUMIERA_CONFIG_TYPES
+#undef LUMIERA_CONFIG_TYPE
+
+
+
+// * {{{ lumiera_config_TYPE_set (const char* key, TYPE*value, const char* fmt) }}}
+// Highlevel interface for different types, fmt is a printf format specifier for the desired format, when NULL, defaults apply.
+/**
+ *
+ */
+#define LUMIERA_CONFIG_TYPE(name, type) \
+ int \
+ lumiera_config_##name##_set (const char* key, type* value);
+LUMIERA_CONFIG_TYPES
+#undef LUMIERA_CONFIG_TYPE
+
+
+// * {{{ lumiera_config_reset(...) }}}
+// * reset a value by key to the system default values, thus removes a user's configuration line.
+/**
+ *
+ */
+int
+lumiera_config_reset (const char* key);
+
+
+// * Find exact place of a setting.
+/**
+ *
+ */
+int
+lumiera_config_info (const char* key, const char** filename, unsigned* line);
+
+#endif
+/*
+// Local Variables:
+// mode: C
+// c-file-style: "gnu"
+// indent-tabs-mode: nil
+// End:
+*/
diff --git a/src/backend/config_lookup.c b/src/backend/config_lookup.c
new file mode 100644
index 000000000..96c62c880
--- /dev/null
+++ b/src/backend/config_lookup.c
@@ -0,0 +1,239 @@
+/*
+ config_lookup.c - Lookup functions for the config subsystem
+
+ Copyright (C) Lumiera.org
+ 2008, Christian Thaeter
+
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+#include "lib/safeclib.h"
+
+#include "backend/config_lookup.h"
+#include "backend/config.h"
+
+/* we only use one fatal error for now, when allocation in the config system fail, something else is pretty wrong */
+LUMIERA_ERROR_DEFINE (CONFIG_LOOKUP, "config lookup failure");
+
+/*
+ support functions for the splay tree
+*/
+static int
+cmp_fn (const void* a, const void* b);
+
+static void
+delete_fn (PSplaynode node);
+
+static const void*
+key_fn (const PSplaynode node);
+
+
+/**
+ * @file
+ * Implementation of the lookup of configuration keys
+ */
+
+
+LumieraConfigLookup
+lumiera_config_lookup_init (LumieraConfigLookup self)
+{
+ TRACE (config_lookup);
+ psplay_init (&self->tree, cmp_fn, key_fn, delete_fn);
+ return self;
+}
+
+
+LumieraConfigLookup
+lumiera_config_lookup_destroy (LumieraConfigLookup self)
+{
+ TRACE (config_lookup);
+ if (self)
+ psplay_destroy (&self->tree);
+ return self;
+}
+
+
+LumieraConfigLookupentry
+lumiera_config_lookup_insert (LumieraConfigLookup self, LumieraConfigitem item)
+{
+ TRACE (config_lookup);
+ REQUIRE (self);
+ REQUIRE (item);
+ REQUIRE (item->key);
+ REQUIRE (item->key_size);
+
+ FIXME ("implement section prefix/suffix for the key");
+ const char* key = lumiera_tmpbuf_strcat3 (NULL, 0, item->key, item->key_size, NULL, 0);
+
+ LumieraConfigLookupentry entry = (LumieraConfigLookupentry)psplay_find (&self->tree, key, 100);
+ if (!entry)
+ entry = (LumieraConfigLookupentry)psplay_insert (&self->tree, &lumiera_config_lookupentry_new (key)->node, 100);
+
+ llist_insert_head (&entry->configitems, &item->lookup);
+ return entry;
+}
+
+
+LumieraConfigLookupentry
+lumiera_config_lookup_insert_default (LumieraConfigLookup self, LumieraConfigitem item)
+{
+ TRACE (config_lookup);
+ REQUIRE (self);
+ REQUIRE (item);
+ REQUIRE (item->key);
+ REQUIRE (item->key_size);
+
+ const char* key = lumiera_tmpbuf_snprintf (SIZE_MAX, "%.*s", item->key_size, item->key);
+ LumieraConfigLookupentry entry = (LumieraConfigLookupentry)psplay_find (&self->tree, key, 100);
+ if (!entry)
+ entry = (LumieraConfigLookupentry)psplay_insert (&self->tree, &lumiera_config_lookupentry_new (key)->node, 100);
+ TODO ("else check that no 'default' item already exists, that is, the tail element's parent points to the 'defaults' in config");
+
+ llist_insert_tail (&entry->configitems, &item->lookup);
+ return entry;
+}
+
+
+LumieraConfigitem
+lumiera_config_lookup_remove (LumieraConfigLookup self, LumieraConfigitem item)
+{
+ TRACE (config_lookup);
+ REQUIRE (!llist_is_empty (&item->lookup), "item is not in a lookup");
+
+ if (llist_is_single (&item->lookup))
+ {
+ /* last item in lookup, remove it from the splay tree */
+ LumieraConfigLookupentry entry = LLIST_TO_STRUCTP (llist_next (&item->lookup), lumiera_config_lookupentry, configitems);
+ llist_unlink (&item->lookup);
+ psplay_delete_node (&self->tree, (PSplaynode)entry);
+ }
+ else
+ {
+ /* more than this item present in hash, just unlink this item */
+ llist_unlink (&item->lookup);
+ }
+
+ return item;
+}
+
+
+LumieraConfigLookupentry
+lumiera_config_lookup_find (LumieraConfigLookup self, const char* key)
+{
+ TRACE (config_lookup);
+ return (LumieraConfigLookupentry)psplay_find (&self->tree, key, 100);
+}
+
+
+LumieraConfigitem
+lumiera_config_lookup_item_find (LumieraConfigLookup self, const char* key)
+{
+ TRACE (config_lookup);
+
+ LumieraConfigLookupentry entry =
+ lumiera_config_lookup_find (self, key);
+
+ if (entry && !llist_is_empty (&entry->configitems))
+ return LLIST_TO_STRUCTP (llist_head (&entry->configitems), lumiera_configitem, lookup);
+
+ return NULL;
+}
+
+
+LumieraConfigitem
+lumiera_config_lookup_item_tail_find (LumieraConfigLookup self, const char* key)
+{
+ TRACE (config_lookup);
+
+ LumieraConfigLookupentry entry =
+ lumiera_config_lookup_find (self, key);
+
+ if (entry && !llist_is_empty (&entry->configitems))
+ return LLIST_TO_STRUCTP (llist_tail (&entry->configitems), lumiera_configitem, lookup);
+
+ return NULL;
+}
+
+
+
+/*
+ Lookup entries
+*/
+
+LumieraConfigLookupentry
+lumiera_config_lookupentry_init (LumieraConfigLookupentry self, const char* key)
+{
+ TRACE (config_lookup, "key = %s", key);
+ if (self)
+ {
+ psplaynode_init (&self->node);
+ llist_init (&self->configitems);
+ self->full_key = lumiera_strndup (key, SIZE_MAX);
+ }
+ return self;
+}
+
+
+LumieraConfigLookupentry
+lumiera_config_lookupentry_new (const char* key)
+{
+ return lumiera_config_lookupentry_init (lumiera_malloc (sizeof (lumiera_config_lookupentry)), key);
+}
+
+
+LumieraConfigLookupentry
+lumiera_config_lookupentry_destroy (LumieraConfigLookupentry self)
+{
+ TRACE (config_lookup);
+ if (self)
+ {
+ REQUIRE (llist_is_empty (&self->configitems), "lookup node still in use");
+ lumiera_free (self->full_key);
+ }
+ return self;
+}
+
+
+void
+lumiera_config_lookupentry_delete (LumieraConfigLookupentry self)
+{
+ lumiera_free (lumiera_config_lookupentry_destroy (self));
+}
+
+static int
+cmp_fn (const void* a, const void* b)
+{
+ return strcmp ((const char*)a, (const char*)b);
+}
+
+static void
+delete_fn (PSplaynode node)
+{
+ lumiera_config_lookupentry_delete ((LumieraConfigLookupentry) node);
+}
+
+
+static const void*
+key_fn (const PSplaynode node)
+{
+ return ((LumieraConfigLookupentry) node)->full_key;
+}
+
+/*
+// Local Variables:
+// mode: C
+// c-file-style: "gnu"
+// indent-tabs-mode: nil
+// End:
+*/
diff --git a/src/backend/config_lookup.h b/src/backend/config_lookup.h
new file mode 100644
index 000000000..a0ec20dd5
--- /dev/null
+++ b/src/backend/config_lookup.h
@@ -0,0 +1,192 @@
+/*
+ config_lookup.h - Lookup functions for the config subsystem
+
+ Copyright (C) Lumiera.org
+ 2008, Christian Thaeter
+
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef LUMIERA_CONFIG_LOOKUP_H
+#define LUMIERA_CONFIG_LOOKUP_H
+
+#include "lib/psplay.h"
+#include "lib/llist.h"
+#include "lib/error.h"
+
+typedef struct lumiera_config_lookup_struct lumiera_config_lookup;
+typedef lumiera_config_lookup* LumieraConfigLookup;
+
+typedef struct lumiera_config_lookupentry_struct lumiera_config_lookupentry;
+typedef lumiera_config_lookupentry* LumieraConfigLookupentry;
+
+
+#include "backend/configitem.h"
+
+
+#include
+
+
+/**
+ * @file
+ * Lookup of configuration keys. Configuration keys are dynamically stored in a splay tree.
+ * This happens for defaults, loaded config files and entries which are set explicitly.
+ * The system maintains no central registry of all possible keys.
+ * We store here the full keys of configentries as well as the keys of section prefixes.
+ * Section prefixes are stored with a trailing dot to disambiguate them from entry keys.
+ */
+
+
+LUMIERA_ERROR_DECLARE (CONFIG_LOOKUP);
+
+/**
+ * Just contains a hashtable to give sufficent abstraction.
+ */
+struct lumiera_config_lookup_struct
+{
+ psplay tree;
+};
+
+/**
+ * Initialize a lookup structure.
+ * @param self lookup structure to be initialized
+ * @return self on success else NULL
+ */
+LumieraConfigLookup
+lumiera_config_lookup_init (LumieraConfigLookup self);
+
+/**
+ * Destruct a lookup structure.
+ * @param self lookup structure to be destructed
+ * @return self
+ */
+LumieraConfigLookup
+lumiera_config_lookup_destroy (LumieraConfigLookup self);
+
+/**
+ * Add a config item to a lookup structure.
+ * Config items are stored under their key and stacked in insertion order.
+ * @param self lookup structure where the item shall be added
+ * @param item config item to add to the lookup structure
+ * @return opaque pointer to a hashtable entry
+ */
+LumieraConfigLookupentry
+lumiera_config_lookup_insert (LumieraConfigLookup self, LumieraConfigitem item);
+
+
+/**
+ * Add a default config item to a lookup structure.
+ * @internal
+ * This function is used internal.
+ * The item must contain a full key and not part of any 'section'
+ * and is inserted as tail of the lookup list.
+ * @param self lookup structure where the item shall be added
+ * @param item config item to add to the lookup structure
+ * @return opaque pointer to a hashtable entry
+ */
+LumieraConfigLookupentry
+lumiera_config_lookup_insert_default (LumieraConfigLookup self, LumieraConfigitem item);
+
+
+/**
+ * Remove a config item from a lookup structure.
+ * Config must be removed from the lookup when they are not used anymore.
+ * Removing a config item unlinks it from the stack of all config items with the same key.
+ * When this was the last config item under that key, the lookup entry is cleaned up.
+ * @param self lookup structure where the item shall be removed
+ * @param item config item to be removed from the lookup
+ * @return item
+ */
+LumieraConfigitem
+lumiera_config_lookup_remove (LumieraConfigLookup self, LumieraConfigitem item);
+
+/**
+ * Find a hashtable entry in the lookup structure.
+ * Internal function, can be used to check if at least one item is available for a given key.
+ * @param self lookup structure where the key shall be searched
+ * @param key string to be looked up
+ * @return NULL if nothing is found, otherwise a opaque pointer to a hash table entry
+ */
+LumieraConfigLookupentry
+lumiera_config_lookup_find (LumieraConfigLookup self, const char* key);
+
+/**
+ * Find a the topmost config item stored to a given key.
+ * @param self lookup structure where the key shall be searched
+ * @param key string to be looked up
+ * @return the config item which was last stored under the given key or NULL when nothing was found
+ */
+LumieraConfigitem
+lumiera_config_lookup_item_find (LumieraConfigLookup self, const char* key);
+
+/**
+ * Find a the bottommost config item stored to a given key.
+ * defaults sits at the bottom if exists
+ * @param self lookup structure where the key shall be searched
+ * @param key string to be looked up
+ * @return TODO
+ */
+LumieraConfigitem
+lumiera_config_lookup_item_tail_find (LumieraConfigLookup self, const char* key);
+
+
+
+/*
+ Lookup hash entries for the cuckoo hash
+*/
+
+/**
+ * Structure defining single hash table entries.
+ * @internal
+ */
+struct lumiera_config_lookupentry_struct
+{
+ psplaynode node;
+ /* stack of all configitems stored under this key */
+ llist configitems;
+
+ /*
+ we store a copy of the full key here
+ configentry keys are complete as expected
+ section keys are the prefix stored with a trailing dot,
+ suffixes will be found by iterative search
+ */
+ char* full_key;
+};
+
+
+/* internal */
+LumieraConfigLookupentry
+lumiera_config_lookupentry_init (LumieraConfigLookupentry self, const char* key);
+
+LumieraConfigLookupentry
+lumiera_config_lookupentry_new (const char* key);
+
+/* internal */
+LumieraConfigLookupentry
+lumiera_config_lookupentry_destroy (LumieraConfigLookupentry self);
+
+
+void
+lumiera_config_lookupentry_delete (LumieraConfigLookupentry self);
+
+#endif
+/*
+// Local Variables:
+// mode: C
+// c-file-style: "gnu"
+// indent-tabs-mode: nil
+// End:
+*/
diff --git a/src/backend/config_typed.c b/src/backend/config_typed.c
new file mode 100644
index 000000000..07c2bb486
--- /dev/null
+++ b/src/backend/config_typed.c
@@ -0,0 +1,313 @@
+/*
+ config_typed.c - Lumiera configuration highlevel interface
+
+ Copyright (C) Lumiera.org
+ 2008, Christian Thaeter
+
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+//TODO: Support library includes//
+#include "lib/safeclib.h"
+
+
+//TODO: Lumiera header includes//
+#include "backend/config.h"
+
+//TODO: internal/static forward declarations//
+extern LumieraConfig lumiera_global_config;
+
+
+//TODO: System includes//
+#include
+
+/**
+ * @file
+ * Here are the high level typed configuration interfaces defined.
+ */
+
+int
+lumiera_config_link_get (const char* key, char** value)
+{
+ TRACE (config_typed);
+ UNIMPLEMENTED();
+ return 0;
+}
+
+int
+lumiera_config_link_set (const char* key, char** value)
+{
+ TRACE (config_typed);
+ UNIMPLEMENTED();
+ return 0;
+}
+
+
+/**
+ * Number
+ * signed integer numbers, in different formats (decimal, hex, oct, binary(for masks))
+ */
+int
+lumiera_config_number_get (const char* key, long long* value)
+{
+ TRACE (config_typed);
+
+ int ret = -1;
+
+ const char* raw_value = NULL;
+
+ LUMIERA_RDLOCK_SECTION (config_typed, &lumiera_global_config->lock)
+ {
+ if (!lumiera_config_get (key, &raw_value))
+ {
+ if (raw_value)
+ {
+ /* got it, scan it */
+ if (sscanf (raw_value, "%Li", value) == 1)
+ ret = 0; /* all ok */
+ else
+ {
+ LUMIERA_ERROR_SET (config_typed, CONFIG_SYNTAX_VALUE);
+ }
+ }
+ else
+ LUMIERA_ERROR_SET (config, CONFIG_NO_ENTRY);
+ }
+ }
+
+ return ret;
+}
+
+int
+lumiera_config_number_set (const char* key, long long* value)
+{
+ TRACE (config_typed);
+ UNIMPLEMENTED();
+ return 0;
+}
+
+
+/**
+ * Real
+ * floating point number in standard formats (see printf/scanf)
+ */
+int
+lumiera_config_real_get (const char* key, long double* value)
+{
+ TRACE (config_typed);
+ UNIMPLEMENTED();
+ return 0;
+}
+
+int
+lumiera_config_real_set (const char* key, long double* value)
+{
+ TRACE (config_typed);
+ UNIMPLEMENTED();
+ return 0;
+}
+
+
+
+/**
+ * String
+ * unquoted string which covers the whole value area and gets chopped or
+ * quoted string which preserves leading/trailing spaces
+ * either single or double quotes are allowed, doubling the quote in a string escapes it
+ */
+
+
+/**
+ * helper function, takes a raw input string and give a tmpbuf with the string parsed back.
+ */
+static char*
+scan_string (const char* in)
+{
+ /* chop leading blanks */
+ in += strspn(in, " \t");
+
+ char quote = *in;
+ char* end;
+ char* ret = NULL;
+
+ if (quote == '"' || quote == '\'')
+ {
+ /* quoted string */
+ ++in;
+ end = strchr (in, quote);
+ while (end && end[1] == quote)
+ end = strchr (end + 2, quote);
+
+ if (end)
+ {
+ ret = lumiera_tmpbuf_strndup (in, end - in);
+
+ /* replace double quote chars with single one */
+ char* wpos;
+ char* rpos;
+ for (wpos = rpos = ret; *rpos; ++rpos, ++wpos)
+ {
+ if (*rpos == quote)
+ ++rpos;
+ *wpos = *rpos;
+ }
+ *wpos = '\0';
+ }
+ else
+ /* quotes doesnt match */
+ LUMIERA_ERROR_SET (config_typed, CONFIG_SYNTAX_VALUE);
+ }
+ else
+ {
+ /* unquoted string */
+ ret = lumiera_tmpbuf_strndup (in, SIZE_MAX);
+
+ /* chop trailing blanks */
+ end = ret + strlen (ret) - 1;
+ while (end > ret && (*end == ' ' || *end == '\t'))
+ *end-- = '\0';
+ }
+
+ return ret;
+}
+
+int
+lumiera_config_string_get (const char* key, char** value)
+{
+ TRACE (config_typed);
+
+ int ret = -1;
+
+ const char* raw_value = NULL;
+
+ LUMIERA_RDLOCK_SECTION (config_typed, &lumiera_global_config->lock)
+ {
+ if (!lumiera_config_get (key, &raw_value))
+ {
+ if (raw_value)
+ {
+ *value = scan_string (raw_value);
+ if (*value)
+ ret = 0; /* all ok */
+ /* else error was raised by scan_string */
+ }
+ else
+ LUMIERA_ERROR_SET (config, CONFIG_NO_ENTRY);
+ }
+ }
+
+ return ret;
+}
+
+int
+lumiera_config_string_set (const char* key, char** value)
+{
+ TRACE (config_typed);
+ UNIMPLEMENTED();
+ return 0;
+}
+
+
+
+/**
+ * Word
+ * A single word, no quotes, chopped
+ */
+
+/**
+ * helper function, takes a raw input string and give a tmpbuf with the word parsed back.
+ */
+static char*
+scan_word (const char* in)
+{
+ /* chop leading blanks */
+ in += strspn(in, " \t");
+
+ char* ret = lumiera_tmpbuf_strndup (in, SIZE_MAX);
+ char* end = ret;
+
+ /* chop trailing blanks */
+ while (*end != ' ' && *end != '\t')
+ ++end;
+
+ *end++ = '\0';
+
+ return ret;
+}
+
+int
+lumiera_config_word_get (const char* key, char** value)
+{
+ TRACE (config_typed, "KEY %s", key);
+
+ int ret = -1;
+
+ const char* raw_value = NULL;
+
+ LUMIERA_RDLOCK_SECTION (config_typed, &lumiera_global_config->lock)
+ {
+ if (!lumiera_config_get (key, &raw_value))
+ {
+ if (raw_value)
+ {
+ *value = scan_word (raw_value);
+ if (*value)
+ ret = 0; /* all ok */
+ }
+ else
+ LUMIERA_ERROR_SET (config, CONFIG_NO_ENTRY);
+ }
+ }
+
+ return ret;
+}
+
+int
+lumiera_config_word_set (const char* key, char** value)
+{
+ TRACE (config_typed);
+ UNIMPLEMENTED();
+ return 0;
+}
+
+
+/**
+ * Bool
+ * Bool in various formats, (0,1(!1), yes/no, true/false, on/off, set/clear)
+ */
+int
+lumiera_config_bool_get (const char* key, int* value)
+{
+ TRACE (config_typed);
+ UNIMPLEMENTED();
+ return 0;
+}
+
+int
+lumiera_config_bool_set (const char* key, int* value)
+{
+ TRACE (config_typed);
+ UNIMPLEMENTED();
+ return 0;
+}
+
+
+/*
+// Local Variables:
+// mode: C
+// c-file-style: "gnu"
+// indent-tabs-mode: nil
+// End:
+*/
diff --git a/src/backend/configentry.c b/src/backend/configentry.c
new file mode 100644
index 000000000..e2c846b12
--- /dev/null
+++ b/src/backend/configentry.c
@@ -0,0 +1,74 @@
+/*
+ configentry.c - single entries from configfiles
+
+ Copyright (C) Lumiera.org
+ 2008, Christian Thaeter
+
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+//TODO: Support library includes//
+#include "lib/safeclib.h"
+
+//TODO: Lumiera header includes//
+#include "backend/configentry.h"
+
+//TODO: internal/static forward declarations//
+
+
+//TODO: System includes//
+
+
+/**
+ * @file
+ *
+ */
+
+//code goes here//
+LumieraConfigitem
+lumiera_configentry_new (LumieraConfigitem tmp)
+{
+ LumieraConfigentry self = lumiera_malloc (sizeof (*self));
+ lumiera_configitem_move ((LumieraConfigitem)self, tmp);
+
+ TODO ("initialize other stuff here (lookup, parent, ...)");
+
+ return (LumieraConfigitem)self;
+}
+
+
+LumieraConfigitem
+lumiera_configentry_destroy (LumieraConfigitem self)
+{
+ TODO ("cleanup other stuff here (lookup, parent, ...)");
+
+ return self;
+}
+
+struct lumiera_configitem_vtable lumiera_configentry_funcs =
+ {
+ .new = lumiera_configentry_new,
+ .destroy = lumiera_configentry_destroy
+ };
+
+
+
+/*
+// Local Variables:
+// mode: C
+// c-file-style: "gnu"
+// indent-tabs-mode: nil
+// End:
+*/
diff --git a/src/lib/locking.h b/src/backend/configentry.h
similarity index 51%
rename from src/lib/locking.h
rename to src/backend/configentry.h
index 3c4d497d8..61f5f5f73 100644
--- a/src/lib/locking.h
+++ b/src/backend/configentry.h
@@ -1,5 +1,5 @@
/*
- locking.h - shared declarations for all locking primitives
+ configentry.h - single entries from configfiles
Copyright (C) Lumiera.org
2008, Christian Thaeter
@@ -19,36 +19,49 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#ifndef LUMIERA_LOCKING_H
-#define LUMIERA_LOCKING_H
+#ifndef LUMIERA_CONFIGENTRY_H
+#define LUMIERA_CONFIGENTRY_H
-#include
-#include
+//TODO: Support library includes//
+
+
+//TODO: Forward declarations//
+typedef struct lumiera_configentry_struct lumiera_configentry;
+typedef lumiera_configentry* LumieraConfigentry;
+
+
+//TODO: Lumiera header includes//
+#include "backend/configitem.h"
+
+//TODO: System includes//
#include
-#include "lib/error.h"
-
-
-LUMIERA_ERROR_DECLARE (MUTEX_LOCK);
-LUMIERA_ERROR_DECLARE (MUTEX_UNLOCK);
-LUMIERA_ERROR_DECLARE (MUTEX_DESTROY);
/**
* @file
- * Shared declarations for all locking primitives.
*/
-/**
- * used to store the current lock state.
- *
- *
- */
-enum lumiera_lockstate
- {
- LUMIERA_UNLOCKED,
- LUMIERA_LOCKED,
- LUMIERA_RDLOCKED,
- LUMIERA_WRLOCKED
- };
+//TODO: declarations go here//
+struct lumiera_configentry_struct
+{
+ lumiera_configitem entry;
+};
+
+extern struct lumiera_configitem_vtable lumiera_configentry_funcs;
+
+
+LumieraConfigitem
+lumiera_configentry_new (LumieraConfigitem tmp);
+
+
+LumieraConfigitem
+lumiera_configentry_destroy (LumieraConfigitem self);
#endif
+/*
+// Local Variables:
+// mode: C
+// c-file-style: "gnu"
+// indent-tabs-mode: nil
+// End:
+*/
diff --git a/src/backend/configitem.c b/src/backend/configitem.c
new file mode 100644
index 000000000..96012ad14
--- /dev/null
+++ b/src/backend/configitem.c
@@ -0,0 +1,392 @@
+/*
+ configitem.c - generalized hierachy of configuration items
+
+ Copyright (C) Lumiera.org
+ 2008, Christian Thaeter
+ Simeon Voelkel
+
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+//TODO: Support library includes//
+#include "lib/llist.h"
+#include "lib/safeclib.h"
+
+
+//TODO: Lumiera header includes//
+#include "backend/config.h"
+#include "backend/configitem.h"
+#include "backend/configentry.h"
+
+//TODO: internal/static forward declarations//
+
+
+//TODO: System includes//
+#include
+#include
+
+/**
+ * @file
+ *
+ */
+
+
+//code goes here//
+
+LumieraConfigitem
+lumiera_configitem_init (LumieraConfigitem self)
+{
+ TRACE (config_item);
+ REQUIRE (self);
+
+ llist_init (&self->link);
+ self->parent = NULL;
+ llist_init (&self->childs);
+
+ llist_init (&self->lookup);
+
+ self->line = NULL;
+
+ self->key = NULL;
+ self->key_size = 0;
+ self->delim = NULL;
+ self->vtable = NULL;
+
+ return self;
+}
+
+LumieraConfigitem
+lumiera_configitem_destroy (LumieraConfigitem self, LumieraConfigLookup lookup)
+{
+ TRACE (config_item);
+
+ if (self)
+ {
+ LLIST_WHILE_HEAD (&self->childs, node)
+ lumiera_configitem_delete ((LumieraConfigitem) node, lookup);
+
+ ENSURE (llist_is_empty (&self->childs), "destructor didn't remove childs");
+
+ if (self->vtable && self->vtable->destroy)
+ self->vtable->destroy (self);
+
+ if (!llist_is_empty (&self->lookup))
+ lumiera_config_lookup_remove (lookup, self);
+
+ llist_unlink (&self->link);
+ lumiera_free (self->line);
+ }
+
+ return self;
+}
+
+
+LumieraConfigitem
+lumiera_configitem_new (const char* line)
+{
+ TRACE (config_item);
+
+ lumiera_configitem tmp;
+ lumiera_configitem_init (&tmp);
+
+ lumiera_configitem_parse (&tmp, line);
+
+ LumieraConfigitem self = tmp.vtable && tmp.vtable->new
+ ? tmp.vtable->new (&tmp)
+ : lumiera_configitem_move (lumiera_malloc (sizeof (*self)), &tmp);
+
+ return self;
+}
+
+
+void
+lumiera_configitem_delete (LumieraConfigitem self, LumieraConfigLookup lookup)
+{
+ TRACE (config_item);
+ lumiera_free (lumiera_configitem_destroy (self, lookup));
+}
+
+
+
+LumieraConfigitem
+lumiera_configitem_move (LumieraConfigitem self, LumieraConfigitem source)
+{
+ TRACE (config_item);
+ REQUIRE (self);
+ REQUIRE (source);
+
+ llist_init (&self->link);
+ llist_insertlist_next (&self->link, &source->link);
+
+ self->parent = source->parent;
+
+ llist_init (&self->childs);
+ llist_insertlist_next (&self->childs, &source->childs);
+
+ llist_init (&self->lookup);
+ llist_insertlist_next (&self->lookup, &source->lookup);
+
+ self->line = source->line;
+ source->line = NULL;
+
+ self->key = source->key;
+ self->key_size = source->key_size;
+ self->delim = source->delim;
+ self->vtable = source->vtable;
+
+ return self;
+}
+
+
+LumieraConfigitem
+lumiera_configitem_parse (LumieraConfigitem self, const char* line)
+{
+ TRACE (config_item);
+
+ self->line = lumiera_strndup (line, SIZE_MAX);
+
+ FIXME ("MOCKUP START");
+
+ TODO ("parsing here");
+ /*
+ HOWTO parse (for simav)
+ in self->line liegt jetzt der 'rohe' string
+
+ parsen setzt folgende werte in self: .key, .key_size, .delim und vtable. den rest macht dann die 'new' funktion aus der vtable
+
+ es geht jetzt da drum rauszufinden ob diese zeile einses der folgenden sachen ist:
+ (ich zeig hier nur die grundsyntax, das parsen sollte auch entartete situationen behandeln, insbesondere leerzeichen/tabulatoren an allen moeglichen stellen)
+ auserdem sollt hier alles soweit wie moeglich validiert werden z.b. keys auf erlaubte zeichen gescheckt (siehe die _tr function)
+
+ section:
+ '[prefix suffix]'
+ .key == prefix
+ .delim == das leerzeichen (oder tab) vor suffix oder aufs abschliessende ] wenn kein suffix
+
+ kommentar:
+ leere zeile, zeile nur aus leerzeichen und tabulatoren, leerzeichen und tabulatoren gefolgt von # bis zum zeilenende
+ alles ausser vtable auf NULL
+
+ direktive:
+ '@direktive argumente'
+ .key == @
+ .delim == leerzeichen oder tab vor argumente, NULL wenn keine argumente
+
+ configentry:
+ 'key = value'
+ .key == key begin
+ .delim == '='
+ 'key < redirect'
+ .key == key begin
+ .delim == '>'
+
+ */
+ /*
+ * What should be working (for cehteh) or not yet..
+ *
+ * die Elemente sollten bereits richtig unterschieden werden, die {} sind noch zu füllen.
+ *
+ * */
+
+ char* itr = self->line;
+
+ /*skip leading whitespaces*/
+ while (*itr && isspace (*itr))
+ itr++;
+
+ /*decide what this line represents*/
+ if (!*itr || *itr == '#' )
+ {
+ /*this is an empty line or a a comment*/
+ }
+ else if (*itr == '@' )
+ {
+ /*this is a directive*/
+
+ /*itr points now to @*/
+ self->key = itr;
+
+ /*check whether there are illegal whitespaces after @*/
+ itr++;
+ if (*itr && !isspace(*itr))
+ {
+ /*now look for the end of the directive and set the keysize*/
+ self->key_size = strspn (itr, LUMIERA_CONFIG_KEY_CHARS);
+
+ itr += self->key_size;
+
+ /*we need a key with a length greather than zero and
+ * either the end of the line
+ * or a whitespace after the key */
+
+ if ( self->key_size && ( !*itr || (*itr && isspace(*itr)) ))
+ {
+ /*look for given arguments*/
+
+ /*skip blanks*/
+ while (*itr && isspace (*itr))
+ itr++;
+
+ if (*itr)
+ {
+ /*there are arguments given, thus set delim*/
+ self->delim = itr - 1;
+ }
+ else
+ {
+ /*no arguments were given*/
+ self->delim = NULL;
+ }
+ }
+ else
+ {
+ /*malformed lines shall be treated like if they were comments*/
+ self->key = NULL;
+ self->key_size = 0;
+
+ LUMIERA_ERROR_SET (config_item, CONFIG_SYNTAX);
+ }
+ }
+ else
+ {
+ /*there occurred already an error right after the @!*/
+ /*malformed lines shall be treated like if they were comments*/
+ self->key = NULL;
+ self->key_size = 0;
+
+ LUMIERA_ERROR_SET (config_item, CONFIG_SYNTAX);
+ }
+ }
+ else if (*itr == '[' )
+ {
+ /*this is a section*/
+
+ /*skip blanks before prefix*/
+ itr++;
+ while (*itr && isspace(*itr))
+ itr++;
+
+ /*itr points now to the begin of the key*/
+ self->key = itr;
+
+ /*now look for the end of the key and set the keysize*/
+ self->key_size = strspn (itr, LUMIERA_CONFIG_KEY_CHARS);
+
+ itr += self->key_size;
+
+ /*if the line ends ends with prefix] delim points to ]
+ * and not the last (blank) character before the final square bracket*/
+ if (self->key_size && *itr && *itr == ']')
+ {
+ self->delim = itr;
+ TODO("self->vtable = &lumiera_configsection_funcs;");
+ }
+ else if (self->key_size && *itr && isspace(*itr))
+ {
+ /* skip blanks until we reach the suffix or the final square bracket*/
+ while (*itr && isspace(*itr))
+ itr++;
+
+ if (*itr && *itr == ']')
+ {
+ /*final square bracket reached, so place delim one char before the
+ * actual position which must be a whitespace: no extra check necessary*/
+ self->delim = itr - 1;
+ TODO("self->vtable = &lumiera_configsection_funcs;");
+ }
+ else if (*itr)
+ {
+ TODO("check wheter suffix is made of legal characters");
+
+ /*delim points to the last whitespace before the actual position;
+ * no extra check needed*/
+ self->delim = itr - 1;
+ TODO("self->vtable = &lumiera_configsection_funcs;");
+ }
+ else
+ {
+ /*malformed section line, treat this line like a comment*/
+ self->key = NULL;
+ self->key_size = 0;
+
+ LUMIERA_ERROR_SET (config_item, CONFIG_SYNTAX);
+
+ }
+ }
+ else
+ {
+ /*error: either *itr is false, points neither to a blank nor to a closed square
+ * bracket or the key_size is zero*/
+
+ /*treat this line like a comment*/
+ self->key = NULL;
+ self->key_size = 0;
+
+ LUMIERA_ERROR_SET (config_item, CONFIG_SYNTAX);
+
+ }
+ }
+ else
+ {
+ /*this is probably a configentry*/
+
+ /*itr points now to the first not-whitespace-character*/
+ self->key = itr;
+
+ /*now look for the end of the key and set the keysize*/
+ self->key_size = strspn (itr, LUMIERA_CONFIG_KEY_CHARS);
+
+ /* skip blanks */
+ itr += self->key_size;
+ while (*itr && isspace (*itr))
+ itr++;
+
+ if (self->key_size && *itr == '=')
+ {
+ /*this configentry assigns a value to a key*/
+ self->delim = itr;
+ self->vtable = &lumiera_configentry_funcs;
+ }
+ else if (self->key_size && *itr == '<')
+ {
+ /*this configentry is a redirect*/
+ self->delim = itr;
+ self->vtable = &lumiera_configentry_funcs;
+ }
+ else
+ {
+ /*this is not a valid configentry; treat this line like a comment*/
+ self->key = NULL;
+ self->key_size = 0;
+
+ LUMIERA_ERROR_SET (config_item, CONFIG_SYNTAX);
+ }
+
+
+ }
+
+
+
+ return self;
+}
+
+
+/*
+// Local Variables:
+// mode: C
+// c-file-style: "gnu"
+// indent-tabs-mode: nil
+// End:
+*/
diff --git a/src/backend/configitem.h b/src/backend/configitem.h
new file mode 100644
index 000000000..c2395b6dc
--- /dev/null
+++ b/src/backend/configitem.h
@@ -0,0 +1,137 @@
+/*
+ configitem.h - generalized hierachy of configuration items
+
+ Copyright (C) Lumiera.org
+ 2008, Christian Thaeter
+
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef LUMIERA_CONFIGITEM_H
+#define LUMIERA_CONFIGITEM_H
+
+//TODO: Support library includes//
+#include "lib/llist.h"
+
+
+//TODO: Forward declarations//
+typedef struct lumiera_configitem_struct lumiera_configitem;
+typedef lumiera_configitem* LumieraConfigitem;
+
+struct lumiera_configitem_vtable;
+
+//TODO: Lumiera header includes//
+#include "backend/config_lookup.h"
+
+
+//TODO: System includes//
+#include
+
+
+/**
+ * @file
+ * configitems build a 3 level hierachy:
+ *
+ * 1. file:
+ * contain sections
+ *
+ * 2. section:
+ * [prefix suffix]
+ * contain lines
+ *
+ * 3. lines are
+ * comment:
+ * empty line or line only containing spaces and tabs
+ * line starting with spaces and tabs followed by a #
+ * directive:
+ * '@include name' or '@readonly'
+ * directives are only valid at the toplevel section []
+ * configurationentry:
+ * 'key = value' or 'key < redirect'
+ */
+
+
+//TODO: declarations go here//
+/**
+ * @file
+ * configitems build a 3 level hierachy:
+ *
+ * 1. file:
+ * contain sections
+ *
+ * 2. section:
+ * [prefix suffix]
+ * contain lines
+ *
+ * 3. lines are
+ * comment:
+ * empty line or line only containing spaces and tabs
+ * line starting with spaces and tabs followed by a #
+ * directive:
+ * '@include name' or '@readonly'
+ * directives are only valid at the toplevel section []
+ * configurationentry:
+ * 'key = value' or 'key < redirect'
+ * errorneous:
+ * any line which cant be parsed
+ */
+
+struct lumiera_configitem_vtable
+{
+ LumieraConfigitem (*new)(LumieraConfigitem);
+ LumieraConfigitem (*destroy)(LumieraConfigitem);
+};
+
+struct lumiera_configitem_struct
+{
+ llist link; // all lines on the same hierachy level are linked here (see childs)
+ LumieraConfigitem parent; // parent section
+ llist childs; // root node for all lines below this hierachy
+
+ llist lookup; // all lines with the same key are stacked up on the loockup
+
+ char* line; // raw line as read in allocated here trailing \n will be replaced with \0
+ char* key; // pointer into line to start of key
+ size_t key_size;
+ char* delim; // delimiter, value starts at delim+1
+ struct lumiera_configitem_vtable* vtable; // functiontable for subclassing
+};
+
+LumieraConfigitem
+lumiera_configitem_init (LumieraConfigitem self);
+
+LumieraConfigitem
+lumiera_configitem_destroy (LumieraConfigitem self, LumieraConfigLookup lookup);
+
+LumieraConfigitem
+lumiera_configitem_new (const char* line);
+
+void
+lumiera_configitem_delete (LumieraConfigitem self, LumieraConfigLookup lookup);
+
+LumieraConfigitem
+lumiera_configitem_parse (LumieraConfigitem self, const char* line);
+
+LumieraConfigitem
+lumiera_configitem_move (LumieraConfigitem self, LumieraConfigitem dest);
+
+#endif
+/*
+// Local Variables:
+// mode: C
+// c-file-style: "gnu"
+// indent-tabs-mode: nil
+// End:
+*/
diff --git a/src/backend/file.c b/src/backend/file.c
index 9af608567..9739e3a58 100644
--- a/src/backend/file.c
+++ b/src/backend/file.c
@@ -50,7 +50,7 @@ lumiera_file_destroy (LumieraFile self)
{
TRACE (file);
lumiera_filedescriptor_release (self->descriptor);
- free ((void*)self->name);
+ lumiera_free (self->name);
return self;
}
@@ -67,7 +67,7 @@ void
lumiera_file_delete (LumieraFile self)
{
TRACE (file);
- free (lumiera_file_destroy (self));
+ lumiera_free (lumiera_file_destroy (self));
}
@@ -79,7 +79,7 @@ lumiera_file_handle_acquire (LumieraFile self)
REQUIRE (self->descriptor);
REQUIRE (lumiera_fhcache);
- LUMIERA_MUTEX_SECTION (file, self->descriptor->rh, &self->descriptor->lock)
+ LUMIERA_MUTEX_SECTION (file, &self->descriptor->lock)
{
if (!self->descriptor->handle)
/* no handle yet, get a new one */
@@ -123,7 +123,7 @@ lumiera_file_handle_release (LumieraFile self)
{
TRACE (file);
- LUMIERA_MUTEX_SECTION (file, self->descriptor->rh, &self->descriptor->lock)
+ LUMIERA_MUTEX_SECTION (file, &self->descriptor->lock)
{
lumiera_filehandlecache_checkin (lumiera_fhcache, self->descriptor->handle);
}
diff --git a/src/backend/file.h b/src/backend/file.h
index bba12a167..bf5f11181 100644
--- a/src/backend/file.h
+++ b/src/backend/file.h
@@ -60,7 +60,7 @@ typedef lumiera_file* LumieraFile;
struct lumiera_file_struct
{
- const char* name;
+ char* name;
LumieraFiledescriptor descriptor;
};
diff --git a/src/backend/filedescriptor.c b/src/backend/filedescriptor.c
index b9608984f..4daa04f3e 100644
--- a/src/backend/filedescriptor.c
+++ b/src/backend/filedescriptor.c
@@ -21,7 +21,6 @@
#include "lib/mutex.h"
#include "lib/safeclib.h"
-#include "lib/cuckoo.h"
#include "backend/file.h"
#include "backend/filedescriptor.h"
@@ -32,6 +31,7 @@
#include
#include
#include
+#include
NOBUG_DEFINE_FLAG_PARENT (filedescriptor, file_all);
@@ -41,46 +41,50 @@ NOBUG_DEFINE_FLAG_PARENT (filedescriptor, file_all);
This registry stores all acquired filedescriptors for lookup, they will be freed when not referenced anymore.
*/
-static Cuckoo registry = NULL;
+static PSplay registry = NULL;
static lumiera_mutex registry_mutex = {PTHREAD_MUTEX_INITIALIZER};
-/*
- * setup hashing and compare functions for cuckoo hashing
- */
-static size_t
-h1 (const void* item, const uint32_t r)
-{
- const LumieraFiledescriptor i = *(const LumieraFiledescriptor*)item;
- return i->stat.st_dev^i->stat.st_ino^(i->flags&LUMIERA_FILE_MASK)
- ^((i->stat.st_dev^i->stat.st_ino^(i->flags&LUMIERA_FILE_MASK))>>7)^r;
-}
-
-static size_t
-h2 (const void* item, const uint32_t r)
-{
- const LumieraFiledescriptor i = *(const LumieraFiledescriptor*)item;
- return i->stat.st_dev^i->stat.st_ino^(i->flags&LUMIERA_FILE_MASK)
- ^((i->stat.st_dev^i->stat.st_ino^(i->flags&LUMIERA_FILE_MASK))>>5)^r;
-}
-
-static size_t
-h3 (const void* item, const uint32_t r)
-{
- const LumieraFiledescriptor i = *(const LumieraFiledescriptor*)item;
- return i->stat.st_dev^i->stat.st_ino^(i->flags&LUMIERA_FILE_MASK)
- ^((i->stat.st_dev^i->stat.st_ino^(i->flags&LUMIERA_FILE_MASK))>>3)^r;
-}
-
static int
-cmp (const void* keya, const void* keyb)
+cmp_fn (const void* keya, const void* keyb)
{
- const LumieraFiledescriptor a = *(const LumieraFiledescriptor*)keya;
- const LumieraFiledescriptor b = *(const LumieraFiledescriptor*)keyb;
- return a->stat.st_dev == b->stat.st_dev && a->stat.st_ino == b->stat.st_ino
- && (a->flags&LUMIERA_FILE_MASK) == (b->flags&LUMIERA_FILE_MASK);
+ const LumieraFiledescriptor a = (const LumieraFiledescriptor)keya;
+ const LumieraFiledescriptor b = (const LumieraFiledescriptor)keyb;
+
+ if (a->stat.st_dev < b->stat.st_dev)
+ return -1;
+ else if (a->stat.st_dev > b->stat.st_dev)
+ return 1;
+
+ if (a->stat.st_ino < b->stat.st_ino)
+ return -1;
+ else if (a->stat.st_ino > b->stat.st_ino)
+ return 1;
+
+ if ((a->flags&LUMIERA_FILE_MASK) < (b->flags&LUMIERA_FILE_MASK))
+ return -1;
+ else if ((a->flags&LUMIERA_FILE_MASK) > (b->flags&LUMIERA_FILE_MASK))
+ return 1;
+
+ return 0;
}
+
+static void
+delete_fn (PSplaynode node)
+{
+ lumiera_filedescriptor_delete ((LumieraFiledescriptor) node);
+}
+
+
+static const void*
+key_fn (const PSplaynode node)
+{
+ return node;
+}
+
+
+
void
lumiera_filedescriptor_registry_init (void)
{
@@ -88,20 +92,24 @@ lumiera_filedescriptor_registry_init (void)
TRACE (filedescriptor);
REQUIRE (!registry);
- registry = cuckoo_new (h1, h2, h3, cmp,
- sizeof (LumieraFiledescriptor),
- 3);
+ registry = psplay_new (cmp_fn, key_fn, delete_fn);
if (!registry)
LUMIERA_DIE (NO_MEMORY);
+
+ RESOURCE_HANDLE_INIT (registry_mutex.rh);
+ RESOURCE_ANNOUNCE (filedescriptor, "mutex", "filedescriptor registry", ®istry, registry_mutex.rh);
}
void
lumiera_filedescriptor_registry_destroy (void)
{
TRACE (filedescriptor);
- REQUIRE (!cuckoo_nelements (registry));
+ REQUIRE (!psplay_nelements (registry));
+
+ RESOURCE_FORGET (filedescriptor, registry_mutex.rh);
+
if (registry)
- cuckoo_free (registry);
+ psplay_destroy (registry);
registry = NULL;
}
@@ -112,82 +120,77 @@ lumiera_filedescriptor_acquire (const char* name, int flags)
TRACE (filedescriptor, "%s", name);
REQUIRE (registry, "not initialized");
- lumiera_mutexacquirer registry_lock;
- lumiera_mutexacquirer_init_mutex (®istry_lock, ®istry_mutex, LUMIERA_LOCKED);
+ LumieraFiledescriptor dest = NULL;
- lumiera_filedescriptor fdesc;
- fdesc.flags = flags;
-
- if (stat (name, &fdesc.stat) != 0)
+ LUMIERA_MUTEX_SECTION (filedescriptor, ®istry_mutex)
{
- if (errno == ENOENT && flags&O_CREAT)
+ lumiera_filedescriptor fdesc;
+ fdesc.flags = flags;
+
+ if (stat (name, &fdesc.stat) != 0)
{
- char* dir = lumiera_tmpbuf_strndup (name, PATH_MAX);
- char* slash = dir;
- while ((slash = strchr (slash+1, '/')))
+ if (errno == ENOENT && flags&O_CREAT)
{
- *slash = '\0';
- INFO (filedescriptor, "try creating dir: %s", dir);
- if (mkdir (dir, 0777) == -1 && errno != EEXIST)
+ char* dir = lumiera_tmpbuf_strndup (name, PATH_MAX);
+ char* slash = dir;
+ while ((slash = strchr (slash+1, '/')))
+ {
+ *slash = '\0';
+ INFO (filedescriptor, "try creating dir: %s", dir);
+ if (mkdir (dir, 0777) == -1 && errno != EEXIST)
+ {
+ LUMIERA_ERROR_SET (filedescriptor, ERRNO);
+ goto error;
+ }
+ *slash = '/';
+ }
+ int fd;
+ INFO (filedescriptor, "try creating file: %s", name);
+ fd = creat (name, 0777);
+ if (fd == -1)
{
LUMIERA_ERROR_SET (filedescriptor, ERRNO);
- goto efile;
+ goto error;
+ }
+ close (fd);
+ if (stat (name, &fdesc.stat) != 0)
+ {
+ /* finally, no luck */
+ LUMIERA_ERROR_SET (filedescriptor, ERRNO);
+ goto error;
}
- *slash = '/';
- }
- int fd;
- INFO (filedescriptor, "try creating file: %s", name);
- fd = creat (name, 0777);
- if (fd == -1)
- {
- LUMIERA_ERROR_SET (filedescriptor, ERRNO);
- goto efile;
- }
- close (fd);
- if (stat (name, &fdesc.stat) != 0)
- {
- /* finally, no luck */
- LUMIERA_ERROR_SET (filedescriptor, ERRNO);
- goto efile;
}
}
- }
- /* lookup/create descriptor */
- LumieraFiledescriptor dest = &fdesc;
- LumieraFiledescriptor* found = cuckoo_find (registry, &dest);
+ /* lookup/create descriptor */
+ dest = (LumieraFiledescriptor) psplay_find (registry, &fdesc, 100);
- if (!found)
- {
- TRACE (filedescriptor, "Descriptor not found");
-
- dest = lumiera_filedescriptor_new (&fdesc);
if (!dest)
- goto ecreate;
+ {
+ TRACE (filedescriptor, "Descriptor not found");
- cuckoo_insert (registry, &dest);
- }
- else
- {
- TRACE (filedescriptor, "Descriptor already existing");
- dest = *found;
- ++dest->refcount;
+ dest = lumiera_filedescriptor_new (&fdesc);
+ if (!dest)
+ goto error;
+
+ psplay_insert (registry, &dest->node, 100);
+ }
+ else
+ {
+ TRACE (filedescriptor, "Descriptor already existing");
+ ++dest->refcount;
+ }
+ error: ;
}
- lumiera_mutexacquirer_unlock (®istry_lock);
return dest;
-
- efile:
- ecreate:
- lumiera_mutexacquirer_unlock (®istry_lock);
- return NULL;
}
void
lumiera_filedescriptor_release (LumieraFiledescriptor self)
{
- TRACE (filedescriptor);
+ TRACE (filedescriptor, "%p", self);
if (!--self->refcount)
lumiera_filedescriptor_delete (self);
}
@@ -199,17 +202,14 @@ lumiera_filedescriptor_new (LumieraFiledescriptor template)
LumieraFiledescriptor self = lumiera_malloc (sizeof (lumiera_filedescriptor));
TRACE (filedescriptor, "at %p", self);
+ psplaynode_init (&self->node);
self->stat = template->stat;
self->flags = template->flags;
- lumiera_mutex_init (&self->lock);
self->refcount = 1;
self->handle = 0;
- const char* type = "mutex";
- const char* name = "filedescriptor";
-
- RESOURCE_ANNOUNCE (filedescriptor, type, name, self, self->rh);
+ lumiera_mutex_init (&self->lock, "filedescriptor", &NOBUG_FLAG (filedescriptor));
return self;
}
@@ -219,22 +219,19 @@ void
lumiera_filedescriptor_delete (LumieraFiledescriptor self)
{
TRACE (filedescriptor, "%p", self);
- lumiera_mutexacquirer registry_lock;
- lumiera_mutexacquirer_init_mutex (®istry_lock, ®istry_mutex, LUMIERA_LOCKED);
- REQUIRE (self->refcount == 0);
+ LUMIERA_MUTEX_SECTION (filedescriptor, ®istry_mutex)
+ {
+ REQUIRE (self->refcount == 0);
- RESOURCE_FORGET (filedescriptor, self->rh);
+ psplay_remove (registry, &self->node);
- cuckoo_remove (registry, cuckoo_find (registry, &self));
-
- TODO ("destruct other members (WIP)");
+ TODO ("destruct other members (WIP)");
- TODO ("release filehandle");
+ TODO ("release filehandle");
- lumiera_mutex_destroy (&self->lock);
- free (self);
-
- lumiera_mutexacquirer_unlock (®istry_lock);
+ lumiera_mutex_destroy (&self->lock, &NOBUG_FLAG (filedescriptor));
+ lumiera_free (self);
+ }
}
diff --git a/src/backend/filedescriptor.h b/src/backend/filedescriptor.h
index 528be41e8..d91296956 100644
--- a/src/backend/filedescriptor.h
+++ b/src/backend/filedescriptor.h
@@ -23,6 +23,7 @@
#define LUMIERA_FILEDESCRIPTOR_H
#include "lib/mutex.h"
+#include "lib/psplay.h"
#include
@@ -47,7 +48,8 @@ typedef lumiera_filedescriptor* LumieraFiledescriptor;
struct lumiera_filedescriptor_struct
{
- struct stat stat; /* create after first open, maintained metadata, MUST BE FIRST! */
+ psplaynode node; /* node for the lookup tree */
+ struct stat stat; /* create after first open, maintained metadata */
int flags; /* open flags, must be masked for reopen */
lumiera_mutex lock; /* locks operations on this file descriptor */
unsigned refcount; /* reference counter, all users sans registry */
@@ -55,8 +57,6 @@ struct lumiera_filedescriptor_struct
LumieraFilehandle handle;
//LumieraFileMap mappings;
//LumieraWriteBuffer writebuffer;
-
- RESOURCE_HANDLE (rh);
};
/**
diff --git a/src/backend/filehandlecache.c b/src/backend/filehandlecache.c
index 181807661..cf8d0a0e5 100644
--- a/src/backend/filehandlecache.c
+++ b/src/backend/filehandlecache.c
@@ -44,8 +44,7 @@ lumiera_filehandlecache_new (int max_entries)
lumiera_mrucache_init (&lumiera_fhcache->cache, lumiera_filehandle_destroy_node);
lumiera_fhcache->available = max_entries;
lumiera_fhcache->checked_out = 0;
- lumiera_mutex_init (&lumiera_fhcache->lock);
- RESOURCE_ANNOUNCE (filehandlecache, "mutex", "filehandlecache", lumiera_fhcache, lumiera_fhcache->rh);
+ lumiera_mutex_init (&lumiera_fhcache->lock, "filehandlecache", &NOBUG_FLAG (filehandlecache));
}
@@ -55,10 +54,9 @@ lumiera_filehandlecache_delete (void)
if (lumiera_fhcache)
{
REQUIRE (!lumiera_fhcache->checked_out, "Filehandles in use at shutdown");
- RESOURCE_FORGET (filehandlecache, lumiera_fhcache->rh);
lumiera_mrucache_destroy (&lumiera_fhcache->cache);
- lumiera_mutex_destroy (&lumiera_fhcache->lock);
- free (lumiera_fhcache);
+ lumiera_mutex_destroy (&lumiera_fhcache->lock, &NOBUG_FLAG (filehandlecache));
+ lumiera_free (lumiera_fhcache);
lumiera_fhcache = NULL;
}
}
@@ -69,7 +67,8 @@ lumiera_filehandlecache_handle_acquire (LumieraFilehandlecache self, LumieraFile
{
TRACE (filehandlecache);
LumieraFilehandle ret = NULL;
- LUMIERA_MUTEX_SECTION (filehandlecache, self->rh, &self->lock)
+
+ LUMIERA_MUTEX_SECTION (filehandlecache, &self->lock)
{
if (self->available <= 0 && self->cache.cached)
{
@@ -106,7 +105,7 @@ lumiera_filehandlecache_checkout (LumieraFilehandlecache self, LumieraFilehandle
if (!handle->use_cnt)
{
/* lock cache and checkout */
- LUMIERA_MUTEX_SECTION (filehandlecache, self->rh, &self->lock)
+ LUMIERA_MUTEX_SECTION (filehandlecache, &self->lock)
{
lumiera_mrucache_checkout (&self->cache, &handle->cachenode);
}
@@ -128,7 +127,7 @@ lumiera_filehandlecache_checkin (LumieraFilehandlecache self, LumieraFilehandle
if (!--handle->use_cnt)
{
/* lock cache and checin */
- LUMIERA_MUTEX_SECTION (filehandlecache, self->rh, &self->lock)
+ LUMIERA_MUTEX_SECTION (filehandlecache, &self->lock)
{
--self->checked_out;
lumiera_mrucache_checkin (&self->cache, &handle->cachenode);
diff --git a/src/backend/filehandlecache.h b/src/backend/filehandlecache.h
index 37c2a416b..f624caefe 100644
--- a/src/backend/filehandlecache.h
+++ b/src/backend/filehandlecache.h
@@ -49,7 +49,6 @@ struct lumiera_filehandlecache_struct
int available;
int checked_out;
lumiera_mutex lock;
- RESOURCE_HANDLE (rh);
};
extern LumieraFilehandlecache lumiera_fhcache;
diff --git a/src/common/cmdline.cpp b/src/common/cmdline.cpp
index dec1a0620..eca0b18bb 100644
--- a/src/common/cmdline.cpp
+++ b/src/common/cmdline.cpp
@@ -52,7 +52,7 @@ namespace util
/** create as a tokenized copy of the current commandline.
* Note that argv[0] is allways ignored. */
- Cmdline::Cmdline (int argc, char* argv[])
+ Cmdline::Cmdline (int argc, const char** argv)
: vector (noneg(argc-1))
{
for (int i=1; i (&cause);
if (err)
- if (isnil (err->cause_))
- return cause.what(); // cause is root cause
- else
- return err->cause_; // cause was caused by another exception
+ {
+ if (isnil (err->cause_))
+ return cause.what(); // cause is root cause
+ else
+ return err->cause_; // cause was caused by another exception
+ }
// unknown other exception type
return cause.what ();
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index f7d9058ae..e7c22abdb 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -26,27 +26,26 @@ liblumi_a_SOURCES = \
$(liblumi_a_srcdir)/mutex.c \
$(liblumi_a_srcdir)/rwlock.c \
$(liblumi_a_srcdir)/condition.c \
- $(liblumi_a_srcdir)/references.c \
- $(liblumi_a_srcdir)/uuid.c \
+ $(liblumi_a_srcdir)/luid.c \
$(liblumi_a_srcdir)/safeclib.c \
$(liblumi_a_srcdir)/cuckoo.c \
+ $(liblumi_a_srcdir)/psplay.c \
$(liblumi_a_srcdir)/mrucache.c \
- $(liblumi_a_srcdir)/time.c \
+ $(liblumi_a_srcdir)/time.c \
$(liblumi_a_srcdir)/appconfig.cpp
noinst_HEADERS += \
$(liblumi_a_srcdir)/plugin.h \
$(liblumi_a_srcdir)/error.h \
- $(liblumi_a_srcdir)/locking.h \
$(liblumi_a_srcdir)/mutex.h \
$(liblumi_a_srcdir)/rwlock.h \
$(liblumi_a_srcdir)/condition.h \
- $(liblumi_a_srcdir)/references.h \
- $(liblumi_a_srcdir)/uuid.h \
+ $(liblumi_a_srcdir)/luid.h \
$(liblumi_a_srcdir)/safeclib.h \
$(liblumi_a_srcdir)/cuckoo.h \
+ $(liblumi_a_srcdir)/psplay.h \
$(liblumi_a_srcdir)/mrucache.h \
- $(liblumi_a_srcdir)/time.h \
+ $(liblumi_a_srcdir)/time.h \
$(liblumi_a_srcdir)/appconfig.hpp \
$(liblumi_a_srcdir)/lifecycleregistry.hpp
diff --git a/src/lib/condition.c b/src/lib/condition.c
index 60e8b6f10..a7f17e57b 100644
--- a/src/lib/condition.c
+++ b/src/lib/condition.c
@@ -28,36 +28,32 @@
LUMIERA_ERROR_DEFINE (CONDITION_DESTROY, "condition destroy failed");
-/**
- * Initialize a condition variable
- * @param self is a pointer to the condition variable to be initialized
- * @return self as given
- */
+
LumieraCondition
-lumiera_condition_init (LumieraCondition self)
+lumiera_condition_init (LumieraCondition self, const char* purpose, struct nobug_flag* flag)
{
if (self)
{
pthread_cond_init (&self->cond, NULL);
pthread_mutex_init (&self->mutex, NULL);
+ NOBUG_RESOURCE_HANDLE_INIT (self->rh);
+ NOBUG_RESOURCE_ANNOUNCE_RAW (flag, "cond_var", purpose, self, self->rh);
}
return self;
}
-/**
- * Destroy a condition variable
- * @param self is a pointer to the condition variable to be destroyed
- * @return self as given
- */
LumieraCondition
-lumiera_condition_destroy (LumieraCondition self)
+lumiera_condition_destroy (LumieraCondition self, struct nobug_flag* flag)
{
if (self)
{
+ NOBUG_RESOURCE_FORGET_RAW (flag, self->rh);
+
if (pthread_mutex_destroy (&self->mutex))
LUMIERA_DIE (MUTEX_DESTROY);
- else if (pthread_cond_destroy (&self->cond))
+
+ if (pthread_cond_destroy (&self->cond))
LUMIERA_DIE (CONDITION_DESTROY);
}
return self;
diff --git a/src/lib/condition.h b/src/lib/condition.h
index dd92f326b..3bdbcbedc 100644
--- a/src/lib/condition.h
+++ b/src/lib/condition.h
@@ -22,7 +22,9 @@
#ifndef LUMIERA_CONDITION_H
#define LUMIERA_CONDITION_H
-#include "lib/locking.h"
+#include "lib/error.h"
+#include "lib/mutex.h"
+
/**
* @file
@@ -31,6 +33,49 @@
LUMIERA_ERROR_DECLARE (CONDITION_DESTROY);
+
+
+/**
+ * Condition section.
+ * Locks the condition mutex, one can use LUMIERA_CONDITION_WAIT to wait for signals or
+ * LUMIERA_CONDITION_SIGNAL or LUMIERA_CONDITION_BROADCAST to wake waiting threads
+ */
+#define LUMIERA_CONDITION_SECTION(nobugflag, cnd) \
+ for (lumiera_conditionacquirer NOBUG_CLEANUP(lumiera_conditionacquirer_ensureunlocked) \
+ lumiera_condition_section_ = {(LumieraCondition)1}; \
+ lumiera_condition_section_.condition;) \
+ for ( \
+ ({ \
+ lumiera_condition_section_.condition = (cnd); \
+ NOBUG_IF(NOBUG_MODE_ALPHA, lumiera_condition_section_.flag = &NOBUG_FLAG(nobugflag)); \
+ NOBUG_RESOURCE_HANDLE_INIT (lumiera_condition_section_.rh); \
+ RESOURCE_ENTER (nobugflag, (cnd)->rh, "acquire condition", &lumiera_condition_section_, \
+ NOBUG_RESOURCE_EXCLUSIVE, lumiera_condition_section_.rh); \
+ if (pthread_mutex_lock (&(cnd)->mutex)) LUMIERA_DIE (MUTEX_LOCK); \
+ }); \
+ lumiera_condition_section_.condition; \
+ ({ \
+ if (lumiera_condition_section_.condition) \
+ { \
+ pthread_mutex_unlock (&lumiera_condition_section_.condition->mutex); \
+ lumiera_condition_section_.condition = NULL; \
+ RESOURCE_LEAVE(nobugflag, lumiera_condition_section_.rh); \
+ } \
+ }))
+
+#define LUMIERA_CONDITION_WAIT \
+ do { \
+ NOBUG_RESOURCE_STATE_RAW (lumiera_condition_section_.flag, lumiera_condition_section_.rh, NOBUG_RESOURCEING); \
+ pthread_cond_wait (&lumiera_condition_section_.condition->cond, &lumiera_condition_section_.condition->mutex); \
+ NOBUG_RESOURCE_STATE_RAW (lumiera_condition_section_.flag, lumiera_condition_section_.rh, NOBUG_RESOURCE_EXCLUSIVE); \
+ while (0)
+
+#define LUMIERA_CONDITION_SIGNAL (nobugflag) pthread_cond_signal (&lumiera_condition_section_.condition->cond)
+
+#define LUMIERA_CONDITION_BROADCAST (nobugflag) pthread_cond_broadcast (&lumiera_condition_section_.condition->cond)
+
+
+
/**
* Condition variables.
*
@@ -39,17 +84,28 @@ struct lumiera_condition_struct
{
pthread_cond_t cond;
pthread_mutex_t mutex;
+ RESOURCE_HANDLE (rh);
};
typedef struct lumiera_condition_struct lumiera_condition;
typedef lumiera_condition* LumieraCondition;
+/**
+ * Initialize a condition variable
+ * @param self is a pointer to the condition variable to be initialized
+ * @return self as given
+ */
LumieraCondition
-lumiera_condition_init (LumieraCondition self);
+lumiera_condition_init (LumieraCondition self, const char* purpose, struct nobug_flag* flag);
+/**
+ * Destroy a condition variable
+ * @param self is a pointer to the condition variable to be destroyed
+ * @return self as given
+ */
LumieraCondition
-lumiera_condition_destroy (LumieraCondition self);
+lumiera_condition_destroy (LumieraCondition self, struct nobug_flag* flag);
/**
@@ -91,8 +147,9 @@ lumiera_condition_broadcast (LumieraCondition self)
*/
struct lumiera_conditionacquirer_struct
{
- LumieraCondition cond;
- enum lumiera_lockstate state;
+ LumieraCondition condition;
+ NOBUG_IF(NOBUG_MODE_ALPHA, struct nobug_flag* flag);
+ RESOURCE_HANDLE (rh);
};
typedef struct lumiera_conditionacquirer_struct lumiera_conditionacquirer;
typedef struct lumiera_conditionacquirer_struct* LumieraConditionacquirer;
@@ -101,108 +158,15 @@ typedef struct lumiera_conditionacquirer_struct* LumieraConditionacquirer;
static inline void
lumiera_conditionacquirer_ensureunlocked (LumieraConditionacquirer self)
{
- ENSURE (self->state == LUMIERA_UNLOCKED, "forgot to unlock the condition mutex");
-}
-
-/* override with a macro to use the cleanup checker */
-#define lumiera_conditionacquirer \
-lumiera_conditionacquirer NOBUG_CLEANUP(lumiera_conditionacquirer_ensureunlocked)
-
-
-/**
- * initialize a conditionacquirer state
- * @param self conditionacquirer to be initialized, must be an automatic variable
- * @param cond associated condition variable
- * @param state initial state of the mutex, either LUMIERA_LOCKED or LUMIERA_UNLOCKED
- * @return self as given
- * errors are fatal
- */
-static inline LumieraConditionacquirer
-lumiera_conditionacquirer_init (LumieraConditionacquirer self, LumieraCondition cond, enum lumiera_lockstate state)
-{
- REQUIRE (self);
- REQUIRE (cond);
- self->cond = cond;
- self->state = state;
- if (state == LUMIERA_LOCKED)
- if (pthread_mutex_lock (&cond->mutex))
- LUMIERA_DIE (MUTEX_LOCK);
-
- return self;
-}
-
-/**
- * lock the mutex.
- * must not already be locked
- * @param self conditionacquirer associated with a condition variable
- */
-static inline void
-lumiera_conditionacquirer_lock (LumieraConditionacquirer self)
-{
- REQUIRE (self);
- REQUIRE (self->state == LUMIERA_UNLOCKED, "mutex already locked");
-
- if (pthread_mutex_lock (&self->cond->mutex))
- LUMIERA_DIE (MUTEX_LOCK);
-
- self->state = LUMIERA_LOCKED;
-}
-
-
-/**
- * wait on a locked condition.
- * Waits until the condition variable gets signaled from another thread. Must already be locked.
- * @param self conditionacquirer associated with a condition variable
- */
-static inline void
-lumiera_conditionacquirer_wait (LumieraConditionacquirer self)
-{
- REQUIRE (self);
- REQUIRE (self->state == LUMIERA_LOCKED, "mutex must be locked");
- pthread_cond_wait (&self->cond->cond, &self->cond->mutex);
-}
-
-
-/**
- * release mutex.
- * a conditionacquirer must be unlocked before leaving scope
- * @param self conditionacquirer associated with a condition variable
- */
-static inline void
-lumiera_conditionacquirer_unlock (LumieraConditionacquirer self)
-{
- REQUIRE (self);
- REQUIRE (self->state == LUMIERA_LOCKED, "mutex was not locked");
- if (pthread_mutex_unlock (&self->cond->mutex))
- LUMIERA_DIE (MUTEX_UNLOCK);
- self->state = LUMIERA_UNLOCKED;
-}
-
-
-/**
- * signal a single waiting thread
- * @param self conditionacquirer associated with the condition variable to be signaled
- */
-static inline void
-lumiera_conditionacquirer_signal (LumieraConditionacquirer self)
-{
- REQUIRE (self);
- REQUIRE (self->state == LUMIERA_LOCKED, "mutex was not locked");
- pthread_cond_signal (&self->cond->cond);
-}
-
-
-/**
- * signal all waiting threads
- * @param self conditionacquirer associated with the condition variable to be signaled
- */
-static inline void
-lumiera_conditionacquirer_broadcast (LumieraConditionacquirer self)
-{
- REQUIRE (self);
- REQUIRE (self->state == LUMIERA_LOCKED, "mutex was not locked");
- pthread_cond_broadcast (&self->cond->cond);
+ ENSURE (!self->condition, "forgot to unlock condition variable");
}
#endif
+/*
+// Local Variables:
+// mode: C
+// c-file-style: "gnu"
+// indent-tabs-mode: nil
+// End:
+*/
diff --git a/src/lib/cuckoo.c b/src/lib/cuckoo.c
index bbcb0e71a..b2ad064c0 100644
--- a/src/lib/cuckoo.c
+++ b/src/lib/cuckoo.c
@@ -23,6 +23,8 @@
#include
+#define CUCKOO_GRANULARITY int
+
enum compact_state
{
COMPACTING_OFF,
@@ -35,14 +37,11 @@ struct cuckoo_struct
size_t size; /* t1 = 4*size; t2 = 2*size; t3 = size */
size_t itemsize;
- cuckoo_hashfunc h1; /* hash function */
- uint32_t r1; /* random, reset for each rehash */
- cuckoo_hashfunc h2;
- uint32_t r2;
- cuckoo_hashfunc h3;
- uint32_t r3;
+ struct cuckoo_vtable vtable;
- cuckoo_cmpfunc cmp;
+ uint32_t r1; /* random, reset for each rehash */
+ uint32_t r2;
+ uint32_t r3;
void* t1;
void* t2;
@@ -61,28 +60,59 @@ static inline uint32_t cuckoo_fast_prng ()
return rnd = rnd<<1 ^ ((rnd>>30) & 1) ^ ((rnd>>2) & 1);
}
+static inline int
+iszero (void* mem, size_t size)
+{
+ while (size && !*(CUCKOO_GRANULARITY*)mem)
+ {
+ size -= sizeof (CUCKOO_GRANULARITY);
+ mem += sizeof (CUCKOO_GRANULARITY);
+ }
+ return !size;
+}
+
+static inline void
+xmemmov (void* dst, void* src, size_t size)
+{
+ while (size)
+ {
+ size -= sizeof (CUCKOO_GRANULARITY);
+ *(CUCKOO_GRANULARITY*)(dst + size) = *(CUCKOO_GRANULARITY*)(src + size);
+ }
+}
+
+
Cuckoo
-cuckoo_init (Cuckoo self,
- cuckoo_hashfunc h1,
- cuckoo_hashfunc h2,
- cuckoo_hashfunc h3,
- cuckoo_cmpfunc cmp,
- size_t itemsize,
- unsigned startsize)
+cuckoo_init (Cuckoo self, size_t itemsize, struct cuckoo_vtable* vtable)
{
if (!self)
return NULL;
- self->size = 1<itemsize = itemsize;
- self->h1 = h1;
+ self->size = 16;
+ self->itemsize = (itemsize * sizeof (CUCKOO_GRANULARITY)
+ + sizeof (CUCKOO_GRANULARITY) - 1) / sizeof (CUCKOO_GRANULARITY); /* round up to next CUCKOO_GRANULARITY boundary */
self->r1 = cuckoo_fast_prng ();
- self->h2 = h2;
self->r2 = cuckoo_fast_prng ();
- self->h3 = h3;
self->r3 = cuckoo_fast_prng ();
- self->cmp = cmp;
+ if (!vtable->h1 || !vtable->h2 || !vtable->h3)
+ return NULL;
+
+ self->vtable.h1 = vtable->h1;
+ self->vtable.h2 = vtable->h2;
+ self->vtable.h3 = vtable->h3;
+
+ if (!vtable->cmp)
+ return NULL;
+
+ self->vtable.cmp = vtable->cmp;
+
+ self->vtable.dtor = vtable->dtor;
+
+ if (vtable->mov)
+ self->vtable.mov = vtable->mov;
+ else
+ self->vtable.mov = xmemmov;
self->t1 = calloc (self->size * 4, itemsize);
self->t2 = calloc (self->size * 2, itemsize);
@@ -101,19 +131,15 @@ cuckoo_init (Cuckoo self,
self->autocompact = COMPACTING_AUTO;
self->elements = 0;
+
return self;
}
Cuckoo
-cuckoo_new (cuckoo_hashfunc h1,
- cuckoo_hashfunc h2,
- cuckoo_hashfunc h3,
- cuckoo_cmpfunc cmp,
- size_t itemsize,
- unsigned startsize)
+cuckoo_new (size_t itemsize, struct cuckoo_vtable* vtable)
{
Cuckoo self = malloc (sizeof (struct cuckoo_struct));
- if (!cuckoo_init (self, h1, h2, h3, cmp, itemsize, startsize))
+ if (!cuckoo_init (self, itemsize, vtable))
{
free (self);
return NULL;
@@ -126,6 +152,18 @@ cuckoo_destroy (Cuckoo self)
{
if (self)
{
+
+ if (self->vtable.dtor)
+ {
+ void* elem;
+ for (elem = self->t1; elem < self->t1 + self->size * 4; elem += self->size)
+ self->vtable.dtor (elem);
+ for (elem = self->t2; elem < self->t1 + self->size * 2; elem += self->size)
+ self->vtable.dtor (elem);
+ for (elem = self->t3; elem < self->t1 + self->size; elem += self->size)
+ self->vtable.dtor (elem);
+ }
+
free (self->t1);
free (self->t2);
free (self->t3);
@@ -135,76 +173,57 @@ cuckoo_destroy (Cuckoo self)
void
-cuckoo_free (Cuckoo self)
+cuckoo_delete (Cuckoo self)
{
free (cuckoo_destroy (self));
}
-static inline int
-iszero (void* mem, size_t size)
-{
- while (size && !*(int*)mem)
- {
- size -= sizeof (int);
- mem += sizeof (int);
- }
- return !size;
-}
-
-static inline void
-xmemcpy (void* dst, void* src, size_t size)
-{
- while (size)
- {
- size -= sizeof (int);
- *(int*)(dst + size) = *(int*)(src + size);
- }
-}
-
-
-static int
+static void*
cuckoo_insert_internal_ (Cuckoo self, void* item)
{
void* pos;
- char tmp[self->itemsize];
+ CUCKOO_GRANULARITY tmp[self->itemsize / sizeof(CUCKOO_GRANULARITY)];
for (unsigned n = 0; n < self->maxloops; ++n)
{
/* find nest */
- pos = self->t1 + self->itemsize * (self->h1 (item, self->r1) % (4*self->size));
+ pos = self->t1 + self->itemsize * (self->vtable.h1 (item, self->r1) % (4*self->size));
/* kick old egg out */
- xmemcpy (tmp, pos, self->itemsize);
+ if (iszero (pos, self->itemsize))
+ memset (tmp, 0, self->itemsize);
+ else
+ self->vtable.mov (tmp, pos, self->itemsize);
/* lay egg */
- xmemcpy (pos, item, self->itemsize);
+ self->vtable.mov (pos, item, self->itemsize);
if (iszero (tmp, self->itemsize))
- return 1;
+ return pos;
/* find nest */
- pos = self->t2 + self->itemsize * (self->h2 (tmp, self->r2) % (2*self->size));
+ pos = self->t2 + self->itemsize * (self->vtable.h2 (tmp, self->r2) % (2*self->size));
/* kick old egg out */
- xmemcpy (item, pos, self->itemsize);
+ self->vtable.mov (item, pos, self->itemsize);
/* lay egg */
- xmemcpy (pos, tmp, self->itemsize);
+ self->vtable.mov (pos, tmp, self->itemsize);
if (iszero (item, self->itemsize))
- return 1;
+ return pos;
/* find nest */
- pos = self->t3 + self->itemsize * (self->h3 (item, self->r3) % self->size);
+ pos = self->t3 + self->itemsize * (self->vtable.h3 (item, self->r3) % self->size);
/* kick old egg out */
- xmemcpy (tmp, pos, self->itemsize);
+ self->vtable.mov (tmp, pos, self->itemsize);
/* lay egg */
- xmemcpy (pos, item, self->itemsize);
+ self->vtable.mov (pos, item, self->itemsize);
if (iszero (tmp, self->itemsize))
- return 1;
+ return pos;
/* copy tmp to item, which will be reinserted on next interation / after rehashing */
- xmemcpy (item, tmp, self->itemsize);
+ self->vtable.mov (item, tmp, self->itemsize);
}
- return 0;
+ return NULL;
}
@@ -230,14 +249,14 @@ cuckoo_rehash (Cuckoo self)
{
for (n = 0; n < self->maxloops; ++n)
{
- unsigned hash = self->h1 (pos, self->r1) % (4*self->size);
+ unsigned hash = self->vtable.h1 (pos, self->r1) % (4*self->size);
if (hash != i)
{
char t[self->itemsize];
void* hpos = self->t1 + self->itemsize * hash;
- xmemcpy (t, hpos, self->itemsize);
- xmemcpy (hpos, pos, self->itemsize);
- xmemcpy (pos, t, self->itemsize);
+ self->vtable.mov (t, hpos, self->itemsize);
+ self->vtable.mov (hpos, pos, self->itemsize);
+ self->vtable.mov (pos, t, self->itemsize);
if (iszero (t, self->itemsize))
break;
}
@@ -260,14 +279,14 @@ cuckoo_rehash (Cuckoo self)
{
for (n = 0; n < self->maxloops; ++n)
{
- unsigned hash = self->h2 (pos, self->r2) % (2*self->size);
+ unsigned hash = self->vtable.h2 (pos, self->r2) % (2*self->size);
if (hash != i)
{
char t[self->itemsize];
void* hpos = self->t2 + self->itemsize * hash;
- xmemcpy (t, hpos, self->itemsize);
- xmemcpy (hpos, pos, self->itemsize);
- xmemcpy (pos, t, self->itemsize);
+ self->vtable.mov (t, hpos, self->itemsize);
+ self->vtable.mov (hpos, pos, self->itemsize);
+ self->vtable.mov (pos, t, self->itemsize);
if (iszero (t, self->itemsize))
break;
}
@@ -290,14 +309,14 @@ cuckoo_rehash (Cuckoo self)
{
for (n = 0; n < self->maxloops; ++n)
{
- unsigned hash = self->h3 (pos, self->r3) % self->size;
+ unsigned hash = self->vtable.h3 (pos, self->r3) % self->size;
if (hash != i)
{
char t[self->itemsize];
void* hpos = self->t3 + self->itemsize * hash;
- xmemcpy (t, hpos, self->itemsize);
- xmemcpy (hpos, pos, self->itemsize);
- xmemcpy (pos, t, self->itemsize);
+ self->vtable.mov (t, hpos, self->itemsize);
+ self->vtable.mov (hpos, pos, self->itemsize);
+ self->vtable.mov (pos, t, self->itemsize);
if (iszero (t, self->itemsize))
break;
}
@@ -314,10 +333,10 @@ static int
cuckoo_grow (Cuckoo self)
{
/* rotate hashfuncs, tables, randoms */
- cuckoo_hashfunc th = self->h3;
- self->h3 = self->h2;
- self->h2 = self->h1;
- self->h1 = th;
+ cuckoo_hashfunc th = self->vtable.h3;
+ self->vtable.h3 = self->vtable.h2;
+ self->vtable.h2 = self->vtable.h1;
+ self->vtable.h1 = th;
uint32_t tr = self->r3;
self->r3 = self->r2;
@@ -380,10 +399,10 @@ cuckoo_compact (Cuckoo self)
if (self->size > 2 && self->elements < self->size * 3)
{
- cuckoo_hashfunc th = self->h1;
- self->h1 = self->h2;
- self->h2 = self->h3;
- self->h3 = th;
+ cuckoo_hashfunc th = self->vtable.h1;
+ self->vtable.h1 = self->vtable.h2;
+ self->vtable.h2 = self->vtable.h3;
+ self->vtable.h3 = th;
uint32_t tr = self->r1;
self->r1 = self->r2;
@@ -425,7 +444,7 @@ cuckoo_compact (Cuckoo self)
}
-int
+void*
cuckoo_insert (Cuckoo self, void* item)
{
char tmp[self->itemsize];
@@ -433,30 +452,32 @@ cuckoo_insert (Cuckoo self, void* item)
void* found;
if ((found = cuckoo_find (self, item)))
{
- xmemcpy (found, item, self->itemsize);
- return 1;
+ if (self->vtable.dtor)
+ self->vtable.dtor (found);
+ self->vtable.mov (found, item, self->itemsize);
+ return found;
}
- xmemcpy (tmp, item, self->itemsize);
+ self->vtable.mov (tmp, item, self->itemsize);
for (unsigned n = 6; n; --n) /* rehash/grow loop */
{
- if (cuckoo_insert_internal_ (self, tmp))
+ if ((found = cuckoo_insert_internal_ (self, tmp)))
{
++self->elements;
- return 1;
+ return found;
}
if (self->elements > n*self->size)
{
n = 6;
if (!cuckoo_grow (self))
- return 0;
+ return NULL;
}
else
cuckoo_rehash (self);
}
- return 0;
+ return NULL;
}
@@ -465,16 +486,16 @@ cuckoo_find (Cuckoo self, void* item)
{
void* pos;
- pos = self->t1 + self->itemsize * (self->h1 (item, self->r1) % (4*self->size));
- if (!iszero (pos, self->itemsize) && self->cmp (item, pos))
+ pos = self->t1 + self->itemsize * (self->vtable.h1 (item, self->r1) % (4*self->size));
+ if (!iszero (pos, self->itemsize) && self->vtable.cmp (item, pos))
return pos;
- pos = self->t2 + self->itemsize * (self->h2 (item, self->r2) % (2*self->size));
- if (!iszero (pos, self->itemsize) && self->cmp (item, pos))
+ pos = self->t2 + self->itemsize * (self->vtable.h2 (item, self->r2) % (2*self->size));
+ if (!iszero (pos, self->itemsize) && self->vtable.cmp (item, pos))
return pos;
- pos = self->t3 + self->itemsize * (self->h3 (item, self->r3) % self->size);
- if (!iszero (pos, self->itemsize) && self->cmp (item, pos))
+ pos = self->t3 + self->itemsize * (self->vtable.h3 (item, self->r3) % self->size);
+ if (!iszero (pos, self->itemsize) && self->vtable.cmp (item, pos))
return pos;
return NULL;
@@ -486,6 +507,9 @@ cuckoo_remove (Cuckoo self, void* item)
{
if (item)
{
+ if (self->vtable.dtor)
+ self->vtable.dtor (item);
+
memset (item, 0, self->itemsize);
--self->elements;
diff --git a/src/lib/cuckoo.h b/src/lib/cuckoo.h
index 323b5cc75..84546d002 100644
--- a/src/lib/cuckoo.h
+++ b/src/lib/cuckoo.h
@@ -54,41 +54,61 @@ typedef size_t (*cuckoo_hashfunc)(const void* item, const uint32_t r);
*/
typedef int (*cuckoo_cmpfunc)(const void* item1, const void* item2);
+/**
+ * Item destructor function.
+ * User supplied destructor function. This function is called when items are removed
+ * from the hash or at hash detroy/delete time. Must be safe to be called on a zeroed element.
+ * @param item address of the item to be destroyed
+ */
+typedef void (*cuckoo_dtorfunc)(void* item);
+
+/**
+ * Move function.
+ * User supplied item move function
+ * @param dest target address for the move operation
+ * @param src source for the move operation
+ * @param size size of a item (requested size rounded up to the next CUCKOO_GRANULARITY)
+ * It might be necessary to invalidate the source in some case, cuckoo will zero it out
+ * after moving.
+ */
+typedef void (*cuckoo_movfunc)(void* dest, void* src, size_t size);
+
+
+/**
+ * Function table used to specialize various funtions used by the hash.
+ * TODO some elements might be NULL, then defaults are used
+ */
+struct cuckoo_vtable
+{
+ cuckoo_hashfunc h1;
+ cuckoo_hashfunc h2;
+ cuckoo_hashfunc h3;
+ cuckoo_cmpfunc cmp;
+ cuckoo_dtorfunc dtor;
+ cuckoo_movfunc mov;
+};
+
+
/**
* Initialize a cuckoo hash.
* @param self pointer to a uninitialized cuckoo datastructure
- * @param h1 hash function for the first table
- * @param h2 hash function for the second table
- * @param h3 hash function for the third table
- * @param cmp function which compares two keys
- * @param startsize initial size of table t3, as 2's exponent
+ * @param itemsize size for a single hash entry, will be rounded up to align CUCKOO_GRANULARITY
+ * @param vtable initialized vtable
* @return The initialized hashtable or NULL at allocation failure
*/
Cuckoo
-cuckoo_init (Cuckoo self,
- cuckoo_hashfunc h1,
- cuckoo_hashfunc h2,
- cuckoo_hashfunc h3,
- cuckoo_cmpfunc cmp,
- size_t itemsize,
- unsigned startsize);
+cuckoo_init (Cuckoo self, size_t itemsize, struct cuckoo_vtable* vtable);
/**
* Allocate a new cuckoo hash.
- * @param h1 hash function for the first table
- * @param h2 hash function for the second table
- * @param h3 hash function for the third table
- * @param cmp function which compares two keys
+ * @param itemsize size for a single hash entry, will be rounded up to align CUCKOO_GRANULARITY
* @param startsize initial size of table t3, as 2's exponent
+ * @param vtable initialized vtable
* @return The initialized hashtable or NULL at allocation failure
*/
Cuckoo
-cuckoo_new (cuckoo_hashfunc h1,
- cuckoo_hashfunc h2,
- cuckoo_hashfunc h3,
- cuckoo_cmpfunc cmp,
- size_t itemsize,
- unsigned startsize);
+cuckoo_new (size_t itemsize, struct cuckoo_vtable* vtable);
+
/**
* Destroy a cuckoo hash.
@@ -104,7 +124,7 @@ cuckoo_destroy (Cuckoo self);
* @param self handle of the hash table to be freed
*/
void
-cuckoo_free (Cuckoo self);
+cuckoo_delete (Cuckoo self);
/**
* Get the number of elements stored in a hash.
@@ -117,12 +137,14 @@ cuckoo_nelements (Cuckoo self);
* Insert an element into a hash.
* amortized O(1) complexity because it may rarely rehash the tables or even grow them.
* see cuckoo_reserve() about how to preallocate entries to prevent the growing costs.
+ * Inserting an element already in the hash calls the dtor for the old entry and places
+ * the new one into the hash.
* @param self handle to the hash table
* @param item pointer to a item to be inserted
- * @return 1 on successful insert, 0 on allocation failure
+ * @return pointer to inserted element on successful insert, NULL on allocation failure
* Note: at failure there is one arbitary hash cell lost!
*/
-int
+void*
cuckoo_insert (Cuckoo self, void* item);
/**
diff --git a/src/lib/error.c b/src/lib/error.c
index b2bc390b6..1d3fb50c3 100644
--- a/src/lib/error.c
+++ b/src/lib/error.c
@@ -45,19 +45,13 @@ lumiera_error_tls_init (void)
pthread_key_create (&lumiera_error_tls, NULL);
}
-/**
- * Set error state for the current thread.
- * If the error state of the current thread was cleared, then set it, else preserve the old state.
- * @param nerr name of the error with 'LUMIERA_ERROR_' prefix (example: LUMIERA_ERROR_NO_MEMORY)
- * @return old state, that is NULL for success, when the state was cleared and a pointer to a pending
- * error when the error state was already set
- */
-const char*
-lumiera_error_set (const char * nerr)
+
+lumiera_err
+lumiera_error_set (lumiera_err nerr)
{
pthread_once (&lumiera_error_initialized, lumiera_error_tls_init);
- const char* err = pthread_getspecific (lumiera_error_tls);
+ lumiera_err err = pthread_getspecific (lumiera_error_tls);
if (!err)
pthread_setspecific (lumiera_error_tls, nerr);
@@ -65,18 +59,12 @@ lumiera_error_set (const char * nerr)
}
-/**
- * Get and clear current error state.
- * This function clears the error state, if it needs to be reused, one has to store it in a temporary
- * variable.
- * @return pointer to any pending error of this thread, NULL if no error is pending
- */
-const char*
+lumiera_err
lumiera_error ()
{
pthread_once (&lumiera_error_initialized, lumiera_error_tls_init);
- const char* err = pthread_getspecific (lumiera_error_tls);
+ lumiera_err err = pthread_getspecific (lumiera_error_tls);
if (err)
pthread_setspecific (lumiera_error_tls, NULL);
return err;
diff --git a/src/lib/error.h b/src/lib/error.h
index 1eeb42dda..5c4a8c145 100644
--- a/src/lib/error.h
+++ b/src/lib/error.h
@@ -35,6 +35,7 @@ extern "C" {
* C Error handling in Lumiera, header.
*/
+typedef const char* lumiera_err;
/**
* Abort unconditionally with a 'Fatal Error!' message.
@@ -49,7 +50,7 @@ extern "C" {
* @param err name of the error without the 'LUMIERA_ERROR_' prefix (example: NO_MEMORY)
*/
#define LUMIERA_ERROR_DECLARE(err) \
-extern const char* LUMIERA_ERROR_##err
+extern lumiera_err LUMIERA_ERROR_##err
/**
* Definition and initialization of an error constant.
@@ -58,7 +59,7 @@ extern const char* LUMIERA_ERROR_##err
* @param msg message describing the error in plain english (example: "memory allocation failed")
*/
#define LUMIERA_ERROR_DEFINE(err, msg) \
-const char* LUMIERA_ERROR_##err = "LUMIERA_ERROR_" #err ":" msg
+lumiera_err LUMIERA_ERROR_##err = "LUMIERA_ERROR_" #err ":" msg
/**
* Helper macro to raise an error for the current thread.
@@ -70,10 +71,23 @@ const char* LUMIERA_ERROR_##err = "LUMIERA_ERROR_" #err ":" msg
(({ERROR (flag, "%s", strchr(LUMIERA_ERROR_##err, ':')+1);}), \
lumiera_error_set(LUMIERA_ERROR_##err))
-const char*
-lumiera_error_set (const char * err);
+/**
+ * Set error state for the current thread.
+ * If the error state of the current thread was cleared, then set it, else preserve the old state.
+ * @param nerr name of the error with 'LUMIERA_ERROR_' prefix (example: LUMIERA_ERROR_NO_MEMORY)
+ * @return old state, that is NULL for success, when the state was cleared and a pointer to a pending
+ * error when the error state was already set
+ */
+lumiera_err
+lumiera_error_set (lumiera_err err);
-const char*
+/**
+ * Get and clear current error state.
+ * This function clears the error state, if it needs to be reused, one has to store it in a temporary
+ * variable.
+ * @return pointer to any pending error of this thread, NULL if no error is pending
+ */
+lumiera_err
lumiera_error ();
/*
diff --git a/src/lib/llist.h b/src/lib/llist.h
index 128a3e826..353fe4320 100644
--- a/src/lib/llist.h
+++ b/src/lib/llist.h
@@ -299,6 +299,9 @@ LLIST_FUNC (LList llist_unlink (LList self),
/**
* Fix a node which got relocated in memory.
* It is supported to realloc/move list nodes in memory but one must call 'list_relocate' after doing so.
+ * IMPORTANT: it is not possible to relocate nodes which are empty this way, nor can this be determined
+ * after the relocation, so either llist_init them afterwards or insert a bogus node before moving the node
+ * and relocating it and remove it afterwards.
* @param self node which got relocated
* @return self
*/
@@ -306,6 +309,7 @@ LLIST_FUNC (LList llist_relocate (LList self),
return self->next->prev = self->prev->next = self;
);
+
/**
* Insert a node after another.
* @param self node after which we want to insert
diff --git a/src/lib/luid.c b/src/lib/luid.c
new file mode 100644
index 000000000..c8d766094
--- /dev/null
+++ b/src/lib/luid.c
@@ -0,0 +1,113 @@
+/*
+ luid - Lumiera unique identifiers
+
+ Copyright (C) Lumiera.org
+ 2008, Christian Thaeter
+
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "lib/luid.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+void
+lumiera_uid_set_ptr (lumiera_uid* luid, void* ptr)
+{
+ memset (luid, 0, 16);
+ *(void**)luid = ptr;
+}
+
+
+void*
+lumiera_uid_ptr_get (lumiera_uid* luid)
+{
+ return *(void**)luid;
+}
+
+
+void
+lumiera_uid_gen (lumiera_uid* luid)
+{
+ static int fd = -2;
+ if (!luid)
+ return;
+
+ if (fd == -2)
+ {
+ fd = open ("/dev/urandom", O_RDONLY);
+ /* on linux /dev/random would be way to slow for our purpose, so we comment that out for now.
+ other unixiods offer a /dev/random which has the same semantics as linux /dev/urandom has,
+ configuration should do this right some day.
+ if (fd == -1)
+ fd = open ("/dev/random", O_RDONLY);
+ */
+ if (fd >= 0)
+ fcntl (fd, F_SETFD, FD_CLOEXEC);
+ else
+ srand (getpid () + time (NULL));
+ }
+
+ do
+ {
+ if (fd < 0)
+ {
+ for (int i = 0; i < 16; ++i)
+ ((unsigned char*)luid)[i] = (unsigned char)(rand()>>7);
+ }
+ else
+ {
+ if (read (fd, luid, 16) < 16)
+ abort ();
+ }
+ }
+ /* we identify generic pointers by having some zeros in the luid,
+ * this happens very unlikely to be in a random luid, just regenerate it then */
+ while (!*(((intptr_t*)luid)+1));
+}
+
+
+void
+lumiera_uid_copy (lumiera_uid* dest, lumiera_uid* src)
+{
+ memcpy (dest, src, 16);
+}
+
+
+int
+lumiera_uid_eq (lumiera_uid* luida, lumiera_uid* luidb)
+{
+ return !memcmp (luida, luidb, 16);
+}
+
+size_t
+lumiera_uid_hash (lumiera_uid* luid)
+{
+ return *(size_t*)luid;
+}
+
+/*
+// Local Variables:
+// mode: C
+// c-file-style: "gnu"
+// indent-tabs-mode: nil
+// End:
+*/
diff --git a/src/lib/luid.h b/src/lib/luid.h
new file mode 100644
index 000000000..a93d004a3
--- /dev/null
+++ b/src/lib/luid.h
@@ -0,0 +1,81 @@
+/*
+ luid - Lumiera unique identifiers
+
+ Copyright (C) Lumiera.org
+ 2008, Christian Thaeter
+
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+#ifndef LUMIERA_LUID_H
+#define LUMIERA_LUID_H
+
+#include
+
+/**
+ * @file
+ * Lumiera unique identifiers are 128 byte random value. Unlike standard uuid's we
+ * don't tag a version within them and we may store generic pointers in the space
+ * occupied by an luid.
+ */
+
+typedef unsigned char lumiera_uid[16];
+
+/**
+ * Retrieve a generic pointer stored in a luid
+ */
+void*
+lumiera_uid_ptr_get (lumiera_uid* luid);
+
+/**
+ * Generate a new luid
+ */
+void
+lumiera_uid_gen (lumiera_uid* luid);
+
+/**
+ * Store a generic pointer in a luid
+ */
+void
+lumiera_uid_set_ptr (lumiera_uid* luid, void* ptr);
+
+
+/**
+ * Copy an luid
+ */
+void
+lumiera_uid_copy (lumiera_uid* dest, lumiera_uid* src);
+
+
+/**
+ * Test 2 luid's for equality
+ */
+int
+lumiera_uid_eq (lumiera_uid* luida, lumiera_uid* luidb);
+
+
+/**
+ * Generate a hashsum over an luid
+ */
+size_t
+lumiera_uid_hash (lumiera_uid* luid);
+
+#endif
+/*
+// Local Variables:
+// mode: C
+// c-file-style: "gnu"
+// indent-tabs-mode: nil
+// End:
+*/
diff --git a/src/lib/mrucache.c b/src/lib/mrucache.c
index 0f9bb86df..d591d5f56 100644
--- a/src/lib/mrucache.c
+++ b/src/lib/mrucache.c
@@ -19,6 +19,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include "lib/safeclib.h"
#include "lib/mrucache.h"
@@ -39,9 +40,9 @@ lumiera_mrucache_destroy (LumieraMruCache self)
{
llist_unlink (node);
if (self->destructor_cb)
- free (self->destructor_cb (node));
+ lumiera_free (self->destructor_cb (node));
else
- free (node);
+ lumiera_free (node);
}
self->cached = 0;
return self;
@@ -52,7 +53,7 @@ lumiera_mrucache_age (LumieraMruCache self, int nelem)
{
REQUIRE (self);
while (self->cached && nelem--)
- free (lumiera_mrucache_pop (self));
+ lumiera_free (lumiera_mrucache_pop (self));
return nelem;
}
diff --git a/src/lib/mutex.c b/src/lib/mutex.c
index b7c5f1844..99ef8897f 100644
--- a/src/lib/mutex.c
+++ b/src/lib/mutex.c
@@ -31,34 +31,35 @@ LUMIERA_ERROR_DEFINE (MUTEX_UNLOCK, "Mutex unlocking failed");
LUMIERA_ERROR_DEFINE (MUTEX_DESTROY, "Mutex destroy failed");
-/**
- * Initialize a mutex variable
- * @param self is a pointer to the mutex to be initialized
- * @return self as given
- */
LumieraMutex
-lumiera_mutex_init (LumieraMutex self)
+lumiera_mutex_init (LumieraMutex self, const char* purpose, struct nobug_flag* flag)
{
if (self)
{
pthread_mutex_init (&self->mutex, NULL);
+ NOBUG_RESOURCE_HANDLE_INIT (self->rh);
+ NOBUG_RESOURCE_ANNOUNCE_RAW (flag, "mutex", purpose, self, self->rh);
}
return self;
}
-/**
- * Destroy a mutex variable
- * @param self is a pointer to the mutex to be destroyed
- * @return self as given
- */
+
LumieraMutex
-lumiera_mutex_destroy (LumieraMutex self)
+lumiera_mutex_destroy (LumieraMutex self, struct nobug_flag* flag)
{
if (self)
{
+ NOBUG_RESOURCE_FORGET_RAW (flag, self->rh);
if (pthread_mutex_destroy (&self->mutex))
LUMIERA_DIE (MUTEX_DESTROY);
}
return self;
}
+/*
+// Local Variables:
+// mode: C
+// c-file-style: "gnu"
+// indent-tabs-mode: nil
+// End:
+*/
diff --git a/src/lib/mutex.h b/src/lib/mutex.h
index f19058e7a..681d29432 100644
--- a/src/lib/mutex.h
+++ b/src/lib/mutex.h
@@ -22,21 +22,43 @@
#ifndef LUMIERA_MUTEX_H
#define LUMIERA_MUTEX_H
-#include "lib/locking.h"
+#include "lib/error.h"
+
+#include
+#include
/**
* @file
* Mutual exclusion locking, header.
*/
-#define LUMIERA_MUTEX_SECTION(flag, handle, mutex) \
-RESOURCE_HANDLE (rh_##__LINE__##_); \
-lumiera_mutexacquirer lock_##__LINE__##_; \
-RESOURCE_ENTER (flag, handle, "acquire mutex", &lock_##__LINE__##_, \
- NOBUG_RESOURCE_EXCLUSIVE, rh_##__LINE__##_); \
-for (lumiera_mutexacquirer_init_mutex (&lock_##__LINE__##_, mutex, LUMIERA_LOCKED); \
- lock_##__LINE__##_.state == LUMIERA_LOCKED; \
- lumiera_mutexacquirer_unlock (&lock_##__LINE__##_), \
- ({RESOURCE_LEAVE(flag, rh_##__LINE__##_);}))
+
+LUMIERA_ERROR_DECLARE (MUTEX_LOCK);
+LUMIERA_ERROR_DECLARE (MUTEX_UNLOCK);
+LUMIERA_ERROR_DECLARE (MUTEX_DESTROY);
+
+/**
+ * Mutual exclusive section.
+ */
+#define LUMIERA_MUTEX_SECTION(nobugflag, mtx) \
+ for (lumiera_mutexacquirer NOBUG_CLEANUP(lumiera_mutexacquirer_ensureunlocked) lumiera_mutex_section_ = {(LumieraMutex)1}; \
+ lumiera_mutex_section_.mutex;) \
+ for ( \
+ ({ \
+ lumiera_mutex_section_.mutex = (mtx); \
+ NOBUG_RESOURCE_HANDLE_INIT (lumiera_mutex_section_.rh); \
+ RESOURCE_ENTER (nobugflag, (mtx)->rh, "acquire mutex", &lumiera_mutex_section_, \
+ NOBUG_RESOURCE_EXCLUSIVE, lumiera_mutex_section_.rh); \
+ if (pthread_mutex_lock (&(mtx)->mutex)) LUMIERA_DIE (MUTEX_LOCK); \
+ }); \
+ lumiera_mutex_section_.mutex; \
+ ({ \
+ if (lumiera_mutex_section_.mutex) \
+ { \
+ pthread_mutex_unlock (&lumiera_mutex_section_.mutex->mutex); \
+ lumiera_mutex_section_.mutex = NULL; \
+ RESOURCE_LEAVE(nobugflag, lumiera_mutex_section_.rh); \
+ } \
+ }))
/**
@@ -46,27 +68,37 @@ for (lumiera_mutexacquirer_init_mutex (&lock_##__LINE__##_, mutex, LUMIERA_LOCKE
struct lumiera_mutex_struct
{
pthread_mutex_t mutex;
+ RESOURCE_HANDLE (rh);
};
typedef struct lumiera_mutex_struct lumiera_mutex;
typedef lumiera_mutex* LumieraMutex;
+/**
+ * Initialize a mutex variable
+ * @param self is a pointer to the mutex to be initialized
+ * @return self as given
+ */
LumieraMutex
-lumiera_mutex_init (LumieraMutex self);
-
-
-LumieraMutex
-lumiera_mutex_destroy (LumieraMutex self);
-
+lumiera_mutex_init (LumieraMutex self, const char* purpose, struct nobug_flag* flag);
/**
- * mutexacquirer used to manage the state of a mutex variable.
+ * Destroy a mutex variable
+ * @param self is a pointer to the mutex to be destroyed
+ * @return self as given
+ */
+LumieraMutex
+lumiera_mutex_destroy (LumieraMutex self, struct nobug_flag* flag);
+
+
+/**
+ * mutexacquirer used to manage the state of a mutex.
*/
struct lumiera_mutexacquirer_struct
{
LumieraMutex mutex;
- enum lumiera_lockstate state;
+ RESOURCE_HANDLE (rh);
};
typedef struct lumiera_mutexacquirer_struct lumiera_mutexacquirer;
typedef struct lumiera_mutexacquirer_struct* LumieraMutexacquirer;
@@ -75,123 +107,14 @@ typedef struct lumiera_mutexacquirer_struct* LumieraMutexacquirer;
static inline void
lumiera_mutexacquirer_ensureunlocked (LumieraMutexacquirer self)
{
- ENSURE (self->state == LUMIERA_UNLOCKED, "forgot to unlock mutex");
-}
-
-/* override with a macro to use the cleanup checker */
-#define lumiera_mutexacquirer \
-lumiera_mutexacquirer NOBUG_CLEANUP(lumiera_mutexacquirer_ensureunlocked)
-
-
-/**
- * initialize a mutexacquirer state without mutex.
- * @param self mutexacquirer to be initialized, must be an automatic variable
- * @return self as given
- * This initialization is used when lumiera_mutexacquirer_try_mutex shall be used later
- */
-static inline LumieraMutexacquirer
-lumiera_mutexacquirer_init (LumieraMutexacquirer self)
-{
- REQUIRE (self);
- self->mutex = NULL;
- self->state = LUMIERA_UNLOCKED;
-
- return self;
-}
-
-/**
- * initialize a mutexacquirer state
- * @param self mutexacquirer to be initialized, must be an automatic variable
- * @param mutex associated mutex
- * @param state initial state of the mutex, either LUMIERA_LOCKED or LUMIERA_UNLOCKED
- * @return self as given
- * errors are fatal
- */
-static inline LumieraMutexacquirer
-lumiera_mutexacquirer_init_mutex (LumieraMutexacquirer self, LumieraMutex mutex, enum lumiera_lockstate state)
-{
- REQUIRE (self);
- REQUIRE (mutex);
- self->mutex = mutex;
- self->state = state;
- if (state == LUMIERA_LOCKED)
- if (pthread_mutex_lock (&mutex->mutex))
- LUMIERA_DIE (MUTEX_LOCK);
-
- return self;
-}
-
-
-/**
- * lock the mutex.
- * must not already be locked
- * @param self mutexacquirer associated with a mutex variable
- */
-static inline void
-lumiera_mutexacquirer_lock (LumieraMutexacquirer self)
-{
- REQUIRE (self);
- REQUIRE (self->state == LUMIERA_UNLOCKED, "mutex already locked");
-
- if (pthread_mutex_lock (&self->mutex->mutex))
- LUMIERA_DIE (MUTEX_LOCK);
-
- self->state = LUMIERA_LOCKED;
-}
-
-
-/**
- * get the state of a lock.
- * @param self mutexacquirer associated with a mutex variable
- * @return LUMIERA_LOCKED when the mutex is locked by this thead
- */
-static inline enum lumiera_lockstate
-lumiera_mutexacquirer_state (LumieraMutexacquirer self)
-{
- REQUIRE (self);
- return self->state;
-}
-
-
-/**
- * try to lock a mutex.
- * must not already be locked
- * @param self mutexacquirer associated with a mutex variable
- * @param mutex pointer to a mutex which should be tried
- * @return LUMIERA_LOCKED when the mutex got locked
- */
-static inline enum lumiera_lockstate
-lumiera_mutexacquirer_try_mutex (LumieraMutexacquirer self, LumieraMutex mutex)
-{
- REQUIRE (self);
- REQUIRE (self->state == LUMIERA_UNLOCKED, "mutex already locked");
-
- self->mutex=mutex;
- switch (pthread_mutex_trylock (&self->mutex->mutex))
- {
- case 0:
- return self->state = LUMIERA_LOCKED;
- case EBUSY:
- return LUMIERA_UNLOCKED;
- default:
- LUMIERA_DIE (MUTEX_LOCK);
- }
-}
-
-
-/**
- * release mutex.
- * a mutexacquirer must be unlocked before leaving scope
- * @param self mutexacquirer associated with a mutex variable
- */
-static inline void
-lumiera_mutexacquirer_unlock (LumieraMutexacquirer self)
-{
- REQUIRE (self);
- REQUIRE (self->state == LUMIERA_LOCKED, "mutex was not locked");
- if (pthread_mutex_unlock (&self->mutex->mutex))
- LUMIERA_DIE (MUTEX_UNLOCK);
- self->state = LUMIERA_UNLOCKED;
+ ENSURE (!self->mutex, "forgot to unlock mutex");
}
#endif
+/*
+// Local Variables:
+// mode: C
+// c-file-style: "gnu"
+// indent-tabs-mode: nil
+// End:
+*/
diff --git a/src/lib/plugin.c b/src/lib/plugin.c
index 1f5e8576e..44cf6abc5 100644
--- a/src/lib/plugin.c
+++ b/src/lib/plugin.c
@@ -111,10 +111,6 @@ lumiera_plugin_name_cmp (const void* a, const void* b)
return strcmp (((struct lumiera_plugin*) a)->name, ((struct lumiera_plugin*) b)->name);
}
-/**
- * Initialize the plugin system.
- * always succeeds or aborts
- */
void
lumiera_init_plugin (void)
{
@@ -173,17 +169,6 @@ lumiera_plugin_lookup (struct lumiera_plugin* self, const char* path)
}
-/**
- * Make an interface available.
- * To use an interface provided by a plugin it must be opened first. It is allowed to open an interface
- * more than once. Each open must be paired with a close.
- * @param name name of the plugin to use.
- * @param interface name of the interface to open.
- * @param min_revision the size of the interface structure is used as measure of a minimal required
- * revision (new functions are appended at the end)
- * @return handle to the interface or NULL in case of a error. The application shall cast this handle to
- * the actual interface type.
- */
struct lumiera_interface*
lumiera_interface_open (const char* name, const char* interface, size_t min_revision)
{
@@ -311,11 +296,6 @@ lumiera_interface_open (const char* name, const char* interface, size_t min_revi
return NULL;
}
-/**
- * Close an interface. Does not free associated resources
- * Calling this function with self==NULL is legal. Every interface handle must be closed only once.
- * @param ptr interface to be closed
- */
void
lumiera_interface_close (void* ptr)
{
diff --git a/src/lib/plugin.h b/src/lib/plugin.h
index 54dad6372..7e17afc18 100644
--- a/src/lib/plugin.h
+++ b/src/lib/plugin.h
@@ -96,14 +96,34 @@ struct lumiera_interface
int (*close)(void);
};
+/**
+ * Initialize the plugin system.
+ * always succeeds or aborts
+ */
void
lumiera_init_plugin (void);
+/**
+ * Make an interface available.
+ * To use an interface provided by a plugin it must be opened first. It is allowed to open an interface
+ * more than once. Each open must be paired with a close.
+ * @param name name of the plugin to use.
+ * @param interface name of the interface to open.
+ * @param min_revision the size of the interface structure is used as measure of a minimal required
+ * revision (new functions are appended at the end)
+ * @return handle to the interface or NULL in case of a error. The application shall cast this handle to
+ * the actual interface type.
+ */
struct lumiera_interface*
lumiera_interface_open (const char* plugin, const char* name, size_t min_revision);
+/**
+ * Close an interface. Does not free associated resources
+ * Calling this function with self==NULL is legal. Every interface handle must be closed only once.
+ * @param ptr interface to be closed
+ */
void
lumiera_interface_close (void* self);
diff --git a/src/lib/psplay.c b/src/lib/psplay.c
new file mode 100644
index 000000000..7647fd905
--- /dev/null
+++ b/src/lib/psplay.c
@@ -0,0 +1,522 @@
+/*
+ psplay.c - probabilistic splay tree
+
+ Copyright (C)
+ 2004, 2005, 2006, Christian Thaeter
+ Copyright (C) CinelerraCV
+ 2007, 2008, Christian Thaeter
+
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "lib/psplay.h"
+
+#include
+#include
+#include
+#include
+
+NOBUG_DEFINE_FLAG (psplay);
+
+#ifndef PSPLAY_TRAIL_DEPTH
+#define PSPLAY_TRAIL_DEPTH 128
+#endif
+
+/*
+ probabilistic distribution, this are the direct splay equations used to determine if to splay
+ or break out of the splaying algorithm.
+
+ useable variables/functions are:
+ self->log2 - log2 of the tree elements, this would be the depth of a fully balanced tree
+ splayfactor - user defined weigth for splaying, we define '100' to be the default
+ depth - depth of the current node in the tree
+ trail->dir - dervitation from tree center
+ psplay_fast_prng () - returns a prng in the range 1...2^31
+*/
+
+#define PSPLAY_FORMULA (self->log2*100/(depth + (psplay_fast_prng () & 63)) + trail->dir) * splayfactor
+
+#ifndef PSPLAY_PROB_ZIGZIG
+#define PSPLAY_PROB_ZIGZIG 5000
+#endif
+#ifndef PSPLAY_PROB_ZIGZAG
+#define PSPLAY_PROB_ZIGZAG 2500
+#endif
+
+
+
+/* simple prng with 2^31-1 cycle */
+static inline uint32_t psplay_fast_prng ()
+{
+ static uint32_t rnd=0xbabeface;
+ return rnd = rnd<<1 ^ ((rnd >> 30) & 1) ^ ((rnd>>2) & 1);
+}
+
+
+PSplay
+psplay_init (PSplay self, psplay_cmp_fn cmp, psplay_key_fn key, psplay_delete_fn delete)
+{
+ NOBUG_INIT_FLAG (psplay);
+ TRACE (psplay);
+ REQUIRE (cmp);
+ REQUIRE (key);
+
+ if (self)
+ {
+ self->tree = NULL;
+ self->found_parent = &self->tree;
+ self->cmp = cmp;
+ self->key = key;
+ self->delete = delete;
+ self->elem_cnt = 0;
+ self->log2 = 0;
+ }
+ return self;
+}
+
+
+PSplay
+psplay_new (psplay_cmp_fn cmp, psplay_key_fn key, psplay_delete_fn delete)
+{
+ PSplay self = malloc (sizeof *self);
+ if (self)
+ {
+ psplay_init (self , cmp, key, delete);
+ }
+ return self;
+}
+
+
+
+PSplay
+psplay_destroy (PSplay self)
+{
+ TRACE (psplay);
+ if (self) while (self->tree)
+ {
+ PSplaynode n = psplay_remove (self, self->tree);
+ if (self->delete)
+ self->delete (n);
+ }
+ return self;
+}
+
+
+void
+psplay_delete (PSplay self)
+{
+ free (psplay_destroy (self));
+}
+
+
+PSplaynode
+psplaynode_init (PSplaynode self)
+{
+ if (self)
+ self->left = self->right = NULL;
+ return self;
+}
+
+
+
+/*
+ Lookup operations (lookup and insert) record the path as they decend into the tree
+ this will allow bottom up splaying without storing 'up' pointers in the node.
+ The length of this trail (PSPLAY_TRAIL_DEPTH) also define the maximal limit on how much
+ a node can be splayed up giving some hard bound for the splay operation.
+
+ General wisdom tells that top down splaying is more efficent to implement than bottom
+ up splaying. Nevertheless we do bottom up splaying here because we can decide
+ randomly on each level if we want to continue splaying or not. No splaying
+ is certainly more efficent than top-down splaying.
+*/
+struct psplaytrail
+{
+ int dir;
+ unsigned depth;
+ PSplaynode* trail[PSPLAY_TRAIL_DEPTH];
+};
+
+static inline unsigned
+trailidx (unsigned n)
+{
+ return n & (PSPLAY_TRAIL_DEPTH-1);
+}
+
+
+static inline void
+psplay_splay (PSplay self, struct psplaytrail* trail, unsigned splayfactor)
+{
+ TRACE (psplay, "%p %u", self, splayfactor);
+
+ if (trail->dir < 0) trail->dir = - trail->dir;
+
+ for (unsigned lim = PSPLAY_TRAIL_DEPTH, depth = trail->depth; lim > 2 && depth > 2; lim-=2, depth-=2)
+ {
+ PSplaynode node = *trail->trail [trailidx (depth)];
+ PSplaynode parent = *trail->trail [trailidx (depth-1)];
+ PSplaynode grandparent = *trail->trail [trailidx (depth-2)];
+
+ unsigned r = PSPLAY_FORMULA;
+ TRACE (psplay, "r is %u", r);
+
+ if (parent == grandparent->left)
+ {
+ TRACE (psplay, "ZIG..");
+ if (node == parent->left)
+ {
+ TRACE (psplay, "..ZIG");
+ if (r < PSPLAY_PROB_ZIGZIG)
+ {
+ TRACE (psplay, "BREAK");
+ return;
+ }
+
+ grandparent->left = parent->right;
+ parent->right = grandparent;
+
+ parent->left = node->right;
+ node->right = parent;
+ }
+ else
+ {
+ TRACE (psplay, "..ZAG");
+ if (r < PSPLAY_PROB_ZIGZAG)
+ {
+ TRACE (psplay, "BREAK");
+ return;
+ }
+
+ parent->right = node->left;
+ node->left = parent;
+
+ grandparent->left = node->right;
+ node->right = grandparent;
+ }
+ }
+ else
+ {
+ TRACE (psplay, "ZAG..");
+ if (node == parent->left)
+ {
+ TRACE (psplay, "..ZIG");
+ if (r < PSPLAY_PROB_ZIGZAG)
+ {
+ TRACE (psplay, "BREAK");
+ return;
+ }
+
+ parent->left = node->right;
+ node->right = parent;
+
+ grandparent->right = node->left;
+ node->left = grandparent;
+ }
+ else
+ {
+ TRACE (psplay, "..ZAG");
+ if (r < PSPLAY_PROB_ZIGZIG)
+ {
+ TRACE (psplay, "BREAK");
+ return;
+ }
+
+ grandparent->right = parent->left;
+ parent->left = grandparent;
+
+ parent->right = node->left;
+ node->left = parent;
+ }
+ }
+ *trail->trail [trailidx (depth-2)] = node;
+ }
+}
+
+
+PSplaynode
+psplay_insert (PSplay self, PSplaynode node, int splayfactor)
+{
+ TRACE (psplay);
+ PSplaynode n = self->tree;
+ struct psplaytrail trail;
+
+ trail.dir = 0;
+ trail.depth = 0;
+ trail.trail [0] = &self->tree;
+
+ if (!n)
+ self->tree = node;
+ else
+ {
+ while (n != node)
+ {
+ int c;
+ c = self->cmp (self->key (node), self->key (n));
+ ++trail.depth;
+
+ if (c < 0)
+ {
+ --trail.dir;
+ if (!n->left)
+ n->left = node;
+ trail.trail [trailidx (trail.depth)] = &n->left;
+ n = n->left;
+ }
+ else if (c > 0)
+ {
+ ++trail.dir;
+ if (!n->right)
+ n->right = node;
+ trail.trail [trailidx (trail.depth)] = &n->right;
+ n = n->right;
+ }
+ else
+ {
+ TODO ("policy for multiple entered items (before, after, fail, replace)");
+ return NULL;
+ }
+ }
+ }
+ ++self->elem_cnt;
+ if (self->elem_cnt >= 1<log2) ++self->log2;
+ if (splayfactor && trail.depth > 2)
+ psplay_splay (self, &trail, splayfactor);
+ return node;
+}
+
+
+
+PSplaynode
+psplay_find (PSplay self, const void* key, int splayfactor)
+{
+ TRACE (psplay);
+ PSplaynode node = self->tree;
+ struct psplaytrail trail;
+ trail.dir = 0;
+ trail.depth = 0;
+ trail.trail [0] = &self->tree;
+
+ while (node)
+ {
+ int c;
+ c = self->cmp (key, self->key (node));
+ ++trail.depth;
+
+ if (c < 0)
+ {
+ --trail.dir;
+ trail.trail [trailidx (trail.depth)] = &node->left;
+ node = node->left;
+ }
+ else if (c > 0)
+ {
+ ++trail.dir;
+ trail.trail [trailidx (trail.depth)] = &node->right;
+ node = node->right;
+ }
+ else
+ {
+ self->found_parent = trail.trail [trailidx (--trail.depth)];
+ break;
+ }
+ }
+ if (node && splayfactor && trail.depth > 2)
+ psplay_splay (self, &trail, splayfactor);
+ return node;
+}
+
+
+PSplaynode
+psplay_remove (PSplay self, PSplaynode node)
+{
+ TRACE (psplay);
+ if (!node) return NULL;
+
+ PSplaynode* r = self->found_parent;
+
+ while (*r != node)
+ {
+ if (!psplay_find (self, self->key (node), 0))
+ {
+ WARN (psplay, "node %p is not in splay tree %p", node, self);
+ return NULL;
+ }
+ r = self->found_parent;
+ }
+
+ if (!node->left)
+ *r = node->right;
+ else if (!node->right)
+ *r = node->left;
+ else
+ {
+ PSplaynode i, iparent = NULL;
+ if (psplay_fast_prng()&1) /* 50% probability removing left or right wards */
+ {
+ for (i = node->left; i->right; iparent = i, i = i->right);
+ if (iparent)
+ iparent->right = i->left;
+ if (node->left != i)
+ i->left = node->left;
+ i->right = node->right;
+ }
+ else
+ {
+ for (i = node->right; i->left; iparent = i, i = i->left);
+ if (iparent)
+ iparent->left = i->right;
+ if (node->right != i)
+ i->right = node->right;
+ i->left = node->left;
+ }
+ *r = i;
+ }
+ --self->elem_cnt;
+ if (self->elem_cnt < 1<log2) --self->log2;
+ return node;
+}
+
+
+PSplaynode
+psplay_remove_key (PSplay self, void* key)
+{
+ return psplay_remove (self, psplay_find (self, key, 0));
+}
+
+
+void
+psplay_delete_node (PSplay self, PSplaynode node)
+{
+ if (node)
+ self->delete (psplay_remove (self, node));
+}
+
+
+void
+psplay_delete_key (PSplay self, void* key)
+{
+ PSplaynode node = psplay_find (self, key, 0);
+ psplay_delete_node (self, node);
+}
+
+
+
+const psplay_delete_fn PSPLAY_CONT = (psplay_delete_fn)0x0;
+const psplay_delete_fn PSPLAY_STOP = (psplay_delete_fn)0x1;
+const psplay_delete_fn PSPLAY_REMOVE = (psplay_delete_fn)0x2;
+
+static int
+psplay_handle (PSplay self, PSplaynode node, psplay_delete_fn res)
+{
+ if (res == PSPLAY_CONT)
+ return 1;
+
+ if (res == PSPLAY_STOP)
+ ;
+ else if (res == PSPLAY_REMOVE)
+ {
+ psplay_remove (self, node);
+ if (self->delete)
+ self->delete (node);
+ }
+ else
+ {
+ psplay_remove (self, node);
+ res (node);
+ }
+ return 0;
+}
+
+
+int
+psplay_walk (PSplay self, PSplaynode node, psplay_action_fn action, int level, void* data)
+{
+ if (!self->tree)
+ return 1;
+
+ if (!node)
+ node = self->tree;
+
+ psplay_delete_fn res;
+
+ res = action (node, PSPLAY_PREORDER, level, data);
+ if (!psplay_handle (self, node, res))
+ return 0;
+
+ if (node->left)
+ if (!psplay_walk (self, node->left, action, level+1, data))
+ return 0;
+
+ res = action (node, PSPLAY_INORDER, level, data);
+ if (!psplay_handle (self, node, res))
+ return 0;
+
+ if (node->right)
+ if (!psplay_walk (self, node->right, action, level+1, data))
+ return 0;
+
+ res = action (node, PSPLAY_POSTORDER, level, data);
+ if (!psplay_handle (self, node, res))
+ return 0;
+
+ return 1;
+}
+
+
+static psplay_delete_fn
+psplay_print_node (PSplaynode node, const enum psplay_order_enum which, int level, void* data)
+{
+ FILE* fh = data;
+ static char* sp = " ";
+ if (level>40)
+ {
+ if (which == PSPLAY_PREORDER)
+ fprintf (fh, "%s ...\n", sp);
+ return PSPLAY_CONT;
+ }
+
+ switch (which)
+ {
+ case PSPLAY_PREORDER:
+ fprintf (fh, "%s%p\n", sp+40-level, node);
+ if (node->left)
+ fprintf (fh, "%sleft %p\n", sp+40-level, node->left);
+ break;
+ case PSPLAY_INORDER:
+ if (node->right)
+ fprintf (fh, "%sright %p\n", sp+40-level, node->right);
+ break;
+ case PSPLAY_POSTORDER:
+ break;
+ }
+
+ return PSPLAY_CONT;
+}
+
+void
+psplay_dump (PSplay self, FILE* dest)
+{
+ fprintf (dest, "root %p\n", self->tree);
+ psplay_walk (self, NULL, psplay_print_node, 0, dest);
+}
+
+
+/*
+// Local Variables:
+// mode: C
+// c-file-style: "gnu"
+// indent-tabs-mode: nil
+// End:
+*/
diff --git a/src/lib/psplay.h b/src/lib/psplay.h
new file mode 100644
index 000000000..26639910a
--- /dev/null
+++ b/src/lib/psplay.h
@@ -0,0 +1,292 @@
+/*
+ psplay.h - probabilistic splay tree
+
+ Copyright (C)
+ 2004, 2005, 2006, Christian Thaeter
+ Copyright (C) Lumiera.org
+ 2007, 2008, Christian Thaeter
+
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef PSPLAY_H
+#define PSPLAY_H
+
+#include
+#include
+
+/**
+ * @file
+ * Probabilistic splay trees
+ * A splay trees is self-optimizing (in contrast to self-balancing) datastructure.
+ * We introduce here a probabilistic bottom up approach which reduces the splay costs.
+ * Without affecting the performance. The randomization gives also some insurance that
+ * worst case situations are extremely unlikely.
+ * Tree nodes are very small (just 2 pointers) and are intrusively placed into the users
+ * datastructure.
+ */
+
+
+/**
+ * Type and handle for a psplay tree node
+ * This node have to be placed inside users data.
+ */
+typedef struct psplaynode_struct psplaynode;
+typedef psplaynode* PSplaynode;
+struct psplaynode_struct
+{
+ PSplaynode left;
+ PSplaynode right;
+};
+
+
+/**
+ * Function use to compare keys
+ * @param a first key
+ * @param b second key
+ * @return shall return -1/0/1 when a is less than/equal to/biggier than b.
+ */
+typedef int (*psplay_cmp_fn)(const void* a, const void* b);
+
+
+/**
+ * Destructor for user defined data
+ * Called when an element got removed from a splay tree.
+ * @param node pointer to the intrusive node inside the users datastructure
+ * The user is responsible for casting 'node' back to his real datastructure (maybe with OFFSET_OF()),
+ * free all resources associated with it and finally free the datastructure itself.
+ */
+typedef void (*psplay_delete_fn)(PSplaynode node);
+
+
+/**
+ * Retrieve the key from a user datastructure
+ * @param node pointer to the intrusive node inside the users datastructure
+ * This functiom must return a pointer to the key under which the user stores his data.
+ */
+typedef const void* (*psplay_key_fn)(const PSplaynode node);
+
+
+/**
+ * Type and handle for a psplay root structure
+ * This structure shall be treated opaque, its only defined in the header to allow
+ * one to integrate it directly instead referencing it.
+ */
+typedef struct psplay_struct psplay;
+typedef psplay* PSplay;
+
+struct psplay_struct
+{
+ PSplaynode tree; /* the tree */
+ PSplaynode* found_parent; /* maybe direct parent of last found node, used for fast remove */
+ psplay_cmp_fn cmp;
+ psplay_key_fn key;
+ psplay_delete_fn delete;
+
+ size_t elem_cnt;
+ unsigned log2; /* roughly log2 of the elem_cnt*/
+};
+
+
+/**
+ * Number of elements in tree
+ * @param self pointer to the tree
+ * @return number of elements
+ */
+static inline size_t
+psplay_nelements (PSplay self)
+{
+ return self->elem_cnt;
+};
+
+
+/**
+ * Initialize a splay tree
+ * @param self pointer to the psplay structure
+ * @param cmp user supplied compare function
+ * @param key user supplied function to retrieve a key
+ * @param delete user supplied destructor function or NULL if no destructor is necessary
+ * @return self
+ */
+PSplay
+psplay_init (PSplay self, psplay_cmp_fn cmp, psplay_key_fn key, psplay_delete_fn delete);
+
+
+/**
+ * Destroy a splay tree
+ * Frees all elements and associated resources of a splay tree
+ * @param self pointer to the psplay structure
+ * @return self
+ */
+PSplay
+psplay_destroy (PSplay self);
+
+/**
+ * Allocate a splay tree
+ * @param cmp user supplied compare function
+ * @param key user supplied function to retrieve a key
+ * @param delete user supplied destructor function or NULL if no destructor is necessary
+ * @return allcoated splay tree or NULL on error
+ */
+PSplay
+psplay_new (psplay_cmp_fn cmp, psplay_key_fn key, psplay_delete_fn delete);
+
+
+/**
+ * Delete a splay tree
+ * Frees all elements and associated resources of a splay tree and then itseld
+ * @param self pointer to the psplay structure
+ */
+void
+psplay_delete (PSplay self);
+
+
+/**
+ * Initialize a splay tree node
+ * The user has to place this nodes within his datastructure and must
+ * initialize them before using them.
+ * @param self pointer to the node to be initialized
+ * @return self
+ */
+PSplaynode
+psplaynode_init (PSplaynode self);
+
+
+/**
+ * Insert a element into a splay tree
+ * @param self pointer to the splay tree
+ * @param node pointer to the node to be inserted
+ * @param splayfactor weight for the probabilistic splaying,
+ * 0 disables the splaying, 100 is the expected normal value
+ * use 100 when in doubt
+ * @return self or NULL when a node with same key already in the tree
+ */
+PSplaynode
+psplay_insert (PSplay self, PSplaynode node, int splayfactor);
+
+
+/**
+ * Find a element in a splay tree
+ * @param self pointer to the splay tree
+ * @param key pointer to the key to be searched
+ * @param splayfactor weight for the probabilistic splaying,
+ * 0 disables the splaying, 100 is the expected normal value
+ * @return found node or NULL if the key was not found in the tree
+ */
+PSplaynode
+psplay_find (PSplay self, const void* key, int splayfactor);
+
+
+/**
+ * Remove a node from a splay tree
+ * @param self pointer to the splay tree
+ * @param node node to be removed
+ * @return pointer to the removed node
+ * removal is optimized for the case where one call it immediately after one did a
+ * psplay_find() as last operation on that tree
+ */
+PSplaynode
+psplay_remove (PSplay self, PSplaynode node);
+
+
+/**
+ * Remove a node by key from a splay tree
+ * @param self pointer to the splay tree
+ * @param key key of the node to be removed
+ * @return pointer to the removed node
+ */
+PSplaynode
+psplay_remove_key (PSplay self, void* key);
+
+
+/**
+ * Delete a node from a splay tree
+ * @param self pointer to the splay tree
+ * @param node node to be removed
+ * Calls the registered delete handler, frees all resources.
+ */
+void
+psplay_delete_node (PSplay self, PSplaynode node);
+
+
+/**
+ * Delete a node by key from a splay tree
+ * @param self pointer to the splay tree
+ * @param key key of the node to be removed
+ * Calls the registered delete handler, frees all resources.
+ */
+void
+psplay_delete_key (PSplay self, void* key);
+
+
+enum psplay_order_enum
+ {
+ PSPLAY_PREORDER,
+ PSPLAY_INORDER,
+ PSPLAY_POSTORDER
+ };
+
+/**
+ * Traverse a splay tree
+ * Traversing a tree calls a user supplied action three times
+ * An 'action' must not alter the tree itself but it can indicate aborting the tree traversal and
+ * how the current node is handled by its return value.
+ * @param node pointer to the currently traversed node
+ * @param which state of the traversal:
+ * PSPLAY_PREORDER before visiting the left subtree,
+ * PSPLAY_INORDER after visiting the left subtree and before the right subtree
+ * PSPLAY_POSTORDER finally after visiting the right subtree.
+ * Example: For to traverse the tree in order action would only handle PSPLAY_INORDER.
+ * This action shall return PSPLAY_CONT when the traversal of the tree shall continue.
+ * @param level depth of the node in the tree
+ * @param data user supplied data which is transparently passed around
+ * @return a pointer to a function which indicates how to proceed, there are three special
+ * return values predefined:
+ * PSPLAY_CONT - continue with the traversal
+ * PSPLAY_STOP - stop the traversal
+ * PSPLAY_REMOVE - stops the traversal and removes the current node, calling the delete handler
+ * any other psplay_delete_fn - stops the traversal and removes the current node, calling the returned delete handler with it
+ */
+typedef psplay_delete_fn (*psplay_action_fn)(PSplaynode node, const enum psplay_order_enum which, int level, void* data);
+
+extern const psplay_delete_fn PSPLAY_CONT;
+extern const psplay_delete_fn PSPLAY_STOP;
+extern const psplay_delete_fn PSPLAY_REMOVE;
+
+/**
+ * Start a tree traversal
+ * @param self the tree to be traversed
+ * @param node pointer to root node where traversal shall start, use NULL for the whole tree
+ * @param action handler function as defined above
+ * @param level initial value for the level
+ * @param data user supplied data which is transparently passed to the action
+ * @return 0 when the tree traversal got aborted (by anything but PSPLAY_CONT as action handler return)
+ * 1 when the whole tree was traversed successfully
+ */
+int
+psplay_walk (PSplay self, PSplaynode node, psplay_action_fn action, int level, void* data);
+
+
+void
+psplay_dump (PSplay self, FILE* dest);
+
+#endif
+/*
+// Local Variables:
+// mode: C
+// c-file-style: "gnu"
+// indent-tabs-mode: nil
+// End:
+*/
diff --git a/src/lib/references.c b/src/lib/references.c
deleted file mode 100644
index 925258377..000000000
--- a/src/lib/references.c
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- references.c - strong and weak references
-
- Copyright (C) Lumiera.org
- 2008, Christian Thaeter
-
- 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 2 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, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-#include "lib/references.h"
-#include "lib/safeclib.h"
-
-/**
- * @file
- * Strong and Weak references
- * Strong references keep some object alive while they existing
- * Weak references become invalidated when the referenced object gets destroyed
- *
- * Thread safety: references protect their internal operations with a mutex (optimization using futex may come in future)
- * while operations on the reference itself (initialization, destruction, strengthen, weaken) and on the referenced object (get)
- * should be protected from elsewhere.
- */
-
-
-/**
- * Construct an initial strong reference from an object.
- * For every object which should be managed with references you need to construct an initial strong reference
- * which then will be used to initialize all further references.
- * @param self pointer to the reference to be initialized
- * @param obj pointer to the object being referenced
- * @param dtor destructor function which will be called on obj when the last strong reference gets deleted
- * @return self as given
- */
-LumieraReference
-lumiera_reference_strong_init_once (LumieraReference self, void* obj, void (*dtor)(void*))
-{
- LumieraReftarget target = lumiera_malloc (sizeof(lumiera_reftarget));
-
- target->object = obj;
- target->dtor = dtor;
- target->strong_cnt = 1;
- target->weak_cnt = 0;
- lumiera_mutex_init (&target->lock);
-
- self->object = obj;
- self->target = target;
- return self;
-}
-
-/**
- * Destroy a reference.
- * All references need to be destroyed when not used any more.
- * When the last strong reference gets destroyed, the object's destructor is called.
- * Remaining weak references stay invalidated then until they get destroyed too.
- * @param self reference to be destroyed
- * @return self as given
- * destroying a reference is not thread safe as far as 2 threads try to concurrently destroy it!
- */
-LumieraReference
-lumiera_reference_destroy (LumieraReference self)
-{
- LumieraReftarget target = self->target;
-
- /* defensive, lets detect errors if anything still tries to use this reference */
- self->target = NULL;
-
- lumiera_mutexacquirer lock;
- lumiera_mutexacquirer_init_mutex (&lock, &target->lock, LUMIERA_LOCKED);
-
- if (self->object)
- {
- /* strong reference */
- if (!--target->strong_cnt)
- {
- /* was last strong reference */
- if (target->dtor)
- target->dtor (target->object);
- target->object = NULL;
- if (!target->weak_cnt)
- {
- /* no weak refs either, destroy it */
- lumiera_mutexacquirer_unlock (&lock);
- lumiera_mutex_destroy (&target->lock);
- free (target);
- return self;
- }
- }
- }
- else
- {
- /* weak reference */
- if (!--target->weak_cnt && !target->strong_cnt)
- {
- /* was last weak reference, and no strong refs left */
- lumiera_mutexacquirer_unlock (&lock);
- lumiera_mutex_destroy (&target->lock);
- free (target);
- return self;
- }
- }
- lumiera_mutexacquirer_unlock (&lock);
- return self;
-}
-
-/**
- * Copy construct a reference as strong reference
- * @param source reference to copy
- * @return self as strong reference (always for strong references) or NULL if source is an invalidated weak reference,
- * in the later case the reference is constructed as weak reference barely to allow it be destroyed
- */
-LumieraReference
-lumiera_reference_strong_init (LumieraReference self, LumieraReference source)
-{
- lumiera_mutexacquirer lock;
- lumiera_mutexacquirer_init_mutex (&lock, &source->target->lock, LUMIERA_LOCKED);
-
- self->object = source->target->object;
- self->target = source->target;
-
- if (self->object)
- {
- ++self->target->strong_cnt;
- }
- else
- {
- ++self->target->weak_cnt;
- self = NULL;
- }
- lumiera_mutexacquirer_unlock (&lock);
- return self;
-}
-
-/**
- * Copy construct a reference as weak reference
- * @param source reference to copy
- * @return self (always for strong references) or NULL if self is an invalidated weak reference
- */
-LumieraReference
-lumiera_reference_weak_init (LumieraReference self, LumieraReference source)
-{
- lumiera_mutexacquirer lock;
- lumiera_mutexacquirer_init_mutex (&lock, &source->target->lock, LUMIERA_LOCKED);
-
- self->object = NULL;
- self->target = source->target;
-
- ++self->target->weak_cnt;
- if (!self->target->object)
- /* already invalidated */
- self = NULL;
-
- lumiera_mutexacquirer_unlock (&lock);
- return self;
-}
-
-/**
- * turn a (strong) reference into a weak reference
- * Weaken a reference may remove its last strong reference and thus destroy the object
- * do nothing if the referene is already weak
- * @return self or NULL if the final strong reference got removed,
- */
-LumieraReference
-lumiera_reference_weaken (restrict LumieraReference self)
-{
- /* is this a strong reference? */
- if (self->object)
- {
- lumiera_mutexacquirer lock;
- lumiera_mutexacquirer_init_mutex (&lock, &self->target->lock, LUMIERA_LOCKED);
-
- self->object = NULL;
- ++self->target->weak_cnt;
- if (!--self->target->strong_cnt)
- {
- if (self->target->dtor)
- self->target->dtor (self->target->object);
- self->target->object = NULL;
- self = NULL;
- }
- lumiera_mutexacquirer_unlock (&lock);
- }
- return self;
-}
-
-
-/**
- * turn a (weak) reference into a strong reference
- * only references of object which are not already destroyed can be strengthened
- * @return self when successful, NULL when the object was already destroyed, 'self' stays a dead weak reference in that case
- */
-LumieraReference
-lumiera_reference_strengthen (LumieraReference self)
-{
- /* is this a weak reference? */
- if (!self->object)
- {
- lumiera_mutexacquirer lock;
- lumiera_mutexacquirer_init_mutex (&lock, &self->target->lock, LUMIERA_LOCKED);
-
- if (self->target->object)
- {
- self->object = self->target->object;
- --self->target->weak_cnt;
- ++self->target->strong_cnt;
- }
- else
- self = NULL;
- lumiera_mutexacquirer_unlock (&lock);
- }
- return self;
-}
-
diff --git a/src/lib/references.h b/src/lib/references.h
deleted file mode 100644
index 6ad65d62f..000000000
--- a/src/lib/references.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- references.h - strong and weak references
-
- Copyright (C) Lumiera.org
- 2008, Christian Thaeter
-
- 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 2 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, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#ifndef LUMIERA_REFERENCES_H
-#define LUMIERA_REFERENCES_H
-
-#include
-
-/**
- * @file
- * Strong and Weak references, header.
- */
-
-
-typedef struct lumiera_reference_struct lumiera_reference;
-typedef lumiera_reference* LumieraReference;
-
-#include "lib/error.h"
-#include "lib/mutex.h"
-
-/* Implementation detail */
-struct lumiera_reftarget_struct
-{
- void* object;
- void (*dtor)(void*);
- unsigned strong_cnt; /*when strong becomes 0 obj is destroyed, if weak is 0 destroy target too*/
- unsigned weak_cnt; /*when weak becomes 0 and !obj and lock strong is 0, destroy target */
- lumiera_mutex lock;
-};
-typedef struct lumiera_reftarget_struct lumiera_reftarget;
-typedef lumiera_reftarget* LumieraReftarget;
-
-
-/**
- * A reference pointing to some other object
- */
-struct lumiera_reference_struct
-{
- void* object; /*set for strong, NULL for weak*/
- LumieraReftarget target;
-};
-
-#define lumiera_reference \
-lumiera_reference NOBUG_CLEANUP(lumiera_reference_ensuredestroyed)
-
-/* helper function for nobug */
-static inline void
-lumiera_reference_ensuredestroyed (LumieraReference self)
-{
- ENSURE (!self->target, "forgot to destroy reference");
-}
-
-
-LumieraReference
-lumiera_reference_strong_init_once (LumieraReference self, void* obj, void (*dtor)(void*));
-
-
-LumieraReference
-lumiera_reference_destroy (LumieraReference self);
-
-/**
- * Get object from a strong reference.
- * @return pointer to object, NULL if applied to a weak reference
- */
-static inline void*
-lumiera_reference_get (LumieraReference self)
-{
- ENSURE (self->target, "illegal reference (not initialized or already destroyed?)");
- return self->object;
-}
-
-
-LumieraReference
-lumiera_reference_strong_init (LumieraReference self, LumieraReference source);
-
-
-LumieraReference
-lumiera_reference_weak_init (LumieraReference self, LumieraReference source);
-
-
-LumieraReference
-lumiera_reference_weaken (restrict LumieraReference self);
-
-
-LumieraReference
-lumiera_reference_strengthen (LumieraReference self);
-
-#endif
diff --git a/src/lib/rwlock.c b/src/lib/rwlock.c
index 077ff9766..c5287d535 100644
--- a/src/lib/rwlock.c
+++ b/src/lib/rwlock.c
@@ -18,161 +18,52 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include
+
+#include "lib/error.h"
#include "lib/rwlock.h"
+
LUMIERA_ERROR_DEFINE(RWLOCK_AGAIN, "maximum number of readlocks exceed");
LUMIERA_ERROR_DEFINE(RWLOCK_DEADLOCK, "deadlock detected");
-LUMIERA_ERROR_DEFINE(RWLOCK_DESTROY, "destroy rwlock");
-LUMIERA_ERROR_DEFINE(RWLOCK_UNLOCK, "unlock");
-LUMIERA_ERROR_DEFINE(RWLOCK_RLOCK, "rlock");
-LUMIERA_ERROR_DEFINE(RWLOCK_WLOCK, "wlock");
+LUMIERA_ERROR_DEFINE(RWLOCK_DESTROY, "destroying rwlock");
+LUMIERA_ERROR_DEFINE(RWLOCK_UNLOCK, "unlock rwlock failed");
+LUMIERA_ERROR_DEFINE(RWLOCK_RDLOCK, "locking rwlock for reading failed");
+LUMIERA_ERROR_DEFINE(RWLOCK_WRLOCK, "locking rwlock for writing failed");
/**
* @file
* Read/write locks.
*/
-
-/**
- * Initialize a rwlock
- * @param self is a pointer to the rwlock to be initialized
- * @return self as given
- */
LumieraRWLock
-lumiera_rwlock_init (LumieraRWLock self)
+lumiera_rwlock_init (LumieraRWLock self, const char* purpose, struct nobug_flag* flag)
{
if (self)
{
pthread_rwlock_init (&self->rwlock, NULL);
+ NOBUG_RESOURCE_HANDLE_INIT (self->rh);
+ NOBUG_RESOURCE_ANNOUNCE_RAW (flag, "rwlock", purpose, self, self->rh);
}
return self;
}
-/**
- * destroy a rwlock
- * @param self is a pointer to the rwlock to be initialized
- * @return self on success or NULL at error
- */
+
LumieraRWLock
-lumiera_rwlock_destroy (LumieraRWLock self)
+lumiera_rwlock_destroy (LumieraRWLock self, struct nobug_flag* flag)
{
if (self)
{
+ NOBUG_RESOURCE_FORGET_RAW (flag, self->rh);
if (pthread_rwlock_destroy (&self->rwlock))
LUMIERA_DIE (RWLOCK_DESTROY);
}
return self;
}
-
-
-
-/**
- * initialize a rwlockacquirer state
- * @param self rwlockacquirer to be initialized, must be an automatic variable
- * @param rwlock associated rwlock
- * @param state initial state of the mutex, either LUMIERA_RDLOCKED, LUMIERA_WRLOCKED or LUMIERA_UNLOCKED
- * @return self as given or NULL on error
- */
-LumieraRWLockacquirer
-lumiera_rwlockacquirer_init (LumieraRWLockacquirer self, LumieraRWLock rwlock, enum lumiera_lockstate state)
-{
- REQUIRE (self);
- REQUIRE (rwlock);
- REQUIRE (state != LUMIERA_LOCKED, "illegal state for rwlock");
- self->rwlock = rwlock;
- self->state = state;
-
- switch (state)
- {
- case LUMIERA_RDLOCKED:
- switch (pthread_rwlock_rdlock (&rwlock->rwlock))
- {
- case 0:
- break;
- case EAGAIN:
- lumiera_error_set (LUMIERA_ERROR_RWLOCK_AGAIN);
- return NULL;
- case EDEADLK:
- lumiera_error_set (LUMIERA_ERROR_RWLOCK_DEADLOCK);
- return NULL;
- default:
- LUMIERA_DIE (RWLOCK_RLOCK);
- }
- case LUMIERA_WRLOCKED:
- switch (pthread_rwlock_wrlock (&rwlock->rwlock))
- {
- case 0:
- break;
- case EDEADLK:
- lumiera_error_set (LUMIERA_ERROR_RWLOCK_DEADLOCK);
- return NULL;
- default:
- LUMIERA_DIE (RWLOCK_WLOCK);
- }
- default:
- break;
- }
- return self;
-}
-
-
-/**
- * readlock the rwlock.
- * must not already be locked
- * @param self rwlockacquirer associated with a rwlock
- * @return self as given or NULL on error
- */
-LumieraRWLockacquirer
-lumiera_rwlockacquirer_rdlock (LumieraRWLockacquirer self)
-{
- REQUIRE (self);
- REQUIRE (self->state == LUMIERA_UNLOCKED, "rwlock already locked");
-
- switch (pthread_rwlock_rdlock (&self->rwlock->rwlock))
- {
- case 0:
- break;
- case EAGAIN:
- lumiera_error_set (LUMIERA_ERROR_RWLOCK_AGAIN);
- return NULL;
- case EDEADLK:
- lumiera_error_set (LUMIERA_ERROR_RWLOCK_DEADLOCK);
- return NULL;
- default:
- LUMIERA_DIE (RWLOCK_RLOCK);
- }
-
- self->state = LUMIERA_RDLOCKED;
- return self;
-}
-
-
-/**
- * writelock the rwlock.
- * must not already be locked
- * @param self rwlockacquirer associated with a rwlock
- * @return self as given or NULL on error
- */
-LumieraRWLockacquirer
-lumiera_rwlockacquirer_wrlock (LumieraRWLockacquirer self)
-{
- REQUIRE (self);
- REQUIRE (self->state == LUMIERA_UNLOCKED, "rwlock already locked");
-
- switch (pthread_rwlock_wrlock (&self->rwlock->rwlock))
- {
- case 0:
- break;
- case EDEADLK:
- lumiera_error_set (LUMIERA_ERROR_RWLOCK_DEADLOCK);
- return NULL;
- default:
- LUMIERA_DIE (RWLOCK_WLOCK);
- }
-
- self->state = LUMIERA_WRLOCKED;
- return self;
-}
-
+/*
+// Local Variables:
+// mode: C
+// c-file-style: "gnu"
+// indent-tabs-mode: nil
+// End:
+*/
diff --git a/src/lib/rwlock.h b/src/lib/rwlock.h
index d58627dda..23376979b 100644
--- a/src/lib/rwlock.h
+++ b/src/lib/rwlock.h
@@ -29,14 +29,12 @@
#include
#include
-#include "lib/locking.h"
-
LUMIERA_ERROR_DECLARE(RWLOCK_AGAIN);
LUMIERA_ERROR_DECLARE(RWLOCK_DEADLOCK);
LUMIERA_ERROR_DECLARE(RWLOCK_DESTROY);
LUMIERA_ERROR_DECLARE(RWLOCK_UNLOCK);
-LUMIERA_ERROR_DECLARE(RWLOCK_RLOCK);
-LUMIERA_ERROR_DECLARE(RWLOCK_WLOCK);
+LUMIERA_ERROR_DECLARE(RWLOCK_RDLOCK);
+LUMIERA_ERROR_DECLARE(RWLOCK_WRLOCK);
/**
* @file
@@ -44,6 +42,56 @@ LUMIERA_ERROR_DECLARE(RWLOCK_WLOCK);
*/
+/**
+ * Read locked section.
+ */
+#define LUMIERA_RDLOCK_SECTION(nobugflag, rwlck) \
+ for (lumiera_rwlockacquirer NOBUG_CLEANUP(lumiera_rwlockacquirer_ensureunlocked) lumiera_rwlock_section_ = {(LumieraRWLock)1}; \
+ lumiera_rwlock_section_.rwlock;) \
+ for ( \
+ ({ \
+ lumiera_rwlock_section_.rwlock = (rwlck); \
+ NOBUG_RESOURCE_HANDLE_INIT (lumiera_rwlock_section_.rh); \
+ RESOURCE_ENTER (nobugflag, (rwlck)->rh, "acquire rwlock for reading", &lumiera_rwlock_section_, \
+ NOBUG_RESOURCE_EXCLUSIVE, lumiera_rwlock_section_.rh); \
+ if (pthread_rwlock_rdlock (&(rwlck)->rwlock)) LUMIERA_DIE (RWLOCK_RDLOCK); \
+ }); \
+ lumiera_rwlock_section_.rwlock; \
+ ({ \
+ if (lumiera_rwlock_section_.rwlock) \
+ { \
+ pthread_rwlock_unlock (&lumiera_rwlock_section_.rwlock->rwlock); \
+ lumiera_rwlock_section_.rwlock = NULL; \
+ RESOURCE_LEAVE(nobugflag, lumiera_rwlock_section_.rh); \
+ } \
+ }))
+
+
+/**
+ * Write locked section.
+ */
+#define LUMIERA_WRLOCK_SECTION(nobugflag, rwlck) \
+ for (lumiera_rwlockacquirer NOBUG_CLEANUP(lumiera_rwlockacquirer_ensureunlocked) lumiera_rwlock_section_ = {(LumieraRWLock)1}; \
+ lumiera_rwlock_section_.rwlock;) \
+ for ( \
+ ({ \
+ lumiera_rwlock_section_.rwlock = (rwlck); \
+ NOBUG_RESOURCE_HANDLE_INIT (lumiera_rwlock_section_.rh); \
+ RESOURCE_ENTER (nobugflag, (rwlck)->rh, "acquire rwlock for reading", &lumiera_rwlock_section_, \
+ NOBUG_RESOURCE_EXCLUSIVE, lumiera_rwlock_section_.rh); \
+ if (pthread_rwlock_wrlock (&(rwlck)->rwlock)) LUMIERA_DIE (RWLOCK_WRLOCK); \
+ }); \
+ lumiera_rwlock_section_.rwlock; \
+ ({ \
+ if (lumiera_rwlock_section_.rwlock) \
+ { \
+ pthread_rwlock_unlock (&lumiera_rwlock_section_.rwlock->rwlock); \
+ lumiera_rwlock_section_.rwlock = NULL; \
+ RESOURCE_LEAVE(nobugflag, lumiera_rwlock_section_.rh); \
+ } \
+ }))
+
+
/**
* RWLock.
*
@@ -51,17 +99,27 @@ LUMIERA_ERROR_DECLARE(RWLOCK_WLOCK);
struct lumiera_rwlock_struct
{
pthread_rwlock_t rwlock;
+ RESOURCE_HANDLE (rh);
};
typedef struct lumiera_rwlock_struct lumiera_rwlock;
typedef lumiera_rwlock* LumieraRWLock;
-
+/**
+ * Initialize a rwlock
+ * @param self is a pointer to the rwlock to be initialized
+ * @return self as given
+ */
LumieraRWLock
-lumiera_rwlock_init (LumieraRWLock self);
-
+lumiera_rwlock_init (LumieraRWLock self, const char* purpose, struct nobug_flag* flag);
+/**
+ * destroy a rwlock
+ * @param self is a pointer to the rwlock to be initialized
+ * @return self on success or NULL at error
+ */
LumieraRWLock
-lumiera_rwlock_destroy (LumieraRWLock self);
+lumiera_rwlock_destroy (LumieraRWLock self, struct nobug_flag* flag);
+
@@ -72,7 +130,7 @@ lumiera_rwlock_destroy (LumieraRWLock self);
struct lumiera_rwlockacquirer_struct
{
LumieraRWLock rwlock;
- enum lumiera_lockstate state;
+ RESOURCE_HANDLE (rh);
};
typedef struct lumiera_rwlockacquirer_struct lumiera_rwlockacquirer;
typedef struct lumiera_rwlockacquirer_struct* LumieraRWLockacquirer;
@@ -81,39 +139,15 @@ typedef struct lumiera_rwlockacquirer_struct* LumieraRWLockacquirer;
static inline void
lumiera_rwlockacquirer_ensureunlocked (LumieraRWLockacquirer self)
{
- ENSURE (self->state == LUMIERA_UNLOCKED, "forgot to unlock the rwlock mutex");
-}
-
-/* override with a macro to use the cleanup checker */
-#define lumiera_rwlockacquirer \
-lumiera_rwlockacquirer NOBUG_CLEANUP(lumiera_rwlockacquirer_ensureunlocked)
-
-
-LumieraRWLockacquirer
-lumiera_rwlockacquirer_init (LumieraRWLockacquirer self, LumieraRWLock rwlock, enum lumiera_lockstate state);
-
-LumieraRWLockacquirer
-lumiera_rwlockacquirer_rdlock (LumieraRWLockacquirer self);
-
-
-LumieraRWLockacquirer
-lumiera_rwlockacquirer_wrlock (LumieraRWLockacquirer self);
-
-
-/**
- * release rwlock.
- * a rwlockacquirer must be unlocked before leaving scope
- * @param self rwlockacquirer associated with a rwlock variable
- */
-static inline void
-lumiera_rwlockacquirer_unlock (LumieraRWLockacquirer self)
-{
- REQUIRE (self);
- REQUIRE (self->state != LUMIERA_UNLOCKED, "rwlock was not locked");
- if (pthread_rwlock_unlock (&self->rwlock->rwlock))
- LUMIERA_DIE (RWLOCK_UNLOCK);
- self->state = LUMIERA_UNLOCKED;
+ ENSURE (!self->rwlock, "forgot to unlock rwlock");
}
#endif
+/*
+// Local Variables:
+// mode: C
+// c-file-style: "gnu"
+// indent-tabs-mode: nil
+// End:
+*/
diff --git a/src/lib/safeclib.c b/src/lib/safeclib.c
index f500ea71c..1c5cf28c6 100644
--- a/src/lib/safeclib.c
+++ b/src/lib/safeclib.c
@@ -18,27 +18,19 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include "error.h"
+#include "lib/error.h"
+#include "lib/safeclib.h"
#include
#include
#include
#include
#include
+#include
-/**
- * @file
- * Portable and safe wrapers around some clib functions and some tools
- */
LUMIERA_ERROR_DEFINE (NO_MEMORY, "Out of Memory!");
-/**
- * Allocate memory.
- * always succeeds or dies
- * @param size memory to be allocated
- * @return pointer to the allocated memory
- */
void*
lumiera_malloc (size_t size)
{
@@ -49,13 +41,6 @@ lumiera_malloc (size_t size)
}
-/**
- * Allocate cleared memory for an array.
- * always succeeds or dies
- * @param n number of elements
- * @param size memory to be allocated
- * @return pointer to the allocated memory
- */
void*
lumiera_calloc (size_t n, size_t size)
{
@@ -66,13 +51,6 @@ lumiera_calloc (size_t n, size_t size)
}
-/**
- * Duplicate a C string.
- * always succeeds or dies
- * @param str string to be copied
- * @param len maximal length to be copied
- * @return pointer to the new string, "" if NULL was passed as str
- */
char*
lumiera_strndup (const char* str, size_t len)
{
@@ -88,14 +66,6 @@ lumiera_strndup (const char* str, size_t len)
}
-/**
- * Compare two C strings.
- * Handles NULL pointers as "", shortcut for same addresses
- * @param a first string for comparsion
- * @param b second string for comparsion
- * @param len maximal length for the comparsion
- * @return 0 if the strings are identical, -1 if smaller 1 if bigger.
- */
int
lumiera_strncmp (const char* a, const char* b, size_t len)
{
@@ -103,12 +73,6 @@ lumiera_strncmp (const char* a, const char* b, size_t len)
}
-/**
- * check 2 strings for identity.
- * @param a first string for comparsion
- * @param b second string for comparsion
- * @return 1 when the strings are the the same, 0 if not.
- */
int
lumiera_streq (const char* a, const char* b)
{
@@ -116,11 +80,6 @@ lumiera_streq (const char* a, const char* b)
}
-/**
- * Round robin temporary buffers.
- * This provides 64 buffers per thread which are recycled with each use.
- * The idea here is to have fast buffers for temporal data without need for explicit heap management.
- */
struct lumiera_tmpbuf_struct
{
void* buffers[64];
@@ -144,13 +103,10 @@ static void
lumiera_tmpbuf_init (void)
{
pthread_key_create (&lumiera_tmpbuf_tls_key, lumiera_tmpbuf_destroy);
+ TODO ("register an atexit() handler to free tmpbufs");
}
-/**
- * free all buffers associated with this thread.
- * This function is called automatically, usually one doesnt need to call it.
- */
void
lumiera_tmpbuf_freeall (void)
{
@@ -160,17 +116,12 @@ lumiera_tmpbuf_freeall (void)
{
pthread_setspecific (lumiera_tmpbuf_tls_key, NULL);
for (int idx = 0; idx < 64; ++idx)
- free (buf->buffers[idx]);
- free (buf);
+ lumiera_free (buf->buffers[idx]);
+ lumiera_free (buf);
}
}
-/**
- * Query a thread local buffer.
- * @param size minimal needed size for the buffer
- * @return the buffer
- */
void*
lumiera_tmpbuf_provide (size_t size)
{
@@ -184,7 +135,7 @@ lumiera_tmpbuf_provide (size_t size)
if (buf->sizes[buf->idx] < size || buf->sizes[buf->idx] > 8*size)
{
- free (buf->buffers[buf->idx]);
+ lumiera_free (buf->buffers[buf->idx]);
buf->sizes[buf->idx] = (size+4*sizeof(long)) & ~(4*sizeof(long)-1);
buf->buffers[buf->idx] = lumiera_malloc (buf->sizes[buf->idx]);
}
@@ -223,3 +174,49 @@ lumiera_tmpbuf_snprintf (size_t size, const char* fmt, ...)
return buf;
}
+
+
+char*
+lumiera_tmpbuf_strcat3 (const char* str1, size_t str1_len,
+ const char* str2, size_t str2_len,
+ const char* str3, size_t str3_len)
+{
+ return lumiera_tmpbuf_snprintf (SIZE_MAX, "%.*s%s%.*s%s%.*s",
+ str1?str1_len:0, str1?str1:"", str1?".":"",
+ str2?str2_len:0, str2?str2:"",
+ str3?".":"", str3?str3_len:0, str3?str3:"");
+}
+
+
+char*
+lumiera_tmpbuf_tr (const char* in, const char* from, const char* to, const char* def)
+{
+ REQUIRE (strlen (from) == strlen (to), "from and to character set must have equal length");
+
+ char* ret = lumiera_tmpbuf_strndup (in, SIZE_MAX);
+
+ char* wpos;
+ char* rpos;
+ for (wpos = rpos = ret; *rpos; ++rpos, ++wpos)
+ {
+ char* found = strchr (from, *rpos);
+ if (found)
+ *wpos = to[found-from];
+ else if (def)
+ {
+ if (*def)
+ *wpos = *def;
+ else
+ {
+ ++rpos;
+ if (!*rpos)
+ break;
+ }
+ }
+ else
+ return NULL;
+ }
+ *wpos = '\0';
+
+ return ret;
+}
diff --git a/src/lib/safeclib.h b/src/lib/safeclib.h
index 6fc532239..79f10d024 100644
--- a/src/lib/safeclib.h
+++ b/src/lib/safeclib.h
@@ -50,6 +50,18 @@ void*
lumiera_calloc (size_t n, size_t size);
+/**
+ * Free previously allocated memory.
+ * @param mem pointer to the memory block obtained by lumiera_malloc or lumiera_calloc
+ */
+static inline void
+lumiera_free (void* mem)
+{
+ /* for now only a alias, might change in future */
+ free (mem);
+}
+
+
/**
* Duplicate a C string.
* always succeeds or dies
@@ -123,3 +135,33 @@ lumiera_tmpbuf_strndup (const char* src, size_t size);
char*
lumiera_tmpbuf_snprintf (size_t size, const char* fmt, ...);
+
+/**
+ * Concat up to 3 strings in a tmpbuf.
+ * @param str1 first string to concat or NULL
+ * @param str1_len how much of the first string shall be used
+ * @param str2 second string to concat or NULL
+ * @param str2_len how much of the second string shall be used
+ * @param str3 third string to concat or NULL
+ * @param str3_len how much of the third string shall be used
+ * @return temporary buffer containing the constructed of the string
+ */
+char*
+lumiera_tmpbuf_strcat3 (const char* str1, size_t str1_len,
+ const char* str2, size_t str2_len,
+ const char* str3, size_t str3_len);
+
+/**
+ * Translates characters in a string, similar to the shell 'tr' utility
+ * @param in input string to be translated
+ * @param from source character set
+ * @param to destination character set
+ * @param def default destination character when a character is not in the source set,
+ * when NULL then translation will abort on unknown characters and return NULL,
+ * when "" then unknown characters will be removed
+ * when set to a single character string, unknown characters will be replaced with this string
+ * @return temporary buffer containing the constructed of the string
+ */
+char*
+lumiera_tmpbuf_tr (const char* in, const char* from, const char* to, const char* def);
+
diff --git a/src/lib/uuid.c b/src/lib/uuid.c
deleted file mode 100644
index d4eee69be..000000000
--- a/src/lib/uuid.c
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- uuid - Universal unique identifiers
-
- Copyright (C) CinelerraCV
- 2008, Christian Thaeter
-
- 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 2 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, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include "lib/uuid.h"
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-void
-lumiera_uuid_set_ptr (lumiera_uuid* uuid, void* ptr)
-{
- memset (uuid, 0, 16);
- *(void**)uuid = ptr;
-}
-
-
-void*
-lumiera_uuid_ptr_get (lumiera_uuid* uuid)
-{
- return *(void**)uuid;
-}
-
-
-void
-lumiera_uuid_gen (lumiera_uuid* uuid)
-{
- static int fd = -2;
- if (!uuid)
- return;
-
- if (fd == -2)
- {
- fd = open ("/dev/urandom", O_RDONLY);
- if (fd == -1)
- fd = open ("/dev/random", O_RDONLY);
- if (fd >= 0)
- fcntl (fd, F_SETFD, FD_CLOEXEC);
- else
- srand (getpid () + time (NULL));
- }
- if (fd < 0)
- {
- for (int i = 0; i < 16; ++i)
- ((unsigned char*)uuid)[i] = (unsigned char)(rand()>>7);
- }
- else
- {
- if (read (fd, uuid, 16) < 0)
- abort ();
- }
-}
-
-
-void
-lumiera_uuid_copy (lumiera_uuid* dest, lumiera_uuid* src)
-{
- memcpy (dest, src, 16);
-}
-
-
-int
-lumiera_uuid_eq (lumiera_uuid* uuida, lumiera_uuid* uuidb)
-{
- return !memcmp (uuida, uuidb, 16);
-}
-
-size_t
-lumiera_uuid_hash (lumiera_uuid* uuid)
-{
- return *(size_t*)uuid;
-}
-
-
diff --git a/src/lib/uuid.h b/src/lib/uuid.h
deleted file mode 100644
index d4cf8ce9d..000000000
--- a/src/lib/uuid.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- uuid - Universal unique identifiers
-
- Copyright (C) CinelerraCV
- 2008, Christian Thaeter
-
- 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 2 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, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-#ifndef LUMIERA_UUID_H
-#define LUMIERA_UUID_H
-
-#include
-
-typedef unsigned char lumiera_uuid[16];
-
-/**
- * Retrieve a generic pointer stored in a uuid
- */
-void*
-lumiera_uuid_ptr_get (lumiera_uuid* uuid);
-
-/**
- * Generate a new uuid
- */
-void
-lumiera_uuid_gen (lumiera_uuid* uuid);
-
-/**
- * Store a generic pointer in a uuid
- */
-void
-lumiera_uuid_set_ptr (lumiera_uuid* uuid, void* ptr);
-
-
-/**
- * Copy an uuid
- */
-void
-lumiera_uuid_copy (lumiera_uuid* dest, lumiera_uuid* src);
-
-
-/**
- * Test 2 uuid's for equality
- */
-int
-lumiera_uuid_eq (lumiera_uuid* uuida, lumiera_uuid* uuidb);
-
-
-/**
- * Generate a hashsum over an uuid
- */
-size_t
-lumiera_uuid_hash (lumiera_uuid* uuid);
-
-#endif
diff --git a/src/proc/asset/category.cpp b/src/proc/asset/category.cpp
index dcb767ccf..3d178e549 100644
--- a/src/proc/asset/category.cpp
+++ b/src/proc/asset/category.cpp
@@ -38,7 +38,9 @@ namespace asset
*/
Category::operator string () const
{
- char *kinds[6] = { "AUDIO"
+ typedef const char * const SymID;
+
+ SymID kinds[6] = { "AUDIO"
, "VIDEO"
, "EFFECT"
, "CODEC"
diff --git a/src/proc/mobject/session/defsregistry.hpp b/src/proc/mobject/session/defsregistry.hpp
index 64f84ab32..73925e11a 100644
--- a/src/proc/mobject/session/defsregistry.hpp
+++ b/src/proc/mobject/session/defsregistry.hpp
@@ -53,6 +53,7 @@ namespace mobject
using boost::lambda::var;
namespace // Implementation details //////////////////TODO better a named implementation namespace (avoids warnings on gcc 4.3)
+//////////////////////////////////////////////////////////FIXME this is a *real* problem, because this namespace create storage, which it shouldn't
{
struct TableEntry
{
diff --git a/src/tool/Makefile.am b/src/tool/Makefile.am
new file mode 100644
index 000000000..69c4a7f25
--- /dev/null
+++ b/src/tool/Makefile.am
@@ -0,0 +1,28 @@
+# Copyright (C) Lumiera.org
+# 2008 Christian Thaeter
+#
+# 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 2 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, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+lumitool_srcdir = $(top_srcdir)/src/tool
+
+noinst_PROGRAMS += luidgen
+
+luidgen_CFLAGS = $(CFLAGS) -std=gnu99 -Wall -Werror
+luidgen_CPPFLAGS = -I$(top_srcdir)/src/
+luidgen_SOURCES = \
+ $(lumitool_srcdir)/luidgen.c
+
+luidgen_LDADD = liblumi.a
+
diff --git a/tests/locking/test-locking.c b/src/tool/luidgen.c
similarity index 60%
rename from tests/locking/test-locking.c
rename to src/tool/luidgen.c
index b37c2c07f..41081ca97 100644
--- a/tests/locking/test-locking.c
+++ b/src/tool/luidgen.c
@@ -1,8 +1,8 @@
/*
- test-locking.c - test locking functions
+ luidgen.c - generate a lumiera uuid
Copyright (C) Lumiera.org
- 2008, Christian Thaeter
+ 2008 Christian Thaeter
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -19,23 +19,33 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include "lib/luid.h"
+
#include
-#include
-#include "tests/test.h"
-int conditionforgotunlock ();
-int mutexforgotunlock ();
+/**
+ * @file
+ * Generate amd print a Lumiera uid as octal escaped string
+ */
-TESTS_BEGIN
-
-TEST ("conditionforgotunlock")
+int
+main (int argc, char** argv)
{
- return conditionforgotunlock ();
+ lumiera_uid luid;
+ lumiera_uid_gen (&luid);
+
+ printf ("\"");
+ for (int i = 0; i < 16; ++i)
+ printf ("\\%.3hho", *(((char*)&luid)+i));
+ printf ("\"\n");
+
+ return 0;
}
-TEST ("mutexforgotunlock")
-{
- return mutexforgotunlock ();
-}
-
-TESTS_END
+/*
+// Local Variables:
+// mode: C
+// c-file-style: "gnu"
+// indent-tabs-mode: nil
+// End:
+*/
diff --git a/tests/15list.tests b/tests/15list.tests
index 88aef3c49..e04044f27 100644
--- a/tests/15list.tests
+++ b/tests/15list.tests
@@ -44,9 +44,11 @@ out: .
out: .
END
+TEST "llist_relocate" relocate < ,tmp_testfile1
+echo testdata > ,tmp_testfile2
+echo testdata > ,tmp_testfile3
+
+TEST "acquire 3 files" acquire_existing_3files <line = ' #comment bla'
+END
+
+TEST "check content of configitem with section" configitem_simple_content_check $'[ key.foo suffix.bar ] ' << END
+out: item->line = '[ key.foo suffix.bar ] '
+out: item->key_size = '7'
+out: item->key = 'key.foo suffix.bar ] '
+out: item->delim = ' suffix.bar ] '
+END
+
+TEST "check content of configitem with directive (without argument)" configitem_simple_content_check $'\t @directive ' << END
+out: item->line = ' @directive '
+out: item->key_size = '9'
+out: item->key = '@directive '
+END
+
+TEST "check content of configitem with directive (with argument)" configitem_simple_content_check $'\t @directive \targument' << END
+out: item->line = ' @directive argument'
+out: item->key_size = '9'
+out: item->key = '@directive argument'
+out: item->delim = ' argument'
+END
+
+TEST "check content of configitem with configentry" configitem_simple_content_check $' \t\t key.foo \t\t=\tbar' << END
+out: item->line = ' key.foo = bar'
+out: item->key_size = '7'
+out: item->key = 'key.foo = bar'
+out: item->delim = '= bar'
+END
+
+TEST "check content of configitem with configentry (redirect)" configitem_simple_content_check $' \t\t key.foo \t\t<\tkey.bar' << END
+out: item->line = ' key.foo < key.bar'
+out: item->key_size = '7'
+out: item->key = 'key.foo < key.bar'
+out: item->delim = '< key.bar'
+END
diff --git a/tests/Makefile.am b/tests/Makefile.am
index f128693c1..fa28a115f 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -24,10 +24,7 @@ test_error_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror
test_error_LDADD = liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl
check_PROGRAMS += test-locking
-test_locking_SOURCES = \
- $(tests_srcdir)/locking/test-locking.c \
- $(tests_srcdir)/locking/mutex.c \
- $(tests_srcdir)/locking/condition.c
+test_locking_SOURCES = $(tests_srcdir)/library/test-locking.c
test_locking_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror
test_locking_LDADD = liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm
@@ -36,20 +33,20 @@ test_llist_SOURCES = $(tests_srcdir)/library/test-llist.c
test_llist_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror
test_llist_LDADD = liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm
+check_PROGRAMS += test-psplay
+test_psplay_SOURCES = $(tests_srcdir)/library/test-psplay.c
+test_psplay_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/
+test_psplay_LDADD = liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm
+
check_PROGRAMS += test-safeclib
test_safeclib_SOURCES = $(tests_srcdir)/library/test-safeclib.c
test_safeclib_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror
test_safeclib_LDADD = liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm
-check_PROGRAMS += test-uuid
-test_uuid_SOURCES = $(tests_srcdir)/library/test-uuid.c
-test_uuid_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror
-test_uuid_LDADD = liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm
-
-check_PROGRAMS += test-references
-test_references_SOURCES = $(tests_srcdir)/library/test-references.c
-test_references_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror
-test_references_LDADD = liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm -lrt
+check_PROGRAMS += test-luid
+test_luid_SOURCES = $(tests_srcdir)/library/test-luid.c
+test_luid_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror
+test_luid_LDADD = liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm
check_PROGRAMS += test-filedescriptors
test_filedescriptors_SOURCES = $(tests_srcdir)/backend/test-filedescriptors.c
@@ -61,4 +58,9 @@ test_filehandles_SOURCES = $(tests_srcdir)/backend/test-filehandles.c
test_filehandles_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror
test_filehandles_LDADD = liblumibackend.a liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm
+check_PROGRAMS += test-config
+test_config_SOURCES = $(tests_srcdir)/backend/test-config.c
+test_config_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/
+test_config_LDADD = liblumibackend.a liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm
+
TESTS = $(tests_srcdir)/test.sh
diff --git a/tests/backend/test-config.c b/tests/backend/test-config.c
new file mode 100644
index 000000000..c9b2aeca3
--- /dev/null
+++ b/tests/backend/test-config.c
@@ -0,0 +1,222 @@
+/*
+ test-config.c - test the config system
+
+ Copyright (C) Lumiera.org
+ 2008, Christian Thaeter
+ Simeon Voelkel
+
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+#include "lib/safeclib.h"
+
+#include "backend/config.h"
+#include "backend/configitem.h"
+
+#include "tests/test.h"
+
+TESTS_BEGIN
+
+TEST ("init")
+{
+ lumiera_config_init ("./");
+ printf ("initialized\n");
+ lumiera_config_destroy ();
+ printf ("destroyed\n");
+}
+
+
+TEST ("configitem_simple")
+{
+ REQUIRE (argv[2]);
+ lumiera_config_init ("./");
+
+ LumieraConfigitem item;
+
+ item = lumiera_configitem_new (argv[2]);
+ ENSURE (item);
+
+ printf ("line = '%s'\n", item->line);
+ if (item->key)
+ printf ("key = '%.*s'\n", (int)item->key_size, item->key);
+ if (item->delim)
+ {
+ printf ("delim = '%c'\n", *item->delim);
+ printf ("value = '%s'\n", item->delim+1);
+ }
+
+ lumiera_configitem_delete (item, NULL);
+
+ lumiera_config_destroy ();
+}
+
+
+TEST ("lookup")
+{
+ lumiera_config_init ("./");
+
+ lumiera_config_lookup lookup;
+ lumiera_config_lookup_init (&lookup);
+
+ LumieraConfigitem item = lumiera_configitem_new ("foo.bar = test");
+ lumiera_config_lookup_insert (&lookup, item);
+
+ LumieraConfigitem found = lumiera_config_lookup_item_find (&lookup, "foo.bar");
+ ENSURE (found == item);
+
+ lumiera_config_lookup_remove (&lookup, found);
+ ENSURE (!lumiera_config_lookup_item_find (&lookup, "foo.bar"));
+
+ lumiera_config_lookup_destroy (&lookup);
+ lumiera_config_destroy ();
+}
+
+
+TEST ("number_get")
+{
+ REQUIRE (argv[2]);
+ REQUIRE (argv[3]);
+
+ lumiera_config_init ("./");
+
+ long long number = 0;
+
+ lumiera_config_setdefault (lumiera_tmpbuf_snprintf (SIZE_MAX, "%s = %s", argv[2], argv[3]));
+
+ if (!lumiera_config_number_get (argv[2], &number))
+ printf ("%lld\n", number);
+ else
+ printf ("%s, %lld\n", lumiera_error (), number);
+
+ lumiera_config_destroy ();
+}
+
+
+TEST ("number_get_nodefault")
+{
+ REQUIRE (argv[2]);
+
+ lumiera_config_init ("./");
+
+ long long number = 0;
+
+ if (!lumiera_config_number_get (argv[2], &number))
+ printf ("%lld\n", number);
+ else
+ printf ("%s\n", lumiera_error ());
+
+ lumiera_config_destroy ();
+}
+
+
+TEST ("string_get")
+{
+ REQUIRE (argv[2]);
+ REQUIRE (argv[3]);
+
+ lumiera_config_init ("./");
+
+ char* string;
+
+ lumiera_config_setdefault (lumiera_tmpbuf_snprintf (SIZE_MAX, "%s = %s", argv[2], argv[3]));
+
+ if (!lumiera_config_string_get (argv[2], &string))
+ printf ("'%s'\n", string);
+ else
+ printf ("%s, '%s'\n", lumiera_error (), string);
+
+ lumiera_config_destroy ();
+}
+
+
+TEST ("string_set")
+{
+ REQUIRE (argv[2]);
+
+ lumiera_config_init ("./");
+
+ lumiera_config_string_set (argv[2], &argv[3]);
+ FIXME ("handle error");
+
+ const char* string;
+ if (!lumiera_config_get (argv[2], &string))
+ printf ("'%s'\n", string);
+ else
+ printf ("%s, '%s'\n", lumiera_error (), string);
+
+ lumiera_config_destroy ();
+}
+
+
+TEST ("word_get")
+{
+ REQUIRE (argv[2]);
+ REQUIRE (argv[3]);
+
+ lumiera_config_init ("./");
+
+ char* word;
+
+ lumiera_config_setdefault (lumiera_tmpbuf_snprintf (SIZE_MAX, "%s = %s", argv[2], argv[3]));
+
+ if (!lumiera_config_word_get (argv[2], &word))
+ printf ("'%s'\n", word);
+ else
+ printf ("%s, '%s'\n", lumiera_error (), word);
+
+ lumiera_config_destroy ();
+}
+
+TEST ("configitem_simple_ctor_dtor")
+{
+ REQUIRE (argv[2]);
+ lumiera_config_init ("./");
+
+ LumieraConfigitem item;
+
+ item = lumiera_configitem_new (argv[2]);
+
+ lumiera_config_destroy ();
+}
+
+TEST ("configitem_simple_content_check")
+{
+ REQUIRE (argv[2]);
+ lumiera_config_init ("./");
+
+ LumieraConfigitem item;
+
+ item = lumiera_configitem_new (argv[2]);
+
+ if ( item->line )
+ {
+ printf("item->line = '%s'\n", item->line);
+ }
+ if ( item->key_size )
+ {
+ printf("item->key_size = '%zi'\n", item->key_size);
+ }
+ if ( item->key )
+ {
+ printf("item->key = '%s'\n", item->key);
+ }
+ if ( item->delim )
+ {
+ printf("item->delim = '%s'\n", item->delim);
+ }
+
+ lumiera_config_destroy ();
+}
+
+TESTS_END
diff --git a/tests/backend/test-filedescriptors.c b/tests/backend/test-filedescriptors.c
index 3e14ead1d..745c4087b 100644
--- a/tests/backend/test-filedescriptors.c
+++ b/tests/backend/test-filedescriptors.c
@@ -57,6 +57,32 @@ TEST ("acquire_existing_again")
return 1;
}
+TEST ("acquire_existing_3files")
+{
+ lumiera_backend_init ();
+ LumieraFiledescriptor descriptor1 = lumiera_filedescriptor_acquire (",tmp_testfile1", LUMIERA_FILE_READONLY);
+
+ LumieraFiledescriptor descriptor2 = lumiera_filedescriptor_acquire (",tmp_testfile2", LUMIERA_FILE_READONLY);
+
+ LumieraFiledescriptor descriptor3 = lumiera_filedescriptor_acquire (",tmp_testfile3", LUMIERA_FILE_READONLY);
+ if (descriptor1)
+ lumiera_filedescriptor_release (descriptor1);
+
+ if (descriptor2)
+ lumiera_filedescriptor_release (descriptor2);
+
+ if (descriptor3)
+ lumiera_filedescriptor_release (descriptor3);
+
+ if (descriptor1 && descriptor2 && descriptor3)
+ {
+ lumiera_backend_destroy ();
+ return 0;
+ }
+ else
+ return 1;
+}
+
TEST ("acquire_create")
{
lumiera_backend_init ();
diff --git a/tests/common/mainsuite.cpp b/tests/common/mainsuite.cpp
index 3ef740744..455bfd98e 100644
--- a/tests/common/mainsuite.cpp
+++ b/tests/common/mainsuite.cpp
@@ -34,7 +34,7 @@ using lumiera::ON_GLOBAL_SHUTDOWN;
* cmd line argument.
* Note: to ease debugging, we don't catch any exceptions.
*/
-int main (int argc, char* argv[])
+int main (int argc, const char* argv[])
{
util::Cmdline args (argc,argv);
test::TestOption optparser (args);
diff --git a/tests/common/singletontestmocktest.cpp b/tests/common/singletontestmocktest.cpp
index ea5e1d70e..2be296bb1 100644
--- a/tests/common/singletontestmocktest.cpp
+++ b/tests/common/singletontestmocktest.cpp
@@ -50,11 +50,11 @@ namespace lumiera
class TestSingletonO
{
int callCnt;
- char* typid;
+ Symbol typid;
format msg;
public:
- TestSingletonO(char* ty="TestSingletonO")
+ TestSingletonO(Symbol ty="TestSingletonO")
: callCnt (0), typid(ty), msg ("%s::doIt() call=%d\n")
{
TRACE (singleton, "ctor %s", typid);
diff --git a/tests/common/test/cmdlinewrappertest.cpp b/tests/common/test/cmdlinewrappertest.cpp
index 668ce8121..f5d1eaf25 100644
--- a/tests/common/test/cmdlinewrappertest.cpp
+++ b/tests/common/test/cmdlinewrappertest.cpp
@@ -85,7 +85,7 @@ namespace util
*/
void testStandardCmdlineformat()
{
- char* fakeArg[3] = {"CMD", "one ", "two"};
+ const char* fakeArg[3] = {"CMD", "one ", "two"};
Cmdline theCmdline(3, fakeArg);
cout << "Standard Cmdlineformat:" << theCmdline << "\n";
}
diff --git a/tests/library/test-llist.c b/tests/library/test-llist.c
index 66bfa614d..520cf9012 100644
--- a/tests/library/test-llist.c
+++ b/tests/library/test-llist.c
@@ -1,5 +1,5 @@
/*
- test-llist.c - test the linked lis lib
+ test-llist.c - test the linked list lib
Copyright (C) Lumiera.org
2008, Christian Thaeter
@@ -185,4 +185,23 @@ TEST ("whiles")
}
+TEST ("relocate")
+{
+ llist source;
+ llist_init (&source);
+
+ llist something;
+ llist_init (&something);
+
+ llist_insert_head (&source, &something);
+
+ llist target = {NULL,NULL};
+
+ target = source;
+
+ llist_relocate (&target);
+ ENSURE (llist_is_head (&target, &something));
+}
+
+
TESTS_END
diff --git a/tests/library/test-locking.c b/tests/library/test-locking.c
new file mode 100644
index 000000000..55ea91cdb
--- /dev/null
+++ b/tests/library/test-locking.c
@@ -0,0 +1,154 @@
+/*
+ test-locking.c - test locking functions
+
+ Copyright (C) Lumiera.org
+ 2008, Christian Thaeter
+
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "tests/test.h"
+#include "lib/mutex.h"
+#include "lib/condition.h"
+#include "lib/rwlock.h"
+
+#include
+#include
+
+TESTS_BEGIN
+
+
+TEST ("mutexsection")
+{
+ lumiera_mutex m;
+ lumiera_mutex_init (&m, "mutexsection", &NOBUG_FLAG(NOBUG_ON));
+
+ LUMIERA_MUTEX_SECTION (NOBUG_ON, &m)
+ {
+ printf ("mutex locked section 1\n");
+ }
+
+ LUMIERA_MUTEX_SECTION (NOBUG_ON, &m)
+ {
+ printf ("mutex locked section 2\n");
+ }
+
+ lumiera_mutex_destroy (&m, &NOBUG_FLAG(NOBUG_ON));
+}
+
+
+TEST ("mutexforgotunlock")
+{
+ lumiera_mutex m;
+ lumiera_mutex_init (&m, "mutexforgotunlock", &NOBUG_FLAG(NOBUG_ON));
+
+ LUMIERA_MUTEX_SECTION (NOBUG_ON, &m)
+ {
+ break; // MUTEX_SECTIONS must not be left by a jump
+ }
+
+ lumiera_mutex_destroy (&m, &NOBUG_FLAG(NOBUG_ON));
+}
+
+
+TEST ("nestedmutexsection")
+{
+ lumiera_mutex m;
+ lumiera_mutex_init (&m, "m_mutexsection", &NOBUG_FLAG(NOBUG_ON));
+
+ lumiera_mutex n;
+ lumiera_mutex_init (&n, "n_mutexsection", &NOBUG_FLAG(NOBUG_ON));
+
+ LUMIERA_MUTEX_SECTION (NOBUG_ON, &m)
+ {
+ printf ("outer mutex locked section\n");
+
+ LUMIERA_MUTEX_SECTION (NOBUG_ON, &n)
+ {
+ printf ("inner mutex locked section\n");
+ }
+ }
+
+ lumiera_mutex_destroy (&n, &NOBUG_FLAG(NOBUG_ON));
+ lumiera_mutex_destroy (&m, &NOBUG_FLAG(NOBUG_ON));
+}
+
+
+
+TEST ("rwlocksection")
+{
+ lumiera_rwlock rwlock;
+ lumiera_rwlock_init (&rwlock, "rwsection", &NOBUG_FLAG(NOBUG_ON));
+
+ LUMIERA_WRLOCK_SECTION (NOBUG_ON, &rwlock)
+ {
+ printf ("write locked section 1\n");
+ }
+
+ LUMIERA_RDLOCK_SECTION (NOBUG_ON, &rwlock)
+ {
+ printf ("read locked section 2\n");
+ }
+
+ lumiera_rwlock_destroy (&rwlock, &NOBUG_FLAG(NOBUG_ON));
+}
+
+TEST ("rwlockforgotunlock")
+{
+ lumiera_rwlock rwlock;
+ lumiera_rwlock_init (&rwlock, "rwlockforgotunlock", &NOBUG_FLAG(NOBUG_ON));
+
+ LUMIERA_RDLOCK_SECTION (NOBUG_ON, &rwlock)
+ {
+ break; // LOCK_SECTIONS must not be left by a jump
+ }
+
+ lumiera_rwlock_destroy (&rwlock, &NOBUG_FLAG(NOBUG_ON));
+}
+
+
+TEST ("conditionsection")
+{
+ lumiera_condition cond;
+ lumiera_condition_init (&cond, "conditionsection", &NOBUG_FLAG(NOBUG_ON));
+
+ LUMIERA_CONDITION_SECTION (NOBUG_ON, &cond)
+ {
+ printf ("condition locked section 1\n");
+ }
+
+ LUMIERA_CONDITION_SECTION (NOBUG_ON, &cond)
+ {
+ printf ("condition locked section 2\n");
+ }
+
+ lumiera_condition_destroy (&cond, &NOBUG_FLAG(NOBUG_ON));
+}
+
+
+TEST ("conditionforgotunlock")
+{
+ lumiera_condition cond;
+ lumiera_condition_init (&cond, "conditionforgotunlock", &NOBUG_FLAG(NOBUG_ON));
+
+ LUMIERA_CONDITION_SECTION (NOBUG_ON, &cond)
+ {
+ break; // CONDITION_SECTIONS must not be left by a jump
+ }
+
+ lumiera_condition_destroy (&cond, &NOBUG_FLAG(NOBUG_ON));
+}
+
+TESTS_END
diff --git a/tests/library/test-uuid.c b/tests/library/test-luid.c
similarity index 60%
rename from tests/library/test-uuid.c
rename to tests/library/test-luid.c
index 4a6050163..1695bbec6 100644
--- a/tests/library/test-uuid.c
+++ b/tests/library/test-luid.c
@@ -1,8 +1,8 @@
/*
- test-uuid.c - test the uuid lib
+ test-luid.c - test the luid lib
- Copyright (C) CinelerraCV
- 2007, Christian Thaeter
+ Copyright (C) Lumiera.org
+ 2007, 2008 Christian Thaeter
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -23,7 +23,7 @@
//#include
-#include "lib/uuid.h"
+#include "lib/luid.h"
#include
@@ -39,35 +39,43 @@ main (int argc, char** argv)
if (!strcmp(argv[1], "uuidgen_2"))
{
- lumiera_uuid uuid1;
- lumiera_uuid uuid2;
+ lumiera_uid luid1;
+ lumiera_uid luid2;
- lumiera_uuid_gen (&uuid1);
- lumiera_uuid_gen (&uuid2);
+ lumiera_uid_gen (&luid1);
+ lumiera_uid_gen (&luid2);
- printf ("%d\n", lumiera_uuid_eq (&uuid2, &uuid1));
+ printf ("%d\n", lumiera_uid_eq (&luid2, &luid1));
}
else if (!strcmp(argv[1], "uuidgen_copy"))
{
- lumiera_uuid uuid1;
- lumiera_uuid uuid2;
+ lumiera_uid luid1;
+ lumiera_uid luid2;
- lumiera_uuid_gen (&uuid1);
+ lumiera_uid_gen (&luid1);
- lumiera_uuid_copy (&uuid2, &uuid1);
+ lumiera_uid_copy (&luid2, &luid1);
- printf ("%d\n", lumiera_uuid_eq (&uuid2, &uuid1));
+ printf ("%d\n", lumiera_uid_eq (&luid2, &luid1));
}
else if (!strcmp(argv[1], "ptrs"))
{
- lumiera_uuid uuid;
+ lumiera_uid luid;
- lumiera_uuid_set_ptr (&uuid, &uuid);
+ lumiera_uid_set_ptr (&luid, &luid);
- printf ("%d\n", lumiera_uuid_ptr_get (&uuid) == &uuid);
+ printf ("%d\n", lumiera_uid_ptr_get (&luid) == &luid);
}
else
return 1;
return 0;
}
+
+/*
+// Local Variables:
+// mode: C
+// c-file-style: "gnu"
+// indent-tabs-mode: nil
+// End:
+*/
diff --git a/tests/library/test-psplay.c b/tests/library/test-psplay.c
new file mode 100644
index 000000000..f7989bae7
--- /dev/null
+++ b/tests/library/test-psplay.c
@@ -0,0 +1,471 @@
+/*
+ test-psplay.c - test the probanilistic splay tree
+
+ Copyright (C) Lumiera.org
+ 2008, Christian Thaeter
+
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include
+#include
+
+#include "lib/psplay.h"
+#include "tests/test.h"
+
+struct testitem
+{
+ psplaynode node;
+ char* key;
+};
+typedef struct testitem* TestItem;
+
+TestItem
+testitem_new (const char* str)
+{
+ TestItem self = malloc (sizeof *self);
+ psplaynode_init (&self->node);
+ self->key = strdup (str);
+ return self;
+}
+
+void
+testitem_delete (TestItem self)
+{
+ free (self->key);
+ free (self);
+}
+
+
+
+static int
+cmp_fn (const void*, const void*);
+
+static const void*
+key_fn (const PSplaynode);
+
+static void
+delete_fn (PSplaynode);
+
+//static psplay_delete_fn
+//action_fn (PSplaynode node, const enum psplay_order_e which, int level, void* data);
+
+static int
+fcmp_fn (const void*, const void*);
+
+static const void*
+fkey_fn (const PSplaynode);
+
+static void
+fdelete_fn (PSplaynode);
+
+//static psplay_delete_fn
+//action_fn (PSplaynode node, const enum psplay_order_e which, int level, void* data);
+
+
+psplay_delete_fn
+testitem_print_node (PSplaynode node, const enum psplay_order_enum which, int level, void* data)
+{
+ FILE* fh = data;
+ static char* sp = " ";
+ if (level>40)
+ {
+ if (which == PSPLAY_PREORDER)
+ fprintf (fh, "%s ...\n", sp);
+ return PSPLAY_CONT;
+ }
+
+ switch (which)
+ {
+ case PSPLAY_PREORDER:
+ fprintf (fh, "%s%p '%s'\n", sp+40-level, node, ((TestItem)node)->key);
+ if (node->left) fprintf (fh, "%sleft %p '%s'\n", sp+40-level, node->left, ((TestItem)node->left)->key);
+ break;
+ case PSPLAY_INORDER:
+ if (node->right) fprintf (fh, "%sright %p '%s'\n", sp+40-level, node->right, ((TestItem)node->right)->key);
+ break;
+ case PSPLAY_POSTORDER:
+ break;
+ }
+
+ return PSPLAY_CONT;
+}
+
+void
+testitem_dump (PSplay self, FILE* dest)
+{
+ fprintf (dest, "root %p '%s'\n", self->tree, self->tree?((TestItem)self->tree)->key:"EMPTY");
+ psplay_walk (self, NULL, testitem_print_node, 0, dest);
+ fprintf (dest, "\n");
+}
+
+psplay_delete_fn
+testitem_graphvizprint_node (PSplaynode node, const enum psplay_order_enum which, int level, void* data)
+{
+ FILE* fh = data;
+
+ switch (which)
+ {
+ case PSPLAY_PREORDER:
+ if (node->left)
+ fprintf (fh, "\t\"%p:%s\":sw -> \"%p:%s\":ne;\n",
+ node,
+ ((TestItem)node)->key,
+ node->left,
+ ((TestItem)node->left)->key);
+ break;
+ case PSPLAY_INORDER:
+ if (node->right)
+ fprintf (fh, "\t\"%p:%s\":se -> \"%p:%s\":nw;\n",
+ node,
+ ((TestItem)node)->key,
+ node->right,
+ ((TestItem)node->right)->key);
+ break;
+ case PSPLAY_POSTORDER:
+ break;
+ }
+
+ return PSPLAY_CONT;
+}
+
+
+
+void
+testitem_graphvizdump (PSplay self, FILE* dest)
+{
+ static int cnt = 0;
+ if (!cnt) cnt = (time(NULL) % 1000) * 100;
+ char cmd[256];
+
+ sprintf(cmd,"dot -Tps >/var/tmp/dbg%d.ps; gv /var/tmp/dbg%d.ps",cnt,cnt);
+ FILE * graph = popen(cmd, "w");
+
+ fprintf(graph, "digraph \"%s\" { center=true; size=\"6,6\"; node [color=lightblue2, style=filled];", "psplay");
+ ++cnt;
+
+ fprintf(graph, "\t\"root\":s -> \"%p:%s\":n;\n",
+ self->tree, self->tree?((TestItem)self->tree)->key:"EMPTY");
+
+ psplay_walk (self, NULL, testitem_graphvizprint_node, 0, graph);
+
+ fprintf(graph, "}");
+
+ pclose(graph);
+}
+
+
+
+TESTS_BEGIN
+
+TEST ("basic")
+{
+ psplay splay_tree;
+ psplay_init (&splay_tree, cmp_fn, key_fn, delete_fn);
+
+ psplay_dump (&splay_tree, stdout);
+
+ psplay_destroy (&splay_tree);
+}
+
+
+TEST ("basic_insert_dump")
+{
+ REQUIRE (argv[2]);
+
+ psplay splay_tree;
+ psplay_init (&splay_tree, cmp_fn, key_fn, delete_fn);
+
+ int end = atoi (argv[2]);
+
+ char key[1024];
+
+ for (int i = 1; i <= end; ++i)
+ {
+ sprintf (key, "%d", i);
+ TRACE (tests, "insert %s", key);
+ psplay_insert (&splay_tree, (PSplaynode)testitem_new (key), 100);
+ }
+
+ psplay_dump (&splay_tree, stderr);
+
+#if 0
+ for (int i = 1; i <= end; ++i)
+ {
+ sprintf (key, "%d", i);
+ TRACE (tests, "insert %s", key);
+ psplay_remove_key (&splay_tree, key);
+ psplay_dump (&splay_tree, stderr);
+ }
+ for (int i = end; i; --i)
+ {
+ sprintf (key, "%d", i);
+ TRACE (tests, "insert %s", key);
+ psplay_remove_key (&splay_tree, key);
+ psplay_dump (&splay_tree, stderr);
+ }
+#endif
+
+ psplay_destroy (&splay_tree);
+ printf ("done\n");
+}
+
+
+TEST ("insert_find")
+{
+ psplay splay_tree;
+ psplay_init (&splay_tree, cmp_fn, key_fn, delete_fn);
+
+ psplay_insert (&splay_tree, (PSplaynode)testitem_new ("foo"), 100);
+ psplay_insert (&splay_tree, (PSplaynode)testitem_new ("bar"), 100);
+ psplay_insert (&splay_tree, (PSplaynode)testitem_new ("baz"), 100);
+ psplay_insert (&splay_tree, (PSplaynode)testitem_new ("test"), 100);
+ psplay_insert (&splay_tree, (PSplaynode)testitem_new ("pap"), 100);
+ psplay_insert (&splay_tree, (PSplaynode)testitem_new ("qux"), 100);
+
+ testitem_graphvizdump (&splay_tree, stdout);
+ psplay_dump (&splay_tree, stdout);
+
+ //TestItem f = (TestItem) psplay_find (&splay_tree, "baz", 100);
+ TestItem f = (TestItem) psplay_find (&splay_tree, "baz", 100);
+ ENSURE (f);
+ printf ("found %p (%.4s)\n", &f->node, f->key);
+ psplay_dump (&splay_tree, stdout);
+
+ f = (TestItem) psplay_find (&splay_tree, "test", 100);
+ ENSURE (f);
+ printf ("found %p (%.4s)\n", &f->node, f->key);
+ psplay_dump (&splay_tree, stdout);
+
+ f = (TestItem) psplay_find (&splay_tree, "test", 100);
+ ENSURE (f);
+ printf ("found %p (%.4s)\n", &f->node, f->key);
+ psplay_dump (&splay_tree, stdout);
+
+ f = (TestItem) psplay_find (&splay_tree, "foo", 100);
+ ENSURE (f);
+ printf ("found %p (%.4s)\n", &f->node, f->key);
+ psplay_dump (&splay_tree, stdout);
+
+#if 0
+ psplay_delete (psplay_remove (&splay_tree, root.tree));
+ psplay_dump (&splay_tree, stdout);
+
+ psplay_delete (psplay_remove (&splay_tree, root.tree));
+ psplay_dump (&splay_tree, stdout);
+
+ psplay_delete (psplay_remove (&splay_tree, root.tree));
+ psplay_dump (&splay_tree, stdout);
+#endif
+ printf ("destroying\n");
+ psplay_destroy (&splay_tree);
+ psplay_dump (&splay_tree, stdout);
+#if 0
+ psplay_delete (psplay_remove (&splay_tree, root.tree));
+ psplay_dump (&splay_tree, stdout);
+
+ psplay_delete (psplay_remove (&splay_tree, root.tree));
+ psplay_dump (&splay_tree, stdout);
+
+ psplay_delete (psplay_remove (&splay_tree, root.tree));
+ psplay_dump (&splay_tree, stdout);
+#endif
+ return 0;
+}
+
+TEST ("basic_insert_splay")
+{
+ REQUIRE (argv[2]);
+
+ psplay splay_tree;
+ psplay_init (&splay_tree, cmp_fn, key_fn, delete_fn);
+
+ int end = atoi (argv[2]);
+
+ char key[1024];
+
+ for (int i = 1; i <= end; ++i)
+ {
+ sprintf (key, "%d", i);
+ TRACE (tests, "insert %s", key);
+ psplay_insert (&splay_tree, (PSplaynode)testitem_new (key), 100);
+ }
+
+ for (int i = end/2; i <= end; ++i)
+ {
+ psplay_dump (&splay_tree, stderr);
+ sprintf (key, "%d", i);
+ psplay_find (&splay_tree, key, 100);
+ }
+ psplay_destroy (&splay_tree);
+ printf ("done\n");
+}
+
+
+TEST ("basic_rand_insert_dump")
+{
+ REQUIRE (argv[2]);
+
+ psplay splay_tree;
+ psplay_init (&splay_tree, cmp_fn, key_fn, delete_fn);
+
+ int end = atoi (argv[2]);
+
+ char key[1024];
+
+ for (int i = 1; i <= end; ++i)
+ {
+ sprintf (key, "%d", i /*rand()*/);
+ psplay_insert (&splay_tree, (PSplaynode)testitem_new (key), 100);
+ }
+
+ testitem_graphvizdump (&splay_tree, stdout);
+ //testitem_dump (&splay_tree, stdout);
+
+ psplay_destroy (&splay_tree);
+ printf ("done\n");
+}
+
+
+TEST ("fast_insert")
+{
+ REQUIRE (argv[2]);
+
+ psplay splay_tree;
+ psplay_init (&splay_tree, fcmp_fn, fkey_fn, fdelete_fn);
+
+ int end = atoi (argv[2]);
+
+ char key[1024];
+
+ for (int i = 1; i <= end; ++i)
+ {
+ sprintf (key, "%d", i);
+ psplay_insert (&splay_tree, (PSplaynode)testitem_new (key), 100);
+ }
+
+ psplay_destroy (&splay_tree);
+ printf ("done\n");
+}
+
+
+
+
+TEST ("nonexistant")
+{
+ REQUIRE (argv[2]);
+
+}
+
+
+TEST ("insert")
+{
+ REQUIRE (argv[2]);
+
+}
+
+
+
+TEST ("insert_rand")
+{
+ REQUIRE (argv[2]);
+
+}
+
+
+
+TEST ("insert_fastcheck")
+{
+ REQUIRE (argv[2]);
+
+}
+
+
+
+TESTS_END
+
+
+
+
+/*
+ cuckoo support functions
+*/
+
+static int
+cmp_fn (const void* a, const void* b)
+{
+ REQUIRE (a);
+ REQUIRE (b);
+ return strcmp (a, b);
+}
+
+static const void*
+key_fn (const PSplaynode node)
+{
+ REQUIRE (node);
+ REQUIRE (((TestItem)node)->key);
+
+ return ((TestItem)node)->key;
+}
+
+static void
+delete_fn (PSplaynode node)
+{
+ REQUIRE (node);
+ testitem_delete ((TestItem) node);
+}
+
+
+//static psplay_delete_fn
+//action_fn (PSplaynode node, const enum psplay_order_e which, int level, void* data)
+//{
+//}
+
+
+static int
+fcmp_fn (const void* a, const void* b)
+{
+ return strcmp (a, b);
+}
+
+static const void*
+fkey_fn (const PSplaynode node)
+{
+ return ((TestItem)node)->key;
+}
+
+static void
+fdelete_fn (PSplaynode node)
+{
+ testitem_delete ((TestItem) node);
+}
+
+//static psplay_delete_fn
+//action_fn (PSplaynode node, const enum psplay_order_e which, int level, void* data)
+//{
+//}
+
+
+
+
+
+
+/*
+// Local Variables:
+// mode: C
+// c-file-style: "gnu"
+// indent-tabs-mode: nil
+// End:
+*/
diff --git a/tests/library/test-references.c b/tests/library/test-references.c
deleted file mode 100644
index c1509c341..000000000
--- a/tests/library/test-references.c
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- test-references.c - test strong and weak references
-
- Copyright (C) Lumiera.org
- 2008, Christian Thaeter
-
- 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 2 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, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include
-//#include
-
-#include "lib/references.h"
-
-
-LUMIERA_ERROR_DEFINE(TEST, "test error");
-
-
-struct example
-{
- int foo;
-};
-
-void
-example_dtor(void* o)
-{
- printf ("destruct: %d\n", ((struct example*)o)->foo);
- ((struct example*)o)->foo = 0;
-
- // free(o)
-}
-
-int
-main (int argc, char** argv)
-{
- NOBUG_INIT;
-
- if (argc == 1)
- return 0;
-
- if (!strcmp(argv[1], "basic"))
- {
- struct example test;
- test.foo = 123;
-
- lumiera_reference hold;
-
- lumiera_reference_strong_init_once (&hold, &test, example_dtor);
-
-
- struct example* r = lumiera_reference_get (&hold);
-
- printf ("got: %d\n", r->foo);
-
- lumiera_reference_destroy (&hold);
- }
- else if (!strcmp(argv[1], "nodeinsert"))
- {
-
- }
- else
- return 1;
-
- return 0;
-}
diff --git a/tests/library/test-safeclib.c b/tests/library/test-safeclib.c
index 837e3d5fd..a5dfa47a9 100644
--- a/tests/library/test-safeclib.c
+++ b/tests/library/test-safeclib.c
@@ -82,4 +82,24 @@ TEST ("tmpbuf")
}
+TEST ("tr0")
+{
+ char* r = lumiera_tmpbuf_tr (argv[2], "abcdeABCDE0123456789", "ABCDEABCDE0123456789", NULL);
+ printf("%s\n", r?r:"failed");
+}
+
+
+TEST ("tr")
+{
+ char* r = lumiera_tmpbuf_tr (argv[2], "abcdeABCDE0123456789", "ABCDEABCDE0123456789", "");
+ printf("%s\n", r?r:"failed");
+}
+
+
+TEST ("tr_")
+{
+ printf("%s\n", lumiera_tmpbuf_tr (argv[2], "abcdeABCDE0123456789", "ABCDEABCDE0123456789", "_"));
+}
+
+
TESTS_END
diff --git a/tests/locking/condition.c b/tests/locking/condition.c
deleted file mode 100644
index 7d79e9a7e..000000000
--- a/tests/locking/condition.c
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- test condition functions
-
- Copyright (C) Lumiera.org
- 2008, Christian Thaeter
-
- 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 2 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, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include "lib/condition.h"
-
-#if 0
-waiting_thread()
-{
- lock;
- wait;
- unlock;
-}
-
-
-signaling_thread()
-{
- signal();
-}
-#endif
-
-
-int
-conditionforgotunlock ()
-{
- lumiera_condition c;
- lumiera_condition_init (&c);
-
- lumiera_conditionacquirer l;
- lumiera_conditionacquirer_init (&l, &c, LUMIERA_LOCKED);
- return 0;
-}
diff --git a/tests/locking/mutex.c b/tests/locking/mutex.c
deleted file mode 100644
index f4f8c18f6..000000000
--- a/tests/locking/mutex.c
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- test mutex functions
-
- Copyright (C) Lumiera.org
- 2008, Christian Thaeter
-
- 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 2 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, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-
-#include "lib/mutex.h"
-
-int mutexforgotunlock()
-{
- lumiera_mutex m;
- lumiera_mutex_init (&m);
-
- lumiera_mutexacquirer l;
- lumiera_mutexacquirer_init_mutex (&l, &m, LUMIERA_LOCKED);
- return 0;
-}
diff --git a/tests/test.h b/tests/test.h
index d25fa0a59..060d007fc 100644
--- a/tests/test.h
+++ b/tests/test.h
@@ -26,6 +26,9 @@
#include "lib/error.h"
+#include
+
+NOBUG_DEFINE_FLAG (tests);
LUMIERA_ERROR_DEFINE (TEST, "test error");
#define TESTS_BEGIN \
@@ -33,20 +36,35 @@ int \
main (int argc, char** argv) \
{ \
NOBUG_INIT; \
+ NOBUG_INIT_FLAG (tests); \
\
if (argc == 1) \
- return 1;
+ { \
+ fprintf (stderr, "missing argument\n"); \
+ return 1; \
+ }
-#define TEST(name) \
+#define TEST(name) \
else if (!strcmp(argv[1], name))
#define TESTS_END \
else \
- return 1; \
+ { \
+ fprintf (stderr, "unknown test\n"); \
+ return 1; \
+ } \
\
return 0; \
}
#endif
+
+/*
+// Local Variables:
+// mode: C
+// c-file-style: "gnu"
+// indent-tabs-mode: nil
+// End:
+*/