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