Add g_key_file_save_to_file()
[glib.git] / gobject / glib-genmarshal.c
blob6ef6ea7250b81d4a51f34a5ee32a12e0355fc79a
1 /* GLIB-GenMarshal - Marshaller generator for GObject library
2 * Copyright (C) 2000-2001 Red Hat, Inc.
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.
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.
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.
20 #include "config.h"
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>
32 #include <glib/gstdio.h>
34 #undef G_LOG_DOMAIN
35 #define G_LOG_DOMAIN "GLib-Genmarshal"
36 #include <glib.h>
37 #include <glib/gprintf.h>
39 #ifdef G_OS_WIN32
40 #include <io.h>
41 #endif
43 /* --- defines --- */
44 #define PRG_NAME "glib-genmarshal"
45 #define PKG_NAME "GLib"
46 #define PKG_HTTP_HOME "http://www.gtk.org"
49 /* --- typedefs & structures --- */
50 typedef struct
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
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
71 gchar *ploc;
72 OutArgument *rarg;
73 GList *args; /* of type InArgument* */
74 } Signature;
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);
84 /* --- variables --- */
85 static const GScannerConfig scanner_config_template =
88 " \t\r" /* "\n" is statement delimiter */
89 ) /* cset_skip_characters */,
91 G_CSET_a_2_z
92 "_"
93 G_CSET_A_2_Z
94 ) /* cset_identifier_first */,
96 G_CSET_a_2_z
97 "_0123456789"
98 G_CSET_A_2_Z
99 ) /* cset_identifier_nth */,
100 ( "#\n" ) /* cpair_comment_single */,
102 FALSE /* case_sensitive */,
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 */,
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;
138 /* --- functions --- */
139 static void
140 put_marshal_value_getters (void)
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);
191 static gboolean
192 complete_in_arg (InArgument *iarg)
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", },
220 guint i;
222 g_return_val_if_fail (iarg != NULL, FALSE);
224 for (i = 0; i < G_N_ELEMENTS (args); i++)
225 if (strcmp (args[i].keyword, iarg->keyword) == 0)
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;
236 return TRUE;
238 return FALSE;
241 static gboolean
242 complete_out_arg (OutArgument *oarg)
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", },
270 guint i;
272 g_return_val_if_fail (oarg != NULL, FALSE);
274 for (i = 0; i < G_N_ELEMENTS (args); i++)
275 if (strcmp (args[i].keyword, oarg->keyword) == 0)
277 oarg->sig_name = args[i].sig_name;
278 oarg->ctype = args[i].ctype;
279 oarg->setter = args[i].setter;
281 return TRUE;
283 return FALSE;
286 static const gchar*
287 pad (const gchar *string)
289 #define PAD_LENGTH 12
290 static gchar *buffer = NULL;
291 gint i;
293 g_return_val_if_fail (string != NULL, NULL);
295 if (!buffer)
296 buffer = g_new (gchar, PAD_LENGTH + 1);
298 /* paranoid check */
299 if (strlen (string) >= PAD_LENGTH)
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;
307 return buffer;
310 for (i = 0; i < PAD_LENGTH; i++)
312 gboolean done = *string == 0;
314 buffer[i] = done ? ' ' : *string++;
316 buffer[i] = 0;
318 return buffer;
321 static const gchar*
322 indent (guint n_spaces)
324 static gchar *buffer = NULL;
325 static guint blength = 0;
327 if (blength <= n_spaces)
329 blength = n_spaces + 1;
330 g_free (buffer);
331 buffer = g_new (gchar, blength);
333 memset (buffer, ' ', n_spaces);
334 buffer[n_spaces] = 0;
336 return buffer;
339 static void
340 generate_marshal (const gchar *signame,
341 Signature *sig)
343 guint ind, a;
344 GList *node;
345 gchar *tmp = g_strconcat (marshaller_prefix, "_", signame, NULL);
346 gboolean have_std_marshaller = FALSE;
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.
353 if (g_hash_table_lookup (marshallers, tmp))
355 /* done, marshaller already generated */
356 g_free (tmp);
357 return;
359 else
361 /* need to alias/generate marshaller, register name */
362 g_hash_table_insert (marshallers, tmp, tmp);
365 /* can we revert to a standard marshaller? */
366 if (std_includes)
368 tmp = g_strconcat (std_marshaller_prefix, "_", signame, NULL);
369 have_std_marshaller = g_hash_table_lookup (marshallers, tmp) != NULL;
370 g_free (tmp);
373 /* GValue marshaller */
374 if (gen_cheader && have_std_marshaller)
376 g_fprintf (fout, "#define %s_%s\t%s_%s\n", marshaller_prefix, signame, std_marshaller_prefix, signame);
378 if (gen_cheader && !have_std_marshaller)
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));
391 if (gen_cbody && !have_std_marshaller)
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");
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)
409 InArgument *iarg = node->data;
411 if (iarg->getter)
412 g_fprintf (fout, "%s%s arg_%d,\n", indent (ind), pad (iarg->ctype), a++);
414 g_fprintf (fout, "%s%s data2);\n", indent (ind), pad ("gpointer"));
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);
423 if (sig->args || sig->rarg->setter)
425 g_fprintf (fout, "\n");
427 if (sig->rarg->setter)
428 g_fprintf (fout, " g_return_if_fail (return_value != NULL);\n");
429 if (sig->args)
431 for (a = 0, node = sig->args; node; node = node->next)
433 InArgument *iarg = node->data;
435 if (iarg->getter)
436 a++;
438 g_fprintf (fout, " g_return_if_fail (n_param_values == %u);\n", 1 + a);
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);
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)
459 InArgument *iarg = node->data;
461 if (iarg->getter)
462 g_fprintf (fout, "%s%s (param_values + %d),\n", indent (ind), iarg->getter, a++);
464 g_fprintf (fout, "%sdata2);\n", indent (ind));
466 /* cfile marshal return value storage */
467 if (sig->rarg->setter)
469 g_fprintf (fout, "\n");
470 g_fprintf (fout, " %s (return_value, v_return);\n", sig->rarg->setter);
473 /* cfile marshal footer */
474 g_fprintf (fout, "}\n");
478 /* vararg marshaller */
479 if (gen_cheader && gen_valist && have_std_marshaller)
481 g_fprintf (fout, "#define %s_%sv\t%s_%sv\n", marshaller_prefix, signame, std_marshaller_prefix, signame);
483 if (gen_cheader && gen_valist && !have_std_marshaller)
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));
496 if (gen_cbody && gen_valist && !have_std_marshaller)
498 gint i;
499 gboolean has_arg;
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");
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)
516 InArgument *iarg = node->data;
518 if (iarg->getter)
519 g_fprintf (fout, ",\n%s%s arg_%d", indent (ind), pad (iarg->ctype), a++);
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;
527 i = 0;
528 for (node = sig->args; node; node = node->next)
530 InArgument *iarg = node->data;
532 if (iarg->getter)
534 g_fprintf (fout, " %s arg%i;\n", iarg->ctype, i++);
535 has_arg = TRUE;
538 if (has_arg)
539 g_fprintf (fout, " va_list args_copy;\n");
541 if (sig->rarg->setter)
542 g_fprintf (fout, " %s v_return;\n", sig->rarg->ctype);
544 if (sig->rarg->setter)
546 g_fprintf (fout, "\n");
547 g_fprintf (fout, " g_return_if_fail (return_value != NULL);\n");
550 /* cfile marshal data1, data2 and callback setup */
551 if (has_arg)
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)
558 InArgument *iarg = node->data;
560 if (iarg->getter)
562 g_fprintf (fout, " arg%i = (%s) va_arg (args_copy, %s);\n",
563 i, iarg->ctype, iarg->promoted_ctype);
565 if (iarg->box != NULL)
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);
581 i++;
583 g_fprintf (fout, " va_end (args_copy);\n");
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);
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");
602 i = 0;
603 for (node = sig->args; node; node = node->next)
605 InArgument *iarg = node->data;
607 if (iarg->getter)
608 g_fprintf (fout, ",\n%sarg%i", indent (ind), i++);
610 g_fprintf (fout, ",\n%sdata2);\n", indent (ind));
612 i = 0;
613 for (node = sig->args; node; node = node->next)
615 InArgument *iarg = node->data;
617 if (iarg->unbox)
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);
632 i++;
635 /* cfile marshal return value storage */
636 if (sig->rarg->setter)
638 g_fprintf (fout, "\n");
639 g_fprintf (fout, " %s (return_value, v_return);\n", sig->rarg->setter);
642 g_fprintf (fout, "}\n\n");
646 static void
647 process_signature (Signature *sig)
649 gchar *pname, *sname, *tmp;
650 GList *node;
652 /* lookup and complete info on arguments */
653 if (!complete_out_arg (sig->rarg))
655 g_warning ("unknown type: %s", sig->rarg->keyword);
656 exit_status |= 1;
657 return;
659 for (node = sig->args; node; node = node->next)
661 InArgument *iarg = node->data;
663 if (!complete_in_arg (iarg))
665 g_warning ("unknown type: %s", iarg->keyword);
666 exit_status |= 1;
667 return;
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)
676 InArgument *iarg = node->data;
677 gchar *tmp;
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);
687 /* introductionary comment */
688 g_fprintf (fout, "\n/* %s", sig->rarg->keyword);
689 for (node = sig->args; node; node = node->next)
691 InArgument *iarg = node->data;
693 g_fprintf (fout, "%c%s", node->prev ? ',' : ':', iarg->keyword);
695 if (!skip_ploc)
696 g_fprintf (fout, " (%s)", sig->ploc);
697 g_fprintf (fout, " */\n");
699 /* ensure technical marshaller exists (<marshaller_prefix>_<sname>) */
700 generate_marshal (sname, sig);
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))
706 g_fprintf (fout, "#define %s_%s\t%s_%s\n", marshaller_prefix, pname, marshaller_prefix, sname);
708 g_hash_table_insert (marshallers, tmp, tmp);
710 else
711 g_free (tmp);
713 g_free (pname);
714 g_free (sname);
717 static InArgument*
718 new_in_arg (const gchar *pname)
720 InArgument *iarg = g_new0 (InArgument, 1);
722 iarg->keyword = g_strdup (pname);
724 return iarg;
727 static OutArgument*
728 new_out_arg (const gchar *pname)
730 OutArgument *oarg = g_new0 (OutArgument, 1);
732 oarg->keyword = g_strdup (pname);
734 return oarg;
737 static guint
738 parse_line (GScanner *scanner,
739 Signature *sig)
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);
746 /* keep a note on the location */
747 sig->ploc = g_strdup_printf ("%s:%u", scanner->input_name, scanner->line);
749 /* expect ':' */
750 if (g_scanner_get_next_token (scanner) != ':')
751 return ':';
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));
758 /* parse rest of argument list */
759 while (g_scanner_peek_next_token (scanner) == ',')
761 /* eat comma */
762 g_scanner_get_next_token (scanner);
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));
770 /* expect end of line, done */
771 if (g_scanner_get_next_token (scanner) != '\n')
772 return '\n';
774 /* success */
775 return G_TOKEN_NONE;
778 static gboolean
779 string_key_destroy (gpointer key,
780 gpointer value,
781 gpointer user_data)
783 g_free (key);
785 return TRUE;
789 main (int argc,
790 char *argv[])
792 const gchar *gobject_marshallers[] = {
793 #include "gmarshal.strings"
795 GScanner *scanner;
796 GSList *slist, *files = NULL;
797 gint i;
799 /* parse args and do fast exits */
800 parse_args (&argc, &argv);
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");
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);
815 /* add standard marshallers of the GObject library */
816 if (std_includes)
817 for (i = 0; i < G_N_ELEMENTS (gobject_marshallers); i++)
819 gchar *tmp = g_strdup (gobject_marshallers[i]);
821 g_hash_table_insert (marshallers, tmp, tmp);
824 /* put out initial heading */
825 g_fprintf (fout, "\n");
827 if (gen_cheader && std_includes)
829 g_fprintf (fout, "#ifndef __%s_MARSHAL_H__\n", marshaller_prefix);
830 g_fprintf (fout, "#define __%s_MARSHAL_H__\n\n", marshaller_prefix);
833 if ((gen_cheader || gen_cbody) && std_includes)
834 g_fprintf (fout, "#include\t<glib-object.h>\n\n");
836 if (gen_cheader)
837 g_fprintf (fout, "G_BEGIN_DECLS\n");
839 /* generate necessary preprocessor directives */
840 if (gen_cbody)
841 put_marshal_value_getters ();
843 /* process input files */
844 for (slist = files; slist; slist = slist->next)
846 gchar *file = slist->data;
847 gint fd;
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);
855 if (fd < 0)
857 g_warning ("failed to open \"%s\": %s", file, g_strerror (errno));
858 exit_status |= 1;
859 continue;
862 /* set file name for error reports */
863 scanner->input_name = file;
865 /* parse & process file */
866 g_scanner_input_file (scanner, fd);
868 /* scanning loop, we parse the input until its end is reached,
869 * or our sub routine came across invalid syntax
873 guint expected_token = G_TOKEN_NONE;
875 switch ((guint) g_scanner_peek_next_token (scanner))
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 */
887 Signature signature = { NULL, NULL, NULL };
888 GList *node;
890 expected_token = parse_line (scanner, &signature);
892 /* once we got a valid signature, process it */
893 if (expected_token == G_TOKEN_NONE)
894 process_signature (&signature);
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)
903 InArgument *iarg = node->data;
905 g_free (iarg->keyword);
906 g_free (iarg);
908 g_list_free (signature.args);
910 break;
913 /* bail out on errors */
914 if (expected_token != G_TOKEN_NONE)
916 g_scanner_unexp_token (scanner, expected_token, "type name", NULL, NULL, NULL, TRUE);
917 exit_status |= 1;
918 break;
921 g_scanner_peek_next_token (scanner);
923 while (scanner->next_token != G_TOKEN_EOF);
925 close (fd);
928 /* put out trailer */
929 if (gen_cheader)
931 g_fprintf (fout, "\nG_END_DECLS\n");
933 if (std_includes)
934 g_fprintf (fout, "\n#endif /* __%s_MARSHAL_H__ */\n", marshaller_prefix);
936 g_fprintf (fout, "\n");
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);
944 return exit_status;
947 static void
948 parse_args (gint *argc_p,
949 gchar ***argv_p)
951 guint argc = *argc_p;
952 gchar **argv = *argv_p;
953 guint i, e;
955 for (i = 1; i < argc; i++)
957 if (strcmp ("--header", argv[i]) == 0)
959 gen_cheader = TRUE;
960 argv[i] = NULL;
962 else if (strcmp ("--body", argv[i]) == 0)
964 gen_cbody = TRUE;
965 argv[i] = NULL;
967 else if (strcmp ("--skip-source", argv[i]) == 0)
969 skip_ploc = TRUE;
970 argv[i] = NULL;
972 else if (strcmp ("--nostdinc", argv[i]) == 0)
974 std_includes = FALSE;
975 argv[i] = NULL;
977 else if (strcmp ("--stdinc", argv[i]) == 0)
979 std_includes = TRUE;
980 argv[i] = NULL;
982 else if (strcmp ("--internal", argv[i]) == 0)
984 gen_internal = TRUE;
985 argv[i] = NULL;
987 else if (strcmp ("--valist-marshallers", argv[i]) == 0)
989 gen_valist = TRUE;
990 argv[i] = NULL;
992 else if ((strcmp ("--prefix", argv[i]) == 0) ||
993 (strncmp ("--prefix=", argv[i], 9) == 0))
995 gchar *equal = argv[i] + 8;
997 if (*equal == '=')
998 marshaller_prefix = g_strdup (equal + 1);
999 else if (i + 1 < argc)
1001 marshaller_prefix = g_strdup (argv[i + 1]);
1002 argv[i] = NULL;
1003 i += 1;
1005 argv[i] = NULL;
1007 else if (strcmp ("-h", argv[i]) == 0 ||
1008 strcmp ("-?", argv[i]) == 0 ||
1009 strcmp ("--help", argv[i]) == 0)
1011 print_blurb (stderr, TRUE);
1012 argv[i] = NULL;
1013 exit (0);
1015 else if (strcmp ("-v", argv[i]) == 0 ||
1016 strcmp ("--version", argv[i]) == 0)
1018 print_blurb (stderr, FALSE);
1019 argv[i] = NULL;
1020 exit (0);
1022 else if (strcmp (argv[i], "--g-fatal-warnings") == 0)
1024 GLogLevelFlags fatal_mask;
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);
1030 argv[i] = NULL;
1034 e = 0;
1035 for (i = 1; i < argc; i++)
1037 if (e)
1039 if (argv[i])
1041 argv[e++] = argv[i];
1042 argv[i] = NULL;
1045 else if (!argv[i])
1046 e = i;
1048 if (e)
1049 *argc_p = e;
1052 static void
1053 print_blurb (FILE *bout,
1054 gboolean print_help)
1056 if (!print_help)
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);
1067 else
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");