home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / perl560.zip / win32 / win32.c < prev    next >
C/C++ Source or Header  |  2000-03-09  |  96KB  |  4,096 lines

  1. /* WIN32.C
  2.  *
  3.  * (c) 1995 Microsoft Corporation. All rights reserved. 
  4.  *         Developed by hip communications inc., http://info.hip.com/info/
  5.  * Portions (c) 1993 Intergraph Corporation. All rights reserved.
  6.  *
  7.  *    You may distribute under the terms of either the GNU General Public
  8.  *    License or the Artistic License, as specified in the README file.
  9.  */
  10.  
  11. #define WIN32_LEAN_AND_MEAN
  12. #define WIN32IO_IS_STDIO
  13. #include <tchar.h>
  14. #ifdef __GNUC__
  15. #define Win32_Winsock
  16. #endif
  17. #include <windows.h>
  18. #ifndef __MINGW32__    /* GCC/Mingw32-2.95.2 forgot the WINAPI on CommandLineToArgvW() */
  19. #  include <shellapi.h>
  20. #else
  21.    LPWSTR* WINAPI CommandLineToArgvW(LPCWSTR lpCommandLine, int * pNumArgs);
  22. #endif
  23. #include <winnt.h>
  24. #include <io.h>
  25.  
  26. /* #include "config.h" */
  27.  
  28. #define PERLIO_NOT_STDIO 0 
  29. #if !defined(PERLIO_IS_STDIO) && !defined(USE_SFIO)
  30. #define PerlIO FILE
  31. #endif
  32.  
  33. #include <sys/stat.h>
  34. #include "EXTERN.h"
  35. #include "perl.h"
  36.  
  37. #define NO_XSLOCKS
  38. #define PERL_NO_GET_CONTEXT
  39. #include "XSUB.h"
  40.  
  41. #include "Win32iop.h"
  42. #include <fcntl.h>
  43. #ifndef __GNUC__
  44. /* assert.h conflicts with #define of assert in perl.h */
  45. #include <assert.h>
  46. #endif
  47. #include <string.h>
  48. #include <stdarg.h>
  49. #include <float.h>
  50. #include <time.h>
  51. #if defined(_MSC_VER) || defined(__MINGW32__)
  52. #include <sys/utime.h>
  53. #else
  54. #include <utime.h>
  55. #endif
  56.  
  57. #ifdef __GNUC__
  58. /* Mingw32 defaults to globing command line 
  59.  * So we turn it off like this:
  60.  */
  61. int _CRT_glob = 0;
  62. #endif
  63.  
  64. #if defined(__MINGW32__)
  65. /* Mingw32 is missing some prototypes */
  66. FILE * _wfopen(LPCWSTR wszFileName, LPCWSTR wszMode);
  67. FILE * _wfdopen(int nFd, LPCWSTR wszMode);
  68. FILE * _freopen(LPCWSTR wszFileName, LPCWSTR wszMode, FILE * pOldStream);
  69. int _flushall();
  70. int _fcloseall();
  71. #endif
  72.  
  73. #if defined(__BORLANDC__)
  74. #  define _stat stat
  75. #  define _utimbuf utimbuf
  76. #endif
  77.  
  78. #define EXECF_EXEC 1
  79. #define EXECF_SPAWN 2
  80. #define EXECF_SPAWN_NOWAIT 3
  81.  
  82. #if defined(PERL_IMPLICIT_SYS)
  83. #  undef win32_get_privlib
  84. #  define win32_get_privlib g_win32_get_privlib
  85. #  undef win32_get_sitelib
  86. #  define win32_get_sitelib g_win32_get_sitelib
  87. #  undef win32_get_vendorlib
  88. #  define win32_get_vendorlib g_win32_get_vendorlib
  89. #  undef do_spawn
  90. #  define do_spawn g_do_spawn
  91. #  undef getlogin
  92. #  define getlogin g_getlogin
  93. #endif
  94.  
  95. #if defined(PERL_OBJECT)
  96. #  undef do_aspawn
  97. #  define do_aspawn g_do_aspawn
  98. #  undef Perl_do_exec
  99. #  define Perl_do_exec g_do_exec
  100. #endif
  101.  
  102. static void        get_shell(void);
  103. static long        tokenize(const char *str, char **dest, char ***destv);
  104.     int        do_spawn2(char *cmd, int exectype);
  105. static BOOL        has_shell_metachars(char *ptr);
  106. static long        filetime_to_clock(PFILETIME ft);
  107. static BOOL        filetime_from_time(PFILETIME ft, time_t t);
  108. static char *        get_emd_part(SV **leading, char *trailing, ...);
  109. static void        remove_dead_process(long deceased);
  110. static long        find_pid(int pid);
  111. static char *        qualified_path(const char *cmd);
  112. static char *        win32_get_xlib(const char *pl, const char *xlib,
  113.                        const char *libname);
  114.  
  115. #ifdef USE_ITHREADS
  116. static void        remove_dead_pseudo_process(long child);
  117. static long        find_pseudo_pid(int pid);
  118. #endif
  119.  
  120. START_EXTERN_C
  121. HANDLE    w32_perldll_handle = INVALID_HANDLE_VALUE;
  122. char    w32_module_name[MAX_PATH+1];
  123. END_EXTERN_C
  124.  
  125. static DWORD    w32_platform = (DWORD)-1;
  126.  
  127. #define ONE_K_BUFSIZE    1024
  128.  
  129. int 
  130. IsWin95(void)
  131. {
  132.     return (win32_os_id() == VER_PLATFORM_WIN32_WINDOWS);
  133. }
  134.  
  135. int
  136. IsWinNT(void)
  137. {
  138.     return (win32_os_id() == VER_PLATFORM_WIN32_NT);
  139. }
  140.  
  141. EXTERN_C void
  142. set_w32_module_name(void)
  143. {
  144.     char* ptr;
  145.     GetModuleFileName((HMODULE)((w32_perldll_handle == INVALID_HANDLE_VALUE)
  146.                 ? GetModuleHandle(NULL)
  147.                 : w32_perldll_handle),
  148.               w32_module_name, sizeof(w32_module_name));
  149.  
  150.     /* try to get full path to binary (which may be mangled when perl is
  151.      * run from a 16-bit app) */
  152.     /*PerlIO_printf(Perl_debug_log, "Before %s\n", w32_module_name);*/
  153.     (void)win32_longpath(w32_module_name);
  154.     /*PerlIO_printf(Perl_debug_log, "After  %s\n", w32_module_name);*/
  155.  
  156.     /* normalize to forward slashes */
  157.     ptr = w32_module_name;
  158.     while (*ptr) {
  159.     if (*ptr == '\\')
  160.         *ptr = '/';
  161.     ++ptr;
  162.     }
  163. }
  164.  
  165. /* *svp (if non-NULL) is expected to be POK (valid allocated SvPVX(*svp)) */
  166. static char*
  167. get_regstr_from(HKEY hkey, const char *valuename, SV **svp)
  168. {
  169.     /* Retrieve a REG_SZ or REG_EXPAND_SZ from the registry */
  170.     HKEY handle;
  171.     DWORD type;
  172.     const char *subkey = "Software\\Perl";
  173.     char *str = Nullch;
  174.     long retval;
  175.  
  176.     retval = RegOpenKeyEx(hkey, subkey, 0, KEY_READ, &handle);
  177.     if (retval == ERROR_SUCCESS) {
  178.     DWORD datalen;
  179.     retval = RegQueryValueEx(handle, valuename, 0, &type, NULL, &datalen);
  180.     if (retval == ERROR_SUCCESS && type == REG_SZ) {
  181.         dTHXo;
  182.         if (!*svp)
  183.         *svp = sv_2mortal(newSVpvn("",0));
  184.         SvGROW(*svp, datalen);
  185.         retval = RegQueryValueEx(handle, valuename, 0, NULL,
  186.                      (PBYTE)SvPVX(*svp), &datalen);
  187.         if (retval == ERROR_SUCCESS) {
  188.         str = SvPVX(*svp);
  189.         SvCUR_set(*svp,datalen-1);
  190.         }
  191.     }
  192.     RegCloseKey(handle);
  193.     }
  194.     return str;
  195. }
  196.  
  197. /* *svp (if non-NULL) is expected to be POK (valid allocated SvPVX(*svp)) */
  198. static char*
  199. get_regstr(const char *valuename, SV **svp)
  200. {
  201.     char *str = get_regstr_from(HKEY_CURRENT_USER, valuename, svp);
  202.     if (!str)
  203.     str = get_regstr_from(HKEY_LOCAL_MACHINE, valuename, svp);
  204.     return str;
  205. }
  206.  
  207. /* *prev_pathp (if non-NULL) is expected to be POK (valid allocated SvPVX(sv)) */
  208. static char *
  209. get_emd_part(SV **prev_pathp, char *trailing_path, ...)
  210. {
  211.     char base[10];
  212.     va_list ap;
  213.     char mod_name[MAX_PATH+1];
  214.     char *ptr;
  215.     char *optr;
  216.     char *strip;
  217.     int oldsize, newsize;
  218.     STRLEN baselen;
  219.  
  220.     va_start(ap, trailing_path);
  221.     strip = va_arg(ap, char *);
  222.  
  223.     sprintf(base, "%d.%d", (int)PERL_REVISION, (int)PERL_VERSION);
  224.     baselen = strlen(base);
  225.  
  226.     if (!*w32_module_name) {
  227.     set_w32_module_name();
  228.     }
  229.     strcpy(mod_name, w32_module_name);
  230.     ptr = strrchr(mod_name, '/');
  231.     while (ptr && strip) {
  232.         /* look for directories to skip back */
  233.     optr = ptr;
  234.     *ptr = '\0';
  235.     ptr = strrchr(mod_name, '/');
  236.     /* avoid stripping component if there is no slash,
  237.      * or it doesn't match ... */
  238.     if (!ptr || stricmp(ptr+1, strip) != 0) {
  239.         /* ... but not if component matches m|5\.$patchlevel.*| */
  240.         if (!ptr || !(*strip == '5' && *(ptr+1) == '5'
  241.               && strncmp(strip, base, baselen) == 0
  242.               && strncmp(ptr+1, base, baselen) == 0))
  243.         {
  244.         *optr = '/';
  245.         ptr = optr;
  246.         }
  247.     }
  248.     strip = va_arg(ap, char *);
  249.     }
  250.     if (!ptr) {
  251.     ptr = mod_name;
  252.     *ptr++ = '.';
  253.     *ptr = '/';
  254.     }
  255.     va_end(ap);
  256.     strcpy(++ptr, trailing_path);
  257.  
  258.     /* only add directory if it exists */
  259.     if (GetFileAttributes(mod_name) != (DWORD) -1) {
  260.     /* directory exists */
  261.     dTHXo;
  262.     if (!*prev_pathp)
  263.         *prev_pathp = sv_2mortal(newSVpvn("",0));
  264.     sv_catpvn(*prev_pathp, ";", 1);
  265.     sv_catpv(*prev_pathp, mod_name);
  266.     return SvPVX(*prev_pathp);
  267.     }
  268.  
  269.     return Nullch;
  270. }
  271.  
  272. char *
  273. win32_get_privlib(const char *pl)
  274. {
  275.     dTHXo;
  276.     char *stdlib = "lib";
  277.     char buffer[MAX_PATH+1];
  278.     SV *sv = Nullsv;
  279.  
  280.     /* $stdlib = $HKCU{"lib-$]"} || $HKLM{"lib-$]"} || $HKCU{"lib"} || $HKLM{"lib"} || "";  */
  281.     sprintf(buffer, "%s-%s", stdlib, pl);
  282.     if (!get_regstr(buffer, &sv))
  283.     (void)get_regstr(stdlib, &sv);
  284.  
  285.     /* $stdlib .= ";$EMD/../../lib" */
  286.     return get_emd_part(&sv, stdlib, ARCHNAME, "bin", Nullch);
  287. }
  288.  
  289. static char *
  290. win32_get_xlib(const char *pl, const char *xlib, const char *libname)
  291. {
  292.     dTHXo;
  293.     char regstr[40];
  294.     char pathstr[MAX_PATH+1];
  295.     DWORD datalen;
  296.     int len, newsize;
  297.     SV *sv1 = Nullsv;
  298.     SV *sv2 = Nullsv;
  299.  
  300.     /* $HKCU{"$xlib-$]"} || $HKLM{"$xlib-$]"} . ---; */
  301.     sprintf(regstr, "%s-%s", xlib, pl);
  302.     (void)get_regstr(regstr, &sv1);
  303.  
  304.     /* $xlib .=
  305.      * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/$libname/$]/lib";  */
  306.     sprintf(pathstr, "%s/%s/lib", libname, pl);
  307.     (void)get_emd_part(&sv1, pathstr, ARCHNAME, "bin", pl, Nullch);
  308.  
  309.     /* $HKCU{$xlib} || $HKLM{$xlib} . ---; */
  310.     (void)get_regstr(xlib, &sv2);
  311.  
  312.     /* $xlib .=
  313.      * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/$libname/lib";  */
  314.     sprintf(pathstr, "%s/lib", libname);
  315.     (void)get_emd_part(&sv2, pathstr, ARCHNAME, "bin", pl, Nullch);
  316.  
  317.     if (!sv1 && !sv2)
  318.     return Nullch;
  319.     if (!sv1)
  320.     return SvPVX(sv2);
  321.     if (!sv2)
  322.     return SvPVX(sv1);
  323.  
  324.     sv_catpvn(sv1, ";", 1);
  325.     sv_catsv(sv1, sv2);
  326.  
  327.     return SvPVX(sv1);
  328. }
  329.  
  330. char *
  331. win32_get_sitelib(const char *pl)
  332. {
  333.     return win32_get_xlib(pl, "sitelib", "site");
  334. }
  335.  
  336. #ifndef PERL_VENDORLIB_NAME
  337. #  define PERL_VENDORLIB_NAME    "vendor"
  338. #endif
  339.  
  340. char *
  341. win32_get_vendorlib(const char *pl)
  342. {
  343.     return win32_get_xlib(pl, "vendorlib", PERL_VENDORLIB_NAME);
  344. }
  345.  
  346. static BOOL
  347. has_shell_metachars(char *ptr)
  348. {
  349.     int inquote = 0;
  350.     char quote = '\0';
  351.  
  352.     /*
  353.      * Scan string looking for redirection (< or >) or pipe
  354.      * characters (|) that are not in a quoted string.
  355.      * Shell variable interpolation (%VAR%) can also happen inside strings.
  356.      */
  357.     while (*ptr) {
  358.     switch(*ptr) {
  359.     case '%':
  360.         return TRUE;
  361.     case '\'':
  362.     case '\"':
  363.         if (inquote) {
  364.         if (quote == *ptr) {
  365.             inquote = 0;
  366.             quote = '\0';
  367.         }
  368.         }
  369.         else {
  370.         quote = *ptr;
  371.         inquote++;
  372.         }
  373.         break;
  374.     case '>':
  375.     case '<':
  376.     case '|':
  377.         if (!inquote)
  378.         return TRUE;
  379.     default:
  380.         break;
  381.     }
  382.     ++ptr;
  383.     }
  384.     return FALSE;
  385. }
  386.  
  387. #if !defined(PERL_IMPLICIT_SYS)
  388. /* since the current process environment is being updated in util.c
  389.  * the library functions will get the correct environment
  390.  */
  391. PerlIO *
  392. Perl_my_popen(pTHX_ char *cmd, char *mode)
  393. {
  394. #ifdef FIXCMD
  395. #define fixcmd(x)   {                    \
  396.             char *pspace = strchr((x),' ');    \
  397.             if (pspace) {            \
  398.                 char *p = (x);        \
  399.                 while (p < pspace) {    \
  400.                 if (*p == '/')        \
  401.                     *p = '\\';        \
  402.                 p++;            \
  403.                 }                \
  404.             }                \
  405.             }
  406. #else
  407. #define fixcmd(x)
  408. #endif
  409.     fixcmd(cmd);
  410.     PERL_FLUSHALL_FOR_CHILD;
  411.     return win32_popen(cmd, mode);
  412. }
  413.  
  414. long
  415. Perl_my_pclose(pTHX_ PerlIO *fp)
  416. {
  417.     return win32_pclose(fp);
  418. }
  419. #endif
  420.  
  421. DllExport unsigned long
  422. win32_os_id(void)
  423. {
  424.     static OSVERSIONINFO osver;
  425.  
  426.     if (osver.dwPlatformId != w32_platform) {
  427.     memset(&osver, 0, sizeof(OSVERSIONINFO));
  428.     osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  429.     GetVersionEx(&osver);
  430.     w32_platform = osver.dwPlatformId;
  431.     }
  432.     return (unsigned long)w32_platform;
  433. }
  434.  
  435. DllExport int
  436. win32_getpid(void)
  437. {
  438. #ifdef USE_ITHREADS
  439.     dTHXo;
  440.     if (w32_pseudo_id)
  441.     return -((int)w32_pseudo_id);
  442. #endif
  443.     return _getpid();
  444. }
  445.  
  446. /* Tokenize a string.  Words are null-separated, and the list
  447.  * ends with a doubled null.  Any character (except null and
  448.  * including backslash) may be escaped by preceding it with a
  449.  * backslash (the backslash will be stripped).
  450.  * Returns number of words in result buffer.
  451.  */
  452. static long
  453. tokenize(const char *str, char **dest, char ***destv)
  454. {
  455.     char *retstart = Nullch;
  456.     char **retvstart = 0;
  457.     int items = -1;
  458.     if (str) {
  459.     dTHXo;
  460.     int slen = strlen(str);
  461.     register char *ret;
  462.     register char **retv;
  463.     New(1307, ret, slen+2, char);
  464.     New(1308, retv, (slen+3)/2, char*);
  465.  
  466.     retstart = ret;
  467.     retvstart = retv;
  468.     *retv = ret;
  469.     items = 0;
  470.     while (*str) {
  471.         *ret = *str++;
  472.         if (*ret == '\\' && *str)
  473.         *ret = *str++;
  474.         else if (*ret == ' ') {
  475.         while (*str == ' ')
  476.             str++;
  477.         if (ret == retstart)
  478.             ret--;
  479.         else {
  480.             *ret = '\0';
  481.             ++items;
  482.             if (*str)
  483.             *++retv = ret+1;
  484.         }
  485.         }
  486.         else if (!*str)
  487.         ++items;
  488.         ret++;
  489.     }
  490.     retvstart[items] = Nullch;
  491.     *ret++ = '\0';
  492.     *ret = '\0';
  493.     }
  494.     *dest = retstart;
  495.     *destv = retvstart;
  496.     return items;
  497. }
  498.  
  499. static void
  500. get_shell(void)
  501. {
  502.     dTHXo;
  503.     if (!w32_perlshell_tokens) {
  504.     /* we don't use COMSPEC here for two reasons:
  505.      *  1. the same reason perl on UNIX doesn't use SHELL--rampant and
  506.      *     uncontrolled unportability of the ensuing scripts.
  507.      *  2. PERL5SHELL could be set to a shell that may not be fit for
  508.      *     interactive use (which is what most programs look in COMSPEC
  509.      *     for).
  510.      */
  511.     const char* defaultshell = (IsWinNT()
  512.                     ? "cmd.exe /x/c" : "command.com /c");
  513.     const char *usershell = getenv("PERL5SHELL");
  514.     w32_perlshell_items = tokenize(usershell ? usershell : defaultshell,
  515.                        &w32_perlshell_tokens,
  516.                        &w32_perlshell_vec);
  517.     }
  518. }
  519.  
  520. int
  521. do_aspawn(void *vreally, void **vmark, void **vsp)
  522. {
  523.     dTHXo;
  524.     SV *really = (SV*)vreally;
  525.     SV **mark = (SV**)vmark;
  526.     SV **sp = (SV**)vsp;
  527.     char **argv;
  528.     char *str;
  529.     int status;
  530.     int flag = P_WAIT;
  531.     int index = 0;
  532.  
  533.     if (sp <= mark)
  534.     return -1;
  535.  
  536.     get_shell();
  537.     New(1306, argv, (sp - mark) + w32_perlshell_items + 2, char*);
  538.  
  539.     if (SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) {
  540.     ++mark;
  541.     flag = SvIVx(*mark);
  542.     }
  543.  
  544.     while (++mark <= sp) {
  545.     if (*mark && (str = SvPV_nolen(*mark)))
  546.         argv[index++] = str;
  547.     else
  548.         argv[index++] = "";
  549.     }
  550.     argv[index++] = 0;
  551.    
  552.     status = win32_spawnvp(flag,
  553.                (const char*)(really ? SvPV_nolen(really) : argv[0]),
  554.                (const char* const*)argv);
  555.  
  556.     if (status < 0 && (errno == ENOEXEC || errno == ENOENT)) {
  557.     /* possible shell-builtin, invoke with shell */
  558.     int sh_items;
  559.     sh_items = w32_perlshell_items;
  560.     while (--index >= 0)
  561.         argv[index+sh_items] = argv[index];
  562.     while (--sh_items >= 0)
  563.         argv[sh_items] = w32_perlshell_vec[sh_items];
  564.    
  565.     status = win32_spawnvp(flag,
  566.                    (const char*)(really ? SvPV_nolen(really) : argv[0]),
  567.                    (const char* const*)argv);
  568.     }
  569.  
  570.     if (flag != P_NOWAIT) {
  571.     if (status < 0) {
  572.             dTHR;
  573.         if (ckWARN(WARN_EXEC))
  574.         Perl_warner(aTHX_ WARN_EXEC, "Can't spawn \"%s\": %s", argv[0], strerror(errno));
  575.         status = 255 * 256;
  576.     }
  577.     else
  578.         status *= 256;
  579.     PL_statusvalue = status;
  580.     }
  581.     Safefree(argv);
  582.     return (status);
  583. }
  584.  
  585. int
  586. do_spawn2(char *cmd, int exectype)
  587. {
  588.     dTHXo;
  589.     char **a;
  590.     char *s;
  591.     char **argv;
  592.     int status = -1;
  593.     BOOL needToTry = TRUE;
  594.     char *cmd2;
  595.  
  596.     /* Save an extra exec if possible. See if there are shell
  597.      * metacharacters in it */
  598.     if (!has_shell_metachars(cmd)) {
  599.     New(1301,argv, strlen(cmd) / 2 + 2, char*);
  600.     New(1302,cmd2, strlen(cmd) + 1, char);
  601.     strcpy(cmd2, cmd);
  602.     a = argv;
  603.     for (s = cmd2; *s;) {
  604.         while (*s && isSPACE(*s))
  605.         s++;
  606.         if (*s)
  607.         *(a++) = s;
  608.         while (*s && !isSPACE(*s))
  609.         s++;
  610.         if (*s)
  611.         *s++ = '\0';
  612.     }
  613.     *a = Nullch;
  614.     if (argv[0]) {
  615.         switch (exectype) {
  616.         case EXECF_SPAWN:
  617.         status = win32_spawnvp(P_WAIT, argv[0],
  618.                        (const char* const*)argv);
  619.         break;
  620.         case EXECF_SPAWN_NOWAIT:
  621.         status = win32_spawnvp(P_NOWAIT, argv[0],
  622.                        (const char* const*)argv);
  623.         break;
  624.         case EXECF_EXEC:
  625.         status = win32_execvp(argv[0], (const char* const*)argv);
  626.         break;
  627.         }
  628.         if (status != -1 || errno == 0)
  629.         needToTry = FALSE;
  630.     }
  631.     Safefree(argv);
  632.     Safefree(cmd2);
  633.     }
  634.     if (needToTry) {
  635.     char **argv;
  636.     int i = -1;
  637.     get_shell();
  638.     New(1306, argv, w32_perlshell_items + 2, char*);
  639.     while (++i < w32_perlshell_items)
  640.         argv[i] = w32_perlshell_vec[i];
  641.     argv[i++] = cmd;
  642.     argv[i] = Nullch;
  643.     switch (exectype) {
  644.     case EXECF_SPAWN:
  645.         status = win32_spawnvp(P_WAIT, argv[0],
  646.                    (const char* const*)argv);
  647.         break;
  648.     case EXECF_SPAWN_NOWAIT:
  649.         status = win32_spawnvp(P_NOWAIT, argv[0],
  650.                    (const char* const*)argv);
  651.         break;
  652.     case EXECF_EXEC:
  653.         status = win32_execvp(argv[0], (const char* const*)argv);
  654.         break;
  655.     }
  656.     cmd = argv[0];
  657.     Safefree(argv);
  658.     }
  659.     if (exectype != EXECF_SPAWN_NOWAIT) {
  660.     if (status < 0) {
  661.             dTHR;
  662.         if (ckWARN(WARN_EXEC))
  663.         Perl_warner(aTHX_ WARN_EXEC, "Can't %s \"%s\": %s",
  664.              (exectype == EXECF_EXEC ? "exec" : "spawn"),
  665.              cmd, strerror(errno));
  666.         status = 255 * 256;
  667.     }
  668.     else
  669.         status *= 256;
  670.     PL_statusvalue = status;
  671.     }
  672.     return (status);
  673. }
  674.  
  675. int
  676. do_spawn(char *cmd)
  677. {
  678.     return do_spawn2(cmd, EXECF_SPAWN);
  679. }
  680.  
  681. int
  682. do_spawn_nowait(char *cmd)
  683. {
  684.     return do_spawn2(cmd, EXECF_SPAWN_NOWAIT);
  685. }
  686.  
  687. bool
  688. Perl_do_exec(pTHX_ char *cmd)
  689. {
  690.     do_spawn2(cmd, EXECF_EXEC);
  691.     return FALSE;
  692. }
  693.  
  694. /* The idea here is to read all the directory names into a string table
  695.  * (separated by nulls) and when one of the other dir functions is called
  696.  * return the pointer to the current file name.
  697.  */
  698. DllExport DIR *
  699. win32_opendir(char *filename)
  700. {
  701.     dTHXo;
  702.     DIR            *dirp;
  703.     long        len;
  704.     long        idx;
  705.     char        scanname[MAX_PATH+3];
  706.     struct stat        sbuf;
  707.     WIN32_FIND_DATAA    aFindData;
  708.     WIN32_FIND_DATAW    wFindData;
  709.     HANDLE        fh;
  710.     char        buffer[MAX_PATH*2];
  711.     WCHAR        wbuffer[MAX_PATH+1];
  712.     char*        ptr;
  713.  
  714.     len = strlen(filename);
  715.     if (len > MAX_PATH)
  716.     return NULL;
  717.  
  718.     /* check to see if filename is a directory */
  719.     if (win32_stat(filename, &sbuf) < 0 || !S_ISDIR(sbuf.st_mode))
  720.     return NULL;
  721.  
  722.     /* Get us a DIR structure */
  723.     Newz(1303, dirp, 1, DIR);
  724.  
  725.     /* Create the search pattern */
  726.     strcpy(scanname, filename);
  727.  
  728.     /* bare drive name means look in cwd for drive */
  729.     if (len == 2 && isALPHA(scanname[0]) && scanname[1] == ':') {
  730.     scanname[len++] = '.';
  731.     scanname[len++] = '/';
  732.     }
  733.     else if (scanname[len-1] != '/' && scanname[len-1] != '\\') {
  734.     scanname[len++] = '/';
  735.     }
  736.     scanname[len++] = '*';
  737.     scanname[len] = '\0';
  738.  
  739.     /* do the FindFirstFile call */
  740.     if (USING_WIDE()) {
  741.     A2WHELPER(scanname, wbuffer, sizeof(wbuffer));
  742.     fh = FindFirstFileW(PerlDir_mapW(wbuffer), &wFindData);
  743.     }
  744.     else {
  745.     fh = FindFirstFileA(PerlDir_mapA(scanname), &aFindData);
  746.     }
  747.     dirp->handle = fh;
  748.     if (fh == INVALID_HANDLE_VALUE) {
  749.     DWORD err = GetLastError();
  750.     /* FindFirstFile() fails on empty drives! */
  751.     switch (err) {
  752.     case ERROR_FILE_NOT_FOUND:
  753.         return dirp;
  754.     case ERROR_NO_MORE_FILES:
  755.     case ERROR_PATH_NOT_FOUND:
  756.         errno = ENOENT;
  757.         break;
  758.     case ERROR_NOT_ENOUGH_MEMORY:
  759.         errno = ENOMEM;
  760.         break;
  761.     default:
  762.         errno = EINVAL;
  763.         break;
  764.     }
  765.     Safefree(dirp);
  766.     return NULL;
  767.     }
  768.  
  769.     /* now allocate the first part of the string table for
  770.      * the filenames that we find.
  771.      */
  772.     if (USING_WIDE()) {
  773.     W2AHELPER(wFindData.cFileName, buffer, sizeof(buffer));
  774.     ptr = buffer;
  775.     }
  776.     else {
  777.     ptr = aFindData.cFileName;
  778.     }
  779.     idx = strlen(ptr)+1;
  780.     if (idx < 256)
  781.     dirp->size = 128;
  782.     else
  783.     dirp->size = idx;
  784.     New(1304, dirp->start, dirp->size, char);
  785.     strcpy(dirp->start, ptr);
  786.     dirp->nfiles++;
  787.     dirp->end = dirp->curr = dirp->start;
  788.     dirp->end += idx;
  789.     return dirp;
  790. }
  791.  
  792.  
  793. /* Readdir just returns the current string pointer and bumps the
  794.  * string pointer to the nDllExport entry.
  795.  */
  796. DllExport struct direct *
  797. win32_readdir(DIR *dirp)
  798. {
  799.     long         len;
  800.  
  801.     if (dirp->curr) {
  802.     /* first set up the structure to return */
  803.     len = strlen(dirp->curr);
  804.     strcpy(dirp->dirstr.d_name, dirp->curr);
  805.     dirp->dirstr.d_namlen = len;
  806.  
  807.     /* Fake an inode */
  808.     dirp->dirstr.d_ino = dirp->curr - dirp->start;
  809.  
  810.     /* Now set up for the next call to readdir */
  811.     dirp->curr += len + 1;
  812.     if (dirp->curr >= dirp->end) {
  813.         dTHXo;
  814.         char*        ptr;
  815.         BOOL        res;
  816.         WIN32_FIND_DATAW    wFindData;
  817.         WIN32_FIND_DATAA    aFindData;
  818.         char        buffer[MAX_PATH*2];
  819.  
  820.         /* finding the next file that matches the wildcard
  821.          * (which should be all of them in this directory!).
  822.          */
  823.         if (USING_WIDE()) {
  824.         res = FindNextFileW(dirp->handle, &wFindData);
  825.         if (res) {
  826.             W2AHELPER(wFindData.cFileName, buffer, sizeof(buffer));
  827.             ptr = buffer;
  828.         }
  829.         }
  830.         else {
  831.         res = FindNextFileA(dirp->handle, &aFindData);
  832.         if (res)
  833.             ptr = aFindData.cFileName;
  834.         }
  835.         if (res) {
  836.         long endpos = dirp->end - dirp->start;
  837.         long newsize = endpos + strlen(ptr) + 1;
  838.         /* bump the string table size by enough for the
  839.          * new name and it's null terminator */
  840.         while (newsize > dirp->size) {
  841.             long curpos = dirp->curr - dirp->start;
  842.             dirp->size *= 2;
  843.             Renew(dirp->start, dirp->size, char);
  844.             dirp->curr = dirp->start + curpos;
  845.         }
  846.         strcpy(dirp->start + endpos, ptr);
  847.         dirp->end = dirp->start + newsize;
  848.         dirp->nfiles++;
  849.         }
  850.         else
  851.         dirp->curr = NULL;
  852.     }
  853.     return &(dirp->dirstr);
  854.     } 
  855.     else
  856.     return NULL;
  857. }
  858.  
  859. /* Telldir returns the current string pointer position */
  860. DllExport long
  861. win32_telldir(DIR *dirp)
  862. {
  863.     return (dirp->curr - dirp->start);
  864. }
  865.  
  866.  
  867. /* Seekdir moves the string pointer to a previously saved position
  868.  * (returned by telldir).
  869.  */
  870. DllExport void
  871. win32_seekdir(DIR *dirp, long loc)
  872. {
  873.     dirp->curr = dirp->start + loc;
  874. }
  875.  
  876. /* Rewinddir resets the string pointer to the start */
  877. DllExport void
  878. win32_rewinddir(DIR *dirp)
  879. {
  880.     dirp->curr = dirp->start;
  881. }
  882.  
  883. /* free the memory allocated by opendir */
  884. DllExport int
  885. win32_closedir(DIR *dirp)
  886. {
  887.     dTHXo;
  888.     if (dirp->handle != INVALID_HANDLE_VALUE)
  889.     FindClose(dirp->handle);
  890.     Safefree(dirp->start);
  891.     Safefree(dirp);
  892.     return 1;
  893. }
  894.  
  895.  
  896. /*
  897.  * various stubs
  898.  */
  899.  
  900.  
  901. /* Ownership
  902.  *
  903.  * Just pretend that everyone is a superuser. NT will let us know if
  904.  * we don\'t really have permission to do something.
  905.  */
  906.  
  907. #define ROOT_UID    ((uid_t)0)
  908. #define ROOT_GID    ((gid_t)0)
  909.  
  910. uid_t
  911. getuid(void)
  912. {
  913.     return ROOT_UID;
  914. }
  915.  
  916. uid_t
  917. geteuid(void)
  918. {
  919.     return ROOT_UID;
  920. }
  921.  
  922. gid_t
  923. getgid(void)
  924. {
  925.     return ROOT_GID;
  926. }
  927.  
  928. gid_t
  929. getegid(void)
  930. {
  931.     return ROOT_GID;
  932. }
  933.  
  934. int
  935. setuid(uid_t auid)
  936.     return (auid == ROOT_UID ? 0 : -1);
  937. }
  938.  
  939. int
  940. setgid(gid_t agid)
  941. {
  942.     return (agid == ROOT_GID ? 0 : -1);
  943. }
  944.  
  945. char *
  946. getlogin(void)
  947. {
  948.     dTHXo;
  949.     char *buf = w32_getlogin_buffer;
  950.     DWORD size = sizeof(w32_getlogin_buffer);
  951.     if (GetUserName(buf,&size))
  952.     return buf;
  953.     return (char*)NULL;
  954. }
  955.  
  956. int
  957. chown(const char *path, uid_t owner, gid_t group)
  958. {
  959.     /* XXX noop */
  960.     return 0;
  961. }
  962.  
  963. static long
  964. find_pid(int pid)
  965. {
  966.     dTHXo;
  967.     long child = w32_num_children;
  968.     while (--child >= 0) {
  969.     if (w32_child_pids[child] == pid)
  970.         return child;
  971.     }
  972.     return -1;
  973. }
  974.  
  975. static void
  976. remove_dead_process(long child)
  977. {
  978.     if (child >= 0) {
  979.     dTHXo;
  980.     CloseHandle(w32_child_handles[child]);
  981.     Move(&w32_child_handles[child+1], &w32_child_handles[child],
  982.          (w32_num_children-child-1), HANDLE);
  983.     Move(&w32_child_pids[child+1], &w32_child_pids[child],
  984.          (w32_num_children-child-1), DWORD);
  985.     w32_num_children--;
  986.     }
  987. }
  988.  
  989. #ifdef USE_ITHREADS
  990. static long
  991. find_pseudo_pid(int pid)
  992. {
  993.     dTHXo;
  994.     long child = w32_num_pseudo_children;
  995.     while (--child >= 0) {
  996.     if (w32_pseudo_child_pids[child] == pid)
  997.         return child;
  998.     }
  999.     return -1;
  1000. }
  1001.  
  1002. static void
  1003. remove_dead_pseudo_process(long child)
  1004. {
  1005.     if (child >= 0) {
  1006.     dTHXo;
  1007.     CloseHandle(w32_pseudo_child_handles[child]);
  1008.     Move(&w32_pseudo_child_handles[child+1], &w32_pseudo_child_handles[child],
  1009.          (w32_num_pseudo_children-child-1), HANDLE);
  1010.     Move(&w32_pseudo_child_pids[child+1], &w32_pseudo_child_pids[child],
  1011.          (w32_num_pseudo_children-child-1), DWORD);
  1012.     w32_num_pseudo_children--;
  1013.     }
  1014. }
  1015. #endif
  1016.  
  1017. DllExport int
  1018. win32_kill(int pid, int sig)
  1019. {
  1020.     dTHXo;
  1021.     HANDLE hProcess;
  1022. #ifdef USE_ITHREADS
  1023.     if (pid < 0) {
  1024.     /* it is a pseudo-forked child */
  1025.     long child = find_pseudo_pid(-pid);
  1026.     if (child >= 0) {
  1027.         if (!sig)
  1028.         return 0;
  1029.         hProcess = w32_pseudo_child_handles[child];
  1030.         if (TerminateThread(hProcess, sig)) {
  1031.         remove_dead_pseudo_process(child);
  1032.         return 0;
  1033.         }
  1034.     }
  1035.     }
  1036.     else
  1037. #endif
  1038.     {
  1039.     long child = find_pid(pid);
  1040.     if (child >= 0) {
  1041.         if (!sig)
  1042.         return 0;
  1043.         hProcess = w32_child_handles[child];
  1044.         if (TerminateProcess(hProcess, sig)) {
  1045.         remove_dead_process(child);
  1046.         return 0;
  1047.         }
  1048.     }
  1049.     else {
  1050.         hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE, pid);
  1051.         if (hProcess) {
  1052.         if (!sig)
  1053.             return 0;
  1054.         if (TerminateProcess(hProcess, sig)) {
  1055.             CloseHandle(hProcess);
  1056.             return 0;
  1057.         }
  1058.         }
  1059.     }
  1060.     }
  1061.     errno = EINVAL;
  1062.     return -1;
  1063. }
  1064.  
  1065. /*
  1066.  * File system stuff
  1067.  */
  1068.  
  1069. DllExport unsigned int
  1070. win32_sleep(unsigned int t)
  1071. {
  1072.     Sleep(t*1000);
  1073.     return 0;
  1074. }
  1075.  
  1076. DllExport int
  1077. win32_stat(const char *path, struct stat *sbuf)
  1078. {
  1079.     dTHXo;
  1080.     char    buffer[MAX_PATH+1]; 
  1081.     int        l = strlen(path);
  1082.     int        res;
  1083.     WCHAR    wbuffer[MAX_PATH+1];
  1084.     WCHAR*    pwbuffer;
  1085.     HANDLE      handle;
  1086.     int         nlink = 1;
  1087.  
  1088.     if (l > 1) {
  1089.     switch(path[l - 1]) {
  1090.     /* FindFirstFile() and stat() are buggy with a trailing
  1091.      * backslash, so change it to a forward slash :-( */
  1092.     case '\\':
  1093.         strncpy(buffer, path, l-1);
  1094.         buffer[l - 1] = '/';
  1095.         buffer[l] = '\0';
  1096.         path = buffer;
  1097.         break;
  1098.     /* FindFirstFile() is buggy with "x:", so add a dot :-( */
  1099.     case ':':
  1100.         if (l == 2 && isALPHA(path[0])) {
  1101.         buffer[0] = path[0];
  1102.         buffer[1] = ':';
  1103.         buffer[2] = '.';
  1104.         buffer[3] = '\0';
  1105.         l = 3;
  1106.         path = buffer;
  1107.         }
  1108.         break;
  1109.     }
  1110.     }
  1111.  
  1112.     /* We *must* open & close the file once; otherwise file attribute changes */
  1113.     /* might not yet have propagated to "other" hard links of the same file.  */
  1114.     /* This also gives us an opportunity to determine the number of links.    */
  1115.     if (USING_WIDE()) {
  1116.     A2WHELPER(path, wbuffer, sizeof(wbuffer));
  1117.     pwbuffer = PerlDir_mapW(wbuffer);
  1118.     handle = CreateFileW(pwbuffer, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
  1119.     }
  1120.     else {
  1121.     path = PerlDir_mapA(path);
  1122.     l = strlen(path);
  1123.     handle = CreateFileA(path, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
  1124.     }
  1125.     if (handle != INVALID_HANDLE_VALUE) {
  1126.     BY_HANDLE_FILE_INFORMATION bhi;
  1127.     if (GetFileInformationByHandle(handle, &bhi))
  1128.         nlink = bhi.nNumberOfLinks;
  1129.     CloseHandle(handle);
  1130.     }
  1131.  
  1132.     /* pwbuffer or path will be mapped correctly above */
  1133.     if (USING_WIDE()) {
  1134.     res = _wstat(pwbuffer, (struct _stat *)sbuf);
  1135.     }
  1136.     else {
  1137.     res = stat(path, sbuf);
  1138.     }
  1139.     sbuf->st_nlink = nlink;
  1140.  
  1141.     if (res < 0) {
  1142.     /* CRT is buggy on sharenames, so make sure it really isn't.
  1143.      * XXX using GetFileAttributesEx() will enable us to set
  1144.      * sbuf->st_*time (but note that's not available on the
  1145.      * Windows of 1995) */
  1146.     DWORD r;
  1147.     if (USING_WIDE()) {
  1148.         r = GetFileAttributesW(pwbuffer);
  1149.     }
  1150.     else {
  1151.         r = GetFileAttributesA(path);
  1152.     }
  1153.     if (r != 0xffffffff && (r & FILE_ATTRIBUTE_DIRECTORY)) {
  1154.         /* sbuf may still contain old garbage since stat() failed */
  1155.         Zero(sbuf, 1, struct stat);
  1156.         sbuf->st_mode = S_IFDIR | S_IREAD;
  1157.         errno = 0;
  1158.         if (!(r & FILE_ATTRIBUTE_READONLY))
  1159.         sbuf->st_mode |= S_IWRITE | S_IEXEC;
  1160.         return 0;
  1161.     }
  1162.     }
  1163.     else {
  1164.     if (l == 3 && isALPHA(path[0]) && path[1] == ':'
  1165.         && (path[2] == '\\' || path[2] == '/'))
  1166.     {
  1167.         /* The drive can be inaccessible, some _stat()s are buggy */
  1168.         if (USING_WIDE()
  1169.         ? !GetVolumeInformationW(pwbuffer,NULL,0,NULL,NULL,NULL,NULL,0)
  1170.         : !GetVolumeInformationA(path,NULL,0,NULL,NULL,NULL,NULL,0)) {
  1171.         errno = ENOENT;
  1172.         return -1;
  1173.         }
  1174.     }
  1175. #ifdef __BORLANDC__
  1176.     if (S_ISDIR(sbuf->st_mode))
  1177.         sbuf->st_mode |= S_IWRITE | S_IEXEC;
  1178.     else if (S_ISREG(sbuf->st_mode)) {
  1179.         int perms;
  1180.         if (l >= 4 && path[l-4] == '.') {
  1181.         const char *e = path + l - 3;
  1182.         if (strnicmp(e,"exe",3)
  1183.             && strnicmp(e,"bat",3)
  1184.             && strnicmp(e,"com",3)
  1185.             && (IsWin95() || strnicmp(e,"cmd",3)))
  1186.             sbuf->st_mode &= ~S_IEXEC;
  1187.         else
  1188.             sbuf->st_mode |= S_IEXEC;
  1189.         }
  1190.         else
  1191.         sbuf->st_mode &= ~S_IEXEC;
  1192.         /* Propagate permissions to _group_ and _others_ */
  1193.         perms = sbuf->st_mode & (S_IREAD|S_IWRITE|S_IEXEC);
  1194.         sbuf->st_mode |= (perms>>3) | (perms>>6);
  1195.     }
  1196. #endif
  1197.     }
  1198.     return res;
  1199. }
  1200.  
  1201. /* Find the longname of a given path.  path is destructively modified.
  1202.  * It should have space for at least MAX_PATH characters. */
  1203. DllExport char *
  1204. win32_longpath(char *path)
  1205. {
  1206.     WIN32_FIND_DATA fdata;
  1207.     HANDLE fhand;
  1208.     char tmpbuf[MAX_PATH+1];
  1209.     char *tmpstart = tmpbuf;
  1210.     char *start = path;
  1211.     char sep;
  1212.     if (!path)
  1213.     return Nullch;
  1214.  
  1215.     /* drive prefix */
  1216.     if (isALPHA(path[0]) && path[1] == ':' &&
  1217.     (path[2] == '/' || path[2] == '\\'))
  1218.     {
  1219.     start = path + 2;
  1220.     *tmpstart++ = path[0];
  1221.     *tmpstart++ = ':';
  1222.     }
  1223.     /* UNC prefix */
  1224.     else if ((path[0] == '/' || path[0] == '\\') &&
  1225.          (path[1] == '/' || path[1] == '\\'))
  1226.     {
  1227.     start = path + 2;
  1228.     *tmpstart++ = path[0];
  1229.     *tmpstart++ = path[1];
  1230.     /* copy machine name */
  1231.     while (*start && *start != '/' && *start != '\\')
  1232.         *tmpstart++ = *start++;
  1233.     if (*start) {
  1234.         *tmpstart++ = *start;
  1235.         start++;
  1236.         /* copy share name */
  1237.         while (*start && *start != '/' && *start != '\\')
  1238.         *tmpstart++ = *start++;
  1239.     }
  1240.     }
  1241.     sep = *start++;
  1242.     if (sep == '/' || sep == '\\')
  1243.     *tmpstart++ = sep;
  1244.     *tmpstart = '\0';
  1245.     while (sep) {
  1246.     /* walk up to slash */
  1247.     while (*start && *start != '/' && *start != '\\')
  1248.         ++start;
  1249.  
  1250.     /* discard doubled slashes */
  1251.     while (*start && (start[1] == '/' || start[1] == '\\'))
  1252.         ++start;
  1253.     sep = *start;
  1254.  
  1255.     /* stop and find full name of component */
  1256.     *start = '\0';
  1257.     fhand = FindFirstFile(path,&fdata);
  1258.     if (fhand != INVALID_HANDLE_VALUE) {
  1259.         strcpy(tmpstart, fdata.cFileName);
  1260.         tmpstart += strlen(fdata.cFileName);
  1261.         if (sep)
  1262.         *tmpstart++ = sep;
  1263.         *tmpstart = '\0';
  1264.         *start++ = sep;
  1265.         FindClose(fhand);
  1266.     }
  1267.     else {
  1268.         /* failed a step, just return without side effects */
  1269.         /*PerlIO_printf(Perl_debug_log, "Failed to find %s\n", path);*/
  1270.         *start = sep;
  1271.         return Nullch;
  1272.     }
  1273.     }
  1274.     strcpy(path,tmpbuf);
  1275.     return path;
  1276. }
  1277.  
  1278. #ifndef USE_WIN32_RTL_ENV
  1279.  
  1280. DllExport char *
  1281. win32_getenv(const char *name)
  1282. {
  1283.     dTHXo;
  1284.     WCHAR wBuffer[MAX_PATH+1];
  1285.     DWORD needlen;
  1286.     SV *curitem = Nullsv;
  1287.  
  1288.     if (USING_WIDE()) {
  1289.     A2WHELPER(name, wBuffer, sizeof(wBuffer));
  1290.     needlen = GetEnvironmentVariableW(wBuffer, NULL, 0);
  1291.     }
  1292.     else
  1293.     needlen = GetEnvironmentVariableA(name,NULL,0);
  1294.     if (needlen != 0) {
  1295.     curitem = sv_2mortal(newSVpvn("", 0));
  1296.     if (USING_WIDE()) {
  1297.         SV *acuritem;
  1298.         do {
  1299.         SvGROW(curitem, (needlen+1)*sizeof(WCHAR));
  1300.         needlen = GetEnvironmentVariableW(wBuffer,
  1301.                           (WCHAR*)SvPVX(curitem),
  1302.                           needlen);
  1303.         } while (needlen >= SvLEN(curitem)/sizeof(WCHAR));
  1304.         SvCUR_set(curitem, (needlen*sizeof(WCHAR))+1);
  1305.         acuritem = sv_2mortal(newSVsv(curitem));
  1306.         W2AHELPER((WCHAR*)SvPVX(acuritem), SvPVX(curitem), SvCUR(curitem));
  1307.     }
  1308.     else {
  1309.         do {
  1310.         SvGROW(curitem, needlen+1);
  1311.         needlen = GetEnvironmentVariableA(name,SvPVX(curitem),
  1312.                           needlen);
  1313.         } while (needlen >= SvLEN(curitem));
  1314.         SvCUR_set(curitem, needlen);
  1315.     }
  1316.     }
  1317.     else {
  1318.     /* allow any environment variables that begin with 'PERL'
  1319.        to be stored in the registry */
  1320.     if (strncmp(name, "PERL", 4) == 0)
  1321.         (void)get_regstr(name, &curitem);
  1322.     }
  1323.     if (curitem && SvCUR(curitem))
  1324.     return SvPVX(curitem);
  1325.  
  1326.     return Nullch;
  1327. }
  1328.  
  1329. DllExport int
  1330. win32_putenv(const char *name)
  1331. {
  1332.     dTHXo;
  1333.     char* curitem;
  1334.     char* val;
  1335.     WCHAR* wCuritem;
  1336.     WCHAR* wVal;
  1337.     int length, relval = -1;
  1338.  
  1339.     if (name) {
  1340.     if (USING_WIDE()) {
  1341.         length = strlen(name)+1;
  1342.         New(1309,wCuritem,length,WCHAR);
  1343.         A2WHELPER(name, wCuritem, length*sizeof(WCHAR));
  1344.         wVal = wcschr(wCuritem, '=');
  1345.         if (wVal) {
  1346.         *wVal++ = '\0';
  1347.         if (SetEnvironmentVariableW(wCuritem, *wVal ? wVal : NULL))
  1348.             relval = 0;
  1349.         }
  1350.         Safefree(wCuritem);
  1351.     }
  1352.     else {
  1353.         New(1309,curitem,strlen(name)+1,char);
  1354.         strcpy(curitem, name);
  1355.         val = strchr(curitem, '=');
  1356.         if (val) {
  1357.         /* The sane way to deal with the environment.
  1358.          * Has these advantages over putenv() & co.:
  1359.          *  * enables us to store a truly empty value in the
  1360.          *    environment (like in UNIX).
  1361.          *  * we don't have to deal with RTL globals, bugs and leaks.
  1362.          *  * Much faster.
  1363.          * Why you may want to enable USE_WIN32_RTL_ENV:
  1364.          *  * environ[] and RTL functions will not reflect changes,
  1365.          *    which might be an issue if extensions want to access
  1366.          *    the env. via RTL.  This cuts both ways, since RTL will
  1367.          *    not see changes made by extensions that call the Win32
  1368.          *    functions directly, either.
  1369.          * GSAR 97-06-07
  1370.          */
  1371.         *val++ = '\0';
  1372.         if (SetEnvironmentVariableA(curitem, *val ? val : NULL))
  1373.             relval = 0;
  1374.         }
  1375.         Safefree(curitem);
  1376.     }
  1377.     }
  1378.     return relval;
  1379. }
  1380.  
  1381. #endif
  1382.  
  1383. static long
  1384. filetime_to_clock(PFILETIME ft)
  1385. {
  1386.     __int64 qw = ft->dwHighDateTime;
  1387.     qw <<= 32;
  1388.     qw |= ft->dwLowDateTime;
  1389.     qw /= 10000;  /* File time ticks at 0.1uS, clock at 1mS */
  1390.     return (long) qw;
  1391. }
  1392.  
  1393. DllExport int
  1394. win32_times(struct tms *timebuf)
  1395. {
  1396.     FILETIME user;
  1397.     FILETIME kernel;
  1398.     FILETIME dummy;
  1399.     if (GetProcessTimes(GetCurrentProcess(), &dummy, &dummy, 
  1400.                         &kernel,&user)) {
  1401.     timebuf->tms_utime = filetime_to_clock(&user);
  1402.     timebuf->tms_stime = filetime_to_clock(&kernel);
  1403.     timebuf->tms_cutime = 0;
  1404.     timebuf->tms_cstime = 0;
  1405.         
  1406.     } else { 
  1407.         /* That failed - e.g. Win95 fallback to clock() */
  1408.         clock_t t = clock();
  1409.     timebuf->tms_utime = t;
  1410.     timebuf->tms_stime = 0;
  1411.     timebuf->tms_cutime = 0;
  1412.     timebuf->tms_cstime = 0;
  1413.     }
  1414.     return 0;
  1415. }
  1416.  
  1417. /* fix utime() so it works on directories in NT */
  1418. static BOOL
  1419. filetime_from_time(PFILETIME pFileTime, time_t Time)
  1420. {
  1421.     struct tm *pTM = localtime(&Time);
  1422.     SYSTEMTIME SystemTime;
  1423.     FILETIME LocalTime;
  1424.  
  1425.     if (pTM == NULL)
  1426.     return FALSE;
  1427.  
  1428.     SystemTime.wYear   = pTM->tm_year + 1900;
  1429.     SystemTime.wMonth  = pTM->tm_mon + 1;
  1430.     SystemTime.wDay    = pTM->tm_mday;
  1431.     SystemTime.wHour   = pTM->tm_hour;
  1432.     SystemTime.wMinute = pTM->tm_min;
  1433.     SystemTime.wSecond = pTM->tm_sec;
  1434.     SystemTime.wMilliseconds = 0;
  1435.  
  1436.     return SystemTimeToFileTime(&SystemTime, &LocalTime) &&
  1437.            LocalFileTimeToFileTime(&LocalTime, pFileTime);
  1438. }
  1439.  
  1440. DllExport int
  1441. win32_unlink(const char *filename)
  1442. {
  1443.     dTHXo;
  1444.     int ret;
  1445.     DWORD attrs;
  1446.  
  1447.     if (USING_WIDE()) {
  1448.     WCHAR wBuffer[MAX_PATH+1];
  1449.     WCHAR* pwBuffer;
  1450.  
  1451.     A2WHELPER(filename, wBuffer, sizeof(wBuffer));
  1452.     pwBuffer = PerlDir_mapW(wBuffer);
  1453.     attrs = GetFileAttributesW(pwBuffer);
  1454.     if (attrs == 0xFFFFFFFF)
  1455.         goto fail;
  1456.     if (attrs & FILE_ATTRIBUTE_READONLY) {
  1457.         (void)SetFileAttributesW(pwBuffer, attrs & ~FILE_ATTRIBUTE_READONLY);
  1458.         ret = _wunlink(pwBuffer);
  1459.         if (ret == -1)
  1460.         (void)SetFileAttributesW(pwBuffer, attrs);
  1461.     }
  1462.     else
  1463.         ret = _wunlink(pwBuffer);
  1464.     }
  1465.     else {
  1466.     filename = PerlDir_mapA(filename);
  1467.     attrs = GetFileAttributesA(filename);
  1468.     if (attrs == 0xFFFFFFFF)
  1469.         goto fail;
  1470.     if (attrs & FILE_ATTRIBUTE_READONLY) {
  1471.         (void)SetFileAttributesA(filename, attrs & ~FILE_ATTRIBUTE_READONLY);
  1472.         ret = unlink(filename);
  1473.         if (ret == -1)
  1474.         (void)SetFileAttributesA(filename, attrs);
  1475.     }
  1476.     else
  1477.         ret = unlink(filename);
  1478.     }
  1479.     return ret;
  1480. fail:
  1481.     errno = ENOENT;
  1482.     return -1;
  1483. }
  1484.  
  1485. DllExport int
  1486. win32_utime(const char *filename, struct utimbuf *times)
  1487. {
  1488.     dTHXo;
  1489.     HANDLE handle;
  1490.     FILETIME ftCreate;
  1491.     FILETIME ftAccess;
  1492.     FILETIME ftWrite;
  1493.     struct utimbuf TimeBuffer;
  1494.     WCHAR wbuffer[MAX_PATH+1];
  1495.     WCHAR* pwbuffer;
  1496.  
  1497.     int rc;
  1498.     if (USING_WIDE()) {
  1499.     A2WHELPER(filename, wbuffer, sizeof(wbuffer));
  1500.     pwbuffer = PerlDir_mapW(wbuffer);
  1501.     rc = _wutime(pwbuffer, (struct _utimbuf*)times);
  1502.     }
  1503.     else {
  1504.     filename = PerlDir_mapA(filename);
  1505.     rc = utime(filename, times);
  1506.     }
  1507.     /* EACCES: path specifies directory or readonly file */
  1508.     if (rc == 0 || errno != EACCES /* || !IsWinNT() */)
  1509.     return rc;
  1510.  
  1511.     if (times == NULL) {
  1512.     times = &TimeBuffer;
  1513.     time(×->actime);
  1514.     times->modtime = times->actime;
  1515.     }
  1516.  
  1517.     /* This will (and should) still fail on readonly files */
  1518.     if (USING_WIDE()) {
  1519.     handle = CreateFileW(pwbuffer, GENERIC_READ | GENERIC_WRITE,
  1520.                 FILE_SHARE_READ | FILE_SHARE_DELETE, NULL,
  1521.                 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
  1522.     }
  1523.     else {
  1524.     handle = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE,
  1525.                 FILE_SHARE_READ | FILE_SHARE_DELETE, NULL,
  1526.                 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
  1527.     }
  1528.     if (handle == INVALID_HANDLE_VALUE)
  1529.     return rc;
  1530.  
  1531.     if (GetFileTime(handle, &ftCreate, &ftAccess, &ftWrite) &&
  1532.     filetime_from_time(&ftAccess, times->actime) &&
  1533.     filetime_from_time(&ftWrite, times->modtime) &&
  1534.     SetFileTime(handle, &ftCreate, &ftAccess, &ftWrite))
  1535.     {
  1536.     rc = 0;
  1537.     }
  1538.  
  1539.     CloseHandle(handle);
  1540.     return rc;
  1541. }
  1542.  
  1543. DllExport int
  1544. win32_uname(struct utsname *name)
  1545. {
  1546.     struct hostent *hep;
  1547.     STRLEN nodemax = sizeof(name->nodename)-1;
  1548.     OSVERSIONINFO osver;
  1549.  
  1550.     memset(&osver, 0, sizeof(OSVERSIONINFO));
  1551.     osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  1552.     if (GetVersionEx(&osver)) {
  1553.     /* sysname */
  1554.     switch (osver.dwPlatformId) {
  1555.     case VER_PLATFORM_WIN32_WINDOWS:
  1556.         strcpy(name->sysname, "Windows");
  1557.         break;
  1558.     case VER_PLATFORM_WIN32_NT:
  1559.         strcpy(name->sysname, "Windows NT");
  1560.         break;
  1561.     case VER_PLATFORM_WIN32s:
  1562.         strcpy(name->sysname, "Win32s");
  1563.         break;
  1564.     default:
  1565.         strcpy(name->sysname, "Win32 Unknown");
  1566.         break;
  1567.     }
  1568.  
  1569.     /* release */
  1570.     sprintf(name->release, "%d.%d",
  1571.         osver.dwMajorVersion, osver.dwMinorVersion);
  1572.  
  1573.     /* version */
  1574.     sprintf(name->version, "Build %d",
  1575.         osver.dwPlatformId == VER_PLATFORM_WIN32_NT
  1576.         ? osver.dwBuildNumber : (osver.dwBuildNumber & 0xffff));
  1577.     if (osver.szCSDVersion[0]) {
  1578.         char *buf = name->version + strlen(name->version);
  1579.         sprintf(buf, " (%s)", osver.szCSDVersion);
  1580.     }
  1581.     }
  1582.     else {
  1583.     *name->sysname = '\0';
  1584.     *name->version = '\0';
  1585.     *name->release = '\0';
  1586.     }
  1587.  
  1588.     /* nodename */
  1589.     hep = win32_gethostbyname("localhost");
  1590.     if (hep) {
  1591.     STRLEN len = strlen(hep->h_name);
  1592.     if (len <= nodemax) {
  1593.         strcpy(name->nodename, hep->h_name);
  1594.     }
  1595.     else {
  1596.         strncpy(name->nodename, hep->h_name, nodemax);
  1597.         name->nodename[nodemax] = '\0';
  1598.     }
  1599.     }
  1600.     else {
  1601.     DWORD sz = nodemax;
  1602.     if (!GetComputerName(name->nodename, &sz))
  1603.         *name->nodename = '\0';
  1604.     }
  1605.  
  1606.     /* machine (architecture) */
  1607.     {
  1608.     SYSTEM_INFO info;
  1609.     char *arch;
  1610.     GetSystemInfo(&info);
  1611.  
  1612. #if defined(__BORLANDC__) || defined(__MINGW32__)
  1613.     switch (info.u.s.wProcessorArchitecture) {
  1614. #else
  1615.     switch (info.wProcessorArchitecture) {
  1616. #endif
  1617.     case PROCESSOR_ARCHITECTURE_INTEL:
  1618.         arch = "x86"; break;
  1619.     case PROCESSOR_ARCHITECTURE_MIPS:
  1620.         arch = "mips"; break;
  1621.     case PROCESSOR_ARCHITECTURE_ALPHA:
  1622.         arch = "alpha"; break;
  1623.     case PROCESSOR_ARCHITECTURE_PPC:
  1624.         arch = "ppc"; break;
  1625.     default:
  1626.         arch = "unknown"; break;
  1627.     }
  1628.     strcpy(name->machine, arch);
  1629.     }
  1630.     return 0;
  1631. }
  1632.  
  1633. DllExport int
  1634. win32_waitpid(int pid, int *status, int flags)
  1635. {
  1636.     dTHXo;
  1637.     int retval = -1;
  1638.     if (pid == -1)                /* XXX threadid == 1 ? */
  1639.     return win32_wait(status);
  1640. #ifdef USE_ITHREADS
  1641.     else if (pid < 0) {
  1642.     long child = find_pseudo_pid(-pid);
  1643.     if (child >= 0) {
  1644.         HANDLE hThread = w32_pseudo_child_handles[child];
  1645.         DWORD waitcode = WaitForSingleObject(hThread, INFINITE);
  1646.         if (waitcode != WAIT_FAILED) {
  1647.         if (GetExitCodeThread(hThread, &waitcode)) {
  1648.             *status = (int)((waitcode & 0xff) << 8);
  1649.             retval = (int)w32_pseudo_child_pids[child];
  1650.             remove_dead_pseudo_process(child);
  1651.             return retval;
  1652.         }
  1653.         }
  1654.         else
  1655.         errno = ECHILD;
  1656.     }
  1657.     }
  1658. #endif
  1659.     else {
  1660.     long child = find_pid(pid);
  1661.     if (child >= 0) {
  1662.         HANDLE hProcess = w32_child_handles[child];
  1663.         DWORD waitcode = WaitForSingleObject(hProcess, INFINITE);
  1664.         if (waitcode != WAIT_FAILED) {
  1665.         if (GetExitCodeProcess(hProcess, &waitcode)) {
  1666.             *status = (int)((waitcode & 0xff) << 8);
  1667.             retval = (int)w32_child_pids[child];
  1668.             remove_dead_process(child);
  1669.             return retval;
  1670.         }
  1671.         }
  1672.         else
  1673.         errno = ECHILD;
  1674.     }
  1675.     else {
  1676.         retval = cwait(status, pid, WAIT_CHILD);
  1677.         /* cwait() returns "correctly" on Borland */
  1678. #ifndef __BORLANDC__
  1679.         if (status)
  1680.         *status *= 256;
  1681. #endif
  1682.     }
  1683.     }
  1684.     return retval >= 0 ? pid : retval;                
  1685. }
  1686.  
  1687. DllExport int
  1688. win32_wait(int *status)
  1689. {
  1690.     /* XXX this wait emulation only knows about processes
  1691.      * spawned via win32_spawnvp(P_NOWAIT, ...).
  1692.      */
  1693.     dTHXo;
  1694.     int i, retval;
  1695.     DWORD exitcode, waitcode;
  1696.  
  1697. #ifdef USE_ITHREADS
  1698.     if (w32_num_pseudo_children) {
  1699.     waitcode = WaitForMultipleObjects(w32_num_pseudo_children,
  1700.                       w32_pseudo_child_handles,
  1701.                       FALSE,
  1702.                       INFINITE);
  1703.     if (waitcode != WAIT_FAILED) {
  1704.         if (waitcode >= WAIT_ABANDONED_0
  1705.         && waitcode < WAIT_ABANDONED_0 + w32_num_pseudo_children)
  1706.         i = waitcode - WAIT_ABANDONED_0;
  1707.         else
  1708.         i = waitcode - WAIT_OBJECT_0;
  1709.         if (GetExitCodeThread(w32_pseudo_child_handles[i], &exitcode)) {
  1710.         *status = (int)((exitcode & 0xff) << 8);
  1711.         retval = (int)w32_pseudo_child_pids[i];
  1712.         remove_dead_pseudo_process(i);
  1713.         return retval;
  1714.         }
  1715.     }
  1716.     }
  1717. #endif
  1718.  
  1719.     if (!w32_num_children) {
  1720.     errno = ECHILD;
  1721.     return -1;
  1722.     }
  1723.  
  1724.     /* if a child exists, wait for it to die */
  1725.     waitcode = WaitForMultipleObjects(w32_num_children,
  1726.                       w32_child_handles,
  1727.                       FALSE,
  1728.                       INFINITE);
  1729.     if (waitcode != WAIT_FAILED) {
  1730.     if (waitcode >= WAIT_ABANDONED_0
  1731.         && waitcode < WAIT_ABANDONED_0 + w32_num_children)
  1732.         i = waitcode - WAIT_ABANDONED_0;
  1733.     else
  1734.         i = waitcode - WAIT_OBJECT_0;
  1735.     if (GetExitCodeProcess(w32_child_handles[i], &exitcode) ) {
  1736.         *status = (int)((exitcode & 0xff) << 8);
  1737.         retval = (int)w32_child_pids[i];
  1738.         remove_dead_process(i);
  1739.         return retval;
  1740.     }
  1741.     }
  1742.  
  1743. FAILED:
  1744.     errno = GetLastError();
  1745.     return -1;
  1746. }
  1747.  
  1748. #ifndef PERL_OBJECT
  1749.  
  1750. static UINT timerid = 0;
  1751.  
  1752. static VOID CALLBACK TimerProc(HWND win, UINT msg, UINT id, DWORD time)
  1753. {
  1754.     dTHXo;
  1755.     KillTimer(NULL,timerid);
  1756.     timerid=0;  
  1757.     sighandler(14);
  1758. }
  1759. #endif    /* !PERL_OBJECT */
  1760.  
  1761. DllExport unsigned int
  1762. win32_alarm(unsigned int sec)
  1763. {
  1764. #ifndef PERL_OBJECT
  1765.     /* 
  1766.      * the 'obvious' implentation is SetTimer() with a callback
  1767.      * which does whatever receiving SIGALRM would do 
  1768.      * we cannot use SIGALRM even via raise() as it is not 
  1769.      * one of the supported codes in <signal.h>
  1770.      *
  1771.      * Snag is unless something is looking at the message queue
  1772.      * nothing happens :-(
  1773.      */ 
  1774.     dTHXo;
  1775.     if (sec)
  1776.      {
  1777.       timerid = SetTimer(NULL,timerid,sec*1000,(TIMERPROC)TimerProc);
  1778.       if (!timerid)
  1779.        Perl_croak_nocontext("Cannot set timer");
  1780.      } 
  1781.     else
  1782.      {
  1783.       if (timerid)
  1784.        {
  1785.         KillTimer(NULL,timerid);
  1786.         timerid=0;  
  1787.        }
  1788.      }
  1789. #endif    /* !PERL_OBJECT */
  1790.     return 0;
  1791. }
  1792.  
  1793. #ifdef HAVE_DES_FCRYPT
  1794. extern char *    des_fcrypt(const char *txt, const char *salt, char *cbuf);
  1795. #endif
  1796.  
  1797. DllExport char *
  1798. win32_crypt(const char *txt, const char *salt)
  1799. {
  1800.     dTHXo;
  1801. #ifdef HAVE_DES_FCRYPT
  1802.     dTHR;
  1803.     return des_fcrypt(txt, salt, w32_crypt_buffer);
  1804. #else
  1805.     Perl_croak(aTHX_ "The crypt() function is unimplemented due to excessive paranoia.");
  1806.     return Nullch;
  1807. #endif
  1808. }
  1809.  
  1810. /* C doesn't like repeat struct definitions */
  1811.  
  1812. #if defined(USE_FIXED_OSFHANDLE) || defined(PERL_MSVCRT_READFIX)
  1813.  
  1814. #ifndef _CRTIMP
  1815. #define _CRTIMP __declspec(dllimport)
  1816. #endif
  1817.  
  1818. /*
  1819.  * Control structure for lowio file handles
  1820.  */
  1821. typedef struct {
  1822.     long osfhnd;    /* underlying OS file HANDLE */
  1823.     char osfile;    /* attributes of file (e.g., open in text mode?) */
  1824.     char pipech;    /* one char buffer for handles opened on pipes */
  1825.     int lockinitflag;
  1826.     CRITICAL_SECTION lock;
  1827. } ioinfo;
  1828.  
  1829.  
  1830. /*
  1831.  * Array of arrays of control structures for lowio files.
  1832.  */
  1833. EXTERN_C _CRTIMP ioinfo* __pioinfo[];
  1834.  
  1835. /*
  1836.  * Definition of IOINFO_L2E, the log base 2 of the number of elements in each
  1837.  * array of ioinfo structs.
  1838.  */
  1839. #define IOINFO_L2E        5
  1840.  
  1841. /*
  1842.  * Definition of IOINFO_ARRAY_ELTS, the number of elements in ioinfo array
  1843.  */
  1844. #define IOINFO_ARRAY_ELTS   (1 << IOINFO_L2E)
  1845.  
  1846. /*
  1847.  * Access macros for getting at an ioinfo struct and its fields from a
  1848.  * file handle
  1849.  */
  1850. #define _pioinfo(i) (__pioinfo[(i) >> IOINFO_L2E] + ((i) & (IOINFO_ARRAY_ELTS - 1)))
  1851. #define _osfhnd(i)  (_pioinfo(i)->osfhnd)
  1852. #define _osfile(i)  (_pioinfo(i)->osfile)
  1853. #define _pipech(i)  (_pioinfo(i)->pipech)
  1854.  
  1855. #endif
  1856.  
  1857. #ifdef USE_FIXED_OSFHANDLE
  1858.  
  1859. #define FOPEN            0x01    /* file handle open */
  1860. #define FNOINHERIT        0x10    /* file handle opened O_NOINHERIT */
  1861. #define FAPPEND            0x20    /* file handle opened O_APPEND */
  1862. #define FDEV            0x40    /* file handle refers to device */
  1863. #define FTEXT            0x80    /* file handle is in text mode */
  1864.  
  1865. /***
  1866. *int my_open_osfhandle(long osfhandle, int flags) - open C Runtime file handle
  1867. *
  1868. *Purpose:
  1869. *       This function allocates a free C Runtime file handle and associates
  1870. *       it with the Win32 HANDLE specified by the first parameter. This is a
  1871. *    temperary fix for WIN95's brain damage GetFileType() error on socket
  1872. *    we just bypass that call for socket
  1873. *
  1874. *    This works with MSVC++ 4.0+ or GCC/Mingw32
  1875. *
  1876. *Entry:
  1877. *       long osfhandle - Win32 HANDLE to associate with C Runtime file handle.
  1878. *       int flags      - flags to associate with C Runtime file handle.
  1879. *
  1880. *Exit:
  1881. *       returns index of entry in fh, if successful
  1882. *       return -1, if no free entry is found
  1883. *
  1884. *Exceptions:
  1885. *
  1886. *******************************************************************************/
  1887.  
  1888. /*
  1889.  * we fake up some parts of the CRT that aren't exported by MSVCRT.dll
  1890.  * this lets sockets work on Win9X with GCC and should fix the problems
  1891.  * with perl95.exe
  1892.  *    -- BKS, 1-23-2000
  1893. */
  1894.  
  1895. /* since we are not doing a dup2(), this works fine */
  1896.  
  1897. #define _set_osfhnd(fh, osfh) (void)(_osfhnd(fh) = osfh)
  1898.  
  1899. /* create an ioinfo entry, kill its handle, and steal the entry */
  1900.  
  1901. static int
  1902. _alloc_osfhnd(void)
  1903. {
  1904.     HANDLE hF = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
  1905.     int fh = _open_osfhandle((long)hF, 0);
  1906.     CloseHandle(hF);
  1907.     if (fh == -1)
  1908.         return fh;
  1909.     EnterCriticalSection(&(_pioinfo(fh)->lock));
  1910.     return fh;
  1911. }
  1912.  
  1913. static int
  1914. my_open_osfhandle(long osfhandle, int flags)
  1915. {
  1916.     int fh;
  1917.     char fileflags;        /* _osfile flags */
  1918.  
  1919.     /* copy relevant flags from second parameter */
  1920.     fileflags = FDEV;
  1921.  
  1922.     if (flags & O_APPEND)
  1923.     fileflags |= FAPPEND;
  1924.  
  1925.     if (flags & O_TEXT)
  1926.     fileflags |= FTEXT;
  1927.  
  1928.     if (flags & O_NOINHERIT)
  1929.     fileflags |= FNOINHERIT;
  1930.  
  1931.     /* attempt to allocate a C Runtime file handle */
  1932.     if ((fh = _alloc_osfhnd()) == -1) {
  1933.     errno = EMFILE;        /* too many open files */
  1934.     _doserrno = 0L;        /* not an OS error */
  1935.     return -1;        /* return error to caller */
  1936.     }
  1937.  
  1938.     /* the file is open. now, set the info in _osfhnd array */
  1939.     _set_osfhnd(fh, osfhandle);
  1940.  
  1941.     fileflags |= FOPEN;        /* mark as open */
  1942.  
  1943.     _osfile(fh) = fileflags;    /* set osfile entry */
  1944.     LeaveCriticalSection(&_pioinfo(fh)->lock);
  1945.  
  1946.     return fh;            /* return handle */
  1947. }
  1948.  
  1949. #endif    /* USE_FIXED_OSFHANDLE */
  1950.  
  1951. /* simulate flock by locking a range on the file */
  1952.  
  1953. #define LK_ERR(f,i)    ((f) ? (i = 0) : (errno = GetLastError()))
  1954. #define LK_LEN        0xffff0000
  1955.  
  1956. DllExport int
  1957. win32_flock(int fd, int oper)
  1958. {
  1959.     OVERLAPPED o;
  1960.     int i = -1;
  1961.     HANDLE fh;
  1962.  
  1963.     if (!IsWinNT()) {
  1964.     dTHXo;
  1965.     Perl_croak_nocontext("flock() unimplemented on this platform");
  1966.     return -1;
  1967.     }
  1968.     fh = (HANDLE)_get_osfhandle(fd);
  1969.     memset(&o, 0, sizeof(o));
  1970.  
  1971.     switch(oper) {
  1972.     case LOCK_SH:        /* shared lock */
  1973.     LK_ERR(LockFileEx(fh, 0, 0, LK_LEN, 0, &o),i);
  1974.     break;
  1975.     case LOCK_EX:        /* exclusive lock */
  1976.     LK_ERR(LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, LK_LEN, 0, &o),i);
  1977.     break;
  1978.     case LOCK_SH|LOCK_NB:    /* non-blocking shared lock */
  1979.     LK_ERR(LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY, 0, LK_LEN, 0, &o),i);
  1980.     break;
  1981.     case LOCK_EX|LOCK_NB:    /* non-blocking exclusive lock */
  1982.     LK_ERR(LockFileEx(fh,
  1983.                LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY,
  1984.                0, LK_LEN, 0, &o),i);
  1985.     break;
  1986.     case LOCK_UN:        /* unlock lock */
  1987.     LK_ERR(UnlockFileEx(fh, 0, LK_LEN, 0, &o),i);
  1988.     break;
  1989.     default:            /* unknown */
  1990.     errno = EINVAL;
  1991.     break;
  1992.     }
  1993.     return i;
  1994. }
  1995.  
  1996. #undef LK_ERR
  1997. #undef LK_LEN
  1998.  
  1999. /*
  2000.  *  redirected io subsystem for all XS modules
  2001.  *
  2002.  */
  2003.  
  2004. DllExport int *
  2005. win32_errno(void)
  2006. {
  2007.     return (&errno);
  2008. }
  2009.  
  2010. DllExport char ***
  2011. win32_environ(void)
  2012. {
  2013.     return (&(_environ));
  2014. }
  2015.  
  2016. /* the rest are the remapped stdio routines */
  2017. DllExport FILE *
  2018. win32_stderr(void)
  2019. {
  2020.     return (stderr);
  2021. }
  2022.  
  2023. DllExport FILE *
  2024. win32_stdin(void)
  2025. {
  2026.     return (stdin);
  2027. }
  2028.  
  2029. DllExport FILE *
  2030. win32_stdout()
  2031. {
  2032.     return (stdout);
  2033. }
  2034.  
  2035. DllExport int
  2036. win32_ferror(FILE *fp)
  2037. {
  2038.     return (ferror(fp));
  2039. }
  2040.  
  2041.  
  2042. DllExport int
  2043. win32_feof(FILE *fp)
  2044. {
  2045.     return (feof(fp));
  2046. }
  2047.  
  2048. /*
  2049.  * Since the errors returned by the socket error function 
  2050.  * WSAGetLastError() are not known by the library routine strerror
  2051.  * we have to roll our own.
  2052.  */
  2053.  
  2054. DllExport char *
  2055. win32_strerror(int e) 
  2056. {
  2057. #ifndef __BORLANDC__        /* Borland intolerance */
  2058.     extern int sys_nerr;
  2059. #endif
  2060.     DWORD source = 0;
  2061.  
  2062.     if (e < 0 || e > sys_nerr) {
  2063.         dTHXo;
  2064.     if (e < 0)
  2065.         e = GetLastError();
  2066.  
  2067.     if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, &source, e, 0,
  2068.               w32_strerror_buffer,
  2069.               sizeof(w32_strerror_buffer), NULL) == 0) 
  2070.         strcpy(w32_strerror_buffer, "Unknown Error");
  2071.  
  2072.     return w32_strerror_buffer;
  2073.     }
  2074.     return strerror(e);
  2075. }
  2076.  
  2077. DllExport void
  2078. win32_str_os_error(void *sv, DWORD dwErr)
  2079. {
  2080.     DWORD dwLen;
  2081.     char *sMsg;
  2082.     dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
  2083.               |FORMAT_MESSAGE_IGNORE_INSERTS
  2084.               |FORMAT_MESSAGE_FROM_SYSTEM, NULL,
  2085.                dwErr, 0, (char *)&sMsg, 1, NULL);
  2086.     /* strip trailing whitespace and period */
  2087.     if (0 < dwLen) {
  2088.     do {
  2089.         --dwLen;    /* dwLen doesn't include trailing null */
  2090.     } while (0 < dwLen && isSPACE(sMsg[dwLen]));
  2091.     if ('.' != sMsg[dwLen])
  2092.         dwLen++;
  2093.     sMsg[dwLen] = '\0';
  2094.     }
  2095.     if (0 == dwLen) {
  2096.     sMsg = (char*)LocalAlloc(0, 64/**sizeof(TCHAR)*/);
  2097.     if (sMsg)
  2098.         dwLen = sprintf(sMsg,
  2099.                 "Unknown error #0x%lX (lookup 0x%lX)",
  2100.                 dwErr, GetLastError());
  2101.     }
  2102.     if (sMsg) {
  2103.     dTHXo;
  2104.     sv_setpvn((SV*)sv, sMsg, dwLen);
  2105.     LocalFree(sMsg);
  2106.     }
  2107. }
  2108.  
  2109.  
  2110. DllExport int
  2111. win32_fprintf(FILE *fp, const char *format, ...)
  2112. {
  2113.     va_list marker;
  2114.     va_start(marker, format);     /* Initialize variable arguments. */
  2115.  
  2116.     return (vfprintf(fp, format, marker));
  2117. }
  2118.  
  2119. DllExport int
  2120. win32_printf(const char *format, ...)
  2121. {
  2122.     va_list marker;
  2123.     va_start(marker, format);     /* Initialize variable arguments. */
  2124.  
  2125.     return (vprintf(format, marker));
  2126. }
  2127.  
  2128. DllExport int
  2129. win32_vfprintf(FILE *fp, const char *format, va_list args)
  2130. {
  2131.     return (vfprintf(fp, format, args));
  2132. }
  2133.  
  2134. DllExport int
  2135. win32_vprintf(const char *format, va_list args)
  2136. {
  2137.     return (vprintf(format, args));
  2138. }
  2139.  
  2140. DllExport size_t
  2141. win32_fread(void *buf, size_t size, size_t count, FILE *fp)
  2142. {
  2143.     return fread(buf, size, count, fp);
  2144. }
  2145.  
  2146. DllExport size_t
  2147. win32_fwrite(const void *buf, size_t size, size_t count, FILE *fp)
  2148. {
  2149.     return fwrite(buf, size, count, fp);
  2150. }
  2151.  
  2152. #define MODE_SIZE 10
  2153.  
  2154. DllExport FILE *
  2155. win32_fopen(const char *filename, const char *mode)
  2156. {
  2157.     dTHXo;
  2158.     WCHAR wMode[MODE_SIZE], wBuffer[MAX_PATH+1];
  2159.     FILE *f;
  2160.     
  2161.     if (!*filename)
  2162.     return NULL;
  2163.  
  2164.     if (stricmp(filename, "/dev/null")==0)
  2165.     filename = "NUL";
  2166.  
  2167.     if (USING_WIDE()) {
  2168.     A2WHELPER(mode, wMode, sizeof(wMode));
  2169.     A2WHELPER(filename, wBuffer, sizeof(wBuffer));
  2170.     f = _wfopen(PerlDir_mapW(wBuffer), wMode);
  2171.     }
  2172.     else
  2173.     f = fopen(PerlDir_mapA(filename), mode);
  2174.     /* avoid buffering headaches for child processes */
  2175.     if (f && *mode == 'a')
  2176.     win32_fseek(f, 0, SEEK_END);
  2177.     return f;
  2178. }
  2179.  
  2180. #ifndef USE_SOCKETS_AS_HANDLES
  2181. #undef fdopen
  2182. #define fdopen my_fdopen
  2183. #endif
  2184.  
  2185. DllExport FILE *
  2186. win32_fdopen(int handle, const char *mode)
  2187. {
  2188.     dTHXo;
  2189.     WCHAR wMode[MODE_SIZE];
  2190.     FILE *f;
  2191.     if (USING_WIDE()) {
  2192.     A2WHELPER(mode, wMode, sizeof(wMode));
  2193.     f = _wfdopen(handle, wMode);
  2194.     }
  2195.     else
  2196.     f = fdopen(handle, (char *) mode);
  2197.     /* avoid buffering headaches for child processes */
  2198.     if (f && *mode == 'a')
  2199.     win32_fseek(f, 0, SEEK_END);
  2200.     return f;
  2201. }
  2202.  
  2203. DllExport FILE *
  2204. win32_freopen(const char *path, const char *mode, FILE *stream)
  2205. {
  2206.     dTHXo;
  2207.     WCHAR wMode[MODE_SIZE], wBuffer[MAX_PATH+1];
  2208.     if (stricmp(path, "/dev/null")==0)
  2209.     path = "NUL";
  2210.  
  2211.     if (USING_WIDE()) {
  2212.     A2WHELPER(mode, wMode, sizeof(wMode));
  2213.     A2WHELPER(path, wBuffer, sizeof(wBuffer));
  2214.     return _wfreopen(PerlDir_mapW(wBuffer), wMode, stream);
  2215.     }
  2216.     return freopen(PerlDir_mapA(path), mode, stream);
  2217. }
  2218.  
  2219. DllExport int
  2220. win32_fclose(FILE *pf)
  2221. {
  2222.     return my_fclose(pf);    /* defined in win32sck.c */
  2223. }
  2224.  
  2225. DllExport int
  2226. win32_fputs(const char *s,FILE *pf)
  2227. {
  2228.     return fputs(s, pf);
  2229. }
  2230.  
  2231. DllExport int
  2232. win32_fputc(int c,FILE *pf)
  2233. {
  2234.     return fputc(c,pf);
  2235. }
  2236.  
  2237. DllExport int
  2238. win32_ungetc(int c,FILE *pf)
  2239. {
  2240.     return ungetc(c,pf);
  2241. }
  2242.  
  2243. DllExport int
  2244. win32_getc(FILE *pf)
  2245. {
  2246.     return getc(pf);
  2247. }
  2248.  
  2249. DllExport int
  2250. win32_fileno(FILE *pf)
  2251. {
  2252.     return fileno(pf);
  2253. }
  2254.  
  2255. DllExport void
  2256. win32_clearerr(FILE *pf)
  2257. {
  2258.     clearerr(pf);
  2259.     return;
  2260. }
  2261.  
  2262. DllExport int
  2263. win32_fflush(FILE *pf)
  2264. {
  2265.     return fflush(pf);
  2266. }
  2267.  
  2268. DllExport long
  2269. win32_ftell(FILE *pf)
  2270. {
  2271.     return ftell(pf);
  2272. }
  2273.  
  2274. DllExport int
  2275. win32_fseek(FILE *pf,long offset,int origin)
  2276. {
  2277.     return fseek(pf, offset, origin);
  2278. }
  2279.  
  2280. DllExport int
  2281. win32_fgetpos(FILE *pf,fpos_t *p)
  2282. {
  2283.     return fgetpos(pf, p);
  2284. }
  2285.  
  2286. DllExport int
  2287. win32_fsetpos(FILE *pf,const fpos_t *p)
  2288. {
  2289.     return fsetpos(pf, p);
  2290. }
  2291.  
  2292. DllExport void
  2293. win32_rewind(FILE *pf)
  2294. {
  2295.     rewind(pf);
  2296.     return;
  2297. }
  2298.  
  2299. DllExport FILE*
  2300. win32_tmpfile(void)
  2301. {
  2302.     return tmpfile();
  2303. }
  2304.  
  2305. DllExport void
  2306. win32_abort(void)
  2307. {
  2308.     abort();
  2309.     return;
  2310. }
  2311.  
  2312. DllExport int
  2313. win32_fstat(int fd,struct stat *sbufptr)
  2314. {
  2315.     return fstat(fd,sbufptr);
  2316. }
  2317.  
  2318. DllExport int
  2319. win32_pipe(int *pfd, unsigned int size, int mode)
  2320. {
  2321.     return _pipe(pfd, size, mode);
  2322. }
  2323.  
  2324. /*
  2325.  * a popen() clone that respects PERL5SHELL
  2326.  */
  2327.  
  2328. DllExport FILE*
  2329. win32_popen(const char *command, const char *mode)
  2330. {
  2331. #ifdef USE_RTL_POPEN
  2332.     return _popen(command, mode);
  2333. #else
  2334.     int p[2];
  2335.     int parent, child;
  2336.     int stdfd, oldfd;
  2337.     int ourmode;
  2338.     int childpid;
  2339.  
  2340.     /* establish which ends read and write */
  2341.     if (strchr(mode,'w')) {
  2342.         stdfd = 0;        /* stdin */
  2343.         parent = 1;
  2344.         child = 0;
  2345.     }
  2346.     else if (strchr(mode,'r')) {
  2347.         stdfd = 1;        /* stdout */
  2348.         parent = 0;
  2349.         child = 1;
  2350.     }
  2351.     else
  2352.         return NULL;
  2353.  
  2354.     /* set the correct mode */
  2355.     if (strchr(mode,'b'))
  2356.         ourmode = O_BINARY;
  2357.     else if (strchr(mode,'t'))
  2358.         ourmode = O_TEXT;
  2359.     else
  2360.         ourmode = _fmode & (O_TEXT | O_BINARY);
  2361.  
  2362.     /* the child doesn't inherit handles */
  2363.     ourmode |= O_NOINHERIT;
  2364.  
  2365.     if (win32_pipe( p, 512, ourmode) == -1)
  2366.         return NULL;
  2367.  
  2368.     /* save current stdfd */
  2369.     if ((oldfd = win32_dup(stdfd)) == -1)
  2370.         goto cleanup;
  2371.  
  2372.     /* make stdfd go to child end of pipe (implicitly closes stdfd) */
  2373.     /* stdfd will be inherited by the child */
  2374.     if (win32_dup2(p[child], stdfd) == -1)
  2375.         goto cleanup;
  2376.  
  2377.     /* close the child end in parent */
  2378.     win32_close(p[child]);
  2379.  
  2380.     /* start the child */
  2381.     {
  2382.     dTHXo;
  2383.     if ((childpid = do_spawn_nowait((char*)command)) == -1)
  2384.         goto cleanup;
  2385.  
  2386.     /* revert stdfd to whatever it was before */
  2387.     if (win32_dup2(oldfd, stdfd) == -1)
  2388.         goto cleanup;
  2389.  
  2390.     /* close saved handle */
  2391.     win32_close(oldfd);
  2392.  
  2393.     sv_setiv(*av_fetch(w32_fdpid, p[parent], TRUE), childpid);
  2394.  
  2395.     /* set process id so that it can be returned by perl's open() */
  2396.     PL_forkprocess = childpid;
  2397.     }
  2398.  
  2399.     /* we have an fd, return a file stream */
  2400.     return (win32_fdopen(p[parent], (char *)mode));
  2401.  
  2402. cleanup:
  2403.     /* we don't need to check for errors here */
  2404.     win32_close(p[0]);
  2405.     win32_close(p[1]);
  2406.     if (oldfd != -1) {
  2407.         win32_dup2(oldfd, stdfd);
  2408.         win32_close(oldfd);
  2409.     }
  2410.     return (NULL);
  2411.  
  2412. #endif /* USE_RTL_POPEN */
  2413. }
  2414.  
  2415. /*
  2416.  * pclose() clone
  2417.  */
  2418.  
  2419. DllExport int
  2420. win32_pclose(FILE *pf)
  2421. {
  2422. #ifdef USE_RTL_POPEN
  2423.     return _pclose(pf);
  2424. #else
  2425.     dTHXo;
  2426.     int childpid, status;
  2427.     SV *sv;
  2428.  
  2429.     sv = *av_fetch(w32_fdpid, win32_fileno(pf), TRUE);
  2430.     if (SvIOK(sv))
  2431.     childpid = SvIVX(sv);
  2432.     else
  2433.     childpid = 0;
  2434.  
  2435.     if (!childpid) {
  2436.     errno = EBADF;
  2437.         return -1;
  2438.     }
  2439.  
  2440.     win32_fclose(pf);
  2441.     SvIVX(sv) = 0;
  2442.  
  2443.     if (win32_waitpid(childpid, &status, 0) == -1)
  2444.         return -1;
  2445.  
  2446.     return status;
  2447.  
  2448. #endif /* USE_RTL_POPEN */
  2449. }
  2450.  
  2451. static BOOL WINAPI
  2452. Nt4CreateHardLinkW(
  2453.     LPCWSTR lpFileName,
  2454.     LPCWSTR lpExistingFileName,
  2455.     LPSECURITY_ATTRIBUTES lpSecurityAttributes)
  2456. {
  2457.     HANDLE handle;
  2458.     WCHAR wFullName[MAX_PATH+1];
  2459.     LPVOID lpContext = NULL;
  2460.     WIN32_STREAM_ID StreamId;
  2461.     DWORD dwSize = (char*)&StreamId.cStreamName - (char*)&StreamId;
  2462.     DWORD dwWritten;
  2463.     DWORD dwLen;
  2464.     BOOL bSuccess;
  2465.  
  2466.     BOOL (__stdcall *pfnBackupWrite)(HANDLE, LPBYTE, DWORD, LPDWORD,
  2467.                      BOOL, BOOL, LPVOID*) =
  2468.     (BOOL (__stdcall *)(HANDLE, LPBYTE, DWORD, LPDWORD,
  2469.                 BOOL, BOOL, LPVOID*))
  2470.     GetProcAddress(GetModuleHandle("kernel32.dll"), "BackupWrite");
  2471.     if (pfnBackupWrite == NULL)
  2472.     return 0;
  2473.  
  2474.     dwLen = GetFullPathNameW(lpFileName, MAX_PATH, wFullName, NULL);
  2475.     if (dwLen == 0)
  2476.     return 0;
  2477.     dwLen = (dwLen+1)*sizeof(WCHAR);
  2478.  
  2479.     handle = CreateFileW(lpExistingFileName, FILE_WRITE_ATTRIBUTES,
  2480.              FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  2481.              NULL, OPEN_EXISTING, 0, NULL);
  2482.     if (handle == INVALID_HANDLE_VALUE)
  2483.     return 0;
  2484.  
  2485.     StreamId.dwStreamId = BACKUP_LINK;
  2486.     StreamId.dwStreamAttributes = 0;
  2487.     StreamId.dwStreamNameSize = 0;
  2488. #if defined(__BORLANDC__) || defined(__MINGW32__)
  2489.     StreamId.Size.u.HighPart = 0;
  2490.     StreamId.Size.u.LowPart = dwLen;
  2491. #else
  2492.     StreamId.Size.HighPart = 0;
  2493.     StreamId.Size.LowPart = dwLen;
  2494. #endif
  2495.  
  2496.     bSuccess = pfnBackupWrite(handle, (LPBYTE)&StreamId, dwSize, &dwWritten,
  2497.                   FALSE, FALSE, &lpContext);
  2498.     if (bSuccess) {
  2499.     bSuccess = pfnBackupWrite(handle, (LPBYTE)wFullName, dwLen, &dwWritten,
  2500.                   FALSE, FALSE, &lpContext);
  2501.     pfnBackupWrite(handle, NULL, 0, &dwWritten, TRUE, FALSE, &lpContext);
  2502.     }
  2503.  
  2504.     CloseHandle(handle);
  2505.     return bSuccess;
  2506. }
  2507.  
  2508. DllExport int
  2509. win32_link(const char *oldname, const char *newname)
  2510. {
  2511.     dTHXo;
  2512.     BOOL (__stdcall *pfnCreateHardLinkW)(LPCWSTR,LPCWSTR,LPSECURITY_ATTRIBUTES);
  2513.     WCHAR wOldName[MAX_PATH+1];
  2514.     WCHAR wNewName[MAX_PATH+1];
  2515.  
  2516.     if (IsWin95())
  2517.     Perl_croak(aTHX_ PL_no_func, "link");
  2518.  
  2519.     pfnCreateHardLinkW =
  2520.     (BOOL (__stdcall *)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES))
  2521.     GetProcAddress(GetModuleHandle("kernel32.dll"), "CreateHardLinkW");
  2522.     if (pfnCreateHardLinkW == NULL)
  2523.     pfnCreateHardLinkW = Nt4CreateHardLinkW;
  2524.  
  2525.     if ((A2WHELPER(oldname, wOldName, sizeof(wOldName))) &&
  2526.     (A2WHELPER(newname, wNewName, sizeof(wNewName))) &&
  2527.     (wcscpy(wOldName, PerlDir_mapW(wOldName)),
  2528.     pfnCreateHardLinkW(PerlDir_mapW(wNewName), wOldName, NULL)))
  2529.     {
  2530.     return 0;
  2531.     }
  2532.     errno = (GetLastError() == ERROR_FILE_NOT_FOUND) ? ENOENT : EINVAL;
  2533.     return -1;
  2534. }
  2535.  
  2536. DllExport int
  2537. win32_rename(const char *oname, const char *newname)
  2538. {
  2539.     WCHAR wOldName[MAX_PATH+1];
  2540.     WCHAR wNewName[MAX_PATH+1];
  2541.     char szOldName[MAX_PATH+1];
  2542.     char szNewName[MAX_PATH+1];
  2543.     BOOL bResult;
  2544.     dTHXo;
  2545.  
  2546.     /* XXX despite what the documentation says about MoveFileEx(),
  2547.      * it doesn't work under Windows95!
  2548.      */
  2549.     if (IsWinNT()) {
  2550.     DWORD dwFlags = MOVEFILE_COPY_ALLOWED;
  2551.     if (USING_WIDE()) {
  2552.         A2WHELPER(oname, wOldName, sizeof(wOldName));
  2553.         A2WHELPER(newname, wNewName, sizeof(wNewName));
  2554.         if (wcsicmp(wNewName, wOldName))
  2555.         dwFlags |= MOVEFILE_REPLACE_EXISTING;
  2556.         wcscpy(wOldName, PerlDir_mapW(wOldName));
  2557.         bResult = MoveFileExW(wOldName,PerlDir_mapW(wNewName), dwFlags);
  2558.     }
  2559.     else {
  2560.         if (stricmp(newname, oname))
  2561.         dwFlags |= MOVEFILE_REPLACE_EXISTING;
  2562.         strcpy(szOldName, PerlDir_mapA(oname));
  2563.         bResult = MoveFileExA(szOldName,PerlDir_mapA(newname), dwFlags);
  2564.     }
  2565.     if (!bResult) {
  2566.         DWORD err = GetLastError();
  2567.         switch (err) {
  2568.         case ERROR_BAD_NET_NAME:
  2569.         case ERROR_BAD_NETPATH:
  2570.         case ERROR_BAD_PATHNAME:
  2571.         case ERROR_FILE_NOT_FOUND:
  2572.         case ERROR_FILENAME_EXCED_RANGE:
  2573.         case ERROR_INVALID_DRIVE:
  2574.         case ERROR_NO_MORE_FILES:
  2575.         case ERROR_PATH_NOT_FOUND:
  2576.         errno = ENOENT;
  2577.         break;
  2578.         default:
  2579.         errno = EACCES;
  2580.         break;
  2581.         }
  2582.         return -1;
  2583.     }
  2584.     return 0;
  2585.     }
  2586.     else {
  2587.     int retval = 0;
  2588.     char szTmpName[MAX_PATH+1];
  2589.     char dname[MAX_PATH+1];
  2590.     char *endname = Nullch;
  2591.     STRLEN tmplen = 0;
  2592.     DWORD from_attr, to_attr;
  2593.  
  2594.     strcpy(szOldName, PerlDir_mapA(oname));
  2595.     strcpy(szNewName, PerlDir_mapA(newname));
  2596.  
  2597.     /* if oname doesn't exist, do nothing */
  2598.     from_attr = GetFileAttributes(szOldName);
  2599.     if (from_attr == 0xFFFFFFFF) {
  2600.         errno = ENOENT;
  2601.         return -1;
  2602.     }
  2603.  
  2604.     /* if newname exists, rename it to a temporary name so that we
  2605.      * don't delete it in case oname happens to be the same file
  2606.      * (but perhaps accessed via a different path)
  2607.      */
  2608.     to_attr = GetFileAttributes(szNewName);
  2609.     if (to_attr != 0xFFFFFFFF) {
  2610.         /* if newname is a directory, we fail
  2611.          * XXX could overcome this with yet more convoluted logic */
  2612.         if (to_attr & FILE_ATTRIBUTE_DIRECTORY) {
  2613.         errno = EACCES;
  2614.         return -1;
  2615.         }
  2616.         tmplen = strlen(szNewName);
  2617.         strcpy(szTmpName,szNewName);
  2618.         endname = szTmpName+tmplen;
  2619.         for (; endname > szTmpName ; --endname) {
  2620.         if (*endname == '/' || *endname == '\\') {
  2621.             *endname = '\0';
  2622.             break;
  2623.         }
  2624.         }
  2625.         if (endname > szTmpName)
  2626.         endname = strcpy(dname,szTmpName);
  2627.         else
  2628.         endname = ".";
  2629.  
  2630.         /* get a temporary filename in same directory
  2631.          * XXX is this really the best we can do? */
  2632.         if (!GetTempFileName((LPCTSTR)endname, "plr", 0, szTmpName)) {
  2633.         errno = ENOENT;
  2634.         return -1;
  2635.         }
  2636.         DeleteFile(szTmpName);
  2637.  
  2638.         retval = rename(szNewName, szTmpName);
  2639.         if (retval != 0) {
  2640.         errno = EACCES;
  2641.         return retval;
  2642.         }
  2643.     }
  2644.  
  2645.     /* rename oname to newname */
  2646.     retval = rename(szOldName, szNewName);
  2647.  
  2648.     /* if we created a temporary file before ... */
  2649.     if (endname != Nullch) {
  2650.         /* ...and rename succeeded, delete temporary file/directory */
  2651.         if (retval == 0)
  2652.         DeleteFile(szTmpName);
  2653.         /* else restore it to what it was */
  2654.         else
  2655.         (void)rename(szTmpName, szNewName);
  2656.     }
  2657.     return retval;
  2658.     }
  2659. }
  2660.  
  2661. DllExport int
  2662. win32_setmode(int fd, int mode)
  2663. {
  2664.     return setmode(fd, mode);
  2665. }
  2666.  
  2667. DllExport long
  2668. win32_lseek(int fd, long offset, int origin)
  2669. {
  2670.     return lseek(fd, offset, origin);
  2671. }
  2672.  
  2673. DllExport long
  2674. win32_tell(int fd)
  2675. {
  2676.     return tell(fd);
  2677. }
  2678.  
  2679. DllExport int
  2680. win32_open(const char *path, int flag, ...)
  2681. {
  2682.     dTHXo;
  2683.     va_list ap;
  2684.     int pmode;
  2685.     WCHAR wBuffer[MAX_PATH+1];
  2686.  
  2687.     va_start(ap, flag);
  2688.     pmode = va_arg(ap, int);
  2689.     va_end(ap);
  2690.  
  2691.     if (stricmp(path, "/dev/null")==0)
  2692.     path = "NUL";
  2693.  
  2694.     if (USING_WIDE()) {
  2695.     A2WHELPER(path, wBuffer, sizeof(wBuffer));
  2696.     return _wopen(PerlDir_mapW(wBuffer), flag, pmode);
  2697.     }
  2698.     return open(PerlDir_mapA(path), flag, pmode);
  2699. }
  2700.  
  2701. DllExport int
  2702. win32_close(int fd)
  2703. {
  2704.     return close(fd);
  2705. }
  2706.  
  2707. DllExport int
  2708. win32_eof(int fd)
  2709. {
  2710.     return eof(fd);
  2711. }
  2712.  
  2713. DllExport int
  2714. win32_dup(int fd)
  2715. {
  2716.     return dup(fd);
  2717. }
  2718.  
  2719. DllExport int
  2720. win32_dup2(int fd1,int fd2)
  2721. {
  2722.     return dup2(fd1,fd2);
  2723. }
  2724.  
  2725. #ifdef PERL_MSVCRT_READFIX
  2726.  
  2727. #define LF        10    /* line feed */
  2728. #define CR        13    /* carriage return */
  2729. #define CTRLZ        26      /* ctrl-z means eof for text */
  2730. #define FOPEN        0x01    /* file handle open */
  2731. #define FEOFLAG        0x02    /* end of file has been encountered */
  2732. #define FCRLF        0x04    /* CR-LF across read buffer (in text mode) */
  2733. #define FPIPE        0x08    /* file handle refers to a pipe */
  2734. #define FAPPEND        0x20    /* file handle opened O_APPEND */
  2735. #define FDEV        0x40    /* file handle refers to device */
  2736. #define FTEXT        0x80    /* file handle is in text mode */
  2737. #define MAX_DESCRIPTOR_COUNT    (64*32) /* this is the maximun that MSVCRT can handle */
  2738.  
  2739. int __cdecl
  2740. _fixed_read(int fh, void *buf, unsigned cnt)
  2741. {
  2742.     int bytes_read;                 /* number of bytes read */
  2743.     char *buffer;                   /* buffer to read to */
  2744.     int os_read;                    /* bytes read on OS call */
  2745.     char *p, *q;                    /* pointers into buffer */
  2746.     char peekchr;                   /* peek-ahead character */
  2747.     ULONG filepos;                  /* file position after seek */
  2748.     ULONG dosretval;                /* o.s. return value */
  2749.  
  2750.     /* validate handle */
  2751.     if (((unsigned)fh >= (unsigned)MAX_DESCRIPTOR_COUNT) ||
  2752.          !(_osfile(fh) & FOPEN))
  2753.     {
  2754.     /* out of range -- return error */
  2755.     errno = EBADF;
  2756.     _doserrno = 0;  /* not o.s. error */
  2757.     return -1;
  2758.     }
  2759.  
  2760.     /*
  2761.      * If lockinitflag is FALSE, assume fd is device
  2762.      * lockinitflag is set to TRUE by open.
  2763.      */
  2764.     if (_pioinfo(fh)->lockinitflag)
  2765.     EnterCriticalSection(&(_pioinfo(fh)->lock));  /* lock file */
  2766.  
  2767.     bytes_read = 0;                 /* nothing read yet */
  2768.     buffer = (char*)buf;
  2769.  
  2770.     if (cnt == 0 || (_osfile(fh) & FEOFLAG)) {
  2771.         /* nothing to read or at EOF, so return 0 read */
  2772.         goto functionexit;
  2773.     }
  2774.  
  2775.     if ((_osfile(fh) & (FPIPE|FDEV)) && _pipech(fh) != LF) {
  2776.         /* a pipe/device and pipe lookahead non-empty: read the lookahead
  2777.          * char */
  2778.         *buffer++ = _pipech(fh);
  2779.         ++bytes_read;
  2780.         --cnt;
  2781.         _pipech(fh) = LF;           /* mark as empty */
  2782.     }
  2783.  
  2784.     /* read the data */
  2785.  
  2786.     if (!ReadFile((HANDLE)_osfhnd(fh), buffer, cnt, (LPDWORD)&os_read, NULL))
  2787.     {
  2788.         /* ReadFile has reported an error. recognize two special cases.
  2789.          *
  2790.          *      1. map ERROR_ACCESS_DENIED to EBADF
  2791.          *
  2792.          *      2. just return 0 if ERROR_BROKEN_PIPE has occurred. it
  2793.          *         means the handle is a read-handle on a pipe for which
  2794.          *         all write-handles have been closed and all data has been
  2795.          *         read. */
  2796.  
  2797.         if ((dosretval = GetLastError()) == ERROR_ACCESS_DENIED) {
  2798.             /* wrong read/write mode should return EBADF, not EACCES */
  2799.             errno = EBADF;
  2800.             _doserrno = dosretval;
  2801.             bytes_read = -1;
  2802.         goto functionexit;
  2803.         }
  2804.         else if (dosretval == ERROR_BROKEN_PIPE) {
  2805.             bytes_read = 0;
  2806.         goto functionexit;
  2807.         }
  2808.         else {
  2809.             bytes_read = -1;
  2810.         goto functionexit;
  2811.         }
  2812.     }
  2813.  
  2814.     bytes_read += os_read;          /* update bytes read */
  2815.  
  2816.     if (_osfile(fh) & FTEXT) {
  2817.         /* now must translate CR-LFs to LFs in the buffer */
  2818.  
  2819.         /* set CRLF flag to indicate LF at beginning of buffer */
  2820.         /* if ((os_read != 0) && (*(char *)buf == LF))   */
  2821.         /*    _osfile(fh) |= FCRLF;                      */
  2822.         /* else                                          */
  2823.         /*    _osfile(fh) &= ~FCRLF;                     */
  2824.  
  2825.         _osfile(fh) &= ~FCRLF;
  2826.  
  2827.         /* convert chars in the buffer: p is src, q is dest */
  2828.         p = q = (char*)buf;
  2829.         while (p < (char *)buf + bytes_read) {
  2830.             if (*p == CTRLZ) {
  2831.                 /* if fh is not a device, set ctrl-z flag */
  2832.                 if (!(_osfile(fh) & FDEV))
  2833.                     _osfile(fh) |= FEOFLAG;
  2834.                 break;              /* stop translating */
  2835.             }
  2836.             else if (*p != CR)
  2837.                 *q++ = *p++;
  2838.             else {
  2839.                 /* *p is CR, so must check next char for LF */
  2840.                 if (p < (char *)buf + bytes_read - 1) {
  2841.                     if (*(p+1) == LF) {
  2842.                         p += 2;
  2843.                         *q++ = LF;  /* convert CR-LF to LF */
  2844.                     }
  2845.                     else
  2846.                         *q++ = *p++;    /* store char normally */
  2847.                 }
  2848.                 else {
  2849.                     /* This is the hard part.  We found a CR at end of
  2850.                        buffer.  We must peek ahead to see if next char
  2851.                        is an LF. */
  2852.                     ++p;
  2853.  
  2854.                     dosretval = 0;
  2855.                     if (!ReadFile((HANDLE)_osfhnd(fh), &peekchr, 1,
  2856.                                     (LPDWORD)&os_read, NULL))
  2857.                         dosretval = GetLastError();
  2858.  
  2859.                     if (dosretval != 0 || os_read == 0) {
  2860.                         /* couldn't read ahead, store CR */
  2861.                         *q++ = CR;
  2862.                     }
  2863.                     else {
  2864.                         /* peekchr now has the extra character -- we now
  2865.                            have several possibilities:
  2866.                            1. disk file and char is not LF; just seek back
  2867.                               and copy CR
  2868.                            2. disk file and char is LF; store LF, don't seek back
  2869.                            3. pipe/device and char is LF; store LF.
  2870.                            4. pipe/device and char isn't LF, store CR and
  2871.                               put char in pipe lookahead buffer. */
  2872.                         if (_osfile(fh) & (FDEV|FPIPE)) {
  2873.                             /* non-seekable device */
  2874.                             if (peekchr == LF)
  2875.                                 *q++ = LF;
  2876.                             else {
  2877.                                 *q++ = CR;
  2878.                                 _pipech(fh) = peekchr;
  2879.                             }
  2880.                         }
  2881.                         else {
  2882.                             /* disk file */
  2883.                             if (peekchr == LF) {
  2884.                                 /* nothing read yet; must make some
  2885.                                    progress */
  2886.                                 *q++ = LF;
  2887.                                 /* turn on this flag for tell routine */
  2888.                                 _osfile(fh) |= FCRLF;
  2889.                             }
  2890.                             else {
  2891.                 HANDLE osHandle;        /* o.s. handle value */
  2892.                                 /* seek back */
  2893.                 if ((osHandle = (HANDLE)_get_osfhandle(fh)) != (HANDLE)-1)
  2894.                 {
  2895.                     if ((filepos = SetFilePointer(osHandle, -1, NULL, FILE_CURRENT)) == -1)
  2896.                     dosretval = GetLastError();
  2897.                 }
  2898.                                 if (peekchr != LF)
  2899.                                     *q++ = CR;
  2900.                             }
  2901.                         }
  2902.                     }
  2903.                 }
  2904.             }
  2905.         }
  2906.  
  2907.         /* we now change bytes_read to reflect the true number of chars
  2908.            in the buffer */
  2909.         bytes_read = q - (char *)buf;
  2910.     }
  2911.  
  2912. functionexit:    
  2913.     if (_pioinfo(fh)->lockinitflag)
  2914.     LeaveCriticalSection(&(_pioinfo(fh)->lock));    /* unlock file */
  2915.  
  2916.     return bytes_read;
  2917. }
  2918.  
  2919. #endif    /* PERL_MSVCRT_READFIX */
  2920.  
  2921. DllExport int
  2922. win32_read(int fd, void *buf, unsigned int cnt)
  2923. {
  2924. #ifdef PERL_MSVCRT_READFIX
  2925.     return _fixed_read(fd, buf, cnt);
  2926. #else
  2927.     return read(fd, buf, cnt);
  2928. #endif
  2929. }
  2930.  
  2931. DllExport int
  2932. win32_write(int fd, const void *buf, unsigned int cnt)
  2933. {
  2934.     return write(fd, buf, cnt);
  2935. }
  2936.  
  2937. DllExport int
  2938. win32_mkdir(const char *dir, int mode)
  2939. {
  2940.     dTHXo;
  2941.     if (USING_WIDE()) {
  2942.     WCHAR wBuffer[MAX_PATH+1];
  2943.     A2WHELPER(dir, wBuffer, sizeof(wBuffer));
  2944.     return _wmkdir(PerlDir_mapW(wBuffer));
  2945.     }
  2946.     return mkdir(PerlDir_mapA(dir)); /* just ignore mode */
  2947. }
  2948.  
  2949. DllExport int
  2950. win32_rmdir(const char *dir)
  2951. {
  2952.     dTHXo;
  2953.     if (USING_WIDE()) {
  2954.     WCHAR wBuffer[MAX_PATH+1];
  2955.     A2WHELPER(dir, wBuffer, sizeof(wBuffer));
  2956.     return _wrmdir(PerlDir_mapW(wBuffer));
  2957.     }
  2958.     return rmdir(PerlDir_mapA(dir));
  2959. }
  2960.  
  2961. DllExport int
  2962. win32_chdir(const char *dir)
  2963. {
  2964.     dTHXo;
  2965.     if (USING_WIDE()) {
  2966.     WCHAR wBuffer[MAX_PATH+1];
  2967.     A2WHELPER(dir, wBuffer, sizeof(wBuffer));
  2968.     return _wchdir(wBuffer);
  2969.     }
  2970.     return chdir(dir);
  2971. }
  2972.  
  2973. DllExport  int
  2974. win32_access(const char *path, int mode)
  2975. {
  2976.     dTHXo;
  2977.     if (USING_WIDE()) {
  2978.     WCHAR wBuffer[MAX_PATH+1];
  2979.     A2WHELPER(path, wBuffer, sizeof(wBuffer));
  2980.     return _waccess(PerlDir_mapW(wBuffer), mode);
  2981.     }
  2982.     return access(PerlDir_mapA(path), mode);
  2983. }
  2984.  
  2985. DllExport  int
  2986. win32_chmod(const char *path, int mode)
  2987. {
  2988.     dTHXo;
  2989.     if (USING_WIDE()) {
  2990.     WCHAR wBuffer[MAX_PATH+1];
  2991.     A2WHELPER(path, wBuffer, sizeof(wBuffer));
  2992.     return _wchmod(PerlDir_mapW(wBuffer), mode);
  2993.     }
  2994.     return chmod(PerlDir_mapA(path), mode);
  2995. }
  2996.  
  2997.  
  2998. static char *
  2999. create_command_line(const char* command, const char * const *args)
  3000. {
  3001.     dTHXo;
  3002.     int index;
  3003.     char *cmd, *ptr, *arg;
  3004.     STRLEN len = strlen(command) + 1;
  3005.  
  3006.     for (index = 0; (ptr = (char*)args[index]) != NULL; ++index)
  3007.     len += strlen(ptr) + 1;
  3008.  
  3009.     New(1310, cmd, len, char);
  3010.     ptr = cmd;
  3011.     strcpy(ptr, command);
  3012.  
  3013.     for (index = 0; (arg = (char*)args[index]) != NULL; ++index) {
  3014.     ptr += strlen(ptr);
  3015.     *ptr++ = ' ';
  3016.     strcpy(ptr, arg);
  3017.     }
  3018.  
  3019.     return cmd;
  3020. }
  3021.  
  3022. static char *
  3023. qualified_path(const char *cmd)
  3024. {
  3025.     dTHXo;
  3026.     char *pathstr;
  3027.     char *fullcmd, *curfullcmd;
  3028.     STRLEN cmdlen = 0;
  3029.     int has_slash = 0;
  3030.  
  3031.     if (!cmd)
  3032.     return Nullch;
  3033.     fullcmd = (char*)cmd;
  3034.     while (*fullcmd) {
  3035.     if (*fullcmd == '/' || *fullcmd == '\\')
  3036.         has_slash++;
  3037.     fullcmd++;
  3038.     cmdlen++;
  3039.     }
  3040.  
  3041.     /* look in PATH */
  3042.     pathstr = win32_getenv("PATH");
  3043.     New(0, fullcmd, MAX_PATH+1, char);
  3044.     curfullcmd = fullcmd;
  3045.  
  3046.     while (1) {
  3047.     DWORD res;
  3048.  
  3049.     /* start by appending the name to the current prefix */
  3050.     strcpy(curfullcmd, cmd);
  3051.     curfullcmd += cmdlen;
  3052.  
  3053.     /* if it doesn't end with '.', or has no extension, try adding
  3054.      * a trailing .exe first */
  3055.     if (cmd[cmdlen-1] != '.'
  3056.         && (cmdlen < 4 || cmd[cmdlen-4] != '.'))
  3057.     {
  3058.         strcpy(curfullcmd, ".exe");
  3059.         res = GetFileAttributes(fullcmd);
  3060.         if (res != 0xFFFFFFFF && !(res & FILE_ATTRIBUTE_DIRECTORY))
  3061.         return fullcmd;
  3062.         *curfullcmd = '\0';
  3063.     }
  3064.  
  3065.     /* that failed, try the bare name */
  3066.     res = GetFileAttributes(fullcmd);
  3067.     if (res != 0xFFFFFFFF && !(res & FILE_ATTRIBUTE_DIRECTORY))
  3068.         return fullcmd;
  3069.  
  3070.     /* quit if no other path exists, or if cmd already has path */
  3071.     if (!pathstr || !*pathstr || has_slash)
  3072.         break;
  3073.  
  3074.     /* skip leading semis */
  3075.     while (*pathstr == ';')
  3076.         pathstr++;
  3077.  
  3078.     /* build a new prefix from scratch */
  3079.     curfullcmd = fullcmd;
  3080.     while (*pathstr && *pathstr != ';') {
  3081.         if (*pathstr == '"') {    /* foo;"baz;etc";bar */
  3082.         pathstr++;        /* skip initial '"' */
  3083.         while (*pathstr && *pathstr != '"') {
  3084.             if (curfullcmd-fullcmd < MAX_PATH-cmdlen-5)
  3085.             *curfullcmd++ = *pathstr;
  3086.             pathstr++;
  3087.         }
  3088.         if (*pathstr)
  3089.             pathstr++;        /* skip trailing '"' */
  3090.         }
  3091.         else {
  3092.         if (curfullcmd-fullcmd < MAX_PATH-cmdlen-5)
  3093.             *curfullcmd++ = *pathstr;
  3094.         pathstr++;
  3095.         }
  3096.     }
  3097.     if (*pathstr)
  3098.         pathstr++;            /* skip trailing semi */
  3099.     if (curfullcmd > fullcmd    /* append a dir separator */
  3100.         && curfullcmd[-1] != '/' && curfullcmd[-1] != '\\')
  3101.     {
  3102.         *curfullcmd++ = '\\';
  3103.     }
  3104.     }
  3105. GIVE_UP:
  3106.     Safefree(fullcmd);
  3107.     return Nullch;
  3108. }
  3109.  
  3110. /* The following are just place holders.
  3111.  * Some hosts may provide and environment that the OS is
  3112.  * not tracking, therefore, these host must provide that
  3113.  * environment and the current directory to CreateProcess
  3114.  */
  3115.  
  3116. void*
  3117. get_childenv(void)
  3118. {
  3119.     return NULL;
  3120. }
  3121.  
  3122. void
  3123. free_childenv(void* d)
  3124. {
  3125. }
  3126.  
  3127. char*
  3128. get_childdir(void)
  3129. {
  3130.     dTHXo;
  3131.     char* ptr;
  3132.     char szfilename[(MAX_PATH+1)*2];
  3133.     if (USING_WIDE()) {
  3134.     WCHAR wfilename[MAX_PATH+1];
  3135.     GetCurrentDirectoryW(MAX_PATH+1, wfilename);
  3136.     W2AHELPER(wfilename, szfilename, sizeof(szfilename));
  3137.     }
  3138.     else {
  3139.     GetCurrentDirectoryA(MAX_PATH+1, szfilename);
  3140.     }
  3141.  
  3142.     New(0, ptr, strlen(szfilename)+1, char);
  3143.     strcpy(ptr, szfilename);
  3144.     return ptr;
  3145. }
  3146.  
  3147. void
  3148. free_childdir(char* d)
  3149. {
  3150.     dTHXo;
  3151.     Safefree(d);
  3152. }
  3153.  
  3154.  
  3155. /* XXX this needs to be made more compatible with the spawnvp()
  3156.  * provided by the various RTLs.  In particular, searching for
  3157.  * *.{com,bat,cmd} files (as done by the RTLs) is unimplemented.
  3158.  * This doesn't significantly affect perl itself, because we
  3159.  * always invoke things using PERL5SHELL if a direct attempt to
  3160.  * spawn the executable fails.
  3161.  * 
  3162.  * XXX splitting and rejoining the commandline between do_aspawn()
  3163.  * and win32_spawnvp() could also be avoided.
  3164.  */
  3165.  
  3166. DllExport int
  3167. win32_spawnvp(int mode, const char *cmdname, const char *const *argv)
  3168. {
  3169. #ifdef USE_RTL_SPAWNVP
  3170.     return spawnvp(mode, cmdname, (char * const *)argv);
  3171. #else
  3172.     dTHXo;
  3173.     int ret;
  3174.     void* env;
  3175.     char* dir;
  3176.     child_IO_table tbl;
  3177.     STARTUPINFO StartupInfo;
  3178.     PROCESS_INFORMATION ProcessInformation;
  3179.     DWORD create = 0;
  3180.  
  3181.     char *cmd = create_command_line(cmdname, strcmp(cmdname, argv[0]) == 0
  3182.                                   ? &argv[1] : argv);
  3183.     char *fullcmd = Nullch;
  3184.  
  3185.     env = PerlEnv_get_childenv();
  3186.     dir = PerlEnv_get_childdir();
  3187.  
  3188.     switch(mode) {
  3189.     case P_NOWAIT:    /* asynch + remember result */
  3190.     if (w32_num_children >= MAXIMUM_WAIT_OBJECTS) {
  3191.         errno = EAGAIN;
  3192.         ret = -1;
  3193.         goto RETVAL;
  3194.     }
  3195.     /* FALL THROUGH */
  3196.     case P_WAIT:    /* synchronous execution */
  3197.     break;
  3198.     default:        /* invalid mode */
  3199.     errno = EINVAL;
  3200.     ret = -1;
  3201.     goto RETVAL;
  3202.     }
  3203.     memset(&StartupInfo,0,sizeof(StartupInfo));
  3204.     StartupInfo.cb = sizeof(StartupInfo);
  3205.     memset(&tbl,0,sizeof(tbl));
  3206.     PerlEnv_get_child_IO(&tbl);
  3207.     StartupInfo.dwFlags        = tbl.dwFlags;
  3208.     StartupInfo.dwX        = tbl.dwX; 
  3209.     StartupInfo.dwY        = tbl.dwY; 
  3210.     StartupInfo.dwXSize        = tbl.dwXSize; 
  3211.     StartupInfo.dwYSize        = tbl.dwYSize; 
  3212.     StartupInfo.dwXCountChars    = tbl.dwXCountChars; 
  3213.     StartupInfo.dwYCountChars    = tbl.dwYCountChars; 
  3214.     StartupInfo.dwFillAttribute    = tbl.dwFillAttribute; 
  3215.     StartupInfo.wShowWindow    = tbl.wShowWindow; 
  3216.     StartupInfo.hStdInput    = tbl.childStdIn;
  3217.     StartupInfo.hStdOutput    = tbl.childStdOut;
  3218.     StartupInfo.hStdError    = tbl.childStdErr;
  3219.     if (StartupInfo.hStdInput != INVALID_HANDLE_VALUE &&
  3220.     StartupInfo.hStdOutput != INVALID_HANDLE_VALUE &&
  3221.     StartupInfo.hStdError != INVALID_HANDLE_VALUE)
  3222.     {
  3223.     StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
  3224.     }
  3225.     else {
  3226.     create |= CREATE_NEW_CONSOLE;
  3227.     }
  3228.  
  3229. RETRY:
  3230.     if (!CreateProcess(cmdname,        /* search PATH to find executable */
  3231.                cmd,        /* executable, and its arguments */
  3232.                NULL,        /* process attributes */
  3233.                NULL,        /* thread attributes */
  3234.                TRUE,        /* inherit handles */
  3235.                create,        /* creation flags */
  3236.                (LPVOID)env,    /* inherit environment */
  3237.                dir,        /* inherit cwd */
  3238.                &StartupInfo,
  3239.                &ProcessInformation))
  3240.     {
  3241.     /* initial NULL argument to CreateProcess() does a PATH
  3242.      * search, but it always first looks in the directory
  3243.      * where the current process was started, which behavior
  3244.      * is undesirable for backward compatibility.  So we
  3245.      * jump through our own hoops by picking out the path
  3246.      * we really want it to use. */
  3247.     if (!fullcmd) {
  3248.         fullcmd = qualified_path(cmdname);
  3249.         if (fullcmd) {
  3250.         cmdname = fullcmd;
  3251.         goto RETRY;
  3252.         }
  3253.     }
  3254.     errno = ENOENT;
  3255.     ret = -1;
  3256.     goto RETVAL;
  3257.     }
  3258.  
  3259.     if (mode == P_NOWAIT) {
  3260.     /* asynchronous spawn -- store handle, return PID */
  3261.     w32_child_handles[w32_num_children] = ProcessInformation.hProcess;
  3262.     w32_child_pids[w32_num_children] = ProcessInformation.dwProcessId;
  3263.     ret = (int)ProcessInformation.dwProcessId;
  3264.     ++w32_num_children;
  3265.     }
  3266.     else  {
  3267.     DWORD status;
  3268.     WaitForSingleObject(ProcessInformation.hProcess, INFINITE);
  3269.     GetExitCodeProcess(ProcessInformation.hProcess, &status);
  3270.     ret = (int)status;
  3271.     CloseHandle(ProcessInformation.hProcess);
  3272.     }
  3273.  
  3274.     CloseHandle(ProcessInformation.hThread);
  3275.  
  3276. RETVAL:
  3277.     PerlEnv_free_childenv(env);
  3278.     PerlEnv_free_childdir(dir);
  3279.     Safefree(cmd);
  3280.     Safefree(fullcmd);
  3281.     return ret;
  3282. #endif
  3283. }
  3284.  
  3285. DllExport int
  3286. win32_execv(const char *cmdname, const char *const *argv)
  3287. {
  3288. #ifdef USE_ITHREADS
  3289.     dTHXo;
  3290.     /* if this is a pseudo-forked child, we just want to spawn
  3291.      * the new program, and return */
  3292.     if (w32_pseudo_id)
  3293.     return spawnv(P_WAIT, cmdname, (char *const *)argv);
  3294. #endif
  3295.     return execv(cmdname, (char *const *)argv);
  3296. }
  3297.  
  3298. DllExport int
  3299. win32_execvp(const char *cmdname, const char *const *argv)
  3300. {
  3301. #ifdef USE_ITHREADS
  3302.     dTHXo;
  3303.     /* if this is a pseudo-forked child, we just want to spawn
  3304.      * the new program, and return */
  3305.     if (w32_pseudo_id)
  3306.     return win32_spawnvp(P_WAIT, cmdname, (char *const *)argv);
  3307. #endif
  3308.     return execvp(cmdname, (char *const *)argv);
  3309. }
  3310.  
  3311. DllExport void
  3312. win32_perror(const char *str)
  3313. {
  3314.     perror(str);
  3315. }
  3316.  
  3317. DllExport void
  3318. win32_setbuf(FILE *pf, char *buf)
  3319. {
  3320.     setbuf(pf, buf);
  3321. }
  3322.  
  3323. DllExport int
  3324. win32_setvbuf(FILE *pf, char *buf, int type, size_t size)
  3325. {
  3326.     return setvbuf(pf, buf, type, size);
  3327. }
  3328.  
  3329. DllExport int
  3330. win32_flushall(void)
  3331. {
  3332.     return flushall();
  3333. }
  3334.  
  3335. DllExport int
  3336. win32_fcloseall(void)
  3337. {
  3338.     return fcloseall();
  3339. }
  3340.  
  3341. DllExport char*
  3342. win32_fgets(char *s, int n, FILE *pf)
  3343. {
  3344.     return fgets(s, n, pf);
  3345. }
  3346.  
  3347. DllExport char*
  3348. win32_gets(char *s)
  3349. {
  3350.     return gets(s);
  3351. }
  3352.  
  3353. DllExport int
  3354. win32_fgetc(FILE *pf)
  3355. {
  3356.     return fgetc(pf);
  3357. }
  3358.  
  3359. DllExport int
  3360. win32_putc(int c, FILE *pf)
  3361. {
  3362.     return putc(c,pf);
  3363. }
  3364.  
  3365. DllExport int
  3366. win32_puts(const char *s)
  3367. {
  3368.     return puts(s);
  3369. }
  3370.  
  3371. DllExport int
  3372. win32_getchar(void)
  3373. {
  3374.     return getchar();
  3375. }
  3376.  
  3377. DllExport int
  3378. win32_putchar(int c)
  3379. {
  3380.     return putchar(c);
  3381. }
  3382.  
  3383. #ifdef MYMALLOC
  3384.  
  3385. #ifndef USE_PERL_SBRK
  3386.  
  3387. static char *committed = NULL;
  3388. static char *base      = NULL;
  3389. static char *reserved  = NULL;
  3390. static char *brk       = NULL;
  3391. static DWORD pagesize  = 0;
  3392. static DWORD allocsize = 0;
  3393.  
  3394. void *
  3395. sbrk(int need)
  3396. {
  3397.  void *result;
  3398.  if (!pagesize)
  3399.   {SYSTEM_INFO info;
  3400.    GetSystemInfo(&info);
  3401.    /* Pretend page size is larger so we don't perpetually
  3402.     * call the OS to commit just one page ...
  3403.     */
  3404.    pagesize = info.dwPageSize << 3;
  3405.    allocsize = info.dwAllocationGranularity;
  3406.   }
  3407.  /* This scheme fails eventually if request for contiguous
  3408.   * block is denied so reserve big blocks - this is only 
  3409.   * address space not memory ...
  3410.   */
  3411.  if (brk+need >= reserved)
  3412.   {
  3413.    DWORD size = 64*1024*1024;
  3414.    char *addr;
  3415.    if (committed && reserved && committed < reserved)
  3416.     {
  3417.      /* Commit last of previous chunk cannot span allocations */
  3418.      addr = (char *) VirtualAlloc(committed,reserved-committed,MEM_COMMIT,PAGE_READWRITE);
  3419.      if (addr)
  3420.       committed = reserved;
  3421.     }
  3422.    /* Reserve some (more) space 
  3423.     * Note this is a little sneaky, 1st call passes NULL as reserved
  3424.     * so lets system choose where we start, subsequent calls pass
  3425.     * the old end address so ask for a contiguous block
  3426.     */
  3427.    addr  = (char *) VirtualAlloc(reserved,size,MEM_RESERVE,PAGE_NOACCESS);
  3428.    if (addr)
  3429.     {
  3430.      reserved = addr+size;
  3431.      if (!base)
  3432.       base = addr;
  3433.      if (!committed)
  3434.       committed = base;
  3435.      if (!brk)
  3436.       brk = committed;
  3437.     }
  3438.    else
  3439.     {
  3440.      return (void *) -1;
  3441.     }
  3442.   }
  3443.  result = brk;
  3444.  brk += need;
  3445.  if (brk > committed)
  3446.   {
  3447.    DWORD size = ((brk-committed + pagesize -1)/pagesize) * pagesize;
  3448.    char *addr = (char *) VirtualAlloc(committed,size,MEM_COMMIT,PAGE_READWRITE);
  3449.    if (addr)
  3450.     {
  3451.      committed += size;
  3452.     }
  3453.    else
  3454.     return (void *) -1;
  3455.   }
  3456.  return result;
  3457. }
  3458.  
  3459. #endif
  3460. #endif
  3461.  
  3462. DllExport void*
  3463. win32_malloc(size_t size)
  3464. {
  3465.     return malloc(size);
  3466. }
  3467.  
  3468. DllExport void*
  3469. win32_calloc(size_t numitems, size_t size)
  3470. {
  3471.     return calloc(numitems,size);
  3472. }
  3473.  
  3474. DllExport void*
  3475. win32_realloc(void *block, size_t size)
  3476. {
  3477.     return realloc(block,size);
  3478. }
  3479.  
  3480. DllExport void
  3481. win32_free(void *block)
  3482. {
  3483.     free(block);
  3484. }
  3485.  
  3486.  
  3487. int
  3488. win32_open_osfhandle(long handle, int flags)
  3489. {
  3490. #ifdef USE_FIXED_OSFHANDLE
  3491.     if (IsWin95())
  3492.     return my_open_osfhandle(handle, flags);
  3493. #endif
  3494.     return _open_osfhandle(handle, flags);
  3495. }
  3496.  
  3497. long
  3498. win32_get_osfhandle(int fd)
  3499. {
  3500.     return _get_osfhandle(fd);
  3501. }
  3502.  
  3503. DllExport void*
  3504. win32_dynaload(const char* filename)
  3505. {
  3506.     dTHXo;
  3507.     HMODULE hModule;
  3508.     if (USING_WIDE()) {
  3509.     WCHAR wfilename[MAX_PATH+1];
  3510.     A2WHELPER(filename, wfilename, sizeof(wfilename));
  3511.     hModule = LoadLibraryExW(PerlDir_mapW(wfilename), NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
  3512.     }
  3513.     else {
  3514.     hModule = LoadLibraryExA(PerlDir_mapA(filename), NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
  3515.     }
  3516.     return hModule;
  3517. }
  3518.  
  3519. /*
  3520.  * Extras.
  3521.  */
  3522.  
  3523. static
  3524. XS(w32_GetCwd)
  3525. {
  3526.     dXSARGS;
  3527.     /* Make the host for current directory */
  3528.     char* ptr = PerlEnv_get_childdir();
  3529.     /* 
  3530.      * If ptr != Nullch 
  3531.      *   then it worked, set PV valid, 
  3532.      *   else return 'undef' 
  3533.      */
  3534.     if (ptr) {
  3535.     SV *sv = sv_newmortal();
  3536.     sv_setpv(sv, ptr);
  3537.     PerlEnv_free_childdir(ptr);
  3538.  
  3539.     EXTEND(SP,1);
  3540.     SvPOK_on(sv);
  3541.     ST(0) = sv;
  3542.     XSRETURN(1);
  3543.     }
  3544.     XSRETURN_UNDEF;
  3545. }
  3546.  
  3547. static
  3548. XS(w32_SetCwd)
  3549. {
  3550.     dXSARGS;
  3551.     if (items != 1)
  3552.     Perl_croak(aTHX_ "usage: Win32::SetCurrentDirectory($cwd)");
  3553.     if (!PerlDir_chdir(SvPV_nolen(ST(0))))
  3554.     XSRETURN_YES;
  3555.  
  3556.     XSRETURN_NO;
  3557. }
  3558.  
  3559. static
  3560. XS(w32_GetNextAvailDrive)
  3561. {
  3562.     dXSARGS;
  3563.     char ix = 'C';
  3564.     char root[] = "_:\\";
  3565.  
  3566.     EXTEND(SP,1);
  3567.     while (ix <= 'Z') {
  3568.     root[0] = ix++;
  3569.     if (GetDriveType(root) == 1) {
  3570.         root[2] = '\0';
  3571.         XSRETURN_PV(root);
  3572.     }
  3573.     }
  3574.     XSRETURN_UNDEF;
  3575. }
  3576.  
  3577. static
  3578. XS(w32_GetLastError)
  3579. {
  3580.     dXSARGS;
  3581.     EXTEND(SP,1);
  3582.     XSRETURN_IV(GetLastError());
  3583. }
  3584.  
  3585. static
  3586. XS(w32_SetLastError)
  3587. {
  3588.     dXSARGS;
  3589.     if (items != 1)
  3590.     Perl_croak(aTHX_ "usage: Win32::SetLastError($error)");
  3591.     SetLastError(SvIV(ST(0)));
  3592.     XSRETURN_EMPTY;
  3593. }
  3594.  
  3595. static
  3596. XS(w32_LoginName)
  3597. {
  3598.     dXSARGS;
  3599.     char *name = w32_getlogin_buffer;
  3600.     DWORD size = sizeof(w32_getlogin_buffer);
  3601.     EXTEND(SP,1);
  3602.     if (GetUserName(name,&size)) {
  3603.     /* size includes NULL */
  3604.     ST(0) = sv_2mortal(newSVpvn(name,size-1));
  3605.     XSRETURN(1);
  3606.     }
  3607.     XSRETURN_UNDEF;
  3608. }
  3609.  
  3610. static
  3611. XS(w32_NodeName)
  3612. {
  3613.     dXSARGS;
  3614.     char name[MAX_COMPUTERNAME_LENGTH+1];
  3615.     DWORD size = sizeof(name);
  3616.     EXTEND(SP,1);
  3617.     if (GetComputerName(name,&size)) {
  3618.     /* size does NOT include NULL :-( */
  3619.     ST(0) = sv_2mortal(newSVpvn(name,size));
  3620.     XSRETURN(1);
  3621.     }
  3622.     XSRETURN_UNDEF;
  3623. }
  3624.  
  3625.  
  3626. static
  3627. XS(w32_DomainName)
  3628. {
  3629.     dXSARGS;
  3630.     HINSTANCE hNetApi32 = LoadLibrary("netapi32.dll");
  3631.     DWORD (__stdcall *pfnNetApiBufferFree)(LPVOID Buffer);
  3632.     DWORD (__stdcall *pfnNetWkstaGetInfo)(LPWSTR servername, DWORD level,
  3633.                       void *bufptr);
  3634.  
  3635.     if (hNetApi32) {
  3636.     pfnNetApiBufferFree = (DWORD (__stdcall *)(void *))
  3637.         GetProcAddress(hNetApi32, "NetApiBufferFree");
  3638.     pfnNetWkstaGetInfo = (DWORD (__stdcall *)(LPWSTR, DWORD, void *))
  3639.         GetProcAddress(hNetApi32, "NetWkstaGetInfo");
  3640.     }
  3641.     EXTEND(SP,1);
  3642.     if (hNetApi32 && pfnNetWkstaGetInfo && pfnNetApiBufferFree) {
  3643.     /* this way is more reliable, in case user has a local account. */
  3644.     char dname[256];
  3645.     DWORD dnamelen = sizeof(dname);
  3646.     struct {
  3647.         DWORD   wki100_platform_id;
  3648.         LPWSTR  wki100_computername;
  3649.         LPWSTR  wki100_langroup;
  3650.         DWORD   wki100_ver_major;
  3651.         DWORD   wki100_ver_minor;
  3652.     } *pwi;
  3653.     /* NERR_Success *is* 0*/
  3654.     if (0 == pfnNetWkstaGetInfo(NULL, 100, &pwi)) {
  3655.         if (pwi->wki100_langroup && *(pwi->wki100_langroup)) {
  3656.         WideCharToMultiByte(CP_ACP, NULL, pwi->wki100_langroup,
  3657.                     -1, (LPSTR)dname, dnamelen, NULL, NULL);
  3658.         }
  3659.         else {
  3660.         WideCharToMultiByte(CP_ACP, NULL, pwi->wki100_computername,
  3661.                     -1, (LPSTR)dname, dnamelen, NULL, NULL);
  3662.         }
  3663.         pfnNetApiBufferFree(pwi);
  3664.         FreeLibrary(hNetApi32);
  3665.         XSRETURN_PV(dname);
  3666.     }
  3667.     FreeLibrary(hNetApi32);
  3668.     }
  3669.     else {
  3670.     /* Win95 doesn't have NetWksta*(), so do it the old way */
  3671.     char name[256];
  3672.     DWORD size = sizeof(name);
  3673.     if (hNetApi32)
  3674.         FreeLibrary(hNetApi32);
  3675.     if (GetUserName(name,&size)) {
  3676.         char sid[ONE_K_BUFSIZE];
  3677.         DWORD sidlen = sizeof(sid);
  3678.         char dname[256];
  3679.         DWORD dnamelen = sizeof(dname);
  3680.         SID_NAME_USE snu;
  3681.         if (LookupAccountName(NULL, name, (PSID)&sid, &sidlen,
  3682.                   dname, &dnamelen, &snu)) {
  3683.         XSRETURN_PV(dname);        /* all that for this */
  3684.         }
  3685.     }
  3686.     }
  3687.     XSRETURN_UNDEF;
  3688. }
  3689.  
  3690. static
  3691. XS(w32_FsType)
  3692. {
  3693.     dXSARGS;
  3694.     char fsname[256];
  3695.     DWORD flags, filecomplen;
  3696.     if (GetVolumeInformation(NULL, NULL, 0, NULL, &filecomplen,
  3697.              &flags, fsname, sizeof(fsname))) {
  3698.     if (GIMME_V == G_ARRAY) {
  3699.         XPUSHs(sv_2mortal(newSVpvn(fsname,strlen(fsname))));
  3700.         XPUSHs(sv_2mortal(newSViv(flags)));
  3701.         XPUSHs(sv_2mortal(newSViv(filecomplen)));
  3702.         PUTBACK;
  3703.         return;
  3704.     }
  3705.     EXTEND(SP,1);
  3706.     XSRETURN_PV(fsname);
  3707.     }
  3708.     XSRETURN_EMPTY;
  3709. }
  3710.  
  3711. static
  3712. XS(w32_GetOSVersion)
  3713. {
  3714.     dXSARGS;
  3715.     OSVERSIONINFOA osver;
  3716.  
  3717.     if (USING_WIDE()) {
  3718.     OSVERSIONINFOW osverw;
  3719.     char szCSDVersion[sizeof(osverw.szCSDVersion)];
  3720.     osverw.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
  3721.     if (!GetVersionExW(&osverw)) {
  3722.         XSRETURN_EMPTY;
  3723.     }
  3724.     W2AHELPER(osverw.szCSDVersion, szCSDVersion, sizeof(szCSDVersion));
  3725.     XPUSHs(newSVpvn(szCSDVersion, strlen(szCSDVersion)));
  3726.     osver.dwMajorVersion = osverw.dwMajorVersion;
  3727.     osver.dwMinorVersion = osverw.dwMinorVersion;
  3728.     osver.dwBuildNumber = osverw.dwBuildNumber;
  3729.     osver.dwPlatformId = osverw.dwPlatformId;
  3730.     }
  3731.     else {
  3732.     osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
  3733.     if (!GetVersionExA(&osver)) {
  3734.         XSRETURN_EMPTY;
  3735.     }
  3736.     XPUSHs(newSVpvn(osver.szCSDVersion, strlen(osver.szCSDVersion)));
  3737.     }
  3738.     XPUSHs(newSViv(osver.dwMajorVersion));
  3739.     XPUSHs(newSViv(osver.dwMinorVersion));
  3740.     XPUSHs(newSViv(osver.dwBuildNumber));
  3741.     XPUSHs(newSViv(osver.dwPlatformId));
  3742.     PUTBACK;
  3743. }
  3744.  
  3745. static
  3746. XS(w32_IsWinNT)
  3747. {
  3748.     dXSARGS;
  3749.     EXTEND(SP,1);
  3750.     XSRETURN_IV(IsWinNT());
  3751. }
  3752.  
  3753. static
  3754. XS(w32_IsWin95)
  3755. {
  3756.     dXSARGS;
  3757.     EXTEND(SP,1);
  3758.     XSRETURN_IV(IsWin95());
  3759. }
  3760.  
  3761. static
  3762. XS(w32_FormatMessage)
  3763. {
  3764.     dXSARGS;
  3765.     DWORD source = 0;
  3766.     char msgbuf[ONE_K_BUFSIZE];
  3767.  
  3768.     if (items != 1)
  3769.     Perl_croak(aTHX_ "usage: Win32::FormatMessage($errno)");
  3770.  
  3771.     if (USING_WIDE()) {
  3772.     WCHAR wmsgbuf[ONE_K_BUFSIZE];
  3773.     if (FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM,
  3774.               &source, SvIV(ST(0)), 0,
  3775.               wmsgbuf, ONE_K_BUFSIZE-1, NULL))
  3776.     {
  3777.         W2AHELPER(wmsgbuf, msgbuf, sizeof(msgbuf));
  3778.         XSRETURN_PV(msgbuf);
  3779.     }
  3780.     }
  3781.     else {
  3782.     if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM,
  3783.               &source, SvIV(ST(0)), 0,
  3784.               msgbuf, sizeof(msgbuf)-1, NULL))
  3785.         XSRETURN_PV(msgbuf);
  3786.     }
  3787.  
  3788.     XSRETURN_UNDEF;
  3789. }
  3790.  
  3791. static
  3792. XS(w32_Spawn)
  3793. {
  3794.     dXSARGS;
  3795.     char *cmd, *args;
  3796.     PROCESS_INFORMATION stProcInfo;
  3797.     STARTUPINFO stStartInfo;
  3798.     BOOL bSuccess = FALSE;
  3799.  
  3800.     if (items != 3)
  3801.     Perl_croak(aTHX_ "usage: Win32::Spawn($cmdName, $args, $PID)");
  3802.  
  3803.     cmd = SvPV_nolen(ST(0));
  3804.     args = SvPV_nolen(ST(1));
  3805.  
  3806.     memset(&stStartInfo, 0, sizeof(stStartInfo));   /* Clear the block */
  3807.     stStartInfo.cb = sizeof(stStartInfo);        /* Set the structure size */
  3808.     stStartInfo.dwFlags = STARTF_USESHOWWINDOW;        /* Enable wShowWindow control */
  3809.     stStartInfo.wShowWindow = SW_SHOWMINNOACTIVE;   /* Start min (normal) */
  3810.  
  3811.     if (CreateProcess(
  3812.         cmd,            /* Image path */
  3813.         args,             /* Arguments for command line */
  3814.         NULL,            /* Default process security */
  3815.         NULL,            /* Default thread security */
  3816.         FALSE,            /* Must be TRUE to use std handles */
  3817.         NORMAL_PRIORITY_CLASS,    /* No special scheduling */
  3818.         NULL,            /* Inherit our environment block */
  3819.         NULL,            /* Inherit our currrent directory */
  3820.         &stStartInfo,        /* -> Startup info */
  3821.         &stProcInfo))        /* <- Process info (if OK) */
  3822.     {
  3823.     CloseHandle(stProcInfo.hThread);/* library source code does this. */
  3824.     sv_setiv(ST(2), stProcInfo.dwProcessId);
  3825.     bSuccess = TRUE;
  3826.     }
  3827.     XSRETURN_IV(bSuccess);
  3828. }
  3829.  
  3830. static
  3831. XS(w32_GetTickCount)
  3832. {
  3833.     dXSARGS;
  3834.     DWORD msec = GetTickCount();
  3835.     EXTEND(SP,1);
  3836.     if ((IV)msec > 0)
  3837.     XSRETURN_IV(msec);
  3838.     XSRETURN_NV(msec);
  3839. }
  3840.  
  3841. static
  3842. XS(w32_GetShortPathName)
  3843. {
  3844.     dXSARGS;
  3845.     SV *shortpath;
  3846.     DWORD len;
  3847.  
  3848.     if (items != 1)
  3849.     Perl_croak(aTHX_ "usage: Win32::GetShortPathName($longPathName)");
  3850.  
  3851.     shortpath = sv_mortalcopy(ST(0));
  3852.     SvUPGRADE(shortpath, SVt_PV);
  3853.     /* src == target is allowed */
  3854.     do {
  3855.     len = GetShortPathName(SvPVX(shortpath),
  3856.                    SvPVX(shortpath),
  3857.                    SvLEN(shortpath));
  3858.     } while (len >= SvLEN(shortpath) && sv_grow(shortpath,len+1));
  3859.     if (len) {
  3860.     SvCUR_set(shortpath,len);
  3861.     ST(0) = shortpath;
  3862.     XSRETURN(1);
  3863.     }
  3864.     XSRETURN_UNDEF;
  3865. }
  3866.  
  3867. static
  3868. XS(w32_GetFullPathName)
  3869. {
  3870.     dXSARGS;
  3871.     SV *filename;
  3872.     SV *fullpath;
  3873.     char *filepart;
  3874.     DWORD len;
  3875.  
  3876.     if (items != 1)
  3877.     Perl_croak(aTHX_ "usage: Win32::GetFullPathName($filename)");
  3878.  
  3879.     filename = ST(0);
  3880.     fullpath = sv_mortalcopy(filename);
  3881.     SvUPGRADE(fullpath, SVt_PV);
  3882.     do {
  3883.     len = GetFullPathName(SvPVX(filename),
  3884.                   SvLEN(fullpath),
  3885.                   SvPVX(fullpath),
  3886.                   &filepart);
  3887.     } while (len >= SvLEN(fullpath) && sv_grow(fullpath,len+1));
  3888.     if (len) {
  3889.     if (GIMME_V == G_ARRAY) {
  3890.         EXTEND(SP,1);
  3891.         XST_mPV(1,filepart);
  3892.         len = filepart - SvPVX(fullpath);
  3893.         items = 2;
  3894.     }
  3895.     SvCUR_set(fullpath,len);
  3896.     ST(0) = fullpath;
  3897.     XSRETURN(items);
  3898.     }
  3899.     XSRETURN_EMPTY;
  3900. }
  3901.  
  3902. static
  3903. XS(w32_GetLongPathName)
  3904. {
  3905.     dXSARGS;
  3906.     SV *path;
  3907.     char tmpbuf[MAX_PATH+1];
  3908.     char *pathstr;
  3909.     STRLEN len;
  3910.  
  3911.     if (items != 1)
  3912.     Perl_croak(aTHX_ "usage: Win32::GetLongPathName($pathname)");
  3913.  
  3914.     path = ST(0);
  3915.     pathstr = SvPV(path,len);
  3916.     strcpy(tmpbuf, pathstr);
  3917.     pathstr = win32_longpath(tmpbuf);
  3918.     if (pathstr) {
  3919.     ST(0) = sv_2mortal(newSVpvn(pathstr, strlen(pathstr)));
  3920.     XSRETURN(1);
  3921.     }
  3922.     XSRETURN_EMPTY;
  3923. }
  3924.  
  3925. static
  3926. XS(w32_Sleep)
  3927. {
  3928.     dXSARGS;
  3929.     if (items != 1)
  3930.     Perl_croak(aTHX_ "usage: Win32::Sleep($milliseconds)");
  3931.     Sleep(SvIV(ST(0)));
  3932.     XSRETURN_YES;
  3933. }
  3934.  
  3935. static
  3936. XS(w32_CopyFile)
  3937. {
  3938.     dXSARGS;
  3939.     BOOL bResult;
  3940.     if (items != 3)
  3941.     Perl_croak(aTHX_ "usage: Win32::CopyFile($from, $to, $overwrite)");
  3942.     if (USING_WIDE()) {
  3943.     WCHAR wSourceFile[MAX_PATH+1];
  3944.     WCHAR wDestFile[MAX_PATH+1];
  3945.     A2WHELPER(SvPV_nolen(ST(0)), wSourceFile, sizeof(wSourceFile));
  3946.     wcscpy(wSourceFile, PerlDir_mapW(wSourceFile));
  3947.     A2WHELPER(SvPV_nolen(ST(1)), wDestFile, sizeof(wDestFile));
  3948.     bResult = CopyFileW(wSourceFile, PerlDir_mapW(wDestFile), !SvTRUE(ST(2)));
  3949.     }
  3950.     else {
  3951.     char szSourceFile[MAX_PATH+1];
  3952.     strcpy(szSourceFile, PerlDir_mapA(SvPV_nolen(ST(0))));
  3953.     bResult = CopyFileA(szSourceFile, PerlDir_mapA(SvPV_nolen(ST(1))), !SvTRUE(ST(2)));
  3954.     }
  3955.  
  3956.     if (bResult)
  3957.     XSRETURN_YES;
  3958.     XSRETURN_NO;
  3959. }
  3960.  
  3961. void
  3962. Perl_init_os_extras(void)
  3963. {
  3964.     dTHXo;
  3965.     char *file = __FILE__;
  3966.     dXSUB_SYS;
  3967.  
  3968.     w32_perlshell_tokens = Nullch;
  3969.     w32_perlshell_items = -1;
  3970.     w32_fdpid = newAV();        /* XXX needs to be in Perl_win32_init()? */
  3971.     New(1313, w32_children, 1, child_tab);
  3972.     w32_num_children = 0;
  3973.     w32_init_socktype = 0;
  3974. #ifdef USE_ITHREADS
  3975.     w32_pseudo_id = 0;
  3976.     New(1313, w32_pseudo_children, 1, child_tab);
  3977.     w32_num_pseudo_children = 0;
  3978. #endif
  3979.  
  3980.     /* these names are Activeware compatible */
  3981.     newXS("Win32::GetCwd", w32_GetCwd, file);
  3982.     newXS("Win32::SetCwd", w32_SetCwd, file);
  3983.     newXS("Win32::GetNextAvailDrive", w32_GetNextAvailDrive, file);
  3984.     newXS("Win32::GetLastError", w32_GetLastError, file);
  3985.     newXS("Win32::SetLastError", w32_SetLastError, file);
  3986.     newXS("Win32::LoginName", w32_LoginName, file);
  3987.     newXS("Win32::NodeName", w32_NodeName, file);
  3988.     newXS("Win32::DomainName", w32_DomainName, file);
  3989.     newXS("Win32::FsType", w32_FsType, file);
  3990.     newXS("Win32::GetOSVersion", w32_GetOSVersion, file);
  3991.     newXS("Win32::IsWinNT", w32_IsWinNT, file);
  3992.     newXS("Win32::IsWin95", w32_IsWin95, file);
  3993.     newXS("Win32::FormatMessage", w32_FormatMessage, file);
  3994.     newXS("Win32::Spawn", w32_Spawn, file);
  3995.     newXS("Win32::GetTickCount", w32_GetTickCount, file);
  3996.     newXS("Win32::GetShortPathName", w32_GetShortPathName, file);
  3997.     newXS("Win32::GetFullPathName", w32_GetFullPathName, file);
  3998.     newXS("Win32::GetLongPathName", w32_GetLongPathName, file);
  3999.     newXS("Win32::CopyFile", w32_CopyFile, file);
  4000.     newXS("Win32::Sleep", w32_Sleep, file);
  4001.  
  4002.     /* XXX Bloat Alert! The following Activeware preloads really
  4003.      * ought to be part of Win32::Sys::*, so they're not included
  4004.      * here.
  4005.      */
  4006.     /* LookupAccountName
  4007.      * LookupAccountSID
  4008.      * InitiateSystemShutdown
  4009.      * AbortSystemShutdown
  4010.      * ExpandEnvrironmentStrings
  4011.      */
  4012. }
  4013.  
  4014. void
  4015. Perl_win32_init(int *argcp, char ***argvp)
  4016. {
  4017.     /* Disable floating point errors, Perl will trap the ones we
  4018.      * care about.  VC++ RTL defaults to switching these off
  4019.      * already, but the Borland RTL doesn't.  Since we don't
  4020.      * want to be at the vendor's whim on the default, we set
  4021.      * it explicitly here.
  4022.      */
  4023. #if !defined(_ALPHA_) && !defined(__GNUC__)
  4024.     _control87(MCW_EM, MCW_EM);
  4025. #endif
  4026.     MALLOC_INIT;
  4027. }
  4028.  
  4029. void
  4030. win32_get_child_IO(child_IO_table* ptbl)
  4031. {
  4032.     ptbl->childStdIn    = GetStdHandle(STD_INPUT_HANDLE);
  4033.     ptbl->childStdOut    = GetStdHandle(STD_OUTPUT_HANDLE);
  4034.     ptbl->childStdErr    = GetStdHandle(STD_ERROR_HANDLE);
  4035. }
  4036.  
  4037.  
  4038. #ifdef USE_ITHREADS
  4039.  
  4040. #  ifdef PERL_OBJECT
  4041. #    undef Perl_sys_intern_dup
  4042. #    define Perl_sys_intern_dup CPerlObj::Perl_sys_intern_dup
  4043. #    define pPerl this
  4044. #  endif
  4045.  
  4046. void
  4047. Perl_sys_intern_dup(pTHX_ struct interp_intern *src, struct interp_intern *dst)
  4048. {
  4049.     dst->perlshell_tokens    = Nullch;
  4050.     dst->perlshell_vec        = (char**)NULL;
  4051.     dst->perlshell_items    = 0;
  4052.     dst->fdpid            = newAV();
  4053.     Newz(1313, dst->children, 1, child_tab);
  4054.     Newz(1313, dst->pseudo_children, 1, child_tab);
  4055.     dst->pseudo_id        = 0;
  4056.     dst->children->num        = 0;
  4057.     dst->thr_intern.Winit_socktype = src->thr_intern.Winit_socktype;
  4058. }
  4059. #endif
  4060.  
  4061. #ifdef PERL_OBJECT
  4062. #  undef this
  4063. #  define this pPerl
  4064. #endif
  4065.  
  4066. static void
  4067. win32_free_argvw(pTHXo_ void *ptr)
  4068. {
  4069.     char** argv = (char**)ptr;
  4070.     while(*argv) {
  4071.     Safefree(*argv);
  4072.     *argv++ = Nullch;
  4073.     }
  4074. }
  4075.  
  4076. void
  4077. win32_argv2utf8(int argc, char** argv)
  4078. {
  4079.     dTHXo;
  4080.     char* psz;
  4081.     int length, wargc;
  4082.     LPWSTR* lpwStr = CommandLineToArgvW(GetCommandLineW(), &wargc);
  4083.     if (lpwStr && argc) {
  4084.     while (argc--) {
  4085.         length = WideCharToMultiByte(CP_UTF8, 0, lpwStr[--wargc], -1, NULL, 0, NULL, NULL);
  4086.         Newz(0, psz, length, char);
  4087.         WideCharToMultiByte(CP_UTF8, 0, lpwStr[wargc], -1, psz, length, NULL, NULL);
  4088.         argv[argc] = psz;
  4089.     }
  4090.     call_atexit(win32_free_argvw, argv);
  4091.     }
  4092.     GlobalFree((HGLOBAL)lpwStr);
  4093. }
  4094.  
  4095.