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;
174 gboolean in_annotation;
182 parser = g_new0 (Parser, 1);
184 parser->refcount = 1;
190 parser_ref (Parser *parser)
192 parser->refcount += 1;
198 parser_unref (Parser *parser)
200 parser->refcount -= 1;
201 if (parser->refcount == 0)
204 node_info_unref (parser->result);
211 parser_check_doctype (Parser *parser,
215 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
217 if (strcmp (doctype, "node") != 0)
221 G_MARKUP_ERROR_PARSE,
222 "D-BUS description file has the wrong document type %s, use node or interface",
231 parse_node (Parser *parser,
232 const char *element_name,
233 const char **attribute_names,
234 const char **attribute_values,
240 if (parser->interface ||
245 parser->in_annotation)
247 g_set_error (error, G_MARKUP_ERROR,
248 G_MARKUP_ERROR_PARSE,
249 _("Can't put <%s> element here"),
255 if (!locate_attributes (element_name, attribute_names,
256 attribute_values, error,
261 /* Only the root node can have no name */
262 if (parser->node_stack != NULL && name == NULL)
264 g_set_error (error, G_MARKUP_ERROR,
265 G_MARKUP_ERROR_PARSE,
266 _("\"%s\" attribute required on <%s> element "),
267 "name", element_name);
271 /* Root element name must be absolute */
272 if (parser->node_stack == NULL && name && *name != '/')
274 g_set_error (error, G_MARKUP_ERROR,
275 G_MARKUP_ERROR_PARSE,
276 _("\"%s\" attribute on <%s> element must be an absolute object path, \"%s\" not OK"),
277 "name", element_name, name);
281 /* Other element names must not be absolute */
282 if (parser->node_stack != NULL && name && *name == '/')
284 g_set_error (error, G_MARKUP_ERROR,
285 G_MARKUP_ERROR_PARSE,
286 _("\"%s\" attribute on <%s> element must not be an absolute object path, \"%s\" starts with /"),
287 "name", element_name, name);
291 node = node_info_new (name);
293 if (parser->node_stack != NULL)
295 node_info_add_node (parser->node_stack->data,
299 parser->node_stack = g_slist_prepend (parser->node_stack,
306 parse_interface (Parser *parser,
307 const char *element_name,
308 const char **attribute_names,
309 const char **attribute_values,
313 InterfaceInfo *iface;
316 if (parser->interface ||
321 parser->in_annotation ||
322 (parser->node_stack == NULL))
324 g_set_error (error, G_MARKUP_ERROR,
325 G_MARKUP_ERROR_PARSE,
326 _("Can't put <%s> element here"),
332 if (!locate_attributes (element_name, attribute_names,
333 attribute_values, error,
340 g_set_error (error, G_MARKUP_ERROR,
341 G_MARKUP_ERROR_PARSE,
342 _("\"%s\" attribute required on <%s> element "),
343 "name", element_name);
347 top = parser->node_stack->data;
349 iface = interface_info_new (name);
350 node_info_add_interface (top, iface);
351 interface_info_unref (iface);
353 parser->interface = iface;
359 parse_method (Parser *parser,
360 const char *element_name,
361 const char **attribute_names,
362 const char **attribute_values,
369 if (parser->interface == NULL ||
370 parser->node_stack == NULL ||
374 parser->in_annotation ||
377 g_set_error (error, G_MARKUP_ERROR,
378 G_MARKUP_ERROR_PARSE,
379 _("Can't put <%s> element here"),
385 if (!locate_attributes (element_name, attribute_names,
386 attribute_values, error,
393 g_set_error (error, G_MARKUP_ERROR,
394 G_MARKUP_ERROR_PARSE,
395 _("\"%s\" attribute required on <%s> element "),
396 "name", element_name);
400 top = parser->node_stack->data;
402 method = method_info_new (name);
403 interface_info_add_method (parser->interface, method);
404 method_info_unref (method);
406 parser->method = method;
412 parse_signal (Parser *parser,
413 const char *element_name,
414 const char **attribute_names,
415 const char **attribute_values,
422 if (parser->interface == NULL ||
423 parser->node_stack == NULL ||
427 parser->in_annotation ||
430 g_set_error (error, G_MARKUP_ERROR,
431 G_MARKUP_ERROR_PARSE,
432 _("Can't put <%s> element here"),
438 if (!locate_attributes (element_name, attribute_names,
439 attribute_values, error,
446 g_set_error (error, G_MARKUP_ERROR,
447 G_MARKUP_ERROR_PARSE,
448 _("\"%s\" attribute required on <%s> element "),
449 "name", element_name);
453 top = parser->node_stack->data;
455 signal = signal_info_new (name);
456 interface_info_add_signal (parser->interface, signal);
457 signal_info_unref (signal);
459 parser->signal = signal;
465 basic_type_from_string (const char *str)
467 if (strcmp (str, "string") == 0)
468 return DBUS_TYPE_STRING;
469 else if (strcmp (str, "int16") == 0)
470 return DBUS_TYPE_INT16;
471 else if (strcmp (str, "uint16") == 0)
472 return DBUS_TYPE_UINT16;
473 else if (strcmp (str, "int32") == 0)
474 return DBUS_TYPE_INT32;
475 else if (strcmp (str, "uint32") == 0)
476 return DBUS_TYPE_UINT32;
477 else if (strcmp (str, "int64") == 0)
478 return DBUS_TYPE_INT64;
479 else if (strcmp (str, "uint64") == 0)
480 return DBUS_TYPE_UINT64;
481 else if (strcmp (str, "double") == 0)
482 return DBUS_TYPE_DOUBLE;
483 else if (strcmp (str, "byte") == 0)
484 return DBUS_TYPE_BYTE;
485 else if (strcmp (str, "boolean") == 0)
486 return DBUS_TYPE_BOOLEAN;
487 else if (strcmp (str, "byte") == 0)
488 return DBUS_TYPE_BYTE;
489 else if (strcmp (str, "object") == 0)
490 return DBUS_TYPE_OBJECT_PATH;
491 else if (strcmp (str, "variant") == 0)
492 return DBUS_TYPE_VARIANT;
494 return DBUS_TYPE_INVALID;
497 /* FIXME we have to allow type signatures, not just basic types
500 type_from_string (const char *str,
501 const char *element_name,
506 t = basic_type_from_string (str);
508 if (t == DBUS_TYPE_INVALID)
510 g_set_error (error, G_MARKUP_ERROR,
511 G_MARKUP_ERROR_PARSE,
512 _("Type \"%s\" not understood on <%s> element "),
520 parse_property (Parser *parser,
521 const char *element_name,
522 const char **attribute_names,
523 const char **attribute_values,
529 PropertyInfo *property;
531 PropertyAccessFlags access_flags;
534 if (parser->interface == NULL ||
535 parser->node_stack == NULL ||
539 parser->in_annotation ||
542 g_set_error (error, G_MARKUP_ERROR,
543 G_MARKUP_ERROR_PARSE,
544 _("Can't put <%s> element here"),
550 if (!locate_attributes (element_name, attribute_names,
551 attribute_values, error,
560 g_set_error (error, G_MARKUP_ERROR,
561 G_MARKUP_ERROR_PARSE,
562 _("\"%s\" attribute required on <%s> element "),
563 "name", element_name);
569 g_set_error (error, G_MARKUP_ERROR,
570 G_MARKUP_ERROR_PARSE,
571 _("\"%s\" attribute required on <%s> element "),
572 "access", element_name);
578 g_set_error (error, G_MARKUP_ERROR,
579 G_MARKUP_ERROR_PARSE,
580 _("\"%s\" attribute required on <%s> element "),
581 "type", element_name);
585 t = type_from_string (type, element_name, error);
586 if (t == DBUS_TYPE_INVALID)
590 if (strcmp (access, "readwrite") == 0)
591 access_flags = PROPERTY_READ | PROPERTY_WRITE;
592 else if (strcmp (access, "read") == 0)
593 access_flags = PROPERTY_READ;
594 else if (strcmp (access, "write") == 0)
595 access_flags = PROPERTY_WRITE;
598 g_set_error (error, G_MARKUP_ERROR,
599 G_MARKUP_ERROR_PARSE,
600 _("access=\"%s\" must have value readwrite, read, or write on %s\n"),
601 access, element_name);
605 top = parser->node_stack->data;
607 property = property_info_new (name, t, access_flags);
608 interface_info_add_property (parser->interface, property);
609 property_info_unref (property);
611 parser->property = property;
617 parse_arg (Parser *parser,
618 const char *element_name,
619 const char **attribute_names,
620 const char **attribute_values,
625 const char *direction;
629 char *generated_name;
631 if (!(parser->method || parser->signal) ||
632 parser->node_stack == NULL ||
634 parser->in_annotation ||
637 g_set_error (error, G_MARKUP_ERROR,
638 G_MARKUP_ERROR_PARSE,
639 _("Can't put <%s> element here"),
645 if (!locate_attributes (element_name, attribute_names,
646 attribute_values, error,
649 "direction", &direction,
653 /* name can be null for args */
657 g_set_error (error, G_MARKUP_ERROR,
658 G_MARKUP_ERROR_PARSE,
659 _("\"%s\" attribute required on <%s> element "),
660 "type", element_name);
664 if (direction == NULL)
666 /* methods default to in, signal to out */
669 else if (parser->signal)
672 g_assert_not_reached ();
677 if (strcmp (direction, "in") == 0)
679 else if (strcmp (direction, "out") == 0)
682 if (dir == ARG_INVALID ||
683 (parser->signal && dir == ARG_IN))
686 g_set_error (error, G_MARKUP_ERROR,
687 G_MARKUP_ERROR_PARSE,
688 _("Signals must have direction=\"out\" (just omit the direction attribute)"));
690 g_set_error (error, G_MARKUP_ERROR,
691 G_MARKUP_ERROR_PARSE,
692 _("\"%s\" attribute on <%s> has value \"in\" or \"out\""),
693 "direction", element_name);
697 t = type_from_string (type, element_name, error);
698 if (t == DBUS_TYPE_INVALID)
701 generated_name = NULL;
703 generated_name = g_strdup_printf ("arg%d",
705 method_info_get_n_args (parser->method) :
706 signal_info_get_n_args (parser->signal));
709 arg = arg_info_new (name ? name : generated_name, dir, t);
711 method_info_add_arg (parser->method, arg);
712 else if (parser->signal)
713 signal_info_add_arg (parser->signal, arg);
715 g_assert_not_reached ();
717 g_free (generated_name);
719 arg_info_unref (arg);
727 parse_annotation (Parser *parser,
728 const char *element_name,
729 const char **attribute_names,
730 const char **attribute_values,
736 if (!(parser->method || parser->interface || parser->arg) ||
737 parser->node_stack == NULL ||
739 parser->in_annotation)
741 g_set_error (error, G_MARKUP_ERROR,
742 G_MARKUP_ERROR_PARSE,
743 _("Can't put <%s> element here"),
749 if (!locate_attributes (element_name, attribute_names,
750 attribute_values, error,
756 /* name can be null for args */
760 g_set_error (error, G_MARKUP_ERROR,
761 G_MARKUP_ERROR_PARSE,
762 _("\"%s\" attribute required on <%s> element "),
763 "name", element_name);
768 g_set_error (error, G_MARKUP_ERROR,
769 G_MARKUP_ERROR_PARSE,
770 _("\"%s\" attribute required on <%s> element "),
771 "value", element_name);
776 method_info_add_annotation (parser->method, name, value);
777 else if (parser->interface)
778 interface_info_add_annotation (parser->interface, name, value);
780 g_assert_not_reached ();
782 parser->in_annotation = TRUE;
788 parser_start_element (Parser *parser,
789 const char *element_name,
790 const char **attribute_names,
791 const char **attribute_values,
794 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
796 if (ELEMENT_IS ("node"))
798 if (!parse_node (parser, element_name, attribute_names,
799 attribute_values, error))
802 else if (ELEMENT_IS ("interface"))
804 if (!parse_interface (parser, element_name, attribute_names,
805 attribute_values, error))
808 else if (ELEMENT_IS ("method"))
810 if (!parse_method (parser, element_name, attribute_names,
811 attribute_values, error))
814 else if (ELEMENT_IS ("signal"))
816 if (!parse_signal (parser, element_name, attribute_names,
817 attribute_values, error))
820 else if (ELEMENT_IS ("property"))
822 if (!parse_property (parser, element_name, attribute_names,
823 attribute_values, error))
826 else if (ELEMENT_IS ("arg"))
828 if (!parse_arg (parser, element_name, attribute_names,
829 attribute_values, error))
832 else if (ELEMENT_IS ("annotation"))
834 if (!parse_annotation (parser, element_name, attribute_names,
835 attribute_values, error))
840 g_set_error (error, G_MARKUP_ERROR,
841 G_MARKUP_ERROR_PARSE,
842 _("Element <%s> not recognized"),
850 parser_end_element (Parser *parser,
851 const char *element_name,
854 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
856 if (ELEMENT_IS ("interface"))
858 parser->interface = NULL;
860 else if (ELEMENT_IS ("method"))
862 parser->method = NULL;
864 else if (ELEMENT_IS ("signal"))
866 parser->signal = NULL;
868 else if (ELEMENT_IS ("property"))
870 parser->property = NULL;
872 else if (ELEMENT_IS ("arg"))
876 else if (ELEMENT_IS ("annotation"))
878 parser->in_annotation = FALSE;
880 else if (ELEMENT_IS ("node"))
884 g_assert (parser->node_stack != NULL);
885 top = parser->node_stack->data;
887 parser->node_stack = g_slist_remove (parser->node_stack,
890 if (parser->node_stack == NULL)
891 parser->result = top; /* We are done, store the result */
894 g_assert_not_reached (); /* should have had an error on start_element */
900 parser_content (Parser *parser,
905 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
907 /* FIXME check that it's all whitespace */
913 parser_finished (Parser *parser,
916 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
922 parser_get_nodes (Parser *parser)
924 return parser->result;
927 #endif /* DOXYGEN_SHOULD_SKIP_THIS */