This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Version bumps
[perl5.git] / dist / Cwd / Cwd.pm
1 package Cwd;
2
3 =head1 NAME
4
5 Cwd - get pathname of current working directory
6
7 =head1 SYNOPSIS
8
9     use Cwd;
10     my $dir = getcwd;
11
12     use Cwd 'abs_path';
13     my $abs_path = abs_path($file);
14
15 =head1 DESCRIPTION
16
17 This module provides functions for determining the pathname of the
18 current working directory.  It is recommended that getcwd (or another
19 *cwd() function) be used in I<all> code to ensure portability.
20
21 By default, it exports the functions cwd(), getcwd(), fastcwd(), and
22 fastgetcwd() (and, on Win32, getdcwd()) into the caller's namespace.  
23
24
25 =head2 getcwd and friends
26
27 Each of these functions are called without arguments and return the
28 absolute path of the current working directory.
29
30 =over 4
31
32 =item getcwd
33
34     my $cwd = getcwd();
35
36 Returns the current working directory.
37
38 Exposes the POSIX function getcwd(3) or re-implements it if it's not
39 available.
40
41 =item cwd
42
43     my $cwd = cwd();
44
45 The cwd() is the most natural form for the current architecture. For
46 most systems it is identical to `pwd` (but without the trailing line
47 terminator).
48
49 =item fastcwd
50
51     my $cwd = fastcwd();
52
53 A more dangerous version of getcwd(), but potentially faster.
54
55 It might conceivably chdir() you out of a directory that it can't
56 chdir() you back into.  If fastcwd encounters a problem it will return
57 undef but will probably leave you in a different directory.  For a
58 measure of extra security, if everything appears to have worked, the
59 fastcwd() function will check that it leaves you in the same directory
60 that it started in. If it has changed it will C<die> with the message
61 "Unstable directory path, current directory changed
62 unexpectedly". That should never happen.
63
64 =item fastgetcwd
65
66   my $cwd = fastgetcwd();
67
68 The fastgetcwd() function is provided as a synonym for cwd().
69
70 =item getdcwd
71
72     my $cwd = getdcwd();
73     my $cwd = getdcwd('C:');
74
75 The getdcwd() function is also provided on Win32 to get the current working
76 directory on the specified drive, since Windows maintains a separate current
77 working directory for each drive.  If no drive is specified then the current
78 drive is assumed.
79
80 This function simply calls the Microsoft C library _getdcwd() function.
81
82 =back
83
84
85 =head2 abs_path and friends
86
87 These functions are exported only on request.  They each take a single
88 argument and return the absolute pathname for it.  If no argument is
89 given they'll use the current working directory.
90
91 =over 4
92
93 =item abs_path
94
95   my $abs_path = abs_path($file);
96
97 Uses the same algorithm as getcwd().  Symbolic links and relative-path
98 components ("." and "..") are resolved to return the canonical
99 pathname, just like realpath(3).
100
101 =item realpath
102
103   my $abs_path = realpath($file);
104
105 A synonym for abs_path().
106
107 =item fast_abs_path
108
109   my $abs_path = fast_abs_path($file);
110
111 A more dangerous, but potentially faster version of abs_path.
112
113 =back
114
115 =head2 $ENV{PWD}
116
117 If you ask to override your chdir() built-in function, 
118
119   use Cwd qw(chdir);
120
121 then your PWD environment variable will be kept up to date.  Note that
122 it will only be kept up to date if all packages which use chdir import
123 it from Cwd.
124
125
126 =head1 NOTES
127
128 =over 4
129
130 =item *
131
132 Since the path separators are different on some operating systems ('/'
133 on Unix, ':' on MacPerl, etc...) we recommend you use the File::Spec
134 modules wherever portability is a concern.
135
136 =item *
137
138 Actually, on Mac OS, the C<getcwd()>, C<fastgetcwd()> and C<fastcwd()>
139 functions  are all aliases for the C<cwd()> function, which, on Mac OS,
140 calls `pwd`. Likewise, the C<abs_path()> function is an alias for
141 C<fast_abs_path()>.
142
143 =back
144
145 =head1 AUTHOR
146
147 Originally by the perl5-porters.
148
149 Maintained by Ken Williams <KWILLIAMS@cpan.org>
150
151 =head1 COPYRIGHT
152
153 Copyright (c) 2004 by the Perl 5 Porters.  All rights reserved.
154
155 This program is free software; you can redistribute it and/or modify
156 it under the same terms as Perl itself.
157
158 Portions of the C code in this library are copyright (c) 1994 by the
159 Regents of the University of California.  All rights reserved.  The
160 license on this code is compatible with the licensing of the rest of
161 the distribution - please see the source code in F<Cwd.xs> for the
162 details.
163
164 =head1 SEE ALSO
165
166 L<File::chdir>
167
168 =cut
169
170 use strict;
171 use Exporter;
172 use vars qw(@ISA @EXPORT @EXPORT_OK $VERSION);
173
174 $VERSION = '3.38';
175 my $xs_version = $VERSION;
176 $VERSION = eval $VERSION;
177
178 @ISA = qw/ Exporter /;
179 @EXPORT = qw(cwd getcwd fastcwd fastgetcwd);
180 push @EXPORT, qw(getdcwd) if $^O eq 'MSWin32';
181 @EXPORT_OK = qw(chdir abs_path fast_abs_path realpath fast_realpath);
182
183 # sys_cwd may keep the builtin command
184
185 # All the functionality of this module may provided by builtins,
186 # there is no sense to process the rest of the file.
187 # The best choice may be to have this in BEGIN, but how to return from BEGIN?
188
189 if ($^O eq 'os2') {
190     local $^W = 0;
191
192     *cwd                = defined &sys_cwd ? \&sys_cwd : \&_os2_cwd;
193     *getcwd             = \&cwd;
194     *fastgetcwd         = \&cwd;
195     *fastcwd            = \&cwd;
196
197     *fast_abs_path      = \&sys_abspath if defined &sys_abspath;
198     *abs_path           = \&fast_abs_path;
199     *realpath           = \&fast_abs_path;
200     *fast_realpath      = \&fast_abs_path;
201
202     return 1;
203 }
204
205 # Need to look up the feature settings on VMS.  The preferred way is to use the
206 # VMS::Feature module, but that may not be available to dual life modules.
207
208 my $use_vms_feature;
209 BEGIN {
210     if ($^O eq 'VMS') {
211         if (eval { local $SIG{__DIE__}; require VMS::Feature; }) {
212             $use_vms_feature = 1;
213         }
214     }
215 }
216
217 # Need to look up the UNIX report mode.  This may become a dynamic mode
218 # in the future.
219 sub _vms_unix_rpt {
220     my $unix_rpt;
221     if ($use_vms_feature) {
222         $unix_rpt = VMS::Feature::current("filename_unix_report");
223     } else {
224         my $env_unix_rpt = $ENV{'DECC$FILENAME_UNIX_REPORT'} || '';
225         $unix_rpt = $env_unix_rpt =~ /^[ET1]/i; 
226     }
227     return $unix_rpt;
228 }
229
230 # Need to look up the EFS character set mode.  This may become a dynamic
231 # mode in the future.
232 sub _vms_efs {
233     my $efs;
234     if ($use_vms_feature) {
235         $efs = VMS::Feature::current("efs_charset");
236     } else {
237         my $env_efs = $ENV{'DECC$EFS_CHARSET'} || '';
238         $efs = $env_efs =~ /^[ET1]/i; 
239     }
240     return $efs;
241 }
242
243
244 # If loading the XS stuff doesn't work, we can fall back to pure perl
245 eval {
246   if ( $] >= 5.006 ) {
247     require XSLoader;
248     XSLoader::load( __PACKAGE__, $xs_version);
249   } else {
250     require DynaLoader;
251     push @ISA, 'DynaLoader';
252     __PACKAGE__->bootstrap( $xs_version );
253   }
254 };
255
256 # Big nasty table of function aliases
257 my %METHOD_MAP =
258   (
259    VMS =>
260    {
261     cwd                 => '_vms_cwd',
262     getcwd              => '_vms_cwd',
263     fastcwd             => '_vms_cwd',
264     fastgetcwd          => '_vms_cwd',
265     abs_path            => '_vms_abs_path',
266     fast_abs_path       => '_vms_abs_path',
267    },
268
269    MSWin32 =>
270    {
271     # We assume that &_NT_cwd is defined as an XSUB or in the core.
272     cwd                 => '_NT_cwd',
273     getcwd              => '_NT_cwd',
274     fastcwd             => '_NT_cwd',
275     fastgetcwd          => '_NT_cwd',
276     abs_path            => 'fast_abs_path',
277     realpath            => 'fast_abs_path',
278    },
279
280    dos => 
281    {
282     cwd                 => '_dos_cwd',
283     getcwd              => '_dos_cwd',
284     fastgetcwd          => '_dos_cwd',
285     fastcwd             => '_dos_cwd',
286     abs_path            => 'fast_abs_path',
287    },
288
289    # QNX4.  QNX6 has a $os of 'nto'.
290    qnx =>
291    {
292     cwd                 => '_qnx_cwd',
293     getcwd              => '_qnx_cwd',
294     fastgetcwd          => '_qnx_cwd',
295     fastcwd             => '_qnx_cwd',
296     abs_path            => '_qnx_abs_path',
297     fast_abs_path       => '_qnx_abs_path',
298    },
299
300    cygwin =>
301    {
302     getcwd              => 'cwd',
303     fastgetcwd          => 'cwd',
304     fastcwd             => 'cwd',
305     abs_path            => 'fast_abs_path',
306     realpath            => 'fast_abs_path',
307    },
308
309    epoc =>
310    {
311     cwd                 => '_epoc_cwd',
312     getcwd              => '_epoc_cwd',
313     fastgetcwd          => '_epoc_cwd',
314     fastcwd             => '_epoc_cwd',
315     abs_path            => 'fast_abs_path',
316    },
317
318    MacOS =>
319    {
320     getcwd              => 'cwd',
321     fastgetcwd          => 'cwd',
322     fastcwd             => 'cwd',
323     abs_path            => 'fast_abs_path',
324    },
325   );
326
327 $METHOD_MAP{NT} = $METHOD_MAP{MSWin32};
328
329
330 # Find the pwd command in the expected locations.  We assume these
331 # are safe.  This prevents _backtick_pwd() consulting $ENV{PATH}
332 # so everything works under taint mode.
333 my $pwd_cmd;
334 foreach my $try ('/bin/pwd',
335                  '/usr/bin/pwd',
336                  '/QOpenSys/bin/pwd', # OS/400 PASE.
337                 ) {
338
339     if( -x $try ) {
340         $pwd_cmd = $try;
341         last;
342     }
343 }
344 my $found_pwd_cmd = defined($pwd_cmd);
345 unless ($pwd_cmd) {
346     # Isn't this wrong?  _backtick_pwd() will fail if somenone has
347     # pwd in their path but it is not /bin/pwd or /usr/bin/pwd?
348     # See [perl #16774]. --jhi
349     $pwd_cmd = 'pwd';
350 }
351
352 # Lazy-load Carp
353 sub _carp  { require Carp; Carp::carp(@_)  }
354 sub _croak { require Carp; Carp::croak(@_) }
355
356 # The 'natural and safe form' for UNIX (pwd may be setuid root)
357 sub _backtick_pwd {
358     # Localize %ENV entries in a way that won't create new hash keys
359     my @localize = grep exists $ENV{$_}, qw(PATH IFS CDPATH ENV BASH_ENV);
360     local @ENV{@localize};
361     
362     my $cwd = `$pwd_cmd`;
363     # Belt-and-suspenders in case someone said "undef $/".
364     local $/ = "\n";
365     # `pwd` may fail e.g. if the disk is full
366     chomp($cwd) if defined $cwd;
367     $cwd;
368 }
369
370 # Since some ports may predefine cwd internally (e.g., NT)
371 # we take care not to override an existing definition for cwd().
372
373 unless ($METHOD_MAP{$^O}{cwd} or defined &cwd) {
374     # The pwd command is not available in some chroot(2)'ed environments
375     my $sep = $Config::Config{path_sep} || ':';
376     my $os = $^O;  # Protect $^O from tainting
377
378
379     # Try again to find a pwd, this time searching the whole PATH.
380     if (defined $ENV{PATH} and $os ne 'MSWin32') {  # no pwd on Windows
381         my @candidates = split($sep, $ENV{PATH});
382         while (!$found_pwd_cmd and @candidates) {
383             my $candidate = shift @candidates;
384             $found_pwd_cmd = 1 if -x "$candidate/pwd";
385         }
386     }
387
388     # MacOS has some special magic to make `pwd` work.
389     if( $os eq 'MacOS' || $found_pwd_cmd )
390     {
391         *cwd = \&_backtick_pwd;
392     }
393     else {
394         *cwd = \&getcwd;
395     }
396 }
397
398 if ($^O eq 'cygwin') {
399   # We need to make sure cwd() is called with no args, because it's
400   # got an arg-less prototype and will die if args are present.
401   local $^W = 0;
402   my $orig_cwd = \&cwd;
403   *cwd = sub { &$orig_cwd() }
404 }
405
406
407 # set a reasonable (and very safe) default for fastgetcwd, in case it
408 # isn't redefined later (20001212 rspier)
409 *fastgetcwd = \&cwd;
410
411 # A non-XS version of getcwd() - also used to bootstrap the perl build
412 # process, when miniperl is running and no XS loading happens.
413 sub _perl_getcwd
414 {
415     abs_path('.');
416 }
417
418 # By John Bazik
419 #
420 # Usage: $cwd = &fastcwd;
421 #
422 # This is a faster version of getcwd.  It's also more dangerous because
423 # you might chdir out of a directory that you can't chdir back into.
424     
425 sub fastcwd_ {
426     my($odev, $oino, $cdev, $cino, $tdev, $tino);
427     my(@path, $path);
428     local(*DIR);
429
430     my($orig_cdev, $orig_cino) = stat('.');
431     ($cdev, $cino) = ($orig_cdev, $orig_cino);
432     for (;;) {
433         my $direntry;
434         ($odev, $oino) = ($cdev, $cino);
435         CORE::chdir('..') || return undef;
436         ($cdev, $cino) = stat('.');
437         last if $odev == $cdev && $oino == $cino;
438         opendir(DIR, '.') || return undef;
439         for (;;) {
440             $direntry = readdir(DIR);
441             last unless defined $direntry;
442             next if $direntry eq '.';
443             next if $direntry eq '..';
444
445             ($tdev, $tino) = lstat($direntry);
446             last unless $tdev != $odev || $tino != $oino;
447         }
448         closedir(DIR);
449         return undef unless defined $direntry; # should never happen
450         unshift(@path, $direntry);
451     }
452     $path = '/' . join('/', @path);
453     if ($^O eq 'apollo') { $path = "/".$path; }
454     # At this point $path may be tainted (if tainting) and chdir would fail.
455     # Untaint it then check that we landed where we started.
456     $path =~ /^(.*)\z/s         # untaint
457         && CORE::chdir($1) or return undef;
458     ($cdev, $cino) = stat('.');
459     die "Unstable directory path, current directory changed unexpectedly"
460         if $cdev != $orig_cdev || $cino != $orig_cino;
461     $path;
462 }
463 if (not defined &fastcwd) { *fastcwd = \&fastcwd_ }
464
465
466 # Keeps track of current working directory in PWD environment var
467 # Usage:
468 #       use Cwd 'chdir';
469 #       chdir $newdir;
470
471 my $chdir_init = 0;
472
473 sub chdir_init {
474     if ($ENV{'PWD'} and $^O ne 'os2' and $^O ne 'dos' and $^O ne 'MSWin32') {
475         my($dd,$di) = stat('.');
476         my($pd,$pi) = stat($ENV{'PWD'});
477         if (!defined $dd or !defined $pd or $di != $pi or $dd != $pd) {
478             $ENV{'PWD'} = cwd();
479         }
480     }
481     else {
482         my $wd = cwd();
483         $wd = Win32::GetFullPathName($wd) if $^O eq 'MSWin32';
484         $ENV{'PWD'} = $wd;
485     }
486     # Strip an automounter prefix (where /tmp_mnt/foo/bar == /foo/bar)
487     if ($^O ne 'MSWin32' and $ENV{'PWD'} =~ m|(/[^/]+(/[^/]+/[^/]+))(.*)|s) {
488         my($pd,$pi) = stat($2);
489         my($dd,$di) = stat($1);
490         if (defined $pd and defined $dd and $di == $pi and $dd == $pd) {
491             $ENV{'PWD'}="$2$3";
492         }
493     }
494     $chdir_init = 1;
495 }
496
497 sub chdir {
498     my $newdir = @_ ? shift : '';       # allow for no arg (chdir to HOME dir)
499     $newdir =~ s|///*|/|g unless $^O eq 'MSWin32';
500     chdir_init() unless $chdir_init;
501     my $newpwd;
502     if ($^O eq 'MSWin32') {
503         # get the full path name *before* the chdir()
504         $newpwd = Win32::GetFullPathName($newdir);
505     }
506
507     return 0 unless CORE::chdir $newdir;
508
509     if ($^O eq 'VMS') {
510         return $ENV{'PWD'} = $ENV{'DEFAULT'}
511     }
512     elsif ($^O eq 'MacOS') {
513         return $ENV{'PWD'} = cwd();
514     }
515     elsif ($^O eq 'MSWin32') {
516         $ENV{'PWD'} = $newpwd;
517         return 1;
518     }
519
520     if (ref $newdir eq 'GLOB') { # in case a file/dir handle is passed in
521         $ENV{'PWD'} = cwd();
522     } elsif ($newdir =~ m#^/#s) {
523         $ENV{'PWD'} = $newdir;
524     } else {
525         my @curdir = split(m#/#,$ENV{'PWD'});
526         @curdir = ('') unless @curdir;
527         my $component;
528         foreach $component (split(m#/#, $newdir)) {
529             next if $component eq '.';
530             pop(@curdir),next if $component eq '..';
531             push(@curdir,$component);
532         }
533         $ENV{'PWD'} = join('/',@curdir) || '/';
534     }
535     1;
536 }
537
538
539 sub _perl_abs_path
540 {
541     my $start = @_ ? shift : '.';
542     my($dotdots, $cwd, @pst, @cst, $dir, @tst);
543
544     unless (@cst = stat( $start ))
545     {
546         _carp("stat($start): $!");
547         return '';
548     }
549
550     unless (-d _) {
551         # Make sure we can be invoked on plain files, not just directories.
552         # NOTE that this routine assumes that '/' is the only directory separator.
553         
554         my ($dir, $file) = $start =~ m{^(.*)/(.+)$}
555             or return cwd() . '/' . $start;
556         
557         # Can't use "-l _" here, because the previous stat was a stat(), not an lstat().
558         if (-l $start) {
559             my $link_target = readlink($start);
560             die "Can't resolve link $start: $!" unless defined $link_target;
561             
562             require File::Spec;
563             $link_target = $dir . '/' . $link_target
564                 unless File::Spec->file_name_is_absolute($link_target);
565             
566             return abs_path($link_target);
567         }
568         
569         return $dir ? abs_path($dir) . "/$file" : "/$file";
570     }
571
572     $cwd = '';
573     $dotdots = $start;
574     do
575     {
576         $dotdots .= '/..';
577         @pst = @cst;
578         local *PARENT;
579         unless (opendir(PARENT, $dotdots))
580         {
581             # probably a permissions issue.  Try the native command.
582             return File::Spec->rel2abs( $start, _backtick_pwd() );
583         }
584         unless (@cst = stat($dotdots))
585         {
586             _carp("stat($dotdots): $!");
587             closedir(PARENT);
588             return '';
589         }
590         if ($pst[0] == $cst[0] && $pst[1] == $cst[1])
591         {
592             $dir = undef;
593         }
594         else
595         {
596             do
597             {
598                 unless (defined ($dir = readdir(PARENT)))
599                 {
600                     _carp("readdir($dotdots): $!");
601                     closedir(PARENT);
602                     return '';
603                 }
604                 $tst[0] = $pst[0]+1 unless (@tst = lstat("$dotdots/$dir"))
605             }
606             while ($dir eq '.' || $dir eq '..' || $tst[0] != $pst[0] ||
607                    $tst[1] != $pst[1]);
608         }
609         $cwd = (defined $dir ? "$dir" : "" ) . "/$cwd" ;
610         closedir(PARENT);
611     } while (defined $dir);
612     chop($cwd) unless $cwd eq '/'; # drop the trailing /
613     $cwd;
614 }
615
616
617 my $Curdir;
618 sub fast_abs_path {
619     local $ENV{PWD} = $ENV{PWD} || ''; # Guard against clobberage
620     my $cwd = getcwd();
621     require File::Spec;
622     my $path = @_ ? shift : ($Curdir ||= File::Spec->curdir);
623
624     # Detaint else we'll explode in taint mode.  This is safe because
625     # we're not doing anything dangerous with it.
626     ($path) = $path =~ /(.*)/;
627     ($cwd)  = $cwd  =~ /(.*)/;
628
629     unless (-e $path) {
630         _croak("$path: No such file or directory");
631     }
632
633     unless (-d _) {
634         # Make sure we can be invoked on plain files, not just directories.
635         
636         my ($vol, $dir, $file) = File::Spec->splitpath($path);
637         return File::Spec->catfile($cwd, $path) unless length $dir;
638
639         if (-l $path) {
640             my $link_target = readlink($path);
641             die "Can't resolve link $path: $!" unless defined $link_target;
642             
643             $link_target = File::Spec->catpath($vol, $dir, $link_target)
644                 unless File::Spec->file_name_is_absolute($link_target);
645             
646             return fast_abs_path($link_target);
647         }
648         
649         return $dir eq File::Spec->rootdir
650           ? File::Spec->catpath($vol, $dir, $file)
651           : fast_abs_path(File::Spec->catpath($vol, $dir, '')) . '/' . $file;
652     }
653
654     if (!CORE::chdir($path)) {
655         _croak("Cannot chdir to $path: $!");
656     }
657     my $realpath = getcwd();
658     if (! ((-d $cwd) && (CORE::chdir($cwd)))) {
659         _croak("Cannot chdir back to $cwd: $!");
660     }
661     $realpath;
662 }
663
664 # added function alias to follow principle of least surprise
665 # based on previous aliasing.  --tchrist 27-Jan-00
666 *fast_realpath = \&fast_abs_path;
667
668
669 # --- PORTING SECTION ---
670
671 # VMS: $ENV{'DEFAULT'} points to default directory at all times
672 # 06-Mar-1996  Charles Bailey  bailey@newman.upenn.edu
673 # Note: Use of Cwd::chdir() causes the logical name PWD to be defined
674 #   in the process logical name table as the default device and directory
675 #   seen by Perl. This may not be the same as the default device
676 #   and directory seen by DCL after Perl exits, since the effects
677 #   the CRTL chdir() function persist only until Perl exits.
678
679 sub _vms_cwd {
680     return $ENV{'DEFAULT'};
681 }
682
683 sub _vms_abs_path {
684     return $ENV{'DEFAULT'} unless @_;
685     my $path = shift;
686
687     my $efs = _vms_efs;
688     my $unix_rpt = _vms_unix_rpt;
689
690     if (defined &VMS::Filespec::vmsrealpath) {
691         my $path_unix = 0;
692         my $path_vms = 0;
693
694         $path_unix = 1 if ($path =~ m#(?<=\^)/#);
695         $path_unix = 1 if ($path =~ /^\.\.?$/);
696         $path_vms = 1 if ($path =~ m#[\[<\]]#);
697         $path_vms = 1 if ($path =~ /^--?$/);
698
699         my $unix_mode = $path_unix;
700         if ($efs) {
701             # In case of a tie, the Unix report mode decides.
702             if ($path_vms == $path_unix) {
703                 $unix_mode = $unix_rpt;
704             } else {
705                 $unix_mode = 0 if $path_vms;
706             }
707         }
708
709         if ($unix_mode) {
710             # Unix format
711             return VMS::Filespec::unixrealpath($path);
712         }
713
714         # VMS format
715
716         my $new_path = VMS::Filespec::vmsrealpath($path);
717
718         # Perl expects directories to be in directory format
719         $new_path = VMS::Filespec::pathify($new_path) if -d $path;
720         return $new_path;
721     }
722
723     # Fallback to older algorithm if correct ones are not
724     # available.
725
726     if (-l $path) {
727         my $link_target = readlink($path);
728         die "Can't resolve link $path: $!" unless defined $link_target;
729
730         return _vms_abs_path($link_target);
731     }
732
733     # may need to turn foo.dir into [.foo]
734     my $pathified = VMS::Filespec::pathify($path);
735     $path = $pathified if defined $pathified;
736         
737     return VMS::Filespec::rmsexpand($path);
738 }
739
740 sub _os2_cwd {
741     $ENV{'PWD'} = `cmd /c cd`;
742     chomp $ENV{'PWD'};
743     $ENV{'PWD'} =~ s:\\:/:g ;
744     return $ENV{'PWD'};
745 }
746
747 sub _win32_cwd_simple {
748     $ENV{'PWD'} = `cd`;
749     chomp $ENV{'PWD'};
750     $ENV{'PWD'} =~ s:\\:/:g ;
751     return $ENV{'PWD'};
752 }
753
754 sub _win32_cwd {
755     # Need to avoid taking any sort of reference to the typeglob or the code in
756     # the optree, so that this tests the runtime state of things, as the
757     # ExtUtils::MakeMaker tests for "miniperl" need to be able to fake things at
758     # runtime by deleting the subroutine. *foo{THING} syntax on a symbol table
759     # lookup avoids needing a string eval, which has been reported to cause
760     # problems (for reasons that we haven't been able to get to the bottom of -
761     # rt.cpan.org #56225)
762     if (*{$DynaLoader::{boot_DynaLoader}}{CODE}) {
763         $ENV{'PWD'} = Win32::GetCwd();
764     }
765     else { # miniperl
766         chomp($ENV{'PWD'} = `cd`);
767     }
768     $ENV{'PWD'} =~ s:\\:/:g ;
769     return $ENV{'PWD'};
770 }
771
772 *_NT_cwd = defined &Win32::GetCwd ? \&_win32_cwd : \&_win32_cwd_simple;
773
774 sub _dos_cwd {
775     if (!defined &Dos::GetCwd) {
776         $ENV{'PWD'} = `command /c cd`;
777         chomp $ENV{'PWD'};
778         $ENV{'PWD'} =~ s:\\:/:g ;
779     } else {
780         $ENV{'PWD'} = Dos::GetCwd();
781     }
782     return $ENV{'PWD'};
783 }
784
785 sub _qnx_cwd {
786         local $ENV{PATH} = '';
787         local $ENV{CDPATH} = '';
788         local $ENV{ENV} = '';
789     $ENV{'PWD'} = `/usr/bin/fullpath -t`;
790     chomp $ENV{'PWD'};
791     return $ENV{'PWD'};
792 }
793
794 sub _qnx_abs_path {
795         local $ENV{PATH} = '';
796         local $ENV{CDPATH} = '';
797         local $ENV{ENV} = '';
798     my $path = @_ ? shift : '.';
799     local *REALPATH;
800
801     defined( open(REALPATH, '-|') || exec '/usr/bin/fullpath', '-t', $path ) or
802       die "Can't open /usr/bin/fullpath: $!";
803     my $realpath = <REALPATH>;
804     close REALPATH;
805     chomp $realpath;
806     return $realpath;
807 }
808
809 sub _epoc_cwd {
810     $ENV{'PWD'} = EPOC::getcwd();
811     return $ENV{'PWD'};
812 }
813
814
815 # Now that all the base-level functions are set up, alias the
816 # user-level functions to the right places
817
818 if (exists $METHOD_MAP{$^O}) {
819   my $map = $METHOD_MAP{$^O};
820   foreach my $name (keys %$map) {
821     local $^W = 0;  # assignments trigger 'subroutine redefined' warning
822     no strict 'refs';
823     *{$name} = \&{$map->{$name}};
824   }
825 }
826
827 # In case the XS version doesn't load.
828 *abs_path = \&_perl_abs_path unless defined &abs_path;
829 *getcwd = \&_perl_getcwd unless defined &getcwd;
830
831 # added function alias for those of us more
832 # used to the libc function.  --tchrist 27-Jan-00
833 *realpath = \&abs_path;
834
835 1;