[glibmm/gmmproc-refactor] Blablabla.



commit 97fe74201f3049835204e4ae62af0bff444a4b88
Author: Krzesimir Nowak <qdlacz gmail com>
Date:   Fri Sep 2 23:15:34 2011 +0200

    Blablabla.

 .gitignore                                         |    1 +
 configure.ac                                       |    2 +
 tools/pm/Gir/Config.pm.in                          |   11 +
 tools/pm/Gir/Handlers/Alias.pm                     |   50 ++++
 tools/pm/Gir/Handlers/Base.pm                      |   29 ++-
 tools/pm/Gir/Handlers/Bitfield.pm                  |   50 ++++
 tools/pm/Gir/Handlers/Callback.pm                  |   58 +++++
 tools/pm/Gir/Handlers/Class.pm                     |  106 +++++++++
 tools/pm/Gir/Handlers/Common.pm                    |   38 +++-
 tools/pm/Gir/Handlers/Constant.pm                  |   50 ++++
 tools/pm/Gir/Handlers/Enumeration.pm               |   58 +++++
 tools/pm/Gir/Handlers/Function.pm                  |   58 +++++
 tools/pm/Gir/Handlers/Ignore.pm                    |   18 +-
 tools/pm/Gir/Handlers/Interface.pm                 |   90 +++++++
 tools/pm/Gir/Handlers/Namespace.pm                 |  139 +++++++++++
 tools/pm/Gir/Handlers/Record.pm                    |   82 +++++++
 tools/pm/Gir/Handlers/Repository.pm                |   52 ++--
 tools/pm/Gir/Handlers/Stores/DocEndStore.pm        |   28 +++
 tools/pm/Gir/Handlers/Stores/DocStartStore.pm      |   28 +++
 tools/pm/Gir/Handlers/Stores/DocStores.pm          |    6 +
 .../pm/Gir/Handlers/{ => Stores}/IgnoreEndStore.pm |    8 +-
 .../Gir/Handlers/{ => Stores}/IgnoreStartStore.pm  |    8 +-
 tools/pm/Gir/Handlers/Stores/IgnoreStores.pm       |    6 +
 tools/pm/Gir/Handlers/{ => Stores}/Store.pm        |    4 +-
 tools/pm/Gir/Handlers/TopLevel.pm                  |   26 ++-
 tools/pm/Gir/Parser.pm                             |  153 +++++++++---
 tools/pm/Gir/State.pm                              |   37 +++-
 tools/pm/Gir/metadata                              |   21 +-
 tools/pm/GobjectIntrospectionBUGS.txt              |   18 ++
 tools/pm/girtest.pl                                |   12 +
 tools/pm/metadatagetter.pl                         |  240 +++++++++++++++++++
 tools/pm/moduleslist                               |    1 +
 tools/pm/taghandlerwriter.pl                       |  250 ++++++++++++++++++++
 33 files changed, 1623 insertions(+), 115 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index ef2bba1..3a527e7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -157,3 +157,4 @@ giommconfig.h
 /tools/extra_defs_gen/generate_defs_glib
 /tools/generate_wrap_init.pl
 /tools/gmmproc
+/tools/pm/Gir/Config.pm
diff --git a/configure.ac b/configure.ac
index ef115f4..b27260f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -72,6 +72,7 @@ PKG_CHECK_MODULES([GIOMM],  [$GIOMM_MODULES])
 
 MM_PKG_CONFIG_SUBST([GTHREAD_CFLAGS], [--cflags-only-other gthread-2.0])
 MM_PKG_CONFIG_SUBST([GTHREAD_LIBS], [--libs gthread-2.0])
+MM_PKG_CONFIG_SUBST([GIR_DIR], [--variable=girdir gobject-introspection-1.0])
 
 AC_CHECK_PROGS([M4], [gm4 m4], [m4])
 GLIB_GSETTINGS
