xref: /onnv-gate/usr/src/cmd/perl/5.8.4/distrib/lib/File/Basename.pm (revision 0:68f95e015346)
1*0Sstevel@tonic-gatepackage File::Basename;
2*0Sstevel@tonic-gate
3*0Sstevel@tonic-gate=head1 NAME
4*0Sstevel@tonic-gate
5*0Sstevel@tonic-gatefileparse - split a pathname into pieces
6*0Sstevel@tonic-gate
7*0Sstevel@tonic-gatebasename - extract just the filename from a path
8*0Sstevel@tonic-gate
9*0Sstevel@tonic-gatedirname - extract just the directory from a path
10*0Sstevel@tonic-gate
11*0Sstevel@tonic-gate=head1 SYNOPSIS
12*0Sstevel@tonic-gate
13*0Sstevel@tonic-gate    use File::Basename;
14*0Sstevel@tonic-gate
15*0Sstevel@tonic-gate    ($name,$path,$suffix) = fileparse($fullname,@suffixlist)
16*0Sstevel@tonic-gate    fileparse_set_fstype($os_string);
17*0Sstevel@tonic-gate    $basename = basename($fullname,@suffixlist);
18*0Sstevel@tonic-gate    $dirname = dirname($fullname);
19*0Sstevel@tonic-gate
20*0Sstevel@tonic-gate    ($name,$path,$suffix) = fileparse("lib/File/Basename.pm",qr{\.pm});
21*0Sstevel@tonic-gate    fileparse_set_fstype("VMS");
22*0Sstevel@tonic-gate    $basename = basename("lib/File/Basename.pm",".pm");
23*0Sstevel@tonic-gate    $dirname = dirname("lib/File/Basename.pm");
24*0Sstevel@tonic-gate
25*0Sstevel@tonic-gate=head1 DESCRIPTION
26*0Sstevel@tonic-gate
27*0Sstevel@tonic-gateThese routines allow you to parse file specifications into useful
28*0Sstevel@tonic-gatepieces using the syntax of different operating systems.
29*0Sstevel@tonic-gate
30*0Sstevel@tonic-gate=over 4
31*0Sstevel@tonic-gate
32*0Sstevel@tonic-gate=item fileparse_set_fstype
33*0Sstevel@tonic-gate
34*0Sstevel@tonic-gateYou select the syntax via the routine fileparse_set_fstype().
35*0Sstevel@tonic-gate
36*0Sstevel@tonic-gateIf the argument passed to it contains one of the substrings
37*0Sstevel@tonic-gate"VMS", "MSDOS", "MacOS", "AmigaOS" or "MSWin32", the file specification
38*0Sstevel@tonic-gatesyntax of that operating system is used in future calls to
39*0Sstevel@tonic-gatefileparse(), basename(), and dirname().  If it contains none of
40*0Sstevel@tonic-gatethese substrings, Unix syntax is used.  This pattern matching is
41*0Sstevel@tonic-gatecase-insensitive.  If you've selected VMS syntax, and the file
42*0Sstevel@tonic-gatespecification you pass to one of these routines contains a "/",
43*0Sstevel@tonic-gatethey assume you are using Unix emulation and apply the Unix syntax
44*0Sstevel@tonic-gaterules instead, for that function call only.
45*0Sstevel@tonic-gate
46*0Sstevel@tonic-gateIf the argument passed to it contains one of the substrings "VMS",
47*0Sstevel@tonic-gate"MSDOS", "MacOS", "AmigaOS", "os2", "MSWin32" or "RISCOS", then the pattern
48*0Sstevel@tonic-gatematching for suffix removal is performed without regard for case,
49*0Sstevel@tonic-gatesince those systems are not case-sensitive when opening existing files
50*0Sstevel@tonic-gate(though some of them preserve case on file creation).
51*0Sstevel@tonic-gate
52*0Sstevel@tonic-gateIf you haven't called fileparse_set_fstype(), the syntax is chosen
53*0Sstevel@tonic-gateby examining the builtin variable C<$^O> according to these rules.
54*0Sstevel@tonic-gate
55*0Sstevel@tonic-gate=item fileparse
56*0Sstevel@tonic-gate
57*0Sstevel@tonic-gateThe fileparse() routine divides a file specification into three
58*0Sstevel@tonic-gateparts: a leading B<path>, a file B<name>, and a B<suffix>.  The
59*0Sstevel@tonic-gateB<path> contains everything up to and including the last directory
60*0Sstevel@tonic-gateseparator in the input file specification.  The remainder of the input
61*0Sstevel@tonic-gatefile specification is then divided into B<name> and B<suffix> based on
62*0Sstevel@tonic-gatethe optional patterns you specify in C<@suffixlist>.  Each element of
63*0Sstevel@tonic-gatethis list can be a qr-quoted pattern (or a string which is interpreted
64*0Sstevel@tonic-gateas a regular expression), and is matched
65*0Sstevel@tonic-gateagainst the end of B<name>.  If this succeeds, the matching portion of
66*0Sstevel@tonic-gateB<name> is removed and prepended to B<suffix>.  By proper use of
67*0Sstevel@tonic-gateC<@suffixlist>, you can remove file types or versions for examination.
68*0Sstevel@tonic-gate
69*0Sstevel@tonic-gateYou are guaranteed that if you concatenate B<path>, B<name>, and
70*0Sstevel@tonic-gateB<suffix> together in that order, the result will denote the same
71*0Sstevel@tonic-gatefile as the input file specification.
72*0Sstevel@tonic-gate
73*0Sstevel@tonic-gate=back
74*0Sstevel@tonic-gate
75*0Sstevel@tonic-gate=head1 EXAMPLES
76*0Sstevel@tonic-gate
77*0Sstevel@tonic-gateUsing Unix file syntax:
78*0Sstevel@tonic-gate
79*0Sstevel@tonic-gate    ($base,$path,$type) = fileparse('/virgil/aeneid/draft.book7',
80*0Sstevel@tonic-gate				    qr{\.book\d+});
81*0Sstevel@tonic-gate
82*0Sstevel@tonic-gatewould yield
83*0Sstevel@tonic-gate
84*0Sstevel@tonic-gate    $base eq 'draft'
85*0Sstevel@tonic-gate    $path eq '/virgil/aeneid/',
86*0Sstevel@tonic-gate    $type eq '.book7'
87*0Sstevel@tonic-gate
88*0Sstevel@tonic-gateSimilarly, using VMS syntax:
89*0Sstevel@tonic-gate
90*0Sstevel@tonic-gate    ($name,$dir,$type) = fileparse('Doc_Root:[Help]Rhetoric.Rnh',
91*0Sstevel@tonic-gate				   qr{\..*});
92*0Sstevel@tonic-gate
93*0Sstevel@tonic-gatewould yield
94*0Sstevel@tonic-gate
95*0Sstevel@tonic-gate    $name eq 'Rhetoric'
96*0Sstevel@tonic-gate    $dir  eq 'Doc_Root:[Help]'
97*0Sstevel@tonic-gate    $type eq '.Rnh'
98*0Sstevel@tonic-gate
99*0Sstevel@tonic-gate=over
100*0Sstevel@tonic-gate
101*0Sstevel@tonic-gate=item C<basename>
102*0Sstevel@tonic-gate
103*0Sstevel@tonic-gateThe basename() routine returns the first element of the list produced
104*0Sstevel@tonic-gateby calling fileparse() with the same arguments, except that it always
105*0Sstevel@tonic-gatequotes metacharacters in the given suffixes.  It is provided for
106*0Sstevel@tonic-gateprogrammer compatibility with the Unix shell command basename(1).
107*0Sstevel@tonic-gate
108*0Sstevel@tonic-gate=item C<dirname>
109*0Sstevel@tonic-gate
110*0Sstevel@tonic-gateThe dirname() routine returns the directory portion of the input file
111*0Sstevel@tonic-gatespecification.  When using VMS or MacOS syntax, this is identical to the
112*0Sstevel@tonic-gatesecond element of the list produced by calling fileparse() with the same
113*0Sstevel@tonic-gateinput file specification.  (Under VMS, if there is no directory information
114*0Sstevel@tonic-gatein the input file specification, then the current default device and
115*0Sstevel@tonic-gatedirectory are returned.)  When using Unix or MSDOS syntax, the return
116*0Sstevel@tonic-gatevalue conforms to the behavior of the Unix shell command dirname(1).  This
117*0Sstevel@tonic-gateis usually the same as the behavior of fileparse(), but differs in some
118*0Sstevel@tonic-gatecases.  For example, for the input file specification F<lib/>, fileparse()
119*0Sstevel@tonic-gateconsiders the directory name to be F<lib/>, while dirname() considers the
120*0Sstevel@tonic-gatedirectory name to be F<.>).
121*0Sstevel@tonic-gate
122*0Sstevel@tonic-gate=back
123*0Sstevel@tonic-gate
124*0Sstevel@tonic-gate=cut
125*0Sstevel@tonic-gate
126*0Sstevel@tonic-gate
127*0Sstevel@tonic-gate## use strict;
128*0Sstevel@tonic-gate# A bit of juggling to insure that C<use re 'taint';> always works, since
129*0Sstevel@tonic-gate# File::Basename is used during the Perl build, when the re extension may
130*0Sstevel@tonic-gate# not be available.
131*0Sstevel@tonic-gateBEGIN {
132*0Sstevel@tonic-gate  unless (eval { require re; })
133*0Sstevel@tonic-gate    { eval ' sub re::import { $^H |= 0x00100000; } ' } # HINT_RE_TAINT
134*0Sstevel@tonic-gate  import re 'taint';
135*0Sstevel@tonic-gate}
136*0Sstevel@tonic-gate
137*0Sstevel@tonic-gate
138*0Sstevel@tonic-gate
139*0Sstevel@tonic-gateuse 5.006;
140*0Sstevel@tonic-gateuse warnings;
141*0Sstevel@tonic-gateour(@ISA, @EXPORT, $VERSION, $Fileparse_fstype, $Fileparse_igncase);
142*0Sstevel@tonic-gaterequire Exporter;
143*0Sstevel@tonic-gate@ISA = qw(Exporter);
144*0Sstevel@tonic-gate@EXPORT = qw(fileparse fileparse_set_fstype basename dirname);
145*0Sstevel@tonic-gate$VERSION = "2.72";
146*0Sstevel@tonic-gate
147*0Sstevel@tonic-gate
148*0Sstevel@tonic-gate#   fileparse_set_fstype() - specify OS-based rules used in future
149*0Sstevel@tonic-gate#                            calls to routines in this package
150*0Sstevel@tonic-gate#
151*0Sstevel@tonic-gate#   Currently recognized values: VMS, MSDOS, MacOS, AmigaOS, os2, RISCOS
152*0Sstevel@tonic-gate#       Any other name uses Unix-style rules and is case-sensitive
153*0Sstevel@tonic-gate
154*0Sstevel@tonic-gatesub fileparse_set_fstype {
155*0Sstevel@tonic-gate  my @old = ($Fileparse_fstype, $Fileparse_igncase);
156*0Sstevel@tonic-gate  if (@_) {
157*0Sstevel@tonic-gate    $Fileparse_fstype = $_[0];
158*0Sstevel@tonic-gate    $Fileparse_igncase = ($_[0] =~ /^(?:MacOS|VMS|AmigaOS|os2|RISCOS|MSWin32|MSDOS)/i);
159*0Sstevel@tonic-gate  }
160*0Sstevel@tonic-gate  wantarray ? @old : $old[0];
161*0Sstevel@tonic-gate}
162*0Sstevel@tonic-gate
163*0Sstevel@tonic-gate#   fileparse() - parse file specification
164*0Sstevel@tonic-gate#
165*0Sstevel@tonic-gate#   Version 2.4  27-Sep-1996  Charles Bailey  bailey@genetics.upenn.edu
166*0Sstevel@tonic-gate
167*0Sstevel@tonic-gate
168*0Sstevel@tonic-gatesub fileparse {
169*0Sstevel@tonic-gate  my($fullname,@suffices) = @_;
170*0Sstevel@tonic-gate  unless (defined $fullname) {
171*0Sstevel@tonic-gate      require Carp;
172*0Sstevel@tonic-gate      Carp::croak("fileparse(): need a valid pathname");
173*0Sstevel@tonic-gate  }
174*0Sstevel@tonic-gate  my($fstype,$igncase) = ($Fileparse_fstype, $Fileparse_igncase);
175*0Sstevel@tonic-gate  my($dirpath,$tail,$suffix,$basename);
176*0Sstevel@tonic-gate  my($taint) = substr($fullname,0,0);  # Is $fullname tainted?
177*0Sstevel@tonic-gate
178*0Sstevel@tonic-gate  if ($fstype =~ /^VMS/i) {
179*0Sstevel@tonic-gate    if ($fullname =~ m#/#) { $fstype = '' }  # We're doing Unix emulation
180*0Sstevel@tonic-gate    else {
181*0Sstevel@tonic-gate      ($dirpath,$basename) = ($fullname =~ /^(.*[:>\]])?(.*)/s);
182*0Sstevel@tonic-gate      $dirpath ||= '';  # should always be defined
183*0Sstevel@tonic-gate    }
184*0Sstevel@tonic-gate  }
185*0Sstevel@tonic-gate  if ($fstype =~ /^MS(DOS|Win32)|epoc/i) {
186*0Sstevel@tonic-gate    ($dirpath,$basename) = ($fullname =~ /^((?:.*[:\\\/])?)(.*)/s);
187*0Sstevel@tonic-gate    $dirpath .= '.\\' unless $dirpath =~ /[\\\/]\z/;
188*0Sstevel@tonic-gate  }
189*0Sstevel@tonic-gate  elsif ($fstype =~ /^os2/i) {
190*0Sstevel@tonic-gate    ($dirpath,$basename) = ($fullname =~ m#^((?:.*[:\\/])?)(.*)#s);
191*0Sstevel@tonic-gate    $dirpath = './' unless $dirpath;	# Can't be 0
192*0Sstevel@tonic-gate    $dirpath .= '/' unless $dirpath =~ m#[\\/]\z#;
193*0Sstevel@tonic-gate  }
194*0Sstevel@tonic-gate  elsif ($fstype =~ /^MacOS/si) {
195*0Sstevel@tonic-gate    ($dirpath,$basename) = ($fullname =~ /^(.*:)?(.*)/s);
196*0Sstevel@tonic-gate    $dirpath = ':' unless $dirpath;
197*0Sstevel@tonic-gate  }
198*0Sstevel@tonic-gate  elsif ($fstype =~ /^AmigaOS/i) {
199*0Sstevel@tonic-gate    ($dirpath,$basename) = ($fullname =~ /(.*[:\/])?(.*)/s);
200*0Sstevel@tonic-gate    $dirpath = './' unless $dirpath;
201*0Sstevel@tonic-gate  }
202*0Sstevel@tonic-gate  elsif ($fstype !~ /^VMS/i) {  # default to Unix
203*0Sstevel@tonic-gate    ($dirpath,$basename) = ($fullname =~ m#^(.*/)?(.*)#s);
204*0Sstevel@tonic-gate    if ($^O eq 'VMS' and $fullname =~ m:^(/[^/]+/000000(/|$))(.*):) {
205*0Sstevel@tonic-gate      # dev:[000000] is top of VMS tree, similar to Unix '/'
206*0Sstevel@tonic-gate      # so strip it off and treat the rest as "normal"
207*0Sstevel@tonic-gate      my $devspec  = $1;
208*0Sstevel@tonic-gate      my $remainder = $3;
209*0Sstevel@tonic-gate      ($dirpath,$basename) = ($remainder =~ m#^(.*/)?(.*)#s);
210*0Sstevel@tonic-gate      $dirpath ||= '';  # should always be defined
211*0Sstevel@tonic-gate      $dirpath = $devspec.$dirpath;
212*0Sstevel@tonic-gate    }
213*0Sstevel@tonic-gate    $dirpath = './' unless $dirpath;
214*0Sstevel@tonic-gate  }
215*0Sstevel@tonic-gate
216*0Sstevel@tonic-gate  if (@suffices) {
217*0Sstevel@tonic-gate    $tail = '';
218*0Sstevel@tonic-gate    foreach $suffix (@suffices) {
219*0Sstevel@tonic-gate      my $pat = ($igncase ? '(?i)' : '') . "($suffix)\$";
220*0Sstevel@tonic-gate      if ($basename =~ s/$pat//s) {
221*0Sstevel@tonic-gate        $taint .= substr($suffix,0,0);
222*0Sstevel@tonic-gate        $tail = $1 . $tail;
223*0Sstevel@tonic-gate      }
224*0Sstevel@tonic-gate    }
225*0Sstevel@tonic-gate  }
226*0Sstevel@tonic-gate
227*0Sstevel@tonic-gate  $tail .= $taint if defined $tail; # avoid warning if $tail == undef
228*0Sstevel@tonic-gate  wantarray ? ($basename .= $taint, $dirpath .= $taint, $tail)
229*0Sstevel@tonic-gate            : ($basename .= $taint);
230*0Sstevel@tonic-gate}
231*0Sstevel@tonic-gate
232*0Sstevel@tonic-gate
233*0Sstevel@tonic-gate#   basename() - returns first element of list returned by fileparse()
234*0Sstevel@tonic-gate
235*0Sstevel@tonic-gatesub basename {
236*0Sstevel@tonic-gate  my($name) = shift;
237*0Sstevel@tonic-gate  (fileparse($name, map("\Q$_\E",@_)))[0];
238*0Sstevel@tonic-gate}
239*0Sstevel@tonic-gate
240*0Sstevel@tonic-gate
241*0Sstevel@tonic-gate#    dirname() - returns device and directory portion of file specification
242*0Sstevel@tonic-gate#        Behavior matches that of Unix dirname(1) exactly for Unix and MSDOS
243*0Sstevel@tonic-gate#        filespecs except for names ending with a separator, e.g., "/xx/yy/".
244*0Sstevel@tonic-gate#        This differs from the second element of the list returned
245*0Sstevel@tonic-gate#        by fileparse() in that the trailing '/' (Unix) or '\' (MSDOS) (and
246*0Sstevel@tonic-gate#        the last directory name if the filespec ends in a '/' or '\'), is lost.
247*0Sstevel@tonic-gate
248*0Sstevel@tonic-gatesub dirname {
249*0Sstevel@tonic-gate    my($basename,$dirname) = fileparse($_[0]);
250*0Sstevel@tonic-gate    my($fstype) = $Fileparse_fstype;
251*0Sstevel@tonic-gate
252*0Sstevel@tonic-gate    if ($fstype =~ /VMS/i) {
253*0Sstevel@tonic-gate        if ($_[0] =~ m#/#) { $fstype = '' }
254*0Sstevel@tonic-gate        else { return $dirname || $ENV{DEFAULT} }
255*0Sstevel@tonic-gate    }
256*0Sstevel@tonic-gate    if ($fstype =~ /MacOS/i) {
257*0Sstevel@tonic-gate	if( !length($basename) && $dirname !~ /^[^:]+:\z/) {
258*0Sstevel@tonic-gate	    $dirname =~ s/([^:]):\z/$1/s;
259*0Sstevel@tonic-gate	    ($basename,$dirname) = fileparse $dirname;
260*0Sstevel@tonic-gate	}
261*0Sstevel@tonic-gate	$dirname .= ":" unless $dirname =~ /:\z/;
262*0Sstevel@tonic-gate    }
263*0Sstevel@tonic-gate    elsif ($fstype =~ /MS(DOS|Win32)|os2/i) {
264*0Sstevel@tonic-gate        $dirname =~ s/([^:])[\\\/]*\z/$1/;
265*0Sstevel@tonic-gate        unless( length($basename) ) {
266*0Sstevel@tonic-gate	    ($basename,$dirname) = fileparse $dirname;
267*0Sstevel@tonic-gate	    $dirname =~ s/([^:])[\\\/]*\z/$1/;
268*0Sstevel@tonic-gate	}
269*0Sstevel@tonic-gate    }
270*0Sstevel@tonic-gate    elsif ($fstype =~ /AmigaOS/i) {
271*0Sstevel@tonic-gate        if ( $dirname =~ /:\z/) { return $dirname }
272*0Sstevel@tonic-gate        chop $dirname;
273*0Sstevel@tonic-gate        $dirname =~ s#[^:/]+\z## unless length($basename);
274*0Sstevel@tonic-gate    }
275*0Sstevel@tonic-gate    else {
276*0Sstevel@tonic-gate        $dirname =~ s:(.)/*\z:$1:s;
277*0Sstevel@tonic-gate        unless( length($basename) ) {
278*0Sstevel@tonic-gate	    local($File::Basename::Fileparse_fstype) = $fstype;
279*0Sstevel@tonic-gate	    ($basename,$dirname) = fileparse $dirname;
280*0Sstevel@tonic-gate	    $dirname =~ s:(.)/*\z:$1:s;
281*0Sstevel@tonic-gate	}
282*0Sstevel@tonic-gate    }
283*0Sstevel@tonic-gate
284*0Sstevel@tonic-gate    $dirname;
285*0Sstevel@tonic-gate}
286*0Sstevel@tonic-gate
287*0Sstevel@tonic-gatefileparse_set_fstype $^O;
288*0Sstevel@tonic-gate
289*0Sstevel@tonic-gate1;
290