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