1 /* GLIB-GenMarshal - Marshaller generator for GObject library
2 * Copyright (C) 2000-2001 Red Hat, Inc.
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.
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.
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.
22 /* ok, this is a bit hackish, have to provide gruntime log domain as
23 * we don't link against -lgruntime
25 char *g_log_domain_gruntime = "GLib-Genmarshal";
37 #include <sys/types.h>
45 #define PRG_NAME "glib-genmarshal"
46 #define PKG_NAME "GLib"
47 #define PKG_HTTP_HOME "http://www.gtk.org"
50 /* --- typedefs & structures --- */
53 gchar *keyword; /* marhaller list keyword [MY_STRING] */
54 const gchar *sig_name; /* signature name [STRING] */
55 const gchar *ctype; /* C type name [gchar*] */
56 const gchar *getter; /* value getter function [g_value_get_string] */
60 gchar *keyword; /* marhaller list keyword [MY_STRING] */
61 const gchar *sig_name; /* signature name [STRING] */
62 const gchar *ctype; /* C type name [gchar*] */
63 const gchar *setter; /* value setter function [g_value_set_string] */
64 const gchar *release; /* value release function [g_free] */
70 GList *args; /* of type InArgument* */
74 /* --- prototypes --- */
75 static void parse_args (gint *argc_p,
77 static void print_blurb (FILE *bout,
81 /* --- variables --- */
82 static FILE *fout = NULL;
83 static GScannerConfig scanner_config_template =
86 " \t\r" /* "\n" is statement delimiter */
87 ) /* cset_skip_characters */,
92 ) /* cset_identifier_first */,
97 ) /* cset_identifier_nth */,
98 ( "#\n" ) /* cpair_comment_single */,
100 FALSE /* case_sensitive */,
102 TRUE /* skip_comment_multi */,
103 TRUE /* skip_comment_single */,
104 TRUE /* scan_comment_multi */,
105 TRUE /* scan_identifier */,
106 FALSE /* scan_identifier_1char */,
107 FALSE /* scan_identifier_NULL */,
108 TRUE /* scan_symbols */,
109 FALSE /* scan_binary */,
110 TRUE /* scan_octal */,
111 TRUE /* scan_float */,
113 FALSE /* scan_hex_dollar */,
114 TRUE /* scan_string_sq */,
115 TRUE /* scan_string_dq */,
116 TRUE /* numbers_2_int */,
117 FALSE /* int_2_float */,
118 FALSE /* identifier_2_string */,
119 TRUE /* char_2_token */,
120 FALSE /* symbol_2_token */,
121 FALSE /* scope_0_fallback */,
123 static gchar *std_marshaller_prefix = "g_cclosure_marshal";
124 static gchar *marshaller_prefix = "g_cclosure_user_marshal";
125 static GHashTable *marshallers = NULL;
126 static gboolean gen_cheader = FALSE;
127 static gboolean gen_cbody = FALSE;
128 static gboolean skip_ploc = FALSE;
129 static gboolean std_includes = TRUE;
132 /* --- functions --- */
134 complete_in_arg (InArgument *iarg)
136 static const InArgument args[] = {
137 /* keyword sig_name ctype getter */
138 { "VOID", "VOID", "void", NULL, },
139 { "BOOLEAN", "BOOLEAN", "gboolean", "g_value_get_boolean", },
140 { "CHAR", "CHAR", "gchar", "g_value_get_char", },
141 { "UCHAR", "UCHAR", "guchar", "g_value_get_uchar", },
142 { "INT", "INT", "gint", "g_value_get_int", },
143 { "UINT", "UINT", "guint", "g_value_get_uint", },
144 { "LONG", "LONG", "glong", "g_value_get_long", },
145 { "ULONG", "ULONG", "gulong", "g_value_get_ulong", },
146 { "ENUM", "ENUM", "gint", "g_value_get_enum", },
147 { "FLAGS", "FLAGS", "guint", "g_value_get_flags", },
148 { "FLOAT", "FLOAT", "gfloat", "g_value_get_float", },
149 { "DOUBLE", "DOUBLE", "gdouble", "g_value_get_double", },
150 { "STRING", "STRING", "gpointer", "(char*) g_value_get_string", },
151 { "PARAM", "PARAM", "gpointer", "g_value_get_param", },
152 { "BOXED", "BOXED", "gpointer", "g_value_get_boxed", },
153 { "POINTER", "POINTER", "gpointer", "g_value_get_pointer", },
154 { "OBJECT", "OBJECT", "gpointer", "g_value_get_object", },
156 { "NONE", "VOID", "void", NULL, },
157 { "BOOL", "BOOLEAN", "gboolean", "g_value_get_boolean", },
159 const guint n_args = sizeof (args) / sizeof (args[0]);
162 g_return_val_if_fail (iarg != NULL, FALSE);
164 for (i = 0; i < n_args; i++)
165 if (strcmp (args[i].keyword, iarg->keyword) == 0)
167 iarg->sig_name = args[i].sig_name;
168 iarg->ctype = args[i].ctype;
169 iarg->getter = args[i].getter;
177 complete_out_arg (OutArgument *oarg)
179 static const OutArgument args[] = {
180 /* keyword sig_name ctype setter release */
181 { "VOID", "VOID", "void", NULL, NULL, },
182 { "BOOLEAN", "BOOLEAN", "gboolean", "g_value_set_boolean", NULL, },
183 { "CHAR", "CHAR", "gchar", "g_value_set_char", NULL, },
184 { "UCHAR", "UCHAR", "guchar", "g_value_set_uchar", NULL, },
185 { "INT", "INT", "gint", "g_value_set_int", NULL, },
186 { "UINT", "UINT", "guint", "g_value_set_uint", NULL, },
187 { "LONG", "LONG", "glong", "g_value_set_long", NULL, },
188 { "ULONG", "ULONG", "gulong", "g_value_set_ulong", NULL, },
189 { "ENUM", "ENUM", "gint", "g_value_set_enum", NULL, },
190 { "FLAGS", "FLAGS", "guint", "g_value_set_flags", NULL, },
191 { "FLOAT", "FLOAT", "gfloat", "g_value_set_float", NULL, },
192 { "DOUBLE", "DOUBLE", "gdouble", "g_value_set_double", NULL, },
193 { "STRING", "STRING", "gchar*", "g_value_set_string_take_ownership", NULL, },
194 { "PARAM", "PARAM", "GParamSpec*", "g_value_set_param", "g_param_spec_unref", },
195 { "BOXED", "BOXED", "gpointer", "g_value_set_boxed_take_ownership", NULL, },
196 { "POINTER", "POINTER", "gpointer", "g_value_set_pointer", NULL, },
197 { "OBJECT", "OBJECT", "GObject*", "g_value_set_object", "g_object_unref", },
199 { "NONE", "VOID", "void", NULL, NULL, },
200 { "BOOL", "BOOLEAN", "gboolean", "g_value_set_boolean", NULL, },
202 const guint n_args = sizeof (args) / sizeof (args[0]);
205 g_return_val_if_fail (oarg != NULL, FALSE);
207 for (i = 0; i < n_args; i++)
208 if (strcmp (args[i].keyword, oarg->keyword) == 0)
210 oarg->sig_name = args[i].sig_name;
211 oarg->ctype = args[i].ctype;
212 oarg->setter = args[i].setter;
213 oarg->release = args[i].release;
221 pad (const gchar *string)
223 #define PAD_LENGTH 12
224 static gchar *buffer = NULL;
227 g_return_val_if_fail (string != NULL, NULL);
230 buffer = g_new (gchar, PAD_LENGTH + 1);
233 if (strlen (string) >= PAD_LENGTH)
236 buffer = g_strdup_printf ("%s ", string);
237 g_warning ("overfull string (%u bytes) for padspace", (guint) strlen (string));
242 for (i = 0; i < PAD_LENGTH; i++)
244 gboolean done = *string == 0;
246 buffer[i] = done ? ' ' : *string++;
254 indent (guint n_spaces)
256 static gchar *buffer = NULL;
257 static guint blength = 0;
259 if (blength <= n_spaces)
261 blength = n_spaces + 1;
263 buffer = g_new (gchar, blength);
265 memset (buffer, ' ', n_spaces);
266 buffer[n_spaces] = 0;
272 generate_marshal (const gchar *signame,
277 gchar *tmp = g_strconcat (marshaller_prefix, "_", signame, NULL);
278 gboolean have_std_marshaller = FALSE;
280 /* here we have to make sure a marshaller named <marshaller_prefix>_<signame>
281 * exists. we might have put it out already, can revert to a standard marshaller
282 * provided by glib, or need to generate one.
285 if (g_hash_table_lookup (marshallers, tmp))
287 /* done, marshaller already generated */
293 /* need to alias/generate marshaller, register name */
294 g_hash_table_insert (marshallers, tmp, tmp);
297 /* can we revert to a standard marshaller? */
300 tmp = g_strconcat (std_marshaller_prefix, "_", signame, NULL);
301 have_std_marshaller = g_hash_table_lookup (marshallers, tmp) != NULL;
305 if (gen_cheader && have_std_marshaller)
307 fprintf (fout, "#define %s_%s\t%s_%s\n", marshaller_prefix, signame, std_marshaller_prefix, signame);
309 if (gen_cheader && !have_std_marshaller)
311 ind = fprintf (fout, "extern void ");
312 ind += fprintf (fout, "%s_%s (", marshaller_prefix, signame);
313 fprintf (fout, "GClosure *closure,\n");
314 fprintf (fout, "%sGValue *return_value,\n", indent (ind));
315 fprintf (fout, "%sguint n_param_values,\n", indent (ind));
316 fprintf (fout, "%sconst GValue *param_values,\n", indent (ind));
317 fprintf (fout, "%sgpointer invocation_hint,\n", indent (ind));
318 fprintf (fout, "%sgpointer marshal_data);\n", indent (ind));
320 if (gen_cbody && !have_std_marshaller)
322 /* cfile marhsal header */
323 fprintf (fout, "void\n");
324 ind = fprintf (fout, "%s_%s (", marshaller_prefix, signame);
325 fprintf (fout, "GClosure *closure,\n");
326 fprintf (fout, "%sGValue *return_value,\n", indent (ind));
327 fprintf (fout, "%sguint n_param_values,\n", indent (ind));
328 fprintf (fout, "%sconst GValue *param_values,\n", indent (ind));
329 fprintf (fout, "%sgpointer invocation_hint,\n", indent (ind));
330 fprintf (fout, "%sgpointer marshal_data)\n", indent (ind));
331 fprintf (fout, "{\n");
333 /* cfile GMarshalFunc typedef */
334 ind = fprintf (fout, " typedef %s (*GMarshalFunc_%s) (", sig->rarg->ctype, signame);
335 fprintf (fout, "%s data1,\n", pad ("gpointer"));
336 for (a = 1, node = sig->args; node; node = node->next)
338 InArgument *iarg = node->data;
341 fprintf (fout, "%s%s arg_%d,\n", indent (ind), pad (iarg->ctype), a++);
343 fprintf (fout, "%s%s data2);\n", indent (ind), pad ("gpointer"));
345 /* cfile marshal variables */
346 fprintf (fout, " register GMarshalFunc_%s callback;\n", signame);
347 fprintf (fout, " register GCClosure *cc = (GCClosure*) closure;\n");
348 fprintf (fout, " register gpointer data1, data2;\n");
349 if (sig->rarg->setter)
350 fprintf (fout, " %s v_return;\n", sig->rarg->ctype);
352 if (sig->args || sig->rarg->setter)
354 fprintf (fout, "\n");
356 if (sig->rarg->setter)
357 fprintf (fout, " g_return_if_fail (return_value != NULL);\n");
360 for (a = 0, node = sig->args; node; node = node->next)
362 InArgument *iarg = node->data;
367 fprintf (fout, " g_return_if_fail (n_param_values == %u);\n", 1 + a);
371 /* cfile marshal data1, data2 and callback setup */
372 fprintf (fout, "\n");
373 fprintf (fout, " if (G_CCLOSURE_SWAP_DATA (closure))\n {\n");
374 fprintf (fout, " data1 = closure->data;\n");
375 fprintf (fout, " data2 = g_value_peek_pointer (param_values + 0);\n");
376 fprintf (fout, " }\n else\n {\n");
377 fprintf (fout, " data1 = g_value_peek_pointer (param_values + 0);\n");
378 fprintf (fout, " data2 = closure->data;\n");
379 fprintf (fout, " }\n");
380 fprintf (fout, " callback = (GMarshalFunc_%s) (marshal_data ? marshal_data : cc->callback);\n", signame);
382 /* cfile marshal callback action */
383 fprintf (fout, "\n");
384 ind = fprintf (fout, " %s callback (", sig->rarg->setter ? " v_return =" : "");
385 fprintf (fout, "data1,\n");
386 for (a = 1, node = sig->args; node; node = node->next)
388 InArgument *iarg = node->data;
391 fprintf (fout, "%s%s (param_values + %d),\n", indent (ind), iarg->getter, a++);
393 fprintf (fout, "%sdata2);\n", indent (ind));
395 /* cfile marshal return value storage */
396 if (sig->rarg->setter)
398 fprintf (fout, "\n");
399 fprintf (fout, " %s (return_value, v_return);\n", sig->rarg->setter);
400 if (sig->rarg->release)
401 fprintf (fout, " %s (v_return);\n", sig->rarg->release);
404 /* cfile marshal footer */
405 fprintf (fout, "}\n");
410 process_signature (Signature *sig)
412 gchar *pname, *sname, *tmp;
415 /* lookup and complete info on arguments */
416 if (!complete_out_arg (sig->rarg))
418 g_warning ("unknown type: %s", sig->rarg->keyword);
421 for (node = sig->args; node; node = node->next)
423 InArgument *iarg = node->data;
425 if (!complete_in_arg (iarg))
427 g_warning ("unknown type: %s", iarg->keyword);
432 /* construct requested marshaller name and technical marshaller name */
433 pname = g_strconcat (sig->rarg->keyword, "_", NULL);
434 sname = g_strconcat (sig->rarg->sig_name, "_", NULL);
435 for (node = sig->args; node; node = node->next)
437 InArgument *iarg = node->data;
441 sname = g_strconcat (tmp, "_", iarg->sig_name, NULL);
444 pname = g_strconcat (tmp, "_", iarg->keyword, NULL);
448 /* introductionary comment */
449 fprintf (fout, "\n/* %s", sig->rarg->keyword);
450 for (node = sig->args; node; node = node->next)
452 InArgument *iarg = node->data;
454 fprintf (fout, "%c%s", node->prev ? ',' : ':', iarg->keyword);
457 fprintf (fout, " (%s)", sig->ploc);
458 fprintf (fout, " */\n");
460 /* ensure technical marshaller exists (<marshaller_prefix>_<sname>) */
461 generate_marshal (sname, sig);
463 /* put out marshaller alias for requested name if required (<marshaller_prefix>_<pname>) */
464 tmp = g_strconcat (marshaller_prefix, "_", pname, NULL);
465 if (gen_cheader && !g_hash_table_lookup (marshallers, tmp))
467 fprintf (fout, "#define %s_%s\t%s_%s\n", marshaller_prefix, pname, marshaller_prefix, sname);
469 g_hash_table_insert (marshallers, tmp, tmp);
479 new_in_arg (const gchar *pname)
481 InArgument *iarg = g_new0 (InArgument, 1);
483 iarg->keyword = g_strdup (pname);
489 new_out_arg (const gchar *pname)
491 OutArgument *oarg = g_new0 (OutArgument, 1);
493 oarg->keyword = g_strdup (pname);
499 parse_line (GScanner *scanner,
502 /* parse identifier for return value */
503 if (g_scanner_get_next_token (scanner) != G_TOKEN_IDENTIFIER)
504 return G_TOKEN_IDENTIFIER;
505 sig->rarg = new_out_arg (scanner->value.v_identifier);
507 /* keep a note on the location */
508 sig->ploc = g_strdup_printf ("%s:%u", scanner->input_name, scanner->line);
511 if (g_scanner_get_next_token (scanner) != ':')
514 /* parse first argument */
515 if (g_scanner_get_next_token (scanner) != G_TOKEN_IDENTIFIER)
516 return G_TOKEN_IDENTIFIER;
517 sig->args = g_list_append (sig->args, new_in_arg (scanner->value.v_identifier));
519 /* parse rest of argument list */
520 while (g_scanner_peek_next_token (scanner) == ',')
523 g_scanner_get_next_token (scanner);
525 /* parse arg identifier */
526 if (g_scanner_get_next_token (scanner) != G_TOKEN_IDENTIFIER)
527 return G_TOKEN_IDENTIFIER;
528 sig->args = g_list_append (sig->args, new_in_arg (scanner->value.v_identifier));
531 /* expect end of line, done */
532 if (g_scanner_get_next_token (scanner) != '\n')
540 string_key_destroy (gpointer key,
553 const gchar *gruntime_marshallers[] = {
554 #include "gmarshal.strings"
557 GSList *slist, *files = NULL;
560 /* parse args and do fast exits */
561 parse_args (&argc, &argv);
563 /* list input files */
564 for (i = 1; i < argc; i++)
565 files = g_slist_prepend (files, argv[i]);
567 files = g_slist_reverse (files);
569 files = g_slist_prepend (files, "/dev/stdin");
571 /* setup auxillary structs */
572 scanner = g_scanner_new (&scanner_config_template);
574 marshallers = g_hash_table_new (g_str_hash, g_str_equal);
576 /* add GRuntime standard marshallers */
578 for (i = 0; i < sizeof (gruntime_marshallers) / sizeof (gruntime_marshallers[0]); i++)
580 gchar *tmp = g_strdup (gruntime_marshallers[i]);
582 g_hash_table_insert (marshallers, tmp, tmp);
585 /* put out initial heading */
586 fprintf (fout, "\n");
590 fprintf (fout, "#include\t<gobject/gmarshal.h>\n\n");
591 fprintf (fout, "#ifdef __cplusplus\nextern \"C\" {\n#endif /* __cplusplus */\n");
594 /* process input files */
595 for (slist = files; slist; slist = slist->next)
597 gchar *file = slist->data;
598 gint fd = open (file, O_RDONLY);
602 g_warning ("failed to open \"%s\": %s", file, g_strerror (errno));
606 /* set file name for error reports */
607 scanner->input_name = file;
609 /* parse & process file */
610 g_scanner_input_file (scanner, fd);
612 /* scanning loop, we parse the input untill it's end is reached,
613 * or our sub routine came across invalid syntax
617 guint expected_token = G_TOKEN_NONE;
619 switch (g_scanner_peek_next_token (scanner))
622 /* eat newline and restart */
623 g_scanner_get_next_token (scanner);
629 /* parse and process signatures */
631 Signature signature = { NULL, NULL, NULL };
634 expected_token = parse_line (scanner, &signature);
636 /* once we got a valid signature, process it */
637 if (expected_token == G_TOKEN_NONE)
638 process_signature (&signature);
640 /* clean up signature contents */
641 g_free (signature.ploc);
643 g_free (signature.rarg->keyword);
644 g_free (signature.rarg);
645 for (node = signature.args; node; node = node->next)
647 InArgument *iarg = node->data;
649 g_free (iarg->keyword);
652 g_list_free (signature.args);
657 /* bail out on errors */
658 if (expected_token != G_TOKEN_NONE)
660 g_scanner_unexp_token (scanner, expected_token, "type name", NULL, NULL, NULL, TRUE);
664 g_scanner_peek_next_token (scanner);
666 while (scanner->next_token != G_TOKEN_EOF);
671 /* put out trailer */
674 fprintf (fout, "\n#ifdef __cplusplus\n}\n#endif /* __cplusplus */\n");
676 fprintf (fout, "\n");
679 g_slist_free (files);
680 g_scanner_destroy (scanner);
681 g_hash_table_foreach_remove (marshallers, string_key_destroy, NULL);
682 g_hash_table_destroy (marshallers);
688 parse_args (gint *argc_p,
691 guint argc = *argc_p;
692 gchar **argv = *argv_p;
695 for (i = 1; i < argc; i++)
697 if (strcmp ("--header", argv[i]) == 0)
702 else if (strcmp ("--body", argv[i]) == 0)
707 else if (strcmp ("--skip-source", argv[i]) == 0)
712 else if (strcmp ("--nostdinc", argv[i]) == 0)
714 std_includes = FALSE;
717 else if (strcmp ("--stdinc", argv[i]) == 0)
722 else if ((strcmp ("--prefix", argv[i]) == 0) ||
723 (strncmp ("--prefix=", argv[i], 9) == 0))
725 gchar *equal = argv[i] + 8;
728 marshaller_prefix = g_strdup (equal + 1);
729 else if (i + 1 < argc)
731 marshaller_prefix = g_strdup (argv[i + 1]);
737 else if (strcmp ("-h", argv[i]) == 0 ||
738 strcmp ("--help", argv[i]) == 0)
740 print_blurb (stderr, TRUE);
744 else if (strcmp ("-v", argv[i]) == 0 ||
745 strcmp ("--version", argv[i]) == 0)
747 print_blurb (stderr, FALSE);
751 else if (strcmp (argv[i], "--g-fatal-warnings") == 0)
753 GLogLevelFlags fatal_mask;
755 fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
756 fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
757 g_log_set_always_fatal (fatal_mask);
764 for (i = 1; i < argc; i++)
782 print_blurb (FILE *bout,
787 fprintf (bout, "%s version ", PRG_NAME);
788 fprintf (bout, "%u.%u.%u", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION);
789 fprintf (bout, "\n");
790 fprintf (bout, "%s comes with ABSOLUTELY NO WARRANTY.\n", PRG_NAME);
791 fprintf (bout, "You may redistribute copies of %s under the terms of\n", PRG_NAME);
792 fprintf (bout, "the GNU General Public License which can be found in the\n");
793 fprintf (bout, "%s source package. Sources, examples and contact\n", PKG_NAME);
794 fprintf (bout, "information are available at %s\n", PKG_HTTP_HOME);
798 fprintf (bout, "Usage: %s [options] [files...]\n", PRG_NAME);
799 fprintf (bout, " --header generate C headers\n");
800 fprintf (bout, " --body generate C code\n");
801 fprintf (bout, " --prefix=string specify marshaller prefix\n");
802 fprintf (bout, " --skip-source skip source location comments\n");
803 fprintf (bout, " --stdinc, --nostdinc include/use GRuntime standard marshallers\n");
804 fprintf (bout, " -h, --help show this help message\n");
805 fprintf (bout, " -v, --version print version informations\n");
806 fprintf (bout, " --g-fatal-warnings make warnings fatal (abort)\n");