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