applied patch, with indentation tweaks
[p5sagit/p5-mst-13.2.git] / win32 / win32.c
index 7733c05..b22ec8a 100644 (file)
 #endif
 #include <windows.h>
 
+#ifndef __MINGW32__
+#include <lmcons.h>
+#include <lmerr.h>
+/* ugliness to work around a buggy struct definition in lmwksta.h */
+#undef LPTSTR
+#define LPTSTR LPWSTR
+#include <lmwksta.h>
+#undef LPTSTR
+#define LPTSTR LPSTR
+#include <lmapibuf.h>
+#endif /* __MINGW32__ */
+
 /* #include "config.h" */
 
 #define PERLIO_NOT_STDIO 0 
@@ -65,8 +77,8 @@ int _CRT_glob = 0;
 #define EXECF_SPAWN_NOWAIT 3
 
 #if defined(PERL_OBJECT)
-#undef win32_get_stdlib
-#define win32_get_stdlib g_win32_get_stdlib
+#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
@@ -98,50 +110,31 @@ static long                tokenize(char *str, char **dest, char ***destv);
 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, ...);
 
-
-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
 
@@ -164,19 +157,19 @@ GetRegStrFromKey(HKEY hkey, const char *lpszValueName, char** ptr, DWORD* lpData
     long retval;
 
     retval = RegOpenKeyEx(hkey, subkey, 0, KEY_READ, &handle);
-    if(retval == ERROR_SUCCESS){
+    if (retval == ERROR_SUCCESS){
        retval = RegQueryValueEx(handle, lpszValueName, 0, &type, NULL, lpDataLen);
-       if(retval == ERROR_SUCCESS && type == REG_SZ) {
-           if(*ptr != NULL) {
+       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;
+           if (retval != ERROR_SUCCESS) {
+               Safefree(*ptr);
+               *ptr = NULL;
            }
        }
        RegCloseKey(handle);
@@ -188,180 +181,123 @@ char*
 GetRegStr(const char *lpszValueName, char** ptr, DWORD* lpDataLen)
 {
     *ptr = GetRegStrFromKey(HKEY_CURRENT_USER, lpszValueName, ptr, lpDataLen);
-    if(*ptr == NULL)
+    if (*ptr == NULL)
     {
        *ptr = GetRegStrFromKey(HKEY_LOCAL_MACHINE, lpszValueName, ptr, lpDataLen);
     }
     return *ptr;
 }
 
-char *
-win32_get_stdlib(char *pl)
-{
-    static char szStdLib[] = "lib";
-    int len = 0, newSize;
-    char szBuffer[MAX_PATH+1];
-    char szModuleName[MAX_PATH];
-    int result;
-    DWORD dwDataLen;
-    char *lpPath = NULL;
+static char *
+get_emd_part(char *prev_path, char *trailing_path, ...)
+{
+    va_list ap;
+    char mod_name[MAX_PATH];
     char *ptr;
-
-    /* $stdlib = $HKCU{"lib-$]"} || $HKLM{"lib-$]"} || $HKCU{"lib"} || $HKLM{"lib"} || "";  */
-    sprintf(szBuffer, "%s-%s", szStdLib, pl);
-    lpPath = GetRegStr(szBuffer, &lpPath, &dwDataLen);
-    if(lpPath == NULL)
-       lpPath = GetRegStr(szStdLib, &lpPath, &dwDataLen);
-
-    /* $stdlib .= ";$EMD/../../lib" */
-    GetModuleFileName(GetModuleHandle(NULL), szModuleName, sizeof(szModuleName));
-    ptr = strrchr(szModuleName, '\\');
-    if(ptr != NULL)
-    {
+    char *optr;
+    char *strip;
+    int oldsize, newsize;
+
+    va_start(ap, trailing_path);
+    strip = va_arg(ap, char *);
+
+    GetModuleFileName(GetModuleHandle(NULL), mod_name, sizeof(mod_name));
+    ptr = strrchr(mod_name, '\\');
+    while (ptr && strip) {
+        /* look for directories to skip back */
+       optr = ptr;
        *ptr = '\0';
-       ptr = strrchr(szModuleName, '\\');
-       if(ptr != NULL)
-       {
-           *ptr = '\0';
-           ptr = strrchr(szModuleName, '\\');
+       ptr = strrchr(mod_name, '\\');
+       if (!ptr || stricmp(ptr+1, strip) != 0) {
+           *optr = '\\';
+           ptr = optr;
        }
+       strip = va_arg(ap, char *);
     }
-    if(ptr == NULL)
-    {
-       ptr = szModuleName;
+    if (!ptr) {
+       ptr = mod_name;
+       *ptr++ = '.';
        *ptr = '\\';
     }
-    strcpy(++ptr, szStdLib);
+    va_end(ap);
+    strcpy(++ptr, trailing_path);
 
-    /* check that this path exists */
-    GetCurrentDirectory(sizeof(szBuffer), szBuffer);
-    result = SetCurrentDirectory(szModuleName);
-    SetCurrentDirectory(szBuffer);
-    if(result == 0)
-    {
-       GetModuleFileName(GetModuleHandle(NULL), szModuleName, sizeof(szModuleName));
-       ptr = strrchr(szModuleName, '\\');
-       if(ptr != NULL)
-           strcpy(++ptr, szStdLib);
+    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);
     }
-
-    newSize = strlen(szModuleName) + 1;
-    if(lpPath != NULL)
-    {
-       len = strlen(lpPath);
-       newSize += len + 1; /* plus 1 for ';' */
-       lpPath = Renew(lpPath, newSize, char);
+    else {
+       New(1311, prev_path, newsize, char);
+       strcpy(prev_path, mod_name);
     }
-    else
-       New(1310, lpPath, newSize, char);
 
-    if(lpPath != NULL)
-    {
-       if(len != 0)
-           lpPath[len++] = ';';
-       strcpy(&lpPath[len], szModuleName);
-    }
-    return lpPath;
+    return prev_path;
 }
 
 char *
-get_sitelib_part(char* lpRegStr, char* lpPathStr)
-{
-    char szBuffer[MAX_PATH+1];
-    char szModuleName[MAX_PATH];
-    DWORD dwDataLen;
-    int len = 0;
-    int result;
-    char *lpPath = NULL;
-    char *ptr;
-
-    lpPath = GetRegStr(lpRegStr, &lpPath, &dwDataLen);
-
-    /* $sitelib .= ";$EMD/../../../<lpPathStr>" */
-    GetModuleFileName(GetModuleHandle(NULL), szModuleName, sizeof(szModuleName));
-    ptr = strrchr(szModuleName, '\\');
-    if(ptr != NULL)
-    {
-       *ptr = '\0';
-       ptr = strrchr(szModuleName, '\\');
-       if(ptr != NULL)
-       {
-           *ptr = '\0';
-           ptr = strrchr(szModuleName, '\\');
-           if(ptr != NULL)
-           {
-               *ptr = '\0';
-               ptr = strrchr(szModuleName, '\\');
-           }
-       }
-    }
-    if(ptr == NULL)
-    {
-       ptr = szModuleName;
-       *ptr = '\\';
-    }
-    strcpy(++ptr, lpPathStr);
-
-    /* check that this path exists */
-    GetCurrentDirectory(sizeof(szBuffer), szBuffer);
-    result = SetCurrentDirectory(szModuleName);
-    SetCurrentDirectory(szBuffer);
+win32_get_privlib(char *pl)
+{
+    char *stdlib = "lib";
+    char buffer[MAX_PATH+1];
+    char *path = Nullch;
+    DWORD datalen;
 
-    if(result)
-    {
-       int newSize = strlen(szModuleName) + 1;
-       if(lpPath != NULL)
-       {
-           len = strlen(lpPath);
-           newSize += len + 1; /* plus 1 for ';' */
-           lpPath = Renew(lpPath, newSize, char);
-       }
-       else
-           New(1311, lpPath, newSize, char);
+    /* $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);
 
-       if(lpPath != NULL)
-       {
-           if(len != 0)
-               lpPath[len++] = ';';
-           strcpy(&lpPath[len], szModuleName);
-       }
-    }
-    return lpPath;
+    /* $stdlib .= ";$EMD/../../lib" */
+    return get_emd_part(path, stdlib, ARCHNAME, "bin", Nullch);
 }
 
 char *
 win32_get_sitelib(char *pl)
 {
-    static char szSiteLib[] = "sitelib";
-    char szRegStr[40];
-    char szPathStr[MAX_PATH];
-    char *lpPath1;
-    char *lpPath2;
+    char *sitelib = "sitelib";
+    char regstr[40];
+    char pathstr[MAX_PATH];
+    DWORD datalen;
+    char *path1 = Nullch;
+    char *path2 = Nullch;
+    int len, newsize;
 
     /* $HKCU{"sitelib-$]"} || $HKLM{"sitelib-$]"} . ---; */
-    sprintf(szRegStr, "%s-%s", szSiteLib, pl);
-    sprintf(szPathStr, "site\\%s\\lib", pl);
-    lpPath1 = get_sitelib_part(szRegStr, szPathStr);
+    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'} . ---; */
-    lpPath2 = get_sitelib_part(szSiteLib, "site\\lib");
-    if(lpPath1 == NULL)
-       return lpPath2;
+    path2 = GetRegStr(sitelib, &path2, &datalen);
 
-    if(lpPath2 == NULL)
-       return lpPath1;
+    /* $sitelib .=
+     * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/site/lib";  */
+    path2 = get_emd_part(path2, "site\\lib", ARCHNAME, "bin", pl, Nullch);
 
-    int len = strlen(lpPath1);
-    int newSize = len + strlen(lpPath2) + 2; /* plus one for ';' */
+    if (!path1)
+       return path2;
 
-    lpPath1 = Renew(lpPath1, newSize, char);
-    if(lpPath1 != NULL)
-    {
-       lpPath1[len++] = ';';
-       strcpy(&lpPath1[len], lpPath2);
-    }
-    Safefree(lpPath2);
-    return lpPath1;
+    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;
 }
 
 
@@ -375,12 +311,12 @@ has_redirection(char *ptr)
      * Scan string looking for redirection (< or >) or pipe
      * characters (|) that are not in a quoted string
      */
-    while(*ptr) {
+    while (*ptr) {
        switch(*ptr) {
        case '\'':
        case '\"':
-           if(inquote) {
-               if(quote == *ptr) {
+           if (inquote) {
+               if (quote == *ptr) {
                    inquote = 0;
                    quote = '\0';
                }
@@ -393,7 +329,7 @@ has_redirection(char *ptr)
        case '>':
        case '<':
        case '|':
-           if(!inquote)
+           if (!inquote)
                return TRUE;
        default:
            break;
@@ -546,7 +482,7 @@ do_aspawn(void *vreally, void **vmark, void **vsp)
        flag = SvIVx(*mark);
     }
 
-    while(++mark <= sp) {
+    while (++mark <= sp) {
        if (*mark && (str = SvPV(*mark, na)))
            argv[index++] = str;
        else
@@ -598,7 +534,7 @@ do_spawn2(char *cmd, int exectype)
 
     /* Save an extra exec if possible. See if there are shell
      * metacharacters in it */
-    if(!has_redirection(cmd)) {
+    if (!has_redirection(cmd)) {
        New(1301,argv, strlen(cmd) / 2 + 2, char*);
        New(1302,cmd2, strlen(cmd) + 1, char);
        strcpy(cmd2, cmd);
@@ -608,9 +544,9 @@ do_spawn2(char *cmd, int exectype)
                s++;
            if (*s)
                *(a++) = s;
-           while(*s && !isspace(*s))
+           while (*s && !isspace(*s))
                s++;
-           if(*s)
+           if (*s)
                *s++ = '\0';
        }
        *a = Nullch;
@@ -693,9 +629,6 @@ do_exec(char *cmd)
     return FALSE;
 }
 
-
-#define PATHLEN 1024
-
 /* The idea here is to read all the directory names into a string table
  * (separated by nulls) and when one of the other dir functions is called
  * return the pointer to the current file name.
@@ -703,19 +636,17 @@ do_exec(char *cmd)
 DIR *
 opendir(char *filename)
 {
-    DIR            *p;
-    long            len;
-    long            idx;
-    char            scannamespc[PATHLEN];
-    char       *scanname = scannamespc;
-    struct stat     sbuf;
-    WIN32_FIND_DATA FindData;
-    HANDLE          fh;
-/*  char            root[_MAX_PATH];*/
-/*  char            volname[_MAX_PATH];*/
-/*  DWORD           serial, maxname, flags;*/
-/*  BOOL            downcase;*/
-/*  char           *dummy;*/
+    DIR                        *p;
+    long               len;
+    long               idx;
+    char               scanname[MAX_PATH+3];
+    struct stat                sbuf;
+    WIN32_FIND_DATA    FindData;
+    HANDLE             fh;
+
+    len = strlen(filename);
+    if (len > MAX_PATH)
+       return NULL;
 
     /* check to see if filename is a directory */
     if (win32_stat(filename, &sbuf) < 0 || (sbuf.st_mode & S_IFDIR) == 0) {
@@ -725,35 +656,21 @@ opendir(char *filename)
            return NULL;
     }
 
-    /* get the file system characteristics */
-/*  if(GetFullPathName(filename, MAX_PATH, root, &dummy)) {
- *     if(dummy = strchr(root, '\\'))
- *         *++dummy = '\0';
- *     if(GetVolumeInformation(root, volname, MAX_PATH, &serial,
- *                             &maxname, &flags, 0, 0)) {
- *         downcase = !(flags & FS_CASE_IS_PRESERVED);
- *     }
- *  }
- *  else {
- *     downcase = TRUE;
- *  }
- */
     /* Get us a DIR structure */
     Newz(1303, p, 1, DIR);
-    if(p == NULL)
+    if (p == NULL)
        return NULL;
 
     /* Create the search pattern */
     strcpy(scanname, filename);
-
-    if(index("/\\", *(scanname + strlen(scanname) - 1)) == NULL)
-       strcat(scanname, "/*");
-    else
-       strcat(scanname, "*");
+    if (scanname[len-1] != '/' && scanname[len-1] != '\\')
+       scanname[len++] = '/';
+    scanname[len++] = '*';
+    scanname[len] = '\0';
 
     /* do the FindFirstFile call */
     fh = FindFirstFile(scanname, &FindData);
-    if(fh == INVALID_HANDLE_VALUE) {
+    if (fh == INVALID_HANDLE_VALUE) {
        return NULL;
     }
 
@@ -762,13 +679,9 @@ opendir(char *filename)
      */
     idx = strlen(FindData.cFileName)+1;
     New(1304, p->start, idx, char);
-    if(p->start == NULL) {
+    if (p->start == NULL)
        croak("opendir: malloc failed!\n");
-    }
     strcpy(p->start, FindData.cFileName);
-/*  if(downcase)
- *     strlwr(p->start);
- */
     p->nfiles++;
 
     /* loop finding all the files that match the wildcard
@@ -782,20 +695,16 @@ opendir(char *filename)
         * new name and it's null terminator
         */
        Renew(p->start, idx+len+1, char);
-       if(p->start == NULL) {
+       if (p->start == NULL)
            croak("opendir: malloc failed!\n");
-       }
        strcpy(&p->start[idx], FindData.cFileName);
-/*     if (downcase) 
- *         strlwr(&p->start[idx]);
- */
-               p->nfiles++;
-               idx += len+1;
-       }
-       FindClose(fh);
-       p->size = idx;
-       p->curr = p->start;
-       return p;
+       p->nfiles++;
+       idx += len+1;
+    }
+    FindClose(fh);
+    p->size = idx;
+    p->curr = p->start;
+    return p;
 }
 
 
@@ -1011,18 +920,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);
+       }
     }
-    if(curitem == NULL)
+    else
     {
-       if(strcmp("PERL5DB", name) == 0)
+       /* 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;
 }
 
@@ -1127,7 +1052,7 @@ win32_utime(const char *filename, struct utimbuf *times)
 DllExport int
 win32_wait(int *status)
 {
-#ifdef __BORLANDC__
+#ifdef USE_RTL_WAIT
     return wait(status);
 #else
     /* XXX this wait emulation only knows about processes
@@ -1288,14 +1213,14 @@ my_open_osfhandle(long osfhandle, int flags)
     /* copy relevant flags from second parameter */
     fileflags = FDEV;
 
-    if(flags & O_APPEND)
+    if (flags & O_APPEND)
        fileflags |= FAPPEND;
 
-    if(flags & O_TEXT)
+    if (flags & O_TEXT)
        fileflags |= FTEXT;
 
     /* attempt to allocate a C Runtime file handle */
-    if((fh = _alloc_osfhnd()) == -1) {
+    if ((fh = _alloc_osfhnd()) == -1) {
        errno = EMFILE;         /* too many open files */
        _doserrno = 0L;         /* not an OS error */
        return -1;              /* return error to caller */
@@ -1430,12 +1355,12 @@ win32_strerror(int e)
 #endif
     DWORD source = 0;
 
-    if(e < 0 || e > sys_nerr) {
+    if (e < 0 || e > sys_nerr) {
         dTHR;
-       if(e < 0)
+       if (e < 0)
            e = GetLastError();
 
-       if(FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, &source, e, 0,
+       if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, &source, e, 0,
                         strerror_buffer, sizeof(strerror_buffer), NULL) == 0) 
            strcpy(strerror_buffer, "Unknown Error");
 
@@ -1652,7 +1577,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];
@@ -1712,7 +1637,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));
@@ -1727,7 +1652,7 @@ cleanup:
     }
     return (NULL);
 
-#endif /* USE_CRT_POPEN */
+#endif /* USE_RTL_POPEN */
 }
 
 /*
@@ -1737,13 +1662,22 @@ 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];
+#ifndef USE_RTL_WAIT
+    int child;
+#endif
+
+    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;
@@ -1751,7 +1685,18 @@ win32_pclose(FILE *pf)
     }
 
     win32_fclose(pf);
-    w32_popen_pids[fd] = 0;
+    SvIVX(sv) = 0;
+
+#ifndef USE_RTL_WAIT
+    for (child = 0 ; child < w32_num_children ; ++child) {
+       if (w32_child_pids[child] == (HANDLE)childpid) {
+           Copy(&w32_child_pids[child+1], &w32_child_pids[child],
+                (w32_num_children-child-1), HANDLE);
+           w32_num_children--;
+           break;
+       }
+    }
+#endif
 
     /* wait for the child */
     if (cwait(&status, childpid, WAIT_CHILD) == -1)
@@ -1763,7 +1708,7 @@ win32_pclose(FILE *pf)
     return (status);
 #endif
 
-#endif /* USE_CRT_OPEN */
+#endif /* USE_RTL_POPEN */
 }
 
 DllExport int
@@ -1858,8 +1803,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.
@@ -2158,6 +2108,8 @@ static
 XS(w32_DomainName)
 {
     dXSARGS;
+#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)) {
@@ -2166,11 +2118,31 @@ XS(w32_DomainName)
        char dname[256];
        DWORD dnamelen = sizeof(dname);
        SID_NAME_USE snu;
-       if (LookupAccountName(NULL, name, (PSID)&sid, &sidlen,
+       if (LookupAccountName(NULL, name, &sid, &sidlen,
                              dname, &dnamelen, &snu)) {
            XSRETURN_PV(dname);         /* all that for this */
        }
     }
+#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);
+    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
     XSRETURN_UNDEF;
 }
 
@@ -2254,7 +2226,7 @@ XS(w32_Spawn)
     STARTUPINFO stStartInfo;
     BOOL bSuccess = FALSE;
 
-    if(items != 3)
+    if (items != 3)
        croak("usage: Win32::Spawn($cmdName, $args, $PID)");
 
     cmd = SvPV(ST(0),na);
@@ -2265,7 +2237,7 @@ XS(w32_Spawn)
     stStartInfo.dwFlags = STARTF_USESHOWWINDOW;            /* Enable wShowWindow control */
     stStartInfo.wShowWindow = SW_SHOWMINNOACTIVE;   /* Start min (normal) */
 
-    if(CreateProcess(
+    if (CreateProcess(
                cmd,                    /* Image path */
                args,                   /* Arguments for command line */
                NULL,                   /* Default process security */
@@ -2298,7 +2270,7 @@ XS(w32_GetShortPathName)
     SV *shortpath;
     DWORD len;
 
-    if(items != 1)
+    if (items != 1)
        croak("usage: Win32::GetShortPathName($longPathName)");
 
     shortpath = sv_mortalcopy(ST(0));
@@ -2362,7 +2334,7 @@ XS(w32_RegCloseKey)
 {
     dXSARGS;
 
-    if(items != 1) 
+    if (items != 1) 
     {
        croak("usage: Win32::RegCloseKey($hkey);\n");
     }
@@ -2376,12 +2348,12 @@ XS(w32_RegConnectRegistry)
     dXSARGS;
     HKEY handle;
 
-    if(items != 3) 
+    if (items != 3) 
     {
        croak("usage: Win32::RegConnectRegistry($machine, $hkey, $handle);\n");
     }
 
-    if(SUCCESSRETURNED(RegConnectRegistry((char *)SvPV(ST(0), na), SvHKEY(ST(1)), &handle))) 
+    if (SUCCESSRETURNED(RegConnectRegistry((char *)SvPV(ST(0), na), SvHKEY(ST(1)), &handle))) 
     {
        SETHKEY(2,handle);
        XSRETURN_YES;
@@ -2397,7 +2369,7 @@ XS(w32_RegCreateKey)
     DWORD disposition;
     long retval;
 
-    if(items != 3) 
+    if (items != 3) 
     {
        croak("usage: Win32::RegCreateKey($hkey, $subkey, $handle);\n");
     }
@@ -2405,7 +2377,7 @@ XS(w32_RegCreateKey)
     retval =  RegCreateKeyEx(SvHKEY(ST(0)), (char *)SvPV(ST(1), na), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
                                        NULL, &handle, &disposition);
 
-    if(SUCCESSRETURNED(retval)) 
+    if (SUCCESSRETURNED(retval)) 
     {
        SETHKEY(2,handle);
        XSRETURN_YES;
@@ -2427,7 +2399,7 @@ XS(w32_RegCreateKeyEx)
     REGSAM sam;
     SECURITY_ATTRIBUTES sa, *psa;
 
-    if(items != 9) 
+    if (items != 9) 
     {
        croak("usage: Win32::RegCreateKeyEx($hkey, $subkey, $reserved, $class, $options, $sam, "
                        "$security, $handle, $disposition);\n");
@@ -2439,7 +2411,7 @@ XS(w32_RegCreateKeyEx)
     options = (DWORD) ((unsigned long)SvIV(ST(4)));
     sam = (REGSAM) ((unsigned long)SvIV(ST(5)));
     psa = (SECURITY_ATTRIBUTES*)SvPV(ST(6), length);
-    if(length != sizeof(SECURITY_ATTRIBUTES))
+    if (length != sizeof(SECURITY_ATTRIBUTES))
     {
        psa = &sa;
        memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES));
@@ -2449,9 +2421,9 @@ XS(w32_RegCreateKeyEx)
     retval =  RegCreateKeyEx(hkey, subkey, 0, keyclass, options, sam,
                                        psa, &handle, &disposition);
 
-    if(SUCCESSRETURNED(retval)) 
+    if (SUCCESSRETURNED(retval)) 
     {
-       if(psa == &sa)
+       if (psa == &sa)
            SETPVN(6, &sa, sizeof(sa));
 
        SETHKEY(7,handle);
@@ -2466,7 +2438,7 @@ XS(w32_RegDeleteKey)
 {
     dXSARGS;
 
-    if(items != 2) 
+    if (items != 2) 
     {
        croak("usage: Win32::RegDeleteKey($hkey, $subkey);\n");
     }
@@ -2479,7 +2451,7 @@ XS(w32_RegDeleteValue)
 {
     dXSARGS;
 
-    if(items != 2) 
+    if (items != 2) 
     {
        croak("usage: Win32::RegDeleteValue($hkey, $valname);\n");
     }
@@ -2494,12 +2466,12 @@ XS(w32_RegEnumKey)
 
     char keybuffer[TMPBUFSZ];
 
-    if(items != 3) 
+    if (items != 3) 
     {
        croak("usage: Win32::RegEnumKey($hkey, $idx, $subkeyname);\n");
     }
 
-    if(SUCCESSRETURNED(RegEnumKey(SvHKEY(ST(0)), SvIV(ST(1)), keybuffer, sizeof(keybuffer)))) 
+    if (SUCCESSRETURNED(RegEnumKey(SvHKEY(ST(0)), SvIV(ST(1)), keybuffer, sizeof(keybuffer)))) 
     {
        SETPV(2, keybuffer);
        XSRETURN_YES;
@@ -2519,7 +2491,7 @@ XS(w32_RegEnumKeyEx)
     long retval;
     FILETIME filetime;
 
-    if(items != 6)                     
+    if (items != 6)                    
     {
        croak("usage: Win32::RegEnumKeyEx($hkey, $idx, $subkeyname, $reserved, $class, $time);\n");
     }
@@ -2528,7 +2500,7 @@ XS(w32_RegEnumKeyEx)
     classsz = sizeof(classbuffer);
     retval = RegEnumKeyEx(SvHKEY(ST(0)), SvIV(ST(1)), keybuffer, &keysz, 0,
                                                classbuffer, &classsz, &filetime);
-    if(SUCCESSRETURNED(retval)) 
+    if (SUCCESSRETURNED(retval)) 
     {
        SETPV(2, keybuffer);
        SETPV(4, classbuffer);
@@ -2549,7 +2521,7 @@ XS(w32_RegEnumValue)
     char  myvalbuf[MAX_LENGTH];
     char  mynambuf[MAX_LENGTH];
 
-    if(items != 6) 
+    if (items != 6) 
     {
        croak("usage: Win32::RegEnumValue($hkey, $i, $name, $reserved, $type, $value);\n");
     }
@@ -2560,7 +2532,7 @@ XS(w32_RegEnumValue)
     // allocate space for them. Free any old storage and set the old key value to the
     // current key.
 
-    if(hkey != (HKEY)last_hkey) 
+    if (hkey != (HKEY)last_hkey) 
     {
        char keyclass[TMPBUFSZ];
        DWORD classsz, subkeys, maxsubkey, maxclass, values, salen, maxnamesz, maxvalsz;
@@ -2569,7 +2541,7 @@ XS(w32_RegEnumValue)
        retval = RegQueryInfoKey(hkey, keyclass, &classsz, 0, &subkeys, &maxsubkey, &maxclass,
                                                &values, &maxnamesz, &maxvalsz, &salen, &ft);
 
-       if(!SUCCESSRETURNED(retval)) 
+       if (!SUCCESSRETURNED(retval)) 
        {
            XSRETURN_NO;
        }
@@ -2581,7 +2553,7 @@ XS(w32_RegEnumValue)
     namesz = MAX_LENGTH;
     valsz = MAX_LENGTH;
     retval = RegEnumValue(hkey, SvIV(ST(1)), mynambuf, &namesz, 0, &type, (LPBYTE) myvalbuf, &valsz);
-    if(!SUCCESSRETURNED(retval)) 
+    if (!SUCCESSRETURNED(retval)) 
     {
        XSRETURN_NO;
     }
@@ -2596,7 +2568,7 @@ XS(w32_RegEnumValue)
            case REG_SZ:
            case REG_MULTI_SZ:
            case REG_EXPAND_SZ:
-               if(valsz)
+               if (valsz)
                    --valsz;
            case REG_BINARY:
                SETPVN(5, myvalbuf, valsz);
@@ -2628,7 +2600,7 @@ XS(w32_RegFlushKey)
 {
     dXSARGS;
 
-    if(items != 1) 
+    if (items != 1) 
     {
        croak("usage: Win32::RegFlushKey($hkey);\n");
     }
@@ -2643,12 +2615,12 @@ XS(w32_RegGetKeySecurity)
     SECURITY_DESCRIPTOR sd;
     DWORD sdsz;
 
-    if(items != 3) 
+    if (items != 3) 
     {
        croak("usage: Win32::RegGetKeySecurity($hkey, $security_info, $security_descriptor);\n");
     }
 
-    if(SUCCESSRETURNED(RegGetKeySecurity(SvHKEY(ST(0)), SvIV(ST(1)), &sd, &sdsz))) 
+    if (SUCCESSRETURNED(RegGetKeySecurity(SvHKEY(ST(0)), SvIV(ST(1)), &sd, &sdsz))) 
     {
        SETPVN(2, &sd, sdsz);
        XSRETURN_YES;
@@ -2661,7 +2633,7 @@ XS(w32_RegLoadKey)
 {
     dXSARGS;
 
-    if(items != 3) 
+    if (items != 3) 
     {
        croak("usage: Win32::RegLoadKey($hkey, $subkey, $filename);\n");
     }
@@ -2681,12 +2653,12 @@ XS(w32_RegOpenKey)
     dXSARGS;
     HKEY handle;
 
-    if(items != 3) 
+    if (items != 3) 
     {
        croak("usage: Win32::RegOpenKey($hkey, $subkey, $handle);\n");
     }
 
-    if(SUCCESSRETURNED(RegOpenKey(SvHKEY(ST(0)), (char *)SvPV(ST(1), na), &handle))) 
+    if (SUCCESSRETURNED(RegOpenKey(SvHKEY(ST(0)), (char *)SvPV(ST(1), na), &handle))) 
     {
        SETHKEY(2,handle);
        XSRETURN_YES;
@@ -2700,12 +2672,12 @@ XS(w32_RegOpenKeyEx)
     dXSARGS;
     HKEY handle;
 
-    if(items != 5) 
+    if (items != 5) 
     {
        croak("usage: Win32::RegOpenKeyEx($hkey, $subkey, $reserved, $sam, $handle);\n");
     }
 
-    if(SUCCESSRETURNED(RegOpenKeyEx(SvHKEY(ST(0)), (char *)SvPV(ST(1), na), 
+    if (SUCCESSRETURNED(RegOpenKeyEx(SvHKEY(ST(0)), (char *)SvPV(ST(1), na), 
                                0, (REGSAM) ((unsigned long)SvIV(ST(3))), &handle))) 
     {
        SETHKEY(4,handle);
@@ -2727,7 +2699,7 @@ XS(w32_RegQueryInfoKey)
     FILETIME ft;
     long retval;
 
-    if(items != 10) 
+    if (items != 10) 
     {
        croak("usage: Win32::RegQueryInfoKey($hkey, $class, $numsubkeys, $maxsubkey,"
                "$maxclass, $values, $maxvalname, $maxvaldata, $secdesclen,"
@@ -2738,7 +2710,7 @@ XS(w32_RegQueryInfoKey)
     retval = RegQueryInfoKey(SvHKEY(ST(0)), keyclass, &classsz, 0, &subkeys, &maxsubkey,
                                &maxclass, &values, &maxvalname, &maxvaldata,
                                        &seclen, &ft);
-    if(SUCCESSRETURNED(retval)) 
+    if (SUCCESSRETURNED(retval)) 
     {
        SETPV(1, keyclass);
        SETIV(2, subkeys);
@@ -2763,12 +2735,12 @@ XS(w32_RegQueryValue)
     unsigned char databuffer[TMPBUFSZ*2];
     long datasz = sizeof(databuffer);
 
-    if(items != 3) 
+    if (items != 3) 
     {
        croak("usage: Win32::RegQueryValue($hkey, $valuename, $data);\n");
     }
 
-    if(SUCCESSRETURNED(RegQueryValue(SvHKEY(ST(0)), SvPV(ST(1), na), (char*)databuffer, &datasz))) 
+    if (SUCCESSRETURNED(RegQueryValue(SvHKEY(ST(0)), SvPV(ST(1), na), (char*)databuffer, &datasz))) 
     {
        // return includes the null terminator so delete it
        SETPVN(2, databuffer, --datasz);
@@ -2788,18 +2760,18 @@ XS(w32_RegQueryValueEx)
     LONG result;
     LPBYTE ptr = databuffer;
 
-    if(items != 5) 
+    if (items != 5) 
     {
        croak("usage: Win32::RegQueryValueEx($hkey, $valuename, $reserved, $type, $data);\n");
     }
 
     result = RegQueryValueEx(SvHKEY(ST(0)), SvPV(ST(1), na), 0, &type, ptr, &datasz);
-    if(result == ERROR_MORE_DATA)
+    if (result == ERROR_MORE_DATA)
     {
        New(0, ptr, datasz+1, BYTE);
        result = RegQueryValueEx(SvHKEY(ST(0)), SvPV(ST(1), na), 0, &type, ptr, &datasz);
     }
-    if(SUCCESSRETURNED(result)) 
+    if (SUCCESSRETURNED(result)) 
     {
        SETIV(3, type);
 
@@ -2831,12 +2803,12 @@ XS(w32_RegQueryValueEx)
                break;
        }
 
-       if(ptr != databuffer)
+       if (ptr != databuffer)
            safefree(ptr);
 
        XSRETURN_YES;
     }
-    if(ptr != databuffer)
+    if (ptr != databuffer)
        safefree(ptr);
 
     XSRETURN_NO;
@@ -2847,7 +2819,7 @@ XS(w32_RegReplaceKey)
 {
     dXSARGS;
 
-    if(items != 4) 
+    if (items != 4) 
     {
        croak("usage: Win32::RegReplaceKey($hkey, $subkey, $newfile, $oldfile);\n");
     }
@@ -2860,7 +2832,7 @@ XS(w32_RegRestoreKey)
 {
     dXSARGS;
 
-    if(items < 2 || items > 3) 
+    if (items < 2 || items > 3) 
     {
        croak("usage: Win32::RegRestoreKey($hkey, $filename [, $flags]);\n");
     }
@@ -2873,7 +2845,7 @@ XS(w32_RegSaveKey)
 {
     dXSARGS;
 
-    if(items != 2) 
+    if (items != 2) 
     {
        croak("usage: Win32::RegSaveKey($hkey, $filename);\n");
     }
@@ -2886,7 +2858,7 @@ XS(w32_RegSetKeySecurity)
 {
     dXSARGS;
 
-    if(items != 3) 
+    if (items != 3) 
     {
        croak("usage: Win32::RegSetKeySecurity($hkey, $security_info, $security_descriptor);\n");
     }
@@ -2901,14 +2873,15 @@ XS(w32_RegSetValue)
 
     unsigned int size;
     char *buffer;
+       DWORD type;
 
-    if(items != 4) 
+    if (items != 4) 
     {
        croak("usage: Win32::RegSetValue($hkey, $subKey, $type, $data);\n");
     }
 
-    DWORD type = SvIV(ST(2));
-    if(type != REG_SZ && type != REG_EXPAND_SZ)
+    type = SvIV(ST(2));
+    if (type != REG_SZ && type != REG_EXPAND_SZ)
     {
        croak("Win32::RegSetValue: Type was not REG_SZ or REG_EXPAND_SZ, cannot set %s\n", (char *)SvPV(ST(1), na));
     }
@@ -2927,7 +2900,7 @@ XS(w32_RegSetValueEx)
     unsigned int size;
     char *buffer;
 
-    if(items != 5) 
+    if (items != 5) 
     {
        croak("usage: Win32::RegSetValueEx($hkey, $valname, $reserved, $type, $data);\n");
     }
@@ -2940,7 +2913,7 @@ XS(w32_RegSetValueEx)
        case REG_MULTI_SZ:
        case REG_EXPAND_SZ:
            buffer = (char *)SvPV(ST(4), size);
-           if(type != REG_BINARY)
+           if (type != REG_BINARY)
                size++; // include null terminator in size
 
            REGRETURN(RegSetValueEx(SvHKEY(ST(0)), (char *)SvPV(ST(1), na), 0, type, (PBYTE) buffer, size));
@@ -2962,7 +2935,7 @@ XS(w32_RegUnloadKey)
 {
     dXSARGS;
 
-    if(items != 2) 
+    if (items != 2) 
     {
        croak("usage: Win32::RegUnLoadKey($hkey, $subkey);\n");
     }
@@ -2979,23 +2952,23 @@ XS(w32_RegisterServer)
     unsigned int length;
     FARPROC sFunc;
 
-    if(items != 1) 
+    if (items != 1) 
     {
        croak("usage: Win32::RegisterServer($LibraryName)\n");
     }
 
     hInstance = LoadLibrary((char *)SvPV(ST(0), length));
-    if(hInstance != NULL)
+    if (hInstance != NULL)
     {
        sFunc = GetProcAddress(hInstance, "DllRegisterServer");
-       if(sFunc != NULL)
+       if (sFunc != NULL)
        {
            bSuccess = (sFunc() == 0);
        }
        FreeLibrary(hInstance);
     }
 
-    if(bSuccess)
+    if (bSuccess)
     {
        XSRETURN_YES;
     }
@@ -3011,23 +2984,23 @@ XS(w32_UnregisterServer)
     unsigned int length;
     FARPROC sFunc;
 
-    if(items != 1) 
+    if (items != 1) 
     {
        croak("usage: Win32::UnregisterServer($LibraryName)\n");
     }
 
     hInstance = LoadLibrary((char *)SvPV(ST(0), length));
-    if(hInstance != NULL)
+    if (hInstance != NULL)
     {
        sFunc = GetProcAddress(hInstance, "DllUnregisterServer");
-       if(sFunc != NULL)
+       if (sFunc != NULL)
        {
            bSuccess = (sFunc() == 0);
        }
        FreeLibrary(hInstance);
     }
 
-    if(bSuccess)
+    if (bSuccess)
     {
        XSRETURN_YES;
     }
@@ -3041,6 +3014,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);
@@ -3117,7 +3097,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