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