[inseparable changes from match from perl-5.003_97 to perl-5.003_97a]
[perl.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) + 4, 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     if (status < 0) {
373         if (dowarn)
374             warn("Can't spawn \"%s\": %s", cmd, strerror(errno));
375         status = 255 << 8;
376     }
377     return (status);
378 }
379
380 int
381 do_spawn(char *cmd)
382 {
383     char **a;
384     char *s;
385     char **argv;
386     int status = -1;
387     BOOL needToTry = TRUE;
388     char *shell, *cmd2;
389
390     /* save an extra exec if possible */
391     shell = GetShell();
392
393     /* see if there are shell metacharacters in it */
394     if(!HasRedirection(cmd)) {
395         New(1102,argv, strlen(cmd) / 2 + 2, char*);
396         New(1103,cmd2, strlen(cmd) + 1, char);
397         strcpy(cmd2, cmd);
398         a = argv;
399         for (s = cmd2; *s;) {
400             while (*s && isspace(*s))
401                 s++;
402             if (*s)
403                 *(a++) = s;
404             while(*s && !isspace(*s))
405                 s++;
406             if(*s)
407                 *s++ = '\0';
408         }
409         *a = Nullch;
410         if(argv[0]) {
411             status = win32_spawnvpe(P_WAIT,
412                                     argv[0],
413                                     (const char* const*)argv,
414                                     (const char* const*)environ);
415             if(status != -1 || errno == 0)
416                 needToTry = FALSE;
417         }
418         Safefree(argv);
419         Safefree(cmd2);
420     }
421     if(needToTry) {
422         status = win32_spawnle(P_WAIT,
423                                shell,
424                                shell,
425                                "/x",
426                                "/c", cmd, (char*)0, environ);
427     }
428     if (status < 0) {
429         if (dowarn)
430             warn("Can't spawn \"%s\": %s", needToTry ? shell : argv[0],
431                  strerror(errno));
432         status = 255 << 8;
433     }
434     return (status);
435 }
436
437
438 #define PATHLEN 1024
439
440 /* The idea here is to read all the directory names into a string table
441  * (separated by nulls) and when one of the other dir functions is called
442  * return the pointer to the current file name.
443  */
444 DIR *
445 opendir(char *filename)
446 {
447     DIR            *p;
448     long            len;
449     long            idx;
450     char            scannamespc[PATHLEN];
451     char       *scanname = scannamespc;
452     struct stat     sbuf;
453     WIN32_FIND_DATA FindData;
454     HANDLE          fh;
455 /*  char            root[_MAX_PATH];*/
456 /*  char            volname[_MAX_PATH];*/
457 /*  DWORD           serial, maxname, flags;*/
458 /*  BOOL            downcase;*/
459 /*  char           *dummy;*/
460
461     /* check to see if filename is a directory */
462     if(stat(filename, &sbuf) < 0 || sbuf.st_mode & _S_IFDIR == 0) {
463         return NULL;
464     }
465
466     /* get the file system characteristics */
467 /*  if(GetFullPathName(filename, MAX_PATH, root, &dummy)) {
468  *      if(dummy = strchr(root, '\\'))
469  *          *++dummy = '\0';
470  *      if(GetVolumeInformation(root, volname, MAX_PATH, &serial,
471  *                              &maxname, &flags, 0, 0)) {
472  *          downcase = !(flags & FS_CASE_IS_PRESERVED);
473  *      }
474  *  }
475  *  else {
476  *      downcase = TRUE;
477  *  }
478  */
479     /* Get us a DIR structure */
480     Newz(1501, p, 1, DIR);
481     if(p == NULL)
482         return NULL;
483
484     /* Create the search pattern */
485     strcpy(scanname, filename);
486
487     if(index("/\\", *(scanname + strlen(scanname) - 1)) == NULL)
488         strcat(scanname, "/*");
489     else
490         strcat(scanname, "*");
491
492     /* do the FindFirstFile call */
493     fh = FindFirstFile(scanname, &FindData);
494     if(fh == INVALID_HANDLE_VALUE) {
495         return NULL;
496     }
497
498     /* now allocate the first part of the string table for
499      * the filenames that we find.
500      */
501     idx = strlen(FindData.cFileName)+1;
502     New(1502, p->start, idx, char);
503     if(p->start == NULL) {
504         CROAK("opendir: malloc failed!\n");
505     }
506     strcpy(p->start, FindData.cFileName);
507 /*  if(downcase)
508  *      strlwr(p->start);
509  */
510     p->nfiles++;
511
512     /* loop finding all the files that match the wildcard
513      * (which should be all of them in this directory!).
514      * the variable idx should point one past the null terminator
515      * of the previous string found.
516      */
517     while (FindNextFile(fh, &FindData)) {
518         len = strlen(FindData.cFileName);
519         /* bump the string table size by enough for the
520          * new name and it's null terminator
521          */
522         Renew(p->start, idx+len+1, char);
523         if(p->start == NULL) {
524             CROAK("opendir: malloc failed!\n");
525         }
526         strcpy(&p->start[idx], FindData.cFileName);
527 /*      if (downcase) 
528  *          strlwr(&p->start[idx]);
529  */
530                 p->nfiles++;
531                 idx += len+1;
532         }
533         FindClose(fh);
534         p->size = idx;
535         p->curr = p->start;
536         return p;
537 }
538
539
540 /* Readdir just returns the current string pointer and bumps the
541  * string pointer to the nDllExport entry.
542  */
543 struct direct *
544 readdir(DIR *dirp)
545 {
546     int         len;
547     static int  dummy = 0;
548
549     if (dirp->curr) {
550         /* first set up the structure to return */
551         len = strlen(dirp->curr);
552         strcpy(dirp->dirstr.d_name, dirp->curr);
553         dirp->dirstr.d_namlen = len;
554
555         /* Fake an inode */
556         dirp->dirstr.d_ino = dummy++;
557
558         /* Now set up for the nDllExport call to readdir */
559         dirp->curr += len + 1;
560         if (dirp->curr >= (dirp->start + dirp->size)) {
561             dirp->curr = NULL;
562         }
563
564         return &(dirp->dirstr);
565     } 
566     else
567         return NULL;
568 }
569
570 /* Telldir returns the current string pointer position */
571 long
572 telldir(DIR *dirp)
573 {
574     return (long) dirp->curr;
575 }
576
577
578 /* Seekdir moves the string pointer to a previously saved position
579  *(Saved by telldir).
580  */
581 void
582 seekdir(DIR *dirp, long loc)
583 {
584     dirp->curr = (char *)loc;
585 }
586
587 /* Rewinddir resets the string pointer to the start */
588 void
589 rewinddir(DIR *dirp)
590 {
591     dirp->curr = dirp->start;
592 }
593
594 /* free the memory allocated by opendir */
595 int
596 closedir(DIR *dirp)
597 {
598     Safefree(dirp->start);
599     Safefree(dirp);
600     return 1;
601 }
602
603
604 /*
605  * various stubs
606  */
607
608
609 /* Ownership
610  *
611  * Just pretend that everyone is a superuser. NT will let us know if
612  * we don\'t really have permission to do something.
613  */
614
615 #define ROOT_UID    ((uid_t)0)
616 #define ROOT_GID    ((gid_t)0)
617
618 uid_t
619 getuid(void)
620 {
621     return ROOT_UID;
622 }
623
624 uid_t
625 geteuid(void)
626 {
627     return ROOT_UID;
628 }
629
630 gid_t
631 getgid(void)
632 {
633     return ROOT_GID;
634 }
635
636 gid_t
637 getegid(void)
638 {
639     return ROOT_GID;
640 }
641
642 int
643 setuid(uid_t uid)
644
645     return (uid == ROOT_UID ? 0 : -1);
646 }
647
648 int
649 setgid(gid_t gid)
650 {
651     return (gid == ROOT_GID ? 0 : -1);
652 }
653
654 /*
655  * pretended kill
656  */
657 int
658 kill(int pid, int sig)
659 {
660     HANDLE hProcess= OpenProcess(PROCESS_ALL_ACCESS, TRUE, pid);
661
662     if (hProcess == NULL) {
663         CROAK("kill process failed!\n");
664     }
665     else {
666         if (!TerminateProcess(hProcess, sig))
667             CROAK("kill process failed!\n");
668         CloseHandle(hProcess);
669     }
670     return 0;
671 }
672       
673 /*
674  * File system stuff
675  */
676
677 int
678 ioctl(int i, unsigned int u, char *data)
679 {
680     CROAK("ioctl not implemented!\n");
681     return -1;
682 }
683
684 unsigned int
685 sleep(unsigned int t)
686 {
687     Sleep(t*1000);
688     return 0;
689 }
690
691
692 #undef rename
693
694 int
695 myrename(char *OldFileName, char *newname)
696 {
697     if(_access(newname, 0) != -1) {     /* file exists */
698         _unlink(newname);
699     }
700     return rename(OldFileName, newname);
701 }
702
703
704 DllExport int
705 win32_stat(const char *path, struct stat *buffer)
706 {
707     char                t[MAX_PATH]; 
708     const char  *p = path;
709     int         l = strlen(path);
710
711     if (l > 1) {
712         switch(path[l - 1]) {
713         case '\\':
714         case '/':
715             if (path[l - 2] != ':') {
716                 strncpy(t, path, l - 1);
717                 t[l - 1] = 0;
718                 p = t;
719             };
720         }
721     }
722     return stat(p, buffer);
723 }
724
725 #undef times
726 int
727 mytimes(struct tms *timebuf)
728 {
729     clock_t     t = clock();
730     timebuf->tms_utime = t;
731     timebuf->tms_stime = 0;
732     timebuf->tms_cutime = 0;
733     timebuf->tms_cstime = 0;
734
735     return 0;
736 }
737
738 #undef alarm
739 unsigned int
740 myalarm(unsigned int sec)
741 {
742     /* we warn the usuage of alarm function */
743     if (sec != 0)
744         WARN("dummy function alarm called, program might not function as expected\n");
745     return 0;
746 }
747
748 /*
749  *  redirected io subsystem for all XS modules
750  *
751  */
752
753 DllExport int *
754 win32_errno(void)
755 {
756     return (pIOSubSystem->pfnerrno());
757 }
758
759 /* the rest are the remapped stdio routines */
760 DllExport FILE *
761 win32_stderr(void)
762 {
763     return (pIOSubSystem->pfnstderr());
764 }
765
766 DllExport FILE *
767 win32_stdin(void)
768 {
769     return (pIOSubSystem->pfnstdin());
770 }
771
772 DllExport FILE *
773 win32_stdout()
774 {
775     return (pIOSubSystem->pfnstdout());
776 }
777
778 DllExport int
779 win32_ferror(FILE *fp)
780 {
781     return (pIOSubSystem->pfnferror(fp));
782 }
783
784
785 DllExport int
786 win32_feof(FILE *fp)
787 {
788     return (pIOSubSystem->pfnfeof(fp));
789 }
790
791 /*
792  * Since the errors returned by the socket error function 
793  * WSAGetLastError() are not known by the library routine strerror
794  * we have to roll our own.
795  */
796
797 __declspec(thread) char strerror_buffer[512];
798
799 DllExport char *
800 win32_strerror(int e) 
801 {
802     extern int sys_nerr;
803     DWORD source = 0;
804
805     if(e < 0 || e > sys_nerr) {
806         if(e < 0)
807             e = GetLastError();
808
809         if(FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, &source, e, 0,
810                          strerror_buffer, sizeof(strerror_buffer), NULL) == 0) 
811             strcpy(strerror_buffer, "Unknown Error");
812
813         return strerror_buffer;
814     }
815     return pIOSubSystem->pfnstrerror(e);
816 }
817
818 DllExport int
819 win32_fprintf(FILE *fp, const char *format, ...)
820 {
821     va_list marker;
822     va_start(marker, format);     /* Initialize variable arguments. */
823
824     return (pIOSubSystem->pfnvfprintf(fp, format, marker));
825 }
826
827 DllExport int
828 win32_printf(const char *format, ...)
829 {
830     va_list marker;
831     va_start(marker, format);     /* Initialize variable arguments. */
832
833     return (pIOSubSystem->pfnvprintf(format, marker));
834 }
835
836 DllExport int
837 win32_vfprintf(FILE *fp, const char *format, va_list args)
838 {
839     return (pIOSubSystem->pfnvfprintf(fp, format, args));
840 }
841
842 DllExport size_t
843 win32_fread(void *buf, size_t size, size_t count, FILE *fp)
844 {
845     return pIOSubSystem->pfnfread(buf, size, count, fp);
846 }
847
848 DllExport size_t
849 win32_fwrite(const void *buf, size_t size, size_t count, FILE *fp)
850 {
851     return pIOSubSystem->pfnfwrite(buf, size, count, fp);
852 }
853
854 DllExport FILE *
855 win32_fopen(const char *filename, const char *mode)
856 {
857     if (stricmp(filename, "/dev/null")==0)
858         return pIOSubSystem->pfnfopen("NUL", mode);
859     return pIOSubSystem->pfnfopen(filename, mode);
860 }
861
862 DllExport FILE *
863 win32_fdopen( int handle, const char *mode)
864 {
865     return pIOSubSystem->pfnfdopen(handle, mode);
866 }
867
868 DllExport FILE *
869 win32_freopen( const char *path, const char *mode, FILE *stream)
870 {
871     if (stricmp(path, "/dev/null")==0)
872         return pIOSubSystem->pfnfreopen("NUL", mode, stream);
873     return pIOSubSystem->pfnfreopen(path, mode, stream);
874 }
875
876 DllExport int
877 win32_fclose(FILE *pf)
878 {
879     return pIOSubSystem->pfnfclose(pf);
880 }
881
882 DllExport int
883 win32_fputs(const char *s,FILE *pf)
884 {
885     return pIOSubSystem->pfnfputs(s, pf);
886 }
887
888 DllExport int
889 win32_fputc(int c,FILE *pf)
890 {
891     return pIOSubSystem->pfnfputc(c,pf);
892 }
893
894 DllExport int
895 win32_ungetc(int c,FILE *pf)
896 {
897     return pIOSubSystem->pfnungetc(c,pf);
898 }
899
900 DllExport int
901 win32_getc(FILE *pf)
902 {
903     return pIOSubSystem->pfngetc(pf);
904 }
905
906 DllExport int
907 win32_fileno(FILE *pf)
908 {
909     return pIOSubSystem->pfnfileno(pf);
910 }
911
912 DllExport void
913 win32_clearerr(FILE *pf)
914 {
915     pIOSubSystem->pfnclearerr(pf);
916     return;
917 }
918
919 DllExport int
920 win32_fflush(FILE *pf)
921 {
922     return pIOSubSystem->pfnfflush(pf);
923 }
924
925 DllExport long
926 win32_ftell(FILE *pf)
927 {
928     return pIOSubSystem->pfnftell(pf);
929 }
930
931 DllExport int
932 win32_fseek(FILE *pf,long offset,int origin)
933 {
934     return pIOSubSystem->pfnfseek(pf, offset, origin);
935 }
936
937 DllExport int
938 win32_fgetpos(FILE *pf,fpos_t *p)
939 {
940     return pIOSubSystem->pfnfgetpos(pf, p);
941 }
942
943 DllExport int
944 win32_fsetpos(FILE *pf,const fpos_t *p)
945 {
946     return pIOSubSystem->pfnfsetpos(pf, p);
947 }
948
949 DllExport void
950 win32_rewind(FILE *pf)
951 {
952     pIOSubSystem->pfnrewind(pf);
953     return;
954 }
955
956 DllExport FILE*
957 win32_tmpfile(void)
958 {
959     return pIOSubSystem->pfntmpfile();
960 }
961
962 DllExport void
963 win32_abort(void)
964 {
965     pIOSubSystem->pfnabort();
966     return;
967 }
968
969 DllExport int
970 win32_fstat(int fd,struct stat *bufptr)
971 {
972     return pIOSubSystem->pfnfstat(fd,bufptr);
973 }
974
975 DllExport int
976 win32_pipe(int *pfd, unsigned int size, int mode)
977 {
978     return pIOSubSystem->pfnpipe(pfd, size, mode);
979 }
980
981 DllExport FILE*
982 win32_popen(const char *command, const char *mode)
983 {
984     return pIOSubSystem->pfnpopen(command, mode);
985 }
986
987 DllExport int
988 win32_pclose(FILE *pf)
989 {
990     return pIOSubSystem->pfnpclose(pf);
991 }
992
993 DllExport int
994 win32_setmode(int fd, int mode)
995 {
996     return pIOSubSystem->pfnsetmode(fd, mode);
997 }
998
999 DllExport int
1000 win32_open(const char *path, int flag, ...)
1001 {
1002     va_list ap;
1003     int pmode;
1004
1005     va_start(ap, flag);
1006     pmode = va_arg(ap, int);
1007     va_end(ap);
1008
1009     if (stricmp(path, "/dev/null")==0)
1010         return pIOSubSystem->pfnopen("NUL", flag, pmode);
1011     return pIOSubSystem->pfnopen(path,flag,pmode);
1012 }
1013
1014 DllExport int
1015 win32_close(int fd)
1016 {
1017     return pIOSubSystem->pfnclose(fd);
1018 }
1019
1020 DllExport int
1021 win32_dup(int fd)
1022 {
1023     return pIOSubSystem->pfndup(fd);
1024 }
1025
1026 DllExport int
1027 win32_dup2(int fd1,int fd2)
1028 {
1029     return pIOSubSystem->pfndup2(fd1,fd2);
1030 }
1031
1032 DllExport int
1033 win32_read(int fd, char *buf, unsigned int cnt)
1034 {
1035     return pIOSubSystem->pfnread(fd, buf, cnt);
1036 }
1037
1038 DllExport int
1039 win32_write(int fd, const char *buf, unsigned int cnt)
1040 {
1041     return pIOSubSystem->pfnwrite(fd, buf, cnt);
1042 }
1043
1044 DllExport int
1045 win32_mkdir(const char *dir, int mode)
1046 {
1047     return pIOSubSystem->pfnmkdir(dir); /* just ignore mode */
1048 }
1049 DllExport int
1050 win32_rmdir(const char *dir)
1051 {
1052     return pIOSubSystem->pfnrmdir(dir);
1053 }
1054 DllExport int
1055 win32_chdir(const char *dir)
1056 {
1057     return pIOSubSystem->pfnchdir(dir);
1058 }
1059 DllExport int
1060 win32_spawnvpe(int mode, const char *cmdname,
1061                const char *const *argv, const char *const *envp)
1062 {
1063     return pIOSubSystem->pfnspawnvpe(mode, cmdname, argv, envp);
1064 }
1065
1066 DllExport int
1067 win32_spawnle(int mode, const char *cmdname, const char *arglist,...)
1068 {
1069     const char* const*  envp;
1070     const char* const*  argp;
1071
1072     argp = &arglist;
1073     while (*argp++) ;
1074     envp = (const char* const*)*argp;
1075
1076     return pIOSubSystem->pfnspawnvpe(mode, cmdname, &arglist, envp);
1077 }
1078
1079 int
1080 stolen_open_osfhandle(long handle, int flags)
1081 {
1082     return pIOSubSystem->pfn_open_osfhandle(handle, flags);
1083 }
1084
1085 long
1086 stolen_get_osfhandle(int fd)
1087 {
1088     return pIOSubSystem->pfn_get_osfhandle(fd);
1089 }