summaryrefslogtreecommitdiff
path: root/tools/pm
diff options
context:
space:
mode:
Diffstat (limited to 'tools/pm')
-rw-r--r--tools/pm/.cvsignore2
-rw-r--r--tools/pm/DocsParser.pm422
-rw-r--r--tools/pm/Enum.pm219
-rw-r--r--tools/pm/Function.pm343
-rw-r--r--tools/pm/FunctionBase.pm207
-rw-r--r--tools/pm/GtkDefs.pm629
-rw-r--r--tools/pm/Makefile.am10
-rw-r--r--tools/pm/Makefile_list_of_sources.am_fragment2
-rw-r--r--tools/pm/Object.pm72
-rw-r--r--tools/pm/Output.pm781
-rw-r--r--tools/pm/Property.pm94
-rw-r--r--tools/pm/Util.pm113
-rw-r--r--tools/pm/WrapParser.pm1197
13 files changed, 4091 insertions, 0 deletions
diff --git a/tools/pm/.cvsignore b/tools/pm/.cvsignore
new file mode 100644
index 00000000..3dda7298
--- /dev/null
+++ b/tools/pm/.cvsignore
@@ -0,0 +1,2 @@
+Makefile.in
+Makefile
diff --git a/tools/pm/DocsParser.pm b/tools/pm/DocsParser.pm
new file mode 100644
index 00000000..3a52f908
--- /dev/null
+++ b/tools/pm/DocsParser.pm
@@ -0,0 +1,422 @@
+# gtkmm - DocsParser module
+#
+# Copyright 2001 Free Software Foundation
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+#
+
+# Based on XML::Parser tutorial found at http://www.devshed.com/Server_Side/Perl/PerlXML/PerlXML1/page1.html
+# This module isn't properly Object Orientated because the XML Parser needs global callbacks.
+
+package DocsParser;
+use XML::Parser;
+use strict;
+use warnings;
+
+# use Util;
+use Function;
+use GtkDefs;
+use Object;
+
+BEGIN {
+ use Exporter ();
+ our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
+
+ # set the version for version checking
+ $VERSION = 1.00;
+
+ @ISA = qw(Exporter);
+ @EXPORT = ( );
+ %EXPORT_TAGS = ( );
+
+ # your exported package globals go here,
+ # as well as any optionally exported functions
+ @EXPORT_OK = ( );
+}
+our @EXPORT_OK;
+
+#####################################
+
+use strict;
+use warnings;
+
+#####################################
+
+
+$DocsParser::refAppendTo = undef; # string reference to store the data into
+$DocsParser::currentParam = undef;
+
+$DocsParser::objCurrentFunction = 0; #Function
+%DocsParser::hasharrayFunctions = (); #Function elements
+$DocsParser::bOverride = 0; #First we parse the C docs, then we parse the C++ override docs.
+
+$DocsParser::commentStart = " /** ";
+$DocsParser::commentMiddleStart = " * ";
+$DocsParser::commentEnd = " */";
+
+sub read_defs($$$)
+{
+ my ($path, $filename, $filename_override) = @_;
+
+ # check that the file is there.
+ my $filepath = "$path/$filename";
+ if ( ! -r $filepath)
+ {
+ print "DocsParser.pm: Error: can't read defs file $filename\n";
+ return;
+ }
+
+ my $filepath_override = "$path/$filename_override";
+ if ( ! -r $filepath_override)
+ {
+ print "DocsParser.pm: Error: can't read defs file $filename_override\n";
+ return;
+ }
+
+ my $objParser = new XML::Parser();
+ $objParser->setHandlers(Start => \&parse_on_start, End => \&parse_on_end, Char => \&parse_on_cdata);
+
+ # Parse the C docs:
+ $objParser->parsefile($filepath);
+
+ # Parse the C++ overide docs:
+ $DocsParser::bOverride = 1; #The callbacks will act differently when this is set.
+ $objParser->parsefile($filepath_override);
+}
+
+sub parse_on_start($$%)
+{
+ my ($objParser, $tag, %attr) = @_;
+
+ $tag = lc($tag);
+
+ if($tag eq "function")
+ {
+ my $functionName = $attr{name};
+
+ #Reuse existing Function, if it exists:
+ #(For instance, if this is the override parse)
+ $DocsParser::objCurrentFunction = $DocsParser::hasharrayFunctions{$functionName};
+ if(!$DocsParser::objCurrentFunction)
+ {
+ #Make a new one if necessary:
+ $DocsParser::objCurrentFunction = Function::new_empty();
+ }
+
+ $$DocsParser::objCurrentFunction{name} = $functionName;
+ $$DocsParser::objCurrentFunction{description} = "";
+ $$DocsParser::objCurrentFunction{param_names} = [];
+ $$DocsParser::objCurrentFunction{param_descriptions} = ();
+ $$DocsParser::objCurrentFunction{return_description} = "";
+ $$DocsParser::objCurrentFunction{description_overridden} = $DocsParser::bOverride;
+ }
+ elsif($tag eq "parameter")
+ {
+ $DocsParser::currentParam = $attr{name};
+ $$DocsParser::objCurrentFunction{param_descriptions}->{$DocsParser::currentParam} = "";
+ }
+ elsif($tag eq "description")
+ {
+ # Set destination for parse_on_cdata().
+ $DocsParser::refAppendTo = \$$DocsParser::objCurrentFunction{description};
+ }
+ elsif($tag eq "parameter_description")
+ {
+ # Set destination for parse_on_cdata().
+ my $param_desc = \$$DocsParser::objCurrentFunction{param_descriptions};
+ $DocsParser::refAppendTo = \$$param_desc->{$DocsParser::currentParam};
+ }
+ elsif($tag eq "return")
+ {
+ # Set destination for parse_on_cdata().
+ $DocsParser::refAppendTo = \$$DocsParser::objCurrentFunction{return_description};
+ }
+}
+
+
+sub parse_on_end($$)
+{
+ my ($parser, $tag) = @_;
+
+ # Clear destination for parse_on_cdata().
+ $DocsParser::refAppendTo = undef;
+
+ $tag = lc($tag);
+
+ if($tag eq "function")
+ {
+ # Store the Function structure in the array:
+ my $functionName = $$DocsParser::objCurrentFunction{name};
+ $DocsParser::hasharrayFunctions{$functionName} = $DocsParser::objCurrentFunction;
+ $DocsParser::objCurrentFunction = undef;
+ }
+ elsif($tag eq "parameter")
+ {
+ # <parameter name="returns"> and <return> means the same.
+ if($DocsParser::currentParam eq "returns")
+ {
+ my $param_descriptions = \$$DocsParser::objCurrentFunction{param_descriptions};
+ my $return_description = \$$DocsParser::objCurrentFunction{return_description};
+ $$return_description = delete $$param_descriptions->{"returns"};
+ }
+ else
+ {
+ # Append to list of parameters.
+ push(@{$$DocsParser::objCurrentFunction{param_names}}, $DocsParser::currentParam);
+ }
+
+ $DocsParser::currentParam = undef;
+ }
+}
+
+
+sub parse_on_cdata($$)
+{
+ my ($parser, $data) = @_;
+
+ if(defined $DocsParser::refAppendTo)
+ {
+ # Dispatch $data to the current destination string.
+ $$DocsParser::refAppendTo .= $data;
+ }
+}
+
+
+# $strCommentBlock lookup_documentation($strFunctionName)
+sub lookup_documentation($)
+{
+ my ($functionName) = @_;
+
+ my $objFunction = $DocsParser::hasharrayFunctions{$functionName};
+ return "" if(!$objFunction);
+
+ my $text = $$objFunction{description};
+
+ DocsParser::convert_docs_to_cpp($objFunction, \$text);
+ DocsParser::append_parameter_docs($objFunction, \$text);
+ DocsParser::append_return_docs($objFunction, \$text);
+
+
+ # Escape the space after "i.e." or "e.g." in the brief description.
+ $text =~ s/^([^.]*\b(?:i\.e\.|e\.g\.))\s/$1\\ /;
+
+ # Convert to Doxygen-style comment.
+ $text =~ s/\n/\n${DocsParser::commentMiddleStart}/g;
+ $text = $DocsParser::commentStart . $text;
+ $text .= "\n${DocsParser::commentEnd}\n";
+
+ return $text;
+}
+
+
+sub append_parameter_docs($$)
+{
+ my ($obj_function, $text) = @_;
+
+ my @param_names = @{$$obj_function{param_names}};
+ my $param_descriptions = \$$obj_function{param_descriptions};
+
+ # Strip first parameter if this is a method.
+ my $defs_method = GtkDefs::lookup_method_dont_mark($$obj_function{name});
+ shift(@param_names) if($defs_method && $$defs_method{class} ne "");
+
+ foreach my $param (@param_names)
+ {
+ my $desc = $$param_descriptions->{$param};
+ DocsParser::convert_docs_to_cpp($obj_function, \$desc);
+
+ if(length($desc) > 0)
+ {
+ $desc .= '.' unless($desc =~ /(?:^|\.)$/);
+ $$text .= "\n\@param ${param} \u${desc}";
+ }
+ }
+}
+
+
+sub append_return_docs($$)
+{
+ my ($obj_function, $text) = @_;
+
+ my $desc = $$obj_function{return_description};
+ DocsParser::convert_docs_to_cpp($obj_function, \$desc);
+
+ $desc =~ s/\.$//;
+ $$text .= "\n\@return \u${desc}." unless($desc eq "");
+}
+
+
+sub convert_docs_to_cpp($$)
+{
+ my ($obj_function, $text) = @_;
+
+ # Chop off leading and trailing whitespace.
+ $$text =~ s/^\s+//;
+ $$text =~ s/\s+$//;
+
+# if(!$$obj_function{description_overridden})
+# {
+ # Convert C documentation to C++.
+ DocsParser::convert_tags_to_doxygen($text);
+ DocsParser::substitute_identifiers($$obj_function{name}, $text);
+
+ $$text =~ s/\bX\s+Window\b/X&nbsp;\%Window/g;
+ $$text =~ s/\bWindow\s+manager/\%Window manager/g;
+# }
+}
+
+
+sub convert_tags_to_doxygen($)
+{
+ my ($text) = @_;
+
+ for($$text)
+ {
+ # Replace format tags.
+ s"&lt;(/?)emphasis&gt;"<$1em>"g;
+ s"&lt;(/?)literal&gt;"<$1tt>"g;
+ s"&lt;(/?)function&gt;"<$1tt>"g;
+
+ # Some argument names are suffixed by "_" -- strip this.
+ s" ?\@([_a-z]*[a-z])_?\b" \@a $1 "g;
+ s"^Note ?\d?: "\@note "mg;
+
+ s"&lt;/?programlisting&gt;""g;
+ s"&lt;informalexample&gt;"\@code"g;
+ s"&lt;/informalexample&gt;"\@endcode"g;
+ s"&lt;!&gt;""g;
+
+ # Remove all link tags.
+ s"&lt;/?u?link[^&]*&gt;""g;
+
+ # Remove all para tags (from tmpl sgml files).
+ s"&lt;/?para&gt;""g;
+
+ s"\b-&gt;\b"->"g;
+
+ # Doxygen is too dumb to handle &mdash;
+ s"&mdash;" \@htmlonly&mdash;\@endhtmlonly "g;
+
+ s"\%?FALSE\b"<tt>false</tt>"g;
+ s"\%?TRUE\b"<tt>true</tt>"g;
+ s"\%?NULL\b"<tt>0</tt>"g;
+
+ s"#?\bgboolean\b"<tt>bool</tt>"g;
+ s"#?\bg(int|short|long)\b"<tt>$1</tt>"g;
+ s"#?\bgu(int|short|long)\b"<tt>unsigned $1</tt>"g;
+
+ # For Gtk::TextIter.
+ s"(\\[rn])\b"<tt>\\$1</tt>"g;
+ }
+}
+
+
+sub substitute_identifiers($$)
+{
+ my ($doc_func, $text) = @_;
+
+ for($$text)
+ {
+ # TODO: handle more than one namespace
+
+ s/[#%]([A-Z][a-z]*)([A-Z][A-Za-z]+)\b/$1::$2/g; # type names
+
+ s/[#%]([A-Z])([A-Z]*)_([A-Z\d_]+)\b/$1\L$2\E::$3/g; # enum values
+
+ # Undo wrong substitutions.
+ s/\bHas::/HAS_/g;
+ s/\bNo::/NO_/g;
+
+ # Replace C function names with C++ counterparts.
+ s/\b([a-z]+_[a-z][a-z\d_]+) ?\(\)/&DocsParser::substitute_function($doc_func, $1)/eg;
+ }
+}
+
+
+sub substitute_function($$)
+{
+ my ($doc_func, $name) = @_;
+
+ if(my $defs_method = GtkDefs::lookup_method_dont_mark($name))
+ {
+ if(my $defs_object = DocsParser::lookup_object_of_method($$defs_method{class}, $name))
+ {
+ my $module = $$defs_object{module};
+ my $class = $$defs_object{name};
+
+ DocsParser::build_method_name($doc_func, $module, $class, \$name);
+ }
+ }
+ else
+ {
+ # Not perfect, but better than nothing.
+ $name =~ s/^g_/Glib::/;
+ }
+
+ return $name . "()";
+}
+
+
+sub lookup_object_of_method($$)
+{
+ my ($object, $name) = @_;
+
+ if($object ne "")
+ {
+ # We already know the C object name, because $name is a non-static method.
+ return GtkDefs::lookup_object($object);
+ }
+
+ my @parts = split(/_/, $name);
+ pop(@parts);
+
+ # (gtk, foo, bar) -> (Gtk, Foo, Bar)
+ foreach(@parts) { $_ = (length > 2) ? ucfirst : uc; }
+
+ # Do a bit of try'n'error.
+ while(scalar(@parts) > 1)
+ {
+ my $try = join("", @parts);
+
+ if(my $defs_object = GtkDefs::lookup_object($try))
+ { return $defs_object; }
+
+ pop(@parts);
+ }
+
+ return undef;
+}
+
+
+sub build_method_name($$$$)
+{
+ my ($doc_func, $module, $class, $name) = @_;
+
+ my $prefix = $module . $class;
+
+ $prefix =~ s/([a-z])([A-Z])/$1_$2/g;
+ $prefix = lc($prefix) . '_';
+
+ if($$name =~ /^$prefix/)
+ {
+ my $scope = "";
+ $scope = "${module}::${class}::" unless($doc_func =~ /^$prefix/);
+
+ substr($$name, 0, length($prefix)) = $scope;
+ }
+}
+
+
+1; # indicate proper module load.
diff --git a/tools/pm/Enum.pm b/tools/pm/Enum.pm
new file mode 100644
index 00000000..51d118f6
--- /dev/null
+++ b/tools/pm/Enum.pm
@@ -0,0 +1,219 @@
+package Enum;
+
+use strict;
+use warnings;
+
+BEGIN {
+ use Exporter ();
+ our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
+
+ # set the version for version checking
+ $VERSION = 1.00;
+ @ISA = qw(Exporter);
+ @EXPORT = ( );
+ %EXPORT_TAGS = ( );
+ # your exported package globals go here,
+ # as well as any optionally exported functions
+ @EXPORT_OK = ( );
+ }
+our @EXPORT_OK;
+
+# class Enum
+# {
+# bool flags;
+# string type;
+# string module;
+# string c_type;
+#
+# string array elem_names;
+# string array elem_values;
+#
+# bool mark;
+# }
+
+
+sub new
+{
+ my ($def) = @_;
+ my $self = {};
+ bless $self;
+
+ $def =~ s/^\(//;
+ $def =~ s/\)$//;
+
+ $$self{mark} = 0;
+ $$self{flags} = 0;
+
+ $$self{elem_names} = [];
+ $$self{elem_values} = [];
+
+ # snarf down the fields
+
+ if($def =~ s/^define-(enum|flags)-extended (\S+)//)
+ {
+ $$self{type} = $2;
+ $$self{flags} = 1 if($1 eq "flags");
+ }
+
+ $$self{module} = $1 if($def =~ s/\(in-module "(\S+)"\)//);
+ $$self{c_type} = $1 if($def =~ s/\(c-name "(\S+)"\)//);
+
+ # values are compound lisp statement
+ if($def =~ s/\(values((?: '\("\S+" "\S+" "[^"]+"\))*) \)//)
+ {
+ $self->parse_values($1);
+ }
+
+ if($def !~ /^\s*$/)
+ {
+ GtkDefs::error("Unhandled enum def ($def) in $$self{module}\::$$self{type}\n")
+ }
+
+ # this should never happen
+ warn if(scalar(@{$$self{elem_names}}) != scalar(@{$$self{elem_values}}));
+
+ return $self;
+}
+
+sub parse_values($$)
+{
+ my ($self, $value) = @_;
+
+ # break up the value statements
+ foreach(split(/\s*'*[()]\s*/, $value))
+ {
+ next if($_ eq "");
+
+ if(/^"\S+" "(\S+)" "([^"]+)"$/)
+ {
+ my ($name, $value) = ($1, $2);
+
+ # cut off the module prefix, e.g. GTK_
+ $name =~ s/^[^_]+_//;
+
+ push(@{$$self{elem_names}}, $name);
+ push(@{$$self{elem_values}}, $value);
+ }
+ else
+ {
+ GtkDefs::error("Unknown value statement ($_) in $$self{c_type}\n");
+ }
+ }
+}
+
+sub beautify_values($)
+{
+ my ($self) = @_;
+
+ return if($$self{flags});
+
+ my $elem_names = $$self{elem_names};
+ my $elem_values = $$self{elem_values};
+
+ my $num_elements = scalar(@$elem_values);
+ return if($num_elements == 0);
+
+ my $first = $$elem_values[0];
+ return if($first !~ /^-?[0-9]+$/);
+
+ my $prev = $first;
+
+ # Continuous? (Aliases to prior enum values are allowed.)
+ foreach my $value (@$elem_values)
+ {
+ return if(($value < $first) || ($value > $prev + 1));
+ $prev = $value;
+ }
+
+ # This point is reached only if the values are a continuous range.
+ # 1) Let's kill all the superfluous values, for better readability.
+ # 2) Substitute aliases to prior enum values.
+
+ my %aliases = ();
+
+ for(my $i = 0; $i < $num_elements; ++$i)
+ {
+ my $value = \$$elem_values[$i];
+ my $alias = \$aliases{$$value};
+
+ if(defined($$alias))
+ {
+ $$value = $$alias;
+ }
+ else
+ {
+ $$alias = $$elem_names[$i];
+ $$value = "" unless($first != 0 && $$value == $first);
+ }
+ }
+}
+
+sub build_element_list($$$$)
+{
+ my ($self, $ref_flags, $ref_no_gtype, $indent) = @_;
+
+ my @subst_in = [];
+ my @subst_out = [];
+
+ # Build a list of custom substitutions, and recognize some flags too.
+
+ foreach(@$ref_flags)
+ {
+ if(/^\s*(NO_GTYPE)\s*$/)
+ {
+ $$ref_no_gtype = $1;
+ }
+ elsif(/^\s*s#([^#]+)#([^#]*)#\s*$/)
+ {
+ push(@subst_in, $1);
+ push(@subst_out, $2);
+ }
+ elsif($_ !~ /^\s*$/)
+ {
+ return undef;
+ }
+ }
+
+ my $elem_names = $$self{elem_names};
+ my $elem_values = $$self{elem_values};
+
+ my $num_elements = scalar(@$elem_names);
+ my $elements = "";
+
+ for(my $i = 0; $i < $num_elements; ++$i)
+ {
+ my $name = $$elem_names[$i];
+ my $value = $$elem_values[$i];
+
+ for(my $ii = 0; $ii < scalar(@subst_in); ++$ii)
+ {
+ $name =~ s/${subst_in[$ii]}/${subst_out[$ii]}/;
+ $value =~ s/${subst_in[$ii]}/${subst_out[$ii]}/;
+ }
+
+ $elements .= "${indent}${name}";
+ $elements .= " = ${value}" if($value ne "");
+ $elements .= ",\n" if($i < $num_elements - 1);
+ }
+
+ return $elements;
+}
+
+sub dump($)
+{
+ my ($self) = @_;
+
+ print "<enum module=\"$$self{module}\" type=\"$$self{type}\" flags=$$self{flags}>\n";
+
+ my $elem_names = $$self{elem_names};
+ my $elem_values = $$self{elem_values};
+
+ for(my $i = 0; $i < scalar(@$elem_names); ++$i)
+ {
+ print " <element name=\"$$elem_names[$i]\" value=\"$$elem_values[$i]\"/>\n";
+ }
+
+ print "</enum>\n\n";
+}
+
+1; # indicate proper module load.
diff --git a/tools/pm/Function.pm b/tools/pm/Function.pm
new file mode 100644
index 00000000..7544016c
--- /dev/null
+++ b/tools/pm/Function.pm
@@ -0,0 +1,343 @@
+package Function;
+
+use strict;
+use warnings;
+use Util;
+use FunctionBase;
+
+BEGIN {
+ use Exporter ();
+ our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
+
+ # set the version for version checking
+ $VERSION = 1.00;
+ @ISA = qw(FunctionBase);
+ @EXPORT = qw(&func1 &func2 &func4);
+ %EXPORT_TAGS = ( );
+ # your exported package globals go here,
+ # as well as any optionally exported functions
+ @EXPORT_OK = qw($Var1 %Hashit &func3);
+ }
+our @EXPORT_OK;
+
+##################################################
+### Function
+# Commonly used algorithm for parsing a function declaration into
+# its component pieces
+#
+# class Function : FunctionBase
+# {
+# string rettype;
+# bool const;
+# bool static;
+# string name; e.g. gtk_accelerator_valid
+# string c_name;
+# string array param_type;
+# string array param_name;
+# string array param_default_value;
+# string in_module; e.g. Gtk
+# string signal_when. e.g. first, last, or both.
+# string class e.g. GtkButton ( == of-object. Useful for signal because their names are not unique.
+# string entity_type. e.g. method or signal
+# }
+
+sub new_empty()
+{
+ my $self = {};
+ bless $self;
+
+ return $self;
+}
+
+# $objFunction new($function_declaration, $objWrapParser)
+sub new($$)
+{
+ #Parse a function/method declaration.
+ #e.g. guint gtk_something_set_thing(guint a, const gchar* something)
+
+ my ($line, $objWrapParser) = @_;
+
+ my $self = {};
+ bless $self;
+
+ #Initialize member data:
+ $$self{rettype} = "";
+ $$self{rettype_needs_ref} = 0; #Often the gtk function doesn't do an extra ref for the receiver.
+ $$self{const} = 0;
+ $$self{name} = "";
+ $$self{param_types} = [];
+ $$self{param_names} = [];
+ $$self{param_default_value} = [];
+ $$self{in_module} = "";
+ $$self{class} = "";
+ $$self{entity_type} = "method";
+
+ $line =~ s/^\s+//; # Remove leading whitespace.
+ $line =~ s/\s+/ /g; # Compress white space.
+
+ if ($line =~ /^static\s+([^()]+)\s+(\S+)\s*\((.*)\)\s*$/)
+ {
+ $$self{rettype} = $1;
+ $$self{name} = $2;
+ $$self{c_name} = $2;
+ $self->parse_param($3);
+ $$self{static} = 1;
+ }
+ elsif ($line =~ /^([^()]+)\s+(\S+)\s*\((.*)\)\s*(const)*$/)
+ {
+ no warnings qw(uninitialized); # disable the uninitialize warning for $4
+ $$self{rettype} = $1;
+ $$self{name} = $2;
+ $$self{c_name} = $2;
+ $self->parse_param($3);
+ $$self{const} = ($4 eq "const");
+ }
+ else
+ {
+ $objWrapParser->error("fail to parse $line\n");
+ }
+
+ return $self;
+}
+
+
+# $objFunction new_ctor($function_declaration, $objWrapParser)
+# Like new(), but the function_declaration doesn't need a return type.
+sub new_ctor($$)
+{
+ #Parse a function/method declaration.
+ #e.g. guint gtk_something_set_thing(guint a, const gchar* something)
+
+ my ($line, $objWrapParser) = @_;
+
+ my $self = {};
+ bless $self;
+
+ #Initialize member data:
+ $$self{rettype} = "";
+ $$self{rettype_needs_ref} = 0;
+ $$self{const} = 0;
+ $$self{name} = "";
+ $$self{param_types} = [];
+ $$self{param_names} = [];
+ $$self{param_default_value} = [];
+ $$self{in_module} = "";
+ $$self{class} = "";
+ $$self{entity_type} = "method";
+
+ $line =~ s/^\s+//; # Remove leading whitespace.
+ $line =~ s/\s+/ /g; # Compress white space.
+
+ if ($line =~ /^(\S+)\s*\((.*)\)\s*/)
+ {
+ $$self{name} = $1;
+ $$self{c_name} = $2;
+ $self->parse_param($2);
+ }
+ else
+ {
+ $objWrapParser->error("fail to parse $line\n");
+ }
+
+ return $self;
+}
+
+# $num num_args()
+sub num_args #($)
+{
+ my ($self) = @_;
+ my $param_types = $$self{param_types};
+ return $#$param_types+1;
+}
+
+# parses C++ parameter lists.
+# forms a list of types, names, and initial values
+# (we don't currently use values)
+sub parse_param($$)
+{
+ my ($self, $line) = @_;
+
+
+ my $type = "";
+ my $name = "";
+ my $value = "";
+ my $id = 0;
+ my $has_value = 0;
+
+ my $param_types = $$self{param_types};
+ my $param_names = $$self{param_names};
+ my $param_default_values = $$self{param_default_value};
+
+ # clean up space and handle empty case
+ $line = string_trim($line);
+ $line =~ s/\s+/ /g; # Compress whitespace.
+ return if ($line =~ /^$/);
+
+ # parse through argument list
+ my @str = ();
+ my $par = 0;
+ foreach (split(/([,=&*()])|(<[^,]*>)|(\s+)/, $line)) #special characters OR <something> OR whitespace.
+ {
+ next if ( !defined($_) or $_ eq "" );
+ if ( $_ eq "(" )
+ {
+ push(@str, $_);
+ $par++;
+ next;
+ }
+ elsif ( $_ eq ")" )
+ {
+ push(@str, $_);
+ $par--;
+ next;
+ }
+ elsif ( $par || /^(const)|(<[^,]*>)|([*&])|(\s+)/ ) #TODO: What's happening here?
+ {
+ push(@str, $_);
+ next;
+ }
+ elsif ( $_ eq "=" ) #Default value
+ {
+ $type = join("", @str); #The type is everything before the = character.
+ @str = (); #Wipe it so that it will only contain the default value, which comes next.
+ $has_value = 1;
+ next;
+ }
+ elsif ( $_ eq "," ) #The end of one parameter:
+ {
+ if ($has_value)
+ {
+ $value = join("", @str); # If there's a default value, then it's the part before the next ",".
+ }
+ else
+ {
+ $type = join("", @str);
+ }
+
+ if ($name eq "")
+ {
+ $name = sprintf("p%s", $#$param_types + 2)
+ }
+
+ $type = string_trim($type);
+
+ push(@$param_types, $type);
+ push(@$param_names, $name);
+ push(@$param_default_values, $value);
+
+ #Clear variables, ready for the next parameter.
+ @str = ();
+ $type= "";
+ $value = "";
+ $has_value = 0;
+ $name = "";
+
+ $id = 0;
+
+ next;
+ }
+
+ if ($has_value)
+ {
+ push(@str, $_);
+ next;
+ }
+
+ $id++;
+ $name = $_ if ($id == 2);
+ push(@str, $_) if ($id == 1);
+
+ if ($id > 2)
+ {
+ print STDERR "Can't parse $line.\n";
+ print STDERR " arg type so far: $type\n";
+ print STDERR " arg name so far: $name\n";
+ print STDERR " arg default value so far: $value\n";
+ }
+ }
+
+ # handle last argument (There's no , at the end.)
+ if ($has_value)
+ {
+ $value = join("", @str);
+ }
+ else
+ {
+ $type = join("", @str);
+ }
+
+ if ($name eq "")
+ {
+ $name = sprintf("p%s", $#$param_types + 2)
+ }
+
+ $type = string_trim($type);
+
+ push(@$param_types, $type);
+ push(@$param_names, $name);
+ push(@$param_default_values, $value);
+}
+
+# add_parameter_autoname($, $type, $name)
+# Adds e.g "sometype somename"
+sub add_parameter_autoname($$)
+{
+ my ($self, $type) = @_;
+
+ add_parameter($self, $type, "");
+}
+
+# add_parameter($, $type, $name)
+# Adds e.g GtkSomething* p1"
+sub add_parameter($$$)
+{
+ my ($self, $type, $name) = @_;
+ $type = string_unquote($type);
+ $type =~ s/-/ /g;
+
+ my $param_names = $$self{param_names};
+
+ if ($name eq "")
+ {
+ $name = sprintf("p%s", $#$param_names + 2);
+ }
+
+ push(@$param_names, $name);
+
+ my $param_types = $$self{param_types};
+
+ push(@$param_types, $type);
+
+ return $self;
+}
+
+# $string get_refdoc_comment()
+# Generate a readable prototype for signals.
+sub get_refdoc_comment($)
+{
+ my ($self) = @_;
+
+ my $str = " /**\n";
+
+ $str .= " * \@par Prototype:\n";
+ $str .= " * <tt>$$self{rettype} \%$$self{name}(";
+
+ my $param_names = $$self{param_names};
+ my $param_types = $$self{param_types};
+ my $num_params = scalar(@$param_types);
+
+ # List the parameters:
+ for(my $i = 0; $i < $num_params; ++$i)
+ {
+ $str .= $$param_types[$i] . ' ' . $$param_names[$i];
+ $str .= ", " if($i < $num_params - 1);
+ }
+
+ $str .= ")</tt>\n";
+ $str .= " */";
+
+ return $str;
+}
+
+1; # indicate proper module load.
+
diff --git a/tools/pm/FunctionBase.pm b/tools/pm/FunctionBase.pm
new file mode 100644
index 00000000..12b89f66
--- /dev/null
+++ b/tools/pm/FunctionBase.pm
@@ -0,0 +1,207 @@
+package FunctionBase;
+
+use strict;
+use warnings;
+use Util;
+
+BEGIN {
+ use Exporter ();
+ our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
+
+ # set the version for version checking
+ $VERSION = 1.00;
+ @ISA = qw(Exporter);
+ @EXPORT = qw(&func1 &func2 &func4);
+ %EXPORT_TAGS = ( );
+ # your exported package globals go here,
+ # as well as any optionally exported functions
+ @EXPORT_OK = qw($Var1 %Hashit &func3);
+ }
+our @EXPORT_OK;
+
+##################################################
+### FunctionBase
+# Contains data and methods used by both Function (C++ declarations) and GtkDefs::Function (C defs descriptions)
+# Note that GtkDefs::Signal inherits from GtkDefs::Function so it get these methods too.
+#
+# class Function : FunctionBase
+# {
+# string array param_types;
+# string array param_names;
+# string array param_documentation;
+# string return_documention;
+# }
+
+
+# $string args_types_only($)
+# comma-delimited argument types.
+sub args_types_only($)
+{
+ my ($self) = @_;
+
+ my $param_types = $$self{param_types};
+ return join(", ", @$param_types);
+}
+
+# $string args_names_only($)
+sub args_names_only($)
+{
+ my ($self) = @_;
+
+ my $param_names = $$self{param_names};
+ return join(", ", @$param_names);
+}
+
+# $string args_types_and_names($)
+sub args_types_and_names($)
+{
+ my ($self) = @_;
+
+ my $i;
+
+ my $param_names = $$self{param_names};
+ my $param_types = $$self{param_types};
+ my @out;
+
+ for ($i = 0; $i < $#$param_types + 1; $i++)
+ {
+ my $str = sprintf("%s %s", $$param_types[$i], $$param_names[$i]);
+ push(@out, $str);
+ }
+
+ return join(", ", @out);
+}
+
+# $string args_names_only_without_object($)
+sub args_names_only_without_object2($)
+{
+ my ($self) = @_;
+
+ my $param_names = $$self{param_names};
+
+ my $result = "";
+ my $bInclude = 0; #Ignore the first (object) arg.
+ foreach (@{$param_names})
+ {
+ # Add comma if there was an arg before this one:
+ if( $result ne "")
+ {
+ $result .= ", ";
+ }
+
+ # Append this arg if it's not the first one:
+ if($bInclude)
+ {
+ $result .= $_;
+ }
+
+ $bInclude = 1;
+ }
+
+ return $result;
+}
+
+# $string args_types_and_names_without_object($)
+sub args_types_and_names_without_object($)
+{
+ my ($self) = @_;
+
+ my $param_names = $$self{param_names};
+ my $param_types = $$self{param_types};
+ my $i = 0;
+ my @out;
+
+ for ($i = 1; $i < $#$param_types + 1; $i++) #Ignore the first arg.
+ {
+ my $str = sprintf("%s %s", $$param_types[$i], $$param_names[$i]);
+ push(@out, $str);
+ }
+
+ return join(", ", @out);
+}
+
+# $string args_names_only_without_object($)
+sub args_names_only_without_object($)
+{
+ my ($self) = @_;
+
+ my $param_names = $$self{param_names};
+
+ my $result = "";
+ my $bInclude = 0; #Ignore the first (object) arg.
+ foreach (@{$param_names})
+ {
+ # Add comma if there was an arg before this one:
+ if( $result ne "")
+ {
+ $result .= ", ";
+ }
+
+ # Append this arg if it's not the first one:
+ if($bInclude)
+ {
+ $result .= $_;
+ }
+
+ $bInclude = 1;
+ }
+
+ return $result;
+}
+
+sub dump($)
+{
+ my ($self) = @_;
+
+ my $param_types = $$self{param_types};
+ my $param_names = $$self{param_names};
+
+ print "<function>\n";
+ foreach (keys %$self)
+ {
+ print " <$_ value=\"$$self{$_}\"/>\n" if (!ref $$self{$_} && $$self{$_} ne "");
+ }
+
+ if (scalar(@$param_types)>0)
+ {
+ print " <parameters>\n";
+
+ for (my $i = 0; $i < scalar(@$param_types); $i++)
+ {
+ print " \"$$param_types[$i]\" \"$$param_names[$i]\" \n";
+ }
+
+ print " </parameters>\n";
+ }
+
+ print "</function>\n\n";
+}
+
+#sub args_types_and_names_with_default_values($)
+#{
+# my ($self) = @_;
+#
+# my $i;
+#
+# my $param_names = $$self{param_names};
+# my $param_types = $$self{param_types};
+# my $param_default_values = $$self{param_default_values};
+# my @out;
+#
+# for ($i = 0; $i < $#$param_types + 1; $i++)
+# {
+# my $str = sprintf("%s %s", $$param_types[$i], $$param_names[$i]);
+#
+# if($$param_default_values[$i] ne "")
+# {
+# $str .= " = " . $$param_default_values[$i];
+# }
+# push(@out, $str);
+# }
+#
+# return join(", ", @out);
+#}
+
+
+1; # indicate proper module load.
+
diff --git a/tools/pm/GtkDefs.pm b/tools/pm/GtkDefs.pm
new file mode 100644
index 00000000..952e2a0b
--- /dev/null
+++ b/tools/pm/GtkDefs.pm
@@ -0,0 +1,629 @@
+# gtkmm - GtkDefs module
+#
+# Copyright 2001 Free Software Foundation
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+#
+package GtkDefs;
+use strict;
+use warnings;
+
+use Util;
+use Enum;
+use Object;
+use Property;
+use FunctionBase;
+
+#
+# Public functions
+# read_defs(path, file)
+#
+# @ get_methods()
+# @ get_signals()
+# @ get_properties()
+#
+# $ lookup_enum(c_type)
+# $ lookup_object(c_name)
+# $ lookup_method(c_name)
+# $ lookup_function(c_name)
+# $ lookup_property(object, c_name)
+# $ lookup_signal(object, c_name)
+#
+
+BEGIN {
+ use Exporter ();
+ our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
+
+ # set the version for version checking
+ $VERSION = 1.00;
+
+ @ISA = qw(Exporter);
+ @EXPORT = ( );
+ %EXPORT_TAGS = ( );
+
+ # your exported package globals go here,
+# # as well as any optionally exported functions
+ @EXPORT_OK = ( );
+}
+our @EXPORT_OK;
+
+#####################################
+
+use strict;
+use warnings;
+
+#####################################
+
+%GtkDefs::enums = (); #Enum
+%GtkDefs::objects = (); #Object
+%GtkDefs::methods = (); #GtkDefs::Function
+%GtkDefs::signals = (); #GtkDefs::Signal
+%GtkDefs::properties = (); #Property
+
+@GtkDefs::read = ();
+@GtkDefs::file = ();
+
+
+#####################################
+#prototype to get rid of warning
+sub read_defs($$;$);
+
+sub read_defs($$;$)
+{
+ my ($path, $filename, $restrict) = @_;
+ $restrict = "" if ($#_ < 2);
+
+ # check that the file is there.
+ if ( ! -r "$path/$filename")
+ {
+ print "Error: can't read defs file $filename\n";
+ return;
+ }
+
+ # break the tokens into lisp phrases up to three levels deep.
+ # WARNING: reading the following perl statement may induce seizures,
+ # please flush eyes with water immediately, and consult a mortician.
+ my @tokens = split(
+ m/(
+ \(
+ (?:
+ [^()]*
+ \(
+ (?:
+ [^()]*
+ \(
+ [^()]+
+ \)
+ )*
+ [^()]*
+ \)
+ )*
+ [^()]*
+ \)
+ )/x,
+ read_file($path, $filename));
+
+ # scan through top level tokens
+ while ($#tokens > -1)
+ {
+ my $token = shift @tokens;
+ next if ($token =~ /^\s*$/);
+
+ if ($token =~ /\(include (\S+)\)/)
+ {
+ read_defs($path,$1,$restrict);
+ next;
+ }
+ elsif ($token =~ /^\(define-flags-extended.*\)$/)
+ { on_enum($token); }
+ elsif ($token =~ /^\(define-enum-extended.*\)$/)
+ { on_enum($token); }
+ elsif ($token =~ /^\(define-flags.*\)$/)
+ { }
+ elsif ($token =~ /^\(define-enum.*\)$/)
+ { }
+ elsif ($token =~ /^\(define-object.*\)$/)
+ { on_object($token); }
+ elsif ($token =~ /^\(define-function.*\)$/)
+ { on_function($token); }
+ elsif ($token =~ /^\(define-method.*\)$/)
+ { on_method($token); }
+ elsif ($token =~ /^\(define-property.*\)$/)
+ { on_property($token); }
+ elsif ($token =~ /^\(define-signal.*\)$/)
+ { on_signal($token); }
+ elsif ($token =~ /^\(define-vfunc.*\)$/)
+ { on_vfunc($token); }
+ else
+ {
+ if ( $token =~ /^\(define-(\S+) (\S+)/)
+ {
+ # FIXME need to figure out the line number.
+ print STDERR "Broken lisp definition for $1 $2.\n";
+ }
+ else
+ {
+ print "unknown token $token \n";
+ }
+ }
+ }
+}
+
+
+sub read_file($$)
+{
+ my ($path, $filename)=@_;
+ my @buf = ();
+
+ # don't read a file twice
+ foreach (@GtkDefs::read)
+ {
+ return "" if ($_ eq "$path/$filename");
+ }
+ push @GtkDefs::read, "$path/$filename";
+
+ # read file while stripping comments
+ open(FILE, "$path/$filename");
+ while (<FILE>)
+ {
+ s/^;.*$//; # remove comments
+ chop; # remove new lines
+ push(@buf, $_);
+ }
+ close(FILE);
+
+ $_ = join("", @buf);
+ s/\s+/ /g;
+ return $_;
+}
+
+
+sub on_enum($)
+{
+ my $thing = Enum::new(shift(@_));
+ $GtkDefs::enums{$$thing{c_type}} = $thing;
+}
+
+sub on_object($)
+{
+ my $thing = Object::new(shift(@_));
+ $GtkDefs::objects{$$thing{c_name}} = $thing;
+}
+
+sub on_function($)
+{
+ my $thing = GtkDefs::Function::new(shift(@_));
+ $GtkDefs::methods{$$thing{c_name}} = $thing;
+}
+
+sub on_method($)
+{
+ my $thing = GtkDefs::Function::new(shift(@_));
+ $GtkDefs::methods{$$thing{c_name}} = $thing if ($thing);
+}
+
+sub on_property($)
+{
+ my $thing = Property::new(shift(@_));
+ $GtkDefs::properties{"$$thing{class}::$$thing{name}"} = $thing;
+}
+
+sub on_signal($)
+{
+ my $thing = GtkDefs::Signal::new(shift(@_));
+ $GtkDefs::signals{"$$thing{class}::$$thing{name}"} = $thing;
+}
+
+sub on_vfunc($)
+{
+ my $thing = GtkDefs::Signal::new(shift(@_));
+ $GtkDefs::signals{"$$thing{class}::$$thing{name}"} = $thing;
+}
+
+##########################
+
+sub get_enums
+{
+ return sort {$$a{c_type} cmp $$b{c_type}} values %GtkDefs::enums;
+}
+sub get_methods
+{
+ return sort {$$a{c_name} cmp $$b{c_name}} values %GtkDefs::methods;
+}
+sub get_signals
+{
+ return sort {$$a{name} cmp $$b{name}} values %GtkDefs::signals;
+}
+sub get_properties
+{
+ return sort {$$a{name} cmp $$b{name}} values %GtkDefs::properties;
+}
+
+sub get_marked
+{
+ no warnings;
+ return grep {$$_{mark}==1} values %GtkDefs::methods;
+}
+
+# This searches for items wrapped by this file and then tries to locate
+# other functions/signal/properties which may have been left unmarked.
+sub get_unwrapped
+{
+ # find methods which were used in for a _WRAP
+ my @targets;
+ push @targets,grep {$$_{entity_type} eq "method" & $$_{mark}==1} values %GtkDefs::methods;
+ push @targets,grep {$$_{mark}==1} values %GtkDefs::signals;
+ push @targets,grep {$$_{mark}==1} values %GtkDefs::properties;
+
+ # find the classes which used them.
+ my @classes = join(" ", unique(map { $$_{class} } @targets));
+
+ # find methods which are in those classes which didn't get marked.
+ my @unwrapped;
+ my $class;
+ foreach $class (@classes)
+ {
+ push @unwrapped, grep {$$_{class} eq $class & $$_{mark}==0} values %GtkDefs::methods;
+ push @unwrapped, grep {$$_{class} eq $class & $$_{mark}==0} values %GtkDefs::properties;
+ push @unwrapped, grep {$$_{class} eq $class & $$_{mark}==0} values %GtkDefs::signals;
+ }
+
+ return @unwrapped;
+}
+
+##########################
+
+sub lookup_enum($)
+{
+ no warnings;
+ my ($c_type) = @_;
+ my $obj = $GtkDefs::enums{$c_type};
+ return 0 if(!$obj);
+ $$obj{mark} = 1;
+ return $obj;
+}
+
+sub lookup_object($)
+{
+ no warnings;
+ return $GtkDefs::objects{$_[0]};
+}
+
+# $objProperty lookup_property($name, $parent_object_name)
+sub lookup_property($$)
+{
+ no warnings;
+ my ($parent_object_name, $name) = @_;
+ $name =~ s/-/_/g;
+ my $obj = $GtkDefs::properties{"${parent_object_name}::${name}"};
+ return 0 if ($obj eq "");
+ $$obj{mark} = 1;
+ return $obj;
+}
+
+sub lookup_method_dont_mark($)
+{
+ no warnings;
+ my ($c_name) = @_;
+ $c_name =~ s/-/_/g;
+
+ my $obj = $GtkDefs::methods{$c_name};
+ return 0 if ($obj eq "");
+
+ return $obj;
+}
+
+sub lookup_method($)
+{
+ my $obj = lookup_method_dont_mark($_);
+
+ $$obj{mark} = 1 if($obj);
+ return $obj;
+}
+
+sub lookup_function($)
+{
+ return lookup_method($_[0]);
+}
+
+sub lookup_signal($$)
+{
+ no warnings;
+ my ($parent_object_name, $name) = @_;
+
+ $name =~ s/-/_/g;
+ my $obj = $GtkDefs::signals{"${parent_object_name}::${name}"};
+ return 0 if ($obj eq "");
+ $$obj{mark} = 1;
+ return $obj;
+}
+
+sub error
+{
+ my $format = shift @_;
+ printf STDERR "GtkDefs.pm: $format\n", @_;
+}
+
+
+########################################################################
+package GtkDefs::Function;
+BEGIN { @GtkDefs::Function::ISA=qw(FunctionBase); }
+
+# class Function : FunctionBase
+#
+# {
+# string name; e.g. gtk_accelerator_valid
+# string c_name;
+# string class e.g. GtkButton
+#
+# string rettype;
+# string array param_types;
+# string array param_names;
+#
+# string entity_type. e.g. method or signal
+#
+# bool varargs;
+# bool mark;
+#
+# }
+
+# "new" can't have prototype
+sub new
+{
+ my ($def) = @_;
+ my $whole = $def;
+ my $self = {};
+ bless $self;
+
+ $def =~ s/^\(//;
+ $def =~ s/\)$//;
+ $def =~ s/^\s*define-(\S+)\s+(\S+)\s*//;
+ $$self{entity_type} = $1;
+ $$self{name} = $2;
+ $$self{name} =~ s/-/_/g; # change - to _
+
+ # init variables
+ $$self{mark} = 0;
+ $$self{rettype} = "none";
+ $$self{param_types} = [];
+ $$self{param_names} = [];
+ $$self{class} = "";
+
+ # snarf down lisp fields
+ $$self{c_name} = $1 if ($def=~s/\(c-name "(\S+)"\)//);
+ $$self{class} = $1 if ($def=~s/\(of-object "(\S+)"\)//);
+
+ if ($def =~ s/\(return-type "(\S+)"\)//)
+ {
+ $$self{rettype} = $1;
+ $$self{rettype} =~ s/-/ /g; #e.g. replace const-gchar* with const gchar*. Otherwise it will be used in code.
+ }
+
+ $$self{varargs} = 1 if ($def=~s/\(varargs\s+#t\)//);
+ $$self{rettype} = "void" if ($$self{rettype} eq "none");
+
+ # methods have a parameter not stated in the defs file
+ if ($$self{entity_type} eq "method")
+ {
+ push( @{$$self{param_types}}, "$$self{class}*" );
+ push( @{$$self{param_names}}, "self" );
+ }
+
+ # parameters are compound lisp statement
+ if ($def =~ s/\(parameters(( '\("\S+" "\S+"\))*) \)//)
+ {
+ $self->parse_param($1);
+ }
+
+ # is-constructor-of:
+ if ($def =~ s/\(is-constructor-of "(\S+)"\)//)
+ {
+ #Ignore them.
+ }
+
+ GtkDefs::error("Unhandled function parameter ($def) in $$self{c_name}\n")
+ if ($def !~ /^\s*$/);
+
+ return $self;
+}
+
+sub parse_param($$)
+{
+ my ($self, $param) = @_;
+
+ # break up the parameter statements
+ foreach (split(/\s*'*[()]\s*/, $param))
+ {
+ next if ($_ eq "");
+ if (/^"(\S+)" "(\S+)"$/)
+ {
+ my ($p1, $p2) = ($1,$2);
+ $p1 =~ s/-/ /;
+ push( @{$$self{param_types}}, $p1);
+ push( @{$$self{param_names}}, $p2);
+ }
+ else
+ {
+ GtkDefs::error("Unknown parameter statement ($_) in $$self{c_name}\n");
+ }
+ }
+}
+
+
+# $string get_return_type_for_methods().
+# Changes gchar* (not const-gchar*) to return-gchar* so that _CONVERT knows that it needs to be freed.
+sub get_return_type_for_methods($)
+{
+ my ($self) = @_;
+
+ my $rettype = $$self{rettype};
+ if($rettype eq "gchar*" || $rettype eq "char*")
+ {
+ $rettype = "return-" . $rettype;
+ }
+
+ return $rettype;
+}
+
+sub get_param_names
+{
+ my ($self) = @_;
+ return @$self{param_names};
+}
+
+######################################################################
+package GtkDefs::Signal;
+BEGIN { @GtkDefs::Signal::ISA=qw(GtkDefs::Function); }
+
+# class Signal : Function
+# {
+# string name; e.g. gtk_accelerator_valid
+# string class e.g. GtkButton ( == of-object.)
+#
+# string rettype;
+#
+# string when. e.g. first, last, or both.
+# string entity_type. e.g. method or signal
+# }
+
+# "new" can't have prototype
+sub new
+{
+ my ($def) = @_;
+
+ my $whole = $def;
+ my $self = {};
+ bless $self;
+
+ #Remove first and last braces:
+ $def =~ s/^\(//;
+ $def =~ s/\)$//;
+
+ $def =~ s/^\s*define-(\S+)\s+(\S+)\s*//;
+ $$self{entity_type} = $1;
+ $$self{name} = $2;
+ $$self{name} =~ s/-/_/g; #change - to _
+
+ # init variables
+ $$self{mark}=0;
+ $$self{rettype} = "none";
+ $$self{param_types} = [];
+ $$self{param_names} = [];
+ $$self{when} = "";
+ $$self{class} = "";
+
+ # snarf down lisp fields
+ if($def =~ s/\(of-object "(\S+)"\)//)
+ {
+ $$self{class} = $1;
+ }
+ else
+ {
+ GtkDefs::error("define-signal/define-vfunc without of-object (entity type: $$self{entity_type}): $whole");
+ }
+
+ if($def =~ s/\(return-type "(\S+)"\)//)
+ {
+ $$self{rettype} = $1;
+ $$self{rettype} =~ s/-/ /g; #e.g. replace const-gchar* with const gchar*. Otherwise it will be used in code.
+ }
+
+ if($def =~ s/\(when "(\S+)"\)//)
+ {
+ $$self{when} = $1;
+ }
+
+ if($$self{rettype} eq "none")
+ {
+ $$self{rettype} = "void"
+ }
+
+ # signals always have a parameter
+ push(@{$$self{param_types}}, "$$self{class}*");
+ push(@{$$self{param_names}}, "self");
+
+ # parameters are compound lisp statement
+ if ($def =~ s/\(parameters(( '\("\S+" "\S+"\))+) \)//)
+ {
+ $self->parse_param($1);
+ }
+
+ if ($def!~/^\s*$/)
+ {
+ GtkDefs::error("Unhandled signal/vfunc def ($def) in $$self{class}::$$self{name}");
+ }
+
+ return $self;
+}
+
+# bool has_same_types($objFunction)
+# Compares return types and argument types
+sub has_same_types($$)
+{
+ my ($self, $objFuncOther) = @_;
+
+ #Compare return types:
+ if($self->types_are_equal($$self{rettype}, $$objFuncOther{rettype}) ne 1)
+ {
+ # printf("debug: different return types: %s, %s\n", $$self{rettype}, $$objFuncOther{rettype});
+ return 0; #Different types found.
+ }
+
+ #Compare arguement types:
+ my $i = 0;
+ my $param_types = $$self{param_types};
+ my $param_types_other = $$objFuncOther{param_types};
+ for ($i = 1; $i < $#$param_types + 1; $i++)
+ {
+ my $type_a = $$param_types[$i];
+ my $type_b = $$param_types_other[$i-1];
+
+ if($self->types_are_equal($type_a, $type_b) ne 1)
+ {
+ # printf("debug: different arg types: %s, %s\n", $type_a, $type_b);
+ return 0; #Different types found.
+ }
+ }
+
+ return 1; #They must all be the same for it to get this far.
+}
+
+# bool types_are_equal($a, $b)
+# Compares types, ignoring gint/int differences, etc.
+sub types_are_equal($$$)
+{
+ #TODO: Proper method of getting a normalized type name.
+
+ my ($self, $type_a, $type_b) = @_;
+
+ if($type_a ne $type_b)
+ {
+ #Try adding g to one of them:
+ if( ("g" . $type_a) ne $type_b )
+ {
+ #Try adding g to the other one:
+ if( $type_a ne ("g" . $type_b) )
+ {
+ #After all these checks it's still not equal:
+ return 0; #not equal.
+ }
+ }
+ }
+
+ # printf("DEBUG: types are equal: %s, %s\n", $$type_a, $$type_b);
+ return 1; #They must be the same for it to get this far.
+}
+
+1; # indicate proper module load.
diff --git a/tools/pm/Makefile.am b/tools/pm/Makefile.am
new file mode 100644
index 00000000..93c0b3fd
--- /dev/null
+++ b/tools/pm/Makefile.am
@@ -0,0 +1,10 @@
+
+include $(top_srcdir)/tools/pm/Makefile_list_of_sources.am_fragment
+
+EXTRA_DIST = Makefile_list_of_sources.am_fragment $(files_tools_pm)
+
+# Install the .pm, files:
+
+tools_pm_includedir = $(libdir)/gtkmm-2.0/proc/pm
+tools_pm_include_HEADERS = $(files_tools_pm)
+
diff --git a/tools/pm/Makefile_list_of_sources.am_fragment b/tools/pm/Makefile_list_of_sources.am_fragment
new file mode 100644
index 00000000..e8df8f44
--- /dev/null
+++ b/tools/pm/Makefile_list_of_sources.am_fragment
@@ -0,0 +1,2 @@
+files_tools_pm = DocsParser.pm GtkDefs.pm Enum.pm Function.pm FunctionBase.pm Object.pm Output.pm Property.pm Util.pm WrapParser.pm
+
diff --git a/tools/pm/Object.pm b/tools/pm/Object.pm
new file mode 100644
index 00000000..aef72c39
--- /dev/null
+++ b/tools/pm/Object.pm
@@ -0,0 +1,72 @@
+package Object;
+
+use strict;
+use warnings;
+
+BEGIN {
+ use Exporter ();
+ our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
+
+ # set the version for version checking
+ $VERSION = 1.00;
+
+ @ISA = qw(Exporter);
+ @EXPORT = ( );
+ %EXPORT_TAGS = ( );
+
+ # your exported package globals go here,
+ # as well as any optionally exported functions
+ @EXPORT_OK = ( );
+}
+our @EXPORT_OK;
+
+# class Object
+# {
+# string name;
+# string module;
+# string parent;
+# string c_name;
+# string gtype_id;
+# }
+
+
+sub new
+{
+ my ($def) = @_;
+
+ my $self = {};
+ bless $self;
+
+ $def =~ s/^\(//;
+ $def =~ s/\)$//;
+
+ # snarf down the fields
+ $$self{name} = $1 if($def =~ s/^define-object (\S+)//);
+ $$self{module} = $1 if($def =~ s/\(in-module "(\S+)"\)//);
+ $$self{parent} = $1 if($def =~ s/\(parent "(\S+)"\)//);
+ $$self{c_name} = $1 if($def =~ s/\(c-name "(\S+)"\)//);
+ $$self{gtype_id} = $1 if($def =~ s/\(gtype-id "(\S+)"\)//);
+
+ if($def !~ /^\s*$/)
+ {
+ GtkDefs::error("Unhandled object def ($def) in $$self{module}\::$$self{name}\n")
+ }
+
+ return $self;
+}
+
+
+sub dump($)
+{
+ my ($self) = @_;
+
+ print "<object>\n";
+
+ foreach(keys %$self)
+ { print " <$_ value=\"$$self{$_}\"/>\n"; }
+
+ print "</object>\n\n";
+}
+
+
+1; # indicate proper module load.
diff --git a/tools/pm/Output.pm b/tools/pm/Output.pm
new file mode 100644
index 00000000..37aea976
--- /dev/null
+++ b/tools/pm/Output.pm
@@ -0,0 +1,781 @@
+# Gtkmmproc Output module
+#
+# Copyright 2001 Free Software Foundation
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+#
+package Output;
+use strict;
+BEGIN { @Namespace::ISA=qw(main); }
+
+# $objOutputter new()
+sub new
+{
+ my ($m4path, $macrodirs) = @_;
+ my $self = {};
+ bless $self;
+
+ $$self{out} = [];
+
+ $$self{source} = "";
+ $$self{tmpdir} = "/tmp";
+ $$self{destdir} = "";
+ $$self{objDefsParser} = undef; # It will be set in set_defsparser()
+
+ $$self{m4path} = $m4path;
+ $$self{m4args} = "-I";
+ $$self{m4args} .= join(" -I", @$macrodirs);
+
+ return $self;
+}
+
+sub set_defsparser($$)
+{
+ my ($self, $objDefsParser) = @_;
+
+ $$self{objDefsParser} = $objDefsParser; #Remember it so that we can use it in our output methods.
+}
+
+sub m4args_append($$)
+{
+ my ($self, $str) = @_;
+ $$self{m4args} .= $str;
+}
+
+sub append($$)
+{
+ my ($self, $str) = @_;
+
+ push(@{$$self{out}}, $str);
+}
+
+# void output_wrap_failed($cname, $error)
+# Puts a comment in the header about the error during code-generation.
+sub output_wrap_failed($$$)
+{
+ my ($self, $cname, $error) = @_;
+
+ my $str = sprintf("//gtkmmproc error: %s : %s", $cname, $error);
+ print STDERR "Output.pm: $cname : $error\n";
+ $self->append($str);
+}
+
+sub error
+{
+ my $format=shift @_;
+ printf STDERR "Output.pm: $format",@_;
+}
+
+### Convert _WRAP to a virtual
+# _VFUNC_H(signame,rettype,`<cppargs>')
+# _VFUNC_PH(gtkname,crettype,cargs and names)
+# void output_wrap_vfunc_h($filename, $line_num, $objCppfunc, $objCDefsFunc)
+sub output_wrap_vfunc_h($$$$$)
+{
+ my ($self, $filename, $line_num, $objCppfunc, $objCDefsFunc) = @_;
+
+ my $str = sprintf("_VFUNC_H(%s,%s,\`%s\')dnl\n",
+ $$objCppfunc{name},
+ $$objCppfunc{rettype},
+ $objCppfunc->args_types_and_names()
+ );
+ $self->append($str);
+
+ #The default callback, which will call *_impl, which will then call the base default callback.
+ #Declares the callback in the private *Class class and sets it in the class_init function.
+
+ my $str = sprintf("_VFUNC_PH(%s,%s,\`%s\')dnl\n",
+ $$objCDefsFunc{name},
+ $$objCDefsFunc{rettype},
+ $objCDefsFunc->args_types_and_names()
+ );
+ $self->append($str);
+}
+
+# _VFUNC_CC(signame,gtkname,rettype,crettype,`<cppargs>',`<cargs>')
+sub output_wrap_vfunc_cc($$$$$$)
+{
+ my ($self, $filename, $line_num, $objCppfunc, $objDefsSignal) = @_;
+
+ my $cname = $$objDefsSignal{name};
+
+ # e.g. Gtk::Button::draw_indicator:
+
+ #Use a different macro for Interfaces, to generate an extra convenience method.
+
+ my $refreturn = "";
+ $refreturn = "refreturn" if($$objCppfunc{rettype_needs_ref});
+
+ my $str = sprintf("_VFUNC_CC(%s,%s,%s,%s,\`%s\',\`%s\',%s)dnl\n",
+ $$objCppfunc{name},
+ $cname,
+ $$objCppfunc{rettype},
+ $$objDefsSignal{rettype},
+ $objCppfunc->args_types_and_names(),
+ convert_args_cpp_to_c($objCppfunc, $objDefsSignal, 0, $line_num), #$objCppfunc->args_names_only(),
+ $refreturn);
+
+ $self->append($str);
+
+ # e.g. Gtk::ButtonClass::draw_indicator():
+
+ my $refreturn_ctype = "";
+ $refreturn_ctype = "refreturn_ctype" if($$objDefsSignal{rettype_needs_ref});
+
+ my $str = sprintf("_VFUNC_PCC(%s,%s,%s,%s,\`%s\',\`%s\',\`%s\',%s,%s)dnl\n",
+ $$objCppfunc{name},
+ $cname,
+ $$objCppfunc{rettype},
+ $$objDefsSignal{rettype},
+ $objDefsSignal->args_types_and_names(),
+ $objDefsSignal->args_names_only(),
+ convert_args_c_to_cpp($objDefsSignal, $objCppfunc, $line_num),
+ ${$objDefsSignal->get_param_names()}[0],
+ $refreturn_ctype);
+
+ $self->append($str);
+}
+
+### Convert _WRAP to a virtual
+# _SIGNAL_H(signame,rettype,`<cppargs>')
+# _SIGNAL_PH(gtkname,crettype,cargs and names)
+# void output_wrap_default_signal_handler_h($filename, $line_num, $objCppfunc, $objCDefsFunc, @args)
+sub output_wrap_default_signal_handler_h($$$$$$)
+{
+ my ($self, $filename, $line_num, $objCppfunc, $objCDefsFunc, $bImplement) = @_;
+
+ my $str = sprintf("_SIGNAL_H(%s,%s,\`%s\')dnl\n",
+ $$objCppfunc{name},
+ $$objCppfunc{rettype},
+ $objCppfunc->args_types_and_names()
+ );
+ $self->append($str);
+
+
+ #The default callback, which will call *_impl, which will then call the base default callback.
+ #Declares the callback in the private *Class class and sets it in the class_init function.
+
+ $str = sprintf("_SIGNAL_PH(%s,%s,\`%s\')dnl\n",
+ $$objCDefsFunc{name},
+ $$objCDefsFunc{rettype},
+ $objCDefsFunc->args_types_and_names()
+ );
+ $self->append($str);
+}
+
+# _SIGNAL_CC(signame,gtkname,rettype,crettype,`<cppargs>',`<cargs>')
+sub output_wrap_default_signal_handler_cc($$$$$)
+{
+ my ($self, $filename, $line_num, $objCppfunc, $objDefsSignal, $bImplement) = @_;
+ my $cname = $$objDefsSignal{name};
+ # $cname = $1 if ($args[3] =~ /"(.*)"/); #TODO: What's this about?
+
+ # e.g. Gtk::Button::on_clicked:
+ if($bImplement eq 1)
+ {
+ my $str = sprintf("_SIGNAL_CC(%s,%s,%s,%s,\`%s\',\`%s\',%s)dnl\n",
+ $$objCppfunc{name},
+ $cname,
+ $$objCppfunc{rettype},
+ $$objDefsSignal{rettype},
+ $objCppfunc->args_types_and_names(),
+ convert_args_cpp_to_c($objCppfunc, $objDefsSignal, 0, $line_num), #$objCppfunc->args_names_only(),
+ $$objCppfunc{const});
+ $self->append($str);
+ }
+
+
+ # e.g. Gtk::ButtonClass::on_clicked():
+
+ #Callbacks always take the object instance as the first argument:
+# my $arglist_names = "object";
+# my $arglist_names_extra = $objDefsSignal->args_names_only();
+# if ($arglist_names_extra)
+# {
+# $arglist_names .= ", ";
+# $arglist_names .= $arglist_names_extra;
+# }
+
+ my $str = sprintf("_SIGNAL_PCC(%s,%s,%s,%s,\`%s\',\`%s\',\`%s\',%s)dnl\n",
+ $$objCppfunc{name},
+ $cname,
+ $$objCppfunc{rettype},
+ $$objDefsSignal{rettype},
+ $objDefsSignal->args_types_and_names(),
+ $objDefsSignal->args_names_only(),
+ convert_args_c_to_cpp($objDefsSignal, $objCppfunc, $line_num),
+ ${$objDefsSignal->get_param_names()}[0]);
+ $self->append($str);
+}
+
+### Convert _WRAP to a method
+# _METHOD(cppname,cname,cpprettype,crettype,arglist,cargs,const)
+# void output_wrap_meth($filename, $line_num, $objCppFunc, $objCDefsFunc, $cppMethodDecl, $documentation)
+sub output_wrap_meth($$$$$$)
+{
+ my ($self, $filename, $line_num, $objCppfunc, $objCDefsFunc, $cppMethodDecl, $documentation) = @_;
+ my $objDefsParser = $$self{objDefsParser};
+
+ # Doxygen documentation before the method declaration:
+ $self->append("\n${documentation}");
+
+ #Declaration:
+ $self->append(" ${cppMethodDecl};");
+
+ my $refneeded = "";
+ if($$objCDefsFunc{rettype_needs_ref})
+ {
+ $refneeded = "refreturn"
+ }
+ my $errthrow = "";
+ if($$objCDefsFunc{throw_any_errors})
+ {
+ $errthrow = "errthrow"
+ }
+
+ #Implementation:
+ my $str;
+ if ($$objCppfunc{static}) {
+ $str = sprintf("_STATIC_METHOD(%s,%s,%s,%s,\`%s\',\`%s\',%s,%s)dnl\n",
+ $$objCppfunc{name},
+ $$objCDefsFunc{c_name},
+ $$objCppfunc{rettype},
+ $objCDefsFunc->get_return_type_for_methods(),
+ $objCppfunc->args_types_and_names(),
+ convert_args_cpp_to_c($objCppfunc, $objCDefsFunc, 1, $line_num, $errthrow), #1 means it's static, so it has 'object'.
+ $refneeded,
+ $errthrow);
+ } else {
+ $str = sprintf("_METHOD(%s,%s,%s,%s,\`%s\',\`%s\',%s,%s,%s)dnl\n",
+ $$objCppfunc{name},
+ $$objCDefsFunc{c_name},
+ $$objCppfunc{rettype},
+ $objCDefsFunc->get_return_type_for_methods(),
+ $objCppfunc->args_types_and_names(),
+ convert_args_cpp_to_c($objCppfunc, $objCDefsFunc, 0, $line_num, $errthrow),
+ $$objCppfunc{const},
+ $refneeded,
+ $errthrow);
+ }
+
+
+ $self->append($str);
+}
+
+### Convert _WRAP_CTOR to a ctor
+# _METHOD(cppname,cname,cpprettype,crettype,arglist,cargs,const)
+# void output_wrap_ctor($filename, $line_num, $objCppFunc, $objCDefsFunc, $cppMethodDecl)
+sub output_wrap_ctor($$$$$)
+{
+ my ($self, $filename, $line_num, $objCppfunc, $objCDefsFunc, $cppMethodDecl) = @_;
+ my $objDefsParser = $$self{objDefsParser};
+
+ #Ctor Declaration:
+ #TODO: Add explicit.
+ $self->append("explicit " . $cppMethodDecl . ";");
+
+ #Implementation:
+ my $str = sprintf("_CTOR_IMPL(%s,%s,\`%s\',\`%s\')dnl\n",
+ $$objCppfunc{name},
+ $$objCDefsFunc{c_name},
+ $objCppfunc->args_types_and_names(),
+ get_ctor_properties($objCppfunc, $objCDefsFunc, $line_num)
+ );
+
+ $self->append($str);
+}
+
+sub output_wrap_create($$$)
+{
+ my ($self, $args_type_and_name_with_default_values, $objWrapParser) = @_;
+
+ #Re-use Function in a very hacky way, to separate the argument types_and_names.
+ my $fake_decl = "void fake_func(" . $args_type_and_name_with_default_values . ")";
+
+ my $objFunction = &Function::new($fake_decl, $objWrapParser);
+ my $args_names_only = $objFunction->args_names_only();
+ my $args_type_and_name = $objFunction->args_types_and_names();
+
+ my $str = sprintf("_CREATE_METHOD(\`%s\',\`%s\')dnl\n",
+ $args_type_and_name, $args_names_only);
+
+ $self->append($str)
+}
+
+# _SIGNAL_IMPL(return_type,func_name,`<args>',cname)
+# sub output_wrap_sig_impl($$$$)
+# {
+# my ($self, $filename, $line_num, $objCppfunc) = @_;
+#
+# my $str;
+# $str = sprintf("_SIGNAL_IMPL(%s,%s,\`%s\')dnl\n",
+# $$objCppfunc{rettype},
+# $$objCppfunc{name},
+# $objCppfunc->args_types_only()
+# );
+#
+# $self->append($str);
+# }
+
+
+# void output_wrap_sig_decl($filename, $line_num, $objCSignal, $objCppfunc, $signal_name)
+# custom_signalproxy_name is "" when no type conversion is required - a normal templates SignalProxy will be used instead.
+sub output_wrap_sig_decl($$$$$$)
+{
+ my ($self, $filename, $line_num, $objCSignal, $objCppfunc, $signal_name) = @_;
+
+# _SIGNAL_PROXY(c_signal_name, c_return_type, `<c_arg_types_and_names>',
+# cpp_signal_name, cpp_return_type, `<cpp_arg_types>',`<c_args_to_cpp>',
+# refdoc_comment)
+
+ my $str = sprintf("_SIGNAL_PROXY(%s,%s,\`%s\',%s,%s,\`%s\',\`%s\',\`%s\')dnl\n",
+ $signal_name,
+ $$objCSignal{rettype},
+ $objCSignal->args_types_and_names_without_object(),
+ $$objCppfunc{name},
+ $$objCppfunc{rettype},
+ $objCppfunc->args_types_only(),
+ convert_args_c_to_cpp($objCSignal, $objCppfunc, $line_num),
+ $objCppfunc->get_refdoc_comment()
+ );
+
+ $self->append($str);
+}
+
+# void output_wrap_enum($filename, $line_num, $cpp_type, $c_type, $comment, @flags)
+sub output_wrap_enum($$$$$$$)
+{
+ my ($self, $filename, $line_num, $cpp_type, $c_type, $comment, @flags) = @_;
+
+ my $objEnum = GtkDefs::lookup_enum($c_type);
+ if(!$objEnum)
+ {
+ $self->output_wrap_failed($c_type, "enum defs lookup failed.");
+ return;
+ }
+
+ $objEnum->beautify_values();
+
+ my $no_gtype = "";
+ my $elements = $objEnum->build_element_list(\@flags, \$no_gtype, " ");
+
+ if(!$elements)
+ {
+ $self->output_wrap_failed($c_type, "unknown _WRAP_ENUM() flag");
+ return;
+ }
+
+ my $value_suffix = "Enum";
+ $value_suffix = "Flags" if($$objEnum{flags});
+
+ my $str = sprintf("_ENUM(%s,%s,%s,\`%s\',\`%s\',\`%s\')dnl\n",
+ $cpp_type,
+ $c_type,
+ $value_suffix,
+ $elements,
+ $no_gtype,
+ $comment
+ );
+
+ $self->append($str);
+}
+
+# void output_wrap_gerror($filename, $line_num, $cpp_type, $c_enum, $domain, @flags)
+sub output_wrap_gerror($$$$$$$)
+{
+ my ($self, $filename, $line_num, $cpp_type, $c_enum, $domain, @flags) = @_;
+
+ my $objDefsParser = $$self{objDefsParser};
+
+ my $objEnum = GtkDefs::lookup_enum($c_enum);
+ if(!$objEnum)
+ {
+ $self->output_wrap_failed($c_enum, "enum defs lookup failed.");
+ return;
+ }
+
+ # Shouldn't happen, and if it does, I'd like to know that.
+ warn if($$objEnum{flags});
+
+ $objEnum->beautify_values();
+
+ # cut off the module prefix, e.g. GDK_
+ my $prefix = $domain;
+ $prefix =~ s/^[^_]+_//;
+
+ # Chop off the domain prefix, because we put the enum into the class.
+ unshift(@flags, "s#^${prefix}_##");
+
+ my $no_gtype = "";
+ my $elements = $objEnum->build_element_list(\@flags, \$no_gtype, " ");
+
+ my $str = sprintf("_GERROR(%s,%s,%s,\`%s\',%s)dnl\n",
+ $cpp_type,
+ $c_enum,
+ $domain,
+ $elements,
+ $no_gtype
+ );
+
+ $self->append($str);
+}
+
+# _PROPERTY_PROXY(name, cpp_type)
+# void output_wrap_property($filename, $line_num, $name, $cpp_type)
+sub output_wrap_property($$$$$$)
+{
+ my ($self, $filename, $line_num, $name, $cpp_type, $c_class) = @_;
+
+ my $objDefsParser = $$self{objDefsParser};
+
+ my $objProperty = GtkDefs::lookup_property($c_class, $name);
+ if($objProperty eq 0) #If the lookup failed:
+ {
+ $self->output_wrap_failed($name, "property defs lookup failed.");
+ }
+ elsif($objProperty->get_construct_only() eq 1)
+ {
+ $self->output_wrap_failed($name, "Attempt to wrap a construct-only property.");
+ }
+ else
+ {
+ # We use a suffix to specify a particular Glib::PropertyProxy* class.
+ my $proxy_suffix = "";
+
+ # Read/Write:
+ if($objProperty->get_readable() ne 1)
+ {
+ $proxy_suffix = "_WriteOnly";
+ }
+ elsif($objProperty->get_writable() ne 1)
+ {
+ $proxy_suffix = "_ReadOnly";
+ }
+
+ $name =~ s/-/_/g;
+
+ my $str = sprintf("_PROPERTY_PROXY(%s,%s,%s)dnl\n",
+ $name,
+ $cpp_type,
+ $proxy_suffix
+ );
+
+ $self->append($str);
+ }
+}
+
+# vpod output_temp_g1($filename, $section) e.g. output_temp_g1(button, gtk)
+sub output_temp_g1($$)
+{
+ my ($self, $section) = @_;
+
+ # Write out *.g1 temporary file
+ open(FILE, '>', "$$self{tmpdir}/gtkmmproc_$$.g1"); # $$ is the Process ID
+
+ print FILE "include(base.m4)dnl\n";
+
+ my $module = $section;
+ my $module_canonical = Util::string_canonical($module); #In case there is a / character in the module.
+ print FILE "_START($$self{source},$module,$module_canonical)dnl\n";
+ print FILE join("", @{$$self{out}});
+ print FILE "_END()\n";
+ close(FILE);
+}
+
+sub make_g2_from_g1($)
+{
+ my ($self) = @_;
+
+ # Execute m4 to get *.g2 file:
+ system("$$self{m4path} $$self{m4args} '$$self{tmpdir}/gtkmmproc_$$.g1' > '$$self{tmpdir}/gtkmmproc_$$.g2'");
+ return ($? >> 8);
+}
+
+# void write_sections_to_files()
+# This is where we snip the /tmp/gtkmmproc*.g2 file into sections (,h, .cc, _private.h)
+sub write_sections_to_files()
+{
+ my ($self) = @_;
+
+ my $fname_h = "$$self{destdir}/$$self{source}.h";
+ my $fname_ph = "$$self{destdir}/private/$$self{source}_p.h";
+ my $fname_cc = "$$self{destdir}/$$self{source}.cc";
+
+ open(INPUT, '<', "$$self{tmpdir}/gtkmmproc_$$.g2"); # $$ is the process ID.
+
+ # open tempory file for each section
+ open(OUTPUT_H, '>', "$fname_h.tmp");
+ open(OUTPUT_PH, '>', "$fname_ph.tmp");
+ open(OUTPUT_CC, '>', "$fname_cc.tmp");
+
+ my $oldfh = select(OUTPUT_H);
+ my $blank = 0;
+
+ while(<INPUT>)
+ {
+ # section switching
+ if(/^#S 0/) { select(OUTPUT_H); next; }
+ if(/^#S 1/) { select(OUTPUT_PH); next; }
+ if(/^#S 2/) { select(OUTPUT_CC); next; }
+
+ # get rid of bogus blank lines
+ if(/^\s*$/) { ++$blank; } else { $blank = 0; }
+ next if($blank > 2);
+
+ print $_;
+ }
+
+ select($oldfh);
+ close(INPUT);
+ close(OUTPUT_H);
+ close(OUTPUT_PH);
+ close(OUTPUT_CC);
+
+ foreach($fname_h, $fname_ph, $fname_cc)
+ {
+ # overwrite the source file only if it has actually changed
+ system("cmp -s '$_.tmp' '$_' || cp '$_.tmp' '$_' ; rm -f '$_.tmp'");
+ }
+}
+
+
+sub remove_temp_files($)
+{
+ my ($self) = @_;
+
+ system("rm -f \"$$self{tmpdir}/gtkmmproc_$$.g1\"");
+ system("rm -f \"$$self{tmpdir}/gtkmmproc_$$.g2\"");
+}
+
+
+
+# procedure for generating CONVERT macros
+# $string convert_args_cpp_to_c($objCppfunc, $objCDefsFunc, $static, $wrap_line_number,$automatic_error)
+sub convert_args_cpp_to_c($$$$;$)
+{
+ my ($objCppfunc, $objCDefsFunc, $static, $wrap_line_number, $automatic_error) = @_;
+
+ $automatic_error = "" unless defined $automatic_error;
+
+ my $cpp_param_names = $$objCppfunc{param_names};
+ my $cpp_param_types = $$objCppfunc{param_types};
+ my $c_param_types = $$objCDefsFunc{param_types};
+
+ my @result;
+
+ my $num_c_args_expected = scalar(@{$c_param_types});
+ if( !($static) ) { $num_c_args_expected--; } #The cpp method will need an Object* paramater at the start.
+
+ my $num_cpp_args = scalar(@{$cpp_param_types});
+
+ # add implicit last error parameter;
+ if ( $automatic_error ne "" &&
+ $num_cpp_args == ($num_c_args_expected - 1) &&
+ ${$c_param_types}[-1] eq "GError**" )
+ {
+ $num_cpp_args++;
+ $cpp_param_names = [@{$cpp_param_names},"error"];
+ $cpp_param_types = [@{$cpp_param_types},"GError*&"];
+ }
+
+ if ( $num_cpp_args != $num_c_args_expected )
+ {
+ Output::error( "convert_args_cpp_to_c(): Incorrect number of arguments. (%d != %d)\n",
+ $num_cpp_args,
+ $num_c_args_expected );
+ $objCppfunc->dump();
+ $objCDefsFunc->dump();
+
+ return "";
+ }
+
+
+ # Loop through the cpp parameters:
+ my $i;
+ my $cpp_param_max = $num_cpp_args;
+ # if( !($static) ) { $cpp_param_max++; }
+
+ for ($i = 0; $i < $cpp_param_max; $i++)
+ {
+ #index of C parameter:
+ my $iCParam = $i;
+ if( !($static) ) { $iCParam++; }
+
+ my $cppParamType = $$cpp_param_types[$i];
+ $cppParamType =~ s/ &/&/g; #Remove space between type and &
+ $cppParamType =~ s/ \*/*/g; #Remove space between type and *
+
+ my $cppParamName = $$cpp_param_names[$i];
+ my $cParamType = $$c_param_types[$iCParam];
+
+ if ($cppParamType ne $cParamType) #If a type conversion is needed.
+ {
+
+
+ push(@result, sprintf("_CONVERT(%s,%s,%s,%s)",
+ $cppParamType,
+ $cParamType,
+ $cppParamName,
+ $wrap_line_number) );
+ }
+ else
+ {
+ push(@result, $cppParamName);
+ }
+ }
+
+ return join(", ", @result);
+}
+
+# procedure for generating CONVERT macros
+# Ignores the first C 'self' argument.
+# $string convert_args_c_to_cpp($objCDefsFunc, $objCppFunc, $wrap_line_number)
+sub convert_args_c_to_cpp($$$)
+{
+ my ($objCDefsFunc, $objCppfunc, $wrap_line_number) = @_;
+
+ my $cpp_param_types = $$objCppfunc{param_types};
+ my $c_param_types = $$objCDefsFunc{param_types};
+ my $c_param_names = $$objCDefsFunc{param_names};
+
+ my @result;
+
+ my $num_c_args = scalar(@{$c_param_types});
+
+ my $num_cpp_args = scalar(@{$cpp_param_types});
+
+ if ( ($num_cpp_args + 1) != $num_c_args )
+ {
+ Output::error( "convert_args_c_to_cpp(): Incorrect number of arguments. (%d != %d)\n",
+ $num_cpp_args + 1,
+ $num_c_args);
+ $objCppfunc->dump();
+ $objCDefsFunc->dump();
+
+ return "";
+ }
+
+
+ # Loop through the c parameters:
+ my $i;
+ my $c_param_max = $num_c_args;
+
+ for ($i = 1; $i < $c_param_max; $i++)
+ {
+ #index of C parameter:
+ my $iCppParam = $i - 1;
+
+ my $cppParamType = $$cpp_param_types[$iCppParam];
+ $cppParamType =~ s/ &/&/g; #Remove space between type and &.
+ $cppParamType =~ s/ \*/*/g; #Remove space between type and *
+
+ my $cParamName = $$c_param_names[$i];
+ my $cParamType = $$c_param_types[$i];
+
+ if ($cParamType ne $cppParamType) #If a type conversion is needed.
+ {
+ push(@result, sprintf("_CONVERT(%s,%s,%s,%s)\n",
+ $cParamType,
+ $cppParamType,
+ $cParamName,
+ $wrap_line_number) );
+ }
+ else
+ {
+ push(@result, $cParamName);
+ }
+ }
+
+ return join(", ",@result);
+}
+
+
+# generates the XXX in g_object_new(get_type(), XXX): A list of property names and values.
+# Uses the cpp arg name as the property name.
+# $string get_ctor_properties($objCppfunc, $objCDefsFunc, $wrap_line_number)
+sub get_ctor_properties($$$$)
+{
+ my ($objCppfunc, $objCDefsFunc, $wrap_line_number) = @_;
+
+ my $cpp_param_names = $$objCppfunc{param_names};
+ my $cpp_param_types = $$objCppfunc{param_types};
+ my $c_param_types = $$objCDefsFunc{param_types};
+
+ my @result;
+
+ my $num_args = scalar(@{$c_param_types});
+
+ my $num_cpp_args = scalar(@{$cpp_param_types});
+ if ( $num_cpp_args != $num_args )
+ {
+ Output::error("get_ctor_properties(): Incorrect number of arguments. (%d != %d)\n",
+ $num_cpp_args,
+ $num_args );
+ return "";
+ }
+
+
+ # Loop through the cpp parameters:
+ my $i = 0;
+
+ for ($i = 0; $i < $num_args; $i++)
+ {
+ my $cppParamType = $$cpp_param_types[$i];
+ $cppParamType =~ s/ &/&/g; #Remove space between type and &
+ $cppParamType =~ s/ \*/*/g; #Remove space between type and *
+
+ my $cppParamName = $$cpp_param_names[$i];
+ my $cParamType = $$c_param_types[$i];
+
+ # Property name:
+ push(@result, "\"" . $cppParamName . "\"");
+
+ # C property value:
+ if ($cppParamType ne $cParamType) #If a type conversion is needed.
+ {
+ push(@result, sprintf("_CONVERT(%s,%s,%s,%s)",
+ $cppParamType,
+ $cParamType,
+ $cppParamName,
+ $wrap_line_number) );
+ }
+ else
+ {
+ push(@result, $cppParamName);
+ }
+ }
+
+ return join(", ", @result);
+}
+
+### Convert _WRAP to a corba method
+# _CORBA_METHOD(retype, method_name,args, arg_names_only) - implemented in libbonobomm.
+# void output_wrap_corba_method($filename, $line_num, $objCppFunc)
+sub output_wrap_corba_method($$$$)
+{
+ my ($self, $filename, $line_num, $objCppfunc) = @_;
+
+ my $str = sprintf("_CORBA_METHOD(%s,%s,\`%s\',\`%s\')dnl\n",
+ $$objCppfunc{rettype},
+ $$objCppfunc{name},
+ $objCppfunc->args_types_and_names(),
+ $objCppfunc->args_names_only()
+ );
+
+ $self->append($str);
+}
+
+
+1; # indicate proper module load.
diff --git a/tools/pm/Property.pm b/tools/pm/Property.pm
new file mode 100644
index 00000000..1f446015
--- /dev/null
+++ b/tools/pm/Property.pm
@@ -0,0 +1,94 @@
+package Property;
+
+use strict;
+use warnings;
+
+BEGIN {
+ use Exporter ();
+ our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
+
+ # set the version for version checking
+ $VERSION = 1.00;
+ @ISA = qw(Exporter);
+ @EXPORT = qw(&func1 &func2 &func4);
+ %EXPORT_TAGS = ( );
+ # your exported package globals go here,
+ # as well as any optionally exported functions
+ @EXPORT_OK = qw($Var1 %Hashit &func3);
+ }
+our @EXPORT_OK;
+
+# class Property
+# {
+# string name;
+# string class;
+# string type;
+# bool readable;
+# bool writable;
+# bool construct_only;
+# }
+
+
+sub new
+{
+ my ($def) = @_;
+ my $self = {};
+ bless $self;
+
+ $def=~s/^\(//;
+ $def=~s/\)$//;
+ # snarf down the fields
+ $$self{mark} = 0;
+ $$self{name} = $1 if ($def =~ s/^define-property (\S+)//);
+ $$self{class} = $1 if ($def =~ s/\(of-object "(\S+)"\)//);
+ $$self{type} = $1 if ($def =~ s/\(prop-type "(\S+)"\)//);
+ $$self{readable} = ($1 eq "#t") if ($def =~ s/\(readable (\S+)\)//);
+ $$self{writable} = ($1 eq "#t") if ($def =~ s/\(writable (\S+)\)//);
+ $$self{construct_only} = ($1 eq "#t") if ($def =~ s/\(construct-only (\S+)\)//);
+
+ $$self{name} =~ s/-/_/g; # change - to _
+
+ GtkDefs::error("Unhandled property def ($def) in $$self{class}\::$$self{name}\n")
+ if ($def !~ /^\s*$/);
+
+ return $self;
+}
+
+sub dump($)
+{
+ my ($self) = @_;
+
+ print "<property>\n";
+
+ foreach (keys %$self)
+ { print " <$_ value=\"$$self{$_}\"/>\n"; }
+
+ print "</property>\n\n";
+}
+
+sub get_construct_only($)
+{
+ my ($self) = @_;
+ return $$self{construct_only};
+}
+
+sub get_type($)
+{
+ my ($self) = @_;
+ return $$self{type};
+}
+
+sub get_readable($)
+{
+ my ($self) = @_;
+ return $$self{readable};
+}
+
+sub get_writable($)
+{
+ my ($self) = @_;
+ return $$self{writable};
+}
+
+
+1; # indicate proper module load.
diff --git a/tools/pm/Util.pm b/tools/pm/Util.pm
new file mode 100644
index 00000000..c3076b4e
--- /dev/null
+++ b/tools/pm/Util.pm
@@ -0,0 +1,113 @@
+# gtkmm - Util module
+#
+# Copyright 2001 Free Software Foundation
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# # but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+#
+#
+# This file holds basic functions used throughout gtkmmproc modules.
+# Functions in this module are exported so there is no need to
+# request them by module name.
+#
+package Util;
+use strict;
+use warnings;
+
+BEGIN {
+ use Exporter ();
+ our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
+
+ # set the version for version checking
+ $VERSION = 1.00;
+ @ISA = qw(Exporter);
+ @EXPORT = qw(&string_unquote &string_trim &string_canonical
+ &trace &unique);
+ %EXPORT_TAGS = ( );
+
+ # your exported package globals go here,
+ # as well as any optionally exported functions
+ #@EXPORT_OK = qw($Var1 %Hashit &func3);
+ }
+our @EXPORT_OK;
+
+
+#$ string_unquote($string)
+# Removes leading and trailing quotes.
+sub string_unquote($)
+{
+ my ($str) = @_;
+
+ $str =~ s/^['`"]// ;
+ $str =~ s/['`"]$// ;
+
+ return $str;
+}
+
+# $ string_trim($string)
+# Removes leading and trailing white space.
+sub string_trim($)
+{
+ ($_) = @_;
+ s/^\s+//;
+ s/\s+$//;
+ return $_;
+}
+
+# $ string_canonical($string)
+# Convert - to _.
+sub string_canonical($)
+{
+ ($_) = @_;
+ s/-/_/g ; # g means 'replace all'
+ s/\//_/g ; # g means 'replace all'
+ return $_;
+}
+
+#
+# Back tracing utility.
+# Prints the call stack.
+#
+# void trace()
+sub trace()
+{
+ my ($package, $filename, $line, $subroutine, $hasargs,
+ $wantarray, $evaltext, $is_require, $hints, $bitmask) = caller(1);
+
+ no warnings qw(uninitialized);
+
+ my $i = 2;
+ print "Trace on ${subroutine} called from ${filename}:${line}\n";
+ while (1)
+ {
+ ($package, $filename, $line, $subroutine) = caller($i);
+ $i++;
+ next if ($line eq "");
+ print " From ${subroutine} call from ${filename}:${line}\n";
+ }
+}
+
+sub unique(@)
+{
+ my %hash;
+ foreach (@_)
+ {
+ $hash{$_}=1;
+ }
+
+ return keys %hash;
+}
+
+1; # indicate proper module load.
+
diff --git a/tools/pm/WrapParser.pm b/tools/pm/WrapParser.pm
new file mode 100644
index 00000000..ce0a5604
--- /dev/null
+++ b/tools/pm/WrapParser.pm
@@ -0,0 +1,1197 @@
+# gtkmm - WrapParser module
+#
+# Copyright 2001 Free Software Foundation
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+#
+package WrapParser;
+use strict;
+use warnings;
+use Util;
+use GtkDefs;
+use Function;
+use DocsParser;
+
+BEGIN {
+ use Exporter ();
+ our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
+
+ # set the version for version checking
+ $VERSION = 1.00;
+ @ISA = qw(Exporter);
+ @EXPORT = ( );
+ %EXPORT_TAGS = ( );
+ # your exported package globals go here,
+ # as well as any optionally exported functions
+ @EXPORT_OK = ( );
+ }
+our @EXPORT_OK;
+
+############################################################################
+
+my @tokens = ();
+
+# $objWrapParser new($objOutputter)
+sub new($)
+{
+ my ($objOutputter) = @_;
+
+ my $self = {};
+ bless $self;
+
+ #Initialize member data:
+ $$self{objOutputter} = $objOutputter;
+ $$self{filename} = "(none)";
+ $$self{line_num} = 0;
+ $$self{mergecdocs} = 0;
+
+ $$self{level} = 0;
+ $$self{class} = "";
+ $$self{c_class} = "";
+ $$self{in_class} = 0;
+ $$self{first_namespace} = 1;
+ $$self{namespace} = [];
+ $$self{in_namespace} = [];
+
+ $$self{defsdir} = ".";
+
+ $$self{module} = ""; #e.g. "gtkmm"
+
+ $$self{type} = "GTKOBJECT"; # or "BOXEDTYPE", or "GOBJECT" - wrapped differently.
+
+ return $self;
+}
+
+# void parse_and_build_output()
+sub parse_and_build_output($)
+{
+ my ($self) = @_;
+
+ my $objOutputter = $$self{objOutputter};
+
+ # Parse the tokens.
+ my $token;
+ while ( scalar(@tokens) )
+ {
+ $token = $self->extract_token();
+ my $bAppend = 1;
+
+ # we need to monitor the depth of braces
+ if ($token eq '{') { $self->on_open_brace(); }
+ if ($token eq '}') { $self->on_close_brace(); $bAppend = 0;}
+
+ # protect `' from the source file from m4
+ if ($token eq "`") { $objOutputter->append("`'__BT__`'"); next; }
+ if ($token eq "'") { $objOutputter->append("`'__FT__`'"); next; }
+
+ if ($token eq '"') { $objOutputter->append($self->on_string_literal()); next; }
+ if ($token eq '//') { $objOutputter->append($self->on_comment_cpp()); next; }
+ if ($token eq '/*') { $objOutputter->append($self->on_comment_c()); next; }
+
+ # handle #m4begin ... #m4end
+ if ($token eq "#m4begin") { $objOutputter->append($self->on_m4_section()); next;}
+
+ # handle #m4 ... \n
+ if ($token eq "#m4") { $objOutputter->append($self->on_m4_line()); next;}
+
+ if ($token eq "_DEFS") { $self->on_defs(); next;} #Read the defs file.
+ if ($token eq "_IGNORE") { $self->on_ignore(); next;} #Ignore a function.
+ if ($token eq "_IGNORE_SIGNAL") { $self->on_ignore_signal(); next;}
+ if ($token eq "_WRAP_METHOD") { $self->on_wrap_method(); next;}
+ if ($token eq "_WRAP_CORBA_METHOD") { $self->on_wrap_corba_method(); next;} #Used in libbonobo*mm.
+ if ($token eq "_WRAP_SIGNAL") { $self->on_wrap_signal(); next;}
+ if ($token eq "_WRAP_PROPERTY") { $self->on_wrap_property(); next;}
+ if ($token eq "_WRAP_VFUNC") { $self->on_wrap_vfunc(); next;}
+ if ($token eq "_WRAP_CTOR") { $self->on_wrap_ctor(); next;}
+ if ($token eq "_WRAP_CREATE") { $self->on_wrap_create(); next;}
+
+ if ($token eq "_WRAP_ENUM") { $self->on_wrap_enum(); next;}
+ if ($token eq "_WRAP_GERROR") { $self->on_wrap_gerror(); next;}
+
+ my $prefix_class = "_CLASS_"; # e.g. _CLASS_GTKOBJECT
+ my $token_prefix = substr($token, 0, length($prefix_class));
+ if ($token_prefix eq $prefix_class)
+ {
+ $self->on_class($token);
+ next;
+
+ # e.g.:
+ # _CLASS_GENERIC
+ # _CLASS_GOBJECT
+ # _CLASS_GTKOBJECT
+ # _CLASS_BOXEDTYPE
+ # _CLASS_BOXEDTYPE_STATIC
+ # _CLASS_INTERFACE
+ # _CLASS_OPAQUE_COPYABLE
+ # _CLASS_OPAQUE_REFCOUNTED
+ }
+
+ if ($token eq "namespace") { $self->on_namespace() };
+
+ # After all token manipulations
+ if($bAppend)
+ {
+ $objOutputter->append($token);
+ }
+ }
+}
+
+sub error($$)
+{
+ my ($self, $format) = @_;
+
+ $format = "$$self{filename}:$$self{line_num}: $format";
+ printf STDERR $format,@_;
+}
+
+######################################################################
+##### 1.1 parser subroutines
+
+########################################
+### returns the next token, ignoring some stuff.
+# $string extract_token()
+sub extract_token($)
+{
+ my ($self) = @_;
+
+ while ( scalar(@tokens) )
+ {
+ $_ = shift @tokens;
+
+ # skip empty tokens
+ next if ( !defined($_) or $_ eq "" );
+
+ # eat line statements. TODO: e.g.?
+ if ( /^#l (\S+)\n/)
+ {
+ $$self{line_num} = $1;
+ next;
+ }
+
+ # eat file statements. TODO: e.g.?
+ if ( /^#f (\S+)\n/)
+ {
+ $$self{filename} = $1;
+ next;
+ }
+
+ return $_;
+ }
+
+ return "";
+}
+
+# bool tokens_remaining()
+sub tokens_remaining($)
+{
+ my ($self) = @_;
+ return scalar(@tokens)!=0;
+}
+
+
+########################################
+### we pass strings literally with quote substitution
+# void on_string_literal()
+sub on_string_literal($)
+{
+ my ($self) = @_;
+
+ my @out;
+ push (@out, '"');
+ while ( scalar(@tokens) )
+ {
+ $_ = $self->extract_token();
+ if ($_ eq "`") { push(@out, "`'__BT__`'"); next; }
+ if ($_ eq "'") { push(@out, "`'__FT__`'"); next; }
+ push (@out, $_);
+
+ return join("",@out) if ($_ eq '"');
+ }
+
+ my $line_num = $$self{line_num};
+ my $filename = $$self{filename};
+ print STDERR "$filename:$line_num: Hit eof while in string\n";
+}
+
+
+########################################
+### we pass comments literally with quote substitution
+# void on_comment_cpp()
+sub on_comment_cpp($)
+{
+ my ($self) = @_;
+
+ my @out;
+ push (@out,"//\`");
+ while ( scalar(@tokens) )
+ {
+ $_ = $self->extract_token();
+ if ($_ eq "`") { push(@out,"\'__BT__\`"); next; }
+ if ($_ eq "'") { push(@out,"\'__FT__\`"); next; }
+ if ($_ eq "\n")
+ {
+ push (@out,"\'\n");
+ return join("",@out)
+ }
+
+ if ($_ =~ /^_[A-Z]+$/) {$_="_$_";} # wipe out potential macros
+
+ push (@out,$_);
+ }
+}
+
+
+########################################
+### we pass C comments literally with quote substitution
+# void on_comment_c()
+sub on_comment_c($)
+{
+ my ($self) = @_;
+
+ my @out;
+ push (@out,"/*\`");
+ while ( scalar(@tokens) )
+ {
+ $_ = $self->extract_token();
+ if ($_ eq "`") { push(@out,"\'__BT__\`"); next; }
+ if ($_ eq "'") { push(@out,"\'__FT__\`"); next; }
+ if ($_ eq "*/")
+ {
+ push (@out,"\'*/");
+ return join("",@out)
+ }
+
+ push (@out,$_);
+ }
+}
+
+
+########################################
+### handle #m4begin ... #m4end
+# we don't substitute ` or ' in #m4begin
+# void on_m4_section()
+sub on_m4_section($)
+{
+ my ($self) = @_;
+
+ my @value;
+ my $token;
+
+ while ( scalar(@tokens) )
+ {
+ $token = $self->extract_token();
+ return join("", @value) if ($token eq "#m4end");
+ push(@value, $token);
+ }
+
+ my $line_num = $$self{line_num};
+ my $filename = $$self{filename};
+ print STDERR "$filename:$line_num: Hit eof looking for #m4end\n";
+ next;
+}
+
+
+########################################
+### handle #m4 ... /n
+# we don't substitute ` or ' in #m4
+# void on_m4_line()
+sub on_m4_line ($)
+{
+ my ($self) = @_;
+
+ my @value;
+ my $token;
+ while ( scalar(@tokens) )
+ {
+ $token = $self->extract_token();
+ push(@value,$token); # push first, so we don't eat the newline
+ return join("",@value) if ($token eq "\n");
+ }
+}
+
+
+########################################
+# m4 needs to know when we entered a namespace
+# void on_namespace()
+sub on_namespace($)
+{
+ my ($self) = @_;
+ my $objOutputter = $$self{objOutputter};
+
+ my $number = 0;
+ my $token;
+ my $arg;
+
+ # we need to peek ahead to figure out what type of namespace
+ # declaration this is.
+ while ( $number < scalar(@tokens) )
+ {
+ $token = $tokens[$number];
+ $number++;
+ next if (!defined($token) or $token eq "");
+# print "> $token\n";
+
+ if ($token eq '{')
+ {
+ $arg = string_trim($arg);
+
+ if ($$self{first_namespace})
+ {
+ $objOutputter->append("_SECTION(SECTION_HEADER2)\n");
+ $$self{first_namespace} = 0;
+ }
+
+ $objOutputter->append("_NAMESPACE($arg)");
+ unshift(@{$$self{namespace}}, $arg);
+ unshift(@{$$self{in_namespace}}, $$self{level}+1);
+ return;
+ }
+
+ next if ( $token =~ /^#[lf] \S+\n/);
+ return if ($token eq ';');
+
+ $arg .= $token; #concatenate
+ }
+}
+
+
+########################################
+### we don't want to report every petty function as unwrapped
+# void on_ignore($)
+sub on_ignore($)
+{
+ my ($self) = @_;
+ my $str = $self->extract_bracketed_text();
+ my @args = split(/\s+|,/,$str);
+ foreach (@args)
+ {
+ next if ($_ eq "");
+ GtkDefs::lookup_function($_); #Pretend that we've used it.
+ }
+}
+
+sub on_ignore_signal($)
+{
+ my ($self) = @_;
+ my $str = $self->extract_bracketed_text();
+ my @args = split(/\s+|,/,$str);
+ foreach (@args)
+ {
+ next if ($_ eq "");
+ GtkDefs::lookup_signal($$self{c_class}, $_); #Pretend that we've used it.
+ }
+}
+
+########################################
+### we have certain macros we need to insert at end of statements
+# void on_class($, $strClassCommand)
+sub on_class($$)
+{
+ my ($self, $class_command) = @_;
+
+ my $objOutputter = $$self{objOutputter};
+
+ $$self{in_class} = $$self{level};
+
+ #Remember the type of wrapper required, so that we can append the correct _END_CLASS_* macro later.
+ {
+ my $str = $class_command;
+ $str =~ s/^_CLASS_//;
+ $$self{type} = $str;
+ }
+
+ my $str = $self->extract_bracketed_text();
+ my ($class, $c_class) = split(',',$str);
+ $class = string_trim($class);
+ $c_class = string_trim($c_class);
+
+ $$self{class} = $class;
+ $$self{c_class} = $c_class;
+
+ my @back;
+ push(@back, $class_command);
+ push(@back, "($str)");
+
+ # When we hit _CLASS, we walk backwards through the output to find "class"
+ my $token;
+ while ( scalar(@{$$objOutputter{out}}) > 0)
+ {
+ $token = pop @{$$objOutputter{out}};
+ unshift(@back, $token);
+ if ($token eq "class")
+ {
+ $objOutputter->append("_CLASS_START()");
+
+ my $strBack = join("", @back);
+
+ $objOutputter->append($strBack);
+ return;
+ }
+ }
+
+ $self->error("$class_command outside of class.\n");
+ exit(-1);
+}
+
+
+# order to read the defs file
+# void on_defs()
+sub on_defs($)
+{
+ my ($self) = @_;
+
+ my $str = $self->extract_bracketed_text();
+ my ($module, $defsfile) = split(/,/, $str); #e.g. _DEFS(gtkmm,gtk), where gtkmm is the module name, and gtk is the defs file name.
+ # $$self{section} = $section; #Save it so that we can reuse it in read_defs_included.
+ $$self{module} = $module; #Use it later in call to output_temp_g1().
+
+ GtkDefs::read_defs("$$self{defsdir}", "$defsfile.defs");
+
+ #Read the documentation too, so that we can merge it into the generated C++ code:
+ if($$self{mergecdocs})
+ {
+ my $docs_filename = $defsfile . "_docs.xml";
+ my $docs_filename_override = $defsfile . "_docs_override.xml";
+ DocsParser::read_defs("$$self{defsdir}", $docs_filename, $docs_filename_override);
+ }
+}
+
+# void on_open_brace()
+sub on_open_brace($)
+{
+ my ($self) = @_;
+
+ $$self{level}++;
+}
+
+# void on_close_brace($)
+sub on_close_brace($)
+{
+ my ($self) = @_;
+ my $objOutputter = $$self{objOutputter};
+
+ #push(@out, "($$self{level})");
+
+ $self->on_end_class()
+ if ($$self{in_class} && $$self{in_class} == $$self{level});
+
+ $objOutputter->append("}"); #We append it here instead of after we return, so that we can end the namespace after it.
+
+ $self->on_end_namespace()
+ if ( (scalar(@{$$self{in_namespace}}) > 0) && (@{$$self{in_namespace}}[0] == $$self{level}) );
+
+ $$self{level}--;
+}
+
+
+########################################
+### denote the end of a class
+# void on_end_class($)
+sub on_end_class($)
+{
+ my ($self) = @_;
+ my $objOutputter = $$self{objOutputter};
+
+ # Examine $$self{type}, which was set in on_class()
+ # And append the _END_CLASS_* macro, which will, in turn, output the m4 code.
+ {
+ my $str = $$self{type};
+ $objOutputter->append("`'_END_CLASS_$str()\n");
+ }
+
+ $$self{class} = "";
+ $$self{c_class} = "";
+ $$self{in_class} = 0;
+}
+
+
+########################################
+###
+# void on_end_namespace($)
+sub on_end_namespace($)
+{
+ my ($self) = @_;
+ my $objOutputter = $$self{objOutputter};
+
+ $objOutputter->append("`'_END_NAMESPACE()");
+ shift( @{$$self{namespace}} );
+ shift( @{$$self{in_namespace}} );
+}
+
+
+######################################################################
+##### some utility subroutines
+
+########################################
+### takes (\S+) from the tokens (smart)
+# $string extract_bracketed_text()
+sub extract_bracketed_text($)
+{
+ my ($self) = @_;
+
+ my $level = 1;
+ my $str = "";
+
+ # Move to the first "(":
+ while ( scalar(@tokens) )
+ {
+ my $t = $self->extract_token();
+ last if ($t eq "(");
+ }
+
+ # Concatenate until the corresponding ")":
+ while ( scalar(@tokens) )
+ {
+ my $t = $self->extract_token();
+ $level++ if ($t eq "(");
+ $level-- if ($t eq ")");
+
+ return $str if (!$level);
+ $str .= $t;
+ }
+
+ return "";
+}
+
+
+########################################
+### breaks up a string by commas (smart)
+# @strings string_split_commas($string)
+sub string_split_commas($)
+{
+ my ($in) = @_;
+
+ my @out;
+ my $level = 0;
+ my $str = "";
+ my @in = split(/([,()])/, $in);
+
+ while ($#in > -1)
+ {
+ my $t = shift @in;
+
+ next if ($t eq "");
+ $level++ if ($t eq "(");
+ $level-- if ($t eq ")");
+
+ # skip , inside functions Ie. void (*)(int,int)
+ if ( ($t eq ",") && !$level)
+ {
+ push(@out, $str);
+ $str="";
+ next;
+ }
+
+ $str .= $t;
+ }
+
+ push(@out,$str);
+ return @out;
+}
+
+
+########################################
+### reads in the preprocessor files
+# we insert line and file directives for later stages
+# void read_file()
+sub read_file($$$)
+{
+ my ($self, $srcdir, $source) = @_;
+
+ my $line;
+ my @in;
+
+ if ( ! -r "${srcdir}/${source}.hg")
+ {
+ print "Unable to find header file $srcdir/$source.hg\n";
+ exit(-1);
+ }
+
+ # Read header file:
+ open(FILE, "${srcdir}/${source}.hg");
+# push(@in, "#f ${source}.hg\n"); #TODO: What does #f do?
+ $line = 1;
+ while (<FILE>)
+ {
+# push(@in, "#l $line\n"); #TODO: What does #l do?
+ push(@in, $_);
+ $line++;
+ }
+ close(FILE);
+ push(@in, "\n_SECTION(SECTION_SRC_CUSTOM)\n");
+
+ # Source file is optional.
+ if ( -r "${srcdir}/${source}.ccg")
+ {
+ open(FILE, "${srcdir}/${source}.ccg");
+ $line = 1;
+# push(@in, "#f ${source}.ccg\n"); #TODO: What does #f do?
+ while (<FILE>)
+ {
+# push(@in, "#l $line\n"); #TODO: What does #l do?
+ push(@in, $_);
+ $line++;
+ }
+ close(FILE);
+ }
+
+ my $strIn = join("", @in);
+
+ # Break the file into tokens. Token is
+ # any group of #, A to z, 0 to 9, _
+ # /*
+ # *.
+ # //
+ # any char proceeded by \
+ # symbols ;{}"`'()
+ # newline
+ @tokens = split(/(\#[lf] \S+\n)|([#A-Za-z0-9_]+)|(\/\*)|(\*\/)|(\/\/)|(\\.)|([;{}"'`()])|(\n)/,
+ $strIn);
+}
+
+
+sub class_prefix($)
+{
+ my ($self) = @_;
+
+ my $str = $$self{class};
+ $str =~ s/([a-z])([A-Z])/$1_$2/g;
+ $str =~ tr/A-Z/a-z/;
+ return $str;
+}
+
+
+######################################################################
+##### 2.1 subroutines for _WRAP
+
+########################################
+
+# $bool check_for_eof()
+sub check_for_eof($)
+{
+ my ($self) = @_;
+
+ my $filename = $$self{filename};
+ my $line_num = $$self{line_num};
+
+ if (!(scalar(@tokens)))
+ {
+ print STDERR "$filename:$line_num:hit eof in _WRAP\n";
+ return 0; #EOF
+ }
+
+ return 1; # No EOF
+}
+
+# void on_wrap_method()
+sub on_wrap_method($)
+{
+ my ($self) = @_;
+ my $objOutputter = $$self{objOutputter};
+
+ if( !($self->check_for_eof()) )
+ {
+ return;
+ }
+
+ my $filename = $$self{filename};
+ my $line_num = $$self{line_num};
+
+ my $str = $self->extract_bracketed_text();
+ my @args = string_split_commas($str);
+
+ my $entity_type = "method";
+
+ if (!$$self{in_class})
+ {
+ print STDERR "$filename:$line_num:_WRAP macro encountered outside class\n";
+ return;
+ }
+
+ my $objCfunc;
+ my $objCppfunc;
+
+ # handle first argument
+ my $argCppMethodDecl = $args[0];
+ if ($argCppMethodDecl =~ /^\S+$/ ) #Checks that it's not empty and that it contains no whitespace.
+ {
+ print STDERR "$filename:$line_num:_WRAP can't handle unspecified method $argCppMethodDecl\n";
+ return;
+ }
+ else
+ {
+ #Parse the method decaration and build an object that holds the details:
+ $objCppfunc = &Function::new($argCppMethodDecl, $self);
+ }
+
+
+ # handle second argument:
+
+ my $argCFunctionName = $args[1];
+ $argCFunctionName = string_trim($argCFunctionName);
+
+ #Get the c function's details:
+
+ #Checks that it's not empty and that it contains no whitespace.
+ if ($argCFunctionName =~ /^\S+$/ )
+ {
+ #c-name. e.g. gtk_clist_set_column_title
+ $objCfunc = GtkDefs::lookup_function($argCFunctionName);
+
+ if(!$objCfunc) #If the lookup failed:
+ {
+ $objOutputter->output_wrap_failed($argCFunctionName, "method defs lookup failed (1)");
+ return;
+ }
+ }
+
+ # Extra ref needed?
+ while(scalar(@args) > 2) # If the optional ref/err arguments are there.
+ {
+ my $argRef = string_trim(pop @args);
+ if($argRef eq "refreturn")
+ {
+ $$objCfunc{rettype_needs_ref} = 1;
+ }
+ if($argRef eq "errthrow")
+ {
+ $$objCfunc{throw_any_errors} = 1;
+ }
+ }
+
+ my $commentblock = "";
+ $commentblock = DocsParser::lookup_documentation($argCFunctionName);
+
+ $objOutputter->output_wrap_meth($filename, $line_num, $objCppfunc, $objCfunc, $argCppMethodDecl, $commentblock);
+}
+
+sub on_wrap_ctor($)
+{
+ my ($self) = @_;
+ my $objOutputter = $$self{objOutputter};
+
+ if( !($self->check_for_eof()) )
+ {
+ return;
+ }
+
+ my $filename = $$self{filename};
+ my $line_num = $$self{line_num};
+
+ my $str = $self->extract_bracketed_text();
+ my @args = string_split_commas($str);
+
+ my $entity_type = "method";
+
+ if (!$$self{in_class})
+ {
+ print STDERR "$filename:$line_num:_WRAP_CTOR macro encountered outside class\n";
+ return;
+ }
+
+ my $objCfunc;
+ my $objCppfunc;
+
+ # handle first argument
+ my $argCppMethodDecl = $args[0];
+ if ($argCppMethodDecl =~ /^\S+$/ ) #Checks that it's not empty and that it contains no whitespace.
+ {
+ print STDERR "$filename:$line_num:_WRAP_CTOR can't handle unspecified method $argCppMethodDecl\n";
+ return;
+ }
+ else
+ {
+ #Parse the method decaration and build an object that holds the details:
+ $objCppfunc = &Function::new_ctor($argCppMethodDecl, $self);
+ }
+
+
+ # handle second argument:
+
+ my $argCFunctionName = $args[1];
+ $argCFunctionName = string_trim($argCFunctionName);
+
+ #Get the c function's details:
+ if ($argCFunctionName =~ /^\S+$/ ) #Checks that it's not empty and that it contains no whitespace.
+ {
+ $objCfunc = GtkDefs::lookup_function($argCFunctionName); #c-name. e.g. gtk_clist_set_column_title
+ if(!$objCfunc) #If the lookup failed:
+ {
+ $objOutputter->output_wrap_failed($argCFunctionName, "ctor defs lookup failed (2)");
+ return;
+ }
+ }
+
+ $objOutputter->output_wrap_ctor($filename, $line_num, $objCppfunc, $objCfunc, $argCppMethodDecl);
+}
+
+sub on_wrap_create($)
+{
+ my ($self) = @_;
+
+ if( !($self->check_for_eof()) )
+ {
+ return;
+ }
+
+ my $str = $self->extract_bracketed_text();
+
+ my $objOutputter = $$self{objOutputter};
+ $objOutputter->output_wrap_create($str, $self);
+}
+
+sub on_wrap_signal($)
+{
+ my ($self) = @_;
+
+ if( !($self->check_for_eof()) )
+ {
+ return;
+ }
+
+ my $str = $self->extract_bracketed_text();
+ my @args = string_split_commas($str);
+
+ #Get the arguments:
+ my $argCppDecl = $args[0];
+ my $argCName = $args[1];
+ $argCName = string_trim($argCName);
+ $argCName = string_unquote($argCName);
+
+ my $bCustomDefaultHandler = 0;
+ if(scalar(@args) > 2) # If the optional argument is there.
+ {
+ my $argRef = string_trim($args[2]);
+ if($argRef eq "custom_default_handler")
+ {
+ $bCustomDefaultHandler = 1;
+ }
+ }
+
+ my $bImplement = 1;
+ if( $bCustomDefaultHandler eq 1) { $bImplement = 0 };
+
+ $self->output_wrap_signal( $argCppDecl, $argCName, $$self{filename}, $$self{line_num}, $bImplement);
+}
+
+# void on_wrap_vfunc()
+sub on_wrap_vfunc($)
+{
+ my ($self) = @_;
+
+ if( !($self->check_for_eof()) )
+ {
+ return;
+ }
+
+ my $str = $self->extract_bracketed_text();
+ my @args = string_split_commas($str);
+
+ #Get the arguments:
+ my $argCppDecl = $args[0];
+ my $argCName = $args[1];
+ $argCName = string_trim($argCName);
+ $argCName = string_unquote($argCName);
+
+ my $refreturn = 0;
+ my $refreturn_ctype = 0;
+
+ # Extra ref needed?
+ while(scalar(@args) > 2) # If the optional ref/err arguments are there.
+ {
+ my $argRef = string_trim(pop @args);
+
+ if($argRef eq "refreturn")
+ { $refreturn = 1; }
+ elsif($argRef eq "refreturn_ctype")
+ { $refreturn_ctype = 1; }
+ }
+
+ $self->output_wrap_vfunc($argCppDecl, $argCName, $refreturn, $refreturn_ctype,
+ $$self{filename}, $$self{line_num});
+}
+
+sub on_wrap_enum($)
+{
+ my ($self) = @_;
+
+ return if(!$self->check_for_eof());
+
+ my $outputter = $$self{objOutputter};
+ my $out = \@{$$outputter{out}};
+
+ # Look back for a Doxygen comment for this _WRAP_ENUM. If there is one,
+ # remove it from the output and pass it to the m4 _ENUM macro instead.
+ my $comment = "";
+
+ if(scalar(@$out) >= 2)
+ {
+ # steal the last two tokens
+ my @back = splice(@$out, -2);
+ local $_ = $back[0];
+
+ # Check for /*[*!] ... */ or //[/!] comments. The closing */ _must_
+ # be the last token of the previous line. Apart from this restriction,
+ # anything else should work, including multi-line comments.
+
+ if($back[1] eq "\n" && (m#^/\*`[*!](.+)'\*/#s || m#^//`[/!](.+)'$#))
+ {
+ $comment = $1;
+ $comment =~ s/\s+$//;
+ }
+ else
+ {
+ # restore stolen tokens
+ push(@$out, @back);
+ }
+ }
+
+ # get the arguments
+ my @args = string_split_commas($self->extract_bracketed_text());
+
+ my $cpp_type = string_trim(shift(@args));
+ my $c_type = string_trim(shift(@args));
+
+ # The remaining elements in @args could be flags or s#^FOO_## substitutions.
+
+ $outputter->output_wrap_enum(
+ $$self{filename}, $$self{line_num}, $cpp_type, $c_type, $comment, @args);
+}
+
+sub on_wrap_gerror($)
+{
+ my ($self) = @_;
+
+ return if(!$self->check_for_eof());
+
+ # get the arguments
+ my @args = string_split_commas($self->extract_bracketed_text());
+
+ my $cpp_type = string_trim(shift(@args));
+ my $c_enum = string_trim(shift(@args));
+ my $domain = string_trim(shift(@args));
+
+ # The remaining elements in @args could be flags or s#^FOO_## substitutions.
+
+ $$self{objOutputter}->output_wrap_gerror(
+ $$self{filename}, $$self{line_num}, $cpp_type, $c_enum, $domain, @args);
+}
+
+sub on_wrap_property($)
+{
+ my ($self) = @_;
+ my $objOutputter = $$self{objOutputter};
+
+ if( !($self->check_for_eof()) )
+ {
+ return;
+ }
+
+ my $str = $self->extract_bracketed_text();
+ my @args = string_split_commas($str);
+
+ #Get the arguments:
+ my $argPropertyName = $args[0];
+ $argPropertyName = string_trim($argPropertyName);
+ $argPropertyName = string_unquote($argPropertyName);
+ my $argCppType = $args[1];
+ $argCppType = string_trim($argCppType);
+ $argCppType = string_unquote($argCppType);
+
+ my $filename = $$self{filename};
+ my $line_num = $$self{line_num};
+
+ $objOutputter->output_wrap_property($filename, $line_num, $argPropertyName, $argCppType, $$self{c_class});
+}
+
+
+sub output_wrap_check($$$$$$)
+{
+ my ($self, $CppDecl, $signal_name, $filename, $line_num, $macro_name) = @_;
+
+ #Some checks:
+
+
+ if (!$$self{in_class})
+ {
+ print STDERR "$filename:$line_num: $macro_name macro encountered outside class\n";
+ return;
+ }
+
+ if ($CppDecl =~ /^\S+$/ ) #If it's not empty and it contains no whitespace.
+ {
+ print STDERR "$filename:$line_num:$macro_name can't handle unspecified entity $CppDecl\n";
+ return;
+ }
+
+
+}
+
+# void output_wrap($CppDecl, $signal_name, $filename, $line_num)
+# Also used for vfunc.
+sub output_wrap_signal($$$$$$)
+{
+ my ($self, $CppDecl, $signal_name, $filename, $line_num, $bImplement) = @_;
+
+ #Some checks:
+ $self->output_wrap_check($CppDecl, $signal_name, $filename, $line_num, "WRAP_SIGNAL");
+
+ # handle first argument
+
+ #Parse the method decaration and build an object that holds the details:
+ my $objCppSignal = &Function::new($CppDecl, $self);
+ $$objCppSignal{class} = $$self{class}; #Remeber the class name for use in Outputter::output_wrap_signal().
+
+
+ # handle second argument:
+ my $objCSignal = undef;
+
+ my $objOutputter = $$self{objOutputter};
+
+ #Get the c function's details:
+ if ($signal_name ne "" ) #If it's not empty and it contains no whitespace.
+ {
+ $objCSignal = GtkDefs::lookup_signal($$self{c_class}, $signal_name);
+
+ # Check for failed lookup.
+ if($objCSignal eq 0)
+ {
+ print STDERR "$signal_name\n";
+ $objOutputter->output_wrap_failed($signal_name,
+ " signal defs lookup failed");
+ return;
+ }
+ }
+
+ #If the C types and C++ types are different, then create a custom SignalProxy,
+ #which will do the C-to-C++ conversion in its C callback.
+# my $no_type_conversion = $objCSignal->has_same_types($objCppSignal);
+# my $custom_signalproxy_name = "";
+# if($no_type_conversion ne 1)
+# {
+# $custom_signalproxy_name = $$objCppSignal{class} . "_" . $$objCppSignal{name};
+# $objOutputter->output_wrap_sig_custom($filename, $line_num, $objCSignal, $objCppSignal, $custom_signalproxy_name);
+# }
+
+ $objOutputter->output_wrap_sig_decl($filename, $line_num, $objCSignal, $objCppSignal, $signal_name);
+ $objOutputter->output_wrap_default_signal_handler_h($filename, $line_num, $objCppSignal, $objCSignal);
+ $objOutputter->output_wrap_default_signal_handler_cc($filename, $line_num, $objCppSignal, $objCSignal, $bImplement);
+}
+
+# void output_wrap($CppDecl, $signal_name, $filename, $line_num)
+# Also used for vfunc.
+sub output_wrap_vfunc($$$$$$$)
+{
+ my ($self, $CppDecl, $vfunc_name, $refreturn, $refreturn_ctype, $filename, $line_num) = @_;
+
+ #Some checks:
+ $self->output_wrap_check($CppDecl, $vfunc_name, $filename, $line_num, "VFUNC");
+
+ # handle first argument
+
+ #Parse the method decaration and build an object that holds the details:
+ my $objCppVfunc = &Function::new($CppDecl, $self);
+
+
+ # handle second argument:
+ my $objCVfunc = undef;
+
+ my $objOutputter = $$self{objOutputter};
+
+ #Get the c function's details:
+ if ($vfunc_name =~ /^\S+$/ ) #If it's not empty and it contains no whitespace.
+ {
+ $objCVfunc = GtkDefs::lookup_signal($$self{c_class},$vfunc_name);
+ if(!$objCVfunc) #If the lookup failed:
+ {
+ $objOutputter->output_wrap_failed($vfunc_name, " vfunc defs lookup failed");
+ return;
+ }
+ }
+
+ # Write out the appropriate macros.
+ # These macros are defined in vfunc.m4:
+
+ $$objCppVfunc{rettype_needs_ref} = $refreturn;
+ $$objCppVfunc{name} .= "_vfunc"; #All vfuncs should have the "_vfunc" prefix, and a separate easily-named invoker method.
+
+ $$objCVfunc{rettype_needs_ref} = $refreturn_ctype;
+
+ $objOutputter->output_wrap_vfunc_h($filename, $line_num, $objCppVfunc, $objCVfunc);
+ $objOutputter->output_wrap_vfunc_cc($filename, $line_num, $objCppVfunc, $objCVfunc);
+}
+
+# give some sort of weights to sorting attibutes
+sub byattrib()
+{
+ my %attrib_value = (
+ "virtual_impl" ,1,
+ "virtual_decl" ,2,
+ # "sig_impl" ,3,
+ "sig_decl" ,4,
+ "meth" ,5
+ );
+
+ # $a and $b are hidden parameters to a sorting function
+ return $attrib_value{$b} <=> $attrib_value{$a};
+}
+
+
+# void on_wrap_corba_method()
+sub on_wrap_corba_method($)
+{
+ my ($self) = @_;
+ my $objOutputter = $$self{objOutputter};
+
+ if( !($self->check_for_eof()) )
+ {
+ return;
+ }
+
+ my $filename = $$self{filename};
+ my $line_num = $$self{line_num};
+
+ my $str = $self->extract_bracketed_text();
+ my @args = string_split_commas($str);
+
+ my $entity_type = "method";
+
+ if (!$$self{in_class})
+ {
+ print STDERR "$filename:$line_num:_WRAP macro encountered outside class\n";
+ return;
+ }
+
+ my $objCfunc;
+ my $objCppfunc;
+
+ # handle first argument
+ my $argCppMethodDecl = $args[0];
+ if ($argCppMethodDecl =~ /^\S+$/ ) #Checks that it's not empty and that it contains no whitespace.
+ {
+ print STDERR "$filename:$line_num:_WRAP can't handle unspecified method $argCppMethodDecl\n";
+ return;
+ }
+ else
+ {
+ #Parse the method decaration and build an object that holds the details:
+ $objCppfunc = &Function::new($argCppMethodDecl, $self);
+ }
+
+ $objOutputter->output_wrap_corba_method($filename, $line_num, $objCppfunc);
+}
+
+
+1; # return package loaded okay.