@@ -135,6 +136,7 @@ AC_CONFIG_FILES([Makefile
                  tools/Makefile
                  tools/gmmproc
                  tools/generate_wrap_init.pl
+                 tools/pm/Gir/Config.pm
                  glib/${GLIBMM_MODULE_NAME}.pc:glib/glibmm.pc.in
                  glib/${GLIBMM_MODULE_NAME}-uninstalled.pc:glib/glibmm-uninstalled.pc.in
                  glib/src/Makefile
diff --git a/tools/pm/Gir/Config.pm.in b/tools/pm/Gir/Config.pm.in
new file mode 100644
index 0000000..18bc0f3
--- /dev/null
+++ b/tools/pm/Gir/Config.pm.in
@@ -0,0 +1,11 @@
+package Gir::Config;
+
+use strict;
+use warnings;
+
+sub get_girdir ()
+{
+  return '@GIRDIR@';
+}
+
+1;
diff --git a/tools/pm/Gir/Handlers/Alias.pm b/tools/pm/Gir/Handlers/Alias.pm
new file mode 100644
index 0000000..c3bbff2
--- /dev/null
+++ b/tools/pm/Gir/Handlers/Alias.pm
@@ -0,0 +1,50 @@
+package Gir::Handlers::Alias;
+
+use strict;
+use warnings;
+
+use parent qw(Gir::Handlers::Base);
+
+use Gir::Handlers::Common;
+use Gir::Handlers::Ignore;
+use Gir::Handlers::Stores::DocStores;
+use Gir::Parser;
+
+##
+## private:
+##
+sub _type_start ($$@)
+{
+  my ($self, $parser, @atts_vals) = @_;
+  my $params = Gir::Handlers::Common::extract_values_warn (['c:type', 'name'], [], \ atts_vals, 'alias/type');
+}
+
+##
+## public:
+##
+sub new ($)
+{
+  my $type = shift;
+  my $class = (ref ($type) or $type or 'Gir::Handlers::Alias');
+  my $self = $class->SUPER::new ();
+
+  $self->_set_handlers
+  (
+    Gir::Handlers::Stores::DocStartStore->new
+    ({
+      'type' => \&_type_start
+    }),
+    Gir::Handlers::Stores::DocEndStore->new
+    ({
+      'type' => \&Gir::Handlers::Common::end_ignore
+    })
+  );
+  $self->_set_subhandlers
+  ({
+    '*' => "Gir::Handlers::Ignore"
+  });
+
+  return bless ($self, $class);
+}
+
+1;
diff --git a/tools/pm/Gir/Handlers/Base.pm b/tools/pm/Gir/Handlers/Base.pm
index c5a52ad..b09ae47 100644
--- a/tools/pm/Gir/Handlers/Base.pm
+++ b/tools/pm/Gir/Handlers/Base.pm
@@ -13,7 +13,8 @@ sub _new_impl_ ($)
   my $self =
   {
     'start_handlers' => {},
-    'end_handlers' => {}
+    'end_handlers' => {},
+    'subhandlers' => {}
   };
 
   return bless ($self, $class);
@@ -30,6 +31,13 @@ sub _set_handlers ($$$)
   $self->{'end_handlers'} = $end_handlers;
 }
 
+sub _set_subhandlers ($$)
+{
+  my ($self, $subhandlers) = @_;
+
+  $self->{'subhandlers'} = $subhandlers;
+}
+
 ##
 ## public:
 ##
@@ -54,7 +62,24 @@ sub get_end_handlers ($)
 
 sub get_subhandlers_for ($$)
 {
-  #TODO: error - not implemented.
+  my ($self, $elem) = @_;
+  my $subhandlers = $self->{'subhandlers'};
+  my $package = undef;
+
+  if (exists ($subhandlers->{$elem}))
+  {
+    $package = $subhandlers->{$elem};
+  }
+  elsif (exists ($subhandlers->{'*'}))
+  {
+    $package = $subhandlers->{'*'};
+  }
+
+  if (defined ($package))
+  {
+    return $package->new ();
+  }
+  return undef;
 }
 
 1;
diff --git a/tools/pm/Gir/Handlers/Bitfield.pm b/tools/pm/Gir/Handlers/Bitfield.pm
new file mode 100644
index 0000000..647d01f
--- /dev/null
+++ b/tools/pm/Gir/Handlers/Bitfield.pm
@@ -0,0 +1,50 @@
+package Gir::Handlers::Bitfield;
+
+use strict;
+use warnings;
+
+use parent qw(Gir::Handlers::Base);
+
+use Gir::Handlers::Common;
+use Gir::Handlers::Ignore;
+use Gir::Handlers::Stores::DocStores;
+use Gir::Parser;
+
+##
+## private:
+##
+sub _member_start ($$@)
+{
+  my ($self, $parser, @atts_vals) = @_;
+  my $params = Gir::Handlers::Common::extract_values_warn (['c:identifier', 'name', 'value'], ['glib:nick'], \ atts_vals, 'bitfield/member');
+}
+
+##
+## public:
+##
+sub new ($)
+{
+  my $type = shift;
+  my $class = (ref ($type) or $type or 'Gir::Handlers::Bitfield');
+  my $self = $class->SUPER::new ();
+
+  $self->_set_handlers
+  (
+    Gir::Handlers::Stores::DocStartStore->new
+    ({
+      'member' => \&_member_start
+    }),
+    Gir::Handlers::Stores::DocEndStore->new
+    ({
+      'member' => \&Gir::Handlers::Common::end_ignore
+    })
+  );
+  $self->_set_subhandlers
+  ({
+    '*' => "Gir::Handlers::Ignore"
+  });
+
+  return bless ($self, $class);
+}
+
+1;
diff --git a/tools/pm/Gir/Handlers/Callback.pm b/tools/pm/Gir/Handlers/Callback.pm
new file mode 100644
index 0000000..8b26b4c
--- /dev/null
+++ b/tools/pm/Gir/Handlers/Callback.pm
@@ -0,0 +1,58 @@
+package Gir::Handlers::Callback;
+
+use strict;
+use warnings;
+
+use parent qw(Gir::Handlers::Base);
+
+use Gir::Handlers::Common;
+use Gir::Handlers::Ignore;
+use Gir::Handlers::Stores::DocStores;
+use Gir::Parser;
+
+##
+## private:
+##
+sub _parameters_start ($$@)
+{
+  my ($self, $parser, @atts_vals) = @_;
+  my $params = Gir::Handlers::Common::extract_values_warn ([], [], \ atts_vals, 'callback/parameters');
+}
+
+sub _return_value_start ($$@)
+{
+  my ($self, $parser, @atts_vals) = @_;
+  my $params = Gir::Handlers::Common::extract_values_warn ([], ['transfer-ownership'], \ atts_vals, 'callback/return-value');
+}
+
+##
+## public:
+##
+sub new ($)
+{
+  my $type = shift;
+  my $class = (ref ($type) or $type or 'Gir::Handlers::Callback');
+  my $self = $class->SUPER::new ();
+
+  $self->_set_handlers
+  (
+    Gir::Handlers::Stores::DocStartStore->new
+    ({
+      'parameters' => \&_parameters_start,
+      'return-value' => \&_return_value_start
+    }),
+    Gir::Handlers::Stores::DocEndStore->new
+    ({
+      'parameters' => \&Gir::Handlers::Common::end_ignore,
+      'return-value' => \&Gir::Handlers::Common::end_ignore
+    })
+  );
+  $self->_set_subhandlers
+  ({
+    '*' => "Gir::Handlers::Ignore"
+  });
+
+  return bless ($self, $class);
+}
+
+1;
diff --git a/tools/pm/Gir/Handlers/Class.pm b/tools/pm/Gir/Handlers/Class.pm
new file mode 100644
index 0000000..1686961
--- /dev/null
+++ b/tools/pm/Gir/Handlers/Class.pm
@@ -0,0 +1,106 @@
+package Gir::Handlers::Class;
+
+use strict;
+use warnings;
+
+use parent qw(Gir::Handlers::Base);
+
+use Gir::Handlers::Common;
+use Gir::Handlers::Ignore;
+use Gir::Handlers::Stores::DocStores;
+use Gir::Parser;
+
+##
+## private:
+##
+sub _constructor_start ($$@)
+{
+  my ($self, $parser, @atts_vals) = @_;
+  my $params = Gir::Handlers::Common::extract_values_warn (['c:identifier', 'name'], ['deprecated', 'deprecated-version', 'introspectable', 'shadowed-by', 'shadows', 'throws', 'version'], \ atts_vals, 'class/constructor');
+}
+
+sub _field_start ($$@)
+{
+  my ($self, $parser, @atts_vals) = @_;
+  my $params = Gir::Handlers::Common::extract_values_warn (['name'], ['bits', 'private', 'readable', 'writable'], \ atts_vals, 'class/field');
+}
+
+sub _function_start ($$@)
+{
+  my ($self, $parser, @atts_vals) = @_;
+  my $params = Gir::Handlers::Common::extract_values_warn (['c:identifier', 'name'], ['deprecated', 'deprecated-version', 'introspectable', 'moved-to', 'shadowed-by', 'shadows', 'throws', 'version'], \ atts_vals, 'class/function');
+}
+
+sub _glib_signal_start ($$@)
+{
+  my ($self, $parser, @atts_vals) = @_;
+  my $params = Gir::Handlers::Common::extract_values_warn (['name'], ['action', 'deprecated', 'deprecated-version', 'detailed', 'introspectable', 'no-hooks', 'no-recurse', 'version', 'when'], \ atts_vals, 'class/glib:signal');
+}
+
+sub _implements_start ($$@)
+{
+  my ($self, $parser, @atts_vals) = @_;
+  my $params = Gir::Handlers::Common::extract_values_warn (['name'], [], \ atts_vals, 'class/implements');
+}
+
+sub _method_start ($$@)
+{
+  my ($self, $parser, @atts_vals) = @_;
+  my $params = Gir::Handlers::Common::extract_values_warn (['c:identifier', 'name'], ['deprecated', 'deprecated-version', 'introspectable', 'shadowed-by', 'shadows', 'throws', 'version'], \ atts_vals, 'class/method');
+}
+
+sub _property_start ($$@)
+{
+  my ($self, $parser, @atts_vals) = @_;
+  my $params = Gir::Handlers::Common::extract_values_warn (['name', 'transfer-ownership'], ['construct-only', 'construct', 'deprecated', 'deprecated-version', 'introspectable', 'readable', 'version', 'writable'], \ atts_vals, 'class/property');
+}
+
+sub _virtual_method_start ($$@)
+{
+  my ($self, $parser, @atts_vals) = @_;
+  my $params = Gir::Handlers::Common::extract_values_warn (['name'], ['deprecated', 'deprecated-version', 'introspectable', 'invoker', 'throws', 'version'], \ atts_vals, 'class/virtual-method');
+}
+
+##
+## public:
+##
+sub new ($)
+{
+  my $type = shift;
+  my $class = (ref ($type) or $type or 'Gir::Handlers::Class');
+  my $self = $class->SUPER::new ();
+
+  $self->_set_handlers
+  (
+    Gir::Handlers::Stores::DocStartStore->new
+    ({
+      'constructor' => \&_constructor_start,
+      'field' => \& _field_start,
+      'function' => \&_function_start,
+      'glib:signal' => \&_glib_signal_start,
+      'implements' => \&_implements_start,
+      'method' => \&_method_start,
+      'property' => \& _property_start,
+      'virtual-method' => \&_virtual_method_start
+    }),
+    Gir::Handlers::Stores::DocEndStore->new
+    ({
+      'constructor' => \&Gir::Handlers::Common::end_ignore,
+      'field' => \&Gir::Handlers::Common::end_ignore,
+      'function' => \&Gir::Handlers::Common::end_ignore,
+      'glib:signal' => \&Gir::Handlers::Common::end_ignore,
+      'implements' => \&Gir::Handlers::Common::end_ignore,
+      'method' => \&Gir::Handlers::Common::end_ignore,
+      'property' => \&Gir::Handlers::Common::end_ignore,
+      'virtual-method' => \&Gir::Handlers::Common::end_ignore
+    })
+  );
+  $self->_set_subhandlers
+  ({
+    '*' => "Gir::Handlers::Ignore"
+  });
+
+  return bless ($self, $class);
+}
+
+1;
diff --git a/tools/pm/Gir/Handlers/Common.pm b/tools/pm/Gir/Handlers/Common.pm
index 16ab33f..edca9ad 100644
--- a/tools/pm/Gir/Handlers/Common.pm
+++ b/tools/pm/Gir/Handlers/Common.pm
@@ -12,6 +12,26 @@ sub start_ignore ($$@)
 sub end_ignore ($$)
 {}
 
+sub doc_start ($$@)
+{
+  my ($self, $parser, @atts_vals) = @_;
+  my $params = extract_values_warn (['xml:whitespace'], [], \ atts_vals, 'doc');
+  my $state = $parser->get_current_state ();
+  my $xml_parser = $state->get_xml_parser ();
+
+  $self->{'doc'} = '';
+  $xml_parser->setHandlers ('Char' => sub { $self->{'doc'} .= $_[1] });
+}
+
+sub doc_end ($$)
+{
+  my ($self, $parser) = @_;
+  my $state = $parser->get_current_state ();
+  my $xml_parser = $state->get_xml_parser ();
+
+  $xml_parser->setHandlers ('Char' => undef);
+}
+
 sub extract_values($$$$)
 {
   my ($keys, $optional_keys, $atts_vals, $tag) = @_;
@@ -21,12 +41,12 @@ sub extract_values($$$$)
   my $leftover = undef;
   my $att = undef;
 
-  foreach my $key (@keys)
+  foreach my $key (@{$keys})
   {
     $params->{$key} = undef;
     $check->{$key} = undef;
   }
-  foreach my $key in (@optional_keys)
+  foreach my $key (@{$optional_keys})
   {
     $params->{$key} = undef;
   }
@@ -52,12 +72,12 @@ sub extract_values($$$$)
     }
     else
     {
-      $params{$att} = $entry;
+      $params->{$att} = $entry;
       $att = undef;
     }
   }
 
-  my @check_keys = keys (%{$check})
+  my @check_keys = keys (%{$check});
 
   if (@check_keys > 0)
   {
@@ -68,8 +88,8 @@ sub extract_values($$$$)
       $message .= "  " . $key . "\n";
     }
     # TODO: change this later maybe to exception and remove $tag parameter.
-    print STDERR $message;
-    exit (1);
+    #print STDERR $message;
+    #exit (1);
   }
 
   return ($params, $leftovers);
@@ -78,7 +98,7 @@ sub extract_values($$$$)
 sub extract_values_warn ($$$$)
 {
   my ($keys, $optional_keys, $atts_vals, $tag) = @_;
-  my ($params, $leftovers) = extract_values ($keys, $optional_keys, $atts_vals);
+  my ($params, $leftovers) = extract_values ($keys, $optional_keys, $atts_vals, $tag);
   my @leftover_keys = keys (%{$leftovers});
 
   if (@leftover_keys > 0)
@@ -90,8 +110,8 @@ sub extract_values_warn ($$$$)
       $message .= "  " . $leftover . " => " . $leftovers->{$leftover} . "\n";
     }
     # TODO: change this later maybe to exception and remove $tag parameter.
-    print STDERR $message;
-    exit (1);
+    #print STDERR $message;
+    #exit (1);
   }
 
   return $params;
