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 2.0
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;
196 parser_unref (Parser *parser)
198 parser->refcount -= 1;
199 if (parser->refcount == 0)
202 node_info_unref (parser->result);
209 parser_check_doctype (Parser *parser,
213 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
215 if (strcmp (doctype, "node") != 0)
219 G_MARKUP_ERROR_PARSE,
220 "D-BUS description file has the wrong document type %s, use node or interface",
229 parse_node (Parser *parser,
230 const char *element_name,
231 const char **attribute_names,
232 const char **attribute_values,
238 if (parser->interface ||
243 g_set_error (error, G_MARKUP_ERROR,
244 G_MARKUP_ERROR_PARSE,
245 _("Can't put a <%s> element here"),
251 if (!locate_attributes (element_name, attribute_names,
252 attribute_values, error,
257 /* Only the root node can have no name */
258 if (parser->node_stack != NULL && name == NULL)
260 g_set_error (error, G_MARKUP_ERROR,
261 G_MARKUP_ERROR_PARSE,
262 _("\"%s\" attribute required on <%s> element "),
263 "name", element_name);
268 node = node_info_new (name);
270 if (parser->node_stack != NULL)
272 node_info_add_node (parser->node_stack->data,
276 parser->node_stack = g_slist_prepend (parser->node_stack,
283 parse_interface (Parser *parser,
284 const char *element_name,
285 const char **attribute_names,
286 const char **attribute_values,
290 InterfaceInfo *iface;
293 if (parser->interface ||
297 (parser->node_stack == NULL))
299 g_set_error (error, G_MARKUP_ERROR,
300 G_MARKUP_ERROR_PARSE,
301 _("Can't put a <%s> element here"),
307 if (!locate_attributes (element_name, attribute_names,
308 attribute_values, error,
315 g_set_error (error, G_MARKUP_ERROR,
316 G_MARKUP_ERROR_PARSE,
317 _("\"%s\" attribute required on <%s> element "),
318 "name", element_name);
322 top = parser->node_stack->data;
324 iface = interface_info_new (name);
325 node_info_add_interface (top, iface);
326 interface_info_unref (iface);
328 parser->interface = iface;
334 parse_method (Parser *parser,
335 const char *element_name,
336 const char **attribute_names,
337 const char **attribute_values,
344 if (parser->interface == NULL ||
345 parser->node_stack == NULL ||
350 g_set_error (error, G_MARKUP_ERROR,
351 G_MARKUP_ERROR_PARSE,
352 _("Can't put a <%s> element here"),
358 if (!locate_attributes (element_name, attribute_names,
359 attribute_values, error,
366 g_set_error (error, G_MARKUP_ERROR,
367 G_MARKUP_ERROR_PARSE,
368 _("\"%s\" attribute required on <%s> element "),
369 "name", element_name);
373 top = parser->node_stack->data;
375 method = method_info_new (name);
376 interface_info_add_method (parser->interface, method);
377 method_info_unref (method);
379 parser->method = method;
385 parse_signal (Parser *parser,
386 const char *element_name,
387 const char **attribute_names,
388 const char **attribute_values,
395 if (parser->interface == NULL ||
396 parser->node_stack == NULL ||
401 g_set_error (error, G_MARKUP_ERROR,
402 G_MARKUP_ERROR_PARSE,
403 _("Can't put a <%s> element here"),
409 if (!locate_attributes (element_name, attribute_names,
410 attribute_values, error,
417 g_set_error (error, G_MARKUP_ERROR,
418 G_MARKUP_ERROR_PARSE,
419 _("\"%s\" attribute required on <%s> element "),
420 "name", element_name);
424 top = parser->node_stack->data;
426 signal = signal_info_new (name);
427 interface_info_add_signal (parser->interface, signal);
428 signal_info_unref (signal);
430 parser->signal = signal;
436 basic_type_from_string (const char *str)
438 if (strcmp (str, "string") == 0)
439 return DBUS_TYPE_STRING;
440 else if (strcmp (str, "int32") == 0)
441 return DBUS_TYPE_INT32;
442 else if (strcmp (str, "uint32") == 0)
443 return DBUS_TYPE_UINT32;
444 else if (strcmp (str, "int64") == 0)
445 return DBUS_TYPE_INT64;
446 else if (strcmp (str, "uint64") == 0)
447 return DBUS_TYPE_UINT64;
448 else if (strcmp (str, "double") == 0)
449 return DBUS_TYPE_DOUBLE;
450 else if (strcmp (str, "byte") == 0)
451 return DBUS_TYPE_BYTE;
452 else if (strcmp (str, "boolean") == 0)
453 return DBUS_TYPE_BOOLEAN;
454 else if (strcmp (str, "byte") == 0)
455 return DBUS_TYPE_BYTE;
456 else if (strcmp (str, "object") == 0)
457 return DBUS_TYPE_OBJECT_PATH;
459 return DBUS_TYPE_INVALID;
463 type_from_string (const char *str)
465 return basic_type_from_string (str);
469 parse_arg (Parser *parser,
470 const char *element_name,
471 const char **attribute_names,
472 const char **attribute_values,
477 const char *direction;
482 if (!(parser->method || parser->signal) ||
483 parser->node_stack == NULL ||
486 g_set_error (error, G_MARKUP_ERROR,
487 G_MARKUP_ERROR_PARSE,
488 _("Can't put a <%s> element here"),
494 if (!locate_attributes (element_name, attribute_names,
495 attribute_values, error,
498 "direction", &direction,
502 /* name can be null for args */
506 g_set_error (error, G_MARKUP_ERROR,
507 G_MARKUP_ERROR_PARSE,
508 _("\"%s\" attribute required on <%s> element "),
509 "type", element_name);
513 if (direction == NULL)
515 /* methods default to in, signal to out */
518 else if (parser->signal)
521 g_assert_not_reached ();
524 if (strcmp (direction, "in") == 0)
526 else if (strcmp (direction, "out") == 0)
530 g_set_error (error, G_MARKUP_ERROR,
531 G_MARKUP_ERROR_PARSE,
532 _("\"%s\" attribute on <%s> has value \"in\" or \"out\""),
533 "direction", element_name);
537 t = type_from_string (type);
539 arg = arg_info_new (name, dir, t);
541 method_info_add_arg (parser->method, arg);
542 else if (parser->signal)
543 signal_info_add_arg (parser->signal, arg);
545 g_assert_not_reached ();
547 arg_info_unref (arg);
555 parser_start_element (Parser *parser,
556 const char *element_name,
557 const char **attribute_names,
558 const char **attribute_values,
561 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
563 if (ELEMENT_IS ("node"))
565 if (!parse_node (parser, element_name, attribute_names,
566 attribute_values, error))
569 else if (ELEMENT_IS ("interface"))
571 if (!parse_interface (parser, element_name, attribute_names,
572 attribute_values, error))
575 else if (ELEMENT_IS ("method"))
577 if (!parse_method (parser, element_name, attribute_names,
578 attribute_values, error))
581 else if (ELEMENT_IS ("signal"))
583 if (!parse_signal (parser, element_name, attribute_names,
584 attribute_values, error))
587 else if (ELEMENT_IS ("arg"))
589 if (!parse_arg (parser, element_name, attribute_names,
590 attribute_values, error))
595 g_set_error (error, G_MARKUP_ERROR,
596 G_MARKUP_ERROR_PARSE,
597 _("Element <%s> not recognized"),
605 parser_end_element (Parser *parser,
606 const char *element_name,
609 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
611 if (ELEMENT_IS ("interface"))
613 parser->interface = NULL;
615 else if (ELEMENT_IS ("method"))
617 parser->method = NULL;
619 else if (ELEMENT_IS ("signal"))
621 parser->signal = NULL;
623 else if (ELEMENT_IS ("arg"))
627 else if (ELEMENT_IS ("node"))
631 g_assert (parser->node_stack != NULL);
632 top = parser->node_stack->data;
634 parser->node_stack = g_slist_remove (parser->node_stack,
637 if (parser->node_stack == NULL)
638 parser->result = top; /* We are done, store the result */
641 g_assert_not_reached (); /* should have had an error on start_element */
647 parser_content (Parser *parser,
652 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
658 parser_finished (Parser *parser,
661 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
667 parser_get_nodes (Parser *parser)
669 return parser->result;
672 #endif /* DOXYGEN_SHOULD_SKIP_THIS */