sl@0: /* GLIB-GenMarshal - Marshaller generator for GObject library
sl@0:  * Copyright (C) 2000-2001 Red Hat, Inc.
sl@0:  * Portions copyright (c) 2006-2009 Nokia Corporation.  All rights reserved.
sl@0:  * This library is free software; you can redistribute it and/or
sl@0:  * modify it under the terms of the GNU Lesser General Public
sl@0:  * License as published by the Free Software Foundation; either
sl@0:  * version 2 of the License, or (at your option) any later version.
sl@0:  *
sl@0:  * This library is distributed in the hope that it will be useful,
sl@0:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
sl@0:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
sl@0:  * Lesser General Public License for more details.
sl@0:  *
sl@0:  * You should have received a copy of the GNU Lesser General Public
sl@0:  * License along with this library; if not, write to the
sl@0:  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
sl@0:  * Boston, MA 02111-1307, USA.
sl@0:  */
sl@0: 
sl@0: #include "config.h"
sl@0: 
sl@0: #include <stdlib.h>
sl@0: #include <fcntl.h>
sl@0: #include <string.h>
sl@0: #include <errno.h>
sl@0: #ifdef HAVE_UNISTD_H
sl@0: #include <unistd.h>
sl@0: #endif
sl@0: #include <sys/types.h>
sl@0: #include <sys/stat.h>
sl@0: 
sl@0: #undef G_LOG_DOMAIN
sl@0: #define G_LOG_DOMAIN "GLib-Genmarshal"
sl@0: #include <glib.h>
sl@0: #include <glib/gprintf.h>
sl@0: 
sl@0: #ifdef G_OS_WIN32
sl@0: #include <io.h>
sl@0: #endif
sl@0: #ifdef __SYMBIAN32__
sl@0: #include "mrt2_glib2_test.h"
sl@0: #endif /*__SYMBIAN32__*/
sl@0: 
sl@0: /* --- defines --- */
sl@0: #define	PRG_NAME	"glib-genmarshal"
sl@0: #define	PKG_NAME	"GLib"
sl@0: #define PKG_HTTP_HOME	"http://www.gtk.org"
sl@0: 
sl@0: 
sl@0: /* --- typedefs & structures --- */
sl@0: typedef struct
sl@0: {
sl@0:   gchar	      *keyword;		/* marhaller list keyword [MY_STRING] */
sl@0:   const gchar *sig_name;	/* signature name [STRING] */
sl@0:   const gchar *ctype;		/* C type name [gchar*] */
sl@0:   const gchar *getter;		/* value getter function [g_value_get_string] */
sl@0: } InArgument;
sl@0: typedef struct
sl@0: {
sl@0:   gchar	      *keyword;		/* marhaller list keyword [MY_STRING] */
sl@0:   const gchar *sig_name;	/* signature name [STRING] */
sl@0:   const gchar *ctype;		/* C type name [gchar*] */
sl@0:   const gchar *setter;		/* value setter function [g_value_set_string] */
sl@0: } OutArgument;
sl@0: typedef struct
sl@0: {
sl@0:   gchar       *ploc;
sl@0:   OutArgument *rarg;
sl@0:   GList       *args;	/* of type InArgument* */
sl@0: } Signature;
sl@0: 
sl@0: 
sl@0: /* --- prototypes --- */
sl@0: static void	parse_args	(gint	   	*argc_p,
sl@0: 				 gchar	     ***argv_p);
sl@0: static void	print_blurb	(FILE	       	*bout,
sl@0: 				 gboolean	 print_help);
sl@0: 
sl@0: 
sl@0: /* --- variables --- */
sl@0: static const GScannerConfig scanner_config_template =
sl@0: {
sl@0:   (
sl@0:    " \t\r"		/* "\n" is statement delimiter */
sl@0:    )                    /* cset_skip_characters */,
sl@0:   (
sl@0:    G_CSET_a_2_z
sl@0:    "_"
sl@0:    G_CSET_A_2_Z
sl@0:    )                    /* cset_identifier_first */,
sl@0:   (
sl@0:    G_CSET_a_2_z
sl@0:    "_0123456789"
sl@0:    G_CSET_A_2_Z
sl@0:    )                    /* cset_identifier_nth */,
sl@0:   ( "#\n" )             /* cpair_comment_single */,
sl@0: 
sl@0:   FALSE                 /* case_sensitive */,
sl@0: 
sl@0:   TRUE                  /* skip_comment_multi */,
sl@0:   TRUE                  /* skip_comment_single */,
sl@0:   TRUE                  /* scan_comment_multi */,
sl@0:   TRUE                  /* scan_identifier */,
sl@0:   FALSE                 /* scan_identifier_1char */,
sl@0:   FALSE                 /* scan_identifier_NULL */,
sl@0:   TRUE                  /* scan_symbols */,
sl@0:   FALSE                 /* scan_binary */,
sl@0:   TRUE                  /* scan_octal */,
sl@0:   TRUE                  /* scan_float */,
sl@0:   TRUE                  /* scan_hex */,
sl@0:   FALSE                 /* scan_hex_dollar */,
sl@0:   TRUE                  /* scan_string_sq */,
sl@0:   TRUE                  /* scan_string_dq */,
sl@0:   TRUE                  /* numbers_2_int */,
sl@0:   FALSE                 /* int_2_float */,
sl@0:   FALSE                 /* identifier_2_string */,
sl@0:   TRUE                  /* char_2_token */,
sl@0:   FALSE                 /* symbol_2_token */,
sl@0:   FALSE                 /* scope_0_fallback */,
sl@0: };
sl@0: static gchar		* const std_marshaller_prefix = "g_cclosure_marshal";
sl@0: static gchar		*marshaller_prefix = "g_cclosure_user_marshal";
sl@0: static GHashTable	*marshallers = NULL;
sl@0: static FILE             *fout = NULL;
sl@0: static gboolean		 gen_cheader = FALSE;
sl@0: static gboolean		 gen_cbody = FALSE;
sl@0: static gboolean          gen_internal = FALSE;
sl@0: static gboolean		 skip_ploc = FALSE;
sl@0: static gboolean		 std_includes = TRUE;
sl@0: static gint              exit_status = 0;
sl@0: 
sl@0: 
sl@0: /* --- functions --- */
sl@0: static void
sl@0: put_marshal_value_getters (void)
sl@0: {
sl@0:   fputs ("\n", fout);
sl@0:   fputs ("#ifdef G_ENABLE_DEBUG\n", fout);
sl@0:   fputs ("#define g_marshal_value_peek_boolean(v)  g_value_get_boolean (v)\n", fout);
sl@0:   fputs ("#define g_marshal_value_peek_char(v)     g_value_get_char (v)\n", fout);
sl@0:   fputs ("#define g_marshal_value_peek_uchar(v)    g_value_get_uchar (v)\n", fout);
sl@0:   fputs ("#define g_marshal_value_peek_int(v)      g_value_get_int (v)\n", fout);
sl@0:   fputs ("#define g_marshal_value_peek_uint(v)     g_value_get_uint (v)\n", fout);
sl@0:   fputs ("#define g_marshal_value_peek_long(v)     g_value_get_long (v)\n", fout);
sl@0:   fputs ("#define g_marshal_value_peek_ulong(v)    g_value_get_ulong (v)\n", fout);
sl@0:   fputs ("#define g_marshal_value_peek_int64(v)    g_value_get_int64 (v)\n", fout);
sl@0:   fputs ("#define g_marshal_value_peek_uint64(v)   g_value_get_uint64 (v)\n", fout);
sl@0:   fputs ("#define g_marshal_value_peek_enum(v)     g_value_get_enum (v)\n", fout);
sl@0:   fputs ("#define g_marshal_value_peek_flags(v)    g_value_get_flags (v)\n", fout);
sl@0:   fputs ("#define g_marshal_value_peek_float(v)    g_value_get_float (v)\n", fout);
sl@0:   fputs ("#define g_marshal_value_peek_double(v)   g_value_get_double (v)\n", fout);
sl@0:   fputs ("#define g_marshal_value_peek_string(v)   (char*) g_value_get_string (v)\n", fout);
sl@0:   fputs ("#define g_marshal_value_peek_param(v)    g_value_get_param (v)\n", fout);
sl@0:   fputs ("#define g_marshal_value_peek_boxed(v)    g_value_get_boxed (v)\n", fout);
sl@0:   fputs ("#define g_marshal_value_peek_pointer(v)  g_value_get_pointer (v)\n", fout);
sl@0:   fputs ("#define g_marshal_value_peek_object(v)   g_value_get_object (v)\n", fout);
sl@0:   fputs ("#else /* !G_ENABLE_DEBUG */\n", fout);
sl@0:   fputs ("/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API.\n", fout);
sl@0:   fputs (" *          Do not access GValues directly in your code. Instead, use the\n", fout);
sl@0:   fputs (" *          g_value_get_*() functions\n", fout);
sl@0:   fputs (" */\n", fout);
sl@0:   fputs ("#define g_marshal_value_peek_boolean(v)  (v)->data[0].v_int\n", fout);
sl@0:   fputs ("#define g_marshal_value_peek_char(v)     (v)->data[0].v_int\n", fout);
sl@0:   fputs ("#define g_marshal_value_peek_uchar(v)    (v)->data[0].v_uint\n", fout);
sl@0:   fputs ("#define g_marshal_value_peek_int(v)      (v)->data[0].v_int\n", fout);
sl@0:   fputs ("#define g_marshal_value_peek_uint(v)     (v)->data[0].v_uint\n", fout);
sl@0:   fputs ("#define g_marshal_value_peek_long(v)     (v)->data[0].v_long\n", fout);
sl@0:   fputs ("#define g_marshal_value_peek_ulong(v)    (v)->data[0].v_ulong\n", fout);
sl@0:   fputs ("#define g_marshal_value_peek_int64(v)    (v)->data[0].v_int64\n", fout);
sl@0:   fputs ("#define g_marshal_value_peek_uint64(v)   (v)->data[0].v_uint64\n", fout);
sl@0:   fputs ("#define g_marshal_value_peek_enum(v)     (v)->data[0].v_long\n", fout);
sl@0:   fputs ("#define g_marshal_value_peek_flags(v)    (v)->data[0].v_ulong\n", fout);
sl@0:   fputs ("#define g_marshal_value_peek_float(v)    (v)->data[0].v_float\n", fout);
sl@0:   fputs ("#define g_marshal_value_peek_double(v)   (v)->data[0].v_double\n", fout);
sl@0:   fputs ("#define g_marshal_value_peek_string(v)   (v)->data[0].v_pointer\n", fout);
sl@0:   fputs ("#define g_marshal_value_peek_param(v)    (v)->data[0].v_pointer\n", fout);
sl@0:   fputs ("#define g_marshal_value_peek_boxed(v)    (v)->data[0].v_pointer\n", fout);
sl@0:   fputs ("#define g_marshal_value_peek_pointer(v)  (v)->data[0].v_pointer\n", fout);
sl@0:   fputs ("#define g_marshal_value_peek_object(v)   (v)->data[0].v_pointer\n", fout);
sl@0:   fputs ("#endif /* !G_ENABLE_DEBUG */\n", fout);
sl@0:   fputs ("\n", fout);
sl@0: }
sl@0: 
sl@0: static gboolean
sl@0: complete_in_arg (InArgument *iarg)
sl@0: {
sl@0:   static const InArgument args[] = {
sl@0:     /* keyword		sig_name	ctype		getter			*/
sl@0:     { "VOID",		"VOID",		"void",		NULL,			},
sl@0:     { "BOOLEAN",	"BOOLEAN",	"gboolean",	"g_marshal_value_peek_boolean",	},
sl@0:     { "CHAR",		"CHAR",		"gchar",	"g_marshal_value_peek_char",	},
sl@0:     { "UCHAR",		"UCHAR",	"guchar",	"g_marshal_value_peek_uchar",	},
sl@0:     { "INT",		"INT",		"gint",		"g_marshal_value_peek_int",	},
sl@0:     { "UINT",		"UINT",		"guint",	"g_marshal_value_peek_uint",	},
sl@0:     { "LONG",		"LONG",		"glong",	"g_marshal_value_peek_long",	},
sl@0:     { "ULONG",		"ULONG",	"gulong",	"g_marshal_value_peek_ulong",	},
sl@0:     { "INT64",		"INT64",	"gint64",       "g_marshal_value_peek_int64",	},
sl@0:     { "UINT64",		"UINT64",	"guint64",	"g_marshal_value_peek_uint64",	},
sl@0:     { "ENUM",		"ENUM",		"gint",		"g_marshal_value_peek_enum",	},
sl@0:     { "FLAGS",		"FLAGS",	"guint",	"g_marshal_value_peek_flags",	},
sl@0:     { "FLOAT",		"FLOAT",	"gfloat",	"g_marshal_value_peek_float",	},
sl@0:     { "DOUBLE",		"DOUBLE",	"gdouble",	"g_marshal_value_peek_double",	},
sl@0:     { "STRING",		"STRING",	"gpointer",	"g_marshal_value_peek_string",	},
sl@0:     { "PARAM",		"PARAM",	"gpointer",	"g_marshal_value_peek_param",	},
sl@0:     { "BOXED",		"BOXED",	"gpointer",	"g_marshal_value_peek_boxed",	},
sl@0:     { "POINTER",	"POINTER",	"gpointer",	"g_marshal_value_peek_pointer",	},
sl@0:     { "OBJECT",		"OBJECT",	"gpointer",	"g_marshal_value_peek_object",	},
sl@0:     /* deprecated: */
sl@0:     { "NONE",		"VOID",		"void",		NULL,			},
sl@0:     { "BOOL",		"BOOLEAN",	"gboolean",	"g_marshal_value_peek_boolean",	},
sl@0:   };
sl@0:   guint i;
sl@0: 
sl@0:   g_return_val_if_fail (iarg != NULL, FALSE);
sl@0: 
sl@0:   for (i = 0; i < G_N_ELEMENTS (args); i++)
sl@0:     if (strcmp (args[i].keyword, iarg->keyword) == 0)
sl@0:       {
sl@0: 	iarg->sig_name = args[i].sig_name;
sl@0: 	iarg->ctype = args[i].ctype;
sl@0: 	iarg->getter = args[i].getter;
sl@0: 
sl@0: 	return TRUE;
sl@0:       }
sl@0:   return FALSE;
sl@0: }
sl@0: 
sl@0: static gboolean
sl@0: complete_out_arg (OutArgument *oarg)
sl@0: {
sl@0:   static const OutArgument args[] = {
sl@0:     /* keyword		sig_name	ctype		setter			*/
sl@0:     { "VOID",		"VOID",		"void",		NULL,					     },
sl@0:     { "BOOLEAN",	"BOOLEAN",	"gboolean",	"g_value_set_boolean",			     },
sl@0:     { "CHAR",		"CHAR",		"gchar",	"g_value_set_char",			     },
sl@0:     { "UCHAR",		"UCHAR",	"guchar",	"g_value_set_uchar",			     },
sl@0:     { "INT",		"INT",		"gint",		"g_value_set_int",			     },
sl@0:     { "UINT",		"UINT",		"guint",	"g_value_set_uint",			     },
sl@0:     { "LONG",		"LONG",		"glong",	"g_value_set_long",			     },
sl@0:     { "ULONG",		"ULONG",	"gulong",	"g_value_set_ulong",			     },
sl@0:     { "INT64",		"INT64",	"gint64",	"g_value_set_int64",			     },
sl@0:     { "UINT64",		"UINT64",	"guint64",	"g_value_set_uint64",			     },
sl@0:     { "ENUM",		"ENUM",		"gint",		"g_value_set_enum",			     },
sl@0:     { "FLAGS",		"FLAGS",	"guint",	"g_value_set_flags",			     },
sl@0:     { "FLOAT",		"FLOAT",	"gfloat",	"g_value_set_float",			     },
sl@0:     { "DOUBLE",		"DOUBLE",	"gdouble",	"g_value_set_double",			     },
sl@0:     { "STRING",		"STRING",	"gchar*",	"g_value_take_string",			     },
sl@0:     { "PARAM",		"PARAM",	"GParamSpec*",	"g_value_take_param",			     },
sl@0:     { "BOXED",		"BOXED",	"gpointer",	"g_value_take_boxed",			     },
sl@0:     { "POINTER",	"POINTER",	"gpointer",	"g_value_set_pointer",			     },
sl@0:     { "OBJECT",		"OBJECT",	"GObject*",	"g_value_take_object",			     },
sl@0:     /* deprecated: */
sl@0:     { "NONE",		"VOID",		"void",		NULL,					     },
sl@0:     { "BOOL",		"BOOLEAN",	"gboolean",	"g_value_set_boolean",			     },
sl@0:   };
sl@0:   guint i;
sl@0: 
sl@0:   g_return_val_if_fail (oarg != NULL, FALSE);
sl@0: 
sl@0:   for (i = 0; i < G_N_ELEMENTS (args); i++)
sl@0:     if (strcmp (args[i].keyword, oarg->keyword) == 0)
sl@0:       {
sl@0: 	oarg->sig_name = args[i].sig_name;
sl@0: 	oarg->ctype = args[i].ctype;
sl@0: 	oarg->setter = args[i].setter;
sl@0: 
sl@0: 	return TRUE;
sl@0:       }
sl@0:   return FALSE;
sl@0: }
sl@0: 
sl@0: static const gchar*
sl@0: pad (const gchar *string)
sl@0: {
sl@0: #define PAD_LENGTH	12
sl@0:   static gchar *buffer = NULL;
sl@0:   gint i;
sl@0: 
sl@0:   g_return_val_if_fail (string != NULL, NULL);
sl@0: 
sl@0:   if (!buffer)
sl@0:     buffer = g_new (gchar, PAD_LENGTH + 1);
sl@0: 
sl@0:   /* paranoid check */
sl@0:   if (strlen (string) >= PAD_LENGTH)
sl@0:     {
sl@0:       g_free (buffer);
sl@0:       buffer = g_strdup_printf ("%s ", string);
sl@0:       g_warning ("overfull string (%u bytes) for padspace",
sl@0:                  (guint) strlen (string));
sl@0:       exit_status |= 2;
sl@0: 
sl@0:       return buffer;
sl@0:     }
sl@0: 
sl@0:   for (i = 0; i < PAD_LENGTH; i++)
sl@0:     {
sl@0:       gboolean done = *string == 0;
sl@0: 
sl@0:       buffer[i] = done ? ' ' : *string++;
sl@0:     }
sl@0:   buffer[i] = 0;
sl@0: 
sl@0:   return buffer;
sl@0: }
sl@0: 
sl@0: static const gchar*
sl@0: indent (guint n_spaces)
sl@0: {
sl@0:   static gchar *buffer = NULL;
sl@0:   static guint blength = 0;
sl@0: 
sl@0:   if (blength <= n_spaces)
sl@0:     {
sl@0:       blength = n_spaces + 1;
sl@0:       g_free (buffer);
sl@0:       buffer = g_new (gchar, blength);
sl@0:     }
sl@0:   memset (buffer, ' ', n_spaces);
sl@0:   buffer[n_spaces] = 0;
sl@0: 
sl@0:   return buffer;
sl@0: }
sl@0: 
sl@0: static void
sl@0: generate_marshal (const gchar *signame,
sl@0: 		  Signature   *sig)
sl@0: {
sl@0:   guint ind, a;
sl@0:   GList *node;
sl@0:   gchar *tmp = g_strconcat (marshaller_prefix, "_", signame, NULL);
sl@0:   gboolean have_std_marshaller = FALSE;
sl@0: 
sl@0:   /* here we have to make sure a marshaller named <marshaller_prefix>_<signame>
sl@0:    * exists. we might have put it out already, can revert to a standard
sl@0:    * marshaller provided by glib, or need to generate one.
sl@0:    */
sl@0: 
sl@0:   if (g_hash_table_lookup (marshallers, tmp))
sl@0:     {
sl@0:       /* done, marshaller already generated */
sl@0:       g_free (tmp);
sl@0:       return;
sl@0:     }
sl@0:   else
sl@0:     {
sl@0:       /* need to alias/generate marshaller, register name */
sl@0:       g_hash_table_insert (marshallers, tmp, tmp);
sl@0:     }
sl@0: 
sl@0:   /* can we revert to a standard marshaller? */
sl@0:   if (std_includes)
sl@0:     {
sl@0:       tmp = g_strconcat (std_marshaller_prefix, "_", signame, NULL);
sl@0:       have_std_marshaller = g_hash_table_lookup (marshallers, tmp) != NULL;
sl@0:       g_free (tmp);
sl@0:     }
sl@0: 
sl@0:   if (gen_cheader && have_std_marshaller)
sl@0:     {
sl@0:       g_fprintf (fout, "#define %s_%s\t%s_%s\n", marshaller_prefix, signame, std_marshaller_prefix, signame);
sl@0:     }
sl@0:   if (gen_cheader && !have_std_marshaller)
sl@0:     {
sl@0:       ind = g_fprintf (fout, gen_internal ? "G_GNUC_INTERNAL " : "extern ");
sl@0:       ind += g_fprintf (fout, "void ");
sl@0:       ind += g_fprintf (fout, "%s_%s (", marshaller_prefix, signame);
sl@0:       g_fprintf (fout,   "GClosure     *closure,\n");
sl@0:       g_fprintf (fout, "%sGValue       *return_value,\n", indent (ind));
sl@0:       g_fprintf (fout, "%sguint         n_param_values,\n", indent (ind));
sl@0:       g_fprintf (fout, "%sconst GValue *param_values,\n", indent (ind));
sl@0:       g_fprintf (fout, "%sgpointer      invocation_hint,\n", indent (ind));
sl@0:       g_fprintf (fout, "%sgpointer      marshal_data);\n",
sl@0:                  indent (ind));
sl@0:     }
sl@0:   if (gen_cbody && !have_std_marshaller)
sl@0:     {
sl@0:       /* cfile marshal header */
sl@0:       g_fprintf (fout, "void\n");
sl@0:       ind = g_fprintf (fout, "%s_%s (", marshaller_prefix, signame);
sl@0:       g_fprintf (fout,   "GClosure     *closure,\n");
sl@0:       g_fprintf (fout, "%sGValue       *return_value G_GNUC_UNUSED,\n", indent (ind));
sl@0:       g_fprintf (fout, "%sguint         n_param_values,\n", indent (ind));
sl@0:       g_fprintf (fout, "%sconst GValue *param_values,\n", indent (ind));
sl@0:       g_fprintf (fout, "%sgpointer      invocation_hint G_GNUC_UNUSED,\n", indent (ind));
sl@0:       g_fprintf (fout, "%sgpointer      marshal_data)\n", indent (ind));
sl@0:       g_fprintf (fout, "{\n");
sl@0: 
sl@0:       /* cfile GMarshalFunc typedef */
sl@0:       ind = g_fprintf (fout, "  typedef %s (*GMarshalFunc_%s) (", sig->rarg->ctype, signame);
sl@0:       g_fprintf (fout, "%s data1,\n", pad ("gpointer"));
sl@0:       for (a = 1, node = sig->args; node; node = node->next)
sl@0: 	{
sl@0: 	  InArgument *iarg = node->data;
sl@0: 
sl@0: 	  if (iarg->getter)
sl@0: 	    g_fprintf (fout, "%s%s arg_%d,\n", indent (ind), pad (iarg->ctype), a++);
sl@0: 	}
sl@0:       g_fprintf (fout, "%s%s data2);\n", indent (ind), pad ("gpointer"));
sl@0: 
sl@0:       /* cfile marshal variables */
sl@0:       g_fprintf (fout, "  register GMarshalFunc_%s callback;\n", signame);
sl@0:       g_fprintf (fout, "  register GCClosure *cc = (GCClosure*) closure;\n");
sl@0:       g_fprintf (fout, "  register gpointer data1, data2;\n");
sl@0:       if (sig->rarg->setter)
sl@0: 	g_fprintf (fout, "  %s v_return;\n", sig->rarg->ctype);
sl@0: 
sl@0:       if (sig->args || sig->rarg->setter)
sl@0: 	{
sl@0: 	  g_fprintf (fout, "\n");
sl@0: 
sl@0: 	  if (sig->rarg->setter)
sl@0: 	    g_fprintf (fout, "  g_return_if_fail (return_value != NULL);\n");
sl@0: 	  if (sig->args)
sl@0: 	    {
sl@0: 	      for (a = 0, node = sig->args; node; node = node->next)
sl@0: 		{
sl@0: 		  InArgument *iarg = node->data;
sl@0: 
sl@0: 		  if (iarg->getter)
sl@0: 		    a++;
sl@0: 		}
sl@0: 	      g_fprintf (fout, "  g_return_if_fail (n_param_values == %u);\n", 1 + a);
sl@0: 	    }
sl@0: 	}
sl@0: 
sl@0:       /* cfile marshal data1, data2 and callback setup */
sl@0:       g_fprintf (fout, "\n");
sl@0:       g_fprintf (fout, "  if (G_CCLOSURE_SWAP_DATA (closure))\n    {\n");
sl@0:       g_fprintf (fout, "      data1 = closure->data;\n");
sl@0:       g_fprintf (fout, "      data2 = g_value_peek_pointer (param_values + 0);\n");
sl@0:       g_fprintf (fout, "    }\n  else\n    {\n");
sl@0:       g_fprintf (fout, "      data1 = g_value_peek_pointer (param_values + 0);\n");
sl@0:       g_fprintf (fout, "      data2 = closure->data;\n");
sl@0:       g_fprintf (fout, "    }\n");
sl@0:       g_fprintf (fout, "  callback = (GMarshalFunc_%s) (marshal_data ? marshal_data : cc->callback);\n", signame);
sl@0: 
sl@0:       /* cfile marshal callback action */
sl@0:       g_fprintf (fout, "\n");
sl@0:       ind = g_fprintf (fout, " %s callback (", sig->rarg->setter ? " v_return =" : "");
sl@0:       g_fprintf (fout, "data1,\n");
sl@0:       for (a = 1, node = sig->args; node; node = node->next)
sl@0: 	{
sl@0: 	  InArgument *iarg = node->data;
sl@0: 
sl@0: 	  if (iarg->getter)
sl@0: 	    g_fprintf (fout, "%s%s (param_values + %d),\n", indent (ind), iarg->getter, a++);
sl@0: 	}
sl@0:       g_fprintf (fout, "%sdata2);\n", indent (ind));
sl@0: 
sl@0:       /* cfile marshal return value storage */
sl@0:       if (sig->rarg->setter)
sl@0: 	{
sl@0: 	  g_fprintf (fout, "\n");
sl@0: 	  g_fprintf (fout, "  %s (return_value, v_return);\n", sig->rarg->setter);
sl@0: 	}
sl@0: 
sl@0:       /* cfile marshal footer */
sl@0:       g_fprintf (fout, "}\n");
sl@0:     }
sl@0: }
sl@0: 
sl@0: static void
sl@0: process_signature (Signature *sig)
sl@0: {
sl@0:   gchar *pname, *sname, *tmp;
sl@0:   GList *node;
sl@0: 
sl@0:   /* lookup and complete info on arguments */
sl@0:   if (!complete_out_arg (sig->rarg))
sl@0:     {
sl@0:       g_warning ("unknown type: %s", sig->rarg->keyword);
sl@0:       exit_status |= 1;
sl@0:       return;
sl@0:     }
sl@0:   for (node = sig->args; node; node = node->next)
sl@0:     {
sl@0:       InArgument *iarg = node->data;
sl@0: 
sl@0:       if (!complete_in_arg (iarg))
sl@0: 	{
sl@0: 	  g_warning ("unknown type: %s", iarg->keyword);
sl@0:           exit_status |= 1;
sl@0: 	  return;
sl@0: 	}
sl@0:     }
sl@0: 
sl@0:   /* construct requested marshaller name and technical marshaller name */
sl@0:   pname = g_strconcat (sig->rarg->keyword, "_", NULL);
sl@0:   sname = g_strconcat (sig->rarg->sig_name, "_", NULL);
sl@0:   for (node = sig->args; node; node = node->next)
sl@0:     {
sl@0:       InArgument *iarg = node->data;
sl@0:       gchar *tmp;
sl@0: 
sl@0:       tmp = sname;
sl@0:       sname = g_strconcat (tmp, "_", iarg->sig_name, NULL);
sl@0:       g_free (tmp);
sl@0:       tmp = pname;
sl@0:       pname = g_strconcat (tmp, "_", iarg->keyword, NULL);
sl@0:       g_free (tmp);
sl@0:     }
sl@0: 
sl@0:   /* introductionary comment */
sl@0:   g_fprintf (fout, "\n/* %s", sig->rarg->keyword);
sl@0:   for (node = sig->args; node; node = node->next)
sl@0:     {
sl@0:       InArgument *iarg = node->data;
sl@0: 
sl@0:       g_fprintf (fout, "%c%s", node->prev ? ',' : ':', iarg->keyword);
sl@0:     }
sl@0:   if (!skip_ploc)
sl@0:     g_fprintf (fout, " (%s)", sig->ploc);
sl@0:   g_fprintf (fout, " */\n");
sl@0: 
sl@0:   /* ensure technical marshaller exists (<marshaller_prefix>_<sname>) */
sl@0:   generate_marshal (sname, sig);
sl@0: 
sl@0:   /* put out marshaller alias for requested name if required (<marshaller_prefix>_<pname>) */
sl@0:   tmp = g_strconcat (marshaller_prefix, "_", pname, NULL);
sl@0:   if (gen_cheader && !g_hash_table_lookup (marshallers, tmp))
sl@0:     {
sl@0:       g_fprintf (fout, "#define %s_%s\t%s_%s\n", marshaller_prefix, pname, marshaller_prefix, sname);
sl@0: 
sl@0:       g_hash_table_insert (marshallers, tmp, tmp);
sl@0:     }
sl@0:   else
sl@0:     g_free (tmp);
sl@0: 
sl@0:   g_free (pname);
sl@0:   g_free (sname);
sl@0: }
sl@0: 
sl@0: static InArgument*
sl@0: new_in_arg (const gchar *pname)
sl@0: {
sl@0:   InArgument *iarg = g_new0 (InArgument, 1);
sl@0: 
sl@0:   iarg->keyword = g_strdup (pname);
sl@0: 
sl@0:   return iarg;
sl@0: }
sl@0: 
sl@0: static OutArgument*
sl@0: new_out_arg (const gchar *pname)
sl@0: {
sl@0:   OutArgument *oarg = g_new0 (OutArgument, 1);
sl@0: 
sl@0:   oarg->keyword = g_strdup (pname);
sl@0: 
sl@0:   return oarg;
sl@0: }
sl@0: 
sl@0: static guint
sl@0: parse_line (GScanner  *scanner,
sl@0: 	    Signature *sig)
sl@0: {
sl@0:   /* parse identifier for return value */
sl@0:   if (g_scanner_get_next_token (scanner) != G_TOKEN_IDENTIFIER)
sl@0:     return G_TOKEN_IDENTIFIER;
sl@0:   sig->rarg = new_out_arg (scanner->value.v_identifier);
sl@0: 
sl@0:   /* keep a note on the location */
sl@0:   sig->ploc = g_strdup_printf ("%s:%u", scanner->input_name, scanner->line);
sl@0: 
sl@0:   /* expect ':' */
sl@0:   if (g_scanner_get_next_token (scanner) != ':')
sl@0:     return ':';
sl@0: 
sl@0:   /* parse first argument */
sl@0:   if (g_scanner_get_next_token (scanner) != G_TOKEN_IDENTIFIER)
sl@0:     return G_TOKEN_IDENTIFIER;
sl@0:   sig->args = g_list_append (sig->args, new_in_arg (scanner->value.v_identifier));
sl@0: 
sl@0:   /* parse rest of argument list */
sl@0:   while (g_scanner_peek_next_token (scanner) == ',')
sl@0:     {
sl@0:       /* eat comma */
sl@0:       g_scanner_get_next_token (scanner);
sl@0: 
sl@0:       /* parse arg identifier */
sl@0:       if (g_scanner_get_next_token (scanner) != G_TOKEN_IDENTIFIER)
sl@0: 	return G_TOKEN_IDENTIFIER;
sl@0:       sig->args = g_list_append (sig->args, new_in_arg (scanner->value.v_identifier));
sl@0:     }
sl@0: 
sl@0:   /* expect end of line, done */
sl@0:   if (g_scanner_get_next_token (scanner) != '\n')
sl@0:     return '\n';
sl@0: 
sl@0:   /* success */
sl@0:   return G_TOKEN_NONE;
sl@0: }
sl@0: 
sl@0: static gboolean
sl@0: string_key_destroy (gpointer key,
sl@0: 		    gpointer value,
sl@0: 		    gpointer user_data)
sl@0: {
sl@0:   g_free (key);
sl@0: 
sl@0:   return TRUE;
sl@0: }
sl@0: 
sl@0: int
sl@0: main (int   argc,
sl@0:       char *argv[])
sl@0: {
sl@0:   const gchar *gobject_marshallers[] = {
sl@0: #include	"gmarshal.strings"
sl@0:   };
sl@0:   GScanner *scanner;
sl@0:   GSList *slist, *files = NULL;
sl@0:   gint i;
sl@0: #ifdef __SYMBIAN32__
sl@0:   gint fd1;
sl@0:   g_log_set_handler (NULL,  G_LOG_FLAG_FATAL| G_LOG_FLAG_RECURSION | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG, &mrtLogHandler, NULL);
sl@0:   g_set_print_handler(mrtPrintHandler);
sl@0:   #endif /*__SYMBIAN32__*/
sl@0:   /* parse args and do fast exits */
sl@0:   parse_args (&argc, &argv);
sl@0: 
sl@0:   /* list input files */
sl@0:   for (i = 1; i < argc; i++)
sl@0:     files = g_slist_prepend (files, argv[i]);
sl@0:   if (files)
sl@0:     files = g_slist_reverse (files);
sl@0:   else
sl@0: #ifdef __SYMBIAN32__
sl@0: 	fd1 = open("c:\\genmarshaltest.txt", O_CREAT, 0666);
sl@0: 	close(fd1);
sl@0: 	files = g_slist_prepend (files, "c:\\genmarshaltest.txt");
sl@0: #else
sl@0:     files = g_slist_prepend (files, "/dev/stdin");
sl@0: #endif//__SYMBIAN32__
sl@0:   
sl@0:   /* setup auxillary structs */
sl@0:   scanner = g_scanner_new (&scanner_config_template);
sl@0:   fout = stdout;
sl@0:   marshallers = g_hash_table_new (g_str_hash, g_str_equal);
sl@0: 
sl@0:   /* add standard marshallers of the GObject library */
sl@0:   if (std_includes)
sl@0:     for (i = 0; i < G_N_ELEMENTS (gobject_marshallers); i++)
sl@0:       {
sl@0: 	gchar *tmp = g_strdup (gobject_marshallers[i]);
sl@0: 
sl@0: 	g_hash_table_insert (marshallers, tmp, tmp);
sl@0:       }
sl@0: 
sl@0:   /* put out initial heading */
sl@0:   g_fprintf (fout, "\n");
sl@0: 
sl@0:   if (gen_cheader && std_includes)
sl@0:     {
sl@0:       g_fprintf (fout, "#ifndef __%s_MARSHAL_H__\n", marshaller_prefix);
sl@0:       g_fprintf (fout, "#define __%s_MARSHAL_H__\n\n", marshaller_prefix);
sl@0:     }
sl@0: 
sl@0:   if ((gen_cheader || gen_cbody) && std_includes)
sl@0:     g_fprintf (fout, "#include\t<glib-object.h>\n\n");
sl@0: 
sl@0:   if (gen_cheader)
sl@0:     g_fprintf (fout, "G_BEGIN_DECLS\n");
sl@0: 
sl@0:   /* generate necessary preprocessor directives */
sl@0:   if (gen_cbody)
sl@0:     put_marshal_value_getters ();
sl@0: 
sl@0:   /* process input files */
sl@0:   for (slist = files; slist; slist = slist->next)
sl@0:     {
sl@0:       gchar *file = slist->data;
sl@0:       gint fd;
sl@0:       
sl@0: #ifdef __SYMBIAN32__
sl@0:       if (strcmp (file, "c:\\genmarshaltest.txt") == 0)
sl@0: #else      
sl@0:       if (strcmp (file, "/dev/stdin") == 0)    	  
sl@0: 	/* Mostly for Win32. This is equivalent to opening /dev/stdin */
sl@0: 	fd = dup (0);
sl@0:       else
sl@0: #endif//__SYMBIAN32__    	  
sl@0: 	fd = open (file, O_RDONLY);
sl@0: 
sl@0:       if (fd < 0)
sl@0: 	{
sl@0: 	  g_warning ("failed to open \"%s\": %s", file, g_strerror (errno));
sl@0: 	  exit_status |= 1;
sl@0: 	  continue;
sl@0: 	}
sl@0: 
sl@0:       /* set file name for error reports */
sl@0:       scanner->input_name = file;
sl@0: 
sl@0:       /* parse & process file */
sl@0:       g_scanner_input_file (scanner, fd);
sl@0: 
sl@0:       /* scanning loop, we parse the input until its end is reached,
sl@0:        * or our sub routine came across invalid syntax
sl@0:        */
sl@0:       do
sl@0: 	{
sl@0: 	  guint expected_token = G_TOKEN_NONE;
sl@0: 
sl@0: 	  switch (g_scanner_peek_next_token (scanner))
sl@0: 	    {
sl@0: 	    case '\n':
sl@0: 	      /* eat newline and restart */
sl@0: 	      g_scanner_get_next_token (scanner);
sl@0: 	      continue;
sl@0: 	    case G_TOKEN_EOF:
sl@0: 	      /* done */
sl@0: 	      break;
sl@0: 	    default:
sl@0: 	      /* parse and process signatures */
sl@0: 	      {
sl@0: 		Signature signature = { NULL, NULL, NULL };
sl@0: 		GList *node;
sl@0: 
sl@0: 		expected_token = parse_line (scanner, &signature);
sl@0: 
sl@0: 		/* once we got a valid signature, process it */
sl@0: 		if (expected_token == G_TOKEN_NONE)
sl@0: 		  process_signature (&signature);
sl@0: 
sl@0: 		/* clean up signature contents */
sl@0: 		g_free (signature.ploc);
sl@0: 		if (signature.rarg)
sl@0: 		  g_free (signature.rarg->keyword);
sl@0: 		g_free (signature.rarg);
sl@0: 		for (node = signature.args; node; node = node->next)
sl@0: 		  {
sl@0: 		    InArgument *iarg = node->data;
sl@0: 
sl@0: 		    g_free (iarg->keyword);
sl@0: 		    g_free (iarg);
sl@0: 		  }
sl@0: 		g_list_free (signature.args);
sl@0: 	      }
sl@0: 	      break;
sl@0: 	    }
sl@0: 
sl@0: 	  /* bail out on errors */
sl@0: 	  if (expected_token != G_TOKEN_NONE)
sl@0: 	    {
sl@0: 	      g_scanner_unexp_token (scanner, expected_token, "type name", NULL, NULL, NULL, TRUE);
sl@0: 	      exit_status |= 1;
sl@0: 	      break;
sl@0: 	    }
sl@0: 
sl@0: 	  g_scanner_peek_next_token (scanner);
sl@0: 	}
sl@0:       while (scanner->next_token != G_TOKEN_EOF);
sl@0: 
sl@0:       close (fd);
sl@0:     }
sl@0: 
sl@0:   /* put out trailer */
sl@0:   if (gen_cheader)
sl@0:     {
sl@0:       g_fprintf (fout, "\nG_END_DECLS\n");
sl@0: 
sl@0:       if (std_includes)
sl@0: 	g_fprintf (fout, "\n#endif /* __%s_MARSHAL_H__ */\n", marshaller_prefix);
sl@0:     }
sl@0:   g_fprintf (fout, "\n");
sl@0: 
sl@0:   /* clean up */
sl@0:   g_slist_free (files);
sl@0:   g_scanner_destroy (scanner);
sl@0:   g_hash_table_foreach_remove (marshallers, string_key_destroy, NULL);
sl@0:   g_hash_table_destroy (marshallers);
sl@0: #ifdef __SYMBIAN32__
sl@0:   testResultXml("glib-genmarshall");
sl@0:   remove("c:\\genmarshaltest.txt");
sl@0: #endif /* EMULATOR */
sl@0:   return exit_status;
sl@0: }
sl@0: 
sl@0: static void
sl@0: parse_args (gint    *argc_p,
sl@0: 	    gchar ***argv_p)
sl@0: {
sl@0:   guint argc = *argc_p;
sl@0:   gchar **argv = *argv_p;
sl@0:   guint i, e;
sl@0: 
sl@0:   for (i = 1; i < argc; i++)
sl@0:     {
sl@0:       if (strcmp ("-header", argv[i]) == 0)
sl@0: 	{
sl@0: 	  gen_cheader = TRUE;
sl@0: 	  argv[i] = NULL;
sl@0: 	}
sl@0:       else if (strcmp ("-body", argv[i]) == 0)
sl@0: 	{
sl@0: 	  gen_cbody = TRUE;
sl@0: 	  argv[i] = NULL;
sl@0: 	}
sl@0:       else if (strcmp ("-skip-source", argv[i]) == 0)
sl@0: 	{
sl@0: 	  skip_ploc = TRUE;
sl@0: 	  argv[i] = NULL;
sl@0: 	}
sl@0:       else if (strcmp ("-nostdinc", argv[i]) == 0)
sl@0: 	{
sl@0: 	  std_includes = FALSE;
sl@0: 	  argv[i] = NULL;
sl@0: 	}
sl@0:       else if (strcmp ("-stdinc", argv[i]) == 0)
sl@0: 	{
sl@0: 	  std_includes = TRUE;
sl@0: 	  argv[i] = NULL;
sl@0: 	}
sl@0:       else if (strcmp ("-internal", argv[i]) == 0)
sl@0: 	{
sl@0: 	  gen_internal = TRUE;
sl@0: 	  argv[i] = NULL;
sl@0: 	}
sl@0:       else if ((strcmp ("-prefix", argv[i]) == 0) ||
sl@0: 	       (strncmp ("-prefix=", argv[i], 9) == 0))
sl@0: 	{
sl@0:           gchar *equal = argv[i] + 8;
sl@0: 
sl@0: 	  if (*equal == '=')
sl@0: 	    marshaller_prefix = g_strdup (equal + 1);
sl@0: 	  else if (i + 1 < argc)
sl@0: 	    {
sl@0: 	      marshaller_prefix = g_strdup (argv[i + 1]);
sl@0: 	      argv[i] = NULL;
sl@0: 	      i += 1;
sl@0: 	    }
sl@0: 	  argv[i] = NULL;
sl@0: 	}
sl@0:       else if (strcmp ("-h", argv[i]) == 0 ||
sl@0:           strcmp ("-?", argv[i]) == 0 ||
sl@0: 	  strcmp ("-help", argv[i]) == 0)
sl@0: 	{
sl@0: 	  print_blurb (stderr, TRUE);
sl@0: 	  argv[i] = NULL;
sl@0: 	  exit (0);
sl@0: 	}
sl@0:       else if (strcmp ("-v", argv[i]) == 0 ||
sl@0: 	       strcmp ("-version", argv[i]) == 0)
sl@0: 	{
sl@0: 	  print_blurb (stderr, FALSE);
sl@0: 	  argv[i] = NULL;
sl@0: 	  exit (0);
sl@0: 	}
sl@0:       else if (strcmp (argv[i], "-g-fatal-warnings") == 0)
sl@0: 	{
sl@0: 	  GLogLevelFlags fatal_mask;
sl@0: 
sl@0: 	  fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
sl@0: 	  fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
sl@0: 	  g_log_set_always_fatal (fatal_mask);
sl@0: 
sl@0: 	  argv[i] = NULL;
sl@0: 	}
sl@0:     }
sl@0: 
sl@0:   e = 0;
sl@0:   for (i = 1; i < argc; i++)
sl@0:     {
sl@0:       if (e)
sl@0: 	{
sl@0: 	  if (argv[i])
sl@0: 	    {
sl@0: 	      argv[e++] = argv[i];
sl@0: 	      argv[i] = NULL;
sl@0: 	    }
sl@0: 	}
sl@0:       else if (!argv[i])
sl@0: 	e = i;
sl@0:     }
sl@0:   if (e)
sl@0:     *argc_p = e;
sl@0: }
sl@0: 
sl@0: static void
sl@0: print_blurb (FILE    *bout,
sl@0: 	     gboolean print_help)
sl@0: {
sl@0:   if (!print_help)
sl@0:     {
sl@0:       g_fprintf (bout, "%s version ", PRG_NAME);
sl@0:       g_fprintf (bout, "%u.%u.%u", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION);
sl@0:       g_fprintf (bout, "\n");
sl@0:       g_fprintf (bout, "%s comes with ABSOLUTELY NO WARRANTY.\n", PRG_NAME);
sl@0:       g_fprintf (bout, "You may redistribute copies of %s under the terms of\n", PRG_NAME);
sl@0:       g_fprintf (bout, "the GNU General Public License which can be found in the\n");
sl@0:       g_fprintf (bout, "%s source package. Sources, examples and contact\n", PKG_NAME);
sl@0:       g_fprintf (bout, "information are available at %s\n", PKG_HTTP_HOME);
sl@0:     }
sl@0:   else
sl@0:     {
sl@0:       g_fprintf (bout, "Usage:\n");
sl@0:       g_fprintf (bout, "  %s [OPTION...] [FILES...]\n\n", PRG_NAME);
sl@0:       g_fprintf (bout, "Help Options:\n");
sl@0:       g_fprintf (bout, "  -h, -help                 Show this help message\n\n");
sl@0:       g_fprintf (bout, "Utility Options:\n");
sl@0:       g_fprintf (bout, "  -header                   Generate C headers\n");
sl@0:       g_fprintf (bout, "  -body                     Generate C code\n");
sl@0:       g_fprintf (bout, "  -prefix=string            Specify marshaller prefix\n");
sl@0:       g_fprintf (bout, "  -skip-source              Skip source location comments\n");
sl@0:       g_fprintf (bout, "  -stdinc, -nostdinc       Include/use standard marshallers\n");
sl@0:       g_fprintf (bout, "  -internal                 Mark generated functions as internal\n");
sl@0:       g_fprintf (bout, "  -v, -version              Print version informations\n");
sl@0:       g_fprintf (bout, "  -g-fatal-warnings         Make warnings fatal (abort)\n");
sl@0:     }
sl@0: }