fixed dealing with collection/lcopy of NULL values.
[platform/upstream/glib.git] / gobject / glib-genmarshal.c
1 /* GLIB-GenMarshal - Marshaller generator for GObject library
2  * Copyright (C) 2000 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
22 /* ok, this is a bit hackish, have to provide gruntime log domain as
23  * we don't link against -lgruntime
24  */
25 char *g_log_domain_gruntime = "GLib-Genmarshal";
26
27 #include        <glib.h>
28
29 #include        <stdio.h>
30 #include        <stdlib.h>
31 #include        <fcntl.h>
32 #include        <string.h>
33 #include        <errno.h>
34 #ifdef HAVE_UNISTD_H
35 #include        <unistd.h>
36 #endif
37 #include        <sys/types.h>
38 #include        <sys/stat.h>
39
40 #ifdef G_OS_WIN32
41 #include <io.h>
42 #endif
43
44 /* --- defines --- */
45 #define PRG_NAME        "glib-genmarshal"
46 #define PKG_NAME        "GLib"
47 #define PKG_HTTP_HOME   "http://www.gtk.org"
48
49
50 /* --- typedefs & structures --- */
51 typedef struct _Argument  Argument;
52 typedef struct _Signature Signature;
53 struct _Argument
54 {
55   gchar       *pname;           /* parsed name */
56   const gchar *sname;           /* signature name */
57   const gchar *func;            /* functional extension */
58   const gchar *cname;           /* C name */
59 };
60 struct _Signature
61 {
62   gchar    *ploc;
63   Argument *rarg;
64   GList    *args;       /* of type Argument* */
65 };
66
67
68 /* --- prototypes --- */
69 static void     parse_args      (gint           *argc_p,
70                                  gchar       ***argv_p);
71 static void     print_blurb     (FILE           *bout,
72                                  gboolean        print_help);
73
74
75 /* --- variables --- */
76 static FILE          *fout = NULL;
77 static GScannerConfig scanner_config_template =
78 {
79   (
80    " \t\r"              /* "\n" is statement delimiter */
81    )                    /* cset_skip_characters */,
82   (
83    G_CSET_a_2_z
84    "_"
85    G_CSET_A_2_Z
86    )                    /* cset_identifier_first */,
87   (
88    G_CSET_a_2_z
89    "_0123456789"
90    G_CSET_A_2_Z
91    )                    /* cset_identifier_nth */,
92   ( "#\n" )             /* cpair_comment_single */,
93
94   FALSE                 /* case_sensitive */,
95
96   TRUE                  /* skip_comment_multi */,
97   TRUE                  /* skip_comment_single */,
98   TRUE                  /* scan_comment_multi */,
99   TRUE                  /* scan_identifier */,
100   FALSE                 /* scan_identifier_1char */,
101   FALSE                 /* scan_identifier_NULL */,
102   TRUE                  /* scan_symbols */,
103   FALSE                 /* scan_binary */,
104   TRUE                  /* scan_octal */,
105   TRUE                  /* scan_float */,
106   TRUE                  /* scan_hex */,
107   FALSE                 /* scan_hex_dollar */,
108   TRUE                  /* scan_string_sq */,
109   TRUE                  /* scan_string_dq */,
110   TRUE                  /* numbers_2_int */,
111   FALSE                 /* int_2_float */,
112   FALSE                 /* identifier_2_string */,
113   TRUE                  /* char_2_token */,
114   FALSE                 /* symbol_2_token */,
115   FALSE                 /* scope_0_fallback */,
116 };
117 static gchar            *std_marshaller_prefix = "g_cclosure_marshal";
118 static gchar            *marshaller_prefix = "g_cclosure_user_marshal";
119 static GHashTable       *marshallers = NULL;
120 static gboolean          gen_cheader = FALSE;
121 static gboolean          gen_cbody = FALSE;
122 static gboolean          skip_ploc = FALSE;
123 static gboolean          std_includes = TRUE;
124
125
126 /* --- functions --- */
127 static gboolean
128 complete_arg (Argument *arg,
129               gboolean  is_return)
130 {
131   static const Argument inout_arguments[] = {
132     /* pname,           sname,          func,                   cname           */
133     { "VOID",           "VOID",         NULL,                   "void",         },
134     { "BOOLEAN",        "BOOLEAN",      "boolean",              "gboolean",     },
135     { "CHAR",           "CHAR",         "char",                 "gchar",        },
136     { "UCHAR",          "UCHAR",        "uchar",                "guchar",       },
137     { "INT",            "INT",          "int",                  "gint",         },
138     { "UINT",           "UINT",         "uint",                 "guint",        },
139     { "LONG",           "LONG",         "long",                 "glong",        },
140     { "ULONG",          "ULONG",        "ulong",                "gulong",       },
141     { "ENUM",           "ENUM",         "enum",                 "gint",         },
142     { "FLAGS",          "FLAGS",        "flags",                "guint",        },
143     { "FLOAT",          "FLOAT",        "float",                "gfloat",       },
144     { "DOUBLE",         "DOUBLE",       "double",               "gdouble",      },
145     /* deprecated: */
146     { "NONE",           "VOID",         NULL,                   "void",         },
147     { "BOOL",           "BOOLEAN",      "boolean",              "gboolean",     },
148   };
149   static const Argument in_arguments[] = {
150     { "STRING",         "POINTER",      "as_pointer",           "gpointer",     },
151     { "BOXED",          "POINTER",      "as_pointer",           "gpointer",     },
152     { "POINTER",        "POINTER",      "as_pointer",           "gpointer",     },
153     { "PARAM",          "POINTER",      "as_pointer",           "gpointer",     },
154     { "OBJECT",         "POINTER",      "as_pointer",           "gpointer",     },
155   };
156   static const Argument out_arguments[] = {
157     { "STRING",         "STRING",       "string",               "gchar*",       },
158     { "BOXED",          "BOXED",        "boxed",                "gpointer",     },
159     { "POINTER",        "POINTER",      "pointer",              "gpointer",     },
160     { "PARAM",          "PARAM",        "param",                "GParamSpec*",  },
161     { "OBJECT",         "OBJECT",       "object",               "GObject*",     },
162   };
163   const guint n_inout_arguments = sizeof (inout_arguments) / sizeof (inout_arguments[0]);
164   const guint n_out_arguments = sizeof (out_arguments) / sizeof (out_arguments[0]);
165   const guint n_in_arguments = sizeof (in_arguments) / sizeof (in_arguments[0]);
166   const Argument *arguments;
167   guint i, n_arguments;
168
169   g_return_val_if_fail (arg != NULL, FALSE);
170
171   arguments = inout_arguments;
172   n_arguments = n_inout_arguments;
173   for (i = 0; i < n_arguments; i++)
174     if (strcmp (arguments[i].pname, arg->pname) == 0)
175       {
176         arg->sname = arguments[i].sname;
177         arg->func = arguments[i].func;
178         arg->cname = arguments[i].cname;
179
180         return TRUE;
181       }
182   arguments = is_return ? out_arguments : in_arguments;
183   n_arguments = is_return ? n_out_arguments : n_in_arguments;
184   for (i = 0; i < n_arguments; i++)
185     if (strcmp (arguments[i].pname, arg->pname) == 0)
186       {
187         arg->sname = arguments[i].sname;
188         arg->func = arguments[i].func;
189         arg->cname = arguments[i].cname;
190
191         return TRUE;
192       }
193
194   return FALSE;
195 }
196
197 static const gchar*
198 pad (const gchar *string)
199 {
200 #define PAD_LENGTH      12
201   static gchar *buffer = NULL;
202   gint i;
203
204   g_return_val_if_fail (string != NULL, NULL);
205
206   if (!buffer)
207     buffer = g_new (gchar, PAD_LENGTH + 1);
208
209   /* paranoid check */
210   if (strlen (string) >= PAD_LENGTH)
211     {
212       g_free (buffer);
213       buffer = g_strdup_printf ("%s ", string);
214       g_warning ("overfull string (%u bytes) for padspace", (guint) strlen (string));
215
216       return buffer;
217     }
218
219   for (i = 0; i < PAD_LENGTH; i++)
220     {
221       gboolean done = *string == 0;
222
223       buffer[i] = done ? ' ' : *string++;
224     }
225   buffer[i] = 0;
226
227   return buffer;
228 }
229
230 static const gchar*
231 indent (guint n_spaces)
232 {
233   static gchar *buffer;
234   static guint blength = 0;
235
236   if (blength <= n_spaces)
237     {
238       blength = n_spaces + 1;
239       g_free (buffer);
240       buffer = g_new (gchar, blength);
241     }
242   memset (buffer, ' ', n_spaces);
243   buffer[n_spaces] = 0;
244
245   return buffer;
246 }
247
248 static void
249 generate_marshal (const gchar *signame,
250                   Signature   *sig)
251 {
252   guint ind, a;
253   GList *node;
254   gchar *tmp = g_strconcat (marshaller_prefix, "_", signame, NULL);
255   gboolean have_std_marshaller = FALSE;
256
257   /* here we have to make sure a marshaller named <marshaller_prefix>_<signame>
258    * exists. we might have put it out already, can revert to a standard marshaller
259    * provided by glib, or need to generate one.
260    */
261
262   if (g_hash_table_lookup (marshallers, tmp))
263     {
264       /* done, marshaller already generated */
265       g_free (tmp);
266       return;
267     }
268   else
269     {
270       /* need to alias/generate marshaller, register name */
271       g_hash_table_insert (marshallers, tmp, tmp);
272     }
273
274   /* can we revert to a standard marshaller? */
275   if (std_includes)
276     {
277       tmp = g_strconcat (std_marshaller_prefix, "_", signame, NULL);
278       have_std_marshaller = g_hash_table_lookup (marshallers, tmp) != NULL;
279       g_free (tmp);
280     }
281
282   if (gen_cheader && have_std_marshaller)
283     {
284       fprintf (fout, "#define %s_%s\t%s_%s\n", marshaller_prefix, signame, std_marshaller_prefix, signame);
285     }
286   if (gen_cheader && !have_std_marshaller)
287     {
288       ind = fprintf (fout, "extern void ");
289       ind += fprintf (fout, "%s_%s (", marshaller_prefix, signame);
290       fprintf (fout,   "GClosure     *closure,\n");
291       fprintf (fout, "%sGValue       *return_value,\n", indent (ind));
292       fprintf (fout, "%sguint         n_param_values,\n", indent (ind));
293       fprintf (fout, "%sconst GValue *param_values,\n", indent (ind));
294       fprintf (fout, "%sgpointer      invocation_hint,\n", indent (ind));
295       fprintf (fout, "%sgpointer      marshal_data);\n", indent (ind));
296     }
297   if (gen_cbody && !have_std_marshaller)
298     {
299       /* cfile marhsal header */
300       fprintf (fout, "void\n");
301       ind = fprintf (fout, "%s_%s (", marshaller_prefix, signame);
302       fprintf (fout,   "GClosure     *closure,\n");
303       fprintf (fout, "%sGValue       *return_value,\n", indent (ind));
304       fprintf (fout, "%sguint         n_param_values,\n", indent (ind));
305       fprintf (fout, "%sconst GValue *param_values,\n", indent (ind));
306       fprintf (fout, "%sgpointer      invocation_hint,\n", indent (ind));
307       fprintf (fout, "%sgpointer      marshal_data)\n", indent (ind));
308       fprintf (fout, "{\n");
309
310       /* cfile GSignalFunc typedef */
311       ind = fprintf (fout, "  typedef %s (*GSignalFunc_%s) (", sig->rarg->cname, signame);
312       fprintf (fout, "%s data1,\n", pad ("gpointer"));
313       for (a = 1, node = sig->args; node; node = node->next)
314         {
315           Argument *arg = node->data;
316
317           if (arg->func)
318             fprintf (fout, "%s%s arg_%d,\n", indent (ind), pad (arg->cname), a++);
319         }
320       fprintf (fout, "%s%s data2);\n", indent (ind), pad ("gpointer"));
321
322       /* cfile marshal variables */
323       fprintf (fout, "  register GSignalFunc_%s callback;\n", signame);
324       fprintf (fout, "  register GCClosure *cc = (GCClosure*) closure;\n");
325       fprintf (fout, "  register gpointer data1, data2;\n");
326       if (sig->rarg->func)
327         fprintf (fout, "  %s v_return;\n", sig->rarg->cname);
328
329       if (sig->args || sig->rarg->func)
330         {
331           fprintf (fout, "\n");
332
333           if (sig->rarg->func)
334             fprintf (fout, "  g_return_if_fail (return_value != NULL);\n");
335           if (sig->args)
336             {
337               for (a = 0, node = sig->args; node; node = node->next)
338                 {
339                   Argument *arg = node->data;
340
341                   if (arg->func)
342                     a++;
343                 }
344               fprintf (fout, "  g_return_if_fail (n_param_values >= %u);\n", 1 + a);
345             }
346         }
347
348       /* cfile marshal data1, data2 and callback setup */
349       fprintf (fout, "\n");
350       fprintf (fout, "  if (G_CCLOSURE_SWAP_DATA (closure))\n    {\n");
351       fprintf (fout, "      data1 = closure->data;\n");
352       fprintf (fout, "      data2 = g_value_get_as_pointer (param_values + 0);\n");
353       fprintf (fout, "    }\n  else\n    {\n");
354       fprintf (fout, "      data1 = g_value_get_as_pointer (param_values + 0);\n");
355       fprintf (fout, "      data2 = closure->data;\n");
356       fprintf (fout, "    }\n");
357       fprintf (fout, "  callback = (GSignalFunc_%s) (marshal_data ? marshal_data : cc->callback);\n", signame);
358
359       /* cfile marshal callback action */
360       fprintf (fout, "\n");
361       ind = fprintf (fout, " %s callback (", sig->rarg->func ? " v_return =" : "");
362       fprintf (fout, "data1,\n");
363       for (a = 1, node = sig->args; node; node = node->next)
364         {
365           Argument *arg = node->data;
366
367           if (arg->func)
368             fprintf (fout, "%sg_value_get_%s (param_values + %d),\n", indent (ind), arg->func, a++);
369         }
370       fprintf (fout, "%sdata2);\n", indent (ind));
371
372       /* cfile marshal return value storage */
373       if (sig->rarg->func)
374         {
375           fprintf (fout, "\n");
376           fprintf (fout, "  g_value_set_%s (return_value, v_return);\n", sig->rarg->func);
377         }
378
379       /* cfile marshal footer */
380       fprintf (fout, "}\n");
381     }
382 }
383
384 static void
385 process_signature (Signature *sig)
386 {
387   gchar *pname, *sname, *tmp;
388   GList *node;
389
390   /* lookup and complete info on arguments */
391   if (!complete_arg (sig->rarg, TRUE))
392     {
393       g_warning ("unknown type: %s", sig->rarg->pname);
394       return;
395     }
396   for (node = sig->args; node; node = node->next)
397     {
398       Argument *arg = node->data;
399
400       if (!complete_arg (arg, FALSE))
401         {
402           g_warning ("unknown type: %s", arg->pname);
403           return;
404         }
405     }
406
407   /* construct requested marshaller name and technical marshaller name */
408   pname = g_strconcat (sig->rarg->pname, "_", NULL);
409   sname = g_strconcat (sig->rarg->sname, "_", NULL);
410   for (node = sig->args; node; node = node->next)
411     {
412       Argument *arg = node->data;
413       gchar *tmp;
414
415       tmp = sname;
416       sname = g_strconcat (tmp, "_", arg->sname, NULL);
417       g_free (tmp);
418       tmp = pname;
419       pname = g_strconcat (tmp, "_", arg->pname, NULL);
420       g_free (tmp);
421     }
422
423   /* introductionary comment */
424   fprintf (fout, "\n/* %s", sig->rarg->pname);
425   for (node = sig->args; node; node = node->next)
426     {
427       Argument *arg = node->data;
428
429       fprintf (fout, "%c%s", node->prev ? ',' : ':', arg->pname);
430     }
431   if (!skip_ploc)
432     fprintf (fout, " (%s)", sig->ploc);
433   fprintf (fout, " */\n");
434
435   /* ensure technical marshaller exists (<marshaller_prefix>_<sname>) */
436   generate_marshal (sname, sig);
437
438   /* put out marshaller alias for requested name if required (<marshaller_prefix>_<pname>) */
439   tmp = g_strconcat (marshaller_prefix, "_", pname, NULL);
440   if (gen_cheader && !g_hash_table_lookup (marshallers, tmp))
441     {
442       fprintf (fout, "#define %s_%s\t%s_%s\n", marshaller_prefix, pname, marshaller_prefix, sname);
443
444       g_hash_table_insert (marshallers, tmp, tmp);
445     }
446   else
447     g_free (tmp);
448
449   g_free (pname);
450   g_free (sname);
451 }
452
453 static Argument*
454 new_arg (const gchar *pname)
455 {
456   Argument *arg = g_new0 (Argument, 1);
457
458   arg->pname = g_strdup (pname);
459
460   return arg;
461 }
462
463 static guint
464 parse_line (GScanner  *scanner,
465             Signature *sig)
466 {
467   /* parse identifier for return value */
468   if (g_scanner_get_next_token (scanner) != G_TOKEN_IDENTIFIER)
469     return G_TOKEN_IDENTIFIER;
470   sig->rarg = new_arg (scanner->value.v_identifier);
471
472   /* keep a note on the location */
473   sig->ploc = g_strdup_printf ("%s:%u", scanner->input_name, scanner->line);
474
475   /* expect ':' */
476   if (g_scanner_get_next_token (scanner) != ':')
477     return ':';
478
479   /* parse first argument */
480   if (g_scanner_get_next_token (scanner) != G_TOKEN_IDENTIFIER)
481     return G_TOKEN_IDENTIFIER;
482   sig->args = g_list_append (sig->args, new_arg (scanner->value.v_identifier));
483
484   /* parse rest of argument list */
485   while (g_scanner_peek_next_token (scanner) == ',')
486     {
487       /* eat comma */
488       g_scanner_get_next_token (scanner);
489
490       /* parse arg identifier */
491       if (g_scanner_get_next_token (scanner) != G_TOKEN_IDENTIFIER)
492         return G_TOKEN_IDENTIFIER;
493       sig->args = g_list_append (sig->args, new_arg (scanner->value.v_identifier));
494     }
495   
496   /* expect end of line, done */
497   if (g_scanner_get_next_token (scanner) != '\n')
498     return '\n';
499   
500   /* success */
501   return G_TOKEN_NONE;
502 }
503
504 static gboolean
505 string_key_destroy (gpointer key,
506                     gpointer value,
507                     gpointer user_data)
508 {
509   g_free (key);
510
511   return TRUE;
512 }
513
514 int
515 main (int   argc,
516       char *argv[])
517 {
518   const gchar *gruntime_marshallers[] = {
519 #include        "gmarshal.strings"
520   };
521   GScanner *scanner;
522   GSList *slist, *files = NULL;
523   gint i;
524
525   /* parse args and do fast exits */
526   parse_args (&argc, &argv);
527
528   /* list input files */
529   for (i = 1; i < argc; i++)
530     files = g_slist_prepend (files, argv[i]);
531   if (files)
532     files = g_slist_reverse (files);
533   else
534     files = g_slist_prepend (files, "/dev/stdin");
535
536   /* setup auxillary structs */
537   scanner = g_scanner_new (&scanner_config_template);
538   fout = stdout;
539   marshallers = g_hash_table_new (g_str_hash, g_str_equal);
540
541   /* add GRuntime standard marshallers */
542   if (std_includes)
543     for (i = 0; i < sizeof (gruntime_marshallers) / sizeof (gruntime_marshallers[0]); i++)
544       {
545         gchar *tmp = g_strdup (gruntime_marshallers[i]);
546         
547         g_hash_table_insert (marshallers, tmp, tmp);
548       }
549
550   /* put out initial heading */
551   fprintf (fout, "\n");
552   if (gen_cheader)
553     {
554       if (std_includes)
555         fprintf (fout, "#include\t<gobject/gmarshal.h>\n\n");
556       fprintf (fout, "#ifdef __cplusplus\nextern \"C\" {\n#endif /* __cplusplus */\n");
557     }
558
559   /* process input files */
560   for (slist = files; slist; slist = slist->next)
561     {
562       gchar *file = slist->data;
563       gint fd = open (file, O_RDONLY);
564
565       if (fd < 0)
566         {
567           g_warning ("failed to open \"%s\": %s", file, g_strerror (errno));
568           continue;
569         }
570
571       /* set file name for error reports */
572       scanner->input_name = file;
573
574       /* parse & process file */
575       g_scanner_input_file (scanner, fd);
576       
577       /* scanning loop, we parse the input untill it's end is reached,
578        * or our sub routine came across invalid syntax
579        */
580       do
581         {
582           guint expected_token = G_TOKEN_NONE;
583
584           switch (g_scanner_peek_next_token (scanner))
585             {
586             case '\n':
587               /* eat newline and restart */
588               g_scanner_get_next_token (scanner);
589               continue;
590             case G_TOKEN_EOF:
591               /* done */
592               break;
593             default:
594               /* parse and process signatures */
595               {
596                 Signature signature = { NULL, NULL, NULL };
597                 GList *node;
598
599                 expected_token = parse_line (scanner, &signature);
600                 
601                 /* once we got a valid signature, process it */
602                 if (expected_token == G_TOKEN_NONE)
603                   process_signature (&signature);
604                 
605                 /* clean up signature contents */
606                 g_free (signature.ploc);
607                 if (signature.rarg)
608                   g_free (signature.rarg->pname);
609                 g_free (signature.rarg);
610                 for (node = signature.args; node; node = node->next)
611                   {
612                     Argument *arg = node->data;
613                     
614                     g_free (arg->pname);
615                     g_free (arg);
616                   }
617                 g_list_free (signature.args);
618               }
619               break;
620             }
621
622           /* bail out on errors */
623           if (expected_token != G_TOKEN_NONE)
624             {
625               g_scanner_unexp_token (scanner, expected_token, "type name", NULL, NULL, NULL, TRUE);
626               break;
627             }
628
629           g_scanner_peek_next_token (scanner);
630         }
631       while (scanner->next_token != G_TOKEN_EOF);
632
633       close (fd);
634     }
635
636   /* put out trailer */
637   if (gen_cheader)
638     {
639       fprintf (fout, "\n#ifdef __cplusplus\n}\n#endif /* __cplusplus */\n");
640     }
641   fprintf (fout, "\n");
642
643   /* clean up */
644   g_slist_free (files);
645   g_scanner_destroy (scanner);
646   g_hash_table_foreach_remove (marshallers, string_key_destroy, NULL);
647   g_hash_table_destroy (marshallers);
648
649   return 0;
650 }
651
652 static void
653 parse_args (gint    *argc_p,
654             gchar ***argv_p)
655 {
656   guint argc = *argc_p;
657   gchar **argv = *argv_p;
658   guint i, e;
659   
660   for (i = 1; i < argc; i++)
661     {
662       if (strcmp ("--header", argv[i]) == 0)
663         {
664           gen_cheader = TRUE;
665           argv[i] = NULL;
666         }
667       else if (strcmp ("--body", argv[i]) == 0)
668         {
669           gen_cbody = TRUE;
670           argv[i] = NULL;
671         }
672       else if (strcmp ("--skip-source", argv[i]) == 0)
673         {
674           skip_ploc = TRUE;
675           argv[i] = NULL;
676         }
677       else if (strcmp ("--nostdinc", argv[i]) == 0)
678         {
679           std_includes = FALSE;
680           argv[i] = NULL;
681         }
682       else if (strcmp ("--stdinc", argv[i]) == 0)
683         {
684           std_includes = TRUE;
685           argv[i] = NULL;
686         }
687       else if ((strcmp ("--prefix", argv[i]) == 0) ||
688                (strncmp ("--prefix=", argv[i], 9) == 0))
689         {
690           gchar *equal = argv[i] + 8;
691
692           if (*equal == '=')
693             marshaller_prefix = g_strdup (equal + 1);
694           else if (i + 1 < argc)
695             {
696               marshaller_prefix = g_strdup (argv[i + 1]);
697               argv[i] = NULL;
698               i += 1;
699             }
700           argv[i] = NULL;
701         }
702       else if (strcmp ("-h", argv[i]) == 0 ||
703           strcmp ("--help", argv[i]) == 0)
704         {
705           print_blurb (stderr, TRUE);
706           argv[i] = NULL;
707           exit (0);
708         }
709       else if (strcmp ("-v", argv[i]) == 0 ||
710                strcmp ("--version", argv[i]) == 0)
711         {
712           print_blurb (stderr, FALSE);
713           argv[i] = NULL;
714           exit (0);
715         }
716       else if (strcmp (argv[i], "--g-fatal-warnings") == 0)
717         {
718           GLogLevelFlags fatal_mask;
719           
720           fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
721           fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
722           g_log_set_always_fatal (fatal_mask);
723           
724           argv[i] = NULL;
725         }
726     }
727   
728   e = 0;
729   for (i = 1; i < argc; i++)
730     {
731       if (e)
732         {
733           if (argv[i])
734             {
735               argv[e++] = argv[i];
736               argv[i] = NULL;
737             }
738         }
739       else if (!argv[i])
740         e = i;
741     }
742   if (e)
743     *argc_p = e;
744 }
745
746 static void
747 print_blurb (FILE    *bout,
748              gboolean print_help)
749 {
750   if (!print_help)
751     {
752       fprintf (bout, "%s version ", PRG_NAME);
753       fprintf (bout, "%u.%u.%u", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION);
754       fprintf (bout, "\n");
755       fprintf (bout, "%s comes with ABSOLUTELY NO WARRANTY.\n", PRG_NAME);
756       fprintf (bout, "You may redistribute copies of %s under the terms of\n", PRG_NAME);
757       fprintf (bout, "the GNU General Public License which can be found in the\n");
758       fprintf (bout, "%s source package. Sources, examples and contact\n", PKG_NAME);
759       fprintf (bout, "information are available at %s\n", PKG_HTTP_HOME);
760     }
761   else
762     {
763       fprintf (bout, "Usage: %s [options] [files...]\n", PRG_NAME);
764       fprintf (bout, "  --header                   generate C headers\n");
765       fprintf (bout, "  --body                     generate C code\n");
766       fprintf (bout, "  --prefix=string            specify marshaller prefix\n");
767       fprintf (bout, "  --skip-source              skip source location comments\n");
768       fprintf (bout, "  --stdinc, --nostdinc       include/use GRuntime standard marshallers\n");
769       fprintf (bout, "  -h, --help                 show this help message\n");
770       fprintf (bout, "  -v, --version              print version informations\n");
771       fprintf (bout, "  --g-fatal-warnings         make warnings fatal (abort)\n");
772     }
773 }