@@ -0,0 +1,149 @@
+#! /usr/bin/perl -w
+
+use File::Basename;
+use File::Path;
+use File::Find;
+use Getopt::Long;
+use strict;
+
+my %symbol_type_name = (
+ n => 'normal', t => 'typedef', e => 'enum', s => 'struct', u => 'union'
+);
+
+my %definitions;
+my %override;
+my %override_locally;
+my %locally_unknown;
+my %locally_defined;
+
+sub expand_types($);
+sub expand_types($) {
+ my ($definition) = @_;
+ local ($_, $1, $2);
+
+ my @defn = split ' ', $definition;
+ for (@defn[1..$#defn]) {
+ if (/^(.)#(.*)/) {
+ #print "<<$defn[0] : $_>>\n";
+ next if exists $locally_defined{$_};
+ $locally_defined{$_} = 1;
+
+ if ($locally_unknown{$_}) {
+ print "$_ $symbol_type_name{$1} $2 { UNKNOWN } \n";
+ } else {
+ if (!exists $definitions{$_}) {
+ die "Missing definition of $symbol_type_name{$1} $2\n";
+ }
+ expand_types("$_ $definitions{$_}");
+ }
+ }
+ }
+ print "override " if $override_locally{$defn[0]};
+ print "$definition\n";
+}
+
+sub pack_dump($$) {
+ my ($dir, $ext) = @_;
+ my @files;
+
+ $ext = ".symtypes" unless defined $ext;
+
+ find(sub ($) { /\Q$ext\E$/ && push @files, $File::Find::name}, $dir);
+ map { s/^\Q$dir\E\/(.*)\Q$ext\E$/$1/ } @files;
+
+ foreach my $file (sort @files) {
+ print "/* $file.o */\n";
+
+ local *FD;
+ open FD, "< $dir/$file$ext"
+ or die "$dir/$file$ext: $!\n";
+ while (<FD>) {
+ chomp;
+
+ my $override = "";
+ if (s/^override //) {
+ $override = $&;
+ }
+
+ if (/^(\S)#(\S+)\s*(.*)/) {
+ my $sym = "$1#$2";
+ my $definition = $3;
+
+ if (/^$sym\s+$symbol_type_name{$1}\s+$2\s+{\s+UNKNOWN\s+}\s*$/) {
+ $_ = $override . substr($sym, 0, 1) . "##" . substr($sym, 2);
+ } else {
+ if (exists $definitions{$sym} && $definitions{$sym} eq $definition) {
+ if (($override ne "") == (exists $override{$sym})) {
+ next;
+ }
+ $_ = "$override$sym";
+ } else {
+ $definitions{$sym} = $definition;
+ if ($override eq "") {
+ delete $override{$sym};
+ } else {
+ $override{$sym} = 1;
+ }
+ }
+ }
+ }
+ print "$_\n";
+ }
+ close FD;
+ print "\n";
+ }
+}
+
+sub unpack_dump($$) {
+ my ($dir, $ext) = @_;
+
+ $ext = ".symref" unless defined $ext;
+
+ while (<STDIN>) {
+ next if /^$/;
+ chomp;
+
+ if (/^\/\* (.*)\.o \*\//) {
+ close STDOUT;
+ mkpath(dirname("$dir/$1$ext"));
+ open STDOUT, "> $dir/$1$ext"
+ or die "$dir/$1$ext: $!\n";
+ %locally_defined = ();
+ %locally_unknown = ();
+ %override_locally = %override;
+ next;
+ }
+
+ my $override = /^override\s/;
+
+ if (/^([^ ])#(#?)([^ ]+) *(.*)$/) {
+ my $sym = "$1#$3";
+
+ if ($4 ne "") {
+ if (/\s+{\s+UNKNOWN\s+}\s*$/) {
+ $locally_unknown{$sym} = 1;
+ $override_locally{$sym} = $override;
+ } else {
+ $definitions{$sym} = $4;
+ $locally_unknown{$sym} = 0;
+ $override{$sym} = $override;
+ $override_locally{$sym} = $override;
+ }
+ } else {
+ $locally_unknown{$sym} = ($2 ne "");
+ $override_locally{$sym} = $override;
+ }
+ next;
+ }
+ expand_types($_);
+ }
+}
+
+my ($pack, $unpack, $ext);
+GetOptions("pack" => \$pack, "unpack" => \$unpack, "ext:s" => \$ext)
+ && ($pack || $unpack) && @ARGV == 1
+ or die "USAGE:\t$0 [--ext extension] --pack {dir} > file\n" .
+ "\t$0 [--ext extension] --unpack {dir} < file\n";
+
+pack_dump($ARGV[0], $ext) if $pack;
+unpack_dump($ARGV[0], $ext) if $unpack;
|