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