Updated Spanish translation
[gtk-doc.git] / gtkdoc-scanobj.in
blob5745cffae02f3492296157db4733a41c9dc3c913
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 heirarchies 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 $PRINT_VERSION;
40 %optctl = (module => \$MODULE,
41            types => \$TYPES_FILE,
42            nogtkinit => \$NO_GTK_INIT,
43            'output-dir' => \$OUTPUT_DIR,
44            'version' => \$PRINT_VERSION,
45            'help' => \$PRINT_HELP);
47 GetOptions(\%optctl, "module=s", "types:s", "output-dir:s", "nogtkinit", "version", "help");
49 if ($PRINT_VERSION) {
50     print "@VERSION@\n";
51     exit 0;
54 if (!$MODULE) {
55     $PRINT_HELP = 1;
58 if ($PRINT_HELP) {
59     print <<EOF;
60 gtkdoc-scanobj version @VERSION@ - introspect gtk-objects
62 --module=MODULE_NAME          Name of the doc module being parsed
63 --types=FILE                  The name of the file to store the types in
64 --output-dir=DIRNAME          The directory where the results are stored
65 --version                     Print the version of this program
66 --help                        Print this help
67 EOF
68     exit 0;
71 $OUTPUT_DIR = $OUTPUT_DIR ? $OUTPUT_DIR : ".";
73 $TYPES_FILE = $TYPES_FILE ? $TYPES_FILE : "$OUTPUT_DIR/$MODULE.types";
75 open (TYPES, $TYPES_FILE) || die "Cannot open $TYPES_FILE: $!\n";
76 open (OUTPUT, ">$MODULE-scan.c") || die "Cannot open $MODULE-scan.c: $!\n";
78 my $old_signals_filename = "$OUTPUT_DIR/$MODULE.signals";
79 my $new_signals_filename = "$OUTPUT_DIR/$MODULE.signals.new";
80 my $old_hierarchy_filename = "$OUTPUT_DIR/$MODULE.hierarchy";
81 my $new_hierarchy_filename = "$OUTPUT_DIR/$MODULE.hierarchy.new";
82 my $old_args_filename = "$OUTPUT_DIR/$MODULE.args";
83 my $new_args_filename = "$OUTPUT_DIR/$MODULE.args.new";
85 # write a C program to scan the types
87 $includes = "";
88 @types = ();
90 for (<TYPES>) {
91     if (/^#include/) {
92         $includes .= $_;
93     } elsif (/^%/) {
94         next;
95     } elsif (/^\s*$/) {
96         next;
97     } else {
98         chomp;
99         push @types, $_;
100     }
103 $ntypes = @types + 1;
105 print OUTPUT <<EOT;
106 #include <string.h>
107 #include <stdlib.h>
108 #include <stdio.h>
109 #include <errno.h>
111 $includes
112 GtkType object_types[$ntypes];
114 GtkType *
115 get_object_types (void)
117     gint i = 0;
120 for (@types) {
121     print OUTPUT "    object_types[i++] = $_ ();\n";
124 print OUTPUT <<EOT;
125     object_types[i] = 0;
127     return object_types;
131  * This uses GTK type functions to output signal prototypes and the widget
132  * hierarchy.
133  */
135 /* The output files */
136 gchar *signals_filename = "$new_signals_filename";
137 gchar *hierarchy_filename = "$new_hierarchy_filename";
138 gchar *args_filename = "$new_args_filename";
141 static void output_signals (void);
142 static void output_widget_signals (FILE *fp,
143                                    GtkType object_type);
144 static void output_widget_signal (FILE *fp,
145                                   GtkType object_type,
146                                   gchar *object_class_name,
147                                   guint signal_id);
148 static gchar * get_type_name (GtkType type,
149                               gboolean * is_pointer);
150 static void output_widget_hierarchy (void);
151 static void output_hierarchy (FILE *fp,
152                               GtkType type,
153                               guint level);
155 static void output_args (void);
156 static void output_widget_args (FILE *fp, GtkType object_type);
159 main (int argc, char *argv[])
163   if ($NO_GTK_INIT) {
164     print OUTPUT <<EOT;
165   gtk_type_init ();
167   } else {
168     print OUTPUT <<EOT;
169   gtk_init (&argc, &argv);
171   }
173 print OUTPUT <<EOT;
174   get_object_types ();
176   output_signals ();
177   output_widget_hierarchy ();
178   output_args ();
180   return 0;
184 static void
185 output_signals (void)
187   FILE *fp;
188   gint i;
190   fp = fopen (signals_filename, "w");
191   if (fp == NULL)
192     {
193       g_warning ("Couldn't open output file: %s : %s", signals_filename, g_strerror(errno));
194       return;
195     }
197   for (i = 0; object_types[i]; i++)
198     output_widget_signals (fp, object_types[i]);
200   fclose (fp);
204 /* This outputs all the signals of one widget. */
205 static void
206 output_widget_signals (FILE *fp, GtkType object_type)
208   GtkObjectClass *class;
209   gchar *object_class_name;
210   guint sig;
212   class = gtk_type_class (object_type);
213   if (!class || class->nsignals == 0)
214     return;
216   object_class_name = gtk_type_name (object_type);
218   for (sig = 0; sig < class->nsignals; sig++)
219     {
220       if (!class->signals[sig])
221         {
222           /*g_print ("Signal slot [%u] is empty\\n", sig);*/
223           continue;
224         }
226       output_widget_signal (fp, object_type, object_class_name,
227                             class->signals[sig]);
228     }
232 /* This outputs one signal. */
233 static void
234 output_widget_signal (FILE *fp,
235                       GtkType object_type,
236                       gchar *object_name,
237                       guint signal_id)
239   GtkSignalQuery *query_info;
240   gchar *ret_type, *pos, *type_name, *arg_name, *object_arg, *object_arg_start;
241   gboolean is_pointer;
242   gchar buffer[1024];
243   guint i, param;
244   gint param_num, widget_num, event_num, callback_num;
245   gint *arg_num;
246   gchar signal_name[128];
248   /*  g_print ("Object: %s Type: %i Signal: %u\\n", object_name, object_type,
249       signal_id);*/
251   param_num = 1;
252   widget_num = event_num = callback_num = 0;
254   query_info = gtk_signal_query (signal_id);
255   if (query_info == NULL)
256     {
257       g_warning ("Couldn't query signal");
258       return;
259     }
261   /* Output the signal object type and the argument name. We assume the
262      type is a pointer - I think that is OK. We remove "Gtk" or "Gnome" and
263      convert to lower case for the argument name. */
264   pos = buffer;
265   sprintf (pos, "%s ", object_name);
266   pos += strlen (pos);
268   /* Try to come up with a sensible variable name for the first arg
269    * I chops off 2 know prefixes :/ and makes the name lowercase
270    * It should replace lowercase -> uppercase with '_'
271    * see gtkdoc-scangobject.in for better algorithm
272    */
273   if (!strncmp (object_name, "Gtk", 3))
274       object_arg = object_name + 3;
275   else if (!strncmp (object_name, "Gnome", 5))
276       object_arg = object_name + 5;
277   else
278       object_arg = object_name;
280   object_arg_start = pos;
281   sprintf (pos, "*%s\\n", object_arg);
282   pos += strlen (pos);
283   g_strdown (object_arg_start);
284   if (!strcmp (object_arg_start, "widget"))
285     widget_num++;
287   /* Convert signal name to use underscores rather than dashes '-'. */
288   strncpy (signal_name, query_info->signal_name, 127);
289   signal_name[127] = '\\0';
290   for (i = 0; signal_name[i]; i++)
291     {
292       if (signal_name[i] == '-')
293         signal_name[i] = '_';
294     }
296   /* Output the signal parameters. */
297   for (param = 0; param < query_info->nparams; param++)
298     {
299       type_name = get_type_name (query_info->params[param], &is_pointer);
301       /* Most arguments to the callback are called "arg1", "arg2", etc.
302          GtkWidgets are called "widget", "widget2", ...
303          GtkCallbacks are called "callback", "callback2", ... */
304       if (!strcmp (type_name, "GtkWidget"))
305         {
306           arg_name = "widget";
307           arg_num = &widget_num;
308         }
309       else if (!strcmp (type_name, "GtkCallback")
310                || !strcmp (type_name, "GtkCCallback"))
311         {
312           arg_name = "callback";
313           arg_num = &callback_num;
314         }
315       else
316         {
317           arg_name = "arg";
318           arg_num = &param_num;
319         }
320       sprintf (pos, "%s ", type_name);
321       pos += strlen (pos);
323       if (!arg_num || *arg_num == 0)
324         sprintf (pos, "%s%s\\n", is_pointer ? "*" : " ", arg_name);
325       else
326         sprintf (pos, "%s%s%i\\n", is_pointer ? "*" : " ", arg_name,
327                  *arg_num);
328           pos += strlen (pos);
330           if (arg_num)
331             *arg_num += 1;
332     }
334   /* Output the return type and function name. */
335   ret_type = get_type_name (query_info->return_val, &is_pointer);
337   fprintf (fp,
338            "<SIGNAL>\\n<NAME>%s::%s</NAME>\\n<RETURNS>%s%s</RETURNS>\\n%s</SIGNAL>\\n\\n",
339            object_name, query_info->signal_name, ret_type, is_pointer ? "*" : "", buffer);
340   g_free (query_info);
344 /* Returns the type name to use for a signal argument or return value, given
345    the GtkType from the signal info. It also sets is_pointer to TRUE if the
346    argument needs a '*' since it is a pointer. */
347 static gchar *
348 get_type_name (GtkType type, gboolean * is_pointer)
350   gchar *type_name;
352   *is_pointer = FALSE;
353   type_name = gtk_type_name (type);
355   switch (type) {
356   case GTK_TYPE_NONE:
357   case GTK_TYPE_CHAR:
358   case GTK_TYPE_UCHAR:
359   case GTK_TYPE_BOOL:
360   case GTK_TYPE_INT:
361   case GTK_TYPE_UINT:
362   case GTK_TYPE_LONG:
363   case GTK_TYPE_ULONG:
364   case GTK_TYPE_FLOAT:
365   case GTK_TYPE_DOUBLE:
366   case GTK_TYPE_POINTER:
367     /* These all have normal C type names so they are OK. */
368     return type_name;
370   case GTK_TYPE_STRING:
371     /* A GtkString is really a gchar*. */
372     *is_pointer = TRUE;
373     return "gchar";
375   case GTK_TYPE_ENUM:
376   case GTK_TYPE_FLAGS:
377     /* We use a gint for both of these. Hopefully a subtype with a decent
378        name will be registered and used instead, as GTK+ does itself. */
379     return "gint";
381   case GTK_TYPE_BOXED:
382     /* A boxed value is just an opaque pointer, I think. */
383     return "gpointer";
385   case GTK_TYPE_SIGNAL:
386   case GTK_TYPE_ARGS:
387   case GTK_TYPE_FOREIGN:
388   case GTK_TYPE_CALLBACK:
389   case GTK_TYPE_C_CALLBACK:
390     /* FIXME: These are wrong. I think they expand into more than 1 argument.
391        See the GtkArg struct in gtktypeutils.h and gtkargcollector.c.
392        Fortunately I doubt anything uses these as signal args. */
393     return "gpointer";
395   default:
396     break;
397   }
399   /* For all GtkObject subclasses we can use the class name with a "*",
400      e.g. 'GtkWidget *'. */
401   if (gtk_type_is_a (type, GTK_TYPE_OBJECT))
402     *is_pointer = TRUE;
404   return type_name;
408 /* This outputs the hierarchy of all widgets which have been initialized,
409    i.e. by calling their XXX_get_type() initialization function. */
410 static void
411 output_widget_hierarchy (void)
413   FILE *fp;
415   fp = fopen (hierarchy_filename, "w");
416   if (fp == NULL)
417     {
418       g_warning ("Couldn't open output file: %s : %s", hierarchy_filename, g_strerror(errno));
419       return;
420     }
421   output_hierarchy (fp, GTK_TYPE_OBJECT, 0);
422   fclose (fp);
426 /* This is called recursively to output the hierarchy of a widget. */
427 static void
428 output_hierarchy (FILE *fp,
429                   GtkType type,
430                   guint level)
432   GList *list;
433   guint i;
435   if (!type)
436     return;
438   for (i = 0; i < level; i++)
439     fprintf (fp, "  ");
440   fprintf (fp, "%s\\n", gtk_type_name (type));
442   list = gtk_type_children_types (type);
444   while (list)
445     {
446       GtkType child = (GtkType) list->data;
447       output_hierarchy (fp, child, level + 1);
448       list = list->next;
449     }
453 static void
454 output_args (void)
456   FILE *fp;
457   gint i;
459   fp = fopen (args_filename, "w");
460   if (fp == NULL)
461     {
462       g_warning ("Couldn't open output file: %s : %s", args_filename, g_strerror(errno));
463       return;
464     }
466   for (i = 0; object_types[i]; i++)
467     output_widget_args (fp, object_types[i]);
469   fclose (fp);
473 static void
474 output_widget_args (FILE *fp, GtkType object_type)
476   GtkObjectClass *class;
477   gchar *object_class_name;
478   GtkArg *args;
479   guint32 *arg_flags;
480   guint n_args;
481   guint arg;
482   gchar flags[16], *pos;
484   class = gtk_type_class (object_type);
485   if (!class)
486     return;
488   object_class_name = gtk_type_name (object_type);
490   args = gtk_object_query_args (class->type, &arg_flags, &n_args);
492   for (arg = 0; arg < n_args; arg++)
493     {
494       pos = flags;
495       /* We use one-character flags for simplicity. */
496       if (arg_flags[arg] & GTK_ARG_READABLE)
497         *pos++ = 'r';
498       if (arg_flags[arg] & GTK_ARG_WRITABLE)
499         *pos++ = 'w';
500       if (arg_flags[arg] & GTK_ARG_CONSTRUCT)
501         *pos++ = 'x';
502       if (arg_flags[arg] & GTK_ARG_CONSTRUCT_ONLY)
503         *pos++ = 'X';
504       if (arg_flags[arg] & GTK_ARG_CHILD_ARG)
505         *pos++ = 'c';
506       *pos = 0;
508       fprintf (fp, "<ARG>\\n<NAME>%s</NAME>\\n<TYPE>%s</TYPE>\\n<FLAGS>%s</FLAGS>\\n</ARG>\\n\\n",
509                args[arg].name, gtk_type_name (args[arg].type), flags);
510     }
512   g_free (args);
513   g_free (arg_flags);
517 close OUTPUT;
519 # Compile and run our file
521 $CC = $ENV{CC} ? $ENV{CC} : "gcc";
522 $LD = $ENV{LD} ? $ENV{LD} : $CC;
523 $CFLAGS = $ENV{CFLAGS} ? $ENV{CFLAGS} : "";
524 $LDFLAGS = $ENV{LDFLAGS} ? $ENV{LDFLAGS} : "";
525 $RUN = $ENV{RUN} ? $ENV{RUN} : "";
527 my $o_file;
528 if ($CC =~ /libtool/) {
529   $o_file  = "$MODULE-scan.lo"
530 } else {
531   $o_file = "$MODULE-scan.o"
534 # Compiling scanner
535 $command = "$CC $CFLAGS -c -o $o_file $MODULE-scan.c";
536 system("($command)") == 0 or die "Compilation of scanner failed: $!\n";
538 # Linking scanner
539 # FIXME: Can we turn off as-needed for the docs (or better fix it?)
540 #$command = "$LD -Wl,--no-as-needed $o_file $LDFLAGS -o $MODULE-scan";
541 $command = "$LD $o_file $LDFLAGS -o $MODULE-scan";
542 system("($command)") == 0 or die "Linking of scanner failed: $!\n";
544 # Running scanner $MODULE-scan ";
545 system("($RUN ./$MODULE-scan)") == 0 or die "Scan failed: $!\n";
547 if (!defined($ENV{"GTK_DOC_KEEP_INTERMEDIATE"})) {
548   unlink "./$MODULE-scan.c", "./$MODULE-scan.o", "./$MODULE-scan.lo", "./$MODULE-scan";
551 &UpdateFileIfChanged ($old_signals_filename, $new_signals_filename, 0);
552 &UpdateFileIfChanged ($old_hierarchy_filename, $new_hierarchy_filename, 0);
553 &UpdateFileIfChanged ($old_args_filename, $new_args_filename, 0);