This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Removed the ifdefs for INCOMPLETE_TAINTS
[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.45';
175 my $xs_version = $VERSION;
176 $VERSION =~ tr/_//;
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 unless (defined &getcwd) {
246   eval {
247     if ( $] >= 5.006 ) {
248       require XSLoader;
249       XSLoader::load( __PACKAGE__, $xs_version);
250     } else {
251       require DynaLoader;
252       push @ISA, 'DynaLoader';
253       __PACKAGE__->bootstrap( $xs_version );
254     }
255   };
256 }
257
258 # Big nasty table of function aliases
259 my %METHOD_MAP =
260   (
261    VMS =>
262    {
263     cwd                 => '_vms_cwd',
264     getcwd              => '_vms_cwd',
265     fastcwd             => '_vms_cwd',
266     fastgetcwd          => '_vms_cwd',
267     abs_path            => '_vms_abs_path',
268     fast_abs_path       => '_vms_abs_path',
269    },
270
271    MSWin32 =>
272    {
273     # We assume that &_NT_cwd is defined as an XSUB or in the core.
274     cwd                 => '_NT_cwd',
275     getcwd              => '_NT_cwd',
276     fastcwd             => '_NT_cwd',
277     fastgetcwd          => '_NT_cwd',
278     abs_path            => 'fast_abs_path',
279     realpath            => 'fast_abs_path',
280    },
281
282    dos => 
283    {
284     cwd                 => '_dos_cwd',
285     getcwd              => '_dos_cwd',
286     fastgetcwd          => '_dos_cwd',
287     fastcwd             => '_dos_cwd',
288     abs_path            => 'fast_abs_path',
289    },
290
291    # QNX4.  QNX6 has a $os of 'nto'.
292    qnx =>
293    {
294     cwd                 => '_qnx_cwd',
295     getcwd              => '_qnx_cwd',
296     fastgetcwd          => '_qnx_cwd',
297     fastcwd             => '_qnx_cwd',
298     abs_path            => '_qnx_abs_path',
299     fast_abs_path       => '_qnx_abs_path',
300    },
301
302    cygwin =>
303    {
304     getcwd              => 'cwd',
305     fastgetcwd          => 'cwd',
306     fastcwd             => 'cwd',
307     abs_path            => 'fast_abs_path',
308     realpath            => 'fast_abs_path',
309    },
310
311    epoc =>
312    {
313     cwd                 => '_epoc_cwd',
314     getcwd              => '_epoc_cwd',
315     fastgetcwd          => '_epoc_cwd',
316     fastcwd             => '_epoc_cwd',
317     abs_path            => 'fast_abs_path',
318    },
319
320    MacOS =>
321    {
322     getcwd              => 'cwd',
323     fastgetcwd          => 'cwd',
324     fastcwd             => 'cwd',
325     abs_path            => 'fast_abs_path',
326    },
327   );
328
329 $METHOD_MAP{NT} = $METHOD_MAP{MSWin32};
330
331
332 # Find the pwd command in the expected locations.  We assume these
333 # are safe.  This prevents _backtick_pwd() consulting $ENV{PATH}
334 # so everything works under taint mode.
335 my $pwd_cmd;
336 foreach my $try ('/bin/pwd',
337                  '/usr/bin/pwd',
338                  '/QOpenSys/bin/pwd', # OS/400 PASE.
339                 ) {
340
341     if( -x $try ) {
342         $pwd_cmd = $try;
343         last;
344     }
345 }
346 my $found_pwd_cmd = defined($pwd_cmd);
347 unless ($pwd_cmd) {
348     # Isn't this wrong?  _backtick_pwd() will fail if someone has
349     # pwd in their path but it is not /bin/pwd or /usr/bin/pwd?
350     # See [perl #16774]. --jhi
351     $pwd_cmd = 'pwd';
352 }
353
354 # Lazy-load Carp
355 sub _carp  { require Carp; Carp::carp(@_)  }
356 sub _croak { require Carp; Carp::croak(@_) }
357
358 # The 'natural and safe form' for UNIX (pwd may be setuid root)
359 sub _backtick_pwd {
360     # Localize %ENV entries in a way that won't create new hash keys
361     my @localize = grep exists $ENV{$_}, qw(PATH IFS CDPATH ENV BASH_ENV);
362     local @ENV{@localize};
363     
364     my $cwd = `$pwd_cmd`;
365     # Belt-and-suspenders in case someone said "undef $/".
366     local $/ = "\n";
367     # `pwd` may fail e.g. if the disk is full
368     chomp($cwd) if defined $cwd;
369     $cwd;
370 }
371
372 # Since some ports may predefine cwd internally (e.g., NT)
373 # we take care not to override an existing definition for cwd().
374
375 unless ($METHOD_MAP{$^O}{cwd} or defined &cwd) {
376     # The pwd command is not available in some chroot(2)'ed environments
377     my $sep = $Config::Config{path_sep} || ':';
378     my $os = $^O;  # Protect $^O from tainting
379
380
381     # Try again to find a pwd, this time searching the whole PATH.
382     if (defined $ENV{PATH} and $os ne 'MSWin32') {  # no pwd on Windows
383         my @candidates = split($sep, $ENV{PATH});
384         while (!$found_pwd_cmd and @candidates) {
385             my $candidate = shift @candidates;
386             $found_pwd_cmd = 1 if -x "$candidate/pwd";
387         }
388     }
389
390     # MacOS has some special magic to make `pwd` work.
391     if( $os eq 'MacOS' || $found_pwd_cmd )
392     {
393         *cwd = \&_backtick_pwd;
394     }
395     else {
396         *cwd = \&getcwd;
397     }
398 }
399
400 if ($^O eq 'cygwin') {
401   # We need to make sure cwd() is called with no args, because it's
402   # got an arg-less prototype and will die if args are present.
403   local $^W = 0;
404   my $orig_cwd = \&cwd;
405   *cwd = sub { &$orig_cwd() }
406 }
407
408
409 # set a reasonable (and very safe) default for fastgetcwd, in case it
410 # isn't redefined later (20001212 rspier)
411 *fastgetcwd = \&cwd;
412
413 # A non-XS version of getcwd() - also used to bootstrap the perl build
414 # process, when miniperl is running and no XS loading happens.
415 sub _perl_getcwd
416 {
417     abs_path('.');
418 }
419
420 # By John Bazik
421 #
422 # Usage: $cwd = &fastcwd;
423 #
424 # This is a faster version of getcwd.  It's also more dangerous because
425 # you might chdir out of a directory that you can't chdir back into.
426     
427 sub fastcwd_ {
428     my($odev, $oino, $cdev, $cino, $tdev, $tino);
429     my(@path, $path);
430     local(*DIR);
431
432     my($orig_cdev, $orig_cino) = stat('.');
433     ($cdev, $cino) = ($orig_cdev, $orig_cino);
434     for (;;) {
435         my $direntry;
436         ($odev, $oino) = ($cdev, $cino);
437         CORE::chdir('..') || return undef;
438         ($cdev, $cino) = stat('.');
439         last if $odev == $cdev && $oino == $cino;
440         opendir(DIR, '.') || return undef;
441         for (;;) {
442             $direntry = readdir(DIR);
443             last unless defined $direntry;
444             next if $direntry eq '.';
445             next if $direntry eq '..';
446
447             ($tdev, $tino) = lstat($direntry);
448             last unless $tdev != $odev || $tino != $oino;
449         }
450         closedir(DIR);
451         return undef unless defined $direntry; # should never happen
452         unshift(@path, $direntry);
453     }
454     $path = '/' . join('/', @path);
455     if ($^O eq 'apollo') { $path = "/".$path; }
456     # At this point $path may be tainted (if tainting) and chdir would fail.
457     # Untaint it then check that we landed where we started.
458     $path =~ /^(.*)\z/s         # untaint
459         && CORE::chdir($1) or return undef;
460     ($cdev, $cino) = stat('.');
461     die "Unstable directory path, current directory changed unexpectedly"
462         if $cdev != $orig_cdev || $cino != $orig_cino;
463     $path;
464 }
465 if (not defined &fastcwd) { *fastcwd = \&fastcwd_ }
466
467
468 # Keeps track of current working directory in PWD environment var
469 # Usage:
470 #       use Cwd 'chdir';
471 #       chdir $newdir;
472
473 my $chdir_init = 0;
474
475 sub chdir_init {
476     if ($ENV{'PWD'} and $^O ne 'os2' and $^O ne 'dos' and $^O ne 'MSWin32') {
477         my($dd,$di) = stat('.');
478         my($pd,$pi) = stat($ENV{'PWD'});
479         if (!defined $dd or !defined $pd or $di != $pi or $dd != $pd) {
480             $ENV{'PWD'} = cwd();
481         }
482     }
483     else {
484         my $wd = cwd();
485         $wd = Win32::GetFullPathName($wd) if $^O eq 'MSWin32';
486         $ENV{'PWD'} = $wd;
487     }
488     # Strip an automounter prefix (where /tmp_mnt/foo/bar == /foo/bar)
489     if ($^O ne 'MSWin32' and $ENV{'PWD'} =~ m|(/[^/]+(/[^/]+/[^/]+))(.*)|s) {
490         my($pd,$pi) = stat($2);
491         my($dd,$di) = stat($1);
492         if (defined $pd and defined $dd and $di == $pi and $dd == $pd) {
493             $ENV{'PWD'}="$2$3";
494         }
495     }
496     $chdir_init = 1;
497 }
498
499 sub chdir {
500     my $newdir = @_ ? shift : '';       # allow for no arg (chdir to HOME dir)
501     $newdir =~ s|///*|/|g unless $^O eq 'MSWin32';
502     chdir_init() unless $chdir_init;
503     my $newpwd;
504     if ($^O eq 'MSWin32') {
505         # get the full path name *before* the chdir()
506         $newpwd = Win32::GetFullPathName($newdir);
507     }
508
509     return 0 unless CORE::chdir $newdir;
510
511     if ($^O eq 'VMS') {
512         return $ENV{'PWD'} = $ENV{'DEFAULT'}
513     }
514     elsif ($^O eq 'MacOS') {
515         return $ENV{'PWD'} = cwd();
516     }
517     elsif ($^O eq 'MSWin32') {
518         $ENV{'PWD'} = $newpwd;
519         return 1;
520     }
521
522     if (ref $newdir eq 'GLOB') { # in case a file/dir handle is passed in
523         $ENV{'PWD'} = cwd();
524     } elsif ($newdir =~ m#^/#s) {
525         $ENV{'PWD'} = $newdir;
526     } else {
527         my @curdir = split(m#/#,$ENV{'PWD'});
528         @curdir = ('') unless @curdir;
529         my $component;
530         foreach $component (split(m#/#, $newdir)) {
531             next if $component eq '.';
532             pop(@curdir),next if $component eq '..';
533             push(@curdir,$component);
534         }
535         $ENV{'PWD'} = join('/',@curdir) || '/';
536     }
537     1;
538 }
539
540
541 sub _perl_abs_path
542 {
543     my $start = @_ ? shift : '.';
544     my($dotdots, $cwd, @pst, @cst, $dir, @tst);
545
546     unless (@cst = stat( $start ))
547     {
548         _carp("stat($start): $!");
549         return '';
550     }
551
552     unless (-d _) {
553         # Make sure we can be invoked on plain files, not just directories.
554         # NOTE that this routine assumes that '/' is the only directory separator.
555         
556         my ($dir, $file) = $start =~ m{^(.*)/(.+)$}
557             or return cwd() . '/' . $start;
558         
559         # Can't use "-l _" here, because the previous stat was a stat(), not an lstat().
560         if (-l $start) {
561             my $link_target = readlink($start);
562             die "Can't resolve link $start: $!" unless defined $link_target;
563             
564             require File::Spec;
565             $link_target = $dir . '/' . $link_target
566                 unless File::Spec->file_name_is_absolute($link_target);
567             
568             return abs_path($link_target);
569         }
570         
571         return $dir ? abs_path($dir) . "/$file" : "/$file";
572     }
573
574     $cwd = '';
575     $dotdots = $start;
576     do
577     {
578         $dotdots .= '/..';
579         @pst = @cst;
580         local *PARENT;
581         unless (opendir(PARENT, $dotdots))
582         {
583             # probably a permissions issue.  Try the native command.
584             require File::Spec;
585             return File::Spec->rel2abs( $start, _backtick_pwd() );
586         }
587         unless (@cst = stat($dotdots))
588         {
589             _carp("stat($dotdots): $!");
590             closedir(PARENT);
591             return '';
592         }
593         if ($pst[0] == $cst[0] && $pst[1] == $cst[1])
594         {
595             $dir = undef;
596         }
597         else
598         {
599             do
600             {
601                 unless (defined ($dir = readdir(PARENT)))
602                 {
603                     _carp("readdir($dotdots): $!");
604                     closedir(PARENT);
605                     return '';
606                 }
607                 $tst[0] = $pst[0]+1 unless (@tst = lstat("$dotdots/$dir"))
608             }
609             while ($dir eq '.' || $dir eq '..' || $tst[0] != $pst[0] ||
610                    $tst[1] != $pst[1]);
611         }
612         $cwd = (defined $dir ? "$dir" : "" ) . "/$cwd" ;
613         closedir(PARENT);
614     } while (defined $dir);
615     chop($cwd) unless $cwd eq '/'; # drop the trailing /
616     $cwd;
617 }
618
619
620 my $Curdir;
621 sub fast_abs_path {
622     local $ENV{PWD} = $ENV{PWD} || ''; # Guard against clobberage
623     my $cwd = getcwd();
624     require File::Spec;
625     my $path = @_ ? shift : ($Curdir ||= File::Spec->curdir);
626
627     # Detaint else we'll explode in taint mode.  This is safe because
628     # we're not doing anything dangerous with it.
629     ($path) = $path =~ /(.*)/s;
630     ($cwd)  = $cwd  =~ /(.*)/s;
631
632     unless (-e $path) {
633         _croak("$path: No such file or directory");
634     }
635
636     unless (-d _) {
637         # Make sure we can be invoked on plain files, not just directories.
638         
639         my ($vol, $dir, $file) = File::Spec->splitpath($path);
640         return File::Spec->catfile($cwd, $path) unless length $dir;
641
642         if (-l $path) {
643             my $link_target = readlink($path);
644             die "Can't resolve link $path: $!" unless defined $link_target;
645             
646             $link_target = File::Spec->catpath($vol, $dir, $link_target)
647                 unless File::Spec->file_name_is_absolute($link_target);
648             
649             return fast_abs_path($link_target);
650         }
651         
652         return $dir eq File::Spec->rootdir
653           ? File::Spec->catpath($vol, $dir, $file)
654           : fast_abs_path(File::Spec->catpath($vol, $dir, '')) . '/' . $file;
655     }
656
657     if (!CORE::chdir($path)) {
658         _croak("Cannot chdir to $path: $!");
659     }
660     my $realpath = getcwd();
661     if (! ((-d $cwd) && (CORE::chdir($cwd)))) {
662         _croak("Cannot chdir back to $cwd: $!");
663     }
664     $realpath;
665 }
666
667 # added function alias to follow principle of least surprise
668 # based on previous aliasing.  --tchrist 27-Jan-00
669 *fast_realpath = \&fast_abs_path;
670
671
672 # --- PORTING SECTION ---
673
674 # VMS: $ENV{'DEFAULT'} points to default directory at all times
675 # 06-Mar-1996  Charles Bailey  bailey@newman.upenn.edu
676 # Note: Use of Cwd::chdir() causes the logical name PWD to be defined
677 #   in the process logical name table as the default device and directory
678 #   seen by Perl. This may not be the same as the default device
679 #   and directory seen by DCL after Perl exits, since the effects
680 #   the CRTL chdir() function persist only until Perl exits.
681
682 sub _vms_cwd {
683     return $ENV{'DEFAULT'};
684 }
685
686 sub _vms_abs_path {
687     return $ENV{'DEFAULT'} unless @_;
688     my $path = shift;
689
690     my $efs = _vms_efs;
691     my $unix_rpt = _vms_unix_rpt;
692
693     if (defined &VMS::Filespec::vmsrealpath) {
694         my $path_unix = 0;
695         my $path_vms = 0;
696
697         $path_unix = 1 if ($path =~ m#(?<=\^)/#);
698         $path_unix = 1 if ($path =~ /^\.\.?$/);
699         $path_vms = 1 if ($path =~ m#[\[<\]]#);
700         $path_vms = 1 if ($path =~ /^--?$/);
701
702         my $unix_mode = $path_unix;
703         if ($efs) {
704             # In case of a tie, the Unix report mode decides.
705             if ($path_vms == $path_unix) {
706                 $unix_mode = $unix_rpt;
707             } else {
708                 $unix_mode = 0 if $path_vms;
709             }
710         }
711
712         if ($unix_mode) {
713             # Unix format
714             return VMS::Filespec::unixrealpath($path);
715         }
716
717         # VMS format
718
719         my $new_path = VMS::Filespec::vmsrealpath($path);
720
721         # Perl expects directories to be in directory format
722         $new_path = VMS::Filespec::pathify($new_path) if -d $path;
723         return $new_path;
724     }
725
726     # Fallback to older algorithm if correct ones are not
727     # available.
728
729     if (-l $path) {
730         my $link_target = readlink($path);
731         die "Can't resolve link $path: $!" unless defined $link_target;
732
733         return _vms_abs_path($link_target);
734     }
735
736     # may need to turn foo.dir into [.foo]
737     my $pathified = VMS::Filespec::pathify($path);
738     $path = $pathified if defined $pathified;
739         
740     return VMS::Filespec::rmsexpand($path);
741 }
742
743 sub _os2_cwd {
744     $ENV{'PWD'} = `cmd /c cd`;
745     chomp $ENV{'PWD'};
746     $ENV{'PWD'} =~ s:\\:/:g ;
747     return $ENV{'PWD'};
748 }
749
750 sub _win32_cwd_simple {
751     $ENV{'PWD'} = `cd`;
752     chomp $ENV{'PWD'};
753     $ENV{'PWD'} =~ s:\\:/:g ;
754     return $ENV{'PWD'};
755 }
756
757 sub _win32_cwd {
758     # Need to avoid taking any sort of reference to the typeglob or the code in
759     # the optree, so that this tests the runtime state of things, as the
760     # ExtUtils::MakeMaker tests for "miniperl" need to be able to fake things at
761     # runtime by deleting the subroutine. *foo{THING} syntax on a symbol table
762     # lookup avoids needing a string eval, which has been reported to cause
763     # problems (for reasons that we haven't been able to get to the bottom of -
764     # rt.cpan.org #56225)
765     if (*{$DynaLoader::{boot_DynaLoader}}{CODE}) {
766         $ENV{'PWD'} = Win32::GetCwd();
767     }
768     else { # miniperl
769         chomp($ENV{'PWD'} = `cd`);
770     }
771     $ENV{'PWD'} =~ s:\\:/:g ;
772     return $ENV{'PWD'};
773 }
774
775 *_NT_cwd = defined &Win32::GetCwd ? \&_win32_cwd : \&_win32_cwd_simple;
776
777 sub _dos_cwd {
778     if (!defined &Dos::GetCwd) {
779         $ENV{'PWD'} = `command /c cd`;
780         chomp $ENV{'PWD'};
781         $ENV{'PWD'} =~ s:\\:/:g ;
782     } else {
783         $ENV{'PWD'} = Dos::GetCwd();
784     }
785     return $ENV{'PWD'};
786 }
787
788 sub _qnx_cwd {
789         local $ENV{PATH} = '';
790         local $ENV{CDPATH} = '';
791         local $ENV{ENV} = '';
792     $ENV{'PWD'} = `/usr/bin/fullpath -t`;
793     chomp $ENV{'PWD'};
794     return $ENV{'PWD'};
795 }
796
797 sub _qnx_abs_path {
798         local $ENV{PATH} = '';
799         local $ENV{CDPATH} = '';
800         local $ENV{ENV} = '';
801     my $path = @_ ? shift : '.';
802     local *REALPATH;
803
804     defined( open(REALPATH, '-|') || exec '/usr/bin/fullpath', '-t', $path ) or
805       die "Can't open /usr/bin/fullpath: $!";
806     my $realpath = <REALPATH>;
807     close REALPATH;
808     chomp $realpath;
809     return $realpath;
810 }
811
812 sub _epoc_cwd {
813     $ENV{'PWD'} = EPOC::getcwd();
814     return $ENV{'PWD'};
815 }
816
817
818 # Now that all the base-level functions are set up, alias the
819 # user-level functions to the right places
820
821 if (exists $METHOD_MAP{$^O}) {
822   my $map = $METHOD_MAP{$^O};
823   foreach my $name (keys %$map) {
824     local $^W = 0;  # assignments trigger 'subroutine redefined' warning
825     no strict 'refs';
826     *{$name} = \&{$map->{$name}};
827   }
828 }
829
830 # In case the XS version doesn't load.
831 *abs_path = \&_perl_abs_path unless defined &abs_path;
832 *getcwd = \&_perl_getcwd unless defined &getcwd;
833
834 # added function alias for those of us more
835 # used to the libc function.  --tchrist 27-Jan-00
836 *realpath = \&abs_path;
837
838 1;