home *** CD-ROM | disk | FTP | other *** search
/ Chip: Windows 2000 Professional Resource Kit / W2KPRK.iso / apps / perl / ActivePerl.exe / data.z / Win32.pm < prev    next >
Encoding:
Perl POD Document  |  1999-10-14  |  10.5 KB  |  399 lines

  1. package File::Spec::Win32;
  2.  
  3. use strict;
  4. use Cwd;
  5. use vars qw(@ISA);
  6. require File::Spec::Unix;
  7. @ISA = qw(File::Spec::Unix);
  8.  
  9. =head1 NAME
  10.  
  11. File::Spec::Win32 - methods for Win32 file specs
  12.  
  13. =head1 SYNOPSIS
  14.  
  15.  require File::Spec::Win32; # Done internally by File::Spec if needed
  16.  
  17. =head1 DESCRIPTION
  18.  
  19. See File::Spec::Unix for a documentation of the methods provided
  20. there. This package overrides the implementation of these methods, not
  21. the semantics.
  22.  
  23. =over
  24.  
  25. =item devnull
  26.  
  27. Returns a string representation of the null device.
  28.  
  29. =cut
  30.  
  31. sub devnull {
  32.     return "nul";
  33. }
  34.  
  35. =item tmpdir
  36.  
  37. Returns a string representation of the first existing directory
  38. from the following list:
  39.  
  40.     $ENV{TMPDIR}
  41.     $ENV{TEMP}
  42.     $ENV{TMP}
  43.     /tmp
  44.     /
  45.  
  46. =cut
  47.  
  48. my $tmpdir;
  49. sub tmpdir {
  50.     return $tmpdir if defined $tmpdir;
  51.     my $self = shift;
  52.     foreach (@ENV{qw(TMPDIR TEMP TMP)}, qw(/tmp /)) {
  53.     next unless defined && -d;
  54.     $tmpdir = $_;
  55.     last;
  56.     }
  57.     $tmpdir = '' unless defined $tmpdir;
  58.     $tmpdir = $self->canonpath($tmpdir);
  59.     return $tmpdir;
  60. }
  61.  
  62. sub file_name_is_absolute {
  63.     my ($self,$file) = @_;
  64.     return scalar($file =~ m{^([a-z]:)?[\\/]}i);
  65. }
  66.  
  67. =item catfile
  68.  
  69. Concatenate one or more directory names and a filename to form a
  70. complete path ending with a filename
  71.  
  72. =cut
  73.  
  74. sub catfile {
  75.     my $self = shift;
  76.     my $file = pop @_;
  77.     return $file unless @_;
  78.     my $dir = $self->catdir(@_);
  79.     $dir .= "\\" unless substr($dir,-1) eq "\\";
  80.     return $dir.$file;
  81. }
  82.  
  83. sub path {
  84.     local $^W = 1;
  85.     my $path = $ENV{'PATH'} || $ENV{'Path'} || $ENV{'path'};
  86.     my @path = split(';',$path);
  87.     foreach (@path) { $_ = '.' if $_ eq '' }
  88.     return @path;
  89. }
  90.  
  91. =item canonpath
  92.  
  93. No physical check on the filesystem, but a logical cleanup of a
  94. path. On UNIX eliminated successive slashes and successive "/.".
  95.  
  96. =cut
  97.  
  98. sub canonpath {
  99.     my ($self,$path,$reduce_ricochet) = @_;
  100.     $path =~ s/^([a-z]:)/\u$1/;
  101.     $path =~ s|/|\\|g;
  102.     $path =~ s|([^\\])\\+|$1\\|g;                  # xx////xx  -> xx/xx
  103.     $path =~ s|(\\\.)+\\|\\|g;                     # xx/././xx -> xx/xx
  104.     $path =~ s|^(\.\\)+|| unless $path eq ".\\";   # ./xx      -> xx
  105.     $path =~ s|\\$||
  106.              unless $path =~ m#^([A-Z]:)?\\$#;     # xx/       -> xx
  107.     return $path;
  108. }
  109.  
  110. =item splitpath
  111.  
  112.     ($volume,$directories,$file) = File::Spec->splitpath( $path );
  113.     ($volume,$directories,$file) = File::Spec->splitpath( $path, $no_file );
  114.  
  115. Splits a path in to volume, directory, and filename portions. Assumes that 
  116. the last file is a path unless the path ends in '\\', '\\.', '\\..'
  117. or $no_file is true.  On Win32 this means that $no_file true makes this return 
  118. ( $volume, $path, undef ).
  119.  
  120. Separators accepted are \ and /.
  121.  
  122. Volumes can be drive letters or UNC sharenames (\\server\share).
  123.  
  124. The results can be passed to L</catpath()> to get back a path equivalent to
  125. (usually identical to) the original path.
  126.  
  127. =cut
  128.  
  129. sub splitpath {
  130.     my ($self,$path, $nofile) = @_;
  131.     my ($volume,$directory,$file) = ('','','');
  132.     if ( $nofile ) {
  133.         $path =~ 
  134.             m@^( (?:[a-zA-Z]:|(?:\\\\\\\\|//)[^\\\\/]+[\\\\/][^\\\\/]+)? ) 
  135.                  (.*)
  136.              @x;
  137.         $volume    = $1;
  138.         $directory = $2;
  139.     }
  140.     else {
  141.         $path =~ 
  142.             m@^ ( (?: [a-zA-Z]: |
  143.                       (?:\\\\\\\\|//)[^\\\\/]+[\\\\/][^\\\\/]+
  144.                   )?
  145.                 )
  146.                 ( (?:.*[\\\\/](?:\.\.?$)?)? )
  147.                 (.*)
  148.              @x;
  149.         $volume    = $1;
  150.         $directory = $2;
  151.         $file      = $3;
  152.     }
  153.  
  154.     return ($volume,$directory,$file);
  155. }
  156.  
  157.  
  158. =item splitdir
  159.  
  160. The opposite of L</catdir()>.
  161.  
  162.     @dirs = File::Spec->splitdir( $directories );
  163.  
  164. $directories must be only the directory portion of the path on systems 
  165. that have the concept of a volume or that have path syntax that differentiates
  166. files from directories.
  167.  
  168. Unlike just splitting the directories on the separator, leading empty and 
  169. trailing directory entries can be returned, because these are significant
  170. on some OSs. So,
  171.  
  172.     File::Spec->splitdir( "/a/b/c" );
  173.  
  174. Yields:
  175.  
  176.     ( '', 'a', 'b', '', 'c', '' )
  177.  
  178. =cut
  179.  
  180. sub splitdir {
  181.     my ($self,$directories) = @_ ;
  182.     #
  183.     # split() likes to forget about trailing null fields, so here we
  184.     # check to be sure that there will not be any before handling the
  185.     # simple case.
  186.     #
  187.     if ( $directories !~ m|[\\/]$| ) {
  188.         return split( m|[\\/]|, $directories );
  189.     }
  190.     else {
  191.         #
  192.         # since there was a trailing separator, add a file name to the end, 
  193.         # then do the split, then replace it with ''.
  194.         #
  195.         my( @directories )= split( m|[\\/]|, "${directories}dummy" ) ;
  196.         $directories[ $#directories ]= '' ;
  197.         return @directories ;
  198.     }
  199. }
  200.  
  201.  
  202. =item catpath
  203.  
  204. Takes volume, directory and file portions and returns an entire path. Under
  205. Unix, $volume is ignored, and this is just like catfile(). On other OSs,
  206. the $volume become significant.
  207.  
  208. =cut
  209.  
  210. sub catpath {
  211.     my ($self,$volume,$directory,$file) = @_;
  212.  
  213.     # If it's UNC, make sure the glue separator is there, reusing
  214.     # whatever separator is first in the $volume
  215.     $volume .= $1
  216.         if ( $volume =~ m@^([\\/])[\\/][^\\/]+[\\/][^\\/]+$@ &&
  217.              $directory =~ m@^[^\\/]@
  218.            ) ;
  219.  
  220.     $volume .= $directory ;
  221.  
  222.     # If the volume is not just A:, make sure the glue separator is 
  223.     # there, reusing whatever separator is first in the $volume if possible.
  224.     if ( $volume !~ m@^[a-zA-Z]:$@ &&
  225.          $volume !~ m@[\\/]$@      &&
  226.          $file   !~ m@^[\\/]@
  227.        ) {
  228.         $volume =~ m@([\\/])@ ;
  229.         my $sep = $1 ? $1 : '\\' ;
  230.         $volume .= $sep ;
  231.     }
  232.  
  233.     $volume .= $file ;
  234.  
  235.     return $volume ;
  236. }
  237.  
  238.  
  239. =item abs2rel
  240.  
  241. Takes a destination path and an optional base path returns a relative path
  242. from the base path to the destination path:
  243.  
  244.     $rel_path = File::Spec->abs2rel( $destination ) ;
  245.     $rel_path = File::Spec->abs2rel( $destination, $base ) ;
  246.  
  247. If $base is not present or '', then L</cwd()> is used. If $base is relative, 
  248. then it is converted to absolute form using L</rel2abs()>. This means that it
  249. is taken to be relative to L<cwd()>.
  250.  
  251. On systems with the concept of a volume, this assumes that both paths 
  252. are on the $destination volume, and ignores the $base volume. 
  253.  
  254. On systems that have a grammar that indicates filenames, this ignores the 
  255. $base filename as well. Otherwise all path components are assumed to be
  256. directories.
  257.  
  258. If $path is relative, it is converted to absolute form using L</rel2abs()>.
  259. This means that it is taken to be relative to L</cwd()>.
  260.  
  261. Based on code written by Shigio Yamaguchi.
  262.  
  263. No checks against the filesystem are made. 
  264.  
  265. =cut
  266.  
  267. sub abs2rel {
  268.     my($self,$path,$base) = @_;
  269.  
  270.     # Clean up $path
  271.     if ( ! $self->file_name_is_absolute( $path ) ) {
  272.         $path = $self->rel2abs( $path ) ;
  273.     }
  274.     else {
  275.         $path = $self->canonpath( $path ) ;
  276.     }
  277.  
  278.     # Figure out the effective $base and clean it up.
  279.     if ( ! $self->file_name_is_absolute( $base ) ) {
  280.         $base = $self->rel2abs( $base ) ;
  281.     }
  282.     elsif ( !defined( $base ) || $base eq '' ) {
  283.         $base = cwd() ;
  284.     }
  285.     else {
  286.         $base = $self->canonpath( $base ) ;
  287.     }
  288.  
  289.     # Split up paths
  290.     my ( $path_volume, $path_directories, $path_file ) =
  291.         $self->splitpath( $path, 1 ) ;
  292.  
  293.     my ( undef, $base_directories, undef ) =
  294.         $self->splitpath( $base, 1 ) ;
  295.  
  296.     # Now, remove all leading components that are the same
  297.     my @pathchunks = $self->splitdir( $path_directories );
  298.     my @basechunks = $self->splitdir( $base_directories );
  299.  
  300.     while ( @pathchunks && 
  301.             @basechunks && 
  302.             lc( $pathchunks[0] ) eq lc( $basechunks[0] ) 
  303.           ) {
  304.         shift @pathchunks ;
  305.         shift @basechunks ;
  306.     }
  307.  
  308.     # No need to catdir, we know these are well formed.
  309.     $path_directories = CORE::join( '\\', @pathchunks );
  310.     $base_directories = CORE::join( '\\', @basechunks );
  311.  
  312.     # $base now contains the directories the resulting relative path 
  313.     # must ascend out of before it can descend to $path_directory.  So, 
  314.     # replace all names with $parentDir
  315.     $base_directories =~ s|[^/]+|..|g ;
  316.  
  317.     # Glue the two together, using a separator if necessary, and preventing an
  318.     # empty result.
  319.     if ( $path ne '' && $base ne '' ) {
  320.         $path_directories = "$base_directories\\$path_directories" ;
  321.     } else {
  322.         $path_directories = "$base_directories$path_directories" ;
  323.     }
  324.  
  325.     return $self->canonpath( 
  326.         $self->catpath( $path_volume, $path_directories, $path_file )
  327.     ) ;
  328. }
  329.  
  330. =item rel2abs
  331.  
  332. Converts a relative path to an absolute path. 
  333.  
  334.     $abs_path = $File::Spec->rel2abs( $destination ) ;
  335.     $abs_path = $File::Spec->rel2abs( $destination, $base ) ;
  336.  
  337. If $base is not present or '', then L<cwd()> is used. If $base is relative, 
  338. then it is converted to absolute form using L</rel2abs()>. This means that it
  339. is taken to be relative to L</cwd()>.
  340.  
  341. Assumes that both paths are on the $base volume, and ignores the 
  342. $destination volume. 
  343.  
  344. On systems that have a grammar that indicates filenames, this ignores the 
  345. $base filename as well. Otherwise all path components are assumed to be
  346. directories.
  347.  
  348. If $path is absolute, it is cleaned up and returned using L</canonpath()>.
  349.  
  350. Based on code written by Shigio Yamaguchi.
  351.  
  352. No checks against the filesystem are made. 
  353.  
  354. =cut
  355.  
  356. sub rel2abs($;$;) {
  357.     my ($self,$path,$base ) = @_;
  358.  
  359.     # Clean up and split up $path
  360.     if ( ! $self->file_name_is_absolute( $path ) ) {
  361.  
  362.         # Figure out the effective $base and clean it up.
  363.         if ( ! $self->file_name_is_absolute( $base ) ) {
  364.             $base = $self->rel2abs( $base ) ;
  365.         }
  366.         elsif ( !defined( $base ) || $base eq '' ) {
  367.             $base = cwd() ;
  368.         }
  369.         else {
  370.             $base = $self->canonpath( $base ) ;
  371.         }
  372.  
  373.         # Split up paths
  374.         my ( undef, $path_directories, $path_file ) =
  375.             $self->splitpath( $path, 1 ) ;
  376.  
  377.         my ( $base_volume, $base_directories, undef ) =
  378.             $self->splitpath( $base, 1 ) ;
  379.  
  380.         $path = $self->catpath( 
  381.             $base_volume, 
  382.             $self->catdir( $base_directories, $path_directories ), 
  383.             $path_file
  384.         ) ;
  385.     }
  386.  
  387.     return $self->canonpath( $path ) ;
  388. }
  389.  
  390. =back
  391.  
  392. =head1 SEE ALSO
  393.  
  394. L<File::Spec>
  395.  
  396. =cut
  397.  
  398. 1;
  399.