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