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