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