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