perldoc pod update
[p5sagit/p5-mst-13.2.git] / win32 / win32.c
CommitLineData
68dc0745 1/* WIN32.C
2 *
3 * (c) 1995 Microsoft Corporation. All rights reserved.
4 * Developed by hip communications inc., http://info.hip.com/info/
5 * Portions (c) 1993 Intergraph Corporation. All rights reserved.
6 *
7 * You may distribute under the terms of either the GNU General Public
8 * License or the Artistic License, as specified in the README file.
9 */
0a753a76 10
11#define WIN32_LEAN_AND_MEAN
12#define WIN32IO_IS_STDIO
13#include <tchar.h>
a835ef8a 14#ifdef __GNUC__
15#define Win32_Winsock
16#endif
0a753a76 17#include <windows.h>
18
e56670dd 19#ifndef __MINGW32__
9404a519 20#include <lmcons.h>
21#include <lmerr.h>
22/* ugliness to work around a buggy struct definition in lmwksta.h */
23#undef LPTSTR
24#define LPTSTR LPWSTR
25#include <lmwksta.h>
26#undef LPTSTR
27#define LPTSTR LPSTR
e56670dd 28#include <lmapibuf.h>
29#endif /* __MINGW32__ */
9404a519 30
68dc0745 31/* #include "config.h" */
0a753a76 32
33#define PERLIO_NOT_STDIO 0
34#if !defined(PERLIO_IS_STDIO) && !defined(USE_SFIO)
35#define PerlIO FILE
36#endif
37
38#include "EXTERN.h"
39#include "perl.h"
c69f6586 40
41#define NO_XSLOCKS
42#ifdef PERL_OBJECT
43extern CPerlObj* pPerl;
44#endif
ad2e33dc 45#include "XSUB.h"
c69f6586 46
47#include "Win32iop.h"
0a753a76 48#include <fcntl.h>
49#include <sys/stat.h>
5b0d9cbe 50#ifndef __GNUC__
51/* assert.h conflicts with #define of assert in perl.h */
0a753a76 52#include <assert.h>
5b0d9cbe 53#endif
0a753a76 54#include <string.h>
55#include <stdarg.h>
ad2e33dc 56#include <float.h>
ad0751ec 57#include <time.h>
3730b96e 58#if defined(_MSC_VER) || defined(__MINGW32__)
ad0751ec 59#include <sys/utime.h>
60#else
61#include <utime.h>
62#endif
0a753a76 63
5b0d9cbe 64#ifdef __GNUC__
65/* Mingw32 defaults to globing command line
66 * So we turn it off like this:
67 */
68int _CRT_glob = 0;
69#endif
70
6890e559 71#define EXECF_EXEC 1
72#define EXECF_SPAWN 2
73#define EXECF_SPAWN_NOWAIT 3
74
c69f6586 75#if defined(PERL_OBJECT)
e5a95ffb 76#undef win32_get_privlib
77#define win32_get_privlib g_win32_get_privlib
00dc2f4f 78#undef win32_get_sitelib
79#define win32_get_sitelib g_win32_get_sitelib
c69f6586 80#undef do_aspawn
81#define do_aspawn g_do_aspawn
82#undef do_spawn
83#define do_spawn g_do_spawn
84#undef do_exec
85#define do_exec g_do_exec
c69f6586 86#undef getlogin
87#define getlogin g_getlogin
88#endif
89
2d7a9237 90static DWORD os_id(void);
ce1da67e 91static void get_shell(void);
92static long tokenize(char *str, char **dest, char ***destv);
c69f6586 93 int do_spawn2(char *cmd, int exectype);
2d7a9237 94static BOOL has_redirection(char *ptr);
95static long filetime_to_clock(PFILETIME ft);
ad0751ec 96static BOOL filetime_from_time(PFILETIME ft, time_t t);
e5a95ffb 97static char * get_emd_part(char *leading, char *trailing, ...);
f55ee38a 98static void remove_dead_process(HANDLE deceased);
c69f6586 99
2d7a9237 100HANDLE w32_perldll_handle = INVALID_HANDLE_VALUE;
4b556e6c 101static DWORD w32_platform = (DWORD)-1;
50892819 102
26618a56 103#ifdef USE_THREADS
104# ifdef USE_DECLSPEC_THREAD
105__declspec(thread) char strerror_buffer[512];
e34ffe5a 106__declspec(thread) char getlogin_buffer[128];
4b556e6c 107__declspec(thread) char w32_perllib_root[MAX_PATH+1];
26618a56 108# ifdef HAVE_DES_FCRYPT
109__declspec(thread) char crypt_buffer[30];
110# endif
111# else
112# define strerror_buffer (thr->i.Wstrerror_buffer)
e34ffe5a 113# define getlogin_buffer (thr->i.Wgetlogin_buffer)
4b556e6c 114# define w32_perllib_root (thr->i.Ww32_perllib_root)
26618a56 115# define crypt_buffer (thr->i.Wcrypt_buffer)
116# endif
117#else
4b556e6c 118static char strerror_buffer[512];
119static char getlogin_buffer[128];
120static char w32_perllib_root[MAX_PATH+1];
26618a56 121# ifdef HAVE_DES_FCRYPT
4b556e6c 122static char crypt_buffer[30];
26618a56 123# endif
124#endif
125
3fe9a6f1 126int
127IsWin95(void) {
2d7a9237 128 return (os_id() == VER_PLATFORM_WIN32_WINDOWS);
3fe9a6f1 129}
130
131int
132IsWinNT(void) {
2d7a9237 133 return (os_id() == VER_PLATFORM_WIN32_NT);
3fe9a6f1 134}
0a753a76 135
00dc2f4f 136char*
137GetRegStrFromKey(HKEY hkey, const char *lpszValueName, char** ptr, DWORD* lpDataLen)
138{ /* Retrieve a REG_SZ or REG_EXPAND_SZ from the registry */
139 HKEY handle;
140 DWORD type;
141 const char *subkey = "Software\\Perl";
142 long retval;
143
144 retval = RegOpenKeyEx(hkey, subkey, 0, KEY_READ, &handle);
ba3eb2af 145 if (retval == ERROR_SUCCESS){
00dc2f4f 146 retval = RegQueryValueEx(handle, lpszValueName, 0, &type, NULL, lpDataLen);
ba3eb2af 147 if (retval == ERROR_SUCCESS && type == REG_SZ) {
c934e9d4 148 if (*ptr) {
00dc2f4f 149 Renew(*ptr, *lpDataLen, char);
150 }
151 else {
152 New(1312, *ptr, *lpDataLen, char);
153 }
154 retval = RegQueryValueEx(handle, lpszValueName, 0, NULL, (PBYTE)*ptr, lpDataLen);
ba3eb2af 155 if (retval != ERROR_SUCCESS) {
e5a95ffb 156 Safefree(*ptr);
c934e9d4 157 *ptr = Nullch;
00dc2f4f 158 }
159 }
160 RegCloseKey(handle);
161 }
162 return *ptr;
163}
164
165char*
166GetRegStr(const char *lpszValueName, char** ptr, DWORD* lpDataLen)
167{
168 *ptr = GetRegStrFromKey(HKEY_CURRENT_USER, lpszValueName, ptr, lpDataLen);
c934e9d4 169 if (*ptr == Nullch)
00dc2f4f 170 {
171 *ptr = GetRegStrFromKey(HKEY_LOCAL_MACHINE, lpszValueName, ptr, lpDataLen);
172 }
173 return *ptr;
174}
175
e5a95ffb 176static char *
177get_emd_part(char *prev_path, char *trailing_path, ...)
00dc2f4f 178{
e5a95ffb 179 va_list ap;
e24c7c18 180 char mod_name[MAX_PATH+1];
00dc2f4f 181 char *ptr;
e5a95ffb 182 char *optr;
183 char *strip;
184 int oldsize, newsize;
185
186 va_start(ap, trailing_path);
187 strip = va_arg(ap, char *);
188
123cbbb4 189 GetModuleFileName((w32_perldll_handle == INVALID_HANDLE_VALUE)
190 ? GetModuleHandle(NULL)
191 : w32_perldll_handle, mod_name, sizeof(mod_name));
e5a95ffb 192 ptr = strrchr(mod_name, '\\');
193 while (ptr && strip) {
194 /* look for directories to skip back */
195 optr = ptr;
00dc2f4f 196 *ptr = '\0';
e5a95ffb 197 ptr = strrchr(mod_name, '\\');
198 if (!ptr || stricmp(ptr+1, strip) != 0) {
199 *optr = '\\';
200 ptr = optr;
00dc2f4f 201 }
e5a95ffb 202 strip = va_arg(ap, char *);
00dc2f4f 203 }
e5a95ffb 204 if (!ptr) {
205 ptr = mod_name;
206 *ptr++ = '.';
00dc2f4f 207 *ptr = '\\';
208 }
e5a95ffb 209 va_end(ap);
210 strcpy(++ptr, trailing_path);
211
212 newsize = strlen(mod_name) + 1;
213 if (prev_path) {
214 oldsize = strlen(prev_path) + 1;
215 newsize += oldsize; /* includes plus 1 for ';' */
216 Renew(prev_path, newsize, char);
0019749d 217 prev_path[oldsize-1] = ';';
e5a95ffb 218 strcpy(&prev_path[oldsize], mod_name);
00dc2f4f 219 }
e5a95ffb 220 else {
221 New(1311, prev_path, newsize, char);
222 strcpy(prev_path, mod_name);
00dc2f4f 223 }
00dc2f4f 224
e5a95ffb 225 return prev_path;
00dc2f4f 226}
227
228char *
e5a95ffb 229win32_get_privlib(char *pl)
00dc2f4f 230{
e5a95ffb 231 char *stdlib = "lib";
232 char buffer[MAX_PATH+1];
233 char *path = Nullch;
234 DWORD datalen;
00dc2f4f 235
e5a95ffb 236 /* $stdlib = $HKCU{"lib-$]"} || $HKLM{"lib-$]"} || $HKCU{"lib"} || $HKLM{"lib"} || ""; */
237 sprintf(buffer, "%s-%s", stdlib, pl);
238 path = GetRegStr(buffer, &path, &datalen);
c934e9d4 239 if (!path)
e5a95ffb 240 path = GetRegStr(stdlib, &path, &datalen);
00dc2f4f 241
e5a95ffb 242 /* $stdlib .= ";$EMD/../../lib" */
243 return get_emd_part(path, stdlib, ARCHNAME, "bin", Nullch);
00dc2f4f 244}
245
68dc0745 246char *
00dc2f4f 247win32_get_sitelib(char *pl)
248{
e5a95ffb 249 char *sitelib = "sitelib";
250 char regstr[40];
e24c7c18 251 char pathstr[MAX_PATH+1];
e5a95ffb 252 DWORD datalen;
253 char *path1 = Nullch;
254 char *path2 = Nullch;
255 int len, newsize;
00dc2f4f 256
257 /* $HKCU{"sitelib-$]"} || $HKLM{"sitelib-$]"} . ---; */
e5a95ffb 258 sprintf(regstr, "%s-%s", sitelib, pl);
259 path1 = GetRegStr(regstr, &path1, &datalen);
260
261 /* $sitelib .=
262 * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/site/$]/lib"; */
263 sprintf(pathstr, "site\\%s\\lib", pl);
264 path1 = get_emd_part(path1, pathstr, ARCHNAME, "bin", pl, Nullch);
00dc2f4f 265
266 /* $HKCU{'sitelib'} || $HKLM{'sitelib'} . ---; */
e5a95ffb 267 path2 = GetRegStr(sitelib, &path2, &datalen);
00dc2f4f 268
e5a95ffb 269 /* $sitelib .=
270 * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/site/lib"; */
271 path2 = get_emd_part(path2, "site\\lib", ARCHNAME, "bin", pl, Nullch);
00dc2f4f 272
e5a95ffb 273 if (!path1)
274 return path2;
00dc2f4f 275
e5a95ffb 276 if (!path2)
277 return path1;
278
279 len = strlen(path1);
280 newsize = len + strlen(path2) + 2; /* plus one for ';' */
281
282 Renew(path1, newsize, char);
283 path1[len++] = ';';
284 strcpy(&path1[len], path2);
285
286 Safefree(path2);
287 return path1;
68dc0745 288}
0a753a76 289
b4793f7f 290
2d7a9237 291static BOOL
292has_redirection(char *ptr)
68dc0745 293{
294 int inquote = 0;
295 char quote = '\0';
296
297 /*
298 * Scan string looking for redirection (< or >) or pipe
299 * characters (|) that are not in a quoted string
300 */
9404a519 301 while (*ptr) {
68dc0745 302 switch(*ptr) {
303 case '\'':
304 case '\"':
9404a519 305 if (inquote) {
306 if (quote == *ptr) {
68dc0745 307 inquote = 0;
308 quote = '\0';
0a753a76 309 }
68dc0745 310 }
311 else {
312 quote = *ptr;
313 inquote++;
314 }
315 break;
316 case '>':
317 case '<':
318 case '|':
9404a519 319 if (!inquote)
68dc0745 320 return TRUE;
321 default:
322 break;
0a753a76 323 }
68dc0745 324 ++ptr;
325 }
326 return FALSE;
0a753a76 327}
328
c69f6586 329#if !defined(PERL_OBJECT)
68dc0745 330/* since the current process environment is being updated in util.c
331 * the library functions will get the correct environment
332 */
333PerlIO *
334my_popen(char *cmd, char *mode)
0a753a76 335{
336#ifdef FIXCMD
68dc0745 337#define fixcmd(x) { \
338 char *pspace = strchr((x),' '); \
339 if (pspace) { \
340 char *p = (x); \
341 while (p < pspace) { \
342 if (*p == '/') \
343 *p = '\\'; \
344 p++; \
345 } \
346 } \
347 }
0a753a76 348#else
349#define fixcmd(x)
350#endif
68dc0745 351 fixcmd(cmd);
3e3baf6d 352 win32_fflush(stdout);
353 win32_fflush(stderr);
0a753a76 354 return win32_popen(cmd, mode);
0a753a76 355}
356
68dc0745 357long
358my_pclose(PerlIO *fp)
0a753a76 359{
360 return win32_pclose(fp);
361}
c69f6586 362#endif
0a753a76 363
8b10511d 364static DWORD
2d7a9237 365os_id(void)
0a753a76 366{
8b10511d 367 static OSVERSIONINFO osver;
0a753a76 368
2d7a9237 369 if (osver.dwPlatformId != w32_platform) {
8b10511d 370 memset(&osver, 0, sizeof(OSVERSIONINFO));
371 osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
372 GetVersionEx(&osver);
2d7a9237 373 w32_platform = osver.dwPlatformId;
8b10511d 374 }
2d7a9237 375 return (w32_platform);
0a753a76 376}
377
ce1da67e 378/* Tokenize a string. Words are null-separated, and the list
379 * ends with a doubled null. Any character (except null and
380 * including backslash) may be escaped by preceding it with a
381 * backslash (the backslash will be stripped).
382 * Returns number of words in result buffer.
383 */
384static long
385tokenize(char *str, char **dest, char ***destv)
386{
387 char *retstart = Nullch;
388 char **retvstart = 0;
389 int items = -1;
390 if (str) {
391 int slen = strlen(str);
392 register char *ret;
393 register char **retv;
394 New(1307, ret, slen+2, char);
395 New(1308, retv, (slen+3)/2, char*);
396
397 retstart = ret;
398 retvstart = retv;
399 *retv = ret;
400 items = 0;
401 while (*str) {
402 *ret = *str++;
403 if (*ret == '\\' && *str)
404 *ret = *str++;
405 else if (*ret == ' ') {
406 while (*str == ' ')
407 str++;
408 if (ret == retstart)
409 ret--;
410 else {
411 *ret = '\0';
412 ++items;
413 if (*str)
414 *++retv = ret+1;
415 }
416 }
417 else if (!*str)
418 ++items;
419 ret++;
420 }
421 retvstart[items] = Nullch;
422 *ret++ = '\0';
423 *ret = '\0';
424 }
425 *dest = retstart;
426 *destv = retvstart;
427 return items;
428}
429
430static void
2d7a9237 431get_shell(void)
0a753a76 432{
ce1da67e 433 if (!w32_perlshell_tokens) {
174c211a 434 /* we don't use COMSPEC here for two reasons:
435 * 1. the same reason perl on UNIX doesn't use SHELL--rampant and
436 * uncontrolled unportability of the ensuing scripts.
437 * 2. PERL5SHELL could be set to a shell that may not be fit for
438 * interactive use (which is what most programs look in COMSPEC
439 * for).
440 */
ce1da67e 441 char* defaultshell = (IsWinNT() ? "cmd.exe /x/c" : "command.com /c");
442 char *usershell = getenv("PERL5SHELL");
443 w32_perlshell_items = tokenize(usershell ? usershell : defaultshell,
444 &w32_perlshell_tokens,
445 &w32_perlshell_vec);
68dc0745 446 }
0a753a76 447}
448
68dc0745 449int
2d7a9237 450do_aspawn(void *vreally, void **vmark, void **vsp)
0a753a76 451{
2d7a9237 452 SV *really = (SV*)vreally;
453 SV **mark = (SV**)vmark;
454 SV **sp = (SV**)vsp;
68dc0745 455 char **argv;
2d7a9237 456 char *str;
68dc0745 457 int status;
2d7a9237 458 int flag = P_WAIT;
68dc0745 459 int index = 0;
68dc0745 460
2d7a9237 461 if (sp <= mark)
462 return -1;
68dc0745 463
ce1da67e 464 get_shell();
465 New(1306, argv, (sp - mark) + w32_perlshell_items + 2, char*);
2d7a9237 466
467 if (SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) {
468 ++mark;
469 flag = SvIVx(*mark);
68dc0745 470 }
471
9404a519 472 while (++mark <= sp) {
6b88bc9c 473 if (*mark && (str = SvPV(*mark, PL_na)))
2d7a9237 474 argv[index++] = str;
475 else
476 argv[index++] = "";
68dc0745 477 }
478 argv[index++] = 0;
479
2d7a9237 480 status = win32_spawnvp(flag,
6b88bc9c 481 (const char*)(really ? SvPV(really,PL_na) : argv[0]),
2d7a9237 482 (const char* const*)argv);
483
484 if (status < 0 && errno == ENOEXEC) {
485 /* possible shell-builtin, invoke with shell */
ce1da67e 486 int sh_items;
487 sh_items = w32_perlshell_items;
2d7a9237 488 while (--index >= 0)
489 argv[index+sh_items] = argv[index];
ce1da67e 490 while (--sh_items >= 0)
491 argv[sh_items] = w32_perlshell_vec[sh_items];
2d7a9237 492
493 status = win32_spawnvp(flag,
6b88bc9c 494 (const char*)(really ? SvPV(really,PL_na) : argv[0]),
2d7a9237 495 (const char* const*)argv);
496 }
68dc0745 497
50892819 498 if (flag != P_NOWAIT) {
499 if (status < 0) {
b28d0864 500 if (PL_dowarn)
50892819 501 warn("Can't spawn \"%s\": %s", argv[0], strerror(errno));
502 status = 255 * 256;
503 }
504 else
505 status *= 256;
b28d0864 506 PL_statusvalue = status;
5aabfad6 507 }
ce1da67e 508 Safefree(argv);
50892819 509 return (status);
68dc0745 510}
511
c69f6586 512int
6890e559 513do_spawn2(char *cmd, int exectype)
68dc0745 514{
515 char **a;
516 char *s;
517 char **argv;
518 int status = -1;
519 BOOL needToTry = TRUE;
2d7a9237 520 char *cmd2;
68dc0745 521
2d7a9237 522 /* Save an extra exec if possible. See if there are shell
523 * metacharacters in it */
9404a519 524 if (!has_redirection(cmd)) {
fc36a67e 525 New(1301,argv, strlen(cmd) / 2 + 2, char*);
526 New(1302,cmd2, strlen(cmd) + 1, char);
68dc0745 527 strcpy(cmd2, cmd);
528 a = argv;
529 for (s = cmd2; *s;) {
530 while (*s && isspace(*s))
531 s++;
532 if (*s)
533 *(a++) = s;
9404a519 534 while (*s && !isspace(*s))
68dc0745 535 s++;
9404a519 536 if (*s)
68dc0745 537 *s++ = '\0';
0a753a76 538 }
68dc0745 539 *a = Nullch;
ce1da67e 540 if (argv[0]) {
6890e559 541 switch (exectype) {
542 case EXECF_SPAWN:
543 status = win32_spawnvp(P_WAIT, argv[0],
544 (const char* const*)argv);
545 break;
546 case EXECF_SPAWN_NOWAIT:
547 status = win32_spawnvp(P_NOWAIT, argv[0],
548 (const char* const*)argv);
549 break;
550 case EXECF_EXEC:
551 status = win32_execvp(argv[0], (const char* const*)argv);
552 break;
553 }
2d7a9237 554 if (status != -1 || errno == 0)
68dc0745 555 needToTry = FALSE;
0a753a76 556 }
0a753a76 557 Safefree(argv);
68dc0745 558 Safefree(cmd2);
559 }
2d7a9237 560 if (needToTry) {
ce1da67e 561 char **argv;
562 int i = -1;
563 get_shell();
564 New(1306, argv, w32_perlshell_items + 2, char*);
565 while (++i < w32_perlshell_items)
566 argv[i] = w32_perlshell_vec[i];
2d7a9237 567 argv[i++] = cmd;
568 argv[i] = Nullch;
6890e559 569 switch (exectype) {
570 case EXECF_SPAWN:
571 status = win32_spawnvp(P_WAIT, argv[0],
572 (const char* const*)argv);
573 break;
574 case EXECF_SPAWN_NOWAIT:
575 status = win32_spawnvp(P_NOWAIT, argv[0],
576 (const char* const*)argv);
577 break;
578 case EXECF_EXEC:
579 status = win32_execvp(argv[0], (const char* const*)argv);
580 break;
581 }
ce1da67e 582 cmd = argv[0];
583 Safefree(argv);
68dc0745 584 }
50892819 585 if (exectype != EXECF_SPAWN_NOWAIT) {
586 if (status < 0) {
b28d0864 587 if (PL_dowarn)
50892819 588 warn("Can't %s \"%s\": %s",
589 (exectype == EXECF_EXEC ? "exec" : "spawn"),
590 cmd, strerror(errno));
591 status = 255 * 256;
592 }
593 else
594 status *= 256;
b28d0864 595 PL_statusvalue = status;
5aabfad6 596 }
50892819 597 return (status);
0a753a76 598}
599
6890e559 600int
601do_spawn(char *cmd)
602{
603 return do_spawn2(cmd, EXECF_SPAWN);
604}
605
2d7a9237 606int
607do_spawn_nowait(char *cmd)
608{
609 return do_spawn2(cmd, EXECF_SPAWN_NOWAIT);
610}
611
6890e559 612bool
613do_exec(char *cmd)
614{
615 do_spawn2(cmd, EXECF_EXEC);
616 return FALSE;
617}
618
68dc0745 619/* The idea here is to read all the directory names into a string table
620 * (separated by nulls) and when one of the other dir functions is called
621 * return the pointer to the current file name.
622 */
623DIR *
ce2e26e5 624win32_opendir(char *filename)
0a753a76 625{
9404a519 626 DIR *p;
627 long len;
628 long idx;
629 char scanname[MAX_PATH+3];
630 struct stat sbuf;
631 WIN32_FIND_DATA FindData;
632 HANDLE fh;
633
634 len = strlen(filename);
635 if (len > MAX_PATH)
636 return NULL;
68dc0745 637
638 /* check to see if filename is a directory */
69d3ab13 639 if (win32_stat(filename, &sbuf) < 0 || !S_ISDIR(sbuf.st_mode))
24caa93f 640 return NULL;
68dc0745 641
68dc0745 642 /* Get us a DIR structure */
fc36a67e 643 Newz(1303, p, 1, DIR);
9404a519 644 if (p == NULL)
68dc0745 645 return NULL;
646
647 /* Create the search pattern */
648 strcpy(scanname, filename);
9404a519 649 if (scanname[len-1] != '/' && scanname[len-1] != '\\')
650 scanname[len++] = '/';
651 scanname[len++] = '*';
652 scanname[len] = '\0';
68dc0745 653
654 /* do the FindFirstFile call */
655 fh = FindFirstFile(scanname, &FindData);
9404a519 656 if (fh == INVALID_HANDLE_VALUE) {
68dc0745 657 return NULL;
658 }
659
660 /* now allocate the first part of the string table for
661 * the filenames that we find.
662 */
663 idx = strlen(FindData.cFileName)+1;
fc36a67e 664 New(1304, p->start, idx, char);
9404a519 665 if (p->start == NULL)
65e48ea9 666 croak("opendir: malloc failed!\n");
68dc0745 667 strcpy(p->start, FindData.cFileName);
68dc0745 668 p->nfiles++;
669
670 /* loop finding all the files that match the wildcard
671 * (which should be all of them in this directory!).
672 * the variable idx should point one past the null terminator
673 * of the previous string found.
674 */
675 while (FindNextFile(fh, &FindData)) {
676 len = strlen(FindData.cFileName);
677 /* bump the string table size by enough for the
678 * new name and it's null terminator
679 */
680 Renew(p->start, idx+len+1, char);
9404a519 681 if (p->start == NULL)
65e48ea9 682 croak("opendir: malloc failed!\n");
68dc0745 683 strcpy(&p->start[idx], FindData.cFileName);
9404a519 684 p->nfiles++;
685 idx += len+1;
686 }
687 FindClose(fh);
688 p->size = idx;
689 p->curr = p->start;
690 return p;
0a753a76 691}
692
693
68dc0745 694/* Readdir just returns the current string pointer and bumps the
695 * string pointer to the nDllExport entry.
696 */
697struct direct *
ce2e26e5 698win32_readdir(DIR *dirp)
0a753a76 699{
68dc0745 700 int len;
701 static int dummy = 0;
0a753a76 702
68dc0745 703 if (dirp->curr) {
704 /* first set up the structure to return */
705 len = strlen(dirp->curr);
706 strcpy(dirp->dirstr.d_name, dirp->curr);
707 dirp->dirstr.d_namlen = len;
0a753a76 708
68dc0745 709 /* Fake an inode */
710 dirp->dirstr.d_ino = dummy++;
0a753a76 711
68dc0745 712 /* Now set up for the nDllExport call to readdir */
713 dirp->curr += len + 1;
714 if (dirp->curr >= (dirp->start + dirp->size)) {
715 dirp->curr = NULL;
716 }
0a753a76 717
68dc0745 718 return &(dirp->dirstr);
719 }
720 else
721 return NULL;
0a753a76 722}
723
68dc0745 724/* Telldir returns the current string pointer position */
725long
ce2e26e5 726win32_telldir(DIR *dirp)
0a753a76 727{
728 return (long) dirp->curr;
729}
730
731
68dc0745 732/* Seekdir moves the string pointer to a previously saved position
733 *(Saved by telldir).
734 */
735void
ce2e26e5 736win32_seekdir(DIR *dirp, long loc)
0a753a76 737{
738 dirp->curr = (char *)loc;
739}
740
68dc0745 741/* Rewinddir resets the string pointer to the start */
742void
ce2e26e5 743win32_rewinddir(DIR *dirp)
0a753a76 744{
745 dirp->curr = dirp->start;
746}
747
68dc0745 748/* free the memory allocated by opendir */
749int
ce2e26e5 750win32_closedir(DIR *dirp)
0a753a76 751{
752 Safefree(dirp->start);
753 Safefree(dirp);
68dc0745 754 return 1;
0a753a76 755}
756
757
68dc0745 758/*
759 * various stubs
760 */
0a753a76 761
762
68dc0745 763/* Ownership
764 *
765 * Just pretend that everyone is a superuser. NT will let us know if
766 * we don\'t really have permission to do something.
767 */
0a753a76 768
769#define ROOT_UID ((uid_t)0)
770#define ROOT_GID ((gid_t)0)
771
68dc0745 772uid_t
773getuid(void)
0a753a76 774{
68dc0745 775 return ROOT_UID;
0a753a76 776}
777
68dc0745 778uid_t
779geteuid(void)
0a753a76 780{
68dc0745 781 return ROOT_UID;
0a753a76 782}
783
68dc0745 784gid_t
785getgid(void)
0a753a76 786{
68dc0745 787 return ROOT_GID;
0a753a76 788}
789
68dc0745 790gid_t
791getegid(void)
0a753a76 792{
68dc0745 793 return ROOT_GID;
0a753a76 794}
795
68dc0745 796int
22239a37 797setuid(uid_t auid)
0a753a76 798{
22239a37 799 return (auid == ROOT_UID ? 0 : -1);
0a753a76 800}
801
68dc0745 802int
22239a37 803setgid(gid_t agid)
0a753a76 804{
22239a37 805 return (agid == ROOT_GID ? 0 : -1);
0a753a76 806}
807
e34ffe5a 808char *
809getlogin(void)
810{
811 dTHR;
812 char *buf = getlogin_buffer;
813 DWORD size = sizeof(getlogin_buffer);
814 if (GetUserName(buf,&size))
815 return buf;
816 return (char*)NULL;
817}
818
b990f8c8 819int
820chown(const char *path, uid_t owner, gid_t group)
821{
822 /* XXX noop */
1c1c7f20 823 return 0;
b990f8c8 824}
825
f55ee38a 826static void
827remove_dead_process(HANDLE deceased)
0a753a76 828{
f55ee38a 829#ifndef USE_RTL_WAIT
830 int child;
831 for (child = 0 ; child < w32_num_children ; ++child) {
832 if (w32_child_pids[child] == deceased) {
833 Copy(&w32_child_pids[child+1], &w32_child_pids[child],
834 (w32_num_children-child-1), HANDLE);
835 w32_num_children--;
836 break;
837 }
838 }
839#endif
840}
841
842DllExport int
843win32_kill(int pid, int sig)
844{
845#ifdef USE_RTL_WAIT
68dc0745 846 HANDLE hProcess= OpenProcess(PROCESS_ALL_ACCESS, TRUE, pid);
f55ee38a 847#else
848 HANDLE hProcess = (HANDLE) pid;
849#endif
0a753a76 850
851 if (hProcess == NULL) {
65e48ea9 852 croak("kill process failed!\n");
68dc0745 853 }
854 else {
855 if (!TerminateProcess(hProcess, sig))
65e48ea9 856 croak("kill process failed!\n");
68dc0745 857 CloseHandle(hProcess);
f55ee38a 858
859 /* WaitForMultipleObjects() on a pid that was killed returns error
860 * so if we know the pid is gone we remove it from process list */
861 remove_dead_process(hProcess);
68dc0745 862 }
863 return 0;
0a753a76 864}
fbbbcc48 865
68dc0745 866/*
867 * File system stuff
868 */
0a753a76 869
f3986ebb 870DllExport unsigned int
871win32_sleep(unsigned int t)
0a753a76 872{
68dc0745 873 Sleep(t*1000);
874 return 0;
0a753a76 875}
876
68dc0745 877DllExport int
878win32_stat(const char *path, struct stat *buffer)
0a753a76 879{
24caa93f 880 char t[MAX_PATH+1];
68dc0745 881 const char *p = path;
882 int l = strlen(path);
67fbe06e 883 int res;
0a753a76 884
68dc0745 885 if (l > 1) {
886 switch(path[l - 1]) {
887 case '\\':
888 case '/':
889 if (path[l - 2] != ':') {
890 strncpy(t, path, l - 1);
891 t[l - 1] = 0;
892 p = t;
893 };
894 }
895 }
390b85e7 896 res = stat(p,buffer);
24caa93f 897 if (res < 0) {
898 /* CRT is buggy on sharenames, so make sure it really isn't.
899 * XXX using GetFileAttributesEx() will enable us to set
900 * buffer->st_*time (but note that's not available on the
901 * Windows of 1995) */
902 DWORD r = GetFileAttributes(p);
903 if (r != 0xffffffff && (r & FILE_ATTRIBUTE_DIRECTORY)) {
904 buffer->st_mode |= S_IFDIR | S_IREAD;
905 errno = 0;
906 if (!(r & FILE_ATTRIBUTE_READONLY))
907 buffer->st_mode |= S_IWRITE | S_IEXEC;
908 return 0;
909 }
910 }
67fbe06e 911#ifdef __BORLANDC__
24caa93f 912 else {
67fbe06e 913 if (S_ISDIR(buffer->st_mode))
914 buffer->st_mode |= S_IWRITE | S_IEXEC;
915 else if (S_ISREG(buffer->st_mode)) {
916 if (l >= 4 && path[l-4] == '.') {
917 const char *e = path + l - 3;
918 if (strnicmp(e,"exe",3)
919 && strnicmp(e,"bat",3)
920 && strnicmp(e,"com",3)
921 && (IsWin95() || strnicmp(e,"cmd",3)))
922 buffer->st_mode &= ~S_IEXEC;
923 else
924 buffer->st_mode |= S_IEXEC;
925 }
926 else
927 buffer->st_mode &= ~S_IEXEC;
928 }
929 }
930#endif
931 return res;
0a753a76 932}
933
0551aaa8 934#ifndef USE_WIN32_RTL_ENV
935
936DllExport char *
937win32_getenv(const char *name)
938{
c934e9d4 939 static char *curitem = Nullch; /* XXX threadead */
46124e9e 940 static DWORD curlen = 0; /* XXX threadead */
0551aaa8 941 DWORD needlen;
46124e9e 942 if (!curitem) {
943 curlen = 512;
0551aaa8 944 New(1305,curitem,curlen,char);
46124e9e 945 }
58a50f62 946
947 needlen = GetEnvironmentVariable(name,curitem,curlen);
948 if (needlen != 0) {
949 while (needlen > curlen) {
950 Renew(curitem,needlen,char);
951 curlen = needlen;
952 needlen = GetEnvironmentVariable(name,curitem,curlen);
953 }
0551aaa8 954 }
c934e9d4 955 else {
7a5f8e82 956 /* allow any environment variables that begin with 'PERL'
c934e9d4 957 to be stored in the registry */
958 if (curitem)
58a50f62 959 *curitem = '\0';
960
7a5f8e82 961 if (strncmp(name, "PERL", 4) == 0) {
c934e9d4 962 if (curitem) {
58a50f62 963 Safefree(curitem);
c934e9d4 964 curitem = Nullch;
46124e9e 965 curlen = 0;
58a50f62 966 }
00dc2f4f 967 curitem = GetRegStr(name, &curitem, &curlen);
58a50f62 968 }
c69f6586 969 }
c934e9d4 970 if (curitem && *curitem == '\0')
58a50f62 971 return Nullch;
972
0551aaa8 973 return curitem;
974}
975
976#endif
977
d55594ae 978static long
2d7a9237 979filetime_to_clock(PFILETIME ft)
d55594ae 980{
981 __int64 qw = ft->dwHighDateTime;
982 qw <<= 32;
983 qw |= ft->dwLowDateTime;
984 qw /= 10000; /* File time ticks at 0.1uS, clock at 1mS */
985 return (long) qw;
986}
987
f3986ebb 988DllExport int
989win32_times(struct tms *timebuf)
0a753a76 990{
d55594ae 991 FILETIME user;
992 FILETIME kernel;
993 FILETIME dummy;
994 if (GetProcessTimes(GetCurrentProcess(), &dummy, &dummy,
995 &kernel,&user)) {
2d7a9237 996 timebuf->tms_utime = filetime_to_clock(&user);
997 timebuf->tms_stime = filetime_to_clock(&kernel);
d55594ae 998 timebuf->tms_cutime = 0;
999 timebuf->tms_cstime = 0;
1000
1001 } else {
1002 /* That failed - e.g. Win95 fallback to clock() */
1003 clock_t t = clock();
1004 timebuf->tms_utime = t;
1005 timebuf->tms_stime = 0;
1006 timebuf->tms_cutime = 0;
1007 timebuf->tms_cstime = 0;
1008 }
68dc0745 1009 return 0;
0a753a76 1010}
1011
ad0751ec 1012/* fix utime() so it works on directories in NT
1013 * thanks to Jan Dubois <jan.dubois@ibm.net>
1014 */
1015static BOOL
1016filetime_from_time(PFILETIME pFileTime, time_t Time)
1017{
1018 struct tm *pTM = gmtime(&Time);
1019 SYSTEMTIME SystemTime;
1020
1021 if (pTM == NULL)
1022 return FALSE;
1023
1024 SystemTime.wYear = pTM->tm_year + 1900;
1025 SystemTime.wMonth = pTM->tm_mon + 1;
1026 SystemTime.wDay = pTM->tm_mday;
1027 SystemTime.wHour = pTM->tm_hour;
1028 SystemTime.wMinute = pTM->tm_min;
1029 SystemTime.wSecond = pTM->tm_sec;
1030 SystemTime.wMilliseconds = 0;
1031
1032 return SystemTimeToFileTime(&SystemTime, pFileTime);
1033}
1034
1035DllExport int
3b405fc5 1036win32_utime(const char *filename, struct utimbuf *times)
ad0751ec 1037{
1038 HANDLE handle;
1039 FILETIME ftCreate;
1040 FILETIME ftAccess;
1041 FILETIME ftWrite;
1042 struct utimbuf TimeBuffer;
1043
1044 int rc = utime(filename,times);
1045 /* EACCES: path specifies directory or readonly file */
1046 if (rc == 0 || errno != EACCES /* || !IsWinNT() */)
1047 return rc;
1048
1049 if (times == NULL) {
1050 times = &TimeBuffer;
1051 time(&times->actime);
1052 times->modtime = times->actime;
1053 }
1054
1055 /* This will (and should) still fail on readonly files */
1056 handle = CreateFile(filename, GENERIC_READ | GENERIC_WRITE,
1057 FILE_SHARE_READ | FILE_SHARE_DELETE, NULL,
1058 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
1059 if (handle == INVALID_HANDLE_VALUE)
1060 return rc;
1061
1062 if (GetFileTime(handle, &ftCreate, &ftAccess, &ftWrite) &&
1063 filetime_from_time(&ftAccess, times->actime) &&
1064 filetime_from_time(&ftWrite, times->modtime) &&
1065 SetFileTime(handle, &ftCreate, &ftAccess, &ftWrite))
1066 {
1067 rc = 0;
1068 }
1069
1070 CloseHandle(handle);
1071 return rc;
1072}
1073
2d7a9237 1074DllExport int
f55ee38a 1075win32_waitpid(int pid, int *status, int flags)
1076{
1077 int rc;
1078 if (pid == -1)
1079 return win32_wait(status);
1080 else {
1081 rc = cwait(status, pid, WAIT_CHILD);
1082 /* cwait() returns differently on Borland */
1083#ifdef __BORLANDC__
1084 if (status)
1085 *status = (((*status >> 8) & 0xff) | ((*status << 8) & 0xff00));
1086#endif
1087 remove_dead_process((HANDLE)pid);
1088 }
1089 return rc >= 0 ? pid : rc;
1090}
1091
1092DllExport int
2d7a9237 1093win32_wait(int *status)
1094{
4b556e6c 1095#ifdef USE_RTL_WAIT
2d7a9237 1096 return wait(status);
1097#else
1098 /* XXX this wait emulation only knows about processes
1099 * spawned via win32_spawnvp(P_NOWAIT, ...).
1100 */
1101 int i, retval;
1102 DWORD exitcode, waitcode;
1103
1104 if (!w32_num_children) {
1105 errno = ECHILD;
1106 return -1;
1107 }
1108
1109 /* if a child exists, wait for it to die */
1110 waitcode = WaitForMultipleObjects(w32_num_children,
1111 w32_child_pids,
1112 FALSE,
1113 INFINITE);
1114 if (waitcode != WAIT_FAILED) {
1115 if (waitcode >= WAIT_ABANDONED_0
1116 && waitcode < WAIT_ABANDONED_0 + w32_num_children)
1117 i = waitcode - WAIT_ABANDONED_0;
1118 else
1119 i = waitcode - WAIT_OBJECT_0;
1120 if (GetExitCodeProcess(w32_child_pids[i], &exitcode) ) {
1121 CloseHandle(w32_child_pids[i]);
1122 *status = (int)((exitcode & 0xff) << 8);
1123 retval = (int)w32_child_pids[i];
1124 Copy(&w32_child_pids[i+1], &w32_child_pids[i],
1125 (w32_num_children-i-1), HANDLE);
1126 w32_num_children--;
1127 return retval;
1128 }
1129 }
1130
1131FAILED:
1132 errno = GetLastError();
1133 return -1;
1134
1135#endif
1136}
d55594ae 1137
2d7a9237 1138static UINT timerid = 0;
d55594ae 1139
1140static VOID CALLBACK TimerProc(HWND win, UINT msg, UINT id, DWORD time)
1141{
1142 KillTimer(NULL,timerid);
1143 timerid=0;
1144 sighandler(14);
1145}
1146
f3986ebb 1147DllExport unsigned int
1148win32_alarm(unsigned int sec)
0a753a76 1149{
d55594ae 1150 /*
1151 * the 'obvious' implentation is SetTimer() with a callback
1152 * which does whatever receiving SIGALRM would do
1153 * we cannot use SIGALRM even via raise() as it is not
1154 * one of the supported codes in <signal.h>
1155 *
1156 * Snag is unless something is looking at the message queue
1157 * nothing happens :-(
1158 */
1159 if (sec)
1160 {
1161 timerid = SetTimer(NULL,timerid,sec*1000,(TIMERPROC)TimerProc);
1162 if (!timerid)
1163 croak("Cannot set timer");
1164 }
1165 else
1166 {
1167 if (timerid)
1168 {
1169 KillTimer(NULL,timerid);
1170 timerid=0;
1171 }
1172 }
68dc0745 1173 return 0;
0a753a76 1174}
1175
ff95b63e 1176#if defined(HAVE_DES_FCRYPT) || defined(PERL_OBJECT)
26618a56 1177#ifdef HAVE_DES_FCRYPT
2d77217b 1178extern char * des_fcrypt(const char *txt, const char *salt, char *cbuf);
ff95b63e 1179#endif
26618a56 1180
1181DllExport char *
1182win32_crypt(const char *txt, const char *salt)
1183{
ff95b63e 1184#ifdef HAVE_DES_FCRYPT
26618a56 1185 dTHR;
2d77217b 1186 return des_fcrypt(txt, salt, crypt_buffer);
ff95b63e 1187#else
1188 die("The crypt() function is unimplemented due to excessive paranoia.");
b8957cf1 1189 return Nullch;
ff95b63e 1190#endif
26618a56 1191}
1192#endif
1193
f3986ebb 1194#ifdef USE_FIXED_OSFHANDLE
390b85e7 1195
1196EXTERN_C int __cdecl _alloc_osfhnd(void);
1197EXTERN_C int __cdecl _set_osfhnd(int fh, long value);
1198EXTERN_C void __cdecl _lock_fhandle(int);
1199EXTERN_C void __cdecl _unlock_fhandle(int);
1200EXTERN_C void __cdecl _unlock(int);
1201
1202#if (_MSC_VER >= 1000)
1203typedef struct {
1204 long osfhnd; /* underlying OS file HANDLE */
1205 char osfile; /* attributes of file (e.g., open in text mode?) */
1206 char pipech; /* one char buffer for handles opened on pipes */
1207#if defined (_MT) && !defined (DLL_FOR_WIN32S)
1208 int lockinitflag;
1209 CRITICAL_SECTION lock;
1210#endif /* defined (_MT) && !defined (DLL_FOR_WIN32S) */
1211} ioinfo;
1212
1213EXTERN_C ioinfo * __pioinfo[];
1214
1215#define IOINFO_L2E 5
1216#define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E)
1217#define _pioinfo(i) (__pioinfo[i >> IOINFO_L2E] + (i & (IOINFO_ARRAY_ELTS - 1)))
1218#define _osfile(i) (_pioinfo(i)->osfile)
1219
1220#else /* (_MSC_VER >= 1000) */
1221extern char _osfile[];
1222#endif /* (_MSC_VER >= 1000) */
1223
1224#define FOPEN 0x01 /* file handle open */
1225#define FAPPEND 0x20 /* file handle opened O_APPEND */
1226#define FDEV 0x40 /* file handle refers to device */
1227#define FTEXT 0x80 /* file handle is in text mode */
1228
1229#define _STREAM_LOCKS 26 /* Table of stream locks */
1230#define _LAST_STREAM_LOCK (_STREAM_LOCKS+_NSTREAM_-1) /* Last stream lock */
1231#define _FH_LOCKS (_LAST_STREAM_LOCK+1) /* Table of fh locks */
1232
1233/***
1234*int my_open_osfhandle(long osfhandle, int flags) - open C Runtime file handle
1235*
1236*Purpose:
1237* This function allocates a free C Runtime file handle and associates
1238* it with the Win32 HANDLE specified by the first parameter. This is a
1239* temperary fix for WIN95's brain damage GetFileType() error on socket
1240* we just bypass that call for socket
1241*
1242*Entry:
1243* long osfhandle - Win32 HANDLE to associate with C Runtime file handle.
1244* int flags - flags to associate with C Runtime file handle.
1245*
1246*Exit:
1247* returns index of entry in fh, if successful
1248* return -1, if no free entry is found
1249*
1250*Exceptions:
1251*
1252*******************************************************************************/
1253
1254static int
1255my_open_osfhandle(long osfhandle, int flags)
1256{
1257 int fh;
1258 char fileflags; /* _osfile flags */
1259
1260 /* copy relevant flags from second parameter */
1261 fileflags = FDEV;
1262
9404a519 1263 if (flags & O_APPEND)
390b85e7 1264 fileflags |= FAPPEND;
1265
9404a519 1266 if (flags & O_TEXT)
390b85e7 1267 fileflags |= FTEXT;
1268
1269 /* attempt to allocate a C Runtime file handle */
9404a519 1270 if ((fh = _alloc_osfhnd()) == -1) {
390b85e7 1271 errno = EMFILE; /* too many open files */
1272 _doserrno = 0L; /* not an OS error */
1273 return -1; /* return error to caller */
1274 }
1275
1276 /* the file is open. now, set the info in _osfhnd array */
1277 _set_osfhnd(fh, osfhandle);
1278
1279 fileflags |= FOPEN; /* mark as open */
1280
1281#if (_MSC_VER >= 1000)
1282 _osfile(fh) = fileflags; /* set osfile entry */
1283 _unlock_fhandle(fh);
1284#else
1285 _osfile[fh] = fileflags; /* set osfile entry */
1286 _unlock(fh+_FH_LOCKS); /* unlock handle */
1287#endif
1288
1289 return fh; /* return handle */
1290}
1291
1292#define _open_osfhandle my_open_osfhandle
f3986ebb 1293#endif /* USE_FIXED_OSFHANDLE */
390b85e7 1294
1295/* simulate flock by locking a range on the file */
1296
1297#define LK_ERR(f,i) ((f) ? (i = 0) : (errno = GetLastError()))
1298#define LK_LEN 0xffff0000
1299
f3986ebb 1300DllExport int
1301win32_flock(int fd, int oper)
390b85e7 1302{
1303 OVERLAPPED o;
1304 int i = -1;
1305 HANDLE fh;
1306
f3986ebb 1307 if (!IsWinNT()) {
1308 croak("flock() unimplemented on this platform");
1309 return -1;
1310 }
390b85e7 1311 fh = (HANDLE)_get_osfhandle(fd);
1312 memset(&o, 0, sizeof(o));
1313
1314 switch(oper) {
1315 case LOCK_SH: /* shared lock */
1316 LK_ERR(LockFileEx(fh, 0, 0, LK_LEN, 0, &o),i);
1317 break;
1318 case LOCK_EX: /* exclusive lock */
1319 LK_ERR(LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, LK_LEN, 0, &o),i);
1320 break;
1321 case LOCK_SH|LOCK_NB: /* non-blocking shared lock */
1322 LK_ERR(LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY, 0, LK_LEN, 0, &o),i);
1323 break;
1324 case LOCK_EX|LOCK_NB: /* non-blocking exclusive lock */
1325 LK_ERR(LockFileEx(fh,
1326 LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY,
1327 0, LK_LEN, 0, &o),i);
1328 break;
1329 case LOCK_UN: /* unlock lock */
1330 LK_ERR(UnlockFileEx(fh, 0, LK_LEN, 0, &o),i);
1331 break;
1332 default: /* unknown */
1333 errno = EINVAL;
1334 break;
1335 }
1336 return i;
1337}
1338
1339#undef LK_ERR
1340#undef LK_LEN
1341
68dc0745 1342/*
1343 * redirected io subsystem for all XS modules
1344 *
1345 */
0a753a76 1346
68dc0745 1347DllExport int *
1348win32_errno(void)
0a753a76 1349{
390b85e7 1350 return (&errno);
0a753a76 1351}
1352
dcb2879a 1353DllExport char ***
1354win32_environ(void)
1355{
390b85e7 1356 return (&(_environ));
dcb2879a 1357}
1358
68dc0745 1359/* the rest are the remapped stdio routines */
1360DllExport FILE *
1361win32_stderr(void)
0a753a76 1362{
390b85e7 1363 return (stderr);
0a753a76 1364}
1365
68dc0745 1366DllExport FILE *
1367win32_stdin(void)
0a753a76 1368{
390b85e7 1369 return (stdin);
0a753a76 1370}
1371
68dc0745 1372DllExport FILE *
1373win32_stdout()
0a753a76 1374{
390b85e7 1375 return (stdout);
0a753a76 1376}
1377
68dc0745 1378DllExport int
1379win32_ferror(FILE *fp)
0a753a76 1380{
390b85e7 1381 return (ferror(fp));
0a753a76 1382}
1383
1384
68dc0745 1385DllExport int
1386win32_feof(FILE *fp)
0a753a76 1387{
390b85e7 1388 return (feof(fp));
0a753a76 1389}
1390
68dc0745 1391/*
1392 * Since the errors returned by the socket error function
1393 * WSAGetLastError() are not known by the library routine strerror
1394 * we have to roll our own.
1395 */
0a753a76 1396
68dc0745 1397DllExport char *
1398win32_strerror(int e)
0a753a76 1399{
3e3baf6d 1400#ifndef __BORLANDC__ /* Borland intolerance */
68dc0745 1401 extern int sys_nerr;
3e3baf6d 1402#endif
68dc0745 1403 DWORD source = 0;
0a753a76 1404
9404a519 1405 if (e < 0 || e > sys_nerr) {
c53bd28a 1406 dTHR;
9404a519 1407 if (e < 0)
68dc0745 1408 e = GetLastError();
0a753a76 1409
9404a519 1410 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, &source, e, 0,
68dc0745 1411 strerror_buffer, sizeof(strerror_buffer), NULL) == 0)
1412 strcpy(strerror_buffer, "Unknown Error");
0a753a76 1413
68dc0745 1414 return strerror_buffer;
1415 }
390b85e7 1416 return strerror(e);
0a753a76 1417}
1418
22fae026 1419DllExport void
3730b96e 1420win32_str_os_error(void *sv, DWORD dwErr)
22fae026 1421{
1422 DWORD dwLen;
1423 char *sMsg;
1424 dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
1425 |FORMAT_MESSAGE_IGNORE_INSERTS
1426 |FORMAT_MESSAGE_FROM_SYSTEM, NULL,
1427 dwErr, 0, (char *)&sMsg, 1, NULL);
1428 if (0 < dwLen) {
1429 while (0 < dwLen && isspace(sMsg[--dwLen]))
1430 ;
1431 if ('.' != sMsg[dwLen])
1432 dwLen++;
1433 sMsg[dwLen]= '\0';
1434 }
1435 if (0 == dwLen) {
c69f6586 1436 sMsg = (char*)LocalAlloc(0, 64/**sizeof(TCHAR)*/);
22fae026 1437 dwLen = sprintf(sMsg,
1438 "Unknown error #0x%lX (lookup 0x%lX)",
1439 dwErr, GetLastError());
1440 }
3730b96e 1441 sv_setpvn((SV*)sv, sMsg, dwLen);
22fae026 1442 LocalFree(sMsg);
1443}
1444
1445
68dc0745 1446DllExport int
1447win32_fprintf(FILE *fp, const char *format, ...)
0a753a76 1448{
68dc0745 1449 va_list marker;
1450 va_start(marker, format); /* Initialize variable arguments. */
0a753a76 1451
390b85e7 1452 return (vfprintf(fp, format, marker));
0a753a76 1453}
1454
68dc0745 1455DllExport int
1456win32_printf(const char *format, ...)
0a753a76 1457{
68dc0745 1458 va_list marker;
1459 va_start(marker, format); /* Initialize variable arguments. */
0a753a76 1460
390b85e7 1461 return (vprintf(format, marker));
0a753a76 1462}
1463
68dc0745 1464DllExport int
1465win32_vfprintf(FILE *fp, const char *format, va_list args)
0a753a76 1466{
390b85e7 1467 return (vfprintf(fp, format, args));
0a753a76 1468}
1469
96e4d5b1 1470DllExport int
1471win32_vprintf(const char *format, va_list args)
1472{
390b85e7 1473 return (vprintf(format, args));
96e4d5b1 1474}
1475
68dc0745 1476DllExport size_t
1477win32_fread(void *buf, size_t size, size_t count, FILE *fp)
0a753a76 1478{
390b85e7 1479 return fread(buf, size, count, fp);
0a753a76 1480}
1481
68dc0745 1482DllExport size_t
1483win32_fwrite(const void *buf, size_t size, size_t count, FILE *fp)
0a753a76 1484{
390b85e7 1485 return fwrite(buf, size, count, fp);
0a753a76 1486}
1487
68dc0745 1488DllExport FILE *
1489win32_fopen(const char *filename, const char *mode)
0a753a76 1490{
68dc0745 1491 if (stricmp(filename, "/dev/null")==0)
390b85e7 1492 return fopen("NUL", mode);
1493 return fopen(filename, mode);
0a753a76 1494}
1495
f3986ebb 1496#ifndef USE_SOCKETS_AS_HANDLES
1497#undef fdopen
1498#define fdopen my_fdopen
1499#endif
1500
68dc0745 1501DllExport FILE *
1502win32_fdopen( int handle, const char *mode)
0a753a76 1503{
390b85e7 1504 return fdopen(handle, (char *) mode);
0a753a76 1505}
1506
68dc0745 1507DllExport FILE *
1508win32_freopen( const char *path, const char *mode, FILE *stream)
0a753a76 1509{
68dc0745 1510 if (stricmp(path, "/dev/null")==0)
390b85e7 1511 return freopen("NUL", mode, stream);
1512 return freopen(path, mode, stream);
0a753a76 1513}
1514
68dc0745 1515DllExport int
1516win32_fclose(FILE *pf)
0a753a76 1517{
f3986ebb 1518 return my_fclose(pf); /* defined in win32sck.c */
0a753a76 1519}
1520
68dc0745 1521DllExport int
1522win32_fputs(const char *s,FILE *pf)
0a753a76 1523{
390b85e7 1524 return fputs(s, pf);
0a753a76 1525}
1526
68dc0745 1527DllExport int
1528win32_fputc(int c,FILE *pf)
0a753a76 1529{
390b85e7 1530 return fputc(c,pf);
0a753a76 1531}
1532
68dc0745 1533DllExport int
1534win32_ungetc(int c,FILE *pf)
0a753a76 1535{
390b85e7 1536 return ungetc(c,pf);
0a753a76 1537}
1538
68dc0745 1539DllExport int
1540win32_getc(FILE *pf)
0a753a76 1541{
390b85e7 1542 return getc(pf);
0a753a76 1543}
1544
68dc0745 1545DllExport int
1546win32_fileno(FILE *pf)
0a753a76 1547{
390b85e7 1548 return fileno(pf);
0a753a76 1549}
1550
68dc0745 1551DllExport void
1552win32_clearerr(FILE *pf)
0a753a76 1553{
390b85e7 1554 clearerr(pf);
68dc0745 1555 return;
0a753a76 1556}
1557
68dc0745 1558DllExport int
1559win32_fflush(FILE *pf)
0a753a76 1560{
390b85e7 1561 return fflush(pf);
0a753a76 1562}
1563
68dc0745 1564DllExport long
1565win32_ftell(FILE *pf)
0a753a76 1566{
390b85e7 1567 return ftell(pf);
0a753a76 1568}
1569
68dc0745 1570DllExport int
1571win32_fseek(FILE *pf,long offset,int origin)
0a753a76 1572{
390b85e7 1573 return fseek(pf, offset, origin);
0a753a76 1574}
1575
68dc0745 1576DllExport int
1577win32_fgetpos(FILE *pf,fpos_t *p)
0a753a76 1578{
390b85e7 1579 return fgetpos(pf, p);
0a753a76 1580}
1581
68dc0745 1582DllExport int
1583win32_fsetpos(FILE *pf,const fpos_t *p)
0a753a76 1584{
390b85e7 1585 return fsetpos(pf, p);
0a753a76 1586}
1587
68dc0745 1588DllExport void
1589win32_rewind(FILE *pf)
0a753a76 1590{
390b85e7 1591 rewind(pf);
68dc0745 1592 return;
0a753a76 1593}
1594
68dc0745 1595DllExport FILE*
1596win32_tmpfile(void)
0a753a76 1597{
390b85e7 1598 return tmpfile();
0a753a76 1599}
1600
68dc0745 1601DllExport void
1602win32_abort(void)
0a753a76 1603{
390b85e7 1604 abort();
68dc0745 1605 return;
0a753a76 1606}
1607
68dc0745 1608DllExport int
22239a37 1609win32_fstat(int fd,struct stat *sbufptr)
0a753a76 1610{
22239a37 1611 return fstat(fd,sbufptr);
0a753a76 1612}
1613
68dc0745 1614DllExport int
1615win32_pipe(int *pfd, unsigned int size, int mode)
0a753a76 1616{
390b85e7 1617 return _pipe(pfd, size, mode);
0a753a76 1618}
1619
50892819 1620/*
1621 * a popen() clone that respects PERL5SHELL
1622 */
1623
68dc0745 1624DllExport FILE*
1625win32_popen(const char *command, const char *mode)
0a753a76 1626{
4b556e6c 1627#ifdef USE_RTL_POPEN
390b85e7 1628 return _popen(command, mode);
50892819 1629#else
1630 int p[2];
1631 int parent, child;
1632 int stdfd, oldfd;
1633 int ourmode;
1634 int childpid;
1635
1636 /* establish which ends read and write */
1637 if (strchr(mode,'w')) {
1638 stdfd = 0; /* stdin */
1639 parent = 1;
1640 child = 0;
1641 }
1642 else if (strchr(mode,'r')) {
1643 stdfd = 1; /* stdout */
1644 parent = 0;
1645 child = 1;
1646 }
1647 else
1648 return NULL;
1649
1650 /* set the correct mode */
1651 if (strchr(mode,'b'))
1652 ourmode = O_BINARY;
1653 else if (strchr(mode,'t'))
1654 ourmode = O_TEXT;
1655 else
1656 ourmode = _fmode & (O_TEXT | O_BINARY);
1657
1658 /* the child doesn't inherit handles */
1659 ourmode |= O_NOINHERIT;
1660
1661 if (win32_pipe( p, 512, ourmode) == -1)
1662 return NULL;
1663
1664 /* save current stdfd */
1665 if ((oldfd = win32_dup(stdfd)) == -1)
1666 goto cleanup;
1667
1668 /* make stdfd go to child end of pipe (implicitly closes stdfd) */
1669 /* stdfd will be inherited by the child */
1670 if (win32_dup2(p[child], stdfd) == -1)
1671 goto cleanup;
1672
1673 /* close the child end in parent */
1674 win32_close(p[child]);
1675
1676 /* start the child */
1677 if ((childpid = do_spawn_nowait((char*)command)) == -1)
1678 goto cleanup;
1679
1680 /* revert stdfd to whatever it was before */
1681 if (win32_dup2(oldfd, stdfd) == -1)
1682 goto cleanup;
1683
1684 /* close saved handle */
1685 win32_close(oldfd);
1686
4b556e6c 1687 sv_setiv(*av_fetch(w32_fdpid, p[parent], TRUE), childpid);
50892819 1688
1689 /* we have an fd, return a file stream */
1690 return (win32_fdopen(p[parent], (char *)mode));
1691
1692cleanup:
1693 /* we don't need to check for errors here */
1694 win32_close(p[0]);
1695 win32_close(p[1]);
1696 if (oldfd != -1) {
1697 win32_dup2(oldfd, stdfd);
1698 win32_close(oldfd);
1699 }
1700 return (NULL);
1701
4b556e6c 1702#endif /* USE_RTL_POPEN */
0a753a76 1703}
1704
50892819 1705/*
1706 * pclose() clone
1707 */
1708
68dc0745 1709DllExport int
1710win32_pclose(FILE *pf)
0a753a76 1711{
4b556e6c 1712#ifdef USE_RTL_POPEN
390b85e7 1713 return _pclose(pf);
50892819 1714#else
50892819 1715
e17cb2a9 1716 int childpid, status;
1717 SV *sv;
1718
4b556e6c 1719 sv = *av_fetch(w32_fdpid, win32_fileno(pf), TRUE);
e17cb2a9 1720 if (SvIOK(sv))
1721 childpid = SvIVX(sv);
1722 else
1723 childpid = 0;
50892819 1724
1725 if (!childpid) {
1726 errno = EBADF;
1727 return -1;
1728 }
1729
1730 win32_fclose(pf);
e17cb2a9 1731 SvIVX(sv) = 0;
1732
f55ee38a 1733 remove_dead_process((HANDLE)childpid);
50892819 1734
1735 /* wait for the child */
1736 if (cwait(&status, childpid, WAIT_CHILD) == -1)
1737 return (-1);
1738 /* cwait() returns differently on Borland */
1739#ifdef __BORLANDC__
1740 return (((status >> 8) & 0xff) | ((status << 8) & 0xff00));
1741#else
1742 return (status);
1743#endif
1744
4b556e6c 1745#endif /* USE_RTL_POPEN */
0a753a76 1746}
1747
68dc0745 1748DllExport int
8d9b2e3c 1749win32_rename(const char *oname, const char *newname)
e24c7c18 1750{
1751 char szNewWorkName[MAX_PATH+1];
1752 WIN32_FIND_DATA fdOldFile, fdNewFile;
1753 HANDLE handle;
1754 char *ptr;
1755
8d9b2e3c 1756 if ((strchr(oname, '\\') || strchr(oname, '/'))
e24c7c18 1757 && strchr(newname, '\\') == NULL
1758 && strchr(newname, '/') == NULL)
1759 {
8d9b2e3c 1760 strcpy(szNewWorkName, oname);
e24c7c18 1761 if ((ptr = strrchr(szNewWorkName, '\\')) == NULL)
1762 ptr = strrchr(szNewWorkName, '/');
1763 strcpy(++ptr, newname);
1764 }
1765 else
1766 strcpy(szNewWorkName, newname);
1767
8d9b2e3c 1768 if (stricmp(oname, szNewWorkName) != 0) {
e24c7c18 1769 // check that we're not being fooled by relative paths
1770 // and only delete the new file
1771 // 1) if it exists
1772 // 2) it is not the same file as the old file
1773 // 3) old file exist
1774 // GetFullPathName does not return the long file name on some systems
8d9b2e3c 1775 handle = FindFirstFile(oname, &fdOldFile);
e24c7c18 1776 if (handle != INVALID_HANDLE_VALUE) {
1777 FindClose(handle);
1778
1779 handle = FindFirstFile(szNewWorkName, &fdNewFile);
1780
1781 if (handle != INVALID_HANDLE_VALUE)
1782 FindClose(handle);
1783 else
1784 fdNewFile.cFileName[0] = '\0';
1785
1786 if (strcmp(fdOldFile.cAlternateFileName,
1787 fdNewFile.cAlternateFileName) != 0
1788 && strcmp(fdOldFile.cFileName, fdNewFile.cFileName) != 0)
1789 {
1790 // file exists and not same file
1791 DeleteFile(szNewWorkName);
1792 }
1793 }
1794 }
8d9b2e3c 1795 return rename(oname, newname);
e24c7c18 1796}
1797
1798DllExport int
68dc0745 1799win32_setmode(int fd, int mode)
0a753a76 1800{
390b85e7 1801 return setmode(fd, mode);
0a753a76 1802}
1803
96e4d5b1 1804DllExport long
1805win32_lseek(int fd, long offset, int origin)
1806{
390b85e7 1807 return lseek(fd, offset, origin);
96e4d5b1 1808}
1809
1810DllExport long
1811win32_tell(int fd)
1812{
390b85e7 1813 return tell(fd);
96e4d5b1 1814}
1815
68dc0745 1816DllExport int
1817win32_open(const char *path, int flag, ...)
0a753a76 1818{
68dc0745 1819 va_list ap;
1820 int pmode;
0a753a76 1821
1822 va_start(ap, flag);
1823 pmode = va_arg(ap, int);
1824 va_end(ap);
1825
68dc0745 1826 if (stricmp(path, "/dev/null")==0)
390b85e7 1827 return open("NUL", flag, pmode);
1828 return open(path,flag,pmode);
0a753a76 1829}
1830
68dc0745 1831DllExport int
1832win32_close(int fd)
0a753a76 1833{
390b85e7 1834 return close(fd);
0a753a76 1835}
1836
68dc0745 1837DllExport int
96e4d5b1 1838win32_eof(int fd)
1839{
390b85e7 1840 return eof(fd);
96e4d5b1 1841}
1842
1843DllExport int
68dc0745 1844win32_dup(int fd)
0a753a76 1845{
390b85e7 1846 return dup(fd);
0a753a76 1847}
1848
68dc0745 1849DllExport int
1850win32_dup2(int fd1,int fd2)
0a753a76 1851{
390b85e7 1852 return dup2(fd1,fd2);
0a753a76 1853}
1854
68dc0745 1855DllExport int
3e3baf6d 1856win32_read(int fd, void *buf, unsigned int cnt)
0a753a76 1857{
390b85e7 1858 return read(fd, buf, cnt);
0a753a76 1859}
1860
68dc0745 1861DllExport int
3e3baf6d 1862win32_write(int fd, const void *buf, unsigned int cnt)
0a753a76 1863{
390b85e7 1864 return write(fd, buf, cnt);
0a753a76 1865}
1866
68dc0745 1867DllExport int
5aabfad6 1868win32_mkdir(const char *dir, int mode)
1869{
390b85e7 1870 return mkdir(dir); /* just ignore mode */
5aabfad6 1871}
96e4d5b1 1872
5aabfad6 1873DllExport int
1874win32_rmdir(const char *dir)
1875{
390b85e7 1876 return rmdir(dir);
5aabfad6 1877}
96e4d5b1 1878
5aabfad6 1879DllExport int
1880win32_chdir(const char *dir)
1881{
390b85e7 1882 return chdir(dir);
5aabfad6 1883}
96e4d5b1 1884
5aabfad6 1885DllExport int
3e3baf6d 1886win32_spawnvp(int mode, const char *cmdname, const char *const *argv)
0a753a76 1887{
2d7a9237 1888 int status;
1889
4b556e6c 1890#ifndef USE_RTL_WAIT
e17cb2a9 1891 if (mode == P_NOWAIT && w32_num_children >= MAXIMUM_WAIT_OBJECTS)
1892 return -1;
1893#endif
1894
2d7a9237 1895 status = spawnvp(mode, cmdname, (char * const *) argv);
4b556e6c 1896#ifndef USE_RTL_WAIT
2d7a9237 1897 /* XXX For the P_NOWAIT case, Borland RTL returns pinfo.dwProcessId
1898 * while VC RTL returns pinfo.hProcess. For purposes of the custom
1899 * implementation of win32_wait(), we assume the latter.
1900 */
1901 if (mode == P_NOWAIT && status >= 0)
1902 w32_child_pids[w32_num_children++] = (HANDLE)status;
1903#endif
1904 return status;
0a753a76 1905}
1906
6890e559 1907DllExport int
eb62e965 1908win32_execv(const char *cmdname, const char *const *argv)
1909{
1910 return execv(cmdname, (char *const *)argv);
1911}
1912
1913DllExport int
6890e559 1914win32_execvp(const char *cmdname, const char *const *argv)
1915{
390b85e7 1916 return execvp(cmdname, (char *const *)argv);
6890e559 1917}
1918
84902520 1919DllExport void
1920win32_perror(const char *str)
1921{
390b85e7 1922 perror(str);
84902520 1923}
1924
1925DllExport void
1926win32_setbuf(FILE *pf, char *buf)
1927{
390b85e7 1928 setbuf(pf, buf);
84902520 1929}
1930
1931DllExport int
1932win32_setvbuf(FILE *pf, char *buf, int type, size_t size)
1933{
390b85e7 1934 return setvbuf(pf, buf, type, size);
84902520 1935}
1936
1937DllExport int
1938win32_flushall(void)
1939{
390b85e7 1940 return flushall();
84902520 1941}
1942
1943DllExport int
1944win32_fcloseall(void)
1945{
390b85e7 1946 return fcloseall();
84902520 1947}
1948
1949DllExport char*
1950win32_fgets(char *s, int n, FILE *pf)
1951{
390b85e7 1952 return fgets(s, n, pf);
84902520 1953}
1954
1955DllExport char*
1956win32_gets(char *s)
1957{
390b85e7 1958 return gets(s);
84902520 1959}
1960
1961DllExport int
1962win32_fgetc(FILE *pf)
1963{
390b85e7 1964 return fgetc(pf);
84902520 1965}
1966
1967DllExport int
1968win32_putc(int c, FILE *pf)
1969{
390b85e7 1970 return putc(c,pf);
84902520 1971}
1972
1973DllExport int
1974win32_puts(const char *s)
1975{
390b85e7 1976 return puts(s);
84902520 1977}
1978
1979DllExport int
1980win32_getchar(void)
1981{
390b85e7 1982 return getchar();
84902520 1983}
1984
1985DllExport int
1986win32_putchar(int c)
1987{
390b85e7 1988 return putchar(c);
84902520 1989}
1990
bbc8f9de 1991#ifdef MYMALLOC
1992
1993#ifndef USE_PERL_SBRK
1994
1995static char *committed = NULL;
1996static char *base = NULL;
1997static char *reserved = NULL;
1998static char *brk = NULL;
1999static DWORD pagesize = 0;
2000static DWORD allocsize = 0;
2001
2002void *
2003sbrk(int need)
2004{
2005 void *result;
2006 if (!pagesize)
2007 {SYSTEM_INFO info;
2008 GetSystemInfo(&info);
2009 /* Pretend page size is larger so we don't perpetually
2010 * call the OS to commit just one page ...
2011 */
2012 pagesize = info.dwPageSize << 3;
2013 allocsize = info.dwAllocationGranularity;
2014 }
2015 /* This scheme fails eventually if request for contiguous
2016 * block is denied so reserve big blocks - this is only
2017 * address space not memory ...
2018 */
2019 if (brk+need >= reserved)
2020 {
2021 DWORD size = 64*1024*1024;
2022 char *addr;
2023 if (committed && reserved && committed < reserved)
2024 {
2025 /* Commit last of previous chunk cannot span allocations */
161b471a 2026 addr = (char *) VirtualAlloc(committed,reserved-committed,MEM_COMMIT,PAGE_READWRITE);
bbc8f9de 2027 if (addr)
2028 committed = reserved;
2029 }
2030 /* Reserve some (more) space
2031 * Note this is a little sneaky, 1st call passes NULL as reserved
2032 * so lets system choose where we start, subsequent calls pass
2033 * the old end address so ask for a contiguous block
2034 */
161b471a 2035 addr = (char *) VirtualAlloc(reserved,size,MEM_RESERVE,PAGE_NOACCESS);
bbc8f9de 2036 if (addr)
2037 {
2038 reserved = addr+size;
2039 if (!base)
2040 base = addr;
2041 if (!committed)
2042 committed = base;
2043 if (!brk)
2044 brk = committed;
2045 }
2046 else
2047 {
2048 return (void *) -1;
2049 }
2050 }
2051 result = brk;
2052 brk += need;
2053 if (brk > committed)
2054 {
2055 DWORD size = ((brk-committed + pagesize -1)/pagesize) * pagesize;
161b471a 2056 char *addr = (char *) VirtualAlloc(committed,size,MEM_COMMIT,PAGE_READWRITE);
bbc8f9de 2057 if (addr)
2058 {
2059 committed += size;
2060 }
2061 else
2062 return (void *) -1;
2063 }
2064 return result;
2065}
2066
2067#endif
2068#endif
2069
84902520 2070DllExport void*
2071win32_malloc(size_t size)
2072{
390b85e7 2073 return malloc(size);
84902520 2074}
2075
2076DllExport void*
2077win32_calloc(size_t numitems, size_t size)
2078{
390b85e7 2079 return calloc(numitems,size);
84902520 2080}
2081
2082DllExport void*
2083win32_realloc(void *block, size_t size)
2084{
390b85e7 2085 return realloc(block,size);
84902520 2086}
2087
2088DllExport void
2089win32_free(void *block)
2090{
390b85e7 2091 free(block);
84902520 2092}
2093
bbc8f9de 2094
68dc0745 2095int
65e48ea9 2096win32_open_osfhandle(long handle, int flags)
0a753a76 2097{
390b85e7 2098 return _open_osfhandle(handle, flags);
0a753a76 2099}
2100
68dc0745 2101long
65e48ea9 2102win32_get_osfhandle(int fd)
0a753a76 2103{
390b85e7 2104 return _get_osfhandle(fd);
0a753a76 2105}
7bac28a0 2106
7bac28a0 2107/*
2108 * Extras.
2109 */
2110
ad2e33dc 2111static
2112XS(w32_GetCwd)
2113{
2114 dXSARGS;
2115 SV *sv = sv_newmortal();
2116 /* Make one call with zero size - return value is required size */
2117 DWORD len = GetCurrentDirectory((DWORD)0,NULL);
2118 SvUPGRADE(sv,SVt_PV);
2119 SvGROW(sv,len);
2120 SvCUR(sv) = GetCurrentDirectory((DWORD) SvLEN(sv), SvPVX(sv));
2121 /*
2122 * If result != 0
2123 * then it worked, set PV valid,
2124 * else leave it 'undef'
2125 */
2126 if (SvCUR(sv))
2127 SvPOK_on(sv);
50892819 2128 EXTEND(SP,1);
ad2e33dc 2129 ST(0) = sv;
2130 XSRETURN(1);
2131}
2132
2133static
2134XS(w32_SetCwd)
2135{
2136 dXSARGS;
2137 if (items != 1)
2138 croak("usage: Win32::SetCurrentDirectory($cwd)");
6b88bc9c 2139 if (SetCurrentDirectory(SvPV(ST(0),PL_na)))
ad2e33dc 2140 XSRETURN_YES;
2141
2142 XSRETURN_NO;
2143}
2144
2145static
2146XS(w32_GetNextAvailDrive)
2147{
2148 dXSARGS;
2149 char ix = 'C';
2150 char root[] = "_:\\";
2151 while (ix <= 'Z') {
2152 root[0] = ix++;
2153 if (GetDriveType(root) == 1) {
2154 root[2] = '\0';
2155 XSRETURN_PV(root);
2156 }
2157 }
2158 XSRETURN_UNDEF;
2159}
2160
2161static
2162XS(w32_GetLastError)
2163{
2164 dXSARGS;
2165 XSRETURN_IV(GetLastError());
2166}
2167
2168static
2169XS(w32_LoginName)
2170{
2171 dXSARGS;
e34ffe5a 2172 char *name = getlogin_buffer;
2173 DWORD size = sizeof(getlogin_buffer);
ad2e33dc 2174 if (GetUserName(name,&size)) {
2175 /* size includes NULL */
2176 ST(0) = sv_2mortal(newSVpv(name,size-1));
2177 XSRETURN(1);
2178 }
2179 XSRETURN_UNDEF;
2180}
2181
2182static
2183XS(w32_NodeName)
2184{
2185 dXSARGS;
2186 char name[MAX_COMPUTERNAME_LENGTH+1];
2187 DWORD size = sizeof(name);
2188 if (GetComputerName(name,&size)) {
2189 /* size does NOT include NULL :-( */
2190 ST(0) = sv_2mortal(newSVpv(name,size));
2191 XSRETURN(1);
2192 }
2193 XSRETURN_UNDEF;
2194}
2195
2196
2197static
2198XS(w32_DomainName)
2199{
2200 dXSARGS;
8c9208bc 2201#ifndef HAS_NETWKSTAGETINFO
2202 /* mingw32 (and Win95) don't have NetWksta*(), so do it the old way */
ad2e33dc 2203 char name[256];
2204 DWORD size = sizeof(name);
2205 if (GetUserName(name,&size)) {
2206 char sid[1024];
2207 DWORD sidlen = sizeof(sid);
2208 char dname[256];
2209 DWORD dnamelen = sizeof(dname);
2210 SID_NAME_USE snu;
db15561c 2211 if (LookupAccountName(NULL, name, (PSID)&sid, &sidlen,
ad2e33dc 2212 dname, &dnamelen, &snu)) {
2213 XSRETURN_PV(dname); /* all that for this */
2214 }
2215 }
e56670dd 2216#else
8c9208bc 2217 /* this way is more reliable, in case user has a local account.
2218 * XXX need dynamic binding of netapi32.dll symbols or this will fail on
2219 * Win95. Probably makes more sense to move it into libwin32. */
9404a519 2220 char dname[256];
2221 DWORD dnamelen = sizeof(dname);
0a2408cf 2222 PWKSTA_INFO_100 pwi;
2223 if (NERR_Success == NetWkstaGetInfo(NULL, 100, (LPBYTE*)&pwi)) {
2224 if (pwi->wki100_langroup && *(pwi->wki100_langroup)) {
2225 WideCharToMultiByte(CP_ACP, NULL, pwi->wki100_langroup,
2226 -1, (LPSTR)dname, dnamelen, NULL, NULL);
2227 }
2228 else {
2229 WideCharToMultiByte(CP_ACP, NULL, pwi->wki100_computername,
2230 -1, (LPSTR)dname, dnamelen, NULL, NULL);
2231 }
2232 NetApiBufferFree(pwi);
9404a519 2233 XSRETURN_PV(dname);
2234 }
e56670dd 2235#endif
ad2e33dc 2236 XSRETURN_UNDEF;
2237}
2238
2239static
2240XS(w32_FsType)
2241{
2242 dXSARGS;
2243 char fsname[256];
2244 DWORD flags, filecomplen;
2245 if (GetVolumeInformation(NULL, NULL, 0, NULL, &filecomplen,
2246 &flags, fsname, sizeof(fsname))) {
2247 if (GIMME == G_ARRAY) {
2248 XPUSHs(sv_2mortal(newSVpv(fsname,0)));
2249 XPUSHs(sv_2mortal(newSViv(flags)));
2250 XPUSHs(sv_2mortal(newSViv(filecomplen)));
2251 PUTBACK;
2252 return;
2253 }
2254 XSRETURN_PV(fsname);
2255 }
2256 XSRETURN_UNDEF;
2257}
2258
2259static
2260XS(w32_GetOSVersion)
2261{
2262 dXSARGS;
2263 OSVERSIONINFO osver;
2264
2265 osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
2266 if (GetVersionEx(&osver)) {
2267 XPUSHs(newSVpv(osver.szCSDVersion, 0));
2268 XPUSHs(newSViv(osver.dwMajorVersion));
2269 XPUSHs(newSViv(osver.dwMinorVersion));
2270 XPUSHs(newSViv(osver.dwBuildNumber));
2271 XPUSHs(newSViv(osver.dwPlatformId));
2272 PUTBACK;
2273 return;
2274 }
2275 XSRETURN_UNDEF;
2276}
2277
2278static
2279XS(w32_IsWinNT)
2280{
2281 dXSARGS;
2282 XSRETURN_IV(IsWinNT());
2283}
2284
2285static
2286XS(w32_IsWin95)
2287{
2288 dXSARGS;
2289 XSRETURN_IV(IsWin95());
2290}
2291
2292static
2293XS(w32_FormatMessage)
2294{
2295 dXSARGS;
2296 DWORD source = 0;
2297 char msgbuf[1024];
2298
2299 if (items != 1)
2300 croak("usage: Win32::FormatMessage($errno)");
2301
2302 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
2303 &source, SvIV(ST(0)), 0,
2304 msgbuf, sizeof(msgbuf)-1, NULL))
2305 XSRETURN_PV(msgbuf);
2306
2307 XSRETURN_UNDEF;
2308}
2309
2310static
2311XS(w32_Spawn)
2312{
2313 dXSARGS;
2314 char *cmd, *args;
2315 PROCESS_INFORMATION stProcInfo;
2316 STARTUPINFO stStartInfo;
2317 BOOL bSuccess = FALSE;
2318
9404a519 2319 if (items != 3)
ad2e33dc 2320 croak("usage: Win32::Spawn($cmdName, $args, $PID)");
2321
6b88bc9c 2322 cmd = SvPV(ST(0),PL_na);
2323 args = SvPV(ST(1), PL_na);
ad2e33dc 2324
2325 memset(&stStartInfo, 0, sizeof(stStartInfo)); /* Clear the block */
2326 stStartInfo.cb = sizeof(stStartInfo); /* Set the structure size */
2327 stStartInfo.dwFlags = STARTF_USESHOWWINDOW; /* Enable wShowWindow control */
2328 stStartInfo.wShowWindow = SW_SHOWMINNOACTIVE; /* Start min (normal) */
2329
9404a519 2330 if (CreateProcess(
ad2e33dc 2331 cmd, /* Image path */
2332 args, /* Arguments for command line */
2333 NULL, /* Default process security */
2334 NULL, /* Default thread security */
2335 FALSE, /* Must be TRUE to use std handles */
2336 NORMAL_PRIORITY_CLASS, /* No special scheduling */
2337 NULL, /* Inherit our environment block */
2338 NULL, /* Inherit our currrent directory */
2339 &stStartInfo, /* -> Startup info */
2340 &stProcInfo)) /* <- Process info (if OK) */
2341 {
2342 CloseHandle(stProcInfo.hThread);/* library source code does this. */
2343 sv_setiv(ST(2), stProcInfo.dwProcessId);
2344 bSuccess = TRUE;
2345 }
2346 XSRETURN_IV(bSuccess);
2347}
2348
2349static
2350XS(w32_GetTickCount)
2351{
2352 dXSARGS;
2353 XSRETURN_IV(GetTickCount());
2354}
2355
2356static
2357XS(w32_GetShortPathName)
2358{
2359 dXSARGS;
2360 SV *shortpath;
e8bab181 2361 DWORD len;
ad2e33dc 2362
9404a519 2363 if (items != 1)
ad2e33dc 2364 croak("usage: Win32::GetShortPathName($longPathName)");
2365
2366 shortpath = sv_mortalcopy(ST(0));
2367 SvUPGRADE(shortpath, SVt_PV);
2368 /* src == target is allowed */
e8bab181 2369 do {
2370 len = GetShortPathName(SvPVX(shortpath),
2371 SvPVX(shortpath),
2372 SvLEN(shortpath));
2373 } while (len >= SvLEN(shortpath) && sv_grow(shortpath,len+1));
2374 if (len) {
2375 SvCUR_set(shortpath,len);
ad2e33dc 2376 ST(0) = shortpath;
e8bab181 2377 }
ad2e33dc 2378 else
6b88bc9c 2379 ST(0) = &PL_sv_undef;
ad2e33dc 2380 XSRETURN(1);
2381}
2382
ad0751ec 2383static
2384XS(w32_Sleep)
2385{
2386 dXSARGS;
2387 if (items != 1)
2388 croak("usage: Win32::Sleep($milliseconds)");
2389 Sleep(SvIV(ST(0)));
2390 XSRETURN_YES;
2391}
2392
ad2e33dc 2393void
f3986ebb 2394Perl_init_os_extras()
ad2e33dc 2395{
2396 char *file = __FILE__;
2397 dXSUB_SYS;
2398
4b556e6c 2399 w32_perlshell_tokens = Nullch;
2400 w32_perlshell_items = -1;
2401 w32_fdpid = newAV(); /* XXX needs to be in Perl_win32_init()? */
2402#ifndef USE_RTL_WAIT
2403 w32_num_children = 0;
2404#endif
2405
ad2e33dc 2406 /* these names are Activeware compatible */
2407 newXS("Win32::GetCwd", w32_GetCwd, file);
2408 newXS("Win32::SetCwd", w32_SetCwd, file);
2409 newXS("Win32::GetNextAvailDrive", w32_GetNextAvailDrive, file);
2410 newXS("Win32::GetLastError", w32_GetLastError, file);
2411 newXS("Win32::LoginName", w32_LoginName, file);
2412 newXS("Win32::NodeName", w32_NodeName, file);
2413 newXS("Win32::DomainName", w32_DomainName, file);
2414 newXS("Win32::FsType", w32_FsType, file);
2415 newXS("Win32::GetOSVersion", w32_GetOSVersion, file);
2416 newXS("Win32::IsWinNT", w32_IsWinNT, file);
2417 newXS("Win32::IsWin95", w32_IsWin95, file);
2418 newXS("Win32::FormatMessage", w32_FormatMessage, file);
2419 newXS("Win32::Spawn", w32_Spawn, file);
2420 newXS("Win32::GetTickCount", w32_GetTickCount, file);
2421 newXS("Win32::GetShortPathName", w32_GetShortPathName, file);
ad0751ec 2422 newXS("Win32::Sleep", w32_Sleep, file);
ad2e33dc 2423
2424 /* XXX Bloat Alert! The following Activeware preloads really
2425 * ought to be part of Win32::Sys::*, so they're not included
2426 * here.
2427 */
2428 /* LookupAccountName
2429 * LookupAccountSID
2430 * InitiateSystemShutdown
2431 * AbortSystemShutdown
2432 * ExpandEnvrironmentStrings
2433 */
2434}
2435
2436void
2437Perl_win32_init(int *argcp, char ***argvp)
2438{
2439 /* Disable floating point errors, Perl will trap the ones we
2440 * care about. VC++ RTL defaults to switching these off
2441 * already, but the Borland RTL doesn't. Since we don't
2442 * want to be at the vendor's whim on the default, we set
2443 * it explicitly here.
2444 */
a835ef8a 2445#if !defined(_ALPHA_) && !defined(__GNUC__)
ad2e33dc 2446 _control87(MCW_EM, MCW_EM);
3dc9191e 2447#endif
4b556e6c 2448 MALLOC_INIT;
ad2e33dc 2449}
d55594ae 2450
a868473f 2451#ifdef USE_BINMODE_SCRIPTS
2452
2453void
2454win32_strip_return(SV *sv)
2455{
2456 char *s = SvPVX(sv);
2457 char *e = s+SvCUR(sv);
2458 char *d = s;
2459 while (s < e)
2460 {
2461 if (*s == '\r' && s[1] == '\n')
2462 {
2463 *d++ = '\n';
2464 s += 2;
2465 }
2466 else
2467 {
2468 *d++ = *s++;
2469 }
2470 }
2471 SvCUR_set(sv,d-SvPVX(sv));
2472}
2473
2474#endif