diff options
author | Nick Ing-Simmons <nik@tiuk.ti.com> | 1998-01-07 18:40:55 +0000 |
---|---|---|
committer | Nick Ing-Simmons <nik@tiuk.ti.com> | 1998-01-07 18:40:55 +0000 |
commit | 750166a8e00335dafb5951e071341ae11e804119 (patch) | |
tree | b9840eb6620f589da6b857b3a81f032f460bfffc | |
parent | 324f2d369a8d4d6edae0a1142d9a03e222f98c36 (diff) | |
parent | ce1da67e6637b3b736abebfc7cd6991d91dbe03a (diff) | |
download | perl-750166a8e00335dafb5951e071341ae11e804119.tar.gz |
Integrate win32 branch
p4raw-id: //depot/ansiperl@395
-rw-r--r-- | README.win32 | 14 | ||||
-rw-r--r-- | doio.c | 3 | ||||
-rw-r--r-- | dosish.h | 16 | ||||
-rw-r--r-- | hv.c | 99 | ||||
-rw-r--r-- | lib/Cwd.pm | 4 | ||||
-rw-r--r-- | lib/ExtUtils/Liblist.pm | 20 | ||||
-rw-r--r-- | lib/FindBin.pm | 4 | ||||
-rw-r--r-- | lib/dumpvar.pl | 3 | ||||
-rw-r--r-- | lib/perl5db.pl | 12 | ||||
-rw-r--r-- | mg.c | 17 | ||||
-rw-r--r-- | perl.h | 6 | ||||
-rw-r--r-- | pod/perlfaq2.pod | 29 | ||||
-rw-r--r-- | pod/perlfunc.pod | 100 | ||||
-rw-r--r-- | pod/perlrun.pod | 18 | ||||
-rw-r--r-- | pod/perlvar.pod | 36 | ||||
-rw-r--r-- | pp_sys.c | 6 | ||||
-rwxr-xr-x | t/op/magic.t | 27 | ||||
-rw-r--r-- | util.c | 10 | ||||
-rw-r--r-- | utils/perldoc.PL | 2 | ||||
-rw-r--r-- | win32/config_H.bc | 8 | ||||
-rw-r--r-- | win32/config_H.gc | 8 | ||||
-rw-r--r-- | win32/config_H.vc | 8 | ||||
-rw-r--r-- | win32/config_h.PL | 8 | ||||
-rw-r--r-- | win32/makedef.pl | 2 | ||||
-rw-r--r-- | win32/perllib.c | 4 | ||||
-rw-r--r-- | win32/win32.c | 335 | ||||
-rw-r--r-- | win32/win32.h | 11 | ||||
-rw-r--r-- | win32/win32iop.h | 4 | ||||
-rw-r--r-- | win32/win32sck.c | 2 | ||||
-rw-r--r-- | win32/win32thread.c | 29 | ||||
-rw-r--r-- | win32/win32thread.h | 45 |
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 @@ -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); @@ -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 */ @@ -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. @@ -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); @@ -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 @@ -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; +} @@ -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) |