• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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