This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Try #2 of getting rid of bincompat5005.
[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_uname(struct utsname *name)
501 {
502     struct hostent *hep;
503     STRLEN nodemax = sizeof(name->nodename)-1;
504     OSVERSIONINFOA osver;
505
506     memset(&osver, 0, sizeof(OSVERSIONINFOA));
507     osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
508     if (XCEGetVersionExA(&osver)) {
509         /* sysname */
510         switch (osver.dwPlatformId) {
511         case VER_PLATFORM_WIN32_CE:
512             strcpy(name->sysname, "Windows CE");
513             break;
514         case VER_PLATFORM_WIN32_WINDOWS:
515             strcpy(name->sysname, "Windows");
516             break;
517         case VER_PLATFORM_WIN32_NT:
518             strcpy(name->sysname, "Windows NT");
519             break;
520         case VER_PLATFORM_WIN32s:
521             strcpy(name->sysname, "Win32s");
522             break;
523         default:
524             strcpy(name->sysname, "Win32 Unknown");
525             break;
526         }
527
528         /* release */
529         sprintf(name->release, "%d.%d",
530                 osver.dwMajorVersion, osver.dwMinorVersion);
531
532         /* version */
533         sprintf(name->version, "Build %d",
534                 osver.dwPlatformId == VER_PLATFORM_WIN32_NT
535                 ? osver.dwBuildNumber : (osver.dwBuildNumber & 0xffff));
536         if (osver.szCSDVersion[0]) {
537             char *buf = name->version + strlen(name->version);
538             sprintf(buf, " (%s)", osver.szCSDVersion);
539         }
540     }
541     else {
542         *name->sysname = '\0';
543         *name->version = '\0';
544         *name->release = '\0';
545     }
546
547     /* nodename */
548     hep = win32_gethostbyname("localhost");
549     if (hep) {
550         STRLEN len = strlen(hep->h_name);
551         if (len <= nodemax) {
552             strcpy(name->nodename, hep->h_name);
553         }
554         else {
555             strncpy(name->nodename, hep->h_name, nodemax);
556             name->nodename[nodemax] = '\0';
557         }
558     }
559     else {
560         DWORD sz = nodemax;
561         if (!XCEGetComputerNameA(name->nodename, &sz))
562             *name->nodename = '\0';
563     }
564
565     /* machine (architecture) */
566     {
567         SYSTEM_INFO info;
568         char *arch;
569         GetSystemInfo(&info);
570
571         switch (info.wProcessorArchitecture) {
572         case PROCESSOR_ARCHITECTURE_INTEL:
573             arch = "x86"; break;
574         case PROCESSOR_ARCHITECTURE_MIPS:
575             arch = "mips"; break;
576         case PROCESSOR_ARCHITECTURE_ALPHA:
577             arch = "alpha"; break;
578         case PROCESSOR_ARCHITECTURE_PPC:
579             arch = "ppc"; break;
580         case PROCESSOR_ARCHITECTURE_ARM:
581             arch = "arm"; break;
582         case PROCESSOR_HITACHI_SH3:
583             arch = "sh3"; break;
584         case PROCESSOR_SHx_SH3:
585             arch = "sh3"; break;
586
587         default:
588             arch = "unknown"; break;
589         }
590         strcpy(name->machine, arch);
591     }
592     return 0;
593 }
594
595 static UINT timerid = 0;
596
597 static VOID CALLBACK TimerProc(HWND win, UINT msg, UINT id, DWORD time)
598 {
599     dTHX;
600     KillTimer(NULL,timerid);
601     timerid=0;  
602     sighandler(14);
603 }
604
605 DllExport unsigned int
606 win32_alarm(unsigned int sec)
607 {
608     /* 
609      * the 'obvious' implentation is SetTimer() with a callback
610      * which does whatever receiving SIGALRM would do 
611      * we cannot use SIGALRM even via raise() as it is not 
612      * one of the supported codes in <signal.h>
613      *
614      * Snag is unless something is looking at the message queue
615      * nothing happens :-(
616      */ 
617     dTHX;
618     if (sec)
619      {
620       timerid = SetTimer(NULL,timerid,sec*1000,(TIMERPROC)TimerProc);
621       if (!timerid)
622        Perl_croak_nocontext("Cannot set timer");
623      } 
624     else
625      {
626       if (timerid)
627        {
628         KillTimer(NULL,timerid);
629         timerid=0;  
630        }
631      }
632     return 0;
633 }
634
635 #ifdef HAVE_DES_FCRYPT
636 extern char *   des_fcrypt(const char *txt, const char *salt, char *cbuf);
637 #endif
638
639 DllExport char *
640 win32_crypt(const char *txt, const char *salt)
641 {
642     dTHX;
643 #ifdef HAVE_DES_FCRYPT
644     dTHR;
645     return des_fcrypt(txt, salt, w32_crypt_buffer);
646 #else
647     Perl_croak(aTHX_ "The crypt() function is unimplemented due to excessive paranoia.");
648     return Nullch;
649 #endif
650 }
651
652 /* C doesn't like repeat struct definitions */
653
654 #if defined(USE_FIXED_OSFHANDLE) || defined(PERL_MSVCRT_READFIX)
655
656 #ifndef _CRTIMP
657 #define _CRTIMP __declspec(dllimport)
658 #endif
659
660 /*
661  * Control structure for lowio file handles
662  */
663 typedef struct {
664     long osfhnd;    /* underlying OS file HANDLE */
665     char osfile;    /* attributes of file (e.g., open in text mode?) */
666     char pipech;    /* one char buffer for handles opened on pipes */
667     int lockinitflag;
668     CRITICAL_SECTION lock;
669 } ioinfo;
670
671
672 /*
673  * Array of arrays of control structures for lowio files.
674  */
675 EXTERN_C _CRTIMP ioinfo* __pioinfo[];
676
677 /*
678  * Definition of IOINFO_L2E, the log base 2 of the number of elements in each
679  * array of ioinfo structs.
680  */
681 #define IOINFO_L2E          5
682
683 /*
684  * Definition of IOINFO_ARRAY_ELTS, the number of elements in ioinfo array
685  */
686 #define IOINFO_ARRAY_ELTS   (1 << IOINFO_L2E)
687
688 /*
689  * Access macros for getting at an ioinfo struct and its fields from a
690  * file handle
691  */
692 #define _pioinfo(i) (__pioinfo[(i) >> IOINFO_L2E] + ((i) & (IOINFO_ARRAY_ELTS - 1)))
693 #define _osfhnd(i)  (_pioinfo(i)->osfhnd)
694 #define _osfile(i)  (_pioinfo(i)->osfile)
695 #define _pipech(i)  (_pioinfo(i)->pipech)
696
697 #endif
698
699 /*
700  *  redirected io subsystem for all XS modules
701  *
702  */
703
704 DllExport int *
705 win32_errno(void)
706 {
707     return (&errno);
708 }
709
710 /* the rest are the remapped stdio routines */
711 DllExport FILE *
712 win32_stderr(void)
713 {
714     return (stderr);
715 }
716
717 DllExport FILE *
718 win32_stdin(void)
719 {
720     return (stdin);
721 }
722
723 DllExport FILE *
724 win32_stdout()
725 {
726     return (stdout);
727 }
728
729 DllExport int
730 win32_ferror(FILE *fp)
731 {
732     return (ferror(fp));
733 }
734
735
736 DllExport int
737 win32_feof(FILE *fp)
738 {
739     return (feof(fp));
740 }
741
742 /*
743  * Since the errors returned by the socket error function 
744  * WSAGetLastError() are not known by the library routine strerror
745  * we have to roll our own.
746  */
747
748 DllExport char *
749 win32_strerror(int e) 
750 {
751   return xcestrerror(e);
752 }
753
754 DllExport void
755 win32_str_os_error(void *sv, DWORD dwErr)
756 {
757   dTHX;
758
759   sv_setpvn((SV*)sv, "Error", 5);
760 }
761
762
763 DllExport int
764 win32_fprintf(FILE *fp, const char *format, ...)
765 {
766     va_list marker;
767     va_start(marker, format);     /* Initialize variable arguments. */
768
769     return (vfprintf(fp, format, marker));
770 }
771
772 DllExport int
773 win32_printf(const char *format, ...)
774 {
775     va_list marker;
776     va_start(marker, format);     /* Initialize variable arguments. */
777
778     return (vprintf(format, marker));
779 }
780
781 DllExport int
782 win32_vfprintf(FILE *fp, const char *format, va_list args)
783 {
784     return (vfprintf(fp, format, args));
785 }
786
787 DllExport int
788 win32_vprintf(const char *format, va_list args)
789 {
790     return (vprintf(format, args));
791 }
792
793 DllExport size_t
794 win32_fread(void *buf, size_t size, size_t count, FILE *fp)
795 {
796   return fread(buf, size, count, fp);
797 }
798
799 DllExport size_t
800 win32_fwrite(const void *buf, size_t size, size_t count, FILE *fp)
801 {
802   return fwrite(buf, size, count, fp);
803 }
804
805 DllExport FILE *
806 win32_fopen(const char *filename, const char *mode)
807 {
808   return xcefopen(filename, mode);
809 }
810
811 DllExport FILE *
812 win32_fdopen(int handle, const char *mode)
813 {
814   return palm_fdopen(handle, mode);
815 }
816
817 DllExport FILE *
818 win32_freopen(const char *path, const char *mode, FILE *stream)
819 {
820   return xcefreopen(path, mode, stream);
821 }
822
823 DllExport int
824 win32_fclose(FILE *pf)
825 {
826   return xcefclose(pf);
827 }
828
829 DllExport int
830 win32_fputs(const char *s,FILE *pf)
831 {
832   return fputs(s, pf);
833 }
834
835 DllExport int
836 win32_fputc(int c,FILE *pf)
837 {
838   return fputc(c,pf);
839 }
840
841 DllExport int
842 win32_ungetc(int c,FILE *pf)
843 {
844   return ungetc(c,pf);
845 }
846
847 DllExport int
848 win32_getc(FILE *pf)
849 {
850   return getc(pf);
851 }
852
853 DllExport int
854 win32_fileno(FILE *pf)
855 {
856   return palm_fileno(pf);
857 }
858
859 DllExport void
860 win32_clearerr(FILE *pf)
861 {
862   clearerr(pf);
863   return;
864 }
865
866 DllExport int
867 win32_fflush(FILE *pf)
868 {
869   return fflush(pf);
870 }
871
872 DllExport long
873 win32_ftell(FILE *pf)
874 {
875   return ftell(pf);
876 }
877
878 DllExport int
879 win32_fseek(FILE *pf,long offset,int origin)
880 {
881   return fseek(pf, offset, origin);
882 }
883
884 /* fpos_t seems to be int64 on hpc pro! Really stupid. */
885 /* But maybe someday there will be such large disks in a hpc... */
886 DllExport int
887 win32_fgetpos(FILE *pf, fpos_t *p)
888 {
889   return fgetpos(pf, p);
890 }
891
892 DllExport int
893 win32_fsetpos(FILE *pf, const fpos_t *p)
894 {
895   return fsetpos(pf, p);
896 }
897
898 DllExport void
899 win32_rewind(FILE *pf)
900 {
901   fseek(pf, 0, SEEK_SET);
902   return;
903 }
904
905 DllExport FILE*
906 win32_tmpfile(void)
907 {
908   Perl_croak(aTHX_ PL_no_func, "tmpfile");
909
910   return NULL;
911 }
912
913 DllExport void
914 win32_abort(void)
915 {
916   xceabort();
917
918   return;
919 }
920
921 DllExport int
922 win32_fstat(int fd, struct stat *sbufptr)
923 {
924   return xcefstat(fd, sbufptr);
925 }
926
927 DllExport int
928 win32_link(const char *oldname, const char *newname)
929 {
930   Perl_croak(aTHX_ PL_no_func, "link");
931
932   return -1;
933 }
934
935 DllExport int
936 win32_rename(const char *oname, const char *newname)
937 {
938   return xcerename(oname, newname);
939 }
940
941 DllExport int
942 win32_setmode(int fd, int mode)
943 {
944   if(mode != O_BINARY)
945     {
946       Perl_croak(aTHX_ PL_no_func, "setmode");
947       return -1;
948     }
949   return 0;
950 }
951
952 DllExport long
953 win32_lseek(int fd, long offset, int origin)
954 {
955   return xcelseek(fd, offset, origin);
956 }
957
958 DllExport long
959 win32_tell(int fd)
960 {
961   return xcelseek(fd, 0, SEEK_CUR);
962 }
963
964 DllExport int
965 win32_open(const char *path, int flag, ...)
966 {
967   int pmode;
968   va_list ap;
969
970   va_start(ap, flag);
971   pmode = va_arg(ap, int);
972   va_end(ap);
973
974   return xceopen(path, flag, pmode);
975 }
976
977 DllExport int
978 win32_close(int fd)
979 {
980   return xceclose(fd);
981 }
982
983 DllExport int
984 win32_eof(int fd)
985 {
986   Perl_croak(aTHX_ PL_no_func, "eof");
987   return -1;
988 }
989
990 DllExport int
991 win32_dup(int fd)
992 {
993   Perl_croak(aTHX_ PL_no_func, "dup");
994   return -1;
995 }
996
997 DllExport int
998 win32_dup2(int fd1,int fd2)
999 {
1000   Perl_croak(aTHX_ PL_no_func, "dup2");
1001   return -1;
1002 }
1003
1004 DllExport int
1005 win32_read(int fd, void *buf, unsigned int cnt)
1006 {
1007   return xceread(fd, buf, cnt);
1008 }
1009
1010 DllExport int
1011 win32_write(int fd, const void *buf, unsigned int cnt)
1012 {
1013   return xcewrite(fd, (void *) buf, cnt);
1014 }
1015
1016 DllExport int
1017 win32_mkdir(const char *dir, int mode)
1018 {
1019   return xcemkdir(dir);
1020 }
1021
1022 DllExport int
1023 win32_rmdir(const char *dir)
1024 {
1025   return xcermdir(dir);
1026 }
1027
1028 DllExport int
1029 win32_chdir(const char *dir)
1030 {
1031   return xcechdir(dir);
1032 }
1033
1034 DllExport  int
1035 win32_access(const char *path, int mode)
1036 {
1037   return xceaccess(path, mode);
1038 }
1039
1040 DllExport  int
1041 win32_chmod(const char *path, int mode)
1042 {
1043   return xcechmod(path, mode);
1044 }
1045
1046 DllExport void
1047 win32_perror(const char *str)
1048 {
1049   xceperror(str);
1050 }
1051
1052 DllExport void
1053 win32_setbuf(FILE *pf, char *buf)
1054 {
1055   Perl_croak(aTHX_ PL_no_func, "setbuf");
1056 }
1057
1058 DllExport int
1059 win32_setvbuf(FILE *pf, char *buf, int type, size_t size)
1060 {
1061   return setvbuf(pf, buf, type, size);
1062 }
1063
1064 DllExport int
1065 win32_flushall(void)
1066 {
1067   return flushall();
1068 }
1069
1070 DllExport int
1071 win32_fcloseall(void)
1072 {
1073   return fcloseall();
1074 }
1075
1076 DllExport char*
1077 win32_fgets(char *s, int n, FILE *pf)
1078 {
1079   return fgets(s, n, pf);
1080 }
1081
1082 DllExport char*
1083 win32_gets(char *s)
1084 {
1085   return gets(s);
1086 }
1087
1088 DllExport int
1089 win32_fgetc(FILE *pf)
1090 {
1091   return fgetc(pf);
1092 }
1093
1094 DllExport int
1095 win32_putc(int c, FILE *pf)
1096 {
1097   return putc(c,pf);
1098 }
1099
1100 DllExport int
1101 win32_puts(const char *s)
1102 {
1103   return puts(s);
1104 }
1105
1106 DllExport int
1107 win32_getchar(void)
1108 {
1109   return getchar();
1110 }
1111
1112 DllExport int
1113 win32_putchar(int c)
1114 {
1115   return putchar(c);
1116 }
1117
1118 #ifdef MYMALLOC
1119
1120 #ifndef USE_PERL_SBRK
1121
1122 static char *committed = NULL;
1123 static char *base      = NULL;
1124 static char *reserved  = NULL;
1125 static char *brk       = NULL;
1126 static DWORD pagesize  = 0;
1127 static DWORD allocsize = 0;
1128
1129 void *
1130 sbrk(int need)
1131 {
1132  void *result;
1133  if (!pagesize)
1134   {SYSTEM_INFO info;
1135    GetSystemInfo(&info);
1136    /* Pretend page size is larger so we don't perpetually
1137     * call the OS to commit just one page ...
1138     */
1139    pagesize = info.dwPageSize << 3;
1140    allocsize = info.dwAllocationGranularity;
1141   }
1142  /* This scheme fails eventually if request for contiguous
1143   * block is denied so reserve big blocks - this is only 
1144   * address space not memory ...
1145   */
1146  if (brk+need >= reserved)
1147   {
1148    DWORD size = 64*1024*1024;
1149    char *addr;
1150    if (committed && reserved && committed < reserved)
1151     {
1152      /* Commit last of previous chunk cannot span allocations */
1153      addr = (char *) VirtualAlloc(committed,reserved-committed,MEM_COMMIT,PAGE_READWRITE);
1154      if (addr)
1155       committed = reserved;
1156     }
1157    /* Reserve some (more) space 
1158     * Note this is a little sneaky, 1st call passes NULL as reserved
1159     * so lets system choose where we start, subsequent calls pass
1160     * the old end address so ask for a contiguous block
1161     */
1162    addr  = (char *) VirtualAlloc(reserved,size,MEM_RESERVE,PAGE_NOACCESS);
1163    if (addr)
1164     {
1165      reserved = addr+size;
1166      if (!base)
1167       base = addr;
1168      if (!committed)
1169       committed = base;
1170      if (!brk)
1171       brk = committed;
1172     }
1173    else
1174     {
1175      return (void *) -1;
1176     }
1177   }
1178  result = brk;
1179  brk += need;
1180  if (brk > committed)
1181   {
1182    DWORD size = ((brk-committed + pagesize -1)/pagesize) * pagesize;
1183    char *addr = (char *) VirtualAlloc(committed,size,MEM_COMMIT,PAGE_READWRITE);
1184    if (addr)
1185     {
1186      committed += size;
1187     }
1188    else
1189     return (void *) -1;
1190   }
1191  return result;
1192 }
1193
1194 #endif
1195 #endif
1196
1197 DllExport void*
1198 win32_malloc(size_t size)
1199 {
1200     return malloc(size);
1201 }
1202
1203 DllExport void*
1204 win32_calloc(size_t numitems, size_t size)
1205 {
1206     return calloc(numitems,size);
1207 }
1208
1209 DllExport void*
1210 win32_realloc(void *block, size_t size)
1211 {
1212     return realloc(block,size);
1213 }
1214
1215 DllExport void
1216 win32_free(void *block)
1217 {
1218     free(block);
1219 }
1220
1221 DllExport int
1222 win32_execv(const char *cmdname, const char *const *argv)
1223 {
1224   Perl_croak(aTHX_ PL_no_func, "execv");
1225   return -1;
1226 }
1227
1228 DllExport int
1229 win32_execvp(const char *cmdname, const char *const *argv)
1230 {
1231   Perl_croak(aTHX_ PL_no_func, "execvp");
1232   return -1;
1233 }
1234
1235 DllExport void*
1236 win32_dynaload(const char* filename)
1237 {
1238     dTHX;
1239     HMODULE hModule;
1240
1241     hModule = XCELoadLibraryA(filename);
1242
1243     return hModule;
1244 }
1245
1246 /* this is needed by Cwd.pm... */
1247
1248 static
1249 XS(w32_GetCwd)
1250 {
1251   dXSARGS;
1252   char buf[MAX_PATH];
1253   SV *sv = sv_newmortal();
1254
1255   xcegetcwd(buf, sizeof(buf));
1256
1257   sv_setpv(sv, xcestrdup(buf));
1258   EXTEND(SP,1);
1259   SvPOK_on(sv);
1260   ST(0) = sv;
1261 #ifndef INCOMPLETE_TAINTS
1262   SvTAINTED_on(ST(0));
1263 #endif
1264   XSRETURN(1);
1265 }
1266
1267 static
1268 XS(w32_SetCwd)
1269 {
1270   dXSARGS;
1271
1272   if (items != 1)
1273     Perl_croak(aTHX_ "usage: Win32::SetCwd($cwd)");
1274
1275   if (!xcechdir(SvPV_nolen(ST(0))))
1276     XSRETURN_YES;
1277
1278   XSRETURN_NO;
1279 }
1280
1281 static
1282 XS(w32_GetTickCount)
1283 {
1284     dXSARGS;
1285     DWORD msec = GetTickCount();
1286     EXTEND(SP,1);
1287     if ((IV)msec > 0)
1288         XSRETURN_IV(msec);
1289     XSRETURN_NV(msec);
1290 }
1291
1292 static
1293 XS(w32_GetOSVersion)
1294 {
1295     dXSARGS;
1296     OSVERSIONINFOA osver;
1297
1298     osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1299     if (!XCEGetVersionExA(&osver)) {
1300       XSRETURN_EMPTY;
1301     }
1302     XPUSHs(newSVpvn(osver.szCSDVersion, strlen(osver.szCSDVersion)));
1303     XPUSHs(newSViv(osver.dwMajorVersion));
1304     XPUSHs(newSViv(osver.dwMinorVersion));
1305     XPUSHs(newSViv(osver.dwBuildNumber));
1306     /* WINCE = 3 */
1307     XPUSHs(newSViv(osver.dwPlatformId));
1308     PUTBACK;
1309 }
1310
1311 static
1312 XS(w32_IsWinNT)
1313 {
1314     dXSARGS;
1315     EXTEND(SP,1);
1316     XSRETURN_IV(IsWinNT());
1317 }
1318
1319 static
1320 XS(w32_IsWin95)
1321 {
1322     dXSARGS;
1323     EXTEND(SP,1);
1324     XSRETURN_IV(IsWin95());
1325 }
1326
1327 static
1328 XS(w32_IsWinCE)
1329 {
1330     dXSARGS;
1331     EXTEND(SP,1);
1332     XSRETURN_IV(IsWinCE());
1333 }
1334
1335 static
1336 XS(w32_GetOemInfo)
1337 {
1338   dXSARGS;
1339   wchar_t wbuf[126];
1340   char buf[126];
1341
1342   if(SystemParametersInfoW(SPI_GETOEMINFO, sizeof(wbuf), wbuf, FALSE))
1343     WideCharToMultiByte(CP_ACP, 0, wbuf, -1, buf, sizeof(buf), 0, 0);
1344   else
1345     sprintf(buf, "SystemParametersInfo failed: %d", GetLastError());
1346
1347   EXTEND(SP,1);
1348   XSRETURN_PV(buf);
1349 }
1350
1351 static
1352 XS(w32_Sleep)
1353 {
1354     dXSARGS;
1355     if (items != 1)
1356         Perl_croak(aTHX_ "usage: Win32::Sleep($milliseconds)");
1357     Sleep(SvIV(ST(0)));
1358     XSRETURN_YES;
1359 }
1360
1361 static
1362 XS(w32_CopyFile)
1363 {
1364     dXSARGS;
1365     BOOL bResult;
1366     if (items != 3)
1367         Perl_croak(aTHX_ "usage: Win32::CopyFile($from, $to, $overwrite)");
1368
1369     {
1370       char szSourceFile[MAX_PATH+1];
1371       strcpy(szSourceFile, PerlDir_mapA(SvPV_nolen(ST(0))));
1372       bResult = XCECopyFileA(szSourceFile, SvPV_nolen(ST(1)), 
1373                              !SvTRUE(ST(2)));
1374     }
1375
1376     if (bResult)
1377         XSRETURN_YES;
1378
1379     XSRETURN_NO;
1380 }
1381
1382 static
1383 XS(w32_MessageBox)
1384 {
1385     dXSARGS;
1386
1387     char *txt;
1388     unsigned int res;
1389     unsigned int flags = MB_OK;
1390
1391     txt = SvPV_nolen(ST(0));
1392     
1393     if (items < 1 || items > 2)
1394         Perl_croak(aTHX_ "usage: Win32::MessageBox($txt, [$flags])");
1395
1396     if(items == 2)
1397       flags = SvIV(ST(1));
1398
1399     res = XCEMessageBoxA(NULL, txt, "Perl", flags);
1400
1401     XSRETURN_IV(res);
1402 }
1403
1404 static
1405 XS(w32_GetPowerStatus)
1406 {
1407   dXSARGS;
1408
1409   SYSTEM_POWER_STATUS_EX sps;
1410
1411   if(GetSystemPowerStatusEx(&sps, TRUE) == FALSE)
1412     {
1413       XSRETURN_EMPTY;
1414     }
1415
1416   XPUSHs(newSViv(sps.ACLineStatus));
1417   XPUSHs(newSViv(sps.BatteryFlag));
1418   XPUSHs(newSViv(sps.BatteryLifePercent));
1419   XPUSHs(newSViv(sps.BatteryLifeTime));
1420   XPUSHs(newSViv(sps.BatteryFullLifeTime));
1421   XPUSHs(newSViv(sps.BackupBatteryFlag));
1422   XPUSHs(newSViv(sps.BackupBatteryLifePercent));
1423   XPUSHs(newSViv(sps.BackupBatteryLifeTime));
1424   XPUSHs(newSViv(sps.BackupBatteryFullLifeTime));
1425
1426   PUTBACK;
1427 }
1428
1429 #if UNDER_CE > 200
1430 static
1431 XS(w32_ShellEx)
1432 {
1433   dXSARGS;
1434
1435   char buf[126];
1436   SHELLEXECUTEINFO si;
1437   char *file, *verb;
1438   wchar_t wfile[MAX_PATH];
1439   wchar_t wverb[20];
1440
1441   if (items != 2)
1442     Perl_croak(aTHX_ "usage: Win32::ShellEx($file, $verb)");
1443
1444   file = SvPV_nolen(ST(0));
1445   verb = SvPV_nolen(ST(1));
1446
1447   memset(&si, 0, sizeof(si));
1448   si.cbSize = sizeof(si);
1449   si.fMask = SEE_MASK_FLAG_NO_UI;
1450
1451   MultiByteToWideChar(CP_ACP, 0, verb, -1, 
1452                       wverb, sizeof(wverb)/2);
1453   si.lpVerb = (TCHAR *)wverb;
1454
1455   MultiByteToWideChar(CP_ACP, 0, file, -1, 
1456                       wfile, sizeof(wfile)/2);
1457   si.lpFile = (TCHAR *)wfile;
1458
1459   if(ShellExecuteEx(&si) == FALSE)
1460     {
1461       XSRETURN_NO;
1462     }
1463   XSRETURN_YES;
1464 }
1465 #endif
1466
1467 void
1468 Perl_init_os_extras(void)
1469 {
1470     dTHX;
1471     char *file = __FILE__;
1472     dXSUB_SYS;
1473
1474     w32_perlshell_tokens = Nullch;
1475     w32_perlshell_items = -1;
1476     w32_fdpid = newAV(); /* XX needs to be in Perl_win32_init()? */
1477     New(1313, w32_children, 1, child_tab);
1478     w32_num_children = 0;
1479
1480     newXS("Win32::GetCwd", w32_GetCwd, file);
1481     newXS("Win32::SetCwd", w32_SetCwd, file);
1482     newXS("Win32::GetTickCount", w32_GetTickCount, file);
1483     newXS("Win32::GetOSVersion", w32_GetOSVersion, file);
1484 #if UNDER_CE > 200
1485     newXS("Win32::ShellEx", w32_ShellEx, file);
1486 #endif
1487     newXS("Win32::IsWinNT", w32_IsWinNT, file);
1488     newXS("Win32::IsWin95", w32_IsWin95, file);
1489     newXS("Win32::IsWinCE", w32_IsWinCE, file);
1490     newXS("Win32::CopyFile", w32_CopyFile, file);
1491     newXS("Win32::Sleep", w32_Sleep, file);
1492     newXS("Win32::MessageBox", w32_MessageBox, file);
1493     newXS("Win32::GetPowerStatus", w32_GetPowerStatus, file);
1494     newXS("Win32::GetOemInfo", w32_GetOemInfo, file);
1495 }
1496
1497 void
1498 myexit(void)
1499 {
1500   char buf[126];
1501
1502   puts("Hit return");
1503   fgets(buf, sizeof(buf), stdin);
1504 }
1505
1506 void
1507 Perl_win32_init(int *argcp, char ***argvp)
1508 {
1509 #ifdef UNDER_CE
1510   char *p;
1511
1512   if((p = xcegetenv("PERLDEBUG")) && (p[0] == 'y' || p[0] == 'Y'))
1513     atexit(myexit);
1514 #endif
1515
1516   MALLOC_INIT;
1517 }
1518
1519 DllExport int
1520 win32_flock(int fd, int oper)
1521 {
1522   Perl_croak(aTHX_ PL_no_func, "flock");
1523   return -1;
1524 }
1525
1526 DllExport int
1527 win32_waitpid(int pid, int *status, int flags)
1528 {
1529   Perl_croak(aTHX_ PL_no_func, "waitpid");
1530   return -1;
1531 }
1532
1533 DllExport int
1534 win32_wait(int *status)
1535 {
1536   Perl_croak(aTHX_ PL_no_func, "wait");
1537   return -1;
1538 }
1539
1540 int
1541 do_spawn(char *cmd)
1542 {
1543   return xcesystem(cmd);
1544 }
1545
1546 int
1547 do_aspawn(void *vreally, void **vmark, void **vsp)
1548 {
1549   Perl_croak(aTHX_ PL_no_func, "aspawn");
1550   return -1;
1551 }
1552
1553 int
1554 wce_reopen_stdout(char *fname)
1555 {     
1556   if(xcefreopen(fname, "w", stdout) == NULL)
1557     return -1;
1558
1559   return 0;
1560 }
1561
1562 void
1563 wce_hitreturn()
1564 {
1565   char buf[126];
1566
1567   printf("Hit RETURN");
1568   fflush(stdout);
1569   fgets(buf, sizeof(buf), stdin);
1570   return;
1571 }
1572
1573 /* //////////////////////////////////////////////////////////////////// */
1574
1575 void
1576 win32_argv2utf8(int argc, char** argv)
1577 {
1578   /* do nothing... */
1579 }
1580
1581 void
1582 Perl_sys_intern_init(pTHX)
1583 {
1584     w32_perlshell_tokens        = Nullch;
1585     w32_perlshell_vec           = (char**)NULL;
1586     w32_perlshell_items         = 0;
1587     w32_fdpid                   = newAV();
1588     New(1313, w32_children, 1, child_tab);
1589     w32_num_children            = 0;
1590 #  ifdef USE_ITHREADS
1591     w32_pseudo_id               = 0;
1592     New(1313, w32_pseudo_children, 1, child_tab);
1593     w32_num_pseudo_children     = 0;
1594 #  endif
1595
1596 #ifndef UNDER_CE
1597     w32_init_socktype           = 0;
1598 #endif
1599 }
1600
1601 void
1602 Perl_sys_intern_clear(pTHX)
1603 {
1604     Safefree(w32_perlshell_tokens);
1605     Safefree(w32_perlshell_vec);
1606     /* NOTE: w32_fdpid is freed by sv_clean_all() */
1607     Safefree(w32_children);
1608 #  ifdef USE_ITHREADS
1609     Safefree(w32_pseudo_children);
1610 #  endif
1611 }
1612
1613 /* //////////////////////////////////////////////////////////////////// */
1614
1615 #undef getcwd
1616
1617 char *
1618 getcwd(char *buf, size_t size)
1619 {
1620   return xcegetcwd(buf, size);
1621 }
1622
1623 int 
1624 isnan(double d)
1625 {
1626   return _isnan(d);
1627 }
1628
1629 int
1630 win32_open_osfhandle(intptr_t osfhandle, int flags)
1631 {
1632     int fh;
1633     char fileflags=0;           /* _osfile flags */
1634
1635     XCEMessageBoxA(NULL, "NEED TO IMPLEMENT a place in ../wince/wince.c(win32_open_osfhandle)", "Perl(developer)", 0);
1636     Perl_croak_nocontext("win32_open_osfhandle() TBD on this platform");
1637     return 0;
1638 }