1 /* GLIB-GenMarshal - Marshaller generator for GObject library
2 * Copyright (C) 2000 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 --- */
51 typedef struct _Argument Argument;
52 typedef struct _Signature Signature;
55 gchar *pname; /* parsed name */
56 const gchar *sname; /* signature name */
57 const gchar *func; /* functional extension */
58 const gchar *cname; /* C name */
64 GList *args; /* of type Argument* */
68 /* --- prototypes --- */
69 static void parse_args (gint *argc_p,
71 static void print_blurb (FILE *bout,
75 /* --- variables --- */
76 static FILE *fout = NULL;
77 static GScannerConfig scanner_config_template =
80 " \t\r" /* "\n" is statement delimiter */
81 ) /* cset_skip_characters */,
86 ) /* cset_identifier_first */,
91 ) /* cset_identifier_nth */,
92 ( "#\n" ) /* cpair_comment_single */,
94 FALSE /* case_sensitive */,
96 TRUE /* skip_comment_multi */,
97 TRUE /* skip_comment_single */,
98 TRUE /* scan_comment_multi */,
99 TRUE /* scan_identifier */,
100 FALSE /* scan_identifier_1char */,
101 FALSE /* scan_identifier_NULL */,
102 TRUE /* scan_symbols */,
103 FALSE /* scan_binary */,
104 TRUE /* scan_octal */,
105 TRUE /* scan_float */,
107 FALSE /* scan_hex_dollar */,
108 TRUE /* scan_string_sq */,
109 TRUE /* scan_string_dq */,
110 TRUE /* numbers_2_int */,
111 FALSE /* int_2_float */,
112 FALSE /* identifier_2_string */,
113 TRUE /* char_2_token */,
114 FALSE /* symbol_2_token */,
115 FALSE /* scope_0_fallback */,
117 static gchar *std_marshaller_prefix = "g_cclosure_marshal";
118 static gchar *marshaller_prefix = "g_cclosure_user_marshal";
119 static GHashTable *marshallers = NULL;
120 static gboolean gen_cheader = FALSE;
121 static gboolean gen_cbody = FALSE;
122 static gboolean skip_ploc = FALSE;
123 static gboolean std_includes = TRUE;
126 /* --- functions --- */
128 complete_arg (Argument *arg,
131 static const Argument inout_arguments[] = {
132 /* pname, sname, func, cname */
133 { "VOID", "VOID", NULL, "void", },
134 { "BOOLEAN", "BOOLEAN", "boolean", "gboolean", },
135 { "CHAR", "CHAR", "char", "gchar", },
136 { "UCHAR", "UCHAR", "uchar", "guchar", },
137 { "INT", "INT", "int", "gint", },
138 { "UINT", "UINT", "uint", "guint", },
139 { "LONG", "LONG", "long", "glong", },
140 { "ULONG", "ULONG", "ulong", "gulong", },
141 { "ENUM", "ENUM", "enum", "gint", },
142 { "FLAGS", "FLAGS", "flags", "guint", },
143 { "FLOAT", "FLOAT", "float", "gfloat", },
144 { "DOUBLE", "DOUBLE", "double", "gdouble", },
146 { "NONE", "VOID", NULL, "void", },
147 { "BOOL", "BOOLEAN", "boolean", "gboolean", },
149 static const Argument in_arguments[] = {
150 { "STRING", "POINTER", "as_pointer", "gpointer", },
151 { "BOXED", "POINTER", "as_pointer", "gpointer", },
152 { "POINTER", "POINTER", "as_pointer", "gpointer", },
153 { "PARAM", "POINTER", "as_pointer", "gpointer", },
154 { "OBJECT", "POINTER", "as_pointer", "gpointer", },
156 static const Argument out_arguments[] = {
157 { "STRING", "STRING", "string", "gchar*", },
158 { "BOXED", "BOXED", "boxed", "gpointer", },
159 { "POINTER", "POINTER", "pointer", "gpointer", },
160 { "PARAM", "PARAM", "param", "GParamSpec*", },
161 { "OBJECT", "OBJECT", "object", "GObject*", },
163 const guint n_inout_arguments = sizeof (inout_arguments) / sizeof (inout_arguments[0]);
164 const guint n_out_arguments = sizeof (out_arguments) / sizeof (out_arguments[0]);
165 const guint n_in_arguments = sizeof (in_arguments) / sizeof (in_arguments[0]);
166 const Argument *arguments;
167 guint i, n_arguments;
169 g_return_val_if_fail (arg != NULL, FALSE);
171 arguments = inout_arguments;
172 n_arguments = n_inout_arguments;
173 for (i = 0; i < n_arguments; i++)
174 if (strcmp (arguments[i].pname, arg->pname) == 0)
176 arg->sname = arguments[i].sname;
177 arg->func = arguments[i].func;
178 arg->cname = arguments[i].cname;
182 arguments = is_return ? out_arguments : in_arguments;
183 n_arguments = is_return ? n_out_arguments : n_in_arguments;
184 for (i = 0; i < n_arguments; i++)
185 if (strcmp (arguments[i].pname, arg->pname) == 0)
187 arg->sname = arguments[i].sname;
188 arg->func = arguments[i].func;
189 arg->cname = arguments[i].cname;
198 pad (const gchar *string)
200 #define PAD_LENGTH 12
201 static gchar *buffer = NULL;
204 g_return_val_if_fail (string != NULL, NULL);
207 buffer = g_new (gchar, PAD_LENGTH + 1);
210 if (strlen (string) >= PAD_LENGTH)
213 buffer = g_strdup_printf ("%s ", string);
214 g_warning ("overfull string (%u bytes) for padspace", (guint) strlen (string));
219 for (i = 0; i < PAD_LENGTH; i++)
221 gboolean done = *string == 0;
223 buffer[i] = done ? ' ' : *string++;
231 indent (guint n_spaces)
233 static gchar *buffer;
234 static guint blength = 0;
236 if (blength <= n_spaces)
238 blength = n_spaces + 1;
240 buffer = g_new (gchar, blength);
242 memset (buffer, ' ', n_spaces);
243 buffer[n_spaces] = 0;
249 generate_marshal (const gchar *signame,
254 gchar *tmp = g_strconcat (marshaller_prefix, "_", signame, NULL);
255 gboolean have_std_marshaller = FALSE;
257 /* here we have to make sure a marshaller named <marshaller_prefix>_<signame>
258 * exists. we might have put it out already, can revert to a standard marshaller
259 * provided by glib, or need to generate one.
262 if (g_hash_table_lookup (marshallers, tmp))
264 /* done, marshaller already generated */
270 /* need to alias/generate marshaller, register name */
271 g_hash_table_insert (marshallers, tmp, tmp);
274 /* can we revert to a standard marshaller? */
277 tmp = g_strconcat (std_marshaller_prefix, "_", signame, NULL);
278 have_std_marshaller = g_hash_table_lookup (marshallers, tmp) != NULL;
282 if (gen_cheader && have_std_marshaller)
284 fprintf (fout, "#define %s_%s\t%s_%s\n", marshaller_prefix, signame, std_marshaller_prefix, signame);
286 if (gen_cheader && !have_std_marshaller)
288 ind = fprintf (fout, "extern void ");
289 ind += fprintf (fout, "%s_%s (", marshaller_prefix, signame);
290 fprintf (fout, "GClosure *closure,\n");
291 fprintf (fout, "%sGValue *return_value,\n", indent (ind));
292 fprintf (fout, "%sguint n_param_values,\n", indent (ind));
293 fprintf (fout, "%sconst GValue *param_values,\n", indent (ind));
294 fprintf (fout, "%sgpointer invocation_hint,\n", indent (ind));
295 fprintf (fout, "%sgpointer marshal_data);\n", indent (ind));
297 if (gen_cbody && !have_std_marshaller)
299 /* cfile marhsal header */
300 fprintf (fout, "void\n");
301 ind = fprintf (fout, "%s_%s (", marshaller_prefix, signame);
302 fprintf (fout, "GClosure *closure,\n");
303 fprintf (fout, "%sGValue *return_value,\n", indent (ind));
304 fprintf (fout, "%sguint n_param_values,\n", indent (ind));
305 fprintf (fout, "%sconst GValue *param_values,\n", indent (ind));
306 fprintf (fout, "%sgpointer invocation_hint,\n", indent (ind));
307 fprintf (fout, "%sgpointer marshal_data)\n", indent (ind));
308 fprintf (fout, "{\n");
310 /* cfile GSignalFunc typedef */
311 ind = fprintf (fout, " typedef %s (*GSignalFunc_%s) (", sig->rarg->cname, signame);
312 fprintf (fout, "%s data1,\n", pad ("gpointer"));
313 for (a = 1, node = sig->args; node; node = node->next)
315 Argument *arg = node->data;
318 fprintf (fout, "%s%s arg_%d,\n", indent (ind), pad (arg->cname), a++);
320 fprintf (fout, "%s%s data2);\n", indent (ind), pad ("gpointer"));
322 /* cfile marshal variables */
323 fprintf (fout, " register GSignalFunc_%s callback;\n", signame);
324 fprintf (fout, " register GCClosure *cc = (GCClosure*) closure;\n");
325 fprintf (fout, " register gpointer data1, data2;\n");
327 fprintf (fout, " %s v_return;\n", sig->rarg->cname);
329 if (sig->args || sig->rarg->func)
331 fprintf (fout, "\n");
334 fprintf (fout, " g_return_if_fail (return_value != NULL);\n");
337 for (a = 0, node = sig->args; node; node = node->next)
339 Argument *arg = node->data;
344 fprintf (fout, " g_return_if_fail (n_param_values >= %u);\n", 1 + a);
348 /* cfile marshal data1, data2 and callback setup */
349 fprintf (fout, "\n");
350 fprintf (fout, " if (G_CCLOSURE_SWAP_DATA (closure))\n {\n");
351 fprintf (fout, " data1 = closure->data;\n");
352 fprintf (fout, " data2 = g_value_get_as_pointer (param_values + 0);\n");
353 fprintf (fout, " }\n else\n {\n");
354 fprintf (fout, " data1 = g_value_get_as_pointer (param_values + 0);\n");
355 fprintf (fout, " data2 = closure->data;\n");
356 fprintf (fout, " }\n");
357 fprintf (fout, " callback = (GSignalFunc_%s) (marshal_data ? marshal_data : cc->callback);\n", signame);
359 /* cfile marshal callback action */
360 fprintf (fout, "\n");
361 ind = fprintf (fout, " %s callback (", sig->rarg->func ? " v_return =" : "");
362 fprintf (fout, "data1,\n");
363 for (a = 1, node = sig->args; node; node = node->next)
365 Argument *arg = node->data;
368 fprintf (fout, "%sg_value_get_%s (param_values + %d),\n", indent (ind), arg->func, a++);
370 fprintf (fout, "%sdata2);\n", indent (ind));
372 /* cfile marshal return value storage */
375 fprintf (fout, "\n");
376 fprintf (fout, " g_value_set_%s (return_value, v_return);\n", sig->rarg->func);
379 /* cfile marshal footer */
380 fprintf (fout, "}\n");
385 process_signature (Signature *sig)
387 gchar *pname, *sname, *tmp;
390 /* lookup and complete info on arguments */
391 if (!complete_arg (sig->rarg, TRUE))
393 g_warning ("unknown type: %s", sig->rarg->pname);
396 for (node = sig->args; node; node = node->next)
398 Argument *arg = node->data;
400 if (!complete_arg (arg, FALSE))
402 g_warning ("unknown type: %s", arg->pname);
407 /* construct requested marshaller name and technical marshaller name */
408 pname = g_strconcat (sig->rarg->pname, "_", NULL);
409 sname = g_strconcat (sig->rarg->sname, "_", NULL);
410 for (node = sig->args; node; node = node->next)
412 Argument *arg = node->data;
416 sname = g_strconcat (tmp, "_", arg->sname, NULL);
419 pname = g_strconcat (tmp, "_", arg->pname, NULL);
423 /* introductionary comment */
424 fprintf (fout, "\n/* %s", sig->rarg->pname);
425 for (node = sig->args; node; node = node->next)
427 Argument *arg = node->data;
429 fprintf (fout, "%c%s", node->prev ? ',' : ':', arg->pname);
432 fprintf (fout, " (%s)", sig->ploc);
433 fprintf (fout, " */\n");
435 /* ensure technical marshaller exists (<marshaller_prefix>_<sname>) */
436 generate_marshal (sname, sig);
438 /* put out marshaller alias for requested name if required (<marshaller_prefix>_<pname>) */
439 tmp = g_strconcat (marshaller_prefix, "_", pname, NULL);
440 if (gen_cheader && !g_hash_table_lookup (marshallers, tmp))
442 fprintf (fout, "#define %s_%s\t%s_%s\n", marshaller_prefix, pname, marshaller_prefix, sname);
444 g_hash_table_insert (marshallers, tmp, tmp);
454 new_arg (const gchar *pname)
456 Argument *arg = g_new0 (Argument, 1);
458 arg->pname = g_strdup (pname);
464 parse_line (GScanner *scanner,
467 /* parse identifier for return value */
468 if (g_scanner_get_next_token (scanner) != G_TOKEN_IDENTIFIER)
469 return G_TOKEN_IDENTIFIER;
470 sig->rarg = new_arg (scanner->value.v_identifier);
472 /* keep a note on the location */
473 sig->ploc = g_strdup_printf ("%s:%u", scanner->input_name, scanner->line);
476 if (g_scanner_get_next_token (scanner) != ':')
479 /* parse first argument */
480 if (g_scanner_get_next_token (scanner) != G_TOKEN_IDENTIFIER)
481 return G_TOKEN_IDENTIFIER;
482 sig->args = g_list_append (sig->args, new_arg (scanner->value.v_identifier));
484 /* parse rest of argument list */
485 while (g_scanner_peek_next_token (scanner) == ',')
488 g_scanner_get_next_token (scanner);
490 /* parse arg identifier */
491 if (g_scanner_get_next_token (scanner) != G_TOKEN_IDENTIFIER)
492 return G_TOKEN_IDENTIFIER;
493 sig->args = g_list_append (sig->args, new_arg (scanner->value.v_identifier));
496 /* expect end of line, done */
497 if (g_scanner_get_next_token (scanner) != '\n')
505 string_key_destroy (gpointer key,
518 const gchar *gruntime_marshallers[] = {
519 #include "gmarshal.strings"
522 GSList *slist, *files = NULL;
525 /* parse args and do fast exits */
526 parse_args (&argc, &argv);
528 /* list input files */
529 for (i = 1; i < argc; i++)
530 files = g_slist_prepend (files, argv[i]);
532 files = g_slist_reverse (files);
534 files = g_slist_prepend (files, "/dev/stdin");
536 /* setup auxillary structs */
537 scanner = g_scanner_new (&scanner_config_template);
539 marshallers = g_hash_table_new (g_str_hash, g_str_equal);
541 /* add GRuntime standard marshallers */
543 for (i = 0; i < sizeof (gruntime_marshallers) / sizeof (gruntime_marshallers[0]); i++)
545 gchar *tmp = g_strdup (gruntime_marshallers[i]);
547 g_hash_table_insert (marshallers, tmp, tmp);
550 /* put out initial heading */
551 fprintf (fout, "\n");
555 fprintf (fout, "#include\t<gobject/gmarshal.h>\n\n");
556 fprintf (fout, "#ifdef __cplusplus\nextern \"C\" {\n#endif /* __cplusplus */\n");
559 /* process input files */
560 for (slist = files; slist; slist = slist->next)
562 gchar *file = slist->data;
563 gint fd = open (file, O_RDONLY);
567 g_warning ("failed to open \"%s\": %s", file, g_strerror (errno));
571 /* set file name for error reports */
572 scanner->input_name = file;
574 /* parse & process file */
575 g_scanner_input_file (scanner, fd);
577 /* scanning loop, we parse the input untill it's end is reached,
578 * or our sub routine came across invalid syntax
582 guint expected_token = G_TOKEN_NONE;
584 switch (g_scanner_peek_next_token (scanner))
587 /* eat newline and restart */
588 g_scanner_get_next_token (scanner);
594 /* parse and process signatures */
596 Signature signature = { NULL, NULL, NULL };
599 expected_token = parse_line (scanner, &signature);
601 /* once we got a valid signature, process it */
602 if (expected_token == G_TOKEN_NONE)
603 process_signature (&signature);
605 /* clean up signature contents */
606 g_free (signature.ploc);
608 g_free (signature.rarg->pname);
609 g_free (signature.rarg);
610 for (node = signature.args; node; node = node->next)
612 Argument *arg = node->data;
617 g_list_free (signature.args);
622 /* bail out on errors */
623 if (expected_token != G_TOKEN_NONE)
625 g_scanner_unexp_token (scanner, expected_token, "type name", NULL, NULL, NULL, TRUE);
629 g_scanner_peek_next_token (scanner);
631 while (scanner->next_token != G_TOKEN_EOF);
636 /* put out trailer */
639 fprintf (fout, "\n#ifdef __cplusplus\n}\n#endif /* __cplusplus */\n");
641 fprintf (fout, "\n");
644 g_slist_free (files);
645 g_scanner_destroy (scanner);
646 g_hash_table_foreach_remove (marshallers, string_key_destroy, NULL);
647 g_hash_table_destroy (marshallers);
653 parse_args (gint *argc_p,
656 guint argc = *argc_p;
657 gchar **argv = *argv_p;
660 for (i = 1; i < argc; i++)
662 if (strcmp ("--header", argv[i]) == 0)
667 else if (strcmp ("--body", argv[i]) == 0)
672 else if (strcmp ("--skip-source", argv[i]) == 0)
677 else if (strcmp ("--nostdinc", argv[i]) == 0)
679 std_includes = FALSE;
682 else if (strcmp ("--stdinc", argv[i]) == 0)
687 else if ((strcmp ("--prefix", argv[i]) == 0) ||
688 (strncmp ("--prefix=", argv[i], 9) == 0))
690 gchar *equal = argv[i] + 8;
693 marshaller_prefix = g_strdup (equal + 1);
694 else if (i + 1 < argc)
696 marshaller_prefix = g_strdup (argv[i + 1]);
702 else if (strcmp ("-h", argv[i]) == 0 ||
703 strcmp ("--help", argv[i]) == 0)
705 print_blurb (stderr, TRUE);
709 else if (strcmp ("-v", argv[i]) == 0 ||
710 strcmp ("--version", argv[i]) == 0)
712 print_blurb (stderr, FALSE);
716 else if (strcmp (argv[i], "--g-fatal-warnings") == 0)
718 GLogLevelFlags fatal_mask;
720 fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
721 fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
722 g_log_set_always_fatal (fatal_mask);
729 for (i = 1; i < argc; i++)
747 print_blurb (FILE *bout,
752 fprintf (bout, "%s version ", PRG_NAME);
753 fprintf (bout, "%u.%u.%u", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION);
754 fprintf (bout, "\n");
755 fprintf (bout, "%s comes with ABSOLUTELY NO WARRANTY.\n", PRG_NAME);
756 fprintf (bout, "You may redistribute copies of %s under the terms of\n", PRG_NAME);
757 fprintf (bout, "the GNU General Public License which can be found in the\n");
758 fprintf (bout, "%s source package. Sources, examples and contact\n", PKG_NAME);
759 fprintf (bout, "information are available at %s\n", PKG_HTTP_HOME);
763 fprintf (bout, "Usage: %s [options] [files...]\n", PRG_NAME);
764 fprintf (bout, " --header generate C headers\n");
765 fprintf (bout, " --body generate C code\n");
766 fprintf (bout, " --prefix=string specify marshaller prefix\n");
767 fprintf (bout, " --skip-source skip source location comments\n");
768 fprintf (bout, " --stdinc, --nostdinc include/use GRuntime standard marshallers\n");
769 fprintf (bout, " -h, --help show this help message\n");
770 fprintf (bout, " -v, --version print version informations\n");
771 fprintf (bout, " --g-fatal-warnings make warnings fatal (abort)\n");