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 1.2
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 void
00188 parser_ref (Parser *parser)
00189 {
00190   parser->refcount += 1;
00191 }
00192 
00193 void
00194 parser_unref (Parser *parser)
00195 {
00196   parser->refcount -= 1;
00197   if (parser->refcount == 0)
00198     {
00199       if (parser->result)
00200         node_info_unref (parser->result);
00201 
00202       g_free (parser);
00203     }
00204 }
00205 
00206 gboolean
00207 parser_check_doctype (Parser      *parser,
00208                       const char  *doctype,
00209                       GError     **error)
00210 {
00211   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
00212   
00213   if (strcmp (doctype, "dbus_description") != 0)
00214     {
00215       g_set_error (error,
00216                    G_MARKUP_ERROR,
00217                    G_MARKUP_ERROR_PARSE,
00218                    "D-BUS description file has the wrong document type %s, use dbus_description",
00219                    doctype);
00220       return FALSE;
00221     }
00222   else
00223     return TRUE;
00224 }
00225 
00226 static gboolean
00227 parse_node (Parser      *parser,
00228             const char  *element_name,
00229             const char **attribute_names,
00230             const char **attribute_values,
00231             GError     **error)
00232 {
00233   const char *name;
00234   NodeInfo *node;
00235   
00236   if (parser->interface ||
00237       parser->method ||
00238       parser->signal ||
00239       parser->arg)
00240     {
00241       g_set_error (error, G_MARKUP_ERROR,
00242                    G_MARKUP_ERROR_PARSE,
00243                    _("Can't put a <%s> element here"),
00244                    element_name);
00245       return FALSE;      
00246     }
00247 
00248   name = NULL;
00249   if (!locate_attributes (element_name, attribute_names,
00250                           attribute_values, error,
00251                           "name", &name,
00252                           NULL))
00253     return FALSE;
00254 
00255   /* Only the root node can have no name */
00256   if (parser->node_stack != NULL && name == NULL)
00257     {
00258       g_set_error (error, G_MARKUP_ERROR,
00259                    G_MARKUP_ERROR_PARSE,
00260                    _("\"%s\" attribute required on <%s> element "),
00261                    "name", element_name);
00262       return FALSE;
00263     }
00264 
00265   
00266   node = node_info_new (name);
00267 
00268   if (parser->node_stack != NULL)
00269     {
00270       node_info_add_node (parser->node_stack->data,
00271                           node);
00272     }
00273   
00274   parser->node_stack = g_slist_prepend (parser->node_stack,
00275                                         node);
00276   
00277   return TRUE;
00278 }
00279 
00280 static gboolean
00281 parse_interface (Parser      *parser,
00282                  const char  *element_name,
00283                  const char **attribute_names,
00284                  const char **attribute_values,
00285                  GError     **error)
00286 {
00287   const char *name;
00288   InterfaceInfo *iface;
00289   NodeInfo *top;
00290   
00291   if (parser->interface ||
00292       parser->method ||
00293       parser->signal ||
00294       parser->arg ||
00295       (parser->node_stack == NULL))
00296     {
00297       g_set_error (error, G_MARKUP_ERROR,
00298                    G_MARKUP_ERROR_PARSE,
00299                    _("Can't put a <%s> element here"),
00300                    element_name);
00301       return FALSE;      
00302     }
00303 
00304   name = NULL;
00305   if (!locate_attributes (element_name, attribute_names,
00306                           attribute_values, error,
00307                           "name", &name,
00308                           NULL))
00309     return FALSE;
00310 
00311   if (name == NULL)
00312     {
00313       g_set_error (error, G_MARKUP_ERROR,
00314                    G_MARKUP_ERROR_PARSE,
00315                    _("\"%s\" attribute required on <%s> element "),
00316                    "name", element_name);
00317       return FALSE;
00318     }
00319 
00320   top = parser->node_stack->data;
00321   
00322   iface = interface_info_new (name);
00323   node_info_add_interface (top, iface);
00324   interface_info_unref (iface);
00325 
00326   parser->interface = iface;
00327   
00328   return TRUE;
00329 }
00330 
00331 static gboolean
00332 parse_method (Parser      *parser,
00333               const char  *element_name,
00334               const char **attribute_names,
00335               const char **attribute_values,
00336               GError     **error)
00337 {
00338   const char *name;
00339   MethodInfo *method;
00340   NodeInfo *top;
00341   
00342   if (parser->interface == NULL ||
00343       parser->node_stack == NULL ||
00344       parser->method ||
00345       parser->signal ||
00346       parser->arg)
00347     {
00348       g_set_error (error, G_MARKUP_ERROR,
00349                    G_MARKUP_ERROR_PARSE,
00350                    _("Can't put a <%s> element here"),
00351                    element_name);
00352       return FALSE;      
00353     }
00354 
00355   name = NULL;
00356   if (!locate_attributes (element_name, attribute_names,
00357                           attribute_values, error,
00358                           "name", &name,
00359                           NULL))
00360     return FALSE;
00361 
00362   if (name == NULL)
00363     {
00364       g_set_error (error, G_MARKUP_ERROR,
00365                    G_MARKUP_ERROR_PARSE,
00366                    _("\"%s\" attribute required on <%s> element "),
00367                    "name", element_name);
00368       return FALSE;
00369     }
00370 
00371   top = parser->node_stack->data;
00372   
00373   method = method_info_new (name);
00374   interface_info_add_method (parser->interface, method);
00375   method_info_unref (method);
00376 
00377   parser->method = method;
00378   
00379   return TRUE;
00380 }
00381 
00382 static gboolean
00383 parse_signal (Parser      *parser,
00384               const char  *element_name,
00385               const char **attribute_names,
00386               const char **attribute_values,
00387               GError     **error)
00388 {
00389   const char *name;
00390   SignalInfo *signal;
00391   NodeInfo *top;
00392   
00393   if (parser->interface == NULL ||
00394       parser->node_stack == NULL ||
00395       parser->signal ||
00396       parser->signal ||
00397       parser->arg)
00398     {
00399       g_set_error (error, G_MARKUP_ERROR,
00400                    G_MARKUP_ERROR_PARSE,
00401                    _("Can't put a <%s> element here"),
00402                    element_name);
00403       return FALSE;      
00404     }
00405 
00406   name = NULL;
00407   if (!locate_attributes (element_name, attribute_names,
00408                           attribute_values, error,
00409                           "name", &name,
00410                           NULL))
00411     return FALSE;
00412 
00413   if (name == NULL)
00414     {
00415       g_set_error (error, G_MARKUP_ERROR,
00416                    G_MARKUP_ERROR_PARSE,
00417                    _("\"%s\" attribute required on <%s> element "),
00418                    "name", element_name);
00419       return FALSE;
00420     }
00421 
00422   top = parser->node_stack->data;
00423   
00424   signal = signal_info_new (name);
00425   interface_info_add_signal (parser->interface, signal);
00426   signal_info_unref (signal);
00427 
00428   parser->signal = signal;
00429   
00430   return TRUE;
00431 }
00432 
00433 static int
00434 basic_type_from_string (const char *str)
00435 {
00436   if (strcmp (str, "string") == 0)
00437     return DBUS_TYPE_STRING;
00438   else if (strcmp (str, "int32") == 0)
00439     return DBUS_TYPE_INT32;
00440   else if (strcmp (str, "uint32") == 0)
00441     return DBUS_TYPE_UINT32;
00442   else if (strcmp (str, "int64") == 0)
00443     return DBUS_TYPE_INT64;
00444   else if (strcmp (str, "uint64") == 0)
00445     return DBUS_TYPE_UINT64;
00446   else if (strcmp (str, "double") == 0)
00447     return DBUS_TYPE_DOUBLE;
00448   else if (strcmp (str, "byte") == 0)
00449     return DBUS_TYPE_BYTE;
00450   else if (strcmp (str, "boolean") == 0)
00451     return DBUS_TYPE_BOOLEAN;
00452   else if (strcmp (str, "byte") == 0)
00453     return DBUS_TYPE_BYTE;
00454   else if (strcmp (str, "object") == 0)
00455     return DBUS_TYPE_OBJECT_PATH;
00456   else
00457     return DBUS_TYPE_INVALID;
00458 }
00459 
00460 static int
00461 type_from_string (const char *str)
00462 {
00463   return basic_type_from_string (str);
00464 }
00465 
00466 static gboolean
00467 parse_arg (Parser      *parser,
00468            const char  *element_name,
00469            const char **attribute_names,
00470            const char **attribute_values,
00471            GError     **error)
00472 {
00473   const char *name;
00474   const char *type;
00475   const char *direction;
00476   ArgDirection dir;
00477   int t;
00478   ArgInfo *arg;
00479   
00480   if (!(parser->method || parser->signal) ||
00481       parser->node_stack == NULL ||
00482       parser->arg)
00483     {
00484       g_set_error (error, G_MARKUP_ERROR,
00485                    G_MARKUP_ERROR_PARSE,
00486                    _("Can't put a <%s> element here"),
00487                    element_name);
00488       return FALSE;      
00489     }
00490 
00491   name = NULL;
00492   if (!locate_attributes (element_name, attribute_names,
00493                           attribute_values, error,
00494                           "name", &name,
00495                           "type", &type,
00496                           "direction", &direction,
00497                           NULL))
00498     return FALSE;
00499 
00500   /* name can be null for args */
00501   
00502   if (type == NULL)
00503     {
00504       g_set_error (error, G_MARKUP_ERROR,
00505                    G_MARKUP_ERROR_PARSE,
00506                    _("\"%s\" attribute required on <%s> element "),
00507                    "type", element_name);
00508       return FALSE;
00509     }
00510 
00511   if (direction == NULL)
00512     {
00513       /* methods default to in, signal to out */
00514       if (parser->method)
00515         direction = "in";
00516       else if (parser->signal)
00517         direction = "out";
00518       else
00519         g_assert_not_reached ();
00520     }
00521 
00522   if (strcmp (direction, "in") == 0)
00523     dir = ARG_IN;
00524   else if (strcmp (direction, "out") == 0)
00525     dir = ARG_OUT;
00526   else
00527     {
00528       g_set_error (error, G_MARKUP_ERROR,
00529                    G_MARKUP_ERROR_PARSE,
00530                    _("\"%s\" attribute on <%s> has value \"in\" or \"out\""),
00531                    "direction", element_name);
00532       return FALSE;
00533     }
00534 
00535   t = type_from_string (type);
00536   
00537   arg = arg_info_new (name, dir, t);
00538   if (parser->method)
00539     method_info_add_arg (parser->method, arg);
00540   else if (parser->signal)
00541     signal_info_add_arg (parser->signal, arg);
00542   else
00543     g_assert_not_reached ();
00544 
00545   arg_info_unref (arg);
00546 
00547   parser->arg = arg;
00548   
00549   return TRUE;
00550 }
00551 
00552 gboolean
00553 parser_start_element (Parser      *parser,
00554                       const char  *element_name,
00555                       const char **attribute_names,
00556                       const char **attribute_values,
00557                       GError     **error)
00558 {
00559   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
00560 
00561   if (ELEMENT_IS ("node"))
00562     {
00563       if (!parse_node (parser, element_name, attribute_names,
00564                        attribute_values, error))
00565         return FALSE;
00566     }
00567   else if (ELEMENT_IS ("interface"))
00568     {
00569       if (!parse_interface (parser, element_name, attribute_names,
00570                             attribute_values, error))
00571         return FALSE;
00572     }
00573   else if (ELEMENT_IS ("method"))
00574     {
00575       if (!parse_method (parser, element_name, attribute_names,
00576                          attribute_values, error))
00577         return FALSE;
00578     }
00579   else if (ELEMENT_IS ("signal"))
00580     {
00581       if (!parse_signal (parser, element_name, attribute_names,
00582                          attribute_values, error))
00583         return FALSE;
00584     }
00585   else if (ELEMENT_IS ("arg"))
00586     {
00587       if (!parse_arg (parser, element_name, attribute_names,
00588                       attribute_values, error))
00589         return FALSE;
00590     }
00591   else
00592     {
00593       g_set_error (error, G_MARKUP_ERROR,
00594                    G_MARKUP_ERROR_PARSE,
00595                    _("Element <%s> not recognized"),
00596                    element_name);
00597     }
00598   
00599   return TRUE;
00600 }
00601 
00602 gboolean
00603 parser_end_element (Parser      *parser,
00604                     const char  *element_name,
00605                     GError     **error)
00606 {
00607   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
00608 
00609   if (ELEMENT_IS ("interface"))
00610     {
00611       parser->interface = NULL;
00612     }
00613   else if (ELEMENT_IS ("method"))
00614     {
00615       parser->method = NULL;
00616     }
00617   else if (ELEMENT_IS ("signal"))
00618     {
00619       parser->signal = NULL;
00620     }
00621   else if (ELEMENT_IS ("arg"))
00622     {
00623       parser->arg = NULL;
00624     }
00625   else if (ELEMENT_IS ("node"))
00626     {
00627       NodeInfo *top;
00628 
00629       g_assert (parser->node_stack != NULL);
00630       top = parser->node_stack->data;
00631 
00632       parser->node_stack = g_slist_remove (parser->node_stack,
00633                                            top);
00634 
00635       if (parser->node_stack == NULL)
00636         parser->result = top; /* We are done, store the result */      
00637     }
00638   else
00639     g_assert_not_reached (); /* should have had an error on start_element */
00640   
00641   return TRUE;
00642 }
00643 
00644 gboolean
00645 parser_content (Parser      *parser,
00646                 const char  *content,
00647                 int          len,
00648                 GError     **error)
00649 {
00650   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
00651 
00652   return TRUE;
00653 }
00654 
00655 gboolean
00656 parser_finished (Parser      *parser,
00657                  GError     **error)
00658 {
00659   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
00660 
00661   return TRUE;
00662 }
00663 
00664 NodeInfo*
00665 parser_get_nodes (Parser *parser)
00666 {
00667   return parser->result;
00668 }
00669 
00670 #endif /* DOXYGEN_SHOULD_SKIP_THIS */

Generated on Tue Feb 10 18:14:02 2004 for D-BUS by doxygen 1.3.5