correct prototype for des_fcrypt(), explain how to add it in more
[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) {
148 if (*ptr != NULL) {
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);
157 *ptr = NULL;
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);
ba3eb2af 169 if (*ptr == NULL)
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);
239 if (path == NULL)
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 */
d55594ae 639 if (win32_stat(filename, &sbuf) < 0 || (sbuf.st_mode & S_IFDIR) == 0) {
c6c1a8fd 640 /* CRT is buggy on sharenames, so make sure it really isn't */
641 DWORD r = GetFileAttributes(filename);
642 if (r == 0xffffffff || !(r & FILE_ATTRIBUTE_DIRECTORY))
643 return NULL;
68dc0745 644 }
645
68dc0745 646 /* Get us a DIR structure */
fc36a67e 647 Newz(1303, p, 1, DIR);
9404a519 648 if (p == NULL)
68dc0745 649 return NULL;
650
651 /* Create the search pattern */
652 strcpy(scanname, filename);
9404a519 653 if (scanname[len-1] != '/' && scanname[len-1] != '\\')
654 scanname[len++] = '/';
655 scanname[len++] = '*';
656 scanname[len] = '\0';
68dc0745 657
658 /* do the FindFirstFile call */
659 fh = FindFirstFile(scanname, &FindData);
9404a519 660 if (fh == INVALID_HANDLE_VALUE) {
68dc0745 661 return NULL;
662 }
663
664 /* now allocate the first part of the string table for
665 * the filenames that we find.
666 */
667 idx = strlen(FindData.cFileName)+1;
fc36a67e 668 New(1304, p->start, idx, char);
9404a519 669 if (p->start == NULL)
65e48ea9 670 croak("opendir: malloc failed!\n");
68dc0745 671 strcpy(p->start, FindData.cFileName);
68dc0745 672 p->nfiles++;
673
674 /* loop finding all the files that match the wildcard
675 * (which should be all of them in this directory!).
676 * the variable idx should point one past the null terminator
677 * of the previous string found.
678 */
679 while (FindNextFile(fh, &FindData)) {
680 len = strlen(FindData.cFileName);
681 /* bump the string table size by enough for the
682 * new name and it's null terminator
683 */
684 Renew(p->start, idx+len+1, char);
9404a519 685 if (p->start == NULL)
65e48ea9 686 croak("opendir: malloc failed!\n");
68dc0745 687 strcpy(&p->start[idx], FindData.cFileName);
9404a519 688 p->nfiles++;
689 idx += len+1;
690 }
691 FindClose(fh);
692 p->size = idx;
693 p->curr = p->start;
694 return p;
0a753a76 695}
696
697
68dc0745 698/* Readdir just returns the current string pointer and bumps the
699 * string pointer to the nDllExport entry.
700 */
701struct direct *
ce2e26e5 702win32_readdir(DIR *dirp)
0a753a76 703{
68dc0745 704 int len;
705 static int dummy = 0;
0a753a76 706
68dc0745 707 if (dirp->curr) {
708 /* first set up the structure to return */
709 len = strlen(dirp->curr);
710 strcpy(dirp->dirstr.d_name, dirp->curr);
711 dirp->dirstr.d_namlen = len;
0a753a76 712
68dc0745 713 /* Fake an inode */
714 dirp->dirstr.d_ino = dummy++;
0a753a76 715
68dc0745 716 /* Now set up for the nDllExport call to readdir */
717 dirp->curr += len + 1;
718 if (dirp->curr >= (dirp->start + dirp->size)) {
719 dirp->curr = NULL;
720 }
0a753a76 721
68dc0745 722 return &(dirp->dirstr);
723 }
724 else
725 return NULL;
0a753a76 726}
727
68dc0745 728/* Telldir returns the current string pointer position */
729long
ce2e26e5 730win32_telldir(DIR *dirp)
0a753a76 731{
732 return (long) dirp->curr;
733}
734
735
68dc0745 736/* Seekdir moves the string pointer to a previously saved position
737 *(Saved by telldir).
738 */
739void
ce2e26e5 740win32_seekdir(DIR *dirp, long loc)
0a753a76 741{
742 dirp->curr = (char *)loc;
743}
744
68dc0745 745/* Rewinddir resets the string pointer to the start */
746void
ce2e26e5 747win32_rewinddir(DIR *dirp)
0a753a76 748{
749 dirp->curr = dirp->start;
750}
751
68dc0745 752/* free the memory allocated by opendir */
753int
ce2e26e5 754win32_closedir(DIR *dirp)
0a753a76 755{
756 Safefree(dirp->start);
757 Safefree(dirp);
68dc0745 758 return 1;
0a753a76 759}
760
761
68dc0745 762/*
763 * various stubs
764 */
0a753a76 765
766
68dc0745 767/* Ownership
768 *
769 * Just pretend that everyone is a superuser. NT will let us know if
770 * we don\'t really have permission to do something.
771 */
0a753a76 772
773#define ROOT_UID ((uid_t)0)
774#define ROOT_GID ((gid_t)0)
775
68dc0745 776uid_t
777getuid(void)
0a753a76 778{
68dc0745 779 return ROOT_UID;
0a753a76 780}
781
68dc0745 782uid_t
783geteuid(void)
0a753a76 784{
68dc0745 785 return ROOT_UID;
0a753a76 786}
787
68dc0745 788gid_t
789getgid(void)
0a753a76 790{
68dc0745 791 return ROOT_GID;
0a753a76 792}
793
68dc0745 794gid_t
795getegid(void)
0a753a76 796{
68dc0745 797 return ROOT_GID;
0a753a76 798}
799
68dc0745 800int
22239a37 801setuid(uid_t auid)
0a753a76 802{
22239a37 803 return (auid == ROOT_UID ? 0 : -1);
0a753a76 804}
805
68dc0745 806int
22239a37 807setgid(gid_t agid)
0a753a76 808{
22239a37 809 return (agid == ROOT_GID ? 0 : -1);
0a753a76 810}
811
e34ffe5a 812char *
813getlogin(void)
814{
815 dTHR;
816 char *buf = getlogin_buffer;
817 DWORD size = sizeof(getlogin_buffer);
818 if (GetUserName(buf,&size))
819 return buf;
820 return (char*)NULL;
821}
822
b990f8c8 823int
824chown(const char *path, uid_t owner, gid_t group)
825{
826 /* XXX noop */
1c1c7f20 827 return 0;
b990f8c8 828}
829
f55ee38a 830static void
831remove_dead_process(HANDLE deceased)
0a753a76 832{
f55ee38a 833#ifndef USE_RTL_WAIT
834 int child;
835 for (child = 0 ; child < w32_num_children ; ++child) {
836 if (w32_child_pids[child] == deceased) {
837 Copy(&w32_child_pids[child+1], &w32_child_pids[child],
838 (w32_num_children-child-1), HANDLE);
839 w32_num_children--;
840 break;
841 }
842 }
843#endif
844}
845
846DllExport int
847win32_kill(int pid, int sig)
848{
849#ifdef USE_RTL_WAIT
68dc0745 850 HANDLE hProcess= OpenProcess(PROCESS_ALL_ACCESS, TRUE, pid);
f55ee38a 851#else
852 HANDLE hProcess = (HANDLE) pid;
853#endif
0a753a76 854
855 if (hProcess == NULL) {
65e48ea9 856 croak("kill process failed!\n");
68dc0745 857 }
858 else {
859 if (!TerminateProcess(hProcess, sig))
65e48ea9 860 croak("kill process failed!\n");
68dc0745 861 CloseHandle(hProcess);
f55ee38a 862
863 /* WaitForMultipleObjects() on a pid that was killed returns error
864 * so if we know the pid is gone we remove it from process list */
865 remove_dead_process(hProcess);
68dc0745 866 }
867 return 0;
0a753a76 868}
fbbbcc48 869
68dc0745 870/*
871 * File system stuff
872 */
0a753a76 873
f3986ebb 874DllExport unsigned int
875win32_sleep(unsigned int t)
0a753a76 876{
68dc0745 877 Sleep(t*1000);
878 return 0;
0a753a76 879}
880
68dc0745 881DllExport int
882win32_stat(const char *path, struct stat *buffer)
0a753a76 883{
e24c7c18 884 char t[MAX_PATH+1];
68dc0745 885 const char *p = path;
886 int l = strlen(path);
67fbe06e 887 int res;
0a753a76 888
68dc0745 889 if (l > 1) {
890 switch(path[l - 1]) {
891 case '\\':
892 case '/':
893 if (path[l - 2] != ':') {
894 strncpy(t, path, l - 1);
895 t[l - 1] = 0;
896 p = t;
897 };
898 }
899 }
390b85e7 900 res = stat(p,buffer);
67fbe06e 901#ifdef __BORLANDC__
902 if (res == 0) {
903 if (S_ISDIR(buffer->st_mode))
904 buffer->st_mode |= S_IWRITE | S_IEXEC;
905 else if (S_ISREG(buffer->st_mode)) {
906 if (l >= 4 && path[l-4] == '.') {
907 const char *e = path + l - 3;
908 if (strnicmp(e,"exe",3)
909 && strnicmp(e,"bat",3)
910 && strnicmp(e,"com",3)
911 && (IsWin95() || strnicmp(e,"cmd",3)))
912 buffer->st_mode &= ~S_IEXEC;
913 else
914 buffer->st_mode |= S_IEXEC;
915 }
916 else
917 buffer->st_mode &= ~S_IEXEC;
918 }
919 }
920#endif
921 return res;
0a753a76 922}
923
0551aaa8 924#ifndef USE_WIN32_RTL_ENV
925
926DllExport char *
927win32_getenv(const char *name)
928{
929 static char *curitem = Nullch;
930 static DWORD curlen = 512;
931 DWORD needlen;
932 if (!curitem)
933 New(1305,curitem,curlen,char);
58a50f62 934
935 needlen = GetEnvironmentVariable(name,curitem,curlen);
936 if (needlen != 0) {
937 while (needlen > curlen) {
938 Renew(curitem,needlen,char);
939 curlen = needlen;
940 needlen = GetEnvironmentVariable(name,curitem,curlen);
941 }
0551aaa8 942 }
58a50f62 943 else
c69f6586 944 {
7a5f8e82 945 /* allow any environment variables that begin with 'PERL'
58a50f62 946 to be stored in the registry
947 */
948 if(curitem != NULL)
949 *curitem = '\0';
950
7a5f8e82 951 if (strncmp(name, "PERL", 4) == 0) {
58a50f62 952 if (curitem != NULL) {
953 Safefree(curitem);
954 curitem = NULL;
955 }
00dc2f4f 956 curitem = GetRegStr(name, &curitem, &curlen);
58a50f62 957 }
c69f6586 958 }
58a50f62 959 if(curitem != NULL && *curitem == '\0')
960 return Nullch;
961
0551aaa8 962 return curitem;
963}
964
965#endif
966
d55594ae 967static long
2d7a9237 968filetime_to_clock(PFILETIME ft)
d55594ae 969{
970 __int64 qw = ft->dwHighDateTime;
971 qw <<= 32;
972 qw |= ft->dwLowDateTime;
973 qw /= 10000; /* File time ticks at 0.1uS, clock at 1mS */
974 return (long) qw;
975}
976
f3986ebb 977DllExport int
978win32_times(struct tms *timebuf)
0a753a76 979{
d55594ae 980 FILETIME user;
981 FILETIME kernel;
982 FILETIME dummy;
983 if (GetProcessTimes(GetCurrentProcess(), &dummy, &dummy,
984 &kernel,&user)) {
2d7a9237 985 timebuf->tms_utime = filetime_to_clock(&user);
986 timebuf->tms_stime = filetime_to_clock(&kernel);
d55594ae 987 timebuf->tms_cutime = 0;
988 timebuf->tms_cstime = 0;
989
990 } else {
991 /* That failed - e.g. Win95 fallback to clock() */
992 clock_t t = clock();
993 timebuf->tms_utime = t;
994 timebuf->tms_stime = 0;
995 timebuf->tms_cutime = 0;
996 timebuf->tms_cstime = 0;
997 }
68dc0745 998 return 0;
0a753a76 999}
1000
ad0751ec 1001/* fix utime() so it works on directories in NT
1002 * thanks to Jan Dubois <jan.dubois@ibm.net>
1003 */
1004static BOOL
1005filetime_from_time(PFILETIME pFileTime, time_t Time)
1006{
1007 struct tm *pTM = gmtime(&Time);
1008 SYSTEMTIME SystemTime;
1009
1010 if (pTM == NULL)
1011 return FALSE;
1012
1013 SystemTime.wYear = pTM->tm_year + 1900;
1014 SystemTime.wMonth = pTM->tm_mon + 1;
1015 SystemTime.wDay = pTM->tm_mday;
1016 SystemTime.wHour = pTM->tm_hour;
1017 SystemTime.wMinute = pTM->tm_min;
1018 SystemTime.wSecond = pTM->tm_sec;
1019 SystemTime.wMilliseconds = 0;
1020
1021 return SystemTimeToFileTime(&SystemTime, pFileTime);
1022}
1023
1024DllExport int
3b405fc5 1025win32_utime(const char *filename, struct utimbuf *times)
ad0751ec 1026{
1027 HANDLE handle;
1028 FILETIME ftCreate;
1029 FILETIME ftAccess;
1030 FILETIME ftWrite;
1031 struct utimbuf TimeBuffer;
1032
1033 int rc = utime(filename,times);
1034 /* EACCES: path specifies directory or readonly file */
1035 if (rc == 0 || errno != EACCES /* || !IsWinNT() */)
1036 return rc;
1037
1038 if (times == NULL) {
1039 times = &TimeBuffer;
1040 time(&times->actime);
1041 times->modtime = times->actime;
1042 }
1043
1044 /* This will (and should) still fail on readonly files */
1045 handle = CreateFile(filename, GENERIC_READ | GENERIC_WRITE,
1046 FILE_SHARE_READ | FILE_SHARE_DELETE, NULL,
1047 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
1048 if (handle == INVALID_HANDLE_VALUE)
1049 return rc;
1050
1051 if (GetFileTime(handle, &ftCreate, &ftAccess, &ftWrite) &&
1052 filetime_from_time(&ftAccess, times->actime) &&
1053 filetime_from_time(&ftWrite, times->modtime) &&
1054 SetFileTime(handle, &ftCreate, &ftAccess, &ftWrite))
1055 {
1056 rc = 0;
1057 }
1058
1059 CloseHandle(handle);
1060 return rc;
1061}
1062
2d7a9237 1063DllExport int
f55ee38a 1064win32_waitpid(int pid, int *status, int flags)
1065{
1066 int rc;
1067 if (pid == -1)
1068 return win32_wait(status);
1069 else {
1070 rc = cwait(status, pid, WAIT_CHILD);
1071 /* cwait() returns differently on Borland */
1072#ifdef __BORLANDC__
1073 if (status)
1074 *status = (((*status >> 8) & 0xff) | ((*status << 8) & 0xff00));
1075#endif
1076 remove_dead_process((HANDLE)pid);
1077 }
1078 return rc >= 0 ? pid : rc;
1079}
1080
1081DllExport int
2d7a9237 1082win32_wait(int *status)
1083{
4b556e6c 1084#ifdef USE_RTL_WAIT
2d7a9237 1085 return wait(status);
1086#else
1087 /* XXX this wait emulation only knows about processes
1088 * spawned via win32_spawnvp(P_NOWAIT, ...).
1089 */
1090 int i, retval;
1091 DWORD exitcode, waitcode;
1092
1093 if (!w32_num_children) {
1094 errno = ECHILD;
1095 return -1;
1096 }
1097
1098 /* if a child exists, wait for it to die */
1099 waitcode = WaitForMultipleObjects(w32_num_children,
1100 w32_child_pids,
1101 FALSE,
1102 INFINITE);
1103 if (waitcode != WAIT_FAILED) {
1104 if (waitcode >= WAIT_ABANDONED_0
1105 && waitcode < WAIT_ABANDONED_0 + w32_num_children)
1106 i = waitcode - WAIT_ABANDONED_0;
1107 else
1108 i = waitcode - WAIT_OBJECT_0;
1109 if (GetExitCodeProcess(w32_child_pids[i], &exitcode) ) {
1110 CloseHandle(w32_child_pids[i]);
1111 *status = (int)((exitcode & 0xff) << 8);
1112 retval = (int)w32_child_pids[i];
1113 Copy(&w32_child_pids[i+1], &w32_child_pids[i],
1114 (w32_num_children-i-1), HANDLE);
1115 w32_num_children--;
1116 return retval;
1117 }
1118 }
1119
1120FAILED:
1121 errno = GetLastError();
1122 return -1;
1123
1124#endif
1125}
d55594ae 1126
2d7a9237 1127static UINT timerid = 0;
d55594ae 1128
1129static VOID CALLBACK TimerProc(HWND win, UINT msg, UINT id, DWORD time)
1130{
1131 KillTimer(NULL,timerid);
1132 timerid=0;
1133 sighandler(14);
1134}
1135
f3986ebb 1136DllExport unsigned int
1137win32_alarm(unsigned int sec)
0a753a76 1138{
d55594ae 1139 /*
1140 * the 'obvious' implentation is SetTimer() with a callback
1141 * which does whatever receiving SIGALRM would do
1142 * we cannot use SIGALRM even via raise() as it is not
1143 * one of the supported codes in <signal.h>
1144 *
1145 * Snag is unless something is looking at the message queue
1146 * nothing happens :-(
1147 */
1148 if (sec)
1149 {
1150 timerid = SetTimer(NULL,timerid,sec*1000,(TIMERPROC)TimerProc);
1151 if (!timerid)
1152 croak("Cannot set timer");
1153 }
1154 else
1155 {
1156 if (timerid)
1157 {
1158 KillTimer(NULL,timerid);
1159 timerid=0;
1160 }
1161 }
68dc0745 1162 return 0;
0a753a76 1163}
1164
ff95b63e 1165#if defined(HAVE_DES_FCRYPT) || defined(PERL_OBJECT)
26618a56 1166#ifdef HAVE_DES_FCRYPT
2d77217b 1167extern char * des_fcrypt(const char *txt, const char *salt, char *cbuf);
ff95b63e 1168#endif
26618a56 1169
1170DllExport char *
1171win32_crypt(const char *txt, const char *salt)
1172{
ff95b63e 1173#ifdef HAVE_DES_FCRYPT
26618a56 1174 dTHR;
2d77217b 1175 return des_fcrypt(txt, salt, crypt_buffer);
ff95b63e 1176#else
1177 die("The crypt() function is unimplemented due to excessive paranoia.");
b8957cf1 1178 return Nullch;
ff95b63e 1179#endif
26618a56 1180}
1181#endif
1182
f3986ebb 1183#ifdef USE_FIXED_OSFHANDLE
390b85e7 1184
1185EXTERN_C int __cdecl _alloc_osfhnd(void);
1186EXTERN_C int __cdecl _set_osfhnd(int fh, long value);
1187EXTERN_C void __cdecl _lock_fhandle(int);
1188EXTERN_C void __cdecl _unlock_fhandle(int);
1189EXTERN_C void __cdecl _unlock(int);
1190
1191#if (_MSC_VER >= 1000)
1192typedef struct {
1193 long osfhnd; /* underlying OS file HANDLE */
1194 char osfile; /* attributes of file (e.g., open in text mode?) */
1195 char pipech; /* one char buffer for handles opened on pipes */
1196#if defined (_MT) && !defined (DLL_FOR_WIN32S)
1197 int lockinitflag;
1198 CRITICAL_SECTION lock;
1199#endif /* defined (_MT) && !defined (DLL_FOR_WIN32S) */
1200} ioinfo;
1201
1202EXTERN_C ioinfo * __pioinfo[];
1203
1204#define IOINFO_L2E 5
1205#define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E)
1206#define _pioinfo(i) (__pioinfo[i >> IOINFO_L2E] + (i & (IOINFO_ARRAY_ELTS - 1)))
1207#define _osfile(i) (_pioinfo(i)->osfile)
1208
1209#else /* (_MSC_VER >= 1000) */
1210extern char _osfile[];
1211#endif /* (_MSC_VER >= 1000) */
1212
1213#define FOPEN 0x01 /* file handle open */
1214#define FAPPEND 0x20 /* file handle opened O_APPEND */
1215#define FDEV 0x40 /* file handle refers to device */
1216#define FTEXT 0x80 /* file handle is in text mode */
1217
1218#define _STREAM_LOCKS 26 /* Table of stream locks */
1219#define _LAST_STREAM_LOCK (_STREAM_LOCKS+_NSTREAM_-1) /* Last stream lock */
1220#define _FH_LOCKS (_LAST_STREAM_LOCK+1) /* Table of fh locks */
1221
1222/***
1223*int my_open_osfhandle(long osfhandle, int flags) - open C Runtime file handle
1224*
1225*Purpose:
1226* This function allocates a free C Runtime file handle and associates
1227* it with the Win32 HANDLE specified by the first parameter. This is a
1228* temperary fix for WIN95's brain damage GetFileType() error on socket
1229* we just bypass that call for socket
1230*
1231*Entry:
1232* long osfhandle - Win32 HANDLE to associate with C Runtime file handle.
1233* int flags - flags to associate with C Runtime file handle.
1234*
1235*Exit:
1236* returns index of entry in fh, if successful
1237* return -1, if no free entry is found
1238*
1239*Exceptions:
1240*
1241*******************************************************************************/
1242
1243static int
1244my_open_osfhandle(long osfhandle, int flags)
1245{
1246 int fh;
1247 char fileflags; /* _osfile flags */
1248
1249 /* copy relevant flags from second parameter */
1250 fileflags = FDEV;
1251
9404a519 1252 if (flags & O_APPEND)
390b85e7 1253 fileflags |= FAPPEND;
1254
9404a519 1255 if (flags & O_TEXT)
390b85e7 1256 fileflags |= FTEXT;
1257
1258 /* attempt to allocate a C Runtime file handle */
9404a519 1259 if ((fh = _alloc_osfhnd()) == -1) {
390b85e7 1260 errno = EMFILE; /* too many open files */
1261 _doserrno = 0L; /* not an OS error */
1262 return -1; /* return error to caller */
1263 }
1264
1265 /* the file is open. now, set the info in _osfhnd array */
1266 _set_osfhnd(fh, osfhandle);
1267
1268 fileflags |= FOPEN; /* mark as open */
1269
1270#if (_MSC_VER >= 1000)
1271 _osfile(fh) = fileflags; /* set osfile entry */
1272 _unlock_fhandle(fh);
1273#else
1274 _osfile[fh] = fileflags; /* set osfile entry */
1275 _unlock(fh+_FH_LOCKS); /* unlock handle */
1276#endif
1277
1278 return fh; /* return handle */
1279}
1280
1281#define _open_osfhandle my_open_osfhandle
f3986ebb 1282#endif /* USE_FIXED_OSFHANDLE */
390b85e7 1283
1284/* simulate flock by locking a range on the file */
1285
1286#define LK_ERR(f,i) ((f) ? (i = 0) : (errno = GetLastError()))
1287#define LK_LEN 0xffff0000
1288
f3986ebb 1289DllExport int
1290win32_flock(int fd, int oper)
390b85e7 1291{
1292 OVERLAPPED o;
1293 int i = -1;
1294 HANDLE fh;
1295
f3986ebb 1296 if (!IsWinNT()) {
1297 croak("flock() unimplemented on this platform");
1298 return -1;
1299 }
390b85e7 1300 fh = (HANDLE)_get_osfhandle(fd);
1301 memset(&o, 0, sizeof(o));
1302
1303 switch(oper) {
1304 case LOCK_SH: /* shared lock */
1305 LK_ERR(LockFileEx(fh, 0, 0, LK_LEN, 0, &o),i);
1306 break;
1307 case LOCK_EX: /* exclusive lock */
1308 LK_ERR(LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, LK_LEN, 0, &o),i);
1309 break;
1310 case LOCK_SH|LOCK_NB: /* non-blocking shared lock */
1311 LK_ERR(LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY, 0, LK_LEN, 0, &o),i);
1312 break;
1313 case LOCK_EX|LOCK_NB: /* non-blocking exclusive lock */
1314 LK_ERR(LockFileEx(fh,
1315 LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY,
1316 0, LK_LEN, 0, &o),i);
1317 break;
1318 case LOCK_UN: /* unlock lock */
1319 LK_ERR(UnlockFileEx(fh, 0, LK_LEN, 0, &o),i);
1320 break;
1321 default: /* unknown */
1322 errno = EINVAL;
1323 break;
1324 }
1325 return i;
1326}
1327
1328#undef LK_ERR
1329#undef LK_LEN
1330
68dc0745 1331/*
1332 * redirected io subsystem for all XS modules
1333 *
1334 */
0a753a76 1335
68dc0745 1336DllExport int *
1337win32_errno(void)
0a753a76 1338{
390b85e7 1339 return (&errno);
0a753a76 1340}
1341
dcb2879a 1342DllExport char ***
1343win32_environ(void)
1344{
390b85e7 1345 return (&(_environ));
dcb2879a 1346}
1347
68dc0745 1348/* the rest are the remapped stdio routines */
1349DllExport FILE *
1350win32_stderr(void)
0a753a76 1351{
390b85e7 1352 return (stderr);
0a753a76 1353}
1354
68dc0745 1355DllExport FILE *
1356win32_stdin(void)
0a753a76 1357{
390b85e7 1358 return (stdin);
0a753a76 1359}
1360
68dc0745 1361DllExport FILE *
1362win32_stdout()
0a753a76 1363{
390b85e7 1364 return (stdout);
0a753a76 1365}
1366
68dc0745 1367DllExport int
1368win32_ferror(FILE *fp)
0a753a76 1369{
390b85e7 1370 return (ferror(fp));
0a753a76 1371}
1372
1373
68dc0745 1374DllExport int
1375win32_feof(FILE *fp)
0a753a76 1376{
390b85e7 1377 return (feof(fp));
0a753a76 1378}
1379
68dc0745 1380/*
1381 * Since the errors returned by the socket error function
1382 * WSAGetLastError() are not known by the library routine strerror
1383 * we have to roll our own.
1384 */
0a753a76 1385
68dc0745 1386DllExport char *
1387win32_strerror(int e)
0a753a76 1388{
3e3baf6d 1389#ifndef __BORLANDC__ /* Borland intolerance */
68dc0745 1390 extern int sys_nerr;
3e3baf6d 1391#endif
68dc0745 1392 DWORD source = 0;
0a753a76 1393
9404a519 1394 if (e < 0 || e > sys_nerr) {
c53bd28a 1395 dTHR;
9404a519 1396 if (e < 0)
68dc0745 1397 e = GetLastError();
0a753a76 1398
9404a519 1399 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, &source, e, 0,
68dc0745 1400 strerror_buffer, sizeof(strerror_buffer), NULL) == 0)
1401 strcpy(strerror_buffer, "Unknown Error");
0a753a76 1402
68dc0745 1403 return strerror_buffer;
1404 }
390b85e7 1405 return strerror(e);
0a753a76 1406}
1407
22fae026 1408DllExport void
3730b96e 1409win32_str_os_error(void *sv, DWORD dwErr)
22fae026 1410{
1411 DWORD dwLen;
1412 char *sMsg;
1413 dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
1414 |FORMAT_MESSAGE_IGNORE_INSERTS
1415 |FORMAT_MESSAGE_FROM_SYSTEM, NULL,
1416 dwErr, 0, (char *)&sMsg, 1, NULL);
1417 if (0 < dwLen) {
1418 while (0 < dwLen && isspace(sMsg[--dwLen]))
1419 ;
1420 if ('.' != sMsg[dwLen])
1421 dwLen++;
1422 sMsg[dwLen]= '\0';
1423 }
1424 if (0 == dwLen) {
c69f6586 1425 sMsg = (char*)LocalAlloc(0, 64/**sizeof(TCHAR)*/);
22fae026 1426 dwLen = sprintf(sMsg,
1427 "Unknown error #0x%lX (lookup 0x%lX)",
1428 dwErr, GetLastError());
1429 }
3730b96e 1430 sv_setpvn((SV*)sv, sMsg, dwLen);
22fae026 1431 LocalFree(sMsg);
1432}
1433
1434
68dc0745 1435DllExport int
1436win32_fprintf(FILE *fp, const char *format, ...)
0a753a76 1437{
68dc0745 1438 va_list marker;
1439 va_start(marker, format); /* Initialize variable arguments. */
0a753a76 1440
390b85e7 1441 return (vfprintf(fp, format, marker));
0a753a76 1442}
1443
68dc0745 1444DllExport int
1445win32_printf(const char *format, ...)
0a753a76 1446{
68dc0745 1447 va_list marker;
1448 va_start(marker, format); /* Initialize variable arguments. */
0a753a76 1449
390b85e7 1450 return (vprintf(format, marker));
0a753a76 1451}
1452
68dc0745 1453DllExport int
1454win32_vfprintf(FILE *fp, const char *format, va_list args)
0a753a76 1455{
390b85e7 1456 return (vfprintf(fp, format, args));
0a753a76 1457}
1458
96e4d5b1 1459DllExport int
1460win32_vprintf(const char *format, va_list args)
1461{
390b85e7 1462 return (vprintf(format, args));
96e4d5b1 1463}
1464
68dc0745 1465DllExport size_t
1466win32_fread(void *buf, size_t size, size_t count, FILE *fp)
0a753a76 1467{
390b85e7 1468 return fread(buf, size, count, fp);
0a753a76 1469}
1470
68dc0745 1471DllExport size_t
1472win32_fwrite(const void *buf, size_t size, size_t count, FILE *fp)
0a753a76 1473{
390b85e7 1474 return fwrite(buf, size, count, fp);
0a753a76 1475}
1476
68dc0745 1477DllExport FILE *
1478win32_fopen(const char *filename, const char *mode)
0a753a76 1479{
68dc0745 1480 if (stricmp(filename, "/dev/null")==0)
390b85e7 1481 return fopen("NUL", mode);
1482 return fopen(filename, mode);
0a753a76 1483}
1484
f3986ebb 1485#ifndef USE_SOCKETS_AS_HANDLES
1486#undef fdopen
1487#define fdopen my_fdopen
1488#endif
1489
68dc0745 1490DllExport FILE *
1491win32_fdopen( int handle, const char *mode)
0a753a76 1492{
390b85e7 1493 return fdopen(handle, (char *) mode);
0a753a76 1494}
1495
68dc0745 1496DllExport FILE *
1497win32_freopen( const char *path, const char *mode, FILE *stream)
0a753a76 1498{
68dc0745 1499 if (stricmp(path, "/dev/null")==0)
390b85e7 1500 return freopen("NUL", mode, stream);
1501 return freopen(path, mode, stream);
0a753a76 1502}
1503
68dc0745 1504DllExport int
1505win32_fclose(FILE *pf)
0a753a76 1506{
f3986ebb 1507 return my_fclose(pf); /* defined in win32sck.c */
0a753a76 1508}
1509
68dc0745 1510DllExport int
1511win32_fputs(const char *s,FILE *pf)
0a753a76 1512{
390b85e7 1513 return fputs(s, pf);
0a753a76 1514}
1515
68dc0745 1516DllExport int
1517win32_fputc(int c,FILE *pf)
0a753a76 1518{
390b85e7 1519 return fputc(c,pf);
0a753a76 1520}
1521
68dc0745 1522DllExport int
1523win32_ungetc(int c,FILE *pf)
0a753a76 1524{
390b85e7 1525 return ungetc(c,pf);
0a753a76 1526}
1527
68dc0745 1528DllExport int
1529win32_getc(FILE *pf)
0a753a76 1530{
390b85e7 1531 return getc(pf);
0a753a76 1532}
1533
68dc0745 1534DllExport int
1535win32_fileno(FILE *pf)
0a753a76 1536{
390b85e7 1537 return fileno(pf);
0a753a76 1538}
1539
68dc0745 1540DllExport void
1541win32_clearerr(FILE *pf)
0a753a76 1542{
390b85e7 1543 clearerr(pf);
68dc0745 1544 return;
0a753a76 1545}
1546
68dc0745 1547DllExport int
1548win32_fflush(FILE *pf)
0a753a76 1549{
390b85e7 1550 return fflush(pf);
0a753a76 1551}
1552
68dc0745 1553DllExport long
1554win32_ftell(FILE *pf)
0a753a76 1555{
390b85e7 1556 return ftell(pf);
0a753a76 1557}
1558
68dc0745 1559DllExport int
1560win32_fseek(FILE *pf,long offset,int origin)
0a753a76 1561{
390b85e7 1562 return fseek(pf, offset, origin);
0a753a76 1563}
1564
68dc0745 1565DllExport int
1566win32_fgetpos(FILE *pf,fpos_t *p)
0a753a76 1567{
390b85e7 1568 return fgetpos(pf, p);
0a753a76 1569}
1570
68dc0745 1571DllExport int
1572win32_fsetpos(FILE *pf,const fpos_t *p)
0a753a76 1573{
390b85e7 1574 return fsetpos(pf, p);
0a753a76 1575}
1576
68dc0745 1577DllExport void
1578win32_rewind(FILE *pf)
0a753a76 1579{
390b85e7 1580 rewind(pf);
68dc0745 1581 return;
0a753a76 1582}
1583
68dc0745 1584DllExport FILE*
1585win32_tmpfile(void)
0a753a76 1586{
390b85e7 1587 return tmpfile();
0a753a76 1588}
1589
68dc0745 1590DllExport void
1591win32_abort(void)
0a753a76 1592{
390b85e7 1593 abort();
68dc0745 1594 return;
0a753a76 1595}
1596
68dc0745 1597DllExport int
22239a37 1598win32_fstat(int fd,struct stat *sbufptr)
0a753a76 1599{
22239a37 1600 return fstat(fd,sbufptr);
0a753a76 1601}
1602
68dc0745 1603DllExport int
1604win32_pipe(int *pfd, unsigned int size, int mode)
0a753a76 1605{
390b85e7 1606 return _pipe(pfd, size, mode);
0a753a76 1607}
1608
50892819 1609/*
1610 * a popen() clone that respects PERL5SHELL
1611 */
1612
68dc0745 1613DllExport FILE*
1614win32_popen(const char *command, const char *mode)
0a753a76 1615{
4b556e6c 1616#ifdef USE_RTL_POPEN
390b85e7 1617 return _popen(command, mode);
50892819 1618#else
1619 int p[2];
1620 int parent, child;
1621 int stdfd, oldfd;
1622 int ourmode;
1623 int childpid;
1624
1625 /* establish which ends read and write */
1626 if (strchr(mode,'w')) {
1627 stdfd = 0; /* stdin */
1628 parent = 1;
1629 child = 0;
1630 }
1631 else if (strchr(mode,'r')) {
1632 stdfd = 1; /* stdout */
1633 parent = 0;
1634 child = 1;
1635 }
1636 else
1637 return NULL;
1638
1639 /* set the correct mode */
1640 if (strchr(mode,'b'))
1641 ourmode = O_BINARY;
1642 else if (strchr(mode,'t'))
1643 ourmode = O_TEXT;
1644 else
1645 ourmode = _fmode & (O_TEXT | O_BINARY);
1646
1647 /* the child doesn't inherit handles */
1648 ourmode |= O_NOINHERIT;
1649
1650 if (win32_pipe( p, 512, ourmode) == -1)
1651 return NULL;
1652
1653 /* save current stdfd */
1654 if ((oldfd = win32_dup(stdfd)) == -1)
1655 goto cleanup;
1656
1657 /* make stdfd go to child end of pipe (implicitly closes stdfd) */
1658 /* stdfd will be inherited by the child */
1659 if (win32_dup2(p[child], stdfd) == -1)
1660 goto cleanup;
1661
1662 /* close the child end in parent */
1663 win32_close(p[child]);
1664
1665 /* start the child */
1666 if ((childpid = do_spawn_nowait((char*)command)) == -1)
1667 goto cleanup;
1668
1669 /* revert stdfd to whatever it was before */
1670 if (win32_dup2(oldfd, stdfd) == -1)
1671 goto cleanup;
1672
1673 /* close saved handle */
1674 win32_close(oldfd);
1675
4b556e6c 1676 sv_setiv(*av_fetch(w32_fdpid, p[parent], TRUE), childpid);
50892819 1677
1678 /* we have an fd, return a file stream */
1679 return (win32_fdopen(p[parent], (char *)mode));
1680
1681cleanup:
1682 /* we don't need to check for errors here */
1683 win32_close(p[0]);
1684 win32_close(p[1]);
1685 if (oldfd != -1) {
1686 win32_dup2(oldfd, stdfd);
1687 win32_close(oldfd);
1688 }
1689 return (NULL);
1690
4b556e6c 1691#endif /* USE_RTL_POPEN */
0a753a76 1692}
1693
50892819 1694/*
1695 * pclose() clone
1696 */
1697
68dc0745 1698DllExport int
1699win32_pclose(FILE *pf)
0a753a76 1700{
4b556e6c 1701#ifdef USE_RTL_POPEN
390b85e7 1702 return _pclose(pf);
50892819 1703#else
50892819 1704
e17cb2a9 1705 int childpid, status;
1706 SV *sv;
1707
4b556e6c 1708 sv = *av_fetch(w32_fdpid, win32_fileno(pf), TRUE);
e17cb2a9 1709 if (SvIOK(sv))
1710 childpid = SvIVX(sv);
1711 else
1712 childpid = 0;
50892819 1713
1714 if (!childpid) {
1715 errno = EBADF;
1716 return -1;
1717 }
1718
1719 win32_fclose(pf);
e17cb2a9 1720 SvIVX(sv) = 0;
1721
f55ee38a 1722 remove_dead_process((HANDLE)childpid);
50892819 1723
1724 /* wait for the child */
1725 if (cwait(&status, childpid, WAIT_CHILD) == -1)
1726 return (-1);
1727 /* cwait() returns differently on Borland */
1728#ifdef __BORLANDC__
1729 return (((status >> 8) & 0xff) | ((status << 8) & 0xff00));
1730#else
1731 return (status);
1732#endif
1733
4b556e6c 1734#endif /* USE_RTL_POPEN */
0a753a76 1735}
1736
68dc0745 1737DllExport int
8d9b2e3c 1738win32_rename(const char *oname, const char *newname)
e24c7c18 1739{
1740 char szNewWorkName[MAX_PATH+1];
1741 WIN32_FIND_DATA fdOldFile, fdNewFile;
1742 HANDLE handle;
1743 char *ptr;
1744
8d9b2e3c 1745 if ((strchr(oname, '\\') || strchr(oname, '/'))
e24c7c18 1746 && strchr(newname, '\\') == NULL
1747 && strchr(newname, '/') == NULL)
1748 {
8d9b2e3c 1749 strcpy(szNewWorkName, oname);
e24c7c18 1750 if ((ptr = strrchr(szNewWorkName, '\\')) == NULL)
1751 ptr = strrchr(szNewWorkName, '/');
1752 strcpy(++ptr, newname);
1753 }
1754 else
1755 strcpy(szNewWorkName, newname);
1756
8d9b2e3c 1757 if (stricmp(oname, szNewWorkName) != 0) {
e24c7c18 1758 // check that we're not being fooled by relative paths
1759 // and only delete the new file
1760 // 1) if it exists
1761 // 2) it is not the same file as the old file
1762 // 3) old file exist
1763 // GetFullPathName does not return the long file name on some systems
8d9b2e3c 1764 handle = FindFirstFile(oname, &fdOldFile);
e24c7c18 1765 if (handle != INVALID_HANDLE_VALUE) {
1766 FindClose(handle);
1767
1768 handle = FindFirstFile(szNewWorkName, &fdNewFile);
1769
1770 if (handle != INVALID_HANDLE_VALUE)
1771 FindClose(handle);
1772 else
1773 fdNewFile.cFileName[0] = '\0';
1774
1775 if (strcmp(fdOldFile.cAlternateFileName,
1776 fdNewFile.cAlternateFileName) != 0
1777 && strcmp(fdOldFile.cFileName, fdNewFile.cFileName) != 0)
1778 {
1779 // file exists and not same file
1780 DeleteFile(szNewWorkName);
1781 }
1782 }
1783 }
8d9b2e3c 1784 return rename(oname, newname);
e24c7c18 1785}
1786
1787DllExport int
68dc0745 1788win32_setmode(int fd, int mode)
0a753a76 1789{
390b85e7 1790 return setmode(fd, mode);
0a753a76 1791}
1792
96e4d5b1 1793DllExport long
1794win32_lseek(int fd, long offset, int origin)
1795{
390b85e7 1796 return lseek(fd, offset, origin);
96e4d5b1 1797}
1798
1799DllExport long
1800win32_tell(int fd)
1801{
390b85e7 1802 return tell(fd);
96e4d5b1 1803}
1804
68dc0745 1805DllExport int
1806win32_open(const char *path, int flag, ...)
0a753a76 1807{
68dc0745 1808 va_list ap;
1809 int pmode;
0a753a76 1810
1811 va_start(ap, flag);
1812 pmode = va_arg(ap, int);
1813 va_end(ap);
1814
68dc0745 1815 if (stricmp(path, "/dev/null")==0)
390b85e7 1816 return open("NUL", flag, pmode);
1817 return open(path,flag,pmode);
0a753a76 1818}
1819
68dc0745 1820DllExport int
1821win32_close(int fd)
0a753a76 1822{
390b85e7 1823 return close(fd);
0a753a76 1824}
1825
68dc0745 1826DllExport int
96e4d5b1 1827win32_eof(int fd)
1828{
390b85e7 1829 return eof(fd);
96e4d5b1 1830}
1831
1832DllExport int
68dc0745 1833win32_dup(int fd)
0a753a76 1834{
390b85e7 1835 return dup(fd);
0a753a76 1836}
1837
68dc0745 1838DllExport int
1839win32_dup2(int fd1,int fd2)
0a753a76 1840{
390b85e7 1841 return dup2(fd1,fd2);
0a753a76 1842}
1843
68dc0745 1844DllExport int
3e3baf6d 1845win32_read(int fd, void *buf, unsigned int cnt)
0a753a76 1846{
390b85e7 1847 return read(fd, buf, cnt);
0a753a76 1848}
1849
68dc0745 1850DllExport int
3e3baf6d 1851win32_write(int fd, const void *buf, unsigned int cnt)
0a753a76 1852{
390b85e7 1853 return write(fd, buf, cnt);
0a753a76 1854}
1855
68dc0745 1856DllExport int
5aabfad6 1857win32_mkdir(const char *dir, int mode)
1858{
390b85e7 1859 return mkdir(dir); /* just ignore mode */
5aabfad6 1860}
96e4d5b1 1861
5aabfad6 1862DllExport int
1863win32_rmdir(const char *dir)
1864{
390b85e7 1865 return rmdir(dir);
5aabfad6 1866}
96e4d5b1 1867
5aabfad6 1868DllExport int
1869win32_chdir(const char *dir)
1870{
390b85e7 1871 return chdir(dir);
5aabfad6 1872}
96e4d5b1 1873
5aabfad6 1874DllExport int
3e3baf6d 1875win32_spawnvp(int mode, const char *cmdname, const char *const *argv)
0a753a76 1876{
2d7a9237 1877 int status;
1878
4b556e6c 1879#ifndef USE_RTL_WAIT
e17cb2a9 1880 if (mode == P_NOWAIT && w32_num_children >= MAXIMUM_WAIT_OBJECTS)
1881 return -1;
1882#endif
1883
2d7a9237 1884 status = spawnvp(mode, cmdname, (char * const *) argv);
4b556e6c 1885#ifndef USE_RTL_WAIT
2d7a9237 1886 /* XXX For the P_NOWAIT case, Borland RTL returns pinfo.dwProcessId
1887 * while VC RTL returns pinfo.hProcess. For purposes of the custom
1888 * implementation of win32_wait(), we assume the latter.
1889 */
1890 if (mode == P_NOWAIT && status >= 0)
1891 w32_child_pids[w32_num_children++] = (HANDLE)status;
1892#endif
1893 return status;
0a753a76 1894}
1895
6890e559 1896DllExport int
eb62e965 1897win32_execv(const char *cmdname, const char *const *argv)
1898{
1899 return execv(cmdname, (char *const *)argv);
1900}
1901
1902DllExport int
6890e559 1903win32_execvp(const char *cmdname, const char *const *argv)
1904{
390b85e7 1905 return execvp(cmdname, (char *const *)argv);
6890e559 1906}
1907
84902520 1908DllExport void
1909win32_perror(const char *str)
1910{
390b85e7 1911 perror(str);
84902520 1912}
1913
1914DllExport void
1915win32_setbuf(FILE *pf, char *buf)
1916{
390b85e7 1917 setbuf(pf, buf);
84902520 1918}
1919
1920DllExport int
1921win32_setvbuf(FILE *pf, char *buf, int type, size_t size)
1922{
390b85e7 1923 return setvbuf(pf, buf, type, size);
84902520 1924}
1925
1926DllExport int
1927win32_flushall(void)
1928{
390b85e7 1929 return flushall();
84902520 1930}
1931
1932DllExport int
1933win32_fcloseall(void)
1934{
390b85e7 1935 return fcloseall();
84902520 1936}
1937
1938DllExport char*
1939win32_fgets(char *s, int n, FILE *pf)
1940{
390b85e7 1941 return fgets(s, n, pf);
84902520 1942}
1943
1944DllExport char*
1945win32_gets(char *s)
1946{
390b85e7 1947 return gets(s);
84902520 1948}
1949
1950DllExport int
1951win32_fgetc(FILE *pf)
1952{
390b85e7 1953 return fgetc(pf);
84902520 1954}
1955
1956DllExport int
1957win32_putc(int c, FILE *pf)
1958{
390b85e7 1959 return putc(c,pf);
84902520 1960}
1961
1962DllExport int
1963win32_puts(const char *s)
1964{
390b85e7 1965 return puts(s);
84902520 1966}
1967
1968DllExport int
1969win32_getchar(void)
1970{
390b85e7 1971 return getchar();
84902520 1972}
1973
1974DllExport int
1975win32_putchar(int c)
1976{
390b85e7 1977 return putchar(c);
84902520 1978}
1979
bbc8f9de 1980#ifdef MYMALLOC
1981
1982#ifndef USE_PERL_SBRK
1983
1984static char *committed = NULL;
1985static char *base = NULL;
1986static char *reserved = NULL;
1987static char *brk = NULL;
1988static DWORD pagesize = 0;
1989static DWORD allocsize = 0;
1990
1991void *
1992sbrk(int need)
1993{
1994 void *result;
1995 if (!pagesize)
1996 {SYSTEM_INFO info;
1997 GetSystemInfo(&info);
1998 /* Pretend page size is larger so we don't perpetually
1999 * call the OS to commit just one page ...
2000 */
2001 pagesize = info.dwPageSize << 3;
2002 allocsize = info.dwAllocationGranularity;
2003 }
2004 /* This scheme fails eventually if request for contiguous
2005 * block is denied so reserve big blocks - this is only
2006 * address space not memory ...
2007 */
2008 if (brk+need >= reserved)
2009 {
2010 DWORD size = 64*1024*1024;
2011 char *addr;
2012 if (committed && reserved && committed < reserved)
2013 {
2014 /* Commit last of previous chunk cannot span allocations */
161b471a 2015 addr = (char *) VirtualAlloc(committed,reserved-committed,MEM_COMMIT,PAGE_READWRITE);
bbc8f9de 2016 if (addr)
2017 committed = reserved;
2018 }
2019 /* Reserve some (more) space
2020 * Note this is a little sneaky, 1st call passes NULL as reserved
2021 * so lets system choose where we start, subsequent calls pass
2022 * the old end address so ask for a contiguous block
2023 */
161b471a 2024 addr = (char *) VirtualAlloc(reserved,size,MEM_RESERVE,PAGE_NOACCESS);
bbc8f9de 2025 if (addr)
2026 {
2027 reserved = addr+size;
2028 if (!base)
2029 base = addr;
2030 if (!committed)
2031 committed = base;
2032 if (!brk)
2033 brk = committed;
2034 }
2035 else
2036 {
2037 return (void *) -1;
2038 }
2039 }
2040 result = brk;
2041 brk += need;
2042 if (brk > committed)
2043 {
2044 DWORD size = ((brk-committed + pagesize -1)/pagesize) * pagesize;
161b471a 2045 char *addr = (char *) VirtualAlloc(committed,size,MEM_COMMIT,PAGE_READWRITE);
bbc8f9de 2046 if (addr)
2047 {
2048 committed += size;
2049 }
2050 else
2051 return (void *) -1;
2052 }
2053 return result;
2054}
2055
2056#endif
2057#endif
2058
84902520 2059DllExport void*
2060win32_malloc(size_t size)
2061{
390b85e7 2062 return malloc(size);
84902520 2063}
2064
2065DllExport void*
2066win32_calloc(size_t numitems, size_t size)
2067{
390b85e7 2068 return calloc(numitems,size);
84902520 2069}
2070
2071DllExport void*
2072win32_realloc(void *block, size_t size)
2073{
390b85e7 2074 return realloc(block,size);
84902520 2075}
2076
2077DllExport void
2078win32_free(void *block)
2079{
390b85e7 2080 free(block);
84902520 2081}
2082
bbc8f9de 2083
68dc0745 2084int
65e48ea9 2085win32_open_osfhandle(long handle, int flags)
0a753a76 2086{
390b85e7 2087 return _open_osfhandle(handle, flags);
0a753a76 2088}
2089
68dc0745 2090long
65e48ea9 2091win32_get_osfhandle(int fd)
0a753a76 2092{
390b85e7 2093 return _get_osfhandle(fd);
0a753a76 2094}
7bac28a0 2095
7bac28a0 2096/*
2097 * Extras.
2098 */
2099
ad2e33dc 2100static
2101XS(w32_GetCwd)
2102{
2103 dXSARGS;
2104 SV *sv = sv_newmortal();
2105 /* Make one call with zero size - return value is required size */
2106 DWORD len = GetCurrentDirectory((DWORD)0,NULL);
2107 SvUPGRADE(sv,SVt_PV);
2108 SvGROW(sv,len);
2109 SvCUR(sv) = GetCurrentDirectory((DWORD) SvLEN(sv), SvPVX(sv));
2110 /*
2111 * If result != 0
2112 * then it worked, set PV valid,
2113 * else leave it 'undef'
2114 */
2115 if (SvCUR(sv))
2116 SvPOK_on(sv);
50892819 2117 EXTEND(SP,1);
ad2e33dc 2118 ST(0) = sv;
2119 XSRETURN(1);
2120}
2121
2122static
2123XS(w32_SetCwd)
2124{
2125 dXSARGS;
2126 if (items != 1)
2127 croak("usage: Win32::SetCurrentDirectory($cwd)");
6b88bc9c 2128 if (SetCurrentDirectory(SvPV(ST(0),PL_na)))
ad2e33dc 2129 XSRETURN_YES;
2130
2131 XSRETURN_NO;
2132}
2133
2134static
2135XS(w32_GetNextAvailDrive)
2136{
2137 dXSARGS;
2138 char ix = 'C';
2139 char root[] = "_:\\";
2140 while (ix <= 'Z') {
2141 root[0] = ix++;
2142 if (GetDriveType(root) == 1) {
2143 root[2] = '\0';
2144 XSRETURN_PV(root);
2145 }
2146 }
2147 XSRETURN_UNDEF;
2148}
2149
2150static
2151XS(w32_GetLastError)
2152{
2153 dXSARGS;
2154 XSRETURN_IV(GetLastError());
2155}
2156
2157static
2158XS(w32_LoginName)
2159{
2160 dXSARGS;
e34ffe5a 2161 char *name = getlogin_buffer;
2162 DWORD size = sizeof(getlogin_buffer);
ad2e33dc 2163 if (GetUserName(name,&size)) {
2164 /* size includes NULL */
2165 ST(0) = sv_2mortal(newSVpv(name,size-1));
2166 XSRETURN(1);
2167 }
2168 XSRETURN_UNDEF;
2169}
2170
2171static
2172XS(w32_NodeName)
2173{
2174 dXSARGS;
2175 char name[MAX_COMPUTERNAME_LENGTH+1];
2176 DWORD size = sizeof(name);
2177 if (GetComputerName(name,&size)) {
2178 /* size does NOT include NULL :-( */
2179 ST(0) = sv_2mortal(newSVpv(name,size));
2180 XSRETURN(1);
2181 }
2182 XSRETURN_UNDEF;
2183}
2184
2185
2186static
2187XS(w32_DomainName)
2188{
2189 dXSARGS;
8c9208bc 2190#ifndef HAS_NETWKSTAGETINFO
2191 /* mingw32 (and Win95) don't have NetWksta*(), so do it the old way */
ad2e33dc 2192 char name[256];
2193 DWORD size = sizeof(name);
2194 if (GetUserName(name,&size)) {
2195 char sid[1024];
2196 DWORD sidlen = sizeof(sid);
2197 char dname[256];
2198 DWORD dnamelen = sizeof(dname);
2199 SID_NAME_USE snu;
db15561c 2200 if (LookupAccountName(NULL, name, (PSID)&sid, &sidlen,
ad2e33dc 2201 dname, &dnamelen, &snu)) {
2202 XSRETURN_PV(dname); /* all that for this */
2203 }
2204 }
e56670dd 2205#else
8c9208bc 2206 /* this way is more reliable, in case user has a local account.
2207 * XXX need dynamic binding of netapi32.dll symbols or this will fail on
2208 * Win95. Probably makes more sense to move it into libwin32. */
9404a519 2209 char dname[256];
2210 DWORD dnamelen = sizeof(dname);
0a2408cf 2211 PWKSTA_INFO_100 pwi;
2212 if (NERR_Success == NetWkstaGetInfo(NULL, 100, (LPBYTE*)&pwi)) {
2213 if (pwi->wki100_langroup && *(pwi->wki100_langroup)) {
2214 WideCharToMultiByte(CP_ACP, NULL, pwi->wki100_langroup,
2215 -1, (LPSTR)dname, dnamelen, NULL, NULL);
2216 }
2217 else {
2218 WideCharToMultiByte(CP_ACP, NULL, pwi->wki100_computername,
2219 -1, (LPSTR)dname, dnamelen, NULL, NULL);
2220 }
2221 NetApiBufferFree(pwi);
9404a519 2222 XSRETURN_PV(dname);
2223 }
e56670dd 2224#endif
ad2e33dc 2225 XSRETURN_UNDEF;
2226}
2227
2228static
2229XS(w32_FsType)
2230{
2231 dXSARGS;
2232 char fsname[256];
2233 DWORD flags, filecomplen;
2234 if (GetVolumeInformation(NULL, NULL, 0, NULL, &filecomplen,
2235 &flags, fsname, sizeof(fsname))) {
2236 if (GIMME == G_ARRAY) {
2237 XPUSHs(sv_2mortal(newSVpv(fsname,0)));
2238 XPUSHs(sv_2mortal(newSViv(flags)));
2239 XPUSHs(sv_2mortal(newSViv(filecomplen)));
2240 PUTBACK;
2241 return;
2242 }
2243 XSRETURN_PV(fsname);
2244 }
2245 XSRETURN_UNDEF;
2246}
2247
2248static
2249XS(w32_GetOSVersion)
2250{
2251 dXSARGS;
2252 OSVERSIONINFO osver;
2253
2254 osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
2255 if (GetVersionEx(&osver)) {
2256 XPUSHs(newSVpv(osver.szCSDVersion, 0));
2257 XPUSHs(newSViv(osver.dwMajorVersion));
2258 XPUSHs(newSViv(osver.dwMinorVersion));
2259 XPUSHs(newSViv(osver.dwBuildNumber));
2260 XPUSHs(newSViv(osver.dwPlatformId));
2261 PUTBACK;
2262 return;
2263 }
2264 XSRETURN_UNDEF;
2265}
2266
2267static
2268XS(w32_IsWinNT)
2269{
2270 dXSARGS;
2271 XSRETURN_IV(IsWinNT());
2272}
2273
2274static
2275XS(w32_IsWin95)
2276{
2277 dXSARGS;
2278 XSRETURN_IV(IsWin95());
2279}
2280
2281static
2282XS(w32_FormatMessage)
2283{
2284 dXSARGS;
2285 DWORD source = 0;
2286 char msgbuf[1024];
2287
2288 if (items != 1)
2289 croak("usage: Win32::FormatMessage($errno)");
2290
2291 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
2292 &source, SvIV(ST(0)), 0,
2293 msgbuf, sizeof(msgbuf)-1, NULL))
2294 XSRETURN_PV(msgbuf);
2295
2296 XSRETURN_UNDEF;
2297}
2298
2299static
2300XS(w32_Spawn)
2301{
2302 dXSARGS;
2303 char *cmd, *args;
2304 PROCESS_INFORMATION stProcInfo;
2305 STARTUPINFO stStartInfo;
2306 BOOL bSuccess = FALSE;
2307
9404a519 2308 if (items != 3)
ad2e33dc 2309 croak("usage: Win32::Spawn($cmdName, $args, $PID)");
2310
6b88bc9c 2311 cmd = SvPV(ST(0),PL_na);
2312 args = SvPV(ST(1), PL_na);
ad2e33dc 2313
2314 memset(&stStartInfo, 0, sizeof(stStartInfo)); /* Clear the block */
2315 stStartInfo.cb = sizeof(stStartInfo); /* Set the structure size */
2316 stStartInfo.dwFlags = STARTF_USESHOWWINDOW; /* Enable wShowWindow control */
2317 stStartInfo.wShowWindow = SW_SHOWMINNOACTIVE; /* Start min (normal) */
2318
9404a519 2319 if (CreateProcess(
ad2e33dc 2320 cmd, /* Image path */
2321 args, /* Arguments for command line */
2322 NULL, /* Default process security */
2323 NULL, /* Default thread security */
2324 FALSE, /* Must be TRUE to use std handles */
2325 NORMAL_PRIORITY_CLASS, /* No special scheduling */
2326 NULL, /* Inherit our environment block */
2327 NULL, /* Inherit our currrent directory */
2328 &stStartInfo, /* -> Startup info */
2329 &stProcInfo)) /* <- Process info (if OK) */
2330 {
2331 CloseHandle(stProcInfo.hThread);/* library source code does this. */
2332 sv_setiv(ST(2), stProcInfo.dwProcessId);
2333 bSuccess = TRUE;
2334 }
2335 XSRETURN_IV(bSuccess);
2336}
2337
2338static
2339XS(w32_GetTickCount)
2340{
2341 dXSARGS;
2342 XSRETURN_IV(GetTickCount());
2343}
2344
2345static
2346XS(w32_GetShortPathName)
2347{
2348 dXSARGS;
2349 SV *shortpath;
e8bab181 2350 DWORD len;
ad2e33dc 2351
9404a519 2352 if (items != 1)
ad2e33dc 2353 croak("usage: Win32::GetShortPathName($longPathName)");
2354
2355 shortpath = sv_mortalcopy(ST(0));
2356 SvUPGRADE(shortpath, SVt_PV);
2357 /* src == target is allowed */
e8bab181 2358 do {
2359 len = GetShortPathName(SvPVX(shortpath),
2360 SvPVX(shortpath),
2361 SvLEN(shortpath));
2362 } while (len >= SvLEN(shortpath) && sv_grow(shortpath,len+1));
2363 if (len) {
2364 SvCUR_set(shortpath,len);
ad2e33dc 2365 ST(0) = shortpath;
e8bab181 2366 }
ad2e33dc 2367 else
6b88bc9c 2368 ST(0) = &PL_sv_undef;
ad2e33dc 2369 XSRETURN(1);
2370}
2371
ad0751ec 2372static
2373XS(w32_Sleep)
2374{
2375 dXSARGS;
2376 if (items != 1)
2377 croak("usage: Win32::Sleep($milliseconds)");
2378 Sleep(SvIV(ST(0)));
2379 XSRETURN_YES;
2380}
2381
ad2e33dc 2382void
f3986ebb 2383Perl_init_os_extras()
ad2e33dc 2384{
2385 char *file = __FILE__;
2386 dXSUB_SYS;
2387
4b556e6c 2388 w32_perlshell_tokens = Nullch;
2389 w32_perlshell_items = -1;
2390 w32_fdpid = newAV(); /* XXX needs to be in Perl_win32_init()? */
2391#ifndef USE_RTL_WAIT
2392 w32_num_children = 0;
2393#endif
2394
ad2e33dc 2395 /* these names are Activeware compatible */
2396 newXS("Win32::GetCwd", w32_GetCwd, file);
2397 newXS("Win32::SetCwd", w32_SetCwd, file);
2398 newXS("Win32::GetNextAvailDrive", w32_GetNextAvailDrive, file);
2399 newXS("Win32::GetLastError", w32_GetLastError, file);
2400 newXS("Win32::LoginName", w32_LoginName, file);
2401 newXS("Win32::NodeName", w32_NodeName, file);
2402 newXS("Win32::DomainName", w32_DomainName, file);
2403 newXS("Win32::FsType", w32_FsType, file);
2404 newXS("Win32::GetOSVersion", w32_GetOSVersion, file);
2405 newXS("Win32::IsWinNT", w32_IsWinNT, file);
2406 newXS("Win32::IsWin95", w32_IsWin95, file);
2407 newXS("Win32::FormatMessage", w32_FormatMessage, file);
2408 newXS("Win32::Spawn", w32_Spawn, file);
2409 newXS("Win32::GetTickCount", w32_GetTickCount, file);
2410 newXS("Win32::GetShortPathName", w32_GetShortPathName, file);
ad0751ec 2411 newXS("Win32::Sleep", w32_Sleep, file);
ad2e33dc 2412
2413 /* XXX Bloat Alert! The following Activeware preloads really
2414 * ought to be part of Win32::Sys::*, so they're not included
2415 * here.
2416 */
2417 /* LookupAccountName
2418 * LookupAccountSID
2419 * InitiateSystemShutdown
2420 * AbortSystemShutdown
2421 * ExpandEnvrironmentStrings
2422 */
2423}
2424
2425void
2426Perl_win32_init(int *argcp, char ***argvp)
2427{
2428 /* Disable floating point errors, Perl will trap the ones we
2429 * care about. VC++ RTL defaults to switching these off
2430 * already, but the Borland RTL doesn't. Since we don't
2431 * want to be at the vendor's whim on the default, we set
2432 * it explicitly here.
2433 */
a835ef8a 2434#if !defined(_ALPHA_) && !defined(__GNUC__)
ad2e33dc 2435 _control87(MCW_EM, MCW_EM);
3dc9191e 2436#endif
4b556e6c 2437 MALLOC_INIT;
ad2e33dc 2438}
d55594ae 2439
a868473f 2440#ifdef USE_BINMODE_SCRIPTS
2441
2442void
2443win32_strip_return(SV *sv)
2444{
2445 char *s = SvPVX(sv);
2446 char *e = s+SvCUR(sv);
2447 char *d = s;
2448 while (s < e)
2449 {
2450 if (*s == '\r' && s[1] == '\n')
2451 {
2452 *d++ = '\n';
2453 s += 2;
2454 }
2455 else
2456 {
2457 *d++ = *s++;
2458 }
2459 }
2460 SvCUR_set(sv,d-SvPVX(sv));
2461}
2462
2463#endif