Home | History | Annotate | Download | only in gobject
      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
    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
    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
    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*
    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*
    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
    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
    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*
    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*
    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
    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
    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
    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
    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
    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