This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Two more delays added to test suite to help *-solaris-thread.
[perl5.git] / win32 / win32.c
1 /* WIN32.C
2  *
3  * (c) 1995 Microsoft Corporation. All rights reserved. 
4  *              Developed by hip communications inc., http://info.hip.com/info/
5  * Portions (c) 1993 Intergraph Corporation. All rights reserved.
6  *
7  *    You may distribute under the terms of either the GNU General Public
8  *    License or the Artistic License, as specified in the README file.
9  */
10
11 #define WIN32_LEAN_AND_MEAN
12 #define WIN32IO_IS_STDIO
13 #include <tchar.h>
14 #include <windows.h>
15
16 /* #include "config.h" */
17
18 #define PERLIO_NOT_STDIO 0 
19 #if !defined(PERLIO_IS_STDIO) && !defined(USE_SFIO)
20 #define PerlIO FILE
21 #endif
22
23 #include "EXTERN.h"
24 #include "perl.h"
25 #include "XSUB.h"
26 #include <fcntl.h>
27 #include <sys/stat.h>
28 #include <assert.h>
29 #include <string.h>
30 #include <stdarg.h>
31 #include <float.h>
32
33 #define CROAK croak
34 #define WARN warn
35
36 #define EXECF_EXEC 1
37 #define EXECF_SPAWN 2
38 #define EXECF_SPAWN_NOWAIT 3
39
40 static DWORD IdOS(void);
41
42 extern WIN32_IOSUBSYSTEM        win32stdio;
43 static PWIN32_IOSUBSYSTEM pIOSubSystem = &win32stdio;
44
45 BOOL  ProbeEnv = FALSE;
46 DWORD Win32System = (DWORD)-1;
47 char  szShellPath[MAX_PATH+1];
48 char  szPerlLibRoot[MAX_PATH+1];
49 HANDLE PerlDllHandle = INVALID_HANDLE_VALUE;
50
51 static int do_spawn2(char *cmd, int exectype);
52
53 int 
54 IsWin95(void) {
55     return (IdOS() == VER_PLATFORM_WIN32_WINDOWS);
56 }
57
58 int
59 IsWinNT(void) {
60     return (IdOS() == VER_PLATFORM_WIN32_NT);
61 }
62
63 DllExport PWIN32_IOSUBSYSTEM
64 SetIOSubSystem(void *p)
65 {
66     PWIN32_IOSUBSYSTEM old = pIOSubSystem;
67     if (p) {
68         PWIN32_IOSUBSYSTEM pio = (PWIN32_IOSUBSYSTEM)p;
69         if (pio->signature_begin == 12345678L
70             && pio->signature_end == 87654321L) {
71             pIOSubSystem = pio;
72         }
73     }
74     else {
75         pIOSubSystem = &win32stdio;
76     }
77     return old;
78 }
79
80 DllExport PWIN32_IOSUBSYSTEM
81 GetIOSubSystem(void)
82 {
83     return pIOSubSystem;
84 }
85
86 char *
87 win32PerlLibPath(void)
88 {
89     char *end;
90     GetModuleFileName((PerlDllHandle == INVALID_HANDLE_VALUE) 
91                       ? GetModuleHandle(NULL)
92                       : PerlDllHandle,
93                       szPerlLibRoot, 
94                       sizeof(szPerlLibRoot));
95
96     *(end = strrchr(szPerlLibRoot, '\\')) = '\0';
97     if (stricmp(end-4,"\\bin") == 0)
98      end -= 4;
99     strcpy(end,"\\lib");
100     return (szPerlLibRoot);
101 }
102
103 char *
104 win32SiteLibPath(void)
105 {
106     static char szPerlSiteLib[MAX_PATH+1];
107     strcpy(szPerlSiteLib, win32PerlLibPath());
108     strcat(szPerlSiteLib, "\\site");
109     return (szPerlSiteLib);
110 }
111
112 BOOL
113 HasRedirection(char *ptr)
114 {
115     int inquote = 0;
116     char quote = '\0';
117
118     /*
119      * Scan string looking for redirection (< or >) or pipe
120      * characters (|) that are not in a quoted string
121      */
122     while(*ptr) {
123         switch(*ptr) {
124         case '\'':
125         case '\"':
126             if(inquote) {
127                 if(quote == *ptr) {
128                     inquote = 0;
129                     quote = '\0';
130                 }
131             }
132             else {
133                 quote = *ptr;
134                 inquote++;
135             }
136             break;
137         case '>':
138         case '<':
139         case '|':
140             if(!inquote)
141                 return TRUE;
142         default:
143             break;
144         }
145         ++ptr;
146     }
147     return FALSE;
148 }
149
150 /* since the current process environment is being updated in util.c
151  * the library functions will get the correct environment
152  */
153 PerlIO *
154 my_popen(char *cmd, char *mode)
155 {
156 #ifdef FIXCMD
157 #define fixcmd(x)       {                                       \
158                             char *pspace = strchr((x),' ');     \
159                             if (pspace) {                       \
160                                 char *p = (x);                  \
161                                 while (p < pspace) {            \
162                                     if (*p == '/')              \
163                                         *p = '\\';              \
164                                     p++;                        \
165                                 }                               \
166                             }                                   \
167                         }
168 #else
169 #define fixcmd(x)
170 #endif
171
172 #if 1
173 /* was #ifndef PERLDLL, but the #else stuff doesn't work on NT
174  * GSAR 97/03/13
175  */
176     fixcmd(cmd);
177 #ifdef __BORLANDC__ /* workaround a Borland stdio bug */
178     win32_fflush(stdout);
179     win32_fflush(stderr);
180 #endif
181     return win32_popen(cmd, mode);
182 #else
183 /*
184  * There seems to be some problems for the _popen call in a DLL
185  * this trick at the moment seems to work but it is never test
186  * on NT yet
187  *
188  */ 
189 #       ifdef __cplusplus
190 #define EXT_C_FUNC      extern "C"
191 #       else
192 #define EXT_C_FUNC      extern
193 #       endif
194
195     EXT_C_FUNC int __cdecl _set_osfhnd(int fh, long value);
196     EXT_C_FUNC void __cdecl _lock_fhandle(int);
197     EXT_C_FUNC void __cdecl _unlock_fhandle(int);
198
199     BOOL        fSuccess;
200     PerlIO      *pf;            /* to store the _popen return value */
201     int         tm = 0;         /* flag indicating tDllExport or binary mode */
202     int         fhNeeded, fhInherited, fhDup;
203     int         ineeded, iinherited;
204     DWORD       dwDup;
205     int         phdls[2];       /* I/O handles for pipe */
206     HANDLE      hPIn, hPOut, hPErr,
207                 hSaveStdin, hSaveStdout, hSaveStderr,
208                 hPNeeded, hPInherited, hPDuped;
209      
210     /* first check for errors in the arguments */
211     if ( (cmd == NULL) || (mode == NULL)
212          || ((*mode != 'w') && (*mode != _T('r'))) )
213         goto error1;
214
215     if ( *(mode + 1) == _T('t') )
216         tm = O_TEXT;
217     else if ( *(mode + 1) == _T('b') )
218         tm = O_BINARY;
219     else
220         tm = (*mode == 'w' ? O_BINARY : O_TEXT);
221
222
223     fixcmd(cmd);
224     if (&win32stdio != pIOSubSystem)
225         return win32_popen(cmd, mode);
226
227 #ifdef EFG
228     if ( _pipe( phdls, 1024, tm ) == -1 )
229 #else
230     if ( win32_pipe( phdls, 1024, tm ) == -1 )
231 #endif
232         goto error1;
233
234     /* save the current situation */
235     hSaveStdin = GetStdHandle(STD_INPUT_HANDLE); 
236     hSaveStdout = GetStdHandle(STD_OUTPUT_HANDLE); 
237     hSaveStderr = GetStdHandle(STD_ERROR_HANDLE); 
238
239     if (*mode == _T('w')) {
240         ineeded = 1;
241         dwDup   = STD_INPUT_HANDLE;
242         iinherited = 0;
243     }
244     else {
245         ineeded = 0;
246         dwDup   = STD_OUTPUT_HANDLE;
247         iinherited = 1;
248     }
249
250     fhNeeded = phdls[ineeded];
251     fhInherited = phdls[iinherited];
252
253     fSuccess = DuplicateHandle(GetCurrentProcess(), 
254                                (HANDLE) stolen_get_osfhandle(fhNeeded), 
255                                GetCurrentProcess(), 
256                                &hPNeeded, 
257                                0, 
258                                FALSE,       /* not inherited */ 
259                                DUPLICATE_SAME_ACCESS); 
260
261     if (!fSuccess)
262         goto error2;
263
264     fhDup = stolen_open_osfhandle((long) hPNeeded, tm);
265     win32_dup2(fhDup, fhNeeded);
266     win32_close(fhDup);
267
268 #ifdef AAA
269     /* Close the Out pipe, child won't need it */
270     hPDuped = (HANDLE) stolen_get_osfhandle(fhNeeded);
271
272     _lock_fhandle(fhNeeded);
273     _set_osfhnd(fhNeeded, (long)hPNeeded); /* put in ours duplicated one */
274     _unlock_fhandle(fhNeeded);
275
276     CloseHandle(hPDuped);       /* close the handle first */
277 #endif
278
279     if (!SetStdHandle(dwDup, (HANDLE) stolen_get_osfhandle(fhInherited)))
280         goto error2;
281
282     /*
283      * make sure the child see the same stderr as the calling program
284      */
285     if (!SetStdHandle(STD_ERROR_HANDLE,
286                       (HANDLE)stolen_get_osfhandle(win32_fileno(win32_stderr()))))
287         goto error2;
288
289     pf = win32_popen(cmd, mode);        /* ask _popen to do the job */
290
291     /* restore to where we were */
292     SetStdHandle(STD_INPUT_HANDLE, hSaveStdin);
293     SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdout);
294     SetStdHandle(STD_ERROR_HANDLE, hSaveStderr);
295
296     /* we don't need it any more, that's for the child */
297     win32_close(fhInherited);
298
299     if (NULL == pf) {
300         /* something wrong */
301         win32_close(fhNeeded);
302         goto error1;
303     }
304     else {
305         /*
306          * here we steal the file handle in pf and stuff ours in
307          */
308         win32_dup2(fhNeeded, win32_fileno(pf));
309         win32_close(fhNeeded);
310     }
311     return (pf);
312
313 error2:
314     win32_close(fhNeeded);
315     win32_close(fhInherited);
316
317 error1:
318     return (NULL);
319
320 #endif
321 }
322
323 long
324 my_pclose(PerlIO *fp)
325 {
326     return win32_pclose(fp);
327 }
328
329 static DWORD
330 IdOS(void)
331 {
332     static OSVERSIONINFO osver;
333
334     if (osver.dwPlatformId != Win32System) {
335         memset(&osver, 0, sizeof(OSVERSIONINFO));
336         osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
337         GetVersionEx(&osver);
338         Win32System = osver.dwPlatformId;
339     }
340     return (Win32System);
341 }
342
343 static char *
344 GetShell(void)
345 {
346     if (!ProbeEnv) {
347         char* defaultshell = (IsWinNT() ? "cmd.exe" : "command.com");
348         /* we don't use COMSPEC here for two reasons:
349          *  1. the same reason perl on UNIX doesn't use SHELL--rampant and
350          *     uncontrolled unportability of the ensuing scripts.
351          *  2. PERL5SHELL could be set to a shell that may not be fit for
352          *     interactive use (which is what most programs look in COMSPEC
353          *     for).
354          */
355         char *usershell = getenv("PERL5SHELL");  
356
357         ProbeEnv = TRUE;
358         strcpy(szShellPath, usershell ? usershell : defaultshell);
359     }
360     return szShellPath;
361 }
362
363 int
364 do_aspawn(void* really, void ** mark, void ** arglast)
365 {
366     char **argv;
367     char *strPtr;
368     char *cmd;
369     int status;
370     unsigned int length;
371     int index = 0;
372     SV *sv = (SV*)really;
373     SV** pSv = (SV**)mark;
374
375     New(1310, argv, (arglast - mark) + 4, char*);
376
377     if(sv != Nullsv) {
378         cmd = SvPV(sv, length);
379     }
380     else {
381         argv[index++] = cmd = GetShell();
382         if (IsWinNT())
383             argv[index++] = "/x";   /* always enable command extensions */
384         argv[index++] = "/c";
385     }
386
387     while(++pSv <= (SV**)arglast) {
388         sv = *pSv;
389         strPtr = SvPV(sv, length);
390         if(strPtr != NULL && *strPtr != '\0')
391             argv[index++] = strPtr;
392     }
393     argv[index++] = 0;
394    
395     status = win32_spawnvp(P_WAIT, cmd, (const char* const*)argv);
396
397     Safefree(argv);
398
399     if (status < 0) {
400         if (dowarn)
401             warn("Can't spawn \"%s\": %s", cmd, strerror(errno));
402         status = 255 << 8;
403     }
404     return (status);
405 }
406
407 int
408 do_spawn2(char *cmd, int exectype)
409 {
410     char **a;
411     char *s;
412     char **argv;
413     int status = -1;
414     BOOL needToTry = TRUE;
415     char *shell, *cmd2;
416
417     /* save an extra exec if possible */
418     shell = GetShell();
419
420     /* see if there are shell metacharacters in it */
421     if(!HasRedirection(cmd)) {
422         New(1301,argv, strlen(cmd) / 2 + 2, char*);
423         New(1302,cmd2, strlen(cmd) + 1, char);
424         strcpy(cmd2, cmd);
425         a = argv;
426         for (s = cmd2; *s;) {
427             while (*s && isspace(*s))
428                 s++;
429             if (*s)
430                 *(a++) = s;
431             while(*s && !isspace(*s))
432                 s++;
433             if(*s)
434                 *s++ = '\0';
435         }
436         *a = Nullch;
437         if(argv[0]) {
438             switch (exectype) {
439             case EXECF_SPAWN:
440                 status = win32_spawnvp(P_WAIT, argv[0],
441                                        (const char* const*)argv);
442                 break;
443             case EXECF_SPAWN_NOWAIT:
444                 status = win32_spawnvp(P_NOWAIT, argv[0],
445                                        (const char* const*)argv);
446                 break;
447             case EXECF_EXEC:
448                 status = win32_execvp(argv[0], (const char* const*)argv);
449                 break;
450             }
451             if(status != -1 || errno == 0)
452                 needToTry = FALSE;
453         }
454         Safefree(argv);
455         Safefree(cmd2);
456     }
457     if(needToTry) {
458         char *argv[5];
459         int i = 0;
460         argv[i++] = shell;
461         if (IsWinNT())
462             argv[i++] = "/x";
463         argv[i++] = "/c"; argv[i++] = cmd; argv[i] = Nullch;
464         switch (exectype) {
465         case EXECF_SPAWN:
466             status = win32_spawnvp(P_WAIT, argv[0],
467                                    (const char* const*)argv);
468             break;
469         case EXECF_SPAWN_NOWAIT:
470             status = win32_spawnvp(P_NOWAIT, argv[0],
471                                    (const char* const*)argv);
472             break;
473         case EXECF_EXEC:
474             status = win32_execvp(argv[0], (const char* const*)argv);
475             break;
476         }
477     }
478     if (status < 0) {
479         if (dowarn)
480             warn("Can't %s \"%s\": %s",
481                  (exectype == EXECF_EXEC ? "exec" : "spawn"),
482                  needToTry ? shell : argv[0],
483                  strerror(errno));
484         status = 255 << 8;
485     }
486     return (status);
487 }
488
489 int
490 do_spawn(char *cmd)
491 {
492     return do_spawn2(cmd, EXECF_SPAWN);
493 }
494
495 bool
496 do_exec(char *cmd)
497 {
498     do_spawn2(cmd, EXECF_EXEC);
499     return FALSE;
500 }
501
502
503 #define PATHLEN 1024
504
505 /* The idea here is to read all the directory names into a string table
506  * (separated by nulls) and when one of the other dir functions is called
507  * return the pointer to the current file name.
508  */
509 DIR *
510 opendir(char *filename)
511 {
512     DIR            *p;
513     long            len;
514     long            idx;
515     char            scannamespc[PATHLEN];
516     char       *scanname = scannamespc;
517     struct stat     sbuf;
518     WIN32_FIND_DATA FindData;
519     HANDLE          fh;
520 /*  char            root[_MAX_PATH];*/
521 /*  char            volname[_MAX_PATH];*/
522 /*  DWORD           serial, maxname, flags;*/
523 /*  BOOL            downcase;*/
524 /*  char           *dummy;*/
525
526     /* check to see if filename is a directory */
527     if (win32_stat(filename, &sbuf) < 0 || (sbuf.st_mode & S_IFDIR) == 0) {
528         return NULL;
529     }
530
531     /* get the file system characteristics */
532 /*  if(GetFullPathName(filename, MAX_PATH, root, &dummy)) {
533  *      if(dummy = strchr(root, '\\'))
534  *          *++dummy = '\0';
535  *      if(GetVolumeInformation(root, volname, MAX_PATH, &serial,
536  *                              &maxname, &flags, 0, 0)) {
537  *          downcase = !(flags & FS_CASE_IS_PRESERVED);
538  *      }
539  *  }
540  *  else {
541  *      downcase = TRUE;
542  *  }
543  */
544     /* Get us a DIR structure */
545     Newz(1303, p, 1, DIR);
546     if(p == NULL)
547         return NULL;
548
549     /* Create the search pattern */
550     strcpy(scanname, filename);
551
552     if(index("/\\", *(scanname + strlen(scanname) - 1)) == NULL)
553         strcat(scanname, "/*");
554     else
555         strcat(scanname, "*");
556
557     /* do the FindFirstFile call */
558     fh = FindFirstFile(scanname, &FindData);
559     if(fh == INVALID_HANDLE_VALUE) {
560         return NULL;
561     }
562
563     /* now allocate the first part of the string table for
564      * the filenames that we find.
565      */
566     idx = strlen(FindData.cFileName)+1;
567     New(1304, p->start, idx, char);
568     if(p->start == NULL) {
569         CROAK("opendir: malloc failed!\n");
570     }
571     strcpy(p->start, FindData.cFileName);
572 /*  if(downcase)
573  *      strlwr(p->start);
574  */
575     p->nfiles++;
576
577     /* loop finding all the files that match the wildcard
578      * (which should be all of them in this directory!).
579      * the variable idx should point one past the null terminator
580      * of the previous string found.
581      */
582     while (FindNextFile(fh, &FindData)) {
583         len = strlen(FindData.cFileName);
584         /* bump the string table size by enough for the
585          * new name and it's null terminator
586          */
587         Renew(p->start, idx+len+1, char);
588         if(p->start == NULL) {
589             CROAK("opendir: malloc failed!\n");
590         }
591         strcpy(&p->start[idx], FindData.cFileName);
592 /*      if (downcase) 
593  *          strlwr(&p->start[idx]);
594  */
595                 p->nfiles++;
596                 idx += len+1;
597         }
598         FindClose(fh);
599         p->size = idx;
600         p->curr = p->start;
601         return p;
602 }
603
604
605 /* Readdir just returns the current string pointer and bumps the
606  * string pointer to the nDllExport entry.
607  */
608 struct direct *
609 readdir(DIR *dirp)
610 {
611     int         len;
612     static int  dummy = 0;
613
614     if (dirp->curr) {
615         /* first set up the structure to return */
616         len = strlen(dirp->curr);
617         strcpy(dirp->dirstr.d_name, dirp->curr);
618         dirp->dirstr.d_namlen = len;
619
620         /* Fake an inode */
621         dirp->dirstr.d_ino = dummy++;
622
623         /* Now set up for the nDllExport call to readdir */
624         dirp->curr += len + 1;
625         if (dirp->curr >= (dirp->start + dirp->size)) {
626             dirp->curr = NULL;
627         }
628
629         return &(dirp->dirstr);
630     } 
631     else
632         return NULL;
633 }
634
635 /* Telldir returns the current string pointer position */
636 long
637 telldir(DIR *dirp)
638 {
639     return (long) dirp->curr;
640 }
641
642
643 /* Seekdir moves the string pointer to a previously saved position
644  *(Saved by telldir).
645  */
646 void
647 seekdir(DIR *dirp, long loc)
648 {
649     dirp->curr = (char *)loc;
650 }
651
652 /* Rewinddir resets the string pointer to the start */
653 void
654 rewinddir(DIR *dirp)
655 {
656     dirp->curr = dirp->start;
657 }
658
659 /* free the memory allocated by opendir */
660 int
661 closedir(DIR *dirp)
662 {
663     Safefree(dirp->start);
664     Safefree(dirp);
665     return 1;
666 }
667
668
669 /*
670  * various stubs
671  */
672
673
674 /* Ownership
675  *
676  * Just pretend that everyone is a superuser. NT will let us know if
677  * we don\'t really have permission to do something.
678  */
679
680 #define ROOT_UID    ((uid_t)0)
681 #define ROOT_GID    ((gid_t)0)
682
683 uid_t
684 getuid(void)
685 {
686     return ROOT_UID;
687 }
688
689 uid_t
690 geteuid(void)
691 {
692     return ROOT_UID;
693 }
694
695 gid_t
696 getgid(void)
697 {
698     return ROOT_GID;
699 }
700
701 gid_t
702 getegid(void)
703 {
704     return ROOT_GID;
705 }
706
707 int
708 setuid(uid_t uid)
709
710     return (uid == ROOT_UID ? 0 : -1);
711 }
712
713 int
714 setgid(gid_t gid)
715 {
716     return (gid == ROOT_GID ? 0 : -1);
717 }
718
719 /*
720  * pretended kill
721  */
722 int
723 kill(int pid, int sig)
724 {
725     HANDLE hProcess= OpenProcess(PROCESS_ALL_ACCESS, TRUE, pid);
726
727     if (hProcess == NULL) {
728         CROAK("kill process failed!\n");
729     }
730     else {
731         if (!TerminateProcess(hProcess, sig))
732             CROAK("kill process failed!\n");
733         CloseHandle(hProcess);
734     }
735     return 0;
736 }
737       
738 /*
739  * File system stuff
740  */
741
742 #if 0
743 int
744 ioctl(int i, unsigned int u, char *data)
745 {
746     CROAK("ioctl not implemented!\n");
747     return -1;
748 }
749 #endif
750
751 unsigned int
752 sleep(unsigned int t)
753 {
754     Sleep(t*1000);
755     return 0;
756 }
757
758
759 #undef rename
760
761 int
762 myrename(char *OldFileName, char *newname)
763 {
764     if(_access(newname, 0) != -1) {     /* file exists */
765         _unlink(newname);
766     }
767     return rename(OldFileName, newname);
768 }
769
770
771 DllExport int
772 win32_stat(const char *path, struct stat *buffer)
773 {
774     char                t[MAX_PATH]; 
775     const char  *p = path;
776     int         l = strlen(path);
777     int         res;
778
779     if (l > 1) {
780         switch(path[l - 1]) {
781         case '\\':
782         case '/':
783             if (path[l - 2] != ':') {
784                 strncpy(t, path, l - 1);
785                 t[l - 1] = 0;
786                 p = t;
787             };
788         }
789     }
790     res = pIOSubSystem->pfnstat(p,buffer);
791 #ifdef __BORLANDC__
792     if (res == 0) {
793         if (S_ISDIR(buffer->st_mode))
794             buffer->st_mode |= S_IWRITE | S_IEXEC;
795         else if (S_ISREG(buffer->st_mode)) {
796             if (l >= 4 && path[l-4] == '.') {
797                 const char *e = path + l - 3;
798                 if (strnicmp(e,"exe",3)
799                     && strnicmp(e,"bat",3)
800                     && strnicmp(e,"com",3)
801                     && (IsWin95() || strnicmp(e,"cmd",3)))
802                     buffer->st_mode &= ~S_IEXEC;
803                 else
804                     buffer->st_mode |= S_IEXEC;
805             }
806             else
807                 buffer->st_mode &= ~S_IEXEC;
808         }
809     }
810 #endif
811     return res;
812 }
813
814 #ifndef USE_WIN32_RTL_ENV
815
816 DllExport char *
817 win32_getenv(const char *name)
818 {
819     static char *curitem = Nullch;
820     static DWORD curlen = 512;
821     DWORD needlen;
822     if (!curitem)
823         New(1305,curitem,curlen,char);
824     if (!(needlen = GetEnvironmentVariable(name,curitem,curlen)))
825         return Nullch;
826     while (needlen > curlen) {
827         Renew(curitem,needlen,char);
828         curlen = needlen;
829         needlen = GetEnvironmentVariable(name,curitem,curlen);
830     }
831     return curitem;
832 }
833
834 #endif
835
836 static long
837 FileTimeToClock(PFILETIME ft)
838 {
839  __int64 qw = ft->dwHighDateTime;
840  qw <<= 32;
841  qw |= ft->dwLowDateTime;
842  qw /= 10000;  /* File time ticks at 0.1uS, clock at 1mS */
843  return (long) qw;
844 }
845
846 #undef times
847 int
848 mytimes(struct tms *timebuf)
849 {
850     FILETIME user;
851     FILETIME kernel;
852     FILETIME dummy;
853     if (GetProcessTimes(GetCurrentProcess(), &dummy, &dummy, 
854                         &kernel,&user)) {
855         timebuf->tms_utime = FileTimeToClock(&user);
856         timebuf->tms_stime = FileTimeToClock(&kernel);
857         timebuf->tms_cutime = 0;
858         timebuf->tms_cstime = 0;
859         
860     } else { 
861         /* That failed - e.g. Win95 fallback to clock() */
862         clock_t t = clock();
863         timebuf->tms_utime = t;
864         timebuf->tms_stime = 0;
865         timebuf->tms_cutime = 0;
866         timebuf->tms_cstime = 0;
867     }
868     return 0;
869 }
870
871 static UINT timerid = 0;
872
873
874 static VOID CALLBACK TimerProc(HWND win, UINT msg, UINT id, DWORD time)
875 {
876  KillTimer(NULL,timerid);
877  timerid=0;  
878  sighandler(14);
879 }
880
881 #undef alarm
882 unsigned int
883 myalarm(unsigned int sec)
884 {
885     /* 
886      * the 'obvious' implentation is SetTimer() with a callback
887      * which does whatever receiving SIGALRM would do 
888      * we cannot use SIGALRM even via raise() as it is not 
889      * one of the supported codes in <signal.h>
890      *
891      * Snag is unless something is looking at the message queue
892      * nothing happens :-(
893      */ 
894     if (sec)
895      {
896       timerid = SetTimer(NULL,timerid,sec*1000,(TIMERPROC)TimerProc);
897       if (!timerid)
898        croak("Cannot set timer");
899      } 
900     else
901      {
902       if (timerid)
903        {
904         KillTimer(NULL,timerid);
905         timerid=0;  
906        }
907      }
908     return 0;
909 }
910
911 /*
912  *  redirected io subsystem for all XS modules
913  *
914  */
915
916 DllExport int *
917 win32_errno(void)
918 {
919     return (pIOSubSystem->pfnerrno());
920 }
921
922 DllExport char ***
923 win32_environ(void)
924 {
925     return (pIOSubSystem->pfnenviron());
926 }
927
928 /* the rest are the remapped stdio routines */
929 DllExport FILE *
930 win32_stderr(void)
931 {
932     return (pIOSubSystem->pfnstderr());
933 }
934
935 DllExport FILE *
936 win32_stdin(void)
937 {
938     return (pIOSubSystem->pfnstdin());
939 }
940
941 DllExport FILE *
942 win32_stdout()
943 {
944     return (pIOSubSystem->pfnstdout());
945 }
946
947 DllExport int
948 win32_ferror(FILE *fp)
949 {
950     return (pIOSubSystem->pfnferror(fp));
951 }
952
953
954 DllExport int
955 win32_feof(FILE *fp)
956 {
957     return (pIOSubSystem->pfnfeof(fp));
958 }
959
960 /*
961  * Since the errors returned by the socket error function 
962  * WSAGetLastError() are not known by the library routine strerror
963  * we have to roll our own.
964  */
965
966 __declspec(thread) char strerror_buffer[512];
967
968 DllExport char *
969 win32_strerror(int e) 
970 {
971 #ifndef __BORLANDC__            /* Borland intolerance */
972     extern int sys_nerr;
973 #endif
974     DWORD source = 0;
975
976     if(e < 0 || e > sys_nerr) {
977         if(e < 0)
978             e = GetLastError();
979
980         if(FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, &source, e, 0,
981                          strerror_buffer, sizeof(strerror_buffer), NULL) == 0) 
982             strcpy(strerror_buffer, "Unknown Error");
983
984         return strerror_buffer;
985     }
986     return pIOSubSystem->pfnstrerror(e);
987 }
988
989 DllExport int
990 win32_fprintf(FILE *fp, const char *format, ...)
991 {
992     va_list marker;
993     va_start(marker, format);     /* Initialize variable arguments. */
994
995     return (pIOSubSystem->pfnvfprintf(fp, format, marker));
996 }
997
998 DllExport int
999 win32_printf(const char *format, ...)
1000 {
1001     va_list marker;
1002     va_start(marker, format);     /* Initialize variable arguments. */
1003
1004     return (pIOSubSystem->pfnvprintf(format, marker));
1005 }
1006
1007 DllExport int
1008 win32_vfprintf(FILE *fp, const char *format, va_list args)
1009 {
1010     return (pIOSubSystem->pfnvfprintf(fp, format, args));
1011 }
1012
1013 DllExport int
1014 win32_vprintf(const char *format, va_list args)
1015 {
1016     return (pIOSubSystem->pfnvprintf(format, args));
1017 }
1018
1019 DllExport size_t
1020 win32_fread(void *buf, size_t size, size_t count, FILE *fp)
1021 {
1022     return pIOSubSystem->pfnfread(buf, size, count, fp);
1023 }
1024
1025 DllExport size_t
1026 win32_fwrite(const void *buf, size_t size, size_t count, FILE *fp)
1027 {
1028     return pIOSubSystem->pfnfwrite(buf, size, count, fp);
1029 }
1030
1031 DllExport FILE *
1032 win32_fopen(const char *filename, const char *mode)
1033 {
1034     if (stricmp(filename, "/dev/null")==0)
1035         return pIOSubSystem->pfnfopen("NUL", mode);
1036     return pIOSubSystem->pfnfopen(filename, mode);
1037 }
1038
1039 DllExport FILE *
1040 win32_fdopen( int handle, const char *mode)
1041 {
1042     return pIOSubSystem->pfnfdopen(handle, (char *) mode);
1043 }
1044
1045 DllExport FILE *
1046 win32_freopen( const char *path, const char *mode, FILE *stream)
1047 {
1048     if (stricmp(path, "/dev/null")==0)
1049         return pIOSubSystem->pfnfreopen("NUL", mode, stream);
1050     return pIOSubSystem->pfnfreopen(path, mode, stream);
1051 }
1052
1053 DllExport int
1054 win32_fclose(FILE *pf)
1055 {
1056     return pIOSubSystem->pfnfclose(pf);
1057 }
1058
1059 DllExport int
1060 win32_fputs(const char *s,FILE *pf)
1061 {
1062     return pIOSubSystem->pfnfputs(s, pf);
1063 }
1064
1065 DllExport int
1066 win32_fputc(int c,FILE *pf)
1067 {
1068     return pIOSubSystem->pfnfputc(c,pf);
1069 }
1070
1071 DllExport int
1072 win32_ungetc(int c,FILE *pf)
1073 {
1074     return pIOSubSystem->pfnungetc(c,pf);
1075 }
1076
1077 DllExport int
1078 win32_getc(FILE *pf)
1079 {
1080     return pIOSubSystem->pfngetc(pf);
1081 }
1082
1083 DllExport int
1084 win32_fileno(FILE *pf)
1085 {
1086     return pIOSubSystem->pfnfileno(pf);
1087 }
1088
1089 DllExport void
1090 win32_clearerr(FILE *pf)
1091 {
1092     pIOSubSystem->pfnclearerr(pf);
1093     return;
1094 }
1095
1096 DllExport int
1097 win32_fflush(FILE *pf)
1098 {
1099     return pIOSubSystem->pfnfflush(pf);
1100 }
1101
1102 DllExport long
1103 win32_ftell(FILE *pf)
1104 {
1105     return pIOSubSystem->pfnftell(pf);
1106 }
1107
1108 DllExport int
1109 win32_fseek(FILE *pf,long offset,int origin)
1110 {
1111     return pIOSubSystem->pfnfseek(pf, offset, origin);
1112 }
1113
1114 DllExport int
1115 win32_fgetpos(FILE *pf,fpos_t *p)
1116 {
1117     return pIOSubSystem->pfnfgetpos(pf, p);
1118 }
1119
1120 DllExport int
1121 win32_fsetpos(FILE *pf,const fpos_t *p)
1122 {
1123     return pIOSubSystem->pfnfsetpos(pf, p);
1124 }
1125
1126 DllExport void
1127 win32_rewind(FILE *pf)
1128 {
1129     pIOSubSystem->pfnrewind(pf);
1130     return;
1131 }
1132
1133 DllExport FILE*
1134 win32_tmpfile(void)
1135 {
1136     return pIOSubSystem->pfntmpfile();
1137 }
1138
1139 DllExport void
1140 win32_abort(void)
1141 {
1142     pIOSubSystem->pfnabort();
1143     return;
1144 }
1145
1146 DllExport int
1147 win32_fstat(int fd,struct stat *bufptr)
1148 {
1149     return pIOSubSystem->pfnfstat(fd,bufptr);
1150 }
1151
1152 DllExport int
1153 win32_pipe(int *pfd, unsigned int size, int mode)
1154 {
1155     return pIOSubSystem->pfnpipe(pfd, size, mode);
1156 }
1157
1158 DllExport FILE*
1159 win32_popen(const char *command, const char *mode)
1160 {
1161     return pIOSubSystem->pfnpopen(command, mode);
1162 }
1163
1164 DllExport int
1165 win32_pclose(FILE *pf)
1166 {
1167     return pIOSubSystem->pfnpclose(pf);
1168 }
1169
1170 DllExport int
1171 win32_setmode(int fd, int mode)
1172 {
1173     return pIOSubSystem->pfnsetmode(fd, mode);
1174 }
1175
1176 DllExport long
1177 win32_lseek(int fd, long offset, int origin)
1178 {
1179     return pIOSubSystem->pfnlseek(fd, offset, origin);
1180 }
1181
1182 DllExport long
1183 win32_tell(int fd)
1184 {
1185     return pIOSubSystem->pfntell(fd);
1186 }
1187
1188 DllExport int
1189 win32_open(const char *path, int flag, ...)
1190 {
1191     va_list ap;
1192     int pmode;
1193
1194     va_start(ap, flag);
1195     pmode = va_arg(ap, int);
1196     va_end(ap);
1197
1198     if (stricmp(path, "/dev/null")==0)
1199         return pIOSubSystem->pfnopen("NUL", flag, pmode);
1200     return pIOSubSystem->pfnopen(path,flag,pmode);
1201 }
1202
1203 DllExport int
1204 win32_close(int fd)
1205 {
1206     return pIOSubSystem->pfnclose(fd);
1207 }
1208
1209 DllExport int
1210 win32_eof(int fd)
1211 {
1212     return pIOSubSystem->pfneof(fd);
1213 }
1214
1215 DllExport int
1216 win32_dup(int fd)
1217 {
1218     return pIOSubSystem->pfndup(fd);
1219 }
1220
1221 DllExport int
1222 win32_dup2(int fd1,int fd2)
1223 {
1224     return pIOSubSystem->pfndup2(fd1,fd2);
1225 }
1226
1227 DllExport int
1228 win32_read(int fd, void *buf, unsigned int cnt)
1229 {
1230     return pIOSubSystem->pfnread(fd, buf, cnt);
1231 }
1232
1233 DllExport int
1234 win32_write(int fd, const void *buf, unsigned int cnt)
1235 {
1236     return pIOSubSystem->pfnwrite(fd, buf, cnt);
1237 }
1238
1239 DllExport int
1240 win32_mkdir(const char *dir, int mode)
1241 {
1242     return pIOSubSystem->pfnmkdir(dir); /* just ignore mode */
1243 }
1244
1245 DllExport int
1246 win32_rmdir(const char *dir)
1247 {
1248     return pIOSubSystem->pfnrmdir(dir);
1249 }
1250
1251 DllExport int
1252 win32_chdir(const char *dir)
1253 {
1254     return pIOSubSystem->pfnchdir(dir);
1255 }
1256
1257 DllExport int
1258 win32_spawnvp(int mode, const char *cmdname, const char *const *argv)
1259 {
1260     return pIOSubSystem->pfnspawnvp(mode, cmdname, (char * const *) argv);
1261 }
1262
1263 DllExport int
1264 win32_execvp(const char *cmdname, const char *const *argv)
1265 {
1266     return pIOSubSystem->pfnexecvp(cmdname, (char *const *)argv);
1267 }
1268
1269 DllExport void
1270 win32_perror(const char *str)
1271 {
1272     pIOSubSystem->pfnperror(str);
1273 }
1274
1275 DllExport void
1276 win32_setbuf(FILE *pf, char *buf)
1277 {
1278     pIOSubSystem->pfnsetbuf(pf, buf);
1279 }
1280
1281 DllExport int
1282 win32_setvbuf(FILE *pf, char *buf, int type, size_t size)
1283 {
1284     return pIOSubSystem->pfnsetvbuf(pf, buf, type, size);
1285 }
1286
1287 DllExport int
1288 win32_flushall(void)
1289 {
1290     return pIOSubSystem->pfnflushall();
1291 }
1292
1293 DllExport int
1294 win32_fcloseall(void)
1295 {
1296     return pIOSubSystem->pfnfcloseall();
1297 }
1298
1299 DllExport char*
1300 win32_fgets(char *s, int n, FILE *pf)
1301 {
1302     return pIOSubSystem->pfnfgets(s, n, pf);
1303 }
1304
1305 DllExport char*
1306 win32_gets(char *s)
1307 {
1308     return pIOSubSystem->pfngets(s);
1309 }
1310
1311 DllExport int
1312 win32_fgetc(FILE *pf)
1313 {
1314     return pIOSubSystem->pfnfgetc(pf);
1315 }
1316
1317 DllExport int
1318 win32_putc(int c, FILE *pf)
1319 {
1320     return pIOSubSystem->pfnputc(c,pf);
1321 }
1322
1323 DllExport int
1324 win32_puts(const char *s)
1325 {
1326     return pIOSubSystem->pfnputs(s);
1327 }
1328
1329 DllExport int
1330 win32_getchar(void)
1331 {
1332     return pIOSubSystem->pfngetchar();
1333 }
1334
1335 DllExport int
1336 win32_putchar(int c)
1337 {
1338     return pIOSubSystem->pfnputchar(c);
1339 }
1340
1341 DllExport void*
1342 win32_malloc(size_t size)
1343 {
1344     return pIOSubSystem->pfnmalloc(size);
1345 }
1346
1347 DllExport void*
1348 win32_calloc(size_t numitems, size_t size)
1349 {
1350     return pIOSubSystem->pfncalloc(numitems,size);
1351 }
1352
1353 DllExport void*
1354 win32_realloc(void *block, size_t size)
1355 {
1356     return pIOSubSystem->pfnrealloc(block,size);
1357 }
1358
1359 DllExport void
1360 win32_free(void *block)
1361 {
1362     pIOSubSystem->pfnfree(block);
1363 }
1364
1365 int
1366 stolen_open_osfhandle(long handle, int flags)
1367 {
1368     return pIOSubSystem->pfn_open_osfhandle(handle, flags);
1369 }
1370
1371 long
1372 stolen_get_osfhandle(int fd)
1373 {
1374     return pIOSubSystem->pfn_get_osfhandle(fd);
1375 }
1376
1377 /*
1378  * Extras.
1379  */
1380
1381 DllExport int
1382 win32_flock(int fd, int oper)
1383 {
1384     if (!IsWinNT()) {
1385         croak("flock() unimplemented on this platform");
1386         return -1;
1387     }
1388     return pIOSubSystem->pfnflock(fd, oper);
1389 }
1390
1391 static
1392 XS(w32_GetCwd)
1393 {
1394     dXSARGS;
1395     SV *sv = sv_newmortal();
1396     /* Make one call with zero size - return value is required size */
1397     DWORD len = GetCurrentDirectory((DWORD)0,NULL);
1398     SvUPGRADE(sv,SVt_PV);
1399     SvGROW(sv,len);
1400     SvCUR(sv) = GetCurrentDirectory((DWORD) SvLEN(sv), SvPVX(sv));
1401     /* 
1402      * If result != 0 
1403      *   then it worked, set PV valid, 
1404      *   else leave it 'undef' 
1405      */
1406     if (SvCUR(sv))
1407         SvPOK_on(sv);
1408     EXTEND(sp,1);
1409     ST(0) = sv;
1410     XSRETURN(1);
1411 }
1412
1413 static
1414 XS(w32_SetCwd)
1415 {
1416     dXSARGS;
1417     if (items != 1)
1418         croak("usage: Win32::SetCurrentDirectory($cwd)");
1419     if (SetCurrentDirectory(SvPV(ST(0),na)))
1420         XSRETURN_YES;
1421
1422     XSRETURN_NO;
1423 }
1424
1425 static
1426 XS(w32_GetNextAvailDrive)
1427 {
1428     dXSARGS;
1429     char ix = 'C';
1430     char root[] = "_:\\";
1431     while (ix <= 'Z') {
1432         root[0] = ix++;
1433         if (GetDriveType(root) == 1) {
1434             root[2] = '\0';
1435             XSRETURN_PV(root);
1436         }
1437     }
1438     XSRETURN_UNDEF;
1439 }
1440
1441 static
1442 XS(w32_GetLastError)
1443 {
1444     dXSARGS;
1445     XSRETURN_IV(GetLastError());
1446 }
1447
1448 static
1449 XS(w32_LoginName)
1450 {
1451     dXSARGS;
1452     char name[256];
1453     DWORD size = sizeof(name);
1454     if (GetUserName(name,&size)) {
1455         /* size includes NULL */
1456         ST(0) = sv_2mortal(newSVpv(name,size-1));
1457         XSRETURN(1);
1458     }
1459     XSRETURN_UNDEF;
1460 }
1461
1462 static
1463 XS(w32_NodeName)
1464 {
1465     dXSARGS;
1466     char name[MAX_COMPUTERNAME_LENGTH+1];
1467     DWORD size = sizeof(name);
1468     if (GetComputerName(name,&size)) {
1469         /* size does NOT include NULL :-( */
1470         ST(0) = sv_2mortal(newSVpv(name,size));
1471         XSRETURN(1);
1472     }
1473     XSRETURN_UNDEF;
1474 }
1475
1476
1477 static
1478 XS(w32_DomainName)
1479 {
1480     dXSARGS;
1481     char name[256];
1482     DWORD size = sizeof(name);
1483     if (GetUserName(name,&size)) {
1484         char sid[1024];
1485         DWORD sidlen = sizeof(sid);
1486         char dname[256];
1487         DWORD dnamelen = sizeof(dname);
1488         SID_NAME_USE snu;
1489         if (LookupAccountName(NULL, name, &sid, &sidlen,
1490                               dname, &dnamelen, &snu)) {
1491             XSRETURN_PV(dname);         /* all that for this */
1492         }
1493     }
1494     XSRETURN_UNDEF;
1495 }
1496
1497 static
1498 XS(w32_FsType)
1499 {
1500     dXSARGS;
1501     char fsname[256];
1502     DWORD flags, filecomplen;
1503     if (GetVolumeInformation(NULL, NULL, 0, NULL, &filecomplen,
1504                          &flags, fsname, sizeof(fsname))) {
1505         if (GIMME == G_ARRAY) {
1506             XPUSHs(sv_2mortal(newSVpv(fsname,0)));
1507             XPUSHs(sv_2mortal(newSViv(flags)));
1508             XPUSHs(sv_2mortal(newSViv(filecomplen)));
1509             PUTBACK;
1510             return;
1511         }
1512         XSRETURN_PV(fsname);
1513     }
1514     XSRETURN_UNDEF;
1515 }
1516
1517 static
1518 XS(w32_GetOSVersion)
1519 {
1520     dXSARGS;
1521     OSVERSIONINFO osver;
1522
1523     osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
1524     if (GetVersionEx(&osver)) {
1525         XPUSHs(newSVpv(osver.szCSDVersion, 0));
1526         XPUSHs(newSViv(osver.dwMajorVersion));
1527         XPUSHs(newSViv(osver.dwMinorVersion));
1528         XPUSHs(newSViv(osver.dwBuildNumber));
1529         XPUSHs(newSViv(osver.dwPlatformId));
1530         PUTBACK;
1531         return;
1532     }
1533     XSRETURN_UNDEF;
1534 }
1535
1536 static
1537 XS(w32_IsWinNT)
1538 {
1539     dXSARGS;
1540     XSRETURN_IV(IsWinNT());
1541 }
1542
1543 static
1544 XS(w32_IsWin95)
1545 {
1546     dXSARGS;
1547     XSRETURN_IV(IsWin95());
1548 }
1549
1550 static
1551 XS(w32_FormatMessage)
1552 {
1553     dXSARGS;
1554     DWORD source = 0;
1555     char msgbuf[1024];
1556
1557     if (items != 1)
1558         croak("usage: Win32::FormatMessage($errno)");
1559
1560     if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
1561                       &source, SvIV(ST(0)), 0,
1562                       msgbuf, sizeof(msgbuf)-1, NULL))
1563         XSRETURN_PV(msgbuf);
1564
1565     XSRETURN_UNDEF;
1566 }
1567
1568 static
1569 XS(w32_Spawn)
1570 {
1571     dXSARGS;
1572     char *cmd, *args;
1573     PROCESS_INFORMATION stProcInfo;
1574     STARTUPINFO stStartInfo;
1575     BOOL bSuccess = FALSE;
1576
1577     if(items != 3)
1578         croak("usage: Win32::Spawn($cmdName, $args, $PID)");
1579
1580     cmd = SvPV(ST(0),na);
1581     args = SvPV(ST(1), na);
1582
1583     memset(&stStartInfo, 0, sizeof(stStartInfo));   /* Clear the block */
1584     stStartInfo.cb = sizeof(stStartInfo);           /* Set the structure size */
1585     stStartInfo.dwFlags = STARTF_USESHOWWINDOW;     /* Enable wShowWindow control */
1586     stStartInfo.wShowWindow = SW_SHOWMINNOACTIVE;   /* Start min (normal) */
1587
1588     if(CreateProcess(
1589                 cmd,                    /* Image path */
1590                 args,                   /* Arguments for command line */
1591                 NULL,                   /* Default process security */
1592                 NULL,                   /* Default thread security */
1593                 FALSE,                  /* Must be TRUE to use std handles */
1594                 NORMAL_PRIORITY_CLASS,  /* No special scheduling */
1595                 NULL,                   /* Inherit our environment block */
1596                 NULL,                   /* Inherit our currrent directory */
1597                 &stStartInfo,           /* -> Startup info */
1598                 &stProcInfo))           /* <- Process info (if OK) */
1599     {
1600         CloseHandle(stProcInfo.hThread);/* library source code does this. */
1601         sv_setiv(ST(2), stProcInfo.dwProcessId);
1602         bSuccess = TRUE;
1603     }
1604     XSRETURN_IV(bSuccess);
1605 }
1606
1607 static
1608 XS(w32_GetTickCount)
1609 {
1610     dXSARGS;
1611     XSRETURN_IV(GetTickCount());
1612 }
1613
1614 static
1615 XS(w32_GetShortPathName)
1616 {
1617     dXSARGS;
1618     SV *shortpath;
1619     DWORD len;
1620
1621     if(items != 1)
1622         croak("usage: Win32::GetShortPathName($longPathName)");
1623
1624     shortpath = sv_mortalcopy(ST(0));
1625     SvUPGRADE(shortpath, SVt_PV);
1626     /* src == target is allowed */
1627     do {
1628         len = GetShortPathName(SvPVX(shortpath),
1629                                SvPVX(shortpath),
1630                                SvLEN(shortpath));
1631     } while (len >= SvLEN(shortpath) && sv_grow(shortpath,len+1));
1632     if (len) {
1633         SvCUR_set(shortpath,len);
1634         ST(0) = shortpath;
1635     }
1636     else
1637         ST(0) = &sv_undef;
1638     XSRETURN(1);
1639 }
1640
1641 void
1642 init_os_extras()
1643 {
1644     char *file = __FILE__;
1645     dXSUB_SYS;
1646
1647     /* XXX should be removed after checking with Nick */
1648     newXS("Win32::GetCurrentDirectory", w32_GetCwd, file);
1649
1650     /* these names are Activeware compatible */
1651     newXS("Win32::GetCwd", w32_GetCwd, file);
1652     newXS("Win32::SetCwd", w32_SetCwd, file);
1653     newXS("Win32::GetNextAvailDrive", w32_GetNextAvailDrive, file);
1654     newXS("Win32::GetLastError", w32_GetLastError, file);
1655     newXS("Win32::LoginName", w32_LoginName, file);
1656     newXS("Win32::NodeName", w32_NodeName, file);
1657     newXS("Win32::DomainName", w32_DomainName, file);
1658     newXS("Win32::FsType", w32_FsType, file);
1659     newXS("Win32::GetOSVersion", w32_GetOSVersion, file);
1660     newXS("Win32::IsWinNT", w32_IsWinNT, file);
1661     newXS("Win32::IsWin95", w32_IsWin95, file);
1662     newXS("Win32::FormatMessage", w32_FormatMessage, file);
1663     newXS("Win32::Spawn", w32_Spawn, file);
1664     newXS("Win32::GetTickCount", w32_GetTickCount, file);
1665     newXS("Win32::GetShortPathName", w32_GetShortPathName, file);
1666
1667     /* XXX Bloat Alert! The following Activeware preloads really
1668      * ought to be part of Win32::Sys::*, so they're not included
1669      * here.
1670      */
1671     /* LookupAccountName
1672      * LookupAccountSID
1673      * InitiateSystemShutdown
1674      * AbortSystemShutdown
1675      * ExpandEnvrironmentStrings
1676      */
1677 }
1678
1679 void
1680 Perl_win32_init(int *argcp, char ***argvp)
1681 {
1682     /* Disable floating point errors, Perl will trap the ones we
1683      * care about.  VC++ RTL defaults to switching these off
1684      * already, but the Borland RTL doesn't.  Since we don't
1685      * want to be at the vendor's whim on the default, we set
1686      * it explicitly here.
1687      */
1688 #if !defined(_ALPHA_)
1689     _control87(MCW_EM, MCW_EM);
1690 #endif
1691 }
1692
1693
1694
1695