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