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