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