Add testcase for #501038. Improve struct parsing to correctly finish if
[gtk-doc.git] / gtkdoc-scanobj.in
blob3098ef3ebd8383001a1479dd2e03fd8ef452fbc2
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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.
27 # NOTE: the lookup_signal_arg_names() function contains the argument names of
28 #       standard GTK signal handlers. This may need to be updated for new
29 #       GTK signals or Gnome widget signals.
31 use Getopt::Long;
33 unshift @INC, '@PACKAGE_DATA_DIR@';
34 require "gtkdoc-common.pl";
36 # Options
38 # name of documentation module
39 my $MODULE;
40 my $OUTPUT_DIR;
41 my $PRINT_VERSION;
43 %optctl = (module => \$MODULE,
44            types => \$TYPES_FILE,
45            nogtkinit => \$NO_GTK_INIT,
46            'output-dir' => \$OUTPUT_DIR,
47            'version' => \$PRINT_VERSION);
48            
49 GetOptions(\%optctl, "module=s", "types:s", "output-dir:s", "nogtkinit", "version");
51 if ($PRINT_VERSION) {
52     print "@VERSION@\n";
53     exit 0;
56 $OUTPUT_DIR = $OUTPUT_DIR ? $OUTPUT_DIR : ".";
58 $TYPES_FILE = $TYPES_FILE ? $TYPES_FILE : "$OUTPUT_DIR/$MODULE.types";
60 open (TYPES, $TYPES_FILE) || die "Cannot open $TYPES_FILE: $!\n";
61 open (OUTPUT, ">$MODULE-scan.c") || die "Cannot open $MODULE-scan.c: $!\n";
63 my $old_signals_filename = "$OUTPUT_DIR/$MODULE.signals";
64 my $new_signals_filename = "$OUTPUT_DIR/$MODULE.signals.new";
65 my $old_hierarchy_filename = "$OUTPUT_DIR/$MODULE.hierarchy";
66 my $new_hierarchy_filename = "$OUTPUT_DIR/$MODULE.hierarchy.new";
67 my $old_args_filename = "$OUTPUT_DIR/$MODULE.args";
68 my $new_args_filename = "$OUTPUT_DIR/$MODULE.args.new";
70 # write a C program to scan the types
72 $includes = "";
73 @types = ();
75 for (<TYPES>) {
76     if (/^#include/) {
77         $includes .= $_;
78     } elsif (/^%/) {
79         next;
80     } elsif (/^\s*$/) {
81         next;
82     } else {
83         chomp;
84         push @types, $_;
85     }
88 $ntypes = @types + 1;
90 print OUTPUT <<EOT;
91 #include <string.h>
92 #include <stdlib.h>
93 #include <stdio.h>
94 #include <errno.h>
96 $includes
97 GtkType object_types[$ntypes];
99 GtkType *
100 get_object_types (void)
102     gint i = 0;
105 for (@types) {
106     print OUTPUT "    object_types[i++] = $_ ();\n";
109 print OUTPUT <<EOT;
110     object_types[i] = 0;
112     return object_types;
116  * This uses GTK type functions to output signal prototypes and the widget
117  * hierarchy.
118  */
120 /* The output files */
121 gchar *signals_filename = "$new_signals_filename";
122 gchar *hierarchy_filename = "$new_hierarchy_filename";
123 gchar *args_filename = "$new_args_filename";
126 static void output_signals (void);
127 static void output_widget_signals (FILE *fp,
128                                    GtkType object_type);
129 static void output_widget_signal (FILE *fp,
130                                   GtkType object_type,
131                                   gchar *object_class_name,
132                                   guint signal_id);
133 static gchar * get_type_name (GtkType type,
134                               gboolean * is_pointer);
135 static gchar * get_gdk_event (const gchar * signal_name);
136 static gchar ** lookup_signal_arg_names (gchar * type,
137                                          const gchar * signal_name);
139 static void output_widget_hierarchy (void);
140 static void output_hierarchy (FILE *fp,
141                               GtkType type,
142                               guint level);
144 static void output_args (void);
145 static void output_widget_args (FILE *fp, GtkType object_type);
148 main (int argc, char *argv[])
152   if ($NO_GTK_INIT) {
153     print OUTPUT <<EOT;
154   gtk_type_init ();
156   } else {
157     print OUTPUT <<EOT;
158   gtk_init (&argc, &argv);
160   }
162 print OUTPUT <<EOT;
163   get_object_types ();
165   output_signals ();
166   output_widget_hierarchy ();
167   output_args ();
169   return 0;
173 static void
174 output_signals (void)
176   FILE *fp;
177   gint i;
179   fp = fopen (signals_filename, "w");
180   if (fp == NULL)
181     {
182       g_warning ("Couldn't open output file: %s : %s", signals_filename, strerror(errno));
183       return;
184     }
186   for (i = 0; object_types[i]; i++)
187     output_widget_signals (fp, object_types[i]);
189   fclose (fp);
193 /* This outputs all the signals of one widget. */
194 static void
195 output_widget_signals (FILE *fp, GtkType object_type)
197   GtkObjectClass *class;
198   gchar *object_class_name;
199   guint sig;
201   class = gtk_type_class (object_type);
202   if (!class || class->nsignals == 0)
203     return;
205   object_class_name = gtk_type_name (object_type);
207   for (sig = 0; sig < class->nsignals; sig++)
208     {
209       if (!class->signals[sig])
210         {
211           /*g_print ("Signal slot [%u] is empty\\n", sig);*/
212           continue;
213         }
215       output_widget_signal (fp, object_type, object_class_name,
216                             class->signals[sig]);
217     }
221 /* This outputs one signal. */
222 static void
223 output_widget_signal (FILE *fp,
224                       GtkType object_type,
225                       gchar *object_name,
226                       guint signal_id)
228   GtkSignalQuery *query_info;
229   gchar *ret_type, *pos, *type_name, *arg_name, *object_arg, *object_arg_start;
230   gboolean is_pointer;
231   gchar ret_type_buffer[1024], buffer[1024];
232   guint i, param;
233   gchar **arg_names;
234   gint param_num, widget_num, event_num, callback_num;
235   gint *arg_num;
236   gchar signal_name[128];
239   /*  g_print ("Object: %s Type: %i Signal: %u\\n", object_name, object_type,
240       signal_id);*/
242   param_num = 1;
243   widget_num = event_num = callback_num = 0;
245   query_info = gtk_signal_query (signal_id);
246   if (query_info == NULL)
247     {
248       g_warning ("Couldn't query signal");
249       return;
250     }
252   /* Output the return type and function name. */
253   ret_type = get_type_name (query_info->return_val, &is_pointer);
254   sprintf (ret_type_buffer, "%s%s", ret_type, is_pointer ? "*" : "");
256   /* Output the signal object type and the argument name. We assume the
257      type is a pointer - I think that is OK. We remove "Gtk" or "Gnome" and
258      convert to lower case for the argument name. */
259   pos = buffer;
260   sprintf (pos, "%s ", object_name);
261   pos += strlen (pos);
263   if (!strncmp (object_name, "Gtk", 3))
264       object_arg = object_name + 3;
265   else if (!strncmp (object_name, "Gnome", 5))
266       object_arg = object_name + 5;
267   else
268       object_arg = object_name;
270   object_arg_start = pos;
271   sprintf (pos, "*%s\\n", object_arg);
272   pos += strlen (pos);
273   g_strdown (object_arg_start);
274   if (!strcmp (object_arg_start, "widget"))
275     widget_num++;
276   
277   /* Convert signal name to use underscores rather than dashes '-'. */
278   strcpy (signal_name, query_info->signal_name);
279   for (i = 0; signal_name[i]; i++)
280     {
281       if (signal_name[i] == '-')
282         signal_name[i] = '_';
283     }
285   /* Output the signal parameters. */
286   arg_names = lookup_signal_arg_names (object_name, signal_name);
288   for (param = 0; param < query_info->nparams; param++)
289     {
290       if (arg_names)
291         {
292           sprintf (pos, "%s\\n", arg_names[param]);
293           pos += strlen (pos);
294         }
295       else
296         {
297           type_name = get_type_name (query_info->params[param], &is_pointer);
299           /* Most arguments to the callback are called "arg1", "arg2", etc.
300              GdkWidgets are called "widget", "widget2", ...
301              GdkEvents are called "event", "event2", ...
302              GtkCallbacks are called "callback", "callback2", ... */
303           if (!strcmp (type_name, "GtkWidget"))
304             {
305               arg_name = "widget";
306               arg_num = &widget_num;
307             }
308           else if (!strcmp (type_name, "GdkEvent"))
309             {
310               type_name = get_gdk_event (signal_name);
311               arg_name = "event";
312               arg_num = &event_num;
313               is_pointer = TRUE;
314             }
315           else if (!strcmp (type_name, "GtkCallback")
316                    || !strcmp (type_name, "GtkCCallback"))
317             {
318               arg_name = "callback";
319               arg_num = &callback_num;
320             }
321           else
322             {
323               arg_name = "arg";
324               arg_num = &param_num;
325             }
326           sprintf (pos, "%s ", type_name);
327           pos += strlen (pos);
329           if (!arg_num || *arg_num == 0)
330             sprintf (pos, "%s%s\\n", is_pointer ? "*" : " ", arg_name);
331           else
332             sprintf (pos, "%s%s%i\\n", is_pointer ? "*" : " ", arg_name,
333                      *arg_num);
334               pos += strlen (pos);
335               
336               if (arg_num)
337                 *arg_num += 1;
338         }
339     }
340   
341   fprintf (fp,
342            "<SIGNAL>\\n<NAME>%s::%s</NAME>\\n<RETURNS>%s</RETURNS>\\n%s</SIGNAL>\\n\\n",
343            object_name, query_info->signal_name, ret_type_buffer, buffer);
344   g_free (query_info);
348 /* Returns the type name to use for a signal argument or return value, given
349    the GtkType from the signal info. It also sets is_pointer to TRUE if the
350    argument needs a '*' since it is a pointer. */
351 static gchar *
352 get_type_name (GtkType type, gboolean * is_pointer)
354   gchar *type_name;
356   *is_pointer = FALSE;
357   type_name = gtk_type_name (type);
359   switch (type) {
360   case GTK_TYPE_NONE:
361   case GTK_TYPE_CHAR:
362   case GTK_TYPE_UCHAR:
363   case GTK_TYPE_BOOL:
364   case GTK_TYPE_INT:
365   case GTK_TYPE_UINT:
366   case GTK_TYPE_LONG:
367   case GTK_TYPE_ULONG:
368   case GTK_TYPE_FLOAT:
369   case GTK_TYPE_DOUBLE:
370   case GTK_TYPE_POINTER:
371     /* These all have normal C type names so they are OK. */
372     return type_name;
374   case GTK_TYPE_STRING:
375     /* A GtkString is really a gchar*. */
376     *is_pointer = TRUE;
377     return "gchar";
379   case GTK_TYPE_ENUM:
380   case GTK_TYPE_FLAGS:
381     /* We use a gint for both of these. Hopefully a subtype with a decent
382        name will be registered and used instead, as GTK+ does itself. */
383     return "gint";
385   case GTK_TYPE_BOXED:
386     /* A boxed value is just an opaque pointer, I think. */
387     return "gpointer";
389   case GTK_TYPE_SIGNAL:
390   case GTK_TYPE_ARGS:
391   case GTK_TYPE_FOREIGN:
392   case GTK_TYPE_CALLBACK:
393   case GTK_TYPE_C_CALLBACK:
394     /* FIXME: These are wrong. I think they expand into more than 1 argument.
395        See the GtkArg struct in gtktypeutils.h and gtkargcollector.c.
396        Fortunately I doubt anything uses these as signal args. */
397     return "gpointer";
399   default:
400     break;
401   }
403   /* For all GtkObject subclasses we can use the class name with a "*",
404      e.g. 'GtkWidget *'. */
405   if (gtk_type_is_a (type, GTK_TYPE_OBJECT))
406     *is_pointer = TRUE;
408   return type_name;
412 static gchar *
413 get_gdk_event (const gchar * signal_name)
415   static gchar *GbGDKEvents[] =
416   {
417     "button_press_event", "GdkEventButton",
418     "button_release_event", "GdkEventButton",
419     "motion_notify_event", "GdkEventMotion",
420     "delete_event", "GdkEvent",
421     "destroy_event", "GdkEvent",
422     "expose_event", "GdkEventExpose",
423     "key_press_event", "GdkEventKey",
424     "key_release_event", "GdkEventKey",
425     "enter_notify_event", "GdkEventCrossing",
426     "leave_notify_event", "GdkEventCrossing",
427     "configure_event", "GdkEventConfigure",
428     "focus_in_event", "GdkEventFocus",
429     "focus_out_event", "GdkEventFocus",
430     "map_event", "GdkEvent",
431     "unmap_event", "GdkEvent",
432     "property_notify_event", "GdkEventProperty",
433     "selection_clear_event", "GdkEventSelection",
434     "selection_request_event", "GdkEventSelection",
435     "selection_notify_event", "GdkEventSelection",
436     "proximity_in_event", "GdkEventProximity",
437     "proximity_out_event", "GdkEventProximity",
438     "drag_begin_event", "GdkEventDragBegin",
439     "drag_request_event", "GdkEventDragRequest",
440     "drag_end_event", "GdkEventDragRequest",
441     "drop_enter_event", "GdkEventDropEnter",
442     "drop_leave_event", "GdkEventDropLeave",
443     "drop_data_available_event", "GdkEventDropDataAvailable",
444     "other_event", "GdkEventOther",
445     "client_event", "GdkEventClient",
446     "no_expose_event", "GdkEventNoExpose",
447     "visibility_notify_event", "GdkEventVisibility",
448     "window_state_event", "GdkEventWindowState",
449     "scroll_event", "GdkEventScroll",
450     NULL
451   };
453   gint i;
455   for (i = 0; GbGDKEvents[i]; i += 2)
456     {
457       if (!strcmp (signal_name, GbGDKEvents[i]))
458         return GbGDKEvents[i + 1];
459     }
460   return "GdkEvent";
464 /* This returns argument names to use for some known GTK signals.
465     It is passed a widget name, e.g. 'GtkCList' and a signal name, e.g.
466     'select_row' and it returns a pointer to an array of argument types and
467     names. */
468 static gchar **
469 lookup_signal_arg_names (gchar * type, const gchar * signal_name)
471   /* Each arg array starts with the object type name and the signal name,
472      and then signal arguments follow. */
473   static gchar *GbArgTable[][16] =
474   {
475     {"GtkCList", "select_row",
476      "gint             row",
477      "gint             column",
478      "GdkEventButton  *event"},
479     {"GtkCList", "unselect_row",
480      "gint             row",
481      "gint             column",
482      "GdkEventButton  *event"},
483     {"GtkCList", "click_column",
484      "gint             column"},
486     {"GtkCList", "resize_column",
487      "gint             column",
488      "gint             width"},
490     {"GtkCList", "extend_selection",
491      "GtkScrollType    scroll_type",
492      "gfloat           position",
493      "gboolean         auto_start_selection"},
494     {"GtkCList", "scroll_vertical",
495      "GtkScrollType    scroll_type",
496      "gfloat           position"},
497     {"GtkCList", "scroll_horizontal",
498      "GtkScrollType    scroll_type",
499      "gfloat           position"},
500     {"GtkContainer", "focus",
501      "GtkDirectionType direction"},
502     {"GtkCTree", "tree_select_row",
503      "GList           *node",
504      "gint             column"},
505     {"GtkCTree", "tree_unselect_row",
506      "GList           *node",
507      "gint             column"},
509     {"GtkCTree", "tree_expand",
510      "GList           *node"},
511     {"GtkCTree", "tree_collapse",
512      "GList           *node"},
513     {"GtkCTree", "tree_move",
514      "GList           *node",
515      "GList           *new_parent",
516      "GList           *new_sibling"},
517     {"GtkCTree", "change_focus_row_expansion",
518      "GtkCTreeExpansionType expansion"},
520     {"GtkEditable", "insert_text",
521      "gchar           *new_text",
522      "gint             new_text_length",
523      "gint            *position"},
524     {"GtkEditable", "delete_text",
525      "gint             start_pos",
526      "gint             end_pos"},
527     {"GtkEditable", "set_editable",
528      "gboolean         is_editable"},
529     {"GtkEditable", "move_cursor",
530      "gint             x",
531      "gint             y"},
532     {"GtkEditable", "move_word",
533      "gint             num_words"},
534     {"GtkEditable", "move_page",
535      "gint             x",
536      "gint             y"},
537     {"GtkEditable", "move_to_row",
538      "gint             row"},
539     {"GtkEditable", "move_to_column",
540      "gint             column"},
542     {"GtkEditable", "kill_char",
543      "gint             direction"},
544     {"GtkEditable", "kill_word",
545      "gint             direction"},
546     {"GtkEditable", "kill_line",
547      "gint             direction"},
550     {"GtkInputDialog", "enable_device",
551      "gint             deviceid"},
552     {"GtkInputDialog", "disable_device",
553      "gint             deviceid"},
555     {"GtkListItem", "extend_selection",
556      "GtkScrollType    scroll_type",
557      "gfloat           position",
558      "gboolean         auto_start_selection"},
559     {"GtkListItem", "scroll_vertical",
560      "GtkScrollType    scroll_type",
561      "gfloat           position"},
562     {"GtkListItem", "scroll_horizontal",
563      "GtkScrollType    scroll_type",
564      "gfloat           position"},
566     {"GtkMenuShell", "move_current",
567      "GtkMenuDirectionType direction"},
568     {"GtkMenuShell", "activate_current",
569      "gboolean         force_hide"},
572     {"GtkNotebook", "switch_page",
573      "GtkNotebookPage *page",
574      "gint             page_num"},
575     {"GtkStatusbar", "text_pushed",
576      "guint            context_id",
577      "gchar           *text"},
578     {"GtkStatusbar", "text_popped",
579      "guint            context_id",
580      "gchar           *text"},
581     {"GtkTipsQuery", "widget_entered",
582      "GtkWidget       *widget",
583      "gchar           *tip_text",
584      "gchar           *tip_private"},
585     {"GtkTipsQuery", "widget_selected",
586      "GtkWidget       *widget",
587      "gchar           *tip_text",
588      "gchar           *tip_private",
589      "GdkEventButton  *event"},
590     {"GtkToolbar", "orientation_changed",
591      "GtkOrientation   orientation"},
592     {"GtkToolbar", "style_changed",
593      "GtkToolbarStyle  style"},
594     {"GtkWidget", "draw",
595      "GdkRectangle    *area"},
596     {"GtkWidget", "size_request",
597      "GtkRequisition  *requisition"},
598     {"GtkWidget", "size_allocate",
599      "GtkAllocation   *allocation"},
600     {"GtkWidget", "state_changed",
601      "GtkStateType     state"},
602     {"GtkWidget", "style_set",
603      "GtkStyle        *previous_style"},
605     {"GtkWidget", "install_accelerator",
606      "gchar           *signal_name",
607      "gchar            key",
608      "gint             modifiers"},
610     {"GtkWidget", "add_accelerator",
611      "guint            accel_signal_id",
612      "GtkAccelGroup   *accel_group",
613      "guint            accel_key",
614      "GdkModifierType  accel_mods",
615      "GtkAccelFlags    accel_flags"},
617     {"GtkWidget", "parent_set",
618      "GtkObject       *old_parent"},
620     {"GtkWidget", "remove_accelerator",
621      "GtkAccelGroup   *accel_group",
622      "guint            accel_key",
623      "GdkModifierType  accel_mods"},
624     {"GtkWidget", "debug_msg",
625      "gchar           *message"},
626     {"GtkWindow", "move_resize",
627      "gint            *x",
628      "gint            *y",
629      "gint             width",
630      "gint             height"},
631     {"GtkWindow", "set_focus",
632      "GtkWidget       *widget"},
634     {"GtkWidget", "selection_get",
635      "GtkSelectionData *data",
636      "guint            info",
637      "guint            time"},
638     {"GtkWidget", "selection_received",
639      "GtkSelectionData *data",
640      "guint            time"},
642     {"GtkWidget", "drag_begin",
643      "GdkDragContext  *drag_context"},
644     {"GtkWidget", "drag_end",
645      "GdkDragContext  *drag_context"},
646     {"GtkWidget", "drag_data_delete",
647      "GdkDragContext  *drag_context"},
648     {"GtkWidget", "drag_leave",
649      "GdkDragContext  *drag_context",
650      "guint            time"},
651     {"GtkWidget", "drag_motion",
652      "GdkDragContext  *drag_context",
653      "gint             x",
654      "gint             y",
655      "guint            time"},
656     {"GtkWidget", "drag_drop",
657      "GdkDragContext  *drag_context",
658      "gint             x",
659      "gint             y",
660      "guint            time"},
661     {"GtkWidget", "drag_data_get",
662      "GdkDragContext  *drag_context",
663      "GtkSelectionData *data",
664      "guint            info",
665      "guint            time"},
666     {"GtkWidget", "drag_data_received",
667      "GdkDragContext  *drag_context",
668      "gint             x",
669      "gint             y",
670      "GtkSelectionData *data",
671      "guint            info",
672      "guint            time"},
674     {NULL}
675   };
677   gint i;
679   for (i = 0; GbArgTable[i][0]; i++)
680     {
681       if (!strcmp (type, GbArgTable[i][0])
682           && !strcmp (signal_name, GbArgTable[i][1]))
683         return &GbArgTable[i][2];
684     }
685   return NULL;
689 /* This outputs the hierarchy of all widgets which have been initialized,
690    i.e. by calling their XXX_get_type() initialization function. */
691 static void
692 output_widget_hierarchy (void)
694   FILE *fp;
696   fp = fopen (hierarchy_filename, "w");
697   if (fp == NULL)
698     {
699       g_warning ("Couldn't open output file: %s : %s", hierarchy_filename, strerror(errno));
700       return;
701     }
702   output_hierarchy (fp, GTK_TYPE_OBJECT, 0);
703   fclose (fp);
707 /* This is called recursively to output the hierarchy of a widget. */
708 static void
709 output_hierarchy (FILE *fp,
710                   GtkType type,
711                   guint level)
713   GList *list;
714   guint i;
716   if (!type)
717     return;
719   for (i = 0; i < level; i++)
720     fprintf (fp, "  ");
721   fprintf (fp, gtk_type_name (type));
722   fprintf (fp, "\\n");
724   list = gtk_type_children_types (type);
726   while (list)
727     {
728       GtkType child = (GtkType) list->data;
729       output_hierarchy (fp, child, level + 1);
730       list = list->next;
731     }
735 static void
736 output_args (void)
738   FILE *fp;
739   gint i;
741   fp = fopen (args_filename, "w");
742   if (fp == NULL)
743     {
744       g_warning ("Couldn't open output file: %s : %s", args_filename, strerror(errno));
745       return;
746     }
748   for (i = 0; object_types[i]; i++)
749     output_widget_args (fp, object_types[i]);
751   fclose (fp);
755 static void
756 output_widget_args (FILE *fp, GtkType object_type)
758   GtkObjectClass *class;
759   gchar *object_class_name;
760   GtkArg *args;
761   guint32 *arg_flags;
762   guint n_args;
763   guint arg;
764   gchar flags[16], *pos;
766   class = gtk_type_class (object_type);
767   if (!class)
768     return;
770   object_class_name = gtk_type_name (object_type);
772   args = gtk_object_query_args (class->type, &arg_flags, &n_args);
774   for (arg = 0; arg < n_args; arg++)
775     {
776       pos = flags;
777       /* We use one-character flags for simplicity. */
778       if (arg_flags[arg] & GTK_ARG_READABLE)
779         *pos++ = 'r';
780       if (arg_flags[arg] & GTK_ARG_WRITABLE)
781         *pos++ = 'w';
782       if (arg_flags[arg] & GTK_ARG_CONSTRUCT)
783         *pos++ = 'x';
784       if (arg_flags[arg] & GTK_ARG_CONSTRUCT_ONLY)
785         *pos++ = 'X';
786       if (arg_flags[arg] & GTK_ARG_CHILD_ARG)
787         *pos++ = 'c';
788       *pos = 0;
790       fprintf (fp, "<ARG>\\n<NAME>%s</NAME>\\n<TYPE>%s</TYPE>\\n<FLAGS>%s</FLAGS>\\n</ARG>\\n\\n",
791                args[arg].name, gtk_type_name (args[arg].type), flags);
792     }
794   g_free (args);
795   g_free (arg_flags);
799 close OUTPUT;
801 # Compile and run our file
803 $CC = $ENV{CC} ? $ENV{CC} : "gcc";
804 $LD = $ENV{LD} ? $ENV{LD} : $CC;
805 $CFLAGS = $ENV{CFLAGS} ? $ENV{CFLAGS} : "";
806 $LDFLAGS = $ENV{LDFLAGS} ? $ENV{LDFLAGS} : "";
808 my $o_file;
809 if ($CC =~ /libtool/) {
810   $o_file  = "$MODULE-scan.lo"
811 } else {
812   $o_file = "$MODULE-scan.o"
815 print "gtk-doc: Compiling scanner\n";
816 $command = "$CC $CFLAGS -c -o $o_file $MODULE-scan.c";
817 system($command) == 0 or die "Compilation of scanner failed: $!\n";
819 print "gtk-doc: Linking scanner\n";
820 $command = "$LD -o $MODULE-scan $o_file $LDFLAGS";
821 system($command) == 0 or die "Linking of scanner failed: $!\n";
823 print "gtk-doc: Running scanner $MODULE-scan\n";
824 system("sh -c ./$MODULE-scan") == 0 or die "Scan failed: $!\n";
826 unlink "./$MODULE-scan.c", "./$MODULE-scan.o", "./$MODULE-scan.lo", "./$MODULE-scan";
828 &UpdateFileIfChanged ($old_signals_filename, $new_signals_filename, 0);
829 &UpdateFileIfChanged ($old_hierarchy_filename, $new_hierarchy_filename, 0);
830 &UpdateFileIfChanged ($old_args_filename, $new_args_filename, 0);