summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am2
-rw-r--r--bin/.gitignore1
-rw-r--r--bin/Makefile.am4
-rw-r--r--bin/dconf.c27
-rw-r--r--client/Makefile.am5
-rw-r--r--client/dconf-client.c129
-rw-r--r--client/dconf-client.h90
-rw-r--r--client/dconf.h9
-rw-r--r--common/dconf-paths.c172
-rw-r--r--common/dconf-paths.h36
-rw-r--r--configure.ac3
-rw-r--r--engine/dconf-engine.c16
-rw-r--r--engine/dconf-engine.h13
-rw-r--r--engine/dconf-readtype.h11
-rw-r--r--engine/dconf-resetlist.h20
-rw-r--r--gsettings/Makefile.am2
-rw-r--r--gsettings/dconfsettingsbackend.c10
-rw-r--r--tests/.gitignore1
-rw-r--r--tests/Makefile.am5
-rw-r--r--tests/paths.c98
20 files changed, 628 insertions, 26 deletions
diff --git a/Makefile.am b/Makefile.am
index d6cb639..d781160 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1 +1 @@
-SUBDIRS = gvdb service gsettings
+SUBDIRS = gvdb service gsettings tests client bin
diff --git a/bin/.gitignore b/bin/.gitignore
new file mode 100644
index 0000000..042fec5
--- /dev/null
+++ b/bin/.gitignore
@@ -0,0 +1 @@
+dconf
diff --git a/bin/Makefile.am b/bin/Makefile.am
new file mode 100644
index 0000000..9f97ef2
--- /dev/null
+++ b/bin/Makefile.am
@@ -0,0 +1,4 @@
+bin_PROGRAMS = dconf
+
+AM_CFLAGS = -I$(top_srcdir)/common -I$(top_srcdir)/client -I$(top_srcdir)/engine $(gio_CFLAGS)
+dconf_LDADD = ../client/libdconf.la
diff --git a/bin/dconf.c b/bin/dconf.c
new file mode 100644
index 0000000..318d42f
--- /dev/null
+++ b/bin/dconf.c
@@ -0,0 +1,27 @@
+#include <dconf.h>
+
+int
+main (int argc, char **argv)
+{
+ DConfClient *client;
+ GVariant *value;
+
+ g_type_init ();
+
+ client = dconf_client_new (NULL, NULL, NULL, NULL);
+
+ value = dconf_client_read (client, argv[1], DCONF_READ_NORMAL);
+
+ if (value == NULL)
+ g_print ("(null)\n");
+ else
+ {
+ gchar *printed;
+ printed = g_variant_print (value, TRUE);
+ g_print ("%s\n", printed);
+ g_variant_unref (value);
+ g_free (printed);
+ }
+
+ return 0;
+}
diff --git a/client/Makefile.am b/client/Makefile.am
new file mode 100644
index 0000000..1e976e8
--- /dev/null
+++ b/client/Makefile.am
@@ -0,0 +1,5 @@
+lib_LTLIBRARIES = libdconf.la
+
+AM_CFLAGS = -I$(top_srcdir)/common -I$(top_srcdir)/engine $(gio_CFLAGS) -I$(top_srcdir)/gvdb
+libdconf_la_SOURCES = dconf-client.c ../common/dconf-paths.c ../engine/dconf-engine.c ../gvdb/gvdb-reader.c
+libdconf_la_LIBADD = $(gio_LIBS)
diff --git a/client/dconf-client.c b/client/dconf-client.c
new file mode 100644
index 0000000..0e7af27
--- /dev/null
+++ b/client/dconf-client.c
@@ -0,0 +1,129 @@
+#include <dconf-engine.h>
+#include "dconf-client.h"
+
+typedef GObjectClass DConfClientClass;
+
+struct _DConfClient
+{
+ GObject parent_instance;
+
+ DConfEngine *engine;
+
+ DConfWatchFunc watch_func;
+ gpointer user_data;
+ GDestroyNotify notify;
+};
+
+G_DEFINE_TYPE (DConfClient, dconf_client, G_TYPE_OBJECT)
+
+static void
+dconf_client_finalize (GObject *object)
+{
+ DConfClient *client = DCONF_CLIENT (object);
+
+ if (client->notify)
+ client->notify (client->user_data);
+
+ G_OBJECT_CLASS (dconf_client_parent_class)
+ ->finalize (object);
+}
+
+static void
+dconf_client_init (DConfClient *client)
+{
+}
+
+static void
+dconf_client_class_init (DConfClientClass *class)
+{
+ class->finalize = dconf_client_finalize;
+}
+
+DConfClient *
+dconf_client_new (const gchar *context,
+ DConfWatchFunc watch_func,
+ gpointer user_data,
+ GDestroyNotify notify)
+{
+ DConfClient *client = g_object_new (DCONF_TYPE_CLIENT, NULL);
+
+ client->engine = dconf_engine_new (context);
+ client->watch_func = watch_func;
+ client->user_data = user_data;
+ client->notify = notify;
+}
+
+GVariant *
+dconf_client_read (DConfClient *client,
+ const gchar *key,
+ DConfReadType type)
+{
+ return dconf_engine_read (client->engine, key, type);
+}
+
+#if 0
+
+GVariant * dconf_client_read (DConfClient *client,
+ const gchar *key,
+ DConfReadType type);
+
+gchar ** dconf_client_list (DConfClient *client,
+ const gchar *prefix,
+ DConfResetList *resets);
+
+gboolean dconf_client_is_writable (DConfClient *client,
+ const gchar *prefix,
+ GError **error);
+
+gboolean dconf_client_write (DConfClient *client,
+ const gchar *key,
+ GVariant *value,
+ GError **error);
+void dconf_client_write_async (DConfClient *client,
+ const gchar *key,
+ GVariant *value,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean dconf_client_write_finish (DConfClient *client,
+ GAsyncResult *result,
+ GError **error);
+
+gboolean dconf_client_write_many (DConfClient *client,
+ const gchar *prefix,
+ const gchar * const *keys,
+ GVariant **values,
+ GError **error);
+void dconf_client_write_many_async (DConfClient *client,
+ const gchar *prefix,
+ const gchar * const *keys,
+ GVariant **values,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean dconf_client_write_many_finish (DConfClient *client,
+ GAsyncResult *result,
+ GError **error);
+
+gboolean dconf_client_watch (DConfClient *client,
+ const gchar *name,
+ GError **error);
+void dconf_client_watch_async (DConfClient *client,
+ const gchar *name,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean dconf_client_watch_finish (DConfClient *client,
+ GAsyncResult *result,
+ gpointer user_data);
+gboolean dconf_client_unwatch (DConfClient *client,
+ const gchar *name,
+ GError **error);
+void dconf_client_unwatch_async (DConfClient *client,
+ const gchar *name,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean dconf_client_unwatch_finish (DConfClient *client,
+ GAsyncResult *result,
+ gpointer user_data);
+
+#endif
+
+
diff --git a/client/dconf-client.h b/client/dconf-client.h
new file mode 100644
index 0000000..d8afc2f
--- /dev/null
+++ b/client/dconf-client.h
@@ -0,0 +1,90 @@
+#ifndef _dconf_client_h_
+#define _dconf_client_h_
+
+#include <dconf-resetlist.h>
+#include <dconf-readtype.h>
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define DCONF_TYPE_CLIENT (dconf_client_get_type ())
+#define DCONF_CLIENT(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), DCONF_TYPE_CLIENT, DConfClient))
+#define DCONF_IS_CLIENT(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), DCONF_TYPE_CLIENT))
+
+typedef struct _DConfClient DConfClient;
+
+typedef void (*DConfWatchFunc) (DConfClient *client,
+ const gchar *path,
+ const gchar * const *items,
+ gpointer user_data);
+
+GType dconf_client_get_type (void);
+DConfClient * dconf_client_new (const gchar *context,
+ DConfWatchFunc watch_func,
+ gpointer user_data,
+ GDestroyNotify notify);
+
+GVariant * dconf_client_read (DConfClient *client,
+ const gchar *key,
+ DConfReadType type);
+
+gchar ** dconf_client_list (DConfClient *client,
+ const gchar *prefix,
+ DConfResetList *resets);
+
+gboolean dconf_client_is_writable (DConfClient *client,
+ const gchar *prefix,
+ GError **error);
+
+gboolean dconf_client_write (DConfClient *client,
+ const gchar *key,
+ GVariant *value,
+ GError **error);
+void dconf_client_write_async (DConfClient *client,
+ const gchar *key,
+ GVariant *value,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean dconf_client_write_finish (DConfClient *client,
+ GAsyncResult *result,
+ GError **error);
+
+gboolean dconf_client_write_many (DConfClient *client,
+ const gchar *prefix,
+ const gchar * const *keys,
+ GVariant **values,
+ GError **error);
+void dconf_client_write_many_async (DConfClient *client,
+ const gchar *prefix,
+ const gchar * const *keys,
+ GVariant **values,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean dconf_client_write_many_finish (DConfClient *client,
+ GAsyncResult *result,
+ GError **error);
+
+gboolean dconf_client_watch (DConfClient *client,
+ const gchar *name,
+ GError **error);
+void dconf_client_watch_async (DConfClient *client,
+ const gchar *name,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean dconf_client_watch_finish (DConfClient *client,
+ GAsyncResult *result,
+ gpointer user_data);
+gboolean dconf_client_unwatch (DConfClient *client,
+ const gchar *name,
+ GError **error);
+void dconf_client_unwatch_async (DConfClient *client,
+ const gchar *name,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean dconf_client_unwatch_finish (DConfClient *client,
+ GAsyncResult *result,
+ gpointer user_data);
+
+G_END_DECLS
+
+#endif
diff --git a/client/dconf.h b/client/dconf.h
new file mode 100644
index 0000000..46cff3a
--- /dev/null
+++ b/client/dconf.h
@@ -0,0 +1,9 @@
+#ifndef _dconf_h_
+#define _dconf_h_
+
+#include <dconf-resetlist.h>
+#include <dconf-paths.h>
+#include <dconf-readtype.h>
+#include <dconf-client.h>
+
+#endif /* _dconf_h_ */
diff --git a/common/dconf-paths.c b/common/dconf-paths.c
new file mode 100644
index 0000000..20d5798
--- /dev/null
+++ b/common/dconf-paths.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright © 2008-2009 Ryan Lortie
+ * Copyright © 2010 Codethink Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Ryan Lortie <desrt@desrt.ca>
+ */
+
+#include "dconf-paths.h"
+
+#define vars gchar c, l
+
+#define absolute \
+ if ((l = *string++) != '/') \
+ return FALSE \
+
+#define relative \
+ l = '/'
+
+#define no_double_slash \
+ while ((c = *string++)) \
+ { \
+ if (c == '/' && l == '/') \
+ return FALSE; \
+ l = c; \
+ } \
+
+#define path \
+ return TRUE
+
+#define key \
+ return l != '/'
+
+#define dir \
+ return l == '/'
+
+
+
+/**
+ * dconf_is_path:
+ * @string: a string
+ * @returns: %TRUE if @string is a path
+ *
+ * Checks if @string is a valid dconf path. dconf keys must start with
+ * '/' and not contain '//'.
+ *
+ * A dconf path may be either a key or a dir. See dconf_is_key() and
+ * dconf_is_dir() for examples of each.
+ **/
+gboolean
+dconf_is_path (const gchar *string)
+{
+ vars; absolute; no_double_slash; path;
+}
+
+/**
+ * dconf_is_key:
+ * @string: a string
+ * @returns: %TRUE if @string is a key
+ *
+ * Checks if @string is a valid dconf key. dconf keys must start with
+ * '/', not contain '//' and not end with '/'.
+ *
+ * A dconf key is the potential location of a single value within the
+ * database.
+ *
+ * "/a", "/a/b" and "/a/b/c" are examples of keys. "", "/", "a", "a/b",
+ * "//a/b", "/a//b", and "/a/" are examples of strings that are not
+ * keys.
+ **/
+gboolean
+dconf_is_key (const gchar *string)
+{
+ vars; absolute; no_double_slash; key;
+}
+
+/**
+ * dconf_is_dir:
+ * @string: a string
+ * @returns: %TRUE if @string is a dir
+ *
+ * Checks if @string is a valid dconf dir. dconf dirs must start and
+ * end with '/' and not contain '//'.
+ *
+ * A dconf dir refers to a subtree of the database that can contain
+ * other dirs or keys. If @string is a dir, then it will be a prefix of
+ * any key or dir contained within it.
+ *
+ * "/", "/a/" and "/a/b/" are examples of dirs. "", "a/", "a/b/",
+ * "//a/b/", "/a//b/" and "/a" are examples of strings that are not
+ * dirs.
+ **/
+gboolean
+dconf_is_dir (const gchar *string)
+{
+ vars; absolute; no_double_slash; dir;
+}
+
+/**
+ * dconf_is_rel:
+ * @string: a string
+ * @returns: %TRUE if @string is a relative path
+ *
+ * Checks if @string is a valid dconf relative path. A relative path is
+ * a string that, when concatenated to a dir, forms a valid dconf path.
+ * This means that a rel must not start with a '/' or contain '//'.
+ *
+ * A dconf rel may be either a relative key or a relative dir. See
+ * dconf_is_rel_key() and dconf_is_rel_dir() for examples of each.
+ **/
+gboolean
+dconf_is_rel (const gchar *string)
+{
+ vars; relative; no_double_slash; path;
+}
+
+
+/**
+ * dconf_is_rel_key:
+ * @string: a string
+ * @returns: %TRUE if @string is a relative key
+ *
+ * Checks if @string is a valid dconf relative key. A relative key is a
+ * string that, when concatenated to a dir, forms a valid dconf key.
+ * This means that a relative key must not start or end with a '/' or
+ * contain '//'.
+ *
+ * "a", "a/b" and "a/b/c" are examples of relative keys. "", "/", "/a",
+ * "/a/b", "//a/b", "/a//b", and "a/" are examples of strings that are
+ * not relative keys.
+ **/
+gboolean
+dconf_is_rel_key (const gchar *string)
+{
+ vars; relative; no_double_slash; key;
+}
+
+/**
+ * dconf_is_rel_dir:
+ * @string: a string
+ * @returns: %TRUE if @string is a relative dir
+ *
+ * Checks if @string is a valid dconf relative dir. A relative dir is a
+ * string that, when appended to a dir, forms a valid dconf dir. This
+ * means that a relative dir must not start with a '/' or contain '//'
+ * and must end with a '/' except in the case that it is the empty
+ * string (in which case the path specified by appending the rel to a
+ * directory is the original directory).
+ *
+ * "", "a/" and "a/b/" are examples of relative dirs. "/", "/a/",
+ * "/a/b/", "//a/b/", "a//b/" and "a" are examples of strings that are
+ * not relative dirs.
+ **/
+gboolean
+dconf_is_rel_dir (const gchar *string)
+{
+ vars; relative; no_double_slash; dir;
+}
diff --git a/common/dconf-paths.h b/common/dconf-paths.h
new file mode 100644
index 0000000..c9f3609
--- /dev/null
+++ b/common/dconf-paths.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright © 2008-2009 Ryan Lortie
+ * Copyright © 2010 Codethink Limited
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the licence, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Ryan Lortie <desrt@desrt.ca>
+ */
+
+#ifndef _dconf_common_h_
+#define _dconf_common_h_
+
+#include <glib.h>
+
+gboolean dconf_is_path (const gchar *string);
+gboolean dconf_is_key (const gchar *string);
+gboolean dconf_is_dir (const gchar *string);
+
+gboolean dconf_is_rel (const gchar *string);
+gboolean dconf_is_rel_key (const gchar *string);
+gboolean dconf_is_rel_dir (const gchar *string);
+
+#endif /* _dconf_common_h_ */
diff --git a/configure.ac b/configure.ac
index 3307de3..709922d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -20,6 +20,9 @@ AC_PATH_PROG(gio_QUERYMODULES, gio-querymodules, no)
AC_OUTPUT([
gsettings/Makefile
service/Makefile
+ client/Makefile
+ tests/Makefile
gvdb/Makefile
+ bin/Makefile
Makefile
])
diff --git a/engine/dconf-engine.c b/engine/dconf-engine.c
index cb0f6d9..de28190 100644
--- a/engine/dconf-engine.c
+++ b/engine/dconf-engine.c
@@ -1,6 +1,6 @@
#include "dconf-engine.h"
-#include <gvdb/gvdb-reader.h>
+#include <gvdb-reader.h>
struct _DConfEngine
{
@@ -8,7 +8,7 @@ struct _DConfEngine
};
DConfEngine *
-dconf_engine_new (DConfEngineServiceFunc service_func)
+dconf_engine_new (const gchar *context)
{
DConfEngine *engine;
@@ -29,21 +29,19 @@ dconf_engine_ref (DConfEngine *engine)
void
dconf_engine_unref (DConfEngine *engine)
{
- if (g_atomic_int_dec_and_test (&engine->ref_count))
- g_slice_free (DConfEngine, engine);
+ g_slice_free (DConfEngine, engine);
}
GVariant *
-dconf_engine_read (DConfEngine *engine,
- const gchar *key,
- const GVariantType *required_type,
- DConfEngineReadType type)
+dconf_engine_read (DConfEngine *engine,
+ const gchar *key,
+ DConfReadType type)
{
GvdbTable *table;
GVariant *value;
gchar *filename;
- if (type == DCONF_ENGINE_READ_RESET)
+ if (type == DCONF_READ_RESET)
return NULL;
filename = g_build_filename (g_get_user_config_dir (), "dconf", NULL);
diff --git a/engine/dconf-engine.h b/engine/dconf-engine.h
index e3d8b40..f766f0b 100644
--- a/engine/dconf-engine.h
+++ b/engine/dconf-engine.h
@@ -1,18 +1,12 @@
#ifndef _dconf_engine_h_
#define _dconf_engine_h_
+#include <dconf-readtype.h>
#include <glib.h>
typedef struct _DConfEngine DConfEngine;
typedef struct _DConfEngineResetList DConfEngineResetList;
-typedef enum
-{
- DCONF_ENGINE_READ_NORMAL,
- DCONF_ENGINE_READ_SET,
- DCONF_ENGINE_READ_RESET
-} DConfEngineReadType;
-
typedef struct
{
gint bus_type;
@@ -28,14 +22,13 @@ typedef struct
typedef GVariant * (*DConfEngineServiceFunc) (DConfEngine *engine,
DConfEngineMessage *message);
-DConfEngine * dconf_engine_new (DConfEngineServiceFunc service_func);
+DConfEngine * dconf_engine_new (const gchar *context);
void dconf_engine_unref (DConfEngine *engine);
DConfEngine * dconf_engine_ref (DConfEngine *engine);
GVariant * dconf_engine_read (DConfEngine *engine,
const gchar *key,
- const GVariantType *required_type,
- DConfEngineReadType type);
+ DConfReadType type);
gchar ** dconf_engine_list (DConfEngine *engine,
const gchar *path,
DConfEngineResetList *resets);
diff --git a/engine/dconf-readtype.h b/engine/dconf-readtype.h
new file mode 100644
index 0000000..fd4ee46
--- /dev/null
+++ b/engine/dconf-readtype.h
@@ -0,0 +1,11 @@
+#ifndef _dconf_readtype_h_
+#define _dconf_readtype_h_
+
+typedef enum
+{
+ DCONF_READ_NORMAL,
+ DCONF_READ_SET,
+ DCONF_READ_RESET
+} DConfReadType;
+
+#endif
diff --git a/engine/dconf-resetlist.h b/engine/dconf-resetlist.h
new file mode 100644
index 0000000..afaf545
--- /dev/null
+++ b/engine/dconf-resetlist.h
@@ -0,0 +1,20 @@
+#ifndef _dconf_resetlist_h_
+#define _dconf_resetlist_h_
+
+#include <glib.h>
+
+typedef struct
+{
+ gpointer opaque[8];
+} DConfResetList;
+
+void dconf_reset_list_init (DConfResetList *list,
+ const gchar *prefix,
+ const gchar * const *rels,
+ gsize n_rels);
+void dconf_reset_list_add (DConfResetList *list,
+ const gchar *path);
+void dconf_reset_list_clear (DConfResetList *list);
+
+
+#endif
diff --git a/gsettings/Makefile.am b/gsettings/Makefile.am
index 3e8f4c0..d32efb4 100644
--- a/gsettings/Makefile.am
+++ b/gsettings/Makefile.am
@@ -1,4 +1,4 @@
-AM_CFLAGS = $(gio_CFLAGS) -I$(top_srcdir)
+AM_CFLAGS = $(gio_CFLAGS) -I$(top_srcdir)/gvdb -I$(top_srcdir)/engine -I$(top_srcdir)/common
giomodules_LTLIBRARIES = libdconfsettings.la
diff --git a/gsettings/dconfsettingsbackend.c b/gsettings/dconfsettingsbackend.c
index b0ff876..c15da74 100644
--- a/gsettings/dconfsettingsbackend.c
+++ b/gsettings/dconfsettingsbackend.c
@@ -21,7 +21,7 @@
#define G_SETTINGS_ENABLE_BACKEND
#include <gio/gsettingsbackend.h>
-#include <engine/dconf-engine.h>
+#include <dconf-engine.h>
#include <gio/gio.h>
#include <string.h>
@@ -248,7 +248,7 @@ dconf_settings_backend_read (GSettingsBackend *backend,
gboolean default_value)
{
DConfSettingsBackend *dcsb = (DConfSettingsBackend *) backend;
- DConfEngineReadType type;
+ DConfReadType type;
if (!default_value)
{
@@ -257,12 +257,12 @@ dconf_settings_backend_read (GSettingsBackend *backend,
if (dconf_settings_backend_scan_outstanding (dcsb, key, &value))
return value;
- type = DCONF_ENGINE_READ_NORMAL;
+ type = DCONF_READ_NORMAL;
}
else
- type = DCONF_ENGINE_READ_RESET;
+ type = DCONF_READ_RESET;
- return dconf_engine_read (dcsb->engine, key, expected_type, type);
+ return dconf_engine_read (dcsb->engine, key, type);
}
static void
diff --git a/tests/.gitignore b/tests/.gitignore
new file mode 100644
index 0000000..217c33c
--- /dev/null
+++ b/tests/.gitignore
@@ -0,0 +1 @@
+paths
diff --git a/tests/Makefile.am b/tests/Makefile.am
new file mode 100644
index 0000000..7014fa4
--- /dev/null
+++ b/tests/Makefile.am
@@ -0,0 +1,5 @@
+noinst_PROGRAMS = paths
+
+AM_CFLAGS = -I$(top_srcdir) $(gio_CFLAGS)
+paths_SOURCES = paths.c ../common/dconf-paths.c
+paths_LDADD = $(gio_LIBS)
diff --git a/tests/paths.c b/tests/paths.c
new file mode 100644
index 0000000..9211cee
--- /dev/null
+++ b/tests/paths.c
@@ -0,0 +1,98 @@
+#include <common/dconf-paths.h>
+
+static void
+test_paths (void)
+{
+ struct test_case {
+ const gchar *string;
+ guint flags;
+ } cases[] = {
+
+#define invalid 0
+#define path 001
+#define key 002 | path
+#define dir 004 | path
+#define rel 010
+#define relkey 020 | rel
+#define reldir 040 | rel
+
+ { "", reldir },
+ { "/", dir },
+
+ { "/key", key },
+ { "/path/", dir },
+ { "/path/key", key },
+ { "/path/path/", dir },
+ { "/a/b", key },
+ { "/a/b/", dir },
+
+ { "//key", invalid },
+ { "//path/", invalid },
+ { "//path/key", invalid },
+ { "//path/path/", invalid },
+ { "//a/b", invalid },
+ { "//a/b/", invalid },
+
+ { "/key", key },
+ { "/path//", invalid },
+ { "/path/key", key },
+ { "/path/path//", invalid },
+ { "/a/b", key },
+ { "/a/b//", invalid },
+
+ { "/key", key },
+ { "/path/", dir },
+ { "/path//key", invalid },
+ { "/path//path/", invalid },
+ { "/a//b", invalid },
+ { "/a//b/", invalid },
+
+ { "key", relkey },
+ { "path/", reldir },
+ { "path/key", relkey },
+ { "path/path/", reldir },
+ { "a/b", relkey },
+ { "a/b/", reldir },
+
+ { "key", relkey },
+ { "path//", invalid },
+ { "path/key", relkey },
+ { "path/path//", invalid },
+ { "a/b", relkey },
+ { "a/b//", invalid },
+
+ { "key", relkey },
+ { "path/", reldir },
+ { "path//key", invalid },
+ { "path//path/", invalid },
+ { "a//b", invalid },
+ { "a//b/", invalid }
+ };
+ gint i;
+
+ for (i = 0; i < G_N_ELEMENTS (cases); i++)
+ {
+ const gchar *string = cases[i].string;
+ guint flags;
+
+ flags = (dconf_is_path (string) ? 001 : 000) |
+ (dconf_is_key (string) ? 002 : 000) |
+ (dconf_is_dir (string) ? 004 : 000) |
+ (dconf_is_rel (string) ? 010 : 000) |
+ (dconf_is_rel_key (string) ? 020 : 000) |
+ (dconf_is_rel_dir (string) ? 040 : 000);
+
+ if (flags != cases[i].flags)
+ {
+ g_print ("case %i: string '%s' should be %o but is %o",
+ i, string, cases[i].flags, flags);
+ g_assert_not_reached ();
+ }
+ }
+}
+
+int
+main (void)
+{
+ test_paths ();
+}