gtkdoc: remove unused imports
[gtk-doc.git] / gtkdoc / scangobj.py
blob5261e01bc671b9149acec0cc700c35d58619db8f
1 # -*- python -*-
3 # gtk-doc - GTK DocBook documentation generator.
4 # Copyright (C) 1998 Damon Chaplin
5 # 2007-2016 Stefan Sauer
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.
22 """
23 The scangobj tool gets information about object hierarchies and signals by
24 compiling and running a small C program. CFLAGS and LDFLAGS must be set
25 appropriately before running this script.
26 """
28 import logging
29 import os
30 import re
31 import string
32 import subprocess
33 import sys
35 from . import common, config
38 COMMON_INCLUDES = """
39 #include <string.h>
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <errno.h>
43 #include <glib-object.h>
44 """
46 QUERY_CHILD_PROPS_PROTOTYPE = "extern GParamSpec** %s (gpointer class, guint *n_properties);"
48 QUERY_CHILD_PROPS_CODE = """
49 if (!child_prop) {
50 properties = %s (class, &n_properties);
51 if (properties) {
52 child_prop = TRUE;
53 continue;
56 """
58 MAIN_CODE = """
60 #ifdef GTK_IS_WIDGET_CLASS
61 #include <gtk/gtk.h>
62 #endif
63 static GType object_types[$ntypes];
65 static GType *
66 get_object_types (void)
68 gpointer g_object_class;
69 gint i = 0;
71 ${get_types}
72 object_types[i] = G_TYPE_INVALID;
74 /* reference the GObjectClass to initialize the param spec pool
75 * potentially needed by interfaces. See http://bugs.gnome.org/571820 */
76 g_object_class = g_type_class_ref (G_TYPE_OBJECT);
78 /* Need to make sure all the types are loaded in and initialize
79 * their signals and properties.
81 for (i=0; object_types[i]; i++) {
82 if (G_TYPE_IS_CLASSED (object_types[i]))
83 g_type_class_ref (object_types[i]);
84 if (G_TYPE_IS_INTERFACE (object_types[i]))
85 g_type_default_interface_ref (object_types[i]);
88 g_type_class_unref (g_object_class);
90 return object_types;
94 * This uses GObject type functions to output signal prototypes and the object
95 * hierarchy.
98 /* The output files */
99 const gchar *signals_filename = "$new_signals_filename";
100 const gchar *hierarchy_filename = "$new_hierarchy_filename";
101 const gchar *interfaces_filename = "$new_interfaces_filename";
102 const gchar *prerequisites_filename = "$new_prerequisites_filename";
103 const gchar *args_filename = "$new_args_filename";
105 static void output_signals (void);
106 static void output_object_signals (FILE *fp,
107 GType object_type);
108 static void output_object_signal (FILE *fp,
109 const gchar *object_class_name,
110 guint signal_id);
111 static const gchar * get_type_name (GType type,
112 gboolean * is_pointer);
113 static void output_object_hierarchy (void);
114 static void output_hierarchy (FILE *fp,
115 GType type,
116 guint level);
118 static void output_object_interfaces (void);
119 static void output_interfaces (FILE *fp,
120 GType type);
122 static void output_interface_prerequisites (void);
123 static void output_prerequisites (FILE *fp,
124 GType type);
126 static void output_args (void);
127 static void output_object_args (FILE *fp, GType object_type);
130 main (int argc, char *argv[])
132 ${type_init_func};
134 get_object_types ();
136 output_signals ();
137 output_object_hierarchy ();
138 output_object_interfaces ();
139 output_interface_prerequisites ();
140 output_args ();
142 return 0;
145 static void
146 output_signals (void)
148 FILE *fp;
149 gint i;
151 fp = fopen (signals_filename, "w");
152 if (fp == NULL) {
153 g_warning ("Couldn't open output file: %s : %s", signals_filename, g_strerror(errno));
154 return;
157 for (i = 0; object_types[i]; i++)
158 output_object_signals (fp, object_types[i]);
160 fclose (fp);
163 static gint
164 compare_signals (const void *a, const void *b)
166 const guint *signal_a = a;
167 const guint *signal_b = b;
169 return strcmp (g_signal_name (*signal_a), g_signal_name (*signal_b));
172 /* This outputs all the signals of one object. */
173 static void
174 output_object_signals (FILE *fp, GType object_type)
176 const gchar *object_class_name;
177 guint *signals, n_signals;
178 guint sig;
180 if (G_TYPE_IS_INSTANTIATABLE (object_type) ||
181 G_TYPE_IS_INTERFACE (object_type)) {
183 object_class_name = g_type_name (object_type);
185 signals = g_signal_list_ids (object_type, &n_signals);
186 qsort (signals, n_signals, sizeof (guint), compare_signals);
188 for (sig = 0; sig < n_signals; sig++) {
189 output_object_signal (fp, object_class_name, signals[sig]);
191 g_free (signals);
195 /* This outputs one signal. */
196 static void
197 output_object_signal (FILE *fp,
198 const gchar *object_name,
199 guint signal_id)
201 GSignalQuery query_info;
202 const gchar *type_name, *ret_type, *object_arg, *arg_name;
203 gchar *pos, *object_arg_lower;
204 gboolean is_pointer;
205 gchar buffer[1024];
206 guint i, param;
207 gint param_num, widget_num, event_num, callback_num;
208 gint *arg_num;
209 gchar signal_name[128];
210 gchar flags[16];
212 /* g_print ("Object: %s Signal: %u\\n", object_name, signal_id);*/
214 param_num = 1;
215 widget_num = event_num = callback_num = 0;
217 g_signal_query (signal_id, &query_info);
219 /* Output the signal object type and the argument name. We assume the
220 * type is a pointer - I think that is OK. We remove "Gtk" or "Gnome" and
221 * convert to lower case for the argument name. */
222 pos = buffer;
223 sprintf (pos, "%s ", object_name);
224 pos += strlen (pos);
226 /* Try to come up with a sensible variable name for the first arg
227 * It chops off 2 know prefixes :/ and makes the name lowercase
228 * It should replace lowercase -> uppercase with '_'
229 * GFileMonitor -> file_monitor
230 * GIOExtensionPoint -> extension_point
231 * GtkTreeView -> tree_view
232 * if 2nd char is upper case too
233 * search for first lower case and go back one char
234 * else
235 * search for next upper case
237 if (!strncmp (object_name, "Gtk", 3))
238 object_arg = object_name + 3;
239 else if (!strncmp (object_name, "Gnome", 5))
240 object_arg = object_name + 5;
241 else
242 object_arg = object_name;
244 object_arg_lower = g_ascii_strdown (object_arg, -1);
245 sprintf (pos, "*%s\\n", object_arg_lower);
246 pos += strlen (pos);
247 if (!strncmp (object_arg_lower, "widget", 6))
248 widget_num = 2;
249 g_free(object_arg_lower);
251 /* Convert signal name to use underscores rather than dashes '-'. */
252 strncpy (signal_name, query_info.signal_name, 127);
253 signal_name[127] = '\\0';
254 for (i = 0; signal_name[i]; i++) {
255 if (signal_name[i] == '-')
256 signal_name[i] = '_';
259 /* Output the signal parameters. */
260 for (param = 0; param < query_info.n_params; param++) {
261 type_name = get_type_name (query_info.param_types[param] & ~G_SIGNAL_TYPE_STATIC_SCOPE, &is_pointer);
263 /* Most arguments to the callback are called "arg1", "arg2", etc.
264 GtkWidgets are called "widget", "widget2", ...
265 GtkCallbacks are called "callback", "callback2", ... */
266 if (!strcmp (type_name, "GtkWidget")) {
267 arg_name = "widget";
268 arg_num = &widget_num;
270 else if (!strcmp (type_name, "GtkCallback")
271 || !strcmp (type_name, "GtkCCallback")) {
272 arg_name = "callback";
273 arg_num = &callback_num;
275 else {
276 arg_name = "arg";
277 arg_num = &param_num;
279 sprintf (pos, "%s ", type_name);
280 pos += strlen (pos);
282 if (!arg_num || *arg_num == 0)
283 sprintf (pos, "%s%s\\n", is_pointer ? "*" : " ", arg_name);
284 else
285 sprintf (pos, "%s%s%i\\n", is_pointer ? "*" : " ", arg_name,
286 *arg_num);
287 pos += strlen (pos);
289 if (arg_num) {
290 if (*arg_num == 0)
291 *arg_num = 2;
292 else
293 *arg_num += 1;
297 pos = flags;
298 /* We use one-character flags for simplicity. */
299 if (query_info.signal_flags & G_SIGNAL_RUN_FIRST)
300 *pos++ = 'f';
301 if (query_info.signal_flags & G_SIGNAL_RUN_LAST)
302 *pos++ = 'l';
303 if (query_info.signal_flags & G_SIGNAL_RUN_CLEANUP)
304 *pos++ = 'c';
305 if (query_info.signal_flags & G_SIGNAL_NO_RECURSE)
306 *pos++ = 'r';
307 if (query_info.signal_flags & G_SIGNAL_DETAILED)
308 *pos++ = 'd';
309 if (query_info.signal_flags & G_SIGNAL_ACTION)
310 *pos++ = 'a';
311 if (query_info.signal_flags & G_SIGNAL_NO_HOOKS)
312 *pos++ = 'h';
313 *pos = 0;
315 /* Output the return type and function name. */
316 ret_type = get_type_name (query_info.return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE, &is_pointer);
318 fprintf (fp,
319 "<SIGNAL>\\n<NAME>%s::%s</NAME>\\n<RETURNS>%s%s</RETURNS>\\n<FLAGS>%s</FLAGS>\\n%s</SIGNAL>\\n\\n",
320 object_name, query_info.signal_name, ret_type, is_pointer ? "*" : "", flags, buffer);
324 /* Returns the type name to use for a signal argument or return value, given
325 the GtkType from the signal info. It also sets is_pointer to TRUE if the
326 argument needs a '*' since it is a pointer. */
327 static const gchar *
328 get_type_name (GType type, gboolean * is_pointer)
330 const gchar *type_name;
332 *is_pointer = FALSE;
333 type_name = g_type_name (type);
335 switch (type) {
336 case G_TYPE_NONE:
337 case G_TYPE_CHAR:
338 case G_TYPE_UCHAR:
339 case G_TYPE_BOOLEAN:
340 case G_TYPE_INT:
341 case G_TYPE_UINT:
342 case G_TYPE_LONG:
343 case G_TYPE_ULONG:
344 case G_TYPE_FLOAT:
345 case G_TYPE_DOUBLE:
346 case G_TYPE_POINTER:
347 /* These all have normal C type names so they are OK. */
348 return type_name;
350 case G_TYPE_STRING:
351 /* A GtkString is really a gchar*. */
352 *is_pointer = TRUE;
353 return "gchar";
355 case G_TYPE_ENUM:
356 case G_TYPE_FLAGS:
357 /* We use a gint for both of these. Hopefully a subtype with a decent
358 name will be registered and used instead, as GTK+ does itself. */
359 return "gint";
361 case G_TYPE_BOXED:
362 /* The boxed type shouldn't be used itself, only subtypes. Though we
363 return 'gpointer' just in case. */
364 return "gpointer";
366 case G_TYPE_PARAM:
367 /* A GParam is really a GParamSpec*. */
368 *is_pointer = TRUE;
369 return "GParamSpec";
371 #if GLIB_CHECK_VERSION (2, 25, 9)
372 case G_TYPE_VARIANT:
373 *is_pointer = TRUE;
374 return "GVariant";
375 #endif
377 default:
378 break;
381 /* For all GObject subclasses we can use the class name with a "*",
382 e.g. 'GtkWidget *'. */
383 if (g_type_is_a (type, G_TYPE_OBJECT))
384 *is_pointer = TRUE;
386 /* Also catch non GObject root types */
387 if (G_TYPE_IS_CLASSED (type))
388 *is_pointer = TRUE;
390 /* All boxed subtypes will be pointers as well. */
391 /* Exception: GStrv */
392 if (g_type_is_a (type, G_TYPE_BOXED) &&
393 !g_type_is_a (type, G_TYPE_STRV))
394 *is_pointer = TRUE;
396 /* All pointer subtypes will be pointers as well. */
397 if (g_type_is_a (type, G_TYPE_POINTER))
398 *is_pointer = TRUE;
400 /* But enums are not */
401 if (g_type_is_a (type, G_TYPE_ENUM) ||
402 g_type_is_a (type, G_TYPE_FLAGS))
403 *is_pointer = FALSE;
405 return type_name;
409 /* This outputs the hierarchy of all objects which have been initialized,
410 i.e. by calling their XXX_get_type() initialization function. */
411 static void
412 output_object_hierarchy (void)
414 FILE *fp;
415 gint i,j;
416 GType root, type;
417 GType root_types[$ntypes] = { G_TYPE_INVALID, };
419 fp = fopen (hierarchy_filename, "w");
420 if (fp == NULL) {
421 g_warning ("Couldn't open output file: %s : %s", hierarchy_filename, g_strerror(errno));
422 return;
424 output_hierarchy (fp, G_TYPE_OBJECT, 0);
425 output_hierarchy (fp, G_TYPE_INTERFACE, 0);
427 for (i=0; object_types[i]; i++) {
428 root = object_types[i];
429 while ((type = g_type_parent (root))) {
430 root = type;
432 if ((root != G_TYPE_OBJECT) && (root != G_TYPE_INTERFACE)) {
433 for (j=0; root_types[j]; j++) {
434 if (root == root_types[j]) {
435 root = G_TYPE_INVALID; break;
438 if(root) {
439 root_types[j] = root;
440 output_hierarchy (fp, root, 0);
445 fclose (fp);
448 /* This is called recursively to output the hierarchy of a object. */
449 static void
450 output_hierarchy (FILE *fp,
451 GType type,
452 guint level)
454 guint i;
455 GType *children;
456 guint n_children;
458 if (!type)
459 return;
461 for (i = 0; i < level; i++)
462 fprintf (fp, " ");
463 fprintf (fp, "%s\\n", g_type_name (type));
465 children = g_type_children (type, &n_children);
467 for (i=0; i < n_children; i++)
468 output_hierarchy (fp, children[i], level + 1);
470 g_free (children);
473 static void output_object_interfaces (void)
475 guint i;
476 FILE *fp;
478 fp = fopen (interfaces_filename, "w");
479 if (fp == NULL) {
480 g_warning ("Couldn't open output file: %s : %s", interfaces_filename, g_strerror(errno));
481 return;
483 output_interfaces (fp, G_TYPE_OBJECT);
485 for (i = 0; object_types[i]; i++) {
486 if (!g_type_parent (object_types[i]) &&
487 (object_types[i] != G_TYPE_OBJECT) &&
488 G_TYPE_IS_INSTANTIATABLE (object_types[i])) {
489 output_interfaces (fp, object_types[i]);
492 fclose (fp);
495 static void
496 output_interfaces (FILE *fp,
497 GType type)
499 guint i;
500 GType *children, *interfaces;
501 guint n_children, n_interfaces;
503 if (!type)
504 return;
506 interfaces = g_type_interfaces (type, &n_interfaces);
508 if (n_interfaces > 0) {
509 fprintf (fp, "%s", g_type_name (type));
510 for (i=0; i < n_interfaces; i++)
511 fprintf (fp, " %s", g_type_name (interfaces[i]));
512 fprintf (fp, "\\n");
514 g_free (interfaces);
516 children = g_type_children (type, &n_children);
518 for (i=0; i < n_children; i++)
519 output_interfaces (fp, children[i]);
521 g_free (children);
524 static void output_interface_prerequisites (void)
526 FILE *fp;
528 fp = fopen (prerequisites_filename, "w");
529 if (fp == NULL) {
530 g_warning ("Couldn't open output file: %s : %s", prerequisites_filename, g_strerror(errno));
531 return;
533 output_prerequisites (fp, G_TYPE_INTERFACE);
534 fclose (fp);
537 static void
538 output_prerequisites (FILE *fp,
539 GType type)
541 #if GLIB_CHECK_VERSION(2,1,0)
542 guint i;
543 GType *children, *prerequisites;
544 guint n_children, n_prerequisites;
546 if (!type)
547 return;
549 prerequisites = g_type_interface_prerequisites (type, &n_prerequisites);
551 if (n_prerequisites > 0) {
552 fprintf (fp, "%s", g_type_name (type));
553 for (i=0; i < n_prerequisites; i++)
554 fprintf (fp, " %s", g_type_name (prerequisites[i]));
555 fprintf (fp, "\\n");
557 g_free (prerequisites);
559 children = g_type_children (type, &n_children);
561 for (i=0; i < n_children; i++)
562 output_prerequisites (fp, children[i]);
564 g_free (children);
565 #endif
568 static void
569 output_args (void)
571 FILE *fp;
572 gint i;
574 fp = fopen (args_filename, "w");
575 if (fp == NULL) {
576 g_warning ("Couldn't open output file: %s : %s", args_filename, g_strerror(errno));
577 return;
580 for (i = 0; object_types[i]; i++) {
581 output_object_args (fp, object_types[i]);
584 fclose (fp);
587 static gint
588 compare_param_specs (const void *a, const void *b)
590 GParamSpec *spec_a = *(GParamSpec **)a;
591 GParamSpec *spec_b = *(GParamSpec **)b;
593 return strcmp (g_param_spec_get_name (spec_a), g_param_spec_get_name (spec_b));
596 /* Its common to have unsigned properties restricted
597 * to the signed range. Therefore we make this look
598 * a bit nicer by spelling out the max constants.
601 /* Don't use "==" with floats, it might trigger a gcc warning. */
602 #define GTKDOC_COMPARE_FLOAT(x, y) (x <= y && x >= y)
604 static gchar*
605 describe_double_constant (gdouble value)
607 gchar *desc;
609 if (GTKDOC_COMPARE_FLOAT (value, G_MAXDOUBLE))
610 desc = g_strdup ("G_MAXDOUBLE");
611 else if (GTKDOC_COMPARE_FLOAT (value, G_MINDOUBLE))
612 desc = g_strdup ("G_MINDOUBLE");
613 else if (GTKDOC_COMPARE_FLOAT (value, -G_MAXDOUBLE))
614 desc = g_strdup ("-G_MAXDOUBLE");
615 else if (GTKDOC_COMPARE_FLOAT (value, G_MAXFLOAT))
616 desc = g_strdup ("G_MAXFLOAT");
617 else if (GTKDOC_COMPARE_FLOAT (value, G_MINFLOAT))
618 desc = g_strdup ("G_MINFLOAT");
619 else if (GTKDOC_COMPARE_FLOAT (value, -G_MAXFLOAT))
620 desc = g_strdup ("-G_MAXFLOAT");
621 else{
622 /* make sure floats are output with a decimal dot irrespective of
623 * current locale. Use formatd since we want human-readable numbers
624 * and do not need the exact same bit representation when deserialising */
625 desc = g_malloc0 (G_ASCII_DTOSTR_BUF_SIZE);
626 g_ascii_formatd (desc, G_ASCII_DTOSTR_BUF_SIZE, "%g", value);
629 return desc;
632 static gchar*
633 describe_signed_constant (gsize size, gint64 value)
635 gchar *desc = NULL;
637 switch (size) {
638 case 2:
639 if (sizeof (int) == 2) {
640 if (value == G_MAXINT)
641 desc = g_strdup ("G_MAXINT");
642 else if (value == G_MININT)
643 desc = g_strdup ("G_MININT");
645 break;
646 case 4:
647 if (sizeof (int) == 4) {
648 if (value == G_MAXINT)
649 desc = g_strdup ("G_MAXINT");
650 else if (value == G_MININT)
651 desc = g_strdup ("G_MININT");
653 if (value == G_MAXLONG)
654 desc = g_strdup ("G_MAXLONG");
655 else if (value == G_MINLONG)
656 desc = g_strdup ("G_MINLONG");
657 break;
658 case 8:
659 if (value == G_MAXINT64)
660 desc = g_strdup ("G_MAXINT64");
661 else if (value == G_MININT64)
662 desc = g_strdup ("G_MININT64");
663 break;
664 default:
665 break;
667 if (!desc)
668 desc = g_strdup_printf ("%" G_GINT64_FORMAT, value);
670 return desc;
673 static gchar*
674 describe_unsigned_constant (gsize size, guint64 value)
676 gchar *desc = NULL;
678 switch (size) {
679 case 2:
680 if (sizeof (int) == 2) {
681 if (value == (guint64)G_MAXINT)
682 desc = g_strdup ("G_MAXINT");
683 else if (value == G_MAXUINT)
684 desc = g_strdup ("G_MAXUINT");
686 break;
687 case 4:
688 if (sizeof (int) == 4) {
689 if (value == (guint64)G_MAXINT)
690 desc = g_strdup ("G_MAXINT");
691 else if (value == G_MAXUINT)
692 desc = g_strdup ("G_MAXUINT");
694 if (value == (guint64)G_MAXLONG)
695 desc = g_strdup ("G_MAXLONG");
696 else if (value == G_MAXULONG)
697 desc = g_strdup ("G_MAXULONG");
698 break;
699 case 8:
700 if (value == G_MAXINT64)
701 desc = g_strdup ("G_MAXINT64");
702 else if (value == G_MAXUINT64)
703 desc = g_strdup ("G_MAXUINT64");
704 break;
705 default:
706 break;
708 if (!desc)
709 desc = g_strdup_printf ("%" G_GUINT64_FORMAT, value);
711 return desc;
714 static gchar*
715 describe_type (GParamSpec *spec)
717 gchar *desc;
718 gchar *lower;
719 gchar *upper;
721 if (G_IS_PARAM_SPEC_CHAR (spec)) {
722 GParamSpecChar *pspec = G_PARAM_SPEC_CHAR (spec);
724 lower = describe_signed_constant (sizeof(gchar), pspec->minimum);
725 upper = describe_signed_constant (sizeof(gchar), pspec->maximum);
726 if (pspec->minimum == G_MININT8 && pspec->maximum == G_MAXINT8)
727 desc = g_strdup ("");
728 else if (pspec->minimum == G_MININT8)
729 desc = g_strdup_printf ("<= %s", upper);
730 else if (pspec->maximum == G_MAXINT8)
731 desc = g_strdup_printf (">= %s", lower);
732 else
733 desc = g_strdup_printf ("[%s,%s]", lower, upper);
734 g_free (lower);
735 g_free (upper);
737 else if (G_IS_PARAM_SPEC_UCHAR (spec)) {
738 GParamSpecUChar *pspec = G_PARAM_SPEC_UCHAR (spec);
740 lower = describe_unsigned_constant (sizeof(guchar), pspec->minimum);
741 upper = describe_unsigned_constant (sizeof(guchar), pspec->maximum);
742 if (pspec->minimum == 0 && pspec->maximum == G_MAXUINT8)
743 desc = g_strdup ("");
744 else if (pspec->minimum == 0)
745 desc = g_strdup_printf ("<= %s", upper);
746 else if (pspec->maximum == G_MAXUINT8)
747 desc = g_strdup_printf (">= %s", lower);
748 else
749 desc = g_strdup_printf ("[%s,%s]", lower, upper);
750 g_free (lower);
751 g_free (upper);
753 else if (G_IS_PARAM_SPEC_INT (spec)) {
754 GParamSpecInt *pspec = G_PARAM_SPEC_INT (spec);
756 lower = describe_signed_constant (sizeof(gint), pspec->minimum);
757 upper = describe_signed_constant (sizeof(gint), pspec->maximum);
758 if (pspec->minimum == G_MININT && pspec->maximum == G_MAXINT)
759 desc = g_strdup ("");
760 else if (pspec->minimum == G_MININT)
761 desc = g_strdup_printf ("<= %s", upper);
762 else if (pspec->maximum == G_MAXINT)
763 desc = g_strdup_printf (">= %s", lower);
764 else
765 desc = g_strdup_printf ("[%s,%s]", lower, upper);
766 g_free (lower);
767 g_free (upper);
769 else if (G_IS_PARAM_SPEC_UINT (spec)) {
770 GParamSpecUInt *pspec = G_PARAM_SPEC_UINT (spec);
772 lower = describe_unsigned_constant (sizeof(guint), pspec->minimum);
773 upper = describe_unsigned_constant (sizeof(guint), pspec->maximum);
774 if (pspec->minimum == 0 && pspec->maximum == G_MAXUINT)
775 desc = g_strdup ("");
776 else if (pspec->minimum == 0)
777 desc = g_strdup_printf ("<= %s", upper);
778 else if (pspec->maximum == G_MAXUINT)
779 desc = g_strdup_printf (">= %s", lower);
780 else
781 desc = g_strdup_printf ("[%s,%s]", lower, upper);
782 g_free (lower);
783 g_free (upper);
785 else if (G_IS_PARAM_SPEC_LONG (spec)) {
786 GParamSpecLong *pspec = G_PARAM_SPEC_LONG (spec);
788 lower = describe_signed_constant (sizeof(glong), pspec->minimum);
789 upper = describe_signed_constant (sizeof(glong), pspec->maximum);
790 if (pspec->minimum == G_MINLONG && pspec->maximum == G_MAXLONG)
791 desc = g_strdup ("");
792 else if (pspec->minimum == G_MINLONG)
793 desc = g_strdup_printf ("<= %s", upper);
794 else if (pspec->maximum == G_MAXLONG)
795 desc = g_strdup_printf (">= %s", lower);
796 else
797 desc = g_strdup_printf ("[%s,%s]", lower, upper);
798 g_free (lower);
799 g_free (upper);
801 else if (G_IS_PARAM_SPEC_ULONG (spec)) {
802 GParamSpecULong *pspec = G_PARAM_SPEC_ULONG (spec);
804 lower = describe_unsigned_constant (sizeof(gulong), pspec->minimum);
805 upper = describe_unsigned_constant (sizeof(gulong), pspec->maximum);
806 if (pspec->minimum == 0 && pspec->maximum == G_MAXULONG)
807 desc = g_strdup ("");
808 else if (pspec->minimum == 0)
809 desc = g_strdup_printf ("<= %s", upper);
810 else if (pspec->maximum == G_MAXULONG)
811 desc = g_strdup_printf (">= %s", lower);
812 else
813 desc = g_strdup_printf ("[%s,%s]", lower, upper);
814 g_free (lower);
815 g_free (upper);
817 else if (G_IS_PARAM_SPEC_INT64 (spec)) {
818 GParamSpecInt64 *pspec = G_PARAM_SPEC_INT64 (spec);
820 lower = describe_signed_constant (sizeof(gint64), pspec->minimum);
821 upper = describe_signed_constant (sizeof(gint64), pspec->maximum);
822 if (pspec->minimum == G_MININT64 && pspec->maximum == G_MAXINT64)
823 desc = g_strdup ("");
824 else if (pspec->minimum == G_MININT64)
825 desc = g_strdup_printf ("<= %s", upper);
826 else if (pspec->maximum == G_MAXINT64)
827 desc = g_strdup_printf (">= %s", lower);
828 else
829 desc = g_strdup_printf ("[%s,%s]", lower, upper);
830 g_free (lower);
831 g_free (upper);
833 else if (G_IS_PARAM_SPEC_UINT64 (spec)) {
834 GParamSpecUInt64 *pspec = G_PARAM_SPEC_UINT64 (spec);
836 lower = describe_unsigned_constant (sizeof(guint64), pspec->minimum);
837 upper = describe_unsigned_constant (sizeof(guint64), pspec->maximum);
838 if (pspec->minimum == 0 && pspec->maximum == G_MAXUINT64)
839 desc = g_strdup ("");
840 else if (pspec->minimum == 0)
841 desc = g_strdup_printf ("<= %s", upper);
842 else if (pspec->maximum == G_MAXUINT64)
843 desc = g_strdup_printf (">= %s", lower);
844 else
845 desc = g_strdup_printf ("[%s,%s]", lower, upper);
846 g_free (lower);
847 g_free (upper);
849 else if (G_IS_PARAM_SPEC_FLOAT (spec)) {
850 GParamSpecFloat *pspec = G_PARAM_SPEC_FLOAT (spec);
852 lower = describe_double_constant (pspec->minimum);
853 upper = describe_double_constant (pspec->maximum);
854 if (GTKDOC_COMPARE_FLOAT (pspec->minimum, -G_MAXFLOAT)) {
855 if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXFLOAT))
856 desc = g_strdup ("");
857 else
858 desc = g_strdup_printf ("<= %s", upper);
860 else if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXFLOAT))
861 desc = g_strdup_printf (">= %s", lower);
862 else
863 desc = g_strdup_printf ("[%s,%s]", lower, upper);
864 g_free (lower);
865 g_free (upper);
867 else if (G_IS_PARAM_SPEC_DOUBLE (spec)) {
868 GParamSpecDouble *pspec = G_PARAM_SPEC_DOUBLE (spec);
870 lower = describe_double_constant (pspec->minimum);
871 upper = describe_double_constant (pspec->maximum);
872 if (GTKDOC_COMPARE_FLOAT (pspec->minimum, -G_MAXDOUBLE)) {
873 if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXDOUBLE))
874 desc = g_strdup ("");
875 else
876 desc = g_strdup_printf ("<= %s", upper);
878 else if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXDOUBLE))
879 desc = g_strdup_printf (">= %s", lower);
880 else
881 desc = g_strdup_printf ("[%s,%s]", lower, upper);
882 g_free (lower);
883 g_free (upper);
885 #if GLIB_CHECK_VERSION (2, 12, 0)
886 else if (G_IS_PARAM_SPEC_GTYPE (spec)) {
887 GParamSpecGType *pspec = G_PARAM_SPEC_GTYPE (spec);
888 gboolean is_pointer;
890 desc = g_strdup (get_type_name (pspec->is_a_type, &is_pointer));
892 #endif
893 #if GLIB_CHECK_VERSION (2, 25, 9)
894 else if (G_IS_PARAM_SPEC_VARIANT (spec)) {
895 GParamSpecVariant *pspec = G_PARAM_SPEC_VARIANT (spec);
896 gchar *variant_type;
898 variant_type = g_variant_type_dup_string (pspec->type);
899 desc = g_strdup_printf ("GVariant<%s>", variant_type);
900 g_free (variant_type);
902 #endif
903 else {
904 desc = g_strdup ("");
907 return desc;
910 static gchar*
911 describe_default (GParamSpec *spec)
913 gchar *desc;
915 if (G_IS_PARAM_SPEC_CHAR (spec)) {
916 GParamSpecChar *pspec = G_PARAM_SPEC_CHAR (spec);
918 desc = g_strdup_printf ("%d", pspec->default_value);
920 else if (G_IS_PARAM_SPEC_UCHAR (spec)) {
921 GParamSpecUChar *pspec = G_PARAM_SPEC_UCHAR (spec);
923 desc = g_strdup_printf ("%u", pspec->default_value);
925 else if (G_IS_PARAM_SPEC_BOOLEAN (spec)) {
926 GParamSpecBoolean *pspec = G_PARAM_SPEC_BOOLEAN (spec);
928 desc = g_strdup_printf ("%s", pspec->default_value ? "TRUE" : "FALSE");
930 else if (G_IS_PARAM_SPEC_INT (spec)) {
931 GParamSpecInt *pspec = G_PARAM_SPEC_INT (spec);
933 desc = g_strdup_printf ("%d", pspec->default_value);
935 else if (G_IS_PARAM_SPEC_UINT (spec)) {
936 GParamSpecUInt *pspec = G_PARAM_SPEC_UINT (spec);
938 desc = g_strdup_printf ("%u", pspec->default_value);
940 else if (G_IS_PARAM_SPEC_LONG (spec)) {
941 GParamSpecLong *pspec = G_PARAM_SPEC_LONG (spec);
943 desc = g_strdup_printf ("%ld", pspec->default_value);
945 else if (G_IS_PARAM_SPEC_LONG (spec)) {
946 GParamSpecULong *pspec = G_PARAM_SPEC_ULONG (spec);
948 desc = g_strdup_printf ("%lu", pspec->default_value);
950 else if (G_IS_PARAM_SPEC_INT64 (spec)) {
951 GParamSpecInt64 *pspec = G_PARAM_SPEC_INT64 (spec);
953 desc = g_strdup_printf ("%" G_GINT64_FORMAT, pspec->default_value);
955 else if (G_IS_PARAM_SPEC_UINT64 (spec))
957 GParamSpecUInt64 *pspec = G_PARAM_SPEC_UINT64 (spec);
959 desc = g_strdup_printf ("%" G_GUINT64_FORMAT, pspec->default_value);
961 else if (G_IS_PARAM_SPEC_UNICHAR (spec)) {
962 GParamSpecUnichar *pspec = G_PARAM_SPEC_UNICHAR (spec);
964 if (g_unichar_isprint (pspec->default_value))
965 desc = g_strdup_printf ("'%c'", pspec->default_value);
966 else
967 desc = g_strdup_printf ("%u", pspec->default_value);
969 else if (G_IS_PARAM_SPEC_ENUM (spec)) {
970 GParamSpecEnum *pspec = G_PARAM_SPEC_ENUM (spec);
972 GEnumValue *value = g_enum_get_value (pspec->enum_class, pspec->default_value);
973 if (value)
974 desc = g_strdup_printf ("%s", value->value_name);
975 else
976 desc = g_strdup_printf ("%d", pspec->default_value);
978 else if (G_IS_PARAM_SPEC_FLAGS (spec)) {
979 GParamSpecFlags *pspec = G_PARAM_SPEC_FLAGS (spec);
980 guint default_value;
981 GString *acc;
983 default_value = pspec->default_value;
984 acc = g_string_new ("");
986 while (default_value) {
987 GFlagsValue *value = g_flags_get_first_value (pspec->flags_class, default_value);
989 if (!value)
990 break;
992 if (acc->len > 0)
993 g_string_append (acc, " | ");
994 g_string_append (acc, value->value_name);
996 default_value &= ~value->value;
999 if (default_value == 0)
1000 desc = g_string_free (acc, FALSE);
1001 else {
1002 desc = g_strdup_printf ("%d", pspec->default_value);
1003 g_string_free (acc, TRUE);
1006 else if (G_IS_PARAM_SPEC_FLOAT (spec)) {
1007 GParamSpecFloat *pspec = G_PARAM_SPEC_FLOAT (spec);
1009 /* make sure floats are output with a decimal dot irrespective of
1010 * current locale. Use formatd since we want human-readable numbers
1011 * and do not need the exact same bit representation when deserialising */
1012 desc = g_malloc0 (G_ASCII_DTOSTR_BUF_SIZE);
1013 g_ascii_formatd (desc, G_ASCII_DTOSTR_BUF_SIZE, "%g",
1014 pspec->default_value);
1016 else if (G_IS_PARAM_SPEC_DOUBLE (spec)) {
1017 GParamSpecDouble *pspec = G_PARAM_SPEC_DOUBLE (spec);
1019 /* make sure floats are output with a decimal dot irrespective of
1020 * current locale. Use formatd since we want human-readable numbers
1021 * and do not need the exact same bit representation when deserialising */
1022 desc = g_malloc0 (G_ASCII_DTOSTR_BUF_SIZE);
1023 g_ascii_formatd (desc, G_ASCII_DTOSTR_BUF_SIZE, "%g",
1024 pspec->default_value);
1026 else if (G_IS_PARAM_SPEC_STRING (spec)) {
1027 GParamSpecString *pspec = G_PARAM_SPEC_STRING (spec);
1029 if (pspec->default_value) {
1030 gchar *esc = g_strescape (pspec->default_value, NULL);
1031 desc = g_strdup_printf ("\\"%s\\"", esc);
1032 g_free (esc);
1034 else
1035 desc = g_strdup_printf ("NULL");
1037 #if GLIB_CHECK_VERSION (2, 25, 9)
1038 else if (G_IS_PARAM_SPEC_VARIANT (spec)) {
1039 GParamSpecVariant *pspec = G_PARAM_SPEC_VARIANT (spec);
1041 if (pspec->default_value)
1042 desc = g_variant_print (pspec->default_value, TRUE);
1043 else
1044 desc = g_strdup ("NULL");
1046 #endif
1047 else {
1048 desc = g_strdup ("");
1051 return desc;
1055 static void
1056 output_object_args (FILE *fp, GType object_type)
1058 gpointer class;
1059 const gchar *object_class_name;
1060 guint arg;
1061 gchar flags[16], *pos;
1062 GParamSpec **properties;
1063 guint n_properties;
1064 gboolean child_prop;
1065 gboolean style_prop;
1066 gboolean is_pointer;
1067 const gchar *type_name;
1068 gchar *type_desc;
1069 gchar *default_value;
1071 if (G_TYPE_IS_OBJECT (object_type)) {
1072 class = g_type_class_peek (object_type);
1073 if (!class)
1074 return;
1076 properties = g_object_class_list_properties (class, &n_properties);
1078 #if GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 3)
1079 else if (G_TYPE_IS_INTERFACE (object_type)) {
1080 class = g_type_default_interface_ref (object_type);
1082 if (!class)
1083 return;
1085 properties = g_object_interface_list_properties (class, &n_properties);
1087 #endif
1088 else
1089 return;
1091 object_class_name = g_type_name (object_type);
1093 child_prop = FALSE;
1094 style_prop = FALSE;
1096 while (TRUE) {
1097 qsort (properties, n_properties, sizeof (GParamSpec *), compare_param_specs);
1098 for (arg = 0; arg < n_properties; arg++) {
1099 GParamSpec *spec = properties[arg];
1100 const gchar *nick, *blurb, *dot;
1102 if (spec->owner_type != object_type)
1103 continue;
1105 pos = flags;
1106 /* We use one-character flags for simplicity. */
1107 if (child_prop && !style_prop)
1108 *pos++ = 'c';
1109 if (style_prop)
1110 *pos++ = 's';
1111 if (spec->flags & G_PARAM_READABLE)
1112 *pos++ = 'r';
1113 if (spec->flags & G_PARAM_WRITABLE)
1114 *pos++ = 'w';
1115 if (spec->flags & G_PARAM_CONSTRUCT)
1116 *pos++ = 'x';
1117 if (spec->flags & G_PARAM_CONSTRUCT_ONLY)
1118 *pos++ = 'X';
1119 *pos = 0;
1121 nick = g_param_spec_get_nick (spec);
1122 blurb = g_param_spec_get_blurb (spec);
1124 dot = "";
1125 if (blurb) {
1126 int str_len = strlen (blurb);
1127 if (str_len > 0 && blurb[str_len - 1] != '.')
1128 dot = ".";
1131 type_desc = describe_type (spec);
1132 default_value = describe_default (spec);
1133 type_name = get_type_name (spec->value_type, &is_pointer);
1134 fprintf (fp, "<ARG>\\n"
1135 "<NAME>%s::%s</NAME>\\n"
1136 "<TYPE>%s%s</TYPE>\\n"
1137 "<RANGE>%s</RANGE>\\n"
1138 "<FLAGS>%s</FLAGS>\\n"
1139 "<NICK>%s</NICK>\\n"
1140 "<BLURB>%s%s</BLURB>\\n"
1141 "<DEFAULT>%s</DEFAULT>\\n"
1142 "</ARG>\\n\\n",
1143 object_class_name, g_param_spec_get_name (spec), type_name,
1144 is_pointer ? "*" : "", type_desc, flags, nick ? nick : "(null)",
1145 blurb ? blurb : "(null)", dot, default_value);
1146 g_free (type_desc);
1147 g_free (default_value);
1150 g_free (properties);
1152 #ifdef GTK_IS_CONTAINER_CLASS
1153 if (!child_prop && GTK_IS_CONTAINER_CLASS (class)) {
1154 properties = gtk_container_class_list_child_properties (class, &n_properties);
1155 child_prop = TRUE;
1156 continue;
1158 #endif
1160 #ifdef GTK_IS_CELL_AREA_CLASS
1161 if (!child_prop && GTK_IS_CELL_AREA_CLASS (class)) {
1162 properties = gtk_cell_area_class_list_cell_properties (class, &n_properties);
1163 child_prop = TRUE;
1164 continue;
1166 #endif
1168 #ifdef GTK_IS_WIDGET_CLASS
1169 #if GTK_CHECK_VERSION(2,1,0) && !GTK_CHECK_VERSION(3,89,2)
1170 if (!style_prop && GTK_IS_WIDGET_CLASS (class)) {
1171 properties = gtk_widget_class_list_style_properties (GTK_WIDGET_CLASS (class), &n_properties);
1172 style_prop = TRUE;
1173 continue;
1175 #endif
1176 #endif
1180 MAIN_CODE_END = """
1181 break;
1187 def run(options):
1189 c_file = options.module + '-scan.c'
1190 output = open(c_file, 'w')
1192 base_filename = os.path.join(options.output_dir, options.module)
1193 old_signals_filename = base_filename + '.signals'
1194 new_signals_filename = base_filename + '.signals.new'
1195 old_hierarchy_filename = base_filename + '.hierarchy'
1196 new_hierarchy_filename = base_filename + '.hierarchy.new'
1197 old_interfaces_filename = base_filename + '.interfaces'
1198 new_interfaces_filename = base_filename + '.interfaces.new'
1199 old_prerequisites_filename = base_filename + '.prerequisites'
1200 new_prerequisites_filename = base_filename + '.prerequisites.new'
1201 old_args_filename = base_filename + '.args'
1202 new_args_filename = base_filename + '.args.new'
1204 # generate a C program to scan the types
1206 includes = ""
1207 forward_decls = ""
1208 get_types = ""
1209 ntypes = 1
1211 for line in open(options.types):
1212 if line.startswith('#include'):
1213 includes += line
1214 elif line.startswith('%') or line.strip() == '':
1215 continue
1216 else:
1217 line = line.strip()
1218 get_types += ' object_types[i++] = ' + line + ' ();\n'
1219 forward_decls += 'extern GType ' + line + ' (void);\n'
1220 ntypes += 1
1222 output.write(COMMON_INCLUDES)
1224 if includes:
1225 output.write(includes)
1226 else:
1227 output.write(forward_decls)
1229 if options.query_child_properties:
1230 output.write(QUERY_CHILD_PROPS_PROTOTYPE % options.query_child_properties)
1232 # substitute local vars in the template
1233 type_init_func = options.type_init_func
1234 output.write(string.Template(MAIN_CODE).substitute(locals()))
1236 if options.query_child_properties:
1237 output.write(QUERY_CHILD_PROPS_CODE % options.query_child_properties)
1239 output.write(MAIN_CODE_END)
1241 output.close()
1243 # Compile and run our file
1244 if 'libtool' in options.cc:
1245 o_file = options.module + '-scan.lo'
1246 else:
1247 o_file = options.module + '-scan.o'
1249 x_file = options.module + '-scan' + config.exeext
1251 stdout = ""
1252 if not options.verbose:
1253 stdout = ">/dev/null"
1255 # Compiling scanner
1256 command = '%s %s %s -c -o %s %s' % (options.cc, stdout, options.cflags, o_file, c_file)
1257 res = subprocess.check_call(command, shell=True)
1258 if res > 0:
1259 logging.warning('Compilation of scanner failed: %d', res)
1260 return res
1262 # Linking scanner
1263 command = '%s %s %s %s -o %s' % (options.ld, stdout, o_file, options.ldflags, x_file)
1264 res = subprocess.check_call(command, shell=True)
1265 if res > 0:
1266 logging.warning('Linking of scanner failed: %d', res)
1267 return res
1269 # Running scanner
1270 command = '%s ./%s' % (options.run, x_file)
1271 res = subprocess.check_call(command, shell=True)
1272 if res > 0:
1273 logging.warning('Running scanner failed: %d', res)
1274 return res
1276 if 'GTK_DOC_KEEP_INTERMEDIATE' not in os.environ:
1277 os.unlink(c_file)
1278 os.unlink(o_file)
1279 os.unlink(x_file)
1281 common.UpdateFileIfChanged(old_signals_filename, new_signals_filename, False)
1282 common.UpdateFileIfChanged(old_hierarchy_filename, new_hierarchy_filename, False)
1283 common.UpdateFileIfChanged(old_interfaces_filename, new_interfaces_filename, False)
1284 common.UpdateFileIfChanged(old_prerequisites_filename, new_prerequisites_filename, False)
1285 common.UpdateFileIfChanged(old_args_filename, new_args_filename, False)
1287 return 0