Main Page | Modules | Data Structures | File List | Data Fields | Related Pages

dbus-gparser.c

00001 /* -*- mode: C; c-file-style: "gnu" -*- */ 00002 /* dbus-gparser.c parse DBus description files 00003 * 00004 * Copyright (C) 2003 Red Hat, Inc. 00005 * 00006 * Licensed under the Academic Free License version 2.1 00007 * 00008 * This program is free software; you can redistribute it and/or modify 00009 * it under the terms of the GNU General Public License as published by 00010 * the Free Software Foundation; either version 2 of the License, or 00011 * (at your option) any later version. 00012 * 00013 * This program is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 * GNU General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU General Public License 00019 * along with this program; if not, write to the Free Software 00020 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00021 * 00022 */ 00023 #include "dbus-gparser.h" 00024 #include "dbus-gidl.h" 00025 #include <string.h> 00026 00027 #include <libintl.h> 00028 #define _(x) gettext ((x)) 00029 #define N_(x) x 00030 00031 #ifndef DOXYGEN_SHOULD_SKIP_THIS 00032 00033 #define ELEMENT_IS(name) (strcmp (element_name, (name)) == 0) 00034 00035 typedef struct 00036 { 00037 const char *name; 00038 const char **retloc; 00039 } LocateAttr; 00040 00041 static gboolean 00042 locate_attributes (const char *element_name, 00043 const char **attribute_names, 00044 const char **attribute_values, 00045 GError **error, 00046 const char *first_attribute_name, 00047 const char **first_attribute_retloc, 00048 ...) 00049 { 00050 va_list args; 00051 const char *name; 00052 const char **retloc; 00053 int n_attrs; 00054 #define MAX_ATTRS 24 00055 LocateAttr attrs[MAX_ATTRS]; 00056 gboolean retval; 00057 int i; 00058 00059 g_return_val_if_fail (first_attribute_name != NULL, FALSE); 00060 g_return_val_if_fail (first_attribute_retloc != NULL, FALSE); 00061 00062 retval = TRUE; 00063 00064 n_attrs = 1; 00065 attrs[0].name = first_attribute_name; 00066 attrs[0].retloc = first_attribute_retloc; 00067 *first_attribute_retloc = NULL; 00068 00069 va_start (args, first_attribute_retloc); 00070 00071 name = va_arg (args, const char*); 00072 retloc = va_arg (args, const char**); 00073 00074 while (name != NULL) 00075 { 00076 g_return_val_if_fail (retloc != NULL, FALSE); 00077 00078 g_assert (n_attrs < MAX_ATTRS); 00079 00080 attrs[n_attrs].name = name; 00081 attrs[n_attrs].retloc = retloc; 00082 n_attrs += 1; 00083 *retloc = NULL; 00084 00085 name = va_arg (args, const char*); 00086 retloc = va_arg (args, const char**); 00087 } 00088 00089 va_end (args); 00090 00091 if (!retval) 00092 return retval; 00093 00094 i = 0; 00095 while (attribute_names[i]) 00096 { 00097 int j; 00098 gboolean found; 00099 00100 found = FALSE; 00101 j = 0; 00102 while (j < n_attrs) 00103 { 00104 if (strcmp (attrs[j].name, attribute_names[i]) == 0) 00105 { 00106 retloc = attrs[j].retloc; 00107 00108 if (*retloc != NULL) 00109 { 00110 g_set_error (error, 00111 G_MARKUP_ERROR, 00112 G_MARKUP_ERROR_PARSE, 00113 _("Attribute \"%s\" repeated twice on the same <%s> element"), 00114 attrs[j].name, element_name); 00115 retval = FALSE; 00116 goto out; 00117 } 00118 00119 *retloc = attribute_values[i]; 00120 found = TRUE; 00121 } 00122 00123 ++j; 00124 } 00125 00126 if (!found) 00127 { 00128 g_set_error (error, 00129 G_MARKUP_ERROR, 00130 G_MARKUP_ERROR_PARSE, 00131 _("Attribute \"%s\" is invalid on <%s> element in this context"), 00132 attribute_names[i], element_name); 00133 retval = FALSE; 00134 goto out; 00135 } 00136 00137 ++i; 00138 } 00139 00140 out: 00141 return retval; 00142 } 00143 00144 static gboolean 00145 check_no_attributes (const char *element_name, 00146 const char **attribute_names, 00147 const char **attribute_values, 00148 GError **error) 00149 { 00150 if (attribute_names[0] != NULL) 00151 { 00152 g_set_error (error, 00153 G_MARKUP_ERROR, 00154 G_MARKUP_ERROR_PARSE, 00155 _("Attribute \"%s\" is invalid on <%s> element in this context"), 00156 attribute_names[0], element_name); 00157 return FALSE; 00158 } 00159 00160 return TRUE; 00161 } 00162 00163 struct Parser 00164 { 00165 int refcount; 00166 00167 NodeInfo *result; /* Filled in when we pop the last node */ 00168 GSList *node_stack; 00169 InterfaceInfo *interface; 00170 MethodInfo *method; 00171 SignalInfo *signal; 00172 ArgInfo *arg; 00173 }; 00174 00175 Parser* 00176 parser_new (void) 00177 { 00178 Parser *parser; 00179 00180 parser = g_new0 (Parser, 1); 00181 00182 parser->refcount = 1; 00183 00184 return parser; 00185 } 00186 00187 Parser * 00188 parser_ref (Parser *parser) 00189 { 00190 parser->refcount += 1; 00191 00192 return parser; 00193 } 00194 00195 void 00196 parser_unref (Parser *parser) 00197 { 00198 parser->refcount -= 1; 00199 if (parser->refcount == 0) 00200 { 00201 if (parser->result) 00202 node_info_unref (parser->result); 00203 00204 g_free (parser); 00205 } 00206 } 00207 00208 gboolean 00209 parser_check_doctype (Parser *parser, 00210 const char *doctype, 00211 GError **error) 00212 { 00213 g_return_val_if_fail (error == NULL || *error == NULL, FALSE); 00214 00215 if (strcmp (doctype, "node") != 0) 00216 { 00217 g_set_error (error, 00218 G_MARKUP_ERROR, 00219 G_MARKUP_ERROR_PARSE, 00220 "D-BUS description file has the wrong document type %s, use node or interface", 00221 doctype); 00222 return FALSE; 00223 } 00224 else 00225 return TRUE; 00226 } 00227 00228 static gboolean 00229 parse_node (Parser *parser, 00230 const char *element_name, 00231 const char **attribute_names, 00232 const char **attribute_values, 00233 GError **error) 00234 { 00235 const char *name; 00236 NodeInfo *node; 00237 00238 if (parser->interface || 00239 parser->method || 00240 parser->signal || 00241 parser->arg) 00242 { 00243 g_set_error (error, G_MARKUP_ERROR, 00244 G_MARKUP_ERROR_PARSE, 00245 _("Can't put a <%s> element here"), 00246 element_name); 00247 return FALSE; 00248 } 00249 00250 name = NULL; 00251 if (!locate_attributes (element_name, attribute_names, 00252 attribute_values, error, 00253 "name", &name, 00254 NULL)) 00255 return FALSE; 00256 00257 /* Only the root node can have no name */ 00258 if (parser->node_stack != NULL && name == NULL) 00259 { 00260 g_set_error (error, G_MARKUP_ERROR, 00261 G_MARKUP_ERROR_PARSE, 00262 _("\"%s\" attribute required on <%s> element "), 00263 "name", element_name); 00264 return FALSE; 00265 } 00266 00267 00268 node = node_info_new (name); 00269 00270 if (parser->node_stack != NULL) 00271 { 00272 node_info_add_node (parser->node_stack->data, 00273 node); 00274 } 00275 00276 parser->node_stack = g_slist_prepend (parser->node_stack, 00277 node); 00278 00279 return TRUE; 00280 } 00281 00282 static gboolean 00283 parse_interface (Parser *parser, 00284 const char *element_name, 00285 const char **attribute_names, 00286 const char **attribute_values, 00287 GError **error) 00288 { 00289 const char *name; 00290 InterfaceInfo *iface; 00291 NodeInfo *top; 00292 00293 if (parser->interface || 00294 parser->method || 00295 parser->signal || 00296 parser->arg || 00297 (parser->node_stack == NULL)) 00298 { 00299 g_set_error (error, G_MARKUP_ERROR, 00300 G_MARKUP_ERROR_PARSE, 00301 _("Can't put a <%s> element here"), 00302 element_name); 00303 return FALSE; 00304 } 00305 00306 name = NULL; 00307 if (!locate_attributes (element_name, attribute_names, 00308 attribute_values, error, 00309 "name", &name, 00310 NULL)) 00311 return FALSE; 00312 00313 if (name == NULL) 00314 { 00315 g_set_error (error, G_MARKUP_ERROR, 00316 G_MARKUP_ERROR_PARSE, 00317 _("\"%s\" attribute required on <%s> element "), 00318 "name", element_name); 00319 return FALSE; 00320 } 00321 00322 top = parser->node_stack->data; 00323 00324 iface = interface_info_new (name); 00325 node_info_add_interface (top, iface); 00326 interface_info_unref (iface); 00327 00328 parser->interface = iface; 00329 00330 return TRUE; 00331 } 00332 00333 static gboolean 00334 parse_method (Parser *parser, 00335 const char *element_name, 00336 const char **attribute_names, 00337 const char **attribute_values, 00338 GError **error) 00339 { 00340 const char *name; 00341 MethodInfo *method; 00342 NodeInfo *top; 00343 00344 if (parser->interface == NULL || 00345 parser->node_stack == NULL || 00346 parser->method || 00347 parser->signal || 00348 parser->arg) 00349 { 00350 g_set_error (error, G_MARKUP_ERROR, 00351 G_MARKUP_ERROR_PARSE, 00352 _("Can't put a <%s> element here"), 00353 element_name); 00354 return FALSE; 00355 } 00356 00357 name = NULL; 00358 if (!locate_attributes (element_name, attribute_names, 00359 attribute_values, error, 00360 "name", &name, 00361 NULL)) 00362 return FALSE; 00363 00364 if (name == NULL) 00365 { 00366 g_set_error (error, G_MARKUP_ERROR, 00367 G_MARKUP_ERROR_PARSE, 00368 _("\"%s\" attribute required on <%s> element "), 00369 "name", element_name); 00370 return FALSE; 00371 } 00372 00373 top = parser->node_stack->data; 00374 00375 method = method_info_new (name); 00376 interface_info_add_method (parser->interface, method); 00377 method_info_unref (method); 00378 00379 parser->method = method; 00380 00381 return TRUE; 00382 } 00383 00384 static gboolean 00385 parse_signal (Parser *parser, 00386 const char *element_name, 00387 const char **attribute_names, 00388 const char **attribute_values, 00389 GError **error) 00390 { 00391 const char *name; 00392 SignalInfo *signal; 00393 NodeInfo *top; 00394 00395 if (parser->interface == NULL || 00396 parser->node_stack == NULL || 00397 parser->signal || 00398 parser->signal || 00399 parser->arg) 00400 { 00401 g_set_error (error, G_MARKUP_ERROR, 00402 G_MARKUP_ERROR_PARSE, 00403 _("Can't put a <%s> element here"), 00404 element_name); 00405 return FALSE; 00406 } 00407 00408 name = NULL; 00409 if (!locate_attributes (element_name, attribute_names, 00410 attribute_values, error, 00411 "name", &name, 00412 NULL)) 00413 return FALSE; 00414 00415 if (name == NULL) 00416 { 00417 g_set_error (error, G_MARKUP_ERROR, 00418 G_MARKUP_ERROR_PARSE, 00419 _("\"%s\" attribute required on <%s> element "), 00420 "name", element_name); 00421 return FALSE; 00422 } 00423 00424 top = parser->node_stack->data; 00425 00426 signal = signal_info_new (name); 00427 interface_info_add_signal (parser->interface, signal); 00428 signal_info_unref (signal); 00429 00430 parser->signal = signal; 00431 00432 return TRUE; 00433 } 00434 00435 static int 00436 basic_type_from_string (const char *str) 00437 { 00438 if (strcmp (str, "string") == 0) 00439 return DBUS_TYPE_STRING; 00440 else if (strcmp (str, "int32") == 0) 00441 return DBUS_TYPE_INT32; 00442 else if (strcmp (str, "uint32") == 0) 00443 return DBUS_TYPE_UINT32; 00444 else if (strcmp (str, "int64") == 0) 00445 return DBUS_TYPE_INT64; 00446 else if (strcmp (str, "uint64") == 0) 00447 return DBUS_TYPE_UINT64; 00448 else if (strcmp (str, "double") == 0) 00449 return DBUS_TYPE_DOUBLE; 00450 else if (strcmp (str, "byte") == 0) 00451 return DBUS_TYPE_BYTE; 00452 else if (strcmp (str, "boolean") == 0) 00453 return DBUS_TYPE_BOOLEAN; 00454 else if (strcmp (str, "byte") == 0) 00455 return DBUS_TYPE_BYTE; 00456 else if (strcmp (str, "object") == 0) 00457 return DBUS_TYPE_OBJECT_PATH; 00458 else 00459 return DBUS_TYPE_INVALID; 00460 } 00461 00462 static int 00463 type_from_string (const char *str) 00464 { 00465 return basic_type_from_string (str); 00466 } 00467 00468 static gboolean 00469 parse_arg (Parser *parser, 00470 const char *element_name, 00471 const char **attribute_names, 00472 const char **attribute_values, 00473 GError **error) 00474 { 00475 const char *name; 00476 const char *type; 00477 const char *direction; 00478 ArgDirection dir; 00479 int t; 00480 ArgInfo *arg; 00481 00482 if (!(parser->method || parser->signal) || 00483 parser->node_stack == NULL || 00484 parser->arg) 00485 { 00486 g_set_error (error, G_MARKUP_ERROR, 00487 G_MARKUP_ERROR_PARSE, 00488 _("Can't put a <%s> element here"), 00489 element_name); 00490 return FALSE; 00491 } 00492 00493 name = NULL; 00494 if (!locate_attributes (element_name, attribute_names, 00495 attribute_values, error, 00496 "name", &name, 00497 "type", &type, 00498 "direction", &direction, 00499 NULL)) 00500 return FALSE; 00501 00502 /* name can be null for args */ 00503 00504 if (type == NULL) 00505 { 00506 g_set_error (error, G_MARKUP_ERROR, 00507 G_MARKUP_ERROR_PARSE, 00508 _("\"%s\" attribute required on <%s> element "), 00509 "type", element_name); 00510 return FALSE; 00511 } 00512 00513 if (direction == NULL) 00514 { 00515 /* methods default to in, signal to out */ 00516 if (parser->method) 00517 direction = "in"; 00518 else if (parser->signal) 00519 direction = "out"; 00520 else 00521 g_assert_not_reached (); 00522 } 00523 00524 if (strcmp (direction, "in") == 0) 00525 dir = ARG_IN; 00526 else if (strcmp (direction, "out") == 0) 00527 dir = ARG_OUT; 00528 else 00529 { 00530 g_set_error (error, G_MARKUP_ERROR, 00531 G_MARKUP_ERROR_PARSE, 00532 _("\"%s\" attribute on <%s> has value \"in\" or \"out\""), 00533 "direction", element_name); 00534 return FALSE; 00535 } 00536 00537 t = type_from_string (type); 00538 00539 arg = arg_info_new (name, dir, t); 00540 if (parser->method) 00541 method_info_add_arg (parser->method, arg); 00542 else if (parser->signal) 00543 signal_info_add_arg (parser->signal, arg); 00544 else 00545 g_assert_not_reached (); 00546 00547 arg_info_unref (arg); 00548 00549 parser->arg = arg; 00550 00551 return TRUE; 00552 } 00553 00554 gboolean 00555 parser_start_element (Parser *parser, 00556 const char *element_name, 00557 const char **attribute_names, 00558 const char **attribute_values, 00559 GError **error) 00560 { 00561 g_return_val_if_fail (error == NULL || *error == NULL, FALSE); 00562 00563 if (ELEMENT_IS ("node")) 00564 { 00565 if (!parse_node (parser, element_name, attribute_names, 00566 attribute_values, error)) 00567 return FALSE; 00568 } 00569 else if (ELEMENT_IS ("interface")) 00570 { 00571 if (!parse_interface (parser, element_name, attribute_names, 00572 attribute_values, error)) 00573 return FALSE; 00574 } 00575 else if (ELEMENT_IS ("method")) 00576 { 00577 if (!parse_method (parser, element_name, attribute_names, 00578 attribute_values, error)) 00579 return FALSE; 00580 } 00581 else if (ELEMENT_IS ("signal")) 00582 { 00583 if (!parse_signal (parser, element_name, attribute_names, 00584 attribute_values, error)) 00585 return FALSE; 00586 } 00587 else if (ELEMENT_IS ("arg")) 00588 { 00589 if (!parse_arg (parser, element_name, attribute_names, 00590 attribute_values, error)) 00591 return FALSE; 00592 } 00593 else 00594 { 00595 g_set_error (error, G_MARKUP_ERROR, 00596 G_MARKUP_ERROR_PARSE, 00597 _("Element <%s> not recognized"), 00598 element_name); 00599 } 00600 00601 return TRUE; 00602 } 00603 00604 gboolean 00605 parser_end_element (Parser *parser, 00606 const char *element_name, 00607 GError **error) 00608 { 00609 g_return_val_if_fail (error == NULL || *error == NULL, FALSE); 00610 00611 if (ELEMENT_IS ("interface")) 00612 { 00613 parser->interface = NULL; 00614 } 00615 else if (ELEMENT_IS ("method")) 00616 { 00617 parser->method = NULL; 00618 } 00619 else if (ELEMENT_IS ("signal")) 00620 { 00621 parser->signal = NULL; 00622 } 00623 else if (ELEMENT_IS ("arg")) 00624 { 00625 parser->arg = NULL; 00626 } 00627 else if (ELEMENT_IS ("node")) 00628 { 00629 NodeInfo *top; 00630 00631 g_assert (parser->node_stack != NULL); 00632 top = parser->node_stack->data; 00633 00634 parser->node_stack = g_slist_remove (parser->node_stack, 00635 top); 00636 00637 if (parser->node_stack == NULL) 00638 parser->result = top; /* We are done, store the result */ 00639 } 00640 else 00641 g_assert_not_reached (); /* should have had an error on start_element */ 00642 00643 return TRUE; 00644 } 00645 00646 gboolean 00647 parser_content (Parser *parser, 00648 const char *content, 00649 int len, 00650 GError **error) 00651 { 00652 g_return_val_if_fail (error == NULL || *error == NULL, FALSE); 00653 00654 return TRUE; 00655 } 00656 00657 gboolean 00658 parser_finished (Parser *parser, 00659 GError **error) 00660 { 00661 g_return_val_if_fail (error == NULL || *error == NULL, FALSE); 00662 00663 return TRUE; 00664 } 00665 00666 NodeInfo* 00667 parser_get_nodes (Parser *parser) 00668 { 00669 return parser->result; 00670 } 00671 00672 #endif /* DOXYGEN_SHOULD_SKIP_THIS */

Generated on Mon Aug 16 17:40:08 2004 for D-BUS by doxygen 1.3.8