1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-gparser.c parse DBus description files
4 * Copyright (C) 2003, 2005 Red Hat, Inc.
6 * Licensed under the Academic Free License version 2.1
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;
172 PropertyInfo *property;
181 parser = g_new0 (Parser, 1);
183 parser->refcount = 1;
189 parser_ref (Parser *parser)
191 parser->refcount += 1;
197 parser_unref (Parser *parser)
199 parser->refcount -= 1;
200 if (parser->refcount == 0)
203 node_info_unref (parser->result);
210 parser_check_doctype (Parser *parser,
214 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
216 if (strcmp (doctype, "node") != 0)
220 G_MARKUP_ERROR_PARSE,
221 "D-BUS description file has the wrong document type %s, use node or interface",
230 parse_node (Parser *parser,
231 const char *element_name,
232 const char **attribute_names,
233 const char **attribute_values,
239 if (parser->interface ||
245 g_set_error (error, G_MARKUP_ERROR,
246 G_MARKUP_ERROR_PARSE,
247 _("Can't put <%s> element here"),
253 if (!locate_attributes (element_name, attribute_names,
254 attribute_values, error,
259 /* Only the root node can have no name */
260 if (parser->node_stack != NULL && name == NULL)
262 g_set_error (error, G_MARKUP_ERROR,
263 G_MARKUP_ERROR_PARSE,
264 _("\"%s\" attribute required on <%s> element "),
265 "name", element_name);
269 /* Root element name must be absolute */
270 if (parser->node_stack == NULL && name && *name != '/')
272 g_set_error (error, G_MARKUP_ERROR,
273 G_MARKUP_ERROR_PARSE,
274 _("\"%s\" attribute on <%s> element must be an absolute object path, \"%s\" not OK"),
275 "name", element_name, name);
279 /* Other element names must not be absolute */
280 if (parser->node_stack != NULL && name && *name == '/')
282 g_set_error (error, G_MARKUP_ERROR,
283 G_MARKUP_ERROR_PARSE,
284 _("\"%s\" attribute on <%s> element must not be an absolute object path, \"%s\" starts with /"),
285 "name", element_name, name);
289 node = node_info_new (name);
291 if (parser->node_stack != NULL)
293 node_info_add_node (parser->node_stack->data,
297 parser->node_stack = g_slist_prepend (parser->node_stack,
304 parse_interface (Parser *parser,
305 const char *element_name,
306 const char **attribute_names,
307 const char **attribute_values,
312 InterfaceInfo *iface;
315 if (parser->interface ||
320 (parser->node_stack == NULL))
322 g_set_error (error, G_MARKUP_ERROR,
323 G_MARKUP_ERROR_PARSE,
324 _("Can't put <%s> element here"),
330 if (!locate_attributes (element_name, attribute_names,
331 attribute_values, error,
339 g_set_error (error, G_MARKUP_ERROR,
340 G_MARKUP_ERROR_PARSE,
341 _("\"%s\" attribute required on <%s> element "),
342 "name", element_name);
346 top = parser->node_stack->data;
348 iface = interface_info_new (name);
350 interface_info_set_binding_name (iface, "C", c_name);
351 node_info_add_interface (top, iface);
352 interface_info_unref (iface);
354 parser->interface = iface;
360 parse_method (Parser *parser,
361 const char *element_name,
362 const char **attribute_names,
363 const char **attribute_values,
371 if (parser->interface == NULL ||
372 parser->node_stack == NULL ||
378 g_set_error (error, G_MARKUP_ERROR,
379 G_MARKUP_ERROR_PARSE,
380 _("Can't put <%s> element here"),
386 if (!locate_attributes (element_name, attribute_names,
387 attribute_values, error,
395 g_set_error (error, G_MARKUP_ERROR,
396 G_MARKUP_ERROR_PARSE,
397 _("\"%s\" attribute required on <%s> element "),
398 "name", element_name);
402 top = parser->node_stack->data;
404 method = method_info_new (name);
406 method_info_set_binding_name (method, "C", c_name);
407 interface_info_add_method (parser->interface, method);
408 method_info_unref (method);
410 parser->method = method;
416 parse_signal (Parser *parser,
417 const char *element_name,
418 const char **attribute_names,
419 const char **attribute_values,
426 if (parser->interface == NULL ||
427 parser->node_stack == NULL ||
433 g_set_error (error, G_MARKUP_ERROR,
434 G_MARKUP_ERROR_PARSE,
435 _("Can't put <%s> element here"),
441 if (!locate_attributes (element_name, attribute_names,
442 attribute_values, error,
449 g_set_error (error, G_MARKUP_ERROR,
450 G_MARKUP_ERROR_PARSE,
451 _("\"%s\" attribute required on <%s> element "),
452 "name", element_name);
456 top = parser->node_stack->data;
458 signal = signal_info_new (name);
459 interface_info_add_signal (parser->interface, signal);
460 signal_info_unref (signal);
462 parser->signal = signal;
468 basic_type_from_string (const char *str)
470 if (strcmp (str, "string") == 0)
471 return DBUS_TYPE_STRING;
472 else if (strcmp (str, "int16") == 0)
473 return DBUS_TYPE_INT16;
474 else if (strcmp (str, "uint16") == 0)
475 return DBUS_TYPE_UINT16;
476 else if (strcmp (str, "int32") == 0)
477 return DBUS_TYPE_INT32;
478 else if (strcmp (str, "uint32") == 0)
479 return DBUS_TYPE_UINT32;
480 else if (strcmp (str, "int64") == 0)
481 return DBUS_TYPE_INT64;
482 else if (strcmp (str, "uint64") == 0)
483 return DBUS_TYPE_UINT64;
484 else if (strcmp (str, "double") == 0)
485 return DBUS_TYPE_DOUBLE;
486 else if (strcmp (str, "byte") == 0)
487 return DBUS_TYPE_BYTE;
488 else if (strcmp (str, "boolean") == 0)
489 return DBUS_TYPE_BOOLEAN;
490 else if (strcmp (str, "byte") == 0)
491 return DBUS_TYPE_BYTE;
492 else if (strcmp (str, "object") == 0)
493 return DBUS_TYPE_OBJECT_PATH;
494 else if (strcmp (str, "variant") == 0)
495 return DBUS_TYPE_VARIANT;
497 return DBUS_TYPE_INVALID;
500 /* FIXME we have to allow type signatures, not just basic types
503 type_from_string (const char *str,
504 const char *element_name,
509 t = basic_type_from_string (str);
511 if (t == DBUS_TYPE_INVALID)
513 g_set_error (error, G_MARKUP_ERROR,
514 G_MARKUP_ERROR_PARSE,
515 _("Type \"%s\" not understood on <%s> element "),
523 parse_property (Parser *parser,
524 const char *element_name,
525 const char **attribute_names,
526 const char **attribute_values,
532 PropertyInfo *property;
534 PropertyAccessFlags access_flags;
537 if (parser->interface == NULL ||
538 parser->node_stack == NULL ||
544 g_set_error (error, G_MARKUP_ERROR,
545 G_MARKUP_ERROR_PARSE,
546 _("Can't put <%s> element here"),
552 if (!locate_attributes (element_name, attribute_names,
553 attribute_values, error,
562 g_set_error (error, G_MARKUP_ERROR,
563 G_MARKUP_ERROR_PARSE,
564 _("\"%s\" attribute required on <%s> element "),
565 "name", element_name);
571 g_set_error (error, G_MARKUP_ERROR,
572 G_MARKUP_ERROR_PARSE,
573 _("\"%s\" attribute required on <%s> element "),
574 "access", element_name);
580 g_set_error (error, G_MARKUP_ERROR,
581 G_MARKUP_ERROR_PARSE,
582 _("\"%s\" attribute required on <%s> element "),
583 "type", element_name);
587 t = type_from_string (type, element_name, error);
588 if (t == DBUS_TYPE_INVALID)
592 if (strcmp (access, "readwrite") == 0)
593 access_flags = PROPERTY_READ | PROPERTY_WRITE;
594 else if (strcmp (access, "read") == 0)
595 access_flags = PROPERTY_READ;
596 else if (strcmp (access, "write") == 0)
597 access_flags = PROPERTY_WRITE;
600 g_set_error (error, G_MARKUP_ERROR,
601 G_MARKUP_ERROR_PARSE,
602 _("access=\"%s\" must have value readwrite, read, or write on %s\n"),
603 access, element_name);
607 top = parser->node_stack->data;
609 property = property_info_new (name, t, access_flags);
610 interface_info_add_property (parser->interface, property);
611 property_info_unref (property);
613 parser->property = property;
619 parse_arg (Parser *parser,
620 const char *element_name,
621 const char **attribute_names,
622 const char **attribute_values,
627 const char *direction;
631 char *generated_name;
633 if (!(parser->method || parser->signal) ||
634 parser->node_stack == NULL ||
638 g_set_error (error, G_MARKUP_ERROR,
639 G_MARKUP_ERROR_PARSE,
640 _("Can't put <%s> element here"),
646 if (!locate_attributes (element_name, attribute_names,
647 attribute_values, error,
650 "direction", &direction,
654 /* name can be null for args */
658 g_set_error (error, G_MARKUP_ERROR,
659 G_MARKUP_ERROR_PARSE,
660 _("\"%s\" attribute required on <%s> element "),
661 "type", element_name);
665 if (direction == NULL)
667 /* methods default to in, signal to out */
670 else if (parser->signal)
673 g_assert_not_reached ();
678 if (strcmp (direction, "in") == 0)
680 else if (strcmp (direction, "out") == 0)
683 if (dir == ARG_INVALID ||
684 (parser->signal && dir == ARG_IN))
687 g_set_error (error, G_MARKUP_ERROR,
688 G_MARKUP_ERROR_PARSE,
689 _("Signals must have direction=\"out\" (just omit the direction attribute)"));
691 g_set_error (error, G_MARKUP_ERROR,
692 G_MARKUP_ERROR_PARSE,
693 _("\"%s\" attribute on <%s> has value \"in\" or \"out\""),
694 "direction", element_name);
698 t = type_from_string (type, element_name, error);
699 if (t == DBUS_TYPE_INVALID)
702 generated_name = NULL;
704 generated_name = g_strdup_printf ("arg%d",
706 method_info_get_n_args (parser->method) :
707 signal_info_get_n_args (parser->signal));
710 arg = arg_info_new (name ? name : generated_name, dir, t);
712 method_info_add_arg (parser->method, arg);
713 else if (parser->signal)
714 signal_info_add_arg (parser->signal, arg);
716 g_assert_not_reached ();
718 g_free (generated_name);
720 arg_info_unref (arg);
728 parser_start_element (Parser *parser,
729 const char *element_name,
730 const char **attribute_names,
731 const char **attribute_values,
734 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
736 if (ELEMENT_IS ("node"))
738 if (!parse_node (parser, element_name, attribute_names,
739 attribute_values, error))
742 else if (ELEMENT_IS ("interface"))
744 if (!parse_interface (parser, element_name, attribute_names,
745 attribute_values, error))
748 else if (ELEMENT_IS ("method"))
750 if (!parse_method (parser, element_name, attribute_names,
751 attribute_values, error))
754 else if (ELEMENT_IS ("signal"))
756 if (!parse_signal (parser, element_name, attribute_names,
757 attribute_values, error))
760 else if (ELEMENT_IS ("property"))
762 if (!parse_property (parser, element_name, attribute_names,
763 attribute_values, error))
766 else if (ELEMENT_IS ("arg"))
768 if (!parse_arg (parser, element_name, attribute_names,
769 attribute_values, error))
774 g_set_error (error, G_MARKUP_ERROR,
775 G_MARKUP_ERROR_PARSE,
776 _("Element <%s> not recognized"),
784 parser_end_element (Parser *parser,
785 const char *element_name,
788 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
790 if (ELEMENT_IS ("interface"))
792 parser->interface = NULL;
794 else if (ELEMENT_IS ("method"))
796 parser->method = NULL;
798 else if (ELEMENT_IS ("signal"))
800 parser->signal = NULL;
802 else if (ELEMENT_IS ("property"))
804 parser->property = NULL;
806 else if (ELEMENT_IS ("arg"))
810 else if (ELEMENT_IS ("node"))
814 g_assert (parser->node_stack != NULL);
815 top = parser->node_stack->data;
817 parser->node_stack = g_slist_remove (parser->node_stack,
820 if (parser->node_stack == NULL)
821 parser->result = top; /* We are done, store the result */
824 g_assert_not_reached (); /* should have had an error on start_element */
830 parser_content (Parser *parser,
835 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
837 /* FIXME check that it's all whitespace */
843 parser_finished (Parser *parser,
846 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
852 parser_get_nodes (Parser *parser)
854 return parser->result;
857 #endif /* DOXYGEN_SHOULD_SKIP_THIS */