This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
various tweaks for PERL_OBJECT build & test
[perl5.git] / win32 / win32.c
index aaf5139..7418fca 100644 (file)
 #include <tchar.h>
 #ifdef __GNUC__
 #define Win32_Winsock
+#  ifdef __cplusplus
+#undef __attribute__           /* seems broken in 2.8.0 */
+#define __attribute__(p)
+#  endif
 #endif
 #include <windows.h>
 
+#ifndef __MINGW32__
 #include <lmcons.h>
 #include <lmerr.h>
 /* ugliness to work around a buggy struct definition in lmwksta.h */
@@ -24,6 +29,8 @@
 #include <lmwksta.h>
 #undef LPTSTR
 #define LPTSTR LPSTR
+#include <lmapibuf.h>
+#endif /* __MINGW32__ */
 
 /* #include "config.h" */
 
 
 #include "EXTERN.h"
 #include "perl.h"
+
+#define NO_XSLOCKS
+#ifdef PERL_OBJECT
+extern CPerlObj* pPerl;
+#endif
 #include "XSUB.h"
+
+#include "Win32iop.h"
 #include <fcntl.h>
 #include <sys/stat.h>
 #ifndef __GNUC__
@@ -62,56 +76,54 @@ int _CRT_glob = 0;
 #define EXECF_SPAWN 2
 #define EXECF_SPAWN_NOWAIT 3
 
+#if defined(PERL_OBJECT)
+#undef win32_get_privlib
+#define win32_get_privlib g_win32_get_privlib
+#undef win32_get_sitelib
+#define win32_get_sitelib g_win32_get_sitelib
+#undef do_aspawn
+#define do_aspawn g_do_aspawn
+#undef do_spawn
+#define do_spawn g_do_spawn
+#undef do_exec
+#define do_exec g_do_exec
+#undef getlogin
+#define getlogin g_getlogin
+#endif
+
 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);
+       int             do_spawn2(char *cmd, int exectype);
 static BOOL            has_redirection(char *ptr);
 static long            filetime_to_clock(PFILETIME ft);
 static BOOL            filetime_from_time(PFILETIME ft, time_t t);
+static char *          get_emd_part(char *leading, char *trailing, ...);
+static void            remove_dead_process(HANDLE deceased);
 
-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
-
-#ifndef FOPEN_MAX
-#  ifdef _NSTREAM_
-#    define FOPEN_MAX _NSTREAM_
-#  elsif _NFILE_
-#    define FOPEN_MAX _NFILE_
-#  elsif _NFILE
-#    define FOPEN_MAX _NFILE
-#  endif
-#endif
-
-#ifndef USE_CRT_POPEN
-int    w32_popen_pids[FOPEN_MAX];
-#endif
+static DWORD   w32_platform = (DWORD)-1;
 
 #ifdef USE_THREADS
 #  ifdef USE_DECLSPEC_THREAD
 __declspec(thread) char        strerror_buffer[512];
 __declspec(thread) char        getlogin_buffer[128];
+__declspec(thread) char        w32_perllib_root[MAX_PATH+1];
 #    ifdef HAVE_DES_FCRYPT
 __declspec(thread) char        crypt_buffer[30];
 #    endif
 #  else
 #    define strerror_buffer    (thr->i.Wstrerror_buffer)
 #    define getlogin_buffer    (thr->i.Wgetlogin_buffer)
+#    define w32_perllib_root   (thr->i.Ww32_perllib_root)
 #    define crypt_buffer       (thr->i.Wcrypt_buffer)
 #  endif
 #else
-char   strerror_buffer[512];
-char   getlogin_buffer[128];
+static char    strerror_buffer[512];
+static char    getlogin_buffer[128];
+static char    w32_perllib_root[MAX_PATH+1];
 #  ifdef HAVE_DES_FCRYPT
-char   crypt_buffer[30];
+static char    crypt_buffer[30];
 #  endif
 #endif
 
@@ -125,29 +137,158 @@ IsWinNT(void) {
     return (os_id() == VER_PLATFORM_WIN32_NT);
 }
 
