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