1*0Sstevel@tonic-gatepackage AutoSplit; 2*0Sstevel@tonic-gate 3*0Sstevel@tonic-gateuse 5.006_001; 4*0Sstevel@tonic-gateuse Exporter (); 5*0Sstevel@tonic-gateuse Config qw(%Config); 6*0Sstevel@tonic-gateuse Carp qw(carp); 7*0Sstevel@tonic-gateuse File::Basename (); 8*0Sstevel@tonic-gateuse File::Path qw(mkpath); 9*0Sstevel@tonic-gateuse File::Spec::Functions qw(curdir catfile catdir); 10*0Sstevel@tonic-gateuse strict; 11*0Sstevel@tonic-gateour($VERSION, @ISA, @EXPORT, @EXPORT_OK, $Verbose, $Keep, $Maxlen, 12*0Sstevel@tonic-gate $CheckForAutoloader, $CheckModTime); 13*0Sstevel@tonic-gate 14*0Sstevel@tonic-gate$VERSION = "1.04"; 15*0Sstevel@tonic-gate@ISA = qw(Exporter); 16*0Sstevel@tonic-gate@EXPORT = qw(&autosplit &autosplit_lib_modules); 17*0Sstevel@tonic-gate@EXPORT_OK = qw($Verbose $Keep $Maxlen $CheckForAutoloader $CheckModTime); 18*0Sstevel@tonic-gate 19*0Sstevel@tonic-gate=head1 NAME 20*0Sstevel@tonic-gate 21*0Sstevel@tonic-gateAutoSplit - split a package for autoloading 22*0Sstevel@tonic-gate 23*0Sstevel@tonic-gate=head1 SYNOPSIS 24*0Sstevel@tonic-gate 25*0Sstevel@tonic-gate autosplit($file, $dir, $keep, $check, $modtime); 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate autosplit_lib_modules(@modules); 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate=head1 DESCRIPTION 30*0Sstevel@tonic-gate 31*0Sstevel@tonic-gateThis function will split up your program into files that the AutoLoader 32*0Sstevel@tonic-gatemodule can handle. It is used by both the standard perl libraries and by 33*0Sstevel@tonic-gatethe MakeMaker utility, to automatically configure libraries for autoloading. 34*0Sstevel@tonic-gate 35*0Sstevel@tonic-gateThe C<autosplit> interface splits the specified file into a hierarchy 36*0Sstevel@tonic-gaterooted at the directory C<$dir>. It creates directories as needed to reflect 37*0Sstevel@tonic-gateclass hierarchy, and creates the file F<autosplit.ix>. This file acts as 38*0Sstevel@tonic-gateboth forward declaration of all package routines, and as timestamp for the 39*0Sstevel@tonic-gatelast update of the hierarchy. 40*0Sstevel@tonic-gate 41*0Sstevel@tonic-gateThe remaining three arguments to C<autosplit> govern other options to 42*0Sstevel@tonic-gatethe autosplitter. 43*0Sstevel@tonic-gate 44*0Sstevel@tonic-gate=over 2 45*0Sstevel@tonic-gate 46*0Sstevel@tonic-gate=item $keep 47*0Sstevel@tonic-gate 48*0Sstevel@tonic-gateIf the third argument, I<$keep>, is false, then any 49*0Sstevel@tonic-gatepre-existing C<*.al> files in the autoload directory are removed if 50*0Sstevel@tonic-gatethey are no longer part of the module (obsoleted functions). 51*0Sstevel@tonic-gate$keep defaults to 0. 52*0Sstevel@tonic-gate 53*0Sstevel@tonic-gate=item $check 54*0Sstevel@tonic-gate 55*0Sstevel@tonic-gateThe 56*0Sstevel@tonic-gatefourth argument, I<$check>, instructs C<autosplit> to check the module 57*0Sstevel@tonic-gatecurrently being split to ensure that it includes a C<use> 58*0Sstevel@tonic-gatespecification for the AutoLoader module, and skips the module if 59*0Sstevel@tonic-gateAutoLoader is not detected. 60*0Sstevel@tonic-gate$check defaults to 1. 61*0Sstevel@tonic-gate 62*0Sstevel@tonic-gate=item $modtime 63*0Sstevel@tonic-gate 64*0Sstevel@tonic-gateLastly, the I<$modtime> argument specifies 65*0Sstevel@tonic-gatethat C<autosplit> is to check the modification time of the module 66*0Sstevel@tonic-gateagainst that of the C<autosplit.ix> file, and only split the module if 67*0Sstevel@tonic-gateit is newer. 68*0Sstevel@tonic-gate$modtime defaults to 1. 69*0Sstevel@tonic-gate 70*0Sstevel@tonic-gate=back 71*0Sstevel@tonic-gate 72*0Sstevel@tonic-gateTypical use of AutoSplit in the perl MakeMaker utility is via the command-line 73*0Sstevel@tonic-gatewith: 74*0Sstevel@tonic-gate 75*0Sstevel@tonic-gate perl -e 'use AutoSplit; autosplit($ARGV[0], $ARGV[1], 0, 1, 1)' 76*0Sstevel@tonic-gate 77*0Sstevel@tonic-gateDefined as a Make macro, it is invoked with file and directory arguments; 78*0Sstevel@tonic-gateC<autosplit> will split the specified file into the specified directory and 79*0Sstevel@tonic-gatedelete obsolete C<.al> files, after checking first that the module does use 80*0Sstevel@tonic-gatethe AutoLoader, and ensuring that the module is not already currently split 81*0Sstevel@tonic-gatein its current form (the modtime test). 82*0Sstevel@tonic-gate 83*0Sstevel@tonic-gateThe C<autosplit_lib_modules> form is used in the building of perl. It takes 84*0Sstevel@tonic-gateas input a list of files (modules) that are assumed to reside in a directory 85*0Sstevel@tonic-gateB<lib> relative to the current directory. Each file is sent to the 86*0Sstevel@tonic-gateautosplitter one at a time, to be split into the directory B<lib/auto>. 87*0Sstevel@tonic-gate 88*0Sstevel@tonic-gateIn both usages of the autosplitter, only subroutines defined following the 89*0Sstevel@tonic-gateperl I<__END__> token are split out into separate files. Some 90*0Sstevel@tonic-gateroutines may be placed prior to this marker to force their immediate loading 91*0Sstevel@tonic-gateand parsing. 92*0Sstevel@tonic-gate 93*0Sstevel@tonic-gate=head2 Multiple packages 94*0Sstevel@tonic-gate 95*0Sstevel@tonic-gateAs of version 1.01 of the AutoSplit module it is possible to have 96*0Sstevel@tonic-gatemultiple packages within a single file. Both of the following cases 97*0Sstevel@tonic-gateare supported: 98*0Sstevel@tonic-gate 99*0Sstevel@tonic-gate package NAME; 100*0Sstevel@tonic-gate __END__ 101*0Sstevel@tonic-gate sub AAA { ... } 102*0Sstevel@tonic-gate package NAME::option1; 103*0Sstevel@tonic-gate sub BBB { ... } 104*0Sstevel@tonic-gate package NAME::option2; 105*0Sstevel@tonic-gate sub BBB { ... } 106*0Sstevel@tonic-gate 107*0Sstevel@tonic-gate package NAME; 108*0Sstevel@tonic-gate __END__ 109*0Sstevel@tonic-gate sub AAA { ... } 110*0Sstevel@tonic-gate sub NAME::option1::BBB { ... } 111*0Sstevel@tonic-gate sub NAME::option2::BBB { ... } 112*0Sstevel@tonic-gate 113*0Sstevel@tonic-gate=head1 DIAGNOSTICS 114*0Sstevel@tonic-gate 115*0Sstevel@tonic-gateC<AutoSplit> will inform the user if it is necessary to create the 116*0Sstevel@tonic-gatetop-level directory specified in the invocation. It is preferred that 117*0Sstevel@tonic-gatethe script or installation process that invokes C<AutoSplit> have 118*0Sstevel@tonic-gatecreated the full directory path ahead of time. This warning may 119*0Sstevel@tonic-gateindicate that the module is being split into an incorrect path. 120*0Sstevel@tonic-gate 121*0Sstevel@tonic-gateC<AutoSplit> will warn the user of all subroutines whose name causes 122*0Sstevel@tonic-gatepotential file naming conflicts on machines with drastically limited 123*0Sstevel@tonic-gate(8 characters or less) file name length. Since the subroutine name is 124*0Sstevel@tonic-gateused as the file name, these warnings can aid in portability to such 125*0Sstevel@tonic-gatesystems. 126*0Sstevel@tonic-gate 127*0Sstevel@tonic-gateWarnings are issued and the file skipped if C<AutoSplit> cannot locate 128*0Sstevel@tonic-gateeither the I<__END__> marker or a "package Name;"-style specification. 129*0Sstevel@tonic-gate 130*0Sstevel@tonic-gateC<AutoSplit> will also emit general diagnostics for inability to 131*0Sstevel@tonic-gatecreate directories or files. 132*0Sstevel@tonic-gate 133*0Sstevel@tonic-gate=cut 134*0Sstevel@tonic-gate 135*0Sstevel@tonic-gate# for portability warn about names longer than $maxlen 136*0Sstevel@tonic-gate$Maxlen = 8; # 8 for dos, 11 (14-".al") for SYSVR3 137*0Sstevel@tonic-gate$Verbose = 1; # 0=none, 1=minimal, 2=list .al files 138*0Sstevel@tonic-gate$Keep = 0; 139*0Sstevel@tonic-gate$CheckForAutoloader = 1; 140*0Sstevel@tonic-gate$CheckModTime = 1; 141*0Sstevel@tonic-gate 142*0Sstevel@tonic-gatemy $IndexFile = "autosplit.ix"; # file also serves as timestamp 143*0Sstevel@tonic-gatemy $maxflen = 255; 144*0Sstevel@tonic-gate$maxflen = 14 if $Config{'d_flexfnam'} ne 'define'; 145*0Sstevel@tonic-gateif (defined (&Dos::UseLFN)) { 146*0Sstevel@tonic-gate $maxflen = Dos::UseLFN() ? 255 : 11; 147*0Sstevel@tonic-gate} 148*0Sstevel@tonic-gatemy $Is_VMS = ($^O eq 'VMS'); 149*0Sstevel@tonic-gate 150*0Sstevel@tonic-gate# allow checking for valid ': attrlist' attachments 151*0Sstevel@tonic-gate# (we use 'our' rather than 'my' here, due to the rather complex and buggy 152*0Sstevel@tonic-gate# behaviour of lexicals with qr// and (??{$lex}) ) 153*0Sstevel@tonic-gateour $nested; 154*0Sstevel@tonic-gate$nested = qr{ \( (?: (?> [^()]+ ) | (??{ $nested }) )* \) }x; 155*0Sstevel@tonic-gateour $one_attr = qr{ (?> (?! \d) \w+ (?:$nested)? ) (?:\s*\:\s*|\s+(?!\:)) }x; 156*0Sstevel@tonic-gateour $attr_list = qr{ \s* : \s* (?: $one_attr )* }x; 157*0Sstevel@tonic-gate 158*0Sstevel@tonic-gate 159*0Sstevel@tonic-gate 160*0Sstevel@tonic-gatesub autosplit{ 161*0Sstevel@tonic-gate my($file, $autodir, $keep, $ckal, $ckmt) = @_; 162*0Sstevel@tonic-gate # $file - the perl source file to be split (after __END__) 163*0Sstevel@tonic-gate # $autodir - the ".../auto" dir below which to write split subs 164*0Sstevel@tonic-gate # Handle optional flags: 165*0Sstevel@tonic-gate $keep = $Keep unless defined $keep; 166*0Sstevel@tonic-gate $ckal = $CheckForAutoloader unless defined $ckal; 167*0Sstevel@tonic-gate $ckmt = $CheckModTime unless defined $ckmt; 168*0Sstevel@tonic-gate autosplit_file($file, $autodir, $keep, $ckal, $ckmt); 169*0Sstevel@tonic-gate} 170*0Sstevel@tonic-gate 171*0Sstevel@tonic-gate 172*0Sstevel@tonic-gate# This function is used during perl building/installation 173*0Sstevel@tonic-gate# ./miniperl -e 'use AutoSplit; autosplit_lib_modules(@ARGV)' ... 174*0Sstevel@tonic-gate 175*0Sstevel@tonic-gatesub autosplit_lib_modules{ 176*0Sstevel@tonic-gate my(@modules) = @_; # list of Module names 177*0Sstevel@tonic-gate 178*0Sstevel@tonic-gate while(defined($_ = shift @modules)){ 179*0Sstevel@tonic-gate while (m#(.*?[^:])::([^:].*)#) { # in case specified as ABC::XYZ 180*0Sstevel@tonic-gate $_ = catfile($1, $2); 181*0Sstevel@tonic-gate } 182*0Sstevel@tonic-gate s|\\|/|g; # bug in ksh OS/2 183*0Sstevel@tonic-gate s#^lib/##s; # incase specified as lib/*.pm 184*0Sstevel@tonic-gate my($lib) = catfile(curdir(), "lib"); 185*0Sstevel@tonic-gate if ($Is_VMS) { # may need to convert VMS-style filespecs 186*0Sstevel@tonic-gate $lib =~ s#^\[\]#.\/#; 187*0Sstevel@tonic-gate } 188*0Sstevel@tonic-gate s#^$lib\W+##s; # incase specified as ./lib/*.pm 189*0Sstevel@tonic-gate if ($Is_VMS && /[:>\]]/) { # may need to convert VMS-style filespecs 190*0Sstevel@tonic-gate my ($dir,$name) = (/(.*])(.*)/s); 191*0Sstevel@tonic-gate $dir =~ s/.*lib[\.\]]//s; 192*0Sstevel@tonic-gate $dir =~ s#[\.\]]#/#g; 193*0Sstevel@tonic-gate $_ = $dir . $name; 194*0Sstevel@tonic-gate } 195*0Sstevel@tonic-gate autosplit_file(catfile($lib, $_), catfile($lib, "auto"), 196*0Sstevel@tonic-gate $Keep, $CheckForAutoloader, $CheckModTime); 197*0Sstevel@tonic-gate } 198*0Sstevel@tonic-gate 0; 199*0Sstevel@tonic-gate} 200*0Sstevel@tonic-gate 201*0Sstevel@tonic-gate 202*0Sstevel@tonic-gate# private functions 203*0Sstevel@tonic-gate 204*0Sstevel@tonic-gatemy $self_mod_time = (stat __FILE__)[9]; 205*0Sstevel@tonic-gate 206*0Sstevel@tonic-gatesub autosplit_file { 207*0Sstevel@tonic-gate my($filename, $autodir, $keep, $check_for_autoloader, $check_mod_time) 208*0Sstevel@tonic-gate = @_; 209*0Sstevel@tonic-gate my(@outfiles); 210*0Sstevel@tonic-gate local($_); 211*0Sstevel@tonic-gate local($/) = "\n"; 212*0Sstevel@tonic-gate 213*0Sstevel@tonic-gate # where to write output files 214*0Sstevel@tonic-gate $autodir ||= catfile(curdir(), "lib", "auto"); 215*0Sstevel@tonic-gate if ($Is_VMS) { 216*0Sstevel@tonic-gate ($autodir = VMS::Filespec::unixpath($autodir)) =~ s|/\z||; 217*0Sstevel@tonic-gate $filename = VMS::Filespec::unixify($filename); # may have dirs 218*0Sstevel@tonic-gate } 219*0Sstevel@tonic-gate unless (-d $autodir){ 220*0Sstevel@tonic-gate mkpath($autodir,0,0755); 221*0Sstevel@tonic-gate # We should never need to create the auto dir 222*0Sstevel@tonic-gate # here. installperl (or similar) should have done 223*0Sstevel@tonic-gate # it. Expecting it to exist is a valuable sanity check against 224*0Sstevel@tonic-gate # autosplitting into some random directory by mistake. 225*0Sstevel@tonic-gate print "Warning: AutoSplit had to create top-level " . 226*0Sstevel@tonic-gate "$autodir unexpectedly.\n"; 227*0Sstevel@tonic-gate } 228*0Sstevel@tonic-gate 229*0Sstevel@tonic-gate # allow just a package name to be used 230*0Sstevel@tonic-gate $filename .= ".pm" unless ($filename =~ m/\.pm\z/); 231*0Sstevel@tonic-gate 232*0Sstevel@tonic-gate open(my $in, "<$filename") or die "AutoSplit: Can't open $filename: $!\n"; 233*0Sstevel@tonic-gate my($pm_mod_time) = (stat($filename))[9]; 234*0Sstevel@tonic-gate my($autoloader_seen) = 0; 235*0Sstevel@tonic-gate my($in_pod) = 0; 236*0Sstevel@tonic-gate my($def_package,$last_package,$this_package,$fnr); 237*0Sstevel@tonic-gate while (<$in>) { 238*0Sstevel@tonic-gate # Skip pod text. 239*0Sstevel@tonic-gate $fnr++; 240*0Sstevel@tonic-gate $in_pod = 1 if /^=\w/; 241*0Sstevel@tonic-gate $in_pod = 0 if /^=cut/; 242*0Sstevel@tonic-gate next if ($in_pod || /^=cut/); 243*0Sstevel@tonic-gate next if /^\s*#/; 244*0Sstevel@tonic-gate 245*0Sstevel@tonic-gate # record last package name seen 246*0Sstevel@tonic-gate $def_package = $1 if (m/^\s*package\s+([\w:]+)\s*;/); 247*0Sstevel@tonic-gate ++$autoloader_seen if m/^\s*(use|require)\s+AutoLoader\b/; 248*0Sstevel@tonic-gate ++$autoloader_seen if m/\bISA\s*=.*\bAutoLoader\b/; 249*0Sstevel@tonic-gate last if /^__END__/; 250*0Sstevel@tonic-gate } 251*0Sstevel@tonic-gate if ($check_for_autoloader && !$autoloader_seen){ 252*0Sstevel@tonic-gate print "AutoSplit skipped $filename: no AutoLoader used\n" 253*0Sstevel@tonic-gate if ($Verbose>=2); 254*0Sstevel@tonic-gate return 0; 255*0Sstevel@tonic-gate } 256*0Sstevel@tonic-gate $_ or die "Can't find __END__ in $filename\n"; 257*0Sstevel@tonic-gate 258*0Sstevel@tonic-gate $def_package or die "Can't find 'package Name;' in $filename\n"; 259*0Sstevel@tonic-gate 260*0Sstevel@tonic-gate my($modpname) = _modpname($def_package); 261*0Sstevel@tonic-gate 262*0Sstevel@tonic-gate # this _has_ to match so we have a reasonable timestamp file 263*0Sstevel@tonic-gate die "Package $def_package ($modpname.pm) does not ". 264*0Sstevel@tonic-gate "match filename $filename" 265*0Sstevel@tonic-gate unless ($filename =~ m/\Q$modpname.pm\E$/ or 266*0Sstevel@tonic-gate ($^O eq 'dos') or ($^O eq 'MSWin32') or ($^O eq 'NetWare') or 267*0Sstevel@tonic-gate $Is_VMS && $filename =~ m/$modpname.pm/i); 268*0Sstevel@tonic-gate 269*0Sstevel@tonic-gate my($al_idx_file) = catfile($autodir, $modpname, $IndexFile); 270*0Sstevel@tonic-gate 271*0Sstevel@tonic-gate if ($check_mod_time){ 272*0Sstevel@tonic-gate my($al_ts_time) = (stat("$al_idx_file"))[9] || 1; 273*0Sstevel@tonic-gate if ($al_ts_time >= $pm_mod_time and 274*0Sstevel@tonic-gate $al_ts_time >= $self_mod_time){ 275*0Sstevel@tonic-gate print "AutoSplit skipped ($al_idx_file newer than $filename)\n" 276*0Sstevel@tonic-gate if ($Verbose >= 2); 277*0Sstevel@tonic-gate return undef; # one undef, not a list 278*0Sstevel@tonic-gate } 279*0Sstevel@tonic-gate } 280*0Sstevel@tonic-gate 281*0Sstevel@tonic-gate my($modnamedir) = catdir($autodir, $modpname); 282*0Sstevel@tonic-gate print "AutoSplitting $filename ($modnamedir)\n" 283*0Sstevel@tonic-gate if $Verbose; 284*0Sstevel@tonic-gate 285*0Sstevel@tonic-gate unless (-d $modnamedir){ 286*0Sstevel@tonic-gate mkpath($modnamedir,0,0777); 287*0Sstevel@tonic-gate } 288*0Sstevel@tonic-gate 289*0Sstevel@tonic-gate # We must try to deal with some SVR3 systems with a limit of 14 290*0Sstevel@tonic-gate # characters for file names. Sadly we *cannot* simply truncate all 291*0Sstevel@tonic-gate # file names to 14 characters on these systems because we *must* 292*0Sstevel@tonic-gate # create filenames which exactly match the names used by AutoLoader.pm. 293*0Sstevel@tonic-gate # This is a problem because some systems silently truncate the file 294*0Sstevel@tonic-gate # names while others treat long file names as an error. 295*0Sstevel@tonic-gate 296*0Sstevel@tonic-gate my $Is83 = $maxflen==11; # plain, case INSENSITIVE dos filenames 297*0Sstevel@tonic-gate 298*0Sstevel@tonic-gate my(@subnames, $subname, %proto, %package); 299*0Sstevel@tonic-gate my @cache = (); 300*0Sstevel@tonic-gate my $caching = 1; 301*0Sstevel@tonic-gate $last_package = ''; 302*0Sstevel@tonic-gate my $out; 303*0Sstevel@tonic-gate while (<$in>) { 304*0Sstevel@tonic-gate $fnr++; 305*0Sstevel@tonic-gate $in_pod = 1 if /^=\w/; 306*0Sstevel@tonic-gate $in_pod = 0 if /^=cut/; 307*0Sstevel@tonic-gate next if ($in_pod || /^=cut/); 308*0Sstevel@tonic-gate # the following (tempting) old coding gives big troubles if a 309*0Sstevel@tonic-gate # cut is forgotten at EOF: 310*0Sstevel@tonic-gate # next if /^=\w/ .. /^=cut/; 311*0Sstevel@tonic-gate if (/^package\s+([\w:]+)\s*;/) { 312*0Sstevel@tonic-gate $this_package = $def_package = $1; 313*0Sstevel@tonic-gate } 314*0Sstevel@tonic-gate 315*0Sstevel@tonic-gate if (/^sub\s+([\w:]+)(\s*(?:\(.*?\))?(?:$attr_list)?)/) { 316*0Sstevel@tonic-gate print $out "# end of $last_package\::$subname\n1;\n" 317*0Sstevel@tonic-gate if $last_package; 318*0Sstevel@tonic-gate $subname = $1; 319*0Sstevel@tonic-gate my $proto = $2 || ''; 320*0Sstevel@tonic-gate if ($subname =~ s/(.*):://){ 321*0Sstevel@tonic-gate $this_package = $1; 322*0Sstevel@tonic-gate } else { 323*0Sstevel@tonic-gate $this_package = $def_package; 324*0Sstevel@tonic-gate } 325*0Sstevel@tonic-gate my $fq_subname = "$this_package\::$subname"; 326*0Sstevel@tonic-gate $package{$fq_subname} = $this_package; 327*0Sstevel@tonic-gate $proto{$fq_subname} = $proto; 328*0Sstevel@tonic-gate push(@subnames, $fq_subname); 329*0Sstevel@tonic-gate my($lname, $sname) = ($subname, substr($subname,0,$maxflen-3)); 330*0Sstevel@tonic-gate $modpname = _modpname($this_package); 331*0Sstevel@tonic-gate my($modnamedir) = catdir($autodir, $modpname); 332*0Sstevel@tonic-gate mkpath($modnamedir,0,0777); 333*0Sstevel@tonic-gate my($lpath) = catfile($modnamedir, "$lname.al"); 334*0Sstevel@tonic-gate my($spath) = catfile($modnamedir, "$sname.al"); 335*0Sstevel@tonic-gate my $path; 336*0Sstevel@tonic-gate 337*0Sstevel@tonic-gate if (!$Is83 and open($out, ">$lpath")){ 338*0Sstevel@tonic-gate $path=$lpath; 339*0Sstevel@tonic-gate print " writing $lpath\n" if ($Verbose>=2); 340*0Sstevel@tonic-gate } else { 341*0Sstevel@tonic-gate open($out, ">$spath") or die "Can't create $spath: $!\n"; 342*0Sstevel@tonic-gate $path=$spath; 343*0Sstevel@tonic-gate print " writing $spath (with truncated name)\n" 344*0Sstevel@tonic-gate if ($Verbose>=1); 345*0Sstevel@tonic-gate } 346*0Sstevel@tonic-gate push(@outfiles, $path); 347*0Sstevel@tonic-gate my $lineno = $fnr - @cache; 348*0Sstevel@tonic-gate print $out <<EOT; 349*0Sstevel@tonic-gate# NOTE: Derived from $filename. 350*0Sstevel@tonic-gate# Changes made here will be lost when autosplit is run again. 351*0Sstevel@tonic-gate# See AutoSplit.pm. 352*0Sstevel@tonic-gatepackage $this_package; 353*0Sstevel@tonic-gate 354*0Sstevel@tonic-gate#line $lineno "$filename (autosplit into $path)" 355*0Sstevel@tonic-gateEOT 356*0Sstevel@tonic-gate print $out @cache; 357*0Sstevel@tonic-gate @cache = (); 358*0Sstevel@tonic-gate $caching = 0; 359*0Sstevel@tonic-gate } 360*0Sstevel@tonic-gate if($caching) { 361*0Sstevel@tonic-gate push(@cache, $_) if @cache || /\S/; 362*0Sstevel@tonic-gate } else { 363*0Sstevel@tonic-gate print $out $_; 364*0Sstevel@tonic-gate } 365*0Sstevel@tonic-gate if(/^\}/) { 366*0Sstevel@tonic-gate if($caching) { 367*0Sstevel@tonic-gate print $out @cache; 368*0Sstevel@tonic-gate @cache = (); 369*0Sstevel@tonic-gate } 370*0Sstevel@tonic-gate print $out "\n"; 371*0Sstevel@tonic-gate $caching = 1; 372*0Sstevel@tonic-gate } 373*0Sstevel@tonic-gate $last_package = $this_package if defined $this_package; 374*0Sstevel@tonic-gate } 375*0Sstevel@tonic-gate if ($subname) { 376*0Sstevel@tonic-gate print $out @cache,"1;\n# end of $last_package\::$subname\n"; 377*0Sstevel@tonic-gate close($out); 378*0Sstevel@tonic-gate } 379*0Sstevel@tonic-gate close($in); 380*0Sstevel@tonic-gate 381*0Sstevel@tonic-gate if (!$keep){ # don't keep any obsolete *.al files in the directory 382*0Sstevel@tonic-gate my(%outfiles); 383*0Sstevel@tonic-gate # @outfiles{@outfiles} = @outfiles; 384*0Sstevel@tonic-gate # perl downcases all filenames on VMS (which upcases all filenames) so 385*0Sstevel@tonic-gate # we'd better downcase the sub name list too, or subs with upper case 386*0Sstevel@tonic-gate # letters in them will get their .al files deleted right after they're 387*0Sstevel@tonic-gate # created. (The mixed case sub name won't match the all-lowercase 388*0Sstevel@tonic-gate # filename, and so be cleaned up as a scrap file) 389*0Sstevel@tonic-gate if ($Is_VMS or $Is83) { 390*0Sstevel@tonic-gate %outfiles = map {lc($_) => lc($_) } @outfiles; 391*0Sstevel@tonic-gate } else { 392*0Sstevel@tonic-gate @outfiles{@outfiles} = @outfiles; 393*0Sstevel@tonic-gate } 394*0Sstevel@tonic-gate my(%outdirs,@outdirs); 395*0Sstevel@tonic-gate for (@outfiles) { 396*0Sstevel@tonic-gate $outdirs{File::Basename::dirname($_)}||=1; 397*0Sstevel@tonic-gate } 398*0Sstevel@tonic-gate for my $dir (keys %outdirs) { 399*0Sstevel@tonic-gate opendir(my $outdir,$dir); 400*0Sstevel@tonic-gate foreach (sort readdir($outdir)){ 401*0Sstevel@tonic-gate next unless /\.al\z/; 402*0Sstevel@tonic-gate my($file) = catfile($dir, $_); 403*0Sstevel@tonic-gate $file = lc $file if $Is83 or $Is_VMS; 404*0Sstevel@tonic-gate next if $outfiles{$file}; 405*0Sstevel@tonic-gate print " deleting $file\n" if ($Verbose>=2); 406*0Sstevel@tonic-gate my($deleted,$thistime); # catch all versions on VMS 407*0Sstevel@tonic-gate do { $deleted += ($thistime = unlink $file) } while ($thistime); 408*0Sstevel@tonic-gate carp "Unable to delete $file: $!" unless $deleted; 409*0Sstevel@tonic-gate } 410*0Sstevel@tonic-gate closedir($outdir); 411*0Sstevel@tonic-gate } 412*0Sstevel@tonic-gate } 413*0Sstevel@tonic-gate 414*0Sstevel@tonic-gate open(my $ts,">$al_idx_file") or 415*0Sstevel@tonic-gate carp "AutoSplit: unable to create timestamp file ($al_idx_file): $!"; 416*0Sstevel@tonic-gate print $ts "# Index created by AutoSplit for $filename\n"; 417*0Sstevel@tonic-gate print $ts "# (file acts as timestamp)\n"; 418*0Sstevel@tonic-gate $last_package = ''; 419*0Sstevel@tonic-gate for my $fqs (@subnames) { 420*0Sstevel@tonic-gate my($subname) = $fqs; 421*0Sstevel@tonic-gate $subname =~ s/.*:://; 422*0Sstevel@tonic-gate print $ts "package $package{$fqs};\n" 423*0Sstevel@tonic-gate unless $last_package eq $package{$fqs}; 424*0Sstevel@tonic-gate print $ts "sub $subname $proto{$fqs};\n"; 425*0Sstevel@tonic-gate $last_package = $package{$fqs}; 426*0Sstevel@tonic-gate } 427*0Sstevel@tonic-gate print $ts "1;\n"; 428*0Sstevel@tonic-gate close($ts); 429*0Sstevel@tonic-gate 430*0Sstevel@tonic-gate _check_unique($filename, $Maxlen, 1, @outfiles); 431*0Sstevel@tonic-gate 432*0Sstevel@tonic-gate @outfiles; 433*0Sstevel@tonic-gate} 434*0Sstevel@tonic-gate 435*0Sstevel@tonic-gatesub _modpname ($) { 436*0Sstevel@tonic-gate my($package) = @_; 437*0Sstevel@tonic-gate my $modpname = $package; 438*0Sstevel@tonic-gate if ($^O eq 'MSWin32') { 439*0Sstevel@tonic-gate $modpname =~ s#::#\\#g; 440*0Sstevel@tonic-gate } else { 441*0Sstevel@tonic-gate my @modpnames = (); 442*0Sstevel@tonic-gate while ($modpname =~ m#(.*?[^:])::([^:].*)#) { 443*0Sstevel@tonic-gate push @modpnames, $1; 444*0Sstevel@tonic-gate $modpname = $2; 445*0Sstevel@tonic-gate } 446*0Sstevel@tonic-gate $modpname = catfile(@modpnames, $modpname); 447*0Sstevel@tonic-gate } 448*0Sstevel@tonic-gate if ($Is_VMS) { 449*0Sstevel@tonic-gate $modpname = VMS::Filespec::unixify($modpname); # may have dirs 450*0Sstevel@tonic-gate } 451*0Sstevel@tonic-gate $modpname; 452*0Sstevel@tonic-gate} 453*0Sstevel@tonic-gate 454*0Sstevel@tonic-gatesub _check_unique { 455*0Sstevel@tonic-gate my($filename, $maxlen, $warn, @outfiles) = @_; 456*0Sstevel@tonic-gate my(%notuniq) = (); 457*0Sstevel@tonic-gate my(%shorts) = (); 458*0Sstevel@tonic-gate my(@toolong) = grep( 459*0Sstevel@tonic-gate length(File::Basename::basename($_)) 460*0Sstevel@tonic-gate > $maxlen, 461*0Sstevel@tonic-gate @outfiles 462*0Sstevel@tonic-gate ); 463*0Sstevel@tonic-gate 464*0Sstevel@tonic-gate foreach (@toolong){ 465*0Sstevel@tonic-gate my($dir) = File::Basename::dirname($_); 466*0Sstevel@tonic-gate my($file) = File::Basename::basename($_); 467*0Sstevel@tonic-gate my($trunc) = substr($file,0,$maxlen); 468*0Sstevel@tonic-gate $notuniq{$dir}{$trunc} = 1 if $shorts{$dir}{$trunc}; 469*0Sstevel@tonic-gate $shorts{$dir}{$trunc} = $shorts{$dir}{$trunc} ? 470*0Sstevel@tonic-gate "$shorts{$dir}{$trunc}, $file" : $file; 471*0Sstevel@tonic-gate } 472*0Sstevel@tonic-gate if (%notuniq && $warn){ 473*0Sstevel@tonic-gate print "$filename: some names are not unique when " . 474*0Sstevel@tonic-gate "truncated to $maxlen characters:\n"; 475*0Sstevel@tonic-gate foreach my $dir (sort keys %notuniq){ 476*0Sstevel@tonic-gate print " directory $dir:\n"; 477*0Sstevel@tonic-gate foreach my $trunc (sort keys %{$notuniq{$dir}}) { 478*0Sstevel@tonic-gate print " $shorts{$dir}{$trunc} truncate to $trunc\n"; 479*0Sstevel@tonic-gate } 480*0Sstevel@tonic-gate } 481*0Sstevel@tonic-gate } 482*0Sstevel@tonic-gate} 483*0Sstevel@tonic-gate 484*0Sstevel@tonic-gate1; 485*0Sstevel@tonic-gate__END__ 486*0Sstevel@tonic-gate 487*0Sstevel@tonic-gate# test functions so AutoSplit.pm can be applied to itself: 488*0Sstevel@tonic-gatesub test1 ($) { "test 1\n"; } 489*0Sstevel@tonic-gatesub test2 ($$) { "test 2\n"; } 490*0Sstevel@tonic-gatesub test3 ($$$) { "test 3\n"; } 491*0Sstevel@tonic-gatesub testtesttesttest4_1 { "test 4\n"; } 492*0Sstevel@tonic-gatesub testtesttesttest4_2 { "duplicate test 4\n"; } 493*0Sstevel@tonic-gatesub Just::Another::test5 { "another test 5\n"; } 494*0Sstevel@tonic-gatesub test6 { return join ":", __FILE__,__LINE__; } 495*0Sstevel@tonic-gatepackage Yet::Another::AutoSplit; 496*0Sstevel@tonic-gatesub testtesttesttest4_1 ($) { "another test 4\n"; } 497*0Sstevel@tonic-gatesub testtesttesttest4_2 ($$) { "another duplicate test 4\n"; } 498*0Sstevel@tonic-gatepackage Yet::More::Attributes; 499*0Sstevel@tonic-gatesub test_a1 ($) : locked :locked { 1; } 500*0Sstevel@tonic-gatesub test_a2 : locked { 1; } 501