2003-08-25 Havoc Pennington <hp@pobox.com>
authorHavoc Pennington <hp@redhat.com>
Mon, 25 Aug 2003 14:56:53 +0000 (14:56 +0000)
committerHavoc Pennington <hp@redhat.com>
Mon, 25 Aug 2003 14:56:53 +0000 (14:56 +0000)
        Just noticed that dbus_message_test is hosed, I wonder when I
broke that. I thought make check was passing earlier...

* dbus/dbus-object-tree.c: add new "object tree" to match DCOP
container tree, will replace most of dbus-object-registry

* dbus/dbus-string.c (_dbus_string_append_printf_valist): fix C99
screwup

ChangeLog
dbus/Makefile.am
dbus/dbus-connection.h
dbus/dbus-message-builder.c
dbus/dbus-object-tree.c [new file with mode: 0644]
dbus/dbus-object-tree.h [new file with mode: 0644]
dbus/dbus-string.c
dbus/dbus-test.c
dbus/dbus-test.h

index b5b37d1..3021737 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2003-08-25  Havoc Pennington  <hp@pobox.com>
+
+        Just noticed that dbus_message_test is hosed, I wonder when I
+       broke that. I thought make check was passing earlier...
+       
+       * dbus/dbus-object-tree.c: add new "object tree" to match DCOP 
+       container tree, will replace most of dbus-object-registry
+
+       * dbus/dbus-string.c (_dbus_string_append_printf_valist): fix C99
+       screwup
+
 2003-08-19  Havoc Pennington  <hp@pobox.com>
 
        * dbus/dbus-message.c (decode_string_field): support FIELD_SENDER
index 3537b93..e59877e 100644 (file)
@@ -49,6 +49,8 @@ DBUS_LIB_SOURCES=                             \
        dbus-objectid.c                         \
        dbus-object-registry.c                  \
        dbus-object-registry.h                  \
+       dbus-object-tree.c                      \
+       dbus-object-tree.h                      \
        dbus-pending-call.c                     \
        dbus-resources.c                        \
        dbus-resources.h                        \
index ef10652..7204c8e 100644 (file)
@@ -198,6 +198,54 @@ void                  dbus_connection_send_preallocated      (DBusConnection
                                                               dbus_uint32_t        *client_serial);
 
 
+/* Object tree functionality */
+
+typedef struct DBusObjectTreeVTable DBusObjectTreeVTable;
+
+typedef void              (* DBusObjectTreeUnregisterFunction) (DBusConnection  *connection,
+                                                                const char     **path,
+                                                                void            *user_data);
+typedef DBusHandlerResult (* DBusObjectTreeMessageFunction)    (DBusConnection  *connection,
+                                                                DBusMessage     *message,
+                                                                void            *user_data);
+typedef dbus_bool_t       (* DBusObjectTreeSubdirsFunction)    (DBusConnection  *connection,
+                                                                const char     **path,
+                                                                char          ***subdirs,
+                                                                int             *n_subdirs,
+                                                                void            *user_data);
+typedef dbus_bool_t       (* DBusObjectTreeObjectsFunction)    (DBusConnection  *connection,
+                                                                const char     **path,
+                                                                DBusObjectID   **object_ids,
+                                                                int             *n_object_ids,
+                                                                void            *user_data);
+typedef dbus_bool_t       (* DBusObjectTreeMethodsFunction)    (DBusConnection  *connection,
+                                                                const char     **path,
+                                                                DBusObjectID   **object_ids,
+                                                                int             *n_object_ids,
+                                                                void            *user_data);
+
+struct DBusObjectTreeVTable
+{
+  DBusObjectTreeUnregisterFunction   unregister_function;
+  DBusObjectTreeMessageFunction      message_function;
+  DBusObjectTreeSubdirsFunction      subdirs_function;
+  DBusObjectTreeObjectsFunction      objects_function;
+  DBusObjectTreeMethodsFunction      methods_function;
+  
+  void (* dbus_internal_pad1) (void *);
+  void (* dbus_internal_pad2) (void *);
+  void (* dbus_internal_pad3) (void *);
+  void (* dbus_internal_pad4) (void *);
+};
+
+dbus_bool_t dbus_connection_register_object_tree   (DBusConnection              *connection,
+                                                    const char                 **path,
+                                                    const DBusObjectTreeVTable  *vtable,
+                                                    void                        *user_data);
+void        dbus_connection_unregister_object_tree (DBusConnection              *connection,
+                                                    const char                 **path);
+
+
 DBUS_END_DECLS;
 
 #endif /* DBUS_CONNECTION_H */
