* xpidl2cs.pl: Generates c# interfaces from xpcom (mozilla)
authorAndreia Gaita <avidigal@novell.com>
Fri, 28 Dec 2007 22:42:29 +0000 (22:42 -0000)
committerAndreia Gaita <avidigal@novell.com>
Fri, 28 Dec 2007 22:42:29 +0000 (22:42 -0000)
idl files.
From a given idl file, generates the corresponding cs file,
and recursively generates all the parents up to nsISupports.
Also generates all related interfaces that are used on methods
and properties.

2007-12-28  Andreia Gaita  <avidigal@novell.com>

svn path=/trunk/mcs/; revision=92003

mcs/class/Mono.Mozilla/tools/xpidl2cs/ChangeLog [new file with mode: 0644]
mcs/class/Mono.Mozilla/tools/xpidl2cs/xpidl2cs.pl [new file with mode: 0755]

diff --git a/mcs/class/Mono.Mozilla/tools/xpidl2cs/ChangeLog b/mcs/class/Mono.Mozilla/tools/xpidl2cs/ChangeLog
new file mode 100644 (file)
index 0000000..1a1ee09
--- /dev/null
@@ -0,0 +1,8 @@
+2007-12-28  Andreia Gaita  <avidigal@novell.com>
+
+       * xpidl2cs.pl: Generates c# interfaces from xpcom (mozilla) 
+       idl files.
+       From a given idl file, generates the corresponding cs file,
+       and recursively generates all the parents up to nsISupports. 
+       Also generates all related interfaces that are used on methods 
+       and properties.
diff --git a/mcs/class/Mono.Mozilla/tools/xpidl2cs/xpidl2cs.pl b/mcs/class/Mono.Mozilla/tools/xpidl2cs/xpidl2cs.pl
new file mode 100755 (executable)
index 0000000..cb58408
--- /dev/null
@@ -0,0 +1,417 @@
+#!/usr/bin/perl
+#
+# xpidl2cs.pl : Generates C# interfaces from idl
+#
+# Author: Andreia Gaita <shana.ufie@gmail.com>
+#
+# Copyright (c) 2007 Novell, Inc.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of version 2 of the GNU General Public
+# License as published by the Free Software Foundation.
+#
+# 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.
+##############################################################
+
+open FILE, '<', @ARGV or die "Can't open file @ARGV";
+
+my %interface = (
+                properties => (), 
+                items => "", 
+                uuid => "", 
+                class => "", 
+                parent => ""
+                );
+my %properties;
+my %methods;
+
+my %types;
+$types{"short"} = {name => "short", out => "out", marshal => ""};
+$types{"unsigned,short"} = {name => "ushort", out => "out", marshal => ""};
+$types{"int"} = {name => "int", out => "out", marshal => ""};
+$types{"nsresult"} = {name => "int", out => "out", marshal => ""};
+$types{"unsigned,int"} = {name => "uint", out => "out", marshal => ""};
+$types{"PRUint32"} = {name => "UInt32", out => "out", marshal => ""};
+$types{"long"} = {name => "int", out => "out", marshal => ""};
+$types{"unsigned,long"} = {name => "uint", out => "out", marshal => ""};
+$types{"float"} = {name => "float", out => "out", marshal => ""};
+$types{"boolean"} = {name => "bool", out => "out", marshal => ""};
+$types{"PRBool"} = {name => "bool", out => "out", marshal => ""};
+$types{"void"} = {name => "", out => "", marshal => ""};
+$types{"DOMString"} = {name => "HandleRef", out => "", marshal => ""};
+$types{"nsCIDRef"} = {name => "Guid", out => "out", marshal => "[MarshalAs (UnmanagedType.LPStruct)] "};
+$types{"nsIIDRef"} = {name => "Guid", out => "out", marshal => "[MarshalAs (UnmanagedType.LPStruct)] "};
+$types{"Guid"} = {name => "Guid", out => "out", marshal => "[MarshalAs (UnmanagedType.LPStruct)] "};
+$types{"string"} = {name => "string", out => "", marshal => "[MarshalAs (UnmanagedType.LPStr)] "};
+$types{"charPtr"} = {name => "StringBuilder", out => "", marshal => ""};
+$types{"voidPtr"} = {name => "IntPtr", out => "", marshal => ""};
+$types{"others"} = {name => "", out => "out", marshal => "[MarshalAs (UnmanagedType.Interface)] "};
+
+
+my %dependents;
+
+sub parse_parent {
+    my $x = shift;
+
+ #   print "perl xpidlimport.pl $x.idl\n";
+    `perl xpidlimport.pl $x.idl`;
+
+    open my $f, '<', "$x.cs";
+    my $start = 0;
+    my $out;
+    while (my $line = <$f>) {
+       chop $line;
+       if (!$start) {
+           if ($line =~ /#region/) {
+               $start = 1;
+               $out .= $line . "\n";
+           }
+       }
+       elsif ($line =~ /\}/) {
+           last;
+       }
+       else {
+           $out .= $line . "\n";
+       }
+    }
+
+    return $out;
+}
+
+sub has_setter {
+    my $x = shift;
+    return !$properties{$x}->{"setter"};
+}
+
+sub get_type {
+    my $x = shift;
+    if (exists $types{$x}) {
+       return $types{$x}->{"name"};
+    }
+    return $x;
+}
+
+sub get_out {
+    my $x = shift;
+    if (exists $types{$x}) {
+       return $types{$x}->{"out"};
+    }
+    return $types{"others"}->{"out"};
+}
+
+sub get_marshal {
+    my $x = shift;
+    if (exists $types{$x}) {
+       return $types{$x}->{"marshal"};
+    }
+    return $types{"others"}->{"marshal"};
+}
+
+sub is_property {
+    my $x = shift;
+    return (exists $properties{$x});
+}
+
+sub add_external {
+    my $x = shift;
+    if ($x !~ /nsISupports/ && !exists $types{$x} && !exists $dependents{$x}) {
+       $dependents{$x} = $x;
+    }
+#    print "add_external $x\n";
+}
+
+sub get_params {
+    my $x = shift;
+    my $ret = '';
+    my %list;
+    my @params = split /,/, $methods{$x}->{"params"};
+
+#    print "params:@params:\n";
+    for my $param (@params) {
+       my $marshal;
+       my $name;
+       my $type;
+       my $out;
+       my $isout;
+
+
+#      print "param:$param:\n";
+       my @p = split (" ", $param);
+
+# need to backtrack to a previous parameter defined by iid_is(name) and 
+# replace the type of this one with that. who the $%#@ came up with this idea? le sigh.
+
+       if (@p[0] =~ m/iid_is/) {
+           shift @p;
+           $name = @p[0];
+           $name =~ s/ //;
+           $type = $list{$name}->{"type"};
+           $marshal = $list{$name}->{"marshal"};
+           shift @p unless @p == 3;
+       }
+
+       shift @p unless @p[0] =~ /(in|out)/;
+
+       if (@p[0] =~ m/out/) {
+           $isout = 1;
+       }
+       shift @p;
+
+       if (!$type) {
+           $type = join ",", @p[0..@p-2];
+           $type=~s/\[.*\],//;
+       }
+
+       $out = &get_out($type) if $isout;
+
+
+
+       $type = &get_type (@p[0]) unless $type;
+       $marshal = &get_marshal ($type) unless $marshal;
+       $name = @p[1];
+
+#      print "=======$marshal===$type======\n";
+
+       $list{$name} = {
+           name => $name,
+           type => $type,
+           marshal => $marshal,
+           out => $out
+       };
+
+       &add_external ($type);
+
+       $ret .= "\n\t\t\t\t$marshal $out $type $name,";
+    }
+
+    if (&get_type ($methods{$x}->{"type"}) ne "") {
+       $type = $methods{$x}->{"type"};
+       $type =~ s/\[.*\],//;
+       $marshal = &get_marshal ($type);
+
+       $ret .= "$marshal ";
+       $ret .= &get_out($type);
+       $ret .= " " . &get_type ($type);
+       $ret .= " ret";
+       &add_external ($type);
+    }
+    $ret =~ s/,$//;
+    return $ret;
+}
+
+sub parse_file {
+    my $method = 0;
+    my $mname = '';
+    my $mtype = '';
+    my $mparams = '';
+    my $start = 0;
+
+    while (my $line = <FILE>) {
+       chop $line;
+
+       next if !$start && $line !~ /\[scriptable/;
+       $start = 1;
+       last if $start && $line =~ /\};/;
+       
+       if (index($line, "*") == -1 && index ($line, "//") == -1 && index ($line, "#include") == -1) {
+           
+           if (index ($line, "uuid") != -1) {
+               my $uuid = $line;
+               $uuid =~ s/\[.*uuid\((.*)\)\]/\1/;
+               $interface->{"uuid"} = $uuid;
+           }
+
+           elsif (index($line, "interface") != -1) {
+               my $class = $line;
+               $class =~ s/interface ([^\:|\s]+)\s:\s+(.*)/\1/;
+#              print "\t\t==============$class\n";
+               my $parent = $line;
+               $parent =~ s/interface ([^\:|\s]+)\s:\s+(.*)/\2/;
+               $interface->{"class"} = $class;
+               $interface->{"parent"} = $parent;
+
+           }
+           elsif (index ($line, "const") != -1) {
+           }
+           elsif (index ($line, "attribute") != -1) {
+               my $att = substr($line, index($line, "attribute") + 10);
+
+               my @atts = split / /, $att;
+
+               my $name = pop @atts;
+               $name =~ s/;//;
+#          print $name . "\n";
+               my @nospaces = grep /[^ ]/, @atts;
+               my $type = join ",", @nospaces;
+
+               my $setter = 0;
+               if (index ($line, "readonly") != -1) {
+                   $setter = 1;
+               }
+#            print $type . "\n";
+               $properties{$name} = {type => $type, setter => $setter};
+               $interface->{"items"} .= $name . ",";
+           }
+           elsif ($line !~ m/[{|}]/ && $line =~ m/./) {
+#          print $line . "\n";
+               if (!$method) {
+                   $method = 1;
+                   my  $m = substr($line, 0, index($line, "("));
+                   my @atts = split / /, $m;
+
+#              print $m;
+                   $mname = pop @atts;
+#              print "name=$mname\n";
+                   my @nospaces = grep /[^ ]/, @atts;
+                   $mtype = join ",", @nospaces;
+#              print "type=$mtype\n";
+                   $mparams .= substr($line, index($line, "(") + 1);
+                   $mparams =~ s/;//;
+                   $mparams =~ s/\)//;
+
+                   @atts = split / /, $mparams;
+                   @nospaces = grep /[^ ]/, @atts;
+                   $mparams = join " ", @nospaces;
+
+               }
+               elsif (index ($line, "raises") == -1) {
+                   $mparams .= $line;
+                   $mparams =~ s/;//;
+                   $mparams =~ s/\)//;
+                   my @atts = split / /, $mparams;
+                   my @nospaces = grep /[^ ]/, @atts;
+                   $mparams = join " ", @nospaces;
+               }
+               if (index ($line, ";") != -1) {
+                   $method = 0;
+                   $mparams =~ s/\[([^\]]+),([^\]]+)\]/\1 \2/;
+                   $mparams =~ s/\(/ /;
+                   $mparams =~ s/\)//;
+                   $mparams =~ s/retval//;
+
+                   $methods{$mname} = {type => $mtype, params => $mparams};
+                   $interface->{"items"} .= $mname . ",";
+#                  print "params=>$mparams\n";
+                   $mname = '';
+                   $mtype = '';
+                   $mparams = '';
+               }
+           }   
+       }
+    }
+}
+
+sub output {
+
+    my $name = $interface->{"class"};
+    print "$name.cs\n";
+    open X, ">$name.cs";
+    print X "// THIS FILE AUTOMATICALLY GENERATED BY xpidlimport.pl\n";
+    print X "// EDITING IS PROBABLY UNWISE\n";
+    print X "// Permission is hereby granted, free of charge, to any person obtaining\n";
+    print X "// a copy of this software and associated documentation files (the\n";
+    print X "// \"Software\"), to deal in the Software without restriction, including\n";
+    print X "// without limitation the rights to use, copy, modify, merge, publish,\n";
+    print X "// distribute, sublicense, and/or sell copies of the Software, and to\n";
+    print X "// permit persons to whom the Software is furnished to do so, subject to\n";
+    print X "// the following conditions:\n";
+    print X "// \n";
+    print X "// The above copyright notice and this permission notice shall be\n";
+    print X "// included in all copies or substantial portions of the Software.\n";
+    print X "// \n";
+    print X "// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n";
+    print X "// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n";
+    print X "// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n";
+    print X "// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\n";
+    print X "// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\n";
+    print X "// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\n";
+    print X "// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n";
+    print X "//\n";
+    print X "// Copyright (c) 2007 Novell, Inc.\n";
+    print X "//\n";
+    print X "// Authors:\n";
+    print X "//        Andreia Gaita (avidigal\@novell.com)\n";
+    print X "//\n";
+    print X "\n";
+    print X "using System;\n";
+    print X "using System.Runtime.InteropServices;\n";
+    print X "using System.Runtime.CompilerServices;\n";
+    print X "using System.Text;\n";
+    print X "\n";
+    print X "namespace Mono.Mozilla {\n";
+    print X "\n";
+
+    my $uuid = $interface->{"uuid"};
+    print X "\t[Guid (\"$uuid\")]\n";
+    print X "\t[InterfaceType (ComInterfaceType.InterfaceIsIUnknown)]\n";
+    print X "\t[ComImport ()]\n";
+    print X "\tinternal interface $name {\n";
+
+
+    if ($interface->{"parent"} ne "nsISupports") {
+       print X &parse_parent ($interface->{"parent"});
+    }
+    print X "\n";
+    print X "#region $name\n";
+
+    my @items = split ",", $interface->{"items"};
+    for my $item (@items) {
+
+       print X "\t\t[PreserveSigAttribute]\n";
+       print X "\t\t[MethodImpl (MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]\n";
+
+       if (&is_property ($item)) {
+           my $marshal = &get_marshal($properties{$item}->{"type"});
+           my $out = &get_out($properties{$item}->{"type"});
+           my $type = &get_type ($properties{$item}->{"type"});
+           my $name = ucfirst($item);
+
+           &add_external ($properties{$item}->{"type"});
+## getter
+
+           print X "\t\tint get$name ($marshal $out $type ret);\n";
+           print X "\n";
+
+## setter
+           if (&has_setter($item)) {
+               print X "\t\t[PreserveSigAttribute]\n";
+               print X "\t\t[MethodImpl (MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]\n";
+               print X "\t\tint set$name ($marshal $type value);\n";
+               print X "\n";
+           }
+
+       } else {
+           print X "\t\t";
+           print X "int " . $item . " (";
+           print X &get_params($item);
+           print X ");";
+           print X "\n\n";
+       }
+    }
+    print X "#endregion\n";
+    print X "\t}\n";
+    print X "}\n";
+    close X;
+}
+
+sub generate_dependents {
+    for my $file (keys %dependents) {
+       print "generating $file\n";
+       if (! (-e "$file.cs") && -e "$file.idl") {
+           my $ret = `perl xpidlimport.pl $file.idl`;
+           print "\n$ret";
+       }
+    }
+}
+
+&parse_file ();
+&output ();
+&generate_dependents ();