-char *
-win32_perllib_path(char *sfx,...)
+char*
+GetRegStrFromKey(HKEY hkey, const char *lpszValueName, char** ptr, DWORD* lpDataLen)
+{   /* Retrieve a REG_SZ or REG_EXPAND_SZ from the registry */
+    HKEY handle;
+    DWORD type;
+    const char *subkey = "Software\\Perl";
+    long retval;
+
+    retval = RegOpenKeyEx(hkey, subkey, 0, KEY_READ, &handle);
+    if (retval == ERROR_SUCCESS){
+       retval = RegQueryValueEx(handle, lpszValueName, 0, &type, NULL, lpDataLen);
+       if (retval == ERROR_SUCCESS && type == REG_SZ) {
+           if (*ptr != NULL) {
+               Renew(*ptr, *lpDataLen, char);
+           }
+           else {
+               New(1312, *ptr, *lpDataLen, char);
+           }
+           retval = RegQueryValueEx(handle, lpszValueName, 0, NULL, (PBYTE)*ptr, lpDataLen);
+           if (retval != ERROR_SUCCESS) {
+               Safefree(*ptr);
+               *ptr = NULL;
+           }
+       }
+       RegCloseKey(handle);
+    }
+    return *ptr;
+}
+
+char*
+GetRegStr(const char *lpszValueName, char** ptr, DWORD* lpDataLen)
+{
+    *ptr = GetRegStrFromKey(HKEY_CURRENT_USER, lpszValueName, ptr, lpDataLen);
+    if (*ptr == NULL)
+    {
+       *ptr = GetRegStrFromKey(HKEY_LOCAL_MACHINE, lpszValueName, ptr, lpDataLen);
+    }
+    return *ptr;
+}
+
+static char *
+get_emd_part(char *prev_path, char *trailing_path, ...)
 {
     va_list ap;
-    char *end;
-    va_start(ap,sfx);
-    GetModuleFileName((w32_perldll_handle == INVALID_HANDLE_VALUE) 
+    char mod_name[MAX_PATH+1];
+    char *ptr;
+    char *optr;
+    char *strip;
+    int oldsize, newsize;
+
+    va_start(ap, trailing_path);
+    strip = va_arg(ap, char *);
+
+    GetModuleFileName((w32_perldll_handle == INVALID_HANDLE_VALUE)
                      ? GetModuleHandle(NULL)
-                     : 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");
-    while (sfx)
-     {
-      strcat(end,"\\");
-      strcat(end,sfx);
-      sfx = va_arg(ap,char *);
-     }
-    va_end(ap); 
-    return (w32_perllib_root);
+                     : w32_perldll_handle, mod_name, sizeof(mod_name));
+    ptr = strrchr(mod_name, '\\');
+    while (ptr && strip) {
+        /* look for directories to skip back */
+       optr = ptr;
+       *ptr = '\0';
+       ptr = strrchr(mod_name, '\\');
+       if (!ptr || stricmp(ptr+1, strip) != 0) {
+           *optr = '\\';
+           ptr = optr;
+       }
+       strip = va_arg(ap, char *);
+    }
+    if (!ptr) {
+       ptr = mod_name;
+       *ptr++ = '.';
+       *ptr = '\\';
+    }
+    va_end(ap);
+    strcpy(++ptr, trailing_path);
+
+    newsize = strlen(mod_name) + 1;
+    if (prev_path) {
+       oldsize = strlen(prev_path) + 1;
+       newsize += oldsize;                     /* includes plus 1 for ';' */
+       Renew(prev_path, newsize, char);
+       prev_path[oldsize] = ';';
+       strcpy(&prev_path[oldsize], mod_name);
+    }
+    else {
+       New(1311, prev_path, newsize, char);
+       strcpy(prev_path, mod_name);
+    }
+
+    return prev_path;
+}
+
+char *
+win32_get_privlib(char *pl)
+{
+    char *stdlib = "lib";
+    char buffer[MAX_PATH+1];
+    char *path = Nullch;
+    DWORD datalen;
+
+    /* $stdlib = $HKCU{"lib-$]"} || $HKLM{"lib-$]"} || $HKCU{"lib"} || $HKLM{"lib"} || "";  */
+    sprintf(buffer, "%s-%s", stdlib, pl);
+    path = GetRegStr(buffer, &path, &datalen);
+    if (path == NULL)
+       path = GetRegStr(stdlib, &path, &datalen);
+
+    /* $stdlib .= ";$EMD/../../lib" */
+    return get_emd_part(path, stdlib, ARCHNAME, "bin", Nullch);
+}
+
+char *
+win32_get_sitelib(char *pl)
+{
+    char *sitelib = "sitelib";
+    char regstr[40];
+    char pathstr[MAX_PATH+1];
+    DWORD datalen;
+    char *path1 = Nullch;
+    char *path2 = Nullch;
+    int len, newsize;
+
+    /* $HKCU{"sitelib-$]"} || $HKLM{"sitelib-$]"} . ---; */
+    sprintf(regstr, "%s-%s", sitelib, pl);
+    path1 = GetRegStr(regstr, &path1, &datalen);
+
+    /* $sitelib .=
+     * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/site/$]/lib";  */
+    sprintf(pathstr, "site\\%s\\lib", pl);
+    path1 = get_emd_part(path1, pathstr, ARCHNAME, "bin", pl, Nullch);
+
+    /* $HKCU{'sitelib'} || $HKLM{'sitelib'} . ---; */
+    path2 = GetRegStr(sitelib, &path2, &datalen);
+
+    /* $sitelib .=
+     * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/site/lib";  */
+    path2 = get_emd_part(path2, "site\\lib", ARCHNAME, "bin", pl, Nullch);
+
+    if (!path1)
+       return path2;
+
+    if (!path2)
+       return path1;
+
+    len = strlen(path1);
+    newsize = len + strlen(path2) + 2; /* plus one for ';' */
+
+    Renew(path1, newsize, char);
+    path1[len++] = ';';
+    strcpy(&path1[len], path2);
+
+    Safefree(path2);
+    return path1;
 }
 
 
@@ -189,6 +330,7 @@ has_redirection(char *ptr)
     return FALSE;
 }
 
