2002-12-11 Havoc Pennington <hp@pobox.com>
authorHavoc Pennington <hp@redhat.com>
Thu, 12 Dec 2002 04:26:46 +0000 (04:26 +0000)
committerHavoc Pennington <hp@redhat.com>
Thu, 12 Dec 2002 04:26:46 +0000 (04:26 +0000)
* dbus/dbus-types.h: add dbus_unichar

* dbus/dbus-internals.c (_dbus_verbose): use _dbus_getenv

* dbus/dbus-connection.c (dbus_connection_send_message): return
TRUE on success

* dbus/dbus-transport.c: include dbus-watch.h

* dbus/dbus-connection.c: include dbus-message-internal.h

* HACKING: add file with coding guidelines stuff.

* dbus/dbus-string.h, dbus/dbus-string.c: Encapsulate all string
handling here, for security purposes (as in vsftpd). Not actually
using this class yet.

* dbus/dbus-sysdeps.h, dbus/dbus-sysdeps.c: Encapsulate all
system/libc usage here, as in vsftpd, for ease of auditing (and
should also simplify portability). Haven't actually moved all the
system/libc usage into here yet.

15 files changed:
ChangeLog
HACKING [new file with mode: 0644]
dbus/Makefile.am
dbus/dbus-connection.c
dbus/dbus-hash.c
dbus/dbus-internals.c
dbus/dbus-internals.h
dbus/dbus-string.c [new file with mode: 0644]
dbus/dbus-string.h [new file with mode: 0644]
dbus/dbus-sysdeps.c [new file with mode: 0644]
dbus/dbus-sysdeps.h [new file with mode: 0644]
dbus/dbus-test.c
dbus/dbus-test.h
dbus/dbus-transport.c
dbus/dbus-types.h

index dce9ece..f9e6132 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,27 @@
+2002-12-11  Havoc Pennington  <hp@pobox.com>
+
+       * dbus/dbus-types.h: add dbus_unichar
+
+       * dbus/dbus-internals.c (_dbus_verbose): use _dbus_getenv
+
+       * dbus/dbus-connection.c (dbus_connection_send_message): return
+       TRUE on success
+
+       * dbus/dbus-transport.c: include dbus-watch.h   
+
+       * dbus/dbus-connection.c: include dbus-message-internal.h
+
+       * HACKING: add file with coding guidelines stuff.
+
+       * dbus/dbus-string.h, dbus/dbus-string.c: Encapsulate all string
+       handling here, for security purposes (as in vsftpd). Not actually
+       using this class yet.
+
+       * dbus/dbus-sysdeps.h, dbus/dbus-sysdeps.c: Encapsulate all
+       system/libc usage here, as in vsftpd, for ease of auditing (and
+       should also simplify portability). Haven't actually moved all the
+       system/libc usage into here yet.
+       
 2002-11-25  Havoc Pennington  <hp@pobox.com>
 
        * dbus/dbus-internals.c (_dbus_verbose): fix to not 
diff --git a/HACKING b/HACKING
new file mode 100644 (file)
index 0000000..8d0b175
--- /dev/null
+++ b/HACKING
@@ -0,0 +1,62 @@
+The guidelines in this file are the ideals; it's better to send a
+not-fully-following-guidelines patch than no patch at all, though.  We
+can always polish it up.
+
+Mailing list
+===
+
+The D-BUS mailing list is message-bus-list@freedesktop.org; discussion
+of patches, etc. should go there.
+
+Security
+===
+
+Most of D-BUS is security sensitive.  Guidelines related to that:
+
+ - avoid memcpy(), sprintf(), strlen(), snprintf, strlcat(),
+   strstr(), strtok(), or any of this stuff. Use DBusString. 
+   If DBusString doesn't have the feature you need, add it 
+   to DBusString. 
+
+   There are some exceptions, for example
+   if your strings are just used to index a hash table 
+   and you don't do any parsing/modification of them, perhaps
+   DBusString is wasteful and wouldn't help much. But definitely 
+   if you're doing any parsing, reallocation, etc. use DBusString.
+
+ - do not include system headers outside of dbus-memory.c, 
+   dbus-sysdeps.c, and other places where they are already 
+   included. This gives us one place to audit all external 
+   dependencies on features in libc, etc.
+
+ - do not use libc features that are "complicated" 
+   and may contain security holes. For example, you probably shouldn't
+   try to use regcomp() to compile an untrusted regular expression.
+   Regular expressions are just too complicated, and there are many 
+   different libc's out there.
+
+ - we need to design the message bus daemon (and any similar features)
+   to use limited privileges, run in a chroot jail, and so on.
+
+http://vsftpd.beasts.org/ has other good security suggestions.
+
+Coding Style
+===
+
+ - The C library uses GNU coding conventions, with GLib-like
+   extensions (e.g. lining up function arguments). The
+   Qt wrapper uses KDE coding conventions.
+
+ - Write docs for all non-static functions and structs and so on. try
+   "doxygen Doxyfile" prior to commit and be sure there are no
+   warnings printed.
+
+ - All external interfaces (network protocols, file formats, etc.)
+   should have documented specifications sufficient to allow an
+   alternative implementation to be written. Our implementation should
+   be strict about specification compliance (should not for example
+   heuristically parse a file and accept not-well-formed
+   data). Avoiding heuristics is also important for security reasons;
+   if it looks funny, ignore it (or exit, or disconnect).
+
index f830bb7..f74c8be 100644 (file)
@@ -48,7 +48,11 @@ libdbus_convenience_la_SOURCES=                      \
        dbus-internals.c                        \
        dbus-internals.h                        \
        dbus-list.c                             \
-       dbus-list.h
+       dbus-list.h                             \
+       dbus-string.c                           \
+       dbus-string.h                           \
+       dbus-sysdeps.c                          \
+       dbus-sysdeps.h
 
 libdbus_1_la_LIBADD=  $(DBUS_CLIENT_LIBS) libdbus-convenience.la
 ## don't export symbols that start with "_" (we use this 
index f60e53a..3c6df57 100644 (file)
@@ -27,6 +27,7 @@
 #include "dbus-watch.h"
 #include "dbus-connection-internal.h"
 #include "dbus-list.h"
