summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Ing-Simmons <nik@tiuk.ti.com>1998-01-07 18:40:55 +0000
committerNick Ing-Simmons <nik@tiuk.ti.com>1998-01-07 18:40:55 +0000
commit750166a8e00335dafb5951e071341ae11e804119 (patch)
treeb9840eb6620f589da6b857b3a81f032f460bfffc
parent324f2d369a8d4d6edae0a1142d9a03e222f98c36 (diff)
parentce1da67e6637b3b736abebfc7cd6991d91dbe03a (diff)
downloadperl-750166a8e00335dafb5951e071341ae11e804119.tar.gz
Integrate win32 branch
p4raw-id: //depot/ansiperl@395
-rw-r--r--README.win3214
-rw-r--r--doio.c3
-rw-r--r--dosish.h16
-rw-r--r--hv.c99
-rw-r--r--lib/Cwd.pm4
-rw-r--r--lib/ExtUtils/Liblist.pm20
-rw-r--r--lib/FindBin.pm4
-rw-r--r--lib/dumpvar.pl3
-rw-r--r--lib/perl5db.pl12
-rw-r--r--mg.c17
-rw-r--r--perl.h6
-rw-r--r--pod/perlfaq2.pod29
-rw-r--r--pod/perlfunc.pod100
-rw-r--r--pod/perlrun.pod18
-rw-r--r--pod/perlvar.pod36
-rw-r--r--pp_sys.c6
-rwxr-xr-xt/op/magic.t27
-rw-r--r--util.c10
-rw-r--r--utils/perldoc.PL2
-rw-r--r--win32/config_H.bc8
-rw-r--r--win32/config_H.gc8
-rw-r--r--win32/config_H.vc8
-rw-r--r--win32/config_h.PL8
-rw-r--r--win32/makedef.pl2
-rw-r--r--win32/perllib.c4
-rw-r--r--win32/win32.c335
-rw-r--r--win32/win32.h11
-rw-r--r--win32/win32iop.h4
-rw-r--r--win32/win32sck.c2
-rw-r--r--win32/win32thread.c29
-rw-r--r--win32/win32thread.h45
31 files changed, 635 insertions, 255 deletions
diff --git a/README.win32 b/README.win32
index 1b596eb1b6..fb42850597 100644
--- a/README.win32
+++ b/README.win32
@@ -503,9 +503,9 @@ The following functions are currently unavailable: C<fork()>,
C<dump()>, C<chown()>, C<link()>, C<symlink()>, C<chroot()>,
C<setpgrp()> and related security functions, C<setpriority()>,
C<getpriority()>, C<syscall()>, C<fcntl()>, C<getpw*()>,
-C<wait*()>, C<msg*()>, C<shm*()>, C<sem*()>, C<alarm()>,
-C<socketpair()>, C<*netent()>, C<*protoent()>, C<*servent()>,
-C<*hostent()>, C<getnetby*()>.
+C<msg*()>, C<shm*()>, C<sem*()>, C<alarm()>, C<socketpair()>,
+C<*netent()>, C<*protoent()>, C<*servent()>, C<*hostent()>,
+C<getnetby*()>.
This list is possibly incomplete.
=item *
@@ -524,9 +524,9 @@ functionality of ioctlsocket() in the Winsock API).
=item *
-C<$?> is set in a way compatible with Unix, so the exitstatus of the
-subprocess is actually obtained by "$? >> 8". Failure to spawn() the
-subprocess is indicated by setting $? to "255 << 8".
+Failure to spawn() a subprocess is indicated by setting $? to "255 << 8".
+C<$?> is set in a way compatible with Unix (i.e. the exitstatus of the
+subprocess is obtained by "$? >> 8", as described in the documentation).
=item *
@@ -598,7 +598,7 @@ sundry hacks since then.
Borland support was added in 5.004_01 (Gurusamy Sarathy).
-Last updated: 23 December 1997
+Last updated: 3 January 1998
=cut
diff --git a/doio.c b/doio.c
index cd718a947f..dce271d4af 100644
--- a/doio.c
+++ b/doio.c
@@ -500,7 +500,8 @@ nextargv(register GV *gv)
return IoIFP(GvIOp(gv));
}
else
- PerlIO_printf(PerlIO_stderr(), "Can't open %s: %s\n",SvPV(sv, na), Strerror(errno));
+ PerlIO_printf(PerlIO_stderr(), "Can't open %s: %s\n",
+ SvPV(sv, na), Strerror(errno));
}
if (inplace) {
(void)do_close(argvoutgv,FALSE);
diff --git a/dosish.h b/dosish.h
index 5704c78cb2..184d3dfb45 100644
--- a/dosish.h
+++ b/dosish.h
@@ -45,12 +45,6 @@
#define dXSUB_SYS
#define TMPPATH "plXXXXXX"
-#ifdef WIN32
-#define HAS_IOCTL
-#define HAS_UTIME
-#define HAS_KILL
-#endif
-
/*
* 5.003_07 and earlier keyed on #ifdef MSDOS for determining if we were
* running on DOS, *and* if we had to cope with 16 bit memory addressing
@@ -124,11 +118,15 @@
#ifndef WIN32
# define Stat(fname,bufptr) stat((fname),(bufptr))
#else
+# define HAS_IOCTL
+# define HAS_UTIME
+# define HAS_KILL
+# define HAS_WAIT
/*
* This provides a layer of functions and macros to ensure extensions will
* get to use the same RTL functions as the core.
*/
-#ifndef HASATTRIBUTE
-# include <win32iop.h>
-#endif
+# ifndef HASATTRIBUTE
+# include <win32iop.h>
+# endif
#endif /* WIN32 */
diff --git a/hv.c b/hv.c
index 079e95297b..21792bda55 100644
--- a/hv.c
+++ b/hv.c
@@ -84,6 +84,7 @@ hv_fetch(HV *hv, char *key, U32 klen, I32 lval)
register XPVHV* xhv;
register U32 hash;
register HE *entry;
+ char *origkey = key;
SV *sv;
if (!hv)
@@ -97,6 +98,12 @@ hv_fetch(HV *hv, char *key, U32 klen, I32 lval)
Sv = sv;
return &Sv;
}
+#ifdef ENV_IS_CASELESS
+ else if (mg_find((SV*)hv,'E')) {
+ sv = sv_2mortal(newSVpv(key,klen));
+ key = strupr(SvPVX(sv));
+ }
+#endif
}
xhv = (XPVHV*)SvANY(hv);
@@ -130,13 +137,13 @@ hv_fetch(HV *hv, char *key, U32 klen, I32 lval)
if ((gotenv = ENV_getenv(key)) != Nullch) {
sv = newSVpv(gotenv,strlen(gotenv));
SvTAINTED_on(sv);
- return hv_store(hv,key,klen,sv,hash);
+ return hv_store(hv,origkey,klen,sv,hash);
}
}
#endif
if (lval) { /* gonna assign to this, so it better be there */
sv = NEWSV(61,0);
- return hv_store(hv,key,klen,sv,hash);
+ return hv_store(hv,origkey,klen,sv,hash);
}
return 0;
}
@@ -150,25 +157,36 @@ hv_fetch_ent(HV *hv, SV *keysv, I32 lval, register U32 hash)
register char *key;
STRLEN klen;
register HE *entry;
+ SV *origkeysv = keysv;
SV *sv;
if (!hv)
return 0;
- if (SvRMAGICAL(hv) && mg_find((SV*)hv,'P')) {
- static HE mh;
+ if (SvRMAGICAL(hv)) {
+ if (mg_find((SV*)hv,'P')) {
+ static HE mh;
- sv = sv_newmortal();
- keysv = sv_2mortal(newSVsv(keysv));
- mg_copy((SV*)hv, sv, (char*)keysv, HEf_SVKEY);
- if (!HeKEY_hek(&mh)) {
- char *k;
- New(54, k, HEK_BASESIZE + sizeof(SV*), char);
- HeKEY_hek(&mh) = (HEK*)k;
+ sv = sv_newmortal();
+ keysv = sv_2mortal(newSVsv(keysv));
+ mg_copy((SV*)hv, sv, (char*)keysv, HEf_SVKEY);
+ if (!HeKEY_hek(&mh)) {
+ char *k;
+ New(54, k, HEK_BASESIZE + sizeof(SV*), char);
+ HeKEY_hek(&mh) = (HEK*)k;
+ }
+ HeSVKEY_set(&mh, keysv);
+ HeVAL(&mh) = sv;
+ return &mh;
+ }
+#ifdef ENV_IS_CASELESS
+ else if (mg_find((SV*)hv,'E')) {
+ key = SvPV(keysv, klen);
+ keysv = sv_2mortal(newSVpv(key,klen));
+ (void)strupr(SvPVX(keysv));
+ hash = 0;
}
- HeSVKEY_set(&mh, keysv);
- HeVAL(&mh) = sv;
- return &mh;
+#endif
}
xhv = (XPVHV*)SvANY(hv);
@@ -205,13 +223,13 @@ hv_fetch_ent(HV *hv, SV *keysv, I32 lval, register U32 hash)
if ((gotenv = ENV_getenv(key)) != Nullch) {
sv = newSVpv(gotenv,strlen(gotenv));
SvTAINTED_on(sv);
- return hv_store_ent(hv,keysv,sv,hash);
+ return hv_store_ent(hv,origkeysv,sv,hash);
}
}
#endif
if (lval) { /* gonna assign to this, so it better be there */
sv = NEWSV(61,0);
- return hv_store_ent(hv,keysv,sv,hash);
+ return hv_store_ent(hv,origkeysv,sv,hash);
}
return 0;
}
@@ -256,6 +274,13 @@ hv_store(HV *hv, char *key, U32 klen, SV *val, register U32 hash)
mg_copy((SV*)hv, val, key, klen);
if (!xhv->xhv_array && !needs_store)
return 0;
+#ifdef ENV_IS_CASELESS
+ else if (mg_find((SV*)hv,'E')) {
+ SV *sv = sv_2mortal(newSVpv(key,klen));
+ key = strupr(SvPVX(sv));
+ hash = 0;
+ }
+#endif
}
}
if (!hash)
@@ -326,11 +351,19 @@ hv_store_ent(HV *hv, SV *keysv, SV *val, register U32 hash)
TAINT_IF(save_taint);
if (!xhv->xhv_array && !needs_store)
return Nullhe;
- }
+#ifdef ENV_IS_CASELESS
+ else if (mg_find((SV*)hv,'E')) {
+ key = SvPV(keysv, klen);
+ keysv = sv_2mortal(newSVpv(key,klen));
+ (void)strupr(SvPVX(keysv));
+ hash = 0;
+ }
+#endif
+ }
}
key = SvPV(keysv, klen);
-
+
if (!hash)
PERL_HASH(hash, key, klen);
@@ -389,10 +422,16 @@ hv_delete(HV *hv, char *key, U32 klen, I32 flags)
if (mg_find(sv, 's')) {
return Nullsv; /* %SIG elements cannot be deleted */
}
- if (mg_find(sv, 'p')) {
+ else if (mg_find(sv, 'p')) {
sv_unmagic(sv, 'p'); /* No longer an element */
return sv;
}
+#ifdef ENV_IS_CASELESS
+ else if (mg_find((SV*)hv,'E')) {
+ sv = sv_2mortal(newSVpv(key,klen));
+ key = strupr(SvPVX(sv));
+ }
+#endif
}
xhv = (XPVHV*)SvANY(hv);
if (!xhv->xhv_array)
@@ -448,6 +487,14 @@ hv_delete_ent(HV *hv, SV *keysv, I32 flags, U32 hash)
sv_unmagic(sv, 'p'); /* No longer an element */
return sv;
}
+#ifdef ENV_IS_CASELESS
+ else if (mg_find((SV*)hv,'E')) {
+ key = SvPV(keysv, klen);
+ keysv = sv_2mortal(newSVpv(key,klen));
+ (void)strupr(SvPVX(keysv));
+ hash = 0;
+ }
+#endif
}
xhv = (XPVHV*)SvANY(hv);
if (!xhv->xhv_array)
@@ -504,6 +551,12 @@ hv_exists(HV *hv, char *key, U32 klen)
magic_existspack(sv, mg_find(sv, 'p'));
return SvTRUE(sv);
}
+#ifdef ENV_IS_CASELESS
+ else if (mg_find((SV*)hv,'E')) {
+ sv = sv_2mortal(newSVpv(key,klen));
+ key = strupr(SvPVX(sv));
+ }
+#endif
}
xhv = (XPVHV*)SvANY(hv);
@@ -547,6 +600,14 @@ hv_exists_ent(HV *hv, SV *keysv, U32 hash)
magic_existspack(sv, mg_find(sv, 'p'));
return SvTRUE(sv);
}
+#ifdef ENV_IS_CASELESS
+ else if (mg_find((SV*)hv,'E')) {
+ key = SvPV(keysv, klen);
+ keysv = sv_2mortal(newSVpv(key,klen));
+ (void)strupr(SvPVX(keysv));
+ hash = 0;
+ }
+#endif
}
xhv = (XPVHV*)SvANY(hv);
diff --git a/lib/Cwd.pm b/lib/Cwd.pm
index 6952411ca2..048842b4ac 100644
--- a/lib/Cwd.pm
+++ b/lib/Cwd.pm
@@ -339,13 +339,13 @@ sub _os2_cwd {
}
sub _win32_cwd {
- $ENV{'PWD'} = Win32::GetCurrentDirectory();
+ $ENV{'PWD'} = Win32::GetCwd();
$ENV{'PWD'} =~ s:\\:/:g ;
return $ENV{'PWD'};
}
*_NT_cwd = \&_win32_cwd if (!defined &_NT_cwd &&
- defined &Win32::GetCurrentDirectory);
+ defined &Win32::GetCwd);
*_NT_cwd = \&_os2_cwd unless defined &_NT_cwd;
diff --git a/lib/ExtUtils/Liblist.pm b/lib/ExtUtils/Liblist.pm
index d821e83729..aebb057d58 100644
--- a/lib/ExtUtils/Liblist.pm
+++ b/lib/ExtUtils/Liblist.pm
@@ -231,7 +231,9 @@ sub _win32_ext {
}
# Handle possible library arguments.
- $thislib =~ s/^-l//;
+ if ($thislib =~ s/^-l// and $thislib !~ /^lib/i) {
+ $thislib = "lib$thislib";
+ }
$thislib .= $libext if $thislib !~ /\Q$libext\E$/i;
my($found_lib)=0;
@@ -522,14 +524,14 @@ Unix-OS/2 version in several respects:
Input library and path specifications are accepted with or without the
C<-l> and C<-L> prefices used by Unix linkers. C<-lfoo> specifies the
-library C<foo.lib> and C<-Ls:ome\dir> specifies a directory to look for
-the libraries that follow. If neither prefix is present, a token is
-considered a directory to search if it is in fact a directory, and a
-library to search for otherwise. The C<$Config{lib_ext}> suffix will
-be appended to any entries that are not directories and don't already
-have the suffix. Authors who wish their extensions to be portable to
-Unix or OS/2 should use the Unix prefixes, since the Unix-OS/2 version
-of ext() requires them.
+library C<libfoo.lib> (unless C<foo> already starts with C<lib>), and
+C<-Ls:ome\dir> specifies a directory to look for the libraries that follow.
+If neither prefix is present, a token is considered a directory to search
+if it is in fact a directory, and a library to search for otherwise. The
+C<$Config{lib_ext}> suffix will be appended to any entries that are not
+directories and don't already have the suffix. Authors who wish their
+extensions to be portable to Unix or OS/2 should use the Unix prefixes,
+since the Unix-OS/2 version of ext() requires them.
=item *
diff --git a/lib/FindBin.pm b/lib/FindBin.pm
index 881caa7559..d6bd7b777e 100644
--- a/lib/FindBin.pm
+++ b/lib/FindBin.pm
@@ -82,7 +82,7 @@ use File::Basename;
%EXPORT_TAGS = (ALL => [qw($Bin $Script $RealBin $RealScript $Dir $RealDir)]);
@ISA = qw(Exporter);
-$VERSION = $VERSION = sprintf("%d.%02d", q$Revision: 1.4 $ =~ /(\d+)\.(\d+)/);
+$VERSION = $VERSION = sprintf("%d.%02d", q$Revision: 1.41 $ =~ /(\d+)\.(\d+)/);
sub is_abs_path
{
@@ -131,7 +131,7 @@ BEGIN
&& -f $script)
{
my $dir;
- my $pathvar = ($IsWin32) ? 'Path' : 'PATH';
+ my $pathvar = 'PATH';
foreach $dir (split(/$Config{'path_sep'}/,$ENV{$pathvar}))
{
diff --git a/lib/dumpvar.pl b/lib/dumpvar.pl
index c32bc2fb5e..cc7da89a62 100644
--- a/lib/dumpvar.pl
+++ b/lib/dumpvar.pl
@@ -22,6 +22,7 @@ $printUndef = 1 unless defined $printUndef;
$tick = "auto" unless defined $tick;
$unctrl = 'quote' unless defined $unctrl;
$subdump = 1;
+$dumpReused = 0 unless defined $dumpReused;
sub main::dumpValue {
local %address;
@@ -118,7 +119,7 @@ sub unwrap {
# Check for reused addresses
if (ref $v) {
($address) = $v =~ /(0x[0-9a-f]+)\)$/ ;
- if (defined $address) {
+ if (!$dumpReused && defined $address) {
($type) = $v =~ /=(.*?)\([^=]+$/ ;
$address{$address}++ ;
if ( $address{$address} > 1 ) {
diff --git a/lib/perl5db.pl b/lib/perl5db.pl
index ea072e0f3b..f0774bcdac 100644
--- a/lib/perl5db.pl
+++ b/lib/perl5db.pl
@@ -173,7 +173,7 @@ $trace = $signal = $single = 0; # Uninitialized warning suppression
# (local $^W cannot help - other packages!).
$inhibit_exit = $option{PrintRet} = 1;
-@options = qw(hashDepth arrayDepth DumpDBFiles DumpPackages
+@options = qw(hashDepth arrayDepth DumpDBFiles DumpPackages DumpReused
compactDump veryCompact quote HighBit undefPrint
globPrint PrintRet UsageOnly frame AutoTrace
TTY noTTY ReadLine NonStop LineInfo maxTraceLen
@@ -185,6 +185,7 @@ $inhibit_exit = $option{PrintRet} = 1;
arrayDepth => \$dumpvar::arrayDepth,
DumpDBFiles => \$dumpvar::dumpDBFiles,
DumpPackages => \$dumpvar::dumpPackages,
+ DumpReused => \$dumpvar::dumpReused,
HighBit => \$dumpvar::quoteHighBit,
undefPrint => \$dumpvar::printUndef,
globPrint => \$dumpvar::globPrint,
@@ -368,7 +369,7 @@ sub DB {
&save;
($package, $filename, $line) = caller;
$filename_ini = $filename;
- $usercontext = '($@, $!, $,, $/, $\, $^W) = @saved;' .
+ $usercontext = '($@, $!, $^E, $,, $/, $\, $^W) = @saved;' .
"package $package;"; # this won't let them modify, alas
local(*dbline) = $main::{'_<' . $filename};
$max = $#dbline;
@@ -1140,7 +1141,7 @@ EOP
&eval;
}
} # if ($single || $signal)
- ($@, $!, $,, $/, $\, $^W) = @saved;
+ ($@, $!, $^E, $,, $/, $\, $^W) = @saved;
();
}
@@ -1190,7 +1191,7 @@ sub sub {
}
sub save {
- @saved = ($@, $!, $,, $/, $\, $^W);
+ @saved = ($@, $!, $^E, $,, $/, $\, $^W);
$, = ""; $/ = "\n"; $\ = ""; $^W = 0;
}
@@ -1210,7 +1211,7 @@ sub eval {
}
my $at = $@;
local $saved[0]; # Preserve the old value of $@
- eval "&DB::save";
+ eval { &DB::save };
if ($at) {
print $OUT $at;
} elsif ($onetimeDump eq 'dump') {
@@ -1785,6 +1786,7 @@ B<O> [I<opt>[B<=>I<val>]] [I<opt>B<\">I<val>B<\">] [I<opt>B<?>]...
I<globPrint>: whether to print contents of globs;
I<DumpDBFiles>: dump arrays holding debugged files;
I<DumpPackages>: dump symbol tables of packages;
+ I<DumpReused>: dump contents of \"reused\" addresses;
I<quote>, I<HighBit>, I<undefPrint>: change style of string dump;
Option I<PrintRet> affects printing of return value after B<r> command,
I<frame> affects printing messages on entry and exit from subroutines.
diff --git a/mg.c b/mg.c
index b032bf3f95..1d0014315d 100644
--- a/mg.c
+++ b/mg.c
@@ -69,7 +69,6 @@ restore_magic(void *p)
}
}
-
void
mg_magical(SV *sv)
{
@@ -350,10 +349,22 @@ magic_get(SV *sv, MAGIC *mg)
sv_setpv(sv, os2error(Perl_rc));
}
#else
+#ifdef WIN32
+ {
+ DWORD dwErr = GetLastError();
+ sv_setnv(sv, (double)dwErr);
+ if (dwErr)
+ win32_str_os_error(sv, dwErr);
+ else
+ sv_setpv(sv, "");
+ SetLastError(dwErr);
+ }
+#else
sv_setnv(sv, (double)errno);
sv_setpv(sv, errno ? Strerror(errno) : "");
#endif
#endif
+#endif
SvNOK_on(sv); /* what a wonderful hack! */
break;
case '\006': /* ^F */
@@ -1349,9 +1360,13 @@ magic_set(SV *sv, MAGIC *mg)
#ifdef VMS
set_vaxc_errno(SvIOK(sv) ? SvIVX(sv) : sv_2iv(sv));
#else
+#ifdef WIN32
+ SetLastError( SvIV(sv) );
+#else
/* will anyone ever use this? */
SETERRNO(SvIOK(sv) ? SvIVX(sv) : sv_2iv(sv), 4);
#endif
+#endif
break;
case '\006': /* ^F */
maxsysfd = SvIOK(sv) ? SvIVX(sv) : sv_2iv(sv);
diff --git a/perl.h b/perl.h
index 59d729305e..9138ba6571 100644
--- a/perl.h
+++ b/perl.h
@@ -1666,6 +1666,10 @@ struct perl_thread {
#include "thrdvar.h"
};
+typedef struct perl_thread *Thread;
+
+#else
+typedef void *Thread;
#endif
/* Done with PERLVAR macros for now ... */
@@ -1673,8 +1677,6 @@ struct perl_thread {
#undef PERLVARI
#undef PERLVARIC
-typedef struct perl_thread *Thread;
-
#include "thread.h"
#include "pp.h"
#include "proto.h"
diff --git a/pod/perlfaq2.pod b/pod/perlfaq2.pod
index 8a954da64e..bbc361a5ba 100644
--- a/pod/perlfaq2.pod
+++ b/pod/perlfaq2.pod
@@ -15,21 +15,22 @@ development team) is distributed only in source code form. You can
find this at http://www.perl.com/CPAN/src/latest.tar.gz, which is a
gzipped archive in POSIX tar format. This source builds with no
porting whatsoever on most Unix systems (Perl's native environment),
-as well as Plan 9, VMS, QNX, OS/2, and the Amiga.
-
-Although it's rumored that the (imminent) 5.004 release may build
-on Windows NT, this is yet to be proven. Binary distributions
-for 32-bit Microsoft systems and for Apple systems can be found
-http://www.perl.com/CPAN/ports/ directory. Because these are not part of
-the standard distribution, they may and in fact do differ from the base
-Perl port in a variety of ways. You'll have to check their respective
-release notes to see just what the differences are. These differences
-can be either positive (e.g. extensions for the features of the particular
-platform that are not supported in the source release of perl) or negative
-(e.g. might be based upon a less current source release of perl).
-
-A useful FAQ for Win32 Perl users is
+as well as Windows NT, Plan 9, VMS, QNX, OS/2, and the Amiga.
+
+Binary distributions for various platforms can be found
+http://www.perl.com/CPAN/ports/ directory. Some of these ports (especially
+the ones that are not part of the standard sources) may behave differently
+than what is documented in the standard source documentation. These
+differences can be either positive (e.g. extensions for the features of the
+particular platform that are not supported in the source release of perl)
+or negative (e.g. might be based upon a less current source release of perl).
+
+A useful FAQ for Win32 Perl users is:
http://www.endcontsw.com/people/evangelo/Perl_for_Win32_FAQ.html
+[This FAQ is seriously outdated as of Jan 1998--it is only relevant to
+the perl that ActiveState distributes, especially where it describes
+various inadequacies and differences with the standard perl extension
+build support.]
=head2 How can I get a binary version of Perl?
diff --git a/pod/perlfunc.pod b/pod/perlfunc.pod
index 49d455b6a2..a89ee99e06 100644
--- a/pod/perlfunc.pod
+++ b/pod/perlfunc.pod
@@ -1,3 +1,4 @@
+
=head1 NAME
perlfunc - Perl builtin functions
@@ -79,117 +80,120 @@ than one place.
=item Functions for SCALARs or strings
-chomp, chop, chr, crypt, hex, index, lc, lcfirst, length,
-oct, ord, pack, q/STRING/, qq/STRING/, reverse, rindex,
-sprintf, substr, tr///, uc, ucfirst, y///
+C<chomp>, C<chop>, C<chr>, C<crypt>, C<hex>, C<index>, C<lc>, C<lcfirst>,
+C<length>, C<oct>, C<ord>, C<pack>, C<q>/STRING/, C<qq>/STRING/, C<reverse>,
+C<rindex>, C<sprintf>, C<substr>, C<tr///>, C<uc>, C<ucfirst>, C<y>///
=item Regular expressions and pattern matching
-m//, pos, quotemeta, s///, split, study
+C<m>//, C<pos>, C<quotemeta>, C<s>///, C<split>, C<study>
=item Numeric functions
-abs, atan2, cos, exp, hex, int, log, oct, rand, sin, sqrt,
-srand
+C<abs>, C<atan2>, C<cos>, C<exp>, C<hex>, C<int>, C<log>, C<oct>, C<rand>,
+C<sin>, C<sqrt>, C<srand>
=item Functions for real @ARRAYs
-pop, push, shift, splice, unshift
+C<pop>, C<push>, C<shift>, C<splice>, C<unshift>
=item Functions for list data
-grep, join, map, qw/STRING/, reverse, sort, unpack
+C<grep>, C<join>, C<map>, C<qw>/STRING/, C<reverse>, C<sort>, C<unpack>
=item Functions for real %HASHes
-delete, each, exists, keys, values
+C<delete>, C<each>, C<exists>, C<keys>, C<values>
=item Input and output functions
-binmode, close, closedir, dbmclose, dbmopen, die, eof,
-fileno, flock, format, getc, print, printf, read, readdir,
-rewinddir, seek, seekdir, select, syscall, sysread, sysseek,
-syswrite, tell, telldir, truncate, warn, write
+C<binmode>, C<close>, C<closedir>, C<dbmclose>, C<dbmopen>, C<die>, C<eof>,
+C<fileno>, C<flock>, C<format>, C<getc>, C<print>, C<printf>, C<read>,
+C<readdir>, C<rewinddir>, C<seek>, C<seekdir>, C<select>, C<syscall>,
+C<sysread>, C<sysseek>, C<syswrite>, C<tell>, C<telldir>, C<truncate>,
+C<warn>, C<write>
=item Functions for fixed length data or records
-pack, read, syscall, sysread, syswrite, unpack, vec
+C<pack>, C<read>, C<syscall>, C<sysread>, C<syswrite>, C<unpack>, C<vec>
=item Functions for filehandles, files, or directories
-I<-X>, chdir, chmod, chown, chroot, fcntl, glob, ioctl, link,
-lstat, mkdir, open, opendir, readlink, rename, rmdir,
-stat, symlink, umask, unlink, utime
+C<-I<X>>, C<chdir>, C<chmod>, C<chown>, C<chroot>, C<fcntl>, C<glob>,
+C<ioctl>, C<link>, C<lstat>, C<mkdir>, C<open>, C<opendir>, C<readlink>,
+C<rename>, C<rmdir>, C<stat>, C<symlink>, C<umask>, C<unlink>, C<utime>
=item Keywords related to the control flow of your perl program
-caller, continue, die, do, dump, eval, exit, goto, last,
-next, redo, return, sub, wantarray
+C<caller>, C<continue>, C<die>, C<do>, C<dump>, C<eval>, C<exit>,
+C<goto>, C<last>, C<next>, C<redo>, C<return>, C<sub>, C<wantarray>
=item Keywords related to scoping
-caller, import, local, my, package, use
+C<caller>, C<import>, C<local>, C<my>, C<package>, C<use>
=item Miscellaneous functions
-defined, dump, eval, formline, local, my, reset, scalar,
-undef, wantarray
+C<defined>, C<dump>, C<eval>, C<formline>, C<local>, C<my>, C<reset>,
+C<scalar>, C<undef>, C<wantarray>
=item Functions for processes and process groups
-alarm, exec, fork, getpgrp, getppid, getpriority, kill,
-pipe, qx/STRING/, setpgrp, setpriority, sleep, system,
-times, wait, waitpid
+C<alarm>, C<exec>, C<fork>, C<getpgrp>, C<getppid>, C<getpriority>, C<kill>,
+C<pipe>, C<qx>/STRING/, C<setpgrp>, C<setpriority>, C<sleep>, C<system>,
+C<times>, C<wait>, C<waitpid>
=item Keywords related to perl modules
-do, import, no, package, require, use
+C<do>, C<import>, C<no>, C<package>, C<require>, C<use>
=item Keywords related to classes and object-orientedness
-bless, dbmclose, dbmopen, package, ref, tie, tied, untie, use
+C<bless>, C<dbmclose>, C<dbmopen>, C<package>, C<ref>, C<tie>, C<tied>,
+C<untie>, C<use>
=item Low-level socket functions
-accept, bind, connect, getpeername, getsockname,
-getsockopt, listen, recv, send, setsockopt, shutdown,
-socket, socketpair
+C<accept>, C<bind>, C<connect>, C<getpeername>, C<getsockname>,
+C<getsockopt>, C<listen>, C<recv>, C<send>, C<setsockopt>, C<shutdown>,
+C<socket>, C<socketpair>
=item System V interprocess communication functions
-msgctl, msgget, msgrcv, msgsnd, semctl, semget, semop,
-shmctl, shmget, shmread, shmwrite
+C<msgctl>, C<msgget>, C<msgrcv>, C<msgsnd>, C<semctl>, C<semget>, C<semop>,
+C<shmctl>, C<shmget>, C<shmread>, C<shmwrite>
=item Fetching user and group info
-endgrent, endhostent, endnetent, endpwent, getgrent,
-getgrgid, getgrnam, getlogin, getpwent, getpwnam,
-getpwuid, setgrent, setpwent
+C<endgrent>, C<endhostent>, C<endnetent>, C<endpwent>, C<getgrent>,
+C<getgrgid>, C<getgrnam>, C<getlogin>, C<getpwent>, C<getpwnam>,
+C<getpwuid>, C<setgrent>, C<setpwent>
=item Fetching network info
-endprotoent, endservent, gethostbyaddr, gethostbyname,
-gethostent, getnetbyaddr, getnetbyname, getnetent,
-getprotobyname, getprotobynumber, getprotoent,
-getservbyname, getservbyport, getservent, sethostent,
-setnetent, setprotoent, setservent
+C<endprotoent>, C<endservent>, C<gethostbyaddr>, C<gethostbyname>,
+C<gethostent>, C<getnetbyaddr>, C<getnetbyname>, C<getnetent>,
+C<getprotobyname>, C<getprotobynumber>, C<getprotoent>,
+C<getservbyname>, C<getservbyport>, C<getservent>, C<sethostent>,
+C<setnetent>, C<setprotoent>, C<setservent>
=item Time-related functions
-gmtime, localtime, time, times
+C<gmtime>, C<localtime>, C<time>, C<times>
=item Functions new in perl5
-abs, bless, chomp, chr, exists, formline, glob, import, lc,
-lcfirst, map, my, no, prototype, qx, qw, readline, readpipe,
-ref, sub*, sysopen, tie, tied, uc, ucfirst, untie, use
+C<abs>, C<bless>, C<chomp>, C<chr>, C<exists>, C<formline>, C<glob>,
+C<import>, C<lc>, C<lcfirst>, C<map>, C<my>, C<no>, C<prototype>, C<qx>,
+C<qw>, C<readline>, C<readpipe>, C<ref>, C<sub*>, C<sysopen>, C<tie>,
+C<tied>, C<uc>, C<ucfirst>, C<untie>, C<use>
* - C<sub> was a keyword in perl4, but in perl5 it is an
operator which can be used in expressions.
=item Functions obsoleted in perl5
-dbmclose, dbmopen
+C<dbmclose>, C<dbmopen>
=back
@@ -197,11 +201,11 @@ dbmclose, dbmopen
=over 8
-=item -X FILEHANDLE
+=item I<-X> FILEHANDLE
-=item -X EXPR
+=item I<-X> EXPR
-=item -X
+=item I<-X>
A file test, where X is one of the letters listed below. This unary
operator takes one argument, either a filename or a filehandle, and
diff --git a/pod/perlrun.pod b/pod/perlrun.pod
index a847133bb9..eccb5e00b7 100644
--- a/pod/perlrun.pod
+++ b/pod/perlrun.pod
@@ -600,13 +600,17 @@ The command used to load the debugger code. The default is:
=item PERL5SHELL (specific to WIN32 port)
May be set to an alternative shell that perl must use internally for
-executing "backtick" commands or system(). Perl doesn't use COMSPEC
-for this purpose because COMSPEC has a high degree of variability
-among users, leading to portability concerns. Besides, perl can use
-a shell that may not be fit for interactive use, and setting COMSPEC
-to such a shell may interfere with the proper functioning of other
-programs (which usually look in COMSPEC to find a shell fit for
-interactive use).
+executing "backtick" commands or system(). Default is C<cmd.exe /x/c>
+on WindowsNT and C<command.com /c> on Windows95. The value is considered
+to be space delimited. Precede any character that needs to be protected
+(like a space or backslash) with a backslash.
+
+Note that Perl doesn't use COMSPEC for this purpose because
+COMSPEC has a high degree of variability among users, leading to
+portability concerns. Besides, perl can use a shell that may not be
+fit for interactive use, and setting COMSPEC to such a shell may
+interfere with the proper functioning of other programs (which usually
+look in COMSPEC to find a shell fit for interactive use).
=item PERL_DEBUG_MSTATS
diff --git a/pod/perlvar.pod b/pod/perlvar.pod
index 75f4e6d5c2..6a1ed81c5d 100644
--- a/pod/perlvar.pod
+++ b/pod/perlvar.pod
@@ -432,10 +432,10 @@ status.
If used in a numeric context, yields the current value of errno, with
all the usual caveats. (This means that you shouldn't depend on the
-value of "C<$!>" to be anything in particular unless you've gotten a
+value of C<$!> to be anything in particular unless you've gotten a
specific error return indicating a system error.) If used in a string
context, yields the corresponding system error string. You can assign
-to "C<$!>" to set I<errno> if, for instance, you want "C<$!>" to return the
+to C<$!> to set I<errno> if, for instance, you want C<"$!"> to return the
string for error I<n>, or you want to set the exit value for the die()
operator. (Mnemonic: What just went bang?)
@@ -443,13 +443,31 @@ operator. (Mnemonic: What just went bang?)
=item $^E
-More specific information about the last system error than that provided by
-C<$!>, if available. (If not, it's just C<$!> again.)
-At the moment, this differs from C<$!> under only VMS and OS/2, where it
-provides the VMS status value from the last system error, and OS/2 error
-code of the last call to OS/2 API either via CRT, or directly from perl. The
-caveats mentioned in the description of C<$!> apply here, too.
-(Mnemonic: Extra error explanation.)
+Error information specific to the current operating system. At
+the moment, this differs from C<$!> under only VMS, OS/2, and Win32
+(and for MacPerl). On all other platforms, C<$^E> is always just
+the same as C<$!>.
+
+Under VMS, C<$^E> provides the VMS status value from the last
+system error. This is more specific information about the last
+system error than that provided by C<$!>. This is particularly
+important when C<$!> is set to E<EVMSERR>.
+
+Under OS/2, C<$^E> is set based on the value returned by the OS/2
+call C<_syserrno()> only when a call into the OS/2 API generates
+an error. In this case, C<$!> is set to a special value to
+indicate that C<$^E> should be checked. Otherwise, C<$^E> is
+just the same as C<$!>.
+
+Under Win32, C<$^E> always returns the last error information
+reported by the Win32 call C<GetLastError()> which describes
+the last error from within the Win32 API. Most Win32-specific
+code will report errors via C<$^E>. ANSI C and UNIX-like calls
+set C<errno> and so most portable Perl code will report errors
+via C<$!>.
+
+Caveats mentioned in the description of C<$!> generally apply to
+C<$^E>, also. (Mnemonic: Extra error explanation.)
=item $EVAL_ERROR
diff --git a/pp_sys.c b/pp_sys.c
index 42e8a9c19a..23c7569df5 100644
--- a/pp_sys.c
+++ b/pp_sys.c
@@ -3097,7 +3097,7 @@ PP(pp_fork)
PP(pp_wait)
{
-#if !defined(DOSISH) || defined(OS2)
+#if !defined(DOSISH) || defined(OS2) || defined(WIN32)
djSP; dTARGET;
int childpid;
int argflags;
@@ -3113,7 +3113,7 @@ PP(pp_wait)
PP(pp_waitpid)
{
-#if !defined(DOSISH) || defined(OS2)
+#if !defined(DOSISH) || defined(OS2) || defined(WIN32)
djSP; dTARGET;
int childpid;
int optype;
@@ -3126,7 +3126,7 @@ PP(pp_waitpid)
SETi(childpid);
RETURN;
#else
- DIE(no_func, "Unsupported function wait");
+ DIE(no_func, "Unsupported function waitpid");
#endif
}
diff --git a/t/op/magic.t b/t/op/magic.t
index 80361ba0b7..ace49b546d 100755
--- a/t/op/magic.t
+++ b/t/op/magic.t
@@ -24,7 +24,7 @@ $Is_VMS = $^O eq 'VMS';
$Is_Dos = $^O eq 'dos';
$PERL = ($Is_MSWin32 ? '.\perl' : './perl');
-print "1..30\n";
+print "1..34\n";
eval '$ENV{"FOO"} = "hi there";'; # check that ENV is inited inside eval
if ($Is_MSWin32) { ok 1, `cmd /x /c set FOO` eq "FOO=hi there\n"; }
@@ -37,8 +37,8 @@ ok 2, $!, $!;
close FOO; # just mention it, squelch used-only-once
if ($Is_MSWin32 || $Is_Dos) {
- ok 3,1;
- ok 4,1;
+ ok "3 # skipped",1;
+ ok "4 # skipped",1;
}
else {
# the next tests are embedded inside system simply because sh spits out
@@ -165,8 +165,8 @@ ok 27, $^O;
ok 28, $^T > 850000000, $^T;
if ($Is_VMS || $Is_Dos) {
- ok 29, 1;
- ok 30, 1;
+ ok "29 # skipped", 1;
+ ok "30 # skipped", 1;
}
else {
$PATH = $ENV{PATH};
@@ -182,3 +182,20 @@ else {
: (`echo \$NoNeSuCh` eq "foo\n") );
}
+# test case-insignificance of %ENV (these tests must be enabled only
+# when perl is compiled with -DENV_IS_CASELESS)
+if ($Is_MSWin32) {
+ %ENV = ();
+ $ENV{'Foo'} = 'bar';
+ $ENV{'fOo'} = 'baz';
+ ok 31, (scalar(keys(%ENV)) == 1);
+ ok 32, exists($ENV{'FOo'});
+ ok 33, (delete($ENV{'foO'}) eq 'baz');
+ ok 34, (scalar(keys(%ENV)) == 0);
+}
+else {
+ ok "31 # skipped",1;
+ ok "32 # skipped",1;
+ ok "33 # skipped",1;
+ ok "34 # skipped",1;
+}
diff --git a/util.c b/util.c
index 86e148d720..1c4b79af7f 100644
--- a/util.c
+++ b/util.c
@@ -2024,6 +2024,9 @@ my_pclose(FILE *ptr)
#ifdef VMS
int saved_vaxc_errno;
#endif
+#ifdef WIN32
+ int saved_win32_errno;
+#endif
svp = av_fetch(fdpid,PerlIO_fileno(ptr),TRUE);
pid = (int)SvIVX(*svp);
@@ -2039,6 +2042,9 @@ my_pclose(FILE *ptr)
#ifdef VMS
saved_vaxc_errno = vaxc$errno;
#endif
+#ifdef WIN32
+ saved_win32_errno = GetLastError();
+#endif
}
#ifdef UTS
if(kill(pid, 0) < 0) { return(pid); } /* HOM 12/23/91 */
@@ -2060,7 +2066,7 @@ my_pclose(FILE *ptr)
}
#endif /* !DOSISH */
-#if !defined(DOSISH) || defined(OS2)
+#if !defined(DOSISH) || defined(OS2) || defined(WIN32)
I32
wait4pid(int pid, int *statusp, int flags)
{
@@ -2118,7 +2124,7 @@ wait4pid(int pid, int *statusp, int flags)
}
#endif
}
-#endif /* !DOSISH */
+#endif /* !DOSISH || OS2 || WIN32 */
void
/*SUPPRESS 590*/
diff --git a/utils/perldoc.PL b/utils/perldoc.PL
index 0ac8e0a806..3acb461f98 100644
--- a/utils/perldoc.PL
+++ b/utils/perldoc.PL
@@ -153,7 +153,7 @@ sub minus_f_nocase {
# on a case-forgiving file system we can simply use -f $file
if ($Is_VMS or $Is_MSWin32 or $^O eq 'os2') {
return $file if -f $file and -r _;
- warn "Ignored $file: unreadable\n" unless -r _;
+ warn "Ignored $file: unreadable\n" if -f _;
return '';
}
local *DIR;
diff --git a/win32/config_H.bc b/win32/config_H.bc
index 846d81d1e4..f587e019c8 100644
--- a/win32/config_H.bc
+++ b/win32/config_H.bc
@@ -1467,7 +1467,7 @@
* in programs that are not prepared to deal with ~ expansion at run-time.
*/
#define ARCHLIB "c:\\perl\\lib\\MSWin32-x86-thread" /**/
-#define ARCHLIB_EXP (win32PerlLibPath(ARCHNAME,NULL)) /**/
+#define ARCHLIB_EXP (win32_perllib_path(ARCHNAME,NULL)) /**/
/* BINCOMPAT3:
* This symbol, if defined, indicates that Perl 5.004 should be
@@ -1714,7 +1714,7 @@
* in programs that are not prepared to deal with ~ expansion at run-time.
*/
#define PRIVLIB "c:\\perl\\lib" /**/
-#define PRIVLIB_EXP (win32PerlLibPath(NULL)) /**/
+#define PRIVLIB_EXP (win32_perllib_path(NULL)) /**/
/* SH_PATH:
* This symbol contains the full pathname to the shell used on this
@@ -1770,7 +1770,7 @@
* in programs that are not prepared to deal with ~ expansion at run-time.
*/
#define SITEARCH "c:\\perl\\lib\\site" /**/
-#define SITEARCH_EXP (win32PerlLibPath("site",ARCHNAME,NULL)) /**/
+#define SITEARCH_EXP (win32_perllib_path("site",ARCHNAME,NULL)) /**/
/* SITELIB:
* This symbol contains the name of the private library for this package.
@@ -1786,7 +1786,7 @@
* in programs that are not prepared to deal with ~ expansion at run-time.
*/
#define SITELIB "c:\\perl\\lib\\site" /**/
-#define SITELIB_EXP (win32PerlLibPath("site",NULL)) /**/
+#define SITELIB_EXP (win32_perllib_path("site",NULL)) /**/
/* STARTPERL:
* This variable contains the string to put in front of a perl
diff --git a/win32/config_H.gc b/win32/config_H.gc
index 35737e7ca0..3e56046835 100644
--- a/win32/config_H.gc
+++ b/win32/config_H.gc
@@ -1467,7 +1467,7 @@
* in programs that are not prepared to deal with ~ expansion at run-time.
*/
#define ARCHLIB "c:\\perl\\lib\\MSWin32-x86-thread" /**/
-#define ARCHLIB_EXP (win32PerlLibPath(ARCHNAME,NULL)) /**/
+#define ARCHLIB_EXP (win32_perllib_path(ARCHNAME,NULL)) /**/
/* BINCOMPAT3:
* This symbol, if defined, indicates that Perl 5.004 should be
@@ -1714,7 +1714,7 @@
* in programs that are not prepared to deal with ~ expansion at run-time.
*/
#define PRIVLIB "c:\\perl\\lib" /**/
-#define PRIVLIB_EXP (win32PerlLibPath(NULL)) /**/
+#define PRIVLIB_EXP (win32_perllib_path(NULL)) /**/
/* SH_PATH:
* This symbol contains the full pathname to the shell used on this
@@ -1770,7 +1770,7 @@
* in programs that are not prepared to deal with ~ expansion at run-time.
*/
#define SITEARCH "c:\\perl\\lib\\site" /**/
-#define SITEARCH_EXP (win32PerlLibPath("site",ARCHNAME,NULL)) /**/
+#define SITEARCH_EXP (win32_perllib_path("site",ARCHNAME,NULL)) /**/
/* SITELIB:
* This symbol contains the name of the private library for this package.
@@ -1786,7 +1786,7 @@
* in programs that are not prepared to deal with ~ expansion at run-time.
*/
#define SITELIB "c:\\perl\\lib\\site" /**/
-#define SITELIB_EXP (win32PerlLibPath("site",NULL)) /**/
+#define SITELIB_EXP (win32_perllib_path("site",NULL)) /**/
/* STARTPERL:
* This variable contains the string to put in front of a perl
diff --git a/win32/config_H.vc b/win32/config_H.vc
index 72caabb9f9..42578bad8e 100644
--- a/win32/config_H.vc
+++ b/win32/config_H.vc
@@ -1467,7 +1467,7 @@
* in programs that are not prepared to deal with ~ expansion at run-time.
*/
#define ARCHLIB "c:\\perl\\lib\\MSWin32-x86-thread" /**/
-#define ARCHLIB_EXP (win32PerlLibPath(ARCHNAME,NULL)) /**/
+#define ARCHLIB_EXP (win32_perllib_path(ARCHNAME,NULL)) /**/
/* BINCOMPAT3:
* This symbol, if defined, indicates that Perl 5.004 should be
@@ -1714,7 +1714,7 @@
* in programs that are not prepared to deal with ~ expansion at run-time.
*/
#define PRIVLIB "c:\\perl\\lib" /**/
-#define PRIVLIB_EXP (win32PerlLibPath(NULL)) /**/
+#define PRIVLIB_EXP (win32_perllib_path(NULL)) /**/
/* SH_PATH:
* This symbol contains the full pathname to the shell used on this
@@ -1770,7 +1770,7 @@
* in programs that are not prepared to deal with ~ expansion at run-time.
*/
#define SITEARCH "c:\\perl\\lib\\site" /**/
-#define SITEARCH_EXP (win32PerlLibPath("site",ARCHNAME,NULL)) /**/
+#define SITEARCH_EXP (win32_perllib_path("site",ARCHNAME,NULL)) /**/
/* SITELIB:
* This symbol contains the name of the private library for this package.
@@ -1786,7 +1786,7 @@
* in programs that are not prepared to deal with ~ expansion at run-time.
*/
#define SITELIB "c:\\perl\\lib\\site" /**/
-#define SITELIB_EXP (win32PerlLibPath("site",NULL)) /**/
+#define SITELIB_EXP (win32_perllib_path("site",NULL)) /**/
/* STARTPERL:
* This variable contains the string to put in front of a perl
diff --git a/win32/config_h.PL b/win32/config_h.PL
index 7f2869c945..8a1665a75a 100644
--- a/win32/config_h.PL
+++ b/win32/config_h.PL
@@ -37,19 +37,19 @@ while (<SH>)
s#/[ *\*]*\*/#/**/#;
if (/^\s*#define\s+ARCHLIB_EXP/)
{
- $_ = "#define ARCHLIB_EXP (win32PerlLibPath(ARCHNAME,NULL))\t/**/\n";
+ $_ = "#define ARCHLIB_EXP (win32_perllib_path(ARCHNAME,NULL))\t/**/\n";
}
if (/^\s*#define\s+PRIVLIB_EXP/)
{
- $_ = "#define PRIVLIB_EXP (win32PerlLibPath(NULL))\t/**/\n"
+ $_ = "#define PRIVLIB_EXP (win32_perllib_path(NULL))\t/**/\n"
}
if (/^\s*#define\s+SITEARCH_EXP/)
{
- $_ = "#define SITEARCH_EXP (win32PerlLibPath(\"site\",ARCHNAME,NULL))\t/**/\n";
+ $_ = "#define SITEARCH_EXP (win32_perllib_path(\"site\",ARCHNAME,NULL))\t/**/\n";
}
if (/^\s*#define\s+SITELIB_EXP/)
{
- $_ = "#define SITELIB_EXP (win32PerlLibPath(\"site\",NULL))\t/**/\n";
+ $_ = "#define SITELIB_EXP (win32_perllib_path(\"site\",NULL))\t/**/\n";
}
print H;
}
diff --git a/win32/makedef.pl b/win32/makedef.pl
index 27bcf95295..ddf01fdab8 100644
--- a/win32/makedef.pl
+++ b/win32/makedef.pl
@@ -508,6 +508,8 @@ win32_alarm
win32_open_osfhandle
win32_get_osfhandle
win32_ioctl
+win32_wait
+win32_str_os_error
Perl_win32_init
Perl_init_os_extras
Perl_getTHR
diff --git a/win32/perllib.c b/win32/perllib.c
index b73a12e31b..4b57963a99 100644
--- a/win32/perllib.c
+++ b/win32/perllib.c
@@ -47,7 +47,7 @@ RunPerl(int argc, char **argv, char **env, void *iosubsystem)
return (exitstatus);
}
-extern HANDLE PerlDllHandle;
+extern HANDLE w32_perldll_handle;
BOOL APIENTRY
DllMain(HANDLE hModule, /* DLL module handle */
@@ -66,7 +66,7 @@ DllMain(HANDLE hModule, /* DLL module handle */
setmode( fileno( stderr ), O_BINARY );
_fmode = O_BINARY;
#endif
- PerlDllHandle = hModule;
+ w32_perldll_handle = hModule;
break;
/* The DLL is detaching from a process due to
diff --git a/win32/win32.c b/win32/win32.c
index f75ec6c88d..9ae2a7d70f 100644
--- a/win32/win32.c
+++ b/win32/win32.c
@@ -47,13 +47,23 @@ int _CRT_glob = 0;
#define EXECF_SPAWN 2
#define EXECF_SPAWN_NOWAIT 3
-static DWORD IdOS(void);
-
-BOOL ProbeEnv = FALSE;
-DWORD Win32System = (DWORD)-1;
-char szShellPath[MAX_PATH+1];
-char szPerlLibRoot[MAX_PATH+1];
-HANDLE PerlDllHandle = INVALID_HANDLE_VALUE;
+static DWORD os_id(void);
+static void get_shell(void);
+static long tokenize(char *str, char **dest, char ***destv);
+static int do_spawn2(char *cmd, int exectype);
+static BOOL has_redirection(char *ptr);
+static long filetime_to_clock(PFILETIME ft);
+
+char * w32_perlshell_tokens = Nullch;
+char ** w32_perlshell_vec;
+long w32_perlshell_items = -1;
+DWORD w32_platform = (DWORD)-1;
+char w32_perllib_root[MAX_PATH+1];
+HANDLE w32_perldll_handle = INVALID_HANDLE_VALUE;
+#ifndef __BORLANDC__
+long w32_num_children = 0;
+HANDLE w32_child_pids[MAXIMUM_WAIT_OBJECTS];
+#endif
#ifdef USE_THREADS
# ifdef USE_DECLSPEC_THREAD
@@ -75,30 +85,28 @@ char crypt_buffer[30];
# endif
#endif
-static int do_spawn2(char *cmd, int exectype);
-
int
IsWin95(void) {
- return (IdOS() == VER_PLATFORM_WIN32_WINDOWS);
+ return (os_id() == VER_PLATFORM_WIN32_WINDOWS);
}
int
IsWinNT(void) {
- return (IdOS() == VER_PLATFORM_WIN32_NT);
+ return (os_id() == VER_PLATFORM_WIN32_NT);
}
char *
-win32PerlLibPath(char *sfx,...)
+win32_perllib_path(char *sfx,...)
{
va_list ap;
char *end;
va_start(ap,sfx);
- GetModuleFileName((PerlDllHandle == INVALID_HANDLE_VALUE)
+ GetModuleFileName((w32_perldll_handle == INVALID_HANDLE_VALUE)
? GetModuleHandle(NULL)
- : PerlDllHandle,
- szPerlLibRoot,
- sizeof(szPerlLibRoot));
- *(end = strrchr(szPerlLibRoot, '\\')) = '\0';
+ : w32_perldll_handle,
+ w32_perllib_root,
+ sizeof(w32_perllib_root));
+ *(end = strrchr(w32_perllib_root, '\\')) = '\0';
if (stricmp(end-4,"\\bin") == 0)
end -= 4;
strcpy(end,"\\lib");
@@ -109,12 +117,12 @@ win32PerlLibPath(char *sfx,...)
sfx = va_arg(ap,char *);
}
va_end(ap);
- return (szPerlLibRoot);
+ return (w32_perllib_root);
}
-BOOL
-HasRedirection(char *ptr)
+static BOOL
+has_redirection(char *ptr)
{
int inquote = 0;
char quote = '\0';
@@ -187,24 +195,75 @@ my_pclose(PerlIO *fp)
}
static DWORD
-IdOS(void)
+os_id(void)
{
static OSVERSIONINFO osver;
- if (osver.dwPlatformId != Win32System) {
+ if (osver.dwPlatformId != w32_platform) {
memset(&osver, 0, sizeof(OSVERSIONINFO));
osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osver);
- Win32System = osver.dwPlatformId;
+ w32_platform = osver.dwPlatformId;
+ }
+ return (w32_platform);
+}
+
+/* Tokenize a string. Words are null-separated, and the list
+ * ends with a doubled null. Any character (except null and
+ * including backslash) may be escaped by preceding it with a
+ * backslash (the backslash will be stripped).
+ * Returns number of words in result buffer.
+ */
+static long
+tokenize(char *str, char **dest, char ***destv)
+{
+ char *retstart = Nullch;
+ char **retvstart = 0;
+ int items = -1;
+ if (str) {
+ int slen = strlen(str);
+ register char *ret;
+ register char **retv;
+ New(1307, ret, slen+2, char);
+ New(1308, retv, (slen+3)/2, char*);
+
+ retstart = ret;
+ retvstart = retv;
+ *retv = ret;
+ items = 0;
+ while (*str) {
+ *ret = *str++;
+ if (*ret == '\\' && *str)
+ *ret = *str++;
+ else if (*ret == ' ') {
+ while (*str == ' ')
+ str++;
+ if (ret == retstart)
+ ret--;
+ else {
+ *ret = '\0';
+ ++items;
+ if (*str)
+ *++retv = ret+1;
+ }
+ }
+ else if (!*str)
+ ++items;
+ ret++;
+ }
+ retvstart[items] = Nullch;
+ *ret++ = '\0';
+ *ret = '\0';
}
- return (Win32System);
+ *dest = retstart;
+ *destv = retvstart;
+ return items;
}
-static char *
-GetShell(void)
+static void
+get_shell(void)
{
- if (!ProbeEnv) {
- char* defaultshell = (IsWinNT() ? "cmd.exe" : "command.com");
+ if (!w32_perlshell_tokens) {
/* we don't use COMSPEC here for two reasons:
* 1. the same reason perl on UNIX doesn't use SHELL--rampant and
* uncontrolled unportability of the ensuing scripts.
@@ -212,59 +271,75 @@ GetShell(void)
* interactive use (which is what most programs look in COMSPEC
* for).
*/
- char *usershell = getenv("PERL5SHELL");
-
- ProbeEnv = TRUE;
- strcpy(szShellPath, usershell ? usershell : defaultshell);
+ char* defaultshell = (IsWinNT() ? "cmd.exe /x/c" : "command.com /c");
+ char *usershell = getenv("PERL5SHELL");
+ w32_perlshell_items = tokenize(usershell ? usershell : defaultshell,
+ &w32_perlshell_tokens,
+ &w32_perlshell_vec);
}
- return szShellPath;
}
int
-do_aspawn(void* really, void ** mark, void ** arglast)
+do_aspawn(void *vreally, void **vmark, void **vsp)
{
+ SV *really = (SV*)vreally;
+ SV **mark = (SV**)vmark;
+ SV **sp = (SV**)vsp;
char **argv;
- char *strPtr;
- char *cmd;
+ char *str;
int status;
- unsigned int length;
+ int flag = P_WAIT;
int index = 0;
- SV *sv = (SV*)really;
- SV** pSv = (SV**)mark;
- New(1310, argv, (arglast - mark) + 4, char*);
+ if (sp <= mark)
+ return -1;
- if(sv != Nullsv) {
- cmd = SvPV(sv, length);
- }
- else {
- argv[index++] = cmd = GetShell();
- if (IsWinNT())
- argv[index++] = "/x"; /* always enable command extensions */
- argv[index++] = "/c";
+ get_shell();
+ New(1306, argv, (sp - mark) + w32_perlshell_items + 2, char*);
+
+ if (SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) {
+ ++mark;
+ flag = SvIVx(*mark);
}
- while(++pSv <= (SV**)arglast) {
- sv = *pSv;
- strPtr = SvPV(sv, length);
- if(strPtr != NULL && *strPtr != '\0')
- argv[index++] = strPtr;
+ while(++mark <= sp) {
+ if (*mark && (str = SvPV(*mark, na)))
+ argv[index++] = str;
+ else
+ argv[index++] = "";
}
argv[index++] = 0;
- status = win32_spawnvp(P_WAIT, cmd, (const char* const*)argv);
-
- Safefree(argv);
+ status = win32_spawnvp(flag,
+ (really ? SvPV(really,na) : argv[0]),
+ (const char* const*)argv);
+
+ if (status < 0 && errno == ENOEXEC) {
+ /* possible shell-builtin, invoke with shell */
+ int sh_items;
+ sh_items = w32_perlshell_items;
+ while (--index >= 0)
+ argv[index+sh_items] = argv[index];
+ while (--sh_items >= 0)
+ argv[sh_items] = w32_perlshell_vec[sh_items];
+
+ status = win32_spawnvp(flag,
+ (really ? SvPV(really,na) : argv[0]),
+ (const char* const*)argv);
+ }
if (status < 0) {
if (dowarn)
- warn("Can't spawn \"%s\": %s", cmd, strerror(errno));
- status = 255;
+ warn("Can't spawn \"%s\": %s", argv[0], strerror(errno));
+ status = 255 * 256;
}
- return (statusvalue = status*256);
+ else if (flag != P_NOWAIT)
+ status *= 256;
+ Safefree(argv);
+ return (statusvalue = status);
}
-int
+static int
do_spawn2(char *cmd, int exectype)
{
char **a;
@@ -272,13 +347,11 @@ do_spawn2(char *cmd, int exectype)
char **argv;
int status = -1;
BOOL needToTry = TRUE;
- char *shell, *cmd2;
+ char *cmd2;
- /* save an extra exec if possible */
- shell = GetShell();
-
- /* see if there are shell metacharacters in it */
- if(!HasRedirection(cmd)) {
+ /* Save an extra exec if possible. See if there are shell
+ * metacharacters in it */
+ if(!has_redirection(cmd)) {
New(1301,argv, strlen(cmd) / 2 + 2, char*);
New(1302,cmd2, strlen(cmd) + 1, char);
strcpy(cmd2, cmd);
@@ -294,7 +367,7 @@ do_spawn2(char *cmd, int exectype)
*s++ = '\0';
}
*a = Nullch;
- if(argv[0]) {
+ if (argv[0]) {
switch (exectype) {
case EXECF_SPAWN:
status = win32_spawnvp(P_WAIT, argv[0],
@@ -308,19 +381,21 @@ do_spawn2(char *cmd, int exectype)
status = win32_execvp(argv[0], (const char* const*)argv);
break;
}
- if(status != -1 || errno == 0)
+ if (status != -1 || errno == 0)
needToTry = FALSE;
}
Safefree(argv);
Safefree(cmd2);
}
- if(needToTry) {
- char *argv[5];
- int i = 0;
- argv[i++] = shell;
- if (IsWinNT())
- argv[i++] = "/x";
- argv[i++] = "/c"; argv[i++] = cmd; argv[i] = Nullch;
+ if (needToTry) {
+ char **argv;
+ int i = -1;
+ get_shell();
+ New(1306, argv, w32_perlshell_items + 2, char*);
+ while (++i < w32_perlshell_items)
+ argv[i] = w32_perlshell_vec[i];
+ argv[i++] = cmd;
+ argv[i] = Nullch;
switch (exectype) {
case EXECF_SPAWN:
status = win32_spawnvp(P_WAIT, argv[0],
@@ -334,16 +409,19 @@ do_spawn2(char *cmd, int exectype)
status = win32_execvp(argv[0], (const char* const*)argv);
break;
}
+ cmd = argv[0];
+ Safefree(argv);
}
if (status < 0) {
if (dowarn)
warn("Can't %s \"%s\": %s",
(exectype == EXECF_EXEC ? "exec" : "spawn"),
- needToTry ? shell : argv[0],
- strerror(errno));
- status = 255;
+ cmd, strerror(errno));
+ status = 255 * 256;
}
- return (statusvalue = status*256);
+ else if (exectype != EXECF_SPAWN_NOWAIT)
+ status *= 256;
+ return (statusvalue = status);
}
int
@@ -352,6 +430,12 @@ do_spawn(char *cmd)
return do_spawn2(cmd, EXECF_SPAWN);
}
+int
+do_spawn_nowait(char *cmd)
+{
+ return do_spawn2(cmd, EXECF_SPAWN_NOWAIT);
+}
+
bool
do_exec(char *cmd)
{
@@ -683,7 +767,7 @@ win32_getenv(const char *name)
#endif
static long
-FileTimeToClock(PFILETIME ft)
+filetime_to_clock(PFILETIME ft)
{
__int64 qw = ft->dwHighDateTime;
qw <<= 32;
@@ -700,8 +784,8 @@ win32_times(struct tms *timebuf)
FILETIME dummy;
if (GetProcessTimes(GetCurrentProcess(), &dummy, &dummy,
&kernel,&user)) {
- timebuf->tms_utime = FileTimeToClock(&user);
- timebuf->tms_stime = FileTimeToClock(&kernel);
+ timebuf->tms_utime = filetime_to_clock(&user);
+ timebuf->tms_stime = filetime_to_clock(&kernel);
timebuf->tms_cutime = 0;
timebuf->tms_cstime = 0;
@@ -716,8 +800,53 @@ win32_times(struct tms *timebuf)
return 0;
}
-static UINT timerid = 0;
+DllExport int
+win32_wait(int *status)
+{
+#ifdef __BORLANDC__
+ return wait(status);
+#else
+ /* XXX this wait emulation only knows about processes
+ * spawned via win32_spawnvp(P_NOWAIT, ...).
+ */
+ int i, retval;
+ DWORD exitcode, waitcode;
+
+ if (!w32_num_children) {
+ errno = ECHILD;
+ return -1;
+ }
+
+ /* if a child exists, wait for it to die */
+ waitcode = WaitForMultipleObjects(w32_num_children,
+ w32_child_pids,
+ FALSE,
+ INFINITE);
+ if (waitcode != WAIT_FAILED) {
+ if (waitcode >= WAIT_ABANDONED_0
+ && waitcode < WAIT_ABANDONED_0 + w32_num_children)
+ i = waitcode - WAIT_ABANDONED_0;
+ else
+ i = waitcode - WAIT_OBJECT_0;
+ if (GetExitCodeProcess(w32_child_pids[i], &exitcode) ) {
+ CloseHandle(w32_child_pids[i]);
+ *status = (int)((exitcode & 0xff) << 8);
+ retval = (int)w32_child_pids[i];
+ Copy(&w32_child_pids[i+1], &w32_child_pids[i],
+ (w32_num_children-i-1), HANDLE);
+ w32_num_children--;
+ return retval;
+ }
+ }
+
+FAILED:
+ errno = GetLastError();
+ return -1;
+#endif
+}
+
+static UINT timerid = 0;
static VOID CALLBACK TimerProc(HWND win, UINT msg, UINT id, DWORD time)
{
@@ -991,6 +1120,33 @@ win32_strerror(int e)
return strerror(e);
}
+DllExport void
+win32_str_os_error(SV *sv, unsigned long dwErr)
+{
+ DWORD dwLen;
+ char *sMsg;
+ dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
+ |FORMAT_MESSAGE_IGNORE_INSERTS
+ |FORMAT_MESSAGE_FROM_SYSTEM, NULL,
+ dwErr, 0, (char *)&sMsg, 1, NULL);
+ if (0 < dwLen) {
+ while (0 < dwLen && isspace(sMsg[--dwLen]))
+ ;
+ if ('.' != sMsg[dwLen])
+ dwLen++;
+ sMsg[dwLen]= '\0';
+ }
+ if (0 == dwLen) {
+ sMsg = LocalAlloc(0, 64/**sizeof(TCHAR)*/);
+ dwLen = sprintf(sMsg,
+ "Unknown error #0x%lX (lookup 0x%lX)",
+ dwErr, GetLastError());
+ }
+ sv_setpvn(sv, sMsg, dwLen);
+ LocalFree(sMsg);
+}
+
+
DllExport int
win32_fprintf(FILE *fp, const char *format, ...)
{
@@ -1267,7 +1423,18 @@ win32_chdir(const char *dir)
DllExport int
win32_spawnvp(int mode, const char *cmdname, const char *const *argv)
{
- return spawnvp(mode, cmdname, (char * const *) argv);
+ int status;
+
+ status = spawnvp(mode, cmdname, (char * const *) argv);
+#ifndef __BORLANDC__
+ /* XXX For the P_NOWAIT case, Borland RTL returns pinfo.dwProcessId
+ * while VC RTL returns pinfo.hProcess. For purposes of the custom
+ * implementation of win32_wait(), we assume the latter.
+ */
+ if (mode == P_NOWAIT && status >= 0)
+ w32_child_pids[w32_num_children++] = (HANDLE)status;
+#endif
+ return status;
}
DllExport int
diff --git a/win32/win32.h b/win32/win32.h
index 1b1f64adac..5a7c89bf97 100644
--- a/win32/win32.h
+++ b/win32/win32.h
@@ -91,6 +91,8 @@ struct tms {
#define USE_FIXED_OSFHANDLE
#endif
+#define ENV_IS_CASELESS
+
#ifndef VER_PLATFORM_WIN32_WINDOWS /* VC-2.0 headers dont have this */
#define VER_PLATFORM_WIN32_WINDOWS 1
#endif
@@ -159,15 +161,17 @@ extern char * getlogin(void);
DllExport void Perl_win32_init(int *argcp, char ***argvp);
DllExport void Perl_init_os_extras(void);
+DllExport void win32_str_os_error(struct sv *s, DWORD err);
#ifndef USE_SOCKETS_AS_HANDLES
extern FILE * my_fdopen(int, char *);
#endif
extern int my_fclose(FILE *);
-extern int do_aspawn(void* really, void ** mark, void ** arglast);
+extern int do_aspawn(void *really, void **mark, void **sp);
extern int do_spawn(char *cmd);
+extern int do_spawn_nowait(char *cmd);
extern char do_exec(char *cmd);
-extern char * win32PerlLibPath(char *sfx,...);
+extern char * win32_perllib_path(char *sfx,...);
extern int IsWin95(void);
extern int IsWinNT(void);
@@ -217,6 +221,9 @@ struct thread_intern {
# ifdef HAVE_DES_FCRYPT
char Wcrypt_buffer[30];
# endif
+# ifdef USE_RTL_THREAD_API
+ void * retv; /* slot for thread return value */
+# endif
};
# endif /* !USE_DECLSPEC_THREAD */
#endif /* USE_THREADS */
diff --git a/win32/win32iop.h b/win32/win32iop.h
index 5e03f952f2..e71bf3865e 100644
--- a/win32/win32iop.h
+++ b/win32/win32iop.h
@@ -112,9 +112,9 @@ DllExport char* win32_getenv(const char *name);
DllExport unsigned win32_sleep(unsigned int);
DllExport int win32_times(struct tms *timebuf);
DllExport unsigned win32_alarm(unsigned int sec);
-DllExport int win32_flock(int fd, int oper);
DllExport int win32_stat(const char *path, struct stat *buf);
DllExport int win32_ioctl(int i, unsigned int u, char *data);
+DllExport int win32_wait(int *status);
#ifdef HAVE_DES_FCRYPT
DllExport char * win32_crypt(const char *txt, const char *salt);
@@ -140,6 +140,7 @@ END_EXTERN_C
#undef times
#undef alarm
#undef ioctl
+#undef wait
#ifdef __BORLANDC__
#undef ungetc
@@ -239,6 +240,7 @@ END_EXTERN_C
#define times win32_times
#define alarm win32_alarm
#define ioctl win32_ioctl
+#define wait win32_wait
#ifdef HAVE_DES_FCRYPT
#undef crypt
diff --git a/win32/win32sck.c b/win32/win32sck.c
index a6e7a990b8..5ac2ef6c65 100644
--- a/win32/win32sck.c
+++ b/win32/win32sck.c
@@ -223,7 +223,7 @@ win32_getsockopt(SOCKET s, int level, int optname, char *optval, int *optlen)
return r;
}
-DllExport int
+int
win32_ioctlsocket(SOCKET s, long cmd, u_long *argp)
{
int r;
diff --git a/win32/win32thread.c b/win32/win32thread.c
index 3ea73c32a5..44f32e27fd 100644
--- a/win32/win32thread.c
+++ b/win32/win32thread.c
@@ -84,11 +84,40 @@ int
Perl_thread_create(struct perl_thread *thr, thread_func_t *fn)
{
DWORD junk;
+ unsigned long th;
MUTEX_LOCK(&thr->mutex);
DEBUG_L(PerlIO_printf(PerlIO_stderr(),
"%p: create OS thread\n", thr));
+#ifdef USE_RTL_THREAD_API
+ /* See comment about USE_RTL_THREAD_API in win32thread.h */
+#if defined(__BORLANDC__)
+ th = _beginthreadNT(fn, /* start address */
+ 0, /* stack size */
+ (void *)thr, /* parameters */
+ (void *)NULL, /* security attrib */
+ 0, /* creation flags */
+ (unsigned long *)&junk); /* tid */
+ if (th == (unsigned long)-1)
+ th = 0;
+#elif defined(_MSC_VER_)
+ th = _beginthreadex((void *)NULL, /* security attrib */
+ 0, /* stack size */
+ fn, /* start address */
+ (void*)thr, /* parameters */
+ 0, /* creation flags */
+ (unsigned *)&junk); /* tid */
+#else /* compilers using CRTDLL.DLL only have _beginthread() */
+ th = _beginthread(fn, /* start address */
+ 0, /* stack size */
+ (void*)thr); /* parameters */
+ if (th == (unsigned long)-1)
+ th = 0;
+#endif
+ thr->self = (HANDLE)th;
+#else /* !USE_RTL_THREAD_API */
thr->self = CreateThread(NULL, 0, fn, (void*)thr, 0, &junk);
+#endif /* !USE_RTL_THREAD_API */
DEBUG_L(PerlIO_printf(PerlIO_stderr(),
"%p: OS thread = %p, id=%ld\n", thr, thr->self, junk));
MUTEX_UNLOCK(&thr->mutex);
diff --git a/win32/win32thread.h b/win32/win32thread.h
index 1a16c78b67..acb136c690 100644
--- a/win32/win32thread.h
+++ b/win32/win32thread.h
@@ -100,8 +100,39 @@ typedef HANDLE perl_mutex;
#define THREAD_CREATE(t, f) Perl_thread_create(t, f)
#define THREAD_POST_CREATE(t) NOOP
-#define THREAD_RET_TYPE DWORD WINAPI
-#define THREAD_RET_CAST(p) ((DWORD)(p))
+
+/* XXX Docs mention that the RTL versions of thread creation routines
+ * should be used, but that advice only seems applicable when the RTL
+ * is not in a DLL. RTL DLLs in both Borland and VC seem to do all of
+ * the init/deinit required upon DLL_THREAD_ATTACH/DETACH. So we seem
+ * to be completely safe using straight Win32 API calls, rather than
+ * the much braindamaged RTL calls.
+ *
+ * _beginthread() in the RTLs call CloseHandle() just after the thread
+ * function returns, which means: 1) we have a race on our hands
+ * 2) it is impossible to implement join() semantics.
+ *
+ * IOW, do *NOT* turn on USE_RTL_THREAD_API! It is here
+ * for experimental purposes only. GSAR 98-01-02
+ */
+#ifdef USE_RTL_THREAD_API
+# include <process.h>
+# if defined(__BORLANDC__)
+ /* Borland RTL doesn't allow a return value from thread function! */
+# define THREAD_RET_TYPE void _USERENTRY
+# define THREAD_RET_CAST(p) ((void)(thr->i.retv = (void *)(p)))
+# elif defined (_MSC_VER)
+# define THREAD_RET_TYPE unsigned __stdcall
+# define THREAD_RET_CAST(p) ((unsigned)(p))
+# else
+ /* CRTDLL.DLL doesn't allow a return value from thread function! */
+# define THREAD_RET_TYPE void __cdecl
+# define THREAD_RET_CAST(p) ((void)(thr->i.retv = (void *)(p)))
+# endif
+#else /* !USE_RTL_THREAD_API */
+# define THREAD_RET_TYPE DWORD WINAPI
+# define THREAD_RET_CAST(p) ((DWORD)(p))
+#endif /* !USE_RTL_THREAD_API */
typedef THREAD_RET_TYPE thread_func_t(void *);
@@ -131,12 +162,22 @@ END_EXTERN_C
#define ALLOC_THREAD_KEY Perl_alloc_thread_key()
#define SET_THREAD_SELF(thr) Perl_set_thread_self(thr)
+#if defined(USE_RTL_THREAD_API) && !defined(_MSC_VER)
+#define JOIN(t, avp) \
+ STMT_START { \
+ if ((WaitForSingleObject((t)->self,INFINITE) == WAIT_FAILED) \
+ || (GetExitCodeThread((t)->self,(LPDWORD)(avp)) == 0)) \
+ croak("panic: JOIN"); \
+ *avp = (AV *)((t)->i.retv); \
+ } STMT_END
+#else /* !USE_RTL_THREAD_API || _MSC_VER */
#define JOIN(t, avp) \
STMT_START { \
if ((WaitForSingleObject((t)->self,INFINITE) == WAIT_FAILED) \
|| (GetExitCodeThread((t)->self,(LPDWORD)(avp)) == 0)) \
croak("panic: JOIN"); \
} STMT_END
+#endif /* !USE_RTL_THREAD_API || _MSC_VER */
#define YIELD Sleep(0)