diff --git a/tools/pm/Gir/Handlers/Constant.pm b/tools/pm/Gir/Handlers/Constant.pm
new file mode 100644
index 0000000..dda2f48
--- /dev/null
+++ b/tools/pm/Gir/Handlers/Constant.pm
@@ -0,0 +1,50 @@
+package Gir::Handlers::Constant;
+
+use strict;
+use warnings;
+
+use parent qw(Gir::Handlers::Base);
+
+use Gir::Handlers::Common;
+use Gir::Handlers::Ignore;
+use Gir::Handlers::Stores::Store;
+use Gir::Parser;
+
+##
+## private:
+##
+sub _type_start ($$@)
+{
+  my ($self, $parser, @atts_vals) = @_;
+  my $params = Gir::Handlers::Common::extract_values_warn (['c:type', 'name'], [], \ atts_vals, 'constant/type');
+}
+
+##
+## public:
+##
+sub new ($)
+{
+  my $type = shift;
+  my $class = (ref ($type) or $type or 'Gir::Handlers::Constant');
+  my $self = $class->SUPER::new ();
+
+  $self->_set_handlers
+  (
+    Gir::Handlers::Stores::Store->new
+    ({
+      'type' => \&_type_start
+    }),
+    Gir::Handlers::Stores::Store->new
+    ({
+      'type' => \&Gir::Handlers::Common::end_ignore
+    })
+  );
+  $self->_set_subhandlers
+  ({
+    '*' => "Gir::Handlers::Ignore"
+  });
+
+  return bless ($self, $class);
+}
+
+1;
diff --git a/tools/pm/Gir/Handlers/Enumeration.pm b/tools/pm/Gir/Handlers/Enumeration.pm
new file mode 100644
index 0000000..e241aec
--- /dev/null
+++ b/tools/pm/Gir/Handlers/Enumeration.pm
@@ -0,0 +1,58 @@
+package Gir::Handlers::Enumeration;
+
+use strict;
+use warnings;
+
+use parent qw(Gir::Handlers::Base);
+
+use Gir::Handlers::Common;
+use Gir::Handlers::Ignore;
+use Gir::Handlers::Stores::DocStores;
+use Gir::Parser;
+
+##
+## private:
+##
+sub _member_start ($$@)
+{
+  my ($self, $parser, @atts_vals) = @_;
+  my $params = Gir::Handlers::Common::extract_values_warn (['c:identifier', 'name', 'value'], ['glib:nick'], \ atts_vals, 'enumeration/member');
+}
+
+sub _function_start ($$@)
+{
+  my ($self, $parser, @atts_vals) = @_;
+  my $params = Gir::Handlers::Common::extract_values_warn (['c:identifier', 'name'], ['deprecated', 'deprecated-version', 'introspectable', 'moved-to', 'shadowed-by', 'shadows', 'throws', 'version'], \ atts_vals, 'enumeration/function');
+}
+
+##
+## public:
+##
+sub new ($)
+{
+  my $type = shift;
+  my $class = (ref ($type) or $type or 'Gir::Handlers::Enumeration');
+  my $self = $class->SUPER::new ();
+
+  $self->_set_handlers
+  (
+    Gir::Handlers::Stores::DocStartStore->new
+    ({
+      'function' => \&_function_start,
+      'member' => \&_member_start
+    }),
+    Gir::Handlers::Stores::DocEndStore->new
+    ({
+      'function' => \&Gir::Handlers::Common::end_ignore,
+      'member' => \&Gir::Handlers::Common::end_ignore
+    })
+  );
+  $self->_set_subhandlers
+  ({
+    '*' => "Gir::Handlers::Ignore"
+  });
+
+  return bless ($self, $class);
+}
+
+1;
diff --git a/tools/pm/Gir/Handlers/Function.pm b/tools/pm/Gir/Handlers/Function.pm
new file mode 100644
index 0000000..3f69559
--- /dev/null
+++ b/tools/pm/Gir/Handlers/Function.pm
@@ -0,0 +1,58 @@
+package Gir::Handlers::Function;
+
+use strict;
+use warnings;
+
+use parent qw(Gir::Handlers::Base);
+
+use Gir::Handlers::Common;
+use Gir::Handlers::Ignore;
+use Gir::Handlers::Stores::DocStores;
+use Gir::Parser;
+
+##
+## private:
+##
+sub _parameters_start ($$@)
+{
+  my ($self, $parser, @atts_vals) = @_;
+  my $params = Gir::Handlers::Common::extract_values_warn ([], [], \ atts_vals, 'function/parameters');
+}
+
+sub _return_value_start ($$@)
+{
+  my ($self, $parser, @atts_vals) = @_;
+  my $params = Gir::Handlers::Common::extract_values_warn ([], ['transfer-ownership'], \ atts_vals, 'function/return-value');
+}
+
+##
+## public:
+##
+sub new ($)
+{
+  my $type = shift;
+  my $class = (ref ($type) or $type or 'Gir::Handlers::Function');
+  my $self = $class->SUPER::new ();
+
+  $self->_set_handlers
+  (
+    Gir::Handlers::Stores::DocStartStore->new
+    ({
+      'parameters' => \&_parameters_start,
+      'return-value' => \&_return_value_start
+    }),
+    Gir::Handlers::Stores::DocEndStore->new
+    ({
+      'parameters' => \&Gir::Handlers::Common::end_ignore,
+      'return-value' => \&Gir::Handlers::Common::end_ignore
+    })
+  );
+  $self->_set_subhandlers
+  ({
+    '*' => "Gir::Handlers::Ignore"
+  });
+
+  return bless ($self, $class);
+}
+
+1;
diff --git a/tools/pm/Gir/Handlers/Ignore.pm b/tools/pm/Gir/Handlers/Ignore.pm
index 5b77b98..b7a9eaa 100644
--- a/tools/pm/Gir/Handlers/Ignore.pm
+++ b/tools/pm/Gir/Handlers/Ignore.pm
@@ -5,8 +5,7 @@ use warnings;
 
 use parent qw(Gir::Handlers::Base);
 
-use Gir::Handlers::IgnoreEndStore;
-use Gir::Handlers::IgnoreStartStore;
+use Gir::Handlers::Stores::IgnoreStores;
 
 ##
 ## public:
@@ -15,20 +14,19 @@ sub new ($)
 {
   my $type = shift;
   my $class = (ref ($type) or $type or 'Gir::Handlers::Ignore');
-  my $self = $class->SUPER->new ();
+  my $self = $class->SUPER::new ();
 
   $self->_set_handlers
   (
-    Gir::Handlers::IgnoreStartStore->new (),
-    Gir::Handlers::IgnoreEndStore->new ()
+    Gir::Handlers::Stores::IgnoreStartStore->new (),
+    Gir::Handlers::Stores::IgnoreEndStore->new ()
   );
+  $self->_set_subhandlers
+  ({
+    '*' => "Gir::Handlers::Ignore"
+  });
 
   return bless ($self, $class);
 }
 
-sub get_subhandlers_for ($$)
-{
-  return Gir::Handlers::Ignore->new ();
-}
-
 1;
