File::Basename doc overhaul
[p5sagit/p5-mst-13.2.git] / lib / File / Basename.pm
1 =head1 NAME
2
3 File::Basename - Parse file paths into directory, filename and suffix.
4
5 =head1 SYNOPSIS
6
7     use File::Basename;
8
9     ($name,$path,$suffix) = fileparse($fullname,@suffixlist);
10     $name = fileparse($fullname,@suffixlist);
11
12     $basename = basename($fullname,@suffixlist);
13     $dirname  = dirname($fullname);
14
15
16 =head1 DESCRIPTION
17
18 These routines allow you to parse file paths into their directory, filename
19 and suffix.
20
21 B<NOTE>: C<dirname()> and C<basename()> emulate the behaviours, and quirks, of
22 the shell and C functions of the same name.  See each function's documention
23 for details.
24
25 =cut
26
27
28 package File::Basename;
29
30 # A bit of juggling to insure that C<use re 'taint';> always works, since
31 # File::Basename is used during the Perl build, when the re extension may
32 # not be available.
33 BEGIN {
34   unless (eval { require re; })
35     { eval ' sub re::import { $^H |= 0x00100000; } ' } # HINT_RE_TAINT
36   import re 'taint';
37 }
38
39
40 use strict;
41 use 5.006;
42 use warnings;
43 our(@ISA, @EXPORT, $VERSION, $Fileparse_fstype, $Fileparse_igncase);
44 require Exporter;
45 @ISA = qw(Exporter);
46 @EXPORT = qw(fileparse fileparse_set_fstype basename dirname);
47 $VERSION = "2.73";
48
49 fileparse_set_fstype($^O);
50
51
52 =over 4
53
54 =item C<fileparse>
55
56     my($filename, $directories, $suffix) = fileparse($path);
57     my($filename, $directories, $suffix) = fileparse($path, @suffixes);
58     my $filename                         = fileparse($path, @suffixes);
59
60 The C<fileparse()> routine divides a file path into its $directories, $filename
61 and (optionally) the filename $suffix.
62
63 $directories contains everything up to and including the last
64 directory separator in the $path including the volume (if applicable).
65 The remainder of the $path is the $filename.
66
67      # On Unix returns ("baz", "/foo/bar/", "")
68      fileparse("/foo/bar/baz");
69
70      # On Windows returns ("baz", "C:\foo\bar\", "")
71      fileparse("C:\foo\bar\baz");
72
73      # On Unix returns ("", "/foo/bar/baz/", "")
74      fileparse("/foo/bar/baz/");
75
76 If @suffixes are given each element is a pattern (either a string or a
77 C<qr//>) matched against the end of the $filename.  The matching
78 portion is removed and becomes the $suffix.
79
80      # On Unix returns ("baz", "/foo/bar", ".txt")
81      fileparse("/foo/bar/baz", qr/\.[^.]*/);
82
83 If type is one of "VMS", "MSDOS", "MacOS", "AmigaOS", "OS2", "MSWin32"
84 or "RISCOS" (see C<fileparse_set_fstype()>) then the pattern matching
85 for suffix removal is performed case-insensitively, since those
86 systems are not case-sensitive when opening existing files.
87
88 You are guaranteed that C<$directories . $filename . $suffix> will
89 denote the same location as the original $path.
90
91 =cut
92
93
94 sub fileparse {
95   my($fullname,@suffices) = @_;
96   unless (defined $fullname) {
97       require Carp;
98       Carp::croak("fileparse(): need a valid pathname");
99   }
100   my($fstype,$igncase) = ($Fileparse_fstype, $Fileparse_igncase);
101   my($dirpath,$tail,$suffix,$basename);
102   my($taint) = substr($fullname,0,0);  # Is $fullname tainted?
103
104   if ($fstype =~ /^VMS/i) {
105     if ($fullname =~ m#/#) { $fstype = '' }  # We're doing Unix emulation
106     else {
107       ($dirpath,$basename) = ($fullname =~ /^(.*[:>\]])?(.*)/s);
108       $dirpath ||= '';  # should always be defined
109     }
110   }
111   if ($fstype =~ /^MS(DOS|Win32)|epoc/i) {
112     ($dirpath,$basename) = ($fullname =~ /^((?:.*[:\\\/])?)(.*)/s);
113     $dirpath .= '.\\' unless $dirpath =~ /[\\\/]\z/;
114   }
115   elsif ($fstype =~ /^os2/i) {
116     ($dirpath,$basename) = ($fullname =~ m#^((?:.*[:\\/])?)(.*)#s);
117     $dirpath = './' unless $dirpath;    # Can't be 0
118     $dirpath .= '/' unless $dirpath =~ m#[\\/]\z#;
119   }
120   elsif ($fstype =~ /^MacOS/si) {
121     ($dirpath,$basename) = ($fullname =~ /^(.*:)?(.*)/s);
122     $dirpath = ':' unless $dirpath;
123   }
124   elsif ($fstype =~ /^AmigaOS/i) {
125     ($dirpath,$basename) = ($fullname =~ /(.*[:\/])?(.*)/s);
126     $dirpath = './' unless $dirpath;
127   }
128   elsif ($fstype !~ /^VMS/i) {  # default to Unix
129     ($dirpath,$basename) = ($fullname =~ m#^(.*/)?(.*)#s);
130     if ($^O eq 'VMS' and $fullname =~ m:^(/[^/]+/000000(/|$))(.*):) {
131       # dev:[000000] is top of VMS tree, similar to Unix '/'
132       # so strip it off and treat the rest as "normal"
133       my $devspec  = $1;
134       my $remainder = $3;
135       ($dirpath,$basename) = ($remainder =~ m#^(.*/)?(.*)#s);
136       $dirpath ||= '';  # should always be defined
137       $dirpath = $devspec.$dirpath;
138     }
139     $dirpath = './' unless $dirpath;
140   }
141
142   if (@suffices) {
143     $tail = '';
144     foreach $suffix (@suffices) {
145       my $pat = ($igncase ? '(?i)' : '') . "($suffix)\$";
146       if ($basename =~ s/$pat//s) {
147         $taint .= substr($suffix,0,0);
148         $tail = $1 . $tail;
149       }
150     }
151   }
152
153   # Ensure taint is propgated from the path to its pieces.
154   $tail .= $taint if defined $tail; # avoid warning if $tail == undef
155   wantarray ? ($basename .= $taint, $dirpath .= $taint, $tail)
156             : ($basename .= $taint);
157 }
158
159
160
161 =item C<basename>
162
163     my $filename = basename($path);
164     my $filename = basename($path, @suffixes);
165
166 C<basename()> works just like C<fileparse()> in scalar context - you only get
167 the $filename - except that it always quotes metacharacters in the @suffixes.
168
169     # These two function calls are equivalent.
170     my $filename = basename("/foo/bar/baz.txt",  ".txt");
171     my $filename = fileparse("/foo/bar/baz.txt", qr/\Q.txt\E/);
172
173 This function is provided for compatibility with the Unix shell command 
174 C<basename(1)>.
175
176 =cut
177
178
179 sub basename {
180   my($name) = shift;
181   (fileparse($name, map("\Q$_\E",@_)))[0];
182 }
183
184
185
186 =item C<dirname>
187
188 This function is provided for compatibility with the Unix shell
189 command C<dirname(1)> and has inherited some of its quirks.  In spite of
190 its name it does B<NOT> always return the directory name as you might
191 expect.  To be safe, if you want the directory name of a path use
192 C<fileparse()>.
193
194     # On all but Unix and MSDOS
195     my $directories = dirname($path);
196
197 On all system types but Unix and MSDOS this works just like
198 C<fileparse($path)> but returning just the $directories.
199
200     # On Unix and MSDOS
201     my $path_one_level_up = dirname($path);
202
203 When using Unix or MSDOS syntax this emulates the C<dirname(1)> shell function
204 which is subtly different from how C<fileparse()> works.  It returns all but
205 the last level of a file path even if the last level is clearly a directory.
206 In effect, it is not returning the directory portion but simply the path one
207 level up acting like C<chop()> for file paths.
208
209 Also unlike C<fileparse()>, C<dirname()> does not include a trailing slash on
210 its returned path.
211
212     # returns /foo/bar.  fileparse() would return /foo/bar/
213     dirname("/foo/bar/baz");
214
215     # also returns /foo/bar despite the fact that baz is clearly a 
216     # directory.  fileparse() would return /foo/bar/baz/
217     dirname("/foo/bar/baz/");
218
219     # returns '.'.  fileparse() would return 'foo/'
220     dirname("foo/");
221
222 Under VMS, if there is no directory information in the $path, then the
223 current default device and directory is used.
224
225 =cut
226
227
228 sub dirname {
229     my($fstype) = $Fileparse_fstype;
230
231     if( $fstype =~ /VMS/i and $_[0] =~ m{/} ) {
232         # Parse as Unix
233         local($File::Basename::Fileparse_fstype) = '';
234         return dirname(@_);
235     }
236
237     my($basename,$dirname) = fileparse($_[0]);
238
239     if ($fstype =~ /VMS/i) { 
240         $dirname ||= $ENV{DEFAULT};
241     }
242     elsif ($fstype =~ /MacOS/i) {
243         if( !length($basename) && $dirname !~ /^[^:]+:\z/) {
244             $dirname =~ s/([^:]):\z/$1/s;
245             ($basename,$dirname) = fileparse $dirname;
246         }
247         $dirname .= ":" unless $dirname =~ /:\z/;
248     }
249     elsif ($fstype =~ /MS(DOS|Win32)|os2/i) { 
250         $dirname =~ s/([^:])[\\\/]*\z/$1/;
251         unless( length($basename) ) {
252             ($basename,$dirname) = fileparse $dirname;
253             $dirname =~ s/([^:])[\\\/]*\z/$1/;
254         }
255     }
256     elsif ($fstype =~ /AmigaOS/i) {
257         if ( $dirname =~ /:\z/) { return $dirname }
258         chop $dirname;
259         $dirname =~ s#[^:/]+\z## unless length($basename);
260     }
261     else {
262         $dirname =~ s{(.)/*\z}{$1}s;
263         unless( length($basename) ) {
264             ($basename,$dirname) = fileparse $dirname;
265             $dirname =~ s{(.)/*\z}{$1}s;
266         }
267     }
268
269     $dirname;
270 }
271
272
273 =item C<fileparse_set_fstype>
274
275   my $previous_fstype = fileparse_set_fstype($type);
276
277 Normally File::Basename will assume a file path type native to your current
278 operating system (ie. /foo/bar style on Unix, \foo\bar on Windows, etc...).
279 With this function you can override that assumption.
280
281 Valid $types are "VMS", "MSDOS", "MacOS", "AmigaOS", "OS2", "RISCOS",
282 "MSWin32" and "Unix" (case-insensitive).  If an unrecognized $type is
283 given Unix semantics will be assumed.
284
285 If you've selected VMS syntax, and the file specification you pass to
286 one of these routines contains a "/", they assume you are using Unix
287 emulation and apply the Unix syntax rules instead, for that function
288 call only.
289
290 =back
291
292 =cut
293
294
295 sub fileparse_set_fstype {
296   my @old = ($Fileparse_fstype, $Fileparse_igncase);
297   if (@_) {
298     $Fileparse_fstype = $_[0];
299     $Fileparse_igncase = ($_[0] =~ /^(?:MacOS|VMS|AmigaOS|os2|RISCOS|MSWin32|MSDOS)/i);
300   }
301   wantarray ? @old : $old[0];
302 }
303
304
305 1;