2005-02-17 Colin Walters <walters@verbum.org>
[platform/upstream/dbus.git] / glib / dbus-gparser.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-gparser.c parse DBus description files
3  *
4  * Copyright (C) 2003, 2005  Red Hat, Inc.
5  *
6  * Licensed under the Academic Free License version 2.1
7  * 
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.
12  *
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.
17  * 
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
21  *
22  */
23 #include "dbus-gparser.h"
24 #include "dbus-gidl.h"
25 #include <string.h>
26
27 #include <libintl.h>
28 #define _(x) gettext ((x))
29 #define N_(x) x
30
31 #ifndef DOXYGEN_SHOULD_SKIP_THIS
32
33 #define ELEMENT_IS(name) (strcmp (element_name, (name)) == 0)
34
35 typedef struct
36 {
37   const char  *name;
38   const char **retloc;
39 } LocateAttr;
40
41 static gboolean
42 locate_attributes (const char  *element_name,
43                    const char **attribute_names,
44                    const char **attribute_values,
45                    GError     **error,
46                    const char  *first_attribute_name,
47                    const char **first_attribute_retloc,
48                    ...)
49 {
50   va_list args;
51   const char *name;
52   const char **retloc;
53   int n_attrs;
54 #define MAX_ATTRS 24
55   LocateAttr attrs[MAX_ATTRS];
56   gboolean retval;
57   int i;
58
59   g_return_val_if_fail (first_attribute_name != NULL, FALSE);
60   g_return_val_if_fail (first_attribute_retloc != NULL, FALSE);
61
62   retval = TRUE;
63
64   n_attrs = 1;
65   attrs[0].name = first_attribute_name;
66   attrs[0].retloc = first_attribute_retloc;
67   *first_attribute_retloc = NULL;
68   
69   va_start (args, first_attribute_retloc);
70
71   name = va_arg (args, const char*);
72   retloc = va_arg (args, const char**);
73
74   while (name != NULL)
75     {
76       g_return_val_if_fail (retloc != NULL, FALSE);
77
78       g_assert (n_attrs < MAX_ATTRS);
79       
80       attrs[n_attrs].name = name;
81       attrs[n_attrs].retloc = retloc;
82       n_attrs += 1;
83       *retloc = NULL;      
84
85       name = va_arg (args, const char*);
86       retloc = va_arg (args, const char**);
87     }
88
89   va_end (args);
90
91   if (!retval)
92     return retval;
93
94   i = 0;
95   while (attribute_names[i])
96     {
97       int j;
98       gboolean found;
99
100       found = FALSE;
101       j = 0;
102       while (j < n_attrs)
103         {
104           if (strcmp (attrs[j].name, attribute_names[i]) == 0)
105             {
106               retloc = attrs[j].retloc;
107
108               if (*retloc != NULL)
109                 {
110                   g_set_error (error,
111                                G_MARKUP_ERROR,
112                                G_MARKUP_ERROR_PARSE,
113                                _("Attribute \"%s\" repeated twice on the same <%s> element"),
114                                attrs[j].name, element_name);
115                   retval = FALSE;
116                   goto out;
117                 }
118
119               *retloc = attribute_values[i];
120               found = TRUE;
121             }
122
123           ++j;
124         }
125
126       if (!found)
127         {
128           g_set_error (error,
129                        G_MARKUP_ERROR,
130                        G_MARKUP_ERROR_PARSE,
131                        _("Attribute \"%s\" is invalid on <%s> element in this context"),
132                        attribute_names[i], element_name);
133           retval = FALSE;
134           goto out;
135         }
136
137       ++i;
138     }
139
140  out:
141   return retval;
142 }
143
144 static gboolean
145 check_no_attributes (const char  *element_name,
146                      const char **attribute_names,
147                      const char **attribute_values,
148                      GError     **error)
149 {
150   if (attribute_names[0] != NULL)
151     {
152       g_set_error (error,
153                    G_MARKUP_ERROR,
154                    G_MARKUP_ERROR_PARSE,
155                    _("Attribute \"%s\" is invalid on <%s> element in this context"),
156                    attribute_names[0], element_name);
157       return FALSE;
158     }
159
160   return TRUE;
161 }
162
163 struct Parser
164 {
165   int refcount;
166
167   NodeInfo *result; /* Filled in when we pop the last node */
168   GSList *node_stack;
169   InterfaceInfo *interface;
170   MethodInfo *method;
171   SignalInfo *signal;
172   PropertyInfo *property;
173   ArgInfo *arg;
174   gboolean in_annotation;
175 };
176
177 Parser*
178 parser_new (void)
179 {
180   Parser *parser;
181
182   parser = g_new0 (Parser, 1);
183
184   parser->refcount = 1;
185
186   return parser;
187 }
188
189 Parser *
190 parser_ref (Parser *parser)
191 {
192   parser->refcount += 1;
193
194   return parser;
195 }
196
197 void
198 parser_unref (Parser *parser)
199 {
200   parser->refcount -= 1;
201   if (parser->refcount == 0)
202     {
203       if (parser->result)
204         node_info_unref (parser->result);
205
206       g_free (parser);
207     }
208 }
209
210 gboolean
211 parser_check_doctype (Parser      *parser,
212                       const char  *doctype,
213                       GError     **error)
214 {
215   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
216   
217   if (strcmp (doctype, "node") != 0)
218     {
219       g_set_error (error,
220                    G_MARKUP_ERROR,
221                    G_MARKUP_ERROR_PARSE,
222                    "D-BUS description file has the wrong document type %s, use node or interface",
223                    doctype);
224       return FALSE;
225     }
226   else
227     return TRUE;
228 }
229
230 static gboolean
231 parse_node (Parser      *parser,
232             const char  *element_name,
233             const char **attribute_names,
234             const char **attribute_values,
235             GError     **error)
236 {
237   const char *name;
238   NodeInfo *node;
239   
240   if (parser->interface ||
241       parser->method ||
242       parser->signal ||
243       parser->property ||
244       parser->arg ||
245       parser->in_annotation)
246     {
247       g_set_error (error, G_MARKUP_ERROR,
248                    G_MARKUP_ERROR_PARSE,
249                    _("Can't put <%s> element here"),
250                    element_name);
251       return FALSE;      
252     }
253
254   name = NULL;
255   if (!locate_attributes (element_name, attribute_names,
256                           attribute_values, error,
257                           "name", &name,
258                           NULL))
259     return FALSE;
260
261   /* Only the root node can have no name */
262   if (parser->node_stack != NULL && name == NULL)
263     {
264       g_set_error (error, G_MARKUP_ERROR,
265                    G_MARKUP_ERROR_PARSE,
266                    _("\"%s\" attribute required on <%s> element "),
267                    "name", element_name);
268       return FALSE;
269     }
270
271   /* Root element name must be absolute */
272   if (parser->node_stack == NULL && name && *name != '/')
273     {
274       g_set_error (error, G_MARKUP_ERROR,
275                    G_MARKUP_ERROR_PARSE,
276                    _("\"%s\" attribute on <%s> element must be an absolute object path, \"%s\" not OK"),
277                    "name", element_name, name);
278       return FALSE;
279     }
280
281   /* Other element names must not be absolute */
282   if (parser->node_stack != NULL && name && *name == '/')
283     {
284       g_set_error (error, G_MARKUP_ERROR,
285                    G_MARKUP_ERROR_PARSE,
286                    _("\"%s\" attribute on <%s> element must not be an absolute object path, \"%s\" starts with /"),
287                    "name", element_name, name);
288       return FALSE;
289     }
290   
291   node = node_info_new (name);
292
293   if (parser->node_stack != NULL)
294     {
295       node_info_add_node (parser->node_stack->data,
296                           node);
297     }
298   
299   parser->node_stack = g_slist_prepend (parser->node_stack,
300                                         node);
301   
302   return TRUE;
303 }
304
305 static gboolean
306 parse_interface (Parser      *parser,
307                  const char  *element_name,
308                  const char **attribute_names,
309                  const char **attribute_values,
310                  GError     **error)
311 {
312   const char *name;
313   InterfaceInfo *iface;
314   NodeInfo *top;
315   
316   if (parser->interface ||
317       parser->method ||
318       parser->signal ||
319       parser->property ||
320       parser->arg ||
321       parser->in_annotation ||
322       (parser->node_stack == NULL))
323     {
324       g_set_error (error, G_MARKUP_ERROR,
325                    G_MARKUP_ERROR_PARSE,
326                    _("Can't put <%s> element here"),
327                    element_name);
328       return FALSE;      
329     }
330
331   name = NULL;
332   if (!locate_attributes (element_name, attribute_names,
333                           attribute_values, error,
334                           "name", &name,
335                           NULL))
336     return FALSE;
337
338   if (name == NULL)
339     {
340       g_set_error (error, G_MARKUP_ERROR,
341                    G_MARKUP_ERROR_PARSE,
342                    _("\"%s\" attribute required on <%s> element "),
343                    "name", element_name);
344       return FALSE;
345     }
346
347   top = parser->node_stack->data;
348   
349   iface = interface_info_new (name);
350   node_info_add_interface (top, iface);
351   interface_info_unref (iface);
352
353   parser->interface = iface;
354   
355   return TRUE;
356 }
357
358 static gboolean
359 parse_method (Parser      *parser,
360               const char  *element_name,
361               const char **attribute_names,
362               const char **attribute_values,
363               GError     **error)
364 {
365   const char *name;
366   MethodInfo *method;
367   NodeInfo *top;
368   
369   if (parser->interface == NULL ||
370       parser->node_stack == NULL ||
371       parser->method ||
372       parser->signal ||
373       parser->property ||
374       parser->in_annotation ||
375       parser->arg)
376     {
377       g_set_error (error, G_MARKUP_ERROR,
378                    G_MARKUP_ERROR_PARSE,
379                    _("Can't put <%s> element here"),
380                    element_name);
381       return FALSE;      
382     }
383
384   name = NULL;
385   if (!locate_attributes (element_name, attribute_names,
386                           attribute_values, error,
387                           "name", &name,
388                           NULL))
389     return FALSE;
390
391   if (name == NULL)
392     {
393       g_set_error (error, G_MARKUP_ERROR,
394                    G_MARKUP_ERROR_PARSE,
395                    _("\"%s\" attribute required on <%s> element "),
396                    "name", element_name);
397       return FALSE;
398     }
399
400   top = parser->node_stack->data;
401   
402   method = method_info_new (name);
403   interface_info_add_method (parser->interface, method);
404   method_info_unref (method);
405
406   parser->method = method;
407   
408   return TRUE;
409 }
410
411 static gboolean
412 parse_signal (Parser      *parser,
413               const char  *element_name,
414               const char **attribute_names,
415               const char **attribute_values,
416               GError     **error)
417 {
418   const char *name;
419   SignalInfo *signal;
420   NodeInfo *top;
421   
422   if (parser->interface == NULL ||
423       parser->node_stack == NULL ||
424       parser->signal ||
425       parser->method ||
426       parser->property ||
427       parser->in_annotation ||
428       parser->arg)
429     {
430       g_set_error (error, G_MARKUP_ERROR,
431                    G_MARKUP_ERROR_PARSE,
432                    _("Can't put <%s> element here"),
433                    element_name);
434       return FALSE;      
435     }
436
437   name = NULL;
438   if (!locate_attributes (element_name, attribute_names,
439                           attribute_values, error,
440                           "name", &name,
441                           NULL))
442     return FALSE;
443
444   if (name == NULL)
445     {
446       g_set_error (error, G_MARKUP_ERROR,
447                    G_MARKUP_ERROR_PARSE,
448                    _("\"%s\" attribute required on <%s> element "),
449                    "name", element_name);
450       return FALSE;
451     }
452
453   top = parser->node_stack->data;
454   
455   signal = signal_info_new (name);
456   interface_info_add_signal (parser->interface, signal);
457   signal_info_unref (signal);
458
459   parser->signal = signal;
460   
461   return TRUE;
462 }
463
464 static int
465 basic_type_from_string (const char *str)
466 {
467   if (strcmp (str, "string") == 0)
468     return DBUS_TYPE_STRING;
469   else if (strcmp (str, "int16") == 0)
470     return DBUS_TYPE_INT16;
471   else if (strcmp (str, "uint16") == 0)
472     return DBUS_TYPE_UINT16;
473   else if (strcmp (str, "int32") == 0)
474     return DBUS_TYPE_INT32;
475   else if (strcmp (str, "uint32") == 0)
476     return DBUS_TYPE_UINT32;
477   else if (strcmp (str, "int64") == 0)
478     return DBUS_TYPE_INT64;
479   else if (strcmp (str, "uint64") == 0)
480     return DBUS_TYPE_UINT64;
481   else if (strcmp (str, "double") == 0)
482     return DBUS_TYPE_DOUBLE;
483   else if (strcmp (str, "byte") == 0)
484     return DBUS_TYPE_BYTE;
485   else if (strcmp (str, "boolean") == 0)
486     return DBUS_TYPE_BOOLEAN;
487   else if (strcmp (str, "byte") == 0)
488     return DBUS_TYPE_BYTE;
489   else if (strcmp (str, "object") == 0)
490     return DBUS_TYPE_OBJECT_PATH;
491   else if (strcmp (str, "variant") == 0)
492     return DBUS_TYPE_VARIANT;
493   else
494     return DBUS_TYPE_INVALID;
495 }
496
497 /* FIXME we have to allow type signatures, not just basic types
498  */
499 static int
500 type_from_string (const char *str,
501                   const char *element_name,
502                   GError    **error)
503 {
504   int t;
505   
506   t = basic_type_from_string (str);
507
508   if (t == DBUS_TYPE_INVALID)
509     {
510       g_set_error (error, G_MARKUP_ERROR,
511                    G_MARKUP_ERROR_PARSE,
512                    _("Type \"%s\" not understood on <%s> element "),
513                    str, element_name);
514     }
515
516   return t;
517 }
518
519 static gboolean
520 parse_property (Parser      *parser,
521                 const char  *element_name,
522                 const char **attribute_names,
523                 const char **attribute_values,
524                 GError     **error)
525 {
526   const char *name;
527   const char *access;
528   const char *type;
529   PropertyInfo *property;
530   NodeInfo *top;
531   PropertyAccessFlags access_flags;
532   int t;
533   
534   if (parser->interface == NULL ||
535       parser->node_stack == NULL ||
536       parser->signal ||
537       parser->method ||
538       parser->property ||
539       parser->in_annotation ||
540       parser->arg)
541     {
542       g_set_error (error, G_MARKUP_ERROR,
543                    G_MARKUP_ERROR_PARSE,
544                    _("Can't put <%s> element here"),
545                    element_name);
546       return FALSE;      
547     }
548
549   name = NULL;
550   if (!locate_attributes (element_name, attribute_names,
551                           attribute_values, error,
552                           "name", &name,
553                           "access", &access,
554                           "type", &type,
555                           NULL))
556     return FALSE;
557
558   if (name == NULL)
559     {
560       g_set_error (error, G_MARKUP_ERROR,
561                    G_MARKUP_ERROR_PARSE,
562                    _("\"%s\" attribute required on <%s> element "),
563                    "name", element_name);
564       return FALSE;
565     }
566
567   if (access == NULL)
568     {
569       g_set_error (error, G_MARKUP_ERROR,
570                    G_MARKUP_ERROR_PARSE,
571                    _("\"%s\" attribute required on <%s> element "),
572                    "access", element_name);
573       return FALSE;
574     }
575
576   if (type == NULL)
577     {
578       g_set_error (error, G_MARKUP_ERROR,
579                    G_MARKUP_ERROR_PARSE,
580                    _("\"%s\" attribute required on <%s> element "),
581                    "type", element_name);
582       return FALSE;
583     }
584
585   t = type_from_string (type, element_name, error);
586   if (t == DBUS_TYPE_INVALID)
587     return FALSE;
588
589   access_flags = 0;
590   if (strcmp (access, "readwrite") == 0)
591     access_flags = PROPERTY_READ | PROPERTY_WRITE;
592   else if (strcmp (access, "read") == 0)
593     access_flags = PROPERTY_READ;
594   else if (strcmp (access, "write") == 0)
595     access_flags = PROPERTY_WRITE;
596   else
597     {
598       g_set_error (error, G_MARKUP_ERROR,
599                    G_MARKUP_ERROR_PARSE,
600                    _("access=\"%s\" must have value readwrite, read, or write on %s\n"),
601                    access, element_name);
602       return FALSE;
603     }
604   
605   top = parser->node_stack->data;
606   
607   property = property_info_new (name, t, access_flags);
608   interface_info_add_property (parser->interface, property);
609   property_info_unref (property);
610
611   parser->property = property;
612   
613   return TRUE;
614 }
615
616 static gboolean
617 parse_arg (Parser      *parser,
618            const char  *element_name,
619            const char **attribute_names,
620            const char **attribute_values,
621            GError     **error)
622 {
623   const char *name;
624   const char *type;
625   const char *direction;
626   ArgDirection dir;
627   int t;
628   ArgInfo *arg;
629   char *generated_name;
630   
631   if (!(parser->method || parser->signal) ||
632       parser->node_stack == NULL ||
633       parser->property ||
634       parser->in_annotation ||
635       parser->arg)
636     {
637       g_set_error (error, G_MARKUP_ERROR,
638                    G_MARKUP_ERROR_PARSE,
639                    _("Can't put <%s> element here"),
640                    element_name);
641       return FALSE;      
642     }
643
644   name = NULL;
645   if (!locate_attributes (element_name, attribute_names,
646                           attribute_values, error,
647                           "name", &name,
648                           "type", &type,
649                           "direction", &direction,
650                           NULL))
651     return FALSE;
652
653   /* name can be null for args */
654   
655   if (type == NULL)
656     {
657       g_set_error (error, G_MARKUP_ERROR,
658                    G_MARKUP_ERROR_PARSE,
659                    _("\"%s\" attribute required on <%s> element "),
660                    "type", element_name);
661       return FALSE;
662     }
663
664   if (direction == NULL)
665     {
666       /* methods default to in, signal to out */
667       if (parser->method)
668         direction = "in";
669       else if (parser->signal)
670         direction = "out";
671       else
672         g_assert_not_reached ();
673     }
674
675   dir = ARG_INVALID;
676   
677   if (strcmp (direction, "in") == 0)
678     dir = ARG_IN;
679   else if (strcmp (direction, "out") == 0)
680     dir = ARG_OUT;
681   
682   if (dir == ARG_INVALID ||
683       (parser->signal && dir == ARG_IN))
684     {
685       if (parser->signal)
686         g_set_error (error, G_MARKUP_ERROR,
687                      G_MARKUP_ERROR_PARSE,
688                      _("Signals must have direction=\"out\" (just omit the direction attribute)"));
689       else
690         g_set_error (error, G_MARKUP_ERROR,
691                      G_MARKUP_ERROR_PARSE,
692                      _("\"%s\" attribute on <%s> has value \"in\" or \"out\""),
693                      "direction", element_name);
694       return FALSE;
695     }
696
697   t = type_from_string (type, element_name, error);
698   if (t == DBUS_TYPE_INVALID)
699     return FALSE;
700
701   generated_name = NULL;
702   if (name == NULL)
703     generated_name = g_strdup_printf ("arg%d",
704                                       parser->method ?
705                                       method_info_get_n_args (parser->method) :
706                                       signal_info_get_n_args (parser->signal));
707                                       
708   
709   arg = arg_info_new (name ? name : generated_name, dir, t);
710   if (parser->method)
711     method_info_add_arg (parser->method, arg);
712   else if (parser->signal)
713     signal_info_add_arg (parser->signal, arg);
714   else
715     g_assert_not_reached ();
716
717   g_free (generated_name);
718   
719   arg_info_unref (arg);
720
721   parser->arg = arg;
722   
723   return TRUE;
724 }
725
726 static gboolean
727 parse_annotation (Parser      *parser,
728                   const char  *element_name,
729                   const char **attribute_names,
730                   const char **attribute_values,
731                   GError     **error)
732 {
733   const char *name;
734   const char *value;
735   
736   if (!(parser->method || parser->interface || parser->arg) || 
737       parser->node_stack == NULL ||
738       parser->signal ||
739       parser->in_annotation)
740     {
741       g_set_error (error, G_MARKUP_ERROR,
742                    G_MARKUP_ERROR_PARSE,
743                    _("Can't put <%s> element here"),
744                    element_name);
745       return FALSE;      
746     }
747
748   name = NULL;
749   if (!locate_attributes (element_name, attribute_names,
750                           attribute_values, error,
751                           "name", &name,
752                           "value", &value,
753                           NULL))
754     return FALSE;
755
756   /* name can be null for args */
757   
758   if (name == NULL)
759     {
760       g_set_error (error, G_MARKUP_ERROR,
761                    G_MARKUP_ERROR_PARSE,
762                    _("\"%s\" attribute required on <%s> element "),
763                    "name", element_name);
764       return FALSE;
765     }
766   if (value == NULL)
767     {
768       g_set_error (error, G_MARKUP_ERROR,
769                    G_MARKUP_ERROR_PARSE,
770                    _("\"%s\" attribute required on <%s> element "),
771                    "value", element_name);
772       return FALSE;
773     }
774
775   if (parser->method)
776     method_info_add_annotation (parser->method, name, value);
777   else if (parser->interface)
778     interface_info_add_annotation (parser->interface, name, value);
779   else
780     g_assert_not_reached ();
781
782   parser->in_annotation = TRUE;
783
784   return TRUE;
785 }
786
787 gboolean
788 parser_start_element (Parser      *parser,
789                       const char  *element_name,
790                       const char **attribute_names,
791                       const char **attribute_values,
792                       GError     **error)
793 {
794   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
795
796   if (ELEMENT_IS ("node"))
797     {
798       if (!parse_node (parser, element_name, attribute_names,
799                        attribute_values, error))
800         return FALSE;
801     }
802   else if (ELEMENT_IS ("interface"))
803     {
804       if (!parse_interface (parser, element_name, attribute_names,
805                             attribute_values, error))
806         return FALSE;
807     }
808   else if (ELEMENT_IS ("method"))
809     {
810       if (!parse_method (parser, element_name, attribute_names,
811                          attribute_values, error))
812         return FALSE;
813     }
814   else if (ELEMENT_IS ("signal"))
815     {
816       if (!parse_signal (parser, element_name, attribute_names,
817                          attribute_values, error))
818         return FALSE;
819     }
820   else if (ELEMENT_IS ("property"))
821     {
822       if (!parse_property (parser, element_name, attribute_names,
823                            attribute_values, error))
824         return FALSE;
825     }
826   else if (ELEMENT_IS ("arg"))
827     {
828       if (!parse_arg (parser, element_name, attribute_names,
829                       attribute_values, error))
830         return FALSE;
831     }
832   else if (ELEMENT_IS ("annotation"))
833     {
834       if (!parse_annotation (parser, element_name, attribute_names,
835                              attribute_values, error))
836         return FALSE;
837     }
838   else
839     {
840       g_set_error (error, G_MARKUP_ERROR,
841                    G_MARKUP_ERROR_PARSE,
842                    _("Element <%s> not recognized"),
843                    element_name);
844     }
845   
846   return TRUE;
847 }
848
849 gboolean
850 parser_end_element (Parser      *parser,
851                     const char  *element_name,
852                     GError     **error)
853 {
854   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
855
856   if (ELEMENT_IS ("interface"))
857     {
858       parser->interface = NULL;
859     }
860   else if (ELEMENT_IS ("method"))
861     {
862       parser->method = NULL;
863     }
864   else if (ELEMENT_IS ("signal"))
865     {
866       parser->signal = NULL;
867     }
868   else if (ELEMENT_IS ("property"))
869     {
870       parser->property = NULL;
871     }
872   else if (ELEMENT_IS ("arg"))
873     {
874       parser->arg = NULL;
875     }
876   else if (ELEMENT_IS ("annotation"))
877     {
878       parser->in_annotation = FALSE;
879     }
880   else if (ELEMENT_IS ("node"))
881     {
882       NodeInfo *top;
883
884       g_assert (parser->node_stack != NULL);
885       top = parser->node_stack->data;
886
887       parser->node_stack = g_slist_remove (parser->node_stack,
888                                            top);
889
890       if (parser->node_stack == NULL)
891         parser->result = top; /* We are done, store the result */      
892     }
893   else
894     g_assert_not_reached (); /* should have had an error on start_element */
895   
896   return TRUE;
897 }
898
899 gboolean
900 parser_content (Parser      *parser,
901                 const char  *content,
902                 int          len,
903                 GError     **error)
904 {
905   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
906
907   /* FIXME check that it's all whitespace */
908   
909   return TRUE;
910 }
911
912 gboolean
913 parser_finished (Parser      *parser,
914                  GError     **error)
915 {
916   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
917
918   return TRUE;
919 }
920
921 NodeInfo*
922 parser_get_nodes (Parser *parser)
923 {
924   return parser->result;
925 }
926
927 #endif /* DOXYGEN_SHOULD_SKIP_THIS */