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