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