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