summaryrefslogtreecommitdiff
path: root/lib/AutoSplit.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/AutoSplit.pm')
-rw-r--r--lib/AutoSplit.pm225
1 files changed, 225 insertions, 0 deletions
diff --git a/lib/AutoSplit.pm b/lib/AutoSplit.pm
new file mode 100644
index 0000000000..dabf43cbb8
--- /dev/null
+++ b/lib/AutoSplit.pm
@@ -0,0 +1,225 @@
+package AutoSplit;
+
+require 5.000;
+require Exporter;
+
+use Config;
+use Carp;
+
+@ISA = qw(Exporter);
+@EXPORT = qw(&autosplit &autosplit_lib_modules);
+@EXPORT_OK = qw($Verbose $Keep);
+
+# for portability warn about names longer than $maxlen
+$Maxlen = 8; # 8 for dos, 11 (14-".al") for SYSVR3
+$Verbose = 1; # 0=none, 1=minimal, 2=list .al files
+$Keep = 0;
+$IndexFile = "autosplit.ix"; # file also serves as timestamp
+
+$maxflen = 255;
+$maxflen = 14 if $Config{'d_flexfnam'} ne 'define';
+$vms = ($Config{'osname'} eq 'VMS');
+
+sub autosplit{
+ my($file, $autodir) = @_;
+ autosplit_file($file, $autodir, $Keep, 1, 0);
+}
+
+
+
+# This function is used during perl building/installation
+# ./miniperl -e 'use AutoSplit; autosplit_modules(@ARGV)' ...
+
+sub autosplit_lib_modules{
+ my(@modules) = @_; # list of Module names
+
+ foreach(@modules){
+ s#::#/#g; # incase specified as ABC::XYZ
+ s#^lib/##; # incase specified as lib/*.pm
+ if ($vms && /[:>\]]/) { # may need to convert VMS-style filespecs
+ my ($dir,$name) = (/(.*])(.*)/);
+ $dir =~ s/.*lib[\.\]]//;
+ $dir =~ s#[\.\]]#/#g;
+ $_ = $dir . $name;
+ }
+ autosplit_file("lib/$_", "lib/auto", $Keep, 1, 1);
+ }
+ 0;
+}
+
+
+# private functions
+
+sub autosplit_file{
+ my($filename, $autodir, $keep, $check_for_autoloader, $check_mod_time) = @_;
+ my(@names);
+
+ # where to write output files
+ $autodir = "lib/auto" unless $autodir;
+ die "autosplit directory $autodir does not exist" unless -d $autodir;
+
+ # allow just a package name to be used
+ $filename .= ".pm" unless ($filename =~ m/\.pm$/);
+
+ open(IN, "<$filename") || die "AutoSplit: Can't open $filename: $!\n";
+ my($pm_mod_time) = (stat($filename))[9];
+ my($autoloader_seen) = 0;
+ while (<IN>) {
+ # record last package name seen
+ $package = $1 if (m/^\s*package\s+([\w:]+)\s*;/);
+ ++$autoloader_seen if m/^\s*use\s+AutoLoader\b/;
+ ++$autoloader_seen if m/\bISA\s*=.*\bAutoLoader\b/;
+ last if /^__END__/;
+ }
+ return 0 if ($check_for_autoloader && !$autoloader_seen);
+ $_ or die "Can't find __END__ in $filename\n";
+
+ $package or die "Can't find 'package Name;' in $filename\n";
+
+ my($modpname) = $package; $modpname =~ s#::#/#g;
+ my($al_idx_file) = "$autodir/$modpname/$IndexFile";
+
+ die "Package $package does not match filename $filename"
+ unless ($filename =~ m/$modpname.pm$/ or
+ $vms && $filename =~ m/$modpname.pm/i);
+
+ if ($check_mod_time){
+ my($al_ts_time) = (stat("$al_idx_file"))[9] || 1;
+ if ($al_ts_time >= $pm_mod_time){
+ print "AutoSplit skipped ($al_idx_file newer that $filename)\n"
+ if ($Verbose >= 2);
+ return undef; # one undef, not a list
+ }
+ }
+
+ my($from) = ($Verbose>=2) ? "$filename => " : "";
+ print "AutoSplitting $package ($from$autodir/$modpname)\n"
+ if $Verbose;
+
+ unless (-d "$autodir/$modpname"){
+ local($", @p)="/";
+ foreach(split(/\//,"$autodir/$modpname")){
+ push(@p, $_);
+ next if -d "@p";
+ mkdir("@p",0777) or die "AutoSplit unable to mkdir @p: $!";
+ }
+ }
+
+ # We must try to deal with some SVR3 systems with a limit of 14
+ # characters for file names. Sadly we *cannot* simply truncate all
+ # file names to 14 characters on these systems because we *must*
+ # create filenames which exactly match the names used by AutoLoader.pm.
+ # This is a problem because some systems silently truncate the file
+ # names while others treat long file names as an error.
+
+ # We do not yet deal with multiple packages within one file.
+ # Ideally both of these styles should work.
+ #
+ # package NAME;
+ # __END__
+ # sub AAA { ... }
+ # package NAME::option1;
+ # sub BBB { ... }
+ # package NAME::option2;
+ # sub BBB { ... }
+ #
+ # package NAME;
+ # __END__
+ # sub AAA { ... }
+ # sub NAME::option1::BBB { ... }
+ # sub NAME::option2::BBB { ... }
+ #
+ # For now both of these produce warnings.
+
+ open(OUT,">/dev/null") || open(OUT,">nla0:"); # avoid 'not opened' warning
+ my(@subnames);
+ while (<IN>) {
+ if (/^package ([\w:]+)\s*;/) {
+ warn "package $1; in AutoSplit section ignored. Not currently supported.";
+ }
+ if (/^sub ([\w:]+)/) {
+ print OUT "1;\n";
+ my($subname) = $1;
+ if ($subname =~ m/::/){
+ warn "subs with package names not currently supported in AutoSplit section";
+ }
+ push(@subnames, $subname);
+ my($lname, $sname) = ($subname, substr($subname,0,$maxflen-3));
+ my($lpath) = "$autodir/$modpname/$lname.al";
+ my($spath) = "$autodir/$modpname/$sname.al";
+ unless(open(OUT, ">$lpath")){
+ open(OUT, ">$spath") or die "Can't create $spath: $!\n";
+ push(@names, $sname);
+ print " writing $spath (with truncated name)\n"
+ if ($Verbose>=1);
+ }else{
+ push(@names, $lname);
+ print " writing $lpath\n" if ($Verbose>=2);
+ }
+ print OUT "# NOTE: Derived from $filename. ",
+ "Changes made here will be lost.\n";
+ print OUT "package $package;\n\n";
+ }
+ print OUT $_;
+ }
+ print OUT "1;\n";
+ close(OUT);
+ close(IN);
+
+ if (!$keep){ # don't keep any obsolete *.al files in the directory
+ my(%names);
+ @names{@names} = @names;
+ opendir(OUTDIR,"$autodir/$modpname");
+ foreach(sort readdir(OUTDIR)){
+ next unless /\.al$/;
+ my($subname) = m/(.*)\.al$/;
+ next if $names{substr($subname,0,$maxflen-3)};
+ my($file) = "$autodir/$modpname/$_";
+ print " deleting $file\n" if ($Verbose>=2);
+ unlink $file or carp "Unable to delete $file: $!";
+ }
+ closedir(OUTDIR);
+ }
+
+ open(TS,">$al_idx_file") or
+ carp "AutoSplit: unable to create timestamp file ($al_idx_file): $!";
+ print TS "# Index created by AutoSplit for $filename (file acts as timestamp)\n";
+ print TS map("sub $_ ;\n", @subnames);
+ close(TS);
+
+ check_unique($package, $Maxlen, 1, @names);
+
+ @names;
+}
+
+
+sub check_unique{
+ my($module, $maxlen, $warn, @names) = @_;
+ my(%notuniq) = ();
+ my(%shorts) = ();
+ my(@toolong) = grep(length > $maxlen, @names);
+
+ foreach(@toolong){
+ my($trunc) = substr($_,0,$maxlen);
+ $notuniq{$trunc}=1 if $shorts{$trunc};
+ $shorts{$trunc} = ($shorts{$trunc}) ? "$shorts{$trunc}, $_" : $_;
+ }
+ if (%notuniq && $warn){
+ print "$module: some names are not unique when truncated to $maxlen characters:\n";
+ foreach(keys %notuniq){
+ print " $shorts{$_} truncate to $_\n";
+ }
+ }
+ %notuniq;
+}
+
+1;
+__END__
+
+# test functions so AutoSplit.pm can be applied to itself:
+sub test1{ "test 1\n"; }
+sub test2{ "test 2\n"; }
+sub test3{ "test 3\n"; }
+sub test4{ "test 4\n"; }
+
+