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