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