e7791d264a88678365244074a3ad0a4daab6b31e
[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 "XSUB.h"
26 #include <fcntl.h>
27 #include <sys/stat.h>
28 #include <assert.h>
29 #include <string.h>
30 #include <stdarg.h>
31 #include <float.h>
32
33 #define CROAK croak
34 #define WARN warn
35
36 #define EXECF_EXEC 1
37 #define EXECF_SPAWN 2
38 #define EXECF_SPAWN_NOWAIT 3
39
40 static DWORD IdOS(void);
41
42 extern WIN32_IOSUBSYSTEM        win32stdio;
43 static PWIN32_IOSUBSYSTEM pIOSubSystem = &win32stdio;
44
45 BOOL  ProbeEnv = FALSE;
46 DWORD Win32System = (DWORD)-1;
47 char  szShellPath[MAX_PATH+1];
48 char  szPerlLibRoot[MAX_PATH+1];
49 HANDLE PerlDllHandle = INVALID_HANDLE_VALUE;
50
51 static int do_spawn2(char *cmd, int exectype);
52
53 int 
54 IsWin95(void) {
55     return (IdOS() == VER_PLATFORM_WIN32_WINDOWS);
56 }
57
58 int
59 IsWinNT(void) {
60     return (IdOS() == VER_PLATFORM_WIN32_NT);
61 }
62
63 DllExport PWIN32_IOSUBSYSTEM
64 SetIOSubSystem(void *p)
65 {
66     PWIN32_IOSUBSYSTEM old = pIOSubSystem;
67     if (p) {
68         PWIN32_IOSUBSYSTEM pio = (PWIN32_IOSUBSYSTEM)p;
69         if (pio->signature_begin == 12345678L
70             && pio->signature_end == 87654321L) {
71             pIOSubSystem = pio;
72         }
73     }
74     else {
75         pIOSubSystem = &win32stdio;
76     }
77     return old;
78 }
79
80 DllExport PWIN32_IOSUBSYSTEM
81 GetIOSubSystem(void)
82 {
83     return pIOSubSystem;
84 }
85
86 char *
87 win32PerlLibPath(void)
88 {
89     char *end;
90     GetModuleFileName((PerlDllHandle == INVALID_HANDLE_VALUE) 
91                       ? GetModuleHandle(NULL)
92                       : PerlDllHandle,
93                       szPerlLibRoot, 
94                       sizeof(szPerlLibRoot));
95
96     *(end = strrchr(szPerlLibRoot, '\\')) = '\0';
97     if (stricmp(end-4,"\\bin") == 0)
98      end -= 4;
99     strcpy(end,"\\lib");
100     return (szPerlLibRoot);
101 }
102
103 char *
104 win32SiteLibPath(void)
105 {
106     static char szPerlSiteLib[MAX_PATH+1];
107     strcpy(szPerlSiteLib, win32PerlLibPath());
108     strcat(szPerlSiteLib, "\\site");
109     return (szPerlSiteLib);
110 }
111
112 BOOL
113 HasRedirection(char *ptr)
114 {
115     int inquote = 0;
116     char quote = '\0';
117
118     /*
119      * Scan string looking for redirection (< or >) or pipe
120      * characters (|) that are not in a quoted string
121      */
122     while(*ptr) {
123         switch(*ptr) {
124         case '\'':
125         case '\"':
126             if(inquote) {
127                 if(quote == *ptr) {
128                     inquote = 0;
129                     quote = '\0';
130                 }
131             }
132             else {
133                 quote = *ptr;
134                 inquote++;
135             }
136             break;
137         case '>':
138         case '<':
139         case '|':
140             if(!inquote)
141                 return TRUE;
142         default:
143             break;
144         }
145         ++ptr;
146     }
147     return FALSE;
148 }
149
150 /* since the current process environment is being updated in util.c
151  * the library functions will get the correct environment
152  */
153 PerlIO *
154 my_popen(char *cmd, char *mode)
155 {
156 #ifdef FIXCMD
157 #define fixcmd(x)       {                                       \
158                             char *pspace = strchr((x),' ');     \
159                             if (pspace) {                       \
160                                 char *p = (x);                  \
161                                 while (p < pspace) {            \
162                                     if (*p == '/')              \
163                                         *p = '\\';              \
164                                     p++;                        \
165                                 }                               \
166                             }                                   \
167                         }
168 #else
169 #define fixcmd(x)
170 #endif
171
172 #if 1
173 /* was #ifndef PERLDLL, but the #else stuff doesn't work on NT
174  * GSAR 97/03/13
175  */
176     fixcmd(cmd);
177 #ifdef __BORLANDC__ /* workaround a Borland stdio bug */
178     win32_fflush(stdout);
179     win32_fflush(stderr);
180 #endif
181     return win32_popen(cmd, mode);
182 #else
183 /*
184  * There seems to be some problems for the _popen call in a DLL
185  * this trick at the moment seems to work but it is never test
186  * on NT yet
187  *
188  */ 
189 #       ifdef __cplusplus
190 #define EXT_C_FUNC      extern "C"
191 #       else
192 #define EXT_C_FUNC      extern
193 #       endif
194
195     EXT_C_FUNC int __cdecl _set_osfhnd(int fh, long value);
196     EXT_C_FUNC void __cdecl _lock_fhandle(int);
197     EXT_C_FUNC void __cdecl _unlock_fhandle(int);
198
199     BOOL        fSuccess;
200     PerlIO      *pf;            /* to store the _popen return value */
201     int         tm = 0;         /* flag indicating tDllExport or binary mode */
202     int         fhNeeded, fhInherited, fhDup;
203     int         ineeded, iinherited;
204     DWORD       dwDup;
205     int         phdls[2];       /* I/O handles for pipe */
206     HANDLE      hPIn, hPOut, hPErr,
207                 hSaveStdin, hSaveStdout, hSaveStderr,
208                 hPNeeded, hPInherited, hPDuped;
209      
210     /* first check for errors in the arguments */
211     if ( (cmd == NULL) || (mode == NULL)
212          || ((*mode != 'w') && (*mode != _T('r'))) )
213         goto error1;
214
215     if ( *(mode + 1) == _T('t') )
216         tm = O_TEXT;
217     else if ( *(mode + 1) == _T('b') )
218         tm = O_BINARY;
219     else
220         tm = (*mode == 'w' ? O_BINARY : O_TEXT);
221
222
223     fixcmd(cmd);
224     if (&win32stdio != pIOSubSystem)
225         return win32_popen(cmd, mode);
226
227 #ifdef EFG
228     if ( _pipe( phdls, 1024, tm ) == -1 )
229 #else
230     if ( win32_pipe( phdls, 1024, tm ) == -1 )
231 #endif
232         goto error1;
233
234     /* save the current situation */
235     hSaveStdin = GetStdHandle(STD_INPUT_HANDLE); 
236     hSaveStdout = GetStdHandle(STD_OUTPUT_HANDLE); 
237     hSaveStderr = GetStdHandle(STD_ERROR_HANDLE); 
238
239     if (*mode == _T('w')) {
240         ineeded = 1;
241         dwDup   = STD_INPUT_HANDLE;
242         iinherited = 0;
243     }
244     else {
245         ineeded = 0;
246         dwDup   = STD_OUTPUT_HANDLE;
247         iinherited = 1;
248     }
249
250     fhNeeded = phdls[ineeded];
251     fhInherited = phdls[iinherited];
252
253     fSuccess = DuplicateHandle(GetCurrentProcess(), 
254                                (HANDLE) stolen_get_osfhandle(fhNeeded), 
255                                GetCurrentProcess(), 
256                                &hPNeeded, 
257                                0, 
258                                FALSE,       /* not inherited */ 
259                                DUPLICATE_SAME_ACCESS); 
260
261     if (!fSuccess)
262         goto error2;
263
264     fhDup = stolen_open_osfhandle((long) hPNeeded, tm);
265     win32_dup2(fhDup, fhNeeded);
266     win32_close(fhDup);
267
268 #ifdef AAA
269     /* Close the Out pipe, child won't need it */
270     hPDuped = (HANDLE) stolen_get_osfhandle(fhNeeded);
271
272     _lock_fhandle(fhNeeded);
273     _set_osfhnd(fhNeeded, (long)hPNeeded); /* put in ours duplicated one */
274     _unlock_fhandle(fhNeeded);
275
276     CloseHandle(hPDuped);       /* close the handle first */
277 #endif
278
279     if (!SetStdHandle(dwDup, (HANDLE) stolen_get_osfhandle(fhInherited)))
280         goto error2;
281
282     /*
283      * make sure the child see the same stderr as the calling program
284      */
285     if (!SetStdHandle(STD_ERROR_HANDLE,
286                       (HANDLE)stolen_get_osfhandle(win32_fileno(win32_stderr()))))
287         goto error2;
288
289     pf = win32_popen(cmd, mode);        /* ask _popen to do the job */
290
291     /* restore to where we were */
292     SetStdHandle(STD_INPUT_HANDLE, hSaveStdin);
293     SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdout);
294     SetStdHandle(STD_ERROR_HANDLE, hSaveStderr);
295
296     /* we don't need it any more, that's for the child */
297     win32_close(fhInherited);
298
299     if (NULL == pf) {
300         /* something wrong */
301         win32_close(fhNeeded);
302         goto error1;
303     }
304     else {
305         /*
306          * here we steal the file handle in pf and stuff ours in
307          */
308         win32_dup2(fhNeeded, win32_fileno(pf));
309         win32_close(fhNeeded);
310     }
311     return (pf);
312
313 error2:
314     win32_close(fhNeeded);
315     win32_close(fhInherited);
316
317 error1:
318     return (NULL);
319
320 #endif
321 }
322
323 long
324 my_pclose(PerlIO *fp)
325 {
326     return win32_pclose(fp);
327 }
328
329 static DWORD
330 IdOS(void)
331 {
332     static OSVERSIONINFO osver;
333
334     if (osver.dwPlatformId != Win32System) {
335         memset(&osver, 0, sizeof(OSVERSIONINFO));
336         osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
337         GetVersionEx(&osver);
338         Win32System = osver.dwPlatformId;
339     }
340     return (Win32System);
341 }
342
343 static char *
344 GetShell(void)
345 {
346     if (!ProbeEnv) {
347         char* defaultshell = (IsWinNT() ? "cmd.exe" : "command.com");
348         /* we don't use COMSPEC here for two reasons:
349          *  1. the same reason perl on UNIX doesn't use SHELL--rampant and
350          *     uncontrolled unportability of the ensuing scripts.
351          *  2. PERL5SHELL could be set to a shell that may not be fit for
352          *     interactive use (which is what most programs look in COMSPEC
353          *     for).
354          */
355         char *usershell = getenv("PERL5SHELL");  
356
357         ProbeEnv = TRUE;
358         strcpy(szShellPath, usershell ? usershell : defaultshell);
359     }
360     return szShellPath;
361 }
362
363 int
364 do_aspawn(void* really, void ** mark, void ** arglast)
365 {
366     char **argv;
367     char *strPtr;
368     char *cmd;
369     int status;
370     unsigned int length;
371     int index = 0;
372     SV *sv = (SV*)really;
373     SV** pSv = (SV**)mark;
374
375     New(1310, argv, (arglast - mark) + 4, char*);
376
377     if(sv != Nullsv) {
378         cmd = SvPV(sv, length);
379     }
380     else {
381         argv[index++] = cmd = GetShell();
382         if (IsWinNT())
383             argv[index++] = "/x";   /* always enable command extensions */
384         argv[index++] = "/c";
385     }
386
387     while(++pSv <= (SV**)arglast) {
388         sv = *pSv;
389         strPtr = SvPV(sv, length);
390         if(strPtr != NULL && *strPtr != '\0')
391             argv[index++] = strPtr;
392     }
393     argv[index++] = 0;
394    
395     status = win32_spawnvp(P_WAIT, cmd, (const char* const*)argv);
396
397     Safefree(argv);
398
399     if (status < 0) {
400         if (dowarn)
401             warn("Can't spawn \"%s\": %s", cmd, strerror(errno));
402         status = 255 << 8;
403     }
404     return (status);
405 }
406
407 int
408 do_spawn2(char *cmd, int exectype)
409 {
410     char **a;
411     char *s;
412     char **argv;
413     int status = -1;
414     BOOL needToTry = TRUE;
415     char *shell, *cmd2;
416
417     /* save an extra exec if possible */
418     shell = GetShell();
419
420     /* see if there are shell metacharacters in it */
421     if(!HasRedirection(cmd)) {
422         New(1301,argv, strlen(cmd) / 2 + 2, char*);
423         New(1302,cmd2, strlen(cmd) + 1, char);
424         strcpy(cmd2, cmd);
425         a = argv;
426         for (s = cmd2; *s;) {
427             while (*s && isspace(*s))
428                 s++;
429             if (*s)
430                 *(a++) = s;
431             while(*s && !isspace(*s))
432                 s++;
433             if(*s)
434                 *s++ = '\0';
435         }
436         *a = Nullch;
437         if(argv[0]) {
438             switch (exectype) {
439             case EXECF_SPAWN:
440                 status = win32_spawnvp(P_WAIT, argv[0],
441                                        (const char* const*)argv);
442                 break;
443             case EXECF_SPAWN_NOWAIT:
444                 status = win32_spawnvp(P_NOWAIT, argv[0],
445                                        (const char* const*)argv);
446                 break;
447             case EXECF_EXEC:
448                 status = win32_execvp(argv[0], (const char* const*)argv);
449                 break;
450             }
451             if(status != -1 || errno == 0)
452                 needToTry = FALSE;
453         }
454         Safefree(argv);
455         Safefree(cmd2);
456     }
457     if(needToTry) {
458         char *argv[5];
459         int i = 0;
460         argv[i++] = shell;
461         if (IsWinNT())
462             argv[i++] = "/x";
463         argv[i++] = "/c"; argv[i++] = cmd; argv[i] = Nullch;
464         switch (exectype) {
465         case EXECF_SPAWN:
466             status = win32_spawnvp(P_WAIT, argv[0],
467                                    (const char* const*)argv);
468             break;
469         case EXECF_SPAWN_NOWAIT:
470             status = win32_spawnvp(P_NOWAIT, argv[0],
471                                    (const char* const*)argv);
472             break;
473         case EXECF_EXEC:
474             status = win32_execvp(argv[0], (const char* const*)argv);
475             break;
476         }
477     }
478     if (status < 0) {
479         if (dowarn)
480             warn("Can't %s \"%s\": %s",
481                  (exectype == EXECF_EXEC ? "exec" : "spawn"),
482                  needToTry ? shell : argv[0],
483                  strerror(errno));
484         status = 255 << 8;
485     }
486     return (status);
487 }
488
489 int
490 do_spawn(char *cmd)
491 {
492     return do_spawn2(cmd, EXECF_SPAWN);
493 }
494
495 bool
496 do_exec(char *cmd)
497 {
498     do_spawn2(cmd, EXECF_EXEC);
499     return FALSE;
500 }
501
502
503 #define PATHLEN 1024
504
505 /* The idea here is to read all the directory names into a string table
506  * (separated by nulls) and when one of the other dir functions is called
507  * return the pointer to the current file name.
508  */
509 DIR *
510 opendir(char *filename)
511 {
512     DIR            *p;
513     long            len;
514     long            idx;
515     char            scannamespc[PATHLEN];
516     char       *scanname = scannamespc;
517     struct stat     sbuf;
518     WIN32_FIND_DATA FindData;
519     HANDLE          fh;
520 /*  char            root[_MAX_PATH];*/
521 /*  char            volname[_MAX_PATH];*/
522 /*  DWORD           serial, maxname, flags;*/
523 /*  BOOL            downcase;*/
524 /*  char           *dummy;*/
525
526     /* check to see if filename is a directory */
527     if (win32_stat(filename, &sbuf) < 0 || (sbuf.st_mode & S_IFDIR) == 0) {
528         return NULL;
529     }
530
531     /* get the file system characteristics */
532 /*  if(GetFullPathName(filename, MAX_PATH, root, &dummy)) {
533  *      if(dummy = strchr(root, '\\'))
534  *          *++dummy = '\0';
535  *      if(GetVolumeInformation(root, volname, MAX_PATH, &serial,
536  *                              &maxname, &flags, 0, 0)) {
537  *          downcase = !(flags & FS_CASE_IS_PRESERVED);
538  *      }
539  *  }
540  *  else {
541  *      downcase = TRUE;
542  *  }
543  */
544     /* Get us a DIR structure */
545     Newz(1303, p, 1, DIR);
546     if(p == NULL)
547         return NULL;
548
549     /* Create the search pattern */
550     strcpy(scanname, filename);
551
552     if(index("/\\", *(scanname + strlen(scanname) - 1)) == NULL)
553         strcat(scanname, "/*");
554     else
555         strcat(scanname, "*");
556
557     /* do the FindFirstFile call */
558     fh = FindFirstFile(scanname, &FindData);
559     if(fh == INVALID_HANDLE_VALUE) {
560         return NULL;
561     }
562
563     /* now allocate the first part of the string table for
564      * the filenames that we find.
565      */
566     idx = strlen(FindData.cFileName)+1;
567     New(1304, p->start, idx, char);
568     if(p->start == NULL) {
569         CROAK("opendir: malloc failed!\n");
570     }
571     strcpy(p->start, FindData.cFileName);
572 /*  if(downcase)
573  *      strlwr(p->start);
574  */
575     p->nfiles++;
576
577     /* loop finding all the files that match the wildcard
578      * (which should be all of them in this directory!).
579      * the variable idx should point one past the null terminator
580      * of the previous string found.
581      */
582     while (FindNextFile(fh, &FindData)) {
583         len = strlen(FindData.cFileName);
584         /* bump the string table size by enough for the
585          * new name and it's null terminator
586          */
587         Renew(p->start, idx+len+1, char);
588         if(p->start == NULL) {
589             CROAK("opendir: malloc failed!\n");
590         }
591         strcpy(&p->start[idx], FindData.cFileName);
592 /*      if (downcase) 
593  *          strlwr(&p->start[idx]);
594  */
595                 p->nfiles++;
596                 idx += len+1;
597         }
598         FindClose(fh);
599         p->size = idx;
600         p->curr = p->start;
601         return p;
602 }
603
604
605 /* Readdir just returns the current string pointer and bumps the
606  * string pointer to the nDllExport entry.
607  */
608 struct direct *
609 readdir(DIR *dirp)
610 {
611     int         len;
612     static int  dummy = 0;
613
614     if (dirp->curr) {
615         /* first set up the structure to return */
616         len = strlen(dirp->curr);
617         strcpy(dirp->dirstr.d_name, dirp->curr);
618         dirp->dirstr.d_namlen = len;
619
620         /* Fake an inode */
621         dirp->dirstr.d_ino = dummy++;
622
623         /* Now set up for the nDllExport call to readdir */
624         dirp->curr += len + 1;
625         if (dirp->curr >= (dirp->start + dirp->size)) {
626             dirp->curr = NULL;
627         }
628
629         return &(dirp->dirstr);
630     } 
631     else
632         return NULL;
633 }
634
635 /* Telldir returns the current string pointer position */
636 long
637 telldir(DIR *dirp)
638 {
639     return (long) dirp->curr;
640 }
641
642
643 /* Seekdir moves the string pointer to a previously saved position
644  *(Saved by telldir).
645  */
646 void
647 seekdir(DIR *dirp, long loc)
648 {
649     dirp->curr = (char *)loc;
650 }
651
652 /* Rewinddir resets the string pointer to the start */
653 void
654 rewinddir(DIR *dirp)
655 {
656     dirp->curr = dirp->start;
657 }
658
659 /* free the memory allocated by opendir */
660 int
661 closedir(DIR *dirp)
662 {
663     Safefree(dirp->start);
664     Safefree(dirp);
665     return 1;
666 }
667
668
669 /*
670  * various stubs
671  */
672
673
674 /* Ownership
675  *
676  * Just pretend that everyone is a superuser. NT will let us know if
677  * we don\'t really have permission to do something.
678  */
679
680 #define ROOT_UID    ((uid_t)0)
681 #define ROOT_GID    ((gid_t)0)
682
683 uid_t
684 getuid(void)
685 {
686     return ROOT_UID;
687 }
688
689 uid_t
690 geteuid(void)
691 {
692     return ROOT_UID;
693 }
694
695 gid_t
696 getgid(void)
697 {
698     return ROOT_GID;
699 }
700
701 gid_t
702 getegid(void)
703 {
704     return ROOT_GID;
705 }
706
707 int
708 setuid(uid_t uid)
709
710     return (uid == ROOT_UID ? 0 : -1);
711 }
712
713 int
714 setgid(gid_t gid)
715 {
716     return (gid == ROOT_GID ? 0 : -1);
717 }
718
719 /*
720  * pretended kill
721  */
722 int
723 kill(int pid, int sig)
724 {
725     HANDLE hProcess= OpenProcess(PROCESS_ALL_ACCESS, TRUE, pid);
726
727     if (hProcess == NULL) {
728         CROAK("kill process failed!\n");
729     }
730     else {
731         if (!TerminateProcess(hProcess, sig))
732             CROAK("kill process failed!\n");
733         CloseHandle(hProcess);
734     }
735     return 0;
736 }
737       
738 /*
739  * File system stuff
740  */
741
742 #if 0
743 int
744 ioctl(int i, unsigned int u, char *data)
745 {
746     CROAK("ioctl not implemented!\n");
747     return -1;
748 }
749 #endif
750
751 unsigned int
752 sleep(unsigned int t)
753 {
754     Sleep(t*1000);
755     return 0;
756 }
757
758
759 #undef rename
760
761 int
762 myrename(char *OldFileName, char *newname)
763 {
764     if(_access(newname, 0) != -1) {     /* file exists */
765         _unlink(newname);
766     }
767     return rename(OldFileName, newname);
768 }
769
770
771 DllExport int
772 win32_stat(const char *path, struct stat *buffer)
773 {
774     char                t[MAX_PATH]; 
775     const char  *p = path;
776     int         l = strlen(path);
777     int         res;
778
779     if (l > 1) {
780         switch(path[l - 1]) {
781         case '\\':
782         case '/':
783             if (path[l - 2] != ':') {
784                 strncpy(t, path, l - 1);
785                 t[l - 1] = 0;
786                 p = t;
787             };
788         }
789     }
790     res = pIOSubSystem->pfnstat(p,buffer);
791 #ifdef __BORLANDC__
792     if (res == 0) {
793         if (S_ISDIR(buffer->st_mode))
794             buffer->st_mode |= S_IWRITE | S_IEXEC;
795         else if (S_ISREG(buffer->st_mode)) {
796             if (l >= 4 && path[l-4] == '.') {
797                 const char *e = path + l - 3;
798                 if (strnicmp(e,"exe",3)
799                     && strnicmp(e,"bat",3)
800                     && strnicmp(e,"com",3)
801                     && (IsWin95() || strnicmp(e,"cmd",3)))
802                     buffer->st_mode &= ~S_IEXEC;
803                 else
804                     buffer->st_mode |= S_IEXEC;
805             }
806             else
807                 buffer->st_mode &= ~S_IEXEC;
808         }
809     }
810 #endif
811     return res;
812 }
813
814 #ifndef USE_WIN32_RTL_ENV
815
816 DllExport char *
817 win32_getenv(const char *name)
818 {
819     static char *curitem = Nullch;
820     static DWORD curlen = 512;
821     DWORD needlen;
822     if (!curitem)
823         New(1305,curitem,curlen,char);
824     if (!(needlen = GetEnvironmentVariable(name,curitem,curlen)))
825         return Nullch;
826     while (needlen > curlen) {
827         Renew(curitem,needlen,char);
828         curlen = needlen;
829         needlen = GetEnvironmentVariable(name,curitem,curlen);
830     }
831     return curitem;
832 }
833
834 #endif
835
836 #undef times
837 int
838 mytimes(struct tms *timebuf)
839 {
840     clock_t     t = clock();
841     timebuf->tms_utime = t;
842     timebuf->tms_stime = 0;
843     timebuf->tms_cutime = 0;
844     timebuf->tms_cstime = 0;
845
846     return 0;
847 }
848
849 #undef alarm
850 unsigned int
851 myalarm(unsigned int sec)
852 {
853     /* we warn the usuage of alarm function */
854     if (sec != 0)
855         WARN("dummy function alarm called, program might not function as expected\n");
856     return 0;
857 }
858
859 /*
860  *  redirected io subsystem for all XS modules
861  *
862  */
863
864 DllExport int *
865 win32_errno(void)
866 {
867     return (pIOSubSystem->pfnerrno());
868 }
869
870 DllExport char ***
871 win32_environ(void)
872 {
873     return (pIOSubSystem->pfnenviron());
874 }
875
876 /* the rest are the remapped stdio routines */
877 DllExport FILE *
878 win32_stderr(void)
879 {
880     return (pIOSubSystem->pfnstderr());
881 }
882
883 DllExport FILE *
884 win32_stdin(void)
885 {
886     return (pIOSubSystem->pfnstdin());
887 }
888
889 DllExport FILE *
890 win32_stdout()
891 {
892     return (pIOSubSystem->pfnstdout());
893 }
894
895 DllExport int
896 win32_ferror(FILE *fp)
897 {
898     return (pIOSubSystem->pfnferror(fp));
899 }
900
901
902 DllExport int
903 win32_feof(FILE *fp)
904 {
905     return (pIOSubSystem->pfnfeof(fp));
906 }
907
908 /*
909  * Since the errors returned by the socket error function 
910  * WSAGetLastError() are not known by the library routine strerror
911  * we have to roll our own.
912  */
913
914 __declspec(thread) char strerror_buffer[512];
915
916 DllExport char *
917 win32_strerror(int e) 
918 {
919 #ifndef __BORLANDC__            /* Borland intolerance */
920     extern int sys_nerr;
921 #endif
922     DWORD source = 0;
923
924     if(e < 0 || e > sys_nerr) {
925         if(e < 0)
926             e = GetLastError();
927
928         if(FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, &source, e, 0,
929                          strerror_buffer, sizeof(strerror_buffer), NULL) == 0) 
930             strcpy(strerror_buffer, "Unknown Error");
931
932         return strerror_buffer;
933     }
934     return pIOSubSystem->pfnstrerror(e);
935 }
936
937 DllExport int
938 win32_fprintf(FILE *fp, const char *format, ...)
939 {
940     va_list marker;
941     va_start(marker, format);     /* Initialize variable arguments. */
942
943     return (pIOSubSystem->pfnvfprintf(fp, format, marker));
944 }
945
946 DllExport int
947 win32_printf(const char *format, ...)
948 {
949     va_list marker;
950     va_start(marker, format);     /* Initialize variable arguments. */
951
952     return (pIOSubSystem->pfnvprintf(format, marker));
953 }
954
955 DllExport int
956 win32_vfprintf(FILE *fp, const char *format, va_list args)
957 {
958     return (pIOSubSystem->pfnvfprintf(fp, format, args));
959 }
960
961 DllExport int
962 win32_vprintf(const char *format, va_list args)
963 {
964     return (pIOSubSystem->pfnvprintf(format, args));
965 }
966
967 DllExport size_t
968 win32_fread(void *buf, size_t size, size_t count, FILE *fp)
969 {
970     return pIOSubSystem->pfnfread(buf, size, count, fp);
971 }
972
973 DllExport size_t
974 win32_fwrite(const void *buf, size_t size, size_t count, FILE *fp)
975 {
976     return pIOSubSystem->pfnfwrite(buf, size, count, fp);
977 }
978
979 DllExport FILE *
980 win32_fopen(const char *filename, const char *mode)
981 {
982     if (stricmp(filename, "/dev/null")==0)
983         return pIOSubSystem->pfnfopen("NUL", mode);
984     return pIOSubSystem->pfnfopen(filename, mode);
985 }
986
987 DllExport FILE *
988 win32_fdopen( int handle, const char *mode)
989 {
990     return pIOSubSystem->pfnfdopen(handle, (char *) mode);
991 }
992
993 DllExport FILE *
994 win32_freopen( const char *path, const char *mode, FILE *stream)
995 {
996     if (stricmp(path, "/dev/null")==0)
997         return pIOSubSystem->pfnfreopen("NUL", mode, stream);
998     return pIOSubSystem->pfnfreopen(path, mode, stream);
999 }
1000
1001 DllExport int
1002 win32_fclose(FILE *pf)
1003 {
1004     return pIOSubSystem->pfnfclose(pf);
1005 }
1006
1007 DllExport int
1008 win32_fputs(const char *s,FILE *pf)
1009 {
1010     return pIOSubSystem->pfnfputs(s, pf);
1011 }
1012
1013 DllExport int
1014 win32_fputc(int c,FILE *pf)
1015 {
1016     return pIOSubSystem->pfnfputc(c,pf);
1017 }
1018
1019 DllExport int
1020 win32_ungetc(int c,FILE *pf)
1021 {
1022     return pIOSubSystem->pfnungetc(c,pf);
1023 }
1024
1025 DllExport int
1026 win32_getc(FILE *pf)
1027 {
1028     return pIOSubSystem->pfngetc(pf);
1029 }
1030
1031 DllExport int
1032 win32_fileno(FILE *pf)
1033 {
1034     return pIOSubSystem->pfnfileno(pf);
1035 }
1036
1037 DllExport void
1038 win32_clearerr(FILE *pf)
1039 {
1040     pIOSubSystem->pfnclearerr(pf);
1041     return;
1042 }
1043
1044 DllExport int
1045 win32_fflush(FILE *pf)
1046 {
1047     return pIOSubSystem->pfnfflush(pf);
1048 }
1049
1050 DllExport long
1051 win32_ftell(FILE *pf)
1052 {
1053     return pIOSubSystem->pfnftell(pf);
1054 }
1055
1056 DllExport int
1057 win32_fseek(FILE *pf,long offset,int origin)
1058 {
1059     return pIOSubSystem->pfnfseek(pf, offset, origin);
1060 }
1061
1062 DllExport int
1063 win32_fgetpos(FILE *pf,fpos_t *p)
1064 {
1065     return pIOSubSystem->pfnfgetpos(pf, p);
1066 }
1067
1068 DllExport int
1069 win32_fsetpos(FILE *pf,const fpos_t *p)
1070 {
1071     return pIOSubSystem->pfnfsetpos(pf, p);
1072 }
1073
1074 DllExport void
1075 win32_rewind(FILE *pf)
1076 {
1077     pIOSubSystem->pfnrewind(pf);
1078     return;
1079 }
1080
1081 DllExport FILE*
1082 win32_tmpfile(void)
1083 {
1084     return pIOSubSystem->pfntmpfile();
1085 }
1086
1087 DllExport void
1088 win32_abort(void)
1089 {
1090     pIOSubSystem->pfnabort();
1091     return;
1092 }
1093
1094 DllExport int
1095 win32_fstat(int fd,struct stat *bufptr)
1096 {
1097     return pIOSubSystem->pfnfstat(fd,bufptr);
1098 }
1099
1100 DllExport int
1101 win32_pipe(int *pfd, unsigned int size, int mode)
1102 {
1103     return pIOSubSystem->pfnpipe(pfd, size, mode);
1104 }
1105
1106 DllExport FILE*
1107 win32_popen(const char *command, const char *mode)
1108 {
1109     return pIOSubSystem->pfnpopen(command, mode);
1110 }
1111
1112 DllExport int
1113 win32_pclose(FILE *pf)
1114 {
1115     return pIOSubSystem->pfnpclose(pf);
1116 }
1117
1118 DllExport int
1119 win32_setmode(int fd, int mode)
1120 {
1121     return pIOSubSystem->pfnsetmode(fd, mode);
1122 }
1123
1124 DllExport long
1125 win32_lseek(int fd, long offset, int origin)
1126 {
1127     return pIOSubSystem->pfnlseek(fd, offset, origin);
1128 }
1129
1130 DllExport long
1131 win32_tell(int fd)
1132 {
1133     return pIOSubSystem->pfntell(fd);
1134 }
1135
1136 DllExport int
1137 win32_open(const char *path, int flag, ...)
1138 {
1139     va_list ap;
1140     int pmode;
1141
1142     va_start(ap, flag);
1143     pmode = va_arg(ap, int);
1144     va_end(ap);
1145
1146     if (stricmp(path, "/dev/null")==0)
1147         return pIOSubSystem->pfnopen("NUL", flag, pmode);
1148     return pIOSubSystem->pfnopen(path,flag,pmode);
1149 }
1150
1151 DllExport int
1152 win32_close(int fd)
1153 {
1154     return pIOSubSystem->pfnclose(fd);
1155 }
1156
1157 DllExport int
1158 win32_eof(int fd)
1159 {
1160     return pIOSubSystem->pfneof(fd);
1161 }
1162
1163 DllExport int
1164 win32_dup(int fd)
1165 {
1166     return pIOSubSystem->pfndup(fd);
1167 }
1168
1169 DllExport int
1170 win32_dup2(int fd1,int fd2)
1171 {
1172     return pIOSubSystem->pfndup2(fd1,fd2);
1173 }
1174
1175 DllExport int
1176 win32_read(int fd, void *buf, unsigned int cnt)
1177 {
1178     return pIOSubSystem->pfnread(fd, buf, cnt);
1179 }
1180
1181 DllExport int
1182 win32_write(int fd, const void *buf, unsigned int cnt)
1183 {
1184     return pIOSubSystem->pfnwrite(fd, buf, cnt);
1185 }
1186
1187 DllExport int
1188 win32_mkdir(const char *dir, int mode)
1189 {
1190     return pIOSubSystem->pfnmkdir(dir); /* just ignore mode */
1191 }
1192
1193 DllExport int
1194 win32_rmdir(const char *dir)
1195 {
1196     return pIOSubSystem->pfnrmdir(dir);
1197 }
1198
1199 DllExport int
1200 win32_chdir(const char *dir)
1201 {
1202     return pIOSubSystem->pfnchdir(dir);
1203 }
1204
1205 DllExport int
1206 win32_spawnvp(int mode, const char *cmdname, const char *const *argv)
1207 {
1208     return pIOSubSystem->pfnspawnvp(mode, cmdname, (char * const *) argv);
1209 }
1210
1211 DllExport int
1212 win32_execvp(const char *cmdname, const char *const *argv)
1213 {
1214     return pIOSubSystem->pfnexecvp(cmdname, (char *const *)argv);
1215 }
1216
1217 DllExport void
1218 win32_perror(const char *str)
1219 {
1220     pIOSubSystem->pfnperror(str);
1221 }
1222
1223 DllExport void
1224 win32_setbuf(FILE *pf, char *buf)
1225 {
1226     pIOSubSystem->pfnsetbuf(pf, buf);
1227 }
1228
1229 DllExport int
1230 win32_setvbuf(FILE *pf, char *buf, int type, size_t size)
1231 {
1232     return pIOSubSystem->pfnsetvbuf(pf, buf, type, size);
1233 }
1234
1235 DllExport int
1236 win32_flushall(void)
1237 {
1238     return pIOSubSystem->pfnflushall();
1239 }
1240
1241 DllExport int
1242 win32_fcloseall(void)
1243 {
1244     return pIOSubSystem->pfnfcloseall();
1245 }
1246
1247 DllExport char*
1248 win32_fgets(char *s, int n, FILE *pf)
1249 {
1250     return pIOSubSystem->pfnfgets(s, n, pf);
1251 }
1252
1253 DllExport char*
1254 win32_gets(char *s)
1255 {
1256     return pIOSubSystem->pfngets(s);
1257 }
1258
1259 DllExport int
1260 win32_fgetc(FILE *pf)
1261 {
1262     return pIOSubSystem->pfnfgetc(pf);
1263 }
1264
1265 DllExport int
1266 win32_putc(int c, FILE *pf)
1267 {
1268     return pIOSubSystem->pfnputc(c,pf);
1269 }
1270
1271 DllExport int
1272 win32_puts(const char *s)
1273 {
1274     return pIOSubSystem->pfnputs(s);
1275 }
1276
1277 DllExport int
1278 win32_getchar(void)
1279 {
1280     return pIOSubSystem->pfngetchar();
1281 }
1282
1283 DllExport int
1284 win32_putchar(int c)
1285 {
1286     return pIOSubSystem->pfnputchar(c);
1287 }
1288
1289 DllExport void*
1290 win32_malloc(size_t size)
1291 {
1292     return pIOSubSystem->pfnmalloc(size);
1293 }
1294
1295 DllExport void*
1296 win32_calloc(size_t numitems, size_t size)
1297 {
1298     return pIOSubSystem->pfncalloc(numitems,size);
1299 }
1300
1301 DllExport void*
1302 win32_realloc(void *block, size_t size)
1303 {
1304     return pIOSubSystem->pfnrealloc(block,size);
1305 }
1306
1307 DllExport void
1308 win32_free(void *block)
1309 {
1310     pIOSubSystem->pfnfree(block);
1311 }
1312
1313 int
1314 stolen_open_osfhandle(long handle, int flags)
1315 {
1316     return pIOSubSystem->pfn_open_osfhandle(handle, flags);
1317 }
1318
1319 long
1320 stolen_get_osfhandle(int fd)
1321 {
1322     return pIOSubSystem->pfn_get_osfhandle(fd);
1323 }
1324
1325 /*
1326  * Extras.
1327  */
1328
1329 DllExport int
1330 win32_flock(int fd, int oper)
1331 {
1332     if (!IsWinNT()) {
1333         croak("flock() unimplemented on this platform");
1334         return -1;
1335     }
1336     return pIOSubSystem->pfnflock(fd, oper);
1337 }
1338
1339 static
1340 XS(w32_GetCwd)
1341 {
1342     dXSARGS;
1343     SV *sv = sv_newmortal();
1344     /* Make one call with zero size - return value is required size */
1345     DWORD len = GetCurrentDirectory((DWORD)0,NULL);
1346     SvUPGRADE(sv,SVt_PV);
1347     SvGROW(sv,len);
1348     SvCUR(sv) = GetCurrentDirectory((DWORD) SvLEN(sv), SvPVX(sv));
1349     /* 
1350      * If result != 0 
1351      *   then it worked, set PV valid, 
1352      *   else leave it 'undef' 
1353      */
1354     if (SvCUR(sv))
1355         SvPOK_on(sv);
1356     EXTEND(sp,1);
1357     ST(0) = sv;
1358     XSRETURN(1);
1359 }
1360
1361 static
1362 XS(w32_SetCwd)
1363 {
1364     dXSARGS;
1365     if (items != 1)
1366         croak("usage: Win32::SetCurrentDirectory($cwd)");
1367     if (SetCurrentDirectory(SvPV(ST(0),na)))
1368         XSRETURN_YES;
1369
1370     XSRETURN_NO;
1371 }
1372
1373 static
1374 XS(w32_GetNextAvailDrive)
1375 {
1376     dXSARGS;
1377     char ix = 'C';
1378     char root[] = "_:\\";
1379     while (ix <= 'Z') {
1380         root[0] = ix++;
1381         if (GetDriveType(root) == 1) {
1382             root[2] = '\0';
1383             XSRETURN_PV(root);
1384         }
1385     }
1386     XSRETURN_UNDEF;
1387 }
1388
1389 static
1390 XS(w32_GetLastError)
1391 {
1392     dXSARGS;
1393     XSRETURN_IV(GetLastError());
1394 }
1395
1396 static
1397 XS(w32_LoginName)
1398 {
1399     dXSARGS;
1400     char name[256];
1401     DWORD size = sizeof(name);
1402     if (GetUserName(name,&size)) {
1403         /* size includes NULL */
1404         ST(0) = sv_2mortal(newSVpv(name,size-1));
1405         XSRETURN(1);
1406     }
1407     XSRETURN_UNDEF;
1408 }
1409
1410 static
1411 XS(w32_NodeName)
1412 {
1413     dXSARGS;
1414     char name[MAX_COMPUTERNAME_LENGTH+1];
1415     DWORD size = sizeof(name);
1416     if (GetComputerName(name,&size)) {
1417         /* size does NOT include NULL :-( */
1418         ST(0) = sv_2mortal(newSVpv(name,size));
1419         XSRETURN(1);
1420     }
1421     XSRETURN_UNDEF;
1422 }
1423
1424
1425 static
1426 XS(w32_DomainName)
1427 {
1428     dXSARGS;
1429     char name[256];
1430     DWORD size = sizeof(name);
1431     if (GetUserName(name,&size)) {
1432         char sid[1024];
1433         DWORD sidlen = sizeof(sid);
1434         char dname[256];
1435         DWORD dnamelen = sizeof(dname);
1436         SID_NAME_USE snu;
1437         if (LookupAccountName(NULL, name, &sid, &sidlen,
1438                               dname, &dnamelen, &snu)) {
1439             XSRETURN_PV(dname);         /* all that for this */
1440         }
1441     }
1442     XSRETURN_UNDEF;
1443 }
1444
1445 static
1446 XS(w32_FsType)
1447 {
1448     dXSARGS;
1449     char fsname[256];
1450     DWORD flags, filecomplen;
1451     if (GetVolumeInformation(NULL, NULL, 0, NULL, &filecomplen,
1452                          &flags, fsname, sizeof(fsname))) {
1453         if (GIMME == G_ARRAY) {
1454             XPUSHs(sv_2mortal(newSVpv(fsname,0)));
1455             XPUSHs(sv_2mortal(newSViv(flags)));
1456             XPUSHs(sv_2mortal(newSViv(filecomplen)));
1457             PUTBACK;
1458             return;
1459         }
1460         XSRETURN_PV(fsname);
1461     }
1462     XSRETURN_UNDEF;
1463 }
1464
1465 static
1466 XS(w32_GetOSVersion)
1467 {
1468     dXSARGS;
1469     OSVERSIONINFO osver;
1470
1471     osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
1472     if (GetVersionEx(&osver)) {
1473         XPUSHs(newSVpv(osver.szCSDVersion, 0));
1474         XPUSHs(newSViv(osver.dwMajorVersion));
1475         XPUSHs(newSViv(osver.dwMinorVersion));
1476         XPUSHs(newSViv(osver.dwBuildNumber));
1477         XPUSHs(newSViv(osver.dwPlatformId));
1478         PUTBACK;
1479         return;
1480     }
1481     XSRETURN_UNDEF;
1482 }
1483
1484 static
1485 XS(w32_IsWinNT)
1486 {
1487     dXSARGS;
1488     XSRETURN_IV(IsWinNT());
1489 }
1490
1491 static
1492 XS(w32_IsWin95)
1493 {
1494     dXSARGS;
1495     XSRETURN_IV(IsWin95());
1496 }
1497
1498 static
1499 XS(w32_FormatMessage)
1500 {
1501     dXSARGS;
1502     DWORD source = 0;
1503     char msgbuf[1024];
1504
1505     if (items != 1)
1506         croak("usage: Win32::FormatMessage($errno)");
1507
1508     if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
1509                       &source, SvIV(ST(0)), 0,
1510                       msgbuf, sizeof(msgbuf)-1, NULL))
1511         XSRETURN_PV(msgbuf);
1512
1513     XSRETURN_UNDEF;
1514 }
1515
1516 static
1517 XS(w32_Spawn)
1518 {
1519     dXSARGS;
1520     char *cmd, *args;
1521     PROCESS_INFORMATION stProcInfo;
1522     STARTUPINFO stStartInfo;
1523     BOOL bSuccess = FALSE;
1524
1525     if(items != 3)
1526         croak("usage: Win32::Spawn($cmdName, $args, $PID)");
1527
1528     cmd = SvPV(ST(0),na);
1529     args = SvPV(ST(1), na);
1530
1531     memset(&stStartInfo, 0, sizeof(stStartInfo));   /* Clear the block */
1532     stStartInfo.cb = sizeof(stStartInfo);           /* Set the structure size */
1533     stStartInfo.dwFlags = STARTF_USESHOWWINDOW;     /* Enable wShowWindow control */
1534     stStartInfo.wShowWindow = SW_SHOWMINNOACTIVE;   /* Start min (normal) */
1535
1536     if(CreateProcess(
1537                 cmd,                    /* Image path */
1538                 args,                   /* Arguments for command line */
1539                 NULL,                   /* Default process security */
1540                 NULL,                   /* Default thread security */
1541                 FALSE,                  /* Must be TRUE to use std handles */
1542                 NORMAL_PRIORITY_CLASS,  /* No special scheduling */
1543                 NULL,                   /* Inherit our environment block */
1544                 NULL,                   /* Inherit our currrent directory */
1545                 &stStartInfo,           /* -> Startup info */
1546                 &stProcInfo))           /* <- Process info (if OK) */
1547     {
1548         CloseHandle(stProcInfo.hThread);/* library source code does this. */
1549         sv_setiv(ST(2), stProcInfo.dwProcessId);
1550         bSuccess = TRUE;
1551     }
1552     XSRETURN_IV(bSuccess);
1553 }
1554
1555 static
1556 XS(w32_GetTickCount)
1557 {
1558     dXSARGS;
1559     XSRETURN_IV(GetTickCount());
1560 }
1561
1562 static
1563 XS(w32_GetShortPathName)
1564 {
1565     dXSARGS;
1566     SV *shortpath;
1567     DWORD len;
1568
1569     if(items != 1)
1570         croak("usage: Win32::GetShortPathName($longPathName)");
1571
1572     shortpath = sv_mortalcopy(ST(0));
1573     SvUPGRADE(shortpath, SVt_PV);
1574     /* src == target is allowed */
1575     do {
1576         len = GetShortPathName(SvPVX(shortpath),
1577                                SvPVX(shortpath),
1578                                SvLEN(shortpath));
1579     } while (len >= SvLEN(shortpath) && sv_grow(shortpath,len+1));
1580     if (len) {
1581         SvCUR_set(shortpath,len);
1582         ST(0) = shortpath;
1583     }
1584     else
1585         ST(0) = &sv_undef;
1586     XSRETURN(1);
1587 }
1588
1589 void
1590 init_os_extras()
1591 {
1592     char *file = __FILE__;
1593     dXSUB_SYS;
1594
1595     /* XXX should be removed after checking with Nick */
1596     newXS("Win32::GetCurrentDirectory", w32_GetCwd, file);
1597
1598     /* these names are Activeware compatible */
1599     newXS("Win32::GetCwd", w32_GetCwd, file);
1600     newXS("Win32::SetCwd", w32_SetCwd, file);
1601     newXS("Win32::GetNextAvailDrive", w32_GetNextAvailDrive, file);
1602     newXS("Win32::GetLastError", w32_GetLastError, file);
1603     newXS("Win32::LoginName", w32_LoginName, file);
1604     newXS("Win32::NodeName", w32_NodeName, file);
1605     newXS("Win32::DomainName", w32_DomainName, file);
1606     newXS("Win32::FsType", w32_FsType, file);
1607     newXS("Win32::GetOSVersion", w32_GetOSVersion, file);
1608     newXS("Win32::IsWinNT", w32_IsWinNT, file);
1609     newXS("Win32::IsWin95", w32_IsWin95, file);
1610     newXS("Win32::FormatMessage", w32_FormatMessage, file);
1611     newXS("Win32::Spawn", w32_Spawn, file);
1612     newXS("Win32::GetTickCount", w32_GetTickCount, file);
1613     newXS("Win32::GetShortPathName", w32_GetShortPathName, file);
1614
1615     /* XXX Bloat Alert! The following Activeware preloads really
1616      * ought to be part of Win32::Sys::*, so they're not included
1617      * here.
1618      */
1619     /* LookupAccountName
1620      * LookupAccountSID
1621      * InitiateSystemShutdown
1622      * AbortSystemShutdown
1623      * ExpandEnvrironmentStrings
1624      */
1625 }
1626
1627 void
1628 Perl_win32_init(int *argcp, char ***argvp)
1629 {
1630     /* Disable floating point errors, Perl will trap the ones we
1631      * care about.  VC++ RTL defaults to switching these off
1632      * already, but the Borland RTL doesn't.  Since we don't
1633      * want to be at the vendor's whim on the default, we set
1634      * it explicitly here.
1635      */
1636 #if !defined(_ALPHA_)
1637     _control87(MCW_EM, MCW_EM);
1638 #endif
1639 }
1640
1641
1642
1643