diff --git a/tools/pm/Gir/Handlers/Interface.pm b/tools/pm/Gir/Handlers/Interface.pm
new file mode 100644
index 0000000..0c66adc
--- /dev/null
+++ b/tools/pm/Gir/Handlers/Interface.pm
@@ -0,0 +1,90 @@
+package Gir::Handlers::Interface;
+
+use strict;
+use warnings;
+
+use parent qw(Gir::Handlers::Base);
+
+use Gir::Handlers::Common;
+use Gir::Handlers::Ignore;
+use Gir::Handlers::Stores::DocStores;
+use Gir::Parser;
+
+##
+## private:
+##
+sub _glib_signal_start ($$@)
+{
+  my ($self, $parser, @atts_vals) = @_;
+  my $params = Gir::Handlers::Common::extract_values_warn (['name'], ['action', 'deprecated', 'deprecated-version', 'detailed', 'introspectable', 'no-hooks', 'no-recurse', 'version', 'when'], \ atts_vals, 'interface/glib:signal');
+}
+
+sub _function_start ($$@)
+{
+  my ($self, $parser, @atts_vals) = @_;
+  my $params = Gir::Handlers::Common::extract_values_warn (['c:identifier', 'name'], ['deprecated', 'deprecated-version', 'introspectable', 'moved-to', 'shadowed-by', 'shadows', 'throws', 'version'], \ atts_vals, 'interface/function');
+}
+
+sub _method_start ($$@)
+{
+  my ($self, $parser, @atts_vals) = @_;
+  my $params = Gir::Handlers::Common::extract_values_warn (['c:identifier', 'name'], ['deprecated', 'deprecated-version', 'introspectable', 'shadowed-by', 'shadows', 'throws', 'version'], \ atts_vals, 'interface/method');
+}
+
+sub _prerequisite_start ($$@)
+{
+  my ($self, $parser, @atts_vals) = @_;
+  my $params = Gir::Handlers::Common::extract_values_warn (['name'], [], \ atts_vals, 'interface/prerequisite');
+}
+
+sub _property_start ($$@)
+{
+  my ($self, $parser, @atts_vals) = @_;
+  my $params = Gir::Handlers::Common::extract_values_warn (['name', 'transfer-ownership'], ['construct-only', 'construct', 'deprecated', 'deprecated-version', 'introspectable', 'readable', 'version', 'writable'], \ atts_vals, 'interface/property');
+}
+
+sub _virtual_method_start ($$@)
+{
+  my ($self, $parser, @atts_vals) = @_;
+  my $params = Gir::Handlers::Common::extract_values_warn (['name'], ['deprecated', 'deprecated-version', 'introspectable', 'invoker', 'throws', 'version'], \ atts_vals, 'interface/virtual-method');
+}
+
+##
+## public:
+##
+sub new ($)
+{
+  my $type = shift;
+  my $class = (ref ($type) or $type or 'Gir::Handlers::Interface');
+  my $self = $class->SUPER::new ();
+
+  $self->_set_handlers
+  (
+    Gir::Handlers::Stores::DocStartStore->new
+    ({
+      'glib:signal' => \&_glib_signal_start,
+      'function' => \&_function_start,
+      'method' => \&_method_start,
+      'prerequisite' => \&_prerequisite_start,
+      'property' => \&_property_start,
+      'virtual-method' => \&_virtual_method_start
+    }),
+    Gir::Handlers::Stores::DocEndStore->new
+    ({
+      'glib:signal' => \&Gir::Handlers::Common::end_ignore,
+      'function' => \&Gir::Handlers::Common::end_ignore,
+      'method' => \&Gir::Handlers::Common::end_ignore,
+      'prerequisite' => \&Gir::Handlers::Common::end_ignore,
+      'property' => \&Gir::Handlers::Common::end_ignore,
+      'virtual-method' => \&Gir::Handlers::Common::end_ignore
+    })
+  );
+  $self->_set_subhandlers
+  ({
+    '*' => "Gir::Handlers::Ignore"
+  });
+
+  return bless ($self, $class);
+}
+
+1;
diff --git a/tools/pm/Gir/Handlers/Namespace.pm b/tools/pm/Gir/Handlers/Namespace.pm
new file mode 100644
index 0000000..a8cbe5d
--- /dev/null
+++ b/tools/pm/Gir/Handlers/Namespace.pm
@@ -0,0 +1,139 @@
+package Gir::Handlers::Namespace;
+
+use strict;
+use warnings;
+
+use parent qw(Gir::Handlers::Base);
+
+use Gir::Handlers::Alias;
+use Gir::Handlers::Bitfield;
+use Gir::Handlers::Common;
+use Gir::Handlers::Callback;
+use Gir::Handlers::Class;
+use Gir::Handlers::Constant;
+use Gir::Handlers::Enumeration;
+use Gir::Handlers::Function;
+use Gir::Handlers::Interface;
+use Gir::Handlers::Record;
+use Gir::Handlers::Stores::Store;
+use Gir::Parser;
+
+##
+## private:
+##
+sub _alias_start ($$@)
+{
+  my ($self, $parser, @atts_vals) = @_;
+  my $params = Gir::Handlers::Common::extract_values_warn (['c:type', 'name'], [], \ atts_vals, 'alias');
+}
+
+sub _bitfield_start ($$@)
+{
+  my ($self, $parser, @atts_vals) = @_;
+  my $params = Gir::Handlers::Common::extract_values_warn (['c:type', 'name'], ['glib:get-type', 'glib:type-name', 'version'], \ atts_vals, 'bitfield');
+}
+
+sub _callback_start ($$@)
+{
+  my ($self, $parser, @atts_vals) = @_;
+  my $params = Gir::Handlers::Common::extract_values_warn (['name'], ['c:type', 'introspectable', 'throws', 'version'], \ atts_vals, 'callback');
+}
+
+sub _class_start ($$@)
+{
+  my ($self, $parser, @atts_vals) = @_;
+  my $params = Gir::Handlers::Common::extract_values_warn (['glib:get-type', 'glib:type-name', 'name'], ['abstract', 'c:symbol-prefix', 'c:type', 'glib:fundamental', 'glib:type-struct', 'parent', 'version'], \ atts_vals, 'class');
+}
+
+sub _constant_start ($$@)
+{
+  my ($self, $parser, @atts_vals) = @_;
+  my $params = Gir::Handlers::Common::extract_values_warn (['name', 'value'], [], \ atts_vals, 'constant');
+}
+
+sub _enumeration_start ($$@)
+{
+  my ($self, $parser, @atts_vals) = @_;
+  my $params = Gir::Handlers::Common::extract_values_warn (['c:type', 'name'], ['deprecated', 'deprecated-version', 'glib:error-domain', 'glib:get-type', 'glib:type-name', 'version'], \ atts_vals, 'enumeration');
+}
+
+sub _function_start ($$@)
+{
+  my ($self, $parser, @atts_vals) = @_;
+  my $params = Gir::Handlers::Common::extract_values_warn (['c:identifier', 'name'], ['deprecated', 'deprecated-version', 'introspectable', 'moved-to', 'shadowed-by', 'shadows', 'throws', 'version'], \ atts_vals, 'function');
+}
+
+sub _interface_start ($$@)
+{
+  my ($self, $parser, @atts_vals) = @_;
+  my $params = Gir::Handlers::Common::extract_values_warn (['c:symbol-prefix', 'c:type', 'glib:get-type', 'glib:type-name', 'name'], ['glib:type-struct', 'version'], \ atts_vals, 'interface');
+}
+
+sub _record_start ($$@)
+{
+  my ($self, $parser, @atts_vals) = @_;
+  my $params = Gir::Handlers::Common::extract_values_warn (['c:type', 'name'], ['c:symbol-prefix', 'deprecated', 'deprecated-version', 'disguised', 'foreign', 'glib:get-type', 'glib:is-gtype-struct-for', 'glib:type-name', 'introspectable', 'version'], \ atts_vals, 'record');
+}
+
+sub _union_start ($$@)
+{
+  my ($self, $parser, @atts_vals) = @_;
+  my $params = Gir::Handlers::Common::extract_values_warn (['c:type', 'name'], ['c:symbol-prefix', 'glib:get-type', 'glib:type-name'], \ atts_vals, 'union');
+}
+
+##
+## public:
+##
+sub new ($)
+{
+  my $type = shift;
+  my $class = (ref ($type) or $type or 'Gir::Handlers::Namespace');
+  my $self = $class->SUPER::new ();
+
+  $self->_set_handlers
+  (
+    Gir::Handlers::Stores::Store->new
+    ({
+      'class' => \&_class_start,
+      'interface' => \&_interface_start,
+      'enumeration' => \&_enumeration_start,
+      'bitfield' => \&_bitfield_start,
+      'record' => \&_record_start,
+      'function' => \&_function_start,
+      'callback' => \&_callback_start,
+      'alias' => \&_alias_start,
+      'constant' => \&_constant_start,
+      'union' => \&_union_start
+    }),
+    Gir::Handlers::Stores::Store->new
+    ({
+      'class' => \&Gir::Handlers::Common::end_ignore,
+      'interface' => \&Gir::Handlers::Common::end_ignore,
+      'enumeration' => \&Gir::Handlers::Common::end_ignore,
+      'bitfield' => \&Gir::Handlers::Common::end_ignore,
+      'record' => \&Gir::Handlers::Common::end_ignore,
+      'function' => \&Gir::Handlers::Common::end_ignore,
+      'callback' => \&Gir::Handlers::Common::end_ignore,
+      'alias' => \&Gir::Handlers::Common::end_ignore,
+      'constant' => \&Gir::Handlers::Common::end_ignore,
+      'union' => \&Gir::Handlers::Common::end_ignore
+    })
+  );
+  $self->_set_subhandlers
+  ({
+    'alias' => "Gir::Handlers::Alias",
+    'bitfield' => "Gir::Handlers::Bitfield",
+    'callback' => "Gir::Handlers::Callback",
+    'class' => "Gir::Handlers::Class",
+    'constant' => "Gir::Handlers::Constant",
+    'enumeration' => "Gir::Handlers::Enumeration",
+    'function' => "Gir::Handlers::Function",
+    'interface' => "Gir::Handlers::Interface",
+    'record' => "Gir::Handlers::Record",
+    '*' => "Gir::Handlers::Ignore"
+  });
+
+  return bless ($self, $class);
+}
+
+1;
diff --git a/tools/pm/Gir/Handlers/Record.pm b/tools/pm/Gir/Handlers/Record.pm
new file mode 100644
index 0000000..21cd774
--- /dev/null
+++ b/tools/pm/Gir/Handlers/Record.pm
@@ -0,0 +1,82 @@
+package Gir::Handlers::Record;
+
+use strict;
+use warnings;
+
+use parent qw(Gir::Handlers::Base);
+
+use Gir::Handlers::Common;
+use Gir::Handlers::Ignore;
+use Gir::Handlers::Stores::DocStores;
+use Gir::Parser;
+
+##
+## private:
+##
+sub _constructor_start ($$@)
+{
+  my ($self, $parser, @atts_vals) = @_;
+  my $params = Gir::Handlers::Common::extract_values_warn (['c:identifier', 'name'], ['deprecated', 'deprecated-version', 'introspectable', 'shadowed-by', 'shadows', 'throws', 'version'], \ atts_vals, 'record/constructor');
+}
+
+sub _field_start ($$@)
+{
+  my ($self, $parser, @atts_vals) = @_;
+  my $params = Gir::Handlers::Common::extract_values_warn (['name'], ['bits', 'private', 'readable', 'writable'], \ atts_vals, 'record/field');
+}
+
+sub _function_start ($$@)
+{
+  my ($self, $parser, @atts_vals) = @_;
+  my $params = Gir::Handlers::Common::extract_values_warn (['c:identifier', 'name'], ['deprecated', 'deprecated-version', 'introspectable', 'moved-to', 'shadowed-by', 'shadows', 'throws', 'version'], \ atts_vals, 'record/function');
+}
+
+sub _method_start ($$@)
+{
+  my ($self, $parser, @atts_vals) = @_;
+  my $params = Gir::Handlers::Common::extract_values_warn (['c:identifier', 'name'], ['deprecated', 'deprecated-version', 'introspectable', 'shadowed-by', 'shadows', 'throws', 'version'], \ atts_vals, 'record/method');
+}
+
+sub _union_start ($$@)
+{
+  my ($self, $parser, @atts_vals) = @_;
+  my $params = Gir::Handlers::Common::extract_values_warn (['c:type', 'name'], ['c:symbol-prefix', 'glib:get-type', 'glib:type-name'], \ atts_vals, 'record/union');
+}
+
+##
+## public:
+##
+sub new ($)
+{
+  my $type = shift;
+  my $class = (ref ($type) or $type or 'Gir::Handlers::Record');
+  my $self = $class->SUPER::new ();
+
+  $self->_set_handlers
+  (
+    Gir::Handlers::Stores::DocStartStore->new
+    ({
+      'constructor' => \&_constructor_start,
+      'field' => \&_field_start,
+      'function' => \&_function_start,
+      'method' => \&_method_start,
+      'union' => \&_union_start
+    }),
+    Gir::Handlers::Stores::DocEndStore->new
+    ({
+      'constructor' => \&Gir::Handlers::Common::end_ignore,
+      'field' => \&Gir::Handlers::Common::end_ignore,
+      'function' => \&Gir::Handlers::Common::end_ignore,
+      'method' => \&Gir::Handlers::Common::end_ignore,
+      'union' => \&Gir::Handlers::Common::end_ignore
+    })
+  );
+  $self->_set_subhandlers
+  ({
+    '*' => "Gir::Handlers::Ignore"
+  });
+
+  return bless ($self, $class);
+}
+
+1;
diff --git a/tools/pm/Gir/Handlers/Repository.pm b/tools/pm/Gir/Handlers/Repository.pm
index baf34b7..b1f4e1b 100644
--- a/tools/pm/Gir/Handlers/Repository.pm
+++ b/tools/pm/Gir/Handlers/Repository.pm
@@ -8,32 +8,37 @@ use parent qw(Gir::Handlers::Base);
 use Gir::Handlers::Common;
 use Gir::Handlers::Ignore;
 use Gir::Handlers::Namespace;
