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