+#include "dbus-message-internal.h"
 
 /**
  * @defgroup DBusConnection DBusConnection
@@ -465,6 +466,8 @@ dbus_connection_send_message (DBusConnection *connection,
   if (connection->n_outgoing == 1)
     _dbus_transport_messages_pending (connection->transport,
                                       connection->n_outgoing);
+
+  return TRUE;
 }
 
 /**
index 48e96ca..f4a2258 100644 (file)
@@ -1405,4 +1405,4 @@ _dbus_hash_test (void)
   return TRUE;
 }
 
-#endif
+#endif /* DBUS_BUILD_TESTS */
index 0fd01c2..f3527eb 100644 (file)
@@ -164,7 +164,7 @@ _dbus_verbose (const char *format,
   
   if (!initted)
     {
-      verbose = getenv ("DBUS_VERBOSE") != NULL;
+      verbose = _dbus_getenv ("DBUS_VERBOSE") != NULL;
       initted = TRUE;
       if (!verbose)
         return;
index 5d00139..fd54a5f 100644 (file)
@@ -32,8 +32,7 @@
 #include <dbus/dbus-memory.h>
 #include <dbus/dbus-types.h>
 #include <dbus/dbus-errors.h>
-#include <stdlib.h> /* for abort() */
-#include <string.h> /* just so it's there in every file */
+#include <dbus/dbus-sysdeps.h>
 
 DBUS_BEGIN_DECLS;
 
@@ -52,7 +51,7 @@ do {                                                                    \
     {                                                                   \
       _dbus_warn ("Assertion failed \"%s\" file \"%s\" line %d\n",      \
                   #condition, __FILE__, __LINE__);                      \
-      abort ();                                                         \
+      _dbus_abort ();                                                   \
     }                                                                   \
 } while (0)
 
@@ -60,10 +59,10 @@ do {                                                                    \
 do {                                                                            \
     _dbus_warn ("File \"%s\" line %d should not have been reached: %s\n",       \
                __FILE__, __LINE__, (explanation));                              \
-    abort ();                                                                   \
+    _dbus_abort ();                                                             \
 } while (0)
 
-#define _DBUS_N_ELEMENTS(array) (sizeof ((array)) / sizeof ((array)[0]))
+#define _DBUS_N_ELEMENTS(array) ((int) (sizeof ((array)) / sizeof ((array)[0])))
 
 #define _DBUS_POINTER_TO_INT(pointer) ((long)(pointer))
 #define _DBUS_INT_TO_POINTER(integer) ((void*)((long)(integer)))
diff --git a/dbus/dbus-string.c b/dbus/dbus-string.c
new file mode 100644 (file)
index 0000000..088ca35
--- /dev/null
@@ -0,0 +1,1224 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-string.c String utility class (internal to D-BUS implementation)
+ * 
+ * Copyright (C) 2002  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-string.h"
+/* we allow a system header here, for speed/convenience */
+#include <string.h>
+
+/**
+ * @defgroup DBusString string class
+ * @ingroup  DBusInternals
+ * @brief DBusString data structure
+ *
+ * Types and functions related to DBusString. DBusString is intended
+ * to be a string class that makes it hard to mess up security issues
+ * (and just in general harder to write buggy code).  It should be
+ * used (or extended and then used) rather than the libc stuff in
+ * string.h.  The string class is a bit inconvenient at spots because
+ * it handles out-of-memory failures and tries to be extra-robust.
+ * 
+ * A DBusString has a maximum length set at initialization time; this
+ * can be used to ensure that a buffer doesn't get too big.  The
+ * _dbus_string_lengthen() method checks for overflow, and for max
+ * length being exceeded.
+ * 
+ * Try to avoid conversion to a plain C string, i.e. add methods on
+ * the string object instead, only convert to C string when passing
+ * things out to the public API. In particular, no sprintf, strcpy,
+ * strcat, any of that should be used. The GString feature of
+ * accepting negative numbers for "length of string" is also absent,
+ * because it could keep us from detecting bogus huge lengths. i.e. if
+ * we passed in some bogus huge length it would be taken to mean
+ * "current length of string" instead of "broken crack"
+ */
+
+/**
+ * @defgroup DBusStringInternals DBusString implementation details
+ * @ingroup  DBusInternals
+ * @brief DBusString implementation details
+ *
+ * The guts of DBusString.
+ *
+ * @{
+ */
+
+/**
+ * @brief Internals of DBusString.
+ * 
+ * DBusString internals. DBusString is an opaque objects, it must be
+ * used via accessor functions.
+ */
+typedef struct
+{
+  unsigned char *str;            /**< String data, plus nul termination */
+  int            len;            /**< Length without nul */
+  int            allocated;      /**< Allocated size of data */
+  int            max_length;     /**< Max length of this string. */
+  unsigned int   constant : 1;   /**< String data is not owned by DBusString */
+  unsigned int   locked : 1;     /**< DBusString has been locked and can't be changed */
+  unsigned int   invalid : 1;    /**< DBusString is invalid (e.g. already freed) */
+} DBusRealString;
+
+/**
+ * Checks a bunch of assertions about a string object
+ *
+ * @param real the DBusRealString
+ */
+#define DBUS_GENERIC_STRING_PREAMBLE(real) _dbus_assert ((real) != NULL); _dbus_assert (!(real)->invalid); _dbus_assert ((real)->len >= 0); _dbus_assert ((real)->allocated >= 0); _dbus_assert ((real)->max_length >= 0); _dbus_assert ((real)->len <= (real)->allocated); _dbus_assert ((real)->len <= (real)->max_length)
+
+/**
+ * Checks assertions about a string object that needs to be
+ * modifiable - may not be locked or const. Also declares
+ * the "real" variable pointing to DBusRealString. 
+ * @param str the string
+ */
+#define DBUS_STRING_PREAMBLE(str) DBusRealString *real = (DBusRealString*) str; \
+  DBUS_GENERIC_STRING_PREAMBLE (real);                                          \
+  _dbus_assert (!(real)->constant);                                             \
+  _dbus_assert (!(real)->locked)
+
+/**
+ * Checks assertions about a string object that may be locked but
+ * can't be const. i.e. a string object that we can free.  Also
+ * declares the "real" variable pointing to DBusRealString.
+ *
+ * @param str the string
+ */
+#define DBUS_LOCKED_STRING_PREAMBLE(str) DBusRealString *real = (DBusRealString*) str; \
+  DBUS_GENERIC_STRING_PREAMBLE (real);                                                 \
+  _dbus_assert (!(real)->constant)
+
+/**
+ * Checks assertions about a string that may be const or locked.  Also
+ * declares the "real" variable pointing to DBusRealString.
+ * @param str the string.
+ */
+#define DBUS_CONST_STRING_PREAMBLE(str) const DBusRealString *real = (DBusRealString*) str; \
+  DBUS_GENERIC_STRING_PREAMBLE (real)
+
+/** @} */
+
+/**
+ * @addtogroup DBusString
+ * @{
+ */
+
+/**
+ * Initializes a string. The maximum length may be _DBUS_INT_MAX for
+ * no maximum. The string starts life with zero length.
+ * The string must eventually be freed with _dbus_string_free().
+ *
+ * @param str memory to hold the string
+ * @param max_length the maximum size of the string
+ * @returns #TRUE on success
+ */
+dbus_bool_t
+_dbus_string_init (DBusString *str,
+                   int         max_length)
+{
+  DBusRealString *real;
+  
+  _dbus_assert (str != NULL);
+  _dbus_assert (max_length >= 0);
+
+  _dbus_assert (sizeof (DBusString) == sizeof (DBusRealString));
+  
+  real = (DBusRealString*) str;
+
+  /* It's very important not to touch anything
+   * other than real->str if we're going to fail,
+   * since we also use this function to reset
+   * an existing string, e.g. in _dbus_string_steal_data()
+   */
+  
+#define INITIAL_ALLOC 2
+  
+  real->str = dbus_malloc (INITIAL_ALLOC);
+  if (real->str == NULL)
+    return FALSE;
+
+  real->allocated = INITIAL_ALLOC;
+  real->len = 0;
+  real->str[real->len] = '\0';
+  
+  real->max_length = max_length;
+  real->constant = FALSE;
+  real->locked = FALSE;
+  real->invalid = FALSE;
+
+  return TRUE;
+}
+
+/**
+ * Initializes a constant string. The value parameter is not copied
+ * (should be static), and the string may never be modified.
+ * It is safe but not necessary to call _dbus_string_free()
+ * on a const string.
+ * 
+ * @param str memory to use for the string
+ * @param value a string to be stored in str (not copied!!!)
+ */
+void
+_dbus_string_init_const (DBusString *str,
+                         const char *value)
+{
+  DBusRealString *real;
+  
+  _dbus_assert (str != NULL);
+  _dbus_assert (value != NULL);
+
+  real = (DBusRealString*) str;
+  
+  real->str = (char*) value;
+  real->len = strlen (real->str);
+  real->allocated = real->len;
+  real->max_length = real->len;
+  real->constant = TRUE;
+  real->invalid = FALSE;
+}
+
+/**
+ * Frees a string created by _dbus_string_init().
+ *
+ * @param str memory where the string is stored.
+ */
+void
+_dbus_string_free (DBusString *str)
+{
+  DBUS_LOCKED_STRING_PREAMBLE (str);
+  
+  if (real->constant)
+    return;
+  
+  dbus_free (real->str);
+
+  real->invalid = TRUE;
+}
+
+/**
+ * Locks a string such that any attempts to change the string
+ * will result in aborting the program. Also, if the string
+ * is wasting a lot of memory (allocation is larger than what
+ * the string is really using), _dbus_string_lock() will realloc
+ * the string's data to "compact" it.
+ *
+ * @param str the string to lock.
+ */
+void
+_dbus_string_lock (DBusString *str)
+{  
+  DBUS_LOCKED_STRING_PREAMBLE (str); /* can lock multiple times */
+
+  real->locked = TRUE;
+
+  /* Try to realloc to avoid excess memory usage, since
+   * we know we won't change the string further
+   */
+#define MAX_WASTE 24
+  if (real->allocated > (real->len + MAX_WASTE))
+    {
+      char *new_str;
+      int new_allocated;
+
+      new_allocated = real->len + 1;
+
+      new_str = dbus_realloc (real->str, new_allocated);
+      if (new_str != NULL)
+        {
+          real->str = new_str;
+          real->allocated = new_allocated;
+        }
+    }
+}
+
+/**
+ * Gets the raw character buffer from the string.  The returned buffer
+ * will be nul-terminated, but note that strings may contain binary
+ * data so there may be extra nul characters prior to the termination.
+ * This function should be little-used, extend DBusString or add
+ * stuff to dbus-sysdeps.c instead. It's an error to use this
+ * function on a const string.
+ *
+ * @param str the string
+ * @param data_return place to store the returned data
+ */
+void
+_dbus_string_get_data (DBusString        *str,
+                       char             **data_return)
+{
+  DBUS_STRING_PREAMBLE (str);
+  _dbus_assert (data_return != NULL);
+  
+  *data_return = real->str;
+}
+
+/**
+ * Gets the raw character buffer from a const string. 
+ *
+ * @param str the string
+ * @param data_return location to store returned data
+ */
+void
+_dbus_string_get_const_data (const DBusString  *str,
+                             const char       **data_return)
+{
+  DBUS_CONST_STRING_PREAMBLE (str);
+  _dbus_assert (data_return != NULL);
+  
+  *data_return = real->str;
+}
+
+/**
+ * Gets a sub-portion of the raw character buffer from the
+ * string. The "len" field is required simply for error
+ * checking, to be sure you don't try to use more
+ * string than exists. The nul termination of the
+ * returned buffer remains at the end of the entire
+ * string, not at start + len.
+ *
+ * @param str the string
+ * @param data_return location to return the buffer
+ * @param start byte offset to return
+ * @param len length of segment to return
+ */
+void
+_dbus_string_get_data_len (DBusString *str,
+                           char      **data_return,
+                           int         start,
+                           int         len)
+{
+  DBUS_STRING_PREAMBLE (str);
+  _dbus_assert (data_return != NULL);
+  _dbus_assert (start >= 0);
+  _dbus_assert (len >= 0);
+  _dbus_assert ((start + len) <= real->len);
+  
+  *data_return = real->str + start;
+}
+
+/**
+ * const version of _dbus_string_get_data_len().
+ *
+ * @param str the string
+ * @param data_return location to return the buffer
+ * @param start byte offset to return
+ * @param len length of segment to return
+ */
+void
+_dbus_string_get_const_data_len (const DBusString  *str,
+                                 const char       **data_return,
+                                 int                start,
+                                 int                len)
+{
+  DBUS_CONST_STRING_PREAMBLE (str);
+  _dbus_assert (data_return != NULL);
+  _dbus_assert (start >= 0);
+  _dbus_assert (len >= 0);
+  _dbus_assert ((start + len) <= real->len);
+  
+  *data_return = real->str + start;
+}
+
+/**
+ * Like _dbus_string_get_data(), but removes the
+ * gotten data from the original string. The caller
+ * must free the data returned. This function may
+ * fail due to lack of memory, and return #FALSE.
+ *
+ * @param str the string
+ * @param data_return location to return the buffer
+ * @returns #TRUE on success
+ */
+dbus_bool_t
+_dbus_string_steal_data (DBusString        *str,
+                         char             **data_return)
+{
+  DBUS_STRING_PREAMBLE (str);
+  _dbus_assert (data_return != NULL);
+  
+  *data_return = real->str;
+
+  /* reset the string */
+  if (!_dbus_string_init (str, real->max_length))
+    {
+      /* hrm, put it back then */
+      real->str = *data_return;
+      *data_return = NULL;
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+/**
+ * Like _dbus_string_get_data_len(), but removes the gotten data from
+ * the original string. The caller must free the data returned. This
+ * function may fail due to lack of memory, and return #FALSE.
+ * The returned string is nul-terminated and has length len.
+ *
+ * @param str the string
+ * @param data_return location to return the buffer
+ * @param start the start of segment to steal
+ * @param len the length of segment to steal
+ * @returns #TRUE on success
+ */
+dbus_bool_t
+_dbus_string_steal_data_len (DBusString        *str,
+                             char             **data_return,
+                             int                start,
+                             int                len)
+{
+  DBusString dest;
+  
+  DBUS_STRING_PREAMBLE (str);
+  _dbus_assert (data_return != NULL);
+  _dbus_assert (start >= 0);
+  _dbus_assert (len >= 0);
+  _dbus_assert ((start + len) <= real->len);
+
+  if (!_dbus_string_init (&dest, real->max_length))
+    return FALSE;
+
+  if (!_dbus_string_move_len (str, start, len, &dest, 0))
+    {
+      _dbus_string_free (&dest);
+      return FALSE;
+    }
+  
+  if (!_dbus_string_steal_data (&dest, data_return))
+    {
+      _dbus_string_free (&dest);
+      return FALSE;
+    }
+
+  _dbus_string_free (&dest);
+  return TRUE;
+}
+
+/**
+ * Gets the length of a string (not including nul termination).
+ *
+ * @returns the length.
+ */
+int
+_dbus_string_get_length (const DBusString  *str)
+{
+  DBUS_CONST_STRING_PREAMBLE (str);
+  
+  return real->len;
+}
+
+static dbus_bool_t
+set_length (DBusRealString *real,
+            int             new_length)
+{
+  /* Note, we are setting the length without nul termination */
+
+  /* exceeding max length is the same as failure to allocate memory */
+  if (new_length > real->max_length)
+    return FALSE;
+  
+  while (new_length >= real->allocated)
+    {
+      int new_allocated;
+      char *new_str;
+      
+      new_allocated = 2 + real->allocated * 2;
+      if (new_allocated < real->allocated)
+        return FALSE; /* overflow */
+        
+      new_str = dbus_realloc (real->str, new_allocated);
+      if (new_str == NULL)
+        return FALSE;
+
+      real->str = new_str;
+      real->allocated = new_allocated;
+    }
+
+  real->len = new_length;
+  real->str[real->len] = '\0';
+
+  return TRUE;
+}
+
+/**
+ * Makes a string longer by the given number of bytes.  Checks whether
+ * adding additional_length to the current length would overflow an
+ * integer, and checks for exceeding a string's max length.
+ * The new bytes are not initialized, other than nul-terminating
+ * the end of the string. The uninitialized bytes may contain
+ * unexpected nul bytes or other junk.
+ *
+ * @param str a string
+ * @param additional_length length to add to the string.
+ * @returns #TRUE on success.
+ */
+dbus_bool_t
+_dbus_string_lengthen (DBusString *str,
+                       int         additional_length)
+{
+  DBUS_STRING_PREAMBLE (str);  
+  _dbus_assert (additional_length >= 0);
+  
+  if ((real->len + additional_length) < real->len)
+    return FALSE; /* overflow */
+  
+  return set_length (real,
+                     real->len + additional_length);
+}
+
+/**
+ * Makes a string shorter by the given number of bytes.
+ *
+ * @param str a string
+ * @param length_to_remove length to remove from the string.
+ */
+void
+_dbus_string_shorten (DBusString *str,
+                      int         length_to_remove)
+{
+  DBUS_STRING_PREAMBLE (str);
+  _dbus_assert (length_to_remove >= 0);
+  _dbus_assert (length_to_remove <= real->len);
+
+  set_length (real,
+              real->len - length_to_remove);
+}
+
+/**
+ * Sets the length of a string. Can be used to truncate or lengthen
+ * the string. If the string is lengthened, the function may fail and
+ * return #FALSE. Newly-added bytes are not initialized, as with
+ * _dbus_string_lengthen().
+ *
+ * @param str a string
+ * @param length new length of the string.
+ * @returns #FALSE on failure.
+ */
+dbus_bool_t
+_dbus_string_set_length (DBusString *str,
+                         int         length)
+{
+  DBUS_STRING_PREAMBLE (str);
+  _dbus_assert (length >= 0);
+
+  return set_length (real, length);
+}
+
+static dbus_bool_t
+append (DBusRealString *real,
+        const char     *buffer,
+        int             buffer_len)
+{
+  if (buffer_len == 0)
+    return TRUE;
+
+  if (!_dbus_string_lengthen ((DBusString*)real, buffer_len))
+    return FALSE;
+
+  memcpy (real->str + (real->len - buffer_len),
+          buffer,
+          buffer_len);
+
+  return TRUE;
+}
+
+/**
+ * Appends a nul-terminated C-style string to a DBusString.
+ *
+ * @param str the DBusString
+ * @param buffer the nul-terminated characters to append
+ * @returns #FALSE if not enough memory.
+ */
+dbus_bool_t
+_dbus_string_append (DBusString *str,
+                     const char *buffer)
+{
+  int buffer_len;
+  
+  DBUS_STRING_PREAMBLE (str);
+  _dbus_assert (buffer != NULL);
+  
+  buffer_len = strlen (buffer);
+
+  return append (real, buffer, buffer_len);
+}
+
+/**
+ * Appends block of bytes with the given length to a DBusString.
+ *
+ * @param str the DBusString
+ * @param buffer the bytes to append
+ * @param len the number of bytes to append
+ * @returns #FALSE if not enough memory.
+ */
+dbus_bool_t
+_dbus_string_append_len (DBusString *str,
+                         const char *buffer,
+                         int         len)
+{
+  DBUS_STRING_PREAMBLE (str);
+  _dbus_assert (buffer != NULL);
+  _dbus_assert (len >= 0);
+
+  return append (real, buffer, len);
+}
+
+/**
+ * Appends a single byte to the string, returning #FALSE
+ * if not enough memory.
+ *
+ * @param str the string
+ * @param byte the byte to append
+ * @returns #TRUE on success
+ */
+dbus_bool_t
+_dbus_string_append_byte (DBusString    *str,
+                          unsigned char  byte)
+{
+  DBUS_STRING_PREAMBLE (str);
+
+  if (!set_length (real, real->len + 1))
+    return FALSE;
+
+  real->str[real->len-1] = byte;
+
+  return TRUE;
+}
+
+/**
+ * Appends a single Unicode character, encoding the character
+ * in UTF-8 format.
+ *
+ * @param str the string
+ * @param ch the Unicode character
+ */
+dbus_bool_t
+_dbus_string_append_unichar (DBusString    *str,
+                             dbus_unichar_t ch)
+{
+  int len;
+  int first;
+  int i;
+  char *out;
+  
+  DBUS_STRING_PREAMBLE (str);
+
+  /* this code is from GLib but is pretty standard I think */
+  
+  len = 0;
+  
+  if (ch < 0x80)
+    {
+      first = 0;
+      len = 1;
+    }
+  else if (ch < 0x800)
+    {
+      first = 0xc0;
+      len = 2;
+    }
+  else if (ch < 0x10000)
+    {
+      first = 0xe0;
+      len = 3;
+    }
+   else if (ch < 0x200000)
+    {
+      first = 0xf0;
+      len = 4;
+    }
+  else if (ch < 0x4000000)
+    {
+      first = 0xf8;
+      len = 5;
+    }
+  else
+    {
+      first = 0xfc;
+      len = 6;
+    }
+
+  if (!set_length (real, real->len + len))
+    return FALSE;
+
+  out = real->str + (real->len - len);
+  
+  for (i = len - 1; i > 0; --i)
+    {
+      out[i] = (ch & 0x3f) | 0x80;
+      ch >>= 6;
+    }
+  out[0] = ch | first;
+
+  return TRUE;
+}
+
+static void
+delete (DBusRealString *real,
+        int             start,
+        int             len)
+{
+  if (len == 0)
+    return;
+  
+  memmove (real->str + start, real->str + start + len, real->len - (start + len));
+  real->len -= len;
+  real->str[real->len] = '\0';
+}
+
+/**
+ * Deletes a segment of a DBusString with length len starting at
+ * start. (Hint: to clear an entire string, setting length to 0
+ * with _dbus_string_set_length() is easier.)
+ *
+ * @param str the DBusString
+ * @param start where to start deleting
+ * @param len the number of bytes to delete
+ */
+void
+_dbus_string_delete (DBusString       *str,
+                     int               start,
+                     int               len)
+{
+  DBUS_STRING_PREAMBLE (str);
+  _dbus_assert (start >= 0);
+  _dbus_assert (len >= 0);
+  _dbus_assert ((start + len) <= real->len);
+
+  delete (real, start, len);
+}
+
+static dbus_bool_t
+copy (DBusRealString *source,
+      int             start,
+      int             len,
+      DBusRealString *dest,
+      int             insert_at)
+{
+  if (len == 0)
+    return TRUE;
+
+  if (!set_length (dest, dest->len + len))
+    return FALSE;
+
+  memmove (dest->str + insert_at + len, 
+           dest->str + insert_at,
+           dest->len - len);
+
+  memcpy (dest->str + insert_at,
+          source->str + start,
+          len);
+
+  return TRUE;
+}
+
+/**
+ * Checks assertions for two strings we're copying a segment between,
+ * and declares real_source/real_dest variables.
+ *
+ * @param source the source string
+ * @param start the starting offset
+ * @param dest the dest string
+ * @param insert_at where the copied segment is inserted
+ */
+#define DBUS_STRING_COPY_PREAMBLE(source, start, dest, insert_at)       \
+  DBusRealString *real_source = (DBusRealString*) source;               \
+  DBusRealString *real_dest = (DBusRealString*) dest;                   \
+  _dbus_assert ((source) != (dest));                                    \
+  DBUS_GENERIC_STRING_PREAMBLE (real_source);                           \
+  DBUS_GENERIC_STRING_PREAMBLE (real_dest);                             \
+  _dbus_assert (!real_source->constant);                                \
+  _dbus_assert (!real_source->locked);                                  \
+  _dbus_assert (!real_dest->constant);                                  \
+  _dbus_assert (!real_dest->locked);                                    \
+  _dbus_assert ((start) >= 0);                                          \
+  _dbus_assert ((start) <= real_source->len);                           \
+  _dbus_assert ((insert_at) >= 0);                                      \
+  _dbus_assert ((insert_at) <= real_dest->len)
+
+/**
+ * Moves the end of one string into another string. Both strings
+ * must be initialized, valid strings.
+ *
+ * @param source the source string
+ * @param start where to chop off the source string
+ * @param dest the destination string
+ * @param insert_at where to move the chopped-off part of source string
+ * @returns #FALSE if not enough memory
+ */
+dbus_bool_t
+_dbus_string_move (DBusString       *source,
+                   int               start,
+                   DBusString       *dest,
+                   int               insert_at)
+{
+  DBUS_STRING_COPY_PREAMBLE (source, start, dest, insert_at);
+  
+  if (!copy (real_source, start,
+             real_source->len - start,
+             real_dest,
+             insert_at))
+    return FALSE;
+
+  delete (real_source, start,
+          real_source->len - start);
+
+  return TRUE;
+}
+
+/**
+ * Like _dbus_string_move(), but does not delete the section
+ * of the source string that's copied to the dest string.
+ *
+ * @param source the source string
+ * @param start where to start copying the source string
+ * @param dest the destination string
+ * @param insert_at where to place the copied part of source string
+ * @returns #FALSE if not enough memory
+ */
+dbus_bool_t
+_dbus_string_copy (const DBusString *source,
+                   int               start,
+                   DBusString       *dest,
+                   int               insert_at)
+{
+  DBUS_STRING_COPY_PREAMBLE (source, start, dest, insert_at);
+
+  return copy (real_source, start,
+               real_source->len - start,
+               real_dest,
+               insert_at);
+}
+
+/**
+ * Like _dbus_string_move(), but can move a segment from
+ * the middle of the source string.
+ * 
+ * @param source the source string
+ * @param start first byte of source string to move
+ * @param len length of segment to move
+ * @param dest the destination string
+ * @param insert_at where to move the bytes from the source string
+ * @returns #FALSE if not enough memory
+ */
+dbus_bool_t
+_dbus_string_move_len (DBusString       *source,
+                       int               start,
+                       int               len,
+                       DBusString       *dest,
+                       int               insert_at)
+
+{
+  DBUS_STRING_COPY_PREAMBLE (source, start, dest, insert_at);
+  _dbus_assert (len >= 0);
+  _dbus_assert ((start + len) <= real_source->len);
+
+  if (!copy (real_source, start, len,
+             real_dest,
+             insert_at))
+    return FALSE;
+
+  delete (real_source, start,
+          real_source->len - start);
+
+  return TRUE;
+}
+
+/**
+ * Like _dbus_string_copy(), but can copy a segment from the middle of
+ * the source string.
+ *
+ * @param source the source string
+ * @param start where to start copying the source string
+ * @param len length of segment to copy
+ * @param dest the destination string
+ * @param insert_at where to place the copied segment of source string
+ * @returns #FALSE if not enough memory
+ */
+dbus_bool_t
+_dbus_string_copy_len (const DBusString *source,
+                       int               start,
+                       int               len,
+                       DBusString       *dest,
+                       int               insert_at)
+{
+  DBUS_STRING_COPY_PREAMBLE (source, start, dest, insert_at);
+  _dbus_assert (len >= 0);
+  _dbus_assert ((start + len) <= real_source->len);
+  
+  return copy (real_source, start, len,
+               real_dest,
+               insert_at);
+}
+
+/* Unicode macros from GLib */
+
+/** computes length and mask of a unicode character
+ * @param Char the char
+ * @param Mask the mask variable to assign to
+ * @param Len the length variable to assign to
+ */
+#define UTF8_COMPUTE(Char, Mask, Len)                                        \
+  if (Char < 128)                                                            \
+    {                                                                        \
+      Len = 1;                                                               \
+      Mask = 0x7f;                                                           \
+    }                                                                        \
+  else if ((Char & 0xe0) == 0xc0)                                            \
+    {                                                                        \
+      Len = 2;                                                               \
+      Mask = 0x1f;                                                           \
+    }                                                                        \
+  else if ((Char & 0xf0) == 0xe0)                                            \
+    {                                                                        \
+      Len = 3;                                                               \
+      Mask = 0x0f;                                                           \
+    }                                                                        \
+  else if ((Char & 0xf8) == 0xf0)                                            \
+    {                                                                        \
+      Len = 4;                                                               \
+      Mask = 0x07;                                                           \
+    }                                                                        \
+  else if ((Char & 0xfc) == 0xf8)                                            \
+    {                                                                        \
+      Len = 5;                                                               \
+      Mask = 0x03;                                                           \
+    }                                                                        \
+  else if ((Char & 0xfe) == 0xfc)                                            \
+    {                                                                        \
+      Len = 6;                                                               \
+      Mask = 0x01;                                                           \
+    }                                                                        \
+  else                                                                       \
+    Len = -1;
+
+/**
+ * computes length of a unicode character in UTF-8
+ * @param Char the char
+ */
+#define UTF8_LENGTH(Char)              \
+  ((Char) < 0x80 ? 1 :                 \
+   ((Char) < 0x800 ? 2 :               \
+    ((Char) < 0x10000 ? 3 :            \
+     ((Char) < 0x200000 ? 4 :          \
+      ((Char) < 0x4000000 ? 5 : 6)))))
+   
+/**
+ * Gets a UTF-8 value.
+ *
+ * @param Result variable for extracted unicode char.
+ * @param Chars the bytes to decode
+ * @param Count counter variable
+ * @param Mask mask for this char
+ * @param Len length for this char in bytes
+ */
+#define UTF8_GET(Result, Chars, Count, Mask, Len)                            \
+  (Result) = (Chars)[0] & (Mask);                                            \
+  for ((Count) = 1; (Count) < (Len); ++(Count))                                      \
+    {                                                                        \
+      if (((Chars)[(Count)] & 0xc0) != 0x80)                                 \
+       {                                                                     \
+         (Result) = -1;                                                      \
+         break;                                                              \
+       }                                                                     \
+      (Result) <<= 6;                                                        \
+      (Result) |= ((Chars)[(Count)] & 0x3f);                                 \
+    }
+
+/**
+ * Check whether a unicode char is in a valid range.
+ *
+ * @param Char the character
+ */
+#define UNICODE_VALID(Char)                   \
+    ((Char) < 0x110000 &&                     \
+     ((Char) < 0xD800 || (Char) >= 0xE000) && \
+     (Char) != 0xFFFE && (Char) != 0xFFFF)   
+
+/**
+ * Gets a unicode character from a UTF-8 string. Does no validation;
+ * you must verify that the string is valid UTF-8 in advance and must
+ * pass in the start of a character.
+ *
+ * @param str the string
+ * @param start the start of the UTF-8 character.
+ * @param ch_return location to return the character
+ * @param end_return location to return the byte index of next character
+ * @returns #TRUE on success, #FALSE otherwise.
+ */
+void
+_dbus_string_get_unichar (const DBusString *str,
+                          int               start,
+                          dbus_unichar_t   *ch_return,
+                          int              *end_return)
+{
+  int i, mask, len;
+  dbus_unichar_t result;
+  unsigned char c;
+  unsigned char *p;
+  DBUS_CONST_STRING_PREAMBLE (str);
+
+  if (ch_return)
+    *ch_return = 0;
+  if (end_return)
+    *end_return = real->len;
+  
+  mask = 0;
+  p = real->str + start;
+  c = *p;
+  
+  UTF8_COMPUTE (c, mask, len);
+  if (len == -1)
+    return;
+  UTF8_GET (result, p, i, mask, len);
+
+  if (result == (dbus_unichar_t)-1)
+    return;
+
+  if (ch_return)
+    *ch_return = result;
+  if (end_return)
+    *end_return = start + len;
+}
+
+/** @} */
+
+#ifdef DBUS_BUILD_TESTS
+#include "dbus-test.h"
+#include <stdio.h>
+
+static void
+test_max_len (DBusString *str,
+              int         max_len)
+{
+  if (max_len > 0)
+    {
+      if (!_dbus_string_set_length (str, max_len - 1))
+        _dbus_assert_not_reached ("setting len to one less than max should have worked");
+    }
+
+  if (!_dbus_string_set_length (str, max_len))
+    _dbus_assert_not_reached ("setting len to max len should have worked");
+
+  if (_dbus_string_set_length (str, max_len + 1))
+    _dbus_assert_not_reached ("setting len to one more than max len should not have worked");
+
+  if (!_dbus_string_set_length (str, 0))
+    _dbus_assert_not_reached ("setting len to zero should have worked");
+}
+
+/**
+ * @ingroup DBusStringInternals
+ * Unit test for DBusString.
+ *
+ * @todo Need to write tests for _dbus_string_copy() and
+ * _dbus_string_move() moving to/from each of start/middle/end of a
+ * string.
+ * 
+ * @returns #TRUE on success.
+ */
+dbus_bool_t
+_dbus_string_test (void)
+{
+  DBusString str;
+  DBusString other;
+  int i, end;
+  long v;
+  double d;
+  int lens[] = { 0, 1, 2, 3, 4, 5, 10, 16, 17, 18, 25, 31, 32, 33, 34, 35, 63, 64, 65, 66, 67, 68, 69, 70, 71, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136 };
+  char *s;
+  dbus_unichar_t ch;
+  
+  i = 0;
+  while (i < _DBUS_N_ELEMENTS (lens))
+    {
+      if (!_dbus_string_init (&str, lens[i]))
+        _dbus_assert_not_reached ("failed to init string");
+      
+      test_max_len (&str, lens[i]);
+      _dbus_string_free (&str);
+
+      ++i;
+    }
+
+  /* Test shortening and setting length */
+  i = 0;
+  while (i < _DBUS_N_ELEMENTS (lens))
+    {
+      int j;
+      
+      if (!_dbus_string_init (&str, lens[i]))
+        _dbus_assert_not_reached ("failed to init string");
+      
+      if (!_dbus_string_set_length (&str, lens[i]))
+        _dbus_assert_not_reached ("failed to set string length");
+
+      j = lens[i];
+      while (j > 0)
+        {
+          _dbus_assert (_dbus_string_get_length (&str) == j);
+          if (j > 0)
+            {
+              _dbus_string_shorten (&str, 1);
+              _dbus_assert (_dbus_string_get_length (&str) == (j - 1));
+            }
+          --j;
+        }
+      
+      _dbus_string_free (&str);
+
+      ++i;
+    }
+
+  /* Test appending data */
+  if (!_dbus_string_init (&str, _DBUS_INT_MAX))
+    _dbus_assert_not_reached ("failed to init string");
+
+  i = 0;
+  while (i < 10)
+    {
+      if (!_dbus_string_append (&str, "a"))
+        _dbus_assert_not_reached ("failed to append string to string\n");
+
+      _dbus_assert (_dbus_string_get_length (&str) == i * 2 + 1);
+
+      if (!_dbus_string_append_byte (&str, 'b'))
+        _dbus_assert_not_reached ("failed to append byte to string\n");
+
+      _dbus_assert (_dbus_string_get_length (&str) == i * 2 + 2);
+                    
+      ++i;
+    }
+
+  _dbus_string_free (&str);
+
+  /* Check steal_data */
+  
+  if (!_dbus_string_init (&str, _DBUS_INT_MAX))
+    _dbus_assert_not_reached ("failed to init string");
+
+  if (!_dbus_string_append (&str, "Hello World"))
+    _dbus_assert_not_reached ("could not append to string");
+
+  i = _dbus_string_get_length (&str);
+  
+  if (!_dbus_string_steal_data (&str, &s))
+    _dbus_assert_not_reached ("failed to steal data");
+
+  _dbus_assert (_dbus_string_get_length (&str) == 0);
+  _dbus_assert (((int)strlen (s)) == i);
+
+  dbus_free (s);
+
+  /* Check move */
+  
+  if (!_dbus_string_append (&str, "Hello World"))
+    _dbus_assert_not_reached ("could not append to string");
+
+  i = _dbus_string_get_length (&str);
+
+  if (!_dbus_string_init (&other, _DBUS_INT_MAX))
+    _dbus_assert_not_reached ("could not init string");
+  
+  if (!_dbus_string_move (&str, 0, &other, 0))
+    _dbus_assert_not_reached ("could not move");
+
+  _dbus_assert (_dbus_string_get_length (&str) == 0);
+  _dbus_assert (_dbus_string_get_length (&other) == i);
+
+  _dbus_string_free (&other);
+
+  /* Check copy */
+  
+  if (!_dbus_string_append (&str, "Hello World"))
+    _dbus_assert_not_reached ("could not append to string");
+
+  i = _dbus_string_get_length (&str);
+  
+  if (!_dbus_string_init (&other, _DBUS_INT_MAX))
+    _dbus_assert_not_reached ("could not init string");
+  
+  if (!_dbus_string_copy (&str, 0, &other, 0))
+    _dbus_assert_not_reached ("could not copy");
+
+  _dbus_assert (_dbus_string_get_length (&str) == i);
+  _dbus_assert (_dbus_string_get_length (&other) == i);
+  
+  _dbus_string_free (&str);
+  _dbus_string_free (&other);
+
+  /* Check append/get unichar */
+  
+  if (!_dbus_string_init (&str, _DBUS_INT_MAX))
+    _dbus_assert_not_reached ("failed to init string");
+
+  ch = 0;
+  if (!_dbus_string_append_unichar (&str, 0xfffc))
+    _dbus_assert_not_reached ("failed to append unichar");
+
+  _dbus_string_get_unichar (&str, 0, &ch, &i);
+
+  _dbus_assert (ch == 0xfffc);
+  _dbus_assert (i == _dbus_string_get_length (&str));
+
+  _dbus_string_free (&str);
+  
+  /* Check append/parse int/double */
+  
+  if (!_dbus_string_init (&str, _DBUS_INT_MAX))
+    _dbus_assert_not_reached ("failed to init string");
+
+  if (!_dbus_string_append_int (&str, 27))
+    _dbus_assert_not_reached ("failed to append int");
+
+  i = _dbus_string_get_length (&str);
+
+  if (!_dbus_string_parse_int (&str, 0, &v, &end))
+    _dbus_assert_not_reached ("failed to parse int");
+
+  _dbus_assert (v == 27);
+  _dbus_assert (end == i);
+    
+  _dbus_string_set_length (&str, 0);
+
+  if (!_dbus_string_init (&str, _DBUS_INT_MAX))
+    _dbus_assert_not_reached ("failed to init string");
+  
+  if (!_dbus_string_append_double (&str, 50.3))
+    _dbus_assert_not_reached ("failed to append float");
+
+  i = _dbus_string_get_length (&str);
+
+  if (!_dbus_string_parse_double (&str, 0, &d, &end))
+    _dbus_assert_not_reached ("failed to parse float");
+
+  _dbus_assert (d > (50.3 - 1e-6) && d < (50.3 + 1e-6));
+  _dbus_assert (end == i);
+
+  _dbus_string_free (&str);
+
+  return TRUE;
+}
+
+#endif /* DBUS_BUILD_TESTS */
diff --git a/dbus/dbus-string.h b/dbus/dbus-string.h
new file mode 100644 (file)
index 0000000..4eda595
--- /dev/null
@@ -0,0 +1,136 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-string.h String utility class (internal to D-BUS implementation)
+ * 
+ * Copyright (C) 2002  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_STRING_H
+#define DBUS_STRING_H
+
+#include <dbus/dbus-internals.h>
+#include <dbus/dbus-memory.h>
+#include <dbus/dbus-types.h>
+
+DBUS_BEGIN_DECLS;
+
+typedef struct DBusString DBusString;
+
+struct DBusString
+{
+  void *dummy1; /**< placeholder */
+  int   dummy2; /**< placeholder */
+  int   dummy3; /**< placeholder */
+  int   dummy4; /**< placeholder */
+  unsigned int dummy5 : 1; /** placeholder */
+  unsigned int dummy6 : 1; /** placeholder */
+  unsigned int dummy7 : 1; /** placeholder */
+};
+
+dbus_bool_t _dbus_string_init           (DBusString *str,
+                                         int         max_length);
+void        _dbus_string_init_const     (DBusString *str,
+                                         const char *value);
+void        _dbus_string_free           (DBusString *str);
+void        _dbus_string_lock           (DBusString *str);
+
+void        _dbus_string_get_data           (DBusString        *str,
+                                             char             **data_return);
+void        _dbus_string_get_const_data     (const DBusString  *str,
+                                             const char       **data_return);
+void        _dbus_string_get_data_len       (DBusString        *str,
+                                             char             **data_return,
+                                             int                start,
+                                             int                len);
+void        _dbus_string_get_const_data_len (const DBusString  *str,
+                                             const char       **data_return,
+                                             int                start,
+                                             int                len);
+dbus_bool_t _dbus_string_steal_data         (DBusString        *str,
+                                             char             **data_return);
+dbus_bool_t _dbus_string_steal_data_len     (DBusString        *str,
+                                             char             **data_return,
+                                             int                start,
+                                             int                len);
+
+int  _dbus_string_get_length         (const DBusString  *str);
+
+dbus_bool_t _dbus_string_lengthen   (DBusString *str,
+                                     int         additional_length);
+void        _dbus_string_shorten    (DBusString *str,
+                                     int         length_to_remove);
+dbus_bool_t _dbus_string_set_length (DBusString *str,
+                                     int         length);
+
+dbus_bool_t _dbus_string_append         (DBusString    *str,
+                                         const char    *buffer);
+dbus_bool_t _dbus_string_append_len     (DBusString    *str,
+                                         const char    *buffer,
+                                         int            len);
+dbus_bool_t _dbus_string_append_int     (DBusString    *str,
+                                         long           value);
+dbus_bool_t _dbus_string_append_double  (DBusString    *str,
+                                         double         value);
+dbus_bool_t _dbus_string_append_byte    (DBusString    *str,
+                                         unsigned char  byte);
+dbus_bool_t _dbus_string_append_unichar (DBusString    *str,
+                                         dbus_unichar_t ch);
+
+
+void        _dbus_string_delete     (DBusString       *str,
+                                     int               start,
+                                     int               len);
+dbus_bool_t _dbus_string_move       (DBusString       *source,
+                                     int               start,
+                                     DBusString       *dest,
+                                     int               insert_at);
+dbus_bool_t _dbus_string_copy       (const DBusString *source,
+                                     int               start,
+                                     DBusString       *dest,
+                                     int               insert_at);
+dbus_bool_t _dbus_string_move_len   (DBusString       *source,
+                                     int               start,
+                                     int               len,
+                                     DBusString       *dest,
+                                     int               insert_at);
+dbus_bool_t _dbus_string_copy_len   (const DBusString *source,
+                                     int               start,
+                                     int               len,
+                                     DBusString       *dest,
+                                     int               insert_at);
+
+
+void       _dbus_string_get_unichar (const DBusString *str,
+                                     int               start,
+                                     dbus_unichar_t   *ch_return,
+                                     int              *end_return);
+
+dbus_bool_t _dbus_string_parse_int    (const DBusString *str,
+                                       int               start,
+                                       long             *value_return,
+                                       int              *end_return);
+dbus_bool_t _dbus_string_parse_double (const DBusString *str,
+                                       int               start,
+                                       double           *value,
+                                       int              *end_return);
+
+
+DBUS_END_DECLS;
+
+#endif /* DBUS_STRING_H */
diff --git a/dbus/dbus-sysdeps.c b/dbus/dbus-sysdeps.c
new file mode 100644 (file)
index 0000000..4bc3db9
--- /dev/null
@@ -0,0 +1,223 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-sysdeps.c Wrappers around system/libc features (internal to D-BUS implementation)
+ * 
+ * Copyright (C) 2002  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-sysdeps.h"
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+
+/**
+ * @addtogroup DBusInternalsUtils
+ * @{
+ */
+/**
+ * Aborts the program with SIGABRT (dumping core).
+ */
+void
+_dbus_abort (void)
+{
+  abort ();
+  _exit (1); /* in case someone manages to ignore SIGABRT */
+}
+
+/**
+ * Wrapper for getenv().
+ *
+ * @param varname name of environment variable
+ * @returns value of environment variable or #NULL if unset
+ */
+const char*
+_dbus_getenv (const char *varname)
+{  
+  return getenv (varname);
+}
+
+/** @} */
+
+/**
+ * @addtogroup DBusString
+ *
+ * @{
+ */
+/**
+ * Appends an integer to a DBusString.
+ * 
+ * @param str the string
+ * @param value the integer value
+ * @returns #FALSE if not enough memory or other failure.
+ */
+dbus_bool_t
+_dbus_string_append_int (DBusString *str,
+                         long        value)
+{
+  /* this calculation is from comp.lang.c faq */
+#define MAX_LONG_LEN ((sizeof (long) * 8 + 2) / 3 + 1)  /* +1 for '-' */
+  int orig_len;
+  int i;
+  char *buf;
+  
+  orig_len = _dbus_string_get_length (str);
+
+  if (!_dbus_string_lengthen (str, MAX_LONG_LEN))
+    return FALSE;
+
+  _dbus_string_get_data_len (str, &buf, orig_len, MAX_LONG_LEN);
+
+  snprintf (buf, MAX_LONG_LEN, "%ld", value);
+
+  i = 0;
+  while (*buf)
+    {
+      ++buf;
+      ++i;
+    }
+  
+  _dbus_string_shorten (str, MAX_LONG_LEN - i);
+  
+  return TRUE;
+}
+
+/**
+ * Appends a double to a DBusString.
+ * 
+ * @param str the string
+ * @param value the floating point value
+ * @returns #FALSE if not enough memory or other failure.
+ */
+dbus_bool_t
+_dbus_string_append_double (DBusString *str,
+                            double      value)
+{
+#define MAX_DOUBLE_LEN 64 /* this is completely made up :-/ */
+  int orig_len;
+  char *buf;
+  int i;
+  
+  orig_len = _dbus_string_get_length (str);
+
+  if (!_dbus_string_lengthen (str, MAX_DOUBLE_LEN))
+    return FALSE;
+
+  _dbus_string_get_data_len (str, &buf, orig_len, MAX_DOUBLE_LEN);
+
+  snprintf (buf, MAX_LONG_LEN, "%g", value);
+
+  i = 0;
+  while (*buf)
+    {
+      ++buf;
+      ++i;
+    }
+  
+  _dbus_string_shorten (str, MAX_DOUBLE_LEN - i);
+  
+  return TRUE;
+}
+
+/**
+ * Parses an integer contained in a DBusString. Either return parameter
+ * may be #NULL if you aren't interested in it. The integer is parsed
+ * and stored in value_return. Return parameters are not initialized
+ * if the function returns #FALSE.
+ *
+ * @param str the string
+ * @param start the byte index of the start of the integer
+ * @param value_return return location of the integer value or #NULL
+ * @param end_return return location of the end of the integer, or #NULL
+ * @returns #TRUE on success
+ */
+dbus_bool_t
+_dbus_string_parse_int (const DBusString *str,
+                        int               start,
+                        long             *value_return,
+                        int              *end_return)
+{
+  long v;
+  const char *p;
+  char *end;
+
+  _dbus_string_get_const_data_len (str, &p, start,
+                                   _dbus_string_get_length (str) - start);
+
+  end = NULL;
+  errno = 0;
+  v = strtol (p, &end, 0);
+  if (end == NULL || end == p || errno != 0)
+    return FALSE;
+
+  if (value_return)
+    *value_return = v;
+  if (end_return)
+    *end_return = (end - p);
+
+  return TRUE;
+}
+
+/**
+ * Parses a floating point number contained in a DBusString. Either
+ * return parameter may be #NULL if you aren't interested in it. The
+ * integer is parsed and stored in value_return. Return parameters are
+ * not initialized if the function returns #FALSE.
+ *
+ * @todo this function is currently locale-dependent. Should
+ * ask alexl to relicense g_ascii_strtod() code and put that in
+ * here instead, so it's locale-independent.
+ *
+ * @param str the string
+ * @param start the byte index of the start of the float
+ * @param value_return return location of the float value or #NULL
+ * @param end_return return location of the end of the float, or #NULL
+ * @returns #TRUE on success
+ */
+dbus_bool_t
+_dbus_string_parse_double (const DBusString *str,
+                           int               start,
+                           double           *value_return,
+                           int              *end_return)
+{
+  double v;
+  const char *p;
+  char *end;
+
+  _dbus_warn ("_dbus_string_parse_double() needs to be made locale-independent\n");
+  
+  _dbus_string_get_const_data_len (str, &p, start,
+                                   _dbus_string_get_length (str) - start);
+
+  end = NULL;
+  errno = 0;
+  v = strtod (p, &end);
+  if (end == NULL || end == p || errno != 0)
+    return FALSE;
+
+  if (value_return)
+    *value_return = v;
+  if (end_return)
+    *end_return = (end - p);
+
+  return TRUE;
+}
+
+/** @} end of DBusString */
diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h
new file mode 100644 (file)
index 0000000..92b782a
--- /dev/null
@@ -0,0 +1,51 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-sysdeps.h Wrappers around system/libc features (internal to D-BUS implementation)
+ * 
+ * Copyright (C) 2002  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_SYSDEPS_H
+#define DBUS_SYSDEPS_H
+
+#include <dbus/dbus-string.h>
+
+/* this is perhaps bogus, but strcmp() etc. are faster if we use the
+ * stuff straight out of string.h, so have this here for now.
+ */
+#include <string.h>
+
+DBUS_BEGIN_DECLS;
+
+/* The idea of this file is to encapsulate everywhere that we're
+ * relying on external libc features, for ease of security
+ * auditing. The idea is from vsftpd. This also gives us a chance to
+ * make things more convenient to use, e.g.  by reading into a
+ * DBusString. Operating system headers aren't intended to be used
+ * outside of this file and a limited number of others (such as
+ * dbus-memory.c)
+ */
+
+void _dbus_abort (void);
+
+const char* _dbus_getenv (const char *varname);
+
+DBUS_END_DECLS;
+
+#endif /* DBUS_SYSDEPS_H */
index ad01fe0..c151424 100644 (file)
@@ -29,6 +29,11 @@ int
 main (int    argc,
       char **argv)
 {
+
+  printf ("%s: running string tests\n", argv[0]);
+  if (!_dbus_string_test ())
+    return 1;
+  
   printf ("%s: running linked list tests\n", argv[0]);
   if (!_dbus_list_test ())
     return 1;
index 29381a5..0df4973 100644 (file)
@@ -26,7 +26,8 @@
 
 #include <dbus/dbus-types.h>
 
-dbus_bool_t _dbus_hash_test (void);
-dbus_bool_t _dbus_list_test (void);
+dbus_bool_t _dbus_hash_test   (void);
+dbus_bool_t _dbus_list_test   (void);
+dbus_bool_t _dbus_string_test (void);
 
 #endif /* DBUS_TEST_H */
index 8549887..e212cf4 100644 (file)
@@ -24,6 +24,7 @@
 #include "dbus-transport-protected.h"
 #include "dbus-transport-unix.h"
 #include "dbus-connection-internal.h"
+#include "dbus-watch.h"
 
 /**
  * @defgroup DBusTransport DBusTransport object
index e55e005..f46b236 100644 (file)
 #ifndef DBUS_TYPES_H
 #define DBUS_TYPES_H
 
-typedef unsigned int dbus_bool_t;
-typedef unsigned int dbus_uint32_t;
-typedef int          dbus_int32_t;
-
+typedef unsigned int  dbus_bool_t;
+typedef unsigned int  dbus_uint32_t;
+typedef int           dbus_int32_t;
+typedef dbus_uint32_t dbus_unichar_t;
 
 /* Normally docs are in .c files, but there isn't a .c file for this. */
 /**