-use Gir::Handlers::Store;
+use Gir::Handlers::Stores::Store;
 use Gir::Parser;
 
 ##
 ## private:
 ##
+sub _include_start ($$@)
+{
+  my ($self, $parser, @atts_vals) = @_;
+  my $params = Gir::Handlers::Common::extract_values_warn (['name', 'version'], [], \ atts_vals, 'include');
+
+  $parser->parse_file ($params->{'name'} . '-' . $params->{'version'} . '.gir');
+}
+
 sub _namespace_start ($$@)
 {
   my ($self, $parser, @atts_vals) = @_;
-  my $params = Gir::Handlers::Common::extract_values (['name', 'version', 'shared-library', 'c:identifier-prefixes', 'c:symbol-prefixes'], [], \ atts_vals, 'namespace');
+  my $params = Gir::Handlers::Common::extract_values_warn (['name', 'version'], ['c:identifier-prefixes', 'c:prefix', 'c:symbol-prefixes', 'shared-library'], \ atts_vals, 'namespace');
   my $api = $parser->get_api ();
   my $name = $params->{'name'};
 
-  if ($api->has_namespace ($name))
-  {
+  #if ($api->has_namespace ($name))
+  #{
     # TODO: error? every gir probably should have different namespace, right?
-  }
-  $api->add_namespace ($name);
-}
+  #}
+  #$api->add_namespace ($name);
 
-sub _include_start ($$@)
-{
-  my ($self, $parser, @atts_vals) = @_;
-  my $params = extract_values_warn (['name', 'version'], [], \ atts_vals, 'include');
+  my $state = $parser->get_current_state ();
 
-  $parser->parse_file ($params->{'name'} . '-' . $params->{'version'});
+  print STDOUT 'Parsing ' . $state->get_parsed_file () . "\n";
+  $state->set_current_namespace ($name);
 }
 
 ##
@@ -43,11 +48,11 @@ sub new ($)
 {
   my $type = shift;
   my $class = (ref ($type) or $type or 'Gir::Handlers::Repository');
-  my $self = $class->SUPER->new ();
+  my $self = $class->SUPER::new ();
 
   $self->_set_handlers
   (
-    Gir::Handlers::Store->new
+    Gir::Handlers::Stores::Store->new
     ({
       'c:include' => \&Gir::Handlers::Common::start_ignore,
       'implementation' => \&Gir::Handlers::Common::start_ignore,
@@ -55,7 +60,7 @@ sub new ($)
       'namespace' => \&_namespace_start,
       'package' => \&Gir::Handlers::Common::start_ignore
     }),
-    Gir::Handlers::Store->new
+    Gir::Handlers::Stores::Store->new
     ({
       'c:include' => \&Gir::Handlers::Common::end_ignore,
       'implementation' => \&Gir::Handlers::Common::end_ignore,
@@ -64,20 +69,13 @@ sub new ($)
       'package' => \&Gir::Handlers::Common::end_ignore
     })
   );
+  $self->_set_subhandlers
+  ({
+    'namespace' => "Gir::Handlers::Namespace",
+    '*' => "Gir::Handlers::Ignore"
+  });
 
   return bless ($self, $class);
 }
 
-sub get_subhandlers_for ($$)
-{
-  my ($self, $elem) = @_;
-
-  if ($elem eq 'namespace')
-  {
-    return Gir::Handlers::Namespace->new ();
-  }
-  # rest is either ignored or has no children
-  return Gir::Handlers::Ignore->new ();
-}
-
 1;
diff --git a/tools/pm/Gir/Handlers/Stores/DocEndStore.pm b/tools/pm/Gir/Handlers/Stores/DocEndStore.pm
new file mode 100644
index 0000000..f60c2a5
--- /dev/null
+++ b/tools/pm/Gir/Handlers/Stores/DocEndStore.pm
@@ -0,0 +1,28 @@
+package Gir::Handlers::Stores::DocEndStore;
+
+use strict;
+use warnings;
+
+use parent qw(Gir::Handlers::Stores::Store);
+
+use Gir::Handlers::Common;
+
+##
+## public:
+##
+sub new ($$)
+{
+  my ($type, $handlers) = @_;
+  my $class = (ref ($type) or $type or 'Gir::Handlers::Stores::DocEndStore');
+
+  unless (exists ($handlers->{'doc'}))
+  {
+    $handlers->{'doc'} = \&Gir::Handlers::Common::doc_end;
+  }
+
+  my $self = $class->SUPER::new ($handlers);
+
+  return bless ($self, $class);
+}
+
+1;
diff --git a/tools/pm/Gir/Handlers/Stores/DocStartStore.pm b/tools/pm/Gir/Handlers/Stores/DocStartStore.pm
new file mode 100644
index 0000000..704a7da
--- /dev/null
+++ b/tools/pm/Gir/Handlers/Stores/DocStartStore.pm
@@ -0,0 +1,28 @@
+package Gir::Handlers::Stores::DocStartStore;
+
+use strict;
+use warnings;
+
+use parent qw(Gir::Handlers::Stores::Store);
+
+use Gir::Handlers::Common;
+
+##
+## public:
+##
+sub new ($$)
+{
+  my ($type, $handlers) = @_;
+  my $class = (ref ($type) or $type or 'Gir::Handlers::Stores::DocStartStore');
+
+  unless (exists ($handlers->{'doc'}))
+  {
+    $handlers->{'doc'} = \&Gir::Handlers::Common::doc_start;
+  }
+
+  my $self = $class->SUPER::new ($handlers);
+
+  return bless ($self, $class);
+}
+
+1;
diff --git a/tools/pm/Gir/Handlers/Stores/DocStores.pm b/tools/pm/Gir/Handlers/Stores/DocStores.pm
new file mode 100644
index 0000000..23c9855
--- /dev/null
+++ b/tools/pm/Gir/Handlers/Stores/DocStores.pm
@@ -0,0 +1,6 @@
+package Gir::Handlers::Stores::DocStores;
+
+use Gir::Handlers::Stores::DocStartStore;
+use Gir::Handlers::Stores::DocEndStore;
+
+1;
diff --git a/tools/pm/Gir/Handlers/IgnoreEndStore.pm b/tools/pm/Gir/Handlers/Stores/IgnoreEndStore.pm
similarity index 55%
rename from tools/pm/Gir/Handlers/IgnoreEndStore.pm
rename to tools/pm/Gir/Handlers/Stores/IgnoreEndStore.pm
index 40ed88a..d74b060 100644
--- a/tools/pm/Gir/Handlers/IgnoreEndStore.pm
+++ b/tools/pm/Gir/Handlers/Stores/IgnoreEndStore.pm
@@ -1,9 +1,9 @@
-package Gir::Handlers::IgnoreEndStore;
+package Gir::Handlers::Stores::IgnoreEndStore;
 
 use strict;
 use warnings;
 
-use parent qw(Gir::Handlers::Store);
+use parent qw(Gir::Handlers::Stores::Store);
 
 use Gir::Handlers::Common;
 
@@ -13,8 +13,8 @@ use Gir::Handlers::Common;
 sub new ($)
 {
   my $type = shift;
-  my $class = (ref ($type) or $type or 'Gir::Handlers::IgnoreEndStore');
-  my $self = $class->SUPER->new ({});
+  my $class = (ref ($type) or $type or 'Gir::Handlers::Stores::IgnoreEndStore');
+  my $self = $class->SUPER::new ({});
 
   return bless ($self, $class);
 }
diff --git a/tools/pm/Gir/Handlers/IgnoreStartStore.pm b/tools/pm/Gir/Handlers/Stores/IgnoreStartStore.pm
similarity index 55%
rename from tools/pm/Gir/Handlers/IgnoreStartStore.pm
rename to tools/pm/Gir/Handlers/Stores/IgnoreStartStore.pm
index 1b5d3f5..166d4dc 100644
--- a/tools/pm/Gir/Handlers/IgnoreStartStore.pm
+++ b/tools/pm/Gir/Handlers/Stores/IgnoreStartStore.pm
@@ -1,9 +1,9 @@
-package Gir::Handlers::IgnoreStartStore;
+package Gir::Handlers::Stores::IgnoreStartStore;
 
 use strict;
 use warnings;
 
-use parent qw(Gir::Handlers::Store);
+use parent qw(Gir::Handlers::Stores::Store);
 
 use Gir::Handlers::Common;
 
@@ -13,8 +13,8 @@ use Gir::Handlers::Common;
 sub new ($)
 {
   my $type = shift;
-  my $class = (ref ($type) or $type or 'Gir::Handlers::IgnoreStartStore');
-  my $self = $class->SUPER->new ({});
+  my $class = (ref ($type) or $type or 'Gir::Handlers::Stores::IgnoreStartStore');
+  my $self = $class->SUPER::new ({});
 
   return bless ($self, $class);
 }
diff --git a/tools/pm/Gir/Handlers/Stores/IgnoreStores.pm b/tools/pm/Gir/Handlers/Stores/IgnoreStores.pm
new file mode 100644
index 0000000..2043ca0
--- /dev/null
+++ b/tools/pm/Gir/Handlers/Stores/IgnoreStores.pm
@@ -0,0 +1,6 @@
+package Gir::Handlers::Stores::IgnoreStores;
+
+use Gir::Handlers::Stores::IgnoreStartStore;
+use Gir::Handlers::Stores::IgnoreEndStore;
+
+1;
diff --git a/tools/pm/Gir/Handlers/Store.pm b/tools/pm/Gir/Handlers/Stores/Store.pm
similarity index 81%
rename from tools/pm/Gir/Handlers/Store.pm
rename to tools/pm/Gir/Handlers/Stores/Store.pm
index 1fbcf9d..b7b59d4 100644
--- a/tools/pm/Gir/Handlers/Store.pm
+++ b/tools/pm/Gir/Handlers/Stores/Store.pm
@@ -1,4 +1,4 @@
-package Gir::Handlers::Store;
+package Gir::Handlers::Stores::Store;
 
 use strict;
 use warnings;
