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