This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Deparse.pm: handle optimised-away keys() better
[perl5.git] / win32 / wince.c
CommitLineData
e1caacb4
JH
1/* WINCE.C - stuff for Windows CE
2 *
ca6c63e1 3 * Time-stamp: <26/10/01 15:25:20 keuchel@keuchelnt>
e1caacb4
JH
4 *
5 * You may distribute under the terms of either the GNU General Public
6 * License or the Artistic License, as specified in the README file.
7 */
8
9#define WIN32_LEAN_AND_MEAN
10#define WIN32IO_IS_STDIO
11#include <windows.h>
216db7ee 12#include <signal.h>
e1caacb4 13
f4257e4d 14#define PERLIO_NOT_STDIO 0
e1caacb4 15
e1caacb4 16#define PerlIO FILE
e1caacb4
JH
17
18#define wince_private
19#include "errno.h"
20
21#include "EXTERN.h"
22#include "perl.h"
23
24#define NO_XSLOCKS
25#define PERL_NO_GET_CONTEXT
26#include "XSUB.h"
27
28#include "win32iop.h"
29#include <string.h>
30#include <stdarg.h>
31#include <float.h>
32#include <shellapi.h>
814ffeea 33#include <process.h>
e1caacb4
JH
34
35#define perl
36#include "celib_defs.h"
37#include "cewin32.h"
38#include "cecrt.h"
39#include "cewin32_defs.h"
40#include "cecrt_defs.h"
41
94081db1
VK
42#define GetCurrentDirectoryW XCEGetCurrentDirectoryW
43
e1caacb4
JH
44#ifdef PALM_SIZE
45#include "stdio-palmsize.h"
46#endif
47
48#define EXECF_EXEC 1
49#define EXECF_SPAWN 2
50#define EXECF_SPAWN_NOWAIT 3
51
52#if defined(PERL_IMPLICIT_SYS)
e1caacb4
JH
53# undef do_spawn
54# define do_spawn g_do_spawn
55# undef getlogin
56# define getlogin g_getlogin
57#endif
58
814ffeea
VK
59static void get_shell(void);
60static long tokenize(const char *str, char **dest, char ***destv);
61static int do_spawn2(pTHX_ char *cmd, int exectype);
62static BOOL has_shell_metachars(char *ptr);
e1caacb4
JH
63static long filetime_to_clock(PFILETIME ft);
64static BOOL filetime_from_time(PFILETIME ft, time_t t);
e6a0bbf8
NC
65static char * get_emd_part(SV **leading, STRLEN *const len,
66 char *trailing, ...);
814ffeea 67static void remove_dead_process(long deceased);
04a2c3d9 68static long find_pid(pTHX_ int pid);
814ffeea 69static char * qualified_path(const char *cmd);
e1caacb4 70static char * win32_get_xlib(const char *pl, const char *xlib,
e6a0bbf8 71 const char *libname, STRLEN *const len);
e1caacb4 72
814ffeea
VK
73#ifdef USE_ITHREADS
74static void remove_dead_pseudo_process(long child);
04a2c3d9 75static long find_pseudo_pid(pTHX_ int pid);
814ffeea
VK
76#endif
77
78int _fmode = O_TEXT; /* celib do not provide _fmode, so we define it here */
79
e1caacb4
JH
80START_EXTERN_C
81HANDLE w32_perldll_handle = INVALID_HANDLE_VALUE;
82char w32_module_name[MAX_PATH+1];
83END_EXTERN_C
84
85static DWORD w32_platform = (DWORD)-1;
86
f4257e4d 87int
e1caacb4
JH
88IsWin95(void)
89{
90 return (win32_os_id() == VER_PLATFORM_WIN32_WINDOWS);
91}
92
93int
94IsWinNT(void)
95{
96 return (win32_os_id() == VER_PLATFORM_WIN32_NT);
97}
98
99int
100IsWinCE(void)
101{
102 return (win32_os_id() == VER_PLATFORM_WIN32_CE);
103}
104
105EXTERN_C void
106set_w32_module_name(void)
107{
108 char* ptr;
109 XCEGetModuleFileNameA((HMODULE)((w32_perldll_handle == INVALID_HANDLE_VALUE)
110 ? XCEGetModuleHandleA(NULL)
111 : w32_perldll_handle),
112 w32_module_name, sizeof(w32_module_name));
113
114 /* normalize to forward slashes */
115 ptr = w32_module_name;
116 while (*ptr) {
117 if (*ptr == '\\')
118 *ptr = '/';
119 ++ptr;
120 }
121}
122
123/* *svp (if non-NULL) is expected to be POK (valid allocated SvPVX(*svp)) */
124static char*
125get_regstr_from(HKEY hkey, const char *valuename, SV **svp)
126{
127 /* Retrieve a REG_SZ or REG_EXPAND_SZ from the registry */
128 HKEY handle;
129 DWORD type;
130 const char *subkey = "Software\\Perl";
4e205ed6 131 char *str = NULL;
e1caacb4
JH
132 long retval;
133
134 retval = XCERegOpenKeyExA(hkey, subkey, 0, KEY_READ, &handle);
135 if (retval == ERROR_SUCCESS) {
136 DWORD datalen;
137 retval = XCERegQueryValueExA(handle, valuename, 0, &type, NULL, &datalen);
138 if (retval == ERROR_SUCCESS && type == REG_SZ) {
acfe0abc 139 dTHX;
e1caacb4 140 if (!*svp)
c2b90b61 141 *svp = sv_2mortal(newSVpvs(""));
e1caacb4
JH
142 SvGROW(*svp, datalen);
143 retval = XCERegQueryValueExA(handle, valuename, 0, NULL,
144 (PBYTE)SvPVX(*svp), &datalen);
145 if (retval == ERROR_SUCCESS) {
146 str = SvPVX(*svp);
147 SvCUR_set(*svp,datalen-1);
148 }
149 }
150 RegCloseKey(handle);
151 }
152 return str;
153}
154
155/* *svp (if non-NULL) is expected to be POK (valid allocated SvPVX(*svp)) */
156static char*
157get_regstr(const char *valuename, SV **svp)
158{
159 char *str = get_regstr_from(HKEY_CURRENT_USER, valuename, svp);
160 if (!str)
161 str = get_regstr_from(HKEY_LOCAL_MACHINE, valuename, svp);
162 return str;
163}
164
165/* *prev_pathp (if non-NULL) is expected to be POK (valid allocated SvPVX(sv)) */
166static char *
e6a0bbf8 167get_emd_part(SV **prev_pathp, STRLEN *const len, char *trailing_path, ...)
e1caacb4
JH
168{
169 char base[10];
170 va_list ap;
171 char mod_name[MAX_PATH+1];
172 char *ptr;
173 char *optr;
174 char *strip;
175 int oldsize, newsize;
176 STRLEN baselen;
177
178 va_start(ap, trailing_path);
179 strip = va_arg(ap, char *);
180
181 sprintf(base, "%d.%d", (int)PERL_REVISION, (int)PERL_VERSION);
182 baselen = strlen(base);
183
184 if (!*w32_module_name) {
185 set_w32_module_name();
186 }
187 strcpy(mod_name, w32_module_name);
188 ptr = strrchr(mod_name, '/');
189 while (ptr && strip) {
190 /* look for directories to skip back */
191 optr = ptr;
192 *ptr = '\0';
193 ptr = strrchr(mod_name, '/');
194 /* avoid stripping component if there is no slash,
195 * or it doesn't match ... */
196 if (!ptr || stricmp(ptr+1, strip) != 0) {
197 /* ... but not if component matches m|5\.$patchlevel.*| */
198 if (!ptr || !(*strip == '5' && *(ptr+1) == '5'
a15aa957
KW
199 && strnEQ(strip, base, baselen)
200 && strnEQ(ptr+1, base, baselen)))
e1caacb4
JH
201 {
202 *optr = '/';
203 ptr = optr;
204 }
205 }
206 strip = va_arg(ap, char *);
207 }
208 if (!ptr) {
209 ptr = mod_name;
210 *ptr++ = '.';
211 *ptr = '/';
212 }
213 va_end(ap);
214 strcpy(++ptr, trailing_path);
215
216 /* only add directory if it exists */
217 if (XCEGetFileAttributesA(mod_name) != (DWORD) -1) {
218 /* directory exists */
acfe0abc 219 dTHX;
e1caacb4 220 if (!*prev_pathp)
c2b90b61 221 *prev_pathp = sv_2mortal(newSVpvs(""));
46e2868e 222 sv_catpvs(*prev_pathp, ";");
e1caacb4 223 sv_catpv(*prev_pathp, mod_name);
e6a0bbf8
NC
224 if(len)
225 *len = SvCUR(*prev_pathp);
e1caacb4
JH
226 return SvPVX(*prev_pathp);
227 }
228
4e205ed6 229 return NULL;
e1caacb4
JH
230}
231
232char *
6937817d 233win32_get_privlib(WIN32_NO_REGISTRY_M_(const char *pl) STRLEN *const len)
e1caacb4 234{
acfe0abc 235 dTHX;
e1caacb4
JH
236 char *stdlib = "lib";
237 char buffer[MAX_PATH+1];
4e205ed6 238 SV *sv = NULL;
e1caacb4
JH
239
240 /* $stdlib = $HKCU{"lib-$]"} || $HKLM{"lib-$]"} || $HKCU{"lib"} || $HKLM{"lib"} || ""; */
241 sprintf(buffer, "%s-%s", stdlib, pl);
242 if (!get_regstr(buffer, &sv))
243 (void)get_regstr(stdlib, &sv);
244
245 /* $stdlib .= ";$EMD/../../lib" */
e6a0bbf8 246 return get_emd_part(&sv, len, stdlib, ARCHNAME, "bin", NULL);
e1caacb4
JH
247}
248
249static char *
e6a0bbf8
NC
250win32_get_xlib(const char *pl, const char *xlib, const char *libname,
251 STRLEN *const len)
e1caacb4 252{
acfe0abc 253 dTHX;
e1caacb4
JH
254 char regstr[40];
255 char pathstr[MAX_PATH+1];
4e205ed6
SP
256 SV *sv1 = NULL;
257 SV *sv2 = NULL;
e1caacb4
JH
258
259 /* $HKCU{"$xlib-$]"} || $HKLM{"$xlib-$]"} . ---; */
260 sprintf(regstr, "%s-%s", xlib, pl);
261 (void)get_regstr(regstr, &sv1);
262
263 /* $xlib .=
264 * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/$libname/$]/lib"; */
265 sprintf(pathstr, "%s/%s/lib", libname, pl);
e6a0bbf8 266 (void)get_emd_part(&sv1, NULL, pathstr, ARCHNAME, "bin", pl, NULL);
e1caacb4
JH
267
268 /* $HKCU{$xlib} || $HKLM{$xlib} . ---; */
269 (void)get_regstr(xlib, &sv2);
270
271 /* $xlib .=
272 * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/$libname/lib"; */
273 sprintf(pathstr, "%s/lib", libname);
e6a0bbf8 274 (void)get_emd_part(&sv2, NULL, pathstr, ARCHNAME, "bin", pl, NULL);
e1caacb4
JH
275
276 if (!sv1 && !sv2)
4e205ed6 277 return NULL;
e6a0bbf8
NC
278 if (!sv1) {
279 sv1 = sv2;
280 } else if (sv2) {
46e2868e 281 sv_catpvs(sv1, ";");
e6a0bbf8
NC
282 sv_catsv(sv1, sv2);
283 }
e1caacb4 284
e6a0bbf8
NC
285 if (len)
286 *len = SvCUR(sv1);
e1caacb4
JH
287 return SvPVX(sv1);
288}
289
290char *
e6a0bbf8 291win32_get_sitelib(const char *pl, STRLEN *const len)
e1caacb4 292{
e6a0bbf8 293 return win32_get_xlib(pl, "sitelib", "site", len);
e1caacb4
JH
294}
295
296#ifndef PERL_VENDORLIB_NAME
297# define PERL_VENDORLIB_NAME "vendor"
298#endif
299
300char *
e6a0bbf8 301win32_get_vendorlib(const char *pl, STRLEN *const len)
e1caacb4 302{
e6a0bbf8 303 return win32_get_xlib(pl, "vendorlib", PERL_VENDORLIB_NAME, len);
e1caacb4
JH
304}
305
814ffeea
VK
306static BOOL
307has_shell_metachars(char *ptr)
308{
309 int inquote = 0;
310 char quote = '\0';
311
312 /*
313 * Scan string looking for redirection (< or >) or pipe
314 * characters (|) that are not in a quoted string.
315 * Shell variable interpolation (%VAR%) can also happen inside strings.
316 */
317 while (*ptr) {
318 switch(*ptr) {
319 case '%':
320 return TRUE;
321 case '\'':
322 case '\"':
323 if (inquote) {
324 if (quote == *ptr) {
325 inquote = 0;
326 quote = '\0';
327 }
328 }
329 else {
330 quote = *ptr;
331 inquote++;
332 }
333 break;
334 case '>':
335 case '<':
336 case '|':
337 if (!inquote)
338 return TRUE;
339 default:
340 break;
341 }
342 ++ptr;
343 }
344 return FALSE;
345}
346
e1caacb4
JH
347#if !defined(PERL_IMPLICIT_SYS)
348/* since the current process environment is being updated in util.c
349 * the library functions will get the correct environment
350 */
351PerlIO *
751e07d2 352Perl_my_popen(pTHX_ const char *cmd, const char *mode)
e1caacb4
JH
353{
354 printf("popen(%s)\n", cmd);
355
356 Perl_croak(aTHX_ PL_no_func, "popen");
357 return NULL;
358}
359
360long
361Perl_my_pclose(pTHX_ PerlIO *fp)
362{
363 Perl_croak(aTHX_ PL_no_func, "pclose");
364 return -1;
365}
366#endif
367
368DllExport unsigned long
369win32_os_id(void)
370{
371 static OSVERSIONINFOA osver;
372
373 if (osver.dwPlatformId != w32_platform) {
374 memset(&osver, 0, sizeof(OSVERSIONINFOA));
375 osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
376 XCEGetVersionExA(&osver);
377 w32_platform = osver.dwPlatformId;
378 }
379 return (unsigned long)w32_platform;
380}
381
382DllExport int
383win32_getpid(void)
384{
814ffeea
VK
385 int pid;
386#ifdef USE_ITHREADS
387 dTHX;
388 if (w32_pseudo_id)
389 return -((int)w32_pseudo_id);
390#endif
391 pid = xcegetpid();
392 return pid;
e1caacb4
JH
393}
394
814ffeea
VK
395/* Tokenize a string. Words are null-separated, and the list
396 * ends with a doubled null. Any character (except null and
397 * including backslash) may be escaped by preceding it with a
398 * backslash (the backslash will be stripped).
399 * Returns number of words in result buffer.
400 */
401static long
402tokenize(const char *str, char **dest, char ***destv)
e1caacb4 403{
4e205ed6 404 char *retstart = NULL;
814ffeea
VK
405 char **retvstart = 0;
406 int items = -1;
407 if (str) {
408 dTHX;
409 int slen = strlen(str);
eb578fdb
KW
410 char *ret;
411 char **retv;
a02a5408
JC
412 Newx(ret, slen+2, char);
413 Newx(retv, (slen+3)/2, char*);
814ffeea
VK
414
415 retstart = ret;
416 retvstart = retv;
417 *retv = ret;
418 items = 0;
419 while (*str) {
420 *ret = *str++;
421 if (*ret == '\\' && *str)
422 *ret = *str++;
423 else if (*ret == ' ') {
424 while (*str == ' ')
425 str++;
426 if (ret == retstart)
427 ret--;
428 else {
429 *ret = '\0';
430 ++items;
431 if (*str)
432 *++retv = ret+1;
433 }
434 }
435 else if (!*str)
436 ++items;
437 ret++;
438 }
4e205ed6 439 retvstart[items] = NULL;
814ffeea
VK
440 *ret++ = '\0';
441 *ret = '\0';
442 }
443 *dest = retstart;
444 *destv = retvstart;
445 return items;
e1caacb4
JH
446}
447
448DllExport int
449win32_pipe(int *pfd, unsigned int size, int mode)
450{
216db7ee 451 dTHX;
e1caacb4
JH
452 Perl_croak(aTHX_ PL_no_func, "pipe");
453 return -1;
454}
455
456DllExport int
457win32_times(struct tms *timebuf)
458{
216db7ee 459 dTHX;
e1caacb4
JH
460 Perl_croak(aTHX_ PL_no_func, "times");
461 return -1;
462}
463
216db7ee
VK
464Sighandler_t
465win32_signal(int sig, Sighandler_t subcode)
42165d27 466{
1829b0dc 467 return xcesignal(sig, subcode);
42165d27 468}
216db7ee 469
814ffeea
VK
470static void
471get_shell(void)
472{
473 dTHX;
474 if (!w32_perlshell_tokens) {
475 /* we don't use COMSPEC here for two reasons:
476 * 1. the same reason perl on UNIX doesn't use SHELL--rampant and
477 * uncontrolled unportability of the ensuing scripts.
478 * 2. PERL5SHELL could be set to a shell that may not be fit for
479 * interactive use (which is what most programs look in COMSPEC
480 * for).
481 */
482 const char* defaultshell = (IsWinNT()
483 ? "cmd.exe /x/d/c" : "command.com /c");
484 const char *usershell = PerlEnv_getenv("PERL5SHELL");
485 w32_perlshell_items = tokenize(usershell ? usershell : defaultshell,
486 &w32_perlshell_tokens,
487 &w32_perlshell_vec);
488 }
489}
490
491int
492Perl_do_aspawn(pTHX_ SV *really, SV **mark, SV **sp)
493{
7918f24d
NC
494 PERL_ARGS_ASSERT_DO_ASPAWN;
495
814ffeea
VK
496 Perl_croak(aTHX_ PL_no_func, "aspawn");
497 return -1;
498}
42165d27 499
814ffeea
VK
500/* returns pointer to the next unquoted space or the end of the string */
501static char*
502find_next_space(const char *s)
e1caacb4 503{
814ffeea
VK
504 bool in_quotes = FALSE;
505 while (*s) {
506 /* ignore doubled backslashes, or backslash+quote */
507 if (*s == '\\' && (s[1] == '\\' || s[1] == '"')) {
508 s += 2;
509 }
510 /* keep track of when we're within quotes */
511 else if (*s == '"') {
512 s++;
513 in_quotes = !in_quotes;
514 }
515 /* break it up only at spaces that aren't in quotes */
516 else if (!in_quotes && isSPACE(*s))
517 return (char*)s;
518 else
519 s++;
520 }
521 return (char*)s;
522}
523
524#if 1
525static int
526do_spawn2(pTHX_ char *cmd, int exectype)
527{
528 char **a;
529 char *s;
530 char **argv;
531 int status = -1;
532 BOOL needToTry = TRUE;
533 char *cmd2;
534
535 /* Save an extra exec if possible. See if there are shell
536 * metacharacters in it */
537 if (!has_shell_metachars(cmd)) {
a02a5408
JC
538 Newx(argv, strlen(cmd) / 2 + 2, char*);
539 Newx(cmd2, strlen(cmd) + 1, char);
814ffeea
VK
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;
547 s = find_next_space(s);
548 if (*s)
549 *s++ = '\0';
550 }
4e205ed6 551 *a = NULL;
814ffeea
VK
552 if (argv[0]) {
553 switch (exectype) {
554 case EXECF_SPAWN:
555 status = win32_spawnvp(P_WAIT, argv[0],
556 (const char* const*)argv);
557 break;
558 case EXECF_SPAWN_NOWAIT:
559 status = win32_spawnvp(P_NOWAIT, argv[0],
560 (const char* const*)argv);
561 break;
562 case EXECF_EXEC:
563 status = win32_execvp(argv[0], (const char* const*)argv);
564 break;
565 }
566 if (status != -1 || errno == 0)
567 needToTry = FALSE;
568 }
569 Safefree(argv);
570 Safefree(cmd2);
571 }
572 if (needToTry) {
573 char **argv;
574 int i = -1;
575 get_shell();
a02a5408 576 Newx(argv, w32_perlshell_items + 2, char*);
814ffeea
VK
577 while (++i < w32_perlshell_items)
578 argv[i] = w32_perlshell_vec[i];
579 argv[i++] = cmd;
4e205ed6 580 argv[i] = NULL;
814ffeea
VK
581 switch (exectype) {
582 case EXECF_SPAWN:
583 status = win32_spawnvp(P_WAIT, argv[0],
584 (const char* const*)argv);
585 break;
586 case EXECF_SPAWN_NOWAIT:
587 status = win32_spawnvp(P_NOWAIT, argv[0],
588 (const char* const*)argv);
589 break;
590 case EXECF_EXEC:
591 status = win32_execvp(argv[0], (const char* const*)argv);
592 break;
593 }
594 cmd = argv[0];
595 Safefree(argv);
596 }
597 if (exectype == EXECF_SPAWN_NOWAIT) {
598 if (IsWin95())
599 PL_statusvalue = -1; /* >16bits hint for pp_system() */
600 }
601 else {
602 if (status < 0) {
603 if (ckWARN(WARN_EXEC))
604 Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't %s \"%s\": %s",
605 (exectype == EXECF_EXEC ? "exec" : "spawn"),
606 cmd, strerror(errno));
607 status = 255 * 256;
608 }
609 else
610 status *= 256;
611 PL_statusvalue = status;
612 }
613 return (status);
614}
615
616int
617Perl_do_spawn(pTHX_ char *cmd)
618{
7918f24d
NC
619 PERL_ARGS_ASSERT_DO_SPAWN;
620
814ffeea
VK
621 return do_spawn2(aTHX_ cmd, EXECF_SPAWN);
622}
623
624int
625Perl_do_spawn_nowait(pTHX_ char *cmd)
626{
7918f24d
NC
627 PERL_ARGS_ASSERT_DO_SPAWN_NOWAIT;
628
814ffeea
VK
629 return do_spawn2(aTHX_ cmd, EXECF_SPAWN_NOWAIT);
630}
631
632bool
751e07d2 633Perl_do_exec(pTHX_ const char *cmd)
814ffeea 634{
7918f24d
NC
635 PERL_ARGS_ASSERT_DO_EXEC;
636
814ffeea
VK
637 do_spawn2(aTHX_ cmd, EXECF_EXEC);
638 return FALSE;
639}
640
641/* The idea here is to read all the directory names into a string table
642 * (separated by nulls) and when one of the other dir functions is called
643 * return the pointer to the current file name.
644 */
645DllExport DIR *
0e06f75d 646win32_opendir(const char *filename)
814ffeea
VK
647{
648 dTHX;
649 DIR *dirp;
650 long len;
651 long idx;
652 char scanname[MAX_PATH+3];
653 Stat_t sbuf;
654 WIN32_FIND_DATAA aFindData;
655 WIN32_FIND_DATAW wFindData;
656 HANDLE fh;
657 char buffer[MAX_PATH*2];
658 WCHAR wbuffer[MAX_PATH+1];
659 char* ptr;
660
661 len = strlen(filename);
662 if (len > MAX_PATH)
663 return NULL;
664
665 /* check to see if filename is a directory */
666 if (win32_stat(filename, &sbuf) < 0 || !S_ISDIR(sbuf.st_mode))
667 return NULL;
668
669 /* Get us a DIR structure */
a02a5408 670 Newxz(dirp, 1, DIR);
814ffeea
VK
671
672 /* Create the search pattern */
673 strcpy(scanname, filename);
674
675 /* bare drive name means look in cwd for drive */
676 if (len == 2 && isALPHA(scanname[0]) && scanname[1] == ':') {
677 scanname[len++] = '.';
678 scanname[len++] = '/';
679 }
680 else if (scanname[len-1] != '/' && scanname[len-1] != '\\') {
681 scanname[len++] = '/';
682 }
683 scanname[len++] = '*';
684 scanname[len] = '\0';
685
686 /* do the FindFirstFile call */
687 fh = FindFirstFile(PerlDir_mapA(scanname), &aFindData);
688 dirp->handle = fh;
689 if (fh == INVALID_HANDLE_VALUE) {
690 DWORD err = GetLastError();
691 /* FindFirstFile() fails on empty drives! */
692 switch (err) {
693 case ERROR_FILE_NOT_FOUND:
694 return dirp;
695 case ERROR_NO_MORE_FILES:
696 case ERROR_PATH_NOT_FOUND:
697 errno = ENOENT;
698 break;
699 case ERROR_NOT_ENOUGH_MEMORY:
700 errno = ENOMEM;
701 break;
702 default:
703 errno = EINVAL;
704 break;
705 }
706 Safefree(dirp);
707 return NULL;
708 }
709
710 /* now allocate the first part of the string table for
711 * the filenames that we find.
712 */
713 ptr = aFindData.cFileName;
714 idx = strlen(ptr)+1;
715 if (idx < 256)
716 dirp->size = 128;
717 else
718 dirp->size = idx;
a02a5408 719 Newx(dirp->start, dirp->size, char);
814ffeea
VK
720 strcpy(dirp->start, ptr);
721 dirp->nfiles++;
722 dirp->end = dirp->curr = dirp->start;
723 dirp->end += idx;
724 return dirp;
725}
726
727
728/* Readdir just returns the current string pointer and bumps the
729 * string pointer to the nDllExport entry.
730 */
731DllExport struct direct *
732win32_readdir(DIR *dirp)
733{
734 long len;
735
736 if (dirp->curr) {
737 /* first set up the structure to return */
738 len = strlen(dirp->curr);
739 strcpy(dirp->dirstr.d_name, dirp->curr);
740 dirp->dirstr.d_namlen = len;
741
742 /* Fake an inode */
743 dirp->dirstr.d_ino = dirp->curr - dirp->start;
744
745 /* Now set up for the next call to readdir */
746 dirp->curr += len + 1;
747 if (dirp->curr >= dirp->end) {
748 dTHX;
749 char* ptr;
750 BOOL res;
751 WIN32_FIND_DATAW wFindData;
752 WIN32_FIND_DATAA aFindData;
753 char buffer[MAX_PATH*2];
754
755 /* finding the next file that matches the wildcard
756 * (which should be all of them in this directory!).
757 */
758 res = FindNextFile(dirp->handle, &aFindData);
759 if (res)
760 ptr = aFindData.cFileName;
761 if (res) {
762 long endpos = dirp->end - dirp->start;
763 long newsize = endpos + strlen(ptr) + 1;
764 /* bump the string table size by enough for the
765 * new name and its null terminator */
766 while (newsize > dirp->size) {
767 long curpos = dirp->curr - dirp->start;
35a27ac0 768 Renew(dirp->start, dirp->size * 2, char);
814ffeea 769 dirp->size *= 2;
814ffeea
VK
770 dirp->curr = dirp->start + curpos;
771 }
772 strcpy(dirp->start + endpos, ptr);
773 dirp->end = dirp->start + newsize;
774 dirp->nfiles++;
775 }
776 else
777 dirp->curr = NULL;
778 }
779 return &(dirp->dirstr);
780 }
781 else
782 return NULL;
783}
784
785/* Telldir returns the current string pointer position */
786DllExport long
787win32_telldir(DIR *dirp)
788{
789 return (dirp->curr - dirp->start);
790}
791
792
793/* Seekdir moves the string pointer to a previously saved position
794 * (returned by telldir).
795 */
796DllExport void
797win32_seekdir(DIR *dirp, long loc)
798{
799 dirp->curr = dirp->start + loc;
800}
801
802/* Rewinddir resets the string pointer to the start */
803DllExport void
804win32_rewinddir(DIR *dirp)
805{
806 dirp->curr = dirp->start;
807}
808
809/* free the memory allocated by opendir */
810DllExport int
811win32_closedir(DIR *dirp)
812{
813 dTHX;
814 if (dirp->handle != INVALID_HANDLE_VALUE)
815 FindClose(dirp->handle);
816 Safefree(dirp->start);
817 Safefree(dirp);
818 return 1;
e1caacb4
JH
819}
820
814ffeea
VK
821#else
822/////!!!!!!!!!!! return here and do right stuff!!!!
823
e1caacb4 824DllExport DIR *
0e06f75d 825win32_opendir(const char *filename)
e1caacb4
JH
826{
827 return opendir(filename);
828}
829
830DllExport struct direct *
831win32_readdir(DIR *dirp)
832{
833 return readdir(dirp);
834}
835
836DllExport long
837win32_telldir(DIR *dirp)
838{
216db7ee 839 dTHX;
e1caacb4
JH
840 Perl_croak(aTHX_ PL_no_func, "telldir");
841 return -1;
842}
843
844DllExport void
845win32_seekdir(DIR *dirp, long loc)
846{
216db7ee 847 dTHX;
e1caacb4
JH
848 Perl_croak(aTHX_ PL_no_func, "seekdir");
849}
850
851DllExport void
852win32_rewinddir(DIR *dirp)
853{
216db7ee 854 dTHX;
e1caacb4
JH
855 Perl_croak(aTHX_ PL_no_func, "rewinddir");
856}
857
858DllExport int
859win32_closedir(DIR *dirp)
860{
861 closedir(dirp);
862 return 0;
863}
814ffeea 864#endif // 1
e1caacb4
JH
865
866DllExport int
867win32_kill(int pid, int sig)
868{
216db7ee 869 dTHX;
e1caacb4
JH
870 Perl_croak(aTHX_ PL_no_func, "kill");
871 return -1;
872}
873
e1caacb4
JH
874DllExport int
875win32_stat(const char *path, struct stat *sbuf)
876{
877 return xcestat(path, sbuf);
878}
879
880DllExport char *
881win32_longpath(char *path)
882{
883 return path;
884}
885
517bb5c6
VK
886static void
887out_of_memory(void)
888{
889 if (PL_curinterp) {
890 dTHX;
891 /* Can't use PerlIO to write as it allocates memory */
892 PerlLIO_write(PerlIO_fileno(Perl_error_log),
893 PL_no_mem, strlen(PL_no_mem));
894 my_exit(1);
895 }
896 exit(1);
897}
898
899/* The win32_ansipath() function takes a Unicode filename and converts it
900 * into the current Windows codepage. If some characters cannot be mapped,
901 * then it will convert the short name instead.
902 *
903 * The buffer to the ansi pathname must be freed with win32_free() when it
904 * it no longer needed.
905 *
906 * The argument to win32_ansipath() must exist before this function is
907 * called; otherwise there is no way to determine the short path name.
908 *
909 * Ideas for future refinement:
910 * - Only convert those segments of the path that are not in the current
911 * codepage, but leave the other segments in their long form.
912 * - If the resulting name is longer than MAX_PATH, start converting
913 * additional path segments into short names until the full name
914 * is shorter than MAX_PATH. Shorten the filename part last!
915 */
916DllExport char *
917win32_ansipath(const WCHAR *widename)
918{
919 char *name;
920 size_t widelen = wcslen(widename)+1;
921 int len = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, widename, widelen,
922 NULL, 0, NULL, NULL);
923 name = win32_malloc(len);
924 if (!name)
925 out_of_memory();
926
927 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, widename, widelen,
928 name, len, NULL, NULL);
929 return name;
930}
931
e1caacb4
JH
932DllExport char *
933win32_getenv(const char *name)
934{
935 return xcegetenv(name);
936}
937
938DllExport int
939win32_putenv(const char *name)
940{
941 return xceputenv(name);
942}
943
e1caacb4
JH
944static long
945filetime_to_clock(PFILETIME ft)
946{
947 __int64 qw = ft->dwHighDateTime;
948 qw <<= 32;
949 qw |= ft->dwLowDateTime;
950 qw /= 10000; /* File time ticks at 0.1uS, clock at 1mS */
951 return (long) qw;
952}
953
954/* fix utime() so it works on directories in NT */
955static BOOL
956filetime_from_time(PFILETIME pFileTime, time_t Time)
957{
958 struct tm *pTM = localtime(&Time);
959 SYSTEMTIME SystemTime;
960 FILETIME LocalTime;
961
962 if (pTM == NULL)
963 return FALSE;
964
965 SystemTime.wYear = pTM->tm_year + 1900;
966 SystemTime.wMonth = pTM->tm_mon + 1;
967 SystemTime.wDay = pTM->tm_mday;
968 SystemTime.wHour = pTM->tm_hour;
969 SystemTime.wMinute = pTM->tm_min;
970 SystemTime.wSecond = pTM->tm_sec;
971 SystemTime.wMilliseconds = 0;
972
973 return SystemTimeToFileTime(&SystemTime, &LocalTime) &&
974 LocalFileTimeToFileTime(&LocalTime, pFileTime);
975}
976
977DllExport int
978win32_unlink(const char *filename)
979{
980 return xceunlink(filename);
981}
982
983DllExport int
984win32_utime(const char *filename, struct utimbuf *times)
985{
986 return xceutime(filename, (struct _utimbuf *) times);
987}
988
989DllExport int
e2a02c1e
VK
990win32_gettimeofday(struct timeval *tp, void *not_used)
991{
992 return xcegettimeofday(tp,not_used);
993}
994
995DllExport int
e1caacb4
JH
996win32_uname(struct utsname *name)
997{
998 struct hostent *hep;
999 STRLEN nodemax = sizeof(name->nodename)-1;
1000 OSVERSIONINFOA osver;
1001
1002 memset(&osver, 0, sizeof(OSVERSIONINFOA));
1003 osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1004 if (XCEGetVersionExA(&osver)) {
1005 /* sysname */
1006 switch (osver.dwPlatformId) {
1007 case VER_PLATFORM_WIN32_CE:
1008 strcpy(name->sysname, "Windows CE");
1009 break;
1010 case VER_PLATFORM_WIN32_WINDOWS:
1011 strcpy(name->sysname, "Windows");
1012 break;
1013 case VER_PLATFORM_WIN32_NT:
1014 strcpy(name->sysname, "Windows NT");
1015 break;
1016 case VER_PLATFORM_WIN32s:
1017 strcpy(name->sysname, "Win32s");
1018 break;
1019 default:
1020 strcpy(name->sysname, "Win32 Unknown");
1021 break;
1022 }
1023
1024 /* release */
1025 sprintf(name->release, "%d.%d",
1026 osver.dwMajorVersion, osver.dwMinorVersion);
1027
1028 /* version */
1029 sprintf(name->version, "Build %d",
1030 osver.dwPlatformId == VER_PLATFORM_WIN32_NT
1031 ? osver.dwBuildNumber : (osver.dwBuildNumber & 0xffff));
1032 if (osver.szCSDVersion[0]) {
1033 char *buf = name->version + strlen(name->version);
1034 sprintf(buf, " (%s)", osver.szCSDVersion);
1035 }
1036 }
1037 else {
1038 *name->sysname = '\0';
1039 *name->version = '\0';
1040 *name->release = '\0';
1041 }
1042
1043 /* nodename */
1044 hep = win32_gethostbyname("localhost");
1045 if (hep) {
1046 STRLEN len = strlen(hep->h_name);
1047 if (len <= nodemax) {
1048 strcpy(name->nodename, hep->h_name);
1049 }
1050 else {
1051 strncpy(name->nodename, hep->h_name, nodemax);
1052 name->nodename[nodemax] = '\0';
1053 }
1054 }
1055 else {
1056 DWORD sz = nodemax;
1057 if (!XCEGetComputerNameA(name->nodename, &sz))
1058 *name->nodename = '\0';
1059 }
1060
1061 /* machine (architecture) */
1062 {
1063 SYSTEM_INFO info;
1064 char *arch;
1065 GetSystemInfo(&info);
1066
e1caacb4 1067 switch (info.wProcessorArchitecture) {
e1caacb4
JH
1068 case PROCESSOR_ARCHITECTURE_INTEL:
1069 arch = "x86"; break;
1070 case PROCESSOR_ARCHITECTURE_MIPS:
1071 arch = "mips"; break;
1072 case PROCESSOR_ARCHITECTURE_ALPHA:
1073 arch = "alpha"; break;
1074 case PROCESSOR_ARCHITECTURE_PPC:
1075 arch = "ppc"; break;
1076 case PROCESSOR_ARCHITECTURE_ARM:
1077 arch = "arm"; break;
1078 case PROCESSOR_HITACHI_SH3:
1079 arch = "sh3"; break;
1080 case PROCESSOR_SHx_SH3:
1081 arch = "sh3"; break;
1082
1083 default:
1084 arch = "unknown"; break;
1085 }
1086 strcpy(name->machine, arch);
1087 }
1088 return 0;
1089}
1090
814ffeea
VK
1091/* Timing related stuff */
1092
1093int
f4257e4d 1094do_raise(pTHX_ int sig)
814ffeea
VK
1095{
1096 if (sig < SIG_SIZE) {
1097 Sighandler_t handler = w32_sighandler[sig];
1098 if (handler == SIG_IGN) {
1099 return 0;
1100 }
1101 else if (handler != SIG_DFL) {
1102 (*handler)(sig);
1103 return 0;
1104 }
1105 else {
1106 /* Choose correct default behaviour */
1107 switch (sig) {
1108#ifdef SIGCLD
1109 case SIGCLD:
1110#endif
1111#ifdef SIGCHLD
1112 case SIGCHLD:
1113#endif
1114 case 0:
1115 return 0;
1116 case SIGTERM:
1117 default:
1118 break;
1119 }
1120 }
1121 }
bb0f0a6a 1122 /* Tell caller to exit thread/process as appropriate */
814ffeea
VK
1123 return 1;
1124}
1125
216db7ee
VK
1126void
1127sig_terminate(pTHX_ int sig)
1128{
2e332e71 1129 Perl_warn(aTHX_ "Terminating on signal SIG%s(%d)\n",PL_sig_name[sig], sig);
f4257e4d
YO
1130 /* exit() seems to be safe, my_exit() or die() is a problem in ^C
1131 thread
216db7ee
VK
1132 */
1133 exit(sig);
1134}
1135
1136DllExport int
1137win32_async_check(pTHX)
1138{
1139 MSG msg;
1140 int ours = 1;
1141 /* Passing PeekMessage -1 as HWND (2nd arg) only get PostThreadMessage() messages
1142 * and ignores window messages - should co-exist better with windows apps e.g. Tk
1143 */
1144 while (PeekMessage(&msg, (HWND)-1, 0, 0, PM_REMOVE|PM_NOYIELD)) {
1145 int sig;
1146 switch(msg.message) {
1147
1148#if 0
1149 /* Perhaps some other messages could map to signals ? ... */
1150 case WM_CLOSE:
1151 case WM_QUIT:
1152 /* Treat WM_QUIT like SIGHUP? */
1153 sig = SIGHUP;
1154 goto Raise;
1155 break;
1156#endif
2e332e71 1157
216db7ee
VK
1158 /* We use WM_USER to fake kill() with other signals */
1159 case WM_USER: {
1160 sig = msg.wParam;
1161 Raise:
1162 if (do_raise(aTHX_ sig)) {
1163 sig_terminate(aTHX_ sig);
1164 }
1165 break;
1166 }
1167
1168 case WM_TIMER: {
1169 /* alarm() is a one-shot but SetTimer() repeats so kill it */
1170 if (w32_timerid) {
1171 KillTimer(NULL,w32_timerid);
1172 w32_timerid=0;
1173 }
1174 /* Now fake a call to signal handler */
1175 if (do_raise(aTHX_ 14)) {
1176 sig_terminate(aTHX_ 14);
1177 }
1178 break;
1179 }
1180
1181 /* Otherwise do normal Win32 thing - in case it is useful */
1182 default:
1183 TranslateMessage(&msg);
1184 DispatchMessage(&msg);
1185 ours = 0;
1186 break;
1187 }
1188 }
1189 w32_poll_count = 0;
1190
1191 /* Above or other stuff may have set a signal flag */
1192 if (PL_sig_pending) {
1193 despatch_signals();
1194 }
1195 return ours;
1196}
1197
1198/* This function will not return until the timeout has elapsed, or until
1199 * one of the handles is ready. */
1200DllExport DWORD
1201win32_msgwait(pTHX_ DWORD count, LPHANDLE handles, DWORD timeout, LPDWORD resultp)
1202{
1203 /* We may need several goes at this - so compute when we stop */
1204 DWORD ticks = 0;
1205 if (timeout != INFINITE) {
1206 ticks = GetTickCount();
1207 timeout += ticks;
1208 }
1209 while (1) {
1210 DWORD result = MsgWaitForMultipleObjects(count,handles,FALSE,timeout-ticks, QS_ALLEVENTS);
1211 if (resultp)
1212 *resultp = result;
1213 if (result == WAIT_TIMEOUT) {
1214 /* Ran out of time - explicit return of zero to avoid -ve if we
1215 have scheduling issues
1216 */
1217 return 0;
1218 }
1219 if (timeout != INFINITE) {
1220 ticks = GetTickCount();
1221 }
1222 if (result == WAIT_OBJECT_0 + count) {
1223 /* Message has arrived - check it */
1224 (void)win32_async_check(aTHX);
1225 }
1226 else {
1227 /* Not timeout or message - one of handles is ready */
1228 break;
1229 }
1230 }
1231 /* compute time left to wait */
1232 ticks = timeout - ticks;
1233 /* If we are past the end say zero */
1234 return (ticks > 0) ? ticks : 0;
1235}
1236
e1caacb4
JH
1237static UINT timerid = 0;
1238
1239static VOID CALLBACK TimerProc(HWND win, UINT msg, UINT id, DWORD time)
1240{
acfe0abc 1241 dTHX;
e1caacb4 1242 KillTimer(NULL,timerid);
f4257e4d 1243 timerid=0;
e1caacb4
JH
1244 sighandler(14);
1245}
e1caacb4
JH
1246
1247DllExport unsigned int
814ffeea
VK
1248win32_sleep(unsigned int t)
1249{
1250 return xcesleep(t);
1251}
1252
1253DllExport unsigned int
e1caacb4
JH
1254win32_alarm(unsigned int sec)
1255{
f4257e4d 1256 /*
e1caacb4 1257 * the 'obvious' implentation is SetTimer() with a callback
f4257e4d
YO
1258 * which does whatever receiving SIGALRM would do
1259 * we cannot use SIGALRM even via raise() as it is not
e1caacb4
JH
1260 * one of the supported codes in <signal.h>
1261 *
1262 * Snag is unless something is looking at the message queue
1263 * nothing happens :-(
f4257e4d 1264 */
acfe0abc 1265 dTHX;
e1caacb4
JH
1266 if (sec)
1267 {
1268 timerid = SetTimer(NULL,timerid,sec*1000,(TIMERPROC)TimerProc);
1269 if (!timerid)
1270 Perl_croak_nocontext("Cannot set timer");
f4257e4d 1271 }
e1caacb4
JH
1272 else
1273 {
1274 if (timerid)
1275 {
1276 KillTimer(NULL,timerid);
f4257e4d 1277 timerid=0;
e1caacb4
JH
1278 }
1279 }
e1caacb4
JH
1280 return 0;
1281}
1282
1283#ifdef HAVE_DES_FCRYPT
1284extern char * des_fcrypt(const char *txt, const char *salt, char *cbuf);
1285#endif
1286
1287DllExport char *
1288win32_crypt(const char *txt, const char *salt)
1289{
acfe0abc 1290 dTHX;
e1caacb4
JH
1291#ifdef HAVE_DES_FCRYPT
1292 dTHR;
1293 return des_fcrypt(txt, salt, w32_crypt_buffer);
1294#else
1295 Perl_croak(aTHX_ "The crypt() function is unimplemented due to excessive paranoia.");
4e205ed6 1296 return NULL;
e1caacb4
JH
1297#endif
1298}
1299
e1caacb4
JH
1300
1301/*
1302 * redirected io subsystem for all XS modules
1303 *
1304 */
1305
1306DllExport int *
1307win32_errno(void)
1308{
1309 return (&errno);
1310}
1311
814ffeea
VK
1312DllExport char ***
1313win32_environ(void)
1314{
1315 return (&(environ));
1316}
1317
e1caacb4
JH
1318/* the rest are the remapped stdio routines */
1319DllExport FILE *
1320win32_stderr(void)
1321{
1322 return (stderr);
1323}
1324
216db7ee
VK
1325char *g_getlogin() {
1326 return "no-getlogin";
1327}
1328
e1caacb4
JH
1329DllExport FILE *
1330win32_stdin(void)
1331{
1332 return (stdin);
1333}
1334
1335DllExport FILE *
1336win32_stdout()
1337{
1338 return (stdout);
1339}
1340
1341DllExport int
1342win32_ferror(FILE *fp)
1343{
1344 return (ferror(fp));
1345}
1346
1347
1348DllExport int
1349win32_feof(FILE *fp)
1350{
1351 return (feof(fp));
1352}
1353
1354/*
f4257e4d 1355 * Since the errors returned by the socket error function
e1caacb4
JH
1356 * WSAGetLastError() are not known by the library routine strerror
1357 * we have to roll our own.
1358 */
1359
1360DllExport char *
814ffeea 1361win32_strerror(int e)
e1caacb4
JH
1362{
1363 return xcestrerror(e);
1364}
1365
1366DllExport void
1367win32_str_os_error(void *sv, DWORD dwErr)
1368{
acfe0abc 1369 dTHX;
e1caacb4 1370
cf97b304 1371 sv_setpvs((SV*)sv, "Error");
e1caacb4
JH
1372}
1373
1374
1375DllExport int
1376win32_fprintf(FILE *fp, const char *format, ...)
1377{
1378 va_list marker;
1379 va_start(marker, format); /* Initialize variable arguments. */
1380
1381 return (vfprintf(fp, format, marker));
1382}
1383
1384DllExport int
1385win32_printf(const char *format, ...)
1386{
1387 va_list marker;
1388 va_start(marker, format); /* Initialize variable arguments. */
1389
1390 return (vprintf(format, marker));
1391}
1392
1393DllExport int
1394win32_vfprintf(FILE *fp, const char *format, va_list args)
1395{
1396 return (vfprintf(fp, format, args));
1397}
1398
1399DllExport int
1400win32_vprintf(const char *format, va_list args)
1401{
1402 return (vprintf(format, args));
1403}
1404
1405DllExport size_t
1406win32_fread(void *buf, size_t size, size_t count, FILE *fp)
1407{
1408 return fread(buf, size, count, fp);
1409}
1410
1411DllExport size_t
1412win32_fwrite(const void *buf, size_t size, size_t count, FILE *fp)
1413{
1414 return fwrite(buf, size, count, fp);
1415}
1416
1417DllExport FILE *
1418win32_fopen(const char *filename, const char *mode)
1419{
1420 return xcefopen(filename, mode);
1421}
1422
1423DllExport FILE *
1424win32_fdopen(int handle, const char *mode)
1425{
1426 return palm_fdopen(handle, mode);
1427}
1428
1429DllExport FILE *
1430win32_freopen(const char *path, const char *mode, FILE *stream)
1431{
1432 return xcefreopen(path, mode, stream);
1433}
1434
1435DllExport int
1436win32_fclose(FILE *pf)
1437{
1438 return xcefclose(pf);
1439}
1440
1441DllExport int
1442win32_fputs(const char *s,FILE *pf)
1443{
1444 return fputs(s, pf);
1445}
1446
1447DllExport int
1448win32_fputc(int c,FILE *pf)
1449{
1450 return fputc(c,pf);
1451}
1452
1453DllExport int
1454win32_ungetc(int c,FILE *pf)
1455{
1456 return ungetc(c,pf);
1457}
1458
1459DllExport int
1460win32_getc(FILE *pf)
1461{
1462 return getc(pf);
1463}
1464
1465DllExport int
1466win32_fileno(FILE *pf)
1467{
1468 return palm_fileno(pf);
1469}
1470
1471DllExport void
1472win32_clearerr(FILE *pf)
1473{
1474 clearerr(pf);
1475 return;
1476}
1477
1478DllExport int
1479win32_fflush(FILE *pf)
1480{
1481 return fflush(pf);
1482}
1483
1484DllExport long
1485win32_ftell(FILE *pf)
1486{
1487 return ftell(pf);
1488}
1489
1490DllExport int
814ffeea 1491win32_fseek(FILE *pf, Off_t offset,int origin)
e1caacb4
JH
1492{
1493 return fseek(pf, offset, origin);
1494}
1495
cb69f87a
MB
1496/* fpos_t seems to be int64 on hpc pro! Really stupid. */
1497/* But maybe someday there will be such large disks in a hpc... */
e1caacb4
JH
1498DllExport int
1499win32_fgetpos(FILE *pf, fpos_t *p)
1500{
1501 return fgetpos(pf, p);
1502}
1503
1504DllExport int
1505win32_fsetpos(FILE *pf, const fpos_t *p)
1506{
1507 return fsetpos(pf, p);
1508}
1509
1510DllExport void
1511win32_rewind(FILE *pf)
1512{
1513 fseek(pf, 0, SEEK_SET);
1514 return;
1515}
1516
81003058
VK
1517DllExport int
1518win32_tmpfd(void)
1519{
1520 dTHX;
1521 char prefix[MAX_PATH+1];
1522 char filename[MAX_PATH+1];
1523 DWORD len = GetTempPath(MAX_PATH, prefix);
1524 if (len && len < MAX_PATH) {
1525 if (GetTempFileName(prefix, "plx", 0, filename)) {
1526 HANDLE fh = CreateFile(filename,
1527 DELETE | GENERIC_READ | GENERIC_WRITE,
1528 0,
1529 NULL,
1530 CREATE_ALWAYS,
1531 FILE_ATTRIBUTE_NORMAL
1532 | FILE_FLAG_DELETE_ON_CLOSE,
1533 NULL);
1534 if (fh != INVALID_HANDLE_VALUE) {
1535 int fd = win32_open_osfhandle((intptr_t)fh, 0);
1536 if (fd >= 0) {
81003058
VK
1537 DEBUG_p(PerlIO_printf(Perl_debug_log,
1538 "Created tmpfile=%s\n",filename));
1539 return fd;
1540 }
1541 }
1542 }
1543 }
1544 return -1;
1545}
1546
e1caacb4
JH
1547DllExport FILE*
1548win32_tmpfile(void)
1549{
81003058
VK
1550 int fd = win32_tmpfd();
1551 if (fd >= 0)
1552 return win32_fdopen(fd, "w+b");
1553 return NULL;
e1caacb4
JH
1554}
1555
1556DllExport void
1557win32_abort(void)
1558{
1559 xceabort();
1560
1561 return;
1562}
1563
1564DllExport int
1565win32_fstat(int fd, struct stat *sbufptr)
1566{
1567 return xcefstat(fd, sbufptr);
1568}
1569
1570DllExport int
1571win32_link(const char *oldname, const char *newname)
1572{
216db7ee 1573 dTHX;
e1caacb4
JH
1574 Perl_croak(aTHX_ PL_no_func, "link");
1575
1576 return -1;
1577}
1578
1579DllExport int
1580win32_rename(const char *oname, const char *newname)
1581{
1582 return xcerename(oname, newname);
1583}
1584
1585DllExport int
1586win32_setmode(int fd, int mode)
1587{
bcdf844e
VK
1588 /* currently 'celib' seem to have this function in src, but not
1589 * exported. When it will be, we'll uncomment following line.
1590 */
1591 /* return xcesetmode(fd, mode); */
1592 return 0;
e1caacb4
JH
1593}
1594
216db7ee
VK
1595DllExport int
1596win32_chsize(int fd, Off_t size)
1597{
1598 return chsize(fd, size);
1599}
1600
e1caacb4 1601DllExport long
814ffeea 1602win32_lseek(int fd, Off_t offset, int origin)
e1caacb4
JH
1603{
1604 return xcelseek(fd, offset, origin);
1605}
1606
1607DllExport long
1608win32_tell(int fd)
1609{
1610 return xcelseek(fd, 0, SEEK_CUR);
1611}
1612
1613DllExport int
1614win32_open(const char *path, int flag, ...)
1615{
1616 int pmode;
1617 va_list ap;
1618
1619 va_start(ap, flag);
1620 pmode = va_arg(ap, int);
1621 va_end(ap);
1622
1623 return xceopen(path, flag, pmode);
1624}
1625
1626DllExport int
1627win32_close(int fd)
1628{
1629 return xceclose(fd);
1630}
1631
1632DllExport int
1633win32_eof(int fd)
1634{
216db7ee 1635 dTHX;
e1caacb4
JH
1636 Perl_croak(aTHX_ PL_no_func, "eof");
1637 return -1;
1638}
1639
1640DllExport int
1641win32_dup(int fd)
1642{
216db7ee 1643 return xcedup(fd); /* from celib/ceio.c; requires some more work on it */
e1caacb4
JH
1644}
1645
1646DllExport int
1647win32_dup2(int fd1,int fd2)
1648{
aebd5ec7 1649 return xcedup2(fd1,fd2);
e1caacb4
JH
1650}
1651
1652DllExport int
1653win32_read(int fd, void *buf, unsigned int cnt)
1654{
1655 return xceread(fd, buf, cnt);
1656}
1657
1658DllExport int
1659win32_write(int fd, const void *buf, unsigned int cnt)
1660{
1661 return xcewrite(fd, (void *) buf, cnt);
1662}
1663
1664DllExport int
1665win32_mkdir(const char *dir, int mode)
1666{
1667 return xcemkdir(dir);
1668}
1669
1670DllExport int
1671win32_rmdir(const char *dir)
1672{
1673 return xcermdir(dir);
1674}
1675
1676DllExport int
1677win32_chdir(const char *dir)
1678{
1679 return xcechdir(dir);
1680}
1681
1682DllExport int
1683win32_access(const char *path, int mode)
1684{
1685 return xceaccess(path, mode);
1686}
1687
1688DllExport int
1689win32_chmod(const char *path, int mode)
1690{
1691 return xcechmod(path, mode);
1692}
1693
814ffeea
VK
1694static char *
1695create_command_line(char *cname, STRLEN clen, const char * const *args)
216db7ee
VK
1696{
1697 dTHX;
1698 int index, argc;
1699 char *cmd, *ptr;
1700 const char *arg;
1701 STRLEN len = 0;
1702 bool bat_file = FALSE;
1703 bool cmd_shell = FALSE;
1704 bool dumb_shell = FALSE;
1705 bool extra_quotes = FALSE;
1706 bool quote_next = FALSE;
1707
1708 if (!cname)
1709 cname = (char*)args[0];
1710
1711 /* The NT cmd.exe shell has the following peculiarity that needs to be
1712 * worked around. It strips a leading and trailing dquote when any
1713 * of the following is true:
1714 * 1. the /S switch was used
1715 * 2. there are more than two dquotes
1716 * 3. there is a special character from this set: &<>()@^|
1717 * 4. no whitespace characters within the two dquotes
1718 * 5. string between two dquotes isn't an executable file
1719 * To work around this, we always add a leading and trailing dquote
1720 * to the string, if the first argument is either "cmd.exe" or "cmd",
1721 * and there were at least two or more arguments passed to cmd.exe
1722 * (not including switches).
1723 * XXX the above rules (from "cmd /?") don't seem to be applied
1724 * always, making for the convolutions below :-(
1725 */
1726 if (cname) {
1727 if (!clen)
1728 clen = strlen(cname);
1729
1730 if (clen > 4
1731 && (stricmp(&cname[clen-4], ".bat") == 0
1732 || (IsWinNT() && stricmp(&cname[clen-4], ".cmd") == 0)))
1733 {
1734 bat_file = TRUE;
1735 len += 3;
1736 }
1737 else {
1738 char *exe = strrchr(cname, '/');
1739 char *exe2 = strrchr(cname, '\\');
1740 if (exe2 > exe)
1741 exe = exe2;
1742 if (exe)
1743 ++exe;
1744 else
1745 exe = cname;
1746 if (stricmp(exe, "cmd.exe") == 0 || stricmp(exe, "cmd") == 0) {
1747 cmd_shell = TRUE;
1748 len += 3;
1749 }
1750 else if (stricmp(exe, "command.com") == 0
1751 || stricmp(exe, "command") == 0)
1752 {
1753 dumb_shell = TRUE;
1754 }
1755 }
1756 }
1757
1758 DEBUG_p(PerlIO_printf(Perl_debug_log, "Args "));
1759 for (index = 0; (arg = (char*)args[index]) != NULL; ++index) {
1760 STRLEN curlen = strlen(arg);
1761 if (!(arg[0] == '"' && arg[curlen-1] == '"'))
1762 len += 2; /* assume quoting needed (worst case) */
1763 len += curlen + 1;
1764 DEBUG_p(PerlIO_printf(Perl_debug_log, "[%s]",arg));
1765 }
1766 DEBUG_p(PerlIO_printf(Perl_debug_log, "\n"));
1767
1768 argc = index;
a02a5408 1769 Newx(cmd, len, char);
216db7ee
VK
1770 ptr = cmd;
1771
1772 if (bat_file) {
1773 *ptr++ = '"';
1774 extra_quotes = TRUE;
1775 }
1776
1777 for (index = 0; (arg = (char*)args[index]) != NULL; ++index) {
1778 bool do_quote = 0;
1779 STRLEN curlen = strlen(arg);
1780
1781 /* we want to protect empty arguments and ones with spaces with
1782 * dquotes, but only if they aren't already there */
1783 if (!dumb_shell) {
1784 if (!curlen) {
1785 do_quote = 1;
1786 }
1787 else if (quote_next) {
1788 /* see if it really is multiple arguments pretending to
1789 * be one and force a set of quotes around it */
1790 if (*find_next_space(arg))
1791 do_quote = 1;
1792 }
1793 else if (!(arg[0] == '"' && curlen > 1 && arg[curlen-1] == '"')) {
1794 STRLEN i = 0;
1795 while (i < curlen) {
1796 if (isSPACE(arg[i])) {
1797 do_quote = 1;
1798 }
1799 else if (arg[i] == '"') {
1800 do_quote = 0;
1801 break;
1802 }
1803 i++;
1804 }
1805 }
1806 }
1807
1808 if (do_quote)
1809 *ptr++ = '"';
1810
1811 strcpy(ptr, arg);
1812 ptr += curlen;
1813
1814 if (do_quote)
1815 *ptr++ = '"';
1816
1817 if (args[index+1])
1818 *ptr++ = ' ';
1819
1820 if (!extra_quotes
1821 && cmd_shell
1822 && curlen >= 2
1823 && *arg == '/' /* see if arg is "/c", "/x/c", "/x/d/c" etc. */
1824 && stricmp(arg+curlen-2, "/c") == 0)
1825 {
1826 /* is there a next argument? */
1827 if (args[index+1]) {
1828 /* are there two or more next arguments? */
1829 if (args[index+2]) {
1830 *ptr++ = '"';
1831 extra_quotes = TRUE;
1832 }
1833 else {
1834 /* single argument, force quoting if it has spaces */
1835 quote_next = TRUE;
1836 }
1837 }
1838 }
1839 }
1840
1841 if (extra_quotes)
1842 *ptr++ = '"';
1843
1844 *ptr = '\0';
1845
1846 return cmd;
1847}
1848
1849static char *
1850qualified_path(const char *cmd)
1851{
1852 dTHX;
1853 char *pathstr;
1854 char *fullcmd, *curfullcmd;
1855 STRLEN cmdlen = 0;
1856 int has_slash = 0;
1857
1858 if (!cmd)
4e205ed6 1859 return NULL;
216db7ee
VK
1860 fullcmd = (char*)cmd;
1861 while (*fullcmd) {
1862 if (*fullcmd == '/' || *fullcmd == '\\')
1863 has_slash++;
1864 fullcmd++;
1865 cmdlen++;
1866 }
1867
1868 /* look in PATH */
1869 pathstr = PerlEnv_getenv("PATH");
a02a5408 1870 Newx(fullcmd, MAX_PATH+1, char);
216db7ee
VK
1871 curfullcmd = fullcmd;
1872
1873 while (1) {
1874 DWORD res;
1875
1876 /* start by appending the name to the current prefix */
1877 strcpy(curfullcmd, cmd);
1878 curfullcmd += cmdlen;
1879
1880 /* if it doesn't end with '.', or has no extension, try adding
1881 * a trailing .exe first */
1882 if (cmd[cmdlen-1] != '.'
1883 && (cmdlen < 4 || cmd[cmdlen-4] != '.'))
1884 {
1885 strcpy(curfullcmd, ".exe");
1886 res = GetFileAttributes(fullcmd);
1887 if (res != 0xFFFFFFFF && !(res & FILE_ATTRIBUTE_DIRECTORY))
1888 return fullcmd;
1889 *curfullcmd = '\0';
1890 }
1891
1892 /* that failed, try the bare name */
1893 res = GetFileAttributes(fullcmd);
1894 if (res != 0xFFFFFFFF && !(res & FILE_ATTRIBUTE_DIRECTORY))
1895 return fullcmd;
1896
1897 /* quit if no other path exists, or if cmd already has path */
1898 if (!pathstr || !*pathstr || has_slash)
1899 break;
1900
1901 /* skip leading semis */
1902 while (*pathstr == ';')
1903 pathstr++;
1904
1905 /* build a new prefix from scratch */
1906 curfullcmd = fullcmd;
1907 while (*pathstr && *pathstr != ';') {
1908 if (*pathstr == '"') { /* foo;"baz;etc";bar */
1909 pathstr++; /* skip initial '"' */
1910 while (*pathstr && *pathstr != '"') {
1911 if ((STRLEN)(curfullcmd-fullcmd) < MAX_PATH-cmdlen-5)
1912 *curfullcmd++ = *pathstr;
1913 pathstr++;
1914 }
1915 if (*pathstr)
1916 pathstr++; /* skip trailing '"' */
1917 }
1918 else {
1919 if ((STRLEN)(curfullcmd-fullcmd) < MAX_PATH-cmdlen-5)
1920 *curfullcmd++ = *pathstr;
1921 pathstr++;
1922 }
1923 }
1924 if (*pathstr)
1925 pathstr++; /* skip trailing semi */
1926 if (curfullcmd > fullcmd /* append a dir separator */
1927 && curfullcmd[-1] != '/' && curfullcmd[-1] != '\\')
1928 {
1929 *curfullcmd++ = '\\';
1930 }
1931 }
1932
1933 Safefree(fullcmd);
4e205ed6 1934 return NULL;
216db7ee
VK
1935}
1936
8f33b42a
VK
1937/* The following are just place holders.
1938 * Some hosts may provide and environment that the OS is
1939 * not tracking, therefore, these host must provide that
1940 * environment and the current directory to CreateProcess
1941 */
1942
1943DllExport void*
1944win32_get_childenv(void)
1945{
1946 return NULL;
1947}
1948
1949DllExport void
1950win32_free_childenv(void* d)
1951{
1952}
1953
1954DllExport void
1955win32_clearenv(void)
1956{
1957 char *envv = GetEnvironmentStrings();
1958 char *cur = envv;
1959 STRLEN len;
1960 while (*cur) {
1961 char *end = strchr(cur,'=');
1962 if (end && end != cur) {
1963 *end = '\0';
1964 xcesetenv(cur, "", 0);
1965 *end = '=';
1966 cur = end + strlen(end+1)+2;
1967 }
1968 else if ((len = strlen(cur)))
1969 cur += len+1;
1970 }
1971 FreeEnvironmentStrings(envv);
1972}
1973
1974DllExport char*
1975win32_get_childdir(void)
1976{
1977 dTHX;
1978 char* ptr;
8c56068e
JD
1979 char szfilename[MAX_PATH+1];
1980 GetCurrentDirectoryA(MAX_PATH+1, szfilename);
8f33b42a 1981
a02a5408 1982 Newx(ptr, strlen(szfilename)+1, char);
8f33b42a
VK
1983 strcpy(ptr, szfilename);
1984 return ptr;
1985}
1986
1987DllExport void
1988win32_free_childdir(char* d)
1989{
1990 dTHX;
1991 Safefree(d);
1992}
1993
216db7ee
VK
1994/* XXX this needs to be made more compatible with the spawnvp()
1995 * provided by the various RTLs. In particular, searching for
1996 * *.{com,bat,cmd} files (as done by the RTLs) is unimplemented.
1997 * This doesn't significantly affect perl itself, because we
1998 * always invoke things using PERL5SHELL if a direct attempt to
1999 * spawn the executable fails.
2000 *
2001 * XXX splitting and rejoining the commandline between do_aspawn()
2002 * and win32_spawnvp() could also be avoided.
2003 */
2004
216db7ee
VK
2005DllExport int
2006win32_spawnvp(int mode, const char *cmdname, const char *const *argv)
2007{
2008#ifdef USE_RTL_SPAWNVP
2009 return spawnvp(mode, cmdname, (char * const *)argv);
2010#else
2011 dTHX;
2012 int ret;
2013 void* env;
2014 char* dir;
2015 child_IO_table tbl;
2016 STARTUPINFO StartupInfo;
2017 PROCESS_INFORMATION ProcessInformation;
2018 DWORD create = 0;
2019 char *cmd;
4e205ed6 2020 char *fullcmd = NULL;
216db7ee
VK
2021 char *cname = (char *)cmdname;
2022 STRLEN clen = 0;
2023
2024 if (cname) {
2025 clen = strlen(cname);
2026 /* if command name contains dquotes, must remove them */
2027 if (strchr(cname, '"')) {
2028 cmd = cname;
a02a5408 2029 Newx(cname,clen+1,char);
216db7ee
VK
2030 clen = 0;
2031 while (*cmd) {
2032 if (*cmd != '"') {
2033 cname[clen] = *cmd;
2034 ++clen;
2035 }
2036 ++cmd;
2037 }
2038 cname[clen] = '\0';
2039 }
2040 }
2041
2042 cmd = create_command_line(cname, clen, argv);
2043
2044 env = PerlEnv_get_childenv();
2045 dir = PerlEnv_get_childdir();
2046
2047 switch(mode) {
2048 case P_NOWAIT: /* asynch + remember result */
2049 if (w32_num_children >= MAXIMUM_WAIT_OBJECTS) {
2050 errno = EAGAIN;
2051 ret = -1;
2052 goto RETVAL;
2053 }
2054 /* Create a new process group so we can use GenerateConsoleCtrlEvent()
2055 * in win32_kill()
2056 */
2057 /* not supported on CE create |= CREATE_NEW_PROCESS_GROUP; */
2058 /* FALL THROUGH */
2059
2060 case P_WAIT: /* synchronous execution */
2061 break;
2062 default: /* invalid mode */
2063 errno = EINVAL;
2064 ret = -1;
2065 goto RETVAL;
2066 }
2067 memset(&StartupInfo,0,sizeof(StartupInfo));
2068 StartupInfo.cb = sizeof(StartupInfo);
2069 memset(&tbl,0,sizeof(tbl));
2070 PerlEnv_get_child_IO(&tbl);
2071 StartupInfo.dwFlags = tbl.dwFlags;
2072 StartupInfo.dwX = tbl.dwX;
2073 StartupInfo.dwY = tbl.dwY;
2074 StartupInfo.dwXSize = tbl.dwXSize;
2075 StartupInfo.dwYSize = tbl.dwYSize;
2076 StartupInfo.dwXCountChars = tbl.dwXCountChars;
2077 StartupInfo.dwYCountChars = tbl.dwYCountChars;
2078 StartupInfo.dwFillAttribute = tbl.dwFillAttribute;
2079 StartupInfo.wShowWindow = tbl.wShowWindow;
2080 StartupInfo.hStdInput = tbl.childStdIn;
2081 StartupInfo.hStdOutput = tbl.childStdOut;
2082 StartupInfo.hStdError = tbl.childStdErr;
2083 if (StartupInfo.hStdInput == INVALID_HANDLE_VALUE &&
2084 StartupInfo.hStdOutput == INVALID_HANDLE_VALUE &&
2085 StartupInfo.hStdError == INVALID_HANDLE_VALUE)
2086 {
2087 create |= CREATE_NEW_CONSOLE;
2088 }
2089 else {
2090 StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
2091 }
2092 if (w32_use_showwindow) {
2093 StartupInfo.dwFlags |= STARTF_USESHOWWINDOW;
2094 StartupInfo.wShowWindow = w32_showwindow;
2095 }
2096
2097 DEBUG_p(PerlIO_printf(Perl_debug_log, "Spawning [%s] with [%s]\n",
2098 cname,cmd));
2099RETRY:
2100 if (!CreateProcess(cname, /* search PATH to find executable */
2101 cmd, /* executable, and its arguments */
2102 NULL, /* process attributes */
2103 NULL, /* thread attributes */
2104 TRUE, /* inherit handles */
2105 create, /* creation flags */
2106 (LPVOID)env, /* inherit environment */
2107 dir, /* inherit cwd */
2108 &StartupInfo,
2109 &ProcessInformation))
2110 {
2111 /* initial NULL argument to CreateProcess() does a PATH
2112 * search, but it always first looks in the directory
2113 * where the current process was started, which behavior
2114 * is undesirable for backward compatibility. So we
2115 * jump through our own hoops by picking out the path
2116 * we really want it to use. */
2117 if (!fullcmd) {
2118 fullcmd = qualified_path(cname);
2119 if (fullcmd) {
2120 if (cname != cmdname)
2121 Safefree(cname);
2122 cname = fullcmd;
2123 DEBUG_p(PerlIO_printf(Perl_debug_log,
2124 "Retrying [%s] with same args\n",
2125 cname));
2126 goto RETRY;
2127 }
2128 }
2129 errno = ENOENT;
2130 ret = -1;
2131 goto RETVAL;
2132 }
2133
2134 if (mode == P_NOWAIT) {
2135 /* asynchronous spawn -- store handle, return PID */
2136 ret = (int)ProcessInformation.dwProcessId;
2137 if (IsWin95() && ret < 0)
2138 ret = -ret;
2139
2140 w32_child_handles[w32_num_children] = ProcessInformation.hProcess;
2141 w32_child_pids[w32_num_children] = (DWORD)ret;
2142 ++w32_num_children;
2143 }
2144 else {
2145 DWORD status;
2146 win32_msgwait(aTHX_ 1, &ProcessInformation.hProcess, INFINITE, NULL);
2147 /* FIXME: if msgwait returned due to message perhaps forward the
2148 "signal" to the process
2149 */
2150 GetExitCodeProcess(ProcessInformation.hProcess, &status);
2151 ret = (int)status;
2152 CloseHandle(ProcessInformation.hProcess);
2153 }
2154
2155 CloseHandle(ProcessInformation.hThread);
2156
2157RETVAL:
2158 PerlEnv_free_childenv(env);
2159 PerlEnv_free_childdir(dir);
2160 Safefree(cmd);
2161 if (cname != cmdname)
2162 Safefree(cname);
2163 return ret;
2164#endif
2165}
2166
e1caacb4
JH
2167DllExport int
2168win32_execv(const char *cmdname, const char *const *argv)
2169{
216db7ee 2170 dTHX;
e1caacb4
JH
2171 Perl_croak(aTHX_ PL_no_func, "execv");
2172 return -1;
2173}
2174
2175DllExport int
2176win32_execvp(const char *cmdname, const char *const *argv)
2177{
216db7ee 2178 dTHX;
e1caacb4
JH
2179 Perl_croak(aTHX_ PL_no_func, "execvp");
2180 return -1;
2181}
2182
814ffeea
VK
2183DllExport void
2184win32_perror(const char *str)
e1caacb4 2185{
814ffeea
VK
2186 xceperror(str);
2187}
e1caacb4 2188
814ffeea
VK
2189DllExport void
2190win32_setbuf(FILE *pf, char *buf)
2191{
2192 dTHX;
2193 Perl_croak(aTHX_ PL_no_func, "setbuf");
2194}
e1caacb4 2195
814ffeea
VK
2196DllExport int
2197win32_setvbuf(FILE *pf, char *buf, int type, size_t size)
2198{
2199 return setvbuf(pf, buf, type, size);
e1caacb4
JH
2200}
2201
814ffeea
VK
2202DllExport int
2203win32_flushall(void)
2204{
2205 return flushall();
2206}
e1caacb4 2207
814ffeea
VK
2208DllExport int
2209win32_fcloseall(void)
e1caacb4 2210{
814ffeea
VK
2211 return fcloseall();
2212}
e1caacb4 2213
814ffeea
VK
2214DllExport char*
2215win32_fgets(char *s, int n, FILE *pf)
2216{
2217 return fgets(s, n, pf);
2218}
e1caacb4 2219
814ffeea
VK
2220DllExport char*
2221win32_gets(char *s)
2222{
2223 return gets(s);
e1caacb4
JH
2224}
2225
814ffeea
VK
2226DllExport int
2227win32_fgetc(FILE *pf)
e1caacb4 2228{
814ffeea
VK
2229 return fgetc(pf);
2230}
e1caacb4 2231
814ffeea
VK
2232DllExport int
2233win32_putc(int c, FILE *pf)
2234{
2235 return putc(c,pf);
2236}
2237
2238DllExport int
2239win32_puts(const char *s)
2240{
2241 return puts(s);
2242}
2243
2244DllExport int
2245win32_getchar(void)
2246{
2247 return getchar();
2248}
2249
2250DllExport int
2251win32_putchar(int c)
2252{
2253 return putchar(c);
2254}
2255
2256#ifdef MYMALLOC
2257
2258#ifndef USE_PERL_SBRK
2259
2260static char *committed = NULL;
2261static char *base = NULL;
2262static char *reserved = NULL;
2263static char *brk = NULL;
2264static DWORD pagesize = 0;
2265static DWORD allocsize = 0;
2266
2267void *
2268sbrk(int need)
2269{
2270 void *result;
2271 if (!pagesize)
2272 {SYSTEM_INFO info;
2273 GetSystemInfo(&info);
2274 /* Pretend page size is larger so we don't perpetually
2275 * call the OS to commit just one page ...
2276 */
2277 pagesize = info.dwPageSize << 3;
2278 allocsize = info.dwAllocationGranularity;
2279 }
2280 /* This scheme fails eventually if request for contiguous
f4257e4d 2281 * block is denied so reserve big blocks - this is only
814ffeea
VK
2282 * address space not memory ...
2283 */
2284 if (brk+need >= reserved)
2285 {
2286 DWORD size = 64*1024*1024;
2287 char *addr;
2288 if (committed && reserved && committed < reserved)
2289 {
2290 /* Commit last of previous chunk cannot span allocations */
2291 addr = (char *) VirtualAlloc(committed,reserved-committed,MEM_COMMIT,PAGE_READWRITE);
2292 if (addr)
2293 committed = reserved;
2294 }
f4257e4d 2295 /* Reserve some (more) space
814ffeea
VK
2296 * Note this is a little sneaky, 1st call passes NULL as reserved
2297 * so lets system choose where we start, subsequent calls pass
2298 * the old end address so ask for a contiguous block
2299 */
2300 addr = (char *) VirtualAlloc(reserved,size,MEM_RESERVE,PAGE_NOACCESS);
2301 if (addr)
2302 {
2303 reserved = addr+size;
2304 if (!base)
2305 base = addr;
2306 if (!committed)
2307 committed = base;
2308 if (!brk)
2309 brk = committed;
2310 }
2311 else
2312 {
2313 return (void *) -1;
2314 }
2315 }
2316 result = brk;
2317 brk += need;
2318 if (brk > committed)
2319 {
2320 DWORD size = ((brk-committed + pagesize -1)/pagesize) * pagesize;
2321 char *addr = (char *) VirtualAlloc(committed,size,MEM_COMMIT,PAGE_READWRITE);
2322 if (addr)
2323 {
2324 committed += size;
2325 }
2326 else
2327 return (void *) -1;
2328 }
2329 return result;
2330}
2331
2332#endif
2333#endif
2334
2335DllExport void*
2336win32_malloc(size_t size)
2337{
2338 return malloc(size);
2339}
2340
2341DllExport void*
2342win32_calloc(size_t numitems, size_t size)
2343{
2344 return calloc(numitems,size);
2345}
2346
2347DllExport void*
2348win32_realloc(void *block, size_t size)
2349{
2350 return realloc(block,size);
2351}
2352
2353DllExport void
2354win32_free(void *block)
2355{
2356 free(block);
2357}
2358
2359int
2360win32_open_osfhandle(intptr_t osfhandle, int flags)
2361{
2362 int fh;
2363 char fileflags=0; /* _osfile flags */
2364
2365 Perl_croak_nocontext("win32_open_osfhandle() TBD on this platform");
2366 return 0;
2367}
2368
2369int
2370win32_get_osfhandle(int fd)
2371{
2372 int fh;
2373 char fileflags=0; /* _osfile flags */
2374
2375 Perl_croak_nocontext("win32_get_osfhandle() TBD on this platform");
2376 return 0;
2377}
2378
2379FILE *
2380win32_fdupopen(FILE *pf)
2381{
2382 FILE* pfdup;
2383 fpos_t pos;
2384 char mode[3];
2385 int fileno = win32_dup(win32_fileno(pf));
2386 int fmode = palm_fgetmode(pfdup);
2387
2388 fprintf(stderr,"DEBUG for win32_fdupopen()\n");
2389
2390 /* open the file in the same mode */
2391 if(fmode & O_RDONLY) {
2392 mode[0] = 'r';
2393 mode[1] = 0;
2394 }
2395 else if(fmode & O_APPEND) {
2396 mode[0] = 'a';
2397 mode[1] = 0;
2398 }
2399 else if(fmode & O_RDWR) {
2400 mode[0] = 'r';
2401 mode[1] = '+';
2402 mode[2] = 0;
2403 }
2404
2405 /* it appears that the binmode is attached to the
2406 * file descriptor so binmode files will be handled
2407 * correctly
2408 */
2409 pfdup = win32_fdopen(fileno, mode);
2410
2411 /* move the file pointer to the same position */
2412 if (!fgetpos(pf, &pos)) {
2413 fsetpos(pfdup, &pos);
2414 }
2415 return pfdup;
2416}
2417
2418DllExport void*
2419win32_dynaload(const char* filename)
2420{
2421 dTHX;
2422 HMODULE hModule;
2423
2424 hModule = XCELoadLibraryA(filename);
2425
2426 return hModule;
2427}
2428
2429/* this is needed by Cwd.pm... */
2430
2431static
2432XS(w32_GetCwd)
2433{
2434 dXSARGS;
2435 char buf[MAX_PATH];
2436 SV *sv = sv_newmortal();
2437
2438 xcegetcwd(buf, sizeof(buf));
2439
2440 sv_setpv(sv, xcestrdup(buf));
2441 EXTEND(SP,1);
2442 SvPOK_on(sv);
2443 ST(0) = sv;
814ffeea 2444 SvTAINTED_on(ST(0));
814ffeea
VK
2445 XSRETURN(1);
2446}
2447
2448static
2449XS(w32_SetCwd)
2450{
2451 dXSARGS;
2452
2453 if (items != 1)
e1caacb4
JH
2454 Perl_croak(aTHX_ "usage: Win32::SetCwd($cwd)");
2455
2456 if (!xcechdir(SvPV_nolen(ST(0))))
2457 XSRETURN_YES;
2458
2459 XSRETURN_NO;
2460}
2461
2462static
2463XS(w32_GetTickCount)
2464{
2465 dXSARGS;
2466 DWORD msec = GetTickCount();
2467 EXTEND(SP,1);
2468 if ((IV)msec > 0)
2469 XSRETURN_IV(msec);
2470 XSRETURN_NV(msec);
2471}
2472
2473static
2474XS(w32_GetOSVersion)
2475{
2476 dXSARGS;
2477 OSVERSIONINFOA osver;
2478
2479 osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
2480 if (!XCEGetVersionExA(&osver)) {
2481 XSRETURN_EMPTY;
2482 }
22f1178f
VP
2483 mXPUSHp(osver.szCSDVersion, strlen(osver.szCSDVersion));
2484 mXPUSHi(osver.dwMajorVersion);
2485 mXPUSHi(osver.dwMinorVersion);
2486 mXPUSHi(osver.dwBuildNumber);
cb69f87a 2487 /* WINCE = 3 */
22f1178f 2488 mXPUSHi(osver.dwPlatformId);
e1caacb4
JH
2489 PUTBACK;
2490}
2491
2492static
2493XS(w32_IsWinNT)
2494{
2495 dXSARGS;
2496 EXTEND(SP,1);
2497 XSRETURN_IV(IsWinNT());
2498}
2499
2500static
2501XS(w32_IsWin95)
2502{
2503 dXSARGS;
2504 EXTEND(SP,1);
2505 XSRETURN_IV(IsWin95());
2506}
2507
2508static
2509XS(w32_IsWinCE)
2510{
2511 dXSARGS;
2512 EXTEND(SP,1);
2513 XSRETURN_IV(IsWinCE());
2514}
2515
2516static
2517XS(w32_GetOemInfo)
2518{
2519 dXSARGS;
2520 wchar_t wbuf[126];
2521 char buf[126];
2522
2523 if(SystemParametersInfoW(SPI_GETOEMINFO, sizeof(wbuf), wbuf, FALSE))
2524 WideCharToMultiByte(CP_ACP, 0, wbuf, -1, buf, sizeof(buf), 0, 0);
2525 else
2526 sprintf(buf, "SystemParametersInfo failed: %d", GetLastError());
2527
2528 EXTEND(SP,1);
2529 XSRETURN_PV(buf);
2530}
2531
2532static
2533XS(w32_Sleep)
2534{
2535 dXSARGS;
2536 if (items != 1)
2537 Perl_croak(aTHX_ "usage: Win32::Sleep($milliseconds)");
2538 Sleep(SvIV(ST(0)));
2539 XSRETURN_YES;
2540}
2541
2542static
2543XS(w32_CopyFile)
2544{
2545 dXSARGS;
2546 BOOL bResult;
2547 if (items != 3)
2548 Perl_croak(aTHX_ "usage: Win32::CopyFile($from, $to, $overwrite)");
2549
2550 {
2551 char szSourceFile[MAX_PATH+1];
2552 strcpy(szSourceFile, PerlDir_mapA(SvPV_nolen(ST(0))));
f4257e4d 2553 bResult = XCECopyFileA(szSourceFile, SvPV_nolen(ST(1)),
e1caacb4
JH
2554 !SvTRUE(ST(2)));
2555 }
2556
2557 if (bResult)
2558 XSRETURN_YES;
2559
2560 XSRETURN_NO;
2561}
2562
2563static
2564XS(w32_MessageBox)
2565{
2566 dXSARGS;
2567
2568 char *txt;
2569 unsigned int res;
2570 unsigned int flags = MB_OK;
2571
2572 txt = SvPV_nolen(ST(0));
f4257e4d 2573
e1caacb4
JH
2574 if (items < 1 || items > 2)
2575 Perl_croak(aTHX_ "usage: Win32::MessageBox($txt, [$flags])");
2576
2577 if(items == 2)
2578 flags = SvIV(ST(1));
2579
2580 res = XCEMessageBoxA(NULL, txt, "Perl", flags);
2581
2582 XSRETURN_IV(res);
2583}
2584
2585static
2586XS(w32_GetPowerStatus)
2587{
2588 dXSARGS;
2589
2590 SYSTEM_POWER_STATUS_EX sps;
2591
2592 if(GetSystemPowerStatusEx(&sps, TRUE) == FALSE)
2593 {
2594 XSRETURN_EMPTY;
2595 }
2596
22f1178f
VP
2597 mXPUSHi(sps.ACLineStatus);
2598 mXPUSHi(sps.BatteryFlag);
2599 mXPUSHi(sps.BatteryLifePercent);
2600 mXPUSHi(sps.BatteryLifeTime);
2601 mXPUSHi(sps.BatteryFullLifeTime);
2602 mXPUSHi(sps.BackupBatteryFlag);
2603 mXPUSHi(sps.BackupBatteryLifePercent);
2604 mXPUSHi(sps.BackupBatteryLifeTime);
2605 mXPUSHi(sps.BackupBatteryFullLifeTime);
e1caacb4
JH
2606
2607 PUTBACK;
2608}
2609
2610#if UNDER_CE > 200
2611static
2612XS(w32_ShellEx)
2613{
2614 dXSARGS;
2615
2616 char buf[126];
2617 SHELLEXECUTEINFO si;
2618 char *file, *verb;
2619 wchar_t wfile[MAX_PATH];
2620 wchar_t wverb[20];
2621
2622 if (items != 2)
2623 Perl_croak(aTHX_ "usage: Win32::ShellEx($file, $verb)");
2624
2625 file = SvPV_nolen(ST(0));
2626 verb = SvPV_nolen(ST(1));
2627
2628 memset(&si, 0, sizeof(si));
2629 si.cbSize = sizeof(si);
2630 si.fMask = SEE_MASK_FLAG_NO_UI;
2631
f4257e4d 2632 MultiByteToWideChar(CP_ACP, 0, verb, -1,
e1caacb4
JH
2633 wverb, sizeof(wverb)/2);
2634 si.lpVerb = (TCHAR *)wverb;
2635
f4257e4d 2636 MultiByteToWideChar(CP_ACP, 0, file, -1,
e1caacb4
JH
2637 wfile, sizeof(wfile)/2);
2638 si.lpFile = (TCHAR *)wfile;
2639
2640 if(ShellExecuteEx(&si) == FALSE)
2641 {
2642 XSRETURN_NO;
2643 }
2644 XSRETURN_YES;
2645}
2646#endif
2647
2648void
2649Perl_init_os_extras(void)
2650{
acfe0abc 2651 dTHX;
e1caacb4
JH
2652 char *file = __FILE__;
2653 dXSUB_SYS;
2654
4e205ed6 2655 w32_perlshell_tokens = NULL;
e1caacb4
JH
2656 w32_perlshell_items = -1;
2657 w32_fdpid = newAV(); /* XX needs to be in Perl_win32_init()? */
a02a5408 2658 Newx(w32_children, 1, child_tab);
e1caacb4
JH
2659 w32_num_children = 0;
2660
2661 newXS("Win32::GetCwd", w32_GetCwd, file);
2662 newXS("Win32::SetCwd", w32_SetCwd, file);
2663 newXS("Win32::GetTickCount", w32_GetTickCount, file);
2664 newXS("Win32::GetOSVersion", w32_GetOSVersion, file);
2665#if UNDER_CE > 200
2666 newXS("Win32::ShellEx", w32_ShellEx, file);
2667#endif
2668 newXS("Win32::IsWinNT", w32_IsWinNT, file);
2669 newXS("Win32::IsWin95", w32_IsWin95, file);
2670 newXS("Win32::IsWinCE", w32_IsWinCE, file);
2671 newXS("Win32::CopyFile", w32_CopyFile, file);
2672 newXS("Win32::Sleep", w32_Sleep, file);
2673 newXS("Win32::MessageBox", w32_MessageBox, file);
2674 newXS("Win32::GetPowerStatus", w32_GetPowerStatus, file);
2675 newXS("Win32::GetOemInfo", w32_GetOemInfo, file);
2676}
2677
2678void
2679myexit(void)
2680{
2681 char buf[126];
2682
2683 puts("Hit return");
2684 fgets(buf, sizeof(buf), stdin);
2685}
2686
2687void
2688Perl_win32_init(int *argcp, char ***argvp)
2689{
2690#ifdef UNDER_CE
2691 char *p;
2692
2693 if((p = xcegetenv("PERLDEBUG")) && (p[0] == 'y' || p[0] == 'Y'))
2694 atexit(myexit);
2695#endif
2696
2697 MALLOC_INIT;
2698}
2699
216db7ee
VK
2700DllExport void
2701Perl_win32_term(void)
2702{
3890ecea 2703 dTHX;
71ad1b0c 2704 HINTS_REFCNT_TERM;
216db7ee 2705 OP_REFCNT_TERM;
3890ecea 2706 PERLIO_TERM;
216db7ee 2707 MALLOC_TERM;
929e1213 2708 LOCALE_TERM;
216db7ee
VK
2709}
2710
2711void
2712win32_get_child_IO(child_IO_table* ptbl)
2713{
2714 ptbl->childStdIn = GetStdHandle(STD_INPUT_HANDLE);
2715 ptbl->childStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
2716 ptbl->childStdErr = GetStdHandle(STD_ERROR_HANDLE);
2717}
2718
e1caacb4
JH
2719win32_flock(int fd, int oper)
2720{
216db7ee 2721 dTHX;
e1caacb4
JH
2722 Perl_croak(aTHX_ PL_no_func, "flock");
2723 return -1;
2724}
2725
2726DllExport int
2727win32_waitpid(int pid, int *status, int flags)
2728{
216db7ee 2729 dTHX;
e1caacb4
JH
2730 Perl_croak(aTHX_ PL_no_func, "waitpid");
2731 return -1;
2732}
2733
2734DllExport int
2735win32_wait(int *status)
2736{
216db7ee 2737 dTHX;
e1caacb4
JH
2738 Perl_croak(aTHX_ PL_no_func, "wait");
2739 return -1;
2740}
2741
2742int
e1caacb4 2743wce_reopen_stdout(char *fname)
f4257e4d 2744{
e1caacb4
JH
2745 if(xcefreopen(fname, "w", stdout) == NULL)
2746 return -1;
2747
2748 return 0;
2749}
2750
2751void
2752wce_hitreturn()
2753{
2754 char buf[126];
2755
2756 printf("Hit RETURN");
2757 fflush(stdout);
2758 fgets(buf, sizeof(buf), stdin);
2759 return;
2760}
2761
cb69f87a 2762/* //////////////////////////////////////////////////////////////////// */
e1caacb4 2763
ca6c63e1
JH
2764#undef getcwd
2765
2766char *
2767getcwd(char *buf, size_t size)
2768{
2769 return xcegetcwd(buf, size);
2770}
2771
18f68570 2772
814ffeea
VK
2773DllExport PerlIO*
2774win32_popenlist(const char *mode, IV narg, SV **args)
18f68570 2775{
814ffeea
VK
2776 dTHX;
2777 Perl_croak(aTHX_ "List form of pipe open not implemented");
2778 return NULL;
18f68570
VK
2779}
2780
2781/*
2782 * a popen() clone that respects PERL5SHELL
2783 *
2784 * changed to return PerlIO* rather than FILE * by BKS, 11-11-2000
2785 */
2786
2787DllExport PerlIO*
2788win32_popen(const char *command, const char *mode)
2789{
814ffeea 2790 return _popen(command, mode);
216db7ee
VK
2791}
2792
18f68570
VK
2793/*
2794 * pclose() clone
2795 */
2796
2797DllExport int
2798win32_pclose(PerlIO *pf)
2799{
18f68570 2800 return _pclose(pf);
18f68570
VK
2801}
2802
216db7ee
VK
2803#ifdef HAVE_INTERP_INTERN
2804
2805
2806static void
2807win32_csighandler(int sig)
2808{
2809#if 0
2810 dTHXa(PERL_GET_SIG_CONTEXT);
2811 Perl_warn(aTHX_ "Got signal %d",sig);
2812#endif
2813 /* Does nothing */
2814}
2815
2816void
2817Perl_sys_intern_init(pTHX)
2818{
2819 int i;
4e205ed6 2820 w32_perlshell_tokens = NULL;
216db7ee
VK
2821 w32_perlshell_vec = (char**)NULL;
2822 w32_perlshell_items = 0;
2823 w32_fdpid = newAV();
a02a5408 2824 Newx(w32_children, 1, child_tab);
216db7ee
VK
2825 w32_num_children = 0;
2826# ifdef USE_ITHREADS
2827 w32_pseudo_id = 0;
a02a5408 2828 Newx(w32_pseudo_children, 1, child_tab);
216db7ee
VK
2829 w32_num_pseudo_children = 0;
2830# endif
2831 w32_init_socktype = 0;
2832 w32_timerid = 0;
2833 w32_poll_count = 0;
2834}
2835
2836void
2837Perl_sys_intern_clear(pTHX)
2838{
2839 Safefree(w32_perlshell_tokens);
2840 Safefree(w32_perlshell_vec);
2841 /* NOTE: w32_fdpid is freed by sv_clean_all() */
2842 Safefree(w32_children);
2843 if (w32_timerid) {
2844 KillTimer(NULL,w32_timerid);
2845 w32_timerid=0;
2846 }
2847# ifdef USE_ITHREADS
2848 Safefree(w32_pseudo_children);
2849# endif
2850}
2851
2852# ifdef USE_ITHREADS
2853
2854void
2855Perl_sys_intern_dup(pTHX_ struct interp_intern *src, struct interp_intern *dst)
2856{
4e205ed6 2857 dst->perlshell_tokens = NULL;
216db7ee
VK
2858 dst->perlshell_vec = (char**)NULL;
2859 dst->perlshell_items = 0;
2860 dst->fdpid = newAV();
a02a5408 2861 Newxz(dst->children, 1, child_tab);
216db7ee 2862 dst->pseudo_id = 0;
a02a5408 2863 Newxz(dst->pseudo_children, 1, child_tab);
216db7ee
VK
2864 dst->thr_intern.Winit_socktype = 0;
2865 dst->timerid = 0;
2866 dst->poll_count = 0;
2867 Copy(src->sigtable,dst->sigtable,SIG_SIZE,Sighandler_t);
2868}
2869# endif /* USE_ITHREADS */
2870#endif /* HAVE_INTERP_INTERN */
2871
216db7ee
VK
2872// added to remove undefied symbol error in CodeWarrior compilation
2873int
2874Perl_Ireentrant_buffer_ptr(aTHX)
2875{
2876 return 0;
2877}