+#if !defined(PERL_OBJECT)
 /* since the current process environment is being updated in util.c
  * the library functions will get the correct environment
  */
@@ -221,6 +363,7 @@ my_pclose(PerlIO *fp)
 {
     return win32_pclose(fp);
 }
+#endif
 
 static DWORD
 os_id(void)
@@ -339,7 +482,7 @@ do_aspawn(void *vreally, void **vmark, void **vsp)
     argv[index++] = 0;
    
     status = win32_spawnvp(flag,
-                          (really ? SvPV(really,na) : argv[0]),
+                          (const char*)(really ? SvPV(really,na) : argv[0]),
                           (const char* const*)argv);
 
     if (status < 0 && errno == ENOEXEC) {
@@ -352,7 +495,7 @@ do_aspawn(void *vreally, void **vmark, void **vsp)
            argv[sh_items] = w32_perlshell_vec[sh_items];
    
        status = win32_spawnvp(flag,
-                              (really ? SvPV(really,na) : argv[0]),
+                              (const char*)(really ? SvPV(really,na) : argv[0]),
                               (const char* const*)argv);
     }
 
@@ -370,7 +513,7 @@ do_aspawn(void *vreally, void **vmark, void **vsp)
     return (status);
 }
 
-static int
+int
 do_spawn2(char *cmd, int exectype)
 {
     char **a;
@@ -482,7 +625,7 @@ do_exec(char *cmd)
  * return the pointer to the current file name.
  */
 DIR *
-opendir(char *filename)
+win32_opendir(char *filename)
 {
     DIR                        *p;
     long               len;
@@ -560,7 +703,7 @@ opendir(char *filename)
  * string pointer to the nDllExport entry.
  */
 struct direct *
-readdir(DIR *dirp)
+win32_readdir(DIR *dirp)
 {
     int         len;
     static int  dummy = 0;
@@ -588,7 +731,7 @@ readdir(DIR *dirp)
 
 /* Telldir returns the current string pointer position */
 long
-telldir(DIR *dirp)
+win32_telldir(DIR *dirp)
 {
     return (long) dirp->curr;
 }
@@ -598,21 +741,21 @@ telldir(DIR *dirp)
  *(Saved by telldir).
  */
 void
-seekdir(DIR *dirp, long loc)
+win32_seekdir(DIR *dirp, long loc)
 {
     dirp->curr = (char *)loc;
 }
 
 /* Rewinddir resets the string pointer to the start */
 void
-rewinddir(DIR *dirp)
+win32_rewinddir(DIR *dirp)
 {
     dirp->curr = dirp->start;
 }
 
 /* free the memory allocated by opendir */
 int
-closedir(DIR *dirp)
+win32_closedir(DIR *dirp)
 {
     Safefree(dirp->start);
     Safefree(dirp);
@@ -688,10 +831,30 @@ chown(const char *path, uid_t owner, gid_t group)
     return 0;
 }
 
-int
-kill(int pid, int sig)
+static void
+remove_dead_process(HANDLE deceased)
+{
+#ifndef USE_RTL_WAIT
+    int child;
+    for (child = 0 ; child < w32_num_children ; ++child) {
+       if (w32_child_pids[child] == deceased) {
+           Copy(&w32_child_pids[child+1], &w32_child_pids[child],
+                (w32_num_children-child-1), HANDLE);
+           w32_num_children--;
+           break;
+       }
+    }
+#endif
+}
+
+DllExport int
+win32_kill(int pid, int sig)
 {
+#ifdef USE_RTL_WAIT
     HANDLE hProcess= OpenProcess(PROCESS_ALL_ACCESS, TRUE, pid);
+#else
+    HANDLE hProcess = (HANDLE) pid;
+#endif
 
     if (hProcess == NULL) {
        croak("kill process failed!\n");
@@ -700,10 +863,14 @@ kill(int pid, int sig)
        if (!TerminateProcess(hProcess, sig))
            croak("kill process failed!\n");
        CloseHandle(hProcess);
+
+       /* WaitForMultipleObjects() on a pid that was killed returns error
+        * so if we know the pid is gone we remove it from process list */
+       remove_dead_process(hProcess);
     }
     return 0;
 }
-      
+
 /*
  * File system stuff
  */
@@ -718,7 +885,7 @@ win32_sleep(unsigned int t)
 DllExport int
 win32_stat(const char *path, struct stat *buffer)
 {
-    char               t[MAX_PATH]; 
+    char               t[MAX_PATH+1]; 
     const char *p = path;
     int                l = strlen(path);
     int                res;
@@ -768,13 +935,34 @@ win32_getenv(const char *name)
     DWORD needlen;
     if (!curitem)
        New(1305,curitem,curlen,char);
-    if (!(needlen = GetEnvironmentVariable(name,curitem,curlen)))
-       return Nullch;
-    while (needlen > curlen) {
-       Renew(curitem,needlen,char);
-       curlen = needlen;
-       needlen = GetEnvironmentVariable(name,curitem,curlen);
+
+    needlen = GetEnvironmentVariable(name,curitem,curlen);
+    if (needlen != 0) {
+       while (needlen > curlen) {
+           Renew(curitem,needlen,char);
+           curlen = needlen;
+           needlen = GetEnvironmentVariable(name,curitem,curlen);
+       }
+    }
+    else
+    {
+       /* allow any environment variables that begin with 'PERL5'
+          to be stored in the registry
+       */
+       if(curitem != NULL)
+           *curitem = '\0';
+
+       if (strncmp(name, "PERL5", 5) == 0) {
+           if (curitem != NULL) {
+               Safefree(curitem);
+               curitem = NULL;
+           }
+           curitem = GetRegStr(name, &curitem, &curlen);
+       }
     }
+    if(curitem != NULL && *curitem == '\0')
+       return Nullch;
+
     return curitem;
 }
 
@@ -877,9 +1065,27 @@ win32_utime(const char *filename, struct utimbuf *times)
 }
 
 DllExport int
-win32_wait(int *status)
+win32_waitpid(int pid, int *status, int flags)
 {
+    int rc;
+    if (pid == -1) 
+      return win32_wait(status);
+    else {
+      rc = cwait(status, pid, WAIT_CHILD);
+    /* cwait() returns differently on Borland */
 #ifdef __BORLANDC__
+    if (status)
+       *status =  (((*status >> 8) & 0xff) | ((*status << 8) & 0xff00));
+#endif
+      remove_dead_process((HANDLE)pid);
+    }
+    return rc >= 0 ? pid : rc;                
+}
+
+DllExport int
+win32_wait(int *status)
+{
+#ifdef USE_RTL_WAIT
     return wait(status);
 #else
     /* XXX this wait emulation only knows about processes
@@ -1213,7 +1419,7 @@ win32_str_os_error(void *sv, DWORD dwErr)
        sMsg[dwLen]= '\0';
     }
     if (0 == dwLen) {
-       sMsg = LocalAlloc(0, 64/**sizeof(TCHAR)*/);
+       sMsg = (char*)LocalAlloc(0, 64/**sizeof(TCHAR)*/);
        dwLen = sprintf(sMsg,
                        "Unknown error #0x%lX (lookup 0x%lX)",
                        dwErr, GetLastError());
@@ -1404,7 +1610,7 @@ win32_pipe(int *pfd, unsigned int size, int mode)
 DllExport FILE*
 win32_popen(const char *command, const char *mode)
 {
-#ifdef USE_CRT_POPEN
+#ifdef USE_RTL_POPEN
     return _popen(command, mode);
 #else
     int p[2];
@@ -1464,7 +1670,7 @@ win32_popen(const char *command, const char *mode)
     /* close saved handle */
     win32_close(oldfd);
 
-    w32_popen_pids[p[parent]] = childpid;
+    sv_setiv(*av_fetch(w32_fdpid, p[parent], TRUE), childpid);
 
     /* we have an fd, return a file stream */
     return (win32_fdopen(p[parent], (char *)mode));
@@ -1479,7 +1685,7 @@ cleanup:
     }
     return (NULL);
 
-#endif /* USE_CRT_POPEN */
+#endif /* USE_RTL_POPEN */
 }
 
 /*
@@ -1489,13 +1695,18 @@ cleanup:
 DllExport int
 win32_pclose(FILE *pf)
 {
-#ifdef USE_CRT_POPEN
+#ifdef USE_RTL_POPEN
     return _pclose(pf);
 #else
-    int fd, childpid, status;
 
-    fd = win32_fileno(pf);
-    childpid = w32_popen_pids[fd];
+    int childpid, status;
+    SV *sv;
+
+    sv = *av_fetch(w32_fdpid, win32_fileno(pf), TRUE);
+    if (SvIOK(sv))
+       childpid = SvIVX(sv);
+    else
+       childpid = 0;
 
     if (!childpid) {
        errno = EBADF;
@@ -1503,7 +1714,9 @@ win32_pclose(FILE *pf)
     }
 
     win32_fclose(pf);
-    w32_popen_pids[fd] = 0;
+    SvIVX(sv) = 0;
+
+    remove_dead_process((HANDLE)childpid);
 
     /* wait for the child */
     if (cwait(&status, childpid, WAIT_CHILD) == -1)
@@ -1515,7 +1728,57 @@ win32_pclose(FILE *pf)
     return (status);
 #endif
 
-#endif /* USE_CRT_OPEN */
+#endif /* USE_RTL_POPEN */
+}
+
+DllExport int
+win32_rename(const char *oname, const char *newname)
+{
+    char szNewWorkName[MAX_PATH+1];
+    WIN32_FIND_DATA fdOldFile, fdNewFile;
+    HANDLE handle;
+    char *ptr;
+
+    if ((strchr(oname, '\\') || strchr(oname, '/'))
+       && strchr(newname, '\\') == NULL
+       && strchr(newname, '/') == NULL)
+    {
+       strcpy(szNewWorkName, oname);
+       if ((ptr = strrchr(szNewWorkName, '\\')) == NULL)
+           ptr = strrchr(szNewWorkName, '/');
+       strcpy(++ptr, newname);
+    }
+    else
+       strcpy(szNewWorkName, newname);
+
+    if (stricmp(oname, szNewWorkName) != 0) {
+       // check that we're not being fooled by relative paths
+       // and only delete the new file
+       //  1) if it exists
+       //  2) it is not the same file as the old file
+       //  3) old file exist
+       // GetFullPathName does not return the long file name on some systems
+       handle = FindFirstFile(oname, &fdOldFile);
+       if (handle != INVALID_HANDLE_VALUE) {
+           FindClose(handle);
+    
+           handle = FindFirstFile(szNewWorkName, &fdNewFile);
+    
+           if (handle != INVALID_HANDLE_VALUE)
+               FindClose(handle);
+           else
+               fdNewFile.cFileName[0] = '\0';
+
+           if (strcmp(fdOldFile.cAlternateFileName,
+                      fdNewFile.cAlternateFileName) != 0
+               && strcmp(fdOldFile.cFileName, fdNewFile.cFileName) != 0)
+           {
+               // file exists and not same file
+               DeleteFile(szNewWorkName);
+           }
+       }
+    }
+    return rename(oname, newname);
 }
 
 DllExport int
@@ -1610,8 +1873,13 @@ win32_spawnvp(int mode, const char *cmdname, const char *const *argv)
 {
     int status;
 
+#ifndef USE_RTL_WAIT
+    if (mode == P_NOWAIT && w32_num_children >= MAXIMUM_WAIT_OBJECTS)
+       return -1;
+#endif
+
     status = spawnvp(mode, cmdname, (char * const *) argv);
-#ifndef __BORLANDC__
+#ifndef USE_RTL_WAIT
     /* 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.
@@ -1623,6 +1891,12 @@ win32_spawnvp(int mode, const char *cmdname, const char *const *argv)
 }
 
 DllExport int
+win32_execv(const char *cmdname, const char *const *argv)
+{
+    return execv(cmdname, (char *const *)argv);
+}
+
+DllExport int
 win32_execvp(const char *cmdname, const char *const *argv)
 {
     return execvp(cmdname, (char *const *)argv);
@@ -1910,8 +2184,8 @@ static
 XS(w32_DomainName)
 {
     dXSARGS;
-#if 0
-    /* doesn't do the right thing if current user is a local account */
+#ifndef HAS_NETWKSTAGETINFO
+    /* mingw32 (and Win95) don't have NetWksta*(), so do it the old way */
     char name[256];
     DWORD size = sizeof(name);
     if (GetUserName(name,&size)) {
@@ -1926,12 +2200,22 @@ XS(w32_DomainName)
        }
     }
 #else
+    /* this way is more reliable, in case user has a local account.
+     * XXX need dynamic binding of netapi32.dll symbols or this will fail on
+     * Win95. Probably makes more sense to move it into libwin32. */
     char dname[256];
     DWORD dnamelen = sizeof(dname);
-    WKSTA_INFO_100 wi;
-    if (NERR_Success == NetWkstaGetInfo(NULL, 100, (LPBYTE*)&wi)) {
-       WideCharToMultiByte(CP_ACP, NULL, wi.wki100_langroup, -1,
-                           (LPSTR)dname, dnamelen, NULL, NULL);
+    PWKSTA_INFO_100 pwi;
+    if (NERR_Success == NetWkstaGetInfo(NULL, 100, (LPBYTE*)&pwi)) {
+       if (pwi->wki100_langroup && *(pwi->wki100_langroup)) {
+           WideCharToMultiByte(CP_ACP, NULL, pwi->wki100_langroup,
+                               -1, (LPSTR)dname, dnamelen, NULL, NULL);
+       }
+       else {
+           WideCharToMultiByte(CP_ACP, NULL, pwi->wki100_computername,
+                               -1, (LPSTR)dname, dnamelen, NULL, NULL);
+       }
+       NetApiBufferFree(pwi);
        XSRETURN_PV(dname);
     }
 #endif
@@ -2098,6 +2382,13 @@ Perl_init_os_extras()
     char *file = __FILE__;
     dXSUB_SYS;
 
+    w32_perlshell_tokens = Nullch;
+    w32_perlshell_items = -1;
+    w32_fdpid = newAV();               /* XXX needs to be in Perl_win32_init()? */
+#ifndef USE_RTL_WAIT
+    w32_num_children = 0;
+#endif
+
     /* these names are Activeware compatible */
     newXS("Win32::GetCwd", w32_GetCwd, file);
     newXS("Win32::SetCwd", w32_SetCwd, file);
@@ -2140,7 +2431,7 @@ Perl_win32_init(int *argcp, char ***argvp)
 #if !defined(_ALPHA_) && !defined(__GNUC__)
     _control87(MCW_EM, MCW_EM);
 #endif
-    MALLOC_INIT; 
+    MALLOC_INIT;
 }
 
 #ifdef USE_BINMODE_SCRIPTS