python: format top comment as doc string.
[gtk-doc.git] / gtkdoc / scangobj.py
blob0add3ea949a275de7bf902baf3ae37554100ba13
1 #!@PYTHON@
2 # -*- python -*-
4 # gtk-doc - GTK DocBook documentation generator.
5 # Copyright (C) 1998 Damon Chaplin
6 # 2007-2016 Stefan Sauer
8 # This program is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 2 of the License, or
11 # (at your option) any later version.
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with this program; if not, write to the Free Software
20 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 """
24 The scangobj tool gets information about object hierarchies and signals by
25 compiling and running a small C program. CFLAGS and LDFLAGS must be set
26 appropriately before running this script.
27 """
29 from __future__ import print_function
31 import logging
32 import os
33 import re
34 import string
35 import subprocess
36 import sys
38 from . import common, config
41 COMMON_INCLUDES = """
42 #include <string.h>
43 #include <stdlib.h>
44 #include <stdio.h>
45 #include <errno.h>
46 #include <glib-object.h>
47 """
49 QUERY_CHILD_PROPS_PROTOTYPE = "extern GParamSpec** %s (gpointer class, guint *n_properties);"
51 QUERY_CHILD_PROPS_CODE = """
52 if (!child_prop) {
53 properties = %s (class, &n_properties);
54 if (properties) {
55 child_prop = TRUE;
56 continue;
59 """
61 MAIN_CODE = """
63 #ifdef GTK_IS_WIDGET_CLASS
64 #include <gtk/gtk.h>
65 #endif
66 static GType object_types[$ntypes];
68 static GType *
69 get_object_types (void)
71 gpointer g_object_class;
72 gint i = 0;
74 ${get_types}
75 object_types[i] = G_TYPE_INVALID;
77 /* reference the GObjectClass to initialize the param spec pool
78 * potentially needed by interfaces. See http://bugs.gnome.org/571820 */
79 g_object_class = g_type_class_ref (G_TYPE_OBJECT);
81 /* Need to make sure all the types are loaded in and initialize
82 * their signals and properties.
84 for (i=0; object_types[i]; i++) {
85 if (G_TYPE_IS_CLASSED (object_types[i]))
86 g_type_class_ref (object_types[i]);
87 if (G_TYPE_IS_INTERFACE (object_types[i]))
88 g_type_default_interface_ref (object_types[i]);
91 g_type_class_unref (g_object_class);
93 return object_types;
97 * This uses GObject type functions to output signal prototypes and the object
98 * hierarchy.
101 /* The output files */
102 const gchar *signals_filename = "$new_signals_filename";
103 const gchar *hierarchy_filename = "$new_hierarchy_filename";
104 const gchar *interfaces_filename = "$new_interfaces_filename";
105 const gchar *prerequisites_filename = "$new_prerequisites_filename";
106 const gchar *args_filename = "$new_args_filename";
108 static void output_signals (void);
109 static void output_object_signals (FILE *fp,
110 GType object_type);
111 static void output_object_signal (FILE *fp,
112 const gchar *object_class_name,
113 guint signal_id);
114 static const gchar * get_type_name (GType type,
115 gboolean * is_pointer);
116 static void output_object_hierarchy (void);
117 static void output_hierarchy (FILE *fp,
118 GType type,
119 guint level);
121 static void output_object_interfaces (void);
122 static void output_interfaces (FILE *fp,
123 GType type);
125 static void output_interface_prerequisites (void);
126 static void output_prerequisites (FILE *fp,
127 GType type);
129 static void output_args (void);
130 static void output_object_args (FILE *fp, GType object_type);
133 main (int argc, char *argv[])
135 ${type_init_func};
137 get_object_types ();
139 output_signals ();
140 output_object_hierarchy ();
141 output_object_interfaces ();
142 output_interface_prerequisites ();
143 output_args ();
145 return 0;
148 static void
149 output_signals (void)
151 FILE *fp;
152 gint i;
154 fp = fopen (signals_filename, "w");
155 if (fp == NULL) {
156 g_warning ("Couldn't open output file: %s : %s", signals_filename, g_strerror(errno));
157 return;
160 for (i = 0; object_types[i]; i++)
161 output_object_signals (fp, object_types[i]);
163 fclose (fp);
166 static gint
167 compare_signals (const void *a, const void *b)
169 const guint *signal_a = a;
170 const guint *signal_b = b;
172 return strcmp (g_signal_name (*signal_a), g_signal_name (*signal_b));
175 /* This outputs all the signals of one object. */
176 static void
177 output_object_signals (FILE *fp, GType object_type)
179 const gchar *object_class_name;
180 guint *signals, n_signals;
181 guint sig;
183 if (G_TYPE_IS_INSTANTIATABLE (object_type) ||
184 G_TYPE_IS_INTERFACE (object_type)) {
186 object_class_name = g_type_name (object_type);
188 signals = g_signal_list_ids (object_type, &n_signals);
189 qsort (signals, n_signals, sizeof (guint), compare_signals);
191 for (sig = 0; sig < n_signals; sig++) {
192 output_object_signal (fp, object_class_name, signals[sig]);
194 g_free (signals);
198 /* This outputs one signal. */
199 static void
200 output_object_signal (FILE *fp,
201 const gchar *object_name,
202 guint signal_id)
204 GSignalQuery query_info;
205 const gchar *type_name, *ret_type, *object_arg, *arg_name;
206 gchar *pos, *object_arg_lower;
207 gboolean is_pointer;
208 gchar buffer[1024];
209 guint i, param;
210 gint param_num, widget_num, event_num, callback_num;
211 gint *arg_num;
212 gchar signal_name[128];
213 gchar flags[16];
215 /* g_print ("Object: %s Signal: %u\\n", object_name, signal_id);*/
217 param_num = 1;
218 widget_num = event_num = callback_num = 0;
220 g_signal_query (signal_id, &query_info);
222 /* Output the signal object type and the argument name. We assume the
223 * type is a pointer - I think that is OK. We remove "Gtk" or "Gnome" and
224 * convert to lower case for the argument name. */
225 pos = buffer;
226 sprintf (pos, "%s ", object_name);
227 pos += strlen (pos);
229 /* Try to come up with a sensible variable name for the first arg
230 * It chops off 2 know prefixes :/ and makes the name lowercase
231 * It should replace lowercase -> uppercase with '_'
232 * GFileMonitor -> file_monitor
233 * GIOExtensionPoint -> extension_point
234 * GtkTreeView -> tree_view
235 * if 2nd char is upper case too
236 * search for first lower case and go back one char
237 * else
238 * search for next upper case
240 if (!strncmp (object_name, "Gtk", 3))
241 object_arg = object_name + 3;
242 else if (!strncmp (object_name, "Gnome", 5))
243 object_arg = object_name + 5;
244 else
245 object_arg = object_name;
247 object_arg_lower = g_ascii_strdown (object_arg, -1);
248 sprintf (pos, "*%s\\n", object_arg_lower);
249 pos += strlen (pos);
250 if (!strncmp (object_arg_lower, "widget", 6))
251 widget_num = 2;
252 g_free(object_arg_lower);
254 /* Convert signal name to use underscores rather than dashes '-'. */
255 strncpy (signal_name, query_info.signal_name, 127);
256 signal_name[127] = '\\0';
257 for (i = 0; signal_name[i]; i++) {
258 if (signal_name[i] == '-')
259 signal_name[i] = '_';
262 /* Output the signal parameters. */
263 for (param = 0; param < query_info.n_params; param++) {
264 type_name = get_type_name (query_info.param_types[param] & ~G_SIGNAL_TYPE_STATIC_SCOPE, &is_pointer);
266 /* Most arguments to the callback are called "arg1", "arg2", etc.
267 GtkWidgets are called "widget", "widget2", ...
268 GtkCallbacks are called "callback", "callback2", ... */
269 if (!strcmp (type_name, "GtkWidget")) {
270 arg_name = "widget";
271 arg_num = &widget_num;
273 else if (!strcmp (type_name, "GtkCallback")
274 || !strcmp (type_name, "GtkCCallback")) {
275 arg_name = "callback";
276 arg_num = &callback_num;
278 else {
279 arg_name = "arg";
280 arg_num = &param_num;
282 sprintf (pos, "%s ", type_name);
283 pos += strlen (pos);
285 if (!arg_num || *arg_num == 0)
286 sprintf (pos, "%s%s\\n", is_pointer ? "*" : " ", arg_name);
287 else
288 sprintf (pos, "%s%s%i\\n", is_pointer ? "*" : " ", arg_name,
289 *arg_num);
290 pos += strlen (pos);
292 if (arg_num) {
293 if (*arg_num == 0)
294 *arg_num = 2;
295 else
296 *arg_num += 1;
300 pos = flags;
301 /* We use one-character flags for simplicity. */
302 if (query_info.signal_flags & G_SIGNAL_RUN_FIRST)
303 *pos++ = 'f';
304 if (query_info.signal_flags & G_SIGNAL_RUN_LAST)
305 *pos++ = 'l';
306 if (query_info.signal_flags & G_SIGNAL_RUN_CLEANUP)
307 *pos++ = 'c';
308 if (query_info.signal_flags & G_SIGNAL_NO_RECURSE)
309 *pos++ = 'r';
310 if (query_info.signal_flags & G_SIGNAL_DETAILED)
311 *pos++ = 'd';
312 if (query_info.signal_flags & G_SIGNAL_ACTION)
313 *pos++ = 'a';
314 if (query_info.signal_flags & G_SIGNAL_NO_HOOKS)
315 *pos++ = 'h';
316 *pos = 0;
318 /* Output the return type and function name. */
319 ret_type = get_type_name (query_info.return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE, &is_pointer);
321 fprintf (fp,
322 "<SIGNAL>\\n<NAME>%s::%s</NAME>\\n<RETURNS>%s%s</RETURNS>\\n<FLAGS>%s</FLAGS>\\n%s</SIGNAL>\\n\\n",
323 object_name, query_info.signal_name, ret_type, is_pointer ? "*" : "", flags, buffer);
327 /* Returns the type name to use for a signal argument or return value, given
328 the GtkType from the signal info. It also sets is_pointer to TRUE if the
329 argument needs a '*' since it is a pointer. */
330 static const gchar *
331 get_type_name (GType type, gboolean * is_pointer)
333 const gchar *type_name;
335 *is_pointer = FALSE;
336 type_name = g_type_name (type);
338 switch (type) {
339 case G_TYPE_NONE:
340 case G_TYPE_CHAR:
341 case G_TYPE_UCHAR:
342 case G_TYPE_BOOLEAN:
343 case G_TYPE_INT:
344 case G_TYPE_UINT:
345 case G_TYPE_LONG:
346 case G_TYPE_ULONG:
347 case G_TYPE_FLOAT:
348 case G_TYPE_DOUBLE:
349 case G_TYPE_POINTER:
350 /* These all have normal C type names so they are OK. */
351 return type_name;
353 case G_TYPE_STRING:
354 /* A GtkString is really a gchar*. */
355 *is_pointer = TRUE;
356 return "gchar";
358 case G_TYPE_ENUM:
359 case G_TYPE_FLAGS:
360 /* We use a gint for both of these. Hopefully a subtype with a decent
361 name will be registered and used instead, as GTK+ does itself. */
362 return "gint";
364 case G_TYPE_BOXED:
365 /* The boxed type shouldn't be used itself, only subtypes. Though we
366 return 'gpointer' just in case. */
367 return "gpointer";
369 case G_TYPE_PARAM:
370 /* A GParam is really a GParamSpec*. */
371 *is_pointer = TRUE;
372 return "GParamSpec";
374 #if GLIB_CHECK_VERSION (2, 25, 9)
375 case G_TYPE_VARIANT:
376 *is_pointer = TRUE;
377 return "GVariant";
378 #endif
380 default:
381 break;
384 /* For all GObject subclasses we can use the class name with a "*",
385 e.g. 'GtkWidget *'. */
386 if (g_type_is_a (type, G_TYPE_OBJECT))
387 *is_pointer = TRUE;
389 /* Also catch non GObject root types */
390 if (G_TYPE_IS_CLASSED (type))
391 *is_pointer = TRUE;
393 /* All boxed subtypes will be pointers as well. */
394 /* Exception: GStrv */
395 if (g_type_is_a (type, G_TYPE_BOXED) &&
396 !g_type_is_a (type, G_TYPE_STRV))
397 *is_pointer = TRUE;
399 /* All pointer subtypes will be pointers as well. */
400 if (g_type_is_a (type, G_TYPE_POINTER))
401 *is_pointer = TRUE;
403 /* But enums are not */
404 if (g_type_is_a (type, G_TYPE_ENUM) ||
405 g_type_is_a (type, G_TYPE_FLAGS))
406 *is_pointer = FALSE;
408 return type_name;
412 /* This outputs the hierarchy of all objects which have been initialized,
413 i.e. by calling their XXX_get_type() initialization function. */
414 static void
415 output_object_hierarchy (void)
417 FILE *fp;
418 gint i,j;
419 GType root, type;
420 GType root_types[$ntypes] = { G_TYPE_INVALID, };
422 fp = fopen (hierarchy_filename, "w");
423 if (fp == NULL) {
424 g_warning ("Couldn't open output file: %s : %s", hierarchy_filename, g_strerror(errno));
425 return;
427 output_hierarchy (fp, G_TYPE_OBJECT, 0);
428 output_hierarchy (fp, G_TYPE_INTERFACE, 0);
430 for (i=0; object_types[i]; i++) {
431 root = object_types[i];
432 while ((type = g_type_parent (root))) {
433 root = type;
435 if ((root != G_TYPE_OBJECT) && (root != G_TYPE_INTERFACE)) {
436 for (j=0; root_types[j]; j++) {
437 if (root == root_types[j]) {
438 root = G_TYPE_INVALID; break;
441 if(root) {
442 root_types[j] = root;
443 output_hierarchy (fp, root, 0);
448 fclose (fp);
451 /* This is called recursively to output the hierarchy of a object. */
452 static void
453 output_hierarchy (FILE *fp,
454 GType type,
455 guint level)
457 guint i;
458 GType *children;
459 guint n_children;
461 if (!type)
462 return;
464 for (i = 0; i < level; i++)
465 fprintf (fp, " ");
466 fprintf (fp, "%s\\n", g_type_name (type));
468 children = g_type_children (type, &n_children);
470 for (i=0; i < n_children; i++)
471 output_hierarchy (fp, children[i], level + 1);
473 g_free (children);
476 static void output_object_interfaces (void)
478 guint i;
479 FILE *fp;
481 fp = fopen (interfaces_filename, "w");
482 if (fp == NULL) {
483 g_warning ("Couldn't open output file: %s : %s", interfaces_filename, g_strerror(errno));
484 return;
486 output_interfaces (fp, G_TYPE_OBJECT);
488 for (i = 0; object_types[i]; i++) {
489 if (!g_type_parent (object_types[i]) &&
490 (object_types[i] != G_TYPE_OBJECT) &&
491 G_TYPE_IS_INSTANTIATABLE (object_types[i])) {
492 output_interfaces (fp, object_types[i]);
495 fclose (fp);
498 static void
499 output_interfaces (FILE *fp,
500 GType type)
502 guint i;
503 GType *children, *interfaces;
504 guint n_children, n_interfaces;
506 if (!type)
507 return;
509 interfaces = g_type_interfaces (type, &n_interfaces);
511 if (n_interfaces > 0) {
512 fprintf (fp, "%s", g_type_name (type));
513 for (i=0; i < n_interfaces; i++)
514 fprintf (fp, " %s", g_type_name (interfaces[i]));
515 fprintf (fp, "\\n");
517 g_free (interfaces);
519 children = g_type_children (type, &n_children);
521 for (i=0; i < n_children; i++)
522 output_interfaces (fp, children[i]);
524 g_free (children);
527 static void output_interface_prerequisites (void)
529 FILE *fp;
531 fp = fopen (prerequisites_filename, "w");
532 if (fp == NULL) {
533 g_warning ("Couldn't open output file: %s : %s", prerequisites_filename, g_strerror(errno));
534 return;
536 output_prerequisites (fp, G_TYPE_INTERFACE);
537 fclose (fp);
540 static void
541 output_prerequisites (FILE *fp,
542 GType type)
544 #if GLIB_CHECK_VERSION(2,1,0)
545 guint i;
546 GType *children, *prerequisites;
547 guint n_children, n_prerequisites;
549 if (!type)
550 return;
552 prerequisites = g_type_interface_prerequisites (type, &n_prerequisites);
554 if (n_prerequisites > 0) {
555 fprintf (fp, "%s", g_type_name (type));
556 for (i=0; i < n_prerequisites; i++)
557 fprintf (fp, " %s", g_type_name (prerequisites[i]));
558 fprintf (fp, "\\n");
560 g_free (prerequisites);
562 children = g_type_children (type, &n_children);
564 for (i=0; i < n_children; i++)
565 output_prerequisites (fp, children[i]);
567 g_free (children);
568 #endif
571 static void
572 output_args (void)
574 FILE *fp;
575 gint i;
577 fp = fopen (args_filename, "w");
578 if (fp == NULL) {
579 g_warning ("Couldn't open output file: %s : %s", args_filename, g_strerror(errno));
580 return;
583 for (i = 0; object_types[i]; i++) {
584 output_object_args (fp, object_types[i]);
587 fclose (fp);
590 static gint
591 compare_param_specs (const void *a, const void *b)
593 GParamSpec *spec_a = *(GParamSpec **)a;
594 GParamSpec *spec_b = *(GParamSpec **)b;
596 return strcmp (g_param_spec_get_name (spec_a), g_param_spec_get_name (spec_b));
599 /* Its common to have unsigned properties restricted
600 * to the signed range. Therefore we make this look
601 * a bit nicer by spelling out the max constants.
604 /* Don't use "==" with floats, it might trigger a gcc warning. */
605 #define GTKDOC_COMPARE_FLOAT(x, y) (x <= y && x >= y)
607 static gchar*
608 describe_double_constant (gdouble value)
610 gchar *desc;
612 if (GTKDOC_COMPARE_FLOAT (value, G_MAXDOUBLE))
613 desc = g_strdup ("G_MAXDOUBLE");
614 else if (GTKDOC_COMPARE_FLOAT (value, G_MINDOUBLE))
615 desc = g_strdup ("G_MINDOUBLE");
616 else if (GTKDOC_COMPARE_FLOAT (value, -G_MAXDOUBLE))
617 desc = g_strdup ("-G_MAXDOUBLE");
618 else if (GTKDOC_COMPARE_FLOAT (value, G_MAXFLOAT))
619 desc = g_strdup ("G_MAXFLOAT");
620 else if (GTKDOC_COMPARE_FLOAT (value, G_MINFLOAT))
621 desc = g_strdup ("G_MINFLOAT");
622 else if (GTKDOC_COMPARE_FLOAT (value, -G_MAXFLOAT))
623 desc = g_strdup ("-G_MAXFLOAT");
624 else{
625 /* make sure floats are output with a decimal dot irrespective of
626 * current locale. Use formatd since we want human-readable numbers
627 * and do not need the exact same bit representation when deserialising */
628 desc = g_malloc0 (G_ASCII_DTOSTR_BUF_SIZE);
629 g_ascii_formatd (desc, G_ASCII_DTOSTR_BUF_SIZE, "%g", value);
632 return desc;
635 static gchar*
636 describe_signed_constant (gsize size, gint64 value)
638 gchar *desc = NULL;
640 switch (size) {
641 case 2:
642 if (sizeof (int) == 2) {
643 if (value == G_MAXINT)
644 desc = g_strdup ("G_MAXINT");
645 else if (value == G_MININT)
646 desc = g_strdup ("G_MININT");
648 break;
649 case 4:
650 if (sizeof (int) == 4) {
651 if (value == G_MAXINT)
652 desc = g_strdup ("G_MAXINT");
653 else if (value == G_MININT)
654 desc = g_strdup ("G_MININT");
656 if (value == G_MAXLONG)
657 desc = g_strdup ("G_MAXLONG");
658 else if (value == G_MINLONG)
659 desc = g_strdup ("G_MINLONG");
660 break;
661 case 8:
662 if (value == G_MAXINT64)
663 desc = g_strdup ("G_MAXINT64");
664 else if (value == G_MININT64)
665 desc = g_strdup ("G_MININT64");
666 break;
667 default:
668 break;
670 if (!desc)
671 desc = g_strdup_printf ("%" G_GINT64_FORMAT, value);
673 return desc;
676 static gchar*
677 describe_unsigned_constant (gsize size, guint64 value)
679 gchar *desc = NULL;
681 switch (size) {
682 case 2:
683 if (sizeof (int) == 2) {
684 if (value == (guint64)G_MAXINT)
685 desc = g_strdup ("G_MAXINT");
686 else if (value == G_MAXUINT)
687 desc = g_strdup ("G_MAXUINT");
689 break;
690 case 4:
691 if (sizeof (int) == 4) {
692 if (value == (guint64)G_MAXINT)
693 desc = g_strdup ("G_MAXINT");
694 else if (value == G_MAXUINT)
695 desc = g_strdup ("G_MAXUINT");
697 if (value == (guint64)G_MAXLONG)
698 desc = g_strdup ("G_MAXLONG");
699 else if (value == G_MAXULONG)
700 desc = g_strdup ("G_MAXULONG");
701 break;
702 case 8:
703 if (value == G_MAXINT64)
704 desc = g_strdup ("G_MAXINT64");
705 else if (value == G_MAXUINT64)
706 desc = g_strdup ("G_MAXUINT64");
707 break;
708 default:
709 break;
711 if (!desc)
712 desc = g_strdup_printf ("%" G_GUINT64_FORMAT, value);
714 return desc;
717 static gchar*
718 describe_type (GParamSpec *spec)
720 gchar *desc;
721 gchar *lower;
722 gchar *upper;
724 if (G_IS_PARAM_SPEC_CHAR (spec)) {
725 GParamSpecChar *pspec = G_PARAM_SPEC_CHAR (spec);
727 lower = describe_signed_constant (sizeof(gchar), pspec->minimum);
728 upper = describe_signed_constant (sizeof(gchar), pspec->maximum);
729 if (pspec->minimum == G_MININT8 && pspec->maximum == G_MAXINT8)
730 desc = g_strdup ("");
731 else if (pspec->minimum == G_MININT8)
732 desc = g_strdup_printf ("<= %s", upper);
733 else if (pspec->maximum == G_MAXINT8)
734 desc = g_strdup_printf (">= %s", lower);
735 else
736 desc = g_strdup_printf ("[%s,%s]", lower, upper);
737 g_free (lower);
738 g_free (upper);
740 else if (G_IS_PARAM_SPEC_UCHAR (spec)) {
741 GParamSpecUChar *pspec = G_PARAM_SPEC_UCHAR (spec);
743 lower = describe_unsigned_constant (sizeof(guchar), pspec->minimum);
744 upper = describe_unsigned_constant (sizeof(guchar), pspec->maximum);
745 if (pspec->minimum == 0 && pspec->maximum == G_MAXUINT8)
746 desc = g_strdup ("");
747 else if (pspec->minimum == 0)
748 desc = g_strdup_printf ("<= %s", upper);
749 else if (pspec->maximum == G_MAXUINT8)
750 desc = g_strdup_printf (">= %s", lower);
751 else
752 desc = g_strdup_printf ("[%s,%s]", lower, upper);
753 g_free (lower);
754 g_free (upper);
756 else if (G_IS_PARAM_SPEC_INT (spec)) {
757 GParamSpecInt *pspec = G_PARAM_SPEC_INT (spec);
759 lower = describe_signed_constant (sizeof(gint), pspec->minimum);
760 upper = describe_signed_constant (sizeof(gint), pspec->maximum);
761 if (pspec->minimum == G_MININT && pspec->maximum == G_MAXINT)
762 desc = g_strdup ("");
763 else if (pspec->minimum == G_MININT)
764 desc = g_strdup_printf ("<= %s", upper);
765 else if (pspec->maximum == G_MAXINT)
766 desc = g_strdup_printf (">= %s", lower);
767 else
768 desc = g_strdup_printf ("[%s,%s]", lower, upper);
769 g_free (lower);
770 g_free (upper);
772 else if (G_IS_PARAM_SPEC_UINT (spec)) {
773 GParamSpecUInt *pspec = G_PARAM_SPEC_UINT (spec);
775 lower = describe_unsigned_constant (sizeof(guint), pspec->minimum);
776 upper = describe_unsigned_constant (sizeof(guint), pspec->maximum);
777 if (pspec->minimum == 0 && pspec->maximum == G_MAXUINT)
778 desc = g_strdup ("");
779 else if (pspec->minimum == 0)
780 desc = g_strdup_printf ("<= %s", upper);
781 else if (pspec->maximum == G_MAXUINT)
782 desc = g_strdup_printf (">= %s", lower);
783 else
784 desc = g_strdup_printf ("[%s,%s]", lower, upper);
785 g_free (lower);
786 g_free (upper);
788 else if (G_IS_PARAM_SPEC_LONG (spec)) {
789 GParamSpecLong *pspec = G_PARAM_SPEC_LONG (spec);
791 lower = describe_signed_constant (sizeof(glong), pspec->minimum);
792 upper = describe_signed_constant (sizeof(glong), pspec->maximum);
793 if (pspec->minimum == G_MINLONG && pspec->maximum == G_MAXLONG)
794 desc = g_strdup ("");
795 else if (pspec->minimum == G_MINLONG)
796 desc = g_strdup_printf ("<= %s", upper);
797 else if (pspec->maximum == G_MAXLONG)
798 desc = g_strdup_printf (">= %s", lower);
799 else
800 desc = g_strdup_printf ("[%s,%s]", lower, upper);
801 g_free (lower);
802 g_free (upper);
804 else if (G_IS_PARAM_SPEC_ULONG (spec)) {
805 GParamSpecULong *pspec = G_PARAM_SPEC_ULONG (spec);
807 lower = describe_unsigned_constant (sizeof(gulong), pspec->minimum);
808 upper = describe_unsigned_constant (sizeof(gulong), pspec->maximum);
809 if (pspec->minimum == 0 && pspec->maximum == G_MAXULONG)
810 desc = g_strdup ("");
811 else if (pspec->minimum == 0)
812 desc = g_strdup_printf ("<= %s", upper);
813 else if (pspec->maximum == G_MAXULONG)
814 desc = g_strdup_printf (">= %s", lower);
815 else
816 desc = g_strdup_printf ("[%s,%s]", lower, upper);
817 g_free (lower);
818 g_free (upper);
820 else if (G_IS_PARAM_SPEC_INT64 (spec)) {
821 GParamSpecInt64 *pspec = G_PARAM_SPEC_INT64 (spec);
823 lower = describe_signed_constant (sizeof(gint64), pspec->minimum);
824 upper = describe_signed_constant (sizeof(gint64), pspec->maximum);
825 if (pspec->minimum == G_MININT64 && pspec->maximum == G_MAXINT64)
826 desc = g_strdup ("");
827 else if (pspec->minimum == G_MININT64)
828 desc = g_strdup_printf ("<= %s", upper);
829 else if (pspec->maximum == G_MAXINT64)
830 desc = g_strdup_printf (">= %s", lower);
831 else
832 desc = g_strdup_printf ("[%s,%s]", lower, upper);
833 g_free (lower);
834 g_free (upper);
836 else if (G_IS_PARAM_SPEC_UINT64 (spec)) {
837 GParamSpecUInt64 *pspec = G_PARAM_SPEC_UINT64 (spec);
839 lower = describe_unsigned_constant (sizeof(guint64), pspec->minimum);
840 upper = describe_unsigned_constant (sizeof(guint64), pspec->maximum);
841 if (pspec->minimum == 0 && pspec->maximum == G_MAXUINT64)
842 desc = g_strdup ("");
843 else if (pspec->minimum == 0)
844 desc = g_strdup_printf ("<= %s", upper);
845 else if (pspec->maximum == G_MAXUINT64)
846 desc = g_strdup_printf (">= %s", lower);
847 else
848 desc = g_strdup_printf ("[%s,%s]", lower, upper);
849 g_free (lower);
850 g_free (upper);
852 else if (G_IS_PARAM_SPEC_FLOAT (spec)) {
853 GParamSpecFloat *pspec = G_PARAM_SPEC_FLOAT (spec);
855 lower = describe_double_constant (pspec->minimum);
856 upper = describe_double_constant (pspec->maximum);
857 if (GTKDOC_COMPARE_FLOAT (pspec->minimum, -G_MAXFLOAT)) {
858 if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXFLOAT))
859 desc = g_strdup ("");
860 else
861 desc = g_strdup_printf ("<= %s", upper);
863 else if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXFLOAT))
864 desc = g_strdup_printf (">= %s", lower);
865 else
866 desc = g_strdup_printf ("[%s,%s]", lower, upper);
867 g_free (lower);
868 g_free (upper);
870 else if (G_IS_PARAM_SPEC_DOUBLE (spec)) {
871 GParamSpecDouble *pspec = G_PARAM_SPEC_DOUBLE (spec);
873 lower = describe_double_constant (pspec->minimum);
874 upper = describe_double_constant (pspec->maximum);
875 if (GTKDOC_COMPARE_FLOAT (pspec->minimum, -G_MAXDOUBLE)) {
876 if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXDOUBLE))
877 desc = g_strdup ("");
878 else
879 desc = g_strdup_printf ("<= %s", upper);
881 else if (GTKDOC_COMPARE_FLOAT (pspec->maximum, G_MAXDOUBLE))
882 desc = g_strdup_printf (">= %s", lower);
883 else
884 desc = g_strdup_printf ("[%s,%s]", lower, upper);
885 g_free (lower);
886 g_free (upper);
888 #if GLIB_CHECK_VERSION (2, 12, 0)
889 else if (G_IS_PARAM_SPEC_GTYPE (spec)) {
890 GParamSpecGType *pspec = G_PARAM_SPEC_GTYPE (spec);
891 gboolean is_pointer;
893 desc = g_strdup (get_type_name (pspec->is_a_type, &is_pointer));
895 #endif
896 #if GLIB_CHECK_VERSION (2, 25, 9)
897 else if (G_IS_PARAM_SPEC_VARIANT (spec)) {
898 GParamSpecVariant *pspec = G_PARAM_SPEC_VARIANT (spec);
899 gchar *variant_type;
901 variant_type = g_variant_type_dup_string (pspec->type);
902 desc = g_strdup_printf ("GVariant<%s>", variant_type);
903 g_free (variant_type);
905 #endif
906 else {
907 desc = g_strdup ("");
910 return desc;
913 static gchar*
914 describe_default (GParamSpec *spec)
916 gchar *desc;
918 if (G_IS_PARAM_SPEC_CHAR (spec)) {
919 GParamSpecChar *pspec = G_PARAM_SPEC_CHAR (spec);
921 desc = g_strdup_printf ("%d", pspec->default_value);
923 else if (G_IS_PARAM_SPEC_UCHAR (spec)) {
924 GParamSpecUChar *pspec = G_PARAM_SPEC_UCHAR (spec);
926 desc = g_strdup_printf ("%u", pspec->default_value);
928 else if (G_IS_PARAM_SPEC_BOOLEAN (spec)) {
929 GParamSpecBoolean *pspec = G_PARAM_SPEC_BOOLEAN (spec);
931 desc = g_strdup_printf ("%s", pspec->default_value ? "TRUE" : "FALSE");
933 else if (G_IS_PARAM_SPEC_INT (spec)) {
934 GParamSpecInt *pspec = G_PARAM_SPEC_INT (spec);
936 desc = g_strdup_printf ("%d", pspec->default_value);
938 else if (G_IS_PARAM_SPEC_UINT (spec)) {
939 GParamSpecUInt *pspec = G_PARAM_SPEC_UINT (spec);
941 desc = g_strdup_printf ("%u", pspec->default_value);
943 else if (G_IS_PARAM_SPEC_LONG (spec)) {
944 GParamSpecLong *pspec = G_PARAM_SPEC_LONG (spec);
946 desc = g_strdup_printf ("%ld", pspec->default_value);
948 else if (G_IS_PARAM_SPEC_LONG (spec)) {
949 GParamSpecULong *pspec = G_PARAM_SPEC_ULONG (spec);
951 desc = g_strdup_printf ("%lu", pspec->default_value);
953 else if (G_IS_PARAM_SPEC_INT64 (spec)) {
954 GParamSpecInt64 *pspec = G_PARAM_SPEC_INT64 (spec);
956 desc = g_strdup_printf ("%" G_GINT64_FORMAT, pspec->default_value);
958 else if (G_IS_PARAM_SPEC_UINT64 (spec))
960 GParamSpecUInt64 *pspec = G_PARAM_SPEC_UINT64 (spec);
962 desc = g_strdup_printf ("%" G_GUINT64_FORMAT, pspec->default_value);
964 else if (G_IS_PARAM_SPEC_UNICHAR (spec)) {
965 GParamSpecUnichar *pspec = G_PARAM_SPEC_UNICHAR (spec);
967 if (g_unichar_isprint (pspec->default_value))
968 desc = g_strdup_printf ("'%c'", pspec->default_value);
969 else
970 desc = g_strdup_printf ("%u", pspec->default_value);
972 else if (G_IS_PARAM_SPEC_ENUM (spec)) {
973 GParamSpecEnum *pspec = G_PARAM_SPEC_ENUM (spec);
975 GEnumValue *value = g_enum_get_value (pspec->enum_class, pspec->default_value);
976 if (value)
977 desc = g_strdup_printf ("%s", value->value_name);
978 else
979 desc = g_strdup_printf ("%d", pspec->default_value);
981 else if (G_IS_PARAM_SPEC_FLAGS (spec)) {
982 GParamSpecFlags *pspec = G_PARAM_SPEC_FLAGS (spec);
983 guint default_value;
984 GString *acc;
986 default_value = pspec->default_value;
987 acc = g_string_new ("");
989 while (default_value) {
990 GFlagsValue *value = g_flags_get_first_value (pspec->flags_class, default_value);
992 if (!value)
993 break;
995 if (acc->len > 0)
996 g_string_append (acc, " | ");
997 g_string_append (acc, value->value_name);
999 default_value &= ~value->value;
1002 if (default_value == 0)
1003 desc = g_string_free (acc, FALSE);
1004 else {
1005 desc = g_strdup_printf ("%d", pspec->default_value);
1006 g_string_free (acc, TRUE);
1009 else if (G_IS_PARAM_SPEC_FLOAT (spec)) {
1010 GParamSpecFloat *pspec = G_PARAM_SPEC_FLOAT (spec);
1012 /* make sure floats are output with a decimal dot irrespective of
1013 * current locale. Use formatd since we want human-readable numbers
1014 * and do not need the exact same bit representation when deserialising */
1015 desc = g_malloc0 (G_ASCII_DTOSTR_BUF_SIZE);
1016 g_ascii_formatd (desc, G_ASCII_DTOSTR_BUF_SIZE, "%g",
1017 pspec->default_value);
1019 else if (G_IS_PARAM_SPEC_DOUBLE (spec)) {
1020 GParamSpecDouble *pspec = G_PARAM_SPEC_DOUBLE (spec);
1022 /* make sure floats are output with a decimal dot irrespective of
1023 * current locale. Use formatd since we want human-readable numbers
1024 * and do not need the exact same bit representation when deserialising */
1025 desc = g_malloc0 (G_ASCII_DTOSTR_BUF_SIZE);
1026 g_ascii_formatd (desc, G_ASCII_DTOSTR_BUF_SIZE, "%g",
1027 pspec->default_value);
1029 else if (G_IS_PARAM_SPEC_STRING (spec)) {
1030 GParamSpecString *pspec = G_PARAM_SPEC_STRING (spec);
1032 if (pspec->default_value) {
1033 gchar *esc = g_strescape (pspec->default_value, NULL);
1034 desc = g_strdup_printf ("\\"%s\\"", esc);
1035 g_free (esc);
1037 else
1038 desc = g_strdup_printf ("NULL");
1040 #if GLIB_CHECK_VERSION (2, 25, 9)
1041 else if (G_IS_PARAM_SPEC_VARIANT (spec)) {
1042 GParamSpecVariant *pspec = G_PARAM_SPEC_VARIANT (spec);
1044 if (pspec->default_value)
1045 desc = g_variant_print (pspec->default_value, TRUE);
1046 else
1047 desc = g_strdup ("NULL");
1049 #endif
1050 else {
1051 desc = g_strdup ("");
1054 return desc;
1058 static void
1059 output_object_args (FILE *fp, GType object_type)
1061 gpointer class;
1062 const gchar *object_class_name;
1063 guint arg;
1064 gchar flags[16], *pos;
1065 GParamSpec **properties;
1066 guint n_properties;
1067 gboolean child_prop;
1068 gboolean style_prop;
1069 gboolean is_pointer;
1070 const gchar *type_name;
1071 gchar *type_desc;
1072 gchar *default_value;
1074 if (G_TYPE_IS_OBJECT (object_type)) {
1075 class = g_type_class_peek (object_type);
1076 if (!class)
1077 return;
1079 properties = g_object_class_list_properties (class, &n_properties);
1081 #if GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 3)
1082 else if (G_TYPE_IS_INTERFACE (object_type)) {
1083 class = g_type_default_interface_ref (object_type);
1085 if (!class)
1086 return;
1088 properties = g_object_interface_list_properties (class, &n_properties);
1090 #endif
1091 else
1092 return;
1094 object_class_name = g_type_name (object_type);
1096 child_prop = FALSE;
1097 style_prop = FALSE;
1099 while (TRUE) {
1100 qsort (properties, n_properties, sizeof (GParamSpec *), compare_param_specs);
1101 for (arg = 0; arg < n_properties; arg++) {
1102 GParamSpec *spec = properties[arg];
1103 const gchar *nick, *blurb, *dot;
1105 if (spec->owner_type != object_type)
1106 continue;
1108 pos = flags;
1109 /* We use one-character flags for simplicity. */
1110 if (child_prop && !style_prop)
1111 *pos++ = 'c';
1112 if (style_prop)
1113 *pos++ = 's';
1114 if (spec->flags & G_PARAM_READABLE)
1115 *pos++ = 'r';
1116 if (spec->flags & G_PARAM_WRITABLE)
1117 *pos++ = 'w';
1118 if (spec->flags & G_PARAM_CONSTRUCT)
1119 *pos++ = 'x';
1120 if (spec->flags & G_PARAM_CONSTRUCT_ONLY)
1121 *pos++ = 'X';
1122 *pos = 0;
1124 nick = g_param_spec_get_nick (spec);
1125 blurb = g_param_spec_get_blurb (spec);
1127 dot = "";
1128 if (blurb) {
1129 int str_len = strlen (blurb);
1130 if (str_len > 0 && blurb[str_len - 1] != '.')
1131 dot = ".";
1134 type_desc = describe_type (spec);
1135 default_value = describe_default (spec);
1136 type_name = get_type_name (spec->value_type, &is_pointer);
1137 fprintf (fp, "<ARG>\\n"
1138 "<NAME>%s::%s</NAME>\\n"
1139 "<TYPE>%s%s</TYPE>\\n"
1140 "<RANGE>%s</RANGE>\\n"
1141 "<FLAGS>%s</FLAGS>\\n"
1142 "<NICK>%s</NICK>\\n"
1143 "<BLURB>%s%s</BLURB>\\n"
1144 "<DEFAULT>%s</DEFAULT>\\n"
1145 "</ARG>\\n\\n",
1146 object_class_name, g_param_spec_get_name (spec), type_name,
1147 is_pointer ? "*" : "", type_desc, flags, nick ? nick : "(null)",
1148 blurb ? blurb : "(null)", dot, default_value);
1149 g_free (type_desc);
1150 g_free (default_value);
1153 g_free (properties);
1155 #ifdef GTK_IS_CONTAINER_CLASS
1156 if (!child_prop && GTK_IS_CONTAINER_CLASS (class)) {
1157 properties = gtk_container_class_list_child_properties (class, &n_properties);
1158 child_prop = TRUE;
1159 continue;
1161 #endif
1163 #ifdef GTK_IS_CELL_AREA_CLASS
1164 if (!child_prop && GTK_IS_CELL_AREA_CLASS (class)) {
1165 properties = gtk_cell_area_class_list_cell_properties (class, &n_properties);
1166 child_prop = TRUE;
1167 continue;
1169 #endif
1171 #ifdef GTK_IS_WIDGET_CLASS
1172 #if GTK_CHECK_VERSION(2,1,0) && !GTK_CHECK_VERSION(3,89,2)
1173 if (!style_prop && GTK_IS_WIDGET_CLASS (class)) {
1174 properties = gtk_widget_class_list_style_properties (GTK_WIDGET_CLASS (class), &n_properties);
1175 style_prop = TRUE;
1176 continue;
1178 #endif
1179 #endif
1183 MAIN_CODE_END = """
1184 break;
1190 def run(options):
1192 c_file = options.module + '-scan.c'
1193 output = open(c_file, 'w')
1195 base_filename = os.path.join(options.output_dir, options.module)
1196 old_signals_filename = base_filename + '.signals'
1197 new_signals_filename = base_filename + '.signals.new'
1198 old_hierarchy_filename = base_filename + '.hierarchy'
1199 new_hierarchy_filename = base_filename + '.hierarchy.new'
1200 old_interfaces_filename = base_filename + '.interfaces'
1201 new_interfaces_filename = base_filename + '.interfaces.new'
1202 old_prerequisites_filename = base_filename + '.prerequisites'
1203 new_prerequisites_filename = base_filename + '.prerequisites.new'
1204 old_args_filename = base_filename + '.args'
1205 new_args_filename = base_filename + '.args.new'
1207 # generate a C program to scan the types
1209 includes = ""
1210 forward_decls = ""
1211 get_types = ""
1212 ntypes = 1
1214 for line in open(options.types):
1215 if line.startswith('#include'):
1216 includes += line
1217 elif line.startswith('%') or line.strip() == '':
1218 continue
1219 else:
1220 line = line.strip()
1221 get_types += ' object_types[i++] = ' + line + ' ();\n'
1222 forward_decls += 'extern GType ' + line + ' (void);\n'
1223 ntypes += 1
1225 output.write(COMMON_INCLUDES)
1227 if includes:
1228 output.write(includes)
1229 else:
1230 output.write(forward_decls)
1232 if options.query_child_properties:
1233 output.write(QUERY_CHILD_PROPS_PROTOTYPE % options.query_child_properties)
1235 # substitute local vars in the template
1236 type_init_func = options.type_init_func
1237 output.write(string.Template(MAIN_CODE).substitute(locals()))
1239 if options.query_child_properties:
1240 output.write(QUERY_CHILD_PROPS_CODE % options.query_child_properties)
1242 output.write(MAIN_CODE_END)
1244 output.close()
1246 # Compile and run our file
1247 if 'libtool' in options.cc:
1248 o_file = options.module + '-scan.lo'
1249 else:
1250 o_file = options.module + '-scan.o'
1252 x_file = options.module + '-scan' + config.exeext
1254 stdout = ""
1255 if not options.verbose:
1256 stdout = ">/dev/null"
1258 # Compiling scanner
1259 command = '%s %s %s -c -o %s %s' % (options.cc, stdout, options.cflags, o_file, c_file)
1260 res = subprocess.check_call(command, shell=True)
1261 if res > 0:
1262 logging.warning('Compilation of scanner failed: %d', res)
1263 return res
1265 # Linking scanner
1266 command = '%s %s %s %s -o %s' % (options.ld, stdout, o_file, options.ldflags, x_file)
1267 res = subprocess.check_call(command, shell=True)
1268 if res > 0:
1269 logging.warning('Linking of scanner failed: %d', res)
1270 return res
1272 # Running scanner
1273 command = '%s ./%s' % (options.run, x_file)
1274 res = subprocess.check_call(command, shell=True)
1275 if res > 0:
1276 logging.warning('Running scanner failed: %d', res)
1277 return res
1279 if 'GTK_DOC_KEEP_INTERMEDIATE' not in os.environ:
1280 os.unlink(c_file)
1281 os.unlink(o_file)
1282 os.unlink(x_file)
1284 common.UpdateFileIfChanged(old_signals_filename, new_signals_filename, False)
1285 common.UpdateFileIfChanged(old_hierarchy_filename, new_hierarchy_filename, False)
1286 common.UpdateFileIfChanged(old_interfaces_filename, new_interfaces_filename, False)
1287 common.UpdateFileIfChanged(old_prerequisites_filename, new_prerequisites_filename, False)
1288 common.UpdateFileIfChanged(old_args_filename, new_args_filename, False)
1290 return 0