index 958e57a..f779c8c 100644 (file)
@@ -411,7 +411,7 @@ _dbus_message_data_load (DBusString       *dest,
           DBusString name;
           int message_type;
 
-          if (_dbus_string_get_length (&line) < strlen ("VALID_HEADER "))
+          if (_dbus_string_get_length (&line) < (int) strlen ("VALID_HEADER "))
             {
               _dbus_warn ("no args to VALID_HEADER\n");
               goto parse_failed;
diff --git a/dbus/dbus-object-tree.c b/dbus/dbus-object-tree.c
new file mode 100644 (file)
index 0000000..7f7e601
--- /dev/null
@@ -0,0 +1,609 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-object-tree.c  DBusObjectTree (internals of DBusConnection)
+ *
+ * Copyright (C) 2003  Red Hat Inc.
+ *
+ * Licensed under the Academic Free License version 1.2
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#include "dbus-object-tree.h"
+#include "dbus-connection-internal.h"
+#include "dbus-internals.h"
+#include "dbus-hash.h"
+#include "dbus-protocol.h"
+#include <string.h>
+#include <stdlib.h>
+
+/**
+ * @defgroup DBusObjectTree A hierarchy of objects with container-contained relationship
+ * @ingroup  DBusInternals
+ * @brief DBusObjectTree is used by DBusConnection to track the object tree
+ *
+ * Types and functions related to DBusObjectTree. These
+ * are all internal.
+ *
+ * @{
+ */
+
+typedef struct DBusObjectSubtree DBusObjectSubtree;
+
+DBusObjectSubtree* _dbus_object_subtree_new   (const char                 **path,
+                                               const DBusObjectTreeVTable  *vtable,
+                                               void                        *user_data);
+void               _dbus_object_subtree_ref   (DBusObjectSubtree           *subtree);
+void               _dbus_object_subtree_unref (DBusObjectSubtree           *subtree);
+
+struct DBusObjectTree
+{
+  int                 refcount;
+  DBusConnection     *connection;
+
+  /* Each subtree is a separate malloc block since that
+   * lets us refcount them and maybe helps with
+   * reentrancy issues when calling back to application code
+   */
+  DBusObjectSubtree **subtrees;
+  int                 n_subtrees;
+  unsigned int        subtrees_sorted : 1;
+};
+
+struct DBusObjectSubtree
+{
+  int                   refcount;
+  char                **path;
+  int                   n_path_elements;
+  DBusObjectTreeVTable  vtable;
+  void                 *user_data;
+};
+
+DBusObjectTree*
+_dbus_object_tree_new (DBusConnection *connection)
+{
+  DBusObjectTree *tree;
+  
+  /* the connection passed in here isn't fully constructed,
+   * so don't do anything more than store a pointer to
+   * it
+   */
+  
+  tree = dbus_new0 (DBusObjectTree, 1);
+  if (tree == NULL)
+    goto oom;
+  
+  tree->refcount = 1;
+  tree->connection = connection;
+  
+  return tree;
+
+ oom:
+  if (tree)
+    {
+      dbus_free (tree);
+    }
+  
+  return NULL;
+}
+
+void
+_dbus_object_tree_ref (DBusObjectTree *tree)
+{
+  _dbus_assert (tree->refcount > 0);
+
+  tree->refcount += 1;
+}
+
+void
+_dbus_object_tree_unref (DBusObjectTree *tree)
+{
+  _dbus_assert (tree->refcount > 0);
+
+  tree->refcount -= 1;
+
+  if (tree->refcount == 0)
+    {
+      if (tree->subtrees)
+        {
+          int i;
+          i = 0;
+          while (i < tree->n_subtrees)
+            {
+              _dbus_object_subtree_unref (tree->subtrees[i]);
+              ++i;
+            }
+        }
+
+      dbus_free (tree);
+    }
+}
+
+static int
+path_cmp (const char **path_a,
+          const char **path_b)
+{
+  /* The comparison is as if the path were flattened
+   * into a single string. strcmp() considers
+   * a shorter string less than a longer string
+   * if the shorter string is the initial part
+   * of the longer
+   */
+  int i;
+
+  i = 0;
+  while (path_a[i] != NULL)
+    {
+      int v;
+      
+      if (path_b[i] == NULL)
+        return 1; /* a is longer than b */
+
+      _dbus_assert (path_a[i] != NULL);
+      _dbus_assert (path_b[i] != NULL);
+      
+      v = strcmp (path_a[i], path_b[i]);
+
+      if (v != 0)
+        return v;
+
+      ++i;
+    }
+
+  _dbus_assert (path_a[i] == NULL);
+  if (path_b[i] == NULL)
+    return 0;
+  
+  /* b is longer than a */
+  return -1;
+}
+
+static int
+subtree_cmp (DBusObjectSubtree *subtree_a,
+             DBusObjectSubtree *subtree_b)
+{
+  return path_cmp ((const char**) subtree_a->path,
+                   (const char**) subtree_b->path);
+}
+
+static int
+subtree_qsort_cmp (const void *a,
+                   const void *b)
+{
+  DBusObjectSubtree **subtree_a_p = (void*) a;
+  DBusObjectSubtree **subtree_b_p = (void*) b;
+
+  return subtree_cmp (*subtree_a_p, *subtree_b_p);  
+}
+
+/* Returns TRUE if a is a subdir of b or vice
+ * versa. This is the case if one is a subpath
+ * of the other.
+ */
+static dbus_bool_t
+path_overlaps (const char **path_a,
+               const char **path_b)
+{
+  int i;
+
+  i = 0;
+  while (path_a[i] != NULL)
+    {
+      int v;
+      
+      if (path_b[i] == NULL)
+        return TRUE; /* b is subpath of a */
+
+      _dbus_assert (path_a[i] != NULL);
+      _dbus_assert (path_b[i] != NULL);
+      
+      v = strcmp (path_a[i], path_b[i]);
+
+      if (v != 0)
+        return FALSE; /* they overlap until here and then are different,
+                       * not overlapping
+                       */
+
+      ++i;
+    }
+
+  /* b is either the same as or a superset of a */
+  _dbus_assert (path_a[i] == NULL);
+  return TRUE;
+}
+
+static dbus_bool_t
+find_subtree (DBusObjectTree *tree,
+              const char    **path,
+              int            *idx_p)
+{
+  int i;
+  
+  if (tree->subtrees == NULL)
+    return FALSE;
+  
+  if (!tree->subtrees_sorted)
+    {
+      qsort (tree->subtrees,
+             tree->n_subtrees,
+             sizeof (DBusObjectSubtree*),
+             subtree_qsort_cmp);
+      tree->subtrees_sorted = TRUE;
+    }
+
+  /* FIXME this should be a binary search,
+   * as that's the whole point of the sorting
+   */
+  i = 0;
+  while (i < tree->n_subtrees)
+    {
+      int v;
+
+      v = path_cmp (path,
+                    (const char**) tree->subtrees[i]->path);
+      if (v == 0)
+        {
+          if (idx_p)
+            *idx_p = i;
+          return TRUE;
+        }
+      else if (v > 0)
+        return FALSE;
+      
+      ++i;
+    }
+
+  return FALSE;
+}
+
+#ifndef DBUS_DISABLE_CHECKS
+static void
+check_overlap (DBusObjectTree *tree,
+               const char    **path)
+{
+  int i;
+
+  i = 0;
+  while (i < tree->n_subtrees)
+    {
+      if (path_overlaps (path, (const char**) tree->subtrees[i]->path))
+        {
+          _dbus_warn ("New path (path[0] = %s) overlaps old path (path[0] = %s)\n",
+                      path[0], tree->subtrees[i]->path[0]);
+        }
+      ++i;
+    }
+}
+#endif
+
+/**
+ * Registers a new subtree in the global object tree.
+ *
+ * @param tree the global object tree
+ * @param path NULL-terminated array of path elements giving path to subtree
+ * @param vtable the vtable used to traverse this subtree
+ * @param user_data user data to pass to methods in the vtable
+ * @returns #FALSE if not enough memory
+ */
+dbus_bool_t
+_dbus_object_tree_register (DBusObjectTree              *tree,
+                            const char                 **path,
+                            const DBusObjectTreeVTable  *vtable,
+                            void                        *user_data)
+{
+  DBusObjectSubtree  *subtree;
+  DBusObjectSubtree **new_subtrees;
+  int new_n_subtrees;
+
+  _dbus_assert (path != NULL);
+#ifndef DBUS_DISABLE_CHECKS
+  check_overlap (tree, path);
+#endif
+  _dbus_assert (path[0] != NULL);
+  
+  subtree = _dbus_object_subtree_new (path, vtable, user_data);
+  if (subtree == NULL)
+    return FALSE;
+  
+  /* FIXME we should do the "double alloc each time" standard thing */
+  new_n_subtrees = tree->n_subtrees + 1;
+  new_subtrees = dbus_realloc (tree->subtrees,
+                               new_n_subtrees);
+  if (new_subtrees == NULL)
+    {
+      _DBUS_ZERO (subtree->vtable); /* to avoid assertion in unref() */
+      _dbus_object_subtree_unref (subtree);
+      return FALSE;
+    }
+
+  tree->subtrees[tree->n_subtrees] = subtree;
+  tree->subtrees_sorted = FALSE;
+  tree->n_subtrees = new_n_subtrees;
+  tree->subtrees = new_subtrees;
+
+  return TRUE;
+}
+
+/**
+ * Unregisters an object subtree that was registered with the
+ * same path.
+ *
+ * @param tree the global object tree
+ * @param path path to the subtree (same as the one passed to _dbus_object_tree_register())
+ */
+void
+_dbus_object_tree_unregister_and_unlock (DBusObjectTree          *tree,
+                                         const char             **path)
+{
+  int i;
+  DBusObjectSubtree *subtree;
+
+  _dbus_assert (path != NULL);
+  _dbus_assert (path[0] != NULL);
+  
+  if (!find_subtree (tree, path, &i))
+    {
+      _dbus_warn ("Attempted to unregister subtree (path[0] = %s) which isn't registered\n",
+                  path[0]);
+      return;
+    }
+
+  subtree = tree->subtrees[i];
+
+  /* assumes a 0-byte memmove is OK */
+  memmove (&tree->subtrees[i],
+           &tree->subtrees[i+1],
+           (tree->n_subtrees - i - 1) * sizeof (tree->subtrees[0]));
+  tree->n_subtrees -= 1;
+  
+  _dbus_object_subtree_ref (subtree);
+
+  /* Unlock and call application code */
+  _dbus_connection_unlock (tree->connection);
+  
+  if (subtree->vtable.unregister_function)
+    {
+      (* subtree->vtable.unregister_function) (tree->connection,
+                                               (const char**) subtree->path,
+                                               subtree->user_data);
+      _DBUS_ZERO (subtree->vtable);
+    }
+}
+
+/**
+ * Tries to dispatch a message by directing it to the object tree
+ * node listed in the message header, if any.
+ *
+ * @param tree the global object tree
+ * @param message the message to dispatch
+ * @returns whether message was handled successfully
+ */
+DBusHandlerResult
+_dbus_object_tree_dispatch_and_unlock (DBusObjectTree          *tree,
+                                       DBusMessage             *message)
+{
+  
+  
+}
+
+DBusObjectSubtree*
+_dbus_object_subtree_new (const char                 **path,
+                          const DBusObjectTreeVTable  *vtable,
+                          void                        *user_data)
+{
+  DBusObjectSubtree *subtree;
+
+  subtree = dbus_new0 (DBusObjectSubtree, 1);
+  if (subtree == NULL)
+    goto oom;
+
+  _dbus_assert (path != NULL);
+  _dbus_assert (path[0] != NULL);
+  
+  subtree->path = _dbus_dup_string_array (path);
+  if (subtree->path == NULL)
+    goto oom;
+
+  subtree->vtable = *vtable;
+  subtree->user_data = user_data;
+  
+  subtree->refcount = 1;
+
+  /* count path elements */
+  while (subtree->path[subtree->n_path_elements])
+    subtree->n_path_elements += 1;
+  
+  return subtree;
+
+ oom:
+  if (subtree)
+    {
+      dbus_free_string_array (subtree->path);
+      dbus_free (subtree);
+    }
+  
+  return NULL;
+}
+
+void
+_dbus_object_subtree_ref (DBusObjectSubtree *subtree)
+{
+  _dbus_assert (subtree->refcount > 0);
+
+  subtree->refcount += 1;
+}
+
+void
+_dbus_object_subtree_unref (DBusObjectSubtree *subtree)
+{
+  _dbus_assert (subtree->refcount > 0);
+
+  subtree->refcount -= 1;
+
+  if (subtree->refcount == 0)
+    {
+      _dbus_assert (subtree->vtable.unregister_function == NULL);
+      
+      dbus_free_string_array (subtree->path);
+
+      dbus_free (subtree);
+    }
+}
+
+/** @} */
+
+#ifdef DBUS_BUILD_TESTS
+#include "dbus-test.h"
+#include <stdio.h>
+
+static dbus_bool_t
+test_subtree_cmp (const char **path1,
+                  const char **path2,
+                  int          expected,
+                  dbus_bool_t  reverse)
+{
+  DBusObjectSubtree *subtree1;
+  DBusObjectSubtree *subtree2;
+  dbus_bool_t retval;
+  DBusObjectTreeVTable vtable;
+
+  _DBUS_ZERO (vtable);
+
+  retval = FALSE;
+  
+  subtree1 = _dbus_object_subtree_new (path1, &vtable, NULL);
+  subtree2 = _dbus_object_subtree_new (path2, &vtable, NULL);
+  if (subtree1 == NULL || subtree2 == NULL)
+    goto out;
+
+  _dbus_assert (subtree_cmp (subtree1, subtree2) == expected);
+
+  retval = TRUE;
+  
+ out:
+
+  if (subtree1)
+    _dbus_object_subtree_unref (subtree1);
+
+  if (subtree2)
+    _dbus_object_subtree_unref (subtree2);
+
+  if (retval && reverse)
+    {
+      /* Verify that the reverse also holds */
+      if (expected > 0)
+        return test_subtree_cmp (path2, path1, -1, FALSE);
+      else if (expected < 0)
+        return test_subtree_cmp (path2, path1, 1, FALSE);
+      else
+        return test_subtree_cmp (path2, path1, 0, FALSE);
+    }
+  
+  return retval;
+}
+
+static void
+test_path_overlap (const char  **path1,
+                   const char  **path2,
+                   dbus_bool_t   expected)
+{
+  _dbus_assert (path_overlaps (path1, path2) == expected);
+  _dbus_assert (path_overlaps (path2, path1) == expected);
+}
+
+static dbus_bool_t
+object_tree_test_iteration (void *data)
+{
+  const char *path1[] = { "foo", NULL };
+  const char *path2[] = { "foo", "bar", NULL };
+  const char *path3[] = { "foo", "bar", "baz", NULL };
+  const char *path4[] = { "foo", "bar", "boo", NULL };
+  const char *path5[] = { "blah", NULL };
+  DBusObjectSubtree *subtree1;
+  DBusObjectSubtree *subtree2;
+  DBusObjectTree *tree;
+
+  tree = NULL;
+  subtree1 = NULL;
+  subtree2 = NULL;
+
+  test_path_overlap (path1, path1, TRUE);
+  test_path_overlap (path1, path2, TRUE);
+  test_path_overlap (path1, path3, TRUE);
+  test_path_overlap (path1, path4, TRUE);
+  test_path_overlap (path1, path5, FALSE); 
+
+  test_path_overlap (path2, path2, TRUE);
+  test_path_overlap (path2, path3, TRUE);
+  test_path_overlap (path2, path4, TRUE);
+  test_path_overlap (path2, path5, FALSE);
+
+  test_path_overlap (path3, path3, TRUE);
+  test_path_overlap (path3, path4, FALSE);
+  test_path_overlap (path3, path5, FALSE);
+
+  test_path_overlap (path4, path4, TRUE);
+  test_path_overlap (path4, path5, FALSE);
+
+  test_path_overlap (path5, path5, TRUE);
+  
+  if (!test_subtree_cmp (path1, path1, 0, TRUE))
+    goto out;
+  if (!test_subtree_cmp (path3, path3, 0, TRUE))
+    goto out;
+  /* When testing -1, the reverse also gets tested */
+  if (!test_subtree_cmp (path1, path2, -1, TRUE))
+    goto out;
+  if (!test_subtree_cmp (path1, path3, -1, TRUE))
+    goto out;
+  if (!test_subtree_cmp (path2, path3, -1, TRUE))
+    goto out;
+  if (!test_subtree_cmp (path2, path4, -1, TRUE))
+    goto out;
+  if (!test_subtree_cmp (path3, path4, -1, TRUE))
+    goto out;
+  if (!test_subtree_cmp (path5, path1, -1, TRUE))
+    goto out;
+  
+  tree = _dbus_object_tree_new (NULL);
+  if (tree == NULL)
+    goto out;
+
+ out:
+  if (subtree1)
+    _dbus_object_subtree_unref (subtree1);
+  if (subtree2)
+    _dbus_object_subtree_unref (subtree2);
+  if (tree)
+    _dbus_object_tree_unref (tree);
+  
+  return TRUE;
+}
+
+/**
+ * @ingroup DBusObjectTree
+ * Unit test for DBusObjectTree
+ * @returns #TRUE on success.
+ */
+dbus_bool_t
+_dbus_object_tree_test (void)
+{
+  _dbus_test_oom_handling ("object tree",
+                           object_tree_test_iteration,
+                           NULL);
+  
+  return TRUE;
+}
+
+#endif /* DBUS_BUILD_TESTS */
diff --git a/dbus/dbus-object-tree.h b/dbus/dbus-object-tree.h
new file mode 100644 (file)
index 0000000..0603333
--- /dev/null
@@ -0,0 +1,48 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-object-tree.h  DBusObjectTree (internals of DBusConnection)
+ *
+ * Copyright (C) 2003  Red Hat Inc.
+ *
+ * Licensed under the Academic Free License version 1.2
+ * 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#ifndef DBUS_OBJECT_TREE_H
+#define DBUS_OBJECT_TREE_H
+
+#include <dbus/dbus-connection.h>
+
+DBUS_BEGIN_DECLS;
+
+typedef struct DBusObjectTree DBusObjectTree;
+
+DBusObjectTree* _dbus_object_tree_new   (DBusConnection *connection);
+void            _dbus_object_tree_ref   (DBusObjectTree *tree);
+void            _dbus_object_tree_unref (DBusObjectTree *tree);
+
+dbus_bool_t       _dbus_object_tree_register              (DBusObjectTree              *tree,
+                                                           const char                 **path,
+                                                           const DBusObjectTreeVTable  *vtable,
+                                                           void                        *user_data);
+void              _dbus_object_tree_unregister_and_unlock (DBusObjectTree              *tree,
+                                                           const char                 **path);
+DBusHandlerResult _dbus_object_tree_dispatch_and_unlock   (DBusObjectTree              *tree,
+                                                           DBusMessage                 *message);
+
+
+DBUS_END_DECLS;
+
+#endif /* DBUS_OBJECT_TREE_H */
index 98b4c60..75b38b9 100644 (file)
@@ -1002,9 +1002,9 @@ _dbus_string_append_printf_valist  (DBusString        *str,
                                     const char        *format,
                                     va_list            args)
 {
-  DBUS_STRING_PREAMBLE (str);
   int len;
   char c;
+  DBUS_STRING_PREAMBLE (str);
   
   /* Measure the message length without terminating nul */
   len = vsnprintf (&c, 1, format, args);
index 8a99d17..2ab7fc2 100644 (file)
@@ -112,6 +112,12 @@ dbus_internal_do_not_use_run_tests (const char *test_data_dir)
   
   check_memleaks ();
 
+  printf ("%s: running object tree tests\n", "dbus-test");
+  if (!_dbus_object_tree_test ())
+    die ("object tree");
+  
+  check_memleaks ();
+  
   printf ("%s: running object tests\n", "dbus-test");
   if (!_dbus_object_test ())
     die ("object");
index 276e8f9..b6c0266 100644 (file)
@@ -56,6 +56,7 @@ dbus_bool_t _dbus_memory_test        (void);
 dbus_bool_t _dbus_object_test          (void);
 dbus_bool_t _dbus_object_id_test       (void);
 dbus_bool_t _dbus_object_registry_test (void);
+dbus_bool_t _dbus_object_tree_test     (void);
 dbus_bool_t _dbus_pending_call_test    (const char *test_data_dir);
 
 void        dbus_internal_do_not_use_run_tests         (const char          *test_data_dir);