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 sl@0: #include sl@0: #include sl@0: #include sl@0: #ifdef HAVE_UNISTD_H sl@0: #include sl@0: #endif sl@0: #include sl@0: #include sl@0: sl@0: #undef G_LOG_DOMAIN sl@0: #define G_LOG_DOMAIN "GLib-Genmarshal" sl@0: #include sl@0: #include sl@0: sl@0: #ifdef G_OS_WIN32 sl@0: #include 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 _ 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 (_) */ sl@0: generate_marshal (sname, sig); sl@0: sl@0: /* put out marshaller alias for requested name if required (_) */ 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\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: }