This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Avoid potentially empty struct.
[perl5.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     /* currently 'celib' seem to have this function in src, but not
951      * exported. When it will be, we'll uncomment following line.
952      */
953     /* return xcesetmode(fd, mode); */
954     return 0;
955 }
956
957 DllExport long
958 win32_lseek(int fd, long offset, int origin)
959 {
960   return xcelseek(fd, offset, origin);
961 }
962
963 DllExport long
964 win32_tell(int fd)
965 {
966   return xcelseek(fd, 0, SEEK_CUR);
967 }
968
969 DllExport int
970 win32_open(const char *path, int flag, ...)
971 {
972   int pmode;
973   va_list ap;
974
975   va_start(ap, flag);
976   pmode = va_arg(ap, int);
977   va_end(ap);
978
979   return xceopen(path, flag, pmode);
980 }
981
982 DllExport int
983 win32_close(int fd)
984 {
985   return xceclose(fd);
986 }
987
988 DllExport int
989 win32_eof(int fd)
990 {
991   Perl_croak(aTHX_ PL_no_func, "eof");
992   return -1;
993 }
994
995 DllExport int
996 win32_dup(int fd)
997 {
998   Perl_croak(aTHX_ PL_no_func, "dup");
999   return -1;
1000 }
1001
1002 DllExport int
1003 win32_dup2(int fd1,int fd2)
1004 {
1005   Perl_croak(aTHX_ PL_no_func, "dup2");
1006   return -1;
1007 }
1008
1009 DllExport int
1010 win32_read(int fd, void *buf, unsigned int cnt)
1011 {
1012   return xceread(fd, buf, cnt);
1013 }
1014
1015 DllExport int
1016 win32_write(int fd, const void *buf, unsigned int cnt)
1017 {
1018   return xcewrite(fd, (void *) buf, cnt);
1019 }
1020
1021 DllExport int
1022 win32_mkdir(const char *dir, int mode)
1023 {
1024   return xcemkdir(dir);
1025 }
1026
1027 DllExport int
1028 win32_rmdir(const char *dir)
1029 {
1030   return xcermdir(dir);
1031 }
1032
1033 DllExport int
1034 win32_chdir(const char *dir)
1035 {
1036   return xcechdir(dir);
1037 }
1038
1039 DllExport  int
1040 win32_access(const char *path, int mode)
1041 {
1042   return xceaccess(path, mode);
1043 }
1044
1045 DllExport  int
1046 win32_chmod(const char *path, int mode)
1047 {
1048   return xcechmod(path, mode);
1049 }
1050
1051 DllExport void
1052 win32_perror(const char *str)
1053 {
1054   xceperror(str);
1055 }
1056
1057 DllExport void
1058 win32_setbuf(FILE *pf, char *buf)
1059 {
1060   Perl_croak(aTHX_ PL_no_func, "setbuf");
1061 }
1062
1063 DllExport int
1064 win32_setvbuf(FILE *pf, char *buf, int type, size_t size)
1065 {
1066   return setvbuf(pf, buf, type, size);
1067 }
1068
1069 DllExport int
1070 win32_flushall(void)
1071 {
1072   return flushall();
1073 }
1074
1075 DllExport int
1076 win32_fcloseall(void)
1077 {
1078   return fcloseall();
1079 }
1080
1081 DllExport char*
1082 win32_fgets(char *s, int n, FILE *pf)
1083 {
1084   return fgets(s, n, pf);
1085 }
1086
1087 DllExport char*
1088 win32_gets(char *s)
1089 {
1090   return gets(s);
1091 }
1092
1093 DllExport int
1094 win32_fgetc(FILE *pf)
1095 {
1096   return fgetc(pf);
1097 }
1098
1099 DllExport int
1100 win32_putc(int c, FILE *pf)
1101 {
1102   return putc(c,pf);
1103 }
1104
1105 DllExport int
1106 win32_puts(const char *s)
1107 {
1108   return puts(s);
1109 }
1110
1111 DllExport int
1112 win32_getchar(void)
1113 {
1114   return getchar();
1115 }
1116
1117 DllExport int
1118 win32_putchar(int c)
1119 {
1120   return putchar(c);
1121 }
1122
1123 #ifdef MYMALLOC
1124
1125 #ifndef USE_PERL_SBRK
1126
1127 static char *committed = NULL;
1128 static char *base      = NULL;
1129 static char *reserved  = NULL;
1130 static char *brk       = NULL;
1131 static DWORD pagesize  = 0;
1132 static DWORD allocsize = 0;
1133
1134 void *
1135 sbrk(int need)
1136 {
1137  void *result;
1138  if (!pagesize)
1139   {SYSTEM_INFO info;
1140    GetSystemInfo(&info);
1141    /* Pretend page size is larger so we don't perpetually
1142     * call the OS to commit just one page ...
1143     */
1144    pagesize = info.dwPageSize << 3;
1145    allocsize = info.dwAllocationGranularity;
1146   }
1147  /* This scheme fails eventually if request for contiguous
1148   * block is denied so reserve big blocks - this is only 
1149   * address space not memory ...
1150   */
1151  if (brk+need >= reserved)
1152   {
1153    DWORD size = 64*1024*1024;
1154    char *addr;
1155    if (committed && reserved && committed < reserved)
1156     {
1157      /* Commit last of previous chunk cannot span allocations */
1158      addr = (char *) VirtualAlloc(committed,reserved-committed,MEM_COMMIT,PAGE_READWRITE);
1159      if (addr)
1160       committed = reserved;
1161     }
1162    /* Reserve some (more) space 
1163     * Note this is a little sneaky, 1st call passes NULL as reserved
1164     * so lets system choose where we start, subsequent calls pass
1165     * the old end address so ask for a contiguous block
1166     */
1167    addr  = (char *) VirtualAlloc(reserved,size,MEM_RESERVE,PAGE_NOACCESS);
1168    if (addr)
1169     {
1170      reserved = addr+size;
1171      if (!base)
1172       base = addr;
1173      if (!committed)
1174       committed = base;
1175      if (!brk)
1176       brk = committed;
1177     }
1178    else
1179     {
1180      return (void *) -1;
1181     }
1182   }
1183  result = brk;
1184  brk += need;
1185  if (brk > committed)
1186   {
1187    DWORD size = ((brk-committed + pagesize -1)/pagesize) * pagesize;
1188    char *addr = (char *) VirtualAlloc(committed,size,MEM_COMMIT,PAGE_READWRITE);
1189    if (addr)
1190     {
1191      committed += size;
1192     }
1193    else
1194     return (void *) -1;
1195   }
1196  return result;
1197 }
1198
1199 #endif
1200 #endif
1201
1202 DllExport void*
1203 win32_malloc(size_t size)
1204 {
1205     return malloc(size);
1206 }
1207
1208 DllExport void*
1209 win32_calloc(size_t numitems, size_t size)
1210 {
1211     return calloc(numitems,size);
1212 }
1213
1214 DllExport void*
1215 win32_realloc(void *block, size_t size)
1216 {
1217     return realloc(block,size);
1218 }
1219
1220 DllExport void
1221 win32_free(void *block)
1222 {
1223     free(block);
1224 }
1225
1226 DllExport int
1227 win32_execv(const char *cmdname, const char *const *argv)
1228 {
1229   Perl_croak(aTHX_ PL_no_func, "execv");
1230   return -1;
1231 }
1232
1233 DllExport int
1234 win32_execvp(const char *cmdname, const char *const *argv)
1235 {
1236   Perl_croak(aTHX_ PL_no_func, "execvp");
1237   return -1;
1238 }
1239
1240 DllExport void*
1241 win32_dynaload(const char* filename)
1242 {
1243     dTHX;
1244     HMODULE hModule;
1245
1246     hModule = XCELoadLibraryA(filename);
1247
1248     return hModule;
1249 }
1250
1251 /* this is needed by Cwd.pm... */
1252
1253 static
1254 XS(w32_GetCwd)
1255 {
1256   dXSARGS;
1257   char buf[MAX_PATH];
1258   SV *sv = sv_newmortal();
1259
1260   xcegetcwd(buf, sizeof(buf));
1261
1262   sv_setpv(sv, xcestrdup(buf));
1263   EXTEND(SP,1);
1264   SvPOK_on(sv);
1265   ST(0) = sv;
1266 #ifndef INCOMPLETE_TAINTS
1267   SvTAINTED_on(ST(0));
1268 #endif
1269   XSRETURN(1);
1270 }
1271
1272 static
1273 XS(w32_SetCwd)
1274 {
1275   dXSARGS;
1276
1277   if (items != 1)
1278     Perl_croak(aTHX_ "usage: Win32::SetCwd($cwd)");
1279
1280   if (!xcechdir(SvPV_nolen(ST(0))))
1281     XSRETURN_YES;
1282
1283   XSRETURN_NO;
1284 }
1285
1286 static
1287 XS(w32_GetTickCount)
1288 {
1289     dXSARGS;
1290     DWORD msec = GetTickCount();
1291     EXTEND(SP,1);
1292     if ((IV)msec > 0)
1293         XSRETURN_IV(msec);
1294     XSRETURN_NV(msec);
1295 }
1296
1297 static
1298 XS(w32_GetOSVersion)
1299 {
1300     dXSARGS;
1301     OSVERSIONINFOA osver;
1302
1303     osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1304     if (!XCEGetVersionExA(&osver)) {
1305       XSRETURN_EMPTY;
1306     }
1307     XPUSHs(newSVpvn(osver.szCSDVersion, strlen(osver.szCSDVersion)));
1308     XPUSHs(newSViv(osver.dwMajorVersion));
1309     XPUSHs(newSViv(osver.dwMinorVersion));
1310     XPUSHs(newSViv(osver.dwBuildNumber));
1311     /* WINCE = 3 */
1312     XPUSHs(newSViv(osver.dwPlatformId));
1313     PUTBACK;
1314 }
1315
1316 static
1317 XS(w32_IsWinNT)
1318 {
1319     dXSARGS;
1320     EXTEND(SP,1);
1321     XSRETURN_IV(IsWinNT());
1322 }
1323
1324 static
1325 XS(w32_IsWin95)
1326 {
1327     dXSARGS;
1328     EXTEND(SP,1);
1329     XSRETURN_IV(IsWin95());
1330 }
1331
1332 static
1333 XS(w32_IsWinCE)
1334 {
1335     dXSARGS;
1336     EXTEND(SP,1);
1337     XSRETURN_IV(IsWinCE());
1338 }
1339
1340 static
1341 XS(w32_GetOemInfo)
1342 {
1343   dXSARGS;
1344   wchar_t wbuf[126];
1345   char buf[126];
1346
1347   if(SystemParametersInfoW(SPI_GETOEMINFO, sizeof(wbuf), wbuf, FALSE))
1348     WideCharToMultiByte(CP_ACP, 0, wbuf, -1, buf, sizeof(buf), 0, 0);
1349   else
1350     sprintf(buf, "SystemParametersInfo failed: %d", GetLastError());
1351
1352   EXTEND(SP,1);
1353   XSRETURN_PV(buf);
1354 }
1355
1356 static
1357 XS(w32_Sleep)
1358 {
1359     dXSARGS;
1360     if (items != 1)
1361         Perl_croak(aTHX_ "usage: Win32::Sleep($milliseconds)");
1362     Sleep(SvIV(ST(0)));
1363     XSRETURN_YES;
1364 }
1365
1366 static
1367 XS(w32_CopyFile)
1368 {
1369     dXSARGS;
1370     BOOL bResult;
1371     if (items != 3)
1372         Perl_croak(aTHX_ "usage: Win32::CopyFile($from, $to, $overwrite)");
1373
1374     {
1375       char szSourceFile[MAX_PATH+1];
1376       strcpy(szSourceFile, PerlDir_mapA(SvPV_nolen(ST(0))));
1377       bResult = XCECopyFileA(szSourceFile, SvPV_nolen(ST(1)), 
1378                              !SvTRUE(ST(2)));
1379     }
1380
1381     if (bResult)
1382         XSRETURN_YES;
1383
1384     XSRETURN_NO;
1385 }
1386
1387 static
1388 XS(w32_MessageBox)
1389 {
1390     dXSARGS;
1391
1392     char *txt;
1393     unsigned int res;
1394     unsigned int flags = MB_OK;
1395
1396     txt = SvPV_nolen(ST(0));
1397     
1398     if (items < 1 || items > 2)
1399         Perl_croak(aTHX_ "usage: Win32::MessageBox($txt, [$flags])");
1400
1401     if(items == 2)
1402       flags = SvIV(ST(1));
1403
1404     res = XCEMessageBoxA(NULL, txt, "Perl", flags);
1405
1406     XSRETURN_IV(res);
1407 }
1408
1409 static
1410 XS(w32_GetPowerStatus)
1411 {
1412   dXSARGS;
1413
1414   SYSTEM_POWER_STATUS_EX sps;
1415
1416   if(GetSystemPowerStatusEx(&sps, TRUE) == FALSE)
1417     {
1418       XSRETURN_EMPTY;
1419     }
1420
1421   XPUSHs(newSViv(sps.ACLineStatus));
1422   XPUSHs(newSViv(sps.BatteryFlag));
1423   XPUSHs(newSViv(sps.BatteryLifePercent));
1424   XPUSHs(newSViv(sps.BatteryLifeTime));
1425   XPUSHs(newSViv(sps.BatteryFullLifeTime));
1426   XPUSHs(newSViv(sps.BackupBatteryFlag));
1427   XPUSHs(newSViv(sps.BackupBatteryLifePercent));
1428   XPUSHs(newSViv(sps.BackupBatteryLifeTime));
1429   XPUSHs(newSViv(sps.BackupBatteryFullLifeTime));
1430
1431   PUTBACK;
1432 }
1433
1434 #if UNDER_CE > 200
1435 static
1436 XS(w32_ShellEx)
1437 {
1438   dXSARGS;
1439
1440   char buf[126];
1441   SHELLEXECUTEINFO si;
1442   char *file, *verb;
1443   wchar_t wfile[MAX_PATH];
1444   wchar_t wverb[20];
1445
1446   if (items != 2)
1447     Perl_croak(aTHX_ "usage: Win32::ShellEx($file, $verb)");
1448
1449   file = SvPV_nolen(ST(0));
1450   verb = SvPV_nolen(ST(1));
1451
1452   memset(&si, 0, sizeof(si));
1453   si.cbSize = sizeof(si);
1454   si.fMask = SEE_MASK_FLAG_NO_UI;
1455
1456   MultiByteToWideChar(CP_ACP, 0, verb, -1, 
1457                       wverb, sizeof(wverb)/2);
1458   si.lpVerb = (TCHAR *)wverb;
1459
1460   MultiByteToWideChar(CP_ACP, 0, file, -1, 
1461                       wfile, sizeof(wfile)/2);
1462   si.lpFile = (TCHAR *)wfile;
1463
1464   if(ShellExecuteEx(&si) == FALSE)
1465     {
1466       XSRETURN_NO;
1467     }
1468   XSRETURN_YES;
1469 }
1470 #endif
1471
1472 void
1473 Perl_init_os_extras(void)
1474 {
1475     dTHX;
1476     char *file = __FILE__;
1477     dXSUB_SYS;
1478
1479     w32_perlshell_tokens = Nullch;
1480     w32_perlshell_items = -1;
1481     w32_fdpid = newAV(); /* XX needs to be in Perl_win32_init()? */
1482     New(1313, w32_children, 1, child_tab);
1483     w32_num_children = 0;
1484
1485     newXS("Win32::GetCwd", w32_GetCwd, file);
1486     newXS("Win32::SetCwd", w32_SetCwd, file);
1487     newXS("Win32::GetTickCount", w32_GetTickCount, file);
1488     newXS("Win32::GetOSVersion", w32_GetOSVersion, file);
1489 #if UNDER_CE > 200
1490     newXS("Win32::ShellEx", w32_ShellEx, file);
1491 #endif
1492     newXS("Win32::IsWinNT", w32_IsWinNT, file);
1493     newXS("Win32::IsWin95", w32_IsWin95, file);
1494     newXS("Win32::IsWinCE", w32_IsWinCE, file);
1495     newXS("Win32::CopyFile", w32_CopyFile, file);
1496     newXS("Win32::Sleep", w32_Sleep, file);
1497     newXS("Win32::MessageBox", w32_MessageBox, file);
1498     newXS("Win32::GetPowerStatus", w32_GetPowerStatus, file);
1499     newXS("Win32::GetOemInfo", w32_GetOemInfo, file);
1500 }
1501
1502 void
1503 myexit(void)
1504 {
1505   char buf[126];
1506
1507   puts("Hit return");
1508   fgets(buf, sizeof(buf), stdin);
1509 }
1510
1511 void
1512 Perl_win32_init(int *argcp, char ***argvp)
1513 {
1514 #ifdef UNDER_CE
1515   char *p;
1516
1517   if((p = xcegetenv("PERLDEBUG")) && (p[0] == 'y' || p[0] == 'Y'))
1518     atexit(myexit);
1519 #endif
1520
1521   MALLOC_INIT;
1522 }
1523
1524 DllExport int
1525 win32_flock(int fd, int oper)
1526 {
1527   Perl_croak(aTHX_ PL_no_func, "flock");
1528   return -1;
1529 }
1530
1531 DllExport int
1532 win32_waitpid(int pid, int *status, int flags)
1533 {
1534   Perl_croak(aTHX_ PL_no_func, "waitpid");
1535   return -1;
1536 }
1537
1538 DllExport int
1539 win32_wait(int *status)
1540 {
1541   Perl_croak(aTHX_ PL_no_func, "wait");
1542   return -1;
1543 }
1544
1545 int
1546 do_spawn(char *cmd)
1547 {
1548   return xcesystem(cmd);
1549 }
1550
1551 int
1552 do_aspawn(void *vreally, void **vmark, void **vsp)
1553 {
1554   Perl_croak(aTHX_ PL_no_func, "aspawn");
1555   return -1;
1556 }
1557
1558 int
1559 wce_reopen_stdout(char *fname)
1560 {     
1561   if(xcefreopen(fname, "w", stdout) == NULL)
1562     return -1;
1563
1564   return 0;
1565 }
1566
1567 void
1568 wce_hitreturn()
1569 {
1570   char buf[126];
1571
1572   printf("Hit RETURN");
1573   fflush(stdout);
1574   fgets(buf, sizeof(buf), stdin);
1575   return;
1576 }
1577
1578 /* //////////////////////////////////////////////////////////////////// */
1579
1580 void
1581 win32_argv2utf8(int argc, char** argv)
1582 {
1583   /* do nothing... */
1584 }
1585
1586 void
1587 Perl_sys_intern_init(pTHX)
1588 {
1589     w32_perlshell_tokens        = Nullch;
1590     w32_perlshell_vec           = (char**)NULL;
1591     w32_perlshell_items         = 0;
1592     w32_fdpid                   = newAV();
1593     New(1313, w32_children, 1, child_tab);
1594     w32_num_children            = 0;
1595 #  ifdef USE_ITHREADS
1596     w32_pseudo_id               = 0;
1597     New(1313, w32_pseudo_children, 1, child_tab);
1598     w32_num_pseudo_children     = 0;
1599 #  endif
1600
1601 #ifndef UNDER_CE
1602     w32_init_socktype           = 0;
1603 #endif
1604 }
1605
1606 void
1607 Perl_sys_intern_clear(pTHX)
1608 {
1609     Safefree(w32_perlshell_tokens);
1610     Safefree(w32_perlshell_vec);
1611     /* NOTE: w32_fdpid is freed by sv_clean_all() */
1612     Safefree(w32_children);
1613 #  ifdef USE_ITHREADS
1614     Safefree(w32_pseudo_children);
1615 #  endif
1616 }
1617
1618 /* //////////////////////////////////////////////////////////////////// */
1619
1620 #undef getcwd
1621
1622 char *
1623 getcwd(char *buf, size_t size)
1624 {
1625   return xcegetcwd(buf, size);
1626 }
1627
1628 int 
1629 isnan(double d)
1630 {
1631   return _isnan(d);
1632 }
1633
1634 int
1635 win32_open_osfhandle(intptr_t osfhandle, int flags)
1636 {
1637     int fh;
1638     char fileflags=0;           /* _osfile flags */
1639
1640     XCEMessageBoxA(NULL, "NEED TO IMPLEMENT in wince/wince.c(win32_open_osfhandle)", "error", 0);
1641     Perl_croak_nocontext("win32_open_osfhandle() TBD on this platform");
1642     return 0;
1643 }
1644
1645 int
1646 win32_get_osfhandle(intptr_t osfhandle, int flags)
1647 {
1648     int fh;
1649     char fileflags=0;           /* _osfile flags */
1650
1651     XCEMessageBoxA(NULL, "NEED TO IMPLEMENT in wince/wince.c(win32_get_osfhandle)", "error", 0);
1652     Perl_croak_nocontext("win32_get_osfhandle() TBD on this platform");
1653     return 0;
1654 }
1655
1656 /*
1657  * a popen() clone that respects PERL5SHELL
1658  *
1659  * changed to return PerlIO* rather than FILE * by BKS, 11-11-2000
1660  */
1661
1662 DllExport PerlIO*
1663 win32_popen(const char *command, const char *mode)
1664 {
1665     XCEMessageBoxA(NULL, "NEED TO IMPLEMENT in wince/wince.c(win32_popen)", "error", 0);
1666     Perl_croak_nocontext("win32_popen() TBD on this platform");
1667 }
1668
1669 /*
1670  * pclose() clone
1671  */
1672
1673 DllExport int
1674 win32_pclose(PerlIO *pf)
1675 {
1676 #ifdef USE_RTL_POPEN
1677     return _pclose(pf);
1678 #else
1679     dTHX;
1680     int childpid, status;
1681     SV *sv;
1682
1683     LOCK_FDPID_MUTEX;
1684     sv = *av_fetch(w32_fdpid, PerlIO_fileno(pf), TRUE);
1685
1686     if (SvIOK(sv))
1687         childpid = SvIVX(sv);
1688     else
1689         childpid = 0;
1690
1691     if (!childpid) {
1692         errno = EBADF;
1693         return -1;
1694     }
1695
1696 #ifdef USE_PERLIO
1697     PerlIO_close(pf);
1698 #else
1699     fclose(pf);
1700 #endif
1701     SvIVX(sv) = 0;
1702     UNLOCK_FDPID_MUTEX;
1703
1704     if (win32_waitpid(childpid, &status, 0) == -1)
1705         return -1;
1706
1707     return status;
1708
1709 #endif /* USE_RTL_POPEN */
1710 }
1711
1712 FILE *
1713 win32_fdupopen(FILE *pf)
1714 {
1715     FILE* pfdup;
1716     fpos_t pos;
1717     char mode[3];
1718     int fileno = win32_dup(win32_fileno(pf));
1719
1720     XCEMessageBoxA(NULL, "NEED TO IMPLEMENT a place in .../wince/wince.c(win32_fdupopen)", "Perl(developer)", 0);
1721     Perl_croak_nocontext("win32_fdupopen() TBD on this platform");
1722
1723 #if 0
1724     /* open the file in the same mode */
1725     if((pf)->_flag & _IOREAD) {
1726         mode[0] = 'r';
1727         mode[1] = 0;
1728     }
1729     else if((pf)->_flag & _IOWRT) {
1730         mode[0] = 'a';
1731         mode[1] = 0;
1732     }
1733     else if((pf)->_flag & _IORW) {
1734         mode[0] = 'r';
1735         mode[1] = '+';
1736         mode[2] = 0;
1737     }
1738
1739     /* it appears that the binmode is attached to the
1740      * file descriptor so binmode files will be handled
1741      * correctly
1742      */
1743     pfdup = win32_fdopen(fileno, mode);
1744
1745     /* move the file pointer to the same position */
1746     if (!fgetpos(pf, &pos)) {
1747         fsetpos(pfdup, &pos);
1748     }
1749 #endif
1750     return pfdup;
1751 }