1de1bb870f77991589e562a272b88c308d7765a5
[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 #ifdef __GNUC__
15 #define Win32_Winsock
16 #endif
17 #include <windows.h>
18
19 /* #include "config.h" */
20
21 #define PERLIO_NOT_STDIO 0 
22 #if !defined(PERLIO_IS_STDIO) && !defined(USE_SFIO)
23 #define PerlIO FILE
24 #endif
25
26 #include "EXTERN.h"
27 #include "perl.h"
28 #include "XSUB.h"
29 #include <fcntl.h>
30 #include <sys/stat.h>
31 #ifndef __GNUC__
32 /* assert.h conflicts with #define of assert in perl.h */
33 #include <assert.h>
34 #endif
35 #include <string.h>
36 #include <stdarg.h>
37 #include <float.h>
38
39 #ifdef __GNUC__
40 /* Mingw32 defaults to globing command line 
41  * So we turn it off like this:
42  */
43 int _CRT_glob = 0;
44 #endif
45
46 #define EXECF_EXEC 1
47 #define EXECF_SPAWN 2
48 #define EXECF_SPAWN_NOWAIT 3
49
50 static DWORD IdOS(void);
51
52 BOOL  ProbeEnv = FALSE;
53 DWORD Win32System = (DWORD)-1;
54 char  szShellPath[MAX_PATH+1];
55 char  szPerlLibRoot[MAX_PATH+1];
56 HANDLE PerlDllHandle = INVALID_HANDLE_VALUE;
57
58 #ifdef USE_THREADS
59 #  ifdef USE_DECLSPEC_THREAD
60 __declspec(thread) char strerror_buffer[512];
61 #    ifdef HAVE_DES_FCRYPT
62 __declspec(thread) char crypt_buffer[30];
63 #    endif
64 #  else
65 #    define strerror_buffer     (thr->i.Wstrerror_buffer)
66 #    define crypt_buffer        (thr->i.Wcrypt_buffer)
67 #  endif
68 #else
69 char    strerror_buffer[512];
70 #  ifdef HAVE_DES_FCRYPT
71 char    crypt_buffer[30];
72 #  endif
73 #endif
74
75 static int do_spawn2(char *cmd, int exectype);
76
77 int 
78 IsWin95(void) {
79     return (IdOS() == VER_PLATFORM_WIN32_WINDOWS);
80 }
81
82 int
83 IsWinNT(void) {
84     return (IdOS() == VER_PLATFORM_WIN32_NT);
85 }
86
87 char *
88 win32PerlLibPath(char *sfx,...)
89 {
90     va_list ap;
91     char *end;
92     va_start(ap,sfx);
93     GetModuleFileName((PerlDllHandle == INVALID_HANDLE_VALUE) 
94                       ? GetModuleHandle(NULL)
95                       : PerlDllHandle,
96                       szPerlLibRoot, 
97                       sizeof(szPerlLibRoot));
98     *(end = strrchr(szPerlLibRoot, '\\')) = '\0';
99     if (stricmp(end-4,"\\bin") == 0)
100      end -= 4;
101     strcpy(end,"\\lib");
102     while (sfx)
103      {
104       strcat(end,"\\");
105       strcat(end,sfx);
106       sfx = va_arg(ap,char *);
107      }
108     va_end(ap); 
109     return (szPerlLibRoot);
110 }
111
112
113 BOOL
114 HasRedirection(char *ptr)
115 {
116     int inquote = 0;
117     char quote = '\0';
118
119     /*
120      * Scan string looking for redirection (< or >) or pipe
121      * characters (|) that are not in a quoted string
122      */
123     while(*ptr) {
124         switch(*ptr) {
125         case '\'':
126         case '\"':
127             if(inquote) {
128                 if(quote == *ptr) {
129                     inquote = 0;
130                     quote = '\0';
131                 }
132             }
133             else {
134                 quote = *ptr;
135                 inquote++;
136             }
137             break;
138         case '>':
139         case '<':
140         case '|':
141             if(!inquote)
142                 return TRUE;
143         default:
144             break;
145         }
146         ++ptr;
147     }
148     return FALSE;
149 }
150
151 /* since the current process environment is being updated in util.c
152  * the library functions will get the correct environment
153  */
154 PerlIO *
155 my_popen(char *cmd, char *mode)
156 {
157 #ifdef FIXCMD
158 #define fixcmd(x)       {                                       \
159                             char *pspace = strchr((x),' ');     \
160                             if (pspace) {                       \
161                                 char *p = (x);                  \
162                                 while (p < pspace) {            \
163                                     if (*p == '/')              \
164                                         *p = '\\';              \
165                                     p++;                        \
166                                 }                               \
167                             }                                   \
168                         }
169 #else
170 #define fixcmd(x)
171 #endif
172     fixcmd(cmd);
173 #ifdef __BORLANDC__ /* workaround a Borland stdio bug */
174     win32_fflush(stdout);
175     win32_fflush(stderr);
176 #endif
177     return win32_popen(cmd, mode);
178 }
179
180 long
181 my_pclose(PerlIO *fp)
182 {
183     return win32_pclose(fp);
184 }
185
186 static DWORD
187 IdOS(void)
188 {
189     static OSVERSIONINFO osver;
190
191     if (osver.dwPlatformId != Win32System) {
192         memset(&osver, 0, sizeof(OSVERSIONINFO));
193         osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
194         GetVersionEx(&osver);
195         Win32System = osver.dwPlatformId;
196     }
197     return (Win32System);
198 }
199
200 static char *
201 GetShell(void)
202 {
203     if (!ProbeEnv) {
204         char* defaultshell = (IsWinNT() ? "cmd.exe" : "command.com");
205         /* we don't use COMSPEC here for two reasons:
206          *  1. the same reason perl on UNIX doesn't use SHELL--rampant and
207          *     uncontrolled unportability of the ensuing scripts.
208          *  2. PERL5SHELL could be set to a shell that may not be fit for
209          *     interactive use (which is what most programs look in COMSPEC
210          *     for).
211          */
212         char *usershell = getenv("PERL5SHELL");  
213
214         ProbeEnv = TRUE;
215         strcpy(szShellPath, usershell ? usershell : defaultshell);
216     }
217     return szShellPath;
218 }
219
220 int
221 do_aspawn(void* really, void ** mark, void ** arglast)
222 {
223     char **argv;
224     char *strPtr;
225     char *cmd;
226     int status;
227     unsigned int length;
228     int index = 0;
229     SV *sv = (SV*)really;
230     SV** pSv = (SV**)mark;
231
232     New(1310, argv, (arglast - mark) + 4, char*);
233
234     if(sv != Nullsv) {
235         cmd = SvPV(sv, length);
236     }
237     else {
238         argv[index++] = cmd = GetShell();
239         if (IsWinNT())
240             argv[index++] = "/x";   /* always enable command extensions */
241         argv[index++] = "/c";
242     }
243
244     while(++pSv <= (SV**)arglast) {
245         sv = *pSv;
246         strPtr = SvPV(sv, length);
247         if(strPtr != NULL && *strPtr != '\0')
248             argv[index++] = strPtr;
249     }
250     argv[index++] = 0;
251    
252     status = win32_spawnvp(P_WAIT, cmd, (const char* const*)argv);
253
254     Safefree(argv);
255
256     if (status < 0) {
257         if (dowarn)
258             warn("Can't spawn \"%s\": %s", cmd, strerror(errno));
259         status = 255 << 8;
260     }
261     return (status);
262 }
263
264 int
265 do_spawn2(char *cmd, int exectype)
266 {
267     char **a;
268     char *s;
269     char **argv;
270     int status = -1;
271     BOOL needToTry = TRUE;
272     char *shell, *cmd2;
273
274     /* save an extra exec if possible */
275     shell = GetShell();
276
277     /* see if there are shell metacharacters in it */
278     if(!HasRedirection(cmd)) {
279         New(1301,argv, strlen(cmd) / 2 + 2, char*);
280         New(1302,cmd2, strlen(cmd) + 1, char);
281         strcpy(cmd2, cmd);
282         a = argv;
283         for (s = cmd2; *s;) {
284             while (*s && isspace(*s))
285                 s++;
286             if (*s)
287                 *(a++) = s;
288             while(*s && !isspace(*s))
289                 s++;
290             if(*s)
291                 *s++ = '\0';
292         }
293         *a = Nullch;
294         if(argv[0]) {
295             switch (exectype) {
296             case EXECF_SPAWN:
297                 status = win32_spawnvp(P_WAIT, argv[0],
298                                        (const char* const*)argv);
299                 break;
300             case EXECF_SPAWN_NOWAIT:
301                 status = win32_spawnvp(P_NOWAIT, argv[0],
302                                        (const char* const*)argv);
303                 break;
304             case EXECF_EXEC:
305                 status = win32_execvp(argv[0], (const char* const*)argv);
306                 break;
307             }
308             if(status != -1 || errno == 0)
309                 needToTry = FALSE;
310         }
311         Safefree(argv);
312         Safefree(cmd2);
313     }
314     if(needToTry) {
315         char *argv[5];
316         int i = 0;
317         argv[i++] = shell;
318         if (IsWinNT())
319             argv[i++] = "/x";
320         argv[i++] = "/c"; argv[i++] = cmd; argv[i] = Nullch;
321         switch (exectype) {
322         case EXECF_SPAWN:
323             status = win32_spawnvp(P_WAIT, argv[0],
324                                    (const char* const*)argv);
325             break;
326         case EXECF_SPAWN_NOWAIT:
327             status = win32_spawnvp(P_NOWAIT, argv[0],
328                                    (const char* const*)argv);
329             break;
330         case EXECF_EXEC:
331             status = win32_execvp(argv[0], (const char* const*)argv);
332             break;
333         }
334     }
335     if (status < 0) {
336         if (dowarn)
337             warn("Can't %s \"%s\": %s",
338                  (exectype == EXECF_EXEC ? "exec" : "spawn"),
339                  needToTry ? shell : argv[0],
340                  strerror(errno));
341         status = 255 << 8;
342     }
343     return (status);
344 }
345
346 int
347 do_spawn(char *cmd)
348 {
349     return do_spawn2(cmd, EXECF_SPAWN);
350 }
351
352 bool
353 do_exec(char *cmd)
354 {
355     do_spawn2(cmd, EXECF_EXEC);
356     return FALSE;
357 }
358
359
360 #define PATHLEN 1024
361
362 /* The idea here is to read all the directory names into a string table
363  * (separated by nulls) and when one of the other dir functions is called
364  * return the pointer to the current file name.
365  */
366 DIR *
367 opendir(char *filename)
368 {
369     DIR            *p;
370     long            len;
371     long            idx;
372     char            scannamespc[PATHLEN];
373     char       *scanname = scannamespc;
374     struct stat     sbuf;
375     WIN32_FIND_DATA FindData;
376     HANDLE          fh;
377 /*  char            root[_MAX_PATH];*/
378 /*  char            volname[_MAX_PATH];*/
379 /*  DWORD           serial, maxname, flags;*/
380 /*  BOOL            downcase;*/
381 /*  char           *dummy;*/
382
383     /* check to see if filename is a directory */
384     if (win32_stat(filename, &sbuf) < 0 || (sbuf.st_mode & S_IFDIR) == 0) {
385         return NULL;
386     }
387
388     /* get the file system characteristics */
389 /*  if(GetFullPathName(filename, MAX_PATH, root, &dummy)) {
390  *      if(dummy = strchr(root, '\\'))
391  *          *++dummy = '\0';
392  *      if(GetVolumeInformation(root, volname, MAX_PATH, &serial,
393  *                              &maxname, &flags, 0, 0)) {
394  *          downcase = !(flags & FS_CASE_IS_PRESERVED);
395  *      }
396  *  }
397  *  else {
398  *      downcase = TRUE;
399  *  }
400  */
401     /* Get us a DIR structure */
402     Newz(1303, p, 1, DIR);
403     if(p == NULL)
404         return NULL;
405
406     /* Create the search pattern */
407     strcpy(scanname, filename);
408
409     if(index("/\\", *(scanname + strlen(scanname) - 1)) == NULL)
410         strcat(scanname, "/*");
411     else
412         strcat(scanname, "*");
413
414     /* do the FindFirstFile call */
415     fh = FindFirstFile(scanname, &FindData);
416     if(fh == INVALID_HANDLE_VALUE) {
417         return NULL;
418     }
419
420     /* now allocate the first part of the string table for
421      * the filenames that we find.
422      */
423     idx = strlen(FindData.cFileName)+1;
424     New(1304, p->start, idx, char);
425     if(p->start == NULL) {
426         croak("opendir: malloc failed!\n");
427     }
428     strcpy(p->start, FindData.cFileName);
429 /*  if(downcase)
430  *      strlwr(p->start);
431  */
432     p->nfiles++;
433
434     /* loop finding all the files that match the wildcard
435      * (which should be all of them in this directory!).
436      * the variable idx should point one past the null terminator
437      * of the previous string found.
438      */
439     while (FindNextFile(fh, &FindData)) {
440         len = strlen(FindData.cFileName);
441         /* bump the string table size by enough for the
442          * new name and it's null terminator
443          */
444         Renew(p->start, idx+len+1, char);
445         if(p->start == NULL) {
446             croak("opendir: malloc failed!\n");
447         }
448         strcpy(&p->start[idx], FindData.cFileName);
449 /*      if (downcase) 
450  *          strlwr(&p->start[idx]);
451  */
452                 p->nfiles++;
453                 idx += len+1;
454         }
455         FindClose(fh);
456         p->size = idx;
457         p->curr = p->start;
458         return p;
459 }
460
461
462 /* Readdir just returns the current string pointer and bumps the
463  * string pointer to the nDllExport entry.
464  */
465 struct direct *
466 readdir(DIR *dirp)
467 {
468     int         len;
469     static int  dummy = 0;
470
471     if (dirp->curr) {
472         /* first set up the structure to return */
473         len = strlen(dirp->curr);
474         strcpy(dirp->dirstr.d_name, dirp->curr);
475         dirp->dirstr.d_namlen = len;
476
477         /* Fake an inode */
478         dirp->dirstr.d_ino = dummy++;
479
480         /* Now set up for the nDllExport call to readdir */
481         dirp->curr += len + 1;
482         if (dirp->curr >= (dirp->start + dirp->size)) {
483             dirp->curr = NULL;
484         }
485
486         return &(dirp->dirstr);
487     } 
488     else
489         return NULL;
490 }
491
492 /* Telldir returns the current string pointer position */
493 long
494 telldir(DIR *dirp)
495 {
496     return (long) dirp->curr;
497 }
498
499
500 /* Seekdir moves the string pointer to a previously saved position
501  *(Saved by telldir).
502  */
503 void
504 seekdir(DIR *dirp, long loc)
505 {
506     dirp->curr = (char *)loc;
507 }
508
509 /* Rewinddir resets the string pointer to the start */
510 void
511 rewinddir(DIR *dirp)
512 {
513     dirp->curr = dirp->start;
514 }
515
516 /* free the memory allocated by opendir */
517 int
518 closedir(DIR *dirp)
519 {
520     Safefree(dirp->start);
521     Safefree(dirp);
522     return 1;
523 }
524
525
526 /*
527  * various stubs
528  */
529
530
531 /* Ownership
532  *
533  * Just pretend that everyone is a superuser. NT will let us know if
534  * we don\'t really have permission to do something.
535  */
536
537 #define ROOT_UID    ((uid_t)0)
538 #define ROOT_GID    ((gid_t)0)
539
540 uid_t
541 getuid(void)
542 {
543     return ROOT_UID;
544 }
545
546 uid_t
547 geteuid(void)
548 {
549     return ROOT_UID;
550 }
551
552 gid_t
553 getgid(void)
554 {
555     return ROOT_GID;
556 }
557
558 gid_t
559 getegid(void)
560 {
561     return ROOT_GID;
562 }
563
564 int
565 setuid(uid_t auid)
566
567     return (auid == ROOT_UID ? 0 : -1);
568 }
569
570 int
571 setgid(gid_t agid)
572 {
573     return (agid == ROOT_GID ? 0 : -1);
574 }
575
576 /*
577  * pretended kill
578  */
579 int
580 kill(int pid, int sig)
581 {
582     HANDLE hProcess= OpenProcess(PROCESS_ALL_ACCESS, TRUE, pid);
583
584     if (hProcess == NULL) {
585         croak("kill process failed!\n");
586     }
587     else {
588         if (!TerminateProcess(hProcess, sig))
589             croak("kill process failed!\n");
590         CloseHandle(hProcess);
591     }
592     return 0;
593 }
594       
595 /*
596  * File system stuff
597  */
598
599 #if 0
600 int
601 ioctl(int i, unsigned int u, char *data)
602 {
603     croak("ioctl not implemented!\n");
604     return -1;
605 }
606 #endif
607
608 DllExport unsigned int
609 win32_sleep(unsigned int t)
610 {
611     Sleep(t*1000);
612     return 0;
613 }
614
615 DllExport int
616 win32_stat(const char *path, struct stat *buffer)
617 {
618     char                t[MAX_PATH]; 
619     const char  *p = path;
620     int         l = strlen(path);
621     int         res;
622
623     if (l > 1) {
624         switch(path[l - 1]) {
625         case '\\':
626         case '/':
627             if (path[l - 2] != ':') {
628                 strncpy(t, path, l - 1);
629                 t[l - 1] = 0;
630                 p = t;
631             };
632         }
633     }
634     res = stat(p,buffer);
635 #ifdef __BORLANDC__
636     if (res == 0) {
637         if (S_ISDIR(buffer->st_mode))
638             buffer->st_mode |= S_IWRITE | S_IEXEC;
639         else if (S_ISREG(buffer->st_mode)) {
640             if (l >= 4 && path[l-4] == '.') {
641                 const char *e = path + l - 3;
642                 if (strnicmp(e,"exe",3)
643                     && strnicmp(e,"bat",3)
644                     && strnicmp(e,"com",3)
645                     && (IsWin95() || strnicmp(e,"cmd",3)))
646                     buffer->st_mode &= ~S_IEXEC;
647                 else
648                     buffer->st_mode |= S_IEXEC;
649             }
650             else
651                 buffer->st_mode &= ~S_IEXEC;
652         }
653     }
654 #endif
655     return res;
656 }
657
658 #ifndef USE_WIN32_RTL_ENV
659
660 DllExport char *
661 win32_getenv(const char *name)
662 {
663     static char *curitem = Nullch;
664     static DWORD curlen = 512;
665     DWORD needlen;
666     if (!curitem)
667         New(1305,curitem,curlen,char);
668     if (!(needlen = GetEnvironmentVariable(name,curitem,curlen)))
669         return Nullch;
670     while (needlen > curlen) {
671         Renew(curitem,needlen,char);
672         curlen = needlen;
673         needlen = GetEnvironmentVariable(name,curitem,curlen);
674     }
675     return curitem;
676 }
677
678 #endif
679
680 static long
681 FileTimeToClock(PFILETIME ft)
682 {
683  __int64 qw = ft->dwHighDateTime;
684  qw <<= 32;
685  qw |= ft->dwLowDateTime;
686  qw /= 10000;  /* File time ticks at 0.1uS, clock at 1mS */
687  return (long) qw;
688 }
689
690 DllExport int
691 win32_times(struct tms *timebuf)
692 {
693     FILETIME user;
694     FILETIME kernel;
695     FILETIME dummy;
696     if (GetProcessTimes(GetCurrentProcess(), &dummy, &dummy, 
697                         &kernel,&user)) {
698         timebuf->tms_utime = FileTimeToClock(&user);
699         timebuf->tms_stime = FileTimeToClock(&kernel);
700         timebuf->tms_cutime = 0;
701         timebuf->tms_cstime = 0;
702         
703     } else { 
704         /* That failed - e.g. Win95 fallback to clock() */
705         clock_t t = clock();
706         timebuf->tms_utime = t;
707         timebuf->tms_stime = 0;
708         timebuf->tms_cutime = 0;
709         timebuf->tms_cstime = 0;
710     }
711     return 0;
712 }
713
714 static UINT timerid = 0;
715
716
717 static VOID CALLBACK TimerProc(HWND win, UINT msg, UINT id, DWORD time)
718 {
719  KillTimer(NULL,timerid);
720  timerid=0;  
721  sighandler(14);
722 }
723
724 DllExport unsigned int
725 win32_alarm(unsigned int sec)
726 {
727     /* 
728      * the 'obvious' implentation is SetTimer() with a callback
729      * which does whatever receiving SIGALRM would do 
730      * we cannot use SIGALRM even via raise() as it is not 
731      * one of the supported codes in <signal.h>
732      *
733      * Snag is unless something is looking at the message queue
734      * nothing happens :-(
735      */ 
736     if (sec)
737      {
738       timerid = SetTimer(NULL,timerid,sec*1000,(TIMERPROC)TimerProc);
739       if (!timerid)
740        croak("Cannot set timer");
741      } 
742     else
743      {
744       if (timerid)
745        {
746         KillTimer(NULL,timerid);
747         timerid=0;  
748        }
749      }
750     return 0;
751 }
752
753 #ifdef HAVE_DES_FCRYPT
754 extern char *   des_fcrypt(char *cbuf, const char *txt, const char *salt);
755
756 DllExport char *
757 win32_crypt(const char *txt, const char *salt)
758 {
759     dTHR;
760     return des_fcrypt(crypt_buffer, txt, salt);
761 }
762 #endif
763
764 #ifdef USE_FIXED_OSFHANDLE
765
766 EXTERN_C int __cdecl _alloc_osfhnd(void);
767 EXTERN_C int __cdecl _set_osfhnd(int fh, long value);
768 EXTERN_C void __cdecl _lock_fhandle(int);
769 EXTERN_C void __cdecl _unlock_fhandle(int);
770 EXTERN_C void __cdecl _unlock(int);
771
772 #if     (_MSC_VER >= 1000)
773 typedef struct  {
774     long osfhnd;    /* underlying OS file HANDLE */
775     char osfile;    /* attributes of file (e.g., open in text mode?) */
776     char pipech;    /* one char buffer for handles opened on pipes */
777 #if defined (_MT) && !defined (DLL_FOR_WIN32S)
778     int lockinitflag;
779     CRITICAL_SECTION lock;
780 #endif  /* defined (_MT) && !defined (DLL_FOR_WIN32S) */
781 }       ioinfo;
782
783 EXTERN_C ioinfo * __pioinfo[];
784
785 #define IOINFO_L2E                      5
786 #define IOINFO_ARRAY_ELTS       (1 << IOINFO_L2E)
787 #define _pioinfo(i)     (__pioinfo[i >> IOINFO_L2E] + (i & (IOINFO_ARRAY_ELTS - 1)))
788 #define _osfile(i)      (_pioinfo(i)->osfile)
789
790 #else   /* (_MSC_VER >= 1000) */
791 extern char _osfile[];
792 #endif  /* (_MSC_VER >= 1000) */
793
794 #define FOPEN                   0x01    /* file handle open */
795 #define FAPPEND                 0x20    /* file handle opened O_APPEND */
796 #define FDEV                    0x40    /* file handle refers to device */
797 #define FTEXT                   0x80    /* file handle is in text mode */
798
799 #define _STREAM_LOCKS   26              /* Table of stream locks */
800 #define _LAST_STREAM_LOCK  (_STREAM_LOCKS+_NSTREAM_-1)  /* Last stream lock */
801 #define _FH_LOCKS          (_LAST_STREAM_LOCK+1)        /* Table of fh locks */
802
803 /***
804 *int my_open_osfhandle(long osfhandle, int flags) - open C Runtime file handle
805 *
806 *Purpose:
807 *       This function allocates a free C Runtime file handle and associates
808 *       it with the Win32 HANDLE specified by the first parameter. This is a
809 *               temperary fix for WIN95's brain damage GetFileType() error on socket
810 *               we just bypass that call for socket
811 *
812 *Entry:
813 *       long osfhandle - Win32 HANDLE to associate with C Runtime file handle.
814 *       int flags      - flags to associate with C Runtime file handle.
815 *
816 *Exit:
817 *       returns index of entry in fh, if successful
818 *       return -1, if no free entry is found
819 *
820 *Exceptions:
821 *
822 *******************************************************************************/
823
824 static int
825 my_open_osfhandle(long osfhandle, int flags)
826 {
827     int fh;
828     char fileflags;             /* _osfile flags */
829
830     /* copy relevant flags from second parameter */
831     fileflags = FDEV;
832
833     if(flags & O_APPEND)
834         fileflags |= FAPPEND;
835
836     if(flags & O_TEXT)
837         fileflags |= FTEXT;
838
839     /* attempt to allocate a C Runtime file handle */
840     if((fh = _alloc_osfhnd()) == -1) {
841         errno = EMFILE;         /* too many open files */
842         _doserrno = 0L;         /* not an OS error */
843         return -1;              /* return error to caller */
844     }
845
846     /* the file is open. now, set the info in _osfhnd array */
847     _set_osfhnd(fh, osfhandle);
848
849     fileflags |= FOPEN;         /* mark as open */
850
851 #if (_MSC_VER >= 1000)
852     _osfile(fh) = fileflags;    /* set osfile entry */
853     _unlock_fhandle(fh);
854 #else
855     _osfile[fh] = fileflags;    /* set osfile entry */
856     _unlock(fh+_FH_LOCKS);              /* unlock handle */
857 #endif
858
859     return fh;                  /* return handle */
860 }
861
862 #define _open_osfhandle my_open_osfhandle
863 #endif  /* USE_FIXED_OSFHANDLE */
864
865 /* simulate flock by locking a range on the file */
866
867 #define LK_ERR(f,i)     ((f) ? (i = 0) : (errno = GetLastError()))
868 #define LK_LEN          0xffff0000
869
870 DllExport int
871 win32_flock(int fd, int oper)
872 {
873     OVERLAPPED o;
874     int i = -1;
875     HANDLE fh;
876
877     if (!IsWinNT()) {
878         croak("flock() unimplemented on this platform");
879         return -1;
880     }
881     fh = (HANDLE)_get_osfhandle(fd);
882     memset(&o, 0, sizeof(o));
883
884     switch(oper) {
885     case LOCK_SH:               /* shared lock */
886         LK_ERR(LockFileEx(fh, 0, 0, LK_LEN, 0, &o),i);
887         break;
888     case LOCK_EX:               /* exclusive lock */
889         LK_ERR(LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, LK_LEN, 0, &o),i);
890         break;
891     case LOCK_SH|LOCK_NB:       /* non-blocking shared lock */
892         LK_ERR(LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY, 0, LK_LEN, 0, &o),i);
893         break;
894     case LOCK_EX|LOCK_NB:       /* non-blocking exclusive lock */
895         LK_ERR(LockFileEx(fh,
896                        LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY,
897                        0, LK_LEN, 0, &o),i);
898         break;
899     case LOCK_UN:               /* unlock lock */
900         LK_ERR(UnlockFileEx(fh, 0, LK_LEN, 0, &o),i);
901         break;
902     default:                    /* unknown */
903         errno = EINVAL;
904         break;
905     }
906     return i;
907 }
908
909 #undef LK_ERR
910 #undef LK_LEN
911
912 /*
913  *  redirected io subsystem for all XS modules
914  *
915  */
916
917 DllExport int *
918 win32_errno(void)
919 {
920     return (&errno);
921 }
922
923 DllExport char ***
924 win32_environ(void)
925 {
926     return (&(_environ));
927 }
928
929 /* the rest are the remapped stdio routines */
930 DllExport FILE *
931 win32_stderr(void)
932 {
933     return (stderr);
934 }
935
936 DllExport FILE *
937 win32_stdin(void)
938 {
939     return (stdin);
940 }
941
942 DllExport FILE *
943 win32_stdout()
944 {
945     return (stdout);
946 }
947
948 DllExport int
949 win32_ferror(FILE *fp)
950 {
951     return (ferror(fp));
952 }
953
954
955 DllExport int
956 win32_feof(FILE *fp)
957 {
958     return (feof(fp));
959 }
960
961 /*
962  * Since the errors returned by the socket error function 
963  * WSAGetLastError() are not known by the library routine strerror
964  * we have to roll our own.
965  */
966
967 DllExport char *
968 win32_strerror(int e) 
969 {
970 #ifndef __BORLANDC__            /* Borland intolerance */
971     extern int sys_nerr;
972 #endif
973     DWORD source = 0;
974
975     if(e < 0 || e > sys_nerr) {
976         dTHR;
977         if(e < 0)
978             e = GetLastError();
979
980         if(FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, &source, e, 0,
981                          strerror_buffer, sizeof(strerror_buffer), NULL) == 0) 
982             strcpy(strerror_buffer, "Unknown Error");
983
984         return strerror_buffer;
985     }
986     return strerror(e);
987 }
988
989 DllExport int
990 win32_fprintf(FILE *fp, const char *format, ...)
991 {
992     va_list marker;
993     va_start(marker, format);     /* Initialize variable arguments. */
994
995     return (vfprintf(fp, format, marker));
996 }
997
998 DllExport int
999 win32_printf(const char *format, ...)
1000 {
1001     va_list marker;
1002     va_start(marker, format);     /* Initialize variable arguments. */
1003
1004     return (vprintf(format, marker));
1005 }
1006
1007 DllExport int
1008 win32_vfprintf(FILE *fp, const char *format, va_list args)
1009 {
1010     return (vfprintf(fp, format, args));
1011 }
1012
1013 DllExport int
1014 win32_vprintf(const char *format, va_list args)
1015 {
1016     return (vprintf(format, args));
1017 }
1018
1019 DllExport size_t
1020 win32_fread(void *buf, size_t size, size_t count, FILE *fp)
1021 {
1022     return fread(buf, size, count, fp);
1023 }
1024
1025 DllExport size_t
1026 win32_fwrite(const void *buf, size_t size, size_t count, FILE *fp)
1027 {
1028     return fwrite(buf, size, count, fp);
1029 }
1030
1031 DllExport FILE *
1032 win32_fopen(const char *filename, const char *mode)
1033 {
1034     if (stricmp(filename, "/dev/null")==0)
1035         return fopen("NUL", mode);
1036     return fopen(filename, mode);
1037 }
1038
1039 #ifndef USE_SOCKETS_AS_HANDLES
1040 #undef fdopen
1041 #define fdopen my_fdopen
1042 #endif
1043
1044 DllExport FILE *
1045 win32_fdopen( int handle, const char *mode)
1046 {
1047     return fdopen(handle, (char *) mode);
1048 }
1049
1050 DllExport FILE *
1051 win32_freopen( const char *path, const char *mode, FILE *stream)
1052 {
1053     if (stricmp(path, "/dev/null")==0)
1054         return freopen("NUL", mode, stream);
1055     return freopen(path, mode, stream);
1056 }
1057
1058 DllExport int
1059 win32_fclose(FILE *pf)
1060 {
1061     return my_fclose(pf);       /* defined in win32sck.c */
1062 }
1063
1064 DllExport int
1065 win32_fputs(const char *s,FILE *pf)
1066 {
1067     return fputs(s, pf);
1068 }
1069
1070 DllExport int
1071 win32_fputc(int c,FILE *pf)
1072 {
1073     return fputc(c,pf);
1074 }
1075
1076 DllExport int
1077 win32_ungetc(int c,FILE *pf)
1078 {
1079     return ungetc(c,pf);
1080 }
1081
1082 DllExport int
1083 win32_getc(FILE *pf)
1084 {
1085     return getc(pf);
1086 }
1087
1088 DllExport int
1089 win32_fileno(FILE *pf)
1090 {
1091     return fileno(pf);
1092 }
1093
1094 DllExport void
1095 win32_clearerr(FILE *pf)
1096 {
1097     clearerr(pf);
1098     return;
1099 }
1100
1101 DllExport int
1102 win32_fflush(FILE *pf)
1103 {
1104     return fflush(pf);
1105 }
1106
1107 DllExport long
1108 win32_ftell(FILE *pf)
1109 {
1110     return ftell(pf);
1111 }
1112
1113 DllExport int
1114 win32_fseek(FILE *pf,long offset,int origin)
1115 {
1116     return fseek(pf, offset, origin);
1117 }
1118
1119 DllExport int
1120 win32_fgetpos(FILE *pf,fpos_t *p)
1121 {
1122     return fgetpos(pf, p);
1123 }
1124
1125 DllExport int
1126 win32_fsetpos(FILE *pf,const fpos_t *p)
1127 {
1128     return fsetpos(pf, p);
1129 }
1130
1131 DllExport void
1132 win32_rewind(FILE *pf)
1133 {
1134     rewind(pf);
1135     return;
1136 }
1137
1138 DllExport FILE*
1139 win32_tmpfile(void)
1140 {
1141     return tmpfile();
1142 }
1143
1144 DllExport void
1145 win32_abort(void)
1146 {
1147     abort();
1148     return;
1149 }
1150
1151 DllExport int
1152 win32_fstat(int fd,struct stat *sbufptr)
1153 {
1154     return fstat(fd,sbufptr);
1155 }
1156
1157 DllExport int
1158 win32_pipe(int *pfd, unsigned int size, int mode)
1159 {
1160     return _pipe(pfd, size, mode);
1161 }
1162
1163 DllExport FILE*
1164 win32_popen(const char *command, const char *mode)
1165 {
1166     return _popen(command, mode);
1167 }
1168
1169 DllExport int
1170 win32_pclose(FILE *pf)
1171 {
1172     return _pclose(pf);
1173 }
1174
1175 DllExport int
1176 win32_setmode(int fd, int mode)
1177 {
1178     return setmode(fd, mode);
1179 }
1180
1181 DllExport long
1182 win32_lseek(int fd, long offset, int origin)
1183 {
1184     return lseek(fd, offset, origin);
1185 }
1186
1187 DllExport long
1188 win32_tell(int fd)
1189 {
1190     return tell(fd);
1191 }
1192
1193 DllExport int
1194 win32_open(const char *path, int flag, ...)
1195 {
1196     va_list ap;
1197     int pmode;
1198
1199     va_start(ap, flag);
1200     pmode = va_arg(ap, int);
1201     va_end(ap);
1202
1203     if (stricmp(path, "/dev/null")==0)
1204         return open("NUL", flag, pmode);
1205     return open(path,flag,pmode);
1206 }
1207
1208 DllExport int
1209 win32_close(int fd)
1210 {
1211     return close(fd);
1212 }
1213
1214 DllExport int
1215 win32_eof(int fd)
1216 {
1217     return eof(fd);
1218 }
1219
1220 DllExport int
1221 win32_dup(int fd)
1222 {
1223     return dup(fd);
1224 }
1225
1226 DllExport int
1227 win32_dup2(int fd1,int fd2)
1228 {
1229     return dup2(fd1,fd2);
1230 }
1231
1232 DllExport int
1233 win32_read(int fd, void *buf, unsigned int cnt)
1234 {
1235     return read(fd, buf, cnt);
1236 }
1237
1238 DllExport int
1239 win32_write(int fd, const void *buf, unsigned int cnt)
1240 {
1241     return write(fd, buf, cnt);
1242 }
1243
1244 DllExport int
1245 win32_mkdir(const char *dir, int mode)
1246 {
1247     return mkdir(dir); /* just ignore mode */
1248 }
1249
1250 DllExport int
1251 win32_rmdir(const char *dir)
1252 {
1253     return rmdir(dir);
1254 }
1255
1256 DllExport int
1257 win32_chdir(const char *dir)
1258 {
1259     return chdir(dir);
1260 }
1261
1262 DllExport int
1263 win32_spawnvp(int mode, const char *cmdname, const char *const *argv)
1264 {
1265     return spawnvp(mode, cmdname, (char * const *) argv);
1266 }
1267
1268 DllExport int
1269 win32_execvp(const char *cmdname, const char *const *argv)
1270 {
1271     return execvp(cmdname, (char *const *)argv);
1272 }
1273
1274 DllExport void
1275 win32_perror(const char *str)
1276 {
1277     perror(str);
1278 }
1279
1280 DllExport void
1281 win32_setbuf(FILE *pf, char *buf)
1282 {
1283     setbuf(pf, buf);
1284 }
1285
1286 DllExport int
1287 win32_setvbuf(FILE *pf, char *buf, int type, size_t size)
1288 {
1289     return setvbuf(pf, buf, type, size);
1290 }
1291
1292 DllExport int
1293 win32_flushall(void)
1294 {
1295     return flushall();
1296 }
1297
1298 DllExport int
1299 win32_fcloseall(void)
1300 {
1301     return fcloseall();
1302 }
1303
1304 DllExport char*
1305 win32_fgets(char *s, int n, FILE *pf)
1306 {
1307     return fgets(s, n, pf);
1308 }
1309
1310 DllExport char*
1311 win32_gets(char *s)
1312 {
1313     return gets(s);
1314 }
1315
1316 DllExport int
1317 win32_fgetc(FILE *pf)
1318 {
1319     return fgetc(pf);
1320 }
1321
1322 DllExport int
1323 win32_putc(int c, FILE *pf)
1324 {
1325     return putc(c,pf);
1326 }
1327
1328 DllExport int
1329 win32_puts(const char *s)
1330 {
1331     return puts(s);
1332 }
1333
1334 DllExport int
1335 win32_getchar(void)
1336 {
1337     return getchar();
1338 }
1339
1340 DllExport int
1341 win32_putchar(int c)
1342 {
1343     return putchar(c);
1344 }
1345
1346 #ifdef MYMALLOC
1347
1348 #ifndef USE_PERL_SBRK
1349
1350 static char *committed = NULL;
1351 static char *base      = NULL;
1352 static char *reserved  = NULL;
1353 static char *brk       = NULL;
1354 static DWORD pagesize  = 0;
1355 static DWORD allocsize = 0;
1356
1357 void *
1358 sbrk(int need)
1359 {
1360  void *result;
1361  if (!pagesize)
1362   {SYSTEM_INFO info;
1363    GetSystemInfo(&info);
1364    /* Pretend page size is larger so we don't perpetually
1365     * call the OS to commit just one page ...
1366     */
1367    pagesize = info.dwPageSize << 3;
1368    allocsize = info.dwAllocationGranularity;
1369   }
1370  /* This scheme fails eventually if request for contiguous
1371   * block is denied so reserve big blocks - this is only 
1372   * address space not memory ...
1373   */
1374  if (brk+need >= reserved)
1375   {
1376    DWORD size = 64*1024*1024;
1377    char *addr;
1378    if (committed && reserved && committed < reserved)
1379     {
1380      /* Commit last of previous chunk cannot span allocations */
1381      addr = (char *) VirtualAlloc(committed,reserved-committed,MEM_COMMIT,PAGE_READWRITE);
1382      if (addr)
1383       committed = reserved;
1384     }
1385    /* Reserve some (more) space 
1386     * Note this is a little sneaky, 1st call passes NULL as reserved
1387     * so lets system choose where we start, subsequent calls pass
1388     * the old end address so ask for a contiguous block
1389     */
1390    addr  = (char *) VirtualAlloc(reserved,size,MEM_RESERVE,PAGE_NOACCESS);
1391    if (addr)
1392     {
1393      reserved = addr+size;
1394      if (!base)
1395       base = addr;
1396      if (!committed)
1397       committed = base;
1398      if (!brk)
1399       brk = committed;
1400     }
1401    else
1402     {
1403      return (void *) -1;
1404     }
1405   }
1406  result = brk;
1407  brk += need;
1408  if (brk > committed)
1409   {
1410    DWORD size = ((brk-committed + pagesize -1)/pagesize) * pagesize;
1411    char *addr = (char *) VirtualAlloc(committed,size,MEM_COMMIT,PAGE_READWRITE);
1412    if (addr)
1413     {
1414      committed += size;
1415     }
1416    else
1417     return (void *) -1;
1418   }
1419  return result;
1420 }
1421
1422 #endif
1423 #endif
1424
1425 DllExport void*
1426 win32_malloc(size_t size)
1427 {
1428     return malloc(size);
1429 }
1430
1431 DllExport void*
1432 win32_calloc(size_t numitems, size_t size)
1433 {
1434     return calloc(numitems,size);
1435 }
1436
1437 DllExport void*
1438 win32_realloc(void *block, size_t size)
1439 {
1440     return realloc(block,size);
1441 }
1442
1443 DllExport void
1444 win32_free(void *block)
1445 {
1446     free(block);
1447 }
1448
1449
1450 int
1451 win32_open_osfhandle(long handle, int flags)
1452 {
1453     return _open_osfhandle(handle, flags);
1454 }
1455
1456 long
1457 win32_get_osfhandle(int fd)
1458 {
1459     return _get_osfhandle(fd);
1460 }
1461
1462 /*
1463  * Extras.
1464  */
1465
1466 static
1467 XS(w32_GetCwd)
1468 {
1469     dXSARGS;
1470     SV *sv = sv_newmortal();
1471     /* Make one call with zero size - return value is required size */
1472     DWORD len = GetCurrentDirectory((DWORD)0,NULL);
1473     SvUPGRADE(sv,SVt_PV);
1474     SvGROW(sv,len);
1475     SvCUR(sv) = GetCurrentDirectory((DWORD) SvLEN(sv), SvPVX(sv));
1476     /* 
1477      * If result != 0 
1478      *   then it worked, set PV valid, 
1479      *   else leave it 'undef' 
1480      */
1481     if (SvCUR(sv))
1482         SvPOK_on(sv);
1483     EXTEND(sp,1);
1484     ST(0) = sv;
1485     XSRETURN(1);
1486 }
1487
1488 static
1489 XS(w32_SetCwd)
1490 {
1491     dXSARGS;
1492     if (items != 1)
1493         croak("usage: Win32::SetCurrentDirectory($cwd)");
1494     if (SetCurrentDirectory(SvPV(ST(0),na)))
1495         XSRETURN_YES;
1496
1497     XSRETURN_NO;
1498 }
1499
1500 static
1501 XS(w32_GetNextAvailDrive)
1502 {
1503     dXSARGS;
1504     char ix = 'C';
1505     char root[] = "_:\\";
1506     while (ix <= 'Z') {
1507         root[0] = ix++;
1508         if (GetDriveType(root) == 1) {
1509             root[2] = '\0';
1510             XSRETURN_PV(root);
1511         }
1512     }
1513     XSRETURN_UNDEF;
1514 }
1515
1516 static
1517 XS(w32_GetLastError)
1518 {
1519     dXSARGS;
1520     XSRETURN_IV(GetLastError());
1521 }
1522
1523 static
1524 XS(w32_LoginName)
1525 {
1526     dXSARGS;
1527     char name[256];
1528     DWORD size = sizeof(name);
1529     if (GetUserName(name,&size)) {
1530         /* size includes NULL */
1531         ST(0) = sv_2mortal(newSVpv(name,size-1));
1532         XSRETURN(1);
1533     }
1534     XSRETURN_UNDEF;
1535 }
1536
1537 static
1538 XS(w32_NodeName)
1539 {
1540     dXSARGS;
1541     char name[MAX_COMPUTERNAME_LENGTH+1];
1542     DWORD size = sizeof(name);
1543     if (GetComputerName(name,&size)) {
1544         /* size does NOT include NULL :-( */
1545         ST(0) = sv_2mortal(newSVpv(name,size));
1546         XSRETURN(1);
1547     }
1548     XSRETURN_UNDEF;
1549 }
1550
1551
1552 static
1553 XS(w32_DomainName)
1554 {
1555     dXSARGS;
1556     char name[256];
1557     DWORD size = sizeof(name);
1558     if (GetUserName(name,&size)) {
1559         char sid[1024];
1560         DWORD sidlen = sizeof(sid);
1561         char dname[256];
1562         DWORD dnamelen = sizeof(dname);
1563         SID_NAME_USE snu;
1564         if (LookupAccountName(NULL, name, &sid, &sidlen,
1565                               dname, &dnamelen, &snu)) {
1566             XSRETURN_PV(dname);         /* all that for this */
1567         }
1568     }
1569     XSRETURN_UNDEF;
1570 }
1571
1572 static
1573 XS(w32_FsType)
1574 {
1575     dXSARGS;
1576     char fsname[256];
1577     DWORD flags, filecomplen;
1578     if (GetVolumeInformation(NULL, NULL, 0, NULL, &filecomplen,
1579                          &flags, fsname, sizeof(fsname))) {
1580         if (GIMME == G_ARRAY) {
1581             XPUSHs(sv_2mortal(newSVpv(fsname,0)));
1582             XPUSHs(sv_2mortal(newSViv(flags)));
1583             XPUSHs(sv_2mortal(newSViv(filecomplen)));
1584             PUTBACK;
1585             return;
1586         }
1587         XSRETURN_PV(fsname);
1588     }
1589     XSRETURN_UNDEF;
1590 }
1591
1592 static
1593 XS(w32_GetOSVersion)
1594 {
1595     dXSARGS;
1596     OSVERSIONINFO osver;
1597
1598     osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
1599     if (GetVersionEx(&osver)) {
1600         XPUSHs(newSVpv(osver.szCSDVersion, 0));
1601         XPUSHs(newSViv(osver.dwMajorVersion));
1602         XPUSHs(newSViv(osver.dwMinorVersion));
1603         XPUSHs(newSViv(osver.dwBuildNumber));
1604         XPUSHs(newSViv(osver.dwPlatformId));
1605         PUTBACK;
1606         return;
1607     }
1608     XSRETURN_UNDEF;
1609 }
1610
1611 static
1612 XS(w32_IsWinNT)
1613 {
1614     dXSARGS;
1615     XSRETURN_IV(IsWinNT());
1616 }
1617
1618 static
1619 XS(w32_IsWin95)
1620 {
1621     dXSARGS;
1622     XSRETURN_IV(IsWin95());
1623 }
1624
1625 static
1626 XS(w32_FormatMessage)
1627 {
1628     dXSARGS;
1629     DWORD source = 0;
1630     char msgbuf[1024];
1631
1632     if (items != 1)
1633         croak("usage: Win32::FormatMessage($errno)");
1634
1635     if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
1636                       &source, SvIV(ST(0)), 0,
1637                       msgbuf, sizeof(msgbuf)-1, NULL))
1638         XSRETURN_PV(msgbuf);
1639
1640     XSRETURN_UNDEF;
1641 }
1642
1643 static
1644 XS(w32_Spawn)
1645 {
1646     dXSARGS;
1647     char *cmd, *args;
1648     PROCESS_INFORMATION stProcInfo;
1649     STARTUPINFO stStartInfo;
1650     BOOL bSuccess = FALSE;
1651
1652     if(items != 3)
1653         croak("usage: Win32::Spawn($cmdName, $args, $PID)");
1654
1655     cmd = SvPV(ST(0),na);
1656     args = SvPV(ST(1), na);
1657
1658     memset(&stStartInfo, 0, sizeof(stStartInfo));   /* Clear the block */
1659     stStartInfo.cb = sizeof(stStartInfo);           /* Set the structure size */
1660     stStartInfo.dwFlags = STARTF_USESHOWWINDOW;     /* Enable wShowWindow control */
1661     stStartInfo.wShowWindow = SW_SHOWMINNOACTIVE;   /* Start min (normal) */
1662
1663     if(CreateProcess(
1664                 cmd,                    /* Image path */
1665                 args,                   /* Arguments for command line */
1666                 NULL,                   /* Default process security */
1667                 NULL,                   /* Default thread security */
1668                 FALSE,                  /* Must be TRUE to use std handles */
1669                 NORMAL_PRIORITY_CLASS,  /* No special scheduling */
1670                 NULL,                   /* Inherit our environment block */
1671                 NULL,                   /* Inherit our currrent directory */
1672                 &stStartInfo,           /* -> Startup info */
1673                 &stProcInfo))           /* <- Process info (if OK) */
1674     {
1675         CloseHandle(stProcInfo.hThread);/* library source code does this. */
1676         sv_setiv(ST(2), stProcInfo.dwProcessId);
1677         bSuccess = TRUE;
1678     }
1679     XSRETURN_IV(bSuccess);
1680 }
1681
1682 static
1683 XS(w32_GetTickCount)
1684 {
1685     dXSARGS;
1686     XSRETURN_IV(GetTickCount());
1687 }
1688
1689 static
1690 XS(w32_GetShortPathName)
1691 {
1692     dXSARGS;
1693     SV *shortpath;
1694     DWORD len;
1695
1696     if(items != 1)
1697         croak("usage: Win32::GetShortPathName($longPathName)");
1698
1699     shortpath = sv_mortalcopy(ST(0));
1700     SvUPGRADE(shortpath, SVt_PV);
1701     /* src == target is allowed */
1702     do {
1703         len = GetShortPathName(SvPVX(shortpath),
1704                                SvPVX(shortpath),
1705                                SvLEN(shortpath));
1706     } while (len >= SvLEN(shortpath) && sv_grow(shortpath,len+1));
1707     if (len) {
1708         SvCUR_set(shortpath,len);
1709         ST(0) = shortpath;
1710     }
1711     else
1712         ST(0) = &sv_undef;
1713     XSRETURN(1);
1714 }
1715
1716 void
1717 Perl_init_os_extras()
1718 {
1719     char *file = __FILE__;
1720     dXSUB_SYS;
1721
1722     /* XXX should be removed after checking with Nick */
1723     newXS("Win32::GetCurrentDirectory", w32_GetCwd, file);
1724
1725     /* these names are Activeware compatible */
1726     newXS("Win32::GetCwd", w32_GetCwd, file);
1727     newXS("Win32::SetCwd", w32_SetCwd, file);
1728     newXS("Win32::GetNextAvailDrive", w32_GetNextAvailDrive, file);
1729     newXS("Win32::GetLastError", w32_GetLastError, file);
1730     newXS("Win32::LoginName", w32_LoginName, file);
1731     newXS("Win32::NodeName", w32_NodeName, file);
1732     newXS("Win32::DomainName", w32_DomainName, file);
1733     newXS("Win32::FsType", w32_FsType, file);
1734     newXS("Win32::GetOSVersion", w32_GetOSVersion, file);
1735     newXS("Win32::IsWinNT", w32_IsWinNT, file);
1736     newXS("Win32::IsWin95", w32_IsWin95, file);
1737     newXS("Win32::FormatMessage", w32_FormatMessage, file);
1738     newXS("Win32::Spawn", w32_Spawn, file);
1739     newXS("Win32::GetTickCount", w32_GetTickCount, file);
1740     newXS("Win32::GetShortPathName", w32_GetShortPathName, file);
1741
1742     /* XXX Bloat Alert! The following Activeware preloads really
1743      * ought to be part of Win32::Sys::*, so they're not included
1744      * here.
1745      */
1746     /* LookupAccountName
1747      * LookupAccountSID
1748      * InitiateSystemShutdown
1749      * AbortSystemShutdown
1750      * ExpandEnvrironmentStrings
1751      */
1752 }
1753
1754 void
1755 Perl_win32_init(int *argcp, char ***argvp)
1756 {
1757     /* Disable floating point errors, Perl will trap the ones we
1758      * care about.  VC++ RTL defaults to switching these off
1759      * already, but the Borland RTL doesn't.  Since we don't
1760      * want to be at the vendor's whim on the default, we set
1761      * it explicitly here.
1762      */
1763 #if !defined(_ALPHA_) && !defined(__GNUC__)
1764     _control87(MCW_EM, MCW_EM);
1765 #endif
1766     MALLOC_INIT; 
1767 }
1768
1769 #ifdef USE_BINMODE_SCRIPTS
1770
1771 void
1772 win32_strip_return(SV *sv)
1773 {
1774  char *s = SvPVX(sv);
1775  char *e = s+SvCUR(sv);
1776  char *d = s;
1777  while (s < e)
1778   {
1779    if (*s == '\r' && s[1] == '\n')
1780     {
1781      *d++ = '\n';
1782      s += 2;
1783     }
1784    else 
1785     {
1786      *d++ = *s++;
1787     }   
1788   }
1789  SvCUR_set(sv,d-SvPVX(sv)); 
1790 }
1791
1792 #endif
1793
1794
1795
1796
1797
1798
1799
1800