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