home *** CD-ROM | disk | FTP | other *** search
/ CLIX - Fazer Clix Custa Nix / CLIX-CD.cdr / mac / lib / Cwd.pm < prev    next >
Text File  |  1997-05-19  |  9KB  |  392 lines

  1. package Cwd;
  2. require 5.000;
  3.  
  4. =head1 NAME
  5.  
  6. getcwd - get pathname of current working directory
  7.  
  8. =head1 SYNOPSIS
  9.  
  10.     use Cwd;
  11.     $dir = cwd;
  12.  
  13.     use Cwd;
  14.     $dir = getcwd;
  15.  
  16.     use Cwd;
  17.     $dir = fastgetcwd;
  18.  
  19.     use Cwd 'chdir';
  20.     chdir "/tmp";
  21.     print $ENV{'PWD'};
  22.  
  23. =head1 DESCRIPTION
  24.  
  25. The getcwd() function re-implements the getcwd(3) (or getwd(3)) functions
  26. in Perl.
  27.  
  28. The fastcwd() function looks the same as getcwd(), but runs faster.
  29. It's also more dangerous because you might conceivably chdir() out of a
  30. directory that you can't chdir() back into.
  31.  
  32. The cwd() function looks the same as getcwd and fastgetcwd but is
  33. implemented using the most natural and safe form for the current
  34. architecture. For most systems it is identical to `pwd` (but without
  35. the trailing line terminator). It is recommended that cwd (or another
  36. *cwd() function) is used in I<all> code to ensure portability.
  37.  
  38. If you ask to override your chdir() built-in function, then your PWD
  39. environment variable will be kept up to date.  (See
  40. L<perlsub/Overriding Builtin Functions>.) Note that it will only be
  41. kept up to date if all packages which use chdir import it from Cwd.
  42.  
  43. =cut
  44.  
  45. ## use strict;
  46.  
  47. use Carp;
  48.  
  49. $VERSION = '2.00';
  50.  
  51. require Exporter;
  52. @ISA = qw(Exporter);
  53. @EXPORT = qw(cwd getcwd fastcwd fastgetcwd);
  54. @EXPORT_OK = qw(chdir abs_path fast_abs_path);
  55.  
  56.  
  57. # The 'natural and safe form' for UNIX (pwd may be setuid root)
  58.  
  59. sub _backtick_pwd {
  60.     my $cwd;
  61.     chop($cwd = `pwd`);
  62.     $cwd;
  63. }
  64.  
  65. # Since some ports may predefine cwd internally (e.g., NT)
  66. # we take care not to override an existing definition for cwd().
  67.  
  68. *cwd = \&_backtick_pwd unless defined &cwd;
  69.  
  70.  
  71. # By Brandon S. Allbery
  72. #
  73. # Usage: $cwd = getcwd();
  74.  
  75. sub getcwd
  76. {
  77.     my($dotdots, $cwd, @pst, @cst, $dir, @tst);
  78.     
  79.     unless (@cst = stat('.'))
  80.     {
  81.     warn "stat(.): $!";
  82.     return '';
  83.     }
  84.     $cwd = '';
  85.     $dotdots = '';
  86.     do
  87.     {
  88.     $dotdots .= '/' if $dotdots;
  89.     $dotdots .= '..';
  90.     @pst = @cst;
  91.     unless (opendir(PARENT, $dotdots))
  92.     {
  93.         warn "opendir($dotdots): $!";
  94.         return '';
  95.     }
  96.     unless (@cst = stat($dotdots))
  97.     {
  98.         warn "stat($dotdots): $!";
  99.         closedir(PARENT);
  100.         return '';
  101.     }
  102.     if ($pst[0] == $cst[0] && $pst[1] == $cst[1])
  103.     {
  104.         $dir = '';
  105.     }
  106.     else
  107.     {
  108.         do
  109.         {
  110.         unless (defined ($dir = readdir(PARENT)))
  111.             {
  112.             warn "readdir($dotdots): $!";
  113.             closedir(PARENT);
  114.             return '';
  115.         }
  116.         unless (@tst = lstat("$dotdots/$dir"))
  117.         {
  118.             # warn "lstat($dotdots/$dir): $!";
  119.             # Just because you can't lstat this directory
  120.             # doesn't mean you'll never find the right one.
  121.             # closedir(PARENT);
  122.             # return '';
  123.         }
  124.         }
  125.         while ($dir eq '.' || $dir eq '..' || $tst[0] != $pst[0] ||
  126.            $tst[1] != $pst[1]);
  127.     }
  128.     $cwd = "$dir/$cwd";
  129.     closedir(PARENT);
  130.     } while ($dir);
  131.     chop($cwd) unless $cwd eq '/'; # drop the trailing /
  132.     $cwd;
  133. }
  134.  
  135.  
  136.  
  137. # By John Bazik
  138. #
  139. # Usage: $cwd = &fastcwd;
  140. #
  141. # This is a faster version of getcwd.  It's also more dangerous because
  142. # you might chdir out of a directory that you can't chdir back into.
  143.  
  144. sub fastcwd {
  145.     my($odev, $oino, $cdev, $cino, $tdev, $tino);
  146.     my(@path, $path);
  147.     local(*DIR);
  148.  
  149.     ($cdev, $cino) = stat('.');
  150.     for (;;) {
  151.     my $direntry;
  152.     ($odev, $oino) = ($cdev, $cino);
  153.     chdir('..');
  154.     ($cdev, $cino) = stat('.');
  155.     last if $odev == $cdev && $oino == $cino;
  156.     opendir(DIR, '.');
  157.     for (;;) {
  158.         $direntry = readdir(DIR);
  159.         next if $direntry eq '.';
  160.         next if $direntry eq '..';
  161.  
  162.         last unless defined $direntry;
  163.         ($tdev, $tino) = lstat($direntry);
  164.         last unless $tdev != $odev || $tino != $oino;
  165.     }
  166.     closedir(DIR);
  167.     unshift(@path, $direntry);
  168.     }
  169.     chdir($path = '/' . join('/', @path));
  170.     $path;
  171. }
  172.  
  173.  
  174. # Keeps track of current working directory in PWD environment var
  175. # Usage:
  176. #    use Cwd 'chdir';
  177. #    chdir $newdir;
  178.  
  179. my $chdir_init = 0;
  180.  
  181. sub chdir_init {
  182.     if ($ENV{'PWD'} and $^O ne 'os2' and $^O ne 'msdos') {
  183.     my($dd,$di) = stat('.');
  184.     my($pd,$pi) = stat($ENV{'PWD'});
  185.     if (!defined $dd or !defined $pd or $di != $pi or $dd != $pd) {
  186.         $ENV{'PWD'} = cwd();
  187.     }
  188.     }
  189.     else {
  190.     $ENV{'PWD'} = cwd();
  191.     }
  192.     # Strip an automounter prefix (where /tmp_mnt/foo/bar == /foo/bar)
  193.     if ($ENV{'PWD'} =~ m|(/[^/]+(/[^/]+/[^/]+))(.*)|) {
  194.     my($pd,$pi) = stat($2);
  195.     my($dd,$di) = stat($1);
  196.     if (defined $pd and defined $dd and $di == $pi and $dd == $pd) {
  197.         $ENV{'PWD'}="$2$3";
  198.     }
  199.     }
  200.     $chdir_init = 1;
  201. }
  202.  
  203. sub chdir {
  204.     my $newdir = shift || '';    # allow for no arg (chdir to HOME dir)
  205.     $newdir =~ s|///*|/|g;
  206.     chdir_init() unless $chdir_init;
  207.     return 0 unless CORE::chdir $newdir;
  208.     if ($^O eq 'VMS') { return $ENV{'PWD'} = $ENV{'DEFAULT'} }
  209.     if ($^O eq 'MacOS') { return $ENV{'PWD'} = cwd(); }
  210.  
  211.     if ($newdir =~ m#^/#) {
  212.     $ENV{'PWD'} = $newdir;
  213.     } else {
  214.     my @curdir = split(m#/#,$ENV{'PWD'});
  215.     @curdir = ('') unless @curdir;
  216.     my $component;
  217.     foreach $component (split(m#/#, $newdir)) {
  218.         next if $component eq '.';
  219.         pop(@curdir),next if $component eq '..';
  220.         push(@curdir,$component);
  221.     }
  222.     $ENV{'PWD'} = join('/',@curdir) || '/';
  223.     }
  224.     1;
  225. }
  226.  
  227. # Taken from Cwd.pm It is really getcwd with an optional
  228. # parameter instead of '.'
  229. #
  230.  
  231. sub abs_path
  232. {
  233.     my $start = shift || '.';
  234.     my($dotdots, $cwd, @pst, @cst, $dir, @tst);
  235.  
  236.     unless (@cst = stat( $start ))
  237.     {
  238.     carp "stat($start): $!";
  239.     return '';
  240.     }
  241.     $cwd = '';
  242.     $dotdots = $start;
  243.     do
  244.     {
  245.     $dotdots .= '/..';
  246.     @pst = @cst;
  247.     unless (opendir(PARENT, $dotdots))
  248.     {
  249.         carp "opendir($dotdots): $!";
  250.         return '';
  251.     }
  252.     unless (@cst = stat($dotdots))
  253.     {
  254.         carp "stat($dotdots): $!";
  255.         closedir(PARENT);
  256.         return '';
  257.     }
  258.     if ($pst[0] == $cst[0] && $pst[1] == $cst[1])
  259.     {
  260.         $dir = '';
  261.     }
  262.     else
  263.     {
  264.         do
  265.         {
  266.         unless (defined ($dir = readdir(PARENT)))
  267.             {
  268.             carp "readdir($dotdots): $!";
  269.             closedir(PARENT);
  270.             return '';
  271.         }
  272.         $tst[0] = $pst[0]+1 unless (@tst = lstat("$dotdots/$dir"))
  273.         }
  274.         while ($dir eq '.' || $dir eq '..' || $tst[0] != $pst[0] ||
  275.            $tst[1] != $pst[1]);
  276.     }
  277.     $cwd = "$dir/$cwd";
  278.     closedir(PARENT);
  279.     } while ($dir);
  280.     chop($cwd); # drop the trailing /
  281.     $cwd;
  282. }
  283.  
  284. sub fast_abs_path {
  285.     my $cwd = getcwd();
  286.     my $path = shift || (($^O eq 'MacOS') ? ':' : '.');
  287.     chdir($path) || croak "Cannot chdir to $path:$!";
  288.     my $realpath = getcwd();
  289.     chdir($cwd)  || croak "Cannot chdir back to $cwd:$!";
  290.     $realpath;
  291. }
  292.  
  293.  
  294. # --- PORTING SECTION ---
  295.  
  296. # VMS: $ENV{'DEFAULT'} points to default directory at all times
  297. # 06-Mar-1996  Charles Bailey  bailey@genetics.upenn.edu
  298. # Note: Use of Cwd::chdir() causes the logical name PWD to be defined
  299. #   in the process logical name table as the default device and directory
  300. #   seen by Perl. This may not be the same as the default device
  301. #   and directory seen by DCL after Perl exits, since the effects
  302. #   the CRTL chdir() function persist only until Perl exits.
  303.  
  304. sub _vms_cwd {
  305.     return $ENV{'DEFAULT'};
  306. }
  307.  
  308. sub _vms_abs_path {
  309.     return $ENV{'DEFAULT'} unless @_;
  310.     my $path = VMS::Filespec::pathify($_[0]);
  311.     croak("Invalid path name $_[0]") unless defined $path;
  312.     return VMS::Filespec::rmsexpand($path);
  313. }
  314.  
  315. sub _os2_cwd {
  316.     $ENV{'PWD'} = `cmd /c cd`;
  317.     chop $ENV{'PWD'};
  318.     $ENV{'PWD'} =~ s:\\:/:g ;
  319.     return $ENV{'PWD'};
  320. }
  321.  
  322. sub _win32_cwd {
  323.     $ENV{'PWD'} = Win32::GetCurrentDirectory();
  324.     $ENV{'PWD'} =~ s:\\:/:g ;
  325.     return $ENV{'PWD'};
  326. }
  327.  
  328. *_NT_cwd = \&_win32_cwd if (!defined &_NT_cwd && 
  329.                             defined &Win32::GetCurrentDirectory);
  330.  
  331. *_NT_cwd = \&_os2_cwd unless defined &_NT_cwd;
  332.  
  333. sub _msdos_cwd {
  334.     $ENV{'PWD'} = `command /c cd`;
  335.     chop $ENV{'PWD'};
  336.     $ENV{'PWD'} =~ s:\\:/:g ;
  337.     return $ENV{'PWD'};
  338. }
  339.  
  340. {
  341.     local $^W = 0;    # assignments trigger 'subroutine redefined' warning
  342.  
  343.     if ($^O eq 'VMS') {
  344.         *cwd        = \&_vms_cwd;
  345.         *getcwd        = \&_vms_cwd;
  346.         *fastcwd    = \&_vms_cwd;
  347.         *fastgetcwd    = \&_vms_cwd;
  348.         *abs_path    = \&_vms_abs_path;
  349.         *fast_abs_path    = \&_vms_abs_path;
  350.     }
  351.     elsif ($^O eq 'NT' or $^O eq 'MSWin32') {
  352.         # We assume that &_NT_cwd is defined as an XSUB or in the core.
  353.         *cwd        = \&_NT_cwd;
  354.         *getcwd        = \&_NT_cwd;
  355.         *fastcwd    = \&_NT_cwd;
  356.         *fastgetcwd    = \&_NT_cwd;
  357.         *abs_path    = \&fast_abs_path;
  358.     }
  359.     elsif ($^O eq 'os2') {
  360.         # sys_cwd may keep the builtin command
  361.         *cwd        = defined &sys_cwd ? \&sys_cwd : \&_os2_cwd;
  362.         *getcwd        = \&cwd;
  363.         *fastgetcwd    = \&cwd;
  364.         *fastcwd    = \&cwd;
  365.         *abs_path    = \&fast_abs_path;
  366.     }
  367.     elsif ($^O eq 'msdos') {
  368.         *cwd        = \&_msdos_cwd;
  369.         *getcwd        = \&_msdos_cwd;
  370.         *fastgetcwd    = \&_msdos_cwd;
  371.         *fastcwd    = \&_msdos_cwd;
  372.         *abs_path    = \&fast_abs_path;
  373.     }
  374.     elsif ($^O eq 'MacOS') {
  375.         *getcwd     = \&cwd;
  376.         *fastgetcwd = \&cwd;
  377.         *fastcwd    = \&cwd;
  378.         *abs_path   = \&fast_abs_path;
  379.     }
  380. }
  381.  
  382. # package main; eval join('',<DATA>) || die $@;    # quick test
  383.  
  384. 1;
  385.  
  386. __END__
  387. BEGIN { import Cwd qw(:DEFAULT chdir); }
  388. print join("\n", cwd, getcwd, fastcwd, "");
  389. chdir('..') || chdir('::');
  390. print join("\n", cwd, getcwd, fastcwd, "");
  391. print "$ENV{PWD}\n";
  392.