update-common: add support for branches
[platform/upstream/gst-common.git] / gstdoc-scangobj
1 #!/usr/bin/env perl
2 # -*- cperl -*-
3 #
4 # gtk-doc - GTK DocBook documentation generator.
5 # Copyright (C) 1998  Damon Chaplin
6 #
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.
11 #
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.
16 #
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 #
21
22 #
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.
26 #
27
28 use Getopt::Long;
29
30 my $GTK_DOC_PREFIX=`pkg-config --variable prefix gtk-doc`;
31 if ($GTK_DOC_PREFIX) {
32   chomp $GTK_DOC_PREFIX;
33   #print "Adding $GTK_DOC_PREFIX/share/gtk-doc/data to \@INC\n";
34   unshift @INC, "$GTK_DOC_PREFIX/share/gtk-doc/data";
35 } else {
36   unshift @INC, '/usr/share/gtk-doc/data';
37 }
38 require "gtkdoc-common.pl";
39
40 # Options
41
42 # name of documentation module
43 my $MODULE;
44 my $OUTPUT_DIR;
45 my $INSPECT_DIR;
46 my $VERBOSE;
47 my $PRINT_VERSION;
48 my $PRINT_HELP;
49 my $TYPE_INIT_FUNC="g_type_init ()";
50
51 # --nogtkinit is deprecated, as it is the default now anyway.
52 %optctl = (module => \$MODULE,
53            source => \$SOURCE,
54            types => \$TYPES_FILE,
55            nogtkinit => \$NO_GTK_INIT,
56            'type-init-func' => \$TYPE_INIT_FUNC,
57            'output-dir' => \$OUTPUT_DIR,
58            'inspect-dir' => \$INSPECT_DIR,
59            'verbose' => \$VERBOSE,
60            'version' => \$PRINT_VERSION,
61            'help' => \$PRINT_HELP);
62
63 GetOptions(\%optctl, "module=s", "source=s", "types:s", "output-dir:s", "inspect-dir:s", "nogtkinit", "type-init-func:s", "verbose", "version", "help");
64
65 if ($NO_GTK_INIT) {
66   # Do nothing. This just avoids a warning.
67   # the option is not used anymore
68 }
69
70 if ($PRINT_VERSION) {
71     print "1.5\n";
72     exit 0;
73 }
74
75 if (!$MODULE) {
76     $PRINT_HELP = 1;
77 }
78
79 if ($PRINT_HELP) {
80     print <<EOF;
81 gstdoc-scangobj version 1.5 - introspect gstreamer-plugins
82
83 --module=MODULE_NAME          Name of the doc module being parsed
84 --source=SOURCE_NAME          Name of the source module for plugins
85 --types=FILE                  The name of the file to store the types in
86 --type-init-func=FUNC         The init function to call instead of g_type_init()
87 --output-dir=DIRNAME          The directory where the results are stored
88 --inspect-dir=DIRNAME         The directory where the plugin inspect data is stored
89 --verbose                     Print extra output while processing
90 --version                     Print the version of this program
91 --help                        Print this help
92 EOF
93     exit 0;
94 }
95
96 $OUTPUT_DIR = $OUTPUT_DIR ? $OUTPUT_DIR : ".";
97
98 $TYPES_FILE = $TYPES_FILE ? $TYPES_FILE : "$OUTPUT_DIR/$MODULE.types";
99
100 open (TYPES, $TYPES_FILE) || die "Cannot open $TYPES_FILE: $!\n";
101 open (OUTPUT, ">$MODULE-scan.c") || die "Cannot open $MODULE-scan.c: $!\n";
102
103 my $old_signals_filename = "$OUTPUT_DIR/$MODULE.signals";
104 my $new_signals_filename = "$OUTPUT_DIR/$MODULE.signals.new";
105 my $old_hierarchy_filename = "$OUTPUT_DIR/$MODULE.hierarchy";
106 my $new_hierarchy_filename = "$OUTPUT_DIR/$MODULE.hierarchy.new";
107 my $old_interfaces_filename = "$OUTPUT_DIR/$MODULE.interfaces";
108 my $new_interfaces_filename = "$OUTPUT_DIR/$MODULE.interfaces.new";
109 my $old_prerequisites_filename = "$OUTPUT_DIR/$MODULE.prerequisites";
110 my $new_prerequisites_filename = "$OUTPUT_DIR/$MODULE.prerequisites.new";
111 my $old_args_filename = "$OUTPUT_DIR/$MODULE.args";
112 my $new_args_filename = "$OUTPUT_DIR/$MODULE.args.new";
113
114 my $debug_log="g_message";
115 if (!defined($VERBOSE) or $VERBOSE eq "0") {
116     $debug_log="//$debug_log";
117 }
118
119 # write a C program to scan the types
120
121 $includes = "";
122 @types = ();
123 @impl_types = ();
124
125 for (<TYPES>) {
126     if (/^#include/) {
127         $includes .= $_;
128     } elsif (/^%/) {
129         next;
130     } elsif (/^\s*$/) {
131         next;
132     } elsif (/^type:(.*)$/) {
133         $t = $1;
134         chomp $t;
135         push @impl_types, $t;
136     } else {
137         chomp;
138         push @types, $_;
139     }
140 }
141
142 $ntypes = @types + @impl_types + 1;
143
144 print OUTPUT <<EOT;
145 #include <string.h>
146 #include <stdlib.h>
147 #include <stdio.h>
148 #include <errno.h>
149
150 $includes
151
152 #ifdef GTK_IS_WIDGET_CLASS
153 #include <gtk/gtkversion.h>
154 #endif
155
156 static GType *object_types = NULL;
157
158 static GString *xmlstr = NULL;
159
160 static const gchar*
161 xmlprint (gint indent, const gchar *tag, const gchar *data)
162 {
163   const gchar indent_str[] = "                                               ";
164
165   /* reset */
166   g_string_truncate (xmlstr, 0);
167   g_string_append_len (xmlstr, indent_str, MIN (indent, strlen (indent_str)));
168   g_string_append_printf (xmlstr, "<%s>", tag);
169
170   if (data) {
171     gchar *s;
172
173     s = g_markup_escape_text (data, -1);
174     g_string_append (xmlstr, s);
175     g_free (s);
176   }
177
178   g_string_append_printf (xmlstr, "</%s>\\n", tag);
179   return xmlstr->str;
180 }
181
182 static gint
183 gst_feature_sort_compare (gconstpointer a, gconstpointer b)
184 {
185   const gchar *name_a = gst_plugin_feature_get_name ((GstPluginFeature *) a);
186   const gchar *name_b = gst_plugin_feature_get_name ((GstPluginFeature *) b);
187   return strcmp (name_a, name_b);
188 }
189
190 static gint
191 static_pad_template_compare (gconstpointer a, gconstpointer b)
192 {
193   GstStaticPadTemplate *spt_a = (GstStaticPadTemplate *) a;
194   GstStaticPadTemplate *spt_b = (GstStaticPadTemplate *) b;
195
196   /* we want SINK before SRC (enum is UNKNOWN, SRC, SINK) */
197   if (spt_a->direction != spt_b->direction)
198     return spt_b->direction - spt_a->direction;
199
200   /* we want ALWAYS first, SOMETIMES second, REQUEST last
201    * (enum is ALWAYS, SOMETIMES, REQUEST) */
202   if (spt_a->presence != spt_b->presence)
203     return spt_a->presence - spt_b->presence;
204
205   return strcmp (spt_a->name_template, spt_b->name_template);
206 }
207
208 static GType *
209 get_object_types (void)
210 {
211     gpointer g_object_class;
212     GList *plugins = NULL;
213     GList *factories = NULL;
214     GList *l;
215     GstElementFactory *factory = NULL;
216     GType type;
217     gint i = 0;
218     gboolean reinspect;
219
220     /* get a list of features from plugins in our source module */
221     plugins = gst_registry_get_plugin_list (gst_registry_get_default());
222
223     xmlstr = g_string_new ("");
224
225     reinspect = !g_file_test ("scanobj-build.stamp", G_FILE_TEST_EXISTS);
226
227     while (plugins) {
228       GList *features;
229       GstPlugin *plugin;
230       const gchar *source;
231       FILE *inspect = NULL;
232       gchar *inspect_name;
233
234       plugin = (GstPlugin *) (plugins->data);
235       plugins = g_list_next (plugins);
236       source = gst_plugin_get_source (plugin);
237       if (!source || strcmp (source, "$SOURCE") != 0) {
238         continue;
239       }
240
241       /* skip static coreelements plugin with pipeline and bin element factory */
242       if (gst_plugin_get_filename (plugin) == NULL)
243         continue;
244
245       $debug_log ("plugin: %s source: %s", plugin->desc.name, source);
246
247       if (reinspect) {
248         inspect_name = g_strdup_printf ("$INSPECT_DIR" G_DIR_SEPARATOR_S "plugin-%s.xml",
249             plugin->desc.name);
250         inspect = fopen (inspect_name, "w");
251         if (inspect == NULL) {
252           g_error ("Could not open %s for writing: %s\\n", inspect_name,
253               g_strerror (errno));
254         }
255         g_free (inspect_name);
256
257         /* output plugin data */
258         fputs ("<plugin>\\n",inspect);
259         fputs (xmlprint(2, "name", plugin->desc.name),inspect);
260         fputs (xmlprint(2, "description", plugin->desc.description),inspect);
261         fputs (xmlprint(2, "filename", plugin->filename),inspect);
262         fputs (xmlprint(2, "basename", plugin->basename),inspect);
263         fputs (xmlprint(2, "version", plugin->desc.version),inspect);
264         fputs (xmlprint(2, "license", plugin->desc.license),inspect);
265         fputs (xmlprint(2, "source", plugin->desc.source),inspect);
266         fputs (xmlprint(2, "package", plugin->desc.package),inspect);
267         fputs (xmlprint(2, "origin", plugin->desc.origin),inspect);
268         fputs ("  <elements>\\n", inspect);
269       }
270
271       features =
272           gst_registry_get_feature_list_by_plugin (gst_registry_get_default (),
273           plugin->desc.name);
274
275       /* sort factories by feature->name */
276       features = g_list_sort (features, gst_feature_sort_compare);
277
278       while (features) {
279         GstPluginFeature *feature;
280         feature = GST_PLUGIN_FEATURE (features->data);
281         feature = gst_plugin_feature_load (feature);
282         if (!feature) {
283           g_warning ("Could not load plugin feature %s",
284                      gst_plugin_feature_get_name (feature));
285         }
286
287         if (GST_IS_ELEMENT_FACTORY (feature)) {
288           const gchar *pad_dir[] = { "unknown","source","sink" };
289           const gchar *pad_pres[] = { "always","sometimes","request" };
290           GList *pads, *pad;
291
292           $debug_log ("  feature: %s", gst_plugin_feature_get_name (feature));
293
294           factory = GST_ELEMENT_FACTORY (feature);
295           factories = g_list_prepend (factories, factory);
296
297           if (reinspect) {
298             /* output element data */
299             fputs ("    <element>\\n", inspect);
300             fputs (xmlprint(6, "name", gst_plugin_feature_get_name (feature)),inspect);
301             fputs (xmlprint(6, "longname", gst_element_factory_get_longname (factory)),inspect);
302             fputs (xmlprint(6, "class", gst_element_factory_get_klass (factory)),inspect);
303             fputs (xmlprint(6, "description", gst_element_factory_get_description (factory)),inspect);
304             fputs (xmlprint(6, "author", gst_element_factory_get_author (factory)),inspect);
305             fputs ("      <pads>\\n", inspect);
306
307             /* output pad-template data */
308             pads = g_list_copy ((GList *) gst_element_factory_get_static_pad_templates (factory));
309             pads = g_list_sort (pads, static_pad_template_compare);
310             for (pad = pads; pad != NULL; pad = pad->next) {
311               GstStaticPadTemplate *pt = pad->data;
312
313               fputs ("        <caps>\\n", inspect);
314               fputs (xmlprint(10, "name", pt->name_template),inspect);
315               fputs (xmlprint(10, "direction", pad_dir[pt->direction]),inspect);
316               fputs (xmlprint(10, "presence", pad_pres[pt->presence]),inspect);
317               fputs (xmlprint(10, "details", pt->static_caps.string),inspect);
318               fputs ("        </caps>\\n", inspect);
319             }
320             g_list_free (pads);
321             fputs ("      </pads>\\n    </element>\\n", inspect);
322           }
323         }
324         features = g_list_next (features);
325       }
326
327       if (reinspect) {
328         fputs ("  </elements>\\n</plugin>", inspect);
329         fclose (inspect);
330       }
331     }
332
333     g_string_free (xmlstr, TRUE);
334
335     $debug_log ("number of element factories: %d", g_list_length (factories));
336
337     /* allocate the object_types array to hold them */
338     object_types = g_new0 (GType, g_list_length (factories)+$ntypes+1);
339
340     l = factories;
341     i = 0;
342
343     /* fill it */
344     while (l) {
345       factory = GST_ELEMENT_FACTORY (l->data);
346       type = gst_element_factory_get_element_type (factory);
347       if (type != 0) {
348         $debug_log ("adding type for factory %s", gst_element_factory_get_longname (factory));
349         object_types[i++] = type;
350       } else {
351         g_message ("type info for factory %s not found",
352             gst_element_factory_get_longname (factory));
353       }
354       l = g_list_next (l);
355     }
356
357 EOT
358
359 # get_type functions:
360 for (@types) {
361 print OUTPUT <<EOT;
362     type = $_ ();
363     if (type == 0) {
364       g_message ("$_ () didn't return a valid type");
365     }
366     else {
367       object_types[i++] = type;
368     }
369 EOT
370 }
371
372 # Implicit types retrieved from GLib:
373 for (@impl_types) {
374 print OUTPUT <<EOT;
375     type = g_type_from_name ("$_");
376     if (type == 0) {
377       g_message ("Implicit type $_ not found");
378     }
379     else {
380       object_types[i++] = type;
381     }
382 EOT
383 }
384
385 print OUTPUT <<EOT;
386
387     object_types[i] = 0;
388
389     /* reference the GObjectClass to initialize the param spec pool
390      * potentially needed by interfaces. See http://bugs.gnome.org/571820 */
391     g_object_class = g_type_class_ref (G_TYPE_OBJECT);
392
393     /* Need to make sure all the types are loaded in and initialize
394      * their signals and properties.
395      */
396     for (i=0; object_types[i]; i++)
397       {
398         if (G_TYPE_IS_CLASSED (object_types[i]))
399           g_type_class_ref (object_types[i]);
400         if (G_TYPE_IS_INTERFACE (object_types[i]))
401           g_type_default_interface_ref (object_types[i]);
402       }
403
404     g_type_class_unref (g_object_class);
405
406     return object_types;
407 }
408
409 /*
410  * This uses GObject type functions to output signal prototypes and the object
411  * hierarchy.
412  */
413
414 /* The output files */
415 const gchar *signals_filename = "$new_signals_filename";
416 const gchar *hierarchy_filename = "$new_hierarchy_filename";
417 const gchar *interfaces_filename = "$new_interfaces_filename";
418 const gchar *prerequisites_filename = "$new_prerequisites_filename";
419 const gchar *args_filename = "$new_args_filename";
420
421
422 static void output_signals (void);
423 static void output_object_signals (FILE *fp,
424                                    GType object_type);
425 static void output_object_signal (FILE *fp,
426                                   const gchar *object_class_name,
427                                   guint signal_id);
428 static const gchar * get_type_name (GType type,
429                                     gboolean * is_pointer);
430 static void output_object_hierarchy (void);
431 static void output_hierarchy (FILE *fp,
432                               GType type,
433                               guint level);
434
435 static void output_object_interfaces (void);
436 static void output_interfaces (FILE *fp,
437                                GType type);
438
439 static void output_interface_prerequisites (void);
440 static void output_prerequisites (FILE *fp,
441                                   GType type);
442
443 static void output_args (void);
444 static void output_object_args (FILE *fp, GType object_type);
445
446 int
447 main (int argc, char *argv[])
448 {
449   /* Silence the compiler: */
450   if (argv != argv) argc = argc;
451
452   $TYPE_INIT_FUNC;
453
454   get_object_types ();
455
456   output_signals ();
457   output_object_hierarchy ();
458   output_object_interfaces ();
459   output_interface_prerequisites ();
460   output_args ();
461
462   return 0;
463 }
464
465
466 static void
467 output_signals (void)
468 {
469   FILE *fp;
470   gint i;
471
472   fp = fopen (signals_filename, "w");
473   if (fp == NULL)
474     {
475       g_warning ("Couldn't open output file: %s : %s", signals_filename, g_strerror(errno));
476       return;
477     }
478
479   for (i = 0; object_types[i]; i++)
480     output_object_signals (fp, object_types[i]);
481
482   fclose (fp);
483 }
484
485 static gint
486 compare_signals (const void *a, const void *b)
487 {
488   const guint *signal_a = a;
489   const guint *signal_b = b;
490
491   return strcmp (g_signal_name (*signal_a), g_signal_name (*signal_b));
492 }
493
494 /* This outputs all the signals of one object. */
495 static void
496 output_object_signals (FILE *fp, GType object_type)
497 {
498   const gchar *object_class_name;
499   guint *signals, n_signals;
500   guint sig;
501
502   if (G_TYPE_IS_INSTANTIATABLE (object_type) ||
503       G_TYPE_IS_INTERFACE (object_type))
504     {
505
506       object_class_name = g_type_name (object_type);
507
508       signals = g_signal_list_ids (object_type, &n_signals);
509       qsort (signals, n_signals, sizeof (guint), compare_signals);
510
511       for (sig = 0; sig < n_signals; sig++)
512         {
513            output_object_signal (fp, object_class_name, signals[sig]);
514         }
515       g_free (signals);
516    }
517 }
518
519
520 /* This outputs one signal. */
521 static void
522 output_object_signal (FILE *fp,
523                       const gchar *object_name,
524                       guint signal_id)
525 {
526   GSignalQuery query_info;
527   const gchar *type_name, *ret_type, *object_arg, *arg_name;
528   gchar *pos, *object_arg_lower;
529   gboolean is_pointer;
530   gchar buffer[1024];
531   guint i, param;
532   gint param_num, widget_num, event_num, callback_num;
533   gint *arg_num;
534   gchar signal_name[128];
535   gchar flags[16];
536
537   $debug_log ("Object: %s Signal: %u", object_name, signal_id);
538
539   param_num = 1;
540   widget_num = event_num = callback_num = 0;
541
542   g_signal_query (signal_id, &query_info);
543
544   /* Output the signal object type and the argument name. We assume the
545      type is a pointer - I think that is OK. We remove "Gtk" or "Gnome" and
546      convert to lower case for the argument name. */
547   pos = buffer;
548   sprintf (pos, "%s ", object_name);
549   pos += strlen (pos);
550
551   /* Try to come up with a sensible variable name for the first arg
552    * It chops off 2 know prefixes :/ and makes the name lowercase
553    * It should replace lowercase -> uppercase with '_'
554    * GFileMonitor -> file_monitor
555    * GIOExtensionPoint -> extension_point
556    * GtkTreeView -> tree_view
557    * if 2nd char is upper case too
558    *   search for first lower case and go back one char
559    * else
560    *   search for next upper case
561    */
562   if (!strncmp (object_name, "Gtk", 3))
563       object_arg = object_name + 3;
564   else if (!strncmp (object_name, "Gnome", 5))
565       object_arg = object_name + 5;
566   else
567       object_arg = object_name;
568
569   object_arg_lower = g_ascii_strdown (object_arg, -1);
570   sprintf (pos, "*%s\\n", object_arg_lower);
571   pos += strlen (pos);
572   if (!strncmp (object_arg_lower, "widget", 6))
573     widget_num = 2;
574   g_free(object_arg_lower);
575
576   /* Convert signal name to use underscores rather than dashes '-'. */
577   strncpy (signal_name, query_info.signal_name, 127);
578   signal_name[127] = '\\0';
579   for (i = 0; signal_name[i]; i++)
580     {
581       if (signal_name[i] == '-')
582         signal_name[i] = '_';
583     }
584
585   /* Output the signal parameters. */
586   for (param = 0; param < query_info.n_params; param++)
587     {
588       type_name = get_type_name (query_info.param_types[param] & ~G_SIGNAL_TYPE_STATIC_SCOPE, &is_pointer);
589
590       /* Most arguments to the callback are called "arg1", "arg2", etc.
591          GtkWidgets are called "widget", "widget2", ...
592          GtkCallbacks are called "callback", "callback2", ... */
593       if (!strcmp (type_name, "GtkWidget"))
594         {
595           arg_name = "widget";
596           arg_num = &widget_num;
597         }
598       else if (!strcmp (type_name, "GtkCallback")
599                || !strcmp (type_name, "GtkCCallback"))
600         {
601           arg_name = "callback";
602           arg_num = &callback_num;
603         }
604       else
605         {
606           arg_name = "arg";
607           arg_num = &param_num;
608         }
609       sprintf (pos, "%s ", type_name);
610       pos += strlen (pos);
611
612       if (!arg_num || *arg_num == 0)
613         sprintf (pos, "%s%s\\n", is_pointer ? "*" : " ", arg_name);
614       else
615         sprintf (pos, "%s%s%i\\n", is_pointer ? "*" : " ", arg_name,
616                  *arg_num);
617       pos += strlen (pos);
618
619       if (arg_num)
620         {
621           if (*arg_num == 0)
622             *arg_num = 2;
623           else
624             *arg_num += 1;
625         }
626     }
627
628   pos = flags;
629   /* We use one-character flags for simplicity. */
630   if (query_info.signal_flags & G_SIGNAL_RUN_FIRST)
631     *pos++ = 'f';
632   if (query_info.signal_flags & G_SIGNAL_RUN_LAST)
633     *pos++ = 'l';
634   if (query_info.signal_flags & G_SIGNAL_RUN_CLEANUP)
635     *pos++ = 'c';
636   if (query_info.signal_flags & G_SIGNAL_NO_RECURSE)
637     *pos++ = 'r';
638   if (query_info.signal_flags & G_SIGNAL_DETAILED)
639     *pos++ = 'd';
640   if (query_info.signal_flags & G_SIGNAL_ACTION)
641     *pos++ = 'a';
642   if (query_info.signal_flags & G_SIGNAL_NO_HOOKS)
643     *pos++ = 'h';
644   *pos = 0;
645
646   /* Output the return type and function name. */
647   ret_type = get_type_name (query_info.return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE, &is_pointer);
648
649   fprintf (fp,
650            "<SIGNAL>\\n<NAME>%s::%s</NAME>\\n<RETURNS>%s%s</RETURNS>\\n<FLAGS>%s</FLAGS>\\n%s</SIGNAL>\\n\\n",
651            object_name, query_info.signal_name, ret_type, is_pointer ? "*" : "", flags, buffer);
652 }
653
654
655 /* Returns the type name to use for a signal argument or return value, given
656    the GtkType from the signal info. It also sets is_pointer to TRUE if the
657    argument needs a '*' since it is a pointer. */
658 static const gchar *
659 get_type_name (GType type, gboolean * is_pointer)
660 {
661   const gchar *type_name;
662
663   *is_pointer = FALSE;
664   type_name = g_type_name (type);
665
666   switch (type) {
667   case G_TYPE_NONE:
668   case G_TYPE_CHAR:
669   case G_TYPE_UCHAR:
670   case G_TYPE_BOOLEAN:
671   case G_TYPE_INT:
672   case G_TYPE_UINT:
673   case G_TYPE_LONG:
674   case G_TYPE_ULONG:
675   case G_TYPE_FLOAT:
676   case G_TYPE_DOUBLE:
677   case G_TYPE_POINTER:
678     /* These all have normal C type names so they are OK. */
679     return type_name;
680
681   case G_TYPE_STRING:
682     /* A GtkString is really a gchar*. */
683     *is_pointer = TRUE;
684     return "gchar";
685
686   case G_TYPE_ENUM:
687   case G_TYPE_FLAGS:
688     /* We use a gint for both of these. Hopefully a subtype with a decent
689        name will be registered and used instead, as GTK+ does itself. */
690     return "gint";
691
692   case G_TYPE_BOXED:
693     /* The boxed type shouldn't be used itself, only subtypes. Though we
694        return 'gpointer' just in case. */
695     return "gpointer";
696
697   case G_TYPE_PARAM:
698     /* A GParam is really a GParamSpec*. */
699     *is_pointer = TRUE;
700     return "GParamSpec";
701
702 #if GLIB_CHECK_VERSION (2, 25, 9)
703   case G_TYPE_VARIANT:
704     *is_pointer = TRUE;
705     return "GVariant";
706 #endif
707
708 default:
709     break;
710   }
711
712   /* For all GObject subclasses we can use the class name with a "*",
713      e.g. 'GtkWidget *'. */
714   if (g_type_is_a (type, G_TYPE_OBJECT))
715     *is_pointer = TRUE;
716
717   /* Also catch non GObject root types */
718   if (G_TYPE_IS_CLASSED (type))
719     *is_pointer = TRUE;
720
721   /* All boxed subtypes will be pointers as well. */
722   /* Exception: GStrv */
723   if (g_type_is_a (type, G_TYPE_BOXED) &&
724       !g_type_is_a (type, G_TYPE_STRV))
725     *is_pointer = TRUE;
726
727   /* All pointer subtypes will be pointers as well. */
728   if (g_type_is_a (type, G_TYPE_POINTER))
729     *is_pointer = TRUE;
730
731   /* But enums are not */
732   if (g_type_is_a (type, G_TYPE_ENUM) ||
733       g_type_is_a (type, G_TYPE_FLAGS))
734     *is_pointer = FALSE;
735
736   return type_name;
737 }
738
739
740 /* This outputs the hierarchy of all objects which have been initialized,
741    i.e. by calling their XXX_get_type() initialization function. */
742 static void
743 output_object_hierarchy (void)
744 {
745   FILE *fp;
746   gint i,j;
747   GType root, type;
748   GType root_types[$ntypes] = { G_TYPE_INVALID, };
749
750   fp = fopen (hierarchy_filename, "w");
751   if (fp == NULL)
752     {
753       g_warning ("Couldn't open output file: %s : %s", hierarchy_filename, g_strerror(errno));
754       return;
755     }
756   output_hierarchy (fp, G_TYPE_OBJECT, 0);
757   output_hierarchy (fp, G_TYPE_INTERFACE, 0);
758
759   for (i=0; object_types[i]; i++) {
760     root = object_types[i];
761     while ((type = g_type_parent (root))) {
762       root = type;
763     }
764     if ((root != G_TYPE_OBJECT) && (root != G_TYPE_INTERFACE)) {
765       for (j=0; root_types[j]; j++) {
766         if (root == root_types[j]) {
767           root = G_TYPE_INVALID; break;
768         }
769       }
770       if(root) {
771         root_types[j] = root;
772         output_hierarchy (fp, root, 0);
773       }
774     }
775   }
776
777   fclose (fp);
778 }
779
780 static int
781 compare_types (const void *a, const void *b)
782 {
783   const char *na = g_type_name (*((GType *)a));
784   const char *nb = g_type_name (*((GType *)b));
785
786   return g_strcmp0 (na, nb);
787 }
788
789
790 /* This is called recursively to output the hierarchy of a object. */
791 static void
792 output_hierarchy (FILE  *fp,
793                   GType  type,
794                   guint   level)
795 {
796   guint i;
797   GType *children;
798   guint n_children;
799
800   if (!type)
801     return;
802
803   for (i = 0; i < level; i++)
804     fprintf (fp, "  ");
805   fprintf (fp, "%s\\n", g_type_name (type));
806
807   children = g_type_children (type, &n_children);
808   qsort (children, n_children, sizeof (GType), compare_types);
809
810
811   for (i=0; i < n_children; i++)
812     output_hierarchy (fp, children[i], level + 1);
813
814   g_free (children);
815 }
816
817 static void output_object_interfaces (void)
818 {
819   guint i;
820   FILE *fp;
821
822   fp = fopen (interfaces_filename, "w");
823   if (fp == NULL)
824     {
825       g_warning ("Couldn't open output file: %s : %s", interfaces_filename, g_strerror(errno));
826       return;
827     }
828   output_interfaces (fp, G_TYPE_OBJECT);
829
830   for (i = 0; object_types[i]; i++)
831     {
832       if (!g_type_parent (object_types[i]) &&
833           (object_types[i] != G_TYPE_OBJECT) &&
834           G_TYPE_IS_INSTANTIATABLE (object_types[i]))
835         {
836           output_interfaces (fp, object_types[i]);
837         }
838     }
839   fclose (fp);
840 }
841
842 static void
843 output_interfaces (FILE  *fp,
844                    GType  type)
845 {
846   guint i;
847   GType *children, *interfaces;
848   guint n_children, n_interfaces;
849
850   if (!type)
851     return;
852
853   interfaces = g_type_interfaces (type, &n_interfaces);
854
855   if (n_interfaces > 0)
856     {
857       fprintf (fp, "%s", g_type_name (type));
858       for (i=0; i < n_interfaces; i++)
859           fprintf (fp, " %s", g_type_name (interfaces[i]));
860       fprintf (fp, "\\n");
861      }
862   g_free (interfaces);
863
864   children = g_type_children (type, &n_children);
865
866   for (i=0; i < n_children; i++)
867     output_interfaces (fp, children[i]);
868
869   g_free (children);
870 }
871
872 static void output_interface_prerequisites (void)
873 {
874   FILE *fp;
875
876   fp = fopen (prerequisites_filename, "w");
877   if (fp == NULL)
878     {
879       g_warning ("Couldn't open output file: %s : %s", prerequisites_filename, g_strerror(errno));
880       return;
881     }
882   output_prerequisites (fp, G_TYPE_INTERFACE);
883   fclose (fp);
884 }
885
886 static void
887 output_prerequisites (FILE  *fp,
888                       GType  type)
889 {
890 #if GLIB_CHECK_VERSION(2,1,0)
891   guint i;
892   GType *children, *prerequisites;
893   guint n_children, n_prerequisites;
894
895   if (!type)
896     return;
897
898   prerequisites = g_type_interface_prerequisites (type, &n_prerequisites);
899
900   if (n_prerequisites > 0)
901     {
902       fprintf (fp, "%s", g_type_name (type));
903       for (i=0; i < n_prerequisites; i++)
904           fprintf (fp, " %s", g_type_name (prerequisites[i]));
905       fprintf (fp, "\\n");
906      }
907   g_free (prerequisites);
908
909   children = g_type_children (type, &n_children);
910
911   for (i=0; i < n_children; i++)
912     output_prerequisites (fp, children[i]);
913
914   g_free (children);
915 #endif
916 }
917
918 static void
919 output_args (void)
920 {
921   FILE *fp;
922   gint i;
923
924   fp = fopen (args_filename, "w");
925   if (fp == NULL)
926     {
927       g_warning ("Couldn't open output file: %s : %s", args_filename, g_strerror(errno));
928       return;
929     }
930
931   for (i = 0; object_types[i]; i++) {
932     output_object_args (fp, object_types[i]);
933   }
934
935   fclose (fp);
936 }
937
938 static gint
939 compare_param_specs (const void *a, const void *b)
940 {
941   GParamSpec *spec_a = *(GParamSpec **)a;
942   GParamSpec *spec_b = *(GParamSpec **)b;
943
944   return strcmp (g_param_spec_get_name (spec_a), g_param_spec_get_name (spec_b));
945 }
946
947 /* Its common to have unsigned properties restricted
948  * to the signed range. Therefore we make this look
949  * a bit nicer by spelling out the max constants.
950  */
951
952 /* Don't use "==" with floats, it might trigger a gcc warning.  */
953 #define GTKDOC_COMPARE_FLOAT(x, y) (x <= y && x >= y)
954
955 static gchar*
956 describe_double_constant (gdouble value)
957 {
958   gchar *desc;
959
960   if (GTKDOC_COMPARE_FLOAT (value, G_MAXDOUBLE))
961     desc = g_strdup ("G_MAXDOUBLE");
962   else if (GTKDOC_COMPARE_FLOAT (value, G_MINDOUBLE))
963     desc = g_strdup ("G_MINDOUBLE");
964   else if (GTKDOC_COMPARE_FLOAT (value, -G_MAXDOUBLE))
965     desc = g_strdup ("-G_MAXDOUBLE");
966   else if (GTKDOC_COMPARE_FLOAT (value, G_MAXFLOAT))
967     desc = g_strdup ("G_MAXFLOAT");
968   else if (GTKDOC_COMPARE_FLOAT (value, G_MINFLOAT))
969     desc = g_strdup ("G_MINFLOAT");
970   else if (GTKDOC_COMPARE_FLOAT (value, -G_MAXFLOAT))
971     desc = g_strdup ("-G_MAXFLOAT");
972   else{
973     /* make sure floats are output with a decimal dot irrespective of
974     * current locale. Use formatd since we want human-readable numbers
975     * and do not need the exact same bit representation when deserialising */
976     desc = g_malloc0 (G_ASCII_DTOSTR_BUF_SIZE);
977     g_ascii_formatd (desc, G_ASCII_DTOSTR_BUF_SIZE, "%g", value);
978   }
979
980   return desc;
981 }
982
983 static gchar*
984 describe_signed_constant (gsize size, gint64 value)
985 {
986   gchar *desc = NULL;
987
988   switch (size) {
989     case 8:
990       if (value == G_MAXINT64)
991         desc = g_strdup ("G_MAXINT64");
992       else if (value == G_MININT64)
993         desc = g_strdup ("G_MININT64");
994       /* fall through */
995     case 4:
996       if (sizeof (int) == 4) {
997         if (value == G_MAXINT)
998           desc = g_strdup ("G_MAXINT");
999         else if (value == G_MININT)
1000           desc = g_strdup ("G_MININT");
1001         else if (value == (gint64)G_MAXUINT)
1002           desc = g_strdup ("G_MAXUINT");
1003       }
1004       if (value == G_MAXLONG)
1005         desc = g_strdup ("G_MAXLONG");
1006       else if (value == G_MINLONG)
1007         desc = g_strdup ("G_MINLONG");
1008       else if (value == (gint64)G_MAXULONG)
1009         desc = g_strdup ("G_MAXULONG");
1010       /* fall through */
1011     case 2:
1012       if (sizeof (int) == 2) {
1013         if (value == G_MAXINT)
1014           desc = g_strdup ("G_MAXINT");
1015         else if (value == G_MININT)
1016           desc = g_strdup ("G_MININT");
1017         else if (value == (gint64)G_MAXUINT)
1018           desc = g_strdup ("G_MAXUINT");
1019       }
1020       break;
1021     default:
1022       break;
1023   }
1024   if (!desc)
1025     desc = g_strdup_printf ("%" G_GINT64_FORMAT, value);
1026
1027   return desc;
1028 }
1029
1030 static gchar*
1031 describe_unsigned_constant (gsize size, guint64 value)
1032 {
1033   gchar *desc = NULL;
1034
1035   switch (size) {
1036     case 8:
1037       if (value == G_MAXINT64)
1038         desc = g_strdup ("G_MAXINT64");
1039       else if (value == G_MAXUINT64)
1040         desc = g_strdup ("G_MAXUINT64");
1041       /* fall through */
1042     case 4:
1043       if (sizeof (int) == 4) {
1044         if (value == (guint64)G_MAXINT)
1045           desc = g_strdup ("G_MAXINT");
1046         else if (value == G_MAXUINT)
1047           desc = g_strdup ("G_MAXUINT");
1048       }
1049       if (value == (guint64)G_MAXLONG)
1050         desc = g_strdup ("G_MAXLONG");
1051       else if (value == G_MAXULONG)
1052         desc = g_strdup ("G_MAXULONG");
1053       /* fall through */
1054     case 2:
1055       if (sizeof (int) == 2) {
1056         if (value == (guint64)G_MAXINT)
1057           desc = g_strdup ("G_MAXINT");
1058         else if (value == G_MAXUINT)
1059           desc = g_strdup ("G_MAXUINT");
1060       }
1061       break;
1062     default:
1063       break;
1064   }
1065   if (!desc)
1066     desc = g_strdup_printf ("%" G_GUINT64_FORMAT, value);
1067
1068   return desc;
1069 }
1070
1071 static gchar*
1072 describe_type (GParamSpec *spec)
1073 {
1074   gchar *desc;
1075   gchar *lower;
1076   gchar *upper;
1077
1078   if (G_IS_PARAM_SPEC_CHAR (spec))
1079     {
1080       GParamSpecChar *pspec = G_PARAM_SPEC_CHAR (spec);
1081
1082       lower = describe_signed_constant (sizeof(gchar), pspec->minimum);
1083       upper = describe_signed_constant (sizeof(gchar), pspec->maximum);
1084       if (pspec->minimum == G_MININT8 && pspec->maximum == G_MAXINT8)
1085         desc = g_strdup ("");
1086       else if (pspec->minimum == G_MININT8)
1087         desc = g_strdup_printf ("<= %s", upper);
1088       else if (pspec->maximum == G_MAXINT8)
1089         desc = g_strdup_printf (">= %s", lower);
1090       else
1091         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1092       g_free (lower);
1093       g_free (upper);
1094     }
1095   else if (G_IS_PARAM_SPEC_UCHAR (spec))
1096     {
1097       GParamSpecUChar *pspec = G_PARAM_SPEC_UCHAR (spec);
1098
1099       lower = describe_unsigned_constant (sizeof(guchar), pspec->minimum);
1100       upper = describe_unsigned_constant (sizeof(guchar), pspec->maximum);
1101       if (pspec->minimum == 0 && pspec->maximum == G_MAXUINT8)
1102         desc = g_strdup ("");
1103       else if (pspec->minimum == 0)
1104         desc = g_strdup_printf ("<= %s", upper);
1105       else if (pspec->maximum == G_MAXUINT8)
1106         desc = g_strdup_printf (">= %s", lower);
1107       else
1108         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1109       g_free (lower);
1110       g_free (upper);
1111     }
1112   else if (G_IS_PARAM_SPEC_INT (spec))
1113     {
1114       GParamSpecInt *pspec = G_PARAM_SPEC_INT (spec);
1115
1116       lower = describe_signed_constant (sizeof(gint), pspec->minimum);
1117       upper = describe_signed_constant (sizeof(gint), pspec->maximum);
1118       if (pspec->minimum == G_MININT && pspec->maximum == G_MAXINT)
1119         desc = g_strdup ("");
1120       else if (pspec->minimum == G_MININT)
1121         desc = g_strdup_printf ("<= %s", upper);
1122       else if (pspec->maximum == G_MAXINT)
1123         desc = g_strdup_printf (">= %s", lower);
1124       else
1125         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1126       g_free (lower);
1127       g_free (upper);
1128     }
1129   else if (G_IS_PARAM_SPEC_UINT (spec))
1130     {
1131       GParamSpecUInt *pspec = G_PARAM_SPEC_UINT (spec);
1132
1133       lower = describe_unsigned_constant (sizeof(guint), pspec->minimum);
1134       upper = describe_unsigned_constant (sizeof(guint), pspec->maximum);
1135       if (pspec->minimum == 0 && pspec->maximum == G_MAXUINT)
1136         desc = g_strdup ("");
1137       else if (pspec->minimum == 0)
1138         desc = g_strdup_printf ("<= %s", upper);
1139       else if (pspec->maximum == G_MAXUINT)
1140         desc = g_strdup_printf (">= %s", lower);
1141       else
1142         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1143       g_free (lower);
1144       g_free (upper);
1145     }
1146   else if (G_IS_PARAM_SPEC_LONG (spec))
1147     {
1148       GParamSpecLong *pspec = G_PARAM_SPEC_LONG (spec);
1149
1150       lower = describe_signed_constant (sizeof(glong), pspec->minimum);
1151       upper = describe_signed_constant (sizeof(glong), pspec->maximum);
1152       if (pspec->minimum == G_MINLONG && pspec->maximum == G_MAXLONG)
1153         desc = g_strdup ("");
1154       else if (pspec->minimum == G_MINLONG)
1155         desc = g_strdup_printf ("<= %s", upper);
1156       else if (pspec->maximum == G_MAXLONG)
1157         desc = g_strdup_printf (">= %s", lower);
1158       else
1159         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1160       g_free (lower);
1161       g_free (upper);
1162     }
1163   else if (G_IS_PARAM_SPEC_ULONG (spec))
1164     {
1165       GParamSpecULong *pspec = G_PARAM_SPEC_ULONG (spec);
1166
1167       lower = describe_unsigned_constant (sizeof(gulong), pspec->minimum);
1168       upper = describe_unsigned_constant (sizeof(gulong), pspec->maximum);
1169       if (pspec->minimum == 0 && pspec->maximum == G_MAXULONG)
1170         desc = g_strdup ("");
1171       else if (pspec->minimum == 0)
1172         desc = g_strdup_printf ("<= %s", upper);
1173       else if (pspec->maximum == G_MAXULONG)
1174         desc = g_strdup_printf (">= %s", lower);
1175       else
1176         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1177       g_free (lower);
1178       g_free (upper);
1179     }
1180   else if (G_IS_PARAM_SPEC_INT64 (spec))
1181     {
1182       GParamSpecInt64 *pspec = G_PARAM_SPEC_INT64 (spec);
1183
1184       lower = describe_signed_constant (sizeof(gint64), pspec->minimum);
1185       upper = describe_signed_constant (sizeof(gint64), pspec->maximum);
1186       if (pspec->minimum == G_MININT64 && pspec->maximum == G_MAXINT64)
1187         desc = g_strdup ("");
1188       else if (pspec->minimum == G_MININT64)
1189         desc = g_strdup_printf ("<= %s", upper);
1190       else if (pspec->maximum == G_MAXINT64)
1191         desc = g_strdup_printf (">= %s", lower);
1192       else
1193         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1194       g_free (lower);
1195       g_free (upper);
1196     }
1197   else if (G_IS_PARAM_SPEC_UINT64 (spec))
1198     {
1199       GParamSpecUInt64 *pspec = G_PARAM_SPEC_UINT64 (spec);
1200
1201       lower = describe_unsigned_constant (sizeof(guint64), pspec->minimum);
1202       upper = describe_unsigned_constant (sizeof(guint64), pspec->maximum);
1203       if (pspec->minimum == 0 && pspec->maximum == G_MAXUINT64)
1204         desc = g_strdup ("");
1205       else if (pspec->minimum == 0)
1206         desc = g_strdup_printf ("<= %s", upper);
1207       else if (pspec->maximum == G_MAXUINT64)
1208         desc = g_strdup_printf (">= %s", lower);
1209       else
1210         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1211       g_free (lower);
1212       g_free (upper);
1213     }
1214   else if (G_IS_PARAM_SPEC_FLOAT (spec))
1215     {
1216       GParamSpecFloat *pspec = G_PARAM_SPEC_FLOAT (spec);
1217
1218       lower = describe_double_constant (pspec->minimum);
1219       upper = describe_double_constant (pspec->maximum);
1220       if (GTKDOC_COMPARE_FLOAT (pspec->minimum, -G_MAXFLOAT))
1221         {
1222           if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXFLOAT))
1223             desc = g_strdup ("");
1224           else
1225             desc = g_strdup_printf ("<= %s", upper);
1226         }
1227       else if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXFLOAT))
1228         desc = g_strdup_printf (">= %s", lower);
1229       else
1230         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1231       g_free (lower);
1232       g_free (upper);
1233     }
1234   else if (G_IS_PARAM_SPEC_DOUBLE (spec))
1235     {
1236       GParamSpecDouble *pspec = G_PARAM_SPEC_DOUBLE (spec);
1237
1238       lower = describe_double_constant (pspec->minimum);
1239       upper = describe_double_constant (pspec->maximum);
1240       if (GTKDOC_COMPARE_FLOAT (pspec->minimum, -G_MAXDOUBLE))
1241         {
1242           if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXDOUBLE))
1243             desc = g_strdup ("");
1244           else
1245             desc = g_strdup_printf ("<= %s", upper);
1246         }
1247       else if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXDOUBLE))
1248         desc = g_strdup_printf (">= %s", lower);
1249       else
1250         desc = g_strdup_printf ("[%s,%s]", lower, upper);
1251       g_free (lower);
1252       g_free (upper);
1253     }
1254 #if GLIB_CHECK_VERSION (2, 12, 0)
1255   else if (G_IS_PARAM_SPEC_GTYPE (spec))
1256     {
1257       GParamSpecGType *pspec = G_PARAM_SPEC_GTYPE (spec);
1258       gboolean is_pointer;
1259
1260       desc = g_strdup (get_type_name (pspec->is_a_type, &is_pointer));
1261     }
1262 #endif
1263 #if GLIB_CHECK_VERSION (2, 25, 9)
1264   else if (G_IS_PARAM_SPEC_VARIANT (spec))
1265     {
1266       GParamSpecVariant *pspec = G_PARAM_SPEC_VARIANT (spec);
1267       gchar *variant_type;
1268
1269       variant_type = g_variant_type_dup_string (pspec->type);
1270       desc = g_strdup_printf ("GVariant<%s>", variant_type);
1271       g_free (variant_type);
1272     }
1273 #endif
1274   else
1275     {
1276       desc = g_strdup ("");
1277     }
1278
1279   return desc;
1280 }
1281
1282 static gchar*
1283 describe_default (GParamSpec *spec)
1284 {
1285   gchar *desc;
1286
1287   if (G_IS_PARAM_SPEC_CHAR (spec))
1288     {
1289       GParamSpecChar *pspec = G_PARAM_SPEC_CHAR (spec);
1290
1291       desc = g_strdup_printf ("%d", pspec->default_value);
1292     }
1293   else if (G_IS_PARAM_SPEC_UCHAR (spec))
1294     {
1295       GParamSpecUChar *pspec = G_PARAM_SPEC_UCHAR (spec);
1296
1297       desc = g_strdup_printf ("%u", pspec->default_value);
1298     }
1299   else if (G_IS_PARAM_SPEC_BOOLEAN (spec))
1300     {
1301       GParamSpecBoolean *pspec = G_PARAM_SPEC_BOOLEAN (spec);
1302
1303       desc = g_strdup_printf ("%s", pspec->default_value ? "TRUE" : "FALSE");
1304     }
1305   else if (G_IS_PARAM_SPEC_INT (spec))
1306     {
1307       GParamSpecInt *pspec = G_PARAM_SPEC_INT (spec);
1308
1309       desc = g_strdup_printf ("%d", pspec->default_value);
1310     }
1311   else if (G_IS_PARAM_SPEC_UINT (spec))
1312     {
1313       GParamSpecUInt *pspec = G_PARAM_SPEC_UINT (spec);
1314
1315       desc = g_strdup_printf ("%u", pspec->default_value);
1316     }
1317   else if (G_IS_PARAM_SPEC_LONG (spec))
1318     {
1319       GParamSpecLong *pspec = G_PARAM_SPEC_LONG (spec);
1320
1321       desc = g_strdup_printf ("%ld", pspec->default_value);
1322     }
1323   else if (G_IS_PARAM_SPEC_LONG (spec))
1324     {
1325       GParamSpecULong *pspec = G_PARAM_SPEC_ULONG (spec);
1326
1327       desc = g_strdup_printf ("%lu", pspec->default_value);
1328     }
1329   else if (G_IS_PARAM_SPEC_INT64 (spec))
1330     {
1331       GParamSpecInt64 *pspec = G_PARAM_SPEC_INT64 (spec);
1332
1333       desc = g_strdup_printf ("%" G_GINT64_FORMAT, pspec->default_value);
1334     }
1335   else if (G_IS_PARAM_SPEC_UINT64 (spec))
1336     {
1337       GParamSpecUInt64 *pspec = G_PARAM_SPEC_UINT64 (spec);
1338
1339       desc = g_strdup_printf ("%" G_GUINT64_FORMAT, pspec->default_value);
1340     }
1341   else if (G_IS_PARAM_SPEC_UNICHAR (spec))
1342     {
1343       GParamSpecUnichar *pspec = G_PARAM_SPEC_UNICHAR (spec);
1344
1345       if (g_unichar_isprint (pspec->default_value))
1346         desc = g_strdup_printf ("'%c'", pspec->default_value);
1347       else
1348         desc = g_strdup_printf ("%u", pspec->default_value);
1349     }
1350   else if (G_IS_PARAM_SPEC_ENUM (spec))
1351     {
1352       GParamSpecEnum *pspec = G_PARAM_SPEC_ENUM (spec);
1353
1354       GEnumValue *value = g_enum_get_value (pspec->enum_class, pspec->default_value);
1355       if (value)
1356         desc = g_strdup_printf ("%s", value->value_name);
1357       else
1358         desc = g_strdup_printf ("%d", pspec->default_value);
1359     }
1360   else if (G_IS_PARAM_SPEC_FLAGS (spec))
1361     {
1362       GParamSpecFlags *pspec = G_PARAM_SPEC_FLAGS (spec);
1363       guint default_value;
1364       GString *acc;
1365
1366       default_value = pspec->default_value;
1367       acc = g_string_new ("");
1368
1369       while (default_value)
1370         {
1371           GFlagsValue *value = g_flags_get_first_value (pspec->flags_class, default_value);
1372
1373           if (!value)
1374             break;
1375
1376           if (acc->len > 0)
1377             g_string_append (acc, "|");
1378           g_string_append (acc, value->value_name);
1379
1380           default_value &= ~value->value;
1381         }
1382
1383       if (default_value == 0)
1384         desc = g_string_free (acc, FALSE);
1385       else
1386         {
1387           desc = g_strdup_printf ("%d", pspec->default_value);
1388           g_string_free (acc, TRUE);
1389         }
1390     }
1391   else if (G_IS_PARAM_SPEC_FLOAT (spec))
1392     {
1393       GParamSpecFloat *pspec = G_PARAM_SPEC_FLOAT (spec);
1394
1395       /* make sure floats are output with a decimal dot irrespective of
1396        * current locale. Use formatd since we want human-readable numbers
1397        * and do not need the exact same bit representation when deserialising */
1398       desc = g_malloc0 (G_ASCII_DTOSTR_BUF_SIZE);
1399       g_ascii_formatd (desc, G_ASCII_DTOSTR_BUF_SIZE, "%g",
1400           pspec->default_value);
1401     }
1402   else if (G_IS_PARAM_SPEC_DOUBLE (spec))
1403     {
1404       GParamSpecDouble *pspec = G_PARAM_SPEC_DOUBLE (spec);
1405
1406       /* make sure floats are output with a decimal dot irrespective of
1407        * current locale. Use formatd since we want human-readable numbers
1408        * and do not need the exact same bit representation when deserialising */
1409       desc = g_malloc0 (G_ASCII_DTOSTR_BUF_SIZE);
1410       g_ascii_formatd (desc, G_ASCII_DTOSTR_BUF_SIZE, "%g",
1411           pspec->default_value);
1412     }
1413   else if (G_IS_PARAM_SPEC_STRING (spec))
1414     {
1415       GParamSpecString *pspec = G_PARAM_SPEC_STRING (spec);
1416
1417       if (pspec->default_value)
1418         {
1419           gchar *esc = g_strescape (pspec->default_value, NULL);
1420
1421           desc = g_strdup_printf ("\\"%s\\"", esc);
1422
1423           g_free (esc);
1424         }
1425       else
1426         desc = g_strdup_printf ("NULL");
1427     }
1428   else
1429     {
1430       desc = g_strdup ("");
1431     }
1432
1433   return desc;
1434 }
1435
1436
1437 static void
1438 output_object_args (FILE *fp, GType object_type)
1439 {
1440   gpointer class;
1441   const gchar *object_class_name;
1442   guint arg;
1443   gchar flags[16], *pos;
1444   GParamSpec **properties;
1445   guint n_properties;
1446   gboolean child_prop;
1447   gboolean style_prop;
1448   gboolean is_pointer;
1449   const gchar *type_name;
1450   gchar *type_desc;
1451   gchar *default_value;
1452
1453   if (G_TYPE_IS_OBJECT (object_type))
1454     {
1455       class = g_type_class_peek (object_type);
1456       if (!class)
1457         return;
1458
1459       properties = g_object_class_list_properties (class, &n_properties);
1460     }
1461 #if GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 3)
1462   else if (G_TYPE_IS_INTERFACE (object_type))
1463     {
1464       class = g_type_default_interface_ref (object_type);
1465
1466       if (!class)
1467         return;
1468
1469       properties = g_object_interface_list_properties (class, &n_properties);
1470     }
1471 #endif
1472   else
1473     return;
1474
1475   object_class_name = g_type_name (object_type);
1476
1477   child_prop = FALSE;
1478   style_prop = FALSE;
1479
1480   while (TRUE) {
1481     qsort (properties, n_properties, sizeof (GParamSpec *), compare_param_specs);
1482     for (arg = 0; arg < n_properties; arg++)
1483       {
1484         GParamSpec *spec = properties[arg];
1485         const gchar *nick, *blurb, *dot;
1486
1487         if (spec->owner_type != object_type)
1488           continue;
1489
1490         pos = flags;
1491         /* We use one-character flags for simplicity. */
1492         if (child_prop && !style_prop)
1493           *pos++ = 'c';
1494         if (style_prop)
1495           *pos++ = 's';
1496         if (spec->flags & G_PARAM_READABLE)
1497           *pos++ = 'r';
1498         if (spec->flags & G_PARAM_WRITABLE)
1499           *pos++ = 'w';
1500         if (spec->flags & G_PARAM_CONSTRUCT)
1501           *pos++ = 'x';
1502         if (spec->flags & G_PARAM_CONSTRUCT_ONLY)
1503           *pos++ = 'X';
1504         *pos = 0;
1505
1506         nick = g_param_spec_get_nick (spec);
1507         blurb = g_param_spec_get_blurb (spec);
1508
1509         dot = "";
1510         if (blurb) {
1511           int str_len = strlen (blurb);
1512           if (str_len > 0  && blurb[str_len - 1] != '.')
1513             dot = ".";
1514         }
1515
1516         type_desc = describe_type (spec);
1517         default_value = describe_default (spec);
1518         type_name = get_type_name (spec->value_type, &is_pointer);
1519         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",
1520                  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);
1521         g_free (type_desc);
1522         g_free (default_value);
1523       }
1524
1525     g_free (properties);
1526
1527 #ifdef GTK_IS_CONTAINER_CLASS
1528     if (!child_prop && GTK_IS_CONTAINER_CLASS (class)) {
1529       properties = gtk_container_class_list_child_properties (class, &n_properties);
1530       child_prop = TRUE;
1531       continue;
1532     }
1533 #endif
1534
1535 #ifdef GTK_IS_CELL_AREA_CLASS
1536     if (!child_prop && GTK_IS_CELL_AREA_CLASS (class)) {
1537       properties = gtk_cell_area_class_list_cell_properties (class, &n_properties);
1538       child_prop = TRUE;
1539       continue;
1540     }
1541 #endif
1542
1543 #ifdef GTK_IS_WIDGET_CLASS
1544 #if GTK_CHECK_VERSION(2,1,0)
1545     if (!style_prop && GTK_IS_WIDGET_CLASS (class)) {
1546       properties = gtk_widget_class_list_style_properties (GTK_WIDGET_CLASS (class), &n_properties);
1547       style_prop = TRUE;
1548       continue;
1549     }
1550 #endif
1551 #endif
1552
1553     break;
1554   }
1555 }
1556 EOT
1557
1558 close OUTPUT;
1559
1560 # Compile and run our file
1561
1562 $CC = $ENV{CC} ? $ENV{CC} : "gcc";
1563 $LD = $ENV{LD} ? $ENV{LD} : $CC;
1564 $CFLAGS = $ENV{CFLAGS} ? "$ENV{CFLAGS}" : "";
1565 $LDFLAGS = $ENV{LDFLAGS} ? $ENV{LDFLAGS} : "";
1566
1567 my $o_file;
1568 if ($CC =~ /libtool/) {
1569   $o_file  = "$MODULE-scan.lo"
1570 } else {
1571   $o_file = "$MODULE-scan.o"
1572 }
1573
1574 my $stdout="";
1575 if (!defined($VERBOSE) or $VERBOSE eq "0") {
1576     $stdout=">/dev/null";
1577 }
1578
1579 # Compiling scanner
1580 $command = "$CC $stdout $CFLAGS -c -o $o_file $MODULE-scan.c";
1581 system("($command)") == 0 or die "Compilation of scanner failed: $!\n";
1582
1583 # Linking scanner
1584 $command = "$LD $stdout -o $MODULE-scan $o_file $LDFLAGS";
1585 system($command) == 0 or die "Linking of scanner failed: $!\n";
1586
1587 # Running scanner $MODULE-scan ";
1588 system("sh -c ./$MODULE-scan") == 0 or die "Scan failed: $!\n";
1589
1590 if (!defined($ENV{"GTK_DOC_KEEP_INTERMEDIATE"})) {
1591   unlink "./$MODULE-scan.c", "./$MODULE-scan.o", "./$MODULE-scan.lo", "./$MODULE-scan";
1592 }
1593
1594 &UpdateFileIfChanged ($old_hierarchy_filename, $new_hierarchy_filename, 0);
1595 # we will merge these in scangobj-merge.py
1596 #&UpdateFileIfChanged ($old_interfaces_filename, $new_interfaces_filename, 0);
1597 #&UpdateFileIfChanged ($old_prerequisites_filename, $new_prerequisites_filename, 0);
1598 #&UpdateFileIfChanged ($old_signals_filename, $new_signals_filename, 0);
1599 #&UpdateFileIfChanged ($old_args_filename, $new_args_filename, 0);
1600