@@ -9,7 +9,7 @@ use warnings;
 sub new ($$)
 {
   my ($type, $methods) = @_;
-  my $class = (ref ($type) or $type or 'Gir::Handlers::Store');
+  my $class = (ref ($type) or $type or 'Gir::Handlers::Stores::Store');
   my $self =
   {
     'methods' => $methods
diff --git a/tools/pm/Gir/Handlers/TopLevel.pm b/tools/pm/Gir/Handlers/TopLevel.pm
index 59fd9f6..dca1f8d 100644
--- a/tools/pm/Gir/Handlers/TopLevel.pm
+++ b/tools/pm/Gir/Handlers/TopLevel.pm
@@ -7,7 +7,13 @@ use parent qw(Gir::Handlers::Base);
 
 use Gir::Handlers::Common;
 use Gir::Handlers::Repository;
-use Gir::Handlers::Store;
+use Gir::Handlers::Stores::Store;
+
+sub _repository_start ($$@)
+{
+  my ($self, $parser, @atts_vals) = @_;
+  my $params = Gir::Handlers::Common::extract_values_warn (['version', 'xmlns', 'xmlns:c'], ['c:identifier-prefixes', 'c:symbol-prefixes', 'xmlns:glib'], \ atts_vals, 'repository');
+}
 
 ##
 ## public:
@@ -16,22 +22,20 @@ sub new ($)
 {
   my $type = shift;
   my $class = (ref ($type) or $type or 'Gir::Handlers::TopLevel');
-  my $self = $class->SUPER->new ();
+  my $self = $class->SUPER::new ();
 
   $self->_set_handlers
   (
-    Gir::Handlers::Store->new ({ 'repository' => \&Gir::Handlers::Common::start_ignore }),
-    Gir::Handlers::Store->new ({ 'repository' => \&Gir::Handlers::Common::end_ignore })
+    Gir::Handlers::Stores::Store->new ({ 'repository' => \&_repository_start }),
+    Gir::Handlers::Stores::Store->new ({ 'repository' => \&Gir::Handlers::Common::end_ignore })
   );
+  $self->_set_subhandlers
+  ({
+    'repository' => "Gir::Handlers::Repository",
+    '*' => "Gir::Handlers::Ignore"
+  });
 
   return bless ($self, $class);
 }
 
-sub get_subhandlers_for ($$)
-{
-  my ($self, $elem) = @_;
-
-  return Gir::Handlers::Repository->new ();
-}
-
 1;
diff --git a/tools/pm/Gir/Parser.pm b/tools/pm/Gir/Parser.pm
index 289ceac..4e0a481 100644
--- a/tools/pm/Gir/Parser.pm
+++ b/tools/pm/Gir/Parser.pm
@@ -1,62 +1,130 @@
-package GirParser;
+package Gir::Parser;
 
 use strict;
 use warnings;
 
-use Gir::Handlers::Store;
+use Encode;
+
+use Gir::Config;
+use Gir::Handlers::Stores::Store;
 use Gir::State;
 
-use XML::Parser;
+use IO::File;
 
-sub _init ($)
-{
-  my $self = shift;
-  my $new_state = Gir::State->new ();
-  my $state_stack = $self->{'states_stack'};
+use XML::Parser::Expat;
 
-  push (@{$state_stack}, $new_state);
-  $self->{'state'} = $new_state;
+sub _print_error ($$$)
+{
+  my ($state, $error, $elem) = @_;
+  my $xml_parser = $state->get_xml_parser ();
+  my $msg = $state->get_parsed_file ()
+    . ':'
+    . $xml_parser->current_line ()
+    . ': '
+    . $error
+    . "\nTags stack:\n";
+  my @context = $xml_parser->context ();
+
+  foreach my $tag (@context)
+  {
+    $msg .= '  ' . $tag . "\n";
+  }
+  if (defined ($elem))
+  {
+    $msg .= '  ' . $elem . "\n";
+  }
+  print STDERR $msg;
 }
 
-sub _final ($)
+sub _get_file_contents_as_utf8 ($)
 {
-  my $self = shift;
-  my $state_stack = $self->{'states_stack'};
+  my $real_filename = shift;
+  my $xml = IO::File->new ($real_filename, 'r');
 
-  pop (@{$state_stack});
-  $self->{'state'} = $state_stack->[-1];
+  unless (defined ($xml))
+  {
+    #TODO: error;
+    print STDERR 'Could not open file: ' . $real_filename . ".\n";
+    exit (1);
+  }
+
+  my $file_size = ($xml->stat ())[7];
+  my $contents = undef;
+
+  unless ($xml->binmode (':raw'))
+  {
+    #TODO: error;
+    print STDERR "Calling binmode on " . $real_filename . " failed.\n";
+    exit (1);
+  }
+
+  my $bytes_read = $xml->read ($contents, $file_size);
+
+  if ($bytes_read != $file_size)
+  {
+    #TODO: error;
+    if (defined ($bytes_read))
+    {
+      print STDERR 'Read ' . $bytes_read . ' bytes from ' . $real_filename . ', wanted: ' . $file_size . " bytes.\n";
+    }
+    else
+    {
+      print STDERR 'Read error from ' . $real_filename . ".\n";
+    }
+    exit (1);
+  }
+  unless ($xml->close ())
+  {
+    print STDERR 'Closing ' . $real_filename . " failed.\n";
+    exit (1);
+  }
+  return decode ('utf-8', $contents);
 }
 
 sub _start ($$$@)
 {
-  my ($self, undef, $elem, @attval) = @_;
-  my $state = $self->{'current_state'};
+  my ($self, undef, $elem, @atts_vals) = @_;
+  my $state = $self->get_current_state ();
   my $handlers = $state->get_current_handlers ();
   my $start_handlers = $handlers->get_start_handlers ();
 
-  if ($start_handlers->has_method_for ($elem))
+  if (defined ($start_handlers))
   {
-    my $method = $start_handlers->get_method_for ($elem);
-    my $subhandlers = $handlers->get_subhandlers_for ($elem);
-
-    if (defined ($subhandlers))
+    if ($start_handlers->has_method_for ($elem))
     {
-      $state->push_handlers ($subhandlers);
-      return $handlers->$method ($self, @attval);
+      my $method = $start_handlers->get_method_for ($elem);
+      my $subhandlers = $handlers->get_subhandlers_for ($elem);
+
+      if (defined ($subhandlers))
+      {
+        $state->push_handlers ($subhandlers);
+        return $handlers->$method ($self, @atts_vals);
+      }
+      # TODO: internal error - wrong implementation of get_subhandlers_for?
+      _print_error ($state, 'Internal error - wrong implementation of get_subhandlers_for?', $elem);
+      exit (1);
     }
-    # TODO: internal error - wrong implementation of get_subhandlers_for?
+    # TODO: unknown elem?
+    _print_error ($state, 'Unknown tag: ' . $elem . '.', $elem);
+    exit (1);
   }
-  # TODO: unknown elem?
+  _print_error ($state, 'No start handlers: ' . $elem . '.', $elem);
+  exit (1);
 }
 
 sub _end ($$$)
 {
   my ($self, undef, $elem) = @_;
-  my $state = $self->{'current_state'};
+  my $state = $self->get_current_state ();
 
   $state->pop_handlers ();
 
   my $handlers = $state->get_current_handlers ();
+  unless (defined $handlers)
+  {
+    _print_error ($state, 'No handlers for tag: ' . $elem . '.', $elem);
+    exit (1);
+  }
   my $end_handlers = $handlers->get_end_handlers ();
 
   if ($end_handlers->has_method_for ($elem))
@@ -65,7 +133,8 @@ sub _end ($$$)
 
     return $handlers->$method ($self);
   }
-  # TODO: unknown elem?
+  _print_error ($state, 'Unknown tag: ' . $elem . '.', $elem);
+  exit (1);
 }
 
 #
@@ -80,8 +149,7 @@ sub new($)
   {
     'states_stack' => [],
     'parsed_girs' => {},
-    'state' => undef,
-    'api' => {} # TODO: replace with Gir::Api->new () or something like that.
+    'api' => {}, # TODO: replace with Gir::Api->new () or something like that.
   };
 
   return bless ($self, $class);
@@ -90,7 +158,7 @@ sub new($)
 sub _create_xml_parser ($)
 {
   my $self = shift;
-  my $xml_parser = XML::Parser->new ();
+  my $xml_parser = XML::Parser::Expat->new ();
 
   #TODO: implement commented methods.
   $xml_parser->setHandlers
@@ -99,8 +167,6 @@ sub _create_xml_parser ($)
 #    Comment => sub { $self->_comment (@_); },
 #    Default => sub { $self->_default (@_); },
     End => sub { $self->_end (@_); },
-    Final => sub { $self->_final (@_); },
-    Init => sub { $self->_init (@_); },
     Start => sub { $self ->_start (@_); },
 #    XMLDecl => sub { $self->_xmldecl (@_); }
   );
@@ -115,11 +181,20 @@ sub parse_file ($$)
 
   unless (exists ($parsed_girs->{$filename}))
   {
-    my $real_filename = File::Spec->catfile (GirConfig::get_girdir(), $filename);
+    my $real_filename = File::Spec->catfile (Gir::Config::get_girdir(), $filename);
     my $xml_parser = $self->_create_xml_parser ();
+    my $new_state = Gir::State->new ($real_filename, $xml_parser);
+    my $states_stack = $self->{'states_stack'};
 
     $parsed_girs->{$filename} = undef;
-    $xml_parser->parsefile ($real_filename);
+    push (@{$states_stack}, $new_state);
+
+    my $contents = _get_file_contents_as_utf8 ($real_filename);
+
+    $xml_parser->parse ($contents);
+    $xml_parser->release ();
+    pop (@{$states_stack});
+    #print STDOUT 'Parsed ' . $real_filename . "\n";
   }
 }
 
@@ -130,4 +205,12 @@ sub get_api ($)
   return $self->{'api'};
 }
 
+sub get_current_state ($)
+{
+  my $self = shift;
+  my $states_stack = $self->{'states_stack'};
+
+  return $states_stack->[-1];
+}
+
 1;
