Test-Harness breaks libwww-perl, Sorry
[p5sagit/p5-mst-13.2.git] / lib / AutoSplit.pm
1 package AutoSplit;
2
3 require 5.000;
4 require Exporter;
5
6 use Config;
7 use Carp;
8
9 @ISA = qw(Exporter);
10 @EXPORT = qw(&autosplit &autosplit_lib_modules);
11 @EXPORT_OK = qw($Verbose $Keep $Maxlen $CheckForAutoloader $CheckModTime);
12
13 =head1 NAME
14
15 AutoSplit - split a package for autoloading
16
17 =head1 SYNOPSIS
18
19  perl -e 'use AutoSplit; autosplit_modules(@ARGV)'  ...
20
21 =head1 DESCRIPTION
22
23 This function will split up your program into files that the AutoLoader
24 module can handle.  Normally only used to build autoloading Perl library
25 modules, especially extensions (like POSIX).  You should look at how
26 they're built out for details.
27
28 =cut
29
30 # for portability warn about names longer than $maxlen
31 $Maxlen  = 8;   # 8 for dos, 11 (14-".al") for SYSVR3
32 $Verbose = 1;   # 0=none, 1=minimal, 2=list .al files
33 $Keep    = 0;
34 $CheckForAutoloader = 1;
35 $CheckModTime = 1;
36
37 $IndexFile = "autosplit.ix";    # file also serves as timestamp
38 $maxflen = 255;
39 $maxflen = 14 if $Config{'d_flexfnam'} ne 'define';
40 $vms = ($Config{'osname'} eq 'VMS');
41
42
43 sub autosplit{
44     my($file, $autodir,  $k, $ckal, $ckmt) = @_;
45     # $file    - the perl source file to be split (after __END__)
46     # $autodir - the ".../auto" dir below which to write split subs
47     # Handle optional flags:
48     $keep = $Keep unless defined $k;
49     $ckal = $CheckForAutoloader unless defined $ckal;
50     $ckmt = $CheckModTime unless defined $ckmt;
51     autosplit_file($file, $autodir, $keep, $ckal, $ckmt);
52 }
53
54
55 # This function is used during perl building/installation
56 # ./miniperl -e 'use AutoSplit; autosplit_modules(@ARGV)' ...
57
58 sub autosplit_lib_modules{
59     my(@modules) = @_; # list of Module names
60
61     foreach(@modules){
62         s#::#/#g;       # incase specified as ABC::XYZ
63         s|\\|/|g;               # bug in ksh OS/2
64         s#^lib/##; # incase specified as lib/*.pm
65         if ($vms && /[:>\]]/) { # may need to convert VMS-style filespecs
66             my ($dir,$name) = (/(.*])(.*)/);
67             $dir =~ s/.*lib[\.\]]//;
68             $dir =~ s#[\.\]]#/#g;
69             $_ = $dir . $name;
70         }
71         autosplit_file("lib/$_", "lib/auto", $Keep, $CheckForAutoloader, $CheckModTime);
72     }
73     0;
74 }
75
76
77 # private functions
78
79 sub autosplit_file{
80     my($filename, $autodir, $keep, $check_for_autoloader, $check_mod_time) = @_;
81     my(@names);
82
83     # where to write output files
84     $autodir = "lib/auto" unless $autodir;
85     if ($Config{'osname'} eq 'VMS') {
86         ($autodir = VMS::Filespec::unixpath($autodir)) =~ s#/$##;
87     }
88     unless (-d $autodir){
89         local($", @p)="/";
90         foreach(split(/\//,$autodir)){
91             push(@p, $_);
92             next if -d "@p/";
93             mkdir("@p",0755) or die "AutoSplit unable to mkdir @p: $!";
94         }
95         # We should never need to create the auto dir here. installperl
96         # (or similar) should have done it. Expecting it to exist is a valuable
97         # sanity check against autosplitting into some random directory by mistake.
98         print "Warning: AutoSplit had to create top-level $autodir unexpectedly.\n";
99     }
100
101     # allow just a package name to be used
102     $filename .= ".pm" unless ($filename =~ m/\.pm$/);
103
104     open(IN, "<$filename") || die "AutoSplit: Can't open $filename: $!\n";
105     my($pm_mod_time) = (stat($filename))[9];
106     my($autoloader_seen) = 0;
107     my($in_pod) = 0;
108     while (<IN>) {
109         # Skip pod text.
110         $in_pod = 1 if /^=/;
111         $in_pod = 0 if /^=cut/;
112         next if ($in_pod || /^=cut/);
113
114         # record last package name seen
115         $package = $1 if (m/^\s*package\s+([\w:]+)\s*;/);
116         ++$autoloader_seen if m/^\s*(use|require)\s+AutoLoader\b/;
117         ++$autoloader_seen if m/\bISA\s*=.*\bAutoLoader\b/;
118         last if /^__END__/;
119     }
120     if ($check_for_autoloader && !$autoloader_seen){
121         print "AutoSplit skipped $filename: no AutoLoader used\n" if ($Verbose>=2);
122         return 0
123     }
124     $_ or die "Can't find __END__ in $filename\n";
125
126     $package or die "Can't find 'package Name;' in $filename\n";
127
128     my($modpname) = $package; $modpname =~ s#::#/#g;
129     my($al_idx_file) = "$autodir/$modpname/$IndexFile";
130
131     die "Package $package does not match filename $filename"
132             unless ($filename =~ m/$modpname.pm$/ or
133                     $vms && $filename =~ m/$modpname.pm/i);
134
135     if ($check_mod_time){
136         my($al_ts_time) = (stat("$al_idx_file"))[9] || 1;
137         if ($al_ts_time >= $pm_mod_time){
138             print "AutoSplit skipped ($al_idx_file newer that $filename)\n"
139                 if ($Verbose >= 2);
140             return undef;       # one undef, not a list
141         }
142     }
143
144     my($from) = ($Verbose>=2) ? "$filename => " : "";
145     print "AutoSplitting $package ($from$autodir/$modpname)\n"
146         if $Verbose;
147
148     unless (-d "$autodir/$modpname"){
149         local($", @p)="/";
150         foreach(split(/\//,"$autodir/$modpname")){
151             push(@p, $_);
152             next if -d "@p/";
153             mkdir("@p",0777) or die "AutoSplit unable to mkdir @p: $!";
154         }
155     }
156
157     # We must try to deal with some SVR3 systems with a limit of 14
158     # characters for file names. Sadly we *cannot* simply truncate all
159     # file names to 14 characters on these systems because we *must*
160     # create filenames which exactly match the names used by AutoLoader.pm.
161     # This is a problem because some systems silently truncate the file
162     # names while others treat long file names as an error.
163
164     # We do not yet deal with multiple packages within one file.
165     # Ideally both of these styles should work.
166     #
167     #   package NAME;
168     #   __END__
169     #   sub AAA { ... }
170     #   package NAME::option1;
171     #   sub BBB { ... }
172     #   package NAME::option2;
173     #   sub BBB { ... }
174     #
175     #   package NAME;
176     #   __END__
177     #   sub AAA { ... }
178     #   sub NAME::option1::BBB { ... }
179     #   sub NAME::option2::BBB { ... }
180     #
181     # For now both of these produce warnings.
182
183     open(OUT,">/dev/null") || open(OUT,">nla0:"); # avoid 'not opened' warning
184     my(@subnames, %proto);
185     while (<IN>) {
186         if (/^package ([\w:]+)\s*;/) {
187             warn "package $1; in AutoSplit section ignored. Not currently supported.";
188         }
189         if (/^sub\s+([\w:]+)(\s*\(.*?\))?/) {
190             print OUT "1;\n";
191             my $subname = $1;
192             $proto{$1} = $2 or '';
193             if ($subname =~ m/::/){
194                 warn "subs with package names not currently supported in AutoSplit section";
195             }
196             push(@subnames, $subname);
197             my($lname, $sname) = ($subname, substr($subname,0,$maxflen-3));
198             my($lpath) = "$autodir/$modpname/$lname.al";
199             my($spath) = "$autodir/$modpname/$sname.al";
200             unless(open(OUT, ">$lpath")){
201                 open(OUT, ">$spath") or die "Can't create $spath: $!\n";
202                 push(@names, $sname);
203                 print "  writing $spath (with truncated name)\n"
204                         if ($Verbose>=1);
205             }else{
206                 push(@names, $lname);
207                 print "  writing $lpath\n" if ($Verbose>=2);
208             }
209             print OUT "# NOTE: Derived from $filename.  ",
210                         "Changes made here will be lost.\n";
211             print OUT "package $package;\n\n";
212         }
213         print OUT $_;
214     }
215     print OUT "1;\n";
216     close(OUT);
217     close(IN);
218
219     if (!$keep){  # don't keep any obsolete *.al files in the directory
220         my(%names);
221         @names{@names} = @names;
222         opendir(OUTDIR,"$autodir/$modpname");
223         foreach(sort readdir(OUTDIR)){
224             next unless /\.al$/;
225             my($subname) = m/(.*)\.al$/;
226             next if $names{substr($subname,0,$maxflen-3)};
227             my($file) = "$autodir/$modpname/$_";
228             print "  deleting $file\n" if ($Verbose>=2);
229             my($deleted,$thistime);  # catch all versions on VMS
230             do { $deleted += ($thistime = unlink $file) } while ($thistime);
231             carp "Unable to delete $file: $!" unless $deleted;
232         }
233         closedir(OUTDIR);
234     }
235
236     open(TS,">$al_idx_file") or
237         carp "AutoSplit: unable to create timestamp file ($al_idx_file): $!";
238     print TS "# Index created by AutoSplit for $filename (file acts as timestamp)\n";
239     print TS "package $package;\n";
240     print TS map("sub $_$proto{$_} ;\n", @subnames);
241     print TS "1;\n";
242     close(TS);
243
244     check_unique($package, $Maxlen, 1, @names);
245
246     @names;
247 }
248
249
250 sub check_unique{
251     my($module, $maxlen, $warn, @names) = @_;
252     my(%notuniq) = ();
253     my(%shorts)  = ();
254     my(@toolong) = grep(length > $maxlen, @names);
255
256     foreach(@toolong){
257         my($trunc) = substr($_,0,$maxlen);
258         $notuniq{$trunc}=1 if $shorts{$trunc};
259         $shorts{$trunc} = ($shorts{$trunc}) ? "$shorts{$trunc}, $_" : $_;
260     }
261     if (%notuniq && $warn){
262         print "$module: some names are not unique when truncated to $maxlen characters:\n";
263         foreach(keys %notuniq){
264             print " $shorts{$_} truncate to $_\n";
265         }
266     }
267     %notuniq;
268 }
269
270 1;
271 __END__
272
273 # test functions so AutoSplit.pm can be applied to itself:
274 sub test1{ "test 1\n"; }
275 sub test2{ "test 2\n"; }
276 sub test3{ "test 3\n"; }
277 sub test4{ "test 4\n"; }
278
279