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