This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Eliminate empty conditional branch
[perl5.git] / win32 / win32.c
CommitLineData
68dc0745 1/* WIN32.C
2 *
3fadfdf1 3 * (c) 1995 Microsoft Corporation. All rights reserved.
0d130a44 4 * Developed by hip communications inc.
68dc0745 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 */
3fadfdf1 10#define PERLIO_NOT_STDIO 0
0a753a76 11#define WIN32_LEAN_AND_MEAN
12#define WIN32IO_IS_STDIO
13#include <tchar.h>
8cbe99e5 14
a835ef8a 15#ifdef __GNUC__
8cbe99e5
JD
16# define Win32_Winsock
17#endif
18
19#ifndef _WIN32_WINNT
20# define _WIN32_WINNT 0x0500 /* needed for CreateHardlink() etc. */
a835ef8a 21#endif
8cbe99e5 22
0a753a76 23#include <windows.h>
8cbe99e5 24
8e564886
JD
25#ifndef HWND_MESSAGE
26# define HWND_MESSAGE ((HWND)-3)
27#endif
28
29#ifndef PROCESSOR_ARCHITECTURE_AMD64
30# define PROCESSOR_ARCHITECTURE_AMD64 9
31#endif
32
33#ifndef WC_NO_BEST_FIT_CHARS
34# define WC_NO_BEST_FIT_CHARS 0x00000400
35#endif
36
5db10396 37#include <winnt.h>
4ebea3c6 38#include <commctrl.h>
542cb85f 39#include <tlhelp32.h>
5db10396 40#include <io.h>
c843839f 41#include <signal.h>
0a753a76 42
68dc0745 43/* #include "config.h" */
0a753a76 44
41addb51
CB
45
46#define PerlIO FILE
0a753a76 47
7a9ec5a3 48#include <sys/stat.h>
0a753a76 49#include "EXTERN.h"
50#include "perl.h"
c69f6586
GS
51
52#define NO_XSLOCKS
c5be433b 53#define PERL_NO_GET_CONTEXT
ad2e33dc 54#include "XSUB.h"
c69f6586 55
0a753a76 56#include <fcntl.h>
5b0d9cbe
NIS
57#ifndef __GNUC__
58/* assert.h conflicts with #define of assert in perl.h */
8cbe99e5 59# include <assert.h>
5b0d9cbe 60#endif
8cbe99e5 61
0a753a76 62#include <string.h>
63#include <stdarg.h>
ad2e33dc 64#include <float.h>
ad0751ec 65#include <time.h>
4eab039d 66#include <sys/utime.h>
8cbe99e5 67
5b0d9cbe 68#ifdef __GNUC__
3fadfdf1 69/* Mingw32 defaults to globing command line
5b0d9cbe
NIS
70 * So we turn it off like this:
71 */
72int _CRT_glob = 0;
73#endif
74
7c5b6093
AB
75#if defined(__MINGW32__) && (__MINGW32_MAJOR_VERSION==1)
76/* Mingw32-1.1 is missing some prototypes */
d06fc7d4 77START_EXTERN_C
f8fb7c90
GS
78FILE * _wfopen(LPCWSTR wszFileName, LPCWSTR wszMode);
79FILE * _wfdopen(int nFd, LPCWSTR wszMode);
80FILE * _freopen(LPCWSTR wszFileName, LPCWSTR wszMode, FILE * pOldStream);
81int _flushall();
82int _fcloseall();
d06fc7d4 83END_EXTERN_C
2b260de0
GS
84#endif
85
6890e559
GS
86#define EXECF_EXEC 1
87#define EXECF_SPAWN 2
88#define EXECF_SPAWN_NOWAIT 3
89
32e30700 90#if defined(PERL_IMPLICIT_SYS)
32e30700
GS
91# undef getlogin
92# define getlogin g_getlogin
93#endif
94
58d049f0
JD
95/* VS2005 (MSC version 14) provides a mechanism to set an invalid
96 * parameter handler. This functionality is not available in the
97 * 64-bit compiler from the Platform SDK, which unfortunately also
98 * believes itself to be MSC version 14.
99 *
100 * There is no #define related to _set_invalid_parameter_handler(),
101 * but we can check for one of the constants defined for
102 * _set_abort_behavior(), which was introduced into stdlib.h at
103 * the same time.
104 */
105
106#if _MSC_VER >= 1400 && defined(_WRITE_ABORT_MSG)
107# define SET_INVALID_PARAMETER_HANDLER
108#endif
109
110#ifdef SET_INVALID_PARAMETER_HANDLER
d52ca586 111static BOOL set_silent_invalid_parameter_handler(BOOL newvalue);
e2cd629f
SH
112static void my_invalid_parameter_handler(const wchar_t* expression,
113 const wchar_t* function, const wchar_t* file,
114 unsigned int line, uintptr_t pReserved);
115#endif
116
6937817d 117#ifndef WIN32_NO_REGISTRY
e2cd629f
SH
118static char* get_regstr_from(HKEY hkey, const char *valuename, SV **svp);
119static char* get_regstr(const char *valuename, SV **svp);
6937817d
DD
120#endif
121
e2cd629f
SH
122static char* get_emd_part(SV **prev_pathp, STRLEN *const len,
123 char *trailing, ...);
6937817d
DD
124static char* win32_get_xlib(const char *pl,
125 WIN32_NO_REGISTRY_M_(const char *xlib)
e2cd629f 126 const char *libname, STRLEN *const len);
6937817d 127
e2cd629f
SH
128static BOOL has_shell_metachars(const char *ptr);
129static long tokenize(const char *str, char **dest, char ***destv);
130static void get_shell(void);
131static char* find_next_space(const char *s);
132static int do_spawn2(pTHX_ const char *cmd, int exectype);
f06c8825
TC
133static int do_spawn2_handles(pTHX_ const char *cmd, int exectype,
134 const int *handles);
135static int do_spawnvp_handles(int mode, const char *cmdname,
136 const char * const *argv, const int *handles);
aac983ac
TC
137static PerlIO * do_popen(const char *mode, const char *command, IV narg,
138 SV **args);
04a2c3d9 139static long find_pid(pTHX_ int pid);
e2cd629f
SH
140static void remove_dead_process(long child);
141static int terminate_process(DWORD pid, HANDLE process_handle, int sig);
721b2674 142static int my_killpg(int pid, int sig);
e2cd629f
SH
143static int my_kill(int pid, int sig);
144static void out_of_memory(void);
00a0ae28 145static char* wstr_to_str(const wchar_t* wstr);
e2cd629f
SH
146static long filetime_to_clock(PFILETIME ft);
147static BOOL filetime_from_time(PFILETIME ft, time_t t);
148static char* create_command_line(char *cname, STRLEN clen,
aac983ac 149 const char * const *args);
f5fe1b19 150static char* qualified_path(const char *cmd, bool other_exts);
e2cd629f
SH
151static void ansify_path(void);
152static LRESULT win32_process_message(HWND hwnd, UINT msg,
153 WPARAM wParam, LPARAM lParam);
154
155#ifdef USE_ITHREADS
04a2c3d9 156static long find_pseudo_pid(pTHX_ int pid);
e2cd629f
SH
157static void remove_dead_pseudo_process(long child);
158static HWND get_hwnd_delay(pTHX, long child, DWORD tries);
159#endif
160
161#ifdef HAVE_INTERP_INTERN
162static void win32_csighandler(int sig);
163#endif
164
165START_EXTERN_C
166HANDLE w32_perldll_handle = INVALID_HANDLE_VALUE;
167char w32_module_name[MAX_PATH+1];
b47a847f
DD
168#ifdef WIN32_DYN_IOINFO_SIZE
169Size_t w32_ioinfo_size;/* avoid 0 extend op b4 mul, otherwise could be a U8 */
170#endif
e2cd629f
SH
171END_EXTERN_C
172
173static OSVERSIONINFO g_osver = {0, 0, 0, 0, 0, ""};
174
6937817d 175#ifndef WIN32_NO_REGISTRY
0517ed38
DD
176/* initialized by Perl_win32_init/PERL_SYS_INIT */
177static HKEY HKCU_Perl_hnd;
178static HKEY HKLM_Perl_hnd;
6937817d 179#endif
0517ed38 180
e2cd629f 181#ifdef SET_INVALID_PARAMETER_HANDLER
d52ca586
SH
182static BOOL silent_invalid_parameter_handler = FALSE;
183
184static BOOL
185set_silent_invalid_parameter_handler(BOOL newvalue)
186{
d52ca586 187 BOOL oldvalue = silent_invalid_parameter_handler;
adb86be5 188# ifdef _DEBUG
d52ca586 189 silent_invalid_parameter_handler = newvalue;
d52ca586 190# endif
adb86be5 191 return oldvalue;
d52ca586
SH
192}
193
e2cd629f
SH
194static void
195my_invalid_parameter_handler(const wchar_t* expression,
0448a0bd
SH
196 const wchar_t* function,
197 const wchar_t* file,
198 unsigned int line,
199 uintptr_t pReserved)
200{
201# ifdef _DEBUG
00a0ae28
SH
202 char* ansi_expression;
203 char* ansi_function;
204 char* ansi_file;
d52ca586
SH
205 if (silent_invalid_parameter_handler)
206 return;
00a0ae28
SH
207 ansi_expression = wstr_to_str(expression);
208 ansi_function = wstr_to_str(function);
209 ansi_file = wstr_to_str(file);
210 fprintf(stderr, "Invalid parameter detected in function %s. "
211 "File: %s, line: %d\n", ansi_function, ansi_file, line);
212 fprintf(stderr, "Expression: %s\n", ansi_expression);
213 free(ansi_expression);
214 free(ansi_function);
215 free(ansi_file);
0448a0bd
SH
216# endif
217}
218#endif
219
2fa86c13
GS
220EXTERN_C void
221set_w32_module_name(void)
222{
aa2b96ec 223 /* this function may be called at DLL_PROCESS_ATTACH time */
2fa86c13 224 char* ptr;
aa2b96ec
JD
225 HMODULE module = (HMODULE)((w32_perldll_handle == INVALID_HANDLE_VALUE)
226 ? GetModuleHandle(NULL)
227 : w32_perldll_handle);
2fa86c13 228
0e7b7035
SH
229 WCHAR modulename[MAX_PATH];
230 WCHAR fullname[MAX_PATH];
231 char *ansi;
232
233 DWORD (__stdcall *pfnGetLongPathNameW)(LPCWSTR, LPWSTR, DWORD) =
234 (DWORD (__stdcall *)(LPCWSTR, LPWSTR, DWORD))
235 GetProcAddress(GetModuleHandle("kernel32.dll"), "GetLongPathNameW");
236
237 GetModuleFileNameW(module, modulename, sizeof(modulename)/sizeof(WCHAR));
238
239 /* Make sure we get an absolute pathname in case the module was loaded
240 * explicitly by LoadLibrary() with a relative path. */
241 GetFullPathNameW(modulename, sizeof(fullname)/sizeof(WCHAR), fullname, NULL);
242
243 /* Make sure we start with the long path name of the module because we
244 * later scan for pathname components to match "5.xx" to locate
245 * compatible sitelib directories, and the short pathname might mangle
246 * this path segment (e.g. by removing the dot on NTFS to something
247 * like "5xx~1.yy") */
248 if (pfnGetLongPathNameW)
249 pfnGetLongPathNameW(fullname, fullname, sizeof(fullname)/sizeof(WCHAR));
250
251 /* remove \\?\ prefix */
252 if (memcmp(fullname, L"\\\\?\\", 4*sizeof(WCHAR)) == 0)
253 memmove(fullname, fullname+4, (wcslen(fullname+4)+1)*sizeof(WCHAR));
254
255 ansi = win32_ansipath(fullname);
256 my_strlcpy(w32_module_name, ansi, sizeof(w32_module_name));
257 win32_free(ansi);
2fa86c13
GS
258
259 /* normalize to forward slashes */
260 ptr = w32_module_name;
261 while (*ptr) {
262 if (*ptr == '\\')
263 *ptr = '/';
264 ++ptr;
265 }
266}
267
6937817d 268#ifndef WIN32_NO_REGISTRY
c5be433b 269/* *svp (if non-NULL) is expected to be POK (valid allocated SvPVX(*svp)) */
51371543 270static char*
0517ed38 271get_regstr_from(HKEY handle, const char *valuename, SV **svp)
349ad1fe
GS
272{
273 /* Retrieve a REG_SZ or REG_EXPAND_SZ from the registry */
00dc2f4f 274 DWORD type;
4e205ed6 275 char *str = NULL;
00dc2f4f 276 long retval;
0517ed38 277 DWORD datalen;
00dc2f4f 278
0517ed38
DD
279 retval = RegQueryValueEx(handle, valuename, 0, &type, NULL, &datalen);
280 if (retval == ERROR_SUCCESS
281 && (type == REG_SZ || type == REG_EXPAND_SZ))
282 {
283 dTHX;
284 if (!*svp)
285 *svp = sv_2mortal(newSVpvs(""));
286 SvGROW(*svp, datalen);
287 retval = RegQueryValueEx(handle, valuename, 0, NULL,
288 (PBYTE)SvPVX(*svp), &datalen);
289 if (retval == ERROR_SUCCESS) {
290 str = SvPVX(*svp);
291 SvCUR_set(*svp,datalen-1);
00dc2f4f 292 }
00dc2f4f 293 }
349ad1fe 294 return str;
00dc2f4f
GS
295}
296
c5be433b 297/* *svp (if non-NULL) is expected to be POK (valid allocated SvPVX(*svp)) */
51371543 298static char*
c5be433b 299get_regstr(const char *valuename, SV **svp)
00dc2f4f 300{
0517ed38
DD
301 char *str;
302 if (HKCU_Perl_hnd) {
303 str = get_regstr_from(HKCU_Perl_hnd, valuename, svp);
304 if (!str)
305 goto try_HKLM;
306 }
307 else {
308 try_HKLM:
309 if (HKLM_Perl_hnd)
310 str = get_regstr_from(HKLM_Perl_hnd, valuename, svp);
311 else
312 str = NULL;
313 }
349ad1fe 314 return str;
00dc2f4f 315}
6937817d 316#endif /* ifndef WIN32_NO_REGISTRY */
00dc2f4f 317
c5be433b 318/* *prev_pathp (if non-NULL) is expected to be POK (valid allocated SvPVX(sv)) */
e5a95ffb 319static char *
e6a0bbf8 320get_emd_part(SV **prev_pathp, STRLEN *const len, char *trailing_path, ...)
00dc2f4f 321{
dc9e4912 322 char base[10];
e5a95ffb 323 va_list ap;
e24c7c18 324 char mod_name[MAX_PATH+1];
00dc2f4f 325 char *ptr;
e5a95ffb
GS
326 char *optr;
327 char *strip;
273cf8d1 328 STRLEN baselen;
e5a95ffb
GS
329
330 va_start(ap, trailing_path);
331 strip = va_arg(ap, char *);
332
273cf8d1
GS
333 sprintf(base, "%d.%d", (int)PERL_REVISION, (int)PERL_VERSION);
334 baselen = strlen(base);
dc9e4912 335
8ac9c18d 336 if (!*w32_module_name) {
2fa86c13 337 set_w32_module_name();
95140b98 338 }
8ac9c18d 339 strcpy(mod_name, w32_module_name);
95140b98 340 ptr = strrchr(mod_name, '/');
e5a95ffb
GS
341 while (ptr && strip) {
342 /* look for directories to skip back */
343 optr = ptr;
00dc2f4f 344 *ptr = '\0';
95140b98 345 ptr = strrchr(mod_name, '/');
1c39adb2
GS
346 /* avoid stripping component if there is no slash,
347 * or it doesn't match ... */
e5a95ffb 348 if (!ptr || stricmp(ptr+1, strip) != 0) {
273cf8d1 349 /* ... but not if component matches m|5\.$patchlevel.*| */
1c39adb2 350 if (!ptr || !(*strip == '5' && *(ptr+1) == '5'
a15aa957
KW
351 && strnEQ(strip, base, baselen)
352 && strnEQ(ptr+1, base, baselen)))
95140b98
GS
353 {
354 *optr = '/';
80252599
GS
355 ptr = optr;
356 }
00dc2f4f 357 }
e5a95ffb 358 strip = va_arg(ap, char *);
00dc2f4f 359 }
e5a95ffb
GS
360 if (!ptr) {
361 ptr = mod_name;
362 *ptr++ = '.';
95140b98 363 *ptr = '/';
00dc2f4f 364 }
e5a95ffb
GS
365 va_end(ap);
366 strcpy(++ptr, trailing_path);
367
dc9e4912 368 /* only add directory if it exists */
349ad1fe 369 if (GetFileAttributes(mod_name) != (DWORD) -1) {
dc9e4912 370 /* directory exists */
acfe0abc 371 dTHX;
c5be433b 372 if (!*prev_pathp)
c2b90b61 373 *prev_pathp = sv_2mortal(newSVpvs(""));
f0c8bec2 374 else if (SvPVX(*prev_pathp))
46e2868e 375 sv_catpvs(*prev_pathp, ";");
c5be433b 376 sv_catpv(*prev_pathp, mod_name);
e6a0bbf8
NC
377 if(len)
378 *len = SvCUR(*prev_pathp);
c5be433b 379 return SvPVX(*prev_pathp);
00dc2f4f 380 }
00dc2f4f 381
4e205ed6 382 return NULL;
00dc2f4f
GS
383}
384
73f2c082 385EXTERN_C char *
6937817d 386win32_get_privlib(WIN32_NO_REGISTRY_M_(const char *pl) STRLEN *const len)
00dc2f4f 387{
e5a95ffb 388 char *stdlib = "lib";
4e205ed6 389 SV *sv = NULL;
6937817d
DD
390#ifndef WIN32_NO_REGISTRY
391 char buffer[MAX_PATH+1];
00dc2f4f 392
e5a95ffb
GS
393 /* $stdlib = $HKCU{"lib-$]"} || $HKLM{"lib-$]"} || $HKCU{"lib"} || $HKLM{"lib"} || ""; */
394 sprintf(buffer, "%s-%s", stdlib, pl);
c5be433b
GS
395 if (!get_regstr(buffer, &sv))
396 (void)get_regstr(stdlib, &sv);
6937817d 397#endif
00dc2f4f 398
e5a95ffb 399 /* $stdlib .= ";$EMD/../../lib" */
e6a0bbf8 400 return get_emd_part(&sv, len, stdlib, ARCHNAME, "bin", NULL);
00dc2f4f
GS
401}
402
4ea817c6 403static char *
6937817d
DD
404win32_get_xlib(const char *pl, WIN32_NO_REGISTRY_M_(const char *xlib)
405 const char *libname, STRLEN *const len)
00dc2f4f 406{
6937817d 407#ifndef WIN32_NO_REGISTRY
e5a95ffb 408 char regstr[40];
6937817d 409#endif
e24c7c18 410 char pathstr[MAX_PATH+1];
4e205ed6
SP
411 SV *sv1 = NULL;
412 SV *sv2 = NULL;
00dc2f4f 413
6937817d 414#ifndef WIN32_NO_REGISTRY
4ea817c6
GS
415 /* $HKCU{"$xlib-$]"} || $HKLM{"$xlib-$]"} . ---; */
416 sprintf(regstr, "%s-%s", xlib, pl);
c5be433b 417 (void)get_regstr(regstr, &sv1);
6937817d 418#endif
e5a95ffb 419
4ea817c6
GS
420 /* $xlib .=
421 * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/$libname/$]/lib"; */
422 sprintf(pathstr, "%s/%s/lib", libname, pl);
e6a0bbf8 423 (void)get_emd_part(&sv1, NULL, pathstr, ARCHNAME, "bin", pl, NULL);
00dc2f4f 424
6937817d 425#ifndef WIN32_NO_REGISTRY
4ea817c6
GS
426 /* $HKCU{$xlib} || $HKLM{$xlib} . ---; */
427 (void)get_regstr(xlib, &sv2);
6937817d 428#endif
00dc2f4f 429
4ea817c6
GS
430 /* $xlib .=
431 * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/$libname/lib"; */
432 sprintf(pathstr, "%s/lib", libname);
e6a0bbf8 433 (void)get_emd_part(&sv2, NULL, pathstr, ARCHNAME, "bin", pl, NULL);
e5a95ffb 434
51371543 435 if (!sv1 && !sv2)
4e205ed6 436 return NULL;
e6a0bbf8
NC
437 if (!sv1) {
438 sv1 = sv2;
439 } else if (sv2) {
04a2c3d9 440 dTHX;
f8db7d5b 441 sv_catpvs(sv1, ";");
e6a0bbf8
NC
442 sv_catsv(sv1, sv2);
443 }
e5a95ffb 444
e6a0bbf8
NC
445 if (len)
446 *len = SvCUR(sv1);
349ad1fe 447 return SvPVX(sv1);
68dc0745 448}
0a753a76 449
73f2c082 450EXTERN_C char *
e6a0bbf8 451win32_get_sitelib(const char *pl, STRLEN *const len)
4ea817c6 452{
6937817d 453 return win32_get_xlib(pl, WIN32_NO_REGISTRY_M_("sitelib") "site", len);
4ea817c6
GS
454}
455
456#ifndef PERL_VENDORLIB_NAME
457# define PERL_VENDORLIB_NAME "vendor"
458#endif
459
73f2c082 460EXTERN_C char *
e6a0bbf8 461win32_get_vendorlib(const char *pl, STRLEN *const len)
4ea817c6 462{
6937817d 463 return win32_get_xlib(pl, WIN32_NO_REGISTRY_M_("vendorlib") PERL_VENDORLIB_NAME, len);
4ea817c6 464}
b4793f7f 465
2d7a9237 466static BOOL
08039b81 467has_shell_metachars(const char *ptr)
68dc0745 468{
469 int inquote = 0;
470 char quote = '\0';
471
472 /*
473 * Scan string looking for redirection (< or >) or pipe
e200fe59
JD
474 * characters (|) that are not in a quoted string.
475 * Shell variable interpolation (%VAR%) can also happen inside strings.
68dc0745 476 */
9404a519 477 while (*ptr) {
68dc0745 478 switch(*ptr) {
e200fe59
JD
479 case '%':
480 return TRUE;
68dc0745 481 case '\'':
482 case '\"':
9404a519
GS
483 if (inquote) {
484 if (quote == *ptr) {
68dc0745 485 inquote = 0;
486 quote = '\0';
0a753a76 487 }
68dc0745 488 }
489 else {
490 quote = *ptr;
491 inquote++;
492 }
493 break;
494 case '>':
495 case '<':
496 case '|':
9404a519 497 if (!inquote)
68dc0745 498 return TRUE;
499 default:
500 break;
0a753a76 501 }
68dc0745 502 ++ptr;
503 }
504 return FALSE;
0a753a76 505}
506
32e30700 507#if !defined(PERL_IMPLICIT_SYS)
68dc0745 508/* since the current process environment is being updated in util.c
509 * the library functions will get the correct environment
510 */
511PerlIO *
79d39d80 512Perl_my_popen(pTHX_ const char *cmd, const char *mode)
0a753a76 513{
45bc9206 514 PERL_FLUSHALL_FOR_CHILD;
0a753a76 515 return win32_popen(cmd, mode);
0a753a76 516}
517
68dc0745 518long
4f63d024 519Perl_my_pclose(pTHX_ PerlIO *fp)
0a753a76 520{
521 return win32_pclose(fp);
522}
c69f6586 523#endif
0a753a76 524
0cb96387
GS
525DllExport unsigned long
526win32_os_id(void)
0a753a76 527{
aeecf691 528 return (unsigned long)g_osver.dwPlatformId;
0a753a76 529}
530
7766f137
GS
531DllExport int
532win32_getpid(void)
533{
534#ifdef USE_ITHREADS
acfe0abc 535 dTHX;
7766f137
GS
536 if (w32_pseudo_id)
537 return -((int)w32_pseudo_id);
538#endif
8cbe99e5 539 return _getpid();
7766f137
GS
540}
541
ce1da67e
GS
542/* Tokenize a string. Words are null-separated, and the list
543 * ends with a doubled null. Any character (except null and
544 * including backslash) may be escaped by preceding it with a
545 * backslash (the backslash will be stripped).
546 * Returns number of words in result buffer.
547 */
548static long
dff6d3cd 549tokenize(const char *str, char **dest, char ***destv)
ce1da67e 550{
4e205ed6 551 char *retstart = NULL;
ce1da67e
GS
552 char **retvstart = 0;
553 int items = -1;
554 if (str) {
555 int slen = strlen(str);
eb578fdb
KW
556 char *ret;
557 char **retv;
a02a5408
JC
558 Newx(ret, slen+2, char);
559 Newx(retv, (slen+3)/2, char*);
ce1da67e
GS
560
561 retstart = ret;
562 retvstart = retv;
563 *retv = ret;
564 items = 0;
565 while (*str) {
566 *ret = *str++;
567 if (*ret == '\\' && *str)
568 *ret = *str++;
569 else if (*ret == ' ') {
570 while (*str == ' ')
571 str++;
572 if (ret == retstart)
573 ret--;
574 else {
575 *ret = '\0';
576 ++items;
577 if (*str)
578 *++retv = ret+1;
579 }
580 }
581 else if (!*str)
582 ++items;
583 ret++;
584 }
4e205ed6 585 retvstart[items] = NULL;
ce1da67e
GS
586 *ret++ = '\0';
587 *ret = '\0';
588 }
589 *dest = retstart;
590 *destv = retvstart;
591 return items;
592}
593
594static void
2d7a9237 595get_shell(void)
0a753a76 596{
acfe0abc 597 dTHX;
ce1da67e 598 if (!w32_perlshell_tokens) {
174c211a
GS
599 /* we don't use COMSPEC here for two reasons:
600 * 1. the same reason perl on UNIX doesn't use SHELL--rampant and
601 * uncontrolled unportability of the ensuing scripts.
602 * 2. PERL5SHELL could be set to a shell that may not be fit for
603 * interactive use (which is what most programs look in COMSPEC
604 * for).
605 */
8cbe99e5 606 const char* defaultshell = "cmd.exe /x/d/c";
2fb9ab56 607 const char *usershell = PerlEnv_getenv("PERL5SHELL");
ce1da67e
GS
608 w32_perlshell_items = tokenize(usershell ? usershell : defaultshell,
609 &w32_perlshell_tokens,
610 &w32_perlshell_vec);
68dc0745 611 }
0a753a76 612}
613
68dc0745 614int
54725af6 615Perl_do_aspawn(pTHX_ SV *really, SV **mark, SV **sp)
0a753a76 616{
68dc0745 617 char **argv;
2d7a9237 618 char *str;
68dc0745 619 int status;
2d7a9237 620 int flag = P_WAIT;
68dc0745 621 int index = 0;
69374fe7 622 int eno;
68dc0745 623
7918f24d
NC
624 PERL_ARGS_ASSERT_DO_ASPAWN;
625
2d7a9237
GS
626 if (sp <= mark)
627 return -1;
68dc0745 628
ce1da67e 629 get_shell();
a02a5408 630 Newx(argv, (sp - mark) + w32_perlshell_items + 2, char*);
2d7a9237
GS
631
632 if (SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) {
633 ++mark;
634 flag = SvIVx(*mark);
68dc0745 635 }
636
9404a519 637 while (++mark <= sp) {
bb897dfc 638 if (*mark && (str = SvPV_nolen(*mark)))
2d7a9237
GS
639 argv[index++] = str;
640 else
641 argv[index++] = "";
68dc0745 642 }
643 argv[index++] = 0;
3fadfdf1 644
2d7a9237 645 status = win32_spawnvp(flag,
bb897dfc 646 (const char*)(really ? SvPV_nolen(really) : argv[0]),
2d7a9237
GS
647 (const char* const*)argv);
648
69374fe7 649 if (status < 0 && (eno = errno, (eno == ENOEXEC || eno == ENOENT))) {
2d7a9237 650 /* possible shell-builtin, invoke with shell */
ce1da67e
GS
651 int sh_items;
652 sh_items = w32_perlshell_items;
2d7a9237
GS
653 while (--index >= 0)
654 argv[index+sh_items] = argv[index];
ce1da67e
GS
655 while (--sh_items >= 0)
656 argv[sh_items] = w32_perlshell_vec[sh_items];
3fadfdf1 657
2d7a9237 658 status = win32_spawnvp(flag,
bb897dfc 659 (const char*)(really ? SvPV_nolen(really) : argv[0]),
2d7a9237
GS
660 (const char* const*)argv);
661 }
68dc0745 662
922b1888 663 if (flag == P_NOWAIT) {
40c7cc6d 664 PL_statusvalue = -1; /* >16bits hint for pp_system() */
922b1888
GS
665 }
666 else {
50892819 667 if (status < 0) {
0453d815 668 if (ckWARN(WARN_EXEC))
f98bc0c6 669 Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't spawn \"%s\": %s", argv[0], strerror(errno));
50892819
GS
670 status = 255 * 256;
671 }
672 else
673 status *= 256;
b28d0864 674 PL_statusvalue = status;
5aabfad6 675 }
ce1da67e 676 Safefree(argv);
50892819 677 return (status);
68dc0745 678}
679
dd7038b3
JH
680/* returns pointer to the next unquoted space or the end of the string */
681static char*
682find_next_space(const char *s)
683{
684 bool in_quotes = FALSE;
685 while (*s) {
686 /* ignore doubled backslashes, or backslash+quote */
687 if (*s == '\\' && (s[1] == '\\' || s[1] == '"')) {
688 s += 2;
689 }
690 /* keep track of when we're within quotes */
691 else if (*s == '"') {
692 s++;
693 in_quotes = !in_quotes;
694 }
695 /* break it up only at spaces that aren't in quotes */
696 else if (!in_quotes && isSPACE(*s))
697 return (char*)s;
698 else
699 s++;
700 }
701 return (char*)s;
702}
703
54725af6 704static int
f06c8825
TC
705do_spawn2(pTHX_ const char *cmd, int exectype) {
706 return do_spawn2_handles(aTHX_ cmd, exectype, NULL);
707}
708
709static int
710do_spawn2_handles(pTHX_ const char *cmd, int exectype, const int *handles)
68dc0745 711{
712 char **a;
713 char *s;
714 char **argv;
715 int status = -1;
716 BOOL needToTry = TRUE;
2d7a9237 717 char *cmd2;
68dc0745 718
2d7a9237
GS
719 /* Save an extra exec if possible. See if there are shell
720 * metacharacters in it */
e200fe59 721 if (!has_shell_metachars(cmd)) {
a02a5408
JC
722 Newx(argv, strlen(cmd) / 2 + 2, char*);
723 Newx(cmd2, strlen(cmd) + 1, char);
68dc0745 724 strcpy(cmd2, cmd);
725 a = argv;
726 for (s = cmd2; *s;) {
de030af3 727 while (*s && isSPACE(*s))
68dc0745 728 s++;
729 if (*s)
730 *(a++) = s;
dd7038b3 731 s = find_next_space(s);
9404a519 732 if (*s)
68dc0745 733 *s++ = '\0';
0a753a76 734 }
4e205ed6 735 *a = NULL;
ce1da67e 736 if (argv[0]) {
6890e559
GS
737 switch (exectype) {
738 case EXECF_SPAWN:
739 status = win32_spawnvp(P_WAIT, argv[0],
740 (const char* const*)argv);
741 break;
742 case EXECF_SPAWN_NOWAIT:
f06c8825
TC
743 status = do_spawnvp_handles(P_NOWAIT, argv[0],
744 (const char* const*)argv, handles);
6890e559
GS
745 break;
746 case EXECF_EXEC:
747 status = win32_execvp(argv[0], (const char* const*)argv);
748 break;
749 }
2d7a9237 750 if (status != -1 || errno == 0)
68dc0745 751 needToTry = FALSE;
0a753a76 752 }
0a753a76 753 Safefree(argv);
68dc0745 754 Safefree(cmd2);
755 }
2d7a9237 756 if (needToTry) {
ce1da67e
GS
757 char **argv;
758 int i = -1;
759 get_shell();
a02a5408 760 Newx(argv, w32_perlshell_items + 2, char*);
ce1da67e
GS
761 while (++i < w32_perlshell_items)
762 argv[i] = w32_perlshell_vec[i];
08039b81 763 argv[i++] = (char *)cmd;
4e205ed6 764 argv[i] = NULL;
6890e559
GS
765 switch (exectype) {
766 case EXECF_SPAWN:
767 status = win32_spawnvp(P_WAIT, argv[0],
768 (const char* const*)argv);
769 break;
770 case EXECF_SPAWN_NOWAIT:
f06c8825
TC
771 status = do_spawnvp_handles(P_NOWAIT, argv[0],
772 (const char* const*)argv, handles);
6890e559
GS
773 break;
774 case EXECF_EXEC:
775 status = win32_execvp(argv[0], (const char* const*)argv);
776 break;
777 }
ce1da67e
GS
778 cmd = argv[0];
779 Safefree(argv);
68dc0745 780 }
922b1888 781 if (exectype == EXECF_SPAWN_NOWAIT) {
40c7cc6d 782 PL_statusvalue = -1; /* >16bits hint for pp_system() */
922b1888
GS
783 }
784 else {
50892819 785 if (status < 0) {
0453d815 786 if (ckWARN(WARN_EXEC))
f98bc0c6 787 Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't %s \"%s\": %s",
50892819
GS
788 (exectype == EXECF_EXEC ? "exec" : "spawn"),
789 cmd, strerror(errno));
790 status = 255 * 256;
791 }
792 else
793 status *= 256;
b28d0864 794 PL_statusvalue = status;
5aabfad6 795 }
50892819 796 return (status);
0a753a76 797}
798
6890e559 799int
54725af6 800Perl_do_spawn(pTHX_ char *cmd)
6890e559 801{
7918f24d
NC
802 PERL_ARGS_ASSERT_DO_SPAWN;
803
54725af6 804 return do_spawn2(aTHX_ cmd, EXECF_SPAWN);
6890e559
GS
805}
806
2d7a9237 807int
54725af6 808Perl_do_spawn_nowait(pTHX_ char *cmd)
2d7a9237 809{
7918f24d
NC
810 PERL_ARGS_ASSERT_DO_SPAWN_NOWAIT;
811
54725af6 812 return do_spawn2(aTHX_ cmd, EXECF_SPAWN_NOWAIT);
2d7a9237
GS
813}
814
6890e559 815bool
79d39d80 816Perl_do_exec(pTHX_ const char *cmd)
6890e559 817{
7918f24d
NC
818 PERL_ARGS_ASSERT_DO_EXEC;
819
08039b81 820 do_spawn2(aTHX_ cmd, EXECF_EXEC);
6890e559
GS
821 return FALSE;
822}
823
68dc0745 824/* The idea here is to read all the directory names into a string table
825 * (separated by nulls) and when one of the other dir functions is called
826 * return the pointer to the current file name.
827 */
c5be433b 828DllExport DIR *
0e06f75d 829win32_opendir(const char *filename)
0a753a76 830{
04a2c3d9 831 dTHXa(NULL);
95136add 832 DIR *dirp;
9404a519
GS
833 long len;
834 long idx;
835 char scanname[MAX_PATH+3];
8cbe99e5 836 WCHAR wscanname[sizeof(scanname)];
35cf1ab6 837 WIN32_FIND_DATAW wFindData;
35cf1ab6 838 char buffer[MAX_PATH*2];
8cbe99e5 839 BOOL use_default;
9404a519
GS
840
841 len = strlen(filename);
525f9ba8
AD
842 if (len == 0) {
843 errno = ENOENT;
9404a519 844 return NULL;
525f9ba8
AD
845 }
846 if (len > MAX_PATH) {
847 errno = ENAMETOOLONG;
24caa93f 848 return NULL;
525f9ba8
AD
849 }
850
68dc0745 851 /* Get us a DIR structure */
a02a5408 852 Newxz(dirp, 1, DIR);
68dc0745 853
854 /* Create the search pattern */
855 strcpy(scanname, filename);
23db2e2d
GS
856
857 /* bare drive name means look in cwd for drive */
858 if (len == 2 && isALPHA(scanname[0]) && scanname[1] == ':') {
859 scanname[len++] = '.';
860 scanname[len++] = '/';
861 }
862 else if (scanname[len-1] != '/' && scanname[len-1] != '\\') {
9404a519 863 scanname[len++] = '/';
23db2e2d 864 }
9404a519
GS
865 scanname[len++] = '*';
866 scanname[len] = '\0';
68dc0745 867
868 /* do the FindFirstFile call */
8cbe99e5 869 MultiByteToWideChar(CP_ACP, 0, scanname, -1, wscanname, sizeof(wscanname)/sizeof(WCHAR));
04a2c3d9 870 aTHXa(PERL_GET_THX);
8cbe99e5
JD
871 dirp->handle = FindFirstFileW(PerlDir_mapW(wscanname), &wFindData);
872
8c56068e 873 if (dirp->handle == INVALID_HANDLE_VALUE) {
95136add 874 DWORD err = GetLastError();
21e72512 875 /* FindFirstFile() fails on empty drives! */
95136add
GS
876 switch (err) {
877 case ERROR_FILE_NOT_FOUND:
878 return dirp;
879 case ERROR_NO_MORE_FILES:
880 case ERROR_PATH_NOT_FOUND:
881 errno = ENOENT;
882 break;
883 case ERROR_NOT_ENOUGH_MEMORY:
884 errno = ENOMEM;
885 break;
886 default:
887 errno = EINVAL;
888 break;
889 }
890 Safefree(dirp);
68dc0745 891 return NULL;
892 }
893
8cbe99e5
JD
894 use_default = FALSE;
895 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS,
896 wFindData.cFileName, -1,
897 buffer, sizeof(buffer), NULL, &use_default);
898 if (use_default && *wFindData.cAlternateFileName) {
35cf1ab6 899 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS,
8cbe99e5
JD
900 wFindData.cAlternateFileName, -1,
901 buffer, sizeof(buffer), NULL, NULL);
35cf1ab6 902 }
8cbe99e5 903
68dc0745 904 /* now allocate the first part of the string table for
905 * the filenames that we find.
906 */
8cbe99e5 907 idx = strlen(buffer)+1;
95136add 908 if (idx < 256)
35cf1ab6 909 dirp->size = 256;
95136add
GS
910 else
911 dirp->size = idx;
a02a5408 912 Newx(dirp->start, dirp->size, char);
8cbe99e5 913 strcpy(dirp->start, buffer);
95136add
GS
914 dirp->nfiles++;
915 dirp->end = dirp->curr = dirp->start;
916 dirp->end += idx;
917 return dirp;
0a753a76 918}
919
920
68dc0745 921/* Readdir just returns the current string pointer and bumps the
922 * string pointer to the nDllExport entry.
923 */
c5be433b 924DllExport struct direct *
ce2e26e5 925win32_readdir(DIR *dirp)
0a753a76 926{
95136add 927 long len;
0a753a76 928
68dc0745 929 if (dirp->curr) {
930 /* first set up the structure to return */
931 len = strlen(dirp->curr);
0f38926b 932 strcpy(dirp->dirstr.d_name, dirp->curr);
68dc0745 933 dirp->dirstr.d_namlen = len;
0a753a76 934
68dc0745 935 /* Fake an inode */
0f38926b 936 dirp->dirstr.d_ino = dirp->curr - dirp->start;
0a753a76 937
95136add 938 /* Now set up for the next call to readdir */
68dc0745 939 dirp->curr += len + 1;
95136add 940 if (dirp->curr >= dirp->end) {
35cf1ab6 941 BOOL res;
35cf1ab6 942 char buffer[MAX_PATH*2];
95136add 943
60b22aca
JD
944 if (dirp->handle == INVALID_HANDLE_VALUE) {
945 res = 0;
946 }
95136add
GS
947 /* finding the next file that matches the wildcard
948 * (which should be all of them in this directory!).
95136add 949 */
8cbe99e5 950 else {
35cf1ab6
JD
951 WIN32_FIND_DATAW wFindData;
952 res = FindNextFileW(dirp->handle, &wFindData);
953 if (res) {
954 BOOL use_default = FALSE;
955 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS,
956 wFindData.cFileName, -1,
957 buffer, sizeof(buffer), NULL, &use_default);
958 if (use_default && *wFindData.cAlternateFileName) {
959 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS,
960 wFindData.cAlternateFileName, -1,
961 buffer, sizeof(buffer), NULL, NULL);
962 }
35cf1ab6
JD
963 }
964 }
95136add 965 if (res) {
0f38926b 966 long endpos = dirp->end - dirp->start;
8cbe99e5 967 long newsize = endpos + strlen(buffer) + 1;
95136add 968 /* bump the string table size by enough for the
022735b4 969 * new name and its null terminator */
0f38926b
GS
970 while (newsize > dirp->size) {
971 long curpos = dirp->curr - dirp->start;
35a27ac0 972 Renew(dirp->start, dirp->size * 2, char);
95136add 973 dirp->size *= 2;
0f38926b 974 dirp->curr = dirp->start + curpos;
95136add 975 }
8cbe99e5 976 strcpy(dirp->start + endpos, buffer);
0f38926b 977 dirp->end = dirp->start + newsize;
95136add
GS
978 dirp->nfiles++;
979 }
60b22aca 980 else {
95136add 981 dirp->curr = NULL;
60b22aca
JD
982 if (dirp->handle != INVALID_HANDLE_VALUE) {
983 FindClose(dirp->handle);
984 dirp->handle = INVALID_HANDLE_VALUE;
985 }
986 }
68dc0745 987 }
68dc0745 988 return &(dirp->dirstr);
3fadfdf1 989 }
68dc0745 990 else
991 return NULL;
0a753a76 992}
993
68dc0745 994/* Telldir returns the current string pointer position */
c5be433b 995DllExport long
ce2e26e5 996win32_telldir(DIR *dirp)
0a753a76 997{
60b22aca 998 return dirp->curr ? (dirp->curr - dirp->start) : -1;
0a753a76 999}
1000
1001
68dc0745 1002/* Seekdir moves the string pointer to a previously saved position
95136add 1003 * (returned by telldir).
68dc0745 1004 */
c5be433b 1005DllExport void
ce2e26e5 1006win32_seekdir(DIR *dirp, long loc)
0a753a76 1007{
60b22aca 1008 dirp->curr = loc == -1 ? NULL : dirp->start + loc;
0a753a76 1009}
1010
68dc0745 1011/* Rewinddir resets the string pointer to the start */
c5be433b 1012DllExport void
ce2e26e5 1013win32_rewinddir(DIR *dirp)
0a753a76 1014{
1015 dirp->curr = dirp->start;
1016}
1017
68dc0745 1018/* free the memory allocated by opendir */
c5be433b 1019DllExport int
ce2e26e5 1020win32_closedir(DIR *dirp)
0a753a76 1021{
95136add 1022 if (dirp->handle != INVALID_HANDLE_VALUE)
0f38926b 1023 FindClose(dirp->handle);
0a753a76 1024 Safefree(dirp->start);
1025 Safefree(dirp);
68dc0745 1026 return 1;
0a753a76 1027}
1028
60b22aca
JD
1029/* duplicate a open DIR* for interpreter cloning */
1030DllExport DIR *
1031win32_dirp_dup(DIR *const dirp, CLONE_PARAMS *const param)
1032{
1033 dVAR;
1034 PerlInterpreter *const from = param->proto_perl;
f76b679e 1035 PerlInterpreter *const to = (PerlInterpreter *)PERL_GET_THX;
60b22aca
JD
1036
1037 long pos;
1038 DIR *dup;
1039
1040 /* switch back to original interpreter because win32_readdir()
1041 * might Renew(dirp->start).
1042 */
1043 if (from != to) {
1044 PERL_SET_THX(from);
1045 }
1046
1047 /* mark current position; read all remaining entries into the
1048 * cache, and then restore to current position.
1049 */
1050 pos = win32_telldir(dirp);
1051 while (win32_readdir(dirp)) {
1052 /* read all entries into cache */
1053 }
1054 win32_seekdir(dirp, pos);
1055
1056 /* switch back to new interpreter to allocate new DIR structure */
1057 if (from != to) {
1058 PERL_SET_THX(to);
1059 }
1060
1061 Newx(dup, 1, DIR);
1062 memcpy(dup, dirp, sizeof(DIR));
1063
1064 Newx(dup->start, dirp->size, char);
1065 memcpy(dup->start, dirp->start, dirp->size);
1066
1067 dup->end = dup->start + (dirp->end - dirp->start);
1068 if (dirp->curr)
1069 dup->curr = dup->start + (dirp->curr - dirp->start);
1070
1071 return dup;
1072}
0a753a76 1073
68dc0745 1074/*
1075 * various stubs
1076 */
0a753a76 1077
1078
68dc0745 1079/* Ownership
1080 *
1081 * Just pretend that everyone is a superuser. NT will let us know if
1082 * we don\'t really have permission to do something.
1083 */
0a753a76 1084
1085#define ROOT_UID ((uid_t)0)
1086#define ROOT_GID ((gid_t)0)
1087
68dc0745 1088uid_t
1089getuid(void)
0a753a76 1090{
68dc0745 1091 return ROOT_UID;
0a753a76 1092}
1093
68dc0745 1094uid_t
1095geteuid(void)
0a753a76 1096{
68dc0745 1097 return ROOT_UID;
0a753a76 1098}
1099
68dc0745 1100gid_t
1101getgid(void)
0a753a76 1102{
68dc0745 1103 return ROOT_GID;
0a753a76 1104}
1105
68dc0745 1106gid_t
1107getegid(void)
0a753a76 1108{
68dc0745 1109 return ROOT_GID;
0a753a76 1110}
1111
68dc0745 1112int
22239a37 1113setuid(uid_t auid)
3fadfdf1 1114{
22239a37 1115 return (auid == ROOT_UID ? 0 : -1);
0a753a76 1116}
1117
68dc0745 1118int
22239a37 1119setgid(gid_t agid)
0a753a76 1120{
22239a37 1121 return (agid == ROOT_GID ? 0 : -1);
0a753a76 1122}
1123
73f2c082 1124EXTERN_C char *
e34ffe5a
GS
1125getlogin(void)
1126{
acfe0abc 1127 dTHX;
3352bfcb
GS
1128 char *buf = w32_getlogin_buffer;
1129 DWORD size = sizeof(w32_getlogin_buffer);
e34ffe5a
GS
1130 if (GetUserName(buf,&size))
1131 return buf;
1132 return (char*)NULL;
1133}
1134
b990f8c8
GS
1135int
1136chown(const char *path, uid_t owner, gid_t group)
1137{
1138 /* XXX noop */
1c1c7f20 1139 return 0;
b990f8c8
GS
1140}
1141
00b02797
JH
1142/*
1143 * XXX this needs strengthening (for PerlIO)
1144 * -- BKS, 11-11-200
1145*/
f33b2f58 1146#if !defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 4
00b02797
JH
1147int mkstemp(const char *path)
1148{
1149 dTHX;
1150 char buf[MAX_PATH+1];
1151 int i = 0, fd = -1;
1152
1153retry:
1154 if (i++ > 10) { /* give up */
1155 errno = ENOENT;
1156 return -1;
1157 }
1158 if (!GetTempFileNameA((LPCSTR)path, "plr", 1, buf)) {
1159 errno = ENOENT;
1160 return -1;
1161 }
1162 fd = PerlLIO_open3(buf, O_CREAT|O_RDWR|O_EXCL, 0600);
1163 if (fd == -1)
1164 goto retry;
1165 return fd;
1166}
f33b2f58 1167#endif
00b02797 1168
0aaad0ff 1169static long
04a2c3d9 1170find_pid(pTHX_ int pid)
0a753a76 1171{
7766f137
GS
1172 long child = w32_num_children;
1173 while (--child >= 0) {
eb160463 1174 if ((int)w32_child_pids[child] == pid)
0aaad0ff
GS
1175 return child;
1176 }
1177 return -1;
1178}
1179
1180static void
1181remove_dead_process(long child)
1182{
1183 if (child >= 0) {
acfe0abc 1184 dTHX;
0aaad0ff 1185 CloseHandle(w32_child_handles[child]);
c00206c8 1186 Move(&w32_child_handles[child+1], &w32_child_handles[child],
0aaad0ff 1187 (w32_num_children-child-1), HANDLE);
c00206c8 1188 Move(&w32_child_pids[child+1], &w32_child_pids[child],
0aaad0ff
GS
1189 (w32_num_children-child-1), DWORD);
1190 w32_num_children--;
f55ee38a 1191 }
f55ee38a
GS
1192}
1193
7766f137
GS
1194#ifdef USE_ITHREADS
1195static long
04a2c3d9 1196find_pseudo_pid(pTHX_ int pid)
7766f137 1197{
7766f137
GS
1198 long child = w32_num_pseudo_children;
1199 while (--child >= 0) {
eb160463 1200 if ((int)w32_pseudo_child_pids[child] == pid)
7766f137
GS
1201 return child;
1202 }
1203 return -1;
1204}
1205
1206static void
1207remove_dead_pseudo_process(long child)
1208{
1209 if (child >= 0) {
acfe0abc 1210 dTHX;
7766f137 1211 CloseHandle(w32_pseudo_child_handles[child]);
c00206c8 1212 Move(&w32_pseudo_child_handles[child+1], &w32_pseudo_child_handles[child],
7766f137 1213 (w32_num_pseudo_children-child-1), HANDLE);
c00206c8 1214 Move(&w32_pseudo_child_pids[child+1], &w32_pseudo_child_pids[child],
7766f137 1215 (w32_num_pseudo_children-child-1), DWORD);
aeecf691
JD
1216 Move(&w32_pseudo_child_message_hwnds[child+1], &w32_pseudo_child_message_hwnds[child],
1217 (w32_num_pseudo_children-child-1), HWND);
8a3cb9c6
JD
1218 Move(&w32_pseudo_child_sigterm[child+1], &w32_pseudo_child_sigterm[child],
1219 (w32_num_pseudo_children-child-1), char);
7766f137
GS
1220 w32_num_pseudo_children--;
1221 }
1222}
8a3cb9c6
JD
1223
1224void
1225win32_wait_for_children(pTHX)
1226{
1227 if (w32_pseudo_children && w32_num_pseudo_children) {
1228 long child = 0;
1229 long count = 0;
1230 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
1231
1232 for (child = 0; child < w32_num_pseudo_children; ++child) {
1233 if (!w32_pseudo_child_sigterm[child])
1234 handles[count++] = w32_pseudo_child_handles[child];
1235 }
1236 /* XXX should use MsgWaitForMultipleObjects() to continue
1237 * XXX processing messages while we wait.
1238 */
1239 WaitForMultipleObjects(count, handles, TRUE, INFINITE);
1240
1241 while (w32_num_pseudo_children)
1242 CloseHandle(w32_pseudo_child_handles[--w32_num_pseudo_children]);
1243 }
1244}
7766f137
GS
1245#endif
1246
542cb85f
JD
1247static int
1248terminate_process(DWORD pid, HANDLE process_handle, int sig)
1249{
1250 switch(sig) {
1251 case 0:
1252 /* "Does process exist?" use of kill */
1253 return 1;
1254 case 2:
1255 if (GenerateConsoleCtrlEvent(CTRL_C_EVENT, pid))
1256 return 1;
1257 break;
1258 case SIGBREAK:
1259 case SIGTERM:
1260 if (GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, pid))
1261 return 1;
1262 break;
1263 default: /* For now be backwards compatible with perl 5.6 */
1264 case 9:
1265 /* Note that we will only be able to kill processes owned by the
1266 * current process owner, even when we are running as an administrator.
1267 * To kill processes of other owners we would need to set the
1268 * 'SeDebugPrivilege' privilege before obtaining the process handle.
1269 */
1270 if (TerminateProcess(process_handle, sig))
1271 return 1;
1272 break;
1273 }
1274 return 0;
1275}
1276
721b2674
DD
1277/* returns number of processes killed */
1278static int
1279my_killpg(int pid, int sig)
542cb85f
JD
1280{
1281 HANDLE process_handle;
1282 HANDLE snapshot_handle;
1283 int killed = 0;
1284
1285 process_handle = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
6a4d57af 1286 if (process_handle == NULL)
542cb85f
JD
1287 return 0;
1288
1289 killed += terminate_process(pid, process_handle, sig);
1290
8cbe99e5 1291 snapshot_handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
542cb85f
JD
1292 if (snapshot_handle != INVALID_HANDLE_VALUE) {
1293 PROCESSENTRY32 entry;
1294
1295 entry.dwSize = sizeof(entry);
8cbe99e5 1296 if (Process32First(snapshot_handle, &entry)) {
542cb85f 1297 do {
8cbe99e5 1298 if (entry.th32ParentProcessID == (DWORD)pid)
721b2674 1299 killed += my_killpg(entry.th32ProcessID, sig);
542cb85f
JD
1300 entry.dwSize = sizeof(entry);
1301 }
8cbe99e5 1302 while (Process32Next(snapshot_handle, &entry));
542cb85f
JD
1303 }
1304 CloseHandle(snapshot_handle);
1305 }
1306 CloseHandle(process_handle);
1307 return killed;
1308}
1309
721b2674 1310/* returns number of processes killed */
542cb85f
JD
1311static int
1312my_kill(int pid, int sig)
1313{
1314 int retval = 0;
1315 HANDLE process_handle;
1316
1317 if (sig < 0)
721b2674 1318 return my_killpg(pid, -sig);
542cb85f
JD
1319
1320 process_handle = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
6a4d57af
JD
1321 /* OpenProcess() returns NULL on error, *not* INVALID_HANDLE_VALUE */
1322 if (process_handle != NULL) {
542cb85f
JD
1323 retval = terminate_process(pid, process_handle, sig);
1324 CloseHandle(process_handle);
1325 }
1326 return retval;
1327}
1328
d903973c 1329#ifdef USE_ITHREADS
17ce47a8
SH
1330/* Get a child pseudo-process HWND, with retrying and delaying/yielding.
1331 * The "tries" parameter is the number of retries to make, with a Sleep(1)
1332 * (waiting and yielding the time slot) between each try. Specifying 0 causes
1333 * only Sleep(0) (no waiting and potentially no yielding) to be used, so is not
1334 * recommended
1335 * Returns an hwnd != INVALID_HANDLE_VALUE (so be aware that NULL can be
1336 * returned) or croaks if the child pseudo-process doesn't schedule and deliver
1337 * a HWND in the time period allowed.
1338 */
d903973c 1339static HWND
17ce47a8
SH
1340get_hwnd_delay(pTHX, long child, DWORD tries)
1341{
d903973c 1342 HWND hwnd = w32_pseudo_child_message_hwnds[child];
d903973c 1343 if (hwnd != INVALID_HANDLE_VALUE) return hwnd;
17ce47a8
SH
1344
1345 /* Pseudo-process has not yet properly initialized since hwnd isn't set.
1346 * Fast sleep: On some NT kernels/systems, a Sleep(0) won't deschedule a
1347 * thread 100% of the time since threads are attached to a CPU for NUMA and
1348 * caching reasons, and the child thread was attached to a different CPU
1349 * therefore there is no workload on that CPU and Sleep(0) returns control
1350 * without yielding the time slot.
1351 * https://rt.perl.org/rt3/Ticket/Display.html?id=88840
1352 */
d903973c
DD
1353 Sleep(0);
1354 win32_async_check(aTHX);
17ce47a8 1355 hwnd = w32_pseudo_child_message_hwnds[child];
d903973c 1356 if (hwnd != INVALID_HANDLE_VALUE) return hwnd;
17ce47a8 1357
d903973c 1358 {
adb86be5 1359 unsigned int count = 0;
17ce47a8
SH
1360 /* No Sleep(1) if tries==0, just fail instead if we get this far. */
1361 while (count++ < tries) {
1362 Sleep(1);
1363 win32_async_check(aTHX);
1364 hwnd = w32_pseudo_child_message_hwnds[child];
1365 if (hwnd != INVALID_HANDLE_VALUE) return hwnd;
1366 }
d903973c 1367 }
17ce47a8
SH
1368
1369 Perl_croak(aTHX_ "panic: child pseudo-process was never scheduled");
d903973c
DD
1370}
1371#endif
1372
f55ee38a
GS
1373DllExport int
1374win32_kill(int pid, int sig)
1375{
acfe0abc 1376 dTHX;
c66b022d 1377 long child;
7766f137
GS
1378#ifdef USE_ITHREADS
1379 if (pid < 0) {
1380 /* it is a pseudo-forked child */
04a2c3d9 1381 child = find_pseudo_pid(aTHX_ -pid);
7766f137 1382 if (child >= 0) {
85c508c3 1383 HANDLE hProcess = w32_pseudo_child_handles[child];
7e5f34c0 1384 switch (sig) {
17ce47a8
SH
1385 case 0:
1386 /* "Does process exist?" use of kill */
7e5f34c0 1387 return 0;
aeecf691 1388
17ce47a8
SH
1389 case 9: {
1390 /* kill -9 style un-graceful exit */
1391 /* Do a wait to make sure child starts and isn't in DLL
1392 * Loader Lock */
1393 HWND hwnd = get_hwnd_delay(aTHX, child, 5);
1394 if (TerminateThread(hProcess, sig)) {
1395 /* Allow the scheduler to finish cleaning up the other
1396 * thread.
1397 * Otherwise, if we ExitProcess() before another context
1398 * switch happens we will end up with a process exit
1399 * code of "sig" instead of our own exit status.
1400 * https://rt.cpan.org/Ticket/Display.html?id=66016#txn-908976
1401 */
1402 Sleep(0);
1403 remove_dead_pseudo_process(child);
1404 return 0;
1405 }
1406 break;
1407 }
1408
1409 default: {
1410 HWND hwnd = get_hwnd_delay(aTHX, child, 5);
1411 /* We fake signals to pseudo-processes using Win32
1412 * message queue. */
1413 if ((hwnd != NULL && PostMessage(hwnd, WM_USER_KILL, sig, 0)) ||
1414 PostThreadMessage(-pid, WM_USER_KILL, sig, 0))
1415 {
1416 /* Don't wait for child process to terminate after we send a
1417 * SIGTERM because the child may be blocked in a system call
1418 * and never receive the signal.
1419 */
1420 if (sig == SIGTERM) {
1421 Sleep(0);
1422 w32_pseudo_child_sigterm[child] = 1;
1423 }
1424 /* It might be us ... */
1425 PERL_ASYNC_CHECK();
1426 return 0;
1427 }
1428 break;
1429 }
1430 } /* switch */
7766f137 1431 }
68dc0745 1432 }
7766f137
GS
1433 else
1434#endif
1435 {
04a2c3d9 1436 child = find_pid(aTHX_ pid);
7766f137 1437 if (child >= 0) {
542cb85f
JD
1438 if (my_kill(pid, sig)) {
1439 DWORD exitcode = 0;
1440 if (GetExitCodeProcess(w32_child_handles[child], &exitcode) &&
1441 exitcode != STILL_ACTIVE)
1442 {
1443 remove_dead_process(child);
1444 }
1445 return 0;
7e5f34c0 1446 }
7766f137
GS
1447 }
1448 else {
8cbe99e5 1449 if (my_kill(pid, sig))
48db714f 1450 return 0;
7766f137
GS
1451 }
1452 }
1453 errno = EINVAL;
1454 return -1;
0a753a76 1455}
fbbbcc48 1456
68dc0745 1457DllExport int
c623ac67 1458win32_stat(const char *path, Stat_t *sbuf)
0a753a76 1459{
3fadfdf1 1460 char buffer[MAX_PATH+1];
68dc0745 1461 int l = strlen(path);
04a2c3d9 1462 dTHX;
67fbe06e 1463 int res;
6b980173 1464 int nlink = 1;
44221b20 1465 BOOL expect_dir = FALSE;
0a753a76 1466
68dc0745 1467 if (l > 1) {
1468 switch(path[l - 1]) {
e1dbac94 1469 /* FindFirstFile() and stat() are buggy with a trailing
44221b20 1470 * slashes, except for the root directory of a drive */
68dc0745 1471 case '\\':
44221b20
JD
1472 case '/':
1473 if (l > sizeof(buffer)) {
0b96339f
JD
1474 errno = ENAMETOOLONG;
1475 return -1;
1476 }
44221b20
JD
1477 --l;
1478 strncpy(buffer, path, l);
1479 /* remove additional trailing slashes */
1480 while (l > 1 && (buffer[l-1] == '/' || buffer[l-1] == '\\'))
1481 --l;
1482 /* add back slash if we otherwise end up with just a drive letter */
1483 if (l == 2 && isALPHA(buffer[0]) && buffer[1] == ':')
1484 buffer[l++] = '\\';
1485 buffer[l] = '\0';
1486 path = buffer;
1487 expect_dir = TRUE;
e1dbac94 1488 break;
44221b20 1489
23db2e2d 1490 /* FindFirstFile() is buggy with "x:", so add a dot :-( */
e1dbac94
GS
1491 case ':':
1492 if (l == 2 && isALPHA(path[0])) {
426c1a18
GS
1493 buffer[0] = path[0];
1494 buffer[1] = ':';
1495 buffer[2] = '.';
1496 buffer[3] = '\0';
e1dbac94 1497 l = 3;
426c1a18 1498 path = buffer;
e1dbac94
GS
1499 }
1500 break;
68dc0745 1501 }
1502 }
6b980173 1503
8c56068e
JD
1504 path = PerlDir_mapA(path);
1505 l = strlen(path);
cba61fe1 1506
8ca2a5d6 1507 if (!w32_sloppystat) {
cba61fe1
JD
1508 /* We must open & close the file once; otherwise file attribute changes */
1509 /* might not yet have propagated to "other" hard links of the same file. */
1510 /* This also gives us an opportunity to determine the number of links. */
1511 HANDLE handle = CreateFileA(path, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
1512 if (handle != INVALID_HANDLE_VALUE) {
1513 BY_HANDLE_FILE_INFORMATION bhi;
1514 if (GetFileInformationByHandle(handle, &bhi))
1515 nlink = bhi.nNumberOfLinks;
1516 CloseHandle(handle);
1517 }
d7a7ed74
DD
1518 else {
1519 DWORD err = GetLastError();
1520 /* very common case, skip CRT stat and its also failing syscalls */
1521 if(err == ERROR_FILE_NOT_FOUND) {
1522 errno = ENOENT;
1523 return -1;
1524 }
1525 }
7fac1903 1526 }
6b980173 1527
8c56068e 1528 /* path will be mapped correctly above */
c623ac67 1529#if defined(WIN64) || defined(USE_LARGE_FILES)
8c56068e 1530 res = _stati64(path, sbuf);
c623ac67 1531#else
8c56068e 1532 res = stat(path, sbuf);
c623ac67 1533#endif
426c1a18 1534 sbuf->st_nlink = nlink;
6b980173 1535
24caa93f
GS
1536 if (res < 0) {
1537 /* CRT is buggy on sharenames, so make sure it really isn't.
1538 * XXX using GetFileAttributesEx() will enable us to set
426c1a18 1539 * sbuf->st_*time (but note that's not available on the
24caa93f 1540 * Windows of 1995) */
8c56068e 1541 DWORD r = GetFileAttributesA(path);
24caa93f 1542 if (r != 0xffffffff && (r & FILE_ATTRIBUTE_DIRECTORY)) {
426c1a18 1543 /* sbuf may still contain old garbage since stat() failed */
c623ac67 1544 Zero(sbuf, 1, Stat_t);
426c1a18 1545 sbuf->st_mode = S_IFDIR | S_IREAD;
24caa93f
GS
1546 errno = 0;
1547 if (!(r & FILE_ATTRIBUTE_READONLY))
426c1a18 1548 sbuf->st_mode |= S_IWRITE | S_IEXEC;
24caa93f
GS
1549 return 0;
1550 }
1551 }
24caa93f 1552 else {
e1dbac94
GS
1553 if (l == 3 && isALPHA(path[0]) && path[1] == ':'
1554 && (path[2] == '\\' || path[2] == '/'))
2293b0e9
AB
1555 {
1556 /* The drive can be inaccessible, some _stat()s are buggy */
8c56068e 1557 if (!GetVolumeInformationA(path,NULL,0,NULL,NULL,NULL,NULL,0)) {
2293b0e9
AB
1558 errno = ENOENT;
1559 return -1;
1560 }
1561 }
44221b20
JD
1562 if (expect_dir && !S_ISDIR(sbuf->st_mode)) {
1563 errno = ENOTDIR;
1564 return -1;
1565 }
038ae9a4
SH
1566 if (S_ISDIR(sbuf->st_mode)) {
1567 /* Ensure the "write" bit is switched off in the mode for
378eeda7
SH
1568 * directories with the read-only attribute set. Some compilers
1569 * switch it on for directories, which is technically correct
038ae9a4
SH
1570 * (directories are indeed always writable unless denied by DACLs),
1571 * but we want stat() and -w to reflect the state of the read-only
1572 * attribute for symmetry with chmod(). */
1573 DWORD r = GetFileAttributesA(path);
1574 if (r != 0xffffffff && (r & FILE_ATTRIBUTE_READONLY)) {
1575 sbuf->st_mode &= ~S_IWRITE;
1576 }
1577 }
2293b0e9 1578 }
67fbe06e 1579 return res;
0a753a76 1580}
1581
bb27e7b6
JH
1582#define isSLASH(c) ((c) == '/' || (c) == '\\')
1583#define SKIP_SLASHES(s) \
1584 STMT_START { \
1585 while (*(s) && isSLASH(*(s))) \
1586 ++(s); \
1587 } STMT_END
1588#define COPY_NONSLASHES(d,s) \
1589 STMT_START { \
1590 while (*(s) && !isSLASH(*(s))) \
1591 *(d)++ = *(s)++; \
1592 } STMT_END
1593
8ac9c18d
GS
1594/* Find the longname of a given path. path is destructively modified.
1595 * It should have space for at least MAX_PATH characters. */
1596DllExport char *
1597win32_longpath(char *path)
1598{
1599 WIN32_FIND_DATA fdata;
1600 HANDLE fhand;
1601 char tmpbuf[MAX_PATH+1];
1602 char *tmpstart = tmpbuf;
1603 char *start = path;
1604 char sep;
1605 if (!path)
4e205ed6 1606 return NULL;
8ac9c18d
GS
1607
1608 /* drive prefix */
bb27e7b6 1609 if (isALPHA(path[0]) && path[1] == ':') {
8ac9c18d
GS
1610 start = path + 2;
1611 *tmpstart++ = path[0];
1612 *tmpstart++ = ':';
1613 }
1614 /* UNC prefix */
bb27e7b6 1615 else if (isSLASH(path[0]) && isSLASH(path[1])) {
8ac9c18d 1616 start = path + 2;
52fcf7ee
GS
1617 *tmpstart++ = path[0];
1618 *tmpstart++ = path[1];
bb27e7b6
JH
1619 SKIP_SLASHES(start);
1620 COPY_NONSLASHES(tmpstart,start); /* copy machine name */
8ac9c18d 1621 if (*start) {
bb27e7b6
JH
1622 *tmpstart++ = *start++;
1623 SKIP_SLASHES(start);
1624 COPY_NONSLASHES(tmpstart,start); /* copy share name */
8ac9c18d
GS
1625 }
1626 }
8ac9c18d 1627 *tmpstart = '\0';
bb27e7b6
JH
1628 while (*start) {
1629 /* copy initial slash, if any */
1630 if (isSLASH(*start)) {
1631 *tmpstart++ = *start++;
1632 *tmpstart = '\0';
1633 SKIP_SLASHES(start);
1634 }
1635
1636 /* FindFirstFile() expands "." and "..", so we need to pass
1637 * those through unmolested */
1638 if (*start == '.'
1639 && (!start[1] || isSLASH(start[1])
1640 || (start[1] == '.' && (!start[2] || isSLASH(start[2])))))
1641 {
1642 COPY_NONSLASHES(tmpstart,start); /* copy "." or ".." */
1643 *tmpstart = '\0';
1644 continue;
1645 }
1646
1647 /* if this is the end, bust outta here */
1648 if (!*start)
1649 break;
8ac9c18d 1650
bb27e7b6
JH
1651 /* now we're at a non-slash; walk up to next slash */
1652 while (*start && !isSLASH(*start))
8ac9c18d 1653 ++start;
8ac9c18d
GS
1654
1655 /* stop and find full name of component */
bb27e7b6 1656 sep = *start;
8ac9c18d
GS
1657 *start = '\0';
1658 fhand = FindFirstFile(path,&fdata);
bb27e7b6 1659 *start = sep;
8ac9c18d 1660 if (fhand != INVALID_HANDLE_VALUE) {
bb27e7b6
JH
1661 STRLEN len = strlen(fdata.cFileName);
1662 if ((STRLEN)(tmpbuf + sizeof(tmpbuf) - tmpstart) > len) {
1663 strcpy(tmpstart, fdata.cFileName);
1664 tmpstart += len;
1665 FindClose(fhand);
1666 }
1667 else {
1668 FindClose(fhand);
1669 errno = ERANGE;
4e205ed6 1670 return NULL;
bb27e7b6 1671 }
8ac9c18d
GS
1672 }
1673 else {
1674 /* failed a step, just return without side effects */
bf49b057 1675 /*PerlIO_printf(Perl_debug_log, "Failed to find %s\n", path);*/
bb27e7b6 1676 errno = EINVAL;
4e205ed6 1677 return NULL;
8ac9c18d
GS
1678 }
1679 }
1680 strcpy(path,tmpbuf);
1681 return path;
1682}
1683
aa2b96ec 1684static void
0934c9d9 1685out_of_memory(void)
aa2b96ec 1686{
4cbe3a7d
DD
1687 if (PL_curinterp)
1688 croak_no_mem();
ae6198af 1689 exit(1);
aa2b96ec
JD
1690}
1691
073dd035
DD
1692void
1693win32_croak_not_implemented(const char * fname)
1694{
1695 PERL_ARGS_ASSERT_WIN32_CROAK_NOT_IMPLEMENTED;
1696
1697 Perl_croak_nocontext("%s not implemented!\n", fname);
1698}
1699
00a0ae28
SH
1700/* Converts a wide character (UTF-16) string to the Windows ANSI code page,
1701 * potentially using the system's default replacement character for any
1702 * unrepresentable characters. The caller must free() the returned string. */
1703static char*
1704wstr_to_str(const wchar_t* wstr)
1705{
1706 BOOL used_default = FALSE;
1707 size_t wlen = wcslen(wstr) + 1;
1708 int len = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, wstr, wlen,
1709 NULL, 0, NULL, NULL);
f76b679e 1710 char* str = (char*)malloc(len);
00a0ae28
SH
1711 if (!str)
1712 out_of_memory();
1713 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, wstr, wlen,
1714 str, len, NULL, &used_default);
1715 return str;
1716}
1717
aa2b96ec
JD
1718/* The win32_ansipath() function takes a Unicode filename and converts it
1719 * into the current Windows codepage. If some characters cannot be mapped,
1720 * then it will convert the short name instead.
1721 *
1722 * The buffer to the ansi pathname must be freed with win32_free() when it
1723 * it no longer needed.
1724 *
1725 * The argument to win32_ansipath() must exist before this function is
1726 * called; otherwise there is no way to determine the short path name.
1727 *
1728 * Ideas for future refinement:
1729 * - Only convert those segments of the path that are not in the current
1730 * codepage, but leave the other segments in their long form.
1731 * - If the resulting name is longer than MAX_PATH, start converting
1732 * additional path segments into short names until the full name
1733 * is shorter than MAX_PATH. Shorten the filename part last!
1734 */
1735DllExport char *
1736win32_ansipath(const WCHAR *widename)
1737{
1738 char *name;
1739 BOOL use_default = FALSE;
1740 size_t widelen = wcslen(widename)+1;
1741 int len = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, widename, widelen,
1742 NULL, 0, NULL, NULL);
f76b679e 1743 name = (char*)win32_malloc(len);
aa2b96ec
JD
1744 if (!name)
1745 out_of_memory();
1746
1747 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, widename, widelen,
1748 name, len, NULL, &use_default);
1749 if (use_default) {
aa2b96ec 1750 DWORD shortlen = GetShortPathNameW(widename, NULL, 0);
ae6198af 1751 if (shortlen) {
f76b679e 1752 WCHAR *shortname = (WCHAR*)win32_malloc(shortlen*sizeof(WCHAR));
ae6198af
JD
1753 if (!shortname)
1754 out_of_memory();
1755 shortlen = GetShortPathNameW(widename, shortname, shortlen)+1;
1756
1757 len = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, shortname, shortlen,
1758 NULL, 0, NULL, NULL);
f76b679e 1759 name = (char*)win32_realloc(name, len);
ae6198af
JD
1760 if (!name)
1761 out_of_memory();
1762 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, shortname, shortlen,
1763 name, len, NULL, NULL);
1764 win32_free(shortname);
1765 }
aa2b96ec
JD
1766 }
1767 return name;
1768}
1769
2c8ca683
DD
1770/* the returned string must be freed with win32_freeenvironmentstrings which is
1771 * implemented as a macro
1772 * void win32_freeenvironmentstrings(void* block)
1773 */
0551aaa8 1774DllExport char *
4f46e52b
KR
1775win32_getenvironmentstrings(void)
1776{
1777 LPWSTR lpWStr, lpWTmp;
1778 LPSTR lpStr, lpTmp;
1779 DWORD env_len, wenvstrings_len = 0, aenvstrings_len = 0;
1780
1781 /* Get the process environment strings */
1782 lpWTmp = lpWStr = (LPWSTR) GetEnvironmentStringsW();
fa467b9b 1783 for (wenvstrings_len = 1; *lpWTmp != '\0'; lpWTmp += env_len + 1) {
4f46e52b
KR
1784 env_len = wcslen(lpWTmp);
1785 /* calculate the size of the environment strings */
1786 wenvstrings_len += env_len + 1;
1787 }
1788
fa467b9b 1789 /* Get the number of bytes required to store the ACP encoded string */
4f46e52b 1790 aenvstrings_len = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS,
fa467b9b 1791 lpWStr, wenvstrings_len, NULL, 0, NULL, NULL);
4f46e52b
KR
1792 lpTmp = lpStr = (char *)win32_calloc(aenvstrings_len, sizeof(char));
1793 if(!lpTmp)
1794 out_of_memory();
1795
1796 /* Convert the string from UTF-16 encoding to ACP encoding */
1797 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, lpWStr, wenvstrings_len, lpStr,
fa467b9b 1798 aenvstrings_len, NULL, NULL);
4f46e52b 1799
a6abe943 1800 FreeEnvironmentStringsW(lpWStr);
90674eaa 1801
4f46e52b
KR
1802 return(lpStr);
1803}
1804
4f46e52b 1805DllExport char *
0551aaa8
GS
1806win32_getenv(const char *name)
1807{
acfe0abc 1808 dTHX;
0551aaa8 1809 DWORD needlen;
4e205ed6 1810 SV *curitem = NULL;
1fcb0052 1811 DWORD last_err;
58a50f62 1812
8c56068e 1813 needlen = GetEnvironmentVariableA(name,NULL,0);
58a50f62 1814 if (needlen != 0) {
c2b90b61 1815 curitem = sv_2mortal(newSVpvs(""));
8c56068e
JD
1816 do {
1817 SvGROW(curitem, needlen+1);
1818 needlen = GetEnvironmentVariableA(name,SvPVX(curitem),
1819 needlen);
1820 } while (needlen >= SvLEN(curitem));
1821 SvCUR_set(curitem, needlen);
0551aaa8 1822 }
c934e9d4 1823 else {
1fcb0052
PM
1824 last_err = GetLastError();
1825 if (last_err == ERROR_NOT_ENOUGH_MEMORY) {
1826 /* It appears the variable is in the env, but the Win32 API
1827 doesn't have a canned way of getting it. So we fall back to
1828 grabbing the whole env and pulling this value out if possible */
1829 char *envv = GetEnvironmentStrings();
1830 char *cur = envv;
1831 STRLEN len;
1832 while (*cur) {
1833 char *end = strchr(cur,'=');
1834 if (end && end != cur) {
1835 *end = '\0';
083b2a61 1836 if (strEQ(cur,name)) {
1fcb0052
PM
1837 curitem = sv_2mortal(newSVpv(end+1,0));
1838 *end = '=';
1839 break;
1840 }
1841 *end = '=';
1842 cur = end + strlen(end+1)+2;
1843 }
1844 else if ((len = strlen(cur)))
1845 cur += len+1;
1846 }
1847 FreeEnvironmentStrings(envv);
1848 }
6937817d 1849#ifndef WIN32_NO_REGISTRY
1fcb0052
PM
1850 else {
1851 /* last ditch: allow any environment variables that begin with 'PERL'
1852 to be obtained from the registry, if found there */
f55ac4a4 1853 if (strBEGINs(name, "PERL"))
1fcb0052
PM
1854 (void)get_regstr(name, &curitem);
1855 }
6937817d 1856#endif
c69f6586 1857 }
51371543
GS
1858 if (curitem && SvCUR(curitem))
1859 return SvPVX(curitem);
58a50f62 1860
4e205ed6 1861 return NULL;
0551aaa8
GS
1862}
1863
ac5c734f
GS
1864DllExport int
1865win32_putenv(const char *name)
1866{
1867 char* curitem;
1868 char* val;
b813a9c7 1869 int relval = -1;
51371543 1870
73c4f7a1 1871 if (name) {
9399a70c 1872 curitem = (char *) win32_malloc(strlen(name)+1);
8c56068e
JD
1873 strcpy(curitem, name);
1874 val = strchr(curitem, '=');
1875 if (val) {
1876 /* The sane way to deal with the environment.
1877 * Has these advantages over putenv() & co.:
1878 * * enables us to store a truly empty value in the
1879 * environment (like in UNIX).
8d0cd07e
SH
1880 * * we don't have to deal with RTL globals, bugs and leaks
1881 * (specifically, see http://support.microsoft.com/kb/235601).
8c56068e 1882 * * Much faster.
d0fc6d8d
SH
1883 * Why you may want to use the RTL environment handling
1884 * (previously enabled by USE_WIN32_RTL_ENV):
8c56068e
JD
1885 * * environ[] and RTL functions will not reflect changes,
1886 * which might be an issue if extensions want to access
1887 * the env. via RTL. This cuts both ways, since RTL will
1888 * not see changes made by extensions that call the Win32
1889 * functions directly, either.
1890 * GSAR 97-06-07
1891 */
1892 *val++ = '\0';
1893 if (SetEnvironmentVariableA(curitem, *val ? val : NULL))
1894 relval = 0;
1895 }
9399a70c 1896 win32_free(curitem);
ac5c734f
GS
1897 }
1898 return relval;
1899}
1900
d55594ae 1901static long
2d7a9237 1902filetime_to_clock(PFILETIME ft)
d55594ae 1903{
7766f137
GS
1904 __int64 qw = ft->dwHighDateTime;
1905 qw <<= 32;
1906 qw |= ft->dwLowDateTime;
1907 qw /= 10000; /* File time ticks at 0.1uS, clock at 1mS */
1908 return (long) qw;
d55594ae
GS
1909}
1910
f3986ebb
GS
1911DllExport int
1912win32_times(struct tms *timebuf)
0a753a76 1913{
d55594ae
GS
1914 FILETIME user;
1915 FILETIME kernel;
1916 FILETIME dummy;
50ee8e5e 1917 clock_t process_time_so_far = clock();
3fadfdf1 1918 if (GetProcessTimes(GetCurrentProcess(), &dummy, &dummy,
d55594ae 1919 &kernel,&user)) {
2d7a9237
GS
1920 timebuf->tms_utime = filetime_to_clock(&user);
1921 timebuf->tms_stime = filetime_to_clock(&kernel);
d55594ae
GS
1922 timebuf->tms_cutime = 0;
1923 timebuf->tms_cstime = 0;
3fadfdf1 1924 } else {
d55594ae 1925 /* That failed - e.g. Win95 fallback to clock() */
50ee8e5e 1926 timebuf->tms_utime = process_time_so_far;
d55594ae
GS
1927 timebuf->tms_stime = 0;
1928 timebuf->tms_cutime = 0;
1929 timebuf->tms_cstime = 0;
1930 }
50ee8e5e 1931 return process_time_so_far;
0a753a76 1932}
1933
9c51cf4c 1934/* fix utime() so it works on directories in NT */
ad0751ec
GS
1935static BOOL
1936filetime_from_time(PFILETIME pFileTime, time_t Time)
1937{
9c51cf4c 1938 struct tm *pTM = localtime(&Time);
ad0751ec 1939 SYSTEMTIME SystemTime;
9c51cf4c 1940 FILETIME LocalTime;
ad0751ec
GS
1941
1942 if (pTM == NULL)
1943 return FALSE;
1944
1945 SystemTime.wYear = pTM->tm_year + 1900;
1946 SystemTime.wMonth = pTM->tm_mon + 1;
1947 SystemTime.wDay = pTM->tm_mday;
1948 SystemTime.wHour = pTM->tm_hour;
1949 SystemTime.wMinute = pTM->tm_min;
1950 SystemTime.wSecond = pTM->tm_sec;
1951 SystemTime.wMilliseconds = 0;
1952
9c51cf4c
GS
1953 return SystemTimeToFileTime(&SystemTime, &LocalTime) &&
1954 LocalFileTimeToFileTime(&LocalTime, pFileTime);
ad0751ec
GS
1955}
1956
1957DllExport int
7766f137
GS
1958win32_unlink(const char *filename)
1959{
acfe0abc 1960 dTHX;
7766f137
GS
1961 int ret;
1962 DWORD attrs;
1963
8c56068e
JD
1964 filename = PerlDir_mapA(filename);
1965 attrs = GetFileAttributesA(filename);
1966 if (attrs == 0xFFFFFFFF) {
1967 errno = ENOENT;
1968 return -1;
7766f137 1969 }
8c56068e
JD
1970 if (attrs & FILE_ATTRIBUTE_READONLY) {
1971 (void)SetFileAttributesA(filename, attrs & ~FILE_ATTRIBUTE_READONLY);
1972 ret = unlink(filename);
1973 if (ret == -1)
1974 (void)SetFileAttributesA(filename, attrs);
7766f137 1975 }
8c56068e
JD
1976 else
1977 ret = unlink(filename);
7766f137
GS
1978 return ret;
1979}
1980
1981DllExport int
3b405fc5 1982win32_utime(const char *filename, struct utimbuf *times)
ad0751ec 1983{
acfe0abc 1984 dTHX;
ad0751ec
GS
1985 HANDLE handle;
1986 FILETIME ftCreate;
1987 FILETIME ftAccess;
1988 FILETIME ftWrite;
1989 struct utimbuf TimeBuffer;
7fac1903 1990 int rc;
8c56068e
JD
1991
1992 filename = PerlDir_mapA(filename);
1993 rc = utime(filename, times);
1994
ad0751ec 1995 /* EACCES: path specifies directory or readonly file */
8cbe99e5 1996 if (rc == 0 || errno != EACCES)
ad0751ec
GS
1997 return rc;
1998
1999 if (times == NULL) {
2000 times = &TimeBuffer;
2001 time(&times->actime);
2002 times->modtime = times->actime;
2003 }
2004
2005 /* This will (and should) still fail on readonly files */
8c56068e
JD
2006 handle = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE,
2007 FILE_SHARE_READ | FILE_SHARE_DELETE, NULL,
2008 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
ad0751ec
GS
2009 if (handle == INVALID_HANDLE_VALUE)
2010 return rc;
2011
2012 if (GetFileTime(handle, &ftCreate, &ftAccess, &ftWrite) &&
2013 filetime_from_time(&ftAccess, times->actime) &&
2014 filetime_from_time(&ftWrite, times->modtime) &&
2015 SetFileTime(handle, &ftCreate, &ftAccess, &ftWrite))
2016 {
2017 rc = 0;
2018 }
2019
2020 CloseHandle(handle);
2021 return rc;
2022}
2023
6e3b076d
JH
2024typedef union {
2025 unsigned __int64 ft_i64;
2026 FILETIME ft_val;
2027} FT_t;
2028
2029#ifdef __GNUC__
2030#define Const64(x) x##LL
2031#else
2032#define Const64(x) x##i64
2033#endif
2034/* Number of 100 nanosecond units from 1/1/1601 to 1/1/1970 */
2035#define EPOCH_BIAS Const64(116444736000000000)
2036
57ab3dfe
GS
2037/* NOTE: This does not compute the timezone info (doing so can be expensive,
2038 * and appears to be unsupported even by glibc) */
2039DllExport int
2040win32_gettimeofday(struct timeval *tp, void *not_used)
2041{
6e3b076d
JH
2042 FT_t ft;
2043
2044 /* this returns time in 100-nanosecond units (i.e. tens of usecs) */
2045 GetSystemTimeAsFileTime(&ft.ft_val);
2046
2047 /* seconds since epoch */
2048 tp->tv_sec = (long)((ft.ft_i64 - EPOCH_BIAS) / Const64(10000000));
2049
2050 /* microseconds remaining */
2051 tp->tv_usec = (long)((ft.ft_i64 / Const64(10)) % Const64(1000000));
2052
2053 return 0;
57ab3dfe
GS
2054}
2055
2d7a9237 2056DllExport int
b2af26b1
GS
2057win32_uname(struct utsname *name)
2058{
2059 struct hostent *hep;
2060 STRLEN nodemax = sizeof(name->nodename)-1;
b2af26b1 2061
aeecf691
JD
2062 /* sysname */
2063 switch (g_osver.dwPlatformId) {
2064 case VER_PLATFORM_WIN32_WINDOWS:
2065 strcpy(name->sysname, "Windows");
2066 break;
2067 case VER_PLATFORM_WIN32_NT:
2068 strcpy(name->sysname, "Windows NT");
2069 break;
2070 case VER_PLATFORM_WIN32s:
2071 strcpy(name->sysname, "Win32s");
2072 break;
2073 default:
2074 strcpy(name->sysname, "Win32 Unknown");
2075 break;
b2af26b1 2076 }
aeecf691
JD
2077
2078 /* release */
2079 sprintf(name->release, "%d.%d",
2080 g_osver.dwMajorVersion, g_osver.dwMinorVersion);
2081
2082 /* version */
2083 sprintf(name->version, "Build %d",
2084 g_osver.dwPlatformId == VER_PLATFORM_WIN32_NT
2085 ? g_osver.dwBuildNumber : (g_osver.dwBuildNumber & 0xffff));
2086 if (g_osver.szCSDVersion[0]) {
2087 char *buf = name->version + strlen(name->version);
2088 sprintf(buf, " (%s)", g_osver.szCSDVersion);
b2af26b1
GS
2089 }
2090
2091 /* nodename */
2092 hep = win32_gethostbyname("localhost");
2093 if (hep) {
2094 STRLEN len = strlen(hep->h_name);
2095 if (len <= nodemax) {
2096 strcpy(name->nodename, hep->h_name);
2097 }
2098 else {
2099 strncpy(name->nodename, hep->h_name, nodemax);
2100 name->nodename[nodemax] = '\0';
2101 }
2102 }
2103 else {
2104 DWORD sz = nodemax;
2105 if (!GetComputerName(name->nodename, &sz))
2106 *name->nodename = '\0';
2107 }
2108
2109 /* machine (architecture) */
2110 {
2111 SYSTEM_INFO info;
fe537c65 2112 DWORD procarch;
b2af26b1
GS
2113 char *arch;
2114 GetSystemInfo(&info);
a6c40364 2115
378eeda7 2116#if (defined(__MINGW32__) && !defined(_ANONYMOUS_UNION) && !defined(__MINGW_EXTENSION))
fe537c65 2117 procarch = info.u.s.wProcessorArchitecture;
a6c40364 2118#else
fe537c65 2119 procarch = info.wProcessorArchitecture;
a6c40364 2120#endif
fe537c65 2121 switch (procarch) {
b2af26b1
GS
2122 case PROCESSOR_ARCHITECTURE_INTEL:
2123 arch = "x86"; break;
fe537c65
GS
2124 case PROCESSOR_ARCHITECTURE_IA64:
2125 arch = "ia64"; break;
fe537c65
GS
2126 case PROCESSOR_ARCHITECTURE_AMD64:
2127 arch = "amd64"; break;
fe537c65 2128 case PROCESSOR_ARCHITECTURE_UNKNOWN:
b2af26b1 2129 arch = "unknown"; break;
fe537c65
GS
2130 default:
2131 sprintf(name->machine, "unknown(0x%x)", procarch);
2132 arch = name->machine;
2133 break;
b2af26b1 2134 }
fe537c65
GS
2135 if (name->machine != arch)
2136 strcpy(name->machine, arch);
b2af26b1
GS
2137 }
2138 return 0;
2139}
2140
8fb3fcfb
NIS
2141/* Timing related stuff */
2142
3fadfdf1
NIS
2143int
2144do_raise(pTHX_ int sig)
2145{
2146 if (sig < SIG_SIZE) {
2147 Sighandler_t handler = w32_sighandler[sig];
2148 if (handler == SIG_IGN) {
2149 return 0;
2150 }
2151 else if (handler != SIG_DFL) {
2152 (*handler)(sig);
2153 return 0;
2154 }
2155 else {
2156 /* Choose correct default behaviour */
2157 switch (sig) {
2158#ifdef SIGCLD
2159 case SIGCLD:
2160#endif
2161#ifdef SIGCHLD
2162 case SIGCHLD:
2163#endif
2164 case 0:
2165 return 0;
2166 case SIGTERM:
2167 default:
2168 break;
2169 }
2170 }
2171 }
bb0f0a6a 2172 /* Tell caller to exit thread/process as appropriate */
3fadfdf1
NIS
2173 return 1;
2174}
2175
2176void
2177sig_terminate(pTHX_ int sig)
2178{
2179 Perl_warn(aTHX_ "Terminating on signal SIG%s(%d)\n",PL_sig_name[sig], sig);
2180 /* exit() seems to be safe, my_exit() or die() is a problem in ^C
2181 thread
2182 */
2183 exit(sig);
2184}
2185
8fb3fcfb
NIS
2186DllExport int
2187win32_async_check(pTHX)
2188{
2189 MSG msg;
aeecf691
JD
2190 HWND hwnd = w32_message_hwnd;
2191
099b16d3
RM
2192 /* Reset w32_poll_count before doing anything else, incase we dispatch
2193 * messages that end up calling back into perl */
aeecf691
JD
2194 w32_poll_count = 0;
2195
099b16d3
RM
2196 if (hwnd != INVALID_HANDLE_VALUE) {
2197 /* Passing PeekMessage -1 as HWND (2nd arg) only gets PostThreadMessage() messages
2198 * and ignores window messages - should co-exist better with windows apps e.g. Tk
2199 */
2200 if (hwnd == NULL)
2201 hwnd = (HWND)-1;
2202
2203 while (PeekMessage(&msg, hwnd, WM_TIMER, WM_TIMER, PM_REMOVE|PM_NOYIELD) ||
2204 PeekMessage(&msg, hwnd, WM_USER_MIN, WM_USER_MAX, PM_REMOVE|PM_NOYIELD))
2205 {
2206 /* re-post a WM_QUIT message (we'll mark it as read later) */
2207 if(msg.message == WM_QUIT) {
2208 PostQuitMessage((int)msg.wParam);
2209 break;
2210 }
8fb3fcfb 2211
099b16d3
RM
2212 if(!CallMsgFilter(&msg, MSGF_USER))
2213 {
2214 TranslateMessage(&msg);
2215 DispatchMessage(&msg);
aeecf691 2216 }
099b16d3 2217 }
8fb3fcfb
NIS
2218 }
2219
099b16d3
RM
2220 /* Call PeekMessage() to mark all pending messages in the queue as "old".
2221 * This is necessary when we are being called by win32_msgwait() to
2222 * make sure MsgWaitForMultipleObjects() stops reporting the same waiting
2223 * message over and over. An example how this can happen is when
2224 * Perl is calling win32_waitpid() inside a GUI application and the GUI
2225 * is generating messages before the process terminated.
2226 */
4386d69d 2227 PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE|PM_NOYIELD);
099b16d3 2228
7e5f34c0 2229 /* Above or other stuff may have set a signal flag */
099b16d3
RM
2230 if (PL_sig_pending)
2231 despatch_signals();
2232
aeecf691 2233 return 1;
8fb3fcfb
NIS
2234}
2235
089197fa
GS
2236/* This function will not return until the timeout has elapsed, or until
2237 * one of the handles is ready. */
8fb3fcfb
NIS
2238DllExport DWORD
2239win32_msgwait(pTHX_ DWORD count, LPHANDLE handles, DWORD timeout, LPDWORD resultp)
2240{
2241 /* We may need several goes at this - so compute when we stop */
001e9f89
DD
2242 FT_t ticks = {0};
2243 unsigned __int64 endtime = timeout;
8fb3fcfb 2244 if (timeout != INFINITE) {
001e9f89
DD
2245 GetSystemTimeAsFileTime(&ticks.ft_val);
2246 ticks.ft_i64 /= 10000;
2247 endtime += ticks.ft_i64;
2248 }
2249 /* This was a race condition. Do not let a non INFINITE timeout to
2250 * MsgWaitForMultipleObjects roll under 0 creating a near
2251 * infinity/~(UINT32)0 timeout which will appear as a deadlock to the
2252 * user who did a CORE perl function with a non infinity timeout,
2253 * sleep for example. This is 64 to 32 truncation minefield.
2254 *
2255 * This scenario can only be created if the timespan from the return of
2256 * MsgWaitForMultipleObjects to GetSystemTimeAsFileTime exceeds 1 ms. To
2257 * generate the scenario, manual breakpoints in a C debugger are required,
bb0f0a6a 2258 * or a context switch occurred in win32_async_check in PeekMessage, or random
001e9f89
DD
2259 * messages are delivered to the *thread* message queue of the Perl thread
2260 * from another process (msctf.dll doing IPC among its instances, VS debugger
2261 * causes msctf.dll to be loaded into Perl by kernel), see [perl #33096].
2262 */
2263 while (ticks.ft_i64 <= endtime) {
9afd6203
SH
2264 /* if timeout's type is lengthened, remember to split 64b timeout
2265 * into multiple non-infinity runs of MWFMO */
2266 DWORD result = MsgWaitForMultipleObjects(count, handles, FALSE,
2267 (DWORD)(endtime - ticks.ft_i64),
2268 QS_POSTMESSAGE|QS_TIMER|QS_SENDMESSAGE);
8fb3fcfb
NIS
2269 if (resultp)
2270 *resultp = result;
2271 if (result == WAIT_TIMEOUT) {
3fadfdf1
NIS
2272 /* Ran out of time - explicit return of zero to avoid -ve if we
2273 have scheduling issues
2274 */
8fb3fcfb
NIS
2275 return 0;
2276 }
2277 if (timeout != INFINITE) {
001e9f89
DD
2278 GetSystemTimeAsFileTime(&ticks.ft_val);
2279 ticks.ft_i64 /= 10000;
2280 }
8fb3fcfb
NIS
2281 if (result == WAIT_OBJECT_0 + count) {
2282 /* Message has arrived - check it */
089197fa 2283 (void)win32_async_check(aTHX);
8fb3fcfb
NIS
2284 }
2285 else {
2286 /* Not timeout or message - one of handles is ready */
2287 break;
2288 }
2289 }
8fb3fcfb 2290 /* If we are past the end say zero */
9afd6203 2291 if (!ticks.ft_i64 || ticks.ft_i64 > endtime)
001e9f89
DD
2292 return 0;
2293 /* compute time left to wait */
2294 ticks.ft_i64 = endtime - ticks.ft_i64;
9afd6203
SH
2295 /* if more ms than DWORD, then return max DWORD */
2296 return ticks.ft_i64 <= UINT_MAX ? (DWORD)ticks.ft_i64 : UINT_MAX;
8fb3fcfb
NIS
2297}
2298
932b7487 2299int
04a2c3d9 2300win32_internal_wait(pTHX_ int *status, DWORD timeout)
932b7487
RC
2301{
2302 /* XXX this wait emulation only knows about processes
2303 * spawned via win32_spawnvp(P_NOWAIT, ...).
2304 */
932b7487
RC
2305 int i, retval;
2306 DWORD exitcode, waitcode;
2307
2308#ifdef USE_ITHREADS
2309 if (w32_num_pseudo_children) {
8fb3fcfb
NIS
2310 win32_msgwait(aTHX_ w32_num_pseudo_children, w32_pseudo_child_handles,
2311 timeout, &waitcode);
932b7487
RC
2312 /* Time out here if there are no other children to wait for. */
2313 if (waitcode == WAIT_TIMEOUT) {
2314 if (!w32_num_children) {
2315 return 0;
2316 }
2317 }
2318 else if (waitcode != WAIT_FAILED) {
2319 if (waitcode >= WAIT_ABANDONED_0
2320 && waitcode < WAIT_ABANDONED_0 + w32_num_pseudo_children)
2321 i = waitcode - WAIT_ABANDONED_0;
2322 else
2323 i = waitcode - WAIT_OBJECT_0;
2324 if (GetExitCodeThread(w32_pseudo_child_handles[i], &exitcode)) {
2325 *status = (int)((exitcode & 0xff) << 8);
2326 retval = (int)w32_pseudo_child_pids[i];
2327 remove_dead_pseudo_process(i);
2328 return -retval;
2329 }
2330 }
2331 }
2332#endif
2333
2334 if (!w32_num_children) {
2335 errno = ECHILD;
2336 return -1;
2337 }
2338
2339 /* if a child exists, wait for it to die */
8fb3fcfb 2340 win32_msgwait(aTHX_ w32_num_children, w32_child_handles, timeout, &waitcode);
932b7487
RC
2341 if (waitcode == WAIT_TIMEOUT) {
2342 return 0;
2343 }
2344 if (waitcode != WAIT_FAILED) {
2345 if (waitcode >= WAIT_ABANDONED_0
2346 && waitcode < WAIT_ABANDONED_0 + w32_num_children)
2347 i = waitcode - WAIT_ABANDONED_0;
2348 else
2349 i = waitcode - WAIT_OBJECT_0;
2350 if (GetExitCodeProcess(w32_child_handles[i], &exitcode) ) {
2351 *status = (int)((exitcode & 0xff) << 8);
2352 retval = (int)w32_child_pids[i];
2353 remove_dead_process(i);
2354 return retval;
2355 }
2356 }
2357
932b7487
RC
2358 errno = GetLastError();
2359 return -1;
2360}
2361
b2af26b1 2362DllExport int
f55ee38a
GS
2363win32_waitpid(int pid, int *status, int flags)
2364{
acfe0abc 2365 dTHX;
922b1888 2366 DWORD timeout = (flags & WNOHANG) ? 0 : INFINITE;
0aaad0ff 2367 int retval = -1;
c66b022d 2368 long child;
7766f137 2369 if (pid == -1) /* XXX threadid == 1 ? */
04a2c3d9 2370 return win32_internal_wait(aTHX_ status, timeout);
7766f137
GS
2371#ifdef USE_ITHREADS
2372 else if (pid < 0) {
04a2c3d9 2373 child = find_pseudo_pid(aTHX_ -pid);
7766f137
GS
2374 if (child >= 0) {
2375 HANDLE hThread = w32_pseudo_child_handles[child];
8fb3fcfb
NIS
2376 DWORD waitcode;
2377 win32_msgwait(aTHX_ 1, &hThread, timeout, &waitcode);
2f67576d
BC
2378 if (waitcode == WAIT_TIMEOUT) {
2379 return 0;
2380 }
8fb3fcfb 2381 else if (waitcode == WAIT_OBJECT_0) {
7766f137
GS
2382 if (GetExitCodeThread(hThread, &waitcode)) {
2383 *status = (int)((waitcode & 0xff) << 8);
2384 retval = (int)w32_pseudo_child_pids[child];
2385 remove_dead_pseudo_process(child);
68a29c53 2386 return -retval;
7766f137
GS
2387 }
2388 }
2389 else
2390 errno = ECHILD;
2391 }
2392 }
2393#endif
f55ee38a 2394 else {
922b1888
GS
2395 HANDLE hProcess;
2396 DWORD waitcode;
04a2c3d9 2397 child = find_pid(aTHX_ pid);
0aaad0ff 2398 if (child >= 0) {
922b1888 2399 hProcess = w32_child_handles[child];
8fb3fcfb 2400 win32_msgwait(aTHX_ 1, &hProcess, timeout, &waitcode);
a7867d0a
GS
2401 if (waitcode == WAIT_TIMEOUT) {
2402 return 0;
2403 }
8fb3fcfb 2404 else if (waitcode == WAIT_OBJECT_0) {
922b1888
GS
2405 if (GetExitCodeProcess(hProcess, &waitcode)) {
2406 *status = (int)((waitcode & 0xff) << 8);
2407 retval = (int)w32_child_pids[child];
2408 remove_dead_process(child);
2409 return retval;
2410 }
a7867d0a 2411 }
0aaad0ff
GS
2412 else
2413 errno = ECHILD;
2414 }
2415 else {
8cbe99e5 2416 hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE, pid);
922b1888 2417 if (hProcess) {
8fb3fcfb 2418 win32_msgwait(aTHX_ 1, &hProcess, timeout, &waitcode);
922b1888 2419 if (waitcode == WAIT_TIMEOUT) {
48db714f 2420 CloseHandle(hProcess);
922b1888
GS
2421 return 0;
2422 }
8fb3fcfb 2423 else if (waitcode == WAIT_OBJECT_0) {
922b1888
GS
2424 if (GetExitCodeProcess(hProcess, &waitcode)) {
2425 *status = (int)((waitcode & 0xff) << 8);
2426 CloseHandle(hProcess);
2427 return pid;
2428 }
2429 }
2430 CloseHandle(hProcess);
2431 }
2432 else
2433 errno = ECHILD;
0aaad0ff 2434 }
f55ee38a 2435 }
3fadfdf1 2436 return retval >= 0 ? pid : retval;
f55ee38a
GS
2437}
2438
2439DllExport int
2d7a9237
GS
2440win32_wait(int *status)
2441{
04a2c3d9
DD
2442 dTHX;
2443 return win32_internal_wait(aTHX_ status, INFINITE);
2d7a9237 2444}
d55594ae 2445
8fb3fcfb
NIS
2446DllExport unsigned int
2447win32_sleep(unsigned int t)
d55594ae 2448{
acfe0abc 2449 dTHX;
8fb3fcfb 2450 /* Win32 times are in ms so *1000 in and /1000 out */
3b9aea04
SH
2451 if (t > UINT_MAX / 1000) {
2452 Perl_ck_warner(aTHX_ packWARN(WARN_OVERFLOW),
2453 "sleep(%lu) too large", t);
2454 }
2455 return win32_msgwait(aTHX_ 0, NULL, t * 1000, NULL) / 1000;
d55594ae
GS
2456}
2457
bbc9927b
TK
2458DllExport int
2459win32_pause(void)
2460{
2461 dTHX;
2462 win32_msgwait(aTHX_ 0, NULL, INFINITE, NULL);
2463 return -1;
2464}
2465
f3986ebb
GS
2466DllExport unsigned int
2467win32_alarm(unsigned int sec)
0a753a76 2468{
3fadfdf1 2469 /*
d55594ae 2470 * the 'obvious' implentation is SetTimer() with a callback
3fadfdf1
NIS
2471 * which does whatever receiving SIGALRM would do
2472 * we cannot use SIGALRM even via raise() as it is not
d55594ae 2473 * one of the supported codes in <signal.h>
3fadfdf1 2474 */
acfe0abc 2475 dTHX;
aeecf691
JD
2476
2477 if (w32_message_hwnd == INVALID_HANDLE_VALUE)
2478 w32_message_hwnd = win32_create_message_window();
2479
8fb3fcfb 2480 if (sec) {
aeecf691
JD
2481 if (w32_message_hwnd == NULL)
2482 w32_timerid = SetTimer(NULL, w32_timerid, sec*1000, NULL);
2483 else {
2484 w32_timerid = 1;
2485 SetTimer(w32_message_hwnd, w32_timerid, sec*1000, NULL);
2486 }
8fb3fcfb
NIS
2487 }
2488 else {
2489 if (w32_timerid) {
aeecf691
JD
2490 KillTimer(w32_message_hwnd, w32_timerid);
2491 w32_timerid = 0;
8fb3fcfb 2492 }
3fadfdf1 2493 }
afe91769 2494 return 0;
0a753a76 2495}
2496
2d77217b 2497extern char * des_fcrypt(const char *txt, const char *salt, char *cbuf);
26618a56
GS
2498
2499DllExport char *
2500win32_crypt(const char *txt, const char *salt)
2501{
acfe0abc 2502 dTHX;
3352bfcb 2503 return des_fcrypt(txt, salt, w32_crypt_buffer);
26618a56 2504}
26618a56 2505
390b85e7
GS
2506/* simulate flock by locking a range on the file */
2507
390b85e7
GS
2508#define LK_LEN 0xffff0000
2509
f3986ebb
GS
2510DllExport int
2511win32_flock(int fd, int oper)
390b85e7
GS
2512{
2513 OVERLAPPED o;
2514 int i = -1;
2515 HANDLE fh;
2516
2517 fh = (HANDLE)_get_osfhandle(fd);
97b33cac
JD
2518 if (fh == (HANDLE)-1) /* _get_osfhandle() already sets errno to EBADF */
2519 return -1;
2520
390b85e7
GS
2521 memset(&o, 0, sizeof(o));
2522
2523 switch(oper) {
2524 case LOCK_SH: /* shared lock */
97b33cac
JD
2525 if (LockFileEx(fh, 0, 0, LK_LEN, 0, &o))
2526 i = 0;
390b85e7
GS
2527 break;
2528 case LOCK_EX: /* exclusive lock */
97b33cac
JD
2529 if (LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, LK_LEN, 0, &o))
2530 i = 0;
390b85e7
GS
2531 break;
2532 case LOCK_SH|LOCK_NB: /* non-blocking shared lock */
97b33cac
JD
2533 if (LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY, 0, LK_LEN, 0, &o))
2534 i = 0;
390b85e7
GS
2535 break;
2536 case LOCK_EX|LOCK_NB: /* non-blocking exclusive lock */
97b33cac
JD
2537 if (LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY,
2538 0, LK_LEN, 0, &o))
2539 i = 0;
390b85e7
GS
2540 break;
2541 case LOCK_UN: /* unlock lock */
97b33cac
JD
2542 if (UnlockFileEx(fh, 0, LK_LEN, 0, &o))
2543 i = 0;
390b85e7
GS
2544 break;
2545 default: /* unknown */
2546 errno = EINVAL;
97b33cac
JD
2547 return -1;
2548 }
2549 if (i == -1) {
2550 if (GetLastError() == ERROR_LOCK_VIOLATION)
b0ba2190 2551 errno = EWOULDBLOCK;
97b33cac
JD
2552 else
2553 errno = EINVAL;
390b85e7
GS
2554 }
2555 return i;
2556}
2557
390b85e7
GS
2558#undef LK_LEN
2559
cd6a3131
SH
2560extern int convert_wsa_error_to_errno(int wsaerr); /* in win32sck.c */
2561
c9beaf97
SH
2562/* Get the errno value corresponding to the given err. This function is not
2563 * intended to handle conversion of general GetLastError() codes. It only exists
2564 * to translate Windows sockets error codes from WSAGetLastError(). Such codes
2565 * used to be assigned to errno/$! in earlier versions of perl; this function is
2566 * used to catch any old Perl code which is still trying to assign such values
2567 * to $! and convert them to errno values instead.
2568 */
2569int
2570win32_get_errno(int err)
2571{
2572 return convert_wsa_error_to_errno(err);
2573}
2574
68dc0745 2575/*
2576 * redirected io subsystem for all XS modules
2577 *
2578 */
0a753a76 2579
68dc0745 2580DllExport int *
2581win32_errno(void)
0a753a76 2582{
390b85e7 2583 return (&errno);
0a753a76 2584}
2585
dcb2879a
GS
2586DllExport char ***
2587win32_environ(void)
2588{
390b85e7 2589 return (&(_environ));
dcb2879a
GS
2590}
2591
68dc0745 2592/* the rest are the remapped stdio routines */
2593DllExport FILE *
2594win32_stderr(void)
0a753a76 2595{
390b85e7 2596 return (stderr);
0a753a76 2597}
2598
68dc0745 2599DllExport FILE *
2600win32_stdin(void)
0a753a76 2601{
390b85e7 2602 return (stdin);
0a753a76 2603}
2604
68dc0745 2605DllExport FILE *
0934c9d9 2606win32_stdout(void)
0a753a76 2607{
390b85e7 2608 return (stdout);
0a753a76 2609}
2610
68dc0745 2611DllExport int
2612win32_ferror(FILE *fp)
0a753a76 2613{
390b85e7 2614 return (ferror(fp));
0a753a76 2615}
2616
2617
68dc0745 2618DllExport int
2619win32_feof(FILE *fp)
0a753a76 2620{
390b85e7 2621 return (feof(fp));
0a753a76 2622}
2623
e85fa3eb 2624#ifdef ERRNO_HAS_POSIX_SUPPLEMENT
cd6a3131 2625extern int convert_errno_to_wsa_error(int err); /* in win32sck.c */
e85fa3eb 2626#endif
cd6a3131 2627
68dc0745 2628/*
3fadfdf1 2629 * Since the errors returned by the socket error function
68dc0745 2630 * WSAGetLastError() are not known by the library routine strerror
cd6a3131
SH
2631 * we have to roll our own to cover the case of socket errors
2632 * that could not be converted to regular errno values by
2633 * get_last_socket_error() in win32/win32sck.c.
68dc0745 2634 */
0a753a76 2635
68dc0745 2636DllExport char *
3fadfdf1 2637win32_strerror(int e)
0a753a76 2638{
378eeda7 2639#if !defined __MINGW32__ /* compiler intolerance */
68dc0745 2640 extern int sys_nerr;
3e3baf6d 2641#endif
0a753a76 2642
9404a519 2643 if (e < 0 || e > sys_nerr) {
9399a70c 2644 dTHXa(NULL);
9404a519 2645 if (e < 0)
68dc0745 2646 e = GetLastError();
e85fa3eb 2647#ifdef ERRNO_HAS_POSIX_SUPPLEMENT
4f79e9b1
SH
2648 /* VC10+ and some MinGW/gcc-4.8+ define a "POSIX supplement" of errno
2649 * values ranging from EADDRINUSE (100) to EWOULDBLOCK (140), but
2650 * sys_nerr is still 43 and strerror() returns "Unknown error" for them.
2651 * We must therefore still roll our own messages for these codes, and
2652 * additionally map them to corresponding Windows (sockets) error codes
2653 * first to avoid getting the wrong system message.
cd6a3131
SH
2654 */
2655 else if (e >= EADDRINUSE && e <= EWOULDBLOCK) {
2656 e = convert_errno_to_wsa_error(e);
2657 }
2658#endif
0a753a76 2659
9399a70c 2660 aTHXa(PERL_GET_THX);
364d54ba
JD
2661 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
2662 |FORMAT_MESSAGE_IGNORE_INSERTS, NULL, e, 0,
2663 w32_strerror_buffer, sizeof(w32_strerror_buffer),
2664 NULL) == 0)
2665 {
3352bfcb 2666 strcpy(w32_strerror_buffer, "Unknown Error");
364d54ba 2667 }
3352bfcb 2668 return w32_strerror_buffer;
68dc0745 2669 }
364d54ba 2670#undef strerror
390b85e7 2671 return strerror(e);
364d54ba 2672#define strerror win32_strerror
0a753a76 2673}
2674
22fae026 2675DllExport void
c5be433b 2676win32_str_os_error(void *sv, DWORD dwErr)
22fae026
TM
2677{
2678 DWORD dwLen;
2679 char *sMsg;
2680 dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
2681 |FORMAT_MESSAGE_IGNORE_INSERTS
2682 |FORMAT_MESSAGE_FROM_SYSTEM, NULL,
2683 dwErr, 0, (char *)&sMsg, 1, NULL);
2ce77adf 2684 /* strip trailing whitespace and period */
22fae026 2685 if (0 < dwLen) {
2ce77adf
GS
2686 do {
2687 --dwLen; /* dwLen doesn't include trailing null */
2688 } while (0 < dwLen && isSPACE(sMsg[dwLen]));
22fae026
TM
2689 if ('.' != sMsg[dwLen])
2690 dwLen++;
2ce77adf 2691 sMsg[dwLen] = '\0';
22fae026
TM
2692 }
2693 if (0 == dwLen) {
c69f6586 2694 sMsg = (char*)LocalAlloc(0, 64/**sizeof(TCHAR)*/);
db7c17d7
GS
2695 if (sMsg)
2696 dwLen = sprintf(sMsg,
2697 "Unknown error #0x%lX (lookup 0x%lX)",
2698 dwErr, GetLastError());
2699 }
2700 if (sMsg) {
acfe0abc 2701 dTHX;
db7c17d7
GS
2702 sv_setpvn((SV*)sv, sMsg, dwLen);
2703 LocalFree(sMsg);
22fae026 2704 }
22fae026
TM
2705}
2706
68dc0745 2707DllExport int
2708win32_fprintf(FILE *fp, const char *format, ...)
0a753a76 2709{
68dc0745 2710 va_list marker;
2711 va_start(marker, format); /* Initialize variable arguments. */
0a753a76 2712
390b85e7 2713 return (vfprintf(fp, format, marker));
0a753a76 2714}
2715
68dc0745 2716DllExport int
2717win32_printf(const char *format, ...)
0a753a76 2718{
68dc0745 2719 va_list marker;
2720 va_start(marker, format); /* Initialize variable arguments. */
0a753a76 2721
390b85e7 2722 return (vprintf(format, marker));
0a753a76 2723}
2724
68dc0745 2725DllExport int
2726win32_vfprintf(FILE *fp, const char *format, va_list args)
0a753a76 2727{
390b85e7 2728 return (vfprintf(fp, format, args));
0a753a76 2729}
2730
96e4d5b1 2731DllExport int
2732win32_vprintf(const char *format, va_list args)
2733{
390b85e7 2734 return (vprintf(format, args));
96e4d5b1 2735}
2736
68dc0745 2737DllExport size_t
2738win32_fread(void *buf, size_t size, size_t count, FILE *fp)
0a753a76 2739{
390b85e7 2740 return fread(buf, size, count, fp);
0a753a76 2741}
2742
68dc0745 2743DllExport size_t
2744win32_fwrite(const void *buf, size_t size, size_t count, FILE *fp)
0a753a76 2745{
390b85e7 2746 return fwrite(buf, size, count, fp);
0a753a76 2747}
2748
7fac1903
GS
2749#define MODE_SIZE 10
2750
68dc0745 2751DllExport FILE *
2752win32_fopen(const char *filename, const char *mode)
0a753a76 2753{
04a2c3d9 2754 dTHXa(NULL);
1c5905c2 2755 FILE *f;
3fadfdf1 2756
c5be433b
GS
2757 if (!*filename)
2758 return NULL;
2759
68dc0745 2760 if (stricmp(filename, "/dev/null")==0)
7fac1903
GS
2761 filename = "NUL";
2762
04a2c3d9 2763 aTHXa(PERL_GET_THX);
8c56068e 2764 f = fopen(PerlDir_mapA(filename), mode);
1c5905c2
GS
2765 /* avoid buffering headaches for child processes */
2766 if (f && *mode == 'a')
2767 win32_fseek(f, 0, SEEK_END);
2768 return f;
0a753a76 2769}
2770
68dc0745 2771DllExport FILE *
7fac1903 2772win32_fdopen(int handle, const char *mode)
0a753a76 2773{
1c5905c2 2774 FILE *f;
8c56068e 2775 f = fdopen(handle, (char *) mode);
1c5905c2
GS
2776 /* avoid buffering headaches for child processes */
2777 if (f && *mode == 'a')
2778 win32_fseek(f, 0, SEEK_END);
2779 return f;
0a753a76 2780}
2781
68dc0745 2782DllExport FILE *
7fac1903 2783win32_freopen(const char *path, const char *mode, FILE *stream)
0a753a76 2784{
04a2c3d9 2785 dTHXa(NULL);
68dc0745 2786 if (stricmp(path, "/dev/null")==0)
7fac1903
GS
2787 path = "NUL";
2788
04a2c3d9 2789 aTHXa(PERL_GET_THX);
7766f137 2790 return freopen(PerlDir_mapA(path), mode, stream);
0a753a76 2791}
2792
68dc0745 2793DllExport int
2794win32_fclose(FILE *pf)
0a753a76 2795{
19253ae6
DD
2796#ifdef WIN32_NO_SOCKETS
2797 return fclose(pf);
2798#else
f3986ebb 2799 return my_fclose(pf); /* defined in win32sck.c */
19253ae6 2800#endif
0a753a76 2801}
2802
68dc0745 2803DllExport int
2804win32_fputs(const char *s,FILE *pf)
0a753a76 2805{
390b85e7 2806 return fputs(s, pf);
0a753a76 2807}
2808
68dc0745 2809DllExport int
2810win32_fputc(int c,FILE *pf)
0a753a76 2811{
390b85e7 2812 return fputc(c,pf);
0a753a76 2813}
2814
68dc0745 2815DllExport int
2816win32_ungetc(int c,FILE *pf)
0a753a76 2817{
390b85e7 2818 return ungetc(c,pf);
0a753a76 2819}
2820
68dc0745 2821DllExport int
2822win32_getc(FILE *pf)
0a753a76 2823{
390b85e7 2824 return getc(pf);
0a753a76 2825}
2826
68dc0745 2827DllExport int
2828win32_fileno(FILE *pf)
0a753a76 2829{
390b85e7 2830 return fileno(pf);
0a753a76 2831}
2832
68dc0745 2833DllExport void
2834win32_clearerr(FILE *pf)
0a753a76 2835{
390b85e7 2836 clearerr(pf);
68dc0745 2837 return;
0a753a76 2838}
2839
68dc0745 2840DllExport int
2841win32_fflush(FILE *pf)
0a753a76 2842{
390b85e7 2843 return fflush(pf);
0a753a76 2844}
2845
c623ac67 2846DllExport Off_t
68dc0745 2847win32_ftell(FILE *pf)
0a753a76 2848{
c623ac67
GS
2849#if defined(WIN64) || defined(USE_LARGE_FILES)
2850 fpos_t pos;
2851 if (fgetpos(pf, &pos))
2852 return -1;
2853 return (Off_t)pos;
2854#else
390b85e7 2855 return ftell(pf);
c623ac67 2856#endif
0a753a76 2857}
2858
68dc0745 2859DllExport int
c623ac67 2860win32_fseek(FILE *pf, Off_t offset,int origin)
0a753a76 2861{
c623ac67
GS
2862#if defined(WIN64) || defined(USE_LARGE_FILES)
2863 fpos_t pos;
2864 switch (origin) {
2865 case SEEK_CUR:
2866 if (fgetpos(pf, &pos))
2867 return -1;
2868 offset += pos;
2869 break;
2870 case SEEK_END:
2871 fseek(pf, 0, SEEK_END);
2872 pos = _telli64(fileno(pf));
2873 offset += pos;
2874 break;
2875 case SEEK_SET:
2876 break;
2877 default:
2878 errno = EINVAL;
2879 return -1;
2880 }
2881 return fsetpos(pf, &offset);
2882#else
8859a7a0 2883 return fseek(pf, (long)offset, origin);
c623ac67 2884#endif
0a753a76 2885}
2886
68dc0745 2887DllExport int
2888win32_fgetpos(FILE *pf,fpos_t *p)
0a753a76 2889{
390b85e7 2890 return fgetpos(pf, p);
0a753a76 2891}
2892
68dc0745 2893DllExport int
2894win32_fsetpos(FILE *pf,const fpos_t *p)
0a753a76 2895{
390b85e7 2896 return fsetpos(pf, p);
0a753a76 2897}
2898
68dc0745 2899DllExport void
2900win32_rewind(FILE *pf)
0a753a76 2901{
390b85e7 2902 rewind(pf);
68dc0745 2903 return;
0a753a76 2904}
2905
2941a2e1
JH
2906DllExport int
2907win32_tmpfd(void)
0a753a76 2908{
b3122bc4
JH
2909 char prefix[MAX_PATH+1];
2910 char filename[MAX_PATH+1];
2911 DWORD len = GetTempPath(MAX_PATH, prefix);
2912 if (len && len < MAX_PATH) {
2913 if (GetTempFileName(prefix, "plx", 0, filename)) {
2914 HANDLE fh = CreateFile(filename,
2915 DELETE | GENERIC_READ | GENERIC_WRITE,
2916 0,
2917 NULL,
2918 CREATE_ALWAYS,
2919 FILE_ATTRIBUTE_NORMAL
2920 | FILE_FLAG_DELETE_ON_CLOSE,
2921 NULL);
2922 if (fh != INVALID_HANDLE_VALUE) {
c623ac67 2923 int fd = win32_open_osfhandle((intptr_t)fh, 0);
b3122bc4 2924 if (fd >= 0) {
2b01189b 2925 PERL_DEB(dTHX;)
b3122bc4
JH
2926 DEBUG_p(PerlIO_printf(Perl_debug_log,
2927 "Created tmpfile=%s\n",filename));
2941a2e1 2928 return fd;
b3122bc4
JH
2929 }
2930 }
2931 }
2932 }
2941a2e1
JH
2933 return -1;
2934}
2935
2936DllExport FILE*
2937win32_tmpfile(void)
2938{
2939 int fd = win32_tmpfd();
2940 if (fd >= 0)
2941 return win32_fdopen(fd, "w+b");
b3122bc4 2942 return NULL;
0a753a76 2943}
2944
68dc0745 2945DllExport void
2946win32_abort(void)
0a753a76 2947{
390b85e7 2948 abort();
68dc0745 2949 return;
0a753a76 2950}
2951
68dc0745 2952DllExport int
c623ac67 2953win32_fstat(int fd, Stat_t *sbufptr)
0a753a76 2954{
378eeda7 2955#if defined(WIN64) || defined(USE_LARGE_FILES)
8cbe99e5 2956 return _fstati64(fd, sbufptr);
378eeda7 2957#else
8cbe99e5 2958 return fstat(fd, sbufptr);
2a07f407 2959#endif
0a753a76 2960}
2961
68dc0745 2962DllExport int
2963win32_pipe(int *pfd, unsigned int size, int mode)
0a753a76 2964{
390b85e7 2965 return _pipe(pfd, size, mode);
0a753a76 2966}
2967
8c0134a8
NIS
2968DllExport PerlIO*
2969win32_popenlist(const char *mode, IV narg, SV **args)
2970{
aac983ac 2971 get_shell();
8c0134a8 2972
aac983ac
TC
2973 return do_popen(mode, NULL, narg, args);
2974}
50892819 2975
aac983ac
TC
2976STATIC PerlIO*
2977do_popen(const char *mode, const char *command, IV narg, SV **args) {
50892819 2978 int p[2];
f06c8825 2979 int handles[3];
50892819 2980 int parent, child;
c161da64 2981 int stdfd;
50892819
GS
2982 int ourmode;
2983 int childpid;
1095be37 2984 DWORD nhandle;
1095be37 2985 int lock_held = 0;
aac983ac 2986 const char **args_pvs = NULL;
50892819
GS
2987
2988 /* establish which ends read and write */
2989 if (strchr(mode,'w')) {
2990 stdfd = 0; /* stdin */
2991 parent = 1;
2992 child = 0;
1095be37 2993 nhandle = STD_INPUT_HANDLE;
50892819
GS
2994 }
2995 else if (strchr(mode,'r')) {
2996 stdfd = 1; /* stdout */
2997 parent = 0;
2998 child = 1;
1095be37 2999 nhandle = STD_OUTPUT_HANDLE;
50892819
GS
3000 }
3001 else
3002 return NULL;
3003
3004 /* set the correct mode */
3005 if (strchr(mode,'b'))
3006 ourmode = O_BINARY;
3007 else if (strchr(mode,'t'))
3008 ourmode = O_TEXT;
3009 else
3010 ourmode = _fmode & (O_TEXT | O_BINARY);
3011
3012 /* the child doesn't inherit handles */
3013 ourmode |= O_NOINHERIT;
3014
1095be37 3015 if (win32_pipe(p, 512, ourmode) == -1)
50892819
GS
3016 return NULL;
3017
f06c8825
TC
3018 /* Previously this code redirected stdin/out temporarily so the
3019 child process inherited those handles, this caused race
3020 conditions when another thread was writing/reading those
3021 handles.
498d7dc4 3022
f06c8825
TC
3023 To avoid that we just feed the handles to CreateProcess() so
3024 the handles are redirected only in the child.
3025 */
3026 handles[child] = p[child];
3027 handles[parent] = -1;
3028 handles[2] = -1;
564914cd 3029
f06c8825 3030 /* CreateProcess() requires inheritable handles */
c161da64 3031 if (!SetHandleInformation((HANDLE)_get_osfhandle(p[child]), HANDLE_FLAG_INHERIT,
f06c8825 3032 HANDLE_FLAG_INHERIT)) {
50892819 3033 goto cleanup;
f06c8825 3034 }
1095be37 3035
50892819 3036 /* start the child */
4f63d024 3037 {
acfe0abc 3038 dTHX;
50892819 3039
aac983ac
TC
3040 if (command) {
3041 if ((childpid = do_spawn2_handles(aTHX_ command, EXECF_SPAWN_NOWAIT, handles)) == -1)
3042 goto cleanup;
3043
3044 }
3045 else {
3046 int i;
f5fe1b19 3047 const char *exe_name;
aac983ac
TC
3048
3049 Newx(args_pvs, narg + 1 + w32_perlshell_items, const char *);
3050 SAVEFREEPV(args_pvs);
3051 for (i = 0; i < narg; ++i)
3052 args_pvs[i] = SvPV_nolen(args[i]);
3053 args_pvs[i] = NULL;
f5fe1b19
TC
3054 exe_name = qualified_path(args_pvs[0], TRUE);
3055 if (!exe_name)
3056 /* let CreateProcess() try to find it instead */
3057 exe_name = args_pvs[0];
aac983ac 3058
f5fe1b19
TC
3059 if ((childpid = do_spawnvp_handles(P_NOWAIT, exe_name, args_pvs, handles)) == -1) {
3060 goto cleanup;
aac983ac
TC
3061 }
3062 }
498d7dc4 3063
f06c8825 3064 win32_close(p[child]);
1095be37 3065
4f63d024 3066 sv_setiv(*av_fetch(w32_fdpid, p[parent], TRUE), childpid);
d91d68c1
RS
3067
3068 /* set process id so that it can be returned by perl's open() */
3069 PL_forkprocess = childpid;
4f63d024 3070 }
50892819
GS
3071
3072 /* we have an fd, return a file stream */
00b02797 3073 return (PerlIO_fdopen(p[parent], (char *)mode));
50892819
GS
3074
3075cleanup:
3076 /* we don't need to check for errors here */
3077 win32_close(p[0]);
3078 win32_close(p[1]);
f06c8825 3079
50892819 3080 return (NULL);
aac983ac
TC
3081}
3082
3083/*
3084 * a popen() clone that respects PERL5SHELL
3085 *
3086 * changed to return PerlIO* rather than FILE * by BKS, 11-11-2000
3087 */
50892819 3088
aac983ac
TC
3089DllExport PerlIO*
3090win32_popen(const char *command, const char *mode)
3091{
3092#ifdef USE_RTL_POPEN
3093 return _popen(command, mode);
3094#else
3095 return do_popen(mode, command, 0, NULL);
4b556e6c 3096#endif /* USE_RTL_POPEN */
0a753a76 3097}
3098
50892819
GS
3099/*
3100 * pclose() clone
3101 */
3102
68dc0745 3103DllExport int
00b02797 3104win32_pclose(PerlIO *pf)
0a753a76 3105{
4b556e6c 3106#ifdef USE_RTL_POPEN
390b85e7 3107 return _pclose(pf);
50892819 3108#else
acfe0abc 3109 dTHX;
e17cb2a9
JD
3110 int childpid, status;
3111 SV *sv;
3112
00b02797 3113 sv = *av_fetch(w32_fdpid, PerlIO_fileno(pf), TRUE);
4755096e 3114
e17cb2a9
JD
3115 if (SvIOK(sv))
3116 childpid = SvIVX(sv);
3117 else
3118 childpid = 0;
50892819
GS
3119
3120 if (!childpid) {
3121 errno = EBADF;
3122 return -1;
3123 }
3124
00b02797
JH
3125#ifdef USE_PERLIO
3126 PerlIO_close(pf);
3127#else
3128 fclose(pf);
3129#endif
e17cb2a9
JD
3130 SvIVX(sv) = 0;
3131
0aaad0ff
GS
3132 if (win32_waitpid(childpid, &status, 0) == -1)
3133 return -1;
50892819 3134
0aaad0ff 3135 return status;
50892819 3136
4b556e6c 3137#endif /* USE_RTL_POPEN */
0a753a76 3138}
6b980173 3139
6b980173
JD
3140DllExport int
3141win32_link(const char *oldname, const char *newname)
3142{
04a2c3d9 3143 dTHXa(NULL);
82867ecf
GS
3144 WCHAR wOldName[MAX_PATH+1];
3145 WCHAR wNewName[MAX_PATH+1];
6b980173 3146
8c56068e
JD
3147 if (MultiByteToWideChar(CP_ACP, 0, oldname, -1, wOldName, MAX_PATH+1) &&
3148 MultiByteToWideChar(CP_ACP, 0, newname, -1, wNewName, MAX_PATH+1) &&
04a2c3d9 3149 ((aTHXa(PERL_GET_THX)), wcscpy(wOldName, PerlDir_mapW(wOldName)),
8cbe99e5 3150 CreateHardLinkW(PerlDir_mapW(wNewName), wOldName, NULL)))
6b980173
JD
3151 {
3152 return 0;
3153 }
2b42d7ed
TC
3154 /* This isn't perfect, eg. Win32 returns ERROR_ACCESS_DENIED for
3155 both permissions errors and if the source is a directory, while
3156 POSIX wants EACCES and EPERM respectively.
3157
3158 Determined by experimentation on Windows 7 x64 SP1, since MS
3159 don't document what error codes are returned.
3160 */
3161 switch (GetLastError()) {
3162 case ERROR_BAD_NET_NAME:
3163 case ERROR_BAD_NETPATH:
3164 case ERROR_BAD_PATHNAME:
3165 case ERROR_FILE_NOT_FOUND:
3166 case ERROR_FILENAME_EXCED_RANGE:
3167 case ERROR_INVALID_DRIVE:
3168 case ERROR_PATH_NOT_FOUND:
3169 errno = ENOENT;
3170 break;
3171 case ERROR_ALREADY_EXISTS:
3172 errno = EEXIST;
3173 break;
3174 case ERROR_ACCESS_DENIED:
3175 errno = EACCES;
3176 break;
3177 case ERROR_NOT_SAME_DEVICE:
3178 errno = EXDEV;
3179 break;
e41416c3
CM
3180 case ERROR_DISK_FULL:
3181 errno = ENOSPC;
3182 break;
3183 case ERROR_NOT_ENOUGH_QUOTA:
3184 errno = EDQUOT;
3185 break;
2b42d7ed
TC
3186 default:
3187 /* ERROR_INVALID_FUNCTION - eg. on a FAT volume */
3188 errno = EINVAL;
3189 break;
3190 }
6b980173
JD
3191 return -1;
3192}
0a753a76 3193
68dc0745 3194DllExport int
8d9b2e3c 3195win32_rename(const char *oname, const char *newname)
e24c7c18 3196{
65cb15a1 3197 char szOldName[MAX_PATH+1];
7fac1903 3198 BOOL bResult;
8cbe99e5 3199 DWORD dwFlags = MOVEFILE_COPY_ALLOWED;
acfe0abc 3200 dTHX;
65cb15a1 3201
8cbe99e5
JD
3202 if (stricmp(newname, oname))
3203 dwFlags |= MOVEFILE_REPLACE_EXISTING;
3204 strcpy(szOldName, PerlDir_mapA(oname));
3205
3206 bResult = MoveFileExA(szOldName,PerlDir_mapA(newname), dwFlags);
3207 if (!bResult) {
3208 DWORD err = GetLastError();
3209 switch (err) {
3210 case ERROR_BAD_NET_NAME:
3211 case ERROR_BAD_NETPATH:
3212 case ERROR_BAD_PATHNAME:
3213 case ERROR_FILE_NOT_FOUND:
3214 case ERROR_FILENAME_EXCED_RANGE:
3215 case ERROR_INVALID_DRIVE:
3216 case ERROR_NO_MORE_FILES:
3217 case ERROR_PATH_NOT_FOUND:
3218 errno = ENOENT;
3219 break;
e41416c3
CM
3220 case ERROR_DISK_FULL:
3221 errno = ENOSPC;
3222 break;
3223 case ERROR_NOT_ENOUGH_QUOTA:
3224 errno = EDQUOT;
3225 break;
8cbe99e5
JD
3226 default:
3227 errno = EACCES;
3228 break;
3229 }
3230 return -1;
e24c7c18 3231 }
8cbe99e5 3232 return 0;
e24c7c18
GS
3233}
3234
3235DllExport int
68dc0745 3236win32_setmode(int fd, int mode)
0a753a76 3237{
390b85e7 3238 return setmode(fd, mode);
0a753a76 3239}
3240
4a9d6100
GS
3241DllExport int
3242win32_chsize(int fd, Off_t size)
3243{
3244#if defined(WIN64) || defined(USE_LARGE_FILES)
3245 int retval = 0;
3246 Off_t cur, end, extend;
3247
3248 cur = win32_tell(fd);
3249 if (cur < 0)
3250 return -1;
3251 end = win32_lseek(fd, 0, SEEK_END);
3252 if (end < 0)
3253 return -1;
3254 extend = size - end;
3255 if (extend == 0) {
3256 /* do nothing */
3257 }
3258 else if (extend > 0) {
3259 /* must grow the file, padding with nulls */
3260 char b[4096];
3261 int oldmode = win32_setmode(fd, O_BINARY);
3262 size_t count;
3263 memset(b, '\0', sizeof(b));
3264 do {
3265 count = extend >= sizeof(b) ? sizeof(b) : (size_t)extend;
3266 count = win32_write(fd, b, count);
21424390 3267 if ((int)count < 0) {
4a9d6100
GS
3268 retval = -1;
3269 break;
3270 }
3271 } while ((extend -= count) > 0);
3272 win32_setmode(fd, oldmode);
3273 }
3274 else {
3275 /* shrink the file */
3276 win32_lseek(fd, size, SEEK_SET);
3277 if (!SetEndOfFile((HANDLE)_get_osfhandle(fd))) {
3278 errno = EACCES;
3279 retval = -1;
3280 }
3281 }
4a9d6100
GS
3282 win32_lseek(fd, cur, SEEK_SET);
3283 return retval;
3284#else
8859a7a0 3285 return chsize(fd, (long)size);
4a9d6100
GS
3286#endif
3287}
3288
c623ac67
GS
3289DllExport Off_t
3290win32_lseek(int fd, Off_t offset, int origin)
96e4d5b1 3291{
c623ac67
GS
3292#if defined(WIN64) || defined(USE_LARGE_FILES)
3293 return _lseeki64(fd, offset, origin);
3294#else
8859a7a0 3295 return lseek(fd, (long)offset, origin);
c623ac67 3296#endif
96e4d5b1 3297}
3298
c623ac67 3299DllExport Off_t
96e4d5b1 3300win32_tell(int fd)
3301{
c623ac67
GS
3302#if defined(WIN64) || defined(USE_LARGE_FILES)
3303 return _telli64(fd);
3304#else
390b85e7 3305 return tell(fd);
c623ac67 3306#endif
96e4d5b1 3307}
3308
68dc0745 3309DllExport int
3310win32_open(const char *path, int flag, ...)
0a753a76 3311{
04a2c3d9 3312 dTHXa(NULL);
68dc0745 3313 va_list ap;
3314 int pmode;
0a753a76 3315
3316 va_start(ap, flag);
3317 pmode = va_arg(ap, int);
3318 va_end(ap);
3319
68dc0745 3320 if (stricmp(path, "/dev/null")==0)
7fac1903
GS
3321 path = "NUL";
3322
04a2c3d9 3323 aTHXa(PERL_GET_THX);
7766f137 3324 return open(PerlDir_mapA(path), flag, pmode);
0a753a76 3325}
3326
00b02797
JH
3327/* close() that understands socket */
3328extern int my_close(int); /* in win32sck.c */
3329
68dc0745 3330DllExport int
3331win32_close(int fd)
0a753a76 3332{
19253ae6
DD
3333#ifdef WIN32_NO_SOCKETS
3334 return close(fd);
3335#else
00b02797 3336 return my_close(fd);
19253ae6 3337#endif
0a753a76 3338}
3339
68dc0745 3340DllExport int
96e4d5b1 3341win32_eof(int fd)
3342{
390b85e7 3343 return eof(fd);
96e4d5b1 3344}
3345
3346DllExport int
4342f4d6
JD
3347win32_isatty(int fd)
3348{
3349 /* The Microsoft isatty() function returns true for *all*
3350 * character mode devices, including "nul". Our implementation
3351 * should only return true if the handle has a console buffer.
3352 */
3353 DWORD mode;
3354 HANDLE fh = (HANDLE)_get_osfhandle(fd);
3355 if (fh == (HANDLE)-1) {
3356 /* errno is already set to EBADF */
3357 return 0;
3358 }
3359
3360 if (GetConsoleMode(fh, &mode))
3361 return 1;
3362
3363 errno = ENOTTY;
3364 return 0;
3365}
3366
3367DllExport int
68dc0745 3368win32_dup(int fd)
0a753a76 3369{
390b85e7 3370 return dup(fd);
0a753a76 3371}
3372
68dc0745 3373DllExport int
3374win32_dup2(int fd1,int fd2)
0a753a76 3375{
390b85e7 3376 return dup2(fd1,fd2);
0a753a76 3377}
3378
68dc0745 3379DllExport int
3e3baf6d 3380win32_read(int fd, void *buf, unsigned int cnt)
0a753a76 3381{
390b85e7 3382 return read(fd, buf, cnt);
0a753a76 3383}
3384
68dc0745 3385DllExport int
3e3baf6d 3386win32_write(int fd, const void *buf, unsigned int cnt)
0a753a76 3387{
390b85e7 3388 return write(fd, buf, cnt);
0a753a76 3389}
3390
68dc0745 3391DllExport int
5aabfad6 3392win32_mkdir(const char *dir, int mode)
3393{
acfe0abc 3394 dTHX;
7766f137 3395 return mkdir(PerlDir_mapA(dir)); /* just ignore mode */
5aabfad6 3396}
96e4d5b1 3397
5aabfad6 3398DllExport int
3399win32_rmdir(const char *dir)
3400{
acfe0abc 3401 dTHX;
7766f137 3402 return rmdir(PerlDir_mapA(dir));
5aabfad6 3403}
96e4d5b1 3404
5aabfad6 3405DllExport int
3406win32_chdir(const char *dir)
3407{
1cdd9224 3408 if (!dir || !*dir) {
9ec3348a
JH
3409 errno = ENOENT;
3410 return -1;
3411 }
390b85e7 3412 return chdir(dir);
5aabfad6 3413}
96e4d5b1 3414
7766f137
GS
3415DllExport int
3416win32_access(const char *path, int mode)
3417{
acfe0abc 3418 dTHX;
7766f137
GS
3419 return access(PerlDir_mapA(path), mode);
3420}
3421
3422DllExport int
3423win32_chmod(const char *path, int mode)
3424{
acfe0abc 3425 dTHX;
7766f137
GS
3426 return chmod(PerlDir_mapA(path), mode);
3427}
3428
3429
0aaad0ff 3430static char *
dd7038b3 3431create_command_line(char *cname, STRLEN clen, const char * const *args)
0aaad0ff 3432{
2b01189b 3433 PERL_DEB(dTHX;)
b309b8ae
JH
3434 int index, argc;
3435 char *cmd, *ptr;
3436 const char *arg;
3437 STRLEN len = 0;
81bc1258 3438 bool bat_file = FALSE;
b309b8ae 3439 bool cmd_shell = FALSE;
7b11e424 3440 bool dumb_shell = FALSE;
b309b8ae 3441 bool extra_quotes = FALSE;
dd7038b3 3442 bool quote_next = FALSE;
81bc1258
JH
3443
3444 if (!cname)
3445 cname = (char*)args[0];
b309b8ae
JH
3446
3447 /* The NT cmd.exe shell has the following peculiarity that needs to be
3448 * worked around. It strips a leading and trailing dquote when any
3449 * of the following is true:
3450 * 1. the /S switch was used
3451 * 2. there are more than two dquotes
3452 * 3. there is a special character from this set: &<>()@^|
3453 * 4. no whitespace characters within the two dquotes
3454 * 5. string between two dquotes isn't an executable file
3455 * To work around this, we always add a leading and trailing dquote
3456 * to the string, if the first argument is either "cmd.exe" or "cmd",
3457 * and there were at least two or more arguments passed to cmd.exe
3458 * (not including switches).
dd7038b3
JH
3459 * XXX the above rules (from "cmd /?") don't seem to be applied
3460 * always, making for the convolutions below :-(
b309b8ae 3461 */
81bc1258 3462 if (cname) {
dd7038b3
JH
3463 if (!clen)
3464 clen = strlen(cname);
3465
81bc1258
JH
3466 if (clen > 4
3467 && (stricmp(&cname[clen-4], ".bat") == 0
8cbe99e5 3468 || (stricmp(&cname[clen-4], ".cmd") == 0)))
81bc1258
JH
3469 {
3470 bat_file = TRUE;
8cbe99e5 3471 len += 3;
81bc1258 3472 }
dd7038b3
JH
3473 else {
3474 char *exe = strrchr(cname, '/');
3475 char *exe2 = strrchr(cname, '\\');
3476 if (exe2 > exe)
3477 exe = exe2;
3478 if (exe)
3479 ++exe;
3480 else
3481 exe = cname;
3482 if (stricmp(exe, "cmd.exe") == 0 || stricmp(exe, "cmd") == 0) {
3483 cmd_shell = TRUE;
3484 len += 3;
3485 }
7b11e424
JH
3486 else if (stricmp(exe, "command.com") == 0
3487 || stricmp(exe, "command") == 0)
3488 {
3489 dumb_shell = TRUE;
3490 }
81bc1258 3491 }
b309b8ae 3492 }
0aaad0ff 3493
b309b8ae
JH
3494 DEBUG_p(PerlIO_printf(Perl_debug_log, "Args "));
3495 for (index = 0; (arg = (char*)args[index]) != NULL; ++index) {
3496 STRLEN curlen = strlen(arg);
3497 if (!(arg[0] == '"' && arg[curlen-1] == '"'))
3498 len += 2; /* assume quoting needed (worst case) */
3499 len += curlen + 1;
3500 DEBUG_p(PerlIO_printf(Perl_debug_log, "[%s]",arg));
3501 }
3502 DEBUG_p(PerlIO_printf(Perl_debug_log, "\n"));
0aaad0ff 3503
b309b8ae 3504 argc = index;
a02a5408 3505 Newx(cmd, len, char);
0aaad0ff 3506 ptr = cmd;
0aaad0ff 3507
8cbe99e5 3508 if (bat_file) {
81bc1258
JH
3509 *ptr++ = '"';
3510 extra_quotes = TRUE;
3511 }
3512
0aaad0ff 3513 for (index = 0; (arg = (char*)args[index]) != NULL; ++index) {
b309b8ae
JH
3514 bool do_quote = 0;
3515 STRLEN curlen = strlen(arg);
3516
81bc1258
JH
3517 /* we want to protect empty arguments and ones with spaces with
3518 * dquotes, but only if they aren't already there */
7b11e424
JH
3519 if (!dumb_shell) {
3520 if (!curlen) {
3521 do_quote = 1;
3522 }
02ef22d5
JH
3523 else if (quote_next) {
3524 /* see if it really is multiple arguments pretending to
3525 * be one and force a set of quotes around it */
3526 if (*find_next_space(arg))
3527 do_quote = 1;
3528 }
7b11e424
JH
3529 else if (!(arg[0] == '"' && curlen > 1 && arg[curlen-1] == '"')) {
3530 STRLEN i = 0;
3531 while (i < curlen) {
3532 if (isSPACE(arg[i])) {
3533 do_quote = 1;
02ef22d5
JH
3534 }
3535 else if (arg[i] == '"') {
3536 do_quote = 0;
7b11e424
JH
3537 break;
3538 }
3539 i++;
b309b8ae 3540 }
b309b8ae 3541 }
dd7038b3 3542 }
b309b8ae
JH
3543
3544 if (do_quote)
3545 *ptr++ = '"';
3546
18a945d4 3547 strcpy(ptr, arg);
b309b8ae
JH
3548 ptr += curlen;
3549
3550 if (do_quote)
3551 *ptr++ = '"';
3552
3553 if (args[index+1])
3554 *ptr++ = ' ';
3555
81bc1258
JH
3556 if (!extra_quotes
3557 && cmd_shell
11998fdb
GS
3558 && curlen >= 2
3559 && *arg == '/' /* see if arg is "/c", "/x/c", "/x/d/c" etc. */
3560 && stricmp(arg+curlen-2, "/c") == 0)
b309b8ae 3561 {
dd7038b3
JH
3562 /* is there a next argument? */
3563 if (args[index+1]) {
3564 /* are there two or more next arguments? */
3565 if (args[index+2]) {
3566 *ptr++ = '"';
3567 extra_quotes = TRUE;
3568 }
3569 else {
02ef22d5 3570 /* single argument, force quoting if it has spaces */
dd7038b3
JH
3571 quote_next = TRUE;
3572 }
3573 }
b309b8ae 3574 }
0aaad0ff
GS
3575 }
3576
b309b8ae
JH
3577 if (extra_quotes)
3578 *ptr++ = '"';
3579
3580 *ptr = '\0';
3581
0aaad0ff
GS
3582 return cmd;
3583}
3584
f5fe1b19
TC
3585static const char *exe_extensions[] =
3586 {
3587 ".exe", /* this must be first */
3588 ".cmd",
3589 ".bat"
3590 };
3591
0aaad0ff 3592static char *
f5fe1b19 3593qualified_path(const char *cmd, bool other_exts)
0aaad0ff
GS
3594{
3595 char *pathstr;
3596 char *fullcmd, *curfullcmd;
3597 STRLEN cmdlen = 0;
3598 int has_slash = 0;
3599
3600 if (!cmd)
4e205ed6 3601 return NULL;
0aaad0ff
GS
3602 fullcmd = (char*)cmd;
3603 while (*fullcmd) {
3604 if (*fullcmd == '/' || *fullcmd == '\\')
3605 has_slash++;
3606 fullcmd++;
3607 cmdlen++;
3608 }
3609
3610 /* look in PATH */
04a2c3d9
DD
3611 {
3612 dTHX;
3613 pathstr = PerlEnv_getenv("PATH");
3614 }
1928965c
JD
3615 /* worst case: PATH is a single directory; we need additional space
3616 * to append "/", ".exe" and trailing "\0" */
a02a5408 3617 Newx(fullcmd, (pathstr ? strlen(pathstr) : 0) + cmdlen + 6, char);
0aaad0ff
GS
3618 curfullcmd = fullcmd;
3619
3620 while (1) {
3621 DWORD res;
3622
3623 /* start by appending the name to the current prefix */
3624 strcpy(curfullcmd, cmd);
3625 curfullcmd += cmdlen;
3626
3627 /* if it doesn't end with '.', or has no extension, try adding
3628 * a trailing .exe first */
3629 if (cmd[cmdlen-1] != '.'
3630 && (cmdlen < 4 || cmd[cmdlen-4] != '.'))
3631 {
f5fe1b19
TC
3632 int i;
3633 /* first extension is .exe */
3634 int ext_limit = other_exts ? C_ARRAY_LENGTH(exe_extensions) : 1;
3635 for (i = 0; i < ext_limit; ++i) {
3636 strcpy(curfullcmd, exe_extensions[i]);
3637 res = GetFileAttributes(fullcmd);
3638 if (res != 0xFFFFFFFF && !(res & FILE_ATTRIBUTE_DIRECTORY))
3639 return fullcmd;
3640 }
3641
0aaad0ff
GS
3642 *curfullcmd = '\0';
3643 }
3644
3645 /* that failed, try the bare name */
3646 res = GetFileAttributes(fullcmd);
3647 if (res != 0xFFFFFFFF && !(res & FILE_ATTRIBUTE_DIRECTORY))
3648 return fullcmd;
3649
3650 /* quit if no other path exists, or if cmd already has path */
3651 if (!pathstr || !*pathstr || has_slash)
3652 break;
3653
3654 /* skip leading semis */
3655 while (*pathstr == ';')
3656 pathstr++;
3657
3658 /* build a new prefix from scratch */
3659 curfullcmd = fullcmd;
3660 while (*pathstr && *pathstr != ';') {
3661 if (*pathstr == '"') { /* foo;"baz;etc";bar */
3662 pathstr++; /* skip initial '"' */
3663 while (*pathstr && *pathstr != '"') {
1928965c 3664 *curfullcmd++ = *pathstr++;
0aaad0ff
GS
3665 }
3666 if (*pathstr)
3667 pathstr++; /* skip trailing '"' */
3668 }
3669 else {
1928965c 3670 *curfullcmd++ = *pathstr++;
0aaad0ff
GS
3671 }
3672 }
3673 if (*pathstr)
3674 pathstr++; /* skip trailing semi */
3675 if (curfullcmd > fullcmd /* append a dir separator */
3676 && curfullcmd[-1] != '/' && curfullcmd[-1] != '\\')
3677 {
3678 *curfullcmd++ = '\\';
3679 }
3680 }
eb160463 3681
0aaad0ff 3682 Safefree(fullcmd);
4e205ed6 3683 return NULL;
0aaad0ff
GS
3684}
3685
3075ddba
GS
3686/* The following are just place holders.
3687 * Some hosts may provide and environment that the OS is
3688 * not tracking, therefore, these host must provide that
3689 * environment and the current directory to CreateProcess
3690 */
3691
df3728a2
JH
3692DllExport void*
3693win32_get_childenv(void)
3075ddba
GS
3694{
3695 return NULL;
3696}
3697
df3728a2
JH
3698DllExport void
3699win32_free_childenv(void* d)
3075ddba
GS
3700{
3701}
3702
df3728a2
JH
3703DllExport void
3704win32_clearenv(void)
3705{
3706 char *envv = GetEnvironmentStrings();
3707 char *cur = envv;
3708 STRLEN len;
3709 while (*cur) {
3710 char *end = strchr(cur,'=');
3711 if (end && end != cur) {
3712 *end = '\0';
3713 SetEnvironmentVariable(cur, NULL);
3714 *end = '=';
3715 cur = end + strlen(end+1)+2;
3716 }
3717 else if ((len = strlen(cur)))
3718 cur += len+1;
3719 }
3720 FreeEnvironmentStrings(envv);
3721}
3722
3723DllExport char*
3724win32_get_childdir(void)
3075ddba 3725{
7766f137 3726 char* ptr;
8c56068e 3727 char szfilename[MAX_PATH+1];
7766f137 3728
8c56068e 3729 GetCurrentDirectoryA(MAX_PATH+1, szfilename);
a02a5408 3730 Newx(ptr, strlen(szfilename)+1, char);
7766f137
GS
3731 strcpy(ptr, szfilename);
3732 return ptr;
3075ddba
GS
3733}
3734
df3728a2
JH
3735DllExport void
3736win32_free_childdir(char* d)
3075ddba 3737{
7766f137 3738 Safefree(d);
3075ddba
GS
3739}
3740
3741
0aaad0ff
GS
3742/* XXX this needs to be made more compatible with the spawnvp()
3743 * provided by the various RTLs. In particular, searching for
3744 * *.{com,bat,cmd} files (as done by the RTLs) is unimplemented.
3745 * This doesn't significantly affect perl itself, because we
3746 * always invoke things using PERL5SHELL if a direct attempt to
3747 * spawn the executable fails.
3fadfdf1 3748 *
0aaad0ff
GS
3749 * XXX splitting and rejoining the commandline between do_aspawn()
3750 * and win32_spawnvp() could also be avoided.
3751 */
3752
5aabfad6 3753DllExport int
3e3baf6d 3754win32_spawnvp(int mode, const char *cmdname, const char *const *argv)
0a753a76 3755{
0aaad0ff 3756#ifdef USE_RTL_SPAWNVP
8fdfe84a 3757 return _spawnvp(mode, cmdname, (char * const *)argv);
0aaad0ff 3758#else
f06c8825
TC
3759 return do_spawnvp_handles(mode, cmdname, argv, NULL);
3760#endif
3761}
3762
3763static int
3764do_spawnvp_handles(int mode, const char *cmdname, const char *const *argv,
3765 const int *handles) {
9399a70c 3766 dTHXa(NULL);
2b260de0 3767 int ret;
3075ddba
GS
3768 void* env;
3769 char* dir;
635bbe87 3770 child_IO_table tbl;
0aaad0ff
GS
3771 STARTUPINFO StartupInfo;
3772 PROCESS_INFORMATION ProcessInformation;
3773 DWORD create = 0;
dd7038b3 3774 char *cmd;
4e205ed6 3775 char *fullcmd = NULL;
dd7038b3
JH
3776 char *cname = (char *)cmdname;
3777 STRLEN clen = 0;
3778
3779 if (cname) {
3780 clen = strlen(cname);
3781 /* if command name contains dquotes, must remove them */
3782 if (strchr(cname, '"')) {
3783 cmd = cname;
a02a5408 3784 Newx(cname,clen+1,char);
dd7038b3
JH
3785 clen = 0;
3786 while (*cmd) {
3787 if (*cmd != '"') {
3788 cname[clen] = *cmd;
3789 ++clen;
3790 }
3791 ++cmd;
3792 }
3793 cname[clen] = '\0';
3794 }
3795 }
3796
3797 cmd = create_command_line(cname, clen, argv);
0aaad0ff 3798
9399a70c 3799 aTHXa(PERL_GET_THX);
3075ddba
GS
3800 env = PerlEnv_get_childenv();
3801 dir = PerlEnv_get_childdir();
3802
0aaad0ff
GS
3803 switch(mode) {
3804 case P_NOWAIT: /* asynch + remember result */
3805 if (w32_num_children >= MAXIMUM_WAIT_OBJECTS) {
3806 errno = EAGAIN;
3807 ret = -1;
3808 goto RETVAL;
3809 }
3fadfdf1 3810 /* Create a new process group so we can use GenerateConsoleCtrlEvent()
7e5f34c0
NIS
3811 * in win32_kill()
3812 */
3fadfdf1 3813 create |= CREATE_NEW_PROCESS_GROUP;
0aaad0ff 3814 /* FALL THROUGH */
7e5f34c0 3815
0aaad0ff
GS
3816 case P_WAIT: /* synchronous execution */
3817 break;
3818 default: /* invalid mode */
3819 errno = EINVAL;
3820 ret = -1;
3821 goto RETVAL;
3822 }
f06c8825 3823
0aaad0ff
GS
3824 memset(&StartupInfo,0,sizeof(StartupInfo));
3825 StartupInfo.cb = sizeof(StartupInfo);
f83751a7 3826 memset(&tbl,0,sizeof(tbl));
635bbe87 3827 PerlEnv_get_child_IO(&tbl);
f83751a7 3828 StartupInfo.dwFlags = tbl.dwFlags;
3fadfdf1
NIS
3829 StartupInfo.dwX = tbl.dwX;
3830 StartupInfo.dwY = tbl.dwY;
3831 StartupInfo.dwXSize = tbl.dwXSize;
3832 StartupInfo.dwYSize = tbl.dwYSize;
3833 StartupInfo.dwXCountChars = tbl.dwXCountChars;
3834 StartupInfo.dwYCountChars = tbl.dwYCountChars;
3835 StartupInfo.dwFillAttribute = tbl.dwFillAttribute;
3836 StartupInfo.wShowWindow = tbl.wShowWindow;
f06c8825
TC
3837 StartupInfo.hStdInput = handles && handles[0] != -1 ?
3838 (HANDLE)_get_osfhandle(handles[0]) : tbl.childStdIn;
3839 StartupInfo.hStdOutput = handles && handles[1] != -1 ?
3840 (HANDLE)_get_osfhandle(handles[1]) : tbl.childStdOut;
3841 StartupInfo.hStdError = handles && handles[2] != -1 ?
3842 (HANDLE)_get_osfhandle(handles[2]) : tbl.childStdErr;
139cf11b
GS
3843 if (StartupInfo.hStdInput == INVALID_HANDLE_VALUE &&
3844 StartupInfo.hStdOutput == INVALID_HANDLE_VALUE &&
3845 StartupInfo.hStdError == INVALID_HANDLE_VALUE)
3ffaa937 3846 {
139cf11b 3847 create |= CREATE_NEW_CONSOLE;
3ffaa937
GS
3848 }
3849 else {
139cf11b 3850 StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
3ffaa937 3851 }
02637f4c
JD
3852 if (w32_use_showwindow) {
3853 StartupInfo.dwFlags |= STARTF_USESHOWWINDOW;
3854 StartupInfo.wShowWindow = w32_showwindow;
3855 }
3ffaa937 3856
b309b8ae 3857 DEBUG_p(PerlIO_printf(Perl_debug_log, "Spawning [%s] with [%s]\n",
dd7038b3 3858 cname,cmd));
0aaad0ff 3859RETRY:
dd7038b3 3860 if (!CreateProcess(cname, /* search PATH to find executable */
0aaad0ff
GS
3861 cmd, /* executable, and its arguments */
3862 NULL, /* process attributes */
3863 NULL, /* thread attributes */
3864 TRUE, /* inherit handles */
3865 create, /* creation flags */
3075ddba
GS
3866 (LPVOID)env, /* inherit environment */
3867 dir, /* inherit cwd */
0aaad0ff
GS
3868 &StartupInfo,
3869 &ProcessInformation))
3870 {
3871 /* initial NULL argument to CreateProcess() does a PATH
3872 * search, but it always first looks in the directory
3873 * where the current process was started, which behavior
3874 * is undesirable for backward compatibility. So we
3875 * jump through our own hoops by picking out the path
3876 * we really want it to use. */
3877 if (!fullcmd) {
f5fe1b19 3878 fullcmd = qualified_path(cname, FALSE);
0aaad0ff 3879 if (fullcmd) {
dd7038b3
JH
3880 if (cname != cmdname)
3881 Safefree(cname);
3882 cname = fullcmd;
b309b8ae
JH
3883 DEBUG_p(PerlIO_printf(Perl_debug_log,
3884 "Retrying [%s] with same args\n",
dd7038b3 3885 cname));
0aaad0ff
GS
3886 goto RETRY;
3887 }
3888 }
3889 errno = ENOENT;
3890 ret = -1;
3891 goto RETVAL;
3892 }
2d7a9237 3893
0aaad0ff
GS
3894 if (mode == P_NOWAIT) {
3895 /* asynchronous spawn -- store handle, return PID */
2b260de0 3896 ret = (int)ProcessInformation.dwProcessId;
922b1888
GS
3897
3898 w32_child_handles[w32_num_children] = ProcessInformation.hProcess;
3899 w32_child_pids[w32_num_children] = (DWORD)ret;
0aaad0ff
GS
3900 ++w32_num_children;
3901 }
3902 else {
2b260de0 3903 DWORD status;
8fb3fcfb 3904 win32_msgwait(aTHX_ 1, &ProcessInformation.hProcess, INFINITE, NULL);
7e5f34c0
NIS
3905 /* FIXME: if msgwait returned due to message perhaps forward the
3906 "signal" to the process
3907 */
2b260de0
GS
3908 GetExitCodeProcess(ProcessInformation.hProcess, &status);
3909 ret = (int)status;
0aaad0ff
GS
3910 CloseHandle(ProcessInformation.hProcess);
3911 }
e17cb2a9 3912
0aaad0ff 3913 CloseHandle(ProcessInformation.hThread);
3075ddba 3914
0aaad0ff 3915RETVAL:
3075ddba
GS
3916 PerlEnv_free_childenv(env);
3917 PerlEnv_free_childdir(dir);
0aaad0ff 3918 Safefree(cmd);
dd7038b3
JH
3919 if (cname != cmdname)
3920 Safefree(cname);
2b260de0 3921 return ret;
0a753a76 3922}
3923
6890e559 3924DllExport int
eb62e965
JD
3925win32_execv(const char *cmdname, const char *const *argv)
3926{
7766f137 3927#ifdef USE_ITHREADS
acfe0abc 3928 dTHX;
7766f137
GS
3929 /* if this is a pseudo-forked child, we just want to spawn
3930 * the new program, and return */
3931 if (w32_pseudo_id)
8fdfe84a 3932 return _spawnv(P_WAIT, cmdname, argv);
7766f137 3933#endif
8fdfe84a 3934 return _execv(cmdname, argv);
eb62e965
JD
3935}
3936
3937DllExport int
6890e559
GS
3938win32_execvp(const char *cmdname, const char *const *argv)
3939{
7766f137 3940#ifdef USE_ITHREADS
acfe0abc 3941 dTHX;
7766f137
GS
3942 /* if this is a pseudo-forked child, we just want to spawn
3943 * the new program, and return */
190e4ad0 3944 if (w32_pseudo_id) {
f026e7c6 3945 int status = win32_spawnvp(P_WAIT, cmdname, (const char *const *)argv);
ba6ce41c
GS
3946 if (status != -1) {
3947 my_exit(status);
3948 return 0;
3949 }
3950 else
3951 return status;
190e4ad0 3952 }
7766f137 3953#endif
8fdfe84a 3954 return _execvp(cmdname, argv);
6890e559
GS
3955}
3956
84902520
TB
3957DllExport void
3958win32_perror(const char *str)
3959{
390b85e7 3960 perror(str);
84902520
TB
3961}
3962
3963DllExport void
3964win32_setbuf(FILE *pf, char *buf)
3965{
390b85e7 3966 setbuf(pf, buf);
84902520
TB
3967}
3968
3969DllExport int
3970win32_setvbuf(FILE *pf, char *buf, int type, size_t size)
3971{
390b85e7 3972 return setvbuf(pf, buf, type, size);
84902520
TB
3973}
3974
3975DllExport int
3976win32_flushall(void)
3977{
390b85e7 3978 return flushall();
84902520
TB
3979}
3980
3981DllExport int
3982win32_fcloseall(void)
3983{
390b85e7 3984 return fcloseall();
84902520
TB
3985}
3986
3987DllExport char*
3988win32_fgets(char *s, int n, FILE *pf)
3989{
390b85e7 3990 return fgets(s, n, pf);
84902520
TB
3991}
3992
3993DllExport char*
3994win32_gets(char *s)
3995{
390b85e7 3996 return gets(s);
84902520
TB
3997}
3998
3999DllExport int
4000win32_fgetc(FILE *pf)
4001{
390b85e7 4002 return fgetc(pf);
84902520
TB
4003}
4004
4005DllExport int
4006win32_putc(int c, FILE *pf)
4007{
390b85e7 4008 return putc(c,pf);
84902520
TB
4009}
4010
4011DllExport int
4012win32_puts(const char *s)
4013{
390b85e7 4014 return puts(s);
84902520
TB
4015}
4016
4017DllExport int
4018win32_getchar(void)
4019{
390b85e7 4020 return getchar();
84902520
TB
4021}
4022
4023DllExport int
4024win32_putchar(int c)
4025{
390b85e7 4026 return putchar(c);
84902520
TB
4027}
4028
bbc8f9de
NIS
4029#ifdef MYMALLOC
4030
4031#ifndef USE_PERL_SBRK
4032
df3728a2
JH
4033static char *committed = NULL; /* XXX threadead */
4034static char *base = NULL; /* XXX threadead */
4035static char *reserved = NULL; /* XXX threadead */
4036static char *brk = NULL; /* XXX threadead */
4037static DWORD pagesize = 0; /* XXX threadead */
bbc8f9de
NIS
4038
4039void *
c623ac67 4040sbrk(ptrdiff_t need)
bbc8f9de
NIS
4041{
4042 void *result;
4043 if (!pagesize)
4044 {SYSTEM_INFO info;
4045 GetSystemInfo(&info);
4046 /* Pretend page size is larger so we don't perpetually
4047 * call the OS to commit just one page ...
4048 */
4049 pagesize = info.dwPageSize << 3;
bbc8f9de 4050 }
bbc8f9de
NIS
4051 if (brk+need >= reserved)
4052 {
b2d41e21 4053 DWORD size = brk+need-reserved;
bbc8f9de 4054 char *addr;
b2d41e21 4055 char *prev_committed = NULL;
bbc8f9de
NIS
4056 if (committed && reserved && committed < reserved)
4057 {
4058 /* Commit last of previous chunk cannot span allocations */
161b471a 4059 addr = (char *) VirtualAlloc(committed,reserved-committed,MEM_COMMIT,PAGE_READWRITE);
bbc8f9de 4060 if (addr)
b2d41e21
SH
4061 {
4062 /* Remember where we committed from in case we want to decommit later */
4063 prev_committed = committed;
bbc8f9de 4064 committed = reserved;
b2d41e21 4065 }
bbc8f9de 4066 }
3fadfdf1 4067 /* Reserve some (more) space
b2d41e21
SH
4068 * Contiguous blocks give us greater efficiency, so reserve big blocks -
4069 * this is only address space not memory...
bbc8f9de
NIS
4070 * Note this is a little sneaky, 1st call passes NULL as reserved
4071 * so lets system choose where we start, subsequent calls pass
4072 * the old end address so ask for a contiguous block
4073 */
b2d41e21
SH
4074sbrk_reserve:
4075 if (size < 64*1024*1024)
4076 size = 64*1024*1024;
4077 size = ((size + pagesize - 1) / pagesize) * pagesize;
161b471a 4078 addr = (char *) VirtualAlloc(reserved,size,MEM_RESERVE,PAGE_NOACCESS);
bbc8f9de
NIS
4079 if (addr)
4080 {
4081 reserved = addr+size;
4082 if (!base)
4083 base = addr;
4084 if (!committed)
4085 committed = base;
4086 if (!brk)
4087 brk = committed;
4088 }
b2d41e21
SH
4089 else if (reserved)
4090 {
4091 /* The existing block could not be extended far enough, so decommit
4092 * anything that was just committed above and start anew */
4093 if (prev_committed)
4094 {
4095 if (!VirtualFree(prev_committed,reserved-prev_committed,MEM_DECOMMIT))
4096 return (void *) -1;
4097 }
4098 reserved = base = committed = brk = NULL;
4099 size = need;
4100 goto sbrk_reserve;
4101 }
bbc8f9de
NIS
4102 else
4103 {
4104 return (void *) -1;
4105 }
4106 }
4107 result = brk;
4108 brk += need;
4109 if (brk > committed)
4110 {
4111 DWORD size = ((brk-committed + pagesize -1)/pagesize) * pagesize;
b2d41e21
SH
4112 char *addr;
4113 if (committed+size > reserved)
4114 size = reserved-committed;
4115 addr = (char *) VirtualAlloc(committed,size,MEM_COMMIT,PAGE_READWRITE);
bbc8f9de 4116 if (addr)
b2d41e21 4117 committed += size;
bbc8f9de
NIS
4118 else
4119 return (void *) -1;
4120 }
4121 return result;
4122}
4123
4124#endif
4125#endif
4126
84902520
TB
4127DllExport void*
4128win32_malloc(size_t size)
4129{
390b85e7 4130 return malloc(size);
84902520
TB
4131}
4132
4133DllExport void*
4134win32_calloc(size_t numitems, size_t size)
4135{
390b85e7 4136 return calloc(numitems,size);
84902520
TB
4137}
4138
4139DllExport void*
4140win32_realloc(void *block, size_t size)
4141{
390b85e7 4142 return realloc(block,size);
84902520
TB
4143}
4144
4145DllExport void
4146win32_free(void *block)
4147{
390b85e7 4148 free(block);
84902520
TB
4149}
4150
bbc8f9de 4151
6e21dc91 4152DllExport int
c623ac67 4153win32_open_osfhandle(intptr_t handle, int flags)
0a753a76 4154{
390b85e7 4155 return _open_osfhandle(handle, flags);
0a753a76 4156}
4157
6e21dc91 4158DllExport intptr_t
65e48ea9 4159win32_get_osfhandle(int fd)
0a753a76 4160{
c623ac67 4161 return (intptr_t)_get_osfhandle(fd);
0a753a76 4162}
7bac28a0 4163
6e21dc91 4164DllExport FILE *
30753f56
NIS
4165win32_fdupopen(FILE *pf)
4166{
4167 FILE* pfdup;
4168 fpos_t pos;
4169 char mode[3];
4170 int fileno = win32_dup(win32_fileno(pf));
4171
4172 /* open the file in the same mode */
1f664ef5 4173 if (PERLIO_FILE_flag(pf) & PERLIO_FILE_flag_RD) {
30753f56
NIS
4174 mode[0] = 'r';
4175 mode[1] = 0;
4176 }
1f664ef5 4177 else if (PERLIO_FILE_flag(pf) & PERLIO_FILE_flag_WR) {
30753f56
NIS
4178 mode[0] = 'a';
4179 mode[1] = 0;
4180 }
1f664ef5 4181 else if (PERLIO_FILE_flag(pf) & PERLIO_FILE_flag_RW) {
30753f56
NIS
4182 mode[0] = 'r';
4183 mode[1] = '+';
4184 mode[2] = 0;
4185 }
30753f56
NIS
4186
4187 /* it appears that the binmode is attached to the
4188 * file descriptor so binmode files will be handled
4189 * correctly
4190 */
4191 pfdup = win32_fdopen(fileno, mode);
4192
4193 /* move the file pointer to the same position */
4194 if (!fgetpos(pf, &pos)) {
4195 fsetpos(pfdup, &pos);
4196 }
4197 return pfdup;
4198}
4199
0cb96387 4200DllExport void*
c5be433b 4201win32_dynaload(const char* filename)
0cb96387 4202{
04a2c3d9 4203 dTHXa(NULL);
32f99636 4204 char buf[MAX_PATH+1];
f76b679e 4205 const char *first;
32f99636
GS
4206
4207 /* LoadLibrary() doesn't recognize forward slashes correctly,
4208 * so turn 'em back. */
4209 first = strchr(filename, '/');
4210 if (first) {
4211 STRLEN len = strlen(filename);
4212 if (len <= MAX_PATH) {
4213 strcpy(buf, filename);
4214 filename = &buf[first - filename];
4215 while (*filename) {
4216 if (*filename == '/')
4217 *(char*)filename = '\\';
4218 ++filename;
4219 }
4220 filename = buf;
4221 }
4222 }
04a2c3d9 4223 aTHXa(PERL_GET_THX);
8c56068e 4224 return LoadLibraryExA(PerlDir_mapA(filename), NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
0cb96387
GS
4225}
4226
5bd7e777
JD
4227XS(w32_SetChildShowWindow)
4228{
4229 dXSARGS;
4230 BOOL use_showwindow = w32_use_showwindow;
4231 /* use "unsigned short" because Perl has redefined "WORD" */
4232 unsigned short showwindow = w32_showwindow;
4233
4234 if (items > 1)
470eba0e 4235 croak_xs_usage(cv, "[showwindow]");
5bd7e777
JD
4236
4237 if (items == 0 || !SvOK(ST(0)))
4238 w32_use_showwindow = FALSE;
4239 else {
4240 w32_use_showwindow = TRUE;
4241 w32_showwindow = (unsigned short)SvIV(ST(0));
4242 }
4243
4244 EXTEND(SP, 1);
4245 if (use_showwindow)
4246 ST(0) = sv_2mortal(newSViv(showwindow));
4247 else
4248 ST(0) = &PL_sv_undef;
4249 XSRETURN(1);
4250}
4251
8f1332ed
DD
4252
4253#ifdef PERL_IS_MINIPERL
4254/* shelling out is much slower, full perl uses Win32.pm */
4255XS(w32_GetCwd)
4256{
4257 dXSARGS;
4258 /* Make the host for current directory */
4259 char* ptr = PerlEnv_get_childdir();
4260 /*
4261 * If ptr != Nullch
4262 * then it worked, set PV valid,
4263 * else return 'undef'
4264 */
4265 if (ptr) {
4266 SV *sv = sv_newmortal();
4267 sv_setpv(sv, ptr);
4268 PerlEnv_free_childdir(ptr);
4269
4270#ifndef INCOMPLETE_TAINTS
4271 SvTAINTED_on(sv);
4272#endif
4273
4274 ST(0) = sv;
4275 XSRETURN(1);
4276 }
4277 XSRETURN_UNDEF;
4278}
4279#endif
4280
ad2e33dc 4281void
c5be433b 4282Perl_init_os_extras(void)
ad2e33dc 4283{
04a2c3d9 4284 dTHXa(NULL);
ad2e33dc 4285 char *file = __FILE__;
ad2e33dc 4286
9fb265f7 4287 /* Initialize Win32CORE if it has been statically linked. */
a19baa61 4288#ifndef PERL_IS_MINIPERL
9fb265f7 4289 void (*pfn_init)(pTHX);
903f2d70
SH
4290 HMODULE module = (HMODULE)((w32_perldll_handle == INVALID_HANDLE_VALUE)
4291 ? GetModuleHandle(NULL)
4292 : w32_perldll_handle);
4293 pfn_init = (void (*)(pTHX))GetProcAddress(module, "init_Win32CORE");
04a2c3d9 4294 aTHXa(PERL_GET_THX);
9fb265f7
JD
4295 if (pfn_init)
4296 pfn_init(aTHX);
04a2c3d9
DD
4297#else
4298 aTHXa(PERL_GET_THX);
a19baa61 4299#endif
78ff2d7b 4300
02637f4c 4301 newXS("Win32::SetChildShowWindow", w32_SetChildShowWindow, file);
8f1332ed
DD
4302#ifdef PERL_IS_MINIPERL
4303 newXS("Win32::GetCwd", w32_GetCwd, file);
4304#endif
ad2e33dc
GS
4305}
4306
f4958739 4307void *
1018e26f 4308win32_signal_context(void)
c843839f
NIS
4309{
4310 dTHX;
f4958739 4311#ifdef MULTIPLICITY
c843839f 4312 if (!my_perl) {
1018e26f 4313 my_perl = PL_curinterp;
c843839f 4314 PERL_SET_THX(my_perl);
3fadfdf1 4315 }
1018e26f 4316 return my_perl;
f4958739 4317#else
d9a047f6
GS
4318 return PL_curinterp;
4319#endif
1018e26f
NIS
4320}
4321
96116d93 4322
3fadfdf1 4323BOOL WINAPI
1018e26f
NIS
4324win32_ctrlhandler(DWORD dwCtrlType)
4325{
96116d93 4326#ifdef MULTIPLICITY
1018e26f
NIS
4327 dTHXa(PERL_GET_SIG_CONTEXT);
4328
4329 if (!my_perl)
4330 return FALSE;
96116d93 4331#endif
c843839f
NIS
4332
4333 switch(dwCtrlType) {
4334 case CTRL_CLOSE_EVENT:
3fadfdf1
NIS
4335 /* A signal that the system sends to all processes attached to a console when
4336 the user closes the console (either by choosing the Close command from the
4337 console window's System menu, or by choosing the End Task command from the
c843839f
NIS
4338 Task List
4339 */
3fadfdf1
NIS
4340 if (do_raise(aTHX_ 1)) /* SIGHUP */
4341 sig_terminate(aTHX_ 1);
4342 return TRUE;
c843839f
NIS
4343
4344 case CTRL_C_EVENT:
4345 /* A CTRL+c signal was received */
3fadfdf1
NIS
4346 if (do_raise(aTHX_ SIGINT))
4347 sig_terminate(aTHX_ SIGINT);
4348 return TRUE;
c843839f
NIS
4349
4350 case CTRL_BREAK_EVENT:
4351 /* A CTRL+BREAK signal was received */
3fadfdf1
NIS
4352 if (do_raise(aTHX_ SIGBREAK))
4353 sig_terminate(aTHX_ SIGBREAK);
4354 return TRUE;
c843839f
NIS
4355
4356 case CTRL_LOGOFF_EVENT:
3fadfdf1
NIS
4357 /* A signal that the system sends to all console processes when a user is logging
4358 off. This signal does not indicate which user is logging off, so no
4359 assumptions can be made.
c843839f 4360 */
3fadfdf1 4361 break;
c843839f 4362 case CTRL_SHUTDOWN_EVENT:
3fadfdf1
NIS
4363 /* A signal that the system sends to all console processes when the system is
4364 shutting down.
c843839f 4365 */
3fadfdf1
NIS
4366 if (do_raise(aTHX_ SIGTERM))
4367 sig_terminate(aTHX_ SIGTERM);
4368 return TRUE;
c843839f 4369 default:
3fadfdf1 4370 break;
c843839f
NIS
4371 }
4372 return FALSE;
4373}
c843839f
NIS
4374
4375
58d049f0 4376#ifdef SET_INVALID_PARAMETER_HANDLER
0448a0bd
SH
4377# include <crtdbg.h>
4378#endif
4379
dc0472e9
JD
4380static void
4381ansify_path(void)
4382{
dc0472e9
JD
4383 size_t len;
4384 char *ansi_path;
4385 WCHAR *wide_path;
4386 WCHAR *wide_dir;
4387
dc0472e9
JD
4388 /* fetch Unicode version of PATH */
4389 len = 2000;
f76b679e 4390 wide_path = (WCHAR*)win32_malloc(len*sizeof(WCHAR));
dc0472e9
JD
4391 while (wide_path) {
4392 size_t newlen = GetEnvironmentVariableW(L"PATH", wide_path, len);
cfd4abf2
SH
4393 if (newlen == 0) {
4394 win32_free(wide_path);
3fcdbd32 4395 return;
cfd4abf2 4396 }
dc0472e9
JD
4397 if (newlen < len)
4398 break;
4399 len = newlen;
f76b679e 4400 wide_path = (WCHAR*)win32_realloc(wide_path, len*sizeof(WCHAR));
dc0472e9
JD
4401 }
4402 if (!wide_path)
4403 return;
4404
4405 /* convert to ANSI pathnames */
4406 wide_dir = wide_path;
4407 ansi_path = NULL;
4408 while (wide_dir) {
4409 WCHAR *sep = wcschr(wide_dir, ';');
4410 char *ansi_dir;
4411 size_t ansi_len;
4412 size_t wide_len;
4413
4414 if (sep)
4415 *sep++ = '\0';
4416
4417 /* remove quotes around pathname */
4418 if (*wide_dir == '"')
4419 ++wide_dir;
4420 wide_len = wcslen(wide_dir);
4421 if (wide_len && wide_dir[wide_len-1] == '"')
4422 wide_dir[wide_len-1] = '\0';
4423
4424 /* append ansi_dir to ansi_path */
4425 ansi_dir = win32_ansipath(wide_dir);
4426 ansi_len = strlen(ansi_dir);
4427 if (ansi_path) {
4428 size_t newlen = len + 1 + ansi_len;
f76b679e 4429 ansi_path = (char*)win32_realloc(ansi_path, newlen+1);
dc0472e9
JD
4430 if (!ansi_path)
4431 break;
4432 ansi_path[len] = ';';
4433 memcpy(ansi_path+len+1, ansi_dir, ansi_len+1);
4434 len = newlen;
4435 }
4436 else {
4437 len = ansi_len;
f76b679e 4438 ansi_path = (char*)win32_malloc(5+len+1);
dc0472e9
JD
4439 if (!ansi_path)
4440 break;
4441 memcpy(ansi_path, "PATH=", 5);
4442 memcpy(ansi_path+5, ansi_dir, len+1);
4443 len += 5;
4444 }
4445 win32_free(ansi_dir);
4446 wide_dir = sep;
4447 }
4448
4449 if (ansi_path) {
4450 /* Update C RTL environ array. This will only have full effect if
4451 * perl_parse() is later called with `environ` as the `env` argument.
4452 * Otherwise S_init_postdump_symbols() will overwrite PATH again.
4453 *
4454 * We do have to ansify() the PATH before Perl has been fully
4455 * initialized because S_find_script() uses the PATH when perl
4456 * is being invoked with the -S option. This happens before %ENV
4457 * is initialized in S_init_postdump_symbols().
4458 *
4459 * XXX Is this a bug? Should S_find_script() use the environment
4460 * XXX passed in the `env` arg to parse_perl()?
4461 */
4462 putenv(ansi_path);
4463 /* Keep system environment in sync because S_init_postdump_symbols()
4464 * will not call mg_set() if it initializes %ENV from `environ`.
4465 */
4466 SetEnvironmentVariableA("PATH", ansi_path+5);
0c2c57a8 4467 win32_free(ansi_path);
dc0472e9
JD
4468 }
4469 win32_free(wide_path);
4470}
c843839f 4471
3e5d884e
JD
4472void
4473Perl_win32_init(int *argcp, char ***argvp)
4474{
58d049f0 4475#ifdef SET_INVALID_PARAMETER_HANDLER
3e5d884e
JD
4476 _invalid_parameter_handler oldHandler, newHandler;
4477 newHandler = my_invalid_parameter_handler;
4478 oldHandler = _set_invalid_parameter_handler(newHandler);
4479 _CrtSetReportMode(_CRT_ASSERT, 0);
4480#endif
4481 /* Disable floating point errors, Perl will trap the ones we
4482 * care about. VC++ RTL defaults to switching these off
378eeda7 4483 * already, but some RTLs don't. Since we don't
3e5d884e
JD
4484 * want to be at the vendor's whim on the default, we set
4485 * it explicitly here.
4486 */
7ffd6586 4487#if !defined(__GNUC__)
3e5d884e
JD
4488 _control87(MCW_EM, MCW_EM);
4489#endif
4490 MALLOC_INIT;
4491
dbb3120a
SH
4492 /* When the manifest resource requests Common-Controls v6 then
4493 * user32.dll no longer registers all the Windows classes used for
4494 * standard controls but leaves some of them to be registered by
4495 * comctl32.dll. InitCommonControls() doesn't do anything but calling
4496 * it makes sure comctl32.dll gets loaded into the process and registers
4497 * the standard control classes. Without this even normal Windows APIs
4498 * like MessageBox() can fail under some versions of Windows XP.
4499 */
4500 InitCommonControls();
4501
3e5d884e
JD
4502 g_osver.dwOSVersionInfoSize = sizeof(g_osver);
4503 GetVersionEx(&g_osver);
4504
b47a847f
DD
4505#ifdef WIN32_DYN_IOINFO_SIZE
4506 {
4507 Size_t ioinfo_size = _msize((void*)__pioinfo[0]);;
4508 if((SSize_t)ioinfo_size <= 0) { /* -1 is err */
4509 fprintf(stderr, "panic: invalid size for ioinfo\n"); /* no interp */
4510 exit(1);
4511 }
4512 ioinfo_size /= IOINFO_ARRAY_ELTS;
4513 w32_ioinfo_size = ioinfo_size;
4514 }
4515#endif
4516
3e5d884e 4517 ansify_path();
6937817d
DD
4518
4519#ifndef WIN32_NO_REGISTRY
0517ed38
DD
4520 {
4521 LONG retval;
4522 retval = RegOpenKeyExW(HKEY_CURRENT_USER, L"SOFTWARE\\Perl", 0, KEY_READ, &HKCU_Perl_hnd);
4523 if (retval != ERROR_SUCCESS) {
4524 HKCU_Perl_hnd = NULL;
4525 }
4526 retval = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Perl", 0, KEY_READ, &HKLM_Perl_hnd);
4527 if (retval != ERROR_SUCCESS) {
4528 HKLM_Perl_hnd = NULL;
4529 }
4530 }
6937817d 4531#endif
3e5d884e
JD
4532}
4533
4534void
4535Perl_win32_term(void)
4536{
3e5d884e
JD
4537 HINTS_REFCNT_TERM;
4538 OP_REFCNT_TERM;
4539 PERLIO_TERM;
4540 MALLOC_TERM;
929e1213 4541 LOCALE_TERM;
6937817d 4542#ifndef WIN32_NO_REGISTRY
0517ed38
DD
4543 /* handles might be NULL, RegCloseKey then returns ERROR_INVALID_HANDLE
4544 but no point of checking and we can't die() at this point */
4545 RegCloseKey(HKLM_Perl_hnd);
4546 RegCloseKey(HKCU_Perl_hnd);
4547 /* the handles are in an undefined state until the next PERL_SYS_INIT3 */
6937817d 4548#endif
3e5d884e
JD
4549}
4550
4551void
4552win32_get_child_IO(child_IO_table* ptbl)
4553{
4554 ptbl->childStdIn = GetStdHandle(STD_INPUT_HANDLE);
4555 ptbl->childStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
4556 ptbl->childStdErr = GetStdHandle(STD_ERROR_HANDLE);
4557}
4558
4559Sighandler_t
4560win32_signal(int sig, Sighandler_t subcode)
4561{
04a2c3d9 4562 dTHXa(NULL);
3e5d884e
JD
4563 if (sig < SIG_SIZE) {
4564 int save_errno = errno;
d52ca586
SH
4565 Sighandler_t result;
4566#ifdef SET_INVALID_PARAMETER_HANDLER
4567 /* Silence our invalid parameter handler since we expect to make some
4568 * calls with invalid signal numbers giving a SIG_ERR result. */
4569 BOOL oldvalue = set_silent_invalid_parameter_handler(TRUE);
4570#endif
4571 result = signal(sig, subcode);
4572#ifdef SET_INVALID_PARAMETER_HANDLER
4573 set_silent_invalid_parameter_handler(oldvalue);
4574#endif
04a2c3d9 4575 aTHXa(PERL_GET_THX);
3e5d884e
JD
4576 if (result == SIG_ERR) {
4577 result = w32_sighandler[sig];
4578 errno = save_errno;
4579 }
4580 w32_sighandler[sig] = subcode;
4581 return result;
4582 }
4583 else {
4584 errno = EINVAL;
4585 return SIG_ERR;
4586 }
4587}
4588
099b16d3
RM
4589/* The PerlMessageWindowClass's WindowProc */
4590LRESULT CALLBACK
4591win32_message_window_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
4592{
4593 return win32_process_message(hwnd, msg, wParam, lParam) ?
4594 0 : DefWindowProc(hwnd, msg, wParam, lParam);
4595}
4596
099b16d3
RM
4597/* The real message handler. Can be called with
4598 * hwnd == NULL to process our thread messages. Returns TRUE for any messages
4599 * that it processes */
4600static LRESULT
4601win32_process_message(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
4602{
4603 /* BEWARE. The context retrieved using dTHX; is the context of the
4604 * 'parent' thread during the CreateWindow() phase - i.e. for all messages
4605 * up to and including WM_CREATE. If it ever happens that you need the
4606 * 'child' context before this, then it needs to be passed into
4607 * win32_create_message_window(), and passed to the WM_NCCREATE handler
4608 * from the lparam of CreateWindow(). It could then be stored/retrieved
4609 * using [GS]etWindowLongPtr(... GWLP_USERDATA ...), possibly eliminating
4610 * the dTHX calls here. */
4611 /* XXX For now it is assumed that the overhead of the dTHX; for what
4612 * are relativley infrequent code-paths, is better than the added
4613 * complexity of getting the correct context passed into
4614 * win32_create_message_window() */
04a2c3d9 4615 dTHX;
099b16d3
RM
4616
4617 switch(msg) {
4618
4619#ifdef USE_ITHREADS
4620 case WM_USER_MESSAGE: {
04a2c3d9 4621 long child = find_pseudo_pid(aTHX_ (int)wParam);
099b16d3 4622 if (child >= 0) {
099b16d3
RM
4623 w32_pseudo_child_message_hwnds[child] = (HWND)lParam;
4624 return 1;
4625 }
4626 break;
4627 }
4628#endif
4629
4630 case WM_USER_KILL: {
099b16d3
RM
4631 /* We use WM_USER_KILL to fake kill() with other signals */
4632 int sig = (int)wParam;
4633 if (do_raise(aTHX_ sig))
4634 sig_terminate(aTHX_ sig);
4635
4636 return 1;
4637 }
4638
4639 case WM_TIMER: {
099b16d3
RM
4640 /* alarm() is a one-shot but SetTimer() repeats so kill it */
4641 if (w32_timerid && w32_timerid==(UINT)wParam) {
4642 KillTimer(w32_message_hwnd, w32_timerid);
4643 w32_timerid=0;
4644
4645 /* Now fake a call to signal handler */
4646 if (do_raise(aTHX_ 14))
4647 sig_terminate(aTHX_ 14);
4648
4649 return 1;
4650 }
4651 break;
4652 }
4653
4654 default:
4655 break;
4656
4657 } /* switch */
4658
4659 /* Above or other stuff may have set a signal flag, and we may not have
4660 * been called from win32_async_check() (e.g. some other GUI's message
4661 * loop. BUT DON'T dispatch signals here: If someone has set a SIGALRM
4662 * handler that die's, and the message loop that calls here is wrapped
4663 * in an eval, then you may well end up with orphaned windows - signals
4664 * are dispatched by win32_async_check() */
4665
4666 return 0;
4667}
4668
4669void
0934c9d9 4670win32_create_message_window_class(void)
099b16d3
RM
4671{
4672 /* create the window class for "message only" windows */
4673 WNDCLASS wc;
4674
4675 Zero(&wc, 1, wc);
4676 wc.lpfnWndProc = win32_message_window_proc;
4677 wc.hInstance = (HINSTANCE)GetModuleHandle(NULL);
4678 wc.lpszClassName = "PerlMessageWindowClass";
4679
4680 /* second and subsequent calls will fail, but class
4681 * will already be registered */
4682 RegisterClass(&wc);
4683}
4684
aeecf691 4685HWND
0934c9d9 4686win32_create_message_window(void)
aeecf691 4687{
8cbe99e5
JD
4688 win32_create_message_window_class();
4689 return CreateWindow("PerlMessageWindowClass", "PerlMessageWindow",
4690 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
aeecf691
JD
4691}
4692
a33ef3f0
SH
4693#ifdef HAVE_INTERP_INTERN
4694
4695static void
4696win32_csighandler(int sig)
4697{
4698#if 0
4699 dTHXa(PERL_GET_SIG_CONTEXT);
4700 Perl_warn(aTHX_ "Got signal %d",sig);
4701#endif
4702 /* Does nothing */
4703}
4704
edb113cf 4705#if defined(__MINGW32__) && defined(__cplusplus)
beeded0b
YO
4706#define CAST_HWND__(x) (HWND__*)(x)
4707#else
4708#define CAST_HWND__(x) x
4709#endif
4710
7766f137 4711void
52853b95
GS
4712Perl_sys_intern_init(pTHX)
4713{
3fadfdf1 4714 int i;
aeecf691 4715
4e205ed6 4716 w32_perlshell_tokens = NULL;
52853b95
GS
4717 w32_perlshell_vec = (char**)NULL;
4718 w32_perlshell_items = 0;
4719 w32_fdpid = newAV();
a02a5408 4720 Newx(w32_children, 1, child_tab);
52853b95
GS
4721 w32_num_children = 0;
4722# ifdef USE_ITHREADS
4723 w32_pseudo_id = 0;
aeecf691 4724 Newx(w32_pseudo_children, 1, pseudo_child_tab);
52853b95
GS
4725 w32_num_pseudo_children = 0;
4726# endif
222c300a 4727 w32_timerid = 0;
beeded0b 4728 w32_message_hwnd = CAST_HWND__(INVALID_HANDLE_VALUE);
05ec9bb3 4729 w32_poll_count = 0;
8ca2a5d6
DD
4730#ifdef PERL_IS_MINIPERL
4731 w32_sloppystat = TRUE;
4732#else
4733 w32_sloppystat = FALSE;
4734#endif
3fadfdf1
NIS
4735 for (i=0; i < SIG_SIZE; i++) {
4736 w32_sighandler[i] = SIG_DFL;
4737 }
00967642 4738# ifdef MULTIPLICITY
1018e26f 4739 if (my_perl == PL_curinterp) {
96116d93
MB
4740# else
4741 {
4742# endif
3fadfdf1 4743 /* Force C runtime signal stuff to set its console handler */
1c127fab
SH
4744 signal(SIGINT,win32_csighandler);
4745 signal(SIGBREAK,win32_csighandler);
0a311364
JD
4746
4747 /* We spawn asynchronous processes with the CREATE_NEW_PROCESS_GROUP
4748 * flag. This has the side-effect of disabling Ctrl-C events in all
8cbe99e5
JD
4749 * processes in this group.
4750 * We re-enable Ctrl-C handling by calling SetConsoleCtrlHandler()
4751 * with a NULL handler.
0a311364 4752 */
8cbe99e5 4753 SetConsoleCtrlHandler(NULL,FALSE);
0a311364 4754
3fadfdf1 4755 /* Push our handler on top */
c843839f
NIS
4756 SetConsoleCtrlHandler(win32_ctrlhandler,TRUE);
4757 }
52853b95
GS
4758}
4759
3dbbd0f5
GS
4760void
4761Perl_sys_intern_clear(pTHX)
4762{
4763 Safefree(w32_perlshell_tokens);
4764 Safefree(w32_perlshell_vec);
4765 /* NOTE: w32_fdpid is freed by sv_clean_all() */
4766 Safefree(w32_children);
222c300a 4767 if (w32_timerid) {
aeecf691
JD
4768 KillTimer(w32_message_hwnd, w32_timerid);
4769 w32_timerid = 0;
222c300a 4770 }
aeecf691
JD
4771 if (w32_message_hwnd != NULL && w32_message_hwnd != INVALID_HANDLE_VALUE)
4772 DestroyWindow(w32_message_hwnd);
96116d93 4773# ifdef MULTIPLICITY
1018e26f 4774 if (my_perl == PL_curinterp) {
96116d93
MB
4775# else
4776 {
4777# endif
c843839f 4778 SetConsoleCtrlHandler(win32_ctrlhandler,FALSE);
c843839f 4779 }
3dbbd0f5
GS
4780# ifdef USE_ITHREADS
4781 Safefree(w32_pseudo_children);
4782# endif
4783}
4784
52853b95
GS
4785# ifdef USE_ITHREADS
4786
4787void
7766f137
GS
4788Perl_sys_intern_dup(pTHX_ struct interp_intern *src, struct interp_intern *dst)
4789{
7918f24d
NC
4790 PERL_ARGS_ASSERT_SYS_INTERN_DUP;
4791
4e205ed6 4792 dst->perlshell_tokens = NULL;
7766f137
GS
4793 dst->perlshell_vec = (char**)NULL;
4794 dst->perlshell_items = 0;
4795 dst->fdpid = newAV();
a02a5408 4796 Newxz(dst->children, 1, child_tab);
7766f137 4797 dst->pseudo_id = 0;
aeecf691
JD
4798 Newxz(dst->pseudo_children, 1, pseudo_child_tab);
4799 dst->timerid = 0;
beeded0b 4800 dst->message_hwnd = CAST_HWND__(INVALID_HANDLE_VALUE);
aeecf691 4801 dst->poll_count = 0;
8ca2a5d6 4802 dst->sloppystat = src->sloppystat;
3fadfdf1 4803 Copy(src->sigtable,dst->sigtable,SIG_SIZE,Sighandler_t);
7766f137 4804}
52853b95
GS
4805# endif /* USE_ITHREADS */
4806#endif /* HAVE_INTERP_INTERN */