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