* 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
* 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
dbus_bool_t failed;
} ExpatParseContext;
+static dbus_bool_t
+process_content (ExpatParseContext *context)
+{
+ if (context->failed)
+ return FALSE;
+
+ if (_dbus_string_get_length (&context->content) > 0)
+ {
+ if (!bus_config_parser_content (context->parser,
+ &context->content,
+ context->error))
+ {
+ context->failed = TRUE;
+ return FALSE;
+ }
+ _dbus_string_set_length (&context->content, 0);
+ }
+
+ return TRUE;
+}
+
static void
expat_StartElementHandler (void *userData,
const XML_Char *name,
int i;
char **names;
char **values;
-
+
/* Expat seems to suck and can't abort the parse if we
* throw an error. Expat 2.0 is supposed to fix this.
*/
if (context->failed)
return;
+ if (!process_content (context))
+ return;
+
/* "atts" is key, value, key, value, NULL */
for (i = 0; atts[i] != NULL; ++i)
; /* nothing */
dbus_free (values);
return;
}
-
+
i = 0;
while (atts[i] != NULL)
{
_dbus_assert (i % 2 == 0);
- names [i / 2] = (char*) atts[i];
- values[i / 2 + 1] = (char*) atts[i+1];
-
+ names [i / 2] = (char*) atts[i];
+ values[i / 2] = (char*) atts[i+1];
+
i += 2;
}
-
+
if (!bus_config_parser_start_element (context->parser,
name,
(const char **) names,
const XML_Char *name)
{
ExpatParseContext *context = userData;
- if (context->failed)
- return;
- if (_dbus_string_get_length (&context->content) > 0)
- {
- if (!bus_config_parser_content (context->parser,
- &context->content,
- context->error))
- {
- context->failed = TRUE;
- return;
- }
- _dbus_string_set_length (&context->content, 0);
- }
+ if (!process_content (context))
+ return;
if (!bus_config_parser_end_element (context->parser,
name,
const char *filename;
BusConfigParser *parser;
ExpatParseContext context;
-
+
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
parser = NULL;
expat = NULL;
context.error = error;
context.failed = FALSE;
-
+
_dbus_string_get_const_data (file, &filename);
-
+
if (!_dbus_string_init (&context.content, _DBUS_INT_MAX))
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
return NULL;
}
-
+
expat = XML_ParserCreate_MM ("UTF-8", &memsuite, NULL);
if (expat == NULL)
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
goto failed;
}
+ context.parser = parser;
XML_SetUserData (expat, &context);
XML_SetElementHandler (expat,
{
DBusString data;
const char *data_str;
-
+
if (!_dbus_string_init (&data, _DBUS_INT_MAX))
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
goto failed;
}
-
+
if (!_dbus_file_get_contents (&data, file, error))
{
_dbus_string_free (&data);
goto failed;
}
-
+
_dbus_string_get_const_data (&data, &data_str);
-
+
if (!XML_Parse (expat, data_str, _dbus_string_get_length (&data), TRUE))
{
if (context.error != NULL &&
!dbus_error_is_set (context.error))
{
enum XML_Error e;
-
+
e = XML_GetErrorCode (expat);
if (e == XML_ERROR_NO_MEMORY)
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
XML_GetCurrentColumnNumber (expat),
XML_ErrorString (e));
}
-
+
_dbus_string_free (&data);
goto failed;
}
if (context.failed)
goto failed;
}
-
+
if (!bus_config_parser_finished (parser, error))
goto failed;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
return parser;
-
+
failed:
_DBUS_ASSERT_ERROR_IS_SET (error);
-
+
_dbus_string_free (&context.content);
if (expat)
XML_ParserFree (expat);
* 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
* 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
typedef enum
{
+ ELEMENT_NONE,
ELEMENT_BUSCONFIG,
ELEMENT_INCLUDE,
ELEMENT_USER,
ELEMENT_LISTEN,
ELEMENT_AUTH,
ELEMENT_POLICY,
- ELEMENT_LIMIT
+ ELEMENT_LIMIT,
+ ELEMENT_ALLOW,
+ ELEMENT_DENY
} ElementType;
typedef struct
{
ElementType type;
+ unsigned int had_content : 1;
+
union
{
struct
{
- BusConfigParser *parser;
+ unsigned int ignore_missing : 1;
} include;
struct
{
- char *username;
- } user;
-
- struct
- {
- char *address;
- } listen;
-
- struct
- {
char *mechanism;
} auth;
{
int foo;
} limit;
-
+
} d;
-
+
} Element;
struct BusConfigParser
{
int refcount;
- DBusList *stack; /**< stack of Element */
+ DBusList *stack; /**< stack of Element */
- char *user; /**< user to run as */
+ char *user; /**< user to run as */
+
+ DBusList *listen_on; /**< List of addresses to listen to */
};
+static const char*
+element_type_to_name (ElementType type)
+{
+ switch (type)
+ {
+ case ELEMENT_NONE:
+ return NULL;
+ case ELEMENT_BUSCONFIG:
+ return "busconfig";
+ case ELEMENT_INCLUDE:
+ return "include";
+ case ELEMENT_USER:
+ return "user";
+ case ELEMENT_LISTEN:
+ return "listen";
+ case ELEMENT_AUTH:
+ return "auth";
+ case ELEMENT_POLICY:
+ return "policy";
+ case ELEMENT_LIMIT:
+ return "limit";
+ case ELEMENT_ALLOW:
+ return "allow";
+ case ELEMENT_DENY:
+ return "deny";
+ }
+
+ _dbus_assert_not_reached ("bad element type");
+
+ return NULL;
+}
static Element*
push_element (BusConfigParser *parser,
{
Element *e;
+ _dbus_assert (type != ELEMENT_NONE);
+
e = dbus_new0 (Element, 1);
if (e == NULL)
return NULL;
+
+ if (!_dbus_list_append (&parser->stack, e))
+ {
+ dbus_free (e);
+ return NULL;
+ }
e->type = type;
}
static void
+element_free (Element *e)
+{
+
+ dbus_free (e);
+}
+
+static void
pop_element (BusConfigParser *parser)
{
Element *e;
e = _dbus_list_pop_last (&parser->stack);
+
+ element_free (e);
+}
- dbus_free (e);
+static Element*
+peek_element (BusConfigParser *parser)
+{
+ Element *e;
+
+ e = _dbus_list_get_last (&parser->stack);
+
+ return e;
+}
+
+static ElementType
+top_element_type (BusConfigParser *parser)
+{
+ Element *e;
+
+ e = _dbus_list_get_last (&parser->stack);
+
+ if (e)
+ return e->type;
+ else
+ return ELEMENT_NONE;
+}
+
+static dbus_bool_t
+merge_included (BusConfigParser *parser,
+ BusConfigParser *included,
+ DBusError *error)
+{
+ DBusList *link;
+
+ if (included->user != NULL)
+ {
+ dbus_free (parser->user);
+ parser->user = included->user;
+ included->user = NULL;
+ }
+
+ while ((link = _dbus_list_pop_first_link (&included->listen_on)))
+ _dbus_list_append_link (&parser->listen_on, link);
+
+ return TRUE;
}
BusConfigParser*
{
while (parser->stack != NULL)
pop_element (parser);
-
+
dbus_free (parser->user);
+ _dbus_list_foreach (&parser->listen_on,
+ (DBusForeachFunction) dbus_free,
+ NULL);
+
+ _dbus_list_clear (&parser->listen_on);
+
dbus_free (parser);
}
}
DBusError *error)
{
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
-
+
if (strcmp (doctype, "busconfig") != 0)
{
dbus_set_error (error,
DBUS_ERROR_FAILED,
- "Document has the wrong type %s",
+ "Configuration file has the wrong document type %s",
doctype);
return FALSE;
}
return TRUE;
}
+typedef struct
+{
+ const char *name;
+ const char **retloc;
+} LocateAttr;
+
+static dbus_bool_t
+locate_attributes (BusConfigParser *parser,
+ const char *element_name,
+ const char **attribute_names,
+ const char **attribute_values,
+ DBusError *error,
+ const char *first_attribute_name,
+ const char **first_attribute_retloc,
+ ...)
+{
+ va_list args;
+ const char *name;
+ const char **retloc;
+ int n_attrs;
+#define MAX_ATTRS 24
+ LocateAttr attrs[MAX_ATTRS];
+ dbus_bool_t retval;
+ int i;
+
+ _dbus_assert (first_attribute_name != NULL);
+ _dbus_assert (first_attribute_retloc != NULL);
+
+ retval = TRUE;
+
+ n_attrs = 1;
+ attrs[0].name = first_attribute_name;
+ attrs[0].retloc = first_attribute_retloc;
+ *first_attribute_retloc = NULL;
+
+ va_start (args, first_attribute_retloc);
+
+ name = va_arg (args, const char*);
+ retloc = va_arg (args, const char**);
+
+ while (name != NULL)
+ {
+ _dbus_assert (retloc != NULL);
+ _dbus_assert (n_attrs < MAX_ATTRS);
+
+ attrs[n_attrs].name = name;
+ attrs[n_attrs].retloc = retloc;
+ n_attrs += 1;
+ *retloc = NULL;
+
+ name = va_arg (args, const char*);
+ retloc = va_arg (args, const char**);
+ }
+
+ va_end (args);
+
+ if (!retval)
+ return retval;
+
+ i = 0;
+ while (attribute_names[i])
+ {
+ int j;
+ dbus_bool_t found;
+
+ found = FALSE;
+ j = 0;
+ while (j < n_attrs)
+ {
+ if (strcmp (attrs[j].name, attribute_names[i]) == 0)
+ {
+ retloc = attrs[j].retloc;
+
+ if (*retloc != NULL)
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "Attribute \"%s\" repeated twice on the same <%s> element",
+ attrs[j].name, element_name);
+ retval = FALSE;
+ goto out;
+ }
+
+ *retloc = attribute_values[i];
+ found = TRUE;
+ }
+
+ ++j;
+ }
+
+ if (!found)
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "Attribute \"%s\" is invalid on <%s> element in this context",
+ attribute_names[i], element_name);
+ retval = FALSE;
+ goto out;
+ }
+
+ ++i;
+ }
+
+ out:
+ return retval;
+}
+
+static dbus_bool_t
+check_no_attributes (BusConfigParser *parser,
+ const char *element_name,
+ const char **attribute_names,
+ const char **attribute_values,
+ DBusError *error)
+{
+ if (attribute_names[0] != NULL)
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "Attribute \"%s\" is invalid on <%s> element in this context",
+ attribute_names[0], element_name);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static dbus_bool_t
+start_busconfig_child (BusConfigParser *parser,
+ const char *element_name,
+ const char **attribute_names,
+ const char **attribute_values,
+ DBusError *error)
+{
+ if (strcmp (element_name, "user") == 0)
+ {
+ if (!check_no_attributes (parser, "user", attribute_names, attribute_values, error))
+ return FALSE;
+
+ if (push_element (parser, ELEMENT_USER) == NULL)
+ {
+ dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+ else if (strcmp (element_name, "listen") == 0)
+ {
+ if (!check_no_attributes (parser, "listen", attribute_names, attribute_values, error))
+ return FALSE;
+
+ if (push_element (parser, ELEMENT_LISTEN) == NULL)
+ {
+ dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+ else if (strcmp (element_name, "include") == 0)
+ {
+ Element *e;
+ const char *ignore_missing;
+
+ if ((e = push_element (parser, ELEMENT_INCLUDE)) == NULL)
+ {
+ dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+ return FALSE;
+ }
+
+ e->d.include.ignore_missing = FALSE;
+
+ if (!locate_attributes (parser, "include",
+ attribute_names,
+ attribute_values,
+ error,
+ "ignore_missing", &ignore_missing,
+ NULL))
+ return FALSE;
+
+ if (ignore_missing != NULL)
+ {
+ if (strcmp (ignore_missing, "yes") == 0)
+ e->d.include.ignore_missing = TRUE;
+ else if (strcmp (ignore_missing, "no") == 0)
+ e->d.include.ignore_missing = FALSE;
+ else
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "ignore_missing attribute must have value \"yes\" or \"no\"");
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+ }
+ else if (strcmp (element_name, "policy") == 0)
+ {
+ Element *e;
+ const char *context;
+ const char *user;
+ const char *group;
+
+ if ((e = push_element (parser, ELEMENT_POLICY)) == NULL)
+ {
+ dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+ return FALSE;
+ }
+
+ if (!locate_attributes (parser, "include",
+ attribute_names,
+ attribute_values,
+ error,
+ "context", &context,
+ "user", &user,
+ "group", &group,
+ NULL))
+ return FALSE;
+
+ /* FIXME */
+
+ return TRUE;
+ }
+ else
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "Element <%s> not allowed inside <%s> in configuration file",
+ element_name, "busconfig");
+ return FALSE;
+ }
+}
+
+static dbus_bool_t
+start_policy_child (BusConfigParser *parser,
+ const char *element_name,
+ const char **attribute_names,
+ const char **attribute_values,
+ DBusError *error)
+{
+ if (strcmp (element_name, "allow") == 0)
+ {
+ if (push_element (parser, ELEMENT_ALLOW) == NULL)
+ {
+ dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+ else if (strcmp (element_name, "deny") == 0)
+ {
+ if (push_element (parser, ELEMENT_DENY) == NULL)
+ {
+ dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+ else
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "Element <%s> not allowed inside <%s> in configuration file",
+ element_name, "policy");
+ return FALSE;
+ }
+}
+
dbus_bool_t
bus_config_parser_start_element (BusConfigParser *parser,
const char *element_name,
const char **attribute_values,
DBusError *error)
{
- _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+ ElementType t;
- return TRUE;
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+ /* printf ("START: %s\n", element_name); */
+
+ t = top_element_type (parser);
+
+ if (t == ELEMENT_NONE)
+ {
+ if (strcmp (element_name, "busconfig") == 0)
+ {
+ if (!check_no_attributes (parser, "busconfig", attribute_names, attribute_values, error))
+ return FALSE;
+
+ if (push_element (parser, ELEMENT_BUSCONFIG) == NULL)
+ {
+ dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+ else
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "Unknown element <%s> at root of configuration file",
+ element_name);
+ return FALSE;
+ }
+ }
+ else if (t == ELEMENT_BUSCONFIG)
+ {
+ return start_busconfig_child (parser, element_name,
+ attribute_names, attribute_values,
+ error);
+ }
+ else if (t == ELEMENT_POLICY)
+ {
+ return start_policy_child (parser, element_name,
+ attribute_names, attribute_values,
+ error);
+ }
+ else
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "Element <%s> is not allowed in this context",
+ element_name);
+ return FALSE;
+ }
}
dbus_bool_t
const char *element_name,
DBusError *error)
{
+ ElementType t;
+ const char *n;
+ Element *e;
+
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
+ /* printf ("END: %s\n", element_name); */
+
+ t = top_element_type (parser);
+
+ if (t == ELEMENT_NONE)
+ {
+ /* should probably be an assertion failure but
+ * being paranoid about XML parsers
+ */
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "XML parser ended element with no element on the stack");
+ return FALSE;
+ }
+
+ n = element_type_to_name (t);
+ _dbus_assert (n != NULL);
+ if (strcmp (n, element_name) != 0)
+ {
+ /* should probably be an assertion failure but
+ * being paranoid about XML parsers
+ */
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "XML element ended which was not the topmost element on the stack");
+ return FALSE;
+ }
+
+ e = peek_element (parser);
+ _dbus_assert (e != NULL);
+
+ switch (e->type)
+ {
+ case ELEMENT_NONE:
+ _dbus_assert_not_reached ("element in stack has no type");
+ break;
+
+ case ELEMENT_INCLUDE:
+ case ELEMENT_USER:
+ case ELEMENT_LISTEN:
+ case ELEMENT_AUTH:
+ if (!e->had_content)
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "XML element <%s> was expected to have content inside it",
+ element_type_to_name (e->type));
+ return FALSE;
+ }
+ break;
+
+ case ELEMENT_BUSCONFIG:
+ case ELEMENT_POLICY:
+ case ELEMENT_LIMIT:
+ case ELEMENT_ALLOW:
+ case ELEMENT_DENY:
+ break;
+ }
+
+ pop_element (parser);
+
return TRUE;
}
+static dbus_bool_t
+all_whitespace (const DBusString *str)
+{
+ int i;
+
+ _dbus_string_skip_white (str, 0, &i);
+
+ return i == _dbus_string_get_length (str);
+}
+
dbus_bool_t
bus_config_parser_content (BusConfigParser *parser,
const DBusString *content,
DBusError *error)
{
+ Element *e;
+
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
+#if 0
+ {
+ const char *c_str;
+
+ _dbus_string_get_const_data (content, &c_str);
+
+ printf ("CONTENT %d bytes: %s\n", _dbus_string_get_length (content), c_str);
+ }
+#endif
+
+ e = peek_element (parser);
+ if (e == NULL)
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "Text content outside of any XML element in configuration file");
+ return FALSE;
+ }
+ else if (e->had_content)
+ {
+ _dbus_assert_not_reached ("Element had multiple content blocks");
+ return FALSE;
+ }
+
+ switch (top_element_type (parser))
+ {
+ case ELEMENT_NONE:
+ _dbus_assert_not_reached ("element at top of stack has no type");
+ return FALSE;
+
+ case ELEMENT_BUSCONFIG:
+ case ELEMENT_POLICY:
+ case ELEMENT_LIMIT:
+ case ELEMENT_ALLOW:
+ case ELEMENT_DENY:
+ if (all_whitespace (content))
+ return TRUE;
+ else
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "No text content expected inside XML element %s in configuration file",
+ element_type_to_name (top_element_type (parser)));
+ return FALSE;
+ }
+
+ case ELEMENT_INCLUDE:
+ {
+ /* FIXME good test case for this would load each config file in the
+ * test suite both alone, and as an include, and check
+ * that the result is the same
+ */
+ BusConfigParser *included;
+ DBusError tmp_error;
+
+ e->had_content = TRUE;
+
+ dbus_error_init (&tmp_error);
+ included = bus_config_load (content, &tmp_error);
+ if (included == NULL)
+ {
+ _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
+ if (dbus_error_has_name (&tmp_error, DBUS_ERROR_FILE_NOT_FOUND) &&
+ e->d.include.ignore_missing)
+ {
+ dbus_error_free (&tmp_error);
+ return TRUE;
+ }
+ else
+ {
+ dbus_move_error (&tmp_error, error);
+ return FALSE;
+ }
+ }
+ else
+ {
+ _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
+
+ if (!merge_included (parser, included, error))
+ return FALSE;
+
+ bus_config_parser_unref (included);
+ return TRUE;
+ }
+ }
+ break;
+
+ case ELEMENT_USER:
+ {
+ char *s;
+
+ e->had_content = TRUE;
+
+ if (!_dbus_string_copy_data (content, &s))
+ goto nomem;
+
+ dbus_free (parser->user);
+ parser->user = s;
+ }
+ break;
+
+ case ELEMENT_LISTEN:
+ {
+ char *s;
+
+ e->had_content = TRUE;
+
+ if (!_dbus_string_copy_data (content, &s))
+ goto nomem;
+
+ if (!_dbus_list_append (&parser->listen_on,
+ s))
+ {
+ dbus_free (s);
+ goto nomem;
+ }
+ }
+ break;
+
+ case ELEMENT_AUTH:
+ {
+ e->had_content = TRUE;
+ /* FIXME */
+ }
+ break;
+ }
+
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
return TRUE;
+
+ nomem:
+ dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+ return FALSE;
}
dbus_bool_t
bus_config_parser_finished (BusConfigParser *parser,
DBusError *error)
{
- _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+ if (parser->stack != NULL)
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "Element <%s> was not closed in configuration file",
+ element_type_to_name (top_element_type (parser)));
+ return FALSE;
+ }
+
return TRUE;
}
const char*
bus_config_parser_get_user (BusConfigParser *parser)
{
-
-
- return NULL;
+ return parser->user;
}
#ifdef DBUS_BUILD_TESTS
DBusError error;
dbus_error_init (&error);
-
+
parser = bus_config_load (full_path, &error);
if (parser == NULL)
{
_DBUS_ASSERT_ERROR_IS_SET (&error);
-
+
if (oom_possible &&
dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
{
return TRUE;
}
else if (validity == VALID)
- {
+ {
_dbus_warn ("Failed to load valid file but still had memory: %s\n",
error.message);
else
{
_DBUS_ASSERT_ERROR_IS_CLEAR (&error);
-
+
bus_config_parser_unref (parser);
-
+
if (validity == INVALID)
{
_dbus_warn ("Accepted invalid file\n");
retval = FALSE;
dir = NULL;
-
+
if (!_dbus_string_init (&test_directory, _DBUS_INT_MAX))
_dbus_assert_not_reached ("didn't allocate test_directory\n");
_dbus_string_init_const (&filename, subdir);
-
+
if (!_dbus_string_copy (test_base_dir, 0,
&test_directory, 0))
_dbus_assert_not_reached ("couldn't copy test_base_dir to test_directory");
-
- if (!_dbus_concat_dir_and_file (&test_directory, &filename))
+
+ if (!_dbus_concat_dir_and_file (&test_directory, &filename))
_dbus_assert_not_reached ("couldn't allocate full path");
_dbus_string_free (&filename);
}
printf ("Testing:\n");
-
+
next:
while (_dbus_directory_get_next_file (dir, &filename, &error))
{
DBusString full_path;
LoaderOomData d;
-
+
if (!_dbus_string_init (&full_path, _DBUS_INT_MAX))
_dbus_assert_not_reached ("couldn't init string");
_dbus_string_get_const_data (&filename, &s);
printf (" %s\n", s);
}
-
+
_dbus_verbose (" expecting %s\n",
validity == VALID ? "valid" :
(validity == INVALID ? "invalid" :
d.validity = validity;
if (!_dbus_test_oom_handling ("config-loader", check_loader_oom_func, &d))
_dbus_assert_not_reached ("test failed");
-
+
_dbus_string_free (&full_path);
}
dbus_error_free (&error);
goto failed;
}
-
+
retval = TRUE;
-
+
failed:
if (dir)
printf ("No test data\n");
return TRUE;
}
-
+
if (!process_test_subdir (test_data_dir, "valid-config-files", VALID))
return FALSE;
-
+
return TRUE;
}
return FALSE;
}
- _dbus_warn ("Broken code in _dbus_string_steal_data_len(), FIXME\n");
+ _dbus_warn ("Broken code in _dbus_string_steal_data_len(), see @todo, FIXME\n");
+ if (!_dbus_string_steal_data (&dest, data_return))
+ {
+ _dbus_string_free (&dest);
+ return FALSE;
+ }
+
+ _dbus_string_free (&dest);
+ return TRUE;
+}
+
+
+/**
+ * Copies the data from the string into a char*
+ *
+ * @param str the string
+ * @param data_return place to return the data
+ * @returns #TRUE on success, #FALSE on no memory
+ */
+dbus_bool_t
+_dbus_string_copy_data (const DBusString *str,
+ char **data_return)
+{
+ DBUS_CONST_STRING_PREAMBLE (str);
+ _dbus_assert (data_return != NULL);
+
+ *data_return = dbus_malloc (real->len + 1);
+ if (*data_return == NULL)
+ return FALSE;
+
+ memcpy (*data_return, real->str, real->len + 1);
+
+ return TRUE;
+}
+
+/**
+ * Copies a segment of the string into a char*
+ *
+ * @param str the string
+ * @param data_return place to return the data
+ * @param start start index
+ * @param len length to copy
+ * @returns #FALSE if no memory
+ */
+dbus_bool_t
+_dbus_string_copy_data_len (const DBusString *str,
+ char **data_return,
+ int start,
+ int len)
+{
+ DBusString dest;
+
+ DBUS_CONST_STRING_PREAMBLE (str);
+ _dbus_assert (data_return != NULL);
+ _dbus_assert (start >= 0);
+ _dbus_assert (len >= 0);
+ _dbus_assert (start <= real->len);
+ _dbus_assert (len <= real->len - start);
+
+ if (!_dbus_string_init (&dest, real->max_length))
+ return FALSE;
+
+ if (!_dbus_string_copy_len (str, start, len, &dest, 0))
+ {
+ _dbus_string_free (&dest);
+ return FALSE;
+ }
+
if (!_dbus_string_steal_data (&dest, data_return))
{
_dbus_string_free (&dest);
*/
#define UNICODE_VALID(Char) \
((Char) < 0x110000 && \
- ((Char) < 0xD800 || (Char) >= 0xE000) && \
- (Char) != 0xFFFE && (Char) != 0xFFFF)
+ (((Char) & 0xFFFFF800) != 0xD800) && \
+ ((Char) < 0xFDD0 || (Char) > 0xFDEF) && \
+ ((Char) & 0xFFFF) != 0xFFFF)
/**
* Gets a unicode character from a UTF-8 string. Does no validation;
/**
* Skips blanks from start, storing the first non-blank in *end
+ * (blank is space or tab).
*
* @param str the string
* @param start where to start
}
/**
+ * Skips whitespace from start, storing the first non-whitespace in *end.
+ * (whitespace is space, tab, newline, CR).
+ *
+ * @param str the string
+ * @param start where to start
+ * @param end where to store the first non-whitespace byte index
+ */
+void
+_dbus_string_skip_white (const DBusString *str,
+ int start,
+ int *end)
+{
+ int i;
+ DBUS_CONST_STRING_PREAMBLE (str);
+ _dbus_assert (start <= real->len);
+ _dbus_assert (start >= 0);
+
+ i = start;
+ while (i < real->len)
+ {
+ if (!(real->str[i] == ' ' ||
+ real->str[i] == '\n' ||
+ real->str[i] == '\r' ||
+ real->str[i] == '\t'))
+ break;
+
+ ++i;
+ }
+
+ _dbus_assert (i == real->len || !(real->str[i] == ' ' ||
+ real->str[i] == '\t'));
+
+ if (end)
+ *end = i;
+}
+
+/**
* Assigns a newline-terminated or \r\n-terminated line from the front
* of the string to the given dest string. The dest string's previous
* contents are deleted. If the source string contains no newline,