From eea6465cf2d04b7c019f7aa304e54bf0d5557ad0 Mon Sep 17 00:00:00 2001 From: Rachel Hestilow Date: Mon, 10 Jun 2002 12:34:09 +0000 Subject: [PATCH] 2002-06-09 Rachel Hestilow * generator/GenBase.cs: new method AppendCustom, moved from ObjectGen. * generator/BoxedGen.cs, ObjectGen.cs, StructGen.cs: Call AppendCustom in Generate (); * generator/Method.cs, Parameters.cs: Add support for "out" parameters. Additionally, output an accessor instead of a regular method if it is an accessor-style function (ie GetStartIter). * generator/Property.cs: Add additional cast to Boxed, if necessary. * glue/textiter.c: New constructor for GtkTextIter. * glue/Makefile.am: Add textiter.c, build with Gtk+ cflags. * configure.in: Check for Gtk+ cflags. * parser/Metadata.pm, Gtk.metadata: Added. * parser/gapi2xml.pl: Call Metadata::fixup on the document. Also work around gtk's screwy boxed type name registration (GtkFoo -> GtkTypeFoo). * gtk/TextIter.custom: Added. svn path=/trunk/gtk-sharp/; revision=5205 --- ChangeLog | 18 ++++ configure.in | 20 ++--- generator/BoxedGen.cs | 1 + generator/GenBase.cs | 12 +++ generator/Method.cs | 31 +++++-- generator/ObjectGen.cs | 10 +-- generator/Parameters.cs | 74 +++++++++++++++- generator/Property.cs | 2 + generator/StructGen.cs | 2 + generator/gtkapi.xml | 2 +- glue/Makefile.am | 3 +- glue/textiter.c | 17 ++++ gtk/TextIter.custom | 30 +++++++ parser/GAPI/Metadata.pm | 190 ++++++++++++++++++++++++++++++++++++++++ parser/Gtk.metadata | 31 +++++++ parser/Metadata.pm | 190 ++++++++++++++++++++++++++++++++++++++++ parser/build.pl | 16 ++++ parser/gapi2xml.pl | 9 +- sources/Gtk.metadata | 31 +++++++ 19 files changed, 660 insertions(+), 29 deletions(-) create mode 100644 glue/textiter.c create mode 100755 gtk/TextIter.custom create mode 100644 parser/GAPI/Metadata.pm create mode 100644 parser/Gtk.metadata create mode 100644 parser/Metadata.pm create mode 100755 parser/build.pl create mode 100644 sources/Gtk.metadata diff --git a/ChangeLog b/ChangeLog index fccf36a63..e5775cf36 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,21 @@ +2002-06-09 Rachel Hestilow + + * generator/GenBase.cs: new method AppendCustom, moved from ObjectGen. + * generator/BoxedGen.cs, ObjectGen.cs, StructGen.cs: + Call AppendCustom in Generate (); + * generator/Method.cs, Parameters.cs: Add support for "out" + parameters. Additionally, output an accessor instead of a + regular method if it is an accessor-style function (ie GetStartIter). + * generator/Property.cs: Add additional cast to Boxed, if necessary. + * glue/textiter.c: New constructor for GtkTextIter. + * glue/Makefile.am: Add textiter.c, build with Gtk+ cflags. + * configure.in: Check for Gtk+ cflags. + * parser/Metadata.pm, Gtk.metadata: Added. + * parser/gapi2xml.pl: Call Metadata::fixup on the document. + Also work around gtk's screwy boxed type name registration + (GtkFoo -> GtkTypeFoo). + * gtk/TextIter.custom: Added. + 2002-06-06 Mike Kestner * glib/Timeout.cs : new Timeout class with Add() and diff --git a/configure.in b/configure.in index b1b23e271..3c5fdbd24 100644 --- a/configure.in +++ b/configure.in @@ -39,10 +39,10 @@ fi dnl for use on the build system dnl pkg-config is stupid -BUILD_GLIB_CFLAGS=`$PKG_CONFIG --cflags glib-2.0` -BUILD_GLIB_LIBS=`$PKG_CONFIG --libs glib-2.0` -AC_SUBST(BUILD_GLIB_CFLAGS) -AC_SUBST(BUILD_GLIB_LIBS) +BUILD_GTK_CFLAGS=`$PKG_CONFIG --cflags gtk+-2.0` +BUILD_GTK_LIBS=`$PKG_CONFIG --libs gtk+-2.0` +AC_SUBST(BUILD_GTK_CFLAGS) +AC_SUBST(BUILD_GTK_LIBS) PKG_PATH= AC_ARG_WITH(crosspkgdir, [ --with-crosspkgdir=/path/to/pkg-config/dir], @@ -58,17 +58,17 @@ AC_ARG_WITH(crosspkgdir, [ --with-crosspkgdir=/path/to/pkg-config/dir], ) ## Versions of dependencies -GLIB_REQUIRED_VERSION=2.0.0 +GTK_REQUIRED_VERSION=2.0.0 -PKG_CHECK_MODULES(BASE_DEPENDENCIES, glib-2.0 >= $GLIB_REQUIRED_VERSION) +PKG_CHECK_MODULES(BASE_DEPENDENCIES, gtk+-2.0 >= $GTK_REQUIRED_VERSION) -GLIB_CFLAGS=`$PKG_CONFIG --cflags glib-2.0` -GLIB_LIBS=`$PKG_CONFIG --libs glib-2.0` +GTK_CFLAGS=`$PKG_CONFIG --cflags gtk+-2.0` +GTK_LIBS=`$PKG_CONFIG --libs gtk+-2.0` GMODULE_CFLAGS=`$PKG_CONFIG --cflags gmodule-2.0` GMODULE_LIBS=`$PKG_CONFIG --libs gmodule-2.0` -AC_SUBST(GLIB_CFLAGS) -AC_SUBST(GLIB_LIBS) +AC_SUBST(GTK_CFLAGS) +AC_SUBST(GTK_LIBS) AC_SUBST(GMODULE_CFLAGS) AC_SUBST(GMODULE_LIBS) diff --git a/generator/BoxedGen.cs b/generator/BoxedGen.cs index ecae75717..bc9c31a81 100644 --- a/generator/BoxedGen.cs +++ b/generator/BoxedGen.cs @@ -97,6 +97,7 @@ namespace GtkSharp.Generation { } } + GenBase.AppendCustom(ns, Name, sw); sw.WriteLine ("\t}"); sw.WriteLine (); sw.WriteLine ("}"); diff --git a/generator/GenBase.cs b/generator/GenBase.cs index 8c468888f..045867aab 100644 --- a/generator/GenBase.cs +++ b/generator/GenBase.cs @@ -59,6 +59,7 @@ namespace GtkSharp.Generation { Directory.CreateDirectory(dir); } String filename = dir + sep + Name + ".cs"; + Console.WriteLine ("creating " + filename); FileStream stream = new FileStream (filename, FileMode.Create, FileAccess.Write); StreamWriter sw = new StreamWriter (stream); @@ -80,6 +81,17 @@ namespace GtkSharp.Generation { sw.Close(); } + public static void AppendCustom (string ns, string name, StreamWriter sw) + { + char sep = Path.DirectorySeparatorChar; + string custom = ".." + sep + ns.ToLower() + sep + name + ".custom"; + if (File.Exists(custom)) { + FileStream custstream = new FileStream(custom, FileMode.Open, FileAccess.Read); + StreamReader sr = new StreamReader(custstream); + sw.WriteLine (sr.ReadToEnd ()); + sr.Close (); + } + } } } diff --git a/generator/Method.cs b/generator/Method.cs index 338c1980a..1dd0ba982 100644 --- a/generator/Method.cs +++ b/generator/Method.cs @@ -103,7 +103,7 @@ namespace GtkSharp.Generation { public void Generate (StreamWriter sw) { string sig, isig, call; - + if (parms != null) { sig = "(" + parms.Signature + ")"; isig = "(IntPtr raw, " + parms.ImportSig + ");"; @@ -130,18 +130,37 @@ namespace GtkSharp.Generation { sw.WriteLine(); sw.Write("\t\tpublic "); - if (elem.HasAttribute("new_flag")) - sw.Write("new "); - sw.WriteLine(s_ret + " " + Name + sig); + bool is_get = (parms != null && parms.IsAccessor && Name.Substring(0, 3) == "Get"); + if (is_get) { + s_ret = parms.AccessorReturnType; + sw.Write(s_ret); + sw.Write(" "); + sw.Write(Name.Substring (3)); + sw.Write(" { get"); + } else { + if (elem.HasAttribute("new_flag")) + sw.Write("new "); + sw.WriteLine(s_ret + " " + Name + sig); + } sw.WriteLine("\t\t{"); + if (parms != null) + parms.Initialize(sw, is_get); sw.Write("\t\t\t"); - if (m_ret == "void") { + if (is_get || m_ret == "void") { sw.WriteLine(cname + call + ";"); } else { sw.WriteLine("return " + SymbolTable.FromNative(rettype, cname + call) + ";"); } + + if (is_get) + sw.WriteLine ("\t\t\treturn " + parms.AccessorName + ";"); - sw.WriteLine("\t\t}"); + + sw.Write("\t\t}"); + if (is_get) + sw.Write(" }"); + + sw.WriteLine(); sw.WriteLine(); Statistics.MethodCount++; diff --git a/generator/ObjectGen.cs b/generator/ObjectGen.cs index 0dba5c5b4..65b043af0 100644 --- a/generator/ObjectGen.cs +++ b/generator/ObjectGen.cs @@ -96,15 +96,7 @@ namespace GtkSharp.Generation { GenProperties (sw); GenSignals (sw); GenMethods (sw); - - char sep = Path.DirectorySeparatorChar; - string custom = ".." + sep + Namespace.ToLower() + sep + Name + ".custom"; - if (File.Exists(custom)) { - FileStream custstream = new FileStream (custom, FileMode.Open, FileAccess.Read); - StreamReader sr = new StreamReader (custstream); - sw.WriteLine (sr.ReadToEnd ()); - sr.Close (); - } + AppendCustom(Namespace, Name, sw); sw.WriteLine ("\t}"); diff --git a/generator/Parameters.cs b/generator/Parameters.cs index e36531047..92eb00890 100644 --- a/generator/Parameters.cs +++ b/generator/Parameters.cs @@ -7,6 +7,7 @@ namespace GtkSharp.Generation { using System; + using System.IO; using System.Xml; public class Parameters { @@ -83,6 +84,10 @@ namespace GtkSharp.Generation { need_sep = true; } + if (p_elem.HasAttribute("pass_as")) { + signature += p_elem.GetAttribute("pass_as") + " "; + } + signature += (cs_type + " " + name); signature_types += cs_type; call_string += call_parm; @@ -91,7 +96,74 @@ namespace GtkSharp.Generation { return true; } - + + public void Initialize (StreamWriter sw, bool is_get) + { + foreach (XmlNode parm in elem.ChildNodes) { + if (parm.Name != "parameter") { + continue; + } + + XmlElement p_elem = (XmlElement) parm; + + string type = SymbolTable.GetCSType(p_elem.GetAttribute ("type")); + string name = MangleName(p_elem.GetAttribute("name")); + if (is_get) { + sw.WriteLine ("\t\t\t" + type + " " + name + ";"); + } + + if (is_get || (p_elem.HasAttribute("pass_as") && p_elem.GetAttribute ("pass_as") == "out")) { + sw.WriteLine("\t\t\t" + name + " = new " + type + "();"); + } + } + + } + + public bool IsAccessor { + get { + int length = 0; + string pass_as; + foreach (XmlNode parm in elem.ChildNodes) { + if (parm.Name != "parameter") { + continue; + } + + XmlElement p_elem = (XmlElement) parm; + length++; + if (length > 1) + return false; + if (p_elem.HasAttribute("pass_as")) + pass_as = p_elem.GetAttribute("pass_as"); + } + + return (length == 1 && pass_as == "out"); + } + } + + public string AccessorReturnType { + get { + foreach (XmlNode parm in elem.ChildNodes) { + if (parm.Name != "parameter") + continue; + XmlElement p_elem = (XmlElement) parm; + return SymbolTable.GetCSType(p_elem.GetAttribute ("type")); + } + return null; + } + } + + public string AccessorName { + get { + foreach (XmlNode parm in elem.ChildNodes) { + if (parm.Name != "parameter") + continue; + XmlElement p_elem = (XmlElement) parm; + return MangleName (p_elem.GetAttribute("name")); + } + return null; + } + } + private string MangleName(string name) { switch (name) { diff --git a/generator/Property.cs b/generator/Property.cs index 00a6e0bec..b78dbacf3 100644 --- a/generator/Property.cs +++ b/generator/Property.cs @@ -63,6 +63,8 @@ namespace GtkSharp.Generation { return; } else if (SymbolTable.IsObject(c_type)) { v_type = "GLib.Object"; + } else if (SymbolTable.IsBoxed (c_type)) { + v_type = "GLib.Boxed"; } if (elem.HasAttribute("construct-only") && !elem.HasAttribute("readable")) { diff --git a/generator/StructGen.cs b/generator/StructGen.cs index a635f3d41..5fd386249 100644 --- a/generator/StructGen.cs +++ b/generator/StructGen.cs @@ -87,6 +87,8 @@ namespace GtkSharp.Generation { } } + GenBase.AppendCustom(ns, Name, sw); + sw.WriteLine ("\t}"); sw.WriteLine (); sw.WriteLine ("}"); diff --git a/generator/gtkapi.xml b/generator/gtkapi.xml index 8f8a2fa43..49300e81c 100644 --- a/generator/gtkapi.xml +++ b/generator/gtkapi.xml @@ -1,2 +1,2 @@ - + diff --git a/glue/Makefile.am b/glue/Makefile.am index afa83423c..58999a0f3 100644 --- a/glue/Makefile.am +++ b/glue/Makefile.am @@ -1,9 +1,10 @@ lib_LTLIBRARIES = libgtksharpglue.la -INCLUDES = $(GLIB_CFLAGS) -I$(top_srcdir) +INCLUDES = $(GTK_CFLAGS) -I$(top_srcdir) libgtksharpglue_la_SOURCES = \ value.c \ + textiter.c \ # libgtksharpglue.dll: $(libgtksharpglue_la_OBJECTS) libgtksharpglue.rc libgtksharpglue.def diff --git a/glue/textiter.c b/glue/textiter.c new file mode 100644 index 000000000..22c880afe --- /dev/null +++ b/glue/textiter.c @@ -0,0 +1,17 @@ +/* textiter.c : Glue to allocate GtkTextIters on the heap. + * + * Author: Rachel Hestilow + * + * 2002 Rachel Hestilow, Mike Kestner + */ + +#include + +GtkTextIter* +gtksharp_text_iter_create (void) +{ + GtkTextIter *iter = g_new0 (GtkTextIter, 1); + return iter; +} + + diff --git a/gtk/TextIter.custom b/gtk/TextIter.custom new file mode 100755 index 000000000..2ee8d9e7f --- /dev/null +++ b/gtk/TextIter.custom @@ -0,0 +1,30 @@ +// Gtk.TextIter.custom - Gtk TextIter class customizations +// +// Author: Rachel Hestilow +// +// (c) 2001 Mike Kestner, 2002 Rachel Hestilow +// +// This code is inserted after the automatically generated code. + + + /// + /// TextIter Constructor + /// + /// + /// + /// Constructs a new TextIter. + + [DllImport("gtksharpglue")] + static extern IntPtr gtksharp_text_iter_create(); + public TextIter () : this (gtksharp_text_iter_create ()) + { + } + + [DllImport("glib-2.0")] + static extern void g_free (IntPtr mem); + + ~TextIter () + { + g_free (Handle); + } + diff --git a/parser/GAPI/Metadata.pm b/parser/GAPI/Metadata.pm new file mode 100644 index 000000000..e00f7c58f --- /dev/null +++ b/parser/GAPI/Metadata.pm @@ -0,0 +1,190 @@ +# +# Metadata.pm: Adds additional properties to a GApi tree. +# +# Author: Rachel Hestilow +# +# 2002 Rachel Hestilow +############################################################## + +package Metadata; + +use XML::LibXML; + +sub new { + my $namespace = $_[1]; + my $file = "$namespace.metadata"; + my $self = {}; + @{$self->{rules}} = (); + $self->{metadata} = $namespace; + bless $self; + $self->load ($file); + return $self; +} + +sub parseClass { + my ($node, $classes) = @_; + my %methods = (); + my @attrs = $node->attributes; + my $class_name = $attrs[0]->value; + ${$classes}{$class_name} = \%methods; + + for ($method_node = $node->firstChild; $method_node != undef; $method_node = $method_node->nextSibling ()) { + next if $method_node->nodeName ne "method"; + $methods{$method_node->firstChild->nodeValue} = 1; + } +} + +sub parseData { + my $node = $_[0]; + my @data = (); + for ($data_node = $node->firstChild; $data_node != undef; $data_node = $data_node->nextSibling ()) { + next if $data_node->nodeName ne "attribute"; + my @attrs = $data_node->attributes; + my $target = $attrs[0]->value; + my ($filter_level, $filter_value, $attr_name, $attr_value); + for ($attr_node = $data_node->firstChild; $attr_node != undef; $attr_node = $attr_node->nextSibling ()) { + if ($attr_node->nodeName eq "filter") { + my @filter_attrs = $attr_node->attributes; + $filter_level = $filter_attrs[0]->value; + $filter_value = $attr_node->firstChild->nodeValue; + } elsif ($attr_node->nodeName eq "name") { + $attr_name = $attr_node->firstChild->nodeValue; + } elsif ($attr_node->nodeName eq "value") { + $attr_value = $attr_node->firstChild->nodeValue; + } + } + my @data_attr = ("attribute", $target, "filter", $filter_level, $filter_value, $attr_name, $attr_value); + push @data, \@data_attr; + } + + return @data; +} + +sub load { + my ($self, $file) = @_; + my $parser = new XML::LibXML; + my $doc = $parser->parse_file($file); + my $root = $doc->documentElement; + for ($rule_node = $root->firstChild; $rule_node != undef; $rule_node = $rule_node->nextSibling ()) { + next if $rule_node->nodeName ne "rule"; + my %classes = (); + my @data; + for ($node = $rule_node->firstChild; $node != undef; $node = $node->nextSibling ()) { + if ($node->nodeName eq "class") { + parseClass ($node, \%classes); + } elsif ($node->nodeName eq "data") { + @data = parseData ($node); + } + } + + push @{$self->{rules}}, [\%classes, \@data]; + } +} + +sub fixupParams { + my ($method_node, $data_list_ref) = @_; + my ($params_node, $node); + for ($node = $method_node->firstChild; $node; $node = $node->nextSibling ()) { + if ($node->nodeName eq "parameters") { + $params_node = $node; + last; + } + } + return if not $params_node; + for ($node = $params_node->firstChild; $node; $node = $node->nextSibling ()) { + my $param_type; + foreach $attr ($node->attributes) { + if ($attr->name eq "type") { + $param_type = $attr->value; + last; + } + } + + foreach $data (@$data_list_ref) { + if ($param_type eq $$data[4]) { + $node->setAttribute ($$data[5], $$data[6]); + } + } + } +} + +sub fixupNamespace { + my ($self, $ns_node) = @_; + my $node; + foreach $rule (@{$self->{rules}}) { + my ($classes_ref, $data_list_ref) = @$rule; + for ($node = $ns_node->firstChild; $node; $node = $node->nextSibling ()) { + next if $node->nodeName ne "object"; + my $class, $methods_ref, $attr; + foreach $attr ($node->attributes) { + if ($attr->name eq "cname") { + $class = $attr->value; + last; + } + } + + my %classes = %$classes_ref; + $methods_ref = $classes{$class}; + next if not $methods_ref; + + for ($method_node = $node->firstChild; $method_node; $method_node = $method_node->nextSibling ()) { + next if $method_node->nodeName ne "method"; + my $method; + foreach $attr ($method_node->attributes) { + if ($attr->name eq "name") { + $method = $attr->value; + last; + } + } + next if not ${$methods_ref}{$method}; + fixupParams ($method_node, $data_list_ref); + } + } + } +} + +sub fixup { + my $doc = $_[0]; + my ($api_node, $ns_node); + my $metadata = undef; + + $api_node = $doc->documentElement; + return if not ($api_node and $api_node->nodeName eq "api"); + for ($ns_node = $api_node->firstChild; $ns_node; $ns_node = $ns_node->nextSibling ()) { + next if $ns_node->nodeName ne "namespace"; + next if not ($ns_node->attributes and (scalar (@{$ns_node->attributes})) + 1); + my @attrs = $ns_node->attributes; + my $namespace = $attrs[0]->value; + if (-f "$namespace.metadata") { + if (not ($metadata and $metadata->{namespace} eq $namespace)) { + $metadata = new Metadata ($namespace); + } + $metadata->fixupNamespace ($ns_node); + } + } +} + +sub output { + my $self = $_[0]; + $rule_num = 0; + foreach $rule (@{$self->{rules}}) { + print "Rule #$rule_num:\n"; + my ($classes_ref, $data_list_ref) = @$rule; + my %classes = %$classes_ref; + my @data_list = @$data_list_ref; + foreach $class (keys (%classes)) { + print "\tClass $class:\n"; + foreach $method (keys %{$classes{$class}}) { + print "\t\tMethod $method\n"; + } + } + print "\tData:\n"; + foreach $data (@data_list) { + printf "\t\tAdd an %s to all %s of %s %s: %s=%s\n", + $$data[0], $$data[1], $$data[3], $$data[4], $$data[5], $$data[6]; + } + $rule_num++; + } +} + +1; diff --git a/parser/Gtk.metadata b/parser/Gtk.metadata new file mode 100644 index 000000000..f80180b68 --- /dev/null +++ b/parser/Gtk.metadata @@ -0,0 +1,31 @@ + + + + + GetIterAtLineOffset + GetIterAtLineIndex + GetIterAtOffset + GetIterAtLine + GetStartIter + GetEndIter + GetBounds + GetIterAtMark + GetIterAtChildAnchor + GetSelectionBounds + + + GetIterAtLine + + + GetIterAtLocation + GetLineAtY + + + + GtkTextIter* + pass_as + out + + + + diff --git a/parser/Metadata.pm b/parser/Metadata.pm new file mode 100644 index 000000000..e00f7c58f --- /dev/null +++ b/parser/Metadata.pm @@ -0,0 +1,190 @@ +# +# Metadata.pm: Adds additional properties to a GApi tree. +# +# Author: Rachel Hestilow +# +# 2002 Rachel Hestilow +############################################################## + +package Metadata; + +use XML::LibXML; + +sub new { + my $namespace = $_[1]; + my $file = "$namespace.metadata"; + my $self = {}; + @{$self->{rules}} = (); + $self->{metadata} = $namespace; + bless $self; + $self->load ($file); + return $self; +} + +sub parseClass { + my ($node, $classes) = @_; + my %methods = (); + my @attrs = $node->attributes; + my $class_name = $attrs[0]->value; + ${$classes}{$class_name} = \%methods; + + for ($method_node = $node->firstChild; $method_node != undef; $method_node = $method_node->nextSibling ()) { + next if $method_node->nodeName ne "method"; + $methods{$method_node->firstChild->nodeValue} = 1; + } +} + +sub parseData { + my $node = $_[0]; + my @data = (); + for ($data_node = $node->firstChild; $data_node != undef; $data_node = $data_node->nextSibling ()) { + next if $data_node->nodeName ne "attribute"; + my @attrs = $data_node->attributes; + my $target = $attrs[0]->value; + my ($filter_level, $filter_value, $attr_name, $attr_value); + for ($attr_node = $data_node->firstChild; $attr_node != undef; $attr_node = $attr_node->nextSibling ()) { + if ($attr_node->nodeName eq "filter") { + my @filter_attrs = $attr_node->attributes; + $filter_level = $filter_attrs[0]->value; + $filter_value = $attr_node->firstChild->nodeValue; + } elsif ($attr_node->nodeName eq "name") { + $attr_name = $attr_node->firstChild->nodeValue; + } elsif ($attr_node->nodeName eq "value") { + $attr_value = $attr_node->firstChild->nodeValue; + } + } + my @data_attr = ("attribute", $target, "filter", $filter_level, $filter_value, $attr_name, $attr_value); + push @data, \@data_attr; + } + + return @data; +} + +sub load { + my ($self, $file) = @_; + my $parser = new XML::LibXML; + my $doc = $parser->parse_file($file); + my $root = $doc->documentElement; + for ($rule_node = $root->firstChild; $rule_node != undef; $rule_node = $rule_node->nextSibling ()) { + next if $rule_node->nodeName ne "rule"; + my %classes = (); + my @data; + for ($node = $rule_node->firstChild; $node != undef; $node = $node->nextSibling ()) { + if ($node->nodeName eq "class") { + parseClass ($node, \%classes); + } elsif ($node->nodeName eq "data") { + @data = parseData ($node); + } + } + + push @{$self->{rules}}, [\%classes, \@data]; + } +} + +sub fixupParams { + my ($method_node, $data_list_ref) = @_; + my ($params_node, $node); + for ($node = $method_node->firstChild; $node; $node = $node->nextSibling ()) { + if ($node->nodeName eq "parameters") { + $params_node = $node; + last; + } + } + return if not $params_node; + for ($node = $params_node->firstChild; $node; $node = $node->nextSibling ()) { + my $param_type; + foreach $attr ($node->attributes) { + if ($attr->name eq "type") { + $param_type = $attr->value; + last; + } + } + + foreach $data (@$data_list_ref) { + if ($param_type eq $$data[4]) { + $node->setAttribute ($$data[5], $$data[6]); + } + } + } +} + +sub fixupNamespace { + my ($self, $ns_node) = @_; + my $node; + foreach $rule (@{$self->{rules}}) { + my ($classes_ref, $data_list_ref) = @$rule; + for ($node = $ns_node->firstChild; $node; $node = $node->nextSibling ()) { + next if $node->nodeName ne "object"; + my $class, $methods_ref, $attr; + foreach $attr ($node->attributes) { + if ($attr->name eq "cname") { + $class = $attr->value; + last; + } + } + + my %classes = %$classes_ref; + $methods_ref = $classes{$class}; + next if not $methods_ref; + + for ($method_node = $node->firstChild; $method_node; $method_node = $method_node->nextSibling ()) { + next if $method_node->nodeName ne "method"; + my $method; + foreach $attr ($method_node->attributes) { + if ($attr->name eq "name") { + $method = $attr->value; + last; + } + } + next if not ${$methods_ref}{$method}; + fixupParams ($method_node, $data_list_ref); + } + } + } +} + +sub fixup { + my $doc = $_[0]; + my ($api_node, $ns_node); + my $metadata = undef; + + $api_node = $doc->documentElement; + return if not ($api_node and $api_node->nodeName eq "api"); + for ($ns_node = $api_node->firstChild; $ns_node; $ns_node = $ns_node->nextSibling ()) { + next if $ns_node->nodeName ne "namespace"; + next if not ($ns_node->attributes and (scalar (@{$ns_node->attributes})) + 1); + my @attrs = $ns_node->attributes; + my $namespace = $attrs[0]->value; + if (-f "$namespace.metadata") { + if (not ($metadata and $metadata->{namespace} eq $namespace)) { + $metadata = new Metadata ($namespace); + } + $metadata->fixupNamespace ($ns_node); + } + } +} + +sub output { + my $self = $_[0]; + $rule_num = 0; + foreach $rule (@{$self->{rules}}) { + print "Rule #$rule_num:\n"; + my ($classes_ref, $data_list_ref) = @$rule; + my %classes = %$classes_ref; + my @data_list = @$data_list_ref; + foreach $class (keys (%classes)) { + print "\tClass $class:\n"; + foreach $method (keys %{$classes{$class}}) { + print "\t\tMethod $method\n"; + } + } + print "\tData:\n"; + foreach $data (@data_list) { + printf "\t\tAdd an %s to all %s of %s %s: %s=%s\n", + $$data[0], $$data[1], $$data[3], $$data[4], $$data[5], $$data[6]; + } + $rule_num++; + } +} + +1; diff --git a/parser/build.pl b/parser/build.pl new file mode 100755 index 000000000..94f9e0163 --- /dev/null +++ b/parser/build.pl @@ -0,0 +1,16 @@ +#!/usr/bin/perl -w + +$file = "../generator/gtkapi.xml"; + +unlink ($file); + +%ns = ( "Atk" => "atk-1.0.2/atk", + "Pango" => "pango-1.0.2/pango", + "Gdk" => "gtk+-2.0.3/gdk", + "Gtk" => "gtk+-2.0.3/gtk"); + +foreach $key (keys %ns) { + $dir = $ns{$key}; + system ("./gapi_pp.pl $dir | ./gapi2xml.pl $key $file"); +} + diff --git a/parser/gapi2xml.pl b/parser/gapi2xml.pl index ee764db0d..740c4a58e 100755 --- a/parser/gapi2xml.pl +++ b/parser/gapi2xml.pl @@ -10,6 +10,7 @@ $debug=1; use XML::LibXML; +use Metadata; if (!$ARGV[0]) { die "Usage: gapi_pp.pl | gapi2xml.pl \n"; @@ -96,7 +97,9 @@ while ($line = ) { } $boxdef =~ s/\n\s*//g; $boxdef =~ /\(\"(\w+)\"/; - $boxdefs{$1} = $boxdef; + my $boxtype = $1; + $boxtype =~ s/($ns)Type(\w+)/$ns$2/; + $boxdefs{$boxtype} = $boxdef; } elsif ($line =~ /^(const|G_CONST_RETURN)?\s*\w+\s*\**\s*(\w+)\s*\(/) { $fname = $2; $fdef = ""; @@ -298,6 +301,10 @@ foreach $key (sort (keys (%types))) { addFieldElems($struct_el, split(/;/, $1)); addFuncElems($struct_el, $key); } +############################################################## +# Add metadata +############################################################## +Metadata::fixup $doc; ############################################################## # Output the tree diff --git a/sources/Gtk.metadata b/sources/Gtk.metadata new file mode 100644 index 000000000..f80180b68 --- /dev/null +++ b/sources/Gtk.metadata @@ -0,0 +1,31 @@ + + + + + GetIterAtLineOffset + GetIterAtLineIndex + GetIterAtOffset + GetIterAtLine + GetStartIter + GetEndIter + GetBounds + GetIterAtMark + GetIterAtChildAnchor + GetSelectionBounds + + + GetIterAtLine + + + GetIterAtLocation + GetLineAtY + + + + GtkTextIter* + pass_as + out + + + +