21da8434dfc2eb7dac99221e7759e42a655fb674
[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 #  ifdef __cplusplus
17 #undef __attribute__            /* seems broken in 2.8.0 */
18 #define __attribute__(p)
19 #  endif
20 #endif
21 #include <windows.h>
22
23 #ifndef __MINGW32__
24 #include <lmcons.h>
25 #include <lmerr.h>
26 /* ugliness to work around a buggy struct definition in lmwksta.h */
27 #undef LPTSTR
28 #define LPTSTR LPWSTR
29 #include <lmwksta.h>
30 #undef LPTSTR
31 #define LPTSTR LPSTR
32 #include <lmapibuf.h>
33 #endif /* __MINGW32__ */
34
35 /* #include "config.h" */
36
37 #define PERLIO_NOT_STDIO 0 
38 #if !defined(PERLIO_IS_STDIO) && !defined(USE_SFIO)
39 #define PerlIO FILE
40 #endif
41
42 #include "EXTERN.h"
43 #include "perl.h"
44
45 #define NO_XSLOCKS
46 #ifdef PERL_OBJECT
47 extern CPerlObj* pPerl;
48 #endif
49 #include "XSUB.h"
50
51 #include "Win32iop.h"
52 #include <fcntl.h>
53 #include <sys/stat.h>
54 #ifndef __GNUC__
55 /* assert.h conflicts with #define of assert in perl.h */
56 #include <assert.h>
57 #endif
58 #include <string.h>
59 #include <stdarg.h>
60 #include <float.h>
61 #include <time.h>
62 #if defined(_MSC_VER) || defined(__MINGW32__)
63 #include <sys/utime.h>
64 #else
65 #include <utime.h>
66 #endif
67
68 #ifdef __GNUC__
69 /* Mingw32 defaults to globing command line 
70  * So we turn it off like this:
71  */
72 int _CRT_glob = 0;
73 #endif
74
75 #define EXECF_EXEC 1
76 #define EXECF_SPAWN 2
77 #define EXECF_SPAWN_NOWAIT 3
78
79 #if defined(PERL_OBJECT)
80 #undef win32_get_stdlib
81 #define win32_get_stdlib g_win32_get_stdlib
82 #undef win32_get_sitelib
83 #define win32_get_sitelib g_win32_get_sitelib
84 #undef do_aspawn
85 #define do_aspawn g_do_aspawn
86 #undef do_spawn
87 #define do_spawn g_do_spawn
88 #undef do_exec
89 #define do_exec g_do_exec
90 #undef opendir
91 #define opendir g_opendir
92 #undef readdir
93 #define readdir g_readdir
94 #undef telldir
95 #define telldir g_telldir
96 #undef seekdir
97 #define seekdir g_seekdir
98 #undef rewinddir
99 #define rewinddir g_rewinddir
100 #undef closedir
101 #define closedir g_closedir
102 #undef getlogin
103 #define getlogin g_getlogin
104 #endif
105
106 static DWORD            os_id(void);
107 static void             get_shell(void);
108 static long             tokenize(char *str, char **dest, char ***destv);
109         int             do_spawn2(char *cmd, int exectype);
110 static BOOL             has_redirection(char *ptr);
111 static long             filetime_to_clock(PFILETIME ft);
112 static BOOL             filetime_from_time(PFILETIME ft, time_t t);
113
114
115 HANDLE  w32_perldll_handle = INVALID_HANDLE_VALUE;
116 static DWORD    w32_platform = (DWORD)-1;
117
118 #ifdef USE_THREADS
119 #  ifdef USE_DECLSPEC_THREAD
120 __declspec(thread) char strerror_buffer[512];
121 __declspec(thread) char getlogin_buffer[128];
122 __declspec(thread) char w32_perllib_root[MAX_PATH+1];
123 #    ifdef HAVE_DES_FCRYPT
124 __declspec(thread) char crypt_buffer[30];
125 #    endif
126 #  else
127 #    define strerror_buffer     (thr->i.Wstrerror_buffer)
128 #    define getlogin_buffer     (thr->i.Wgetlogin_buffer)
129 #    define w32_perllib_root    (thr->i.Ww32_perllib_root)
130 #    define crypt_buffer        (thr->i.Wcrypt_buffer)
131 #  endif
132 #else
133 static char     strerror_buffer[512];
134 static char     getlogin_buffer[128];
135 static char     w32_perllib_root[MAX_PATH+1];
136 #  ifdef HAVE_DES_FCRYPT
137 static char     crypt_buffer[30];
138 #  endif
139 #endif
140
141 int 
142 IsWin95(void) {
143     return (os_id() == VER_PLATFORM_WIN32_WINDOWS);
144 }
145
146 int
147 IsWinNT(void) {
148     return (os_id() == VER_PLATFORM_WIN32_NT);
149 }
150
151 char*
152 GetRegStrFromKey(HKEY hkey, const char *lpszValueName, char** ptr, DWORD* lpDataLen)
153 {   /* Retrieve a REG_SZ or REG_EXPAND_SZ from the registry */
154     HKEY handle;
155     DWORD type;
156     const char *subkey = "Software\\Perl";
157     long retval;
158
159     retval = RegOpenKeyEx(hkey, subkey, 0, KEY_READ, &handle);
160     if (retval == ERROR_SUCCESS){
161         retval = RegQueryValueEx(handle, lpszValueName, 0, &type, NULL, lpDataLen);
162         if (retval == ERROR_SUCCESS && type == REG_SZ) {
163             if (*ptr != NULL) {
164                 Renew(*ptr, *lpDataLen, char);
165             }
166             else {
167                 New(1312, *ptr, *lpDataLen, char);
168             }
169             retval = RegQueryValueEx(handle, lpszValueName, 0, NULL, (PBYTE)*ptr, lpDataLen);
170             if (retval != ERROR_SUCCESS) {
171                 Safefree(ptr);
172                 ptr = NULL;
173             }
174         }
175         RegCloseKey(handle);
176     }
177     return *ptr;
178 }
179
180 char*
181 GetRegStr(const char *lpszValueName, char** ptr, DWORD* lpDataLen)
182 {
183     *ptr = GetRegStrFromKey(HKEY_CURRENT_USER, lpszValueName, ptr, lpDataLen);
184     if (*ptr == NULL)
185     {
186         *ptr = GetRegStrFromKey(HKEY_LOCAL_MACHINE, lpszValueName, ptr, lpDataLen);
187     }
188     return *ptr;
189 }
190
191 char *
192 win32_get_stdlib(char *pl)
193 {
194     static char szStdLib[] = "lib";
195     int len = 0, newSize;
196     char szBuffer[MAX_PATH+1];
197     char szModuleName[MAX_PATH];
198     int result;
199     DWORD dwDataLen;
200     char *lpPath = NULL;
201     char *ptr;
202
203     /* $stdlib = $HKCU{"lib-$]"} || $HKLM{"lib-$]"} || $HKCU{"lib"} || $HKLM{"lib"} || "";  */
204     sprintf(szBuffer, "%s-%s", szStdLib, pl);
205     lpPath = GetRegStr(szBuffer, &lpPath, &dwDataLen);
206     if (lpPath == NULL)
207         lpPath = GetRegStr(szStdLib, &lpPath, &dwDataLen);
208
209     /* $stdlib .= ";$EMD/../../lib" */
210     GetModuleFileName(GetModuleHandle(NULL), szModuleName, sizeof(szModuleName));
211     ptr = strrchr(szModuleName, '\\');
212     if (ptr != NULL)
213     {
214         *ptr = '\0';
215         ptr = strrchr(szModuleName, '\\');
216         if (ptr != NULL)
217         {
218             *ptr = '\0';
219             ptr = strrchr(szModuleName, '\\');
220         }
221     }
222     if (ptr == NULL)
223     {
224         ptr = szModuleName;
225         *ptr = '\\';
226     }
227     strcpy(++ptr, szStdLib);
228
229     /* check that this path exists */
230     GetCurrentDirectory(sizeof(szBuffer), szBuffer);
231     result = SetCurrentDirectory(szModuleName);
232     SetCurrentDirectory(szBuffer);
233     if (result == 0)
234     {
235         GetModuleFileName(GetModuleHandle(NULL), szModuleName, sizeof(szModuleName));
236         ptr = strrchr(szModuleName, '\\');
237         if (ptr != NULL)
238             strcpy(++ptr, szStdLib);
239     }
240
241     newSize = strlen(szModuleName) + 1;
242     if (lpPath != NULL)
243     {
244         len = strlen(lpPath);
245         newSize += len + 1; /* plus 1 for ';' */
246         lpPath = Renew(lpPath, newSize, char);
247     }
248     else
249         New(1310, lpPath, newSize, char);
250
251     if (lpPath != NULL)
252     {
253         if (len != 0)
254             lpPath[len++] = ';';
255         strcpy(&lpPath[len], szModuleName);
256     }
257     return lpPath;
258 }
259
260 char *
261 get_sitelib_part(char* lpRegStr, char* lpPathStr)
262 {
263     char szBuffer[MAX_PATH+1];
264     char szModuleName[MAX_PATH];
265     DWORD dwDataLen;
266     int len = 0;
267     int result;
268     char *lpPath = NULL;
269     char *ptr;
270
271     lpPath = GetRegStr(lpRegStr, &lpPath, &dwDataLen);
272
273     /* $sitelib .= ";$EMD/../../../<lpPathStr>" */
274     GetModuleFileName(GetModuleHandle(NULL), szModuleName, sizeof(szModuleName));
275     ptr = strrchr(szModuleName, '\\');
276     if (ptr != NULL)
277     {
278         *ptr = '\0';
279         ptr = strrchr(szModuleName, '\\');
280         if (ptr != NULL)
281         {
282             *ptr = '\0';
283             ptr = strrchr(szModuleName, '\\');
284             if (ptr != NULL)
285             {
286                 *ptr = '\0';
287                 ptr = strrchr(szModuleName, '\\');
288             }
289         }
290     }
291     if (ptr == NULL)
292     {
293         ptr = szModuleName;
294         *ptr = '\\';
295     }
296     strcpy(++ptr, lpPathStr);
297
298     /* check that this path exists */
299     GetCurrentDirectory(sizeof(szBuffer), szBuffer);
300     result = SetCurrentDirectory(szModuleName);
301     SetCurrentDirectory(szBuffer);
302
303     if (result)
304     {
305         int newSize = strlen(szModuleName) + 1;
306         if (lpPath != NULL)
307         {
308             len = strlen(lpPath);
309             newSize += len + 1; /* plus 1 for ';' */
310             lpPath = Renew(lpPath, newSize, char);
311         }
312         else
313             New(1311, lpPath, newSize, char);
314
315         if (lpPath != NULL)
316         {
317             if (len != 0)
318                 lpPath[len++] = ';';
319             strcpy(&lpPath[len], szModuleName);
320         }
321     }
322     return lpPath;
323 }
324
325 char *
326 win32_get_sitelib(char *pl)
327 {
328     static char szSiteLib[] = "sitelib";
329     char szRegStr[40];
330     char szPathStr[MAX_PATH];
331     char *lpPath1;
332     char *lpPath2;
333         int len, newSize;
334
335     /* $HKCU{"sitelib-$]"} || $HKLM{"sitelib-$]"} . ---; */
336     sprintf(szRegStr, "%s-%s", szSiteLib, pl);
337     sprintf(szPathStr, "site\\%s\\lib", pl);
338     lpPath1 = get_sitelib_part(szRegStr, szPathStr);
339
340     /* $HKCU{'sitelib'} || $HKLM{'sitelib'} . ---; */
341     lpPath2 = get_sitelib_part(szSiteLib, "site\\lib");
342     if (lpPath1 == NULL)
343         return lpPath2;
344
345     if (lpPath2 == NULL)
346         return lpPath1;
347
348     len = strlen(lpPath1);
349     newSize = len + strlen(lpPath2) + 2; /* plus one for ';' */
350
351     lpPath1 = Renew(lpPath1, newSize, char);
352     if (lpPath1 != NULL)
353     {
354         lpPath1[len++] = ';';
355         strcpy(&lpPath1[len], lpPath2);
356     }
357     Safefree(lpPath2);
358     return lpPath1;
359 }
360
361
362 static BOOL
363 has_redirection(char *ptr)
364 {
365     int inquote = 0;
366     char quote = '\0';
367
368     /*
369      * Scan string looking for redirection (< or >) or pipe
370      * characters (|) that are not in a quoted string
371      */
372     while (*ptr) {
373         switch(*ptr) {
374         case '\'':
375         case '\"':
376             if (inquote) {
377                 if (quote == *ptr) {
378                     inquote = 0;
379                     quote = '\0';
380                 }
381             }
382             else {
383                 quote = *ptr;
384                 inquote++;
385             }
386             break;
387         case '>':
388         case '<':
389         case '|':
390             if (!inquote)
391                 return TRUE;
392         default:
393             break;
394         }
395         ++ptr;
396     }
397     return FALSE;
398 }
399
400 #if !defined(PERL_OBJECT)
401 /* since the current process environment is being updated in util.c
402  * the library functions will get the correct environment
403  */
404 PerlIO *
405 my_popen(char *cmd, char *mode)
406 {
407 #ifdef FIXCMD
408 #define fixcmd(x)       {                                       \
409                             char *pspace = strchr((x),' ');     \
410                             if (pspace) {                       \
411                                 char *p = (x);                  \
412                                 while (p < pspace) {            \
413                                     if (*p == '/')              \
414                                         *p = '\\';              \
415                                     p++;                        \
416                                 }                               \
417                             }                                   \
418                         }
419 #else
420 #define fixcmd(x)
421 #endif
422     fixcmd(cmd);
423     win32_fflush(stdout);
424     win32_fflush(stderr);
425     return win32_popen(cmd, mode);
426 }
427
428 long
429 my_pclose(PerlIO *fp)
430 {
431     return win32_pclose(fp);
432 }
433 #endif
434
435 static DWORD
436 os_id(void)
437 {
438     static OSVERSIONINFO osver;
439
440     if (osver.dwPlatformId != w32_platform) {
441         memset(&osver, 0, sizeof(OSVERSIONINFO));
442         osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
443         GetVersionEx(&osver);
444         w32_platform = osver.dwPlatformId;
445     }
446     return (w32_platform);
447 }
448
449 /* Tokenize a string.  Words are null-separated, and the list
450  * ends with a doubled null.  Any character (except null and
451  * including backslash) may be escaped by preceding it with a
452  * backslash (the backslash will be stripped).
453  * Returns number of words in result buffer.
454  */
455 static long
456 tokenize(char *str, char **dest, char ***destv)
457 {
458     char *retstart = Nullch;
459     char **retvstart = 0;
460     int items = -1;
461     if (str) {
462         int slen = strlen(str);
463         register char *ret;
464         register char **retv;
465         New(1307, ret, slen+2, char);
466         New(1308, retv, (slen+3)/2, char*);
467
468         retstart = ret;
469         retvstart = retv;
470         *retv = ret;
471         items = 0;
472         while (*str) {
473             *ret = *str++;
474             if (*ret == '\\' && *str)
475                 *ret = *str++;
476             else if (*ret == ' ') {
477                 while (*str == ' ')
478                     str++;
479                 if (ret == retstart)
480                     ret--;
481                 else {
482                     *ret = '\0';
483                     ++items;
484                     if (*str)
485                         *++retv = ret+1;
486                 }
487             }
488             else if (!*str)
489                 ++items;
490             ret++;
491         }
492         retvstart[items] = Nullch;
493         *ret++ = '\0';
494         *ret = '\0';
495     }
496     *dest = retstart;
497     *destv = retvstart;
498     return items;
499 }
500
501 static void
502 get_shell(void)
503 {
504     if (!w32_perlshell_tokens) {
505         /* we don't use COMSPEC here for two reasons:
506          *  1. the same reason perl on UNIX doesn't use SHELL--rampant and
507          *     uncontrolled unportability of the ensuing scripts.
508          *  2. PERL5SHELL could be set to a shell that may not be fit for
509          *     interactive use (which is what most programs look in COMSPEC
510          *     for).
511          */
512         char* defaultshell = (IsWinNT() ? "cmd.exe /x/c" : "command.com /c");
513         char *usershell = getenv("PERL5SHELL");
514         w32_perlshell_items = tokenize(usershell ? usershell : defaultshell,
515                                        &w32_perlshell_tokens,
516                                        &w32_perlshell_vec);
517     }
518 }
519
520 int
521 do_aspawn(void *vreally, void **vmark, void **vsp)
522 {
523     SV *really = (SV*)vreally;
524     SV **mark = (SV**)vmark;
525     SV **sp = (SV**)vsp;
526     char **argv;
527     char *str;
528     int status;
529     int flag = P_WAIT;
530     int index = 0;
531
532     if (sp <= mark)
533         return -1;
534
535     get_shell();
536     New(1306, argv, (sp - mark) + w32_perlshell_items + 2, char*);
537
538     if (SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) {
539         ++mark;
540         flag = SvIVx(*mark);
541     }
542
543     while (++mark <= sp) {
544         if (*mark && (str = SvPV(*mark, na)))
545             argv[index++] = str;
546         else
547             argv[index++] = "";
548     }
549     argv[index++] = 0;
550    
551     status = win32_spawnvp(flag,
552                            (const char*)(really ? SvPV(really,na) : argv[0]),
553                            (const char* const*)argv);
554
555     if (status < 0 && errno == ENOEXEC) {
556         /* possible shell-builtin, invoke with shell */
557         int sh_items;
558         sh_items = w32_perlshell_items;
559         while (--index >= 0)
560             argv[index+sh_items] = argv[index];
561         while (--sh_items >= 0)
562             argv[sh_items] = w32_perlshell_vec[sh_items];
563    
564         status = win32_spawnvp(flag,
565                                (const char*)(really ? SvPV(really,na) : argv[0]),
566                                (const char* const*)argv);
567     }
568
569     if (flag != P_NOWAIT) {
570         if (status < 0) {
571             if (dowarn)
572                 warn("Can't spawn \"%s\": %s", argv[0], strerror(errno));
573             status = 255 * 256;
574         }
575         else
576             status *= 256;
577         statusvalue = status;
578     }
579     Safefree(argv);
580     return (status);
581 }
582
583 int
584 do_spawn2(char *cmd, int exectype)
585 {
586     char **a;
587     char *s;
588     char **argv;
589     int status = -1;
590     BOOL needToTry = TRUE;
591     char *cmd2;
592
593     /* Save an extra exec if possible. See if there are shell
594      * metacharacters in it */
595     if (!has_redirection(cmd)) {
596         New(1301,argv, strlen(cmd) / 2 + 2, char*);
597         New(1302,cmd2, strlen(cmd) + 1, char);
598         strcpy(cmd2, cmd);
599         a = argv;
600         for (s = cmd2; *s;) {
601             while (*s && isspace(*s))
602                 s++;
603             if (*s)
604                 *(a++) = s;
605             while (*s && !isspace(*s))
606                 s++;
607             if (*s)
608                 *s++ = '\0';
609         }
610         *a = Nullch;
611         if (argv[0]) {
612             switch (exectype) {
613             case EXECF_SPAWN:
614                 status = win32_spawnvp(P_WAIT, argv[0],
615                                        (const char* const*)argv);
616                 break;
617             case EXECF_SPAWN_NOWAIT:
618                 status = win32_spawnvp(P_NOWAIT, argv[0],
619                                        (const char* const*)argv);
620                 break;
621             case EXECF_EXEC:
622                 status = win32_execvp(argv[0], (const char* const*)argv);
623                 break;
624             }
625             if (status != -1 || errno == 0)
626                 needToTry = FALSE;
627         }
628         Safefree(argv);
629         Safefree(cmd2);
630     }
631     if (needToTry) {
632         char **argv;
633         int i = -1;
634         get_shell();
635         New(1306, argv, w32_perlshell_items + 2, char*);
636         while (++i < w32_perlshell_items)
637             argv[i] = w32_perlshell_vec[i];
638         argv[i++] = cmd;
639         argv[i] = Nullch;
640         switch (exectype) {
641         case EXECF_SPAWN:
642             status = win32_spawnvp(P_WAIT, argv[0],
643                                    (const char* const*)argv);
644             break;
645         case EXECF_SPAWN_NOWAIT:
646             status = win32_spawnvp(P_NOWAIT, argv[0],
647                                    (const char* const*)argv);
648             break;
649         case EXECF_EXEC:
650             status = win32_execvp(argv[0], (const char* const*)argv);
651             break;
652         }
653         cmd = argv[0];
654         Safefree(argv);
655     }
656     if (exectype != EXECF_SPAWN_NOWAIT) {
657         if (status < 0) {
658             if (dowarn)
659                 warn("Can't %s \"%s\": %s",
660                      (exectype == EXECF_EXEC ? "exec" : "spawn"),
661                      cmd, strerror(errno));
662             status = 255 * 256;
663         }
664         else
665             status *= 256;
666         statusvalue = status;
667     }
668     return (status);
669 }
670
671 int
672 do_spawn(char *cmd)
673 {
674     return do_spawn2(cmd, EXECF_SPAWN);
675 }
676
677 int
678 do_spawn_nowait(char *cmd)
679 {
680     return do_spawn2(cmd, EXECF_SPAWN_NOWAIT);
681 }
682
683 bool
684 do_exec(char *cmd)
685 {
686     do_spawn2(cmd, EXECF_EXEC);
687     return FALSE;
688 }
689
690 /* The idea here is to read all the directory names into a string table
691  * (separated by nulls) and when one of the other dir functions is called
692  * return the pointer to the current file name.
693  */
694 DIR *
695 opendir(char *filename)
696 {
697     DIR                 *p;
698     long                len;
699     long                idx;
700     char                scanname[MAX_PATH+3];
701     struct stat         sbuf;
702     WIN32_FIND_DATA     FindData;
703     HANDLE              fh;
704
705     len = strlen(filename);
706     if (len > MAX_PATH)
707         return NULL;
708
709     /* check to see if filename is a directory */
710     if (win32_stat(filename, &sbuf) < 0 || (sbuf.st_mode & S_IFDIR) == 0) {
711         /* CRT is buggy on sharenames, so make sure it really isn't */
712         DWORD r = GetFileAttributes(filename);
713         if (r == 0xffffffff || !(r & FILE_ATTRIBUTE_DIRECTORY))
714             return NULL;
715     }
716
717     /* Get us a DIR structure */
718     Newz(1303, p, 1, DIR);
719     if (p == NULL)
720         return NULL;
721
722     /* Create the search pattern */
723     strcpy(scanname, filename);
724     if (scanname[len-1] != '/' && scanname[len-1] != '\\')
725         scanname[len++] = '/';
726     scanname[len++] = '*';
727     scanname[len] = '\0';
728
729     /* do the FindFirstFile call */
730     fh = FindFirstFile(scanname, &FindData);
731     if (fh == INVALID_HANDLE_VALUE) {
732         return NULL;
733     }
734
735     /* now allocate the first part of the string table for
736      * the filenames that we find.
737      */
738     idx = strlen(FindData.cFileName)+1;
739     New(1304, p->start, idx, char);
740     if (p->start == NULL)
741         croak("opendir: malloc failed!\n");
742     strcpy(p->start, FindData.cFileName);
743     p->nfiles++;
744
745     /* loop finding all the files that match the wildcard
746      * (which should be all of them in this directory!).
747      * the variable idx should point one past the null terminator
748      * of the previous string found.
749      */
750     while (FindNextFile(fh, &FindData)) {
751         len = strlen(FindData.cFileName);
752         /* bump the string table size by enough for the
753          * new name and it's null terminator
754          */
755         Renew(p->start, idx+len+1, char);
756         if (p->start == NULL)
757             croak("opendir: malloc failed!\n");
758         strcpy(&p->start[idx], FindData.cFileName);
759         p->nfiles++;
760         idx += len+1;
761     }
762     FindClose(fh);
763     p->size = idx;
764     p->curr = p->start;
765     return p;
766 }
767
768
769 /* Readdir just returns the current string pointer and bumps the
770  * string pointer to the nDllExport entry.
771  */
772 struct direct *
773 readdir(DIR *dirp)
774 {
775     int         len;
776     static int  dummy = 0;
777
778     if (dirp->curr) {
779         /* first set up the structure to return */
780         len = strlen(dirp->curr);
781         strcpy(dirp->dirstr.d_name, dirp->curr);
782         dirp->dirstr.d_namlen = len;
783
784         /* Fake an inode */
785         dirp->dirstr.d_ino = dummy++;
786
787         /* Now set up for the nDllExport call to readdir */
788         dirp->curr += len + 1;
789         if (dirp->curr >= (dirp->start + dirp->size)) {
790             dirp->curr = NULL;
791         }
792
793         return &(dirp->dirstr);
794     } 
795     else
796         return NULL;
797 }
798
799 /* Telldir returns the current string pointer position */
800 long
801 telldir(DIR *dirp)
802 {
803     return (long) dirp->curr;
804 }
805
806
807 /* Seekdir moves the string pointer to a previously saved position
808  *(Saved by telldir).
809  */
810 void
811 seekdir(DIR *dirp, long loc)
812 {
813     dirp->curr = (char *)loc;
814 }
815
816 /* Rewinddir resets the string pointer to the start */
817 void
818 rewinddir(DIR *dirp)
819 {
820     dirp->curr = dirp->start;
821 }
822
823 /* free the memory allocated by opendir */
824 int
825 closedir(DIR *dirp)
826 {
827     Safefree(dirp->start);
828     Safefree(dirp);
829     return 1;
830 }
831
832
833 /*
834  * various stubs
835  */
836
837
838 /* Ownership
839  *
840  * Just pretend that everyone is a superuser. NT will let us know if
841  * we don\'t really have permission to do something.
842  */
843
844 #define ROOT_UID    ((uid_t)0)
845 #define ROOT_GID    ((gid_t)0)
846
847 uid_t
848 getuid(void)
849 {
850     return ROOT_UID;
851 }
852
853 uid_t
854 geteuid(void)
855 {
856     return ROOT_UID;
857 }
858
859 gid_t
860 getgid(void)
861 {
862     return ROOT_GID;
863 }
864
865 gid_t
866 getegid(void)
867 {
868     return ROOT_GID;
869 }
870
871 int
872 setuid(uid_t auid)
873
874     return (auid == ROOT_UID ? 0 : -1);
875 }
876
877 int
878 setgid(gid_t agid)
879 {
880     return (agid == ROOT_GID ? 0 : -1);
881 }
882
883 char *
884 getlogin(void)
885 {
886     dTHR;
887     char *buf = getlogin_buffer;
888     DWORD size = sizeof(getlogin_buffer);
889     if (GetUserName(buf,&size))
890         return buf;
891     return (char*)NULL;
892 }
893
894 int
895 chown(const char *path, uid_t owner, gid_t group)
896 {
897     /* XXX noop */
898     return 0;
899 }
900
901 int
902 kill(int pid, int sig)
903 {
904     HANDLE hProcess= OpenProcess(PROCESS_ALL_ACCESS, TRUE, pid);
905
906     if (hProcess == NULL) {
907         croak("kill process failed!\n");
908     }
909     else {
910         if (!TerminateProcess(hProcess, sig))
911             croak("kill process failed!\n");
912         CloseHandle(hProcess);
913     }
914     return 0;
915 }
916
917 /*
918  * File system stuff
919  */
920
921 DllExport unsigned int
922 win32_sleep(unsigned int t)
923 {
924     Sleep(t*1000);
925     return 0;
926 }
927
928 DllExport int
929 win32_stat(const char *path, struct stat *buffer)
930 {
931     char                t[MAX_PATH]; 
932     const char  *p = path;
933     int         l = strlen(path);
934     int         res;
935
936     if (l > 1) {
937         switch(path[l - 1]) {
938         case '\\':
939         case '/':
940             if (path[l - 2] != ':') {
941                 strncpy(t, path, l - 1);
942                 t[l - 1] = 0;
943                 p = t;
944             };
945         }
946     }
947     res = stat(p,buffer);
948 #ifdef __BORLANDC__
949     if (res == 0) {
950         if (S_ISDIR(buffer->st_mode))
951             buffer->st_mode |= S_IWRITE | S_IEXEC;
952         else if (S_ISREG(buffer->st_mode)) {
953             if (l >= 4 && path[l-4] == '.') {
954                 const char *e = path + l - 3;
955                 if (strnicmp(e,"exe",3)
956                     && strnicmp(e,"bat",3)
957                     && strnicmp(e,"com",3)
958                     && (IsWin95() || strnicmp(e,"cmd",3)))
959                     buffer->st_mode &= ~S_IEXEC;
960                 else
961                     buffer->st_mode |= S_IEXEC;
962             }
963             else
964                 buffer->st_mode &= ~S_IEXEC;
965         }
966     }
967 #endif
968     return res;
969 }
970
971 #ifndef USE_WIN32_RTL_ENV
972
973 DllExport char *
974 win32_getenv(const char *name)
975 {
976     static char *curitem = Nullch;
977     static DWORD curlen = 512;
978     DWORD needlen;
979     if (!curitem)
980         New(1305,curitem,curlen,char);
981
982     needlen = GetEnvironmentVariable(name,curitem,curlen);
983     if (needlen != 0) {
984         while (needlen > curlen) {
985             Renew(curitem,needlen,char);
986             curlen = needlen;
987             needlen = GetEnvironmentVariable(name,curitem,curlen);
988         }
989     }
990     else
991     {
992         /* allow any environment variables that begin with 'PERL5'
993            to be stored in the registry
994         */
995         if(curitem != NULL)
996             *curitem = '\0';
997
998         if (strncmp(name, "PERL5", 5) == 0) {
999             if (curitem != NULL) {
1000                 Safefree(curitem);
1001                 curitem = NULL;
1002             }
1003             curitem = GetRegStr(name, &curitem, &curlen);
1004         }
1005     }
1006     if(curitem != NULL && *curitem == '\0')
1007         return Nullch;
1008
1009     return curitem;
1010 }
1011
1012 #endif
1013
1014 static long
1015 filetime_to_clock(PFILETIME ft)
1016 {
1017  __int64 qw = ft->dwHighDateTime;
1018  qw <<= 32;
1019  qw |= ft->dwLowDateTime;
1020  qw /= 10000;  /* File time ticks at 0.1uS, clock at 1mS */
1021  return (long) qw;
1022 }
1023
1024 DllExport int
1025 win32_times(struct tms *timebuf)
1026 {
1027     FILETIME user;
1028     FILETIME kernel;
1029     FILETIME dummy;
1030     if (GetProcessTimes(GetCurrentProcess(), &dummy, &dummy, 
1031                         &kernel,&user)) {
1032         timebuf->tms_utime = filetime_to_clock(&user);
1033         timebuf->tms_stime = filetime_to_clock(&kernel);
1034         timebuf->tms_cutime = 0;
1035         timebuf->tms_cstime = 0;
1036         
1037     } else { 
1038         /* That failed - e.g. Win95 fallback to clock() */
1039         clock_t t = clock();
1040         timebuf->tms_utime = t;
1041         timebuf->tms_stime = 0;
1042         timebuf->tms_cutime = 0;
1043         timebuf->tms_cstime = 0;
1044     }
1045     return 0;
1046 }
1047
1048 /* fix utime() so it works on directories in NT
1049  * thanks to Jan Dubois <jan.dubois@ibm.net>
1050  */
1051 static BOOL
1052 filetime_from_time(PFILETIME pFileTime, time_t Time)
1053 {
1054     struct tm *pTM = gmtime(&Time);
1055     SYSTEMTIME SystemTime;
1056
1057     if (pTM == NULL)
1058         return FALSE;
1059
1060     SystemTime.wYear   = pTM->tm_year + 1900;
1061     SystemTime.wMonth  = pTM->tm_mon + 1;
1062     SystemTime.wDay    = pTM->tm_mday;
1063     SystemTime.wHour   = pTM->tm_hour;
1064     SystemTime.wMinute = pTM->tm_min;
1065     SystemTime.wSecond = pTM->tm_sec;
1066     SystemTime.wMilliseconds = 0;
1067
1068     return SystemTimeToFileTime(&SystemTime, pFileTime);
1069 }
1070
1071 DllExport int
1072 win32_utime(const char *filename, struct utimbuf *times)
1073 {
1074     HANDLE handle;
1075     FILETIME ftCreate;
1076     FILETIME ftAccess;
1077     FILETIME ftWrite;
1078     struct utimbuf TimeBuffer;
1079
1080     int rc = utime(filename,times);
1081     /* EACCES: path specifies directory or readonly file */
1082     if (rc == 0 || errno != EACCES /* || !IsWinNT() */)
1083         return rc;
1084
1085     if (times == NULL) {
1086         times = &TimeBuffer;
1087         time(&times->actime);
1088         times->modtime = times->actime;
1089     }
1090
1091     /* This will (and should) still fail on readonly files */
1092     handle = CreateFile(filename, GENERIC_READ | GENERIC_WRITE,
1093                         FILE_SHARE_READ | FILE_SHARE_DELETE, NULL,
1094                         OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
1095     if (handle == INVALID_HANDLE_VALUE)
1096         return rc;
1097
1098     if (GetFileTime(handle, &ftCreate, &ftAccess, &ftWrite) &&
1099         filetime_from_time(&ftAccess, times->actime) &&
1100         filetime_from_time(&ftWrite, times->modtime) &&
1101         SetFileTime(handle, &ftCreate, &ftAccess, &ftWrite))
1102     {
1103         rc = 0;
1104     }
1105
1106     CloseHandle(handle);
1107     return rc;
1108 }
1109
1110 DllExport int
1111 win32_wait(int *status)
1112 {
1113 #ifdef USE_RTL_WAIT
1114     return wait(status);
1115 #else
1116     /* XXX this wait emulation only knows about processes
1117      * spawned via win32_spawnvp(P_NOWAIT, ...).
1118      */
1119     int i, retval;
1120     DWORD exitcode, waitcode;
1121
1122     if (!w32_num_children) {
1123         errno = ECHILD;
1124         return -1;
1125     }
1126
1127     /* if a child exists, wait for it to die */
1128     waitcode = WaitForMultipleObjects(w32_num_children,
1129                                       w32_child_pids,
1130                                       FALSE,
1131                                       INFINITE);
1132     if (waitcode != WAIT_FAILED) {
1133         if (waitcode >= WAIT_ABANDONED_0
1134             && waitcode < WAIT_ABANDONED_0 + w32_num_children)
1135             i = waitcode - WAIT_ABANDONED_0;
1136         else
1137             i = waitcode - WAIT_OBJECT_0;
1138         if (GetExitCodeProcess(w32_child_pids[i], &exitcode) ) {
1139             CloseHandle(w32_child_pids[i]);
1140             *status = (int)((exitcode & 0xff) << 8);
1141             retval = (int)w32_child_pids[i];
1142             Copy(&w32_child_pids[i+1], &w32_child_pids[i],
1143                  (w32_num_children-i-1), HANDLE);
1144             w32_num_children--;
1145             return retval;
1146         }
1147     }
1148
1149 FAILED:
1150     errno = GetLastError();
1151     return -1;
1152
1153 #endif
1154 }
1155
1156 static UINT timerid = 0;
1157
1158 static VOID CALLBACK TimerProc(HWND win, UINT msg, UINT id, DWORD time)
1159 {
1160  KillTimer(NULL,timerid);
1161  timerid=0;  
1162  sighandler(14);
1163 }
1164
1165 DllExport unsigned int
1166 win32_alarm(unsigned int sec)
1167 {
1168     /* 
1169      * the 'obvious' implentation is SetTimer() with a callback
1170      * which does whatever receiving SIGALRM would do 
1171      * we cannot use SIGALRM even via raise() as it is not 
1172      * one of the supported codes in <signal.h>
1173      *
1174      * Snag is unless something is looking at the message queue
1175      * nothing happens :-(
1176      */ 
1177     if (sec)
1178      {
1179       timerid = SetTimer(NULL,timerid,sec*1000,(TIMERPROC)TimerProc);
1180       if (!timerid)
1181        croak("Cannot set timer");
1182      } 
1183     else
1184      {
1185       if (timerid)
1186        {
1187         KillTimer(NULL,timerid);
1188         timerid=0;  
1189        }
1190      }
1191     return 0;
1192 }
1193
1194 #ifdef HAVE_DES_FCRYPT
1195 extern char *   des_fcrypt(char *cbuf, const char *txt, const char *salt);
1196
1197 DllExport char *
1198 win32_crypt(const char *txt, const char *salt)
1199 {
1200     dTHR;
1201     return des_fcrypt(crypt_buffer, txt, salt);
1202 }
1203 #endif
1204
1205 #ifdef USE_FIXED_OSFHANDLE
1206
1207 EXTERN_C int __cdecl _alloc_osfhnd(void);
1208 EXTERN_C int __cdecl _set_osfhnd(int fh, long value);
1209 EXTERN_C void __cdecl _lock_fhandle(int);
1210 EXTERN_C void __cdecl _unlock_fhandle(int);
1211 EXTERN_C void __cdecl _unlock(int);
1212
1213 #if     (_MSC_VER >= 1000)
1214 typedef struct  {
1215     long osfhnd;    /* underlying OS file HANDLE */
1216     char osfile;    /* attributes of file (e.g., open in text mode?) */
1217     char pipech;    /* one char buffer for handles opened on pipes */
1218 #if defined (_MT) && !defined (DLL_FOR_WIN32S)
1219     int lockinitflag;
1220     CRITICAL_SECTION lock;
1221 #endif  /* defined (_MT) && !defined (DLL_FOR_WIN32S) */
1222 }       ioinfo;
1223
1224 EXTERN_C ioinfo * __pioinfo[];
1225
1226 #define IOINFO_L2E                      5
1227 #define IOINFO_ARRAY_ELTS       (1 << IOINFO_L2E)
1228 #define _pioinfo(i)     (__pioinfo[i >> IOINFO_L2E] + (i & (IOINFO_ARRAY_ELTS - 1)))
1229 #define _osfile(i)      (_pioinfo(i)->osfile)
1230
1231 #else   /* (_MSC_VER >= 1000) */
1232 extern char _osfile[];
1233 #endif  /* (_MSC_VER >= 1000) */
1234
1235 #define FOPEN                   0x01    /* file handle open */
1236 #define FAPPEND                 0x20    /* file handle opened O_APPEND */
1237 #define FDEV                    0x40    /* file handle refers to device */
1238 #define FTEXT                   0x80    /* file handle is in text mode */
1239
1240 #define _STREAM_LOCKS   26              /* Table of stream locks */
1241 #define _LAST_STREAM_LOCK  (_STREAM_LOCKS+_NSTREAM_-1)  /* Last stream lock */
1242 #define _FH_LOCKS          (_LAST_STREAM_LOCK+1)        /* Table of fh locks */
1243
1244 /***
1245 *int my_open_osfhandle(long osfhandle, int flags) - open C Runtime file handle
1246 *
1247 *Purpose:
1248 *       This function allocates a free C Runtime file handle and associates
1249 *       it with the Win32 HANDLE specified by the first parameter. This is a
1250 *               temperary fix for WIN95's brain damage GetFileType() error on socket
1251 *               we just bypass that call for socket
1252 *
1253 *Entry:
1254 *       long osfhandle - Win32 HANDLE to associate with C Runtime file handle.
1255 *       int flags      - flags to associate with C Runtime file handle.
1256 *
1257 *Exit:
1258 *       returns index of entry in fh, if successful
1259 *       return -1, if no free entry is found
1260 *
1261 *Exceptions:
1262 *
1263 *******************************************************************************/
1264
1265 static int
1266 my_open_osfhandle(long osfhandle, int flags)
1267 {
1268     int fh;
1269     char fileflags;             /* _osfile flags */
1270
1271     /* copy relevant flags from second parameter */
1272     fileflags = FDEV;
1273
1274     if (flags & O_APPEND)
1275         fileflags |= FAPPEND;
1276
1277     if (flags & O_TEXT)
1278         fileflags |= FTEXT;
1279
1280     /* attempt to allocate a C Runtime file handle */
1281     if ((fh = _alloc_osfhnd()) == -1) {
1282         errno = EMFILE;         /* too many open files */
1283         _doserrno = 0L;         /* not an OS error */
1284         return -1;              /* return error to caller */
1285     }
1286
1287     /* the file is open. now, set the info in _osfhnd array */
1288     _set_osfhnd(fh, osfhandle);
1289
1290     fileflags |= FOPEN;         /* mark as open */
1291
1292 #if (_MSC_VER >= 1000)
1293     _osfile(fh) = fileflags;    /* set osfile entry */
1294     _unlock_fhandle(fh);
1295 #else
1296     _osfile[fh] = fileflags;    /* set osfile entry */
1297     _unlock(fh+_FH_LOCKS);              /* unlock handle */
1298 #endif
1299
1300     return fh;                  /* return handle */
1301 }
1302
1303 #define _open_osfhandle my_open_osfhandle
1304 #endif  /* USE_FIXED_OSFHANDLE */
1305
1306 /* simulate flock by locking a range on the file */
1307
1308 #define LK_ERR(f,i)     ((f) ? (i = 0) : (errno = GetLastError()))
1309 #define LK_LEN          0xffff0000
1310
1311 DllExport int
1312 win32_flock(int fd, int oper)
1313 {
1314     OVERLAPPED o;
1315     int i = -1;
1316     HANDLE fh;
1317
1318     if (!IsWinNT()) {
1319         croak("flock() unimplemented on this platform");
1320         return -1;
1321     }
1322     fh = (HANDLE)_get_osfhandle(fd);
1323     memset(&o, 0, sizeof(o));
1324
1325     switch(oper) {
1326     case LOCK_SH:               /* shared lock */
1327         LK_ERR(LockFileEx(fh, 0, 0, LK_LEN, 0, &o),i);
1328         break;
1329     case LOCK_EX:               /* exclusive lock */
1330         LK_ERR(LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, LK_LEN, 0, &o),i);
1331         break;
1332     case LOCK_SH|LOCK_NB:       /* non-blocking shared lock */
1333         LK_ERR(LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY, 0, LK_LEN, 0, &o),i);
1334         break;
1335     case LOCK_EX|LOCK_NB:       /* non-blocking exclusive lock */
1336         LK_ERR(LockFileEx(fh,
1337                        LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY,
1338                        0, LK_LEN, 0, &o),i);
1339         break;
1340     case LOCK_UN:               /* unlock lock */
1341         LK_ERR(UnlockFileEx(fh, 0, LK_LEN, 0, &o),i);
1342         break;
1343     default:                    /* unknown */
1344         errno = EINVAL;
1345         break;
1346     }
1347     return i;
1348 }
1349
1350 #undef LK_ERR
1351 #undef LK_LEN
1352
1353 /*
1354  *  redirected io subsystem for all XS modules
1355  *
1356  */
1357
1358 DllExport int *
1359 win32_errno(void)
1360 {
1361     return (&errno);
1362 }
1363
1364 DllExport char ***
1365 win32_environ(void)
1366 {
1367     return (&(_environ));
1368 }
1369
1370 /* the rest are the remapped stdio routines */
1371 DllExport FILE *
1372 win32_stderr(void)
1373 {
1374     return (stderr);
1375 }
1376
1377 DllExport FILE *
1378 win32_stdin(void)
1379 {
1380     return (stdin);
1381 }
1382
1383 DllExport FILE *
1384 win32_stdout()
1385 {
1386     return (stdout);
1387 }
1388
1389 DllExport int
1390 win32_ferror(FILE *fp)
1391 {
1392     return (ferror(fp));
1393 }
1394
1395
1396 DllExport int
1397 win32_feof(FILE *fp)
1398 {
1399     return (feof(fp));
1400 }
1401
1402 /*
1403  * Since the errors returned by the socket error function 
1404  * WSAGetLastError() are not known by the library routine strerror
1405  * we have to roll our own.
1406  */
1407
1408 DllExport char *
1409 win32_strerror(int e) 
1410 {
1411 #ifndef __BORLANDC__            /* Borland intolerance */
1412     extern int sys_nerr;
1413 #endif
1414     DWORD source = 0;
1415
1416     if (e < 0 || e > sys_nerr) {
1417         dTHR;
1418         if (e < 0)
1419             e = GetLastError();
1420
1421         if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, &source, e, 0,
1422                          strerror_buffer, sizeof(strerror_buffer), NULL) == 0) 
1423             strcpy(strerror_buffer, "Unknown Error");
1424
1425         return strerror_buffer;
1426     }
1427     return strerror(e);
1428 }
1429
1430 DllExport void
1431 win32_str_os_error(void *sv, DWORD dwErr)
1432 {
1433     DWORD dwLen;
1434     char *sMsg;
1435     dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
1436                           |FORMAT_MESSAGE_IGNORE_INSERTS
1437                           |FORMAT_MESSAGE_FROM_SYSTEM, NULL,
1438                            dwErr, 0, (char *)&sMsg, 1, NULL);
1439     if (0 < dwLen) {
1440         while (0 < dwLen  &&  isspace(sMsg[--dwLen]))
1441             ;
1442         if ('.' != sMsg[dwLen])
1443             dwLen++;
1444         sMsg[dwLen]= '\0';
1445     }
1446     if (0 == dwLen) {
1447         sMsg = (char*)LocalAlloc(0, 64/**sizeof(TCHAR)*/);
1448         dwLen = sprintf(sMsg,
1449                         "Unknown error #0x%lX (lookup 0x%lX)",
1450                         dwErr, GetLastError());
1451     }
1452     sv_setpvn((SV*)sv, sMsg, dwLen);
1453     LocalFree(sMsg);
1454 }
1455
1456
1457 DllExport int
1458 win32_fprintf(FILE *fp, const char *format, ...)
1459 {
1460     va_list marker;
1461     va_start(marker, format);     /* Initialize variable arguments. */
1462
1463     return (vfprintf(fp, format, marker));
1464 }
1465
1466 DllExport int
1467 win32_printf(const char *format, ...)
1468 {
1469     va_list marker;
1470     va_start(marker, format);     /* Initialize variable arguments. */
1471
1472     return (vprintf(format, marker));
1473 }
1474
1475 DllExport int
1476 win32_vfprintf(FILE *fp, const char *format, va_list args)
1477 {
1478     return (vfprintf(fp, format, args));
1479 }
1480
1481 DllExport int
1482 win32_vprintf(const char *format, va_list args)
1483 {
1484     return (vprintf(format, args));
1485 }
1486
1487 DllExport size_t
1488 win32_fread(void *buf, size_t size, size_t count, FILE *fp)
1489 {
1490     return fread(buf, size, count, fp);
1491 }
1492
1493 DllExport size_t
1494 win32_fwrite(const void *buf, size_t size, size_t count, FILE *fp)
1495 {
1496     return fwrite(buf, size, count, fp);
1497 }
1498
1499 DllExport FILE *
1500 win32_fopen(const char *filename, const char *mode)
1501 {
1502     if (stricmp(filename, "/dev/null")==0)
1503         return fopen("NUL", mode);
1504     return fopen(filename, mode);
1505 }
1506
1507 #ifndef USE_SOCKETS_AS_HANDLES
1508 #undef fdopen
1509 #define fdopen my_fdopen
1510 #endif
1511
1512 DllExport FILE *
1513 win32_fdopen( int handle, const char *mode)
1514 {
1515     return fdopen(handle, (char *) mode);
1516 }
1517
1518 DllExport FILE *
1519 win32_freopen( const char *path, const char *mode, FILE *stream)
1520 {
1521     if (stricmp(path, "/dev/null")==0)
1522         return freopen("NUL", mode, stream);
1523     return freopen(path, mode, stream);
1524 }
1525
1526 DllExport int
1527 win32_fclose(FILE *pf)
1528 {
1529     return my_fclose(pf);       /* defined in win32sck.c */
1530 }
1531
1532 DllExport int
1533 win32_fputs(const char *s,FILE *pf)
1534 {
1535     return fputs(s, pf);
1536 }
1537
1538 DllExport int
1539 win32_fputc(int c,FILE *pf)
1540 {
1541     return fputc(c,pf);
1542 }
1543
1544 DllExport int
1545 win32_ungetc(int c,FILE *pf)
1546 {
1547     return ungetc(c,pf);
1548 }
1549
1550 DllExport int
1551 win32_getc(FILE *pf)
1552 {
1553     return getc(pf);
1554 }
1555
1556 DllExport int
1557 win32_fileno(FILE *pf)
1558 {
1559     return fileno(pf);
1560 }
1561
1562 DllExport void
1563 win32_clearerr(FILE *pf)
1564 {
1565     clearerr(pf);
1566     return;
1567 }
1568
1569 DllExport int
1570 win32_fflush(FILE *pf)
1571 {
1572     return fflush(pf);
1573 }
1574
1575 DllExport long
1576 win32_ftell(FILE *pf)
1577 {
1578     return ftell(pf);
1579 }
1580
1581 DllExport int
1582 win32_fseek(FILE *pf,long offset,int origin)
1583 {
1584     return fseek(pf, offset, origin);
1585 }
1586
1587 DllExport int
1588 win32_fgetpos(FILE *pf,fpos_t *p)
1589 {
1590     return fgetpos(pf, p);
1591 }
1592
1593 DllExport int
1594 win32_fsetpos(FILE *pf,const fpos_t *p)
1595 {
1596     return fsetpos(pf, p);
1597 }
1598
1599 DllExport void
1600 win32_rewind(FILE *pf)
1601 {
1602     rewind(pf);
1603     return;
1604 }
1605
1606 DllExport FILE*
1607 win32_tmpfile(void)
1608 {
1609     return tmpfile();
1610 }
1611
1612 DllExport void
1613 win32_abort(void)
1614 {
1615     abort();
1616     return;
1617 }
1618
1619 DllExport int
1620 win32_fstat(int fd,struct stat *sbufptr)
1621 {
1622     return fstat(fd,sbufptr);
1623 }
1624
1625 DllExport int
1626 win32_pipe(int *pfd, unsigned int size, int mode)
1627 {
1628     return _pipe(pfd, size, mode);
1629 }
1630
1631 /*
1632  * a popen() clone that respects PERL5SHELL
1633  */
1634
1635 DllExport FILE*
1636 win32_popen(const char *command, const char *mode)
1637 {
1638 #ifdef USE_RTL_POPEN
1639     return _popen(command, mode);
1640 #else
1641     int p[2];
1642     int parent, child;
1643     int stdfd, oldfd;
1644     int ourmode;
1645     int childpid;
1646
1647     /* establish which ends read and write */
1648     if (strchr(mode,'w')) {
1649         stdfd = 0;              /* stdin */
1650         parent = 1;
1651         child = 0;
1652     }
1653     else if (strchr(mode,'r')) {
1654         stdfd = 1;              /* stdout */
1655         parent = 0;
1656         child = 1;
1657     }
1658     else
1659         return NULL;
1660
1661     /* set the correct mode */
1662     if (strchr(mode,'b'))
1663         ourmode = O_BINARY;
1664     else if (strchr(mode,'t'))
1665         ourmode = O_TEXT;
1666     else
1667         ourmode = _fmode & (O_TEXT | O_BINARY);
1668
1669     /* the child doesn't inherit handles */
1670     ourmode |= O_NOINHERIT;
1671
1672     if (win32_pipe( p, 512, ourmode) == -1)
1673         return NULL;
1674
1675     /* save current stdfd */
1676     if ((oldfd = win32_dup(stdfd)) == -1)
1677         goto cleanup;
1678
1679     /* make stdfd go to child end of pipe (implicitly closes stdfd) */
1680     /* stdfd will be inherited by the child */
1681     if (win32_dup2(p[child], stdfd) == -1)
1682         goto cleanup;
1683
1684     /* close the child end in parent */
1685     win32_close(p[child]);
1686
1687     /* start the child */
1688     if ((childpid = do_spawn_nowait((char*)command)) == -1)
1689         goto cleanup;
1690
1691     /* revert stdfd to whatever it was before */
1692     if (win32_dup2(oldfd, stdfd) == -1)
1693         goto cleanup;
1694
1695     /* close saved handle */
1696     win32_close(oldfd);
1697
1698     sv_setiv(*av_fetch(w32_fdpid, p[parent], TRUE), childpid);
1699
1700     /* we have an fd, return a file stream */
1701     return (win32_fdopen(p[parent], (char *)mode));
1702
1703 cleanup:
1704     /* we don't need to check for errors here */
1705     win32_close(p[0]);
1706     win32_close(p[1]);
1707     if (oldfd != -1) {
1708         win32_dup2(oldfd, stdfd);
1709         win32_close(oldfd);
1710     }
1711     return (NULL);
1712
1713 #endif /* USE_RTL_POPEN */
1714 }
1715
1716 /*
1717  * pclose() clone
1718  */
1719
1720 DllExport int
1721 win32_pclose(FILE *pf)
1722 {
1723 #ifdef USE_RTL_POPEN
1724     return _pclose(pf);
1725 #else
1726
1727 #ifndef USE_RTL_WAIT
1728     int child;
1729 #endif
1730
1731     int childpid, status;
1732     SV *sv;
1733
1734     sv = *av_fetch(w32_fdpid, win32_fileno(pf), TRUE);
1735     if (SvIOK(sv))
1736         childpid = SvIVX(sv);
1737     else
1738         childpid = 0;
1739
1740     if (!childpid) {
1741         errno = EBADF;
1742         return -1;
1743     }
1744
1745     win32_fclose(pf);
1746     SvIVX(sv) = 0;
1747
1748 #ifndef USE_RTL_WAIT
1749     for (child = 0 ; child < w32_num_children ; ++child) {
1750         if (w32_child_pids[child] == (HANDLE)childpid) {
1751             Copy(&w32_child_pids[child+1], &w32_child_pids[child],
1752                  (w32_num_children-child-1), HANDLE);
1753             w32_num_children--;
1754             break;
1755         }
1756     }
1757 #endif
1758
1759     /* wait for the child */
1760     if (cwait(&status, childpid, WAIT_CHILD) == -1)
1761         return (-1);
1762     /* cwait() returns differently on Borland */
1763 #ifdef __BORLANDC__
1764     return (((status >> 8) & 0xff) | ((status << 8) & 0xff00));
1765 #else
1766     return (status);
1767 #endif
1768
1769 #endif /* USE_RTL_POPEN */
1770 }
1771
1772 DllExport int
1773 win32_setmode(int fd, int mode)
1774 {
1775     return setmode(fd, mode);
1776 }
1777
1778 DllExport long
1779 win32_lseek(int fd, long offset, int origin)
1780 {
1781     return lseek(fd, offset, origin);
1782 }
1783
1784 DllExport long
1785 win32_tell(int fd)
1786 {
1787     return tell(fd);
1788 }
1789
1790 DllExport int
1791 win32_open(const char *path, int flag, ...)
1792 {
1793     va_list ap;
1794     int pmode;
1795
1796     va_start(ap, flag);
1797     pmode = va_arg(ap, int);
1798     va_end(ap);
1799
1800     if (stricmp(path, "/dev/null")==0)
1801         return open("NUL", flag, pmode);
1802     return open(path,flag,pmode);
1803 }
1804
1805 DllExport int
1806 win32_close(int fd)
1807 {
1808     return close(fd);
1809 }
1810
1811 DllExport int
1812 win32_eof(int fd)
1813 {
1814     return eof(fd);
1815 }
1816
1817 DllExport int
1818 win32_dup(int fd)
1819 {
1820     return dup(fd);
1821 }
1822
1823 DllExport int
1824 win32_dup2(int fd1,int fd2)
1825 {
1826     return dup2(fd1,fd2);
1827 }
1828
1829 DllExport int
1830 win32_read(int fd, void *buf, unsigned int cnt)
1831 {
1832     return read(fd, buf, cnt);
1833 }
1834
1835 DllExport int
1836 win32_write(int fd, const void *buf, unsigned int cnt)
1837 {
1838     return write(fd, buf, cnt);
1839 }
1840
1841 DllExport int
1842 win32_mkdir(const char *dir, int mode)
1843 {
1844     return mkdir(dir); /* just ignore mode */
1845 }
1846
1847 DllExport int
1848 win32_rmdir(const char *dir)
1849 {
1850     return rmdir(dir);
1851 }
1852
1853 DllExport int
1854 win32_chdir(const char *dir)
1855 {
1856     return chdir(dir);
1857 }
1858
1859 DllExport int
1860 win32_spawnvp(int mode, const char *cmdname, const char *const *argv)
1861 {
1862     int status;
1863
1864 #ifndef USE_RTL_WAIT
1865     if (mode == P_NOWAIT && w32_num_children >= MAXIMUM_WAIT_OBJECTS)
1866         return -1;
1867 #endif
1868
1869     status = spawnvp(mode, cmdname, (char * const *) argv);
1870 #ifndef USE_RTL_WAIT
1871     /* XXX For the P_NOWAIT case, Borland RTL returns pinfo.dwProcessId
1872      * while VC RTL returns pinfo.hProcess. For purposes of the custom
1873      * implementation of win32_wait(), we assume the latter.
1874      */
1875     if (mode == P_NOWAIT && status >= 0)
1876         w32_child_pids[w32_num_children++] = (HANDLE)status;
1877 #endif
1878     return status;
1879 }
1880
1881 DllExport int
1882 win32_execvp(const char *cmdname, const char *const *argv)
1883 {
1884     return execvp(cmdname, (char *const *)argv);
1885 }
1886
1887 DllExport void
1888 win32_perror(const char *str)
1889 {
1890     perror(str);
1891 }
1892
1893 DllExport void
1894 win32_setbuf(FILE *pf, char *buf)
1895 {
1896     setbuf(pf, buf);
1897 }
1898
1899 DllExport int
1900 win32_setvbuf(FILE *pf, char *buf, int type, size_t size)
1901 {
1902     return setvbuf(pf, buf, type, size);
1903 }
1904
1905 DllExport int
1906 win32_flushall(void)
1907 {
1908     return flushall();
1909 }
1910
1911 DllExport int
1912 win32_fcloseall(void)
1913 {
1914     return fcloseall();
1915 }
1916
1917 DllExport char*
1918 win32_fgets(char *s, int n, FILE *pf)
1919 {
1920     return fgets(s, n, pf);
1921 }
1922
1923 DllExport char*
1924 win32_gets(char *s)
1925 {
1926     return gets(s);
1927 }
1928
1929 DllExport int
1930 win32_fgetc(FILE *pf)
1931 {
1932     return fgetc(pf);
1933 }
1934
1935 DllExport int
1936 win32_putc(int c, FILE *pf)
1937 {
1938     return putc(c,pf);
1939 }
1940
1941 DllExport int
1942 win32_puts(const char *s)
1943 {
1944     return puts(s);
1945 }
1946
1947 DllExport int
1948 win32_getchar(void)
1949 {
1950     return getchar();
1951 }
1952
1953 DllExport int
1954 win32_putchar(int c)
1955 {
1956     return putchar(c);
1957 }
1958
1959 #ifdef MYMALLOC
1960
1961 #ifndef USE_PERL_SBRK
1962
1963 static char *committed = NULL;
1964 static char *base      = NULL;
1965 static char *reserved  = NULL;
1966 static char *brk       = NULL;
1967 static DWORD pagesize  = 0;
1968 static DWORD allocsize = 0;
1969
1970 void *
1971 sbrk(int need)
1972 {
1973  void *result;
1974  if (!pagesize)
1975   {SYSTEM_INFO info;
1976    GetSystemInfo(&info);
1977    /* Pretend page size is larger so we don't perpetually
1978     * call the OS to commit just one page ...
1979     */
1980    pagesize = info.dwPageSize << 3;
1981    allocsize = info.dwAllocationGranularity;
1982   }
1983  /* This scheme fails eventually if request for contiguous
1984   * block is denied so reserve big blocks - this is only 
1985   * address space not memory ...
1986   */
1987  if (brk+need >= reserved)
1988   {
1989    DWORD size = 64*1024*1024;
1990    char *addr;
1991    if (committed && reserved && committed < reserved)
1992     {
1993      /* Commit last of previous chunk cannot span allocations */
1994      addr = (char *) VirtualAlloc(committed,reserved-committed,MEM_COMMIT,PAGE_READWRITE);
1995      if (addr)
1996       committed = reserved;
1997     }
1998    /* Reserve some (more) space 
1999     * Note this is a little sneaky, 1st call passes NULL as reserved
2000     * so lets system choose where we start, subsequent calls pass
2001     * the old end address so ask for a contiguous block
2002     */
2003    addr  = (char *) VirtualAlloc(reserved,size,MEM_RESERVE,PAGE_NOACCESS);
2004    if (addr)
2005     {
2006      reserved = addr+size;
2007      if (!base)
2008       base = addr;
2009      if (!committed)
2010       committed = base;
2011      if (!brk)
2012       brk = committed;
2013     }
2014    else
2015     {
2016      return (void *) -1;
2017     }
2018   }
2019  result = brk;
2020  brk += need;
2021  if (brk > committed)
2022   {
2023    DWORD size = ((brk-committed + pagesize -1)/pagesize) * pagesize;
2024    char *addr = (char *) VirtualAlloc(committed,size,MEM_COMMIT,PAGE_READWRITE);
2025    if (addr)
2026     {
2027      committed += size;
2028     }
2029    else
2030     return (void *) -1;
2031   }
2032  return result;
2033 }
2034
2035 #endif
2036 #endif
2037
2038 DllExport void*
2039 win32_malloc(size_t size)
2040 {
2041     return malloc(size);
2042 }
2043
2044 DllExport void*
2045 win32_calloc(size_t numitems, size_t size)
2046 {
2047     return calloc(numitems,size);
2048 }
2049
2050 DllExport void*
2051 win32_realloc(void *block, size_t size)
2052 {
2053     return realloc(block,size);
2054 }
2055
2056 DllExport void
2057 win32_free(void *block)
2058 {
2059     free(block);
2060 }
2061
2062
2063 int
2064 win32_open_osfhandle(long handle, int flags)
2065 {
2066     return _open_osfhandle(handle, flags);
2067 }
2068
2069 long
2070 win32_get_osfhandle(int fd)
2071 {
2072     return _get_osfhandle(fd);
2073 }
2074
2075 /*
2076  * Extras.
2077  */
2078
2079 static
2080 XS(w32_GetCwd)
2081 {
2082     dXSARGS;
2083     SV *sv = sv_newmortal();
2084     /* Make one call with zero size - return value is required size */
2085     DWORD len = GetCurrentDirectory((DWORD)0,NULL);
2086     SvUPGRADE(sv,SVt_PV);
2087     SvGROW(sv,len);
2088     SvCUR(sv) = GetCurrentDirectory((DWORD) SvLEN(sv), SvPVX(sv));
2089     /* 
2090      * If result != 0 
2091      *   then it worked, set PV valid, 
2092      *   else leave it 'undef' 
2093      */
2094     if (SvCUR(sv))
2095         SvPOK_on(sv);
2096     EXTEND(SP,1);
2097     ST(0) = sv;
2098     XSRETURN(1);
2099 }
2100
2101 static
2102 XS(w32_SetCwd)
2103 {
2104     dXSARGS;
2105     if (items != 1)
2106         croak("usage: Win32::SetCurrentDirectory($cwd)");
2107     if (SetCurrentDirectory(SvPV(ST(0),na)))
2108         XSRETURN_YES;
2109
2110     XSRETURN_NO;
2111 }
2112
2113 static
2114 XS(w32_GetNextAvailDrive)
2115 {
2116     dXSARGS;
2117     char ix = 'C';
2118     char root[] = "_:\\";
2119     while (ix <= 'Z') {
2120         root[0] = ix++;
2121         if (GetDriveType(root) == 1) {
2122             root[2] = '\0';
2123             XSRETURN_PV(root);
2124         }
2125     }
2126     XSRETURN_UNDEF;
2127 }
2128
2129 static
2130 XS(w32_GetLastError)
2131 {
2132     dXSARGS;
2133     XSRETURN_IV(GetLastError());
2134 }
2135
2136 static
2137 XS(w32_LoginName)
2138 {
2139     dXSARGS;
2140     char *name = getlogin_buffer;
2141     DWORD size = sizeof(getlogin_buffer);
2142     if (GetUserName(name,&size)) {
2143         /* size includes NULL */
2144         ST(0) = sv_2mortal(newSVpv(name,size-1));
2145         XSRETURN(1);
2146     }
2147     XSRETURN_UNDEF;
2148 }
2149
2150 static
2151 XS(w32_NodeName)
2152 {
2153     dXSARGS;
2154     char name[MAX_COMPUTERNAME_LENGTH+1];
2155     DWORD size = sizeof(name);
2156     if (GetComputerName(name,&size)) {
2157         /* size does NOT include NULL :-( */
2158         ST(0) = sv_2mortal(newSVpv(name,size));
2159         XSRETURN(1);
2160     }
2161     XSRETURN_UNDEF;
2162 }
2163
2164
2165 static
2166 XS(w32_DomainName)
2167 {
2168     dXSARGS;
2169 #ifndef HAS_NETWKSTAGETINFO
2170     /* mingw32 (and Win95) don't have NetWksta*(), so do it the old way */
2171     char name[256];
2172     DWORD size = sizeof(name);
2173     if (GetUserName(name,&size)) {
2174         char sid[1024];
2175         DWORD sidlen = sizeof(sid);
2176         char dname[256];
2177         DWORD dnamelen = sizeof(dname);
2178         SID_NAME_USE snu;
2179         if (LookupAccountName(NULL, name, &sid, &sidlen,
2180                               dname, &dnamelen, &snu)) {
2181             XSRETURN_PV(dname);         /* all that for this */
2182         }
2183     }
2184 #else
2185     /* this way is more reliable, in case user has a local account.
2186      * XXX need dynamic binding of netapi32.dll symbols or this will fail on
2187      * Win95. Probably makes more sense to move it into libwin32. */
2188     char dname[256];
2189     DWORD dnamelen = sizeof(dname);
2190     PWKSTA_INFO_100 pwi;
2191     if (NERR_Success == NetWkstaGetInfo(NULL, 100, (LPBYTE*)&pwi)) {
2192         if (pwi->wki100_langroup && *(pwi->wki100_langroup)) {
2193             WideCharToMultiByte(CP_ACP, NULL, pwi->wki100_langroup,
2194                                 -1, (LPSTR)dname, dnamelen, NULL, NULL);
2195         }
2196         else {
2197             WideCharToMultiByte(CP_ACP, NULL, pwi->wki100_computername,
2198                                 -1, (LPSTR)dname, dnamelen, NULL, NULL);
2199         }
2200         NetApiBufferFree(pwi);
2201         XSRETURN_PV(dname);
2202     }
2203 #endif
2204     XSRETURN_UNDEF;
2205 }
2206
2207 static
2208 XS(w32_FsType)
2209 {
2210     dXSARGS;
2211     char fsname[256];
2212     DWORD flags, filecomplen;
2213     if (GetVolumeInformation(NULL, NULL, 0, NULL, &filecomplen,
2214                          &flags, fsname, sizeof(fsname))) {
2215         if (GIMME == G_ARRAY) {
2216             XPUSHs(sv_2mortal(newSVpv(fsname,0)));
2217             XPUSHs(sv_2mortal(newSViv(flags)));
2218             XPUSHs(sv_2mortal(newSViv(filecomplen)));
2219             PUTBACK;
2220             return;
2221         }
2222         XSRETURN_PV(fsname);
2223     }
2224     XSRETURN_UNDEF;
2225 }
2226
2227 static
2228 XS(w32_GetOSVersion)
2229 {
2230     dXSARGS;
2231     OSVERSIONINFO osver;
2232
2233     osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
2234     if (GetVersionEx(&osver)) {
2235         XPUSHs(newSVpv(osver.szCSDVersion, 0));
2236         XPUSHs(newSViv(osver.dwMajorVersion));
2237         XPUSHs(newSViv(osver.dwMinorVersion));
2238         XPUSHs(newSViv(osver.dwBuildNumber));
2239         XPUSHs(newSViv(osver.dwPlatformId));
2240         PUTBACK;
2241         return;
2242     }
2243     XSRETURN_UNDEF;
2244 }
2245
2246 static
2247 XS(w32_IsWinNT)
2248 {
2249     dXSARGS;
2250     XSRETURN_IV(IsWinNT());
2251 }
2252
2253 static
2254 XS(w32_IsWin95)
2255 {
2256     dXSARGS;
2257     XSRETURN_IV(IsWin95());
2258 }
2259
2260 static
2261 XS(w32_FormatMessage)
2262 {
2263     dXSARGS;
2264     DWORD source = 0;
2265     char msgbuf[1024];
2266
2267     if (items != 1)
2268         croak("usage: Win32::FormatMessage($errno)");
2269
2270     if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
2271                       &source, SvIV(ST(0)), 0,
2272                       msgbuf, sizeof(msgbuf)-1, NULL))
2273         XSRETURN_PV(msgbuf);
2274
2275     XSRETURN_UNDEF;
2276 }
2277
2278 static
2279 XS(w32_Spawn)
2280 {
2281     dXSARGS;
2282     char *cmd, *args;
2283     PROCESS_INFORMATION stProcInfo;
2284     STARTUPINFO stStartInfo;
2285     BOOL bSuccess = FALSE;
2286
2287     if (items != 3)
2288         croak("usage: Win32::Spawn($cmdName, $args, $PID)");
2289
2290     cmd = SvPV(ST(0),na);
2291     args = SvPV(ST(1), na);
2292
2293     memset(&stStartInfo, 0, sizeof(stStartInfo));   /* Clear the block */
2294     stStartInfo.cb = sizeof(stStartInfo);           /* Set the structure size */
2295     stStartInfo.dwFlags = STARTF_USESHOWWINDOW;     /* Enable wShowWindow control */
2296     stStartInfo.wShowWindow = SW_SHOWMINNOACTIVE;   /* Start min (normal) */
2297
2298     if (CreateProcess(
2299                 cmd,                    /* Image path */
2300                 args,                   /* Arguments for command line */
2301                 NULL,                   /* Default process security */
2302                 NULL,                   /* Default thread security */
2303                 FALSE,                  /* Must be TRUE to use std handles */
2304                 NORMAL_PRIORITY_CLASS,  /* No special scheduling */
2305                 NULL,                   /* Inherit our environment block */
2306                 NULL,                   /* Inherit our currrent directory */
2307                 &stStartInfo,           /* -> Startup info */
2308                 &stProcInfo))           /* <- Process info (if OK) */
2309     {
2310         CloseHandle(stProcInfo.hThread);/* library source code does this. */
2311         sv_setiv(ST(2), stProcInfo.dwProcessId);
2312         bSuccess = TRUE;
2313     }
2314     XSRETURN_IV(bSuccess);
2315 }
2316
2317 static
2318 XS(w32_GetTickCount)
2319 {
2320     dXSARGS;
2321     XSRETURN_IV(GetTickCount());
2322 }
2323
2324 static
2325 XS(w32_GetShortPathName)
2326 {
2327     dXSARGS;
2328     SV *shortpath;
2329     DWORD len;
2330
2331     if (items != 1)
2332         croak("usage: Win32::GetShortPathName($longPathName)");
2333
2334     shortpath = sv_mortalcopy(ST(0));
2335     SvUPGRADE(shortpath, SVt_PV);
2336     /* src == target is allowed */
2337     do {
2338         len = GetShortPathName(SvPVX(shortpath),
2339                                SvPVX(shortpath),
2340                                SvLEN(shortpath));
2341     } while (len >= SvLEN(shortpath) && sv_grow(shortpath,len+1));
2342     if (len) {
2343         SvCUR_set(shortpath,len);
2344         ST(0) = shortpath;
2345     }
2346     else
2347         ST(0) = &sv_undef;
2348     XSRETURN(1);
2349 }
2350
2351 static
2352 XS(w32_Sleep)
2353 {
2354     dXSARGS;
2355     if (items != 1)
2356         croak("usage: Win32::Sleep($milliseconds)");
2357     Sleep(SvIV(ST(0)));
2358     XSRETURN_YES;
2359 }
2360
2361 #define TMPBUFSZ 1024
2362 #define MAX_LENGTH 2048
2363 #define SUCCESSRETURNED(x)      (x == ERROR_SUCCESS)
2364 #define REGRETURN(x) XSRETURN_IV(SUCCESSRETURNED(x))
2365 #define SvHKEY(index) (HKEY)((unsigned long)SvIV(index))
2366 #define SETIV(index,value) sv_setiv(ST(index), value)
2367 #define SETNV(index,value) sv_setnv(ST(index), value)
2368 #define SETPV(index,string) sv_setpv(ST(index), string)
2369 #define SETPVN(index, buffer, length) sv_setpvn(ST(index), (char*)buffer, length)
2370 #define SETHKEY(index, hkey)    SETIV(index,(long)hkey)
2371
2372 static time_t ft2timet(FILETIME *ft)
2373 {
2374     SYSTEMTIME st;
2375     struct tm tm;
2376
2377     FileTimeToSystemTime(ft, &st);
2378     tm.tm_sec = st.wSecond;
2379     tm.tm_min = st.wMinute;
2380     tm.tm_hour = st.wHour;
2381     tm.tm_mday = st.wDay;
2382     tm.tm_mon = st.wMonth - 1;
2383     tm.tm_year = st.wYear - 1900;
2384     tm.tm_wday = st.wDayOfWeek;
2385     tm.tm_yday = -1;
2386     tm.tm_isdst = -1;
2387     return mktime (&tm);
2388 }
2389
2390 static
2391 XS(w32_RegCloseKey)
2392 {
2393     dXSARGS;
2394
2395     if (items != 1) 
2396     {
2397         croak("usage: Win32::RegCloseKey($hkey);\n");
2398     }
2399
2400     REGRETURN(RegCloseKey(SvHKEY(ST(0))));
2401 }
2402
2403 static
2404 XS(w32_RegConnectRegistry)
2405 {
2406     dXSARGS;
2407     HKEY handle;
2408
2409     if (items != 3) 
2410     {
2411         croak("usage: Win32::RegConnectRegistry($machine, $hkey, $handle);\n");
2412     }
2413
2414     if (SUCCESSRETURNED(RegConnectRegistry((char *)SvPV(ST(0), na), SvHKEY(ST(1)), &handle))) 
2415     {
2416         SETHKEY(2,handle);
2417         XSRETURN_YES;
2418     }
2419     XSRETURN_NO;
2420 }
2421
2422 static
2423 XS(w32_RegCreateKey)
2424 {
2425     dXSARGS;
2426     HKEY handle;
2427     DWORD disposition;
2428     long retval;
2429
2430     if (items != 3) 
2431     {
2432         croak("usage: Win32::RegCreateKey($hkey, $subkey, $handle);\n");
2433     }
2434
2435     retval =  RegCreateKeyEx(SvHKEY(ST(0)), (char *)SvPV(ST(1), na), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
2436                                         NULL, &handle, &disposition);
2437
2438     if (SUCCESSRETURNED(retval)) 
2439     {
2440         SETHKEY(2,handle);
2441         XSRETURN_YES;
2442     }
2443     XSRETURN_NO;
2444 }
2445
2446 static
2447 XS(w32_RegCreateKeyEx)
2448 {
2449     dXSARGS;
2450
2451     unsigned int length;
2452     long retval;
2453     HKEY hkey, handle;
2454     char *subkey;
2455     char *keyclass;
2456     DWORD options, disposition;
2457     REGSAM sam;
2458     SECURITY_ATTRIBUTES sa, *psa;
2459
2460     if (items != 9) 
2461     {
2462         croak("usage: Win32::RegCreateKeyEx($hkey, $subkey, $reserved, $class, $options, $sam, "
2463                         "$security, $handle, $disposition);\n");
2464     }
2465
2466     hkey = SvHKEY(ST(0));
2467     subkey = (char *)SvPV(ST(1), na);
2468     keyclass = (char *)SvPV(ST(3), na);
2469     options = (DWORD) ((unsigned long)SvIV(ST(4)));
2470     sam = (REGSAM) ((unsigned long)SvIV(ST(5)));
2471     psa = (SECURITY_ATTRIBUTES*)SvPV(ST(6), length);
2472     if (length != sizeof(SECURITY_ATTRIBUTES))
2473     {
2474         psa = &sa;
2475         memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES));
2476         sa.nLength = sizeof(SECURITY_ATTRIBUTES);
2477     }
2478
2479     retval =  RegCreateKeyEx(hkey, subkey, 0, keyclass, options, sam,
2480                                         psa, &handle, &disposition);
2481
2482     if (SUCCESSRETURNED(retval)) 
2483     {
2484         if (psa == &sa)
2485             SETPVN(6, &sa, sizeof(sa));
2486
2487         SETHKEY(7,handle);
2488         SETIV(8,disposition);
2489         XSRETURN_YES;
2490     }
2491     XSRETURN_NO;
2492 }
2493
2494 static
2495 XS(w32_RegDeleteKey)
2496 {
2497     dXSARGS;
2498
2499     if (items != 2) 
2500     {
2501         croak("usage: Win32::RegDeleteKey($hkey, $subkey);\n");
2502     }
2503
2504     REGRETURN(RegDeleteKey(SvHKEY(ST(0)), (char *)SvPV(ST(1), na)));
2505 }
2506
2507 static
2508 XS(w32_RegDeleteValue)
2509 {
2510     dXSARGS;
2511
2512     if (items != 2) 
2513     {
2514         croak("usage: Win32::RegDeleteValue($hkey, $valname);\n");
2515     }
2516
2517     REGRETURN(RegDeleteValue(SvHKEY(ST(0)), (char *)SvPV(ST(1), na)));
2518 }
2519
2520 static
2521 XS(w32_RegEnumKey)
2522 {
2523     dXSARGS;
2524
2525     char keybuffer[TMPBUFSZ];
2526
2527     if (items != 3) 
2528     {
2529         croak("usage: Win32::RegEnumKey($hkey, $idx, $subkeyname);\n");
2530     }
2531
2532     if (SUCCESSRETURNED(RegEnumKey(SvHKEY(ST(0)), SvIV(ST(1)), keybuffer, sizeof(keybuffer)))) 
2533     {
2534         SETPV(2, keybuffer);
2535         XSRETURN_YES;
2536     }
2537     XSRETURN_NO;
2538 }
2539
2540 static
2541 XS(w32_RegEnumKeyEx)
2542 {
2543     dXSARGS;
2544     int length;
2545
2546     DWORD keysz, classsz;
2547     char keybuffer[TMPBUFSZ];
2548     char classbuffer[TMPBUFSZ];
2549     long retval;
2550     FILETIME filetime;
2551
2552     if (items != 6)                     
2553     {
2554         croak("usage: Win32::RegEnumKeyEx($hkey, $idx, $subkeyname, $reserved, $class, $time);\n");
2555     }
2556
2557     keysz = sizeof(keybuffer);
2558     classsz = sizeof(classbuffer);
2559     retval = RegEnumKeyEx(SvHKEY(ST(0)), SvIV(ST(1)), keybuffer, &keysz, 0,
2560                                                 classbuffer, &classsz, &filetime);
2561     if (SUCCESSRETURNED(retval)) 
2562     {
2563         SETPV(2, keybuffer);
2564         SETPV(4, classbuffer);
2565         SETIV(5, ft2timet(&filetime));
2566         XSRETURN_YES;
2567     }
2568     XSRETURN_NO;
2569 }
2570
2571 static
2572 XS(w32_RegEnumValue)
2573 {
2574     dXSARGS;
2575     HKEY hkey;
2576     DWORD type, namesz, valsz;
2577     long retval;
2578     static HKEY last_hkey;
2579     char  myvalbuf[MAX_LENGTH];
2580     char  mynambuf[MAX_LENGTH];
2581
2582     if (items != 6) 
2583     {
2584         croak("usage: Win32::RegEnumValue($hkey, $i, $name, $reserved, $type, $value);\n");
2585     }
2586
2587     hkey = SvHKEY(ST(0));
2588
2589     // If this is a new key, find out how big the maximum name and value sizes are and
2590     // allocate space for them. Free any old storage and set the old key value to the
2591     // current key.
2592
2593     if (hkey != (HKEY)last_hkey) 
2594     {
2595         char keyclass[TMPBUFSZ];
2596         DWORD classsz, subkeys, maxsubkey, maxclass, values, salen, maxnamesz, maxvalsz;
2597         FILETIME ft;
2598         classsz = sizeof(keyclass);
2599         retval = RegQueryInfoKey(hkey, keyclass, &classsz, 0, &subkeys, &maxsubkey, &maxclass,
2600                                                 &values, &maxnamesz, &maxvalsz, &salen, &ft);
2601
2602         if (!SUCCESSRETURNED(retval)) 
2603         {
2604             XSRETURN_NO;
2605         }
2606         memset(myvalbuf, 0, MAX_LENGTH);
2607         memset(mynambuf, 0, MAX_LENGTH);
2608         last_hkey = hkey;
2609     }
2610
2611     namesz = MAX_LENGTH;
2612     valsz = MAX_LENGTH;
2613     retval = RegEnumValue(hkey, SvIV(ST(1)), mynambuf, &namesz, 0, &type, (LPBYTE) myvalbuf, &valsz);
2614     if (!SUCCESSRETURNED(retval)) 
2615     {
2616         XSRETURN_NO;
2617     }
2618     else 
2619     {
2620         SETPV(2, mynambuf);
2621         SETIV(4, type);
2622
2623         // return includes the null terminator so delete it if REG_SZ, REG_MULTI_SZ or REG_EXPAND_SZ
2624         switch(type)
2625         {
2626             case REG_SZ:
2627             case REG_MULTI_SZ:
2628             case REG_EXPAND_SZ:
2629                 if (valsz)
2630                     --valsz;
2631             case REG_BINARY:
2632                 SETPVN(5, myvalbuf, valsz);
2633                 break;
2634
2635             case REG_DWORD_BIG_ENDIAN:
2636                 {
2637                     BYTE tmp = myvalbuf[0];
2638                     myvalbuf[0] = myvalbuf[3];
2639                     myvalbuf[3] = tmp;
2640                     tmp = myvalbuf[1];
2641                     myvalbuf[1] = myvalbuf[2];
2642                     myvalbuf[2] = tmp;
2643                 }
2644             case REG_DWORD_LITTLE_ENDIAN:       // same as REG_DWORD
2645                 SETNV(5, (double)*((DWORD*)myvalbuf));
2646                 break;
2647
2648             default:
2649                 break;
2650         }
2651
2652         XSRETURN_YES;
2653     }
2654 }
2655
2656 static
2657 XS(w32_RegFlushKey)
2658 {
2659     dXSARGS;
2660
2661     if (items != 1) 
2662     {
2663         croak("usage: Win32::RegFlushKey($hkey);\n");
2664     }
2665
2666     REGRETURN(RegFlushKey(SvHKEY(ST(0))));
2667 }
2668
2669 static
2670 XS(w32_RegGetKeySecurity)
2671 {
2672     dXSARGS;
2673     SECURITY_DESCRIPTOR sd;
2674     DWORD sdsz;
2675
2676     if (items != 3) 
2677     {
2678         croak("usage: Win32::RegGetKeySecurity($hkey, $security_info, $security_descriptor);\n");
2679     }
2680
2681     if (SUCCESSRETURNED(RegGetKeySecurity(SvHKEY(ST(0)), SvIV(ST(1)), &sd, &sdsz))) 
2682     {
2683         SETPVN(2, &sd, sdsz);
2684         XSRETURN_YES;
2685     }
2686     XSRETURN_NO;
2687 }
2688
2689 static
2690 XS(w32_RegLoadKey)
2691 {
2692     dXSARGS;
2693
2694     if (items != 3) 
2695     {
2696         croak("usage: Win32::RegLoadKey($hkey, $subkey, $filename);\n");
2697     }
2698
2699     REGRETURN(RegLoadKey(SvHKEY(ST(0)), (char *)SvPV(ST(1), na), (char *)SvPV(ST(2), na)));
2700 }
2701
2702 static
2703 XS(w32_RegNotifyChangeKeyValue)
2704 {
2705     croak("Win32::RegNotifyChangeKeyValue not yet implemented!\n");
2706 }
2707
2708 static
2709 XS(w32_RegOpenKey)
2710 {
2711     dXSARGS;
2712     HKEY handle;
2713
2714     if (items != 3) 
2715     {
2716         croak("usage: Win32::RegOpenKey($hkey, $subkey, $handle);\n");
2717     }
2718
2719     if (SUCCESSRETURNED(RegOpenKey(SvHKEY(ST(0)), (char *)SvPV(ST(1), na), &handle))) 
2720     {
2721         SETHKEY(2,handle);
2722         XSRETURN_YES;
2723     }
2724     XSRETURN_NO;
2725 }
2726
2727 static
2728 XS(w32_RegOpenKeyEx)
2729 {
2730     dXSARGS;
2731     HKEY handle;
2732
2733     if (items != 5) 
2734     {
2735         croak("usage: Win32::RegOpenKeyEx($hkey, $subkey, $reserved, $sam, $handle);\n");
2736     }
2737
2738     if (SUCCESSRETURNED(RegOpenKeyEx(SvHKEY(ST(0)), (char *)SvPV(ST(1), na), 
2739                                 0, (REGSAM) ((unsigned long)SvIV(ST(3))), &handle))) 
2740     {
2741         SETHKEY(4,handle);
2742         XSRETURN_YES;
2743     }
2744     XSRETURN_NO;
2745 }
2746
2747 #pragma optimize("", off)
2748 static
2749 XS(w32_RegQueryInfoKey)
2750 {
2751     dXSARGS;
2752     int length;
2753
2754     char keyclass[TMPBUFSZ];
2755     DWORD subkeys, maxsubkey, maxclass, values, maxvalname, maxvaldata;
2756     DWORD seclen, classsz;
2757     FILETIME ft;
2758     long retval;
2759
2760     if (items != 10) 
2761     {
2762         croak("usage: Win32::RegQueryInfoKey($hkey, $class, $numsubkeys, $maxsubkey,"
2763                 "$maxclass, $values, $maxvalname, $maxvaldata, $secdesclen,"
2764                         "$lastwritetime);\n");
2765     }
2766
2767     classsz = sizeof(keyclass);
2768     retval = RegQueryInfoKey(SvHKEY(ST(0)), keyclass, &classsz, 0, &subkeys, &maxsubkey,
2769                                 &maxclass, &values, &maxvalname, &maxvaldata,
2770                                         &seclen, &ft);
2771     if (SUCCESSRETURNED(retval)) 
2772     {
2773         SETPV(1, keyclass);
2774         SETIV(2, subkeys);
2775         SETIV(3, maxsubkey);
2776         SETIV(4, maxclass);
2777         SETIV(5, values);
2778         SETIV(6, maxvalname);
2779         SETIV(7, maxvaldata);
2780         SETIV(8, seclen);
2781         SETIV(9, ft2timet(&ft));
2782         XSRETURN_YES;
2783     }
2784     XSRETURN_NO;
2785 }
2786 #pragma optimize("", on)
2787
2788 static
2789 XS(w32_RegQueryValue)
2790 {
2791     dXSARGS;
2792
2793     unsigned char databuffer[TMPBUFSZ*2];
2794     long datasz = sizeof(databuffer);
2795
2796     if (items != 3) 
2797     {
2798         croak("usage: Win32::RegQueryValue($hkey, $valuename, $data);\n");
2799     }
2800
2801     if (SUCCESSRETURNED(RegQueryValue(SvHKEY(ST(0)), SvPV(ST(1), na), (char*)databuffer, &datasz))) 
2802     {
2803         // return includes the null terminator so delete it
2804         SETPVN(2, databuffer, --datasz);
2805         XSRETURN_YES;
2806     }
2807     XSRETURN_NO;
2808 }
2809
2810 static
2811 XS(w32_RegQueryValueEx)
2812 {
2813     dXSARGS;
2814
2815     unsigned char databuffer[TMPBUFSZ*2];
2816     DWORD datasz = sizeof(databuffer);
2817     DWORD type;
2818     LONG result;
2819     LPBYTE ptr = databuffer;
2820
2821     if (items != 5) 
2822     {
2823         croak("usage: Win32::RegQueryValueEx($hkey, $valuename, $reserved, $type, $data);\n");
2824     }
2825
2826     result = RegQueryValueEx(SvHKEY(ST(0)), SvPV(ST(1), na), 0, &type, ptr, &datasz);
2827     if (result == ERROR_MORE_DATA)
2828     {
2829         New(0, ptr, datasz+1, BYTE);
2830         result = RegQueryValueEx(SvHKEY(ST(0)), SvPV(ST(1), na), 0, &type, ptr, &datasz);
2831     }
2832     if (SUCCESSRETURNED(result)) 
2833     {
2834         SETIV(3, type);
2835
2836         // return includes the null terminator so delete it if REG_SZ, REG_MULTI_SZ or REG_EXPAND_SZ
2837         switch(type)
2838         {
2839             case REG_SZ:
2840             case REG_MULTI_SZ:
2841             case REG_EXPAND_SZ:
2842                 --datasz;
2843             case REG_BINARY:
2844                 SETPVN(4, ptr, datasz);
2845                 break;
2846
2847             case REG_DWORD_BIG_ENDIAN:
2848                 {
2849                     BYTE tmp = ptr[0];
2850                     ptr[0] = ptr[3];
2851                     ptr[3] = tmp;
2852                     tmp = ptr[1];
2853                     ptr[1] = ptr[2];
2854                     ptr[2] = tmp;
2855                 }
2856             case REG_DWORD_LITTLE_ENDIAN:       // same as REG_DWORD
2857                 SETNV(4, (double)*((DWORD*)ptr));
2858                 break;
2859
2860             default:
2861                 break;
2862         }
2863
2864         if (ptr != databuffer)
2865             safefree(ptr);
2866
2867         XSRETURN_YES;
2868     }
2869     if (ptr != databuffer)
2870         safefree(ptr);
2871
2872     XSRETURN_NO;
2873 }
2874
2875 static
2876 XS(w32_RegReplaceKey)
2877 {
2878     dXSARGS;
2879
2880     if (items != 4) 
2881     {
2882         croak("usage: Win32::RegReplaceKey($hkey, $subkey, $newfile, $oldfile);\n");
2883     }
2884
2885     REGRETURN(RegReplaceKey(SvHKEY(ST(0)), (char *)SvPV(ST(1), na), (char *)SvPV(ST(2), na), (char *)SvPV(ST(3), na)));
2886 }
2887
2888 static
2889 XS(w32_RegRestoreKey)
2890 {
2891     dXSARGS;
2892
2893     if (items < 2 || items > 3) 
2894     {
2895         croak("usage: Win32::RegRestoreKey($hkey, $filename [, $flags]);\n");
2896     }
2897
2898     REGRETURN(RegRestoreKey(SvHKEY(ST(0)), (char*)SvPV(ST(1), na), (DWORD)((items == 3) ? SvIV(ST(2)) : 0)));
2899 }
2900
2901 static
2902 XS(w32_RegSaveKey)
2903 {
2904     dXSARGS;
2905
2906     if (items != 2) 
2907     {
2908         croak("usage: Win32::RegSaveKey($hkey, $filename);\n");
2909     }
2910
2911     REGRETURN(RegSaveKey(SvHKEY(ST(0)), (char *)SvPV(ST(1), na), NULL));
2912 }
2913
2914 static
2915 XS(w32_RegSetKeySecurity)
2916 {
2917     dXSARGS;
2918
2919     if (items != 3) 
2920     {
2921         croak("usage: Win32::RegSetKeySecurity($hkey, $security_info, $security_descriptor);\n");
2922     }
2923
2924     REGRETURN(RegSetKeySecurity(SvHKEY(ST(0)), SvIV(ST(1)), (SECURITY_DESCRIPTOR*)SvPV(ST(2), na)));
2925 }
2926
2927 static
2928 XS(w32_RegSetValue)
2929 {
2930     dXSARGS;
2931
2932     unsigned int size;
2933     char *buffer;
2934         DWORD type;
2935
2936     if (items != 4) 
2937     {
2938         croak("usage: Win32::RegSetValue($hkey, $subKey, $type, $data);\n");
2939     }
2940
2941     type = SvIV(ST(2));
2942     if (type != REG_SZ && type != REG_EXPAND_SZ)
2943     {
2944         croak("Win32::RegSetValue: Type was not REG_SZ or REG_EXPAND_SZ, cannot set %s\n", (char *)SvPV(ST(1), na));
2945     }
2946
2947     buffer = (char *)SvPV(ST(3), size);
2948     REGRETURN(RegSetValue(SvHKEY(ST(0)), SvPV(ST(1), na), REG_SZ, buffer, size));
2949 }
2950
2951 static
2952 XS(w32_RegSetValueEx)
2953 {
2954     dXSARGS;
2955
2956     DWORD type;
2957     DWORD val;
2958     unsigned int size;
2959     char *buffer;
2960
2961     if (items != 5) 
2962     {
2963         croak("usage: Win32::RegSetValueEx($hkey, $valname, $reserved, $type, $data);\n");
2964     }
2965
2966     type = (DWORD)SvIV(ST(3));
2967     switch(type) 
2968     {
2969         case REG_SZ:
2970         case REG_BINARY:
2971         case REG_MULTI_SZ:
2972         case REG_EXPAND_SZ:
2973             buffer = (char *)SvPV(ST(4), size);
2974             if (type != REG_BINARY)
2975                 size++; // include null terminator in size
2976
2977             REGRETURN(RegSetValueEx(SvHKEY(ST(0)), (char *)SvPV(ST(1), na), 0, type, (PBYTE) buffer, size));
2978             break;
2979
2980         case REG_DWORD_BIG_ENDIAN:
2981         case REG_DWORD_LITTLE_ENDIAN: // Same as REG_DWORD
2982             val = (DWORD)SvIV(ST(4));
2983             REGRETURN(RegSetValueEx(SvHKEY(ST(0)), (char *)SvPV(ST(1), na), 0, type, (PBYTE) &val, sizeof(DWORD)));
2984             break;
2985
2986         default:
2987             croak("Win32::RegSetValueEx: Type not specified, cannot set %s\n", (char *)SvPV(ST(1), na));
2988     }
2989 }
2990
2991 static
2992 XS(w32_RegUnloadKey)
2993 {
2994     dXSARGS;
2995
2996     if (items != 2) 
2997     {
2998         croak("usage: Win32::RegUnLoadKey($hkey, $subkey);\n");
2999     }
3000
3001     REGRETURN(RegUnLoadKey(SvHKEY(ST(0)), (char *)SvPV(ST(1), na)));
3002 }
3003
3004 static
3005 XS(w32_RegisterServer)
3006 {
3007     dXSARGS;
3008     BOOL bSuccess = FALSE;
3009     HINSTANCE hInstance;
3010     unsigned int length;
3011     FARPROC sFunc;
3012
3013     if (items != 1) 
3014     {
3015         croak("usage: Win32::RegisterServer($LibraryName)\n");
3016     }
3017
3018     hInstance = LoadLibrary((char *)SvPV(ST(0), length));
3019     if (hInstance != NULL)
3020     {
3021         sFunc = GetProcAddress(hInstance, "DllRegisterServer");
3022         if (sFunc != NULL)
3023         {
3024             bSuccess = (sFunc() == 0);
3025         }
3026         FreeLibrary(hInstance);
3027     }
3028
3029     if (bSuccess)
3030     {
3031         XSRETURN_YES;
3032     }
3033     XSRETURN_NO;
3034 }
3035
3036 static
3037 XS(w32_UnregisterServer)
3038 {
3039     dXSARGS;
3040     BOOL bSuccess = FALSE;
3041     HINSTANCE hInstance;
3042     unsigned int length;
3043     FARPROC sFunc;
3044
3045     if (items != 1) 
3046     {
3047         croak("usage: Win32::UnregisterServer($LibraryName)\n");
3048     }
3049
3050     hInstance = LoadLibrary((char *)SvPV(ST(0), length));
3051     if (hInstance != NULL)
3052     {
3053         sFunc = GetProcAddress(hInstance, "DllUnregisterServer");
3054         if (sFunc != NULL)
3055         {
3056             bSuccess = (sFunc() == 0);
3057         }
3058         FreeLibrary(hInstance);
3059     }
3060
3061     if (bSuccess)
3062     {
3063         XSRETURN_YES;
3064     }
3065     XSRETURN_NO;
3066 }
3067
3068
3069 void
3070 Perl_init_os_extras()
3071 {
3072     char *file = __FILE__;
3073     dXSUB_SYS;
3074
3075     w32_perlshell_tokens = Nullch;
3076     w32_perlshell_items = -1;
3077     w32_fdpid = newAV();                /* XXX needs to be in Perl_win32_init()? */
3078 #ifndef USE_RTL_WAIT
3079     w32_num_children = 0;
3080 #endif
3081
3082     /* these names are Activeware compatible */
3083     newXS("Win32::GetCwd", w32_GetCwd, file);
3084     newXS("Win32::SetCwd", w32_SetCwd, file);
3085     newXS("Win32::GetNextAvailDrive", w32_GetNextAvailDrive, file);
3086     newXS("Win32::GetLastError", w32_GetLastError, file);
3087     newXS("Win32::LoginName", w32_LoginName, file);
3088     newXS("Win32::NodeName", w32_NodeName, file);
3089     newXS("Win32::DomainName", w32_DomainName, file);
3090     newXS("Win32::FsType", w32_FsType, file);
3091     newXS("Win32::GetOSVersion", w32_GetOSVersion, file);
3092     newXS("Win32::IsWinNT", w32_IsWinNT, file);
3093     newXS("Win32::IsWin95", w32_IsWin95, file);
3094     newXS("Win32::FormatMessage", w32_FormatMessage, file);
3095     newXS("Win32::Spawn", w32_Spawn, file);
3096     newXS("Win32::GetTickCount", w32_GetTickCount, file);
3097     newXS("Win32::GetShortPathName", w32_GetShortPathName, file);
3098     newXS("Win32::Sleep", w32_Sleep, file);
3099
3100     /* the following extensions are used interally and may be changed at any time */
3101     /* therefore no documentation is provided */
3102     newXS("Win32::RegCloseKey", w32_RegCloseKey, file);
3103     newXS("Win32::RegConnectRegistry", w32_RegConnectRegistry, file);
3104     newXS("Win32::RegCreateKey", w32_RegCreateKey, file);
3105     newXS("Win32::RegCreateKeyEx", w32_RegCreateKeyEx, file);
3106     newXS("Win32::RegDeleteKey", w32_RegDeleteKey, file);
3107     newXS("Win32::RegDeleteValue", w32_RegDeleteValue, file);
3108
3109     newXS("Win32::RegEnumKey", w32_RegEnumKey, file);
3110     newXS("Win32::RegEnumKeyEx", w32_RegEnumKeyEx, file);
3111     newXS("Win32::RegEnumValue", w32_RegEnumValue, file);
3112
3113     newXS("Win32::RegFlushKey", w32_RegFlushKey, file);
3114     newXS("Win32::RegGetKeySecurity", w32_RegGetKeySecurity, file);
3115
3116     newXS("Win32::RegLoadKey", w32_RegLoadKey, file);
3117     newXS("Win32::RegOpenKey", w32_RegOpenKey, file);
3118     newXS("Win32::RegOpenKeyEx", w32_RegOpenKeyEx, file);
3119     newXS("Win32::RegQueryInfoKey", w32_RegQueryInfoKey, file);
3120     newXS("Win32::RegQueryValue", w32_RegQueryValue, file);
3121     newXS("Win32::RegQueryValueEx", w32_RegQueryValueEx, file);
3122
3123     newXS("Win32::RegReplaceKey", w32_RegReplaceKey, file);
3124     newXS("Win32::RegRestoreKey", w32_RegRestoreKey, file);
3125     newXS("Win32::RegSaveKey", w32_RegSaveKey, file);
3126     newXS("Win32::RegSetKeySecurity", w32_RegSetKeySecurity, file);
3127     newXS("Win32::RegSetValue", w32_RegSetValue, file);
3128     newXS("Win32::RegSetValueEx", w32_RegSetValueEx, file);
3129     newXS("Win32::RegUnloadKey", w32_RegUnloadKey, file);
3130
3131     newXS("Win32::RegisterServer", w32_RegisterServer, file);
3132     newXS("Win32::UnregisterServer", w32_UnregisterServer, file);
3133
3134     /* XXX Bloat Alert! The following Activeware preloads really
3135      * ought to be part of Win32::Sys::*, so they're not included
3136      * here.
3137      */
3138     /* LookupAccountName
3139      * LookupAccountSID
3140      * InitiateSystemShutdown
3141      * AbortSystemShutdown
3142      * ExpandEnvrironmentStrings
3143      */
3144 }
3145
3146 void
3147 Perl_win32_init(int *argcp, char ***argvp)
3148 {
3149     /* Disable floating point errors, Perl will trap the ones we
3150      * care about.  VC++ RTL defaults to switching these off
3151      * already, but the Borland RTL doesn't.  Since we don't
3152      * want to be at the vendor's whim on the default, we set
3153      * it explicitly here.
3154      */
3155 #if !defined(_ALPHA_) && !defined(__GNUC__)
3156     _control87(MCW_EM, MCW_EM);
3157 #endif
3158     MALLOC_INIT;
3159 }
3160
3161 #ifdef USE_BINMODE_SCRIPTS
3162
3163 void
3164 win32_strip_return(SV *sv)
3165 {
3166  char *s = SvPVX(sv);
3167  char *e = s+SvCUR(sv);
3168  char *d = s;
3169  while (s < e)
3170   {
3171    if (*s == '\r' && s[1] == '\n')
3172     {
3173      *d++ = '\n';
3174      s += 2;
3175     }
3176    else 
3177     {
3178      *d++ = *s++;
3179     }   
3180   }
3181  SvCUR_set(sv,d-SvPVX(sv)); 
3182 }
3183
3184 #endif