vargars: cleanup varargs handling
[gtk-doc.git] / gtkdoc-scangobj.in
blob8090c7d8c1eb10daa821908c9303ae83d35915aa
1 #!@PERL@ -w
2 # -*- cperl -*-
4 # gtk-doc - GTK DocBook documentation generator.
5 # Copyright (C) 1998  Damon Chaplin
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 2 of the License, or
10 # (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with this program; if not, write to the Free Software
19 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 # This gets information about object hierarchies and signals
24 # by compiling a small C program. CFLAGS and LDFLAGS must be
25 # set appropriately before running this script.
28 use Getopt::Long;
30 push @INC, '@PACKAGE_DATA_DIR@';
31 require "gtkdoc-common.pl";
33 # Options
35 # name of documentation module
36 my $MODULE;
37 my $OUTPUT_DIR;
38 my $VERBOSE;
39 my $PRINT_VERSION;
40 my $PRINT_HELP;
41 my $TYPE_INIT_FUNC="g_type_init(); g_type_class_ref(G_TYPE_OBJECT)";
42 my $QUERY_CHILD_PROPERTIES;
44 # --nogtkinit is deprecated, as it is the default now anyway.
45 %optctl = (module => \$MODULE,
46            types => \$TYPES_FILE,
47            nogtkinit => \$NO_GTK_INIT,
48            'type-init-func' => \$TYPE_INIT_FUNC,
49            'query-child-properties' => \$QUERY_CHILD_PROPERTIES,
50            'output-dir' => \$OUTPUT_DIR,
51            'verbose' => \$VERBOSE,
52            'version' => \$PRINT_VERSION,
53            'help' => \$PRINT_HELP);
55 GetOptions(\%optctl, "module=s", "types:s", "output-dir:s", "nogtkinit", "type-init-func:s", "query-child-properties:s", "verbose", "version", "help");
57 if ($NO_GTK_INIT) {
58   # Do nothing. This just avoids a warning.
59   # the option is not used anymore
62 if ($PRINT_VERSION) {
63     print "@VERSION@\n";
64     exit 0;
67 if (!$MODULE) {
68     $PRINT_HELP = 1;
71 if ($PRINT_HELP) {
72     print <<EOF;
73 gtkdoc-scangobj version @VERSION@ - introspect g-objects
75 --module=MODULE_NAME          Name of the doc module being parsed
76 --types=FILE                  The name of the file to store the types in
77 --type-init-func=FUNC         The init function to call instead of g_type_init()
78 --query-child-properties=FUNC A function that returns a list of child
79                               properties for a class
80 --output-dir=DIRNAME          The directory where the results are stored
81 --verbose                     Print extra output while processing
82 --version                     Print the version of this program
83 --help                        Print this help
84 EOF
85     exit 0;
88 $OUTPUT_DIR = $OUTPUT_DIR ? $OUTPUT_DIR : ".";
90 $TYPES_FILE = $TYPES_FILE ? $TYPES_FILE : "$OUTPUT_DIR/$MODULE.types";
92 open (TYPES, $TYPES_FILE) || die "Cannot open $TYPES_FILE: $!\n";
93 open (OUTPUT, ">$MODULE-scan.c") || die "Cannot open $MODULE-scan.c: $!\n";
95 my $old_signals_filename = "$OUTPUT_DIR/$MODULE.signals";
96 my $new_signals_filename = "$OUTPUT_DIR/$MODULE.signals.new";
97 my $old_hierarchy_filename = "$OUTPUT_DIR/$MODULE.hierarchy";
98 my $new_hierarchy_filename = "$OUTPUT_DIR/$MODULE.hierarchy.new";
99 my $old_interfaces_filename = "$OUTPUT_DIR/$MODULE.interfaces";
100 my $new_interfaces_filename = "$OUTPUT_DIR/$MODULE.interfaces.new";
101 my $old_prerequisites_filename = "$OUTPUT_DIR/$MODULE.prerequisites";
102 my $new_prerequisites_filename = "$OUTPUT_DIR/$MODULE.prerequisites.new";
103 my $old_args_filename = "$OUTPUT_DIR/$MODULE.args";
104 my $new_args_filename = "$OUTPUT_DIR/$MODULE.args.new";
106 # write a C program to scan the types
108 $includes = "";
109 @types = ();
111 for (<TYPES>) {
112     if (/^#include/) {
113         $includes .= $_;
114     } elsif (/^gnome_keyring_item_info_get_type$/) {
115         # HACK: This isn't really a GObject type so skip it.
116         next;
117     } elsif (/^%/) {
118         next;
119     } elsif (/^\s*$/) {
120         next;
121     } else {
122         chomp;
123         push @types, $_;
124     }
127 $ntypes = @types + 1;
129 print OUTPUT <<EOT;
130 #include <string.h>
131 #include <stdlib.h>
132 #include <stdio.h>
133 #include <errno.h>
134 #include <glib-object.h>
138 if ($includes) {
139     print OUTPUT $includes;
140 } else {
141     for (@types) {
142         print OUTPUT "extern GType $_ (void);\n";
143     }
146 if ($QUERY_CHILD_PROPERTIES) {
147   print OUTPUT <<EOT;
148 extern GParamSpec** $QUERY_CHILD_PROPERTIES (gpointer class, guint *n_properties);
152 print OUTPUT <<EOT;
154 #ifdef GTK_IS_WIDGET_CLASS
155 #include <gtk/gtk.h>
156 #endif
157 GType object_types[$ntypes];
159 static GType *
160 get_object_types (void)
162     gpointer g_object_class;
163     gint i = 0;
166 for (@types) {
167     print OUTPUT "    object_types[i++] = $_ ();\n";
170 print OUTPUT <<EOT;
171     object_types[i] = 0;
173     /* reference the GObjectClass to initialize the param spec pool
174      * potentially needed by interfaces. See http://bugs.gnome.org/571820 */
175     g_object_class = g_type_class_ref (G_TYPE_OBJECT);
177     /* Need to make sure all the types are loaded in and initialize
178      * their signals and properties.
179      */
180     for (i=0; object_types[i]; i++)
181       {
182         if (G_TYPE_IS_CLASSED (object_types[i]))
183           g_type_class_ref (object_types[i]);
184         if (G_TYPE_IS_INTERFACE (object_types[i]))
185           g_type_default_interface_ref (object_types[i]);
186       }
188     g_type_class_unref (g_object_class);
190     return object_types;
194  * This uses GObject type functions to output signal prototypes and the object
195  * hierarchy.
196  */
198 /* The output files */
199 const gchar *signals_filename = "$new_signals_filename";
200 const gchar *hierarchy_filename = "$new_hierarchy_filename";
201 const gchar *interfaces_filename = "$new_interfaces_filename";
202 const gchar *prerequisites_filename = "$new_prerequisites_filename";
203 const gchar *args_filename = "$new_args_filename";
206 static void output_signals (void);
207 static void output_object_signals (FILE *fp,
208                                    GType object_type);
209 static void output_object_signal (FILE *fp,
210                                   const gchar *object_class_name,
211                                   guint signal_id);
212 static const gchar * get_type_name (GType type,
213                                     gboolean * is_pointer);
214 static void output_object_hierarchy (void);
215 static void output_hierarchy (FILE *fp,
216                               GType type,
217                               guint level);
219 static void output_object_interfaces (void);
220 static void output_interfaces (FILE *fp,
221                                GType type);
223 static void output_interface_prerequisites (void);
224 static void output_prerequisites (FILE *fp,
225                                   GType type);
227 static void output_args (void);
228 static void output_object_args (FILE *fp, GType object_type);
231 main (int argc, char *argv[])
233   $TYPE_INIT_FUNC;
235   get_object_types ();
237   output_signals ();
238   output_object_hierarchy ();
239   output_object_interfaces ();
240   output_interface_prerequisites ();
241   output_args ();
243   return 0;
247 static void
248 output_signals (void)
250   FILE *fp;
251   gint i;
253   fp = fopen (signals_filename, "w");
254   if (fp == NULL)
255     {
256       g_warning ("Couldn't open output file: %s : %s", signals_filename, g_strerror(errno));
257       return;
258     }
260   for (i = 0; object_types[i]; i++)
261     output_object_signals (fp, object_types[i]);
263   fclose (fp);
266 static gint
267 compare_signals (const void *a, const void *b)
269   const guint *signal_a = a;
270   const guint *signal_b = b;
272   return strcmp (g_signal_name (*signal_a), g_signal_name (*signal_b));
275 /* This outputs all the signals of one object. */
276 static void
277 output_object_signals (FILE *fp, GType object_type)
279   const gchar *object_class_name;
280   guint *signals, n_signals;
281   guint sig;
283   if (G_TYPE_IS_INSTANTIATABLE (object_type) ||
284       G_TYPE_IS_INTERFACE (object_type))
285     {
287       object_class_name = g_type_name (object_type);
289       signals = g_signal_list_ids (object_type, &n_signals);
290       qsort (signals, n_signals, sizeof (guint), compare_signals);
292       for (sig = 0; sig < n_signals; sig++)
293         {
294            output_object_signal (fp, object_class_name, signals[sig]);
295         }
296       g_free (signals);
297    }
301 /* This outputs one signal. */
302 static void
303 output_object_signal (FILE *fp,
304                       const gchar *object_name,
305                       guint signal_id)
307   GSignalQuery query_info;
308   const gchar *type_name, *ret_type, *object_arg, *arg_name;
309   gchar *pos, *object_arg_lower;
310   gboolean is_pointer;
311   gchar buffer[1024];
312   guint i, param;
313   gint param_num, widget_num, event_num, callback_num;
314   gint *arg_num;
315   gchar signal_name[128];
316   gchar flags[16];
318   /*  g_print ("Object: %s Signal: %u\\n", object_name, signal_id);*/
320   param_num = 1;
321   widget_num = event_num = callback_num = 0;
323   g_signal_query (signal_id, &query_info);
325   /* Output the signal object type and the argument name. We assume the
326      type is a pointer - I think that is OK. We remove "Gtk" or "Gnome" and
327      convert to lower case for the argument name. */
328   pos = buffer;
329   sprintf (pos, "%s ", object_name);
330   pos += strlen (pos);
332   /* Try to come up with a sensible variable name for the first arg
333    * It chops off 2 know prefixes :/ and makes the name lowercase
334    * It should replace lowercase -> uppercase with '_'
335    * GFileMonitor -> file_monitor
336    * GIOExtensionPoint -> extension_point
337    * GtkTreeView -> tree_view
338    * if 2nd char is upper case too
339    *   search for first lower case and go back one char
340    * else
341    *   search for next upper case
342    */
343   if (!strncmp (object_name, "Gtk", 3))
344       object_arg = object_name + 3;
345   else if (!strncmp (object_name, "Gnome", 5))
346       object_arg = object_name + 5;
347   else
348       object_arg = object_name;
350   object_arg_lower = g_ascii_strdown (object_arg, -1);
351   sprintf (pos, "*%s\\n", object_arg_lower);
352   pos += strlen (pos);
353   if (!strncmp (object_arg_lower, "widget", 6))
354     widget_num = 2;
355   g_free(object_arg_lower);
357   /* Convert signal name to use underscores rather than dashes '-'. */
358   strncpy (signal_name, query_info.signal_name, 127);
359   signal_name[127] = '\\0';
360   for (i = 0; signal_name[i]; i++)
361     {
362       if (signal_name[i] == '-')
363         signal_name[i] = '_';
364     }
366   /* Output the signal parameters. */
367   for (param = 0; param < query_info.n_params; param++)
368     {
369       type_name = get_type_name (query_info.param_types[param] & ~G_SIGNAL_TYPE_STATIC_SCOPE, &is_pointer);
371       /* Most arguments to the callback are called "arg1", "arg2", etc.
372          GtkWidgets are called "widget", "widget2", ...
373          GtkCallbacks are called "callback", "callback2", ... */
374       if (!strcmp (type_name, "GtkWidget"))
375         {
376           arg_name = "widget";
377           arg_num = &widget_num;
378         }
379       else if (!strcmp (type_name, "GtkCallback")
380                || !strcmp (type_name, "GtkCCallback"))
381         {
382           arg_name = "callback";
383           arg_num = &callback_num;
384         }
385       else
386         {
387           arg_name = "arg";
388           arg_num = &param_num;
389         }
390       sprintf (pos, "%s ", type_name);
391       pos += strlen (pos);
393       if (!arg_num || *arg_num == 0)
394         sprintf (pos, "%s%s\\n", is_pointer ? "*" : " ", arg_name);
395       else
396         sprintf (pos, "%s%s%i\\n", is_pointer ? "*" : " ", arg_name,
397                  *arg_num);
398       pos += strlen (pos);
400       if (arg_num)
401         {
402           if (*arg_num == 0)
403             *arg_num = 2;
404           else
405             *arg_num += 1;
406         }
407     }
409   pos = flags;
410   /* We use one-character flags for simplicity. */
411   if (query_info.signal_flags & G_SIGNAL_RUN_FIRST)
412     *pos++ = 'f';
413   if (query_info.signal_flags & G_SIGNAL_RUN_LAST)
414     *pos++ = 'l';
415   if (query_info.signal_flags & G_SIGNAL_RUN_CLEANUP)
416     *pos++ = 'c';
417   if (query_info.signal_flags & G_SIGNAL_NO_RECURSE)
418     *pos++ = 'r';
419   if (query_info.signal_flags & G_SIGNAL_DETAILED)
420     *pos++ = 'd';
421   if (query_info.signal_flags & G_SIGNAL_ACTION)
422     *pos++ = 'a';
423   if (query_info.signal_flags & G_SIGNAL_NO_HOOKS)
424     *pos++ = 'h';
425   *pos = 0;
427   /* Output the return type and function name. */
428   ret_type = get_type_name (query_info.return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE, &is_pointer);
430   fprintf (fp,
431            "<SIGNAL>\\n<NAME>%s::%s</NAME>\\n<RETURNS>%s%s</RETURNS>\\n<FLAGS>%s</FLAGS>\\n%s</SIGNAL>\\n\\n",
432            object_name, query_info.signal_name, ret_type, is_pointer ? "*" : "", flags, buffer);
436 /* Returns the type name to use for a signal argument or return value, given
437    the GtkType from the signal info. It also sets is_pointer to TRUE if the
438    argument needs a '*' since it is a pointer. */
439 static const gchar *
440 get_type_name (GType type, gboolean * is_pointer)
442   const gchar *type_name;
444   *is_pointer = FALSE;
445   type_name = g_type_name (type);
447   switch (type) {
448   case G_TYPE_NONE:
449   case G_TYPE_CHAR:
450   case G_TYPE_UCHAR:
451   case G_TYPE_BOOLEAN:
452   case G_TYPE_INT:
453   case G_TYPE_UINT:
454   case G_TYPE_LONG:
455   case G_TYPE_ULONG:
456   case G_TYPE_FLOAT:
457   case G_TYPE_DOUBLE:
458   case G_TYPE_POINTER:
459     /* These all have normal C type names so they are OK. */
460     return type_name;
462   case G_TYPE_STRING:
463     /* A GtkString is really a gchar*. */
464     *is_pointer = TRUE;
465     return "gchar";
467   case G_TYPE_ENUM:
468   case G_TYPE_FLAGS:
469     /* We use a gint for both of these. Hopefully a subtype with a decent
470        name will be registered and used instead, as GTK+ does itself. */
471     return "gint";
473   case G_TYPE_BOXED:
474     /* The boxed type shouldn't be used itself, only subtypes. Though we
475        return 'gpointer' just in case. */
476     return "gpointer";
478   case G_TYPE_PARAM:
479     /* A GParam is really a GParamSpec*. */
480     *is_pointer = TRUE;
481     return "GParamSpec";
483 #if GLIB_CHECK_VERSION (2, 25, 9)
484   case G_TYPE_VARIANT:
485     *is_pointer = TRUE;
486     return "GVariant";
487 #endif
489 default:
490     break;
491   }
493   /* For all GObject subclasses we can use the class name with a "*",
494      e.g. 'GtkWidget *'. */
495   if (g_type_is_a (type, G_TYPE_OBJECT))
496     *is_pointer = TRUE;
498   /* Also catch non GObject root types */
499   if (G_TYPE_IS_CLASSED (type))
500     *is_pointer = TRUE;
502   /* All boxed subtypes will be pointers as well. */
503   /* Exception: GStrv */
504   if (g_type_is_a (type, G_TYPE_BOXED) &&
505       !g_type_is_a (type, G_TYPE_STRV))
506     *is_pointer = TRUE;
508   /* All pointer subtypes will be pointers as well. */
509   if (g_type_is_a (type, G_TYPE_POINTER))
510     *is_pointer = TRUE;
512   /* But enums are not */
513   if (g_type_is_a (type, G_TYPE_ENUM) ||
514       g_type_is_a (type, G_TYPE_FLAGS))
515     *is_pointer = FALSE;
517   return type_name;
521 /* This outputs the hierarchy of all objects which have been initialized,
522    i.e. by calling their XXX_get_type() initialization function. */
523 static void
524 output_object_hierarchy (void)
526   FILE *fp;
527   gint i,j;
528   GType root, type;
529   GType root_types[$ntypes] = { G_TYPE_INVALID, };
531   fp = fopen (hierarchy_filename, "w");
532   if (fp == NULL)
533     {
534       g_warning ("Couldn't open output file: %s : %s", hierarchy_filename, g_strerror(errno));
535       return;
536     }
537   output_hierarchy (fp, G_TYPE_OBJECT, 0);
538   output_hierarchy (fp, G_TYPE_INTERFACE, 0);
540   for (i=0; object_types[i]; i++) {
541     root = object_types[i];
542     while ((type = g_type_parent (root))) {
543       root = type;
544     }
545     if ((root != G_TYPE_OBJECT) && (root != G_TYPE_INTERFACE)) {
546       for (j=0; root_types[j]; j++) {
547         if (root == root_types[j]) {
548           root = G_TYPE_INVALID; break;
549         }
550       }
551       if(root) {
552         root_types[j] = root;
553         output_hierarchy (fp, root, 0);
554       }
555     }
556   }
558   fclose (fp);
561 /* This is called recursively to output the hierarchy of a object. */
562 static void
563 output_hierarchy (FILE  *fp,
564                   GType  type,
565                   guint   level)
567   guint i;
568   GType *children;
569   guint n_children;
571   if (!type)
572     return;
574   for (i = 0; i < level; i++)
575     fprintf (fp, "  ");
576   fprintf (fp, "%s\\n", g_type_name (type));
578   children = g_type_children (type, &n_children);
580   for (i=0; i < n_children; i++)
581     output_hierarchy (fp, children[i], level + 1);
583   g_free (children);
586 static void output_object_interfaces (void)
588   guint i;
589   FILE *fp;
591   fp = fopen (interfaces_filename, "w");
592   if (fp == NULL)
593     {
594       g_warning ("Couldn't open output file: %s : %s", interfaces_filename, g_strerror(errno));
595       return;
596     }
597   output_interfaces (fp, G_TYPE_OBJECT);
599   for (i = 0; object_types[i]; i++)
600     {
601       if (!g_type_parent (object_types[i]) &&
602           (object_types[i] != G_TYPE_OBJECT) &&
603           G_TYPE_IS_INSTANTIATABLE (object_types[i]))
604         {
605           output_interfaces (fp, object_types[i]);
606         }
607     }
608   fclose (fp);
611 static void
612 output_interfaces (FILE  *fp,
613                    GType  type)
615   guint i;
616   GType *children, *interfaces;
617   guint n_children, n_interfaces;
619   if (!type)
620     return;
622   interfaces = g_type_interfaces (type, &n_interfaces);
624   if (n_interfaces > 0)
625     {
626       fprintf (fp, "%s", g_type_name (type));
627       for (i=0; i < n_interfaces; i++)
628           fprintf (fp, " %s", g_type_name (interfaces[i]));
629       fprintf (fp, "\\n");
630      }
631   g_free (interfaces);
633   children = g_type_children (type, &n_children);
635   for (i=0; i < n_children; i++)
636     output_interfaces (fp, children[i]);
638   g_free (children);
641 static void output_interface_prerequisites (void)
643   FILE *fp;
645   fp = fopen (prerequisites_filename, "w");
646   if (fp == NULL)
647     {
648       g_warning ("Couldn't open output file: %s : %s", prerequisites_filename, g_strerror(errno));
649       return;
650     }
651   output_prerequisites (fp, G_TYPE_INTERFACE);
652   fclose (fp);
655 static void
656 output_prerequisites (FILE  *fp,
657                       GType  type)
659 #if GLIB_CHECK_VERSION(2,1,0)
660   guint i;
661   GType *children, *prerequisites;
662   guint n_children, n_prerequisites;
664   if (!type)
665     return;
667   prerequisites = g_type_interface_prerequisites (type, &n_prerequisites);
669   if (n_prerequisites > 0)
670     {
671       fprintf (fp, "%s", g_type_name (type));
672       for (i=0; i < n_prerequisites; i++)
673           fprintf (fp, " %s", g_type_name (prerequisites[i]));
674       fprintf (fp, "\\n");
675      }
676   g_free (prerequisites);
678   children = g_type_children (type, &n_children);
680   for (i=0; i < n_children; i++)
681     output_prerequisites (fp, children[i]);
683   g_free (children);
684 #endif
687 static void
688 output_args (void)
690   FILE *fp;
691   gint i;
693   fp = fopen (args_filename, "w");
694   if (fp == NULL)
695     {
696       g_warning ("Couldn't open output file: %s : %s", args_filename, g_strerror(errno));
697       return;
698     }
700   for (i = 0; object_types[i]; i++) {
701     output_object_args (fp, object_types[i]);
702   }
704   fclose (fp);
707 static gint
708 compare_param_specs (const void *a, const void *b)
710   GParamSpec *spec_a = *(GParamSpec **)a;
711   GParamSpec *spec_b = *(GParamSpec **)b;
713   return strcmp (g_param_spec_get_name (spec_a), g_param_spec_get_name (spec_b));
716 /* Its common to have unsigned properties restricted
717  * to the signed range. Therefore we make this look
718  * a bit nicer by spelling out the max constants.
719  */
721 /* Don't use "==" with floats, it might trigger a gcc warning.  */
722 #define GTKDOC_COMPARE_FLOAT(x, y) (x <= y && x >= y)
724 static gchar*
725 describe_double_constant (gdouble value)
727   gchar *desc;
729   if (GTKDOC_COMPARE_FLOAT (value, G_MAXDOUBLE))
730     desc = g_strdup ("G_MAXDOUBLE");
731   else if (GTKDOC_COMPARE_FLOAT (value, G_MINDOUBLE))
732     desc = g_strdup ("G_MINDOUBLE");
733   else if (GTKDOC_COMPARE_FLOAT (value, -G_MAXDOUBLE))
734     desc = g_strdup ("-G_MAXDOUBLE");
735   else if (GTKDOC_COMPARE_FLOAT (value, G_MAXFLOAT))
736     desc = g_strdup ("G_MAXFLOAT");
737   else if (GTKDOC_COMPARE_FLOAT (value, G_MINFLOAT))
738     desc = g_strdup ("G_MINFLOAT");
739   else if (GTKDOC_COMPARE_FLOAT (value, -G_MAXFLOAT))
740     desc = g_strdup ("-G_MAXFLOAT");
741   else{
742     /* make sure floats are output with a decimal dot irrespective of
743     * current locale. Use formatd since we want human-readable numbers
744     * and do not need the exact same bit representation when deserialising */
745     desc = g_malloc0 (G_ASCII_DTOSTR_BUF_SIZE);
746     g_ascii_formatd (desc, G_ASCII_DTOSTR_BUF_SIZE, "%g", value);
747   }
749   return desc;
752 static gchar*
753 describe_signed_constant (gsize size, gint64 value)
755   gchar *desc = NULL;
757   switch (size) {
758     case 2:
759       if (sizeof (int) == 2) {
760         if (value == G_MAXINT)
761           desc = g_strdup ("G_MAXINT");
762         else if (value == G_MININT)
763           desc = g_strdup ("G_MININT");
764         else if (value == (gint64)G_MAXUINT)
765           desc = g_strdup ("G_MAXUINT");
766       }
767       break;
768     case 4:
769       if (sizeof (int) == 4) {
770         if (value == G_MAXINT)
771           desc = g_strdup ("G_MAXINT");
772         else if (value == G_MININT)
773           desc = g_strdup ("G_MININT");
774         else if (value == (gint64)G_MAXUINT)
775           desc = g_strdup ("G_MAXUINT");
776       }
777       if (value == G_MAXLONG)
778         desc = g_strdup ("G_MAXLONG");
779       else if (value == G_MINLONG)
780         desc = g_strdup ("G_MINLONG");
781       else if (value == (gint64)G_MAXULONG)
782         desc = g_strdup ("G_MAXULONG");
783       break;
784     case 8:
785       if (value == G_MAXINT64)
786         desc = g_strdup ("G_MAXINT64");
787       else if (value == G_MININT64)
788         desc = g_strdup ("G_MININT64");
789       break;
790     default:
791       break;
792   }
793   if (!desc)
794     desc = g_strdup_printf ("%" G_GINT64_FORMAT, value);
796   return desc;
799 static gchar*
800 describe_unsigned_constant (gsize size, guint64 value)
802   gchar *desc = NULL;
804   switch (size) {
805     case 2:
806       if (sizeof (int) == 2) {
807         if (value == (guint64)G_MAXINT)
808           desc = g_strdup ("G_MAXINT");
809         else if (value == G_MAXUINT)
810           desc = g_strdup ("G_MAXUINT");
811       }
812       break;
813     case 4:
814       if (sizeof (int) == 4) {
815         if (value == (guint64)G_MAXINT)
816           desc = g_strdup ("G_MAXINT");
817         else if (value == G_MAXUINT)
818           desc = g_strdup ("G_MAXUINT");
819       }
820       if (value == (guint64)G_MAXLONG)
821         desc = g_strdup ("G_MAXLONG");
822       else if (value == G_MAXULONG)
823         desc = g_strdup ("G_MAXULONG");
824       break;
825     case 8:
826       if (value == G_MAXINT64)
827         desc = g_strdup ("G_MAXINT64");
828       else if (value == G_MAXUINT64)
829         desc = g_strdup ("G_MAXUINT64");
830       break;
831     default:
832       break;
833   }
834   if (!desc)
835     desc = g_strdup_printf ("%" G_GUINT64_FORMAT, value);
837   return desc;
840 static gchar*
841 describe_type (GParamSpec *spec)
843   gchar *desc;
844   gchar *lower;
845   gchar *upper;
847   if (G_IS_PARAM_SPEC_CHAR (spec))
848     {
849       GParamSpecChar *pspec = G_PARAM_SPEC_CHAR (spec);
851       lower = describe_signed_constant (sizeof(gchar), pspec->minimum);
852       upper = describe_signed_constant (sizeof(gchar), pspec->maximum);
853       if (pspec->minimum == G_MININT8 && pspec->maximum == G_MAXINT8)
854         desc = g_strdup ("");
855       else if (pspec->minimum == G_MININT8)
856         desc = g_strdup_printf ("<= %s", upper);
857       else if (pspec->maximum == G_MAXINT8)
858         desc = g_strdup_printf (">= %s", lower);
859       else
860         desc = g_strdup_printf ("[%s,%s]", lower, upper);
861       g_free (lower);
862       g_free (upper);
863     }
864   else if (G_IS_PARAM_SPEC_UCHAR (spec))
865     {
866       GParamSpecUChar *pspec = G_PARAM_SPEC_UCHAR (spec);
868       lower = describe_unsigned_constant (sizeof(guchar), pspec->minimum);
869       upper = describe_unsigned_constant (sizeof(guchar), pspec->maximum);
870       if (pspec->minimum == 0 && pspec->maximum == G_MAXUINT8)
871         desc = g_strdup ("");
872       else if (pspec->minimum == 0)
873         desc = g_strdup_printf ("<= %s", upper);
874       else if (pspec->maximum == G_MAXUINT8)
875         desc = g_strdup_printf (">= %s", lower);
876       else
877         desc = g_strdup_printf ("[%s,%s]", lower, upper);
878       g_free (lower);
879       g_free (upper);
880     }
881   else if (G_IS_PARAM_SPEC_INT (spec))
882     {
883       GParamSpecInt *pspec = G_PARAM_SPEC_INT (spec);
885       lower = describe_signed_constant (sizeof(gint), pspec->minimum);
886       upper = describe_signed_constant (sizeof(gint), pspec->maximum);
887       if (pspec->minimum == G_MININT && pspec->maximum == G_MAXINT)
888         desc = g_strdup ("");
889       else if (pspec->minimum == G_MININT)
890         desc = g_strdup_printf ("<= %s", upper);
891       else if (pspec->maximum == G_MAXINT)
892         desc = g_strdup_printf (">= %s", lower);
893       else
894         desc = g_strdup_printf ("[%s,%s]", lower, upper);
895       g_free (lower);
896       g_free (upper);
897     }
898   else if (G_IS_PARAM_SPEC_UINT (spec))
899     {
900       GParamSpecUInt *pspec = G_PARAM_SPEC_UINT (spec);
902       lower = describe_unsigned_constant (sizeof(guint), pspec->minimum);
903       upper = describe_unsigned_constant (sizeof(guint), pspec->maximum);
904       if (pspec->minimum == 0 && pspec->maximum == G_MAXUINT)
905         desc = g_strdup ("");
906       else if (pspec->minimum == 0)
907         desc = g_strdup_printf ("<= %s", upper);
908       else if (pspec->maximum == G_MAXUINT)
909         desc = g_strdup_printf (">= %s", lower);
910       else
911         desc = g_strdup_printf ("[%s,%s]", lower, upper);
912       g_free (lower);
913       g_free (upper);
914     }
915   else if (G_IS_PARAM_SPEC_LONG (spec))
916     {
917       GParamSpecLong *pspec = G_PARAM_SPEC_LONG (spec);
919       lower = describe_signed_constant (sizeof(glong), pspec->minimum);
920       upper = describe_signed_constant (sizeof(glong), pspec->maximum);
921       if (pspec->minimum == G_MINLONG && pspec->maximum == G_MAXLONG)
922         desc = g_strdup ("");
923       else if (pspec->minimum == G_MINLONG)
924         desc = g_strdup_printf ("<= %s", upper);
925       else if (pspec->maximum == G_MAXLONG)
926         desc = g_strdup_printf (">= %s", lower);
927       else
928         desc = g_strdup_printf ("[%s,%s]", lower, upper);
929       g_free (lower);
930       g_free (upper);
931     }
932   else if (G_IS_PARAM_SPEC_ULONG (spec))
933     {
934       GParamSpecULong *pspec = G_PARAM_SPEC_ULONG (spec);
936       lower = describe_unsigned_constant (sizeof(gulong), pspec->minimum);
937       upper = describe_unsigned_constant (sizeof(gulong), pspec->maximum);
938       if (pspec->minimum == 0 && pspec->maximum == G_MAXULONG)
939         desc = g_strdup ("");
940       else if (pspec->minimum == 0)
941         desc = g_strdup_printf ("<= %s", upper);
942       else if (pspec->maximum == G_MAXULONG)
943         desc = g_strdup_printf (">= %s", lower);
944       else
945         desc = g_strdup_printf ("[%s,%s]", lower, upper);
946       g_free (lower);
947       g_free (upper);
948     }
949   else if (G_IS_PARAM_SPEC_INT64 (spec))
950     {
951       GParamSpecInt64 *pspec = G_PARAM_SPEC_INT64 (spec);
953       lower = describe_signed_constant (sizeof(gint64), pspec->minimum);
954       upper = describe_signed_constant (sizeof(gint64), pspec->maximum);
955       if (pspec->minimum == G_MININT64 && pspec->maximum == G_MAXINT64)
956         desc = g_strdup ("");
957       else if (pspec->minimum == G_MININT64)
958         desc = g_strdup_printf ("<= %s", upper);
959       else if (pspec->maximum == G_MAXINT64)
960         desc = g_strdup_printf (">= %s", lower);
961       else
962         desc = g_strdup_printf ("[%s,%s]", lower, upper);
963       g_free (lower);
964       g_free (upper);
965     }
966   else if (G_IS_PARAM_SPEC_UINT64 (spec))
967     {
968       GParamSpecUInt64 *pspec = G_PARAM_SPEC_UINT64 (spec);
970       lower = describe_unsigned_constant (sizeof(guint64), pspec->minimum);
971       upper = describe_unsigned_constant (sizeof(guint64), pspec->maximum);
972       if (pspec->minimum == 0 && pspec->maximum == G_MAXUINT64)
973         desc = g_strdup ("");
974       else if (pspec->minimum == 0)
975         desc = g_strdup_printf ("<= %s", upper);
976       else if (pspec->maximum == G_MAXUINT64)
977         desc = g_strdup_printf (">= %s", lower);
978       else
979         desc = g_strdup_printf ("[%s,%s]", lower, upper);
980       g_free (lower);
981       g_free (upper);
982     }
983   else if (G_IS_PARAM_SPEC_FLOAT (spec))
984     {
985       GParamSpecFloat *pspec = G_PARAM_SPEC_FLOAT (spec);
987       lower = describe_double_constant (pspec->minimum);
988       upper = describe_double_constant (pspec->maximum);
989       if (GTKDOC_COMPARE_FLOAT (pspec->minimum, -G_MAXFLOAT))
990         {
991           if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXFLOAT))
992             desc = g_strdup ("");
993           else
994             desc = g_strdup_printf ("<= %s", upper);
995         }
996       else if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXFLOAT))
997         desc = g_strdup_printf (">= %s", lower);
998       else
999         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1000       g_free (lower);
1001       g_free (upper);
1002     }
1003   else if (G_IS_PARAM_SPEC_DOUBLE (spec))
1004     {
1005       GParamSpecDouble *pspec = G_PARAM_SPEC_DOUBLE (spec);
1007       lower = describe_double_constant (pspec->minimum);
1008       upper = describe_double_constant (pspec->maximum);
1009       if (GTKDOC_COMPARE_FLOAT (pspec->minimum, -G_MAXDOUBLE))
1010         {
1011           if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXDOUBLE))
1012             desc = g_strdup ("");
1013           else
1014             desc = g_strdup_printf ("<= %s", upper);
1015         }
1016       else if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXDOUBLE))
1017         desc = g_strdup_printf (">= %s", lower);
1018       else
1019         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1020       g_free (lower);
1021       g_free (upper);
1022     }
1023 #if GLIB_CHECK_VERSION (2, 12, 0)
1024   else if (G_IS_PARAM_SPEC_GTYPE (spec))
1025     {
1026       GParamSpecGType *pspec = G_PARAM_SPEC_GTYPE (spec);
1027       gboolean is_pointer;
1029       desc = g_strdup (get_type_name (pspec->is_a_type, &is_pointer));
1030     }
1031 #endif
1032 #if GLIB_CHECK_VERSION (2, 25, 9)
1033   else if (G_IS_PARAM_SPEC_VARIANT (spec))
1034     {
1035       GParamSpecVariant *pspec = G_PARAM_SPEC_VARIANT (spec);
1036       gchar *variant_type;
1038       variant_type = g_variant_type_dup_string (pspec->type);
1039       desc = g_strdup_printf ("GVariant<%s>", variant_type);
1040       g_free (variant_type);
1041     }
1042 #endif
1043   else
1044     {
1045       desc = g_strdup ("");
1046     }
1048   return desc;
1051 static gchar*
1052 describe_default (GParamSpec *spec)
1054   gchar *desc;
1056   if (G_IS_PARAM_SPEC_CHAR (spec))
1057     {
1058       GParamSpecChar *pspec = G_PARAM_SPEC_CHAR (spec);
1060       desc = g_strdup_printf ("%d", pspec->default_value);
1061     }
1062   else if (G_IS_PARAM_SPEC_UCHAR (spec))
1063     {
1064       GParamSpecUChar *pspec = G_PARAM_SPEC_UCHAR (spec);
1066       desc = g_strdup_printf ("%u", pspec->default_value);
1067     }
1068   else if (G_IS_PARAM_SPEC_BOOLEAN (spec))
1069     {
1070       GParamSpecBoolean *pspec = G_PARAM_SPEC_BOOLEAN (spec);
1072       desc = g_strdup_printf ("%s", pspec->default_value ? "TRUE" : "FALSE");
1073     }
1074   else if (G_IS_PARAM_SPEC_INT (spec))
1075     {
1076       GParamSpecInt *pspec = G_PARAM_SPEC_INT (spec);
1078       desc = g_strdup_printf ("%d", pspec->default_value);
1079     }
1080   else if (G_IS_PARAM_SPEC_UINT (spec))
1081     {
1082       GParamSpecUInt *pspec = G_PARAM_SPEC_UINT (spec);
1084       desc = g_strdup_printf ("%u", pspec->default_value);
1085     }
1086   else if (G_IS_PARAM_SPEC_LONG (spec))
1087     {
1088       GParamSpecLong *pspec = G_PARAM_SPEC_LONG (spec);
1090       desc = g_strdup_printf ("%ld", pspec->default_value);
1091     }
1092   else if (G_IS_PARAM_SPEC_LONG (spec))
1093     {
1094       GParamSpecULong *pspec = G_PARAM_SPEC_ULONG (spec);
1096       desc = g_strdup_printf ("%lu", pspec->default_value);
1097     }
1098   else if (G_IS_PARAM_SPEC_INT64 (spec))
1099     {
1100       GParamSpecInt64 *pspec = G_PARAM_SPEC_INT64 (spec);
1102       desc = g_strdup_printf ("%" G_GINT64_FORMAT, pspec->default_value);
1103     }
1104   else if (G_IS_PARAM_SPEC_UINT64 (spec))
1105     {
1106       GParamSpecUInt64 *pspec = G_PARAM_SPEC_UINT64 (spec);
1108       desc = g_strdup_printf ("%" G_GUINT64_FORMAT, pspec->default_value);
1109     }
1110   else if (G_IS_PARAM_SPEC_UNICHAR (spec))
1111     {
1112       GParamSpecUnichar *pspec = G_PARAM_SPEC_UNICHAR (spec);
1114       if (g_unichar_isprint (pspec->default_value))
1115         desc = g_strdup_printf ("'%c'", pspec->default_value);
1116       else
1117         desc = g_strdup_printf ("%u", pspec->default_value);
1118     }
1119   else if (G_IS_PARAM_SPEC_ENUM (spec))
1120     {
1121       GParamSpecEnum *pspec = G_PARAM_SPEC_ENUM (spec);
1123       GEnumValue *value = g_enum_get_value (pspec->enum_class, pspec->default_value);
1124       if (value)
1125         desc = g_strdup_printf ("%s", value->value_name);
1126       else
1127         desc = g_strdup_printf ("%d", pspec->default_value);
1128     }
1129   else if (G_IS_PARAM_SPEC_FLAGS (spec))
1130     {
1131       GParamSpecFlags *pspec = G_PARAM_SPEC_FLAGS (spec);
1132       guint default_value;
1133       GString *acc;
1135       default_value = pspec->default_value;
1136       acc = g_string_new ("");
1138       while (default_value)
1139         {
1140           GFlagsValue *value = g_flags_get_first_value (pspec->flags_class, default_value);
1142           if (!value)
1143             break;
1145           if (acc->len > 0)
1146             g_string_append (acc, "|");
1147           g_string_append (acc, value->value_name);
1149           default_value &= ~value->value;
1150         }
1152       if (default_value == 0)
1153         desc = g_string_free (acc, FALSE);
1154       else
1155         {
1156           desc = g_strdup_printf ("%d", pspec->default_value);
1157           g_string_free (acc, TRUE);
1158         }
1159     }
1160   else if (G_IS_PARAM_SPEC_FLOAT (spec))
1161     {
1162       GParamSpecFloat *pspec = G_PARAM_SPEC_FLOAT (spec);
1164       /* make sure floats are output with a decimal dot irrespective of
1165        * current locale. Use formatd since we want human-readable numbers
1166        * and do not need the exact same bit representation when deserialising */
1167       desc = g_malloc0 (G_ASCII_DTOSTR_BUF_SIZE);
1168       g_ascii_formatd (desc, G_ASCII_DTOSTR_BUF_SIZE, "%g",
1169           pspec->default_value);
1170     }
1171   else if (G_IS_PARAM_SPEC_DOUBLE (spec))
1172     {
1173       GParamSpecDouble *pspec = G_PARAM_SPEC_DOUBLE (spec);
1175       /* make sure floats are output with a decimal dot irrespective of
1176        * current locale. Use formatd since we want human-readable numbers
1177        * and do not need the exact same bit representation when deserialising */
1178       desc = g_malloc0 (G_ASCII_DTOSTR_BUF_SIZE);
1179       g_ascii_formatd (desc, G_ASCII_DTOSTR_BUF_SIZE, "%g",
1180           pspec->default_value);
1181     }
1182   else if (G_IS_PARAM_SPEC_STRING (spec))
1183     {
1184       GParamSpecString *pspec = G_PARAM_SPEC_STRING (spec);
1186       if (pspec->default_value)
1187         {
1188           gchar *esc = g_strescape (pspec->default_value, NULL);
1190           desc = g_strdup_printf ("\\"%s\\"", esc);
1192           g_free (esc);
1193         }
1194       else
1195         desc = g_strdup_printf ("NULL");
1196     }
1197 #if GLIB_CHECK_VERSION (2, 25, 9)
1198   else if (G_IS_PARAM_SPEC_VARIANT (spec))
1199     {
1200       GParamSpecVariant *pspec = G_PARAM_SPEC_VARIANT (spec);
1202       if (pspec->default_value)
1203         desc = g_variant_print (pspec->default_value, TRUE);
1204       else
1205         desc = g_strdup ("NULL");
1206     }
1207 #endif
1208   else
1209     {
1210       desc = g_strdup ("");
1211     }
1213   return desc;
1217 static void
1218 output_object_args (FILE *fp, GType object_type)
1220   gpointer class;
1221   const gchar *object_class_name;
1222   guint arg;
1223   gchar flags[16], *pos;
1224   GParamSpec **properties;
1225   guint n_properties;
1226   gboolean child_prop;
1227   gboolean style_prop;
1228   gboolean is_pointer;
1229   const gchar *type_name;
1230   gchar *type_desc;
1231   gchar *default_value;
1233   if (G_TYPE_IS_OBJECT (object_type))
1234     {
1235       class = g_type_class_peek (object_type);
1236       if (!class)
1237         return;
1239       properties = g_object_class_list_properties (class, &n_properties);
1240     }
1241 #if GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 3)
1242   else if (G_TYPE_IS_INTERFACE (object_type))
1243     {
1244       class = g_type_default_interface_ref (object_type);
1246       if (!class)
1247         return;
1249       properties = g_object_interface_list_properties (class, &n_properties);
1250     }
1251 #endif
1252   else
1253     return;
1255   object_class_name = g_type_name (object_type);
1257   child_prop = FALSE;
1258   style_prop = FALSE;
1260   while (TRUE) {
1261     qsort (properties, n_properties, sizeof (GParamSpec *), compare_param_specs);
1262     for (arg = 0; arg < n_properties; arg++)
1263       {
1264         GParamSpec *spec = properties[arg];
1265         const gchar *nick, *blurb, *dot;
1267         if (spec->owner_type != object_type)
1268           continue;
1270         pos = flags;
1271         /* We use one-character flags for simplicity. */
1272         if (child_prop && !style_prop)
1273              *pos++ = 'c';
1274         if (style_prop)
1275              *pos++ = 's';
1276         if (spec->flags & G_PARAM_READABLE)
1277            *pos++ = 'r';
1278         if (spec->flags & G_PARAM_WRITABLE)
1279           *pos++ = 'w';
1280         if (spec->flags & G_PARAM_CONSTRUCT)
1281           *pos++ = 'x';
1282         if (spec->flags & G_PARAM_CONSTRUCT_ONLY)
1283           *pos++ = 'X';
1284         *pos = 0;
1286         nick = g_param_spec_get_nick (spec);
1287         blurb = g_param_spec_get_blurb (spec);
1289         dot = "";
1290         if (blurb) {
1291           int str_len = strlen (blurb);
1292           if (str_len > 0  && blurb[str_len - 1] != '.')
1293             dot = ".";
1294         }
1296         type_desc = describe_type (spec);
1297         default_value = describe_default (spec);
1298         type_name = get_type_name (spec->value_type, &is_pointer);
1299         fprintf (fp, "<ARG>\\n<NAME>%s::%s</NAME>\\n<TYPE>%s%s</TYPE>\\n<RANGE>%s</RANGE>\\n<FLAGS>%s</FLAGS>\\n<NICK>%s</NICK>\\n<BLURB>%s%s</BLURB>\\n<DEFAULT>%s</DEFAULT>\\n</ARG>\\n\\n",
1300                  object_class_name, g_param_spec_get_name (spec), type_name, is_pointer ? "*" : "", type_desc, flags, nick ? nick : "(null)", blurb ? blurb : "(null)", dot, default_value);
1301         g_free (type_desc);
1302         g_free (default_value);
1303       }
1305     g_free (properties);
1307 #ifdef GTK_IS_CONTAINER_CLASS
1308     if (!child_prop && GTK_IS_CONTAINER_CLASS (class)) {
1309       properties = gtk_container_class_list_child_properties (class, &n_properties);
1310       child_prop = TRUE;
1311       continue;
1312     }
1313 #endif
1315 #ifdef GTK_IS_CELL_AREA_CLASS
1316     if (!child_prop && GTK_IS_CELL_AREA_CLASS (class)) {
1317       properties = gtk_cell_area_class_list_cell_properties (class, &n_properties);
1318       child_prop = TRUE;
1319       continue;
1320     }
1321 #endif
1323 #ifdef GTK_IS_WIDGET_CLASS
1324 #if GTK_CHECK_VERSION(2,1,0)
1325     if (!style_prop && GTK_IS_WIDGET_CLASS (class)) {
1326       properties = gtk_widget_class_list_style_properties (GTK_WIDGET_CLASS (class), &n_properties);
1327       style_prop = TRUE;
1328       continue;
1329     }
1330 #endif
1331 #endif
1335 if ($QUERY_CHILD_PROPERTIES) {
1336   print OUTPUT <<EOT;
1337     if (!child_prop) {
1338       properties = $QUERY_CHILD_PROPERTIES (class, &n_properties);
1339       if (properties) {
1340         child_prop = TRUE;
1341         continue;
1342       }
1343    }
1348 print OUTPUT <<EOT;
1349     break;
1350   }
1354 close OUTPUT;
1356 # Compile and run our file
1358 $CC = $ENV{CC} ? $ENV{CC} : "gcc";
1359 $LD = $ENV{LD} ? $ENV{LD} : $CC;
1360 $CFLAGS = $ENV{CFLAGS} ? $ENV{CFLAGS} : "";
1361 $LDFLAGS = $ENV{LDFLAGS} ? $ENV{LDFLAGS} : "";
1362 $RUN = $ENV{RUN} ? $ENV{RUN} : "";
1364 my $o_file;
1365 if ($CC =~ /libtool/) {
1366   $o_file  = "$MODULE-scan.lo"
1367 } else {
1368   $o_file = "$MODULE-scan.o"
1371 my $stdout="";
1372 if (!defined($VERBOSE) or $VERBOSE eq "0") {
1373     $stdout=">/dev/null";
1376 # Compiling scanner
1377 $command = "$CC $stdout $CFLAGS -c -o $o_file $MODULE-scan.c";
1378 system("($command)") == 0 or die "Compilation of scanner failed: $!\n";
1380 # Linking scanner
1381 # FIXME: Can we turn off as-needed for the docs (or better fix it?)
1382 #$command = "$LD -Wl,--no-as-needed $o_file $LDFLAGS -o $MODULE-scan";
1383 $command = "$LD $stdout $o_file $LDFLAGS -o $MODULE-scan";
1384 system("($command)") == 0 or die "Linking of scanner failed: $!\n";
1386 # Running scanner $MODULE-scan ";
1387 system("($RUN ./$MODULE-scan)") == 0 or die "Scan failed: $!\n";
1390 if (!defined($ENV{"GTK_DOC_KEEP_INTERMEDIATE"})) {
1391   unlink "./$MODULE-scan.c", "./$MODULE-scan.o", "./$MODULE-scan.lo", "./$MODULE-scan";
1394 &UpdateFileIfChanged ($old_signals_filename, $new_signals_filename, 0);
1395 &UpdateFileIfChanged ($old_hierarchy_filename, $new_hierarchy_filename, 0);
1396 &UpdateFileIfChanged ($old_interfaces_filename, $new_interfaces_filename, 0);
1397 &UpdateFileIfChanged ($old_prerequisites_filename, $new_prerequisites_filename, 0);
1398 &UpdateFileIfChanged ($old_args_filename, $new_args_filename, 0);