3d226ce998f73f1ed881ccdec762b7d7ede12491
[p5sagit/p5-mst-13.2.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 <fcntl.h>
26 #include <sys/stat.h>
27 #include <assert.h>
28 #include <string.h>
29 #include <stdarg.h>
30
31 #define CROAK croak
32 #define WARN warn
33
34 #define EXECF_EXEC 1
35 #define EXECF_SPAWN 2
36 #define EXECF_SPAWN_NOWAIT 3
37
38 static DWORD IdOS(void);
39
40 extern WIN32_IOSUBSYSTEM        win32stdio;
41 static PWIN32_IOSUBSYSTEM pIOSubSystem = &win32stdio;
42
43 BOOL  ProbeEnv = FALSE;
44 DWORD Win32System = (DWORD)-1;
45 char  szShellPath[MAX_PATH+1];
46 char  szPerlLibRoot[MAX_PATH+1];
47 HANDLE PerlDllHandle = INVALID_HANDLE_VALUE;
48
49 static int do_spawn2(char *cmd, int exectype);
50
51 int 
52 IsWin95(void) {
53     return (IdOS() == VER_PLATFORM_WIN32_WINDOWS);
54 }
55
56 int
57 IsWinNT(void) {
58     return (IdOS() == VER_PLATFORM_WIN32_NT);
59 }
60
61 void *
62 SetIOSubSystem(void *p)
63 {
64     PWIN32_IOSUBSYSTEM old = pIOSubSystem;
65     if (p) {
66         PWIN32_IOSUBSYSTEM pio = (PWIN32_IOSUBSYSTEM)p;
67         if (pio->signature_begin == 12345678L
68             && pio->signature_end == 87654321L) {
69             pIOSubSystem = pio;
70         }
71     }
72     else {
73         pIOSubSystem = &win32stdio;
74     }
75     return old;
76 }
77
78 char *
79 win32PerlLibPath(void)
80 {
81     char *end;
82     GetModuleFileName((PerlDllHandle == INVALID_HANDLE_VALUE) 
83                       ? GetModuleHandle(NULL)
84                       : PerlDllHandle,
85                       szPerlLibRoot, 
86                       sizeof(szPerlLibRoot));
87
88     *(end = strrchr(szPerlLibRoot, '\\')) = '\0';
89     if (stricmp(end-4,"\\bin") == 0)
90      end -= 4;
91     strcpy(end,"\\lib");
92     return (szPerlLibRoot);
93 }
94
95 char *
96 win32SiteLibPath(void)
97 {
98     static char szPerlSiteLib[MAXPATH+1];
99     strcpy(szPerlSiteLib, win32PerlLibPath());
100     strcat(szPerlSiteLib, "\\site");
101     return (szPerlSiteLib);
102 }
103
104 BOOL
105 HasRedirection(char *ptr)
106 {
107     int inquote = 0;
108     char quote = '\0';
109
110     /*
111      * Scan string looking for redirection (< or >) or pipe
112      * characters (|) that are not in a quoted string
113      */
114     while(*ptr) {
115         switch(*ptr) {
116         case '\'':
117         case '\"':
118             if(inquote) {
119                 if(quote == *ptr) {
120                     inquote = 0;
121                     quote = '\0';
122                 }
123             }
124             else {
125                 quote = *ptr;
126                 inquote++;
127             }
128             break;
129         case '>':
130         case '<':
131         case '|':
132             if(!inquote)
133                 return TRUE;
134         default:
135             break;
136         }
137         ++ptr;
138     }
139     return FALSE;
140 }
141
142 /* since the current process environment is being updated in util.c
143  * the library functions will get the correct environment
144  */
145 PerlIO *
146 my_popen(char *cmd, char *mode)
147 {
148 #ifdef FIXCMD
149 #define fixcmd(x)       {                                       \
150                             char *pspace = strchr((x),' ');     \
151                             if (pspace) {                       \
152                                 char *p = (x);                  \
153                                 while (p < pspace) {            \
154                                     if (*p == '/')              \
155                                         *p = '\\';              \
156                                     p++;                        \
157                                 }                               \
158                             }                                   \
159                         }
160 #else
161 #define fixcmd(x)
162 #endif
163
164 #if 1
165 /* was #ifndef PERLDLL, but the #else stuff doesn't work on NT
166  * GSAR 97/03/13
167  */
168     fixcmd(cmd);
169 #ifdef __BORLANDC__ /* workaround a Borland stdio bug */
170     win32_fflush(stdout);
171     win32_fflush(stderr);
172 #endif
173     return win32_popen(cmd, mode);
174 #else
175 /*
176  * There seems to be some problems for the _popen call in a DLL
177  * this trick at the moment seems to work but it is never test
178  * on NT yet
179  *
180  */ 
181 #       ifdef __cplusplus
182 #define EXT_C_FUNC      extern "C"
183 #       else
184 #define EXT_C_FUNC      extern
185 #       endif
186
187     EXT_C_FUNC int __cdecl _set_osfhnd(int fh, long value);
188     EXT_C_FUNC void __cdecl _lock_fhandle(int);
189     EXT_C_FUNC void __cdecl _unlock_fhandle(int);
190
191     BOOL        fSuccess;
192     PerlIO      *pf;            /* to store the _popen return value */
193     int         tm = 0;         /* flag indicating tDllExport or binary mode */
194     int         fhNeeded, fhInherited, fhDup;
195     int         ineeded, iinherited;
196     DWORD       dwDup;
197     int         phdls[2];       /* I/O handles for pipe */
198     HANDLE      hPIn, hPOut, hPErr,
199                 hSaveStdin, hSaveStdout, hSaveStderr,
200                 hPNeeded, hPInherited, hPDuped;
201      
202     /* first check for errors in the arguments */
203     if ( (cmd == NULL) || (mode == NULL)
204          || ((*mode != 'w') && (*mode != _T('r'))) )
205         goto error1;
206
207     if ( *(mode + 1) == _T('t') )
208         tm = O_TEXT;
209     else if ( *(mode + 1) == _T('b') )
210         tm = O_BINARY;
211     else
212         tm = (*mode == 'w' ? O_BINARY : O_TEXT);
213
214
215     fixcmd(cmd);
216     if (&win32stdio != pIOSubSystem)
217         return win32_popen(cmd, mode);
218
219 #ifdef EFG
220     if ( _pipe( phdls, 1024, tm ) == -1 )
221 #else
222     if ( win32_pipe( phdls, 1024, tm ) == -1 )
223 #endif
224         goto error1;
225
226     /* save the current situation */
227     hSaveStdin = GetStdHandle(STD_INPUT_HANDLE); 
228     hSaveStdout = GetStdHandle(STD_OUTPUT_HANDLE); 
229     hSaveStderr = GetStdHandle(STD_ERROR_HANDLE); 
230
231     if (*mode == _T('w')) {
232         ineeded = 1;
233         dwDup   = STD_INPUT_HANDLE;
234         iinherited = 0;
235     }
236     else {
237         ineeded = 0;
238         dwDup   = STD_OUTPUT_HANDLE;
239         iinherited = 1;
240     }
241
242     fhNeeded = phdls[ineeded];
243     fhInherited = phdls[iinherited];
244
245     fSuccess = DuplicateHandle(GetCurrentProcess(), 
246                                (HANDLE) stolen_get_osfhandle(fhNeeded), 
247                                GetCurrentProcess(), 
248                                &hPNeeded, 
249                                0, 
250                                FALSE,       /* not inherited */ 
251                                DUPLICATE_SAME_ACCESS); 
252
253     if (!fSuccess)
254         goto error2;
255
256     fhDup = stolen_open_osfhandle((long) hPNeeded, tm);
257     win32_dup2(fhDup, fhNeeded);
258     win32_close(fhDup);
259
260 #ifdef AAA
261     /* Close the Out pipe, child won't need it */
262     hPDuped = (HANDLE) stolen_get_osfhandle(fhNeeded);
263
264     _lock_fhandle(fhNeeded);
265     _set_osfhnd(fhNeeded, (long)hPNeeded); /* put in ours duplicated one */
266     _unlock_fhandle(fhNeeded);
267
268     CloseHandle(hPDuped);       /* close the handle first */
269 #endif
270
271     if (!SetStdHandle(dwDup, (HANDLE) stolen_get_osfhandle(fhInherited)))
272         goto error2;
273
274     /*
275      * make sure the child see the same stderr as the calling program
276      */
277     if (!SetStdHandle(STD_ERROR_HANDLE,
278                       (HANDLE)stolen_get_osfhandle(win32_fileno(win32_stderr()))))
279         goto error2;
280
281     pf = win32_popen(cmd, mode);        /* ask _popen to do the job */
282
283     /* restore to where we were */
284     SetStdHandle(STD_INPUT_HANDLE, hSaveStdin);
285     SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdout);
286     SetStdHandle(STD_ERROR_HANDLE, hSaveStderr);
287
288     /* we don't need it any more, that's for the child */
289     win32_close(fhInherited);
290
291     if (NULL == pf) {
292         /* something wrong */
293         win32_close(fhNeeded);
294         goto error1;
295     }
296     else {
297         /*
298          * here we steal the file handle in pf and stuff ours in
299          */
300         win32_dup2(fhNeeded, win32_fileno(pf));
301         win32_close(fhNeeded);
302     }
303     return (pf);
304
305 error2:
306     win32_close(fhNeeded);
307     win32_close(fhInherited);
308
309 error1:
310     return (NULL);
311
312 #endif
313 }
314
315 long
316 my_pclose(PerlIO *fp)
317 {
318     return win32_pclose(fp);
319 }
320
321 static DWORD
322 IdOS(void)
323 {
324     static OSVERSIONINFO osver;
325
326     if (osver.dwPlatformId != Win32System) {
327         memset(&osver, 0, sizeof(OSVERSIONINFO));
328         osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
329         GetVersionEx(&osver);
330         Win32System = osver.dwPlatformId;
331     }
332     return (Win32System);
333 }
334
335 static char *
336 GetShell(void)
337 {
338     if (!ProbeEnv) {
339         char* defaultshell = (IsWinNT() ? "cmd.exe" : "command.com");
340         /* we don't use COMSPEC here for two reasons:
341          *  1. the same reason perl on UNIX doesn't use SHELL--rampant and
342          *     uncontrolled unportability of the ensuing scripts.
343          *  2. PERL5SHELL could be set to a shell that may not be fit for
344          *     interactive use (which is what most programs look in COMSPEC
345          *     for).
346          */
347         char *usershell = getenv("PERL5SHELL");  
348
349         ProbeEnv = TRUE;
350         strcpy(szShellPath, usershell ? usershell : defaultshell);
351     }
352     return szShellPath;
353 }
354
355 int
356 do_aspawn(void* really, void** mark, void** arglast)
357 {
358     char **argv;
359     char *strPtr;
360     char *cmd;
361     int status;
362     unsigned int length;
363     int index = 0;
364     SV *sv = (SV*)really;
365     SV** pSv = (SV**)mark;
366
367     New(1310, argv, (arglast - mark) + 4, char*);
368
369     if(sv != Nullsv) {
370         cmd = SvPV(sv, length);
371     }
372     else {
373         argv[index++] = cmd = GetShell();
374         argv[index++] = "/x";   /* always enable command extensions */
375         argv[index++] = "/c";
376     }
377
378     while(++pSv <= (SV**)arglast) {
379         sv = *pSv;
380         strPtr = SvPV(sv, length);
381         if(strPtr != NULL && *strPtr != '\0')
382             argv[index++] = strPtr;
383     }
384     argv[index++] = 0;
385    
386     status = win32_spawnvp(P_WAIT, cmd, (const char* const*)argv);
387
388     Safefree(argv);
389
390     if (status < 0) {
391         if (dowarn)
392             warn("Can't spawn \"%s\": %s", cmd, strerror(errno));
393         status = 255 << 8;
394     }
395     return (status);
396 }
397
398 int
399 do_spawn2(char *cmd, int exectype)
400 {
401     char **a;
402     char *s;
403     char **argv;
404     int status = -1;
405     BOOL needToTry = TRUE;
406     char *shell, *cmd2;
407
408     /* save an extra exec if possible */
409     shell = GetShell();
410
411     /* see if there are shell metacharacters in it */
412     if(!HasRedirection(cmd)) {
413         New(1301,argv, strlen(cmd) / 2 + 2, char*);
414         New(1302,cmd2, strlen(cmd) + 1, char);
415         strcpy(cmd2, cmd);
416         a = argv;
417         for (s = cmd2; *s;) {
418             while (*s && isspace(*s))
419                 s++;
420             if (*s)
421                 *(a++) = s;
422             while(*s && !isspace(*s))
423                 s++;
424             if(*s)
425                 *s++ = '\0';
426         }
427         *a = Nullch;
428         if(argv[0]) {
429             switch (exectype) {
430             case EXECF_SPAWN:
431                 status = win32_spawnvp(P_WAIT, argv[0],
432                                        (const char* const*)argv);
433                 break;
434             case EXECF_SPAWN_NOWAIT:
435                 status = win32_spawnvp(P_NOWAIT, argv[0],
436                                        (const char* const*)argv);
437                 break;
438             case EXECF_EXEC:
439                 status = win32_execvp(argv[0], (const char* const*)argv);
440                 break;
441             }
442             if(status != -1 || errno == 0)
443                 needToTry = FALSE;
444         }
445         Safefree(argv);
446         Safefree(cmd2);
447     }
448     if(needToTry) {
449         char *argv[5];
450         argv[0] = shell; argv[1] = "/x"; argv[2] = "/c";
451         argv[3] = cmd; argv[4] = Nullch;
452         switch (exectype) {
453         case EXECF_SPAWN:
454             status = win32_spawnvp(P_WAIT, argv[0],
455                                    (const char* const*)argv);
456             break;
457         case EXECF_SPAWN_NOWAIT:
458             status = win32_spawnvp(P_NOWAIT, argv[0],
459                                    (const char* const*)argv);
460             break;
461         case EXECF_EXEC:
462             status = win32_execvp(argv[0], (const char* const*)argv);
463             break;
464         }
465     }
466     if (status < 0) {
467         if (dowarn)
468             warn("Can't %s \"%s\": %s",
469                  (exectype == EXECF_EXEC ? "exec" : "spawn"),
470                  needToTry ? shell : argv[0],
471                  strerror(errno));
472         status = 255 << 8;
473     }
474     return (status);
475 }
476
477 int
478 do_spawn(char *cmd)
479 {
480     return do_spawn2(cmd, EXECF_SPAWN);
481 }
482
483 bool
484 do_exec(char *cmd)
485 {
486     do_spawn2(cmd, EXECF_EXEC);
487     return FALSE;
488 }
489
490
491 #define PATHLEN 1024
492
493 /* The idea here is to read all the directory names into a string table
494  * (separated by nulls) and when one of the other dir functions is called
495  * return the pointer to the current file name.
496  */
497 DIR *
498 opendir(char *filename)
499 {
500     DIR            *p;
501     long            len;
502     long            idx;
503     char            scannamespc[PATHLEN];
504     char       *scanname = scannamespc;
505     struct stat     sbuf;
506     WIN32_FIND_DATA FindData;
507     HANDLE          fh;
508 /*  char            root[_MAX_PATH];*/
509 /*  char            volname[_MAX_PATH];*/
510 /*  DWORD           serial, maxname, flags;*/
511 /*  BOOL            downcase;*/
512 /*  char           *dummy;*/
513
514     /* check to see if filename is a directory */
515     if(stat(filename, &sbuf) < 0 || sbuf.st_mode & S_IFDIR == 0) {
516         return NULL;
517     }
518
519     /* get the file system characteristics */
520 /*  if(GetFullPathName(filename, MAX_PATH, root, &dummy)) {
521  *      if(dummy = strchr(root, '\\'))
522  *          *++dummy = '\0';
523  *      if(GetVolumeInformation(root, volname, MAX_PATH, &serial,
524  *                              &maxname, &flags, 0, 0)) {
525  *          downcase = !(flags & FS_CASE_IS_PRESERVED);
526  *      }
527  *  }
528  *  else {
529  *      downcase = TRUE;
530  *  }
531  */
532     /* Get us a DIR structure */
533     Newz(1303, p, 1, DIR);
534     if(p == NULL)
535         return NULL;
536
537     /* Create the search pattern */
538     strcpy(scanname, filename);
539
540     if(index("/\\", *(scanname + strlen(scanname) - 1)) == NULL)
541         strcat(scanname, "/*");
542     else
543         strcat(scanname, "*");
544
545     /* do the FindFirstFile call */
546     fh = FindFirstFile(scanname, &FindData);
547     if(fh == INVALID_HANDLE_VALUE) {
548         return NULL;
549     }
550
551     /* now allocate the first part of the string table for
552      * the filenames that we find.
553      */
554     idx = strlen(FindData.cFileName)+1;
555     New(1304, p->start, idx, char);
556     if(p->start == NULL) {
557         CROAK("opendir: malloc failed!\n");
558     }
559     strcpy(p->start, FindData.cFileName);
560 /*  if(downcase)
561  *      strlwr(p->start);
562  */
563     p->nfiles++;
564
565     /* loop finding all the files that match the wildcard
566      * (which should be all of them in this directory!).
567      * the variable idx should point one past the null terminator
568      * of the previous string found.
569      */
570     while (FindNextFile(fh, &FindData)) {
571         len = strlen(FindData.cFileName);
572         /* bump the string table size by enough for the
573          * new name and it's null terminator
574          */
575         Renew(p->start, idx+len+1, char);
576         if(p->start == NULL) {
577             CROAK("opendir: malloc failed!\n");
578         }
579         strcpy(&p->start[idx], FindData.cFileName);
580 /*      if (downcase) 
581  *          strlwr(&p->start[idx]);
582  */
583                 p->nfiles++;
584                 idx += len+1;
585         }
586         FindClose(fh);
587         p->size = idx;
588         p->curr = p->start;
589         return p;
590 }
591
592
593 /* Readdir just returns the current string pointer and bumps the
594  * string pointer to the nDllExport entry.
595  */
596 struct direct *
597 readdir(DIR *dirp)
598 {
599     int         len;
600     static int  dummy = 0;
601
602     if (dirp->curr) {
603         /* first set up the structure to return */
604         len = strlen(dirp->curr);
605         strcpy(dirp->dirstr.d_name, dirp->curr);
606         dirp->dirstr.d_namlen = len;
607
608         /* Fake an inode */
609         dirp->dirstr.d_ino = dummy++;
610
611         /* Now set up for the nDllExport call to readdir */
612         dirp->curr += len + 1;
613         if (dirp->curr >= (dirp->start + dirp->size)) {
614             dirp->curr = NULL;
615         }
616
617         return &(dirp->dirstr);
618     } 
619     else
620         return NULL;
621 }
622
623 /* Telldir returns the current string pointer position */
624 long
625 telldir(DIR *dirp)
626 {
627     return (long) dirp->curr;
628 }
629
630
631 /* Seekdir moves the string pointer to a previously saved position
632  *(Saved by telldir).
633  */
634 void
635 seekdir(DIR *dirp, long loc)
636 {
637     dirp->curr = (char *)loc;
638 }
639
640 /* Rewinddir resets the string pointer to the start */
641 void
642 rewinddir(DIR *dirp)
643 {
644     dirp->curr = dirp->start;
645 }
646
647 /* free the memory allocated by opendir */
648 int
649 closedir(DIR *dirp)
650 {
651     Safefree(dirp->start);
652     Safefree(dirp);
653     return 1;
654 }
655
656
657 /*
658  * various stubs
659  */
660
661
662 /* Ownership
663  *
664  * Just pretend that everyone is a superuser. NT will let us know if
665  * we don\'t really have permission to do something.
666  */
667
668 #define ROOT_UID    ((uid_t)0)
669 #define ROOT_GID    ((gid_t)0)
670
671 uid_t
672 getuid(void)
673 {
674     return ROOT_UID;
675 }
676
677 uid_t
678 geteuid(void)
679 {
680     return ROOT_UID;
681 }
682
683 gid_t
684 getgid(void)
685 {
686     return ROOT_GID;
687 }
688
689 gid_t
690 getegid(void)
691 {
692     return ROOT_GID;
693 }
694
695 int
696 setuid(uid_t uid)
697
698     return (uid == ROOT_UID ? 0 : -1);
699 }
700
701 int
702 setgid(gid_t gid)
703 {
704     return (gid == ROOT_GID ? 0 : -1);
705 }
706
707 /*
708  * pretended kill
709  */
710 int
711 kill(int pid, int sig)
712 {
713     HANDLE hProcess= OpenProcess(PROCESS_ALL_ACCESS, TRUE, pid);
714
715     if (hProcess == NULL) {
716         CROAK("kill process failed!\n");
717     }
718     else {
719         if (!TerminateProcess(hProcess, sig))
720             CROAK("kill process failed!\n");
721         CloseHandle(hProcess);
722     }
723     return 0;
724 }
725       
726 /*
727  * File system stuff
728  */
729
730 #if 0
731 int
732 ioctl(int i, unsigned int u, char *data)
733 {
734     CROAK("ioctl not implemented!\n");
735     return -1;
736 }
737 #endif
738
739 unsigned int
740 sleep(unsigned int t)
741 {
742     Sleep(t*1000);
743     return 0;
744 }
745
746
747 #undef rename
748
749 int
750 myrename(char *OldFileName, char *newname)
751 {
752     if(_access(newname, 0) != -1) {     /* file exists */
753         _unlink(newname);
754     }
755     return rename(OldFileName, newname);
756 }
757
758
759 DllExport int
760 win32_stat(const char *path, struct stat *buffer)
761 {
762     char                t[MAX_PATH]; 
763     const char  *p = path;
764     int         l = strlen(path);
765
766     if (l > 1) {
767         switch(path[l - 1]) {
768         case '\\':
769         case '/':
770             if (path[l - 2] != ':') {
771                 strncpy(t, path, l - 1);
772                 t[l - 1] = 0;
773                 p = t;
774             };
775         }
776     }
777     return stat(p, buffer);
778 }
779
780 #undef times
781 int
782 mytimes(struct tms *timebuf)
783 {
784     clock_t     t = clock();
785     timebuf->tms_utime = t;
786     timebuf->tms_stime = 0;
787     timebuf->tms_cutime = 0;
788     timebuf->tms_cstime = 0;
789
790     return 0;
791 }
792
793 #undef alarm
794 unsigned int
795 myalarm(unsigned int sec)
796 {
797     /* we warn the usuage of alarm function */
798     if (sec != 0)
799         WARN("dummy function alarm called, program might not function as expected\n");
800     return 0;
801 }
802
803 /*
804  *  redirected io subsystem for all XS modules
805  *
806  */
807
808 DllExport int *
809 win32_errno(void)
810 {
811     return (pIOSubSystem->pfnerrno());
812 }
813
814 DllExport char ***
815 win32_environ(void)
816 {
817     return (pIOSubSystem->pfnenviron());
818 }
819
820 /* the rest are the remapped stdio routines */
821 DllExport FILE *
822 win32_stderr(void)
823 {
824     return (pIOSubSystem->pfnstderr());
825 }
826
827 DllExport FILE *
828 win32_stdin(void)
829 {
830     return (pIOSubSystem->pfnstdin());
831 }
832
833 DllExport FILE *
834 win32_stdout()
835 {
836     return (pIOSubSystem->pfnstdout());
837 }
838
839 DllExport int
840 win32_ferror(FILE *fp)
841 {
842     return (pIOSubSystem->pfnferror(fp));
843 }
844
845
846 DllExport int
847 win32_feof(FILE *fp)
848 {
849     return (pIOSubSystem->pfnfeof(fp));
850 }
851
852 /*
853  * Since the errors returned by the socket error function 
854  * WSAGetLastError() are not known by the library routine strerror
855  * we have to roll our own.
856  */
857
858 __declspec(thread) char strerror_buffer[512];
859
860 DllExport char *
861 win32_strerror(int e) 
862 {
863 #ifndef __BORLANDC__            /* Borland intolerance */
864     extern int sys_nerr;
865 #endif
866     DWORD source = 0;
867
868     if(e < 0 || e > sys_nerr) {
869         if(e < 0)
870             e = GetLastError();
871
872         if(FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, &source, e, 0,
873                          strerror_buffer, sizeof(strerror_buffer), NULL) == 0) 
874             strcpy(strerror_buffer, "Unknown Error");
875
876         return strerror_buffer;
877     }
878     return pIOSubSystem->pfnstrerror(e);
879 }
880
881 DllExport int
882 win32_fprintf(FILE *fp, const char *format, ...)
883 {
884     va_list marker;
885     va_start(marker, format);     /* Initialize variable arguments. */
886
887     return (pIOSubSystem->pfnvfprintf(fp, format, marker));
888 }
889
890 DllExport int
891 win32_printf(const char *format, ...)
892 {
893     va_list marker;
894     va_start(marker, format);     /* Initialize variable arguments. */
895
896     return (pIOSubSystem->pfnvprintf(format, marker));
897 }
898
899 DllExport int
900 win32_vfprintf(FILE *fp, const char *format, va_list args)
901 {
902     return (pIOSubSystem->pfnvfprintf(fp, format, args));
903 }
904
905 DllExport int
906 win32_vprintf(const char *format, va_list args)
907 {
908     return (pIOSubSystem->pfnvprintf(format, args));
909 }
910
911 DllExport size_t
912 win32_fread(void *buf, size_t size, size_t count, FILE *fp)
913 {
914     return pIOSubSystem->pfnfread(buf, size, count, fp);
915 }
916
917 DllExport size_t
918 win32_fwrite(const void *buf, size_t size, size_t count, FILE *fp)
919 {
920     return pIOSubSystem->pfnfwrite(buf, size, count, fp);
921 }
922
923 DllExport FILE *
924 win32_fopen(const char *filename, const char *mode)
925 {
926     if (stricmp(filename, "/dev/null")==0)
927         return pIOSubSystem->pfnfopen("NUL", mode);
928     return pIOSubSystem->pfnfopen(filename, mode);
929 }
930
931 DllExport FILE *
932 win32_fdopen( int handle, const char *mode)
933 {
934     return pIOSubSystem->pfnfdopen(handle, mode);
935 }
936
937 DllExport FILE *
938 win32_freopen( const char *path, const char *mode, FILE *stream)
939 {
940     if (stricmp(path, "/dev/null")==0)
941         return pIOSubSystem->pfnfreopen("NUL", mode, stream);
942     return pIOSubSystem->pfnfreopen(path, mode, stream);
943 }
944
945 DllExport int
946 win32_fclose(FILE *pf)
947 {
948     return pIOSubSystem->pfnfclose(pf);
949 }
950
951 DllExport int
952 win32_fputs(const char *s,FILE *pf)
953 {
954     return pIOSubSystem->pfnfputs(s, pf);
955 }
956
957 DllExport int
958 win32_fputc(int c,FILE *pf)
959 {
960     return pIOSubSystem->pfnfputc(c,pf);
961 }
962
963 DllExport int
964 win32_ungetc(int c,FILE *pf)
965 {
966     return pIOSubSystem->pfnungetc(c,pf);
967 }
968
969 DllExport int
970 win32_getc(FILE *pf)
971 {
972     return pIOSubSystem->pfngetc(pf);
973 }
974
975 DllExport int
976 win32_fileno(FILE *pf)
977 {
978     return pIOSubSystem->pfnfileno(pf);
979 }
980
981 DllExport void
982 win32_clearerr(FILE *pf)
983 {
984     pIOSubSystem->pfnclearerr(pf);
985     return;
986 }
987
988 DllExport int
989 win32_fflush(FILE *pf)
990 {
991     return pIOSubSystem->pfnfflush(pf);
992 }
993
994 DllExport long
995 win32_ftell(FILE *pf)
996 {
997     return pIOSubSystem->pfnftell(pf);
998 }
999
1000 DllExport int
1001 win32_fseek(FILE *pf,long offset,int origin)
1002 {
1003     return pIOSubSystem->pfnfseek(pf, offset, origin);
1004 }
1005
1006 DllExport int
1007 win32_fgetpos(FILE *pf,fpos_t *p)
1008 {
1009     return pIOSubSystem->pfnfgetpos(pf, p);
1010 }
1011
1012 DllExport int
1013 win32_fsetpos(FILE *pf,const fpos_t *p)
1014 {
1015     return pIOSubSystem->pfnfsetpos(pf, p);
1016 }
1017
1018 DllExport void
1019 win32_rewind(FILE *pf)
1020 {
1021     pIOSubSystem->pfnrewind(pf);
1022     return;
1023 }
1024
1025 DllExport FILE*
1026 win32_tmpfile(void)
1027 {
1028     return pIOSubSystem->pfntmpfile();
1029 }
1030
1031 DllExport void
1032 win32_abort(void)
1033 {
1034     pIOSubSystem->pfnabort();
1035     return;
1036 }
1037
1038 DllExport int
1039 win32_fstat(int fd,struct stat *bufptr)
1040 {
1041     return pIOSubSystem->pfnfstat(fd,bufptr);
1042 }
1043
1044 DllExport int
1045 win32_pipe(int *pfd, unsigned int size, int mode)
1046 {
1047     return pIOSubSystem->pfnpipe(pfd, size, mode);
1048 }
1049
1050 DllExport FILE*
1051 win32_popen(const char *command, const char *mode)
1052 {
1053     return pIOSubSystem->pfnpopen(command, mode);
1054 }
1055
1056 DllExport int
1057 win32_pclose(FILE *pf)
1058 {
1059     return pIOSubSystem->pfnpclose(pf);
1060 }
1061
1062 DllExport int
1063 win32_setmode(int fd, int mode)
1064 {
1065     return pIOSubSystem->pfnsetmode(fd, mode);
1066 }
1067
1068 DllExport long
1069 win32_lseek(int fd, long offset, int origin)
1070 {
1071     return pIOSubSystem->pfnlseek(fd, offset, origin);
1072 }
1073
1074 DllExport long
1075 win32_tell(int fd)
1076 {
1077     return pIOSubSystem->pfntell(fd);
1078 }
1079
1080 DllExport int
1081 win32_open(const char *path, int flag, ...)
1082 {
1083     va_list ap;
1084     int pmode;
1085
1086     va_start(ap, flag);
1087     pmode = va_arg(ap, int);
1088     va_end(ap);
1089
1090     if (stricmp(path, "/dev/null")==0)
1091         return pIOSubSystem->pfnopen("NUL", flag, pmode);
1092     return pIOSubSystem->pfnopen(path,flag,pmode);
1093 }
1094
1095 DllExport int
1096 win32_close(int fd)
1097 {
1098     return pIOSubSystem->pfnclose(fd);
1099 }
1100
1101 DllExport int
1102 win32_eof(int fd)
1103 {
1104     return pIOSubSystem->pfneof(fd);
1105 }
1106
1107 DllExport int
1108 win32_dup(int fd)
1109 {
1110     return pIOSubSystem->pfndup(fd);
1111 }
1112
1113 DllExport int
1114 win32_dup2(int fd1,int fd2)
1115 {
1116     return pIOSubSystem->pfndup2(fd1,fd2);
1117 }
1118
1119 DllExport int
1120 win32_read(int fd, void *buf, unsigned int cnt)
1121 {
1122     return pIOSubSystem->pfnread(fd, buf, cnt);
1123 }
1124
1125 DllExport int
1126 win32_write(int fd, const void *buf, unsigned int cnt)
1127 {
1128     return pIOSubSystem->pfnwrite(fd, buf, cnt);
1129 }
1130
1131 DllExport int
1132 win32_mkdir(const char *dir, int mode)
1133 {
1134     return pIOSubSystem->pfnmkdir(dir); /* just ignore mode */
1135 }
1136
1137 DllExport int
1138 win32_rmdir(const char *dir)
1139 {
1140     return pIOSubSystem->pfnrmdir(dir);
1141 }
1142
1143 DllExport int
1144 win32_chdir(const char *dir)
1145 {
1146     return pIOSubSystem->pfnchdir(dir);
1147 }
1148
1149 DllExport int
1150 win32_spawnvp(int mode, const char *cmdname, const char *const *argv)
1151 {
1152     return pIOSubSystem->pfnspawnvp(mode, cmdname, argv);
1153 }
1154
1155 DllExport int
1156 win32_execvp(const char *cmdname, const char *const *argv)
1157 {
1158     return pIOSubSystem->pfnexecvp(cmdname, argv);
1159 }
1160
1161 int
1162 stolen_open_osfhandle(long handle, int flags)
1163 {
1164     return pIOSubSystem->pfn_open_osfhandle(handle, flags);
1165 }
1166
1167 long
1168 stolen_get_osfhandle(int fd)
1169 {
1170     return pIOSubSystem->pfn_get_osfhandle(fd);
1171 }
1172
1173 /*
1174  * Extras.
1175  */
1176
1177 DllExport int
1178 win32_flock(int fd, int oper)
1179 {
1180     if (!IsWinNT()) {
1181         croak("flock() unimplemented on this platform");
1182         return -1;
1183     }
1184     return pIOSubSystem->pfnflock(fd, oper);
1185 }
1186