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