|
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 * const 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 < G_N_ELEMENTS (gobject_marshallers); 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 } |