#! /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', E => 'enum constant' ); 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 "override " if $override_locally{$_}; 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; $dir =~ s/\/+$//; 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 () { 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; $_ = "$override$_"; } } } } elsif ($override) { $_ = "$override$_"; } print "$_\n"; } close FD; print "\n"; } } sub unpack_dump($$) { my ($dir, $ext) = @_; $ext = ".symref" unless defined $ext; while () { 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/; s/^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; } elsif (/^([^# ]*)/) { $override_locally{$1} = $override; } 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;