[glibmm] gmmproc: _WRAP_METHOD: Allow setting parameters from C output params.



commit 63cae37cd9dde19ffffe6d1b40c6bbb300f04a97
Author: Josà Alburquerque <jaalburqu svn gnome org>
Date:   Tue Sep 18 15:22:25 2012 -0400

    gmmproc: _WRAP_METHOD: Allow setting parameters from C output params.
    
    	* tools/m4/convert_base.m4 (_INITIALIZATION): Insert newlines between
    	a possible series of statements that has been specified as an
    	initialization.  For example, the declaration, assignment and the
    	g_free() call would each be on a seperate line in the following (from
    	datainputstream.hg):
    
    	_INITIALIZATION(`std::string&',`return-char*',`char* tmp = $4; $3 = tmp; g_free(tmp)')
    
    	* tools/pm/Function.pm (FLAG_PARAM_OPTIONAL):
    	(FLAG_PARAM_OUTPUT): Added new constant flags representing if a
    	parameter is optional or if it is an output parameter.
    	(EXPORT_OK): Exported the above flags so they can be used in other
    	modules.
    	(param_optional): Renamed to param_flags.  Redesigned it to store a
    	possible combination of both flags above and not just if a parameter
    	is optional.
    	(parse_param): Modified the subroutine to look for an '>>' in a
    	possible '{.*}' following the current parameter name which would
    	signal that the parameter is an output parameter.  The syntax for
    	signaling if a parameter is optional, is an output parameter or should
    	be mapped to a specific C parameter would be:
    
    	cpp_param_name{c_param_name>>?}
    
    	c_param_name means that the C++ parameter should be mapped to the C
    	parameter no matter the parameter order of either.  The '>>' means
    	that the parameter should be set from the C parameter because the C
    	parameter is an output parameter.   Finally, the '?' means that the
    	parameter is optional thus overloads should be generated without that
    	paramter.  All three components within the {} are optional.  A '.' may
    	be used instead of the c parameter name if the C++ parameter name is
    	the same as the C parameter name.
    
    	(possible_args_list): Modified to use the param_flags variable.
    
    	* tools/pm/Output.pm (output_wrap_vfunc_h): Modified to receive the
    	new return type from convert_args_cpp_to_c() (see below).
    	(output_wrap_meth): Modified to receive the new return from
    	convert_args_cpp_to_c (see below) and pass them to the _METHOD() and
    	_STATIC_METHOD() macros.
    	(convert_args_cpp_to_c): Modified to generate a
    	list of C declarations for any possible C output parameters and to
    	generate a list of _INITIALIZE() macros to initialize the C++
    	parameters from the C output parameters.  The function returns an array
    	of three strings (the convert macros, the possible C declarations and
    	the _INITIALIZE() macros in that order).
    
    	* tools/pm/WrapParser.pm (string_split_commas): Modified the
    	subroutine to ignore '>>' if they are in '{}' (so that the '>>' can
    	signal that a parameter should be set from a C output parameter.
    
    	* tools/m4/method.m4 (_METHOD, _STATIC_METHOD): Rewrote to accept
    	C declarations of possible C output parameters and _INITIALIZE macros
    	which would initialize the appropriate C++ parameters from the output
    	variables and insert them appropriately in the generated code.
    
    	Bug #662371.

 ChangeLog                |   62 ++++++++++++++++++
 tools/m4/convert_base.m4 |    3 +-
 tools/m4/convert_gio.m4  |    1 +
 tools/m4/method.m4       |  162 +++++++++++++++++++++++++++++----------------
 tools/pm/Function.pm     |   63 ++++++++++--------
 tools/pm/Output.pm       |  111 ++++++++++++++++++++++----------
 tools/pm/WrapParser.pm   |   13 +++-
 7 files changed, 293 insertions(+), 122 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 37799b1..0c735b5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,65 @@
+2012-09-18  Josà Alburquerque  <jaalburqu svn gnome org>
+
+	gmmproc: _WRAP_METHOD: Allow setting parameters from C output params.
+
+	* tools/m4/convert_base.m4 (_INITIALIZATION): Insert newlines between
+	a possible series of statements that has been specified as an
+	initialization.  For example, the declaration, assignment and the
+	g_free() call would each be on a seperate line in the following (from
+	datainputstream.hg):
+
+	_INITIALIZATION(`std::string&',`return-char*',`char* tmp = $4; $3 = tmp; g_free(tmp)')
+
+	* tools/pm/Function.pm (FLAG_PARAM_OPTIONAL):
+	(FLAG_PARAM_OUTPUT): Added new constant flags representing if a
+	parameter is optional or if it is an output parameter.
+	(EXPORT_OK): Exported the above flags so they can be used in other
+	modules.
+	(param_optional): Renamed to param_flags.  Redesigned it to store a
+	possible combination of both flags above and not just if a parameter
+	is optional.
+	(parse_param): Modified the subroutine to look for an '>>' in a
+	possible '{.*}' following the current parameter name which would
+	signal that the parameter is an output parameter.  The syntax for
+	signaling if a parameter is optional, is an output parameter or should
+	be mapped to a specific C parameter would be:
+
+	cpp_param_name{c_param_name>>?}
+
+	c_param_name means that the C++ parameter should be mapped to the C
+	parameter no matter the parameter order of either.  The '>>' means
+	that the parameter should be set from the C parameter because the C
+	parameter is an output parameter.   Finally, the '?' means that the
+	parameter is optional thus overloads should be generated without that
+	paramter.  All three components within the {} are optional.  A '.' may
+	be used instead of the c parameter name if the C++ parameter name is
+	the same as the C parameter name.
+
+	(possible_args_list): Modified to use the param_flags variable.
+
+	* tools/pm/Output.pm (output_wrap_vfunc_h): Modified to receive the
+	new return type from convert_args_cpp_to_c() (see below).
+	(output_wrap_meth): Modified to receive the new return from
+	convert_args_cpp_to_c (see below) and pass them to the _METHOD() and
+	_STATIC_METHOD() macros.
+	(convert_args_cpp_to_c): Modified to generate a
+	list of C declarations for any possible C output parameters and to
+	generate a list of _INITIALIZE() macros to initialize the C++
+	parameters from the C output parameters.  The function returns an array
+	of three strings (the convert macros, the possible C declarations and
+	the _INITIALIZE() macros in that order).
+
+	* tools/pm/WrapParser.pm (string_split_commas): Modified the
+	subroutine to ignore '>>' if they are in '{}' (so that the '>>' can
+	signal that a parameter should be set from a C output parameter.
+
+	* tools/m4/method.m4 (_METHOD, _STATIC_METHOD): Rewrote to accept
+	C declarations of possible C output parameters and _INITIALIZE macros
+	which would initialize the appropriate C++ parameters from the output
+	variables and insert them appropriately in the generated code.
+
+	Bug #662371.
+
 2012-09-18  Kjell Ahlstedt  <kjell ahlstedt bredband net>
 
 	Improve the use of _IGNORE. Don't use gio_others.defs.
diff --git a/tools/m4/convert_base.m4 b/tools/m4/convert_base.m4
index aabbc70..ff00606 100644
--- a/tools/m4/convert_base.m4
+++ b/tools/m4/convert_base.m4
@@ -65,7 +65,8 @@ m4_m4exit(1)
 #  Functions for populating initialization tables.
 #
 define(`_INITIALIZATION',`
-m4_ifelse(`$3',,,`define(IN`'__HASH2(`$1',`$2'),`$3')')
+m4_ifelse(`$3',,,`define(IN`'__HASH2(`$1',`$2'),m4_patsubst(`$3',`; +',`;
+  '))')
 ')
 
 define(`_EQUAL',`define(EV`'__HASH(`$1'),`$2')')
diff --git a/tools/m4/convert_gio.m4 b/tools/m4/convert_gio.m4
index e8a6780..4e2e4fc 100644
--- a/tools/m4/convert_gio.m4
+++ b/tools/m4/convert_gio.m4
@@ -261,6 +261,7 @@ _CONVERSION(`const Glib::VariantContainerBase&',`GVariant*',`const_cast<GVariant
 
 #VariantType
 _CONVERSION(`const GVariantType*',`Glib::VariantType',`Glib::wrap(const_cast<GVariantType*>($3), false)')
+_CONVERSION(`const Glib::VariantType&',`const GVariantType*',`$3.gobj()')
 
 #Volume
 _CONVERSION(`GVolume*',`Glib::RefPtr<Volume>',`Glib::wrap($3)')
diff --git a/tools/m4/method.m4 b/tools/m4/method.m4
index 7551c42..5dd7fd7 100644
--- a/tools/m4/method.m4
+++ b/tools/m4/method.m4
@@ -8,96 +8,142 @@ dnl
 
 
 dnl
-dnl method 
-dnl           $1      $2     $3         $4       $5     $6    $7     $8        $9        $10         $11       $12         $13                $14        $15             $16
-dnl  _METHOD(cppname,cname,cpprettype,crettype,arglist,cargs,const,refreturn,errthrow,deprecated,constversion,ifdef,arglist_without_types,out_param,out_param_cpptype,wrap_line)
+dnl method
+dnl           $1       $2     $3         $4       $5        $6        $7         $8          $9     $10       $11       $12         $13       $14         $15               $16        $17             $18
+dnl  _METHOD(cppname,cname,cpprettype,crettype,arglist,cdeclarations,cargs,cinitializations,const,refreturn,errthrow,deprecated,constversion,ifdef,arglist_without_types,out_param,out_param_cpptype,wrap_line)
 define(`_METHOD',`dnl
 _PUSH(SECTION_CC)
-ifelse(`$10',,,`_DEPRECATE_IFDEF_START
+ifelse(`$12',,,`_DEPRECATE_IFDEF_START
 ')dnl
-ifelse(`$13',,,`#ifdef $13'
+ifelse(`$15',,,`#ifdef $15'
 )dnl
-$3 __CPPNAME__::$1`'($5)ifelse(`$7',1,` const')
+$3 __CPPNAME__::$1`'($5)ifelse(`$9',1,` const')
 {
-ifelse(`$11',,dnl
-`ifelse(`$8'`$9',,dnl If it is not errthrow or refreturn
-`ifelse(`$14',,dnl If no output parameter is specified
-`ifelse(`$3',void,dnl If it returns voids:
-`  $2(ifelse(`$7',1,const_cast<__CNAME__*>(gobj()),gobj())`'ifelse(`$6',,,`, ')$6);' dnl It it returns non-void:
-,`  return _CONVERT($4,`$3',`$2`'(ifelse(`$7',1,const_cast<__CNAME__*>(gobj()),gobj())`'ifelse(`$6',,,`, ')$6)');'dnl
-)'dnl End if it returns voids.
-dnl An output parameter is specified:
-,`  _INITIALIZE($15,$4,`$14',`$2`'(ifelse(`$7',1,const_cast<__CNAME__*>(gobj()),gobj())`'ifelse(`$6',,,`, ')$6)',$16);'dnl
-)',dnl End if an output parameter is specified.
+ifelse(`$13',,dnl
+`ifelse(`$10'`$11',,dnl If it is not errthrow or refreturn
+dnl Insert the declarations for C output parameters
+`ifelse(`$6',,,`$6
+')`'dnl
+ifelse(`$16',,dnl If no C++ output parameter is specified
+`ifelse(`$3',void,dnl If the C function returns voids:
+`  $2(ifelse(`$9',1,const_cast<__CNAME__*>(gobj()),gobj())`'ifelse(`$7',,,`, ')$7);dnl
+dnl Insert the initializations for the C output parameters
+ifelse(`$8',,,`$8
+')dnl
+'dnl If the C function returns non-void:
+,dnl Insert the declarations for C output parameters
+dnl Store the return if there are C output parameters.
+`ifelse(`$6',,`  return ',`  `$3' retvalue = ')_CONVERT($4,`$3',`$2`'(ifelse(`$9',1,const_cast<__CNAME__*>(gobj()),gobj())`'ifelse(`$7',,,`, ')$7)');dnl
+dnl Insert the initializations for the C output parameters
+ifelse(`$8',,,`$8
+')dnl
+dnl return the value
+ifelse(`$6',,,`  return retvalue;
+')dnl
+')'dnl End if it returns voids.
+dnl A C++ output parameter is specified:
+,`  _INITIALIZE($17,$4,`$16',`$2`'(ifelse(`$9',1,const_cast<__CNAME__*>(gobj()),gobj())`'ifelse(`$7',,,`, ')$7)',$18);
+dnl
+dnl Insert the initializations for the C output parameters
+ifelse(`$8',,,`$8
+')dnl
+')',dnl End if a C++ output parameter is specified.
 dnl If is errthrow or refreturn
-`ifelse(`$9',,,`  GError* gerror = 0;')
-ifelse(`$14',,dnl If no output parameter is specified:
-`  ifelse(`$3',void,,``$3' retvalue = ')_CONVERT($4,`$3',`$2`'(ifelse(`$7',1,const_cast<__CNAME__*>(gobj()),gobj())`'ifelse(`$6',,,`, ')$6)');'dnl
-dnl An output parameter is specified:
-,`  _INITIALIZE($15,$4,`$14',`$2`'(ifelse(`$7',1,const_cast<__CNAME__*>(gobj()),gobj())`'ifelse(`$6',,,`, ')$6)',$16);'dnl
+`ifelse(`$11',,,`  GError* gerror = 0;
+')dnl
+dnl Insert the declarations for C output parameters
+ifelse(`$6',,,`$6
+')`'dnl
+ifelse(`$16',,dnl If no C++ output parameter is specified:
+`  ifelse(`$3',void,,``$3' retvalue = ')_CONVERT($4,`$3',`$2`'(ifelse(`$9',1,const_cast<__CNAME__*>(gobj()),gobj())`'ifelse(`$7',,,`, ')$7)');dnl
+'dnl
+,dnl A C++ output parameter is specified:
+`  _INITIALIZE($17,$4,`$16',`$2`'(ifelse(`$9',1,const_cast<__CNAME__*>(gobj()),gobj())`'ifelse(`$7',,,`, ')$7)',$18);
+'dnl
 )dnl
-ifelse(`$9',,,`
+ifelse(`$11',,,`
   if(gerror)
     ::Glib::Error::throw_exception(gerror);
-')
-ifelse(`$8',,,`dnl
-  if(ifelse(`$14',,`retvalue',$14))
-    ifelse(`$14',,`retvalue',$14)->reference(); //The function does not do a ref for us.
 ')dnl
-ifelse(`$3',void,,`  return retvalue;')
+ifelse(`$10',,,`
+  if(ifelse(`$16',,`retvalue',$16))
+    ifelse(`$16',,`retvalue',$16)->reference(); //The function does not do a ref for us.
+')dnl
+dnl Insert the initializations for the C output parameters
+ifelse(`$8',,,`$8
+')`'dnl
+ifelse(`$3',void,,`  return retvalue;')dnl
 ')dnl End errthrow/refreturn
-',`  return const_cast<__CPPNAME__*>(this)->$1($12);')
+',`  return const_cast<__CPPNAME__*>(this)->$1($14);')
 }
 
-ifelse(`$13',,,`
-#endif // $13
+ifelse(`$15',,,`
+#endif // $15
 ')dnl
-ifelse(`$10',,,`_DEPRECATE_IFDEF_END
+ifelse(`$12',,,`_DEPRECATE_IFDEF_END
 ')dnl
 _POP()')
 
 dnl
 dnl static method
-dnl                  $1       $2     $3         $4      $5     $6      $7      $8         $9       $10     $11        $12           $13
-dnl  _STATIC_METHOD(cppname,cname,cpprettype,crettype,arglist,cargs,refreturn,errthrow,deprecated,ifdef,out_param,out_param_type,wrap_line)
+dnl                  $1       $2     $3         $4      $5        $6         $7         $8            $9      $10         $11       $12     $13        $14          $15
+dnl  _STATIC_METHOD(cppname,cname,cpprettype,crettype,arglist,cdeclarations,cargs,cinitializations,refreturn,errthrow,deprecated,ifdef,out_param,out_param_type,wrap_line)
 define(`_STATIC_METHOD',`dnl
 _PUSH(SECTION_CC)
-ifelse(`$9',,,`_DEPRECATE_IFDEF_START
+ifelse(`$11',,,`_DEPRECATE_IFDEF_START
 ')dnl
-ifelse(`$10',,,`#ifdef $10'
+ifelse(`$12',,,`#ifdef $12'
 )dnl
 $3 __CPPNAME__::$1($5)
 {
-ifelse(`$7'`$8',,dnl
-`ifelse(`$11',,dnl If no output parameter is specified
-`ifelse(`$3',void,,`  return ')_CONVERT($4,`$3',`$2`'($6)');
-'dnl
-dnl An output parameter is specified:
-,`  _INITIALIZE($12,$4,`$11',`$2`'($6)',$13);'
-)',dnl End if an output parameter is specified.
-`ifelse(`$8',,,`  GError* gerror = 0;')
-ifelse(`$11',,dnl If no output parameter is specified:
-  ifelse(`$3',void,,``$3' retvalue = ')_CONVERT($4,`$3',`$2`'($6)');
-dnl An output parameter is specified:
-,`  _INITIALIZE($12,$4,`$11',`$2`'($6)',$13);'dnl
+ifelse(`$9'`$10',,dnl
+dnl Insert declarations for C the output parameters
+ifelse(`$6',,,`$6
+')`'dnl
+`ifelse(`$13',,
+dnl If no C++ output parameter is specified.
+`  ifelse(`$3',void,,dnl
+dnl Returns non-void:
+dnl Store the return if there are C output parameters
+ifelse(`$6',,`return ',``$3' retval = '))_CONVERT($4,`$3',`$2`'($7)');'dnl
+dnl A C++ output parameter is specified so initialize it from C return
+,`  _INITIALIZE($14,$4,`$13',`$2`'($7)',$15);'dnl
+)
+dnl Insert the initializations for the C output parameters if there are any
+ifelse(`$8',,,`$8
+')`'dnl
+dnl Return the value if it was stored and if the method returns something
+ifelse(`$3',void,,`ifelse(`$6',,,`  return retval;
+')')dnl
+',dnl End if a C++ output parameter is specified.
+`ifelse(`$10',,,`  GError* gerror = 0;')
+dnl Insert the declarations for the C output parameters
+ifelse(`$6',,,`$6
+')`'dnl
+ifelse(`$13',,dnl If no C++ output parameter is specified:
+  ifelse(`$3',void,,``$3' retvalue = ')_CONVERT($4,`$3',`$2`'($7)');dnl
+dnl A C++ output parameter is specified:
+,`  _INITIALIZE($14,$4,`$13',`$2`'($7)',$15);'dnl
 )dnl
-ifelse(`$8',,,`
+ifelse(`$10',,,`
   if(gerror)
     ::Glib::Error::throw_exception(gerror);
-')
-ifelse(`$7',,,`dnl
-  if(ifelse(`$11',,`retvalue',$11))
-    ifelse(`$11',,`retvalue',$11)->reference(); //The function does not do a ref for us
 ')dnl
-ifelse(`$3',void,,`  return retvalue;')
+dnl Insert the initializations for the C output parameters.
+ifelse(`$8',,,`$8
+')`'dnl
+ifelse(`$9',,,`
+  if(ifelse(`$13',,`retvalue',$13))
+    ifelse(`$13',,`retvalue',$13)->reference(); //The function does not do a ref for us
+')dnl
+ifelse(`$3',void,,`  return retvalue;
+')dnl
 ')dnl
 }
 
-ifelse(`$10',,,`
-#endif // $10
+ifelse(`$12',,,`
+#endif // $12
 ')dnl
-ifelse(`$9',,,`_DEPRECATE_IFDEF_END
+ifelse(`$11',,,`_DEPRECATE_IFDEF_END
 ')
 _POP()')
-
-
diff --git a/tools/pm/Function.pm b/tools/pm/Function.pm
index 7073ebe..598178b 100644
--- a/tools/pm/Function.pm
+++ b/tools/pm/Function.pm
@@ -5,6 +5,11 @@ use warnings;
 use Util;
 use FunctionBase;
 
+# These are flags that indicate whether parameters are optional or output
+# parameters.
+use constant FLAG_PARAM_OPTIONAL => 1;
+use constant FLAG_PARAM_OUTPUT => 2;
+
 BEGIN {
      use Exporter   ();
      our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
@@ -16,7 +21,7 @@ BEGIN {
      %EXPORT_TAGS = ( );
      # your exported package globals go here,
      # as well as any optionally exported functions
-     @EXPORT_OK   = qw($Var1 %Hashit &func3);
+     @EXPORT_OK   = qw($Var1 %Hashit &func3 FLAG_PARAM_OPTIONAL FLAG_PARAM_OUTPUT);
      }
 our @EXPORT_OK;
 
@@ -35,7 +40,7 @@ our @EXPORT_OK;
 #       string array param_type;
 #       string array param_name;
 #       string array param_default_value;
-#       bool array param_optional;
+#       int array param_flags; (stores flags form params: 1 => optional, 2 => output)
 #       hash param_mappings; (maps C param names (if specified) to the C++ index)
 #       string array possible_args_list; (a list of space separated indexes)
 #       string in_module; e.g. Gtk
@@ -75,7 +80,7 @@ sub new($$)
   $$self{param_types} = [];
   $$self{param_names} = [];
   $$self{param_default_values} = [];
-  $$self{param_optional} = [];
+  $$self{param_flags} = [];
   $$self{param_mappings} = {};
   $$self{possible_args_list} = [];
   $$self{in_module} = "";
@@ -136,7 +141,7 @@ sub new_ctor($$)
   $$self{param_types} = [];
   $$self{param_names} = [];
   $$self{param_default_values} = [];
-  $$self{param_optional} = [];
+  $$self{param_flags} = [];
   $$self{param_mappings} = {};
   $$self{possible_args_list} = [];
   $$self{in_module} = "";
@@ -186,13 +191,13 @@ sub parse_param($$)
   my $value = "";
   my $id = 0;
   my $has_value = 0;
-  my $is_optional = 0;
+  my $flags = 0;
   my $curr_param = 0;
 
   my $param_types = $$self{param_types};
   my $param_names = $$self{param_names};
   my $param_default_values = $$self{param_default_values};
-  my $param_optional = $$self{param_optional};
+  my $param_flags = $$self{param_flags};
   my $param_mappings = $$self{param_mappings};
 
   # Mappings from a C name to this C++ param defaults to empty (no mapping).
@@ -206,7 +211,7 @@ sub parse_param($$)
   # parse through argument list
   my @str = ();
   my $par = 0;
-  foreach (split(/(const )|([,=&*()])|(<[^,]*>)|(\s+)/, $line)) #special characters OR <something> OR whitespace.
+  foreach (split(/(const )|([,=&*()])|(<[^,{}]*>)|(\s+)/, $line)) #special characters OR <something> OR whitespace.
   {
     next if ( !defined($_) or $_ eq "" );
 
@@ -222,7 +227,7 @@ sub parse_param($$)
        $par--; #Decrement the number of parameters.
        next;
     }
-    elsif ( $par || /^(const )|(<[^,]*>)|([*&])|(\s+)/ ) #TODO: What's happening here?
+    elsif ( $par || /^(const )|(<[^,{}]*>)|([*&])|(\s+)/ ) #TODO: What's happening here?
     {
       push(@str, $_); #This looks like part of the type, so we store it.
       next;
@@ -252,21 +257,24 @@ sub parse_param($$)
 
       $type = string_trim($type);
 
-      # Determine if the param is optional or if a C param name should be
-      # mapped to the current C++ index (if name ends with {c_name?}). (A
-      # '.' for the name means use the C++ as the C name).
-      if ($name =~ /\{\s*(\w*|\.)\s*(\??)\s*\}$/)
+      # Determine if the param is optional, an output param or if a C param
+      # name should be mapped to the current C++ index (if name ends with
+      # {c_name>>?}). (A '.' for the name means use the C++ as the C name).
+      # '@' - Means that it is an output parameter.
+      # '?' - Means that it is an optional parameter.
+      if ($name =~ /\{\s*(\w+|\.)?\s*(>>)?\s*(\??)\s*\}$/)
       {
-        $is_optional = 1 if($2);
+        $flags = FLAG_PARAM_OPTIONAL if($3);
+        $flags |= FLAG_PARAM_OUTPUT if($2);
         $mapping = $1 if($1);
-        $name =~ s/\{\s*(\w|\.)*\??\s*\}$//;
+        $name =~ s/\{\s*(\w+|\.)?\s*(>>)?\s*\??\s*\}$//;
         $mapping = $name if($mapping eq ".");
       }
 
       push(@$param_types, $type);
       push(@$param_names, $name);
       push(@$param_default_values, $value);
-      push(@$param_optional, $is_optional);
+      push(@$param_flags, $flags);
 
       # Map from the c_name to the C++ index (no map if no name given).
       $$param_mappings{$mapping} = $curr_param if($mapping);
@@ -277,7 +285,7 @@ sub parse_param($$)
       $value = "";
       $has_value = 0;
       $name = "";
-      $is_optional = 0;
+      $flags = 0;
       $curr_param++;
 
       # Mappings from a C name to this C++ param defaults to empty (no mapping).
@@ -323,22 +331,23 @@ sub parse_param($$)
   }
 
   $type = string_trim($type);
-
-  # Determine if the param is optional or if a C param name should be
-  # mapped to the current C++ index (if name ends with {c_name?}). (A
-  # '.' for the name means use the C++ as the C name).
-  if ($name =~ /\{\s*(\w*|\.)\s*(\??)\s*\}$/)
+  
+  # Determine if the param is optional, an output param or if a C param
+  # name should be mapped to the current C++ index (if name ends with
+  # {c_name>>?}). (A '.' for the name means use the C++ as the C name).
+  if ($name =~ /\{\s*(\w+|\.)?\s*(>>)?\s*(\??)\s*\}$/)
   {
-    $is_optional = 1 if($2);
+    $flags = FLAG_PARAM_OPTIONAL if($3);
+    $flags |= FLAG_PARAM_OUTPUT if($2);
     $mapping = $1 if($1);
-    $name =~ s/\{\s*(\w*|\.)\??\s*\}$//;
+    $name =~ s/\{\s*(\w+|\.)?\s*(>>)?\??\s*\}$//;
     $mapping = $name if($mapping eq ".");
   }
 
   push(@$param_types, $type);
   push(@$param_names, $name);
   push(@$param_default_values, $value);
-  push(@$param_optional, $is_optional);
+  push(@$param_flags, $flags);
 
   # Map from the c_name to the C++ index (no map if no name given).
   $$param_mappings{$mapping} = $curr_param if($mapping);
@@ -434,7 +443,7 @@ sub possible_args_list($$)
 
   my $param_names = $$self{param_names};
   my $param_types = $$self{param_types};
-  my $param_optional = $$self{param_optional};
+  my $param_flags = $$self{param_flags};
 
   my @result = ();
 
@@ -455,7 +464,7 @@ sub possible_args_list($$)
   	push(@result, "$i");
   	# And if it's optional also add an empty string to represent that it is
   	# not added.
-  	push(@result, "") if ($$param_optional[$i]);
+  	push(@result, "") if ($$param_flags[$i] & FLAG_PARAM_OPTIONAL);
   	return @result;
   }
 
@@ -477,7 +486,7 @@ sub possible_args_list($$)
 
   # If this parameter is optional, append the remaining possibilities without
   # this param's type and name.
-  if($$param_optional[$i])
+  if($$param_flags[$i] & FLAG_PARAM_OPTIONAL)
   {
     foreach my $possibility (@remaining)
     {
diff --git a/tools/pm/Output.pm b/tools/pm/Output.pm
index 2cad5d8..a820d24 100644
--- a/tools/pm/Output.pm
+++ b/tools/pm/Output.pm
@@ -19,6 +19,7 @@
 package Output;
 use strict;
 use open IO => ":utf8";
+use Function qw(FLAG_PARAM_OPTIONAL FLAG_PARAM_OUTPUT);
 
 use DocsParser;
 
@@ -84,23 +85,23 @@ sub error
 
 sub ifdef($$)
 {
-  my ($self, $ifdef) = @_;
-  if ($ifdef)
-  {
-    $self->append("\n#ifdef $ifdef\n");
-  }
+	my ($self, $ifdef) = @_;
+	if ($ifdef)
+	{
+		$self->append("\n#ifdef $ifdef\n");
+	}
 }
 
 sub endif($$)
 {
-  my ($self, $ifdef) = @_;
-  if ($ifdef)
-  {
-    $self->append("\n#endif // $ifdef\n");
-  }
+	my ($self, $ifdef) = @_;
+	if ($ifdef)
+	{
+		$self->append("\n#endif // $ifdef\n");
+	}
 }
 
-### Convert _WRAP to a virtual 
+### 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)
@@ -162,13 +163,16 @@ sub output_wrap_vfunc_cc($$$$$$$$)
     my $refreturn = "";
     $refreturn = "refreturn" if($$objCppfunc{rettype_needs_ref});
 
+    my ($conversions, $declarations, $initializations) =
+      convert_args_cpp_to_c($objCppfunc, $objCFunc, 0, $line_num, $errthrow);
+
     my $str = sprintf("_VFUNC_CC(%s,%s,%s,%s,\`%s\',\`%s\',%s,%s,%s,%s)dnl\n",
       $$objCppfunc{name},
       $cname,
       $$objCppfunc{rettype},
       $$objCFunc{rettype},
       $objCppfunc->args_types_and_names(),
-      convert_args_cpp_to_c($objCppfunc, $objCFunc, 0, $line_num, $errthrow), #$objCppfunc->args_names_only(),
+      $conversions,
       $objCppfunc->get_is_const(),
       $refreturn,
       $ifdef,
@@ -375,14 +379,19 @@ sub output_wrap_meth($$$$$$$)
     #Implementation:
     my $str;
     if ($$objCppfunc{static}) {
-      $str = sprintf("_STATIC_METHOD(%s,%s,`%s\',%s,\`%s\',\`%s\',%s,%s,%s,%s,%s,%s,%s)dnl\n",
+      my ($conversions, $declarations, $initializations) =
+        convert_args_cpp_to_c($objCppfunc, $objCDefsFunc, 1, $line_num,
+        $errthrow, $arg_list); #1 means it's static, so it has 'object'.
+
+      $str = sprintf("_STATIC_METHOD(%s,%s,\`%s\',%s,\`%s\',\`%s\',\`%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($arg_list),
-        convert_args_cpp_to_c($objCppfunc, $objCDefsFunc, 1, $line_num,
-          $errthrow, $arg_list), #1 means it's static, so it has 'object'.
+        $declarations,
+        $conversions,
+        $initializations,
         $refneeded,
         $errthrow,
         $deprecated,
@@ -392,14 +401,19 @@ sub output_wrap_meth($$$$$$$)
         $line_num
         );
     } else {
-      $str = sprintf("_METHOD(%s,%s,`%s\',%s,\`%s\',\`%s\',%s,%s,%s,%s,%s,\`%s\',%s,%s,%s,%s)dnl\n",
+      my ($conversions, $declarations, $initializations) =
+        convert_args_cpp_to_c($objCppfunc, $objCDefsFunc, 0, $line_num,
+        $errthrow, $arg_list);
+
+      $str = sprintf("_METHOD(%s,%s,\`%s\',%s,\`%s\',\`%s\',\`%s\',\`%s\',%s,%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($arg_list),
-        convert_args_cpp_to_c($objCppfunc, $objCDefsFunc, 0, $line_num,
-          $errthrow, $arg_list),
+        $declarations,
+        $conversions,
+        $initializations,
         $$objCppfunc{const},
         $refneeded,
         $errthrow,
@@ -824,8 +838,12 @@ sub remove_temp_files($)
 
 
 
-# procedure for generating CONVERT macros
-# $string convert_args_cpp_to_c($objCppfunc, $objCDefsFunc, $static, $wrap_line_number,$automatic_error, $index = 0)
+# procedure for generating CONVERT macros, C declarations (for C output
+# variables), and INITIALIZE macros (to set the corresponding C++ parameters
+# from the C output parameters) for the specified argument list
+# (string, string, string) convert_args_cpp_to_c($objCppfunc, $objCDefsFunc, $static, $wrap_line_number,$automatic_error, $index = 0)
+# The return is an array of 3 strings: The _CONVERT macros, the C declarations
+# and the _INITIALIZE macros.
 # The optional index specifies which arg list out of the possible combination
 # of arguments based on whether any arguments are optional. index = 0 ==> all
 # the arguments.
@@ -838,12 +856,14 @@ sub convert_args_cpp_to_c($$$$$)
 
   my $cpp_param_names = $$objCppfunc{param_names};
   my $cpp_param_types = $$objCppfunc{param_types};
-  my $cpp_param_optional = $$objCppfunc{param_optional};
+  my $cpp_param_flags = $$objCppfunc{param_flags};
   my $cpp_param_mappings = $$objCppfunc{param_mappings};
   my $c_param_types = $$objCDefsFunc{param_types};
   my $c_param_names = $$objCDefsFunc{param_names};
 
-  my @result;
+  my @conversions;
+  my @declarations;
+  my @initializations;
 
   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.
@@ -871,7 +891,7 @@ sub convert_args_cpp_to_c($$$$$)
     $num_cpp_args++;
     $cpp_param_names = [ {$cpp_param_names},"gerror"];
     $cpp_param_types = [ {$cpp_param_types},"GError*&"];
-    $cpp_param_optional = [ {$cpp_param_optional}, 0];
+    $cpp_param_flags = [ {$cpp_param_flags}, 0];
 
     # Map from the C gerror param name to the newly added C++ param index.
     # The correct C++ index to map to (from the C name) depends on if there
@@ -889,10 +909,10 @@ sub convert_args_cpp_to_c($$$$$)
     $objCppfunc->dump();
     $objCDefsFunc->dump();
 
-    return "";
+    return ("", "", "");
   }
 
-  # If there is an output variable it must be processed so re-increment (now)
+  # If there is an output parameter it must be processed so re-increment (now)
   # the number of C++ arguments.
   $num_cpp_args++ if($has_output_param);
 
@@ -932,18 +952,40 @@ sub convert_args_cpp_to_c($$$$$)
       # If the C++ index is not found in the list of desired parameters, pass
       # NULL to the C func unless the param is not optional (applies to a
       # possibly added GError parameter).
-      if ($$cpp_param_optional[$cpp_param_index])
+      if (($$cpp_param_flags[$cpp_param_index] & FLAG_PARAM_OPTIONAL))
       {
-        push(@result, "0");
+        push(@conversions, "0");
         next;
       }
     }
 
+    if ($$cpp_param_flags[$cpp_param_index] & FLAG_PARAM_OUTPUT)
+    {
+      # Get a generic name for the C output parameter name.
+      my $cOutputParamName = "g_" . $$c_param_names[$iCParam];
+      my $cOutputParamType = $cParamType;
+      # Remove a possible final '*' from the output parameter type because it
+      # will be passed by C reference (&name).
+      $cOutputParamType =~ s/\*$//;
+
+      push(@declarations, "  $cOutputParamType $cOutputParamName = 0;");
+
+      push(@conversions, "&" . $cOutputParamName);
+
+      push(@initializations, sprintf("  _INITIALIZE(\`%s\',%s,%s,%s,%s);",
+                    $cppParamType,
+                    $cOutputParamType,
+                    $cppParamName,
+                    $cOutputParamName,
+                    $wrap_line_number));
+      next;
+    }
+
     if ($cppParamType ne $cParamType) #If a type conversion is needed.
     {
 
 
-      push(@result, sprintf("_CONVERT(%s,%s,%s,%s)",
+      push(@conversions, sprintf("_CONVERT(%s,%s,%s,%s)",
                   $cppParamType,
                   $cParamType,
                   $cppParamName,
@@ -951,11 +993,12 @@ sub convert_args_cpp_to_c($$$$$)
     }
     else
     {
-      push(@result, $cppParamName);
+      push(@conversions, $cppParamName);
     }
   }
 
-  return join(", ", @result);
+  return ( join(", ", @conversions), join("\n  ", @declarations),
+    join("\n  ", @initializations) );
 }
 
 # procedure for generating CONVERT macros
@@ -1039,7 +1082,7 @@ sub get_ctor_properties($$$$$)
 
   my $cpp_param_names = $$objCppfunc{param_names};
   my $cpp_param_types = $$objCppfunc{param_types};
-  my $cpp_param_optional = $$objCppfunc{param_optional};
+  my $cpp_param_flags = $$objCppfunc{param_flags};
   my $cpp_param_mappings = $$objCppfunc{param_mappings};
   my $c_param_types = $$objCDefsFunc{param_types};
   my $c_param_names = $$objCDefsFunc{param_names};
@@ -1084,7 +1127,7 @@ sub get_ctor_properties($$$$$)
     {
       # If the C++ index is not found in the list of desired parameters, pass
       # NULL to the C func unless the param is not optional.
-      if ($$cpp_param_optional[$cpp_param_index])
+      if (~($$cpp_param_flags[$cpp_param_index] & FLAG_PARAM_OPTIONAL))
       {
         push(@result, "0");
         next;
@@ -1131,8 +1174,8 @@ sub output_implements_interface($$)
   my ($self, $interface, $ifdef) = @_;
 
   my $str = sprintf("_IMPLEMENTS_INTERFACE_CC(%s, %s)dnl\n",
-      $interface,
-      $ifdef);
+  	$interface,
+  	$ifdef);
 
   $self->append($str);
 }
diff --git a/tools/pm/WrapParser.pm b/tools/pm/WrapParser.pm
index 3841fee..e55479b 100644
--- a/tools/pm/WrapParser.pm
+++ b/tools/pm/WrapParser.pm
@@ -681,16 +681,25 @@ sub string_split_commas($)
 
   my @out;
   my $level = 0;
+  my $in_braces = 0;
   my $str = "";
-  my @in = split(/([,()<>])/, $in);
+  my @in = split(/([,()<>{}])/, $in);
 
   while ($#in > -1)
     {
       my $t = shift @in;
 
       next if ($t eq "");
+
+      $in_braces++ if ($t eq "{");
+      $in_braces-- if ($t eq "}");
+
       $level++ if ($t eq "(" or $t eq "<");
-      $level-- if ($t eq ")" or $t eq ">");
+
+      # In the case of a '>' decrease the level if it is not in a {...}
+      # because if it is found in a {...} it is most likely indicating that
+      # a parameter in a method declaration is an output param. 
+      $level-- if ($t eq ")" or ($t eq ">" && !$in_braces));
 
       # skip , inside functions  Ie.  void (*)(int,int)
       if ( ($t eq ",") && !$level) 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]