Make some changes to the way that GMainContext works:
[platform/upstream/glib.git] / gobject / glib-genmarshal.c
1 /* GLIB-GenMarshal - Marshaller generator for GObject library
2  * Copyright (C) 2000-2001 Red Hat, Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19 #include        "config.h"
20
21
22 /* ok, this is a bit hackish, have to provide gruntime log domain as
23  * we don't link against -lgruntime
24  */
25 char *g_log_domain_gruntime = "GLib-Genmarshal";
26
27 #include        <glib.h>
28
29 #include        <stdio.h>
30 #include        <stdlib.h>
31 #include        <fcntl.h>
32 #include        <string.h>
33 #include        <errno.h>
34 #ifdef HAVE_UNISTD_H
35 #include        <unistd.h>
36 #endif
37 #include        <sys/types.h>
38 #include        <sys/stat.h>
39
40 #ifdef G_OS_WIN32
41 #include <io.h>
42 #endif
43
44 /* --- defines --- */
45 #define PRG_NAME        "glib-genmarshal"
46 #define PKG_NAME        "GLib"
47 #define PKG_HTTP_HOME   "http://www.gtk.org"
48
49
50 /* --- typedefs & structures --- */
51 typedef struct
52 {
53   gchar       *keyword;         /* marhaller list keyword [MY_STRING] */
54   const gchar *sig_name;        /* signature name [STRING] */
55   const gchar *ctype;           /* C type name [gchar*] */
56   const gchar *getter;          /* value getter function [g_value_get_string] */
57 } InArgument;
58 typedef struct
59 {
60   gchar       *keyword;         /* marhaller list keyword [MY_STRING] */
61   const gchar *sig_name;        /* signature name [STRING] */
62   const gchar *ctype;           /* C type name [gchar*] */
63   const gchar *setter;          /* value setter function [g_value_set_string] */
64   const gchar *release;         /* value release function [g_free] */
65 } OutArgument;
66 typedef struct
67 {
68   gchar       *ploc;
69   OutArgument *rarg;
70   GList       *args;    /* of type InArgument* */
71 } Signature;
72
73
74 /* --- prototypes --- */
75 static void     parse_args      (gint           *argc_p,
76                                  gchar       ***argv_p);
77 static void     print_blurb     (FILE           *bout,
78                                  gboolean        print_help);
79
80
81 /* --- variables --- */
82 static FILE          *fout = NULL;
83 static GScannerConfig scanner_config_template =
84 {
85   (
86    " \t\r"              /* "\n" is statement delimiter */
87    )                    /* cset_skip_characters */,
88   (
89    G_CSET_a_2_z
90    "_"
91    G_CSET_A_2_Z
92    )                    /* cset_identifier_first */,
93   (
94    G_CSET_a_2_z
95    "_0123456789"
96    G_CSET_A_2_Z
97    )                    /* cset_identifier_nth */,
98   ( "#\n" )             /* cpair_comment_single */,
99
100   FALSE                 /* case_sensitive */,
101
102   TRUE                  /* skip_comment_multi */,
103   TRUE                  /* skip_comment_single */,
104   TRUE                  /* scan_comment_multi */,
105   TRUE                  /* scan_identifier */,
106   FALSE                 /* scan_identifier_1char */,
107   FALSE                 /* scan_identifier_NULL */,
108   TRUE                  /* scan_symbols */,
109   FALSE                 /* scan_binary */,
110   TRUE                  /* scan_octal */,
111   TRUE                  /* scan_float */,
112   TRUE                  /* scan_hex */,
113   FALSE                 /* scan_hex_dollar */,
114   TRUE                  /* scan_string_sq */,
115   TRUE                  /* scan_string_dq */,
116   TRUE                  /* numbers_2_int */,
117   FALSE                 /* int_2_float */,
118   FALSE                 /* identifier_2_string */,
119   TRUE                  /* char_2_token */,
120   FALSE                 /* symbol_2_token */,
121   FALSE                 /* scope_0_fallback */,
122 };
123 static gchar            *std_marshaller_prefix = "g_cclosure_marshal";
124 static gchar            *marshaller_prefix = "g_cclosure_user_marshal";
125 static GHashTable       *marshallers = NULL;
126 static gboolean          gen_cheader = FALSE;
127 static gboolean          gen_cbody = FALSE;
128 static gboolean          skip_ploc = FALSE;
129 static gboolean          std_includes = TRUE;
130
131
132 /* --- functions --- */
133 static gboolean
134 complete_in_arg (InArgument *iarg)
135 {
136   static const InArgument args[] = {
137     /* keyword          sig_name        ctype           getter                  */
138     { "VOID",           "VOID",         "void",         NULL,                   },
139     { "BOOLEAN",        "BOOLEAN",      "gboolean",     "g_value_get_boolean",  },
140     { "CHAR",           "CHAR",         "gchar",        "g_value_get_char",     },
141     { "UCHAR",          "UCHAR",        "guchar",       "g_value_get_uchar",    },
142     { "INT",            "INT",          "gint",         "g_value_get_int",      },
143     { "UINT",           "UINT",         "guint",        "g_value_get_uint",     },
144     { "LONG",           "LONG",         "glong",        "g_value_get_long",     },
145     { "ULONG",          "ULONG",        "gulong",       "g_value_get_ulong",    },
146     { "ENUM",           "ENUM",         "gint",         "g_value_get_enum",     },
147     { "FLAGS",          "FLAGS",        "guint",        "g_value_get_flags",    },
148     { "FLOAT",          "FLOAT",        "gfloat",       "g_value_get_float",    },
149     { "DOUBLE",         "DOUBLE",       "gdouble",      "g_value_get_double",   },
150     { "STRING",         "STRING",       "gpointer",     "(char*) g_value_get_string",   },
151     { "PARAM",          "PARAM",        "gpointer",     "g_value_get_param",    },
152     { "BOXED",          "BOXED",        "gpointer",     "g_value_get_boxed",    },
153     { "POINTER",        "POINTER",      "gpointer",     "g_value_get_pointer",  },
154     { "OBJECT",         "OBJECT",       "gpointer",     "g_value_get_object",   },
155     /* deprecated: */
156     { "NONE",           "VOID",         "void",         NULL,                   },
157     { "BOOL",           "BOOLEAN",      "gboolean",     "g_value_get_boolean",  },
158   };
159   const guint n_args = sizeof (args) / sizeof (args[0]);
160   guint i;
161
162   g_return_val_if_fail (iarg != NULL, FALSE);
163
164   for (i = 0; i < n_args; i++)
165     if (strcmp (args[i].keyword, iarg->keyword) == 0)
166       {
167         iarg->sig_name = args[i].sig_name;
168         iarg->ctype = args[i].ctype;
169         iarg->getter = args[i].getter;
170
171         return TRUE;
172       }
173   return FALSE;
174 }
175
176 static gboolean
177 complete_out_arg (OutArgument *oarg)
178 {
179   static const OutArgument args[] = {
180     /* keyword          sig_name        ctype           setter                  release */
181     { "VOID",           "VOID",         "void",         NULL,                   NULL,                   },
182     { "BOOLEAN",        "BOOLEAN",      "gboolean",     "g_value_set_boolean",  NULL,                   },
183     { "CHAR",           "CHAR",         "gchar",        "g_value_set_char",     NULL,                   },
184     { "UCHAR",          "UCHAR",        "guchar",       "g_value_set_uchar",    NULL,                   },
185     { "INT",            "INT",          "gint",         "g_value_set_int",      NULL,                   },
186     { "UINT",           "UINT",         "guint",        "g_value_set_uint",     NULL,                   },
187     { "LONG",           "LONG",         "glong",        "g_value_set_long",     NULL,                   },
188     { "ULONG",          "ULONG",        "gulong",       "g_value_set_ulong",    NULL,                   },
189     { "ENUM",           "ENUM",         "gint",         "g_value_set_enum",     NULL,                   },
190     { "FLAGS",          "FLAGS",        "guint",        "g_value_set_flags",    NULL,                   },
191     { "FLOAT",          "FLOAT",        "gfloat",       "g_value_set_float",    NULL,                   },
192     { "DOUBLE",         "DOUBLE",       "gdouble",      "g_value_set_double",   NULL,                   },
193     { "STRING",         "STRING",       "gchar*",       "g_value_set_string_take_ownership", NULL,      },
194     { "PARAM",          "PARAM",        "GParamSpec*",  "g_value_set_param",    "g_param_spec_unref",   },
195     { "BOXED",          "BOXED",        "gpointer",     "g_value_set_boxed_take_ownership", NULL,       },
196     { "POINTER",        "POINTER",      "gpointer",     "g_value_set_pointer",  NULL,                   },
197     { "OBJECT",         "OBJECT",       "GObject*",     "g_value_set_object",   "g_object_unref",       },
198     /* deprecated: */
199     { "NONE",           "VOID",         "void",         NULL,                   NULL,                   },
200     { "BOOL",           "BOOLEAN",      "gboolean",     "g_value_set_boolean",  NULL,                   },
201   };
202   const guint n_args = sizeof (args) / sizeof (args[0]);
203   guint i;
204
205   g_return_val_if_fail (oarg != NULL, FALSE);
206
207   for (i = 0; i < n_args; i++)
208     if (strcmp (args[i].keyword, oarg->keyword) == 0)
209       {
210         oarg->sig_name = args[i].sig_name;
211         oarg->ctype = args[i].ctype;
212         oarg->setter = args[i].setter;
213         oarg->release = args[i].release;
214
215         return TRUE;
216       }
217   return FALSE;
218 }
219
220 static const gchar*
221 pad (const gchar *string)
222 {
223 #define PAD_LENGTH      12
224   static gchar *buffer = NULL;
225   gint i;
226
227   g_return_val_if_fail (string != NULL, NULL);
228
229   if (!buffer)
230     buffer = g_new (gchar, PAD_LENGTH + 1);
231
232   /* paranoid check */
233   if (strlen (string) >= PAD_LENGTH)
234     {
235       g_free (buffer);
236       buffer = g_strdup_printf ("%s ", string);
237       g_warning ("overfull string (%u bytes) for padspace", (guint) strlen (string));
238
239       return buffer;
240     }
241
242   for (i = 0; i < PAD_LENGTH; i++)
243     {
244       gboolean done = *string == 0;
245
246       buffer[i] = done ? ' ' : *string++;
247     }
248   buffer[i] = 0;
249
250   return buffer;
251 }
252
253 static const gchar*
254 indent (guint n_spaces)
255 {
256   static gchar *buffer = NULL;
257   static guint blength = 0;
258
259   if (blength <= n_spaces)
260     {
261       blength = n_spaces + 1;
262       g_free (buffer);
263       buffer = g_new (gchar, blength);
264     }
265   memset (buffer, ' ', n_spaces);
266   buffer[n_spaces] = 0;
267
268   return buffer;
269 }
270
271 static void
272 generate_marshal (const gchar *signame,
273                   Signature   *sig)
274 {
275   guint ind, a;
276   GList *node;
277   gchar *tmp = g_strconcat (marshaller_prefix, "_", signame, NULL);
278   gboolean have_std_marshaller = FALSE;
279
280   /* here we have to make sure a marshaller named <marshaller_prefix>_<signame>
281    * exists. we might have put it out already, can revert to a standard marshaller
282    * provided by glib, or need to generate one.
283    */
284
285   if (g_hash_table_lookup (marshallers, tmp))
286     {
287       /* done, marshaller already generated */
288       g_free (tmp);
289       return;
290     }
291   else
292     {
293       /* need to alias/generate marshaller, register name */
294       g_hash_table_insert (marshallers, tmp, tmp);
295     }
296
297   /* can we revert to a standard marshaller? */
298   if (std_includes)
299     {
300       tmp = g_strconcat (std_marshaller_prefix, "_", signame, NULL);
301       have_std_marshaller = g_hash_table_lookup (marshallers, tmp) != NULL;
302       g_free (tmp);
303     }
304
305   if (gen_cheader && have_std_marshaller)
306     {
307       fprintf (fout, "#define %s_%s\t%s_%s\n", marshaller_prefix, signame, std_marshaller_prefix, signame);
308     }
309   if (gen_cheader && !have_std_marshaller)
310     {
311       ind = fprintf (fout, "extern void ");
312       ind += fprintf (fout, "%s_%s (", marshaller_prefix, signame);
313       fprintf (fout,   "GClosure     *closure,\n");
314       fprintf (fout, "%sGValue       *return_value,\n", indent (ind));
315       fprintf (fout, "%sguint         n_param_values,\n", indent (ind));
316       fprintf (fout, "%sconst GValue *param_values,\n", indent (ind));
317       fprintf (fout, "%sgpointer      invocation_hint,\n", indent (ind));
318       fprintf (fout, "%sgpointer      marshal_data);\n", indent (ind));
319     }
320   if (gen_cbody && !have_std_marshaller)
321     {
322       /* cfile marhsal header */
323       fprintf (fout, "void\n");
324       ind = fprintf (fout, "%s_%s (", marshaller_prefix, signame);
325       fprintf (fout,   "GClosure     *closure,\n");
326       fprintf (fout, "%sGValue       *return_value,\n", indent (ind));
327       fprintf (fout, "%sguint         n_param_values,\n", indent (ind));
328       fprintf (fout, "%sconst GValue *param_values,\n", indent (ind));
329       fprintf (fout, "%sgpointer      invocation_hint,\n", indent (ind));
330       fprintf (fout, "%sgpointer      marshal_data)\n", indent (ind));
331       fprintf (fout, "{\n");
332
333       /* cfile GMarshalFunc typedef */
334       ind = fprintf (fout, "  typedef %s (*GMarshalFunc_%s) (", sig->rarg->ctype, signame);
335       fprintf (fout, "%s data1,\n", pad ("gpointer"));
336       for (a = 1, node = sig->args; node; node = node->next)
337         {
338           InArgument *iarg = node->data;
339
340           if (iarg->getter)
341             fprintf (fout, "%s%s arg_%d,\n", indent (ind), pad (iarg->ctype), a++);
342         }
343       fprintf (fout, "%s%s data2);\n", indent (ind), pad ("gpointer"));
344
345       /* cfile marshal variables */
346       fprintf (fout, "  register GMarshalFunc_%s callback;\n", signame);
347       fprintf (fout, "  register GCClosure *cc = (GCClosure*) closure;\n");
348       fprintf (fout, "  register gpointer data1, data2;\n");
349       if (sig->rarg->setter)
350         fprintf (fout, "  %s v_return;\n", sig->rarg->ctype);
351
352       if (sig->args || sig->rarg->setter)
353         {
354           fprintf (fout, "\n");
355
356           if (sig->rarg->setter)
357             fprintf (fout, "  g_return_if_fail (return_value != NULL);\n");
358           if (sig->args)
359             {
360               for (a = 0, node = sig->args; node; node = node->next)
361                 {
362                   InArgument *iarg = node->data;
363
364                   if (iarg->getter)
365                     a++;
366                 }
367               fprintf (fout, "  g_return_if_fail (n_param_values == %u);\n", 1 + a);
368             }
369         }
370
371       /* cfile marshal data1, data2 and callback setup */
372       fprintf (fout, "\n");
373       fprintf (fout, "  if (G_CCLOSURE_SWAP_DATA (closure))\n    {\n");
374       fprintf (fout, "      data1 = closure->data;\n");
375       fprintf (fout, "      data2 = g_value_peek_pointer (param_values + 0);\n");
376       fprintf (fout, "    }\n  else\n    {\n");
377       fprintf (fout, "      data1 = g_value_peek_pointer (param_values + 0);\n");
378       fprintf (fout, "      data2 = closure->data;\n");
379       fprintf (fout, "    }\n");
380       fprintf (fout, "  callback = (GMarshalFunc_%s) (marshal_data ? marshal_data : cc->callback);\n", signame);
381
382       /* cfile marshal callback action */
383       fprintf (fout, "\n");
384       ind = fprintf (fout, " %s callback (", sig->rarg->setter ? " v_return =" : "");
385       fprintf (fout, "data1,\n");
386       for (a = 1, node = sig->args; node; node = node->next)
387         {
388           InArgument *iarg = node->data;
389
390           if (iarg->getter)
391             fprintf (fout, "%s%s (param_values + %d),\n", indent (ind), iarg->getter, a++);
392         }
393       fprintf (fout, "%sdata2);\n", indent (ind));
394
395       /* cfile marshal return value storage */
396       if (sig->rarg->setter)
397         {
398           fprintf (fout, "\n");
399           fprintf (fout, "  %s (return_value, v_return);\n", sig->rarg->setter);
400           if (sig->rarg->release)
401             fprintf (fout, "  %s (v_return);\n", sig->rarg->release);
402         }
403
404       /* cfile marshal footer */
405       fprintf (fout, "}\n");
406     }
407 }
408
409 static void
410 process_signature (Signature *sig)
411 {
412   gchar *pname, *sname, *tmp;
413   GList *node;
414
415   /* lookup and complete info on arguments */
416   if (!complete_out_arg (sig->rarg))
417     {
418       g_warning ("unknown type: %s", sig->rarg->keyword);
419       return;
420     }
421   for (node = sig->args; node; node = node->next)
422     {
423       InArgument *iarg = node->data;
424
425       if (!complete_in_arg (iarg))
426         {
427           g_warning ("unknown type: %s", iarg->keyword);
428           return;
429         }
430     }
431
432   /* construct requested marshaller name and technical marshaller name */
433   pname = g_strconcat (sig->rarg->keyword, "_", NULL);
434   sname = g_strconcat (sig->rarg->sig_name, "_", NULL);
435   for (node = sig->args; node; node = node->next)
436     {
437       InArgument *iarg = node->data;
438       gchar *tmp;
439
440       tmp = sname;
441       sname = g_strconcat (tmp, "_", iarg->sig_name, NULL);
442       g_free (tmp);
443       tmp = pname;
444       pname = g_strconcat (tmp, "_", iarg->keyword, NULL);
445       g_free (tmp);
446     }
447
448   /* introductionary comment */
449   fprintf (fout, "\n/* %s", sig->rarg->keyword);
450   for (node = sig->args; node; node = node->next)
451     {
452       InArgument *iarg = node->data;
453
454       fprintf (fout, "%c%s", node->prev ? ',' : ':', iarg->keyword);
455     }
456   if (!skip_ploc)
457     fprintf (fout, " (%s)", sig->ploc);
458   fprintf (fout, " */\n");
459
460   /* ensure technical marshaller exists (<marshaller_prefix>_<sname>) */
461   generate_marshal (sname, sig);
462
463   /* put out marshaller alias for requested name if required (<marshaller_prefix>_<pname>) */
464   tmp = g_strconcat (marshaller_prefix, "_", pname, NULL);
465   if (gen_cheader && !g_hash_table_lookup (marshallers, tmp))
466     {
467       fprintf (fout, "#define %s_%s\t%s_%s\n", marshaller_prefix, pname, marshaller_prefix, sname);
468
469       g_hash_table_insert (marshallers, tmp, tmp);
470     }
471   else
472     g_free (tmp);
473
474   g_free (pname);
475   g_free (sname);
476 }
477
478 static InArgument*
479 new_in_arg (const gchar *pname)
480 {
481   InArgument *iarg = g_new0 (InArgument, 1);
482
483   iarg->keyword = g_strdup (pname);
484
485   return iarg;
486 }
487
488 static OutArgument*
489 new_out_arg (const gchar *pname)
490 {
491   OutArgument *oarg = g_new0 (OutArgument, 1);
492
493   oarg->keyword = g_strdup (pname);
494
495   return oarg;
496 }
497
498 static guint
499 parse_line (GScanner  *scanner,
500             Signature *sig)
501 {
502   /* parse identifier for return value */
503   if (g_scanner_get_next_token (scanner) != G_TOKEN_IDENTIFIER)
504     return G_TOKEN_IDENTIFIER;
505   sig->rarg = new_out_arg (scanner->value.v_identifier);
506
507   /* keep a note on the location */
508   sig->ploc = g_strdup_printf ("%s:%u", scanner->input_name, scanner->line);
509
510   /* expect ':' */
511   if (g_scanner_get_next_token (scanner) != ':')
512     return ':';
513
514   /* parse first argument */
515   if (g_scanner_get_next_token (scanner) != G_TOKEN_IDENTIFIER)
516     return G_TOKEN_IDENTIFIER;
517   sig->args = g_list_append (sig->args, new_in_arg (scanner->value.v_identifier));
518
519   /* parse rest of argument list */
520   while (g_scanner_peek_next_token (scanner) == ',')
521     {
522       /* eat comma */
523       g_scanner_get_next_token (scanner);
524
525       /* parse arg identifier */
526       if (g_scanner_get_next_token (scanner) != G_TOKEN_IDENTIFIER)
527         return G_TOKEN_IDENTIFIER;
528       sig->args = g_list_append (sig->args, new_in_arg (scanner->value.v_identifier));
529     }
530   
531   /* expect end of line, done */
532   if (g_scanner_get_next_token (scanner) != '\n')
533     return '\n';
534   
535   /* success */
536   return G_TOKEN_NONE;
537 }
538
539 static gboolean
540 string_key_destroy (gpointer key,
541                     gpointer value,
542                     gpointer user_data)
543 {
544   g_free (key);
545
546   return TRUE;
547 }
548
549 int
550 main (int   argc,
551       char *argv[])
552 {
553   const gchar *gruntime_marshallers[] = {
554 #include        "gmarshal.strings"
555   };
556   GScanner *scanner;
557   GSList *slist, *files = NULL;
558   gint i;
559
560   /* parse args and do fast exits */
561   parse_args (&argc, &argv);
562
563   /* list input files */
564   for (i = 1; i < argc; i++)
565     files = g_slist_prepend (files, argv[i]);
566   if (files)
567     files = g_slist_reverse (files);
568   else
569     files = g_slist_prepend (files, "/dev/stdin");
570
571   /* setup auxillary structs */
572   scanner = g_scanner_new (&scanner_config_template);
573   fout = stdout;
574   marshallers = g_hash_table_new (g_str_hash, g_str_equal);
575
576   /* add GRuntime standard marshallers */
577   if (std_includes)
578     for (i = 0; i < sizeof (gruntime_marshallers) / sizeof (gruntime_marshallers[0]); i++)
579       {
580         gchar *tmp = g_strdup (gruntime_marshallers[i]);
581         
582         g_hash_table_insert (marshallers, tmp, tmp);
583       }
584
585   /* put out initial heading */
586   fprintf (fout, "\n");
587   if (gen_cheader)
588     {
589       if (std_includes)
590         fprintf (fout, "#include\t<gobject/gmarshal.h>\n\n");
591       fprintf (fout, "#ifdef __cplusplus\nextern \"C\" {\n#endif /* __cplusplus */\n");
592     }
593
594   /* process input files */
595   for (slist = files; slist; slist = slist->next)
596     {
597       gchar *file = slist->data;
598       gint fd = open (file, O_RDONLY);
599
600       if (fd < 0)
601         {
602           g_warning ("failed to open \"%s\": %s", file, g_strerror (errno));
603           continue;
604         }
605
606       /* set file name for error reports */
607       scanner->input_name = file;
608
609       /* parse & process file */
610       g_scanner_input_file (scanner, fd);
611       
612       /* scanning loop, we parse the input untill it's end is reached,
613        * or our sub routine came across invalid syntax
614        */
615       do
616         {
617           guint expected_token = G_TOKEN_NONE;
618
619           switch (g_scanner_peek_next_token (scanner))
620             {
621             case '\n':
622               /* eat newline and restart */
623               g_scanner_get_next_token (scanner);
624               continue;
625             case G_TOKEN_EOF:
626               /* done */
627               break;
628             default:
629               /* parse and process signatures */
630               {
631                 Signature signature = { NULL, NULL, NULL };
632                 GList *node;
633
634                 expected_token = parse_line (scanner, &signature);
635                 
636                 /* once we got a valid signature, process it */
637                 if (expected_token == G_TOKEN_NONE)
638                   process_signature (&signature);
639                 
640                 /* clean up signature contents */
641                 g_free (signature.ploc);
642                 if (signature.rarg)
643                   g_free (signature.rarg->keyword);
644                 g_free (signature.rarg);
645                 for (node = signature.args; node; node = node->next)
646                   {
647                     InArgument *iarg = node->data;
648                     
649                     g_free (iarg->keyword);
650                     g_free (iarg);
651                   }
652                 g_list_free (signature.args);
653               }
654               break;
655             }
656
657           /* bail out on errors */
658           if (expected_token != G_TOKEN_NONE)
659             {
660               g_scanner_unexp_token (scanner, expected_token, "type name", NULL, NULL, NULL, TRUE);
661               break;
662             }
663
664           g_scanner_peek_next_token (scanner);
665         }
666       while (scanner->next_token != G_TOKEN_EOF);
667
668       close (fd);
669     }
670
671   /* put out trailer */
672   if (gen_cheader)
673     {
674       fprintf (fout, "\n#ifdef __cplusplus\n}\n#endif /* __cplusplus */\n");
675     }
676   fprintf (fout, "\n");
677
678   /* clean up */
679   g_slist_free (files);
680   g_scanner_destroy (scanner);
681   g_hash_table_foreach_remove (marshallers, string_key_destroy, NULL);
682   g_hash_table_destroy (marshallers);
683
684   return 0;
685 }
686
687 static void
688 parse_args (gint    *argc_p,
689             gchar ***argv_p)
690 {
691   guint argc = *argc_p;
692   gchar **argv = *argv_p;
693   guint i, e;
694   
695   for (i = 1; i < argc; i++)
696     {
697       if (strcmp ("--header", argv[i]) == 0)
698         {
699           gen_cheader = TRUE;
700           argv[i] = NULL;
701         }
702       else if (strcmp ("--body", argv[i]) == 0)
703         {
704           gen_cbody = TRUE;
705           argv[i] = NULL;
706         }
707       else if (strcmp ("--skip-source", argv[i]) == 0)
708         {
709           skip_ploc = TRUE;
710           argv[i] = NULL;
711         }
712       else if (strcmp ("--nostdinc", argv[i]) == 0)
713         {
714           std_includes = FALSE;
715           argv[i] = NULL;
716         }
717       else if (strcmp ("--stdinc", argv[i]) == 0)
718         {
719           std_includes = TRUE;
720           argv[i] = NULL;
721         }
722       else if ((strcmp ("--prefix", argv[i]) == 0) ||
723                (strncmp ("--prefix=", argv[i], 9) == 0))
724         {
725           gchar *equal = argv[i] + 8;
726
727           if (*equal == '=')
728             marshaller_prefix = g_strdup (equal + 1);
729           else if (i + 1 < argc)
730             {
731               marshaller_prefix = g_strdup (argv[i + 1]);
732               argv[i] = NULL;
733               i += 1;
734             }
735           argv[i] = NULL;
736         }
737       else if (strcmp ("-h", argv[i]) == 0 ||
738           strcmp ("--help", argv[i]) == 0)
739         {
740           print_blurb (stderr, TRUE);
741           argv[i] = NULL;
742           exit (0);
743         }
744       else if (strcmp ("-v", argv[i]) == 0 ||
745                strcmp ("--version", argv[i]) == 0)
746         {
747           print_blurb (stderr, FALSE);
748           argv[i] = NULL;
749           exit (0);
750         }
751       else if (strcmp (argv[i], "--g-fatal-warnings") == 0)
752         {
753           GLogLevelFlags fatal_mask;
754           
755           fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
756           fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
757           g_log_set_always_fatal (fatal_mask);
758           
759           argv[i] = NULL;
760         }
761     }
762   
763   e = 0;
764   for (i = 1; i < argc; i++)
765     {
766       if (e)
767         {
768           if (argv[i])
769             {
770               argv[e++] = argv[i];
771               argv[i] = NULL;
772             }
773         }
774       else if (!argv[i])
775         e = i;
776     }
777   if (e)
778     *argc_p = e;
779 }
780
781 static void
782 print_blurb (FILE    *bout,
783              gboolean print_help)
784 {
785   if (!print_help)
786     {
787       fprintf (bout, "%s version ", PRG_NAME);
788       fprintf (bout, "%u.%u.%u", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION);
789       fprintf (bout, "\n");
790       fprintf (bout, "%s comes with ABSOLUTELY NO WARRANTY.\n", PRG_NAME);
791       fprintf (bout, "You may redistribute copies of %s under the terms of\n", PRG_NAME);
792       fprintf (bout, "the GNU General Public License which can be found in the\n");
793       fprintf (bout, "%s source package. Sources, examples and contact\n", PKG_NAME);
794       fprintf (bout, "information are available at %s\n", PKG_HTTP_HOME);
795     }
796   else
797     {
798       fprintf (bout, "Usage: %s [options] [files...]\n", PRG_NAME);
799       fprintf (bout, "  --header                   generate C headers\n");
800       fprintf (bout, "  --body                     generate C code\n");
801       fprintf (bout, "  --prefix=string            specify marshaller prefix\n");
802       fprintf (bout, "  --skip-source              skip source location comments\n");
803       fprintf (bout, "  --stdinc, --nostdinc       include/use GRuntime standard marshallers\n");
804       fprintf (bout, "  -h, --help                 show this help message\n");
805       fprintf (bout, "  -v, --version              print version informations\n");
806       fprintf (bout, "  --g-fatal-warnings         make warnings fatal (abort)\n");
807     }
808 }