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