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.0
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 Wed Jun 9 05:01:25 2004 for D-BUS by doxygen1.2.15