source: trunk/third/glib2/gobject/glib-genmarshal.c @ 20721

Revision 20721, 27.1 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20720, which included commits to RCS files with non-trunk default branches.
Line 
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 --- */
47typedef 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;
54typedef 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;
61typedef struct
62{
63  gchar       *ploc;
64  OutArgument *rarg;
65  GList       *args;    /* of type InArgument* */
66} Signature;
67
68
69/* --- prototypes --- */
70static void     parse_args      (gint           *argc_p,
71                                 gchar       ***argv_p);
72static void     print_blurb     (FILE           *bout,
73                                 gboolean        print_help);
74
75
76/* --- variables --- */
77static FILE          *fout = NULL;
78static 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};
118static gchar            *std_marshaller_prefix = "g_cclosure_marshal";
119static gchar            *marshaller_prefix = "g_cclosure_user_marshal";
120static GHashTable       *marshallers = NULL;
121static gboolean          gen_cheader = FALSE;
122static gboolean          gen_cbody = FALSE;
123static gboolean          skip_ploc = FALSE;
124static gboolean          std_includes = TRUE;
125
126
127/* --- functions --- */
128static void
129put_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
178static gboolean
179complete_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
223static gboolean
224complete_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
268static const gchar*
269pad (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
301static const gchar*
302indent (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
319static void
320generate_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
455static void
456process_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
524static InArgument*
525new_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
534static OutArgument*
535new_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
544static guint
545parse_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
585static gboolean
586string_key_destroy (gpointer key,
587                    gpointer value,
588                    gpointer user_data)
589{
590  g_free (key);
591
592  return TRUE;
593}
594
595int
596main (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
749static void
750parse_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
843static void
844print_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}
Note: See TracBrowser for help on using the repository browser.