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);
266 node = node_info_new (name);
268 if (parser->node_stack != NULL)
270 node_info_add_node (parser->node_stack->data,
274 parser->node_stack = g_slist_prepend (parser->node_stack,
281 parse_interface (Parser *parser,
282 const char *element_name,
283 const char **attribute_names,
284 const char **attribute_values,
288 InterfaceInfo *iface;
291 if (parser->interface ||
295 (parser->node_stack == NULL))
297 g_set_error (error, G_MARKUP_ERROR,
298 G_MARKUP_ERROR_PARSE,
299 _("Can't put a <%s> element here"),
305 if (!locate_attributes (element_name, attribute_names,
306 attribute_values, error,
313 g_set_error (error, G_MARKUP_ERROR,
314 G_MARKUP_ERROR_PARSE,
315 _("\"%s\" attribute required on <%s> element "),
316 "name", element_name);
320 top = parser->node_stack->data;
322 iface = interface_info_new (name);
323 node_info_add_interface (top, iface);
324 interface_info_unref (iface);
326 parser->interface = iface;
332 parse_method (Parser *parser,
333 const char *element_name,
334 const char **attribute_names,
335 const char **attribute_values,
342 if (parser->interface == NULL ||
343 parser->node_stack == NULL ||
348 g_set_error (error, G_MARKUP_ERROR,
349 G_MARKUP_ERROR_PARSE,
350 _("Can't put a <%s> element here"),
356 if (!locate_attributes (element_name, attribute_names,
357 attribute_values, error,
364 g_set_error (error, G_MARKUP_ERROR,
365 G_MARKUP_ERROR_PARSE,
366 _("\"%s\" attribute required on <%s> element "),
367 "name", element_name);
371 top = parser->node_stack->data;
373 method = method_info_new (name);
374 interface_info_add_method (parser->interface, method);
375 method_info_unref (method);
377 parser->method = method;
383 parse_signal (Parser *parser,
384 const char *element_name,
385 const char **attribute_names,
386 const char **attribute_values,
393 if (parser->interface == NULL ||
394 parser->node_stack == NULL ||
399 g_set_error (error, G_MARKUP_ERROR,
400 G_MARKUP_ERROR_PARSE,
401 _("Can't put a <%s> element here"),
407 if (!locate_attributes (element_name, attribute_names,
408 attribute_values, error,
415 g_set_error (error, G_MARKUP_ERROR,
416 G_MARKUP_ERROR_PARSE,
417 _("\"%s\" attribute required on <%s> element "),
418 "name", element_name);
422 top = parser->node_stack->data;
424 signal = signal_info_new (name);
425 interface_info_add_signal (parser->interface, signal);
426 signal_info_unref (signal);
428 parser->signal = signal;
434 basic_type_from_string (const char *str)
436 if (strcmp (str, "string") == 0)
437 return DBUS_TYPE_STRING;
438 else if (strcmp (str, "int32") == 0)
439 return DBUS_TYPE_INT32;
440 else if (strcmp (str, "uint32") == 0)
441 return DBUS_TYPE_UINT32;
442 else if (strcmp (str, "int64") == 0)
443 return DBUS_TYPE_INT64;
444 else if (strcmp (str, "uint64") == 0)
445 return DBUS_TYPE_UINT64;
446 else if (strcmp (str, "double") == 0)
447 return DBUS_TYPE_DOUBLE;
448 else if (strcmp (str, "byte") == 0)
449 return DBUS_TYPE_BYTE;
450 else if (strcmp (str, "boolean") == 0)
451 return DBUS_TYPE_BOOLEAN;
452 else if (strcmp (str, "byte") == 0)
453 return DBUS_TYPE_BYTE;
454 else if (strcmp (str, "object") == 0)
455 return DBUS_TYPE_OBJECT_PATH;
457 return DBUS_TYPE_INVALID;
461 type_from_string (const char *str)
463 return basic_type_from_string (str);
467 parse_arg (Parser *parser,
468 const char *element_name,
469 const char **attribute_names,
470 const char **attribute_values,
475 const char *direction;
480 if (!(parser->method || parser->signal) ||
481 parser->node_stack == NULL ||
484 g_set_error (error, G_MARKUP_ERROR,
485 G_MARKUP_ERROR_PARSE,
486 _("Can't put a <%s> element here"),
492 if (!locate_attributes (element_name, attribute_names,
493 attribute_values, error,
496 "direction", &direction,
500 /* name can be null for args */
504 g_set_error (error, G_MARKUP_ERROR,
505 G_MARKUP_ERROR_PARSE,
506 _("\"%s\" attribute required on <%s> element "),
507 "type", element_name);
511 if (direction == NULL)
513 /* methods default to in, signal to out */
516 else if (parser->signal)
519 g_assert_not_reached ();
522 if (strcmp (direction, "in") == 0)
524 else if (strcmp (direction, "out") == 0)
528 g_set_error (error, G_MARKUP_ERROR,
529 G_MARKUP_ERROR_PARSE,
530 _("\"%s\" attribute on <%s> has value \"in\" or \"out\""),
531 "direction", element_name);
535 t = type_from_string (type);
537 arg = arg_info_new (name, dir, t);
539 method_info_add_arg (parser->method, arg);
540 else if (parser->signal)
541 signal_info_add_arg (parser->signal, arg);
543 g_assert_not_reached ();
545 arg_info_unref (arg);
553 parser_start_element (Parser *parser,
554 const char *element_name,
555 const char **attribute_names,
556 const char **attribute_values,
559 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
561 if (ELEMENT_IS ("node"))
563 if (!parse_node (parser, element_name, attribute_names,
564 attribute_values, error))
567 else if (ELEMENT_IS ("interface"))
569 if (!parse_interface (parser, element_name, attribute_names,
570 attribute_values, error))
573 else if (ELEMENT_IS ("method"))
575 if (!parse_method (parser, element_name, attribute_names,
576 attribute_values, error))
579 else if (ELEMENT_IS ("signal"))
581 if (!parse_signal (parser, element_name, attribute_names,
582 attribute_values, error))
585 else if (ELEMENT_IS ("arg"))
587 if (!parse_arg (parser, element_name, attribute_names,
588 attribute_values, error))
593 g_set_error (error, G_MARKUP_ERROR,
594 G_MARKUP_ERROR_PARSE,
595 _("Element <%s> not recognized"),
603 parser_end_element (Parser *parser,
604 const char *element_name,
607 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
609 if (ELEMENT_IS ("interface"))
611 parser->interface = NULL;
613 else if (ELEMENT_IS ("method"))
615 parser->method = NULL;
617 else if (ELEMENT_IS ("signal"))
619 parser->signal = NULL;
621 else if (ELEMENT_IS ("arg"))
625 else if (ELEMENT_IS ("node"))
629 g_assert (parser->node_stack != NULL);
630 top = parser->node_stack->data;
632 parser->node_stack = g_slist_remove (parser->node_stack,
635 if (parser->node_stack == NULL)
636 parser->result = top; /* We are done, store the result */
639 g_assert_not_reached (); /* should have had an error on start_element */
645 parser_content (Parser *parser,
650 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
656 parser_finished (Parser *parser,
659 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
665 parser_get_nodes (Parser *parser)
667 return parser->result;
670 #endif /* DOXYGEN_SHOULD_SKIP_THIS */