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