diff --git a/tools/pm/Gir/State.pm b/tools/pm/Gir/State.pm
index 18cfd01..6fafebb 100644
--- a/tools/pm/Gir/State.pm
+++ b/tools/pm/Gir/State.pm
@@ -7,13 +7,16 @@ use Gir::Handlers::TopLevel;
 ##
 ## public:
 ##
-sub new ($)
+sub new ($$$)
 {
-  my $type = shift;
+  my ($type, $parsed_file, $xml_parser) = @_;
   my $class = (ref ($type) or $type or 'Gir::State');
   my $self =
   {
-    'handlers_stack' => [Gir::Handlers::TopLevel->new ()]
+    'handlers_stack' => [Gir::Handlers::TopLevel->new ()],
+    'current_namespace' => undef,
+    'parsed_file' => $parsed_file,
+    'xml_parser' => $xml_parser
   };
 
   return bless ($self, $class);
@@ -43,4 +46,32 @@ sub get_current_handlers ($)
   return ${handlers_stack}->[-1];
 }
 
+sub get_current_namespace ($)
+{
+  my $self = shift;
+
+  return $self->{'current_namespace'};
+}
+
+sub set_current_namespace ($$)
+{
+  my ($self, $namespace) = @_;
+
+  $self->{'current_namespace'} = $namespace;
+}
+
+sub get_parsed_file ($)
+{
+  my $self = shift;
+
+  return $self->{'parsed_file'};
+}
+
+sub get_xml_parser ($)
+{
+  my $self = shift;
+
+  return $self->{'xml_parser'};
+}
+
 1;
diff --git a/tools/pm/Gir/metadata b/tools/pm/Gir/metadata
index 872f140..2d0e6b5 100644
--- a/tools/pm/Gir/metadata
+++ b/tools/pm/Gir/metadata
@@ -12,20 +12,21 @@ ATTR_FUNC: name c:identifier ?version? ?introspectable? ?deprecated? ?deprecated
 
 alias: name c:type
 array: ?zero-terminated? c:type ?fixed-size? ?length? // length is actually an index of parameter describing its length; fixed-size us specified for array[];
-bitfield: name ?version? glib:type-name glib:get-type c:type
-callback: name ?c:type? ?introspectable? ?version? ??deprecated?? ??deprecated-version??
-class: name, c:symbol-prefix, c:type, parent, abstract, glib:type-name, glib:get-type
+bitfield: name c:type ?version? ?glib:type-name? ?glib:get-type?
+callback: name c:type ?deprecated? ?deprecated-version? ?introspectable? ?version? ?throws?
+class: name c:symbol-prefix glib:type-name glib:get-type ?abstract? ?c:type? ?version? ?glib:type-struct? ?parent?]
+constant: name value
 constructor: name c:identifier ?version? ?deprecated? ?deprecated-version?
 c:include: {ignored}
 doc: // none important
-enumeration: name ?version? glib:type-name glib:get-type c:type
+enumeration: name c:type ?version? ?glib:type-name? ?glib:get-type? ?glib:error-quark? ?deprecated? ?deprecated-version?
 field: name ?writable? ?introspectable? ?readable? ?private?
-function: ATTR_FUNC
+function: name c:identifier ?introspectable? ?deprecated? ?deprecated-version? ?throws? ?version? ?shadowed-by? ?shadows?
 glib:signal: name when ?detailed? ?version? ??deprecated?? ??deprecated-version??
 implements: name
 implementation: {ignored}
 include: name version
-interface: name c:symbol-prefix c:type glib:type-name glib:get-type glib:type-struct ?version?
+interface: name c:symbol-prefix c:type glib:type-name glib:get-type ?glib:type-struct? ?version?
 member: name value c:identifier glib:nick
 method: ATTR_FUNC
 namespace: name, version, shared-library, c:identifier-prefixes, c:symbol-prefixes
@@ -34,11 +35,12 @@ parameters: // none
 parameter: name transfer-ownership ?allow-none? ?direction? ?caller-allocates?
 prerequisite: name
 property: name ?writable? ?construct-only? transfer-ownership ?version? ?readable? ?construct?
-record: name c:type ?disguised? ?glib:type-name? ?glib:get-type? ?c:symbol-prefix? ?glib:is-gtype-struct-for? ?version?
-repository: version
+record: name c:type ?glib:type-name? ?version? ?c:symbol-prefix? ?glib:get-type? ?glib:is-gtype-struct-for? ?disguised? ?introspectable? ?foreign?
+repository: version xmlns xmlns:c xmlns:glib
 return-value: transfer-ownership
 type: name ?c:type?
 virtual-method: name ?introspectable? ?invoker? ?version? ?throws? ??deprecated?? ??deprecated-version??
+union: name c:type ?glib:type-name? ?c:symbol-prefix? ?glib:get-type?
 
 ==============
 TAGS HIERARCHY
@@ -109,6 +111,9 @@ repository 1
 | | `-FUNC_COMMON 1
 | +-callback n
 | | `-FUNC_COMMON 1
+| +-union n
+| | +-CLASS_COMMON 1
+| | `-constructor n
 | +-alias n
 | | `-TYPE_COMMON 1
 | `-constant n
diff --git a/tools/pm/GobjectIntrospectionBUGS.txt b/tools/pm/GobjectIntrospectionBUGS.txt
new file mode 100644
index 0000000..5279945
--- /dev/null
+++ b/tools/pm/GobjectIntrospectionBUGS.txt
@@ -0,0 +1,18 @@
+gunixsocketaddress.c:288
+
+There is a gtk-doc comment:
+/**
+ * GUnixSocketAddress:abstract:
+ *
+ * Whether or not this is an abstract address
+ *
+ * Deprecated: Use #GUnixSocketAddress:address-type, which
+ * distinguishes between zero-padded and non-zero-padded
+ * abstract addresses.
+ */
+
+In gir file, attribute "deprecated" holds text:
+"Use #GUnixSocketAddress:address-type, which"
+the rest of lines is thrown away.
+
+========
diff --git a/tools/pm/girtest.pl b/tools/pm/girtest.pl
new file mode 100755
index 0000000..93233cf
--- /dev/null
+++ b/tools/pm/girtest.pl
@@ -0,0 +1,12 @@
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+
+push (@INC, '.');
+
+require Gir::Parser;
+
+my $parser = Gir::Parser->new ();
+
+$parser->parse_file ('GtkSource-3.0.gir');
diff --git a/tools/pm/metadatagetter.pl b/tools/pm/metadatagetter.pl
new file mode 100755
index 0000000..77cb7ef
--- /dev/null
+++ b/tools/pm/metadatagetter.pl
@@ -0,0 +1,240 @@
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+
+use File::Spec;
+
+use XML::Parser::Expat;
+
+# TODO: options: --output-file=<file>, --ignore-file=<file>
+# --output-file=<file> - result will be written to this file.
+# --ignore-file=<file> - path to file containing a list of gir files to ignore.
+
+unless (@ARGV)
+{
+  print STDERR "No files given.\n";
+}
+
+# $tag =>
+# {
+#   $attribute =>
+#   {
+#     '! #$_COUNT_$#@!' => $count,
+#     '! #$_VALUE_$#@!' => $value
+#   },
+#   '! #$_COUNT_$#@!' => $count
+# }
+my $tags = {};
+# $tag =>
+# {
+#   $kid1 =>
+#   {
+#     $grandkid1 => ...
+#     $grandkid2 => ...
+#     ...
+#   }
+#   $kid2 =>
+#   {
+#     $grandkid1 => ...
+#     $grandkid2 => ...
+#     ...
+#   }
+#   ...
+# }
+my $glob_tree = {};
+my $magic_count = '! #$_COUNT_$#@!';
+my $magic_value = '! #$_VALUE_$#@!';
+
+sub handle_tree ($$)
+{
+  my ($expat, $tag) = @_;
+  my @context = $expat->context;
+  my $root = $glob_tree;
+
+#  print STDERR "\n====\n";
+  foreach my $elem (@context)
+  {
+    unless (exists ($root->{$elem}))
+    {
+      $root->{$elem} = {};
+    }
+
+    my $href = $root->{$elem};
+
+#    print STDERR $elem . " (" . $href . ")\n";
+    $root = $href;
+  }
+  unless (exists ($root->{$tag}))
+  {
+    $root->{$tag} = {};
+  }
+
+#  print STDERR "TREE\n";
+
+#  foreach my $key (sort keys %{$glob_tree})
+#  {
+#    print STDERR $key . "\n";
+#  }
+}
+
+sub print_tree ($$);
+
+sub print_tree ($$)
+{
+  my ($subtree, $level) = @_;
+
+  foreach my $key (sort keys %{$subtree})
+  {
+    print STDOUT '  ' x $level . $key . "\n";
+    print_tree ($subtree->{$key}, $level + 1);
+  }
+}
+
+sub handle_attributes ($$@)
+{
+  my ($expat, $tag, @atts_vals) = @_;
+
+  unless (exists ($tags->{$tag}))
+  {
+    $tags->{$tag} = {$magic_count => 0};
+  }
+
+  my $elem = $tags->{$tag};
+  my $att = undef;
+
+  ++$elem->{$magic_count};
+  foreach my $entry (@atts_vals)
+  {
+    unless (defined ($att))
+    {
+      $att = $entry;
+    }
+    else
+    {
+      if (exists ($elem->{$att}))
+      {
+        my $attribute = $elem->{$att};
+
+        ++$attribute->{$magic_count};
+
+        if ($attribute->{$magic_value} ne $entry)
+        {
+          $attribute->{$magic_value} = '! #$$#@!';
+        }
+      }
+      else
+      {
+        $elem->{$att} = {$magic_count => 1, $magic_value => $entry};
+      }
+      $att = undef;
+    }
+  }
+}
+
+my %omit_files =
+(
+  'GTop-2.0.gir' => undef
+);
+
+my @used_files = ();
+my @omitted_files = ();
+
+for my $file (@ARGV)
+{
+  my (undef, undef, $basename) = File::Spec->splitpath ($file);
+
+  if (exists $omit_files{$basename})
+  {
+    print STDERR 'Omitting ' . $basename . ".\n";
+    push (@omitted_files, $basename);
+  }
+  else
+  {
+    print STDERR 'Parsing ' . $basename . ".\n";
+    push (@used_files, $basename);
+
+    my $parser = XML::Parser::Expat->new ();
+
+    $parser->setHandlers
+    (
+      'Start' => sub {handle_attributes ($_[0], $_[1], @_[2 .. @_ - 1]); handle_tree ($_[0], $_[1])}
+    );
+    $parser->parsefile ($file);
+    $parser->release ();
+  }
+}
+
+{
+  my $msg = "Metadata were generated by parsing the following files:\n";
+
+  foreach my $file (@used_files)
+  {
+    $msg .= $file . "\n";
+  }
+
+  if (@omitted_files > 0)
+  {
+    $msg .= "\nFollowing files were omitted:\n";
+
+    foreach my $file (sort @omitted_files)
+    {
+      $msg .= $file . "\n";
+    }
+  }
+  print STDOUT $msg;
+}
+
+print STDOUT "\n==========\n\n";
+
+foreach my $tag (sort keys (%{$tags}))
+{
+  my $elem = delete $tags->{$tag};
+  my $elem_count = delete $elem->{$magic_count};
+  my %mandatory_atts = ();
+  my %optional_atts = ();
+  my $any_mandatory = 0;
+  my $any_optional = 0;
+
+  foreach my $att (keys (%{$elem}))
+  {
+    my $attribute = delete $elem->{$att};
+    my $att_count = delete $attribute->{$magic_count};
+    my $att_value = delete $attribute->{$magic_value};
+
+    if ($att_count == $elem_count)
+    {
+      $mandatory_atts{$att} = $att_value;
+      $any_mandatory = 1;
+    }
+    else
+    {
+      $optional_atts{$att} = $att_value;
+      $any_optional = 1;
+    }
+  }
+
+  delete $tags->{$tag};
+
+  my $msg = "Tag:\n  Name: " . $tag . "\n";
+  if ($any_mandatory)
+  {
+    $msg .= "  Mandatory attributes:\n";
+    foreach my $att (sort keys %mandatory_atts)
+    {
+      $msg .= '    ' . $att . ' => ' . $mandatory_atts{$att} . "\n";
+    }
+  }
+  if ($any_optional)
+  {
+    $msg .= "  Optional attributes:\n";
+    foreach my $att (sort keys %optional_atts)
+    {
+      $msg .= '    ' . $att . ' => ' . $optional_atts{$att} . "\n";
+    }
+  }
+  print STDOUT $msg;
+}
+
+print STDOUT "\n==========\n\n";
+print_tree ($glob_tree, 0);
diff --git a/tools/pm/moduleslist b/tools/pm/moduleslist
new file mode 100644
index 0000000..429b04c
--- /dev/null
+++ b/tools/pm/moduleslist
@@ -0,0 +1 @@
+{{Atk-1,Gdk-3,GdkPixbuf-2,GdkX11-3,Gio-2,GLib-2,GModule-2,GObject-2,Gtk-3,GtkSource-3,Pango-1,PangoCairo-1,PangoFT2-1,PangoXft-1}.0.gir,Vte-2.90.gir}
diff --git a/tools/pm/taghandlerwriter.pl b/tools/pm/taghandlerwriter.pl
new file mode 100755
index 0000000..af5dff0
--- /dev/null
+++ b/tools/pm/taghandlerwriter.pl
@@ -0,0 +1,250 @@
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+
+use File::Spec;
+
+use XML::Parser::Expat;
+
+# TODO: options: --output-dir=<dir>, --ignore-file=<file>
+# --output-dir=<dir> - all files will be written into this directory.
+# --ignore-file=<file> - path to file containing a list of gir files to ignore.
+# TODO: generate tag handlers packages too?
+
+unless (@ARGV)
+{
+  print STDERR "No files given.\n";
+}
+
+# $tag =>
+# {
+#   $attribute =>
+#   {
+#     '! #$_COUNT_$#@!' => $count,
+#     '! #$_VALUE_$#@!' => $value
+#   },
+#   '! #$_COUNT_$#@!' => $count
+# }
+my $tags = {};
+# $tag =>
+# {
+#   $kid1 =>
+#   {
+#     $grandkid1 => ...
+#     $grandkid2 => ...
+#     ...
+#   }
+#   $kid2 =>
+#   {
+#     $grandkid1 => ...
+#     $grandkid2 => ...
+#     ...
+#   }
+#   ...
+# }
+my $glob_tree = {};
+my $magic_count = '! #$_COUNT_$#@!';
+my $magic_value = '! #$_VALUE_$#@!';
+
+sub handle_tree ($$)
+{
+  my ($expat, $tag) = @_;
+  my @context = $expat->context;
+  my $root = $glob_tree;
+
+#  print STDERR "\n====\n";
+  foreach my $elem (@context)
+  {
+    unless (exists ($root->{$elem}))
+    {
+      $root->{$elem} = {};
+    }
+
+    my $href = $root->{$elem};
+
+#    print STDERR $elem . " (" . $href . ")\n";
+    $root = $href;
+  }
+  unless (exists ($root->{$tag}))
+  {
+    $root->{$tag} = {};
+  }
+
+#  print STDERR "TREE\n";
+
+#  foreach my $key (sort keys %{$glob_tree})
+#  {
+#    print STDERR $key . "\n";
+#  }
+}
+
+sub print_tree ($$);
+
+sub print_tree ($$)
+{
+  my ($subtree, $level) = @_;
+
+  foreach my $key (sort keys %{$subtree})
+  {
+    print STDOUT '  ' x $level . $key . "\n";
+    print_tree ($subtree->{$key}, $level + 1);
+  }
+}
+
+sub handle_attributes ($$@)
+{
+  my ($expat, $tag, @atts_vals) = @_;
+
+  unless (exists ($tags->{$tag}))
+  {
+    $tags->{$tag} = {$magic_count => 0};
+  }
+
+  my $elem = $tags->{$tag};
+  my $att = undef;
+
+  ++$elem->{$magic_count};
+  foreach my $entry (@atts_vals)
+  {
+    unless (defined ($att))
+    {
+      $att = $entry;
+    }
+    else
+    {
+      if (exists ($elem->{$att}))
+      {
+        my $attribute = $elem->{$att};
+
+        ++$attribute->{$magic_count};
+
+        if ($attribute->{$magic_value} ne $entry)
+        {
+          $attribute->{$magic_value} = '! #$$#@!';
+        }
+      }
+      else
+      {
+        $elem->{$att} = {$magic_count => 1, $magic_value => $entry};
+      }
+      $att = undef;
+    }
+  }
+}
+
+my %omit_files =
+(
+  'DBus-1.0.gir' => undef,
+  'DBusGLib-1.0.gir' => undef,
+  'fontconfig-2.0.gir' => undef,
+  'freetype2-2.0.gir' => undef,
+  'GL-1.0.gir' => undef,
+  'GTop-2.0.gir' => undef,
+  'libxml2-2.0.gir' => undef,
+  'xfixes-4.0.gir' => undef,
+  'xft-2.0.gir' => undef,
+  'xrandr-1.3.gir' => undef
+);
+
+my @used_files = ();
+my @omitted_files = ();
+
+for my $file (@ARGV)
+{
+  my (undef, undef, $basename) = File::Spec->splitpath ($file);
+
+  if (exists $omit_files{$basename})
+  {
+    print STDERR 'Omitting ' . $basename . ".\n";
+    push (@omitted_files, $basename);
+  }
+  else
+  {
+    print STDERR 'Parsing ' . $basename . ".\n";
+    push (@used_files, $basename);
+
+    my $parser = XML::Parser::Expat->new ();
+
+    $parser->setHandlers
+    (
+      'Start' => sub {handle_attributes ($_[0], $_[1], @_[2 .. @_ - 1]); handle_tree ($_[0], $_[1])}
+    );
+    $parser->parsefile ($file);
+    $parser->release ();
+  }
+}
+
+my $contents = "#This file was generated by taghandlerwriter.pl script.\n\npackage Gir::Handlers::Generated::Tags;\n\n";
+
+foreach my $tag (sort keys (%{$tags}))
+{
+  my $elem = delete $tags->{$tag};
+  my $elem_count = delete $elem->{$magic_count};
+  my %mandatory_atts = ();
+  my %optional_atts = ();
+  my $any_mandatory = 0;
+  my $any_optional = 0;
+
+  foreach my $att (keys (%{$elem}))
+  {
+    my $attribute = delete $elem->{$att};
+    my $att_count = delete $attribute->{$magic_count};
+    my $att_value = delete $attribute->{$magic_value};
+
+    if ($att_count == $elem_count)
+    {
+      $mandatory_atts{$att} = $att_value;
+      $any_mandatory = 1;
+    }
+    else
+    {
+      $optional_atts{$att} = $att_value;
+      $any_optional = 1;
+    }
+  }
+
+  delete $tags->{$tag};
+
+  my $func_tag = lc ($tag);
+
+  $func_tag =~ s/\W+/_/g;
+  $contents .= 'sub ' . $func_tag . "_start (@)\n{\n  return Gir::Handlers::Common::extract_values\n  (\n    [\n";
+
+  {
+    my @atts = sort keys %mandatory_atts;
+    my $iter = 0;
+
+    foreach my $att (@atts)
+    {
+      ++$iter;
+      $contents .= "      '" . $att . "'";
+      if ($iter != @atts)
+      {
+        $contents .= ',';
+      }
+      $contents .= "\n";
+    }
+  }
+
+  $contents .= "    ],\n    [\n";
+
+  {
+    my @atts = sort keys %optional_atts;
+    my $iter = 0;
+
+    foreach my $att (@atts)
+    {
+      ++$iter;
+      $contents .= "      '" . $att . "'";
+      if ($iter != @atts)
+      {
+        $contents .= ',';
+      }
+      $contents .= "\n";
+    }
+  }
+  $contents .= "    ],\n    \\\ _\n  );\n}\n\n";
+}
+
+print STDOUT $contents;



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