Initial commit of OpenSPARC T2 design and verification files.
[OpenSPARC-T2-DV] / tools / perl-5.8.0 / lib / site_perl / 5.8.0 / sun4-solaris / Tk / pTk / mkVFunc
#!/usr/local/bin/perl -w
use strict;
my %Ignore;
my %Ignored;
my %WinIgnore;
my %Exclude;
my $oops = 0;
use Getopt::Std;
my %opt;
getopts('mt',\%opt);
my @Files;
sub openRO
{
my ($fh,$file) = @_;
if (-f $file && !-w $file)
{
chmod(0666,$file) || warn "Cannot change permissions on $file:$!";
}
open($fh,">$file") || return 0;
push(@Files,$file);
return 1;
}
END
{
while (@Files)
{
my $file = pop(@Files);
if (-f $file)
{
chmod(0444,$file) || warn "Cannot change permissions on $file:$!";
}
}
}
my $win_arch = shift;
die "Unknown \$win_arch" unless $win_arch eq 'open32'
or $win_arch eq 'pm'
or $win_arch eq 'x'
or $win_arch eq 'MSWin32';
my $xexcl = <<EOM;
#if (defined(__WIN32__) || defined(__PM__)) && !defined(DO_X_EXCLUDE)
# define DO_X_EXCLUDE
#endif
EOM
sub Ignore
{
my $cfile = shift;
if (open(C,"<$cfile"))
{
while (<C>)
{
if (/^([A-Za-z][A-Za-z0-9_]*)/)
{
$Ignore{$1} = $cfile;
}
}
close(C);
}
else
{
warn "Cannot open $cfile:$!";
}
}
sub WinIgnore
{
my $cfile = shift;
if (open(C,"<$cfile"))
{
while (<C>)
{
if (/^([A-Za-z][A-Za-z0-9_]*)/)
{
$WinIgnore{$1} = $cfile;
}
}
close(C);
}
else
{
warn "Cannot open $cfile:$!";
}
}
sub Exclude
{
my $cfile = shift;
if (open(C,"<$cfile"))
{
while (<C>)
{
if (/{\s*\"[^\"]+\"\s*,\s*(\w+)\s*}/)
{
$Exclude{$1} = $cfile;
}
}
close(C);
}
else
{
warn "Cannot open $cfile:$!";
}
}
sub Vfunc
{
my $hfile = shift;
my %VFunc = ();
my %VVar = ();
my %VError= ();
open(H,"<$hfile") || die "Cannot open $hfile:$!";
while (<H>)
{
if (/^\s*(MOVEXT|COREXT|EXTERN|extern)\s*(.*?)\s*(\w+)\s+_ANSI_ARGS_\s*\((TCL_VARARGS)?\(/)
{
my ($type,$name,$op) = ($2,$3,$4);
if ($1 eq 'MOVEXT' || $1 eq 'COREXT')
{
warn "$1 $name\n";
$oops++;
$Ignore{$name} = $hfile;
}
$op = "" unless (defined $op);
my $defn = "VFUNC($type,$name,V_$name,_ANSI_ARGS_($op(";
$_ = $';
until (/\)\);\s*$/)
{
$defn .= $_;
$_ = <H>;
if (/^\S/)
{
chomp($_);
die $_;
}
}
s/\)\);\s*$/\)\)\)\n/;
$defn .= $_;
$VFunc{$name} = $defn;
}
elsif (/^\s*(MOVEXT|COREXT|EXTERN|extern)\s*(.*?)\s*(\w+)\s*;/)
{
my ($type,$name) = ($2,$3);
if ($1 eq 'MOVEXT' || $1 eq 'COREXT')
{
warn "$1 $name\n";
$oops++;
$Ignore{$name} = $hfile;
}
$VVar{$name} = "VVAR($type,$name,V_$name)\n";
}
elsif (/\b(EXTERN|extern)\s+[\w_]+\s+[\w_]+\[\];$/)
{
}
elsif (/\b(EXTERN|extern)\s*"C"\s*\{\s*$/)
{
}
elsif (/\b(EXTERN|extern)\b/)
{
warn "$hfile:$.: $_" unless (/^\s*\#\s*define/);
}
}
close(H);
if (keys %VFunc || keys %VVar)
{
my $gard = "\U$hfile";
$gard =~ s/\..*$//;
$gard =~ s#/#_#g;
my $name = "\u\L${gard}\UV";
my $fdef = $hfile;
$fdef =~ s/\..*$/.t/;
my $mdef = $hfile;
$mdef =~ s/\..*$/.m/;
$mdef .= 'dmy' unless $opt{'m'};
$fdef .= 'dmy' unless $opt{'t'};
my $htfile = $hfile;
$htfile =~ s/\..*$/_f.h/;
unless (-r $htfile)
{
openRO(\*C,$htfile) || die "Cannot open $htfile:$!";
print C "#ifndef ${gard}_VT\n";
print C "#define ${gard}_VT\n";
print C "typedef struct ${name}tab\n{\n";
print C "#define VFUNC(type,name,mem,args) type (*mem) args;\n";
print C "#define VVAR(type,name,mem) type (*mem);\n";
print C "#include \"$fdef\"\n";
print C "#undef VFUNC\n";
print C "#undef VVAR\n";
print C "} ${name}tab;\n";
print C "extern ${name}tab *${name}ptr;\n";
print C "extern ${name}tab *${name}Get _ANSI_ARGS_((void));\n";
print C "#endif /* ${gard}_VT */\n";
close(C);
}
my $cfile = $hfile;
$cfile =~ s/\..*$/_f.c/;
unless (-r $cfile)
{
openRO(\*C,$cfile) || die "Cannot open $cfile:$!";
print C "#include \"$hfile\"\n";
print C "#include \"$htfile\"\n";
print C "static ${name}tab ${name}table =\n{\n";
print C "#define VFUNC(type,name,mem,args) name,\n";
print C "#define VVAR(type,name,mem) &name,\n";
print C "#include \"$fdef\"\n";
print C "#undef VFUNC\n";
print C "#undef VVAR\n";
print C "};\n";
print C "${name}tab *${name}ptr;\n";
print C "${name}tab *${name}Get() { return ${name}ptr = &${name}table;}\n";
close(C);
}
print STDERR "$gard\n";
openRO(\*VFUNC,$fdef) || die "Cannot open $fdef:$!";
openRO(\*VMACRO,$mdef) || die "Cannot open $mdef:$!";
print VFUNC "#ifdef _$gard\n";
print VMACRO "#ifndef _${gard}_VM\n";
print VMACRO "#define _${gard}_VM\n";
print VMACRO "#include \"$htfile\"\n";
print VMACRO "#ifndef NO_VTABLES\n";
print VMACRO $xexcl if %WinIgnore;
print VFUNC $xexcl if %WinIgnore;
foreach my $func (sort keys %VVar)
{
if (!exists($Exclude{$func}) && !exists($Ignore{$func}))
{
print VFUNC $VVar{$func};
print VMACRO "#define $func (*${name}ptr->V_$func)\n";
}
$Ignored{$func} = delete $Ignore{$func} if exists $Ignore{$func};
}
foreach my $func (sort keys %VFunc)
{
if (!exists($Exclude{$func}) && !exists($Ignore{$func}))
{
print VFUNC "#ifndef DO_X_EXCLUDE\n" if exists($WinIgnore{$func});
print VFUNC "#ifndef $func\n";
print VFUNC $VFunc{$func};
print VFUNC "#endif\n";
print VFUNC "#endif /* !DO_X_EXCLUDE */\n" if exists($WinIgnore{$func});
print VFUNC "\n";
print VMACRO "#ifndef DO_X_EXCLUDE\n" if exists($WinIgnore{$func});
print VMACRO "#ifndef $func\n";
print VMACRO "# define $func (*${name}ptr->V_$func)\n";
print VMACRO "#endif\n";
print VMACRO "#endif /* !DO_X_EXCLUDE */\n" if exists($WinIgnore{$func});
print VMACRO "\n";
}
$Ignored{$func} = delete $Ignore{$func} if exists $Ignore{$func};
}
print VMACRO "#endif /* NO_VTABLES */\n";
print VMACRO "#endif /* _${gard}_VM */\n";
close(VMACRO);
print VFUNC "#endif /* _$gard */\n";
close(VFUNC); # Close this last - Makefile dependancy
unlink($mdef) unless $opt{'m'};
unlink($fdef) unless $opt{'t'};
}
}
foreach (<tk*Tab.c>)
{
Exclude($_);
}
die "Usage: $0 <some.h>\n" if (@ARGV != 1);
my $h = shift;
my $x = $h;
$x =~ s/\.h/.exc/;
Ignore($x) if (-f $x);
$x =~ s/\.exc/.excwin/;
WinIgnore($x) if (-f $x);
Vfunc($h);
foreach my $s (sort keys %Ignore)
{
warn "$s is not in $h\n";
$oops++;
}
if ($oops)
{
$x = $h;
$x =~ s/\.h/.exc/;
rename($x,"$x.old") || die "Cannot rename $x to $x.old:$!";
open(EXC,">$x") || die "Cannot open $x:$!";
foreach my $s (sort keys %Ignored)
{
print EXC $s,"\n";
}
close(EXC);
}
__END__
=head1 NAME
mkVFunc - Support for "nested" dynamic loading
=head1 SYNOPSIS
mkVFunc xxx.h
=head1 DESCRIPTION
B<perl/Tk> is designed so that B<Tk> can be dynamically loaded 'on top of'
perl. That is the easy bit. What it also does is allow Tk::Xxxx to be
dynamically loaded 'on top of' the B<perl/Tk> composite. Thus when
you 'require Tk::HList' the shared object F<.../HList.so> needs to be
able to call functions defined in perl I<and> functions defined in loadable
.../Tk.so . Now functions in 'base executable' are a well known problem,
and are solved by DynaLoader. However most of dynamic loading schemes
cannot handle one loadable calling another loadable.
Thus what Tk does is build a table of functions that should be callable.
This table is auto-generated from the .h file by looking for
'extern' (and EXTERN which is #defined to 'extern').
Thus any function marked as 'extern' is 'referenced' by the table.
The address of the table is then stored in a perl variable when Tk is loaded.
When HList is loaded it looks in the perl variable (via functions
in perl - the 'base executable') to get the address of the table.
The same utility that builds the table also builds a set of #define's.
HList.c (and any other .c files which comprise HList) #include these
#define's. So that
Tk_SomeFunc(x,y,z)
Is actually compiled as
(*TkVptr->V_Tk_SomeFunc)(x,y,z)
Where Tk_ptr is pointer to the table.
See:
Tk-b*/pTk/mkVFunc - perl script that produces tables
/tk.h - basis from which table is generated
/tk.m - #define's to include in sub-extension
/tk_f.h - #included both sides.
/tk_f.c - Actual table definition.
/tk.t - 'shared' set of macros which produce table
included in tk_f.c and tk_f.h
/tkVMacro.h - Wrapper to include *.m files
In addition to /tk* there are /tkInt*, /Lang* and /tix*
=cut