d4be76a7bd08983536f7625c535a7bd5897d64f6
[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     if (!(needlen = GetEnvironmentVariable(name,curitem,curlen)))
982         return Nullch;
983     while (needlen > curlen) {
984         Renew(curitem,needlen,char);
985         curlen = needlen;
986         needlen = GetEnvironmentVariable(name,curitem,curlen);
987     }
988     if (curitem == NULL)
989     {
990         if (strcmp("PERL5DB", name) == 0)
991             curitem = GetRegStr(name, &curitem, &curlen);
992     }
993     return curitem;
994 }
995
996 #endif
997
998 static long
999 filetime_to_clock(PFILETIME ft)
1000 {
1001  __int64 qw = ft->dwHighDateTime;
1002  qw <<= 32;
1003  qw |= ft->dwLowDateTime;
1004  qw /= 10000;  /* File time ticks at 0.1uS, clock at 1mS */
1005  return (long) qw;
1006 }
1007
1008 DllExport int
1009 win32_times(struct tms *timebuf)
1010 {
1011     FILETIME user;
1012     FILETIME kernel;
1013     FILETIME dummy;
1014     if (GetProcessTimes(GetCurrentProcess(), &dummy, &dummy, 
1015                         &kernel,&user)) {
1016         timebuf->tms_utime = filetime_to_clock(&user);
1017         timebuf->tms_stime = filetime_to_clock(&kernel);
1018         timebuf->tms_cutime = 0;
1019         timebuf->tms_cstime = 0;
1020         
1021     } else { 
1022         /* That failed - e.g. Win95 fallback to clock() */
1023         clock_t t = clock();
1024         timebuf->tms_utime = t;
1025         timebuf->tms_stime = 0;
1026         timebuf->tms_cutime = 0;
1027         timebuf->tms_cstime = 0;
1028     }
1029     return 0;
1030 }
1031
1032 /* fix utime() so it works on directories in NT
1033  * thanks to Jan Dubois <jan.dubois@ibm.net>
1034  */
1035 static BOOL
1036 filetime_from_time(PFILETIME pFileTime, time_t Time)
1037 {
1038     struct tm *pTM = gmtime(&Time);
1039     SYSTEMTIME SystemTime;
1040
1041     if (pTM == NULL)
1042         return FALSE;
1043
1044     SystemTime.wYear   = pTM->tm_year + 1900;
1045     SystemTime.wMonth  = pTM->tm_mon + 1;
1046     SystemTime.wDay    = pTM->tm_mday;
1047     SystemTime.wHour   = pTM->tm_hour;
1048     SystemTime.wMinute = pTM->tm_min;
1049     SystemTime.wSecond = pTM->tm_sec;
1050     SystemTime.wMilliseconds = 0;
1051
1052     return SystemTimeToFileTime(&SystemTime, pFileTime);
1053 }
1054
1055 DllExport int
1056 win32_utime(const char *filename, struct utimbuf *times)
1057 {
1058     HANDLE handle;
1059     FILETIME ftCreate;
1060     FILETIME ftAccess;
1061     FILETIME ftWrite;
1062     struct utimbuf TimeBuffer;
1063
1064     int rc = utime(filename,times);
1065     /* EACCES: path specifies directory or readonly file */
1066     if (rc == 0 || errno != EACCES /* || !IsWinNT() */)
1067         return rc;
1068
1069     if (times == NULL) {
1070         times = &TimeBuffer;
1071         time(&times->actime);
1072         times->modtime = times->actime;
1073     }
1074
1075     /* This will (and should) still fail on readonly files */
1076     handle = CreateFile(filename, GENERIC_READ | GENERIC_WRITE,
1077                         FILE_SHARE_READ | FILE_SHARE_DELETE, NULL,
1078                         OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
1079     if (handle == INVALID_HANDLE_VALUE)
1080         return rc;
1081
1082     if (GetFileTime(handle, &ftCreate, &ftAccess, &ftWrite) &&
1083         filetime_from_time(&ftAccess, times->actime) &&
1084         filetime_from_time(&ftWrite, times->modtime) &&
1085         SetFileTime(handle, &ftCreate, &ftAccess, &ftWrite))
1086     {
1087         rc = 0;
1088     }
1089
1090     CloseHandle(handle);
1091     return rc;
1092 }
1093
1094 DllExport int
1095 win32_wait(int *status)
1096 {
1097 #ifdef USE_RTL_WAIT
1098     return wait(status);
1099 #else
1100     /* XXX this wait emulation only knows about processes
1101      * spawned via win32_spawnvp(P_NOWAIT, ...).
1102      */
1103     int i, retval;
1104     DWORD exitcode, waitcode;
1105
1106     if (!w32_num_children) {
1107         errno = ECHILD;
1108         return -1;
1109     }
1110
1111     /* if a child exists, wait for it to die */
1112     waitcode = WaitForMultipleObjects(w32_num_children,
1113                                       w32_child_pids,
1114                                       FALSE,
1115                                       INFINITE);
1116     if (waitcode != WAIT_FAILED) {
1117         if (waitcode >= WAIT_ABANDONED_0
1118             && waitcode < WAIT_ABANDONED_0 + w32_num_children)
1119             i = waitcode - WAIT_ABANDONED_0;
1120         else
1121             i = waitcode - WAIT_OBJECT_0;
1122         if (GetExitCodeProcess(w32_child_pids[i], &exitcode) ) {
1123             CloseHandle(w32_child_pids[i]);
1124             *status = (int)((exitcode & 0xff) << 8);
1125             retval = (int)w32_child_pids[i];
1126             Copy(&w32_child_pids[i+1], &w32_child_pids[i],
1127                  (w32_num_children-i-1), HANDLE);
1128             w32_num_children--;
1129             return retval;
1130         }
1131     }
1132
1133 FAILED:
1134     errno = GetLastError();
1135     return -1;
1136
1137 #endif
1138 }
1139
1140 static UINT timerid = 0;
1141
1142 static VOID CALLBACK TimerProc(HWND win, UINT msg, UINT id, DWORD time)
1143 {
1144  KillTimer(NULL,timerid);
1145  timerid=0;  
1146  sighandler(14);
1147 }
1148
1149 DllExport unsigned int
1150 win32_alarm(unsigned int sec)
1151 {
1152     /* 
1153      * the 'obvious' implentation is SetTimer() with a callback
1154      * which does whatever receiving SIGALRM would do 
1155      * we cannot use SIGALRM even via raise() as it is not 
1156      * one of the supported codes in <signal.h>
1157      *
1158      * Snag is unless something is looking at the message queue
1159      * nothing happens :-(
1160      */ 
1161     if (sec)
1162      {
1163       timerid = SetTimer(NULL,timerid,sec*1000,(TIMERPROC)TimerProc);
1164       if (!timerid)
1165        croak("Cannot set timer");
1166      } 
1167     else
1168      {
1169       if (timerid)
1170        {
1171         KillTimer(NULL,timerid);
1172         timerid=0;  
1173        }
1174      }
1175     return 0;
1176 }
1177
1178 #ifdef HAVE_DES_FCRYPT
1179 extern char *   des_fcrypt(char *cbuf, const char *txt, const char *salt);
1180
1181 DllExport char *
1182 win32_crypt(const char *txt, const char *salt)
1183 {
1184     dTHR;
1185     return des_fcrypt(crypt_buffer, txt, salt);
1186 }
1187 #endif
1188
1189 #ifdef USE_FIXED_OSFHANDLE
1190
1191 EXTERN_C int __cdecl _alloc_osfhnd(void);
1192 EXTERN_C int __cdecl _set_osfhnd(int fh, long value);
1193 EXTERN_C void __cdecl _lock_fhandle(int);
1194 EXTERN_C void __cdecl _unlock_fhandle(int);
1195 EXTERN_C void __cdecl _unlock(int);
1196
1197 #if     (_MSC_VER >= 1000)
1198 typedef struct  {
1199     long osfhnd;    /* underlying OS file HANDLE */
1200     char osfile;    /* attributes of file (e.g., open in text mode?) */
1201     char pipech;    /* one char buffer for handles opened on pipes */
1202 #if defined (_MT) && !defined (DLL_FOR_WIN32S)
1203     int lockinitflag;
1204     CRITICAL_SECTION lock;
1205 #endif  /* defined (_MT) && !defined (DLL_FOR_WIN32S) */
1206 }       ioinfo;
1207
1208 EXTERN_C ioinfo * __pioinfo[];
1209
1210 #define IOINFO_L2E                      5
1211 #define IOINFO_ARRAY_ELTS       (1 << IOINFO_L2E)
1212 #define _pioinfo(i)     (__pioinfo[i >> IOINFO_L2E] + (i & (IOINFO_ARRAY_ELTS - 1)))
1213 #define _osfile(i)      (_pioinfo(i)->osfile)
1214
1215 #else   /* (_MSC_VER >= 1000) */
1216 extern char _osfile[];
1217 #endif  /* (_MSC_VER >= 1000) */
1218
1219 #define FOPEN                   0x01    /* file handle open */
1220 #define FAPPEND                 0x20    /* file handle opened O_APPEND */
1221 #define FDEV                    0x40    /* file handle refers to device */
1222 #define FTEXT                   0x80    /* file handle is in text mode */
1223
1224 #define _STREAM_LOCKS   26              /* Table of stream locks */
1225 #define _LAST_STREAM_LOCK  (_STREAM_LOCKS+_NSTREAM_-1)  /* Last stream lock */
1226 #define _FH_LOCKS          (_LAST_STREAM_LOCK+1)        /* Table of fh locks */
1227
1228 /***
1229 *int my_open_osfhandle(long osfhandle, int flags) - open C Runtime file handle
1230 *
1231 *Purpose:
1232 *       This function allocates a free C Runtime file handle and associates
1233 *       it with the Win32 HANDLE specified by the first parameter. This is a
1234 *               temperary fix for WIN95's brain damage GetFileType() error on socket
1235 *               we just bypass that call for socket
1236 *
1237 *Entry:
1238 *       long osfhandle - Win32 HANDLE to associate with C Runtime file handle.
1239 *       int flags      - flags to associate with C Runtime file handle.
1240 *
1241 *Exit:
1242 *       returns index of entry in fh, if successful
1243 *       return -1, if no free entry is found
1244 *
1245 *Exceptions:
1246 *
1247 *******************************************************************************/
1248
1249 static int
1250 my_open_osfhandle(long osfhandle, int flags)
1251 {
1252     int fh;
1253     char fileflags;             /* _osfile flags */
1254
1255     /* copy relevant flags from second parameter */
1256     fileflags = FDEV;
1257
1258     if (flags & O_APPEND)
1259         fileflags |= FAPPEND;
1260
1261     if (flags & O_TEXT)
1262         fileflags |= FTEXT;
1263
1264     /* attempt to allocate a C Runtime file handle */
1265     if ((fh = _alloc_osfhnd()) == -1) {
1266         errno = EMFILE;         /* too many open files */
1267         _doserrno = 0L;         /* not an OS error */
1268         return -1;              /* return error to caller */
1269     }
1270
1271     /* the file is open. now, set the info in _osfhnd array */
1272     _set_osfhnd(fh, osfhandle);
1273
1274     fileflags |= FOPEN;         /* mark as open */
1275
1276 #if (_MSC_VER >= 1000)
1277     _osfile(fh) = fileflags;    /* set osfile entry */
1278     _unlock_fhandle(fh);
1279 #else
1280     _osfile[fh] = fileflags;    /* set osfile entry */
1281     _unlock(fh+_FH_LOCKS);              /* unlock handle */
1282 #endif
1283
1284     return fh;                  /* return handle */
1285 }
1286
1287 #define _open_osfhandle my_open_osfhandle
1288 #endif  /* USE_FIXED_OSFHANDLE */
1289
1290 /* simulate flock by locking a range on the file */
1291
1292 #define LK_ERR(f,i)     ((f) ? (i = 0) : (errno = GetLastError()))
1293 #define LK_LEN          0xffff0000
1294
1295 DllExport int
1296 win32_flock(int fd, int oper)
1297 {
1298     OVERLAPPED o;
1299     int i = -1;
1300     HANDLE fh;
1301
1302     if (!IsWinNT()) {
1303         croak("flock() unimplemented on this platform");
1304         return -1;
1305     }
1306     fh = (HANDLE)_get_osfhandle(fd);
1307     memset(&o, 0, sizeof(o));
1308
1309     switch(oper) {
1310     case LOCK_SH:               /* shared lock */
1311         LK_ERR(LockFileEx(fh, 0, 0, LK_LEN, 0, &o),i);
1312         break;
1313     case LOCK_EX:               /* exclusive lock */
1314         LK_ERR(LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, LK_LEN, 0, &o),i);
1315         break;
1316     case LOCK_SH|LOCK_NB:       /* non-blocking shared lock */
1317         LK_ERR(LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY, 0, LK_LEN, 0, &o),i);
1318         break;
1319     case LOCK_EX|LOCK_NB:       /* non-blocking exclusive lock */
1320         LK_ERR(LockFileEx(fh,
1321                        LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY,
1322                        0, LK_LEN, 0, &o),i);
1323         break;
1324     case LOCK_UN:               /* unlock lock */
1325         LK_ERR(UnlockFileEx(fh, 0, LK_LEN, 0, &o),i);
1326         break;
1327     default:                    /* unknown */
1328         errno = EINVAL;
1329         break;
1330     }
1331     return i;
1332 }
1333
1334 #undef LK_ERR
1335 #undef LK_LEN
1336
1337 /*
1338  *  redirected io subsystem for all XS modules
1339  *
1340  */
1341
1342 DllExport int *
1343 win32_errno(void)
1344 {
1345     return (&errno);
1346 }
1347
1348 DllExport char ***
1349 win32_environ(void)
1350 {
1351     return (&(_environ));
1352 }
1353
1354 /* the rest are the remapped stdio routines */
1355 DllExport FILE *
1356 win32_stderr(void)
1357 {
1358     return (stderr);
1359 }
1360
1361 DllExport FILE *
1362 win32_stdin(void)
1363 {
1364     return (stdin);
1365 }
1366
1367 DllExport FILE *
1368 win32_stdout()
1369 {
1370     return (stdout);
1371 }
1372
1373 DllExport int
1374 win32_ferror(FILE *fp)
1375 {
1376     return (ferror(fp));
1377 }
1378
1379
1380 DllExport int
1381 win32_feof(FILE *fp)
1382 {
1383     return (feof(fp));
1384 }
1385
1386 /*
1387  * Since the errors returned by the socket error function 
1388  * WSAGetLastError() are not known by the library routine strerror
1389  * we have to roll our own.
1390  */
1391
1392 DllExport char *
1393 win32_strerror(int e) 
1394 {
1395 #ifndef __BORLANDC__            /* Borland intolerance */
1396     extern int sys_nerr;
1397 #endif
1398     DWORD source = 0;
1399
1400     if (e < 0 || e > sys_nerr) {
1401         dTHR;
1402         if (e < 0)
1403             e = GetLastError();
1404
1405         if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, &source, e, 0,
1406                          strerror_buffer, sizeof(strerror_buffer), NULL) == 0) 
1407             strcpy(strerror_buffer, "Unknown Error");
1408
1409         return strerror_buffer;
1410     }
1411     return strerror(e);
1412 }
1413
1414 DllExport void
1415 win32_str_os_error(void *sv, DWORD dwErr)
1416 {
1417     DWORD dwLen;
1418     char *sMsg;
1419     dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
1420                           |FORMAT_MESSAGE_IGNORE_INSERTS
1421                           |FORMAT_MESSAGE_FROM_SYSTEM, NULL,
1422                            dwErr, 0, (char *)&sMsg, 1, NULL);
1423     if (0 < dwLen) {
1424         while (0 < dwLen  &&  isspace(sMsg[--dwLen]))
1425             ;
1426         if ('.' != sMsg[dwLen])
1427             dwLen++;
1428         sMsg[dwLen]= '\0';
1429     }
1430     if (0 == dwLen) {
1431         sMsg = (char*)LocalAlloc(0, 64/**sizeof(TCHAR)*/);
1432         dwLen = sprintf(sMsg,
1433                         "Unknown error #0x%lX (lookup 0x%lX)",
1434                         dwErr, GetLastError());
1435     }
1436     sv_setpvn((SV*)sv, sMsg, dwLen);
1437     LocalFree(sMsg);
1438 }
1439
1440
1441 DllExport int
1442 win32_fprintf(FILE *fp, const char *format, ...)
1443 {
1444     va_list marker;
1445     va_start(marker, format);     /* Initialize variable arguments. */
1446
1447     return (vfprintf(fp, format, marker));
1448 }
1449
1450 DllExport int
1451 win32_printf(const char *format, ...)
1452 {
1453     va_list marker;
1454     va_start(marker, format);     /* Initialize variable arguments. */
1455
1456     return (vprintf(format, marker));
1457 }
1458
1459 DllExport int
1460 win32_vfprintf(FILE *fp, const char *format, va_list args)
1461 {
1462     return (vfprintf(fp, format, args));
1463 }
1464
1465 DllExport int
1466 win32_vprintf(const char *format, va_list args)
1467 {
1468     return (vprintf(format, args));
1469 }
1470
1471 DllExport size_t
1472 win32_fread(void *buf, size_t size, size_t count, FILE *fp)
1473 {
1474     return fread(buf, size, count, fp);
1475 }
1476
1477 DllExport size_t
1478 win32_fwrite(const void *buf, size_t size, size_t count, FILE *fp)
1479 {
1480     return fwrite(buf, size, count, fp);
1481 }
1482
1483 DllExport FILE *
1484 win32_fopen(const char *filename, const char *mode)
1485 {
1486     if (stricmp(filename, "/dev/null")==0)
1487         return fopen("NUL", mode);
1488     return fopen(filename, mode);
1489 }
1490
1491 #ifndef USE_SOCKETS_AS_HANDLES
1492 #undef fdopen
1493 #define fdopen my_fdopen
1494 #endif
1495
1496 DllExport FILE *
1497 win32_fdopen( int handle, const char *mode)
1498 {
1499     return fdopen(handle, (char *) mode);
1500 }
1501
1502 DllExport FILE *
1503 win32_freopen( const char *path, const char *mode, FILE *stream)
1504 {
1505     if (stricmp(path, "/dev/null")==0)
1506         return freopen("NUL", mode, stream);
1507     return freopen(path, mode, stream);
1508 }
1509
1510 DllExport int
1511 win32_fclose(FILE *pf)
1512 {
1513     return my_fclose(pf);       /* defined in win32sck.c */
1514 }
1515
1516 DllExport int
1517 win32_fputs(const char *s,FILE *pf)
1518 {
1519     return fputs(s, pf);
1520 }
1521
1522 DllExport int
1523 win32_fputc(int c,FILE *pf)
1524 {
1525     return fputc(c,pf);
1526 }
1527
1528 DllExport int
1529 win32_ungetc(int c,FILE *pf)
1530 {
1531     return ungetc(c,pf);
1532 }
1533
1534 DllExport int
1535 win32_getc(FILE *pf)
1536 {
1537     return getc(pf);
1538 }
1539
1540 DllExport int
1541 win32_fileno(FILE *pf)
1542 {
1543     return fileno(pf);
1544 }
1545
1546 DllExport void
1547 win32_clearerr(FILE *pf)
1548 {
1549     clearerr(pf);
1550     return;
1551 }
1552
1553 DllExport int
1554 win32_fflush(FILE *pf)
1555 {
1556     return fflush(pf);
1557 }
1558
1559 DllExport long
1560 win32_ftell(FILE *pf)
1561 {
1562     return ftell(pf);
1563 }
1564
1565 DllExport int
1566 win32_fseek(FILE *pf,long offset,int origin)
1567 {
1568     return fseek(pf, offset, origin);
1569 }
1570
1571 DllExport int
1572 win32_fgetpos(FILE *pf,fpos_t *p)
1573 {
1574     return fgetpos(pf, p);
1575 }
1576
1577 DllExport int
1578 win32_fsetpos(FILE *pf,const fpos_t *p)
1579 {
1580     return fsetpos(pf, p);
1581 }
1582
1583 DllExport void
1584 win32_rewind(FILE *pf)
1585 {
1586     rewind(pf);
1587     return;
1588 }
1589
1590 DllExport FILE*
1591 win32_tmpfile(void)
1592 {
1593     return tmpfile();
1594 }
1595
1596 DllExport void
1597 win32_abort(void)
1598 {
1599     abort();
1600     return;
1601 }
1602
1603 DllExport int
1604 win32_fstat(int fd,struct stat *sbufptr)
1605 {
1606     return fstat(fd,sbufptr);
1607 }
1608
1609 DllExport int
1610 win32_pipe(int *pfd, unsigned int size, int mode)
1611 {
1612     return _pipe(pfd, size, mode);
1613 }
1614
1615 /*
1616  * a popen() clone that respects PERL5SHELL
1617  */
1618
1619 DllExport FILE*
1620 win32_popen(const char *command, const char *mode)
1621 {
1622 #ifdef USE_RTL_POPEN
1623     return _popen(command, mode);
1624 #else
1625     int p[2];
1626     int parent, child;
1627     int stdfd, oldfd;
1628     int ourmode;
1629     int childpid;
1630
1631     /* establish which ends read and write */
1632     if (strchr(mode,'w')) {
1633         stdfd = 0;              /* stdin */
1634         parent = 1;
1635         child = 0;
1636     }
1637     else if (strchr(mode,'r')) {
1638         stdfd = 1;              /* stdout */
1639         parent = 0;
1640         child = 1;
1641     }
1642     else
1643         return NULL;
1644
1645     /* set the correct mode */
1646     if (strchr(mode,'b'))
1647         ourmode = O_BINARY;
1648     else if (strchr(mode,'t'))
1649         ourmode = O_TEXT;
1650     else
1651         ourmode = _fmode & (O_TEXT | O_BINARY);
1652
1653     /* the child doesn't inherit handles */
1654     ourmode |= O_NOINHERIT;
1655
1656     if (win32_pipe( p, 512, ourmode) == -1)
1657         return NULL;
1658
1659     /* save current stdfd */
1660     if ((oldfd = win32_dup(stdfd)) == -1)
1661         goto cleanup;
1662
1663     /* make stdfd go to child end of pipe (implicitly closes stdfd) */
1664     /* stdfd will be inherited by the child */
1665     if (win32_dup2(p[child], stdfd) == -1)
1666         goto cleanup;
1667
1668     /* close the child end in parent */
1669     win32_close(p[child]);
1670
1671     /* start the child */
1672     if ((childpid = do_spawn_nowait((char*)command)) == -1)
1673         goto cleanup;
1674
1675     /* revert stdfd to whatever it was before */
1676     if (win32_dup2(oldfd, stdfd) == -1)
1677         goto cleanup;
1678
1679     /* close saved handle */
1680     win32_close(oldfd);
1681
1682     sv_setiv(*av_fetch(w32_fdpid, p[parent], TRUE), childpid);
1683
1684     /* we have an fd, return a file stream */
1685     return (win32_fdopen(p[parent], (char *)mode));
1686
1687 cleanup:
1688     /* we don't need to check for errors here */
1689     win32_close(p[0]);
1690     win32_close(p[1]);
1691     if (oldfd != -1) {
1692         win32_dup2(oldfd, stdfd);
1693         win32_close(oldfd);
1694     }
1695     return (NULL);
1696
1697 #endif /* USE_RTL_POPEN */
1698 }
1699
1700 /*
1701  * pclose() clone
1702  */
1703
1704 DllExport int
1705 win32_pclose(FILE *pf)
1706 {
1707 #ifdef USE_RTL_POPEN
1708     return _pclose(pf);
1709 #else
1710
1711 #ifndef USE_RTL_WAIT
1712     int child;
1713 #endif
1714
1715     int childpid, status;
1716     SV *sv;
1717
1718     sv = *av_fetch(w32_fdpid, win32_fileno(pf), TRUE);
1719     if (SvIOK(sv))
1720         childpid = SvIVX(sv);
1721     else
1722         childpid = 0;
1723
1724     if (!childpid) {
1725         errno = EBADF;
1726         return -1;
1727     }
1728
1729     win32_fclose(pf);
1730     SvIVX(sv) = 0;
1731
1732 #ifndef USE_RTL_WAIT
1733     for (child = 0 ; child < w32_num_children ; ++child) {
1734         if (w32_child_pids[child] == (HANDLE)childpid) {
1735             Copy(&w32_child_pids[child+1], &w32_child_pids[child],
1736                  (w32_num_children-child-1), HANDLE);
1737             w32_num_children--;
1738             break;
1739         }
1740     }
1741 #endif
1742
1743     /* wait for the child */
1744     if (cwait(&status, childpid, WAIT_CHILD) == -1)
1745         return (-1);
1746     /* cwait() returns differently on Borland */
1747 #ifdef __BORLANDC__
1748     return (((status >> 8) & 0xff) | ((status << 8) & 0xff00));
1749 #else
1750     return (status);
1751 #endif
1752
1753 #endif /* USE_RTL_POPEN */
1754 }
1755
1756 DllExport int
1757 win32_setmode(int fd, int mode)
1758 {
1759     return setmode(fd, mode);
1760 }
1761
1762 DllExport long
1763 win32_lseek(int fd, long offset, int origin)
1764 {
1765     return lseek(fd, offset, origin);
1766 }
1767
1768 DllExport long
1769 win32_tell(int fd)
1770 {
1771     return tell(fd);
1772 }
1773
1774 DllExport int
1775 win32_open(const char *path, int flag, ...)
1776 {
1777     va_list ap;
1778     int pmode;
1779
1780     va_start(ap, flag);
1781     pmode = va_arg(ap, int);
1782     va_end(ap);
1783
1784     if (stricmp(path, "/dev/null")==0)
1785         return open("NUL", flag, pmode);
1786     return open(path,flag,pmode);
1787 }
1788
1789 DllExport int
1790 win32_close(int fd)
1791 {
1792     return close(fd);
1793 }
1794
1795 DllExport int
1796 win32_eof(int fd)
1797 {
1798     return eof(fd);
1799 }
1800
1801 DllExport int
1802 win32_dup(int fd)
1803 {
1804     return dup(fd);
1805 }
1806
1807 DllExport int
1808 win32_dup2(int fd1,int fd2)
1809 {
1810     return dup2(fd1,fd2);
1811 }
1812
1813 DllExport int
1814 win32_read(int fd, void *buf, unsigned int cnt)
1815 {
1816     return read(fd, buf, cnt);
1817 }
1818
1819 DllExport int
1820 win32_write(int fd, const void *buf, unsigned int cnt)
1821 {
1822     return write(fd, buf, cnt);
1823 }
1824
1825 DllExport int
1826 win32_mkdir(const char *dir, int mode)
1827 {
1828     return mkdir(dir); /* just ignore mode */
1829 }
1830
1831 DllExport int
1832 win32_rmdir(const char *dir)
1833 {
1834     return rmdir(dir);
1835 }
1836
1837 DllExport int
1838 win32_chdir(const char *dir)
1839 {
1840     return chdir(dir);
1841 }
1842
1843 DllExport int
1844 win32_spawnvp(int mode, const char *cmdname, const char *const *argv)
1845 {
1846     int status;
1847
1848 #ifndef USE_RTL_WAIT
1849     if (mode == P_NOWAIT && w32_num_children >= MAXIMUM_WAIT_OBJECTS)
1850         return -1;
1851 #endif
1852
1853     status = spawnvp(mode, cmdname, (char * const *) argv);
1854 #ifndef USE_RTL_WAIT
1855     /* XXX For the P_NOWAIT case, Borland RTL returns pinfo.dwProcessId
1856      * while VC RTL returns pinfo.hProcess. For purposes of the custom
1857      * implementation of win32_wait(), we assume the latter.
1858      */
1859     if (mode == P_NOWAIT && status >= 0)
1860         w32_child_pids[w32_num_children++] = (HANDLE)status;
1861 #endif
1862     return status;
1863 }
1864
1865 DllExport int
1866 win32_execvp(const char *cmdname, const char *const *argv)
1867 {
1868     return execvp(cmdname, (char *const *)argv);
1869 }
1870
1871 DllExport void
1872 win32_perror(const char *str)
1873 {
1874     perror(str);
1875 }
1876
1877 DllExport void
1878 win32_setbuf(FILE *pf, char *buf)
1879 {
1880     setbuf(pf, buf);
1881 }
1882
1883 DllExport int
1884 win32_setvbuf(FILE *pf, char *buf, int type, size_t size)
1885 {
1886     return setvbuf(pf, buf, type, size);
1887 }
1888
1889 DllExport int
1890 win32_flushall(void)
1891 {
1892     return flushall();
1893 }
1894
1895 DllExport int
1896 win32_fcloseall(void)
1897 {
1898     return fcloseall();
1899 }
1900
1901 DllExport char*
1902 win32_fgets(char *s, int n, FILE *pf)
1903 {
1904     return fgets(s, n, pf);
1905 }
1906
1907 DllExport char*
1908 win32_gets(char *s)
1909 {
1910     return gets(s);
1911 }
1912
1913 DllExport int
1914 win32_fgetc(FILE *pf)
1915 {
1916     return fgetc(pf);
1917 }
1918
1919 DllExport int
1920 win32_putc(int c, FILE *pf)
1921 {
1922     return putc(c,pf);
1923 }
1924
1925 DllExport int
1926 win32_puts(const char *s)
1927 {
1928     return puts(s);
1929 }
1930
1931 DllExport int
1932 win32_getchar(void)
1933 {
1934     return getchar();
1935 }
1936
1937 DllExport int
1938 win32_putchar(int c)
1939 {
1940     return putchar(c);
1941 }
1942
1943 #ifdef MYMALLOC
1944
1945 #ifndef USE_PERL_SBRK
1946
1947 static char *committed = NULL;
1948 static char *base      = NULL;
1949 static char *reserved  = NULL;
1950 static char *brk       = NULL;
1951 static DWORD pagesize  = 0;
1952 static DWORD allocsize = 0;
1953
1954 void *
1955 sbrk(int need)
1956 {
1957  void *result;
1958  if (!pagesize)
1959   {SYSTEM_INFO info;
1960    GetSystemInfo(&info);
1961    /* Pretend page size is larger so we don't perpetually
1962     * call the OS to commit just one page ...
1963     */
1964    pagesize = info.dwPageSize << 3;
1965    allocsize = info.dwAllocationGranularity;
1966   }
1967  /* This scheme fails eventually if request for contiguous
1968   * block is denied so reserve big blocks - this is only 
1969   * address space not memory ...
1970   */
1971  if (brk+need >= reserved)
1972   {
1973    DWORD size = 64*1024*1024;
1974    char *addr;
1975    if (committed && reserved && committed < reserved)
1976     {
1977      /* Commit last of previous chunk cannot span allocations */
1978      addr = (char *) VirtualAlloc(committed,reserved-committed,MEM_COMMIT,PAGE_READWRITE);
1979      if (addr)
1980       committed = reserved;
1981     }
1982    /* Reserve some (more) space 
1983     * Note this is a little sneaky, 1st call passes NULL as reserved
1984     * so lets system choose where we start, subsequent calls pass
1985     * the old end address so ask for a contiguous block
1986     */
1987    addr  = (char *) VirtualAlloc(reserved,size,MEM_RESERVE,PAGE_NOACCESS);
1988    if (addr)
1989     {
1990      reserved = addr+size;
1991      if (!base)
1992       base = addr;
1993      if (!committed)
1994       committed = base;
1995      if (!brk)
1996       brk = committed;
1997     }
1998    else
1999     {
2000      return (void *) -1;
2001     }
2002   }
2003  result = brk;
2004  brk += need;
2005  if (brk > committed)
2006   {
2007    DWORD size = ((brk-committed + pagesize -1)/pagesize) * pagesize;
2008    char *addr = (char *) VirtualAlloc(committed,size,MEM_COMMIT,PAGE_READWRITE);
2009    if (addr)
2010     {
2011      committed += size;
2012     }
2013    else
2014     return (void *) -1;
2015   }
2016  return result;
2017 }
2018
2019 #endif
2020 #endif
2021
2022 DllExport void*
2023 win32_malloc(size_t size)
2024 {
2025     return malloc(size);
2026 }
2027
2028 DllExport void*
2029 win32_calloc(size_t numitems, size_t size)
2030 {
2031     return calloc(numitems,size);
2032 }
2033
2034 DllExport void*
2035 win32_realloc(void *block, size_t size)
2036 {
2037     return realloc(block,size);
2038 }
2039
2040 DllExport void
2041 win32_free(void *block)
2042 {
2043     free(block);
2044 }
2045
2046
2047 int
2048 win32_open_osfhandle(long handle, int flags)
2049 {
2050     return _open_osfhandle(handle, flags);
2051 }
2052
2053 long
2054 win32_get_osfhandle(int fd)
2055 {
2056     return _get_osfhandle(fd);
2057 }
2058
2059 /*
2060  * Extras.
2061  */
2062
2063 static
2064 XS(w32_GetCwd)
2065 {
2066     dXSARGS;
2067     SV *sv = sv_newmortal();
2068     /* Make one call with zero size - return value is required size */
2069     DWORD len = GetCurrentDirectory((DWORD)0,NULL);
2070     SvUPGRADE(sv,SVt_PV);
2071     SvGROW(sv,len);
2072     SvCUR(sv) = GetCurrentDirectory((DWORD) SvLEN(sv), SvPVX(sv));
2073     /* 
2074      * If result != 0 
2075      *   then it worked, set PV valid, 
2076      *   else leave it 'undef' 
2077      */
2078     if (SvCUR(sv))
2079         SvPOK_on(sv);
2080     EXTEND(SP,1);
2081     ST(0) = sv;
2082     XSRETURN(1);
2083 }
2084
2085 static
2086 XS(w32_SetCwd)
2087 {
2088     dXSARGS;
2089     if (items != 1)
2090         croak("usage: Win32::SetCurrentDirectory($cwd)");
2091     if (SetCurrentDirectory(SvPV(ST(0),na)))
2092         XSRETURN_YES;
2093
2094     XSRETURN_NO;
2095 }
2096
2097 static
2098 XS(w32_GetNextAvailDrive)
2099 {
2100     dXSARGS;
2101     char ix = 'C';
2102     char root[] = "_:\\";
2103     while (ix <= 'Z') {
2104         root[0] = ix++;
2105         if (GetDriveType(root) == 1) {
2106             root[2] = '\0';
2107             XSRETURN_PV(root);
2108         }
2109     }
2110     XSRETURN_UNDEF;
2111 }
2112
2113 static
2114 XS(w32_GetLastError)
2115 {
2116     dXSARGS;
2117     XSRETURN_IV(GetLastError());
2118 }
2119
2120 static
2121 XS(w32_LoginName)
2122 {
2123     dXSARGS;
2124     char *name = getlogin_buffer;
2125     DWORD size = sizeof(getlogin_buffer);
2126     if (GetUserName(name,&size)) {
2127         /* size includes NULL */
2128         ST(0) = sv_2mortal(newSVpv(name,size-1));
2129         XSRETURN(1);
2130     }
2131     XSRETURN_UNDEF;
2132 }
2133
2134 static
2135 XS(w32_NodeName)
2136 {
2137     dXSARGS;
2138     char name[MAX_COMPUTERNAME_LENGTH+1];
2139     DWORD size = sizeof(name);
2140     if (GetComputerName(name,&size)) {
2141         /* size does NOT include NULL :-( */
2142         ST(0) = sv_2mortal(newSVpv(name,size));
2143         XSRETURN(1);
2144     }
2145     XSRETURN_UNDEF;
2146 }
2147
2148
2149 static
2150 XS(w32_DomainName)
2151 {
2152     dXSARGS;
2153 #ifndef HAS_NETWKSTAGETINFO
2154     /* mingw32 (and Win95) don't have NetWksta*(), so do it the old way */
2155     char name[256];
2156     DWORD size = sizeof(name);
2157     if (GetUserName(name,&size)) {
2158         char sid[1024];
2159         DWORD sidlen = sizeof(sid);
2160         char dname[256];
2161         DWORD dnamelen = sizeof(dname);
2162         SID_NAME_USE snu;
2163         if (LookupAccountName(NULL, name, &sid, &sidlen,
2164                               dname, &dnamelen, &snu)) {
2165             XSRETURN_PV(dname);         /* all that for this */
2166         }
2167     }
2168 #else
2169     /* this way is more reliable, in case user has a local account.
2170      * XXX need dynamic binding of netapi32.dll symbols or this will fail on
2171      * Win95. Probably makes more sense to move it into libwin32. */
2172     char dname[256];
2173     DWORD dnamelen = sizeof(dname);
2174     PWKSTA_INFO_100 pwi;
2175     if (NERR_Success == NetWkstaGetInfo(NULL, 100, (LPBYTE*)&pwi)) {
2176         if (pwi->wki100_langroup && *(pwi->wki100_langroup)) {
2177             WideCharToMultiByte(CP_ACP, NULL, pwi->wki100_langroup,
2178                                 -1, (LPSTR)dname, dnamelen, NULL, NULL);
2179         }
2180         else {
2181             WideCharToMultiByte(CP_ACP, NULL, pwi->wki100_computername,
2182                                 -1, (LPSTR)dname, dnamelen, NULL, NULL);
2183         }
2184         NetApiBufferFree(pwi);
2185         XSRETURN_PV(dname);
2186     }
2187 #endif
2188     XSRETURN_UNDEF;
2189 }
2190
2191 static
2192 XS(w32_FsType)
2193 {
2194     dXSARGS;
2195     char fsname[256];
2196     DWORD flags, filecomplen;
2197     if (GetVolumeInformation(NULL, NULL, 0, NULL, &filecomplen,
2198                          &flags, fsname, sizeof(fsname))) {
2199         if (GIMME == G_ARRAY) {
2200             XPUSHs(sv_2mortal(newSVpv(fsname,0)));
2201             XPUSHs(sv_2mortal(newSViv(flags)));
2202             XPUSHs(sv_2mortal(newSViv(filecomplen)));
2203             PUTBACK;
2204             return;
2205         }
2206         XSRETURN_PV(fsname);
2207     }
2208     XSRETURN_UNDEF;
2209 }
2210
2211 static
2212 XS(w32_GetOSVersion)
2213 {
2214     dXSARGS;
2215     OSVERSIONINFO osver;
2216
2217     osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
2218     if (GetVersionEx(&osver)) {
2219         XPUSHs(newSVpv(osver.szCSDVersion, 0));
2220         XPUSHs(newSViv(osver.dwMajorVersion));
2221         XPUSHs(newSViv(osver.dwMinorVersion));
2222         XPUSHs(newSViv(osver.dwBuildNumber));
2223         XPUSHs(newSViv(osver.dwPlatformId));
2224         PUTBACK;
2225         return;
2226     }
2227     XSRETURN_UNDEF;
2228 }
2229
2230 static
2231 XS(w32_IsWinNT)
2232 {
2233     dXSARGS;
2234     XSRETURN_IV(IsWinNT());
2235 }
2236
2237 static
2238 XS(w32_IsWin95)
2239 {
2240     dXSARGS;
2241     XSRETURN_IV(IsWin95());
2242 }
2243
2244 static
2245 XS(w32_FormatMessage)
2246 {
2247     dXSARGS;
2248     DWORD source = 0;
2249     char msgbuf[1024];
2250
2251     if (items != 1)
2252         croak("usage: Win32::FormatMessage($errno)");
2253
2254     if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
2255                       &source, SvIV(ST(0)), 0,
2256                       msgbuf, sizeof(msgbuf)-1, NULL))
2257         XSRETURN_PV(msgbuf);
2258
2259     XSRETURN_UNDEF;
2260 }
2261
2262 static
2263 XS(w32_Spawn)
2264 {
2265     dXSARGS;
2266     char *cmd, *args;
2267     PROCESS_INFORMATION stProcInfo;
2268     STARTUPINFO stStartInfo;
2269     BOOL bSuccess = FALSE;
2270
2271     if (items != 3)
2272         croak("usage: Win32::Spawn($cmdName, $args, $PID)");
2273
2274     cmd = SvPV(ST(0),na);
2275     args = SvPV(ST(1), na);
2276
2277     memset(&stStartInfo, 0, sizeof(stStartInfo));   /* Clear the block */
2278     stStartInfo.cb = sizeof(stStartInfo);           /* Set the structure size */
2279     stStartInfo.dwFlags = STARTF_USESHOWWINDOW;     /* Enable wShowWindow control */
2280     stStartInfo.wShowWindow = SW_SHOWMINNOACTIVE;   /* Start min (normal) */
2281
2282     if (CreateProcess(
2283                 cmd,                    /* Image path */
2284                 args,                   /* Arguments for command line */
2285                 NULL,                   /* Default process security */
2286                 NULL,                   /* Default thread security */
2287                 FALSE,                  /* Must be TRUE to use std handles */
2288                 NORMAL_PRIORITY_CLASS,  /* No special scheduling */
2289                 NULL,                   /* Inherit our environment block */
2290                 NULL,                   /* Inherit our currrent directory */
2291                 &stStartInfo,           /* -> Startup info */
2292                 &stProcInfo))           /* <- Process info (if OK) */
2293     {
2294         CloseHandle(stProcInfo.hThread);/* library source code does this. */
2295         sv_setiv(ST(2), stProcInfo.dwProcessId);
2296         bSuccess = TRUE;
2297     }
2298     XSRETURN_IV(bSuccess);
2299 }
2300
2301 static
2302 XS(w32_GetTickCount)
2303 {
2304     dXSARGS;
2305     XSRETURN_IV(GetTickCount());
2306 }
2307
2308 static
2309 XS(w32_GetShortPathName)
2310 {
2311     dXSARGS;
2312     SV *shortpath;
2313     DWORD len;
2314
2315     if (items != 1)
2316         croak("usage: Win32::GetShortPathName($longPathName)");
2317
2318     shortpath = sv_mortalcopy(ST(0));
2319     SvUPGRADE(shortpath, SVt_PV);
2320     /* src == target is allowed */
2321     do {
2322         len = GetShortPathName(SvPVX(shortpath),
2323                                SvPVX(shortpath),
2324                                SvLEN(shortpath));
2325     } while (len >= SvLEN(shortpath) && sv_grow(shortpath,len+1));
2326     if (len) {
2327         SvCUR_set(shortpath,len);
2328         ST(0) = shortpath;
2329     }
2330     else
2331         ST(0) = &sv_undef;
2332     XSRETURN(1);
2333 }
2334
2335 static
2336 XS(w32_Sleep)
2337 {
2338     dXSARGS;
2339     if (items != 1)
2340         croak("usage: Win32::Sleep($milliseconds)");
2341     Sleep(SvIV(ST(0)));
2342     XSRETURN_YES;
2343 }
2344
2345 #define TMPBUFSZ 1024
2346 #define MAX_LENGTH 2048
2347 #define SUCCESSRETURNED(x)      (x == ERROR_SUCCESS)
2348 #define REGRETURN(x) XSRETURN_IV(SUCCESSRETURNED(x))
2349 #define SvHKEY(index) (HKEY)((unsigned long)SvIV(index))
2350 #define SETIV(index,value) sv_setiv(ST(index), value)
2351 #define SETNV(index,value) sv_setnv(ST(index), value)
2352 #define SETPV(index,string) sv_setpv(ST(index), string)
2353 #define SETPVN(index, buffer, length) sv_setpvn(ST(index), (char*)buffer, length)
2354 #define SETHKEY(index, hkey)    SETIV(index,(long)hkey)
2355
2356 static time_t ft2timet(FILETIME *ft)
2357 {
2358     SYSTEMTIME st;
2359     struct tm tm;
2360
2361     FileTimeToSystemTime(ft, &st);
2362     tm.tm_sec = st.wSecond;
2363     tm.tm_min = st.wMinute;
2364     tm.tm_hour = st.wHour;
2365     tm.tm_mday = st.wDay;
2366     tm.tm_mon = st.wMonth - 1;
2367     tm.tm_year = st.wYear - 1900;
2368     tm.tm_wday = st.wDayOfWeek;
2369     tm.tm_yday = -1;
2370     tm.tm_isdst = -1;
2371     return mktime (&tm);
2372 }
2373
2374 static
2375 XS(w32_RegCloseKey)
2376 {
2377     dXSARGS;
2378
2379     if (items != 1) 
2380     {
2381         croak("usage: Win32::RegCloseKey($hkey);\n");
2382     }
2383
2384     REGRETURN(RegCloseKey(SvHKEY(ST(0))));
2385 }
2386
2387 static
2388 XS(w32_RegConnectRegistry)
2389 {
2390     dXSARGS;
2391     HKEY handle;
2392
2393     if (items != 3) 
2394     {
2395         croak("usage: Win32::RegConnectRegistry($machine, $hkey, $handle);\n");
2396     }
2397
2398     if (SUCCESSRETURNED(RegConnectRegistry((char *)SvPV(ST(0), na), SvHKEY(ST(1)), &handle))) 
2399     {
2400         SETHKEY(2,handle);
2401         XSRETURN_YES;
2402     }
2403     XSRETURN_NO;
2404 }
2405
2406 static
2407 XS(w32_RegCreateKey)
2408 {
2409     dXSARGS;
2410     HKEY handle;
2411     DWORD disposition;
2412     long retval;
2413
2414     if (items != 3) 
2415     {
2416         croak("usage: Win32::RegCreateKey($hkey, $subkey, $handle);\n");
2417     }
2418
2419     retval =  RegCreateKeyEx(SvHKEY(ST(0)), (char *)SvPV(ST(1), na), 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
2420                                         NULL, &handle, &disposition);
2421
2422     if (SUCCESSRETURNED(retval)) 
2423     {
2424         SETHKEY(2,handle);
2425         XSRETURN_YES;
2426     }
2427     XSRETURN_NO;
2428 }
2429
2430 static
2431 XS(w32_RegCreateKeyEx)
2432 {
2433     dXSARGS;
2434
2435     unsigned int length;
2436     long retval;
2437     HKEY hkey, handle;
2438     char *subkey;
2439     char *keyclass;
2440     DWORD options, disposition;
2441     REGSAM sam;
2442     SECURITY_ATTRIBUTES sa, *psa;
2443
2444     if (items != 9) 
2445     {
2446         croak("usage: Win32::RegCreateKeyEx($hkey, $subkey, $reserved, $class, $options, $sam, "
2447                         "$security, $handle, $disposition);\n");
2448     }
2449
2450     hkey = SvHKEY(ST(0));
2451     subkey = (char *)SvPV(ST(1), na);
2452     keyclass = (char *)SvPV(ST(3), na);
2453     options = (DWORD) ((unsigned long)SvIV(ST(4)));
2454     sam = (REGSAM) ((unsigned long)SvIV(ST(5)));
2455     psa = (SECURITY_ATTRIBUTES*)SvPV(ST(6), length);
2456     if (length != sizeof(SECURITY_ATTRIBUTES))
2457     {
2458         psa = &sa;
2459         memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES));
2460         sa.nLength = sizeof(SECURITY_ATTRIBUTES);
2461     }
2462
2463     retval =  RegCreateKeyEx(hkey, subkey, 0, keyclass, options, sam,
2464                                         psa, &handle, &disposition);
2465
2466     if (SUCCESSRETURNED(retval)) 
2467     {
2468         if (psa == &sa)
2469             SETPVN(6, &sa, sizeof(sa));
2470
2471         SETHKEY(7,handle);
2472         SETIV(8,disposition);
2473         XSRETURN_YES;
2474     }
2475     XSRETURN_NO;
2476 }
2477
2478 static
2479 XS(w32_RegDeleteKey)
2480 {
2481     dXSARGS;
2482
2483     if (items != 2) 
2484     {
2485         croak("usage: Win32::RegDeleteKey($hkey, $subkey);\n");
2486     }
2487
2488     REGRETURN(RegDeleteKey(SvHKEY(ST(0)), (char *)SvPV(ST(1), na)));
2489 }
2490
2491 static
2492 XS(w32_RegDeleteValue)
2493 {
2494     dXSARGS;
2495
2496     if (items != 2) 
2497     {
2498         croak("usage: Win32::RegDeleteValue($hkey, $valname);\n");
2499     }
2500
2501     REGRETURN(RegDeleteValue(SvHKEY(ST(0)), (char *)SvPV(ST(1), na)));
2502 }
2503
2504 static
2505 XS(w32_RegEnumKey)
2506 {
2507     dXSARGS;
2508
2509     char keybuffer[TMPBUFSZ];
2510
2511     if (items != 3) 
2512     {
2513         croak("usage: Win32::RegEnumKey($hkey, $idx, $subkeyname);\n");
2514     }
2515
2516     if (SUCCESSRETURNED(RegEnumKey(SvHKEY(ST(0)), SvIV(ST(1)), keybuffer, sizeof(keybuffer)))) 
2517     {
2518         SETPV(2, keybuffer);
2519         XSRETURN_YES;
2520     }
2521     XSRETURN_NO;
2522 }
2523
2524 static
2525 XS(w32_RegEnumKeyEx)
2526 {
2527     dXSARGS;
2528     int length;
2529
2530     DWORD keysz, classsz;
2531     char keybuffer[TMPBUFSZ];
2532     char classbuffer[TMPBUFSZ];
2533     long retval;
2534     FILETIME filetime;
2535
2536     if (items != 6)                     
2537     {
2538         croak("usage: Win32::RegEnumKeyEx($hkey, $idx, $subkeyname, $reserved, $class, $time);\n");
2539     }
2540
2541     keysz = sizeof(keybuffer);
2542     classsz = sizeof(classbuffer);
2543     retval = RegEnumKeyEx(SvHKEY(ST(0)), SvIV(ST(1)), keybuffer, &keysz, 0,
2544                                                 classbuffer, &classsz, &filetime);
2545     if (SUCCESSRETURNED(retval)) 
2546     {
2547         SETPV(2, keybuffer);
2548         SETPV(4, classbuffer);
2549         SETIV(5, ft2timet(&filetime));
2550         XSRETURN_YES;
2551     }
2552     XSRETURN_NO;
2553 }
2554
2555 static
2556 XS(w32_RegEnumValue)
2557 {
2558     dXSARGS;
2559     HKEY hkey;
2560     DWORD type, namesz, valsz;
2561     long retval;
2562     static HKEY last_hkey;
2563     char  myvalbuf[MAX_LENGTH];
2564     char  mynambuf[MAX_LENGTH];
2565
2566     if (items != 6) 
2567     {
2568         croak("usage: Win32::RegEnumValue($hkey, $i, $name, $reserved, $type, $value);\n");
2569     }
2570
2571     hkey = SvHKEY(ST(0));
2572
2573     // If this is a new key, find out how big the maximum name and value sizes are and
2574     // allocate space for them. Free any old storage and set the old key value to the
2575     // current key.
2576
2577     if (hkey != (HKEY)last_hkey) 
2578     {
2579         char keyclass[TMPBUFSZ];
2580         DWORD classsz, subkeys, maxsubkey, maxclass, values, salen, maxnamesz, maxvalsz;
2581         FILETIME ft;
2582         classsz = sizeof(keyclass);
2583         retval = RegQueryInfoKey(hkey, keyclass, &classsz, 0, &subkeys, &maxsubkey, &maxclass,
2584                                                 &values, &maxnamesz, &maxvalsz, &salen, &ft);
2585
2586         if (!SUCCESSRETURNED(retval)) 
2587         {
2588             XSRETURN_NO;
2589         }
2590         memset(myvalbuf, 0, MAX_LENGTH);
2591         memset(mynambuf, 0, MAX_LENGTH);
2592         last_hkey = hkey;
2593     }
2594
2595     namesz = MAX_LENGTH;
2596     valsz = MAX_LENGTH;
2597     retval = RegEnumValue(hkey, SvIV(ST(1)), mynambuf, &namesz, 0, &type, (LPBYTE) myvalbuf, &valsz);
2598     if (!SUCCESSRETURNED(retval)) 
2599     {
2600         XSRETURN_NO;
2601     }
2602     else 
2603     {
2604         SETPV(2, mynambuf);
2605         SETIV(4, type);
2606
2607         // return includes the null terminator so delete it if REG_SZ, REG_MULTI_SZ or REG_EXPAND_SZ
2608         switch(type)
2609         {
2610             case REG_SZ:
2611             case REG_MULTI_SZ:
2612             case REG_EXPAND_SZ:
2613                 if (valsz)
2614                     --valsz;
2615             case REG_BINARY:
2616                 SETPVN(5, myvalbuf, valsz);
2617                 break;
2618
2619             case REG_DWORD_BIG_ENDIAN:
2620                 {
2621                     BYTE tmp = myvalbuf[0];
2622                     myvalbuf[0] = myvalbuf[3];
2623                     myvalbuf[3] = tmp;
2624                     tmp = myvalbuf[1];
2625                     myvalbuf[1] = myvalbuf[2];
2626                     myvalbuf[2] = tmp;
2627                 }
2628             case REG_DWORD_LITTLE_ENDIAN:       // same as REG_DWORD
2629                 SETNV(5, (double)*((DWORD*)myvalbuf));
2630                 break;
2631
2632             default:
2633                 break;
2634         }
2635
2636         XSRETURN_YES;
2637     }
2638 }
2639
2640 static
2641 XS(w32_RegFlushKey)
2642 {
2643     dXSARGS;
2644
2645     if (items != 1) 
2646     {
2647         croak("usage: Win32::RegFlushKey($hkey);\n");
2648     }
2649
2650     REGRETURN(RegFlushKey(SvHKEY(ST(0))));
2651 }
2652
2653 static
2654 XS(w32_RegGetKeySecurity)
2655 {
2656     dXSARGS;
2657     SECURITY_DESCRIPTOR sd;
2658     DWORD sdsz;
2659
2660     if (items != 3) 
2661     {
2662         croak("usage: Win32::RegGetKeySecurity($hkey, $security_info, $security_descriptor);\n");
2663     }
2664
2665     if (SUCCESSRETURNED(RegGetKeySecurity(SvHKEY(ST(0)), SvIV(ST(1)), &sd, &sdsz))) 
2666     {
2667         SETPVN(2, &sd, sdsz);
2668         XSRETURN_YES;
2669     }
2670     XSRETURN_NO;
2671 }
2672
2673 static
2674 XS(w32_RegLoadKey)
2675 {
2676     dXSARGS;
2677
2678     if (items != 3) 
2679     {
2680         croak("usage: Win32::RegLoadKey($hkey, $subkey, $filename);\n");
2681     }
2682
2683     REGRETURN(RegLoadKey(SvHKEY(ST(0)), (char *)SvPV(ST(1), na), (char *)SvPV(ST(2), na)));
2684 }
2685
2686 static
2687 XS(w32_RegNotifyChangeKeyValue)
2688 {
2689     croak("Win32::RegNotifyChangeKeyValue not yet implemented!\n");
2690 }
2691
2692 static
2693 XS(w32_RegOpenKey)
2694 {
2695     dXSARGS;
2696     HKEY handle;
2697
2698     if (items != 3) 
2699     {
2700         croak("usage: Win32::RegOpenKey($hkey, $subkey, $handle);\n");
2701     }
2702
2703     if (SUCCESSRETURNED(RegOpenKey(SvHKEY(ST(0)), (char *)SvPV(ST(1), na), &handle))) 
2704     {
2705         SETHKEY(2,handle);
2706         XSRETURN_YES;
2707     }
2708     XSRETURN_NO;
2709 }
2710
2711 static
2712 XS(w32_RegOpenKeyEx)
2713 {
2714     dXSARGS;
2715     HKEY handle;
2716
2717     if (items != 5) 
2718     {
2719         croak("usage: Win32::RegOpenKeyEx($hkey, $subkey, $reserved, $sam, $handle);\n");
2720     }
2721
2722     if (SUCCESSRETURNED(RegOpenKeyEx(SvHKEY(ST(0)), (char *)SvPV(ST(1), na), 
2723                                 0, (REGSAM) ((unsigned long)SvIV(ST(3))), &handle))) 
2724     {
2725         SETHKEY(4,handle);
2726         XSRETURN_YES;
2727     }
2728     XSRETURN_NO;
2729 }
2730
2731 #pragma optimize("", off)
2732 static
2733 XS(w32_RegQueryInfoKey)
2734 {
2735     dXSARGS;
2736     int length;
2737
2738     char keyclass[TMPBUFSZ];
2739     DWORD subkeys, maxsubkey, maxclass, values, maxvalname, maxvaldata;
2740     DWORD seclen, classsz;
2741     FILETIME ft;
2742     long retval;
2743
2744     if (items != 10) 
2745     {
2746         croak("usage: Win32::RegQueryInfoKey($hkey, $class, $numsubkeys, $maxsubkey,"
2747                 "$maxclass, $values, $maxvalname, $maxvaldata, $secdesclen,"
2748                         "$lastwritetime);\n");
2749     }
2750
2751     classsz = sizeof(keyclass);
2752     retval = RegQueryInfoKey(SvHKEY(ST(0)), keyclass, &classsz, 0, &subkeys, &maxsubkey,
2753                                 &maxclass, &values, &maxvalname, &maxvaldata,
2754                                         &seclen, &ft);
2755     if (SUCCESSRETURNED(retval)) 
2756     {
2757         SETPV(1, keyclass);
2758         SETIV(2, subkeys);
2759         SETIV(3, maxsubkey);
2760         SETIV(4, maxclass);
2761         SETIV(5, values);
2762         SETIV(6, maxvalname);
2763         SETIV(7, maxvaldata);
2764         SETIV(8, seclen);
2765         SETIV(9, ft2timet(&ft));
2766         XSRETURN_YES;
2767     }
2768     XSRETURN_NO;
2769 }
2770 #pragma optimize("", on)
2771
2772 static
2773 XS(w32_RegQueryValue)
2774 {
2775     dXSARGS;
2776
2777     unsigned char databuffer[TMPBUFSZ*2];
2778     long datasz = sizeof(databuffer);
2779
2780     if (items != 3) 
2781     {
2782         croak("usage: Win32::RegQueryValue($hkey, $valuename, $data);\n");
2783     }
2784
2785     if (SUCCESSRETURNED(RegQueryValue(SvHKEY(ST(0)), SvPV(ST(1), na), (char*)databuffer, &datasz))) 
2786     {
2787         // return includes the null terminator so delete it
2788         SETPVN(2, databuffer, --datasz);
2789         XSRETURN_YES;
2790     }
2791     XSRETURN_NO;
2792 }
2793
2794 static
2795 XS(w32_RegQueryValueEx)
2796 {
2797     dXSARGS;
2798
2799     unsigned char databuffer[TMPBUFSZ*2];
2800     DWORD datasz = sizeof(databuffer);
2801     DWORD type;
2802     LONG result;
2803     LPBYTE ptr = databuffer;
2804
2805     if (items != 5) 
2806     {
2807         croak("usage: Win32::RegQueryValueEx($hkey, $valuename, $reserved, $type, $data);\n");
2808     }
2809
2810     result = RegQueryValueEx(SvHKEY(ST(0)), SvPV(ST(1), na), 0, &type, ptr, &datasz);
2811     if (result == ERROR_MORE_DATA)
2812     {
2813         New(0, ptr, datasz+1, BYTE);
2814         result = RegQueryValueEx(SvHKEY(ST(0)), SvPV(ST(1), na), 0, &type, ptr, &datasz);
2815     }
2816     if (SUCCESSRETURNED(result)) 
2817     {
2818         SETIV(3, type);
2819
2820         // return includes the null terminator so delete it if REG_SZ, REG_MULTI_SZ or REG_EXPAND_SZ
2821         switch(type)
2822         {
2823             case REG_SZ:
2824             case REG_MULTI_SZ:
2825             case REG_EXPAND_SZ:
2826                 --datasz;
2827             case REG_BINARY:
2828                 SETPVN(4, ptr, datasz);
2829                 break;
2830
2831             case REG_DWORD_BIG_ENDIAN:
2832                 {
2833                     BYTE tmp = ptr[0];
2834                     ptr[0] = ptr[3];
2835                     ptr[3] = tmp;
2836                     tmp = ptr[1];
2837                     ptr[1] = ptr[2];
2838                     ptr[2] = tmp;
2839                 }
2840             case REG_DWORD_LITTLE_ENDIAN:       // same as REG_DWORD
2841                 SETNV(4, (double)*((DWORD*)ptr));
2842                 break;
2843
2844             default:
2845                 break;
2846         }
2847
2848         if (ptr != databuffer)
2849             safefree(ptr);
2850
2851         XSRETURN_YES;
2852     }
2853     if (ptr != databuffer)
2854         safefree(ptr);
2855
2856     XSRETURN_NO;
2857 }
2858
2859 static
2860 XS(w32_RegReplaceKey)
2861 {
2862     dXSARGS;
2863
2864     if (items != 4) 
2865     {
2866         croak("usage: Win32::RegReplaceKey($hkey, $subkey, $newfile, $oldfile);\n");
2867     }
2868
2869     REGRETURN(RegReplaceKey(SvHKEY(ST(0)), (char *)SvPV(ST(1), na), (char *)SvPV(ST(2), na), (char *)SvPV(ST(3), na)));
2870 }
2871
2872 static
2873 XS(w32_RegRestoreKey)
2874 {
2875     dXSARGS;
2876
2877     if (items < 2 || items > 3) 
2878     {
2879         croak("usage: Win32::RegRestoreKey($hkey, $filename [, $flags]);\n");
2880     }
2881
2882     REGRETURN(RegRestoreKey(SvHKEY(ST(0)), (char*)SvPV(ST(1), na), (DWORD)((items == 3) ? SvIV(ST(2)) : 0)));
2883 }
2884
2885 static
2886 XS(w32_RegSaveKey)
2887 {
2888     dXSARGS;
2889
2890     if (items != 2) 
2891     {
2892         croak("usage: Win32::RegSaveKey($hkey, $filename);\n");
2893     }
2894
2895     REGRETURN(RegSaveKey(SvHKEY(ST(0)), (char *)SvPV(ST(1), na), NULL));
2896 }
2897
2898 static
2899 XS(w32_RegSetKeySecurity)
2900 {
2901     dXSARGS;
2902
2903     if (items != 3) 
2904     {
2905         croak("usage: Win32::RegSetKeySecurity($hkey, $security_info, $security_descriptor);\n");
2906     }
2907
2908     REGRETURN(RegSetKeySecurity(SvHKEY(ST(0)), SvIV(ST(1)), (SECURITY_DESCRIPTOR*)SvPV(ST(2), na)));
2909 }
2910
2911 static
2912 XS(w32_RegSetValue)
2913 {
2914     dXSARGS;
2915
2916     unsigned int size;
2917     char *buffer;
2918         DWORD type;
2919
2920     if (items != 4) 
2921     {
2922         croak("usage: Win32::RegSetValue($hkey, $subKey, $type, $data);\n");
2923     }
2924
2925     type = SvIV(ST(2));
2926     if (type != REG_SZ && type != REG_EXPAND_SZ)
2927     {
2928         croak("Win32::RegSetValue: Type was not REG_SZ or REG_EXPAND_SZ, cannot set %s\n", (char *)SvPV(ST(1), na));
2929     }
2930
2931     buffer = (char *)SvPV(ST(3), size);
2932     REGRETURN(RegSetValue(SvHKEY(ST(0)), SvPV(ST(1), na), REG_SZ, buffer, size));
2933 }
2934
2935 static
2936 XS(w32_RegSetValueEx)
2937 {
2938     dXSARGS;
2939
2940     DWORD type;
2941     DWORD val;
2942     unsigned int size;
2943     char *buffer;
2944
2945     if (items != 5) 
2946     {
2947         croak("usage: Win32::RegSetValueEx($hkey, $valname, $reserved, $type, $data);\n");
2948     }
2949
2950     type = (DWORD)SvIV(ST(3));
2951     switch(type) 
2952     {
2953         case REG_SZ:
2954         case REG_BINARY:
2955         case REG_MULTI_SZ:
2956         case REG_EXPAND_SZ:
2957             buffer = (char *)SvPV(ST(4), size);
2958             if (type != REG_BINARY)
2959                 size++; // include null terminator in size
2960
2961             REGRETURN(RegSetValueEx(SvHKEY(ST(0)), (char *)SvPV(ST(1), na), 0, type, (PBYTE) buffer, size));
2962             break;
2963
2964         case REG_DWORD_BIG_ENDIAN:
2965         case REG_DWORD_LITTLE_ENDIAN: // Same as REG_DWORD
2966             val = (DWORD)SvIV(ST(4));
2967             REGRETURN(RegSetValueEx(SvHKEY(ST(0)), (char *)SvPV(ST(1), na), 0, type, (PBYTE) &val, sizeof(DWORD)));
2968             break;
2969
2970         default:
2971             croak("Win32::RegSetValueEx: Type not specified, cannot set %s\n", (char *)SvPV(ST(1), na));
2972     }
2973 }
2974
2975 static
2976 XS(w32_RegUnloadKey)
2977 {
2978     dXSARGS;
2979
2980     if (items != 2) 
2981     {
2982         croak("usage: Win32::RegUnLoadKey($hkey, $subkey);\n");
2983     }
2984
2985     REGRETURN(RegUnLoadKey(SvHKEY(ST(0)), (char *)SvPV(ST(1), na)));
2986 }
2987
2988 static
2989 XS(w32_RegisterServer)
2990 {
2991     dXSARGS;
2992     BOOL bSuccess = FALSE;
2993     HINSTANCE hInstance;
2994     unsigned int length;
2995     FARPROC sFunc;
2996
2997     if (items != 1) 
2998     {
2999         croak("usage: Win32::RegisterServer($LibraryName)\n");
3000     }
3001
3002     hInstance = LoadLibrary((char *)SvPV(ST(0), length));
3003     if (hInstance != NULL)
3004     {
3005         sFunc = GetProcAddress(hInstance, "DllRegisterServer");
3006         if (sFunc != NULL)
3007         {
3008             bSuccess = (sFunc() == 0);
3009         }
3010         FreeLibrary(hInstance);
3011     }
3012
3013     if (bSuccess)
3014     {
3015         XSRETURN_YES;
3016     }
3017     XSRETURN_NO;
3018 }
3019
3020 static
3021 XS(w32_UnregisterServer)
3022 {
3023     dXSARGS;
3024     BOOL bSuccess = FALSE;
3025     HINSTANCE hInstance;
3026     unsigned int length;
3027     FARPROC sFunc;
3028
3029     if (items != 1) 
3030     {
3031         croak("usage: Win32::UnregisterServer($LibraryName)\n");
3032     }
3033
3034     hInstance = LoadLibrary((char *)SvPV(ST(0), length));
3035     if (hInstance != NULL)
3036     {
3037         sFunc = GetProcAddress(hInstance, "DllUnregisterServer");
3038         if (sFunc != NULL)
3039         {
3040             bSuccess = (sFunc() == 0);
3041         }
3042         FreeLibrary(hInstance);
3043     }
3044
3045     if (bSuccess)
3046     {
3047         XSRETURN_YES;
3048     }
3049     XSRETURN_NO;
3050 }
3051
3052
3053 void
3054 Perl_init_os_extras()
3055 {
3056     char *file = __FILE__;
3057     dXSUB_SYS;
3058
3059     w32_perlshell_tokens = Nullch;
3060     w32_perlshell_items = -1;
3061     w32_fdpid = newAV();                /* XXX needs to be in Perl_win32_init()? */
3062 #ifndef USE_RTL_WAIT
3063     w32_num_children = 0;
3064 #endif
3065
3066     /* these names are Activeware compatible */
3067     newXS("Win32::GetCwd", w32_GetCwd, file);
3068     newXS("Win32::SetCwd", w32_SetCwd, file);
3069     newXS("Win32::GetNextAvailDrive", w32_GetNextAvailDrive, file);
3070     newXS("Win32::GetLastError", w32_GetLastError, file);
3071     newXS("Win32::LoginName", w32_LoginName, file);
3072     newXS("Win32::NodeName", w32_NodeName, file);
3073     newXS("Win32::DomainName", w32_DomainName, file);
3074     newXS("Win32::FsType", w32_FsType, file);
3075     newXS("Win32::GetOSVersion", w32_GetOSVersion, file);
3076     newXS("Win32::IsWinNT", w32_IsWinNT, file);
3077     newXS("Win32::IsWin95", w32_IsWin95, file);
3078     newXS("Win32::FormatMessage", w32_FormatMessage, file);
3079     newXS("Win32::Spawn", w32_Spawn, file);
3080     newXS("Win32::GetTickCount", w32_GetTickCount, file);
3081     newXS("Win32::GetShortPathName", w32_GetShortPathName, file);
3082     newXS("Win32::Sleep", w32_Sleep, file);
3083
3084     /* the following extensions are used interally and may be changed at any time */
3085     /* therefore no documentation is provided */
3086     newXS("Win32::RegCloseKey", w32_RegCloseKey, file);
3087     newXS("Win32::RegConnectRegistry", w32_RegConnectRegistry, file);
3088     newXS("Win32::RegCreateKey", w32_RegCreateKey, file);
3089     newXS("Win32::RegCreateKeyEx", w32_RegCreateKeyEx, file);
3090     newXS("Win32::RegDeleteKey", w32_RegDeleteKey, file);
3091     newXS("Win32::RegDeleteValue", w32_RegDeleteValue, file);
3092
3093     newXS("Win32::RegEnumKey", w32_RegEnumKey, file);
3094     newXS("Win32::RegEnumKeyEx", w32_RegEnumKeyEx, file);
3095     newXS("Win32::RegEnumValue", w32_RegEnumValue, file);
3096
3097     newXS("Win32::RegFlushKey", w32_RegFlushKey, file);
3098     newXS("Win32::RegGetKeySecurity", w32_RegGetKeySecurity, file);
3099
3100     newXS("Win32::RegLoadKey", w32_RegLoadKey, file);
3101     newXS("Win32::RegOpenKey", w32_RegOpenKey, file);
3102     newXS("Win32::RegOpenKeyEx", w32_RegOpenKeyEx, file);
3103     newXS("Win32::RegQueryInfoKey", w32_RegQueryInfoKey, file);
3104     newXS("Win32::RegQueryValue", w32_RegQueryValue, file);
3105     newXS("Win32::RegQueryValueEx", w32_RegQueryValueEx, file);
3106
3107     newXS("Win32::RegReplaceKey", w32_RegReplaceKey, file);
3108     newXS("Win32::RegRestoreKey", w32_RegRestoreKey, file);
3109     newXS("Win32::RegSaveKey", w32_RegSaveKey, file);
3110     newXS("Win32::RegSetKeySecurity", w32_RegSetKeySecurity, file);
3111     newXS("Win32::RegSetValue", w32_RegSetValue, file);
3112     newXS("Win32::RegSetValueEx", w32_RegSetValueEx, file);
3113     newXS("Win32::RegUnloadKey", w32_RegUnloadKey, file);
3114
3115     newXS("Win32::RegisterServer", w32_RegisterServer, file);
3116     newXS("Win32::UnregisterServer", w32_UnregisterServer, file);
3117
3118     /* XXX Bloat Alert! The following Activeware preloads really
3119      * ought to be part of Win32::Sys::*, so they're not included
3120      * here.
3121      */
3122     /* LookupAccountName
3123      * LookupAccountSID
3124      * InitiateSystemShutdown
3125      * AbortSystemShutdown
3126      * ExpandEnvrironmentStrings
3127      */
3128 }
3129
3130 void
3131 Perl_win32_init(int *argcp, char ***argvp)
3132 {
3133     /* Disable floating point errors, Perl will trap the ones we
3134      * care about.  VC++ RTL defaults to switching these off
3135      * already, but the Borland RTL doesn't.  Since we don't
3136      * want to be at the vendor's whim on the default, we set
3137      * it explicitly here.
3138      */
3139 #if !defined(_ALPHA_) && !defined(__GNUC__)
3140     _control87(MCW_EM, MCW_EM);
3141 #endif
3142     MALLOC_INIT;
3143 }
3144
3145 #ifdef USE_BINMODE_SCRIPTS
3146
3147 void
3148 win32_strip_return(SV *sv)
3149 {
3150  char *s = SvPVX(sv);
3151  char *e = s+SvCUR(sv);
3152  char *d = s;
3153  while (s < e)
3154   {
3155    if (*s == '\r' && s[1] == '\n')
3156     {
3157      *d++ = '\n';
3158      s += 2;
3159     }
3160    else 
3161     {
3162      *d++ = *s++;
3163     }   
3164   }
3165  SvCUR_set(sv,d-SvPVX(sv)); 
3166 }
3167
3168 #endif