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