1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-gparser.c parse DBus description files
4 * Copyright (C) 2003 Red Hat, Inc.
6 * Licensed under the Academic Free License version 1.2
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "dbus-gparser.h"
24 #include "dbus-gidl.h"
28 #define _(x) gettext ((x))
31 #ifndef DOXYGEN_SHOULD_SKIP_THIS
33 #define ELEMENT_IS(name) (strcmp (element_name, (name)) == 0)
42 locate_attributes (const char *element_name,
43 const char **attribute_names,
44 const char **attribute_values,
46 const char *first_attribute_name,
47 const char **first_attribute_retloc,
55 LocateAttr attrs[MAX_ATTRS];
59 g_return_val_if_fail (first_attribute_name != NULL, FALSE);
60 g_return_val_if_fail (first_attribute_retloc != NULL, FALSE);
65 attrs[0].name = first_attribute_name;
66 attrs[0].retloc = first_attribute_retloc;
67 *first_attribute_retloc = NULL;
69 va_start (args, first_attribute_retloc);
71 name = va_arg (args, const char*);
72 retloc = va_arg (args, const char**);
76 g_return_val_if_fail (retloc != NULL, FALSE);
78 g_assert (n_attrs < MAX_ATTRS);
80 attrs[n_attrs].name = name;
81 attrs[n_attrs].retloc = retloc;
85 name = va_arg (args, const char*);
86 retloc = va_arg (args, const char**);
95 while (attribute_names[i])
104 if (strcmp (attrs[j].name, attribute_names[i]) == 0)
106 retloc = attrs[j].retloc;
112 G_MARKUP_ERROR_PARSE,
113 _("Attribute \"%s\" repeated twice on the same <%s> element"),
114 attrs[j].name, element_name);
119 *retloc = attribute_values[i];
130 G_MARKUP_ERROR_PARSE,
131 _("Attribute \"%s\" is invalid on <%s> element in this context"),
132 attribute_names[i], element_name);
145 check_no_attributes (const char *element_name,
146 const char **attribute_names,
147 const char **attribute_values,
150 if (attribute_names[0] != NULL)
154 G_MARKUP_ERROR_PARSE,
155 _("Attribute \"%s\" is invalid on <%s> element in this context"),
156 attribute_names[0], element_name);
167 NodeInfo *result; /* Filled in when we pop the last node */
169 InterfaceInfo *interface;
180 parser = g_new0 (Parser, 1);
182 parser->refcount = 1;
188 parser_ref (Parser *parser)
190 parser->refcount += 1;
194 parser_unref (Parser *parser)
196 parser->refcount -= 1;
197 if (parser->refcount == 0)
200 node_info_unref (parser->result);
207 parser_check_doctype (Parser *parser,
211 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
213 if (strcmp (doctype, "dbus_description") != 0)
217 G_MARKUP_ERROR_PARSE,
218 "D-BUS description file has the wrong document type %s, use dbus_description",
227 parse_node (Parser *parser,
228 const char *element_name,
229 const char **attribute_names,
230 const char **attribute_values,
236 if (parser->interface ||
241 g_set_error (error, G_MARKUP_ERROR,
242 G_MARKUP_ERROR_PARSE,
243 _("Can't put a <%s> element here"),
249 if (!locate_attributes (element_name, attribute_names,
250 attribute_values, error,
255 /* Only the root node can have no name */
256 if (parser->node_stack != NULL && name == NULL)
258 g_set_error (error, G_MARKUP_ERROR,
259 G_MARKUP_ERROR_PARSE,
260 _("\"%s\" attribute required on <%s> element "),
261 "name", element_name);
265 node = node_info_new (name);
266 parser->node_stack = g_slist_prepend (parser->node_stack,
273 parse_interface (Parser *parser,
274 const char *element_name,
275 const char **attribute_names,
276 const char **attribute_values,
280 InterfaceInfo *iface;
283 if (parser->interface ||
287 (parser->node_stack == NULL))
289 g_set_error (error, G_MARKUP_ERROR,
290 G_MARKUP_ERROR_PARSE,
291 _("Can't put a <%s> element here"),
297 if (!locate_attributes (element_name, attribute_names,
298 attribute_values, error,
305 g_set_error (error, G_MARKUP_ERROR,
306 G_MARKUP_ERROR_PARSE,
307 _("\"%s\" attribute required on <%s> element "),
308 "name", element_name);
312 top = parser->node_stack->data;
314 iface = interface_info_new (name);
315 node_info_add_interface (top, iface);
316 interface_info_unref (iface);
318 parser->interface = iface;
324 parse_method (Parser *parser,
325 const char *element_name,
326 const char **attribute_names,
327 const char **attribute_values,
334 if (parser->interface == NULL ||
335 parser->node_stack == NULL ||
340 g_set_error (error, G_MARKUP_ERROR,
341 G_MARKUP_ERROR_PARSE,
342 _("Can't put a <%s> element here"),
348 if (!locate_attributes (element_name, attribute_names,
349 attribute_values, error,
356 g_set_error (error, G_MARKUP_ERROR,
357 G_MARKUP_ERROR_PARSE,
358 _("\"%s\" attribute required on <%s> element "),
359 "name", element_name);
363 top = parser->node_stack->data;
365 method = method_info_new (name);
366 interface_info_add_method (parser->interface, method);
367 method_info_unref (method);
369 parser->method = method;
375 parse_signal (Parser *parser,
376 const char *element_name,
377 const char **attribute_names,
378 const char **attribute_values,
385 if (parser->interface == NULL ||
386 parser->node_stack == NULL ||
391 g_set_error (error, G_MARKUP_ERROR,
392 G_MARKUP_ERROR_PARSE,
393 _("Can't put a <%s> element here"),
399 if (!locate_attributes (element_name, attribute_names,
400 attribute_values, error,
407 g_set_error (error, G_MARKUP_ERROR,
408 G_MARKUP_ERROR_PARSE,
409 _("\"%s\" attribute required on <%s> element "),
410 "name", element_name);
414 top = parser->node_stack->data;
416 signal = signal_info_new (name);
417 interface_info_add_signal (parser->interface, signal);
418 signal_info_unref (signal);
420 parser->signal = signal;
426 basic_type_from_string (const char *str)
428 if (strcmp (str, "string") == 0)
429 return DBUS_TYPE_STRING;
430 else if (strcmp (str, "int32") == 0)
431 return DBUS_TYPE_INT32;
432 else if (strcmp (str, "uint32") == 0)
433 return DBUS_TYPE_UINT32;
434 else if (strcmp (str, "int64") == 0)
435 return DBUS_TYPE_INT64;
436 else if (strcmp (str, "uint64") == 0)
437 return DBUS_TYPE_UINT64;
438 else if (strcmp (str, "double") == 0)
439 return DBUS_TYPE_DOUBLE;
440 else if (strcmp (str, "byte") == 0)
441 return DBUS_TYPE_BYTE;
442 else if (strcmp (str, "boolean") == 0)
443 return DBUS_TYPE_BOOLEAN;
444 else if (strcmp (str, "byte") == 0)
445 return DBUS_TYPE_BYTE;
446 else if (strcmp (str, "object") == 0)
447 return DBUS_TYPE_OBJECT_PATH;
449 return DBUS_TYPE_INVALID;
453 type_from_string (const char *str)
455 return basic_type_from_string (str);
459 parse_arg (Parser *parser,
460 const char *element_name,
461 const char **attribute_names,
462 const char **attribute_values,
467 const char *direction;
472 if (!(parser->method || parser->signal) ||
473 parser->node_stack == NULL ||
476 g_set_error (error, G_MARKUP_ERROR,
477 G_MARKUP_ERROR_PARSE,
478 _("Can't put a <%s> element here"),
484 if (!locate_attributes (element_name, attribute_names,
485 attribute_values, error,
488 "direction", &direction,
492 /* name can be null for args */
496 g_set_error (error, G_MARKUP_ERROR,
497 G_MARKUP_ERROR_PARSE,
498 _("\"%s\" attribute required on <%s> element "),
499 "type", element_name);
503 if (direction == NULL)
505 /* methods default to in, signal to out */
508 else if (parser->signal)
511 g_assert_not_reached ();
514 if (strcmp (direction, "in") == 0)
516 else if (strcmp (direction, "out") == 0)
520 g_set_error (error, G_MARKUP_ERROR,
521 G_MARKUP_ERROR_PARSE,
522 _("\"%s\" attribute on <%s> has value \"in\" or \"out\""),
523 "direction", element_name);
527 t = type_from_string (type);
529 arg = arg_info_new (name, dir, t);
531 method_info_add_arg (parser->method, arg);
532 else if (parser->signal)
533 signal_info_add_arg (parser->signal, arg);
535 g_assert_not_reached ();
537 arg_info_unref (arg);
545 parser_start_element (Parser *parser,
546 const char *element_name,
547 const char **attribute_names,
548 const char **attribute_values,
551 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
553 if (ELEMENT_IS ("node"))
555 if (!parse_node (parser, element_name, attribute_names,
556 attribute_values, error))
559 else if (ELEMENT_IS ("interface"))
561 if (!parse_interface (parser, element_name, attribute_names,
562 attribute_values, error))
565 else if (ELEMENT_IS ("method"))
567 if (!parse_method (parser, element_name, attribute_names,
568 attribute_values, error))
571 else if (ELEMENT_IS ("signal"))
573 if (!parse_signal (parser, element_name, attribute_names,
574 attribute_values, error))
577 else if (ELEMENT_IS ("arg"))
579 if (!parse_arg (parser, element_name, attribute_names,
580 attribute_values, error))
585 g_set_error (error, G_MARKUP_ERROR,
586 G_MARKUP_ERROR_PARSE,
587 _("Element <%s> not recognized"),
595 parser_end_element (Parser *parser,
596 const char *element_name,
599 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
601 if (ELEMENT_IS ("interface"))
603 parser->interface = NULL;
605 else if (ELEMENT_IS ("method"))
607 parser->method = NULL;
609 else if (ELEMENT_IS ("signal"))
611 parser->signal = NULL;
613 else if (ELEMENT_IS ("arg"))
617 else if (ELEMENT_IS ("node"))
621 g_assert (parser->node_stack != NULL);
622 top = parser->node_stack->data;
624 parser->node_stack = g_slist_remove (parser->node_stack,
627 if (parser->node_stack == NULL)
628 parser->result = top; /* We are done, store the result */
631 g_assert_not_reached (); /* should have had an error on start_element */
637 parser_content (Parser *parser,
642 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
648 parser_finished (Parser *parser,
651 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
657 parser_get_nodes (Parser *parser)
659 return parser->result;
662 #endif /* DOXYGEN_SHOULD_SKIP_THIS */