f72c1fef1e32080a902a40e63d545f6b85d86c5a
[p5sagit/p5-mst-13.2.git] / wince / wince.c
1 /*  WINCE.C - stuff for Windows CE
2  *
3  *  Time-stamp: <26/10/01 15:25:20 keuchel@keuchelnt>
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>
12
13 #define PERLIO_NOT_STDIO 0 
14
15 #if !defined(PERLIO_IS_STDIO) && !defined(USE_SFIO)
16 #define PerlIO FILE
17 #endif
18
19 #define wince_private
20 #include "errno.h"
21
22 #include "EXTERN.h"
23 #include "perl.h"
24
25 #define NO_XSLOCKS
26 #define PERL_NO_GET_CONTEXT
27 #include "XSUB.h"
28
29 #include "win32iop.h"
30 #include <string.h>
31 #include <stdarg.h>
32 #include <float.h>
33 #include <shellapi.h>
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
42 #ifdef PALM_SIZE
43 #include "stdio-palmsize.h"
44 #endif
45
46 #define EXECF_EXEC 1
47 #define EXECF_SPAWN 2
48 #define EXECF_SPAWN_NOWAIT 3
49
50 #if defined(PERL_IMPLICIT_SYS)
51 #  undef win32_get_privlib
52 #  define win32_get_privlib g_win32_get_privlib
53 #  undef win32_get_sitelib
54 #  define win32_get_sitelib g_win32_get_sitelib
55 #  undef win32_get_vendorlib
56 #  define win32_get_vendorlib g_win32_get_vendorlib
57 #  undef do_spawn
58 #  define do_spawn g_do_spawn
59 #  undef getlogin
60 #  define getlogin g_getlogin
61 #endif
62
63 static long             filetime_to_clock(PFILETIME ft);
64 static BOOL             filetime_from_time(PFILETIME ft, time_t t);
65 static char *           get_emd_part(SV **leading, char *trailing, ...);
66 static char *           win32_get_xlib(const char *pl, const char *xlib,
67                                        const char *libname);
68
69 START_EXTERN_C
70 HANDLE  w32_perldll_handle = INVALID_HANDLE_VALUE;
71 char    w32_module_name[MAX_PATH+1];
72 END_EXTERN_C
73
74 static DWORD    w32_platform = (DWORD)-1;
75
76 int 
77 IsWin95(void)
78 {
79   return (win32_os_id() == VER_PLATFORM_WIN32_WINDOWS);
80 }
81
82 int
83 IsWinNT(void)
84 {
85   return (win32_os_id() == VER_PLATFORM_WIN32_NT);
86 }
87
88 int
89 IsWinCE(void)
90 {
91   return (win32_os_id() == VER_PLATFORM_WIN32_CE);
92 }
93
94 EXTERN_C void
95 set_w32_module_name(void)
96 {
97   char* ptr;
98   XCEGetModuleFileNameA((HMODULE)((w32_perldll_handle == INVALID_HANDLE_VALUE)
99                                   ? XCEGetModuleHandleA(NULL)
100                                   : w32_perldll_handle),
101                         w32_module_name, sizeof(w32_module_name));
102
103   /* normalize to forward slashes */
104   ptr = w32_module_name;
105   while (*ptr) {
106     if (*ptr == '\\')
107       *ptr = '/';
108     ++ptr;
109   }
110 }
111
112 /* *svp (if non-NULL) is expected to be POK (valid allocated SvPVX(*svp)) */
113 static char*
114 get_regstr_from(HKEY hkey, const char *valuename, SV **svp)
115 {
116     /* Retrieve a REG_SZ or REG_EXPAND_SZ from the registry */
117     HKEY handle;
118     DWORD type;
119     const char *subkey = "Software\\Perl";
120     char *str = Nullch;
121     long retval;
122
123     retval = XCERegOpenKeyExA(hkey, subkey, 0, KEY_READ, &handle);
124     if (retval == ERROR_SUCCESS) {
125         DWORD datalen;
126         retval = XCERegQueryValueExA(handle, valuename, 0, &type, NULL, &datalen);
127         if (retval == ERROR_SUCCESS && type == REG_SZ) {
128             dTHX;
129             if (!*svp)
130                 *svp = sv_2mortal(newSVpvn("",0));
131             SvGROW(*svp, datalen);
132             retval = XCERegQueryValueExA(handle, valuename, 0, NULL,
133                                      (PBYTE)SvPVX(*svp), &datalen);
134             if (retval == ERROR_SUCCESS) {
135                 str = SvPVX(*svp);
136                 SvCUR_set(*svp,datalen-1);
137             }
138         }
139         RegCloseKey(handle);
140     }
141     return str;
142 }
143
144 /* *svp (if non-NULL) is expected to be POK (valid allocated SvPVX(*svp)) */
145 static char*
146 get_regstr(const char *valuename, SV **svp)
147 {
148     char *str = get_regstr_from(HKEY_CURRENT_USER, valuename, svp);
149     if (!str)
150         str = get_regstr_from(HKEY_LOCAL_MACHINE, valuename, svp);
151     return str;
152 }
153
154 /* *prev_pathp (if non-NULL) is expected to be POK (valid allocated SvPVX(sv)) */
155 static char *
156 get_emd_part(SV **prev_pathp, char *trailing_path, ...)
157 {
158     char base[10];
159     va_list ap;
160     char mod_name[MAX_PATH+1];
161     char *ptr;
162     char *optr;
163     char *strip;
164     int oldsize, newsize;
165     STRLEN baselen;
166
167     va_start(ap, trailing_path);
168     strip = va_arg(ap, char *);
169
170     sprintf(base, "%d.%d", (int)PERL_REVISION, (int)PERL_VERSION);
171     baselen = strlen(base);
172
173     if (!*w32_module_name) {
174         set_w32_module_name();
175     }
176     strcpy(mod_name, w32_module_name);
177     ptr = strrchr(mod_name, '/');
178     while (ptr && strip) {
179         /* look for directories to skip back */
180         optr = ptr;
181         *ptr = '\0';
182         ptr = strrchr(mod_name, '/');
183         /* avoid stripping component if there is no slash,
184          * or it doesn't match ... */
185         if (!ptr || stricmp(ptr+1, strip) != 0) {
186             /* ... but not if component matches m|5\.$patchlevel.*| */
187             if (!ptr || !(*strip == '5' && *(ptr+1) == '5'
188                           && strncmp(strip, base, baselen) == 0
189                           && strncmp(ptr+1, base, baselen) == 0))
190             {
191                 *optr = '/';
192                 ptr = optr;
193             }
194         }
195         strip = va_arg(ap, char *);
196     }
197     if (!ptr) {
198         ptr = mod_name;
199         *ptr++ = '.';
200         *ptr = '/';
201     }
202     va_end(ap);
203     strcpy(++ptr, trailing_path);
204
205     /* only add directory if it exists */
206     if (XCEGetFileAttributesA(mod_name) != (DWORD) -1) {
207         /* directory exists */
208         dTHX;
209         if (!*prev_pathp)
210             *prev_pathp = sv_2mortal(newSVpvn("",0));
211         sv_catpvn(*prev_pathp, ";", 1);
212         sv_catpv(*prev_pathp, mod_name);
213         return SvPVX(*prev_pathp);
214     }
215
216     return Nullch;
217 }
218
219 char *
220 win32_get_privlib(const char *pl)
221 {
222     dTHX;
223     char *stdlib = "lib";
224     char buffer[MAX_PATH+1];
225     SV *sv = Nullsv;
226
227     /* $stdlib = $HKCU{"lib-$]"} || $HKLM{"lib-$]"} || $HKCU{"lib"} || $HKLM{"lib"} || "";  */
228     sprintf(buffer, "%s-%s", stdlib, pl);
229     if (!get_regstr(buffer, &sv))
230         (void)get_regstr(stdlib, &sv);
231
232     /* $stdlib .= ";$EMD/../../lib" */
233     return get_emd_part(&sv, stdlib, ARCHNAME, "bin", Nullch);
234 }
235
236 static char *
237 win32_get_xlib(const char *pl, const char *xlib, const char *libname)
238 {
239     dTHX;
240     char regstr[40];
241     char pathstr[MAX_PATH+1];
242     DWORD datalen;
243     int len, newsize;
244     SV *sv1 = Nullsv;
245     SV *sv2 = Nullsv;
246
247     /* $HKCU{"$xlib-$]"} || $HKLM{"$xlib-$]"} . ---; */
248     sprintf(regstr, "%s-%s", xlib, pl);
249     (void)get_regstr(regstr, &sv1);
250
251     /* $xlib .=
252      * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/$libname/$]/lib";  */
253     sprintf(pathstr, "%s/%s/lib", libname, pl);
254     (void)get_emd_part(&sv1, pathstr, ARCHNAME, "bin", pl, Nullch);
255
256     /* $HKCU{$xlib} || $HKLM{$xlib} . ---; */
257     (void)get_regstr(xlib, &sv2);
258
259     /* $xlib .=
260      * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/$libname/lib";  */
261     sprintf(pathstr, "%s/lib", libname);
262     (void)get_emd_part(&sv2, pathstr, ARCHNAME, "bin", pl, Nullch);
263
264     if (!sv1 && !sv2)
265         return Nullch;
266     if (!sv1)
267         return SvPVX(sv2);
268     if (!sv2)
269         return SvPVX(sv1);
270
271     sv_catpvn(sv1, ";", 1);
272     sv_catsv(sv1, sv2);
273
274     return SvPVX(sv1);
275 }
276
277 char *
278 win32_get_sitelib(const char *pl)
279 {
280     return win32_get_xlib(pl, "sitelib", "site");
281 }
282
283 #ifndef PERL_VENDORLIB_NAME
284 #  define PERL_VENDORLIB_NAME   "vendor"
285 #endif
286
287 char *
288 win32_get_vendorlib(const char *pl)
289 {
290     return win32_get_xlib(pl, "vendorlib", PERL_VENDORLIB_NAME);
291 }
292
293 #if !defined(PERL_IMPLICIT_SYS)
294 /* since the current process environment is being updated in util.c
295  * the library functions will get the correct environment
296  */
297 PerlIO *
298 Perl_my_popen(pTHX_ char *cmd, char *mode)
299 {
300   printf("popen(%s)\n", cmd);
301
302   Perl_croak(aTHX_ PL_no_func, "popen");
303   return NULL;
304 }
305
306 long
307 Perl_my_pclose(pTHX_ PerlIO *fp)
308 {
309   Perl_croak(aTHX_ PL_no_func, "pclose");
310   return -1;
311 }
312 #endif
313
314 DllExport unsigned long
315 win32_os_id(void)
316 {
317     static OSVERSIONINFOA osver;
318
319     if (osver.dwPlatformId != w32_platform) {
320         memset(&osver, 0, sizeof(OSVERSIONINFOA));
321         osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
322         XCEGetVersionExA(&osver);
323         w32_platform = osver.dwPlatformId;
324     }
325     return (unsigned long)w32_platform;
326 }
327
328 DllExport int
329 win32_getpid(void)
330 {
331   return xcegetpid();
332 }
333
334 bool
335 Perl_do_exec(pTHX_ char *cmd)
336 {
337   Perl_croak_nocontext("exec() unimplemented on this platform");
338   return FALSE;
339 }
340
341 DllExport int
342 win32_pipe(int *pfd, unsigned int size, int mode)
343 {
344   Perl_croak(aTHX_ PL_no_func, "pipe");
345   return -1;
346 }
347
348 DllExport int
349 win32_times(struct tms *timebuf)
350 {
351   Perl_croak(aTHX_ PL_no_func, "times");
352   return -1;
353 }
354
355 /* TODO */
356 bool
357 win32_signal()
358 {
359   Perl_croak_nocontext("signal() TBD on this platform");
360   return FALSE;
361 }
362 DllExport void
363 win32_clearenv()
364 {
365   return;
366 }
367
368
369 DllExport char ***
370 win32_environ(void)
371 {
372   return (&(environ));
373 }
374
375 DllExport DIR *
376 win32_opendir(char *filename)
377 {
378   return opendir(filename);
379 }
380
381 DllExport struct direct *
382 win32_readdir(DIR *dirp)
383 {
384   return readdir(dirp);
385 }
386
387 DllExport long
388 win32_telldir(DIR *dirp)
389 {
390   Perl_croak(aTHX_ PL_no_func, "telldir");
391   return -1;
392 }
393
394 DllExport void
395 win32_seekdir(DIR *dirp, long loc)
396 {
397   Perl_croak(aTHX_ PL_no_func, "seekdir");
398 }
399
400 DllExport void
401 win32_rewinddir(DIR *dirp)
402 {
403   Perl_croak(aTHX_ PL_no_func, "rewinddir");
404 }
405
406 DllExport int
407 win32_closedir(DIR *dirp)
408 {
409   closedir(dirp);
410   return 0;
411 }
412
413 DllExport int
414 win32_kill(int pid, int sig)
415 {
416   Perl_croak(aTHX_ PL_no_func, "kill");
417   return -1;
418 }
419
420 DllExport unsigned int
421 win32_sleep(unsigned int t)
422 {
423   return xcesleep(t);
424 }
425
426 DllExport int
427 win32_stat(const char *path, struct stat *sbuf)
428 {
429   return xcestat(path, sbuf);
430 }
431
432 DllExport char *
433 win32_longpath(char *path)
434 {
435   return path;
436 }
437
438 #ifndef USE_WIN32_RTL_ENV
439
440 DllExport char *
441 win32_getenv(const char *name)
442 {
443   return xcegetenv(name);
444 }
445
446 DllExport int
447 win32_putenv(const char *name)
448 {
449   return xceputenv(name);
450 }
451
452 #endif
453
454 static long
455 filetime_to_clock(PFILETIME ft)
456 {
457     __int64 qw = ft->dwHighDateTime;
458     qw <<= 32;
459     qw |= ft->dwLowDateTime;
460     qw /= 10000;  /* File time ticks at 0.1uS, clock at 1mS */
461     return (long) qw;
462 }
463
464 /* fix utime() so it works on directories in NT */
465 static BOOL
466 filetime_from_time(PFILETIME pFileTime, time_t Time)
467 {
468     struct tm *pTM = localtime(&Time);
469     SYSTEMTIME SystemTime;
470     FILETIME LocalTime;
471
472     if (pTM == NULL)
473         return FALSE;
474
475     SystemTime.wYear   = pTM->tm_year + 1900;
476     SystemTime.wMonth  = pTM->tm_mon + 1;
477     SystemTime.wDay    = pTM->tm_mday;
478     SystemTime.wHour   = pTM->tm_hour;
479     SystemTime.wMinute = pTM->tm_min;
480     SystemTime.wSecond = pTM->tm_sec;
481     SystemTime.wMilliseconds = 0;
482
483     return SystemTimeToFileTime(&SystemTime, &LocalTime) &&
484            LocalFileTimeToFileTime(&LocalTime, pFileTime);
485 }
486
487 DllExport int
488 win32_unlink(const char *filename)
489 {
490   return xceunlink(filename);
491 }
492
493 DllExport int
494 win32_utime(const char *filename, struct utimbuf *times)
495 {
496   return xceutime(filename, (struct _utimbuf *) times);
497 }
498
499 DllExport int
500 win32_gettimeofday(struct timeval *tp, void *not_used)
501 {
502     return xcegettimeofday(tp,not_used);
503 }
504
505 DllExport int
506 win32_uname(struct utsname *name)
507 {
508     struct hostent *hep;
509     STRLEN nodemax = sizeof(name->nodename)-1;
510     OSVERSIONINFOA osver;
511
512     memset(&osver, 0, sizeof(OSVERSIONINFOA));
513     osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
514     if (XCEGetVersionExA(&osver)) {
515         /* sysname */
516         switch (osver.dwPlatformId) {
517         case VER_PLATFORM_WIN32_CE:
518             strcpy(name->sysname, "Windows CE");
519             break;
520         case VER_PLATFORM_WIN32_WINDOWS:
521             strcpy(name->sysname, "Windows");
522             break;
523         case VER_PLATFORM_WIN32_NT:
524             strcpy(name->sysname, "Windows NT");
525             break;
526         case VER_PLATFORM_WIN32s:
527             strcpy(name->sysname, "Win32s");
528             break;
529         default:
530             strcpy(name->sysname, "Win32 Unknown");
531             break;
532         }
533
534         /* release */
535         sprintf(name->release, "%d.%d",
536                 osver.dwMajorVersion, osver.dwMinorVersion);
537
538         /* version */
539         sprintf(name->version, "Build %d",
540                 osver.dwPlatformId == VER_PLATFORM_WIN32_NT
541                 ? osver.dwBuildNumber : (osver.dwBuildNumber & 0xffff));
542         if (osver.szCSDVersion[0]) {
543             char *buf = name->version + strlen(name->version);
544             sprintf(buf, " (%s)", osver.szCSDVersion);
545         }
546     }
547     else {
548         *name->sysname = '\0';
549         *name->version = '\0';
550         *name->release = '\0';
551     }
552
553     /* nodename */
554     hep = win32_gethostbyname("localhost");
555     if (hep) {
556         STRLEN len = strlen(hep->h_name);
557         if (len <= nodemax) {
558             strcpy(name->nodename, hep->h_name);
559         }
560         else {
561             strncpy(name->nodename, hep->h_name, nodemax);
562             name->nodename[nodemax] = '\0';
563         }
564     }
565     else {
566         DWORD sz = nodemax;
567         if (!XCEGetComputerNameA(name->nodename, &sz))
568             *name->nodename = '\0';
569     }
570
571     /* machine (architecture) */
572     {
573         SYSTEM_INFO info;
574         char *arch;
575         GetSystemInfo(&info);
576
577         switch (info.wProcessorArchitecture) {
578         case PROCESSOR_ARCHITECTURE_INTEL:
579             arch = "x86"; break;
580         case PROCESSOR_ARCHITECTURE_MIPS:
581             arch = "mips"; break;
582         case PROCESSOR_ARCHITECTURE_ALPHA:
583             arch = "alpha"; break;
584         case PROCESSOR_ARCHITECTURE_PPC:
585             arch = "ppc"; break;
586         case PROCESSOR_ARCHITECTURE_ARM:
587             arch = "arm"; break;
588         case PROCESSOR_HITACHI_SH3:
589             arch = "sh3"; break;
590         case PROCESSOR_SHx_SH3:
591             arch = "sh3"; break;
592
593         default:
594             arch = "unknown"; break;
595         }
596         strcpy(name->machine, arch);
597     }
598     return 0;
599 }
600
601 static UINT timerid = 0;
602
603 static VOID CALLBACK TimerProc(HWND win, UINT msg, UINT id, DWORD time)
604 {
605     dTHX;
606     KillTimer(NULL,timerid);
607     timerid=0;  
608     sighandler(14);
609 }
610
611 DllExport unsigned int
612 win32_alarm(unsigned int sec)
613 {
614     /* 
615      * the 'obvious' implentation is SetTimer() with a callback
616      * which does whatever receiving SIGALRM would do 
617      * we cannot use SIGALRM even via raise() as it is not 
618      * one of the supported codes in <signal.h>
619      *
620      * Snag is unless something is looking at the message queue
621      * nothing happens :-(
622      */ 
623     dTHX;
624     if (sec)
625      {
626       timerid = SetTimer(NULL,timerid,sec*1000,(TIMERPROC)TimerProc);
627       if (!timerid)
628        Perl_croak_nocontext("Cannot set timer");
629      } 
630     else
631      {
632       if (timerid)
633        {
634         KillTimer(NULL,timerid);
635         timerid=0;  
636        }
637      }
638     return 0;
639 }
640
641 #ifdef HAVE_DES_FCRYPT
642 extern char *   des_fcrypt(const char *txt, const char *salt, char *cbuf);
643 #endif
644
645 DllExport char *
646 win32_crypt(const char *txt, const char *salt)
647 {
648     dTHX;
649 #ifdef HAVE_DES_FCRYPT
650     dTHR;
651     return des_fcrypt(txt, salt, w32_crypt_buffer);
652 #else
653     Perl_croak(aTHX_ "The crypt() function is unimplemented due to excessive paranoia.");
654     return Nullch;
655 #endif
656 }
657
658 /* C doesn't like repeat struct definitions */
659
660 #if defined(USE_FIXED_OSFHANDLE) || defined(PERL_MSVCRT_READFIX)
661
662 #ifndef _CRTIMP
663 #define _CRTIMP __declspec(dllimport)
664 #endif
665
666 /*
667  * Control structure for lowio file handles
668  */
669 typedef struct {
670     long osfhnd;    /* underlying OS file HANDLE */
671     char osfile;    /* attributes of file (e.g., open in text mode?) */
672     char pipech;    /* one char buffer for handles opened on pipes */
673     int lockinitflag;
674     CRITICAL_SECTION lock;
675 } ioinfo;
676
677
678 /*
679  * Array of arrays of control structures for lowio files.
680  */
681 EXTERN_C _CRTIMP ioinfo* __pioinfo[];
682
683 /*
684  * Definition of IOINFO_L2E, the log base 2 of the number of elements in each
685  * array of ioinfo structs.
686  */
687 #define IOINFO_L2E          5
688
689 /*
690  * Definition of IOINFO_ARRAY_ELTS, the number of elements in ioinfo array
691  */
692 #define IOINFO_ARRAY_ELTS   (1 << IOINFO_L2E)
693
694 /*
695  * Access macros for getting at an ioinfo struct and its fields from a
696  * file handle
697  */
698 #define _pioinfo(i) (__pioinfo[(i) >> IOINFO_L2E] + ((i) & (IOINFO_ARRAY_ELTS - 1)))
699 #define _osfhnd(i)  (_pioinfo(i)->osfhnd)
700 #define _osfile(i)  (_pioinfo(i)->osfile)
701 #define _pipech(i)  (_pioinfo(i)->pipech)
702
703 #endif
704
705 /*
706  *  redirected io subsystem for all XS modules
707  *
708  */
709
710 DllExport int *
711 win32_errno(void)
712 {
713     return (&errno);
714 }
715
716 /* the rest are the remapped stdio routines */
717 DllExport FILE *
718 win32_stderr(void)
719 {
720     return (stderr);
721 }
722
723 DllExport FILE *
724 win32_stdin(void)
725 {
726     return (stdin);
727 }
728
729 DllExport FILE *
730 win32_stdout()
731 {
732     return (stdout);
733 }
734
735 DllExport int
736 win32_ferror(FILE *fp)
737 {
738     return (ferror(fp));
739 }
740
741
742 DllExport int
743 win32_feof(FILE *fp)
744 {
745     return (feof(fp));
746 }
747
748 /*
749  * Since the errors returned by the socket error function 
750  * WSAGetLastError() are not known by the library routine strerror
751  * we have to roll our own.
752  */
753
754 DllExport char *
755 win32_strerror(int e) 
756 {
757   return xcestrerror(e);
758 }
759
760 DllExport void
761 win32_str_os_error(void *sv, DWORD dwErr)
762 {
763   dTHX;
764
765   sv_setpvn((SV*)sv, "Error", 5);
766 }
767
768
769 DllExport int
770 win32_fprintf(FILE *fp, const char *format, ...)
771 {
772     va_list marker;
773     va_start(marker, format);     /* Initialize variable arguments. */
774
775     return (vfprintf(fp, format, marker));
776 }
777
778 DllExport int
779 win32_printf(const char *format, ...)
780 {
781     va_list marker;
782     va_start(marker, format);     /* Initialize variable arguments. */
783
784     return (vprintf(format, marker));
785 }
786
787 DllExport int
788 win32_vfprintf(FILE *fp, const char *format, va_list args)
789 {
790     return (vfprintf(fp, format, args));
791 }
792
793 DllExport int
794 win32_vprintf(const char *format, va_list args)
795 {
796     return (vprintf(format, args));
797 }
798
799 DllExport size_t
800 win32_fread(void *buf, size_t size, size_t count, FILE *fp)
801 {
802   return fread(buf, size, count, fp);
803 }
804
805 DllExport size_t
806 win32_fwrite(const void *buf, size_t size, size_t count, FILE *fp)
807 {
808   return fwrite(buf, size, count, fp);
809 }
810
811 DllExport FILE *
812 win32_fopen(const char *filename, const char *mode)
813 {
814   return xcefopen(filename, mode);
815 }
816
817 DllExport FILE *
818 win32_fdopen(int handle, const char *mode)
819 {
820   return palm_fdopen(handle, mode);
821 }
822
823 DllExport FILE *
824 win32_freopen(const char *path, const char *mode, FILE *stream)
825 {
826   return xcefreopen(path, mode, stream);
827 }
828
829 DllExport int
830 win32_fclose(FILE *pf)
831 {
832   return xcefclose(pf);
833 }
834
835 DllExport int
836 win32_fputs(const char *s,FILE *pf)
837 {
838   return fputs(s, pf);
839 }
840
841 DllExport int
842 win32_fputc(int c,FILE *pf)
843 {
844   return fputc(c,pf);
845 }
846
847 DllExport int
848 win32_ungetc(int c,FILE *pf)
849 {
850   return ungetc(c,pf);
851 }
852
853 DllExport int
854 win32_getc(FILE *pf)
855 {
856   return getc(pf);
857 }
858
859 DllExport int
860 win32_fileno(FILE *pf)
861 {
862   return palm_fileno(pf);
863 }
864
865 DllExport void
866 win32_clearerr(FILE *pf)
867 {
868   clearerr(pf);
869   return;
870 }
871
872 DllExport int
873 win32_fflush(FILE *pf)
874 {
875   return fflush(pf);
876 }
877
878 DllExport long
879 win32_ftell(FILE *pf)
880 {
881   return ftell(pf);
882 }
883
884 DllExport int
885 win32_fseek(FILE *pf,long offset,int origin)
886 {
887   return fseek(pf, offset, origin);
888 }
889
890 /* fpos_t seems to be int64 on hpc pro! Really stupid. */
891 /* But maybe someday there will be such large disks in a hpc... */
892 DllExport int
893 win32_fgetpos(FILE *pf, fpos_t *p)
894 {
895   return fgetpos(pf, p);
896 }
897
898 DllExport int
899 win32_fsetpos(FILE *pf, const fpos_t *p)
900 {
901   return fsetpos(pf, p);
902 }
903
904 DllExport void
905 win32_rewind(FILE *pf)
906 {
907   fseek(pf, 0, SEEK_SET);
908   return;
909 }
910
911 DllExport FILE*
912 win32_tmpfile(void)
913 {
914   Perl_croak(aTHX_ PL_no_func, "tmpfile");
915
916   return NULL;
917 }
918
919 DllExport void
920 win32_abort(void)
921 {
922   xceabort();
923
924   return;
925 }
926
927 DllExport int
928 win32_fstat(int fd, struct stat *sbufptr)
929 {
930   return xcefstat(fd, sbufptr);
931 }
932
933 DllExport int
934 win32_link(const char *oldname, const char *newname)
935 {
936   Perl_croak(aTHX_ PL_no_func, "link");
937
938   return -1;
939 }
940
941 DllExport int
942 win32_rename(const char *oname, const char *newname)
943 {
944   return xcerename(oname, newname);
945 }
946
947 DllExport int
948 win32_setmode(int fd, int mode)
949 {
950   if(mode != O_BINARY)
951     {
952       Perl_croak(aTHX_ PL_no_func, "setmode");
953       return -1;
954     }
955   return 0;
956 }
957
958 DllExport long
959 win32_lseek(int fd, long offset, int origin)
960 {
961   return xcelseek(fd, offset, origin);
962 }
963
964 DllExport long
965 win32_tell(int fd)
966 {
967   return xcelseek(fd, 0, SEEK_CUR);
968 }
969
970 DllExport int
971 win32_open(const char *path, int flag, ...)
972 {
973   int pmode;
974   va_list ap;
975
976   va_start(ap, flag);
977   pmode = va_arg(ap, int);
978   va_end(ap);
979
980   return xceopen(path, flag, pmode);
981 }
982
983 DllExport int
984 win32_close(int fd)
985 {
986   return xceclose(fd);
987 }
988
989 DllExport int
990 win32_eof(int fd)
991 {
992   Perl_croak(aTHX_ PL_no_func, "eof");
993   return -1;
994 }
995
996 DllExport int
997 win32_dup(int fd)
998 {
999   Perl_croak(aTHX_ PL_no_func, "dup");
1000   return -1;
1001 }
1002
1003 DllExport int
1004 win32_dup2(int fd1,int fd2)
1005 {
1006   Perl_croak(aTHX_ PL_no_func, "dup2");
1007   return -1;
1008 }
1009
1010 DllExport int
1011 win32_read(int fd, void *buf, unsigned int cnt)
1012 {
1013   return xceread(fd, buf, cnt);
1014 }
1015
1016 DllExport int
1017 win32_write(int fd, const void *buf, unsigned int cnt)
1018 {
1019   return xcewrite(fd, (void *) buf, cnt);
1020 }
1021
1022 DllExport int
1023 win32_mkdir(const char *dir, int mode)
1024 {
1025   return xcemkdir(dir);
1026 }
1027
1028 DllExport int
1029 win32_rmdir(const char *dir)
1030 {
1031   return xcermdir(dir);
1032 }
1033
1034 DllExport int
1035 win32_chdir(const char *dir)
1036 {
1037   return xcechdir(dir);
1038 }
1039
1040 DllExport  int
1041 win32_access(const char *path, int mode)
1042 {
1043   return xceaccess(path, mode);
1044 }
1045
1046 DllExport  int
1047 win32_chmod(const char *path, int mode)
1048 {
1049   return xcechmod(path, mode);
1050 }
1051
1052 DllExport void
1053 win32_perror(const char *str)
1054 {
1055   xceperror(str);
1056 }
1057
1058 DllExport void
1059 win32_setbuf(FILE *pf, char *buf)
1060 {
1061   Perl_croak(aTHX_ PL_no_func, "setbuf");
1062 }
1063
1064 DllExport int
1065 win32_setvbuf(FILE *pf, char *buf, int type, size_t size)
1066 {
1067   return setvbuf(pf, buf, type, size);
1068 }
1069
1070 DllExport int
1071 win32_flushall(void)
1072 {
1073   return flushall();
1074 }
1075
1076 DllExport int
1077 win32_fcloseall(void)
1078 {
1079   return fcloseall();
1080 }
1081
1082 DllExport char*
1083 win32_fgets(char *s, int n, FILE *pf)
1084 {
1085   return fgets(s, n, pf);
1086 }
1087
1088 DllExport char*
1089 win32_gets(char *s)
1090 {
1091   return gets(s);
1092 }
1093
1094 DllExport int
1095 win32_fgetc(FILE *pf)
1096 {
1097   return fgetc(pf);
1098 }
1099
1100 DllExport int
1101 win32_putc(int c, FILE *pf)
1102 {
1103   return putc(c,pf);
1104 }
1105
1106 DllExport int
1107 win32_puts(const char *s)
1108 {
1109   return puts(s);
1110 }
1111
1112 DllExport int
1113 win32_getchar(void)
1114 {
1115   return getchar();
1116 }
1117
1118 DllExport int
1119 win32_putchar(int c)
1120 {
1121   return putchar(c);
1122 }
1123
1124 #ifdef MYMALLOC
1125
1126 #ifndef USE_PERL_SBRK
1127
1128 static char *committed = NULL;
1129 static char *base      = NULL;
1130 static char *reserved  = NULL;
1131 static char *brk       = NULL;
1132 static DWORD pagesize  = 0;
1133 static DWORD allocsize = 0;
1134
1135 void *
1136 sbrk(int need)
1137 {
1138  void *result;
1139  if (!pagesize)
1140   {SYSTEM_INFO info;
1141    GetSystemInfo(&info);
1142    /* Pretend page size is larger so we don't perpetually
1143     * call the OS to commit just one page ...
1144     */
1145    pagesize = info.dwPageSize << 3;
1146    allocsize = info.dwAllocationGranularity;
1147   }
1148  /* This scheme fails eventually if request for contiguous
1149   * block is denied so reserve big blocks - this is only 
1150   * address space not memory ...
1151   */
1152  if (brk+need >= reserved)
1153   {
1154    DWORD size = 64*1024*1024;
1155    char *addr;
1156    if (committed && reserved && committed < reserved)
1157     {
1158      /* Commit last of previous chunk cannot span allocations */
1159      addr = (char *) VirtualAlloc(committed,reserved-committed,MEM_COMMIT,PAGE_READWRITE);
1160      if (addr)
1161       committed = reserved;
1162     }
1163    /* Reserve some (more) space 
1164     * Note this is a little sneaky, 1st call passes NULL as reserved
1165     * so lets system choose where we start, subsequent calls pass
1166     * the old end address so ask for a contiguous block
1167     */
1168    addr  = (char *) VirtualAlloc(reserved,size,MEM_RESERVE,PAGE_NOACCESS);
1169    if (addr)
1170     {
1171      reserved = addr+size;
1172      if (!base)
1173       base = addr;
1174      if (!committed)
1175       committed = base;
1176      if (!brk)
1177       brk = committed;
1178     }
1179    else
1180     {
1181      return (void *) -1;
1182     }
1183   }
1184  result = brk;
1185  brk += need;
1186  if (brk > committed)
1187   {
1188    DWORD size = ((brk-committed + pagesize -1)/pagesize) * pagesize;
1189    char *addr = (char *) VirtualAlloc(committed,size,MEM_COMMIT,PAGE_READWRITE);
1190    if (addr)
1191     {
1192      committed += size;
1193     }
1194    else
1195     return (void *) -1;
1196   }
1197  return result;
1198 }
1199
1200 #endif
1201 #endif
1202
1203 DllExport void*
1204 win32_malloc(size_t size)
1205 {
1206     return malloc(size);
1207 }
1208
1209 DllExport void*
1210 win32_calloc(size_t numitems, size_t size)
1211 {
1212     return calloc(numitems,size);
1213 }
1214
1215 DllExport void*
1216 win32_realloc(void *block, size_t size)
1217 {
1218     return realloc(block,size);
1219 }
1220
1221 DllExport void
1222 win32_free(void *block)
1223 {
1224     free(block);
1225 }
1226
1227 DllExport int
1228 win32_execv(const char *cmdname, const char *const *argv)
1229 {
1230   Perl_croak(aTHX_ PL_no_func, "execv");
1231   return -1;
1232 }
1233
1234 DllExport int
1235 win32_execvp(const char *cmdname, const char *const *argv)
1236 {
1237   Perl_croak(aTHX_ PL_no_func, "execvp");
1238   return -1;
1239 }
1240
1241 DllExport void*
1242 win32_dynaload(const char* filename)
1243 {
1244     dTHX;
1245     HMODULE hModule;
1246
1247     hModule = XCELoadLibraryA(filename);
1248
1249     return hModule;
1250 }
1251
1252 /* this is needed by Cwd.pm... */
1253
1254 static
1255 XS(w32_GetCwd)
1256 {
1257   dXSARGS;
1258   char buf[MAX_PATH];
1259   SV *sv = sv_newmortal();
1260
1261   xcegetcwd(buf, sizeof(buf));
1262
1263   sv_setpv(sv, xcestrdup(buf));
1264   EXTEND(SP,1);
1265   SvPOK_on(sv);
1266   ST(0) = sv;
1267 #ifndef INCOMPLETE_TAINTS
1268   SvTAINTED_on(ST(0));
1269 #endif
1270   XSRETURN(1);
1271 }
1272
1273 static
1274 XS(w32_SetCwd)
1275 {
1276   dXSARGS;
1277
1278   if (items != 1)
1279     Perl_croak(aTHX_ "usage: Win32::SetCwd($cwd)");
1280
1281   if (!xcechdir(SvPV_nolen(ST(0))))
1282     XSRETURN_YES;
1283
1284   XSRETURN_NO;
1285 }
1286
1287 static
1288 XS(w32_GetTickCount)
1289 {
1290     dXSARGS;
1291     DWORD msec = GetTickCount();
1292     EXTEND(SP,1);
1293     if ((IV)msec > 0)
1294         XSRETURN_IV(msec);
1295     XSRETURN_NV(msec);
1296 }
1297
1298 static
1299 XS(w32_GetOSVersion)
1300 {
1301     dXSARGS;
1302     OSVERSIONINFOA osver;
1303
1304     osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1305     if (!XCEGetVersionExA(&osver)) {
1306       XSRETURN_EMPTY;
1307     }
1308     XPUSHs(newSVpvn(osver.szCSDVersion, strlen(osver.szCSDVersion)));
1309     XPUSHs(newSViv(osver.dwMajorVersion));
1310     XPUSHs(newSViv(osver.dwMinorVersion));
1311     XPUSHs(newSViv(osver.dwBuildNumber));
1312     /* WINCE = 3 */
1313     XPUSHs(newSViv(osver.dwPlatformId));
1314     PUTBACK;
1315 }
1316
1317 static
1318 XS(w32_IsWinNT)
1319 {
1320     dXSARGS;
1321     EXTEND(SP,1);
1322     XSRETURN_IV(IsWinNT());
1323 }
1324
1325 static
1326 XS(w32_IsWin95)
1327 {
1328     dXSARGS;
1329     EXTEND(SP,1);
1330     XSRETURN_IV(IsWin95());
1331 }
1332
1333 static
1334 XS(w32_IsWinCE)
1335 {
1336     dXSARGS;
1337     EXTEND(SP,1);
1338     XSRETURN_IV(IsWinCE());
1339 }
1340
1341 static
1342 XS(w32_GetOemInfo)
1343 {
1344   dXSARGS;
1345   wchar_t wbuf[126];
1346   char buf[126];
1347
1348   if(SystemParametersInfoW(SPI_GETOEMINFO, sizeof(wbuf), wbuf, FALSE))
1349     WideCharToMultiByte(CP_ACP, 0, wbuf, -1, buf, sizeof(buf), 0, 0);
1350   else
1351     sprintf(buf, "SystemParametersInfo failed: %d", GetLastError());
1352
1353   EXTEND(SP,1);
1354   XSRETURN_PV(buf);
1355 }
1356
1357 static
1358 XS(w32_Sleep)
1359 {
1360     dXSARGS;
1361     if (items != 1)
1362         Perl_croak(aTHX_ "usage: Win32::Sleep($milliseconds)");
1363     Sleep(SvIV(ST(0)));
1364     XSRETURN_YES;
1365 }
1366
1367 static
1368 XS(w32_CopyFile)
1369 {
1370     dXSARGS;
1371     BOOL bResult;
1372     if (items != 3)
1373         Perl_croak(aTHX_ "usage: Win32::CopyFile($from, $to, $overwrite)");
1374
1375     {
1376       char szSourceFile[MAX_PATH+1];
1377       strcpy(szSourceFile, PerlDir_mapA(SvPV_nolen(ST(0))));
1378       bResult = XCECopyFileA(szSourceFile, SvPV_nolen(ST(1)), 
1379                              !SvTRUE(ST(2)));
1380     }
1381
1382     if (bResult)
1383         XSRETURN_YES;
1384
1385     XSRETURN_NO;
1386 }
1387
1388 static
1389 XS(w32_MessageBox)
1390 {
1391     dXSARGS;
1392
1393     char *txt;
1394     unsigned int res;
1395     unsigned int flags = MB_OK;
1396
1397     txt = SvPV_nolen(ST(0));
1398     
1399     if (items < 1 || items > 2)
1400         Perl_croak(aTHX_ "usage: Win32::MessageBox($txt, [$flags])");
1401
1402     if(items == 2)
1403       flags = SvIV(ST(1));
1404
1405     res = XCEMessageBoxA(NULL, txt, "Perl", flags);
1406
1407     XSRETURN_IV(res);
1408 }
1409
1410 static
1411 XS(w32_GetPowerStatus)
1412 {
1413   dXSARGS;
1414
1415   SYSTEM_POWER_STATUS_EX sps;
1416
1417   if(GetSystemPowerStatusEx(&sps, TRUE) == FALSE)
1418     {
1419       XSRETURN_EMPTY;
1420     }
1421
1422   XPUSHs(newSViv(sps.ACLineStatus));
1423   XPUSHs(newSViv(sps.BatteryFlag));
1424   XPUSHs(newSViv(sps.BatteryLifePercent));
1425   XPUSHs(newSViv(sps.BatteryLifeTime));
1426   XPUSHs(newSViv(sps.BatteryFullLifeTime));
1427   XPUSHs(newSViv(sps.BackupBatteryFlag));
1428   XPUSHs(newSViv(sps.BackupBatteryLifePercent));
1429   XPUSHs(newSViv(sps.BackupBatteryLifeTime));
1430   XPUSHs(newSViv(sps.BackupBatteryFullLifeTime));
1431
1432   PUTBACK;
1433 }
1434
1435 #if UNDER_CE > 200
1436 static
1437 XS(w32_ShellEx)
1438 {
1439   dXSARGS;
1440
1441   char buf[126];
1442   SHELLEXECUTEINFO si;
1443   char *file, *verb;
1444   wchar_t wfile[MAX_PATH];
1445   wchar_t wverb[20];
1446
1447   if (items != 2)
1448     Perl_croak(aTHX_ "usage: Win32::ShellEx($file, $verb)");
1449
1450   file = SvPV_nolen(ST(0));
1451   verb = SvPV_nolen(ST(1));
1452
1453   memset(&si, 0, sizeof(si));
1454   si.cbSize = sizeof(si);
1455   si.fMask = SEE_MASK_FLAG_NO_UI;
1456
1457   MultiByteToWideChar(CP_ACP, 0, verb, -1, 
1458                       wverb, sizeof(wverb)/2);
1459   si.lpVerb = (TCHAR *)wverb;
1460
1461   MultiByteToWideChar(CP_ACP, 0, file, -1, 
1462                       wfile, sizeof(wfile)/2);
1463   si.lpFile = (TCHAR *)wfile;
1464
1465   if(ShellExecuteEx(&si) == FALSE)
1466     {
1467       XSRETURN_NO;
1468     }
1469   XSRETURN_YES;
1470 }
1471 #endif
1472
1473 void
1474 Perl_init_os_extras(void)
1475 {
1476     dTHX;
1477     char *file = __FILE__;
1478     dXSUB_SYS;
1479
1480     w32_perlshell_tokens = Nullch;
1481     w32_perlshell_items = -1;
1482     w32_fdpid = newAV(); /* XX needs to be in Perl_win32_init()? */
1483     New(1313, w32_children, 1, child_tab);
1484     w32_num_children = 0;
1485
1486     newXS("Win32::GetCwd", w32_GetCwd, file);
1487     newXS("Win32::SetCwd", w32_SetCwd, file);
1488     newXS("Win32::GetTickCount", w32_GetTickCount, file);
1489     newXS("Win32::GetOSVersion", w32_GetOSVersion, file);
1490 #if UNDER_CE > 200
1491     newXS("Win32::ShellEx", w32_ShellEx, file);
1492 #endif
1493     newXS("Win32::IsWinNT", w32_IsWinNT, file);
1494     newXS("Win32::IsWin95", w32_IsWin95, file);
1495     newXS("Win32::IsWinCE", w32_IsWinCE, file);
1496     newXS("Win32::CopyFile", w32_CopyFile, file);
1497     newXS("Win32::Sleep", w32_Sleep, file);
1498     newXS("Win32::MessageBox", w32_MessageBox, file);
1499     newXS("Win32::GetPowerStatus", w32_GetPowerStatus, file);
1500     newXS("Win32::GetOemInfo", w32_GetOemInfo, file);
1501 }
1502
1503 void
1504 myexit(void)
1505 {
1506   char buf[126];
1507
1508   puts("Hit return");
1509   fgets(buf, sizeof(buf), stdin);
1510 }
1511
1512 void
1513 Perl_win32_init(int *argcp, char ***argvp)
1514 {
1515 #ifdef UNDER_CE
1516   char *p;
1517
1518   if((p = xcegetenv("PERLDEBUG")) && (p[0] == 'y' || p[0] == 'Y'))
1519     atexit(myexit);
1520 #endif
1521
1522   MALLOC_INIT;
1523 }
1524
1525 DllExport int
1526 win32_flock(int fd, int oper)
1527 {
1528   Perl_croak(aTHX_ PL_no_func, "flock");
1529   return -1;
1530 }
1531
1532 DllExport int
1533 win32_waitpid(int pid, int *status, int flags)
1534 {
1535   Perl_croak(aTHX_ PL_no_func, "waitpid");
1536   return -1;
1537 }
1538
1539 DllExport int
1540 win32_wait(int *status)
1541 {
1542   Perl_croak(aTHX_ PL_no_func, "wait");
1543   return -1;
1544 }
1545
1546 int
1547 do_spawn(char *cmd)
1548 {
1549   return xcesystem(cmd);
1550 }
1551
1552 int
1553 do_aspawn(void *vreally, void **vmark, void **vsp)
1554 {
1555   Perl_croak(aTHX_ PL_no_func, "aspawn");
1556   return -1;
1557 }
1558
1559 int
1560 wce_reopen_stdout(char *fname)
1561 {     
1562   if(xcefreopen(fname, "w", stdout) == NULL)
1563     return -1;
1564
1565   return 0;
1566 }
1567
1568 void
1569 wce_hitreturn()
1570 {
1571   char buf[126];
1572
1573   printf("Hit RETURN");
1574   fflush(stdout);
1575   fgets(buf, sizeof(buf), stdin);
1576   return;
1577 }
1578
1579 /* //////////////////////////////////////////////////////////////////// */
1580
1581 void
1582 win32_argv2utf8(int argc, char** argv)
1583 {
1584   /* do nothing... */
1585 }
1586
1587 void
1588 Perl_sys_intern_init(pTHX)
1589 {
1590     w32_perlshell_tokens        = Nullch;
1591     w32_perlshell_vec           = (char**)NULL;
1592     w32_perlshell_items         = 0;
1593     w32_fdpid                   = newAV();
1594     New(1313, w32_children, 1, child_tab);
1595     w32_num_children            = 0;
1596 #  ifdef USE_ITHREADS
1597     w32_pseudo_id               = 0;
1598     New(1313, w32_pseudo_children, 1, child_tab);
1599     w32_num_pseudo_children     = 0;
1600 #  endif
1601
1602 #ifndef UNDER_CE
1603     w32_init_socktype           = 0;
1604 #endif
1605 }
1606
1607 void
1608 Perl_sys_intern_clear(pTHX)
1609 {
1610     Safefree(w32_perlshell_tokens);
1611     Safefree(w32_perlshell_vec);
1612     /* NOTE: w32_fdpid is freed by sv_clean_all() */
1613     Safefree(w32_children);
1614 #  ifdef USE_ITHREADS
1615     Safefree(w32_pseudo_children);
1616 #  endif
1617 }
1618
1619 /* //////////////////////////////////////////////////////////////////// */
1620
1621 #undef getcwd
1622
1623 char *
1624 getcwd(char *buf, size_t size)
1625 {
1626   return xcegetcwd(buf, size);
1627 }
1628
1629 int 
1630 isnan(double d)
1631 {
1632   return _isnan(d);
1633 }
1634
1635 int
1636 win32_open_osfhandle(intptr_t osfhandle, int flags)
1637 {
1638     int fh;
1639     char fileflags=0;           /* _osfile flags */
1640
1641     XCEMessageBoxA(NULL, "NEED TO IMPLEMENT in wince/wince.c(win32_open_osfhandle)", "error", 0);
1642     Perl_croak_nocontext("win32_open_osfhandle() TBD on this platform");
1643     return 0;
1644 }
1645
1646 int
1647 win32_get_osfhandle(intptr_t osfhandle, int flags)
1648 {
1649     int fh;
1650     char fileflags=0;           /* _osfile flags */
1651
1652     XCEMessageBoxA(NULL, "NEED TO IMPLEMENT in wince/wince.c(win32_get_osfhandle)", "error", 0);
1653     Perl_croak_nocontext("win32_get_osfhandle() TBD on this platform");
1654     return 0;
1655 }
1656
1657 /*
1658  * a popen() clone that respects PERL5SHELL
1659  *
1660  * changed to return PerlIO* rather than FILE * by BKS, 11-11-2000
1661  */
1662
1663 DllExport PerlIO*
1664 win32_popen(const char *command, const char *mode)
1665 {
1666     XCEMessageBoxA(NULL, "NEED TO IMPLEMENT in wince/wince.c(win32_popen)", "error", 0);
1667     Perl_croak_nocontext("win32_popen() TBD on this platform");
1668 }
1669
1670 /*
1671  * pclose() clone
1672  */
1673
1674 DllExport int
1675 win32_pclose(PerlIO *pf)
1676 {
1677 #ifdef USE_RTL_POPEN
1678     return _pclose(pf);
1679 #else
1680     dTHX;
1681     int childpid, status;
1682     SV *sv;
1683
1684     LOCK_FDPID_MUTEX;
1685     sv = *av_fetch(w32_fdpid, PerlIO_fileno(pf), TRUE);
1686
1687     if (SvIOK(sv))
1688         childpid = SvIVX(sv);
1689     else
1690         childpid = 0;
1691
1692     if (!childpid) {
1693         errno = EBADF;
1694         return -1;
1695     }
1696
1697 #ifdef USE_PERLIO
1698     PerlIO_close(pf);
1699 #else
1700     fclose(pf);
1701 #endif
1702     SvIVX(sv) = 0;
1703     UNLOCK_FDPID_MUTEX;
1704
1705     if (win32_waitpid(childpid, &status, 0) == -1)
1706         return -1;
1707
1708     return status;
1709
1710 #endif /* USE_RTL_POPEN */
1711 }
1712
1713 FILE *
1714 win32_fdupopen(FILE *pf)
1715 {
1716     FILE* pfdup;
1717     fpos_t pos;
1718     char mode[3];
1719     int fileno = win32_dup(win32_fileno(pf));
1720
1721     XCEMessageBoxA(NULL, "NEED TO IMPLEMENT a place in .../wince/wince.c(win32_fdupopen)", "Perl(developer)", 0);
1722     Perl_croak_nocontext("win32_fdupopen() TBD on this platform");
1723
1724 #if 0
1725     /* open the file in the same mode */
1726     if((pf)->_flag & _IOREAD) {
1727         mode[0] = 'r';
1728         mode[1] = 0;
1729     }
1730     else if((pf)->_flag & _IOWRT) {
1731         mode[0] = 'a';
1732         mode[1] = 0;
1733     }
1734     else if((pf)->_flag & _IORW) {
1735         mode[0] = 'r';
1736         mode[1] = '+';
1737         mode[2] = 0;
1738     }
1739
1740     /* it appears that the binmode is attached to the
1741      * file descriptor so binmode files will be handled
1742      * correctly
1743      */
1744     pfdup = win32_fdopen(fileno, mode);
1745
1746     /* move the file pointer to the same position */
1747     if (!fgetpos(pf, &pos)) {
1748         fsetpos(pfdup, &pos);
1749     }
1750 #endif
1751     return pfdup;
1752 }