Integrate win32 branch into mainline
[p5sagit/p5-mst-13.2.git] / win32 / win32.c
CommitLineData
68dc0745 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 */
0a753a76 10
11#define WIN32_LEAN_AND_MEAN
12#define WIN32IO_IS_STDIO
13#include <tchar.h>
a835ef8a 14#ifdef __GNUC__
15#define Win32_Winsock
16#endif
0a753a76 17#include <windows.h>
18
e56670dd 19#ifndef __MINGW32__
9404a519 20#include <lmcons.h>
21#include <lmerr.h>
22/* ugliness to work around a buggy struct definition in lmwksta.h */
23#undef LPTSTR
24#define LPTSTR LPWSTR
25#include <lmwksta.h>
26#undef LPTSTR
27#define LPTSTR LPSTR
e56670dd 28#include <lmapibuf.h>
29#endif /* __MINGW32__ */
9404a519 30
68dc0745 31/* #include "config.h" */
0a753a76 32
33#define PERLIO_NOT_STDIO 0
34#if !defined(PERLIO_IS_STDIO) && !defined(USE_SFIO)
35#define PerlIO FILE
36#endif
37
38#include "EXTERN.h"
39#include "perl.h"
ad2e33dc 40#include "XSUB.h"
0a753a76 41#include <fcntl.h>
42#include <sys/stat.h>
5b0d9cbe 43#ifndef __GNUC__
44/* assert.h conflicts with #define of assert in perl.h */
0a753a76 45#include <assert.h>
5b0d9cbe 46#endif
0a753a76 47#include <string.h>
48#include <stdarg.h>
ad2e33dc 49#include <float.h>
ad0751ec 50#include <time.h>
3730b96e 51#if defined(_MSC_VER) || defined(__MINGW32__)
ad0751ec 52#include <sys/utime.h>
53#else
54#include <utime.h>
55#endif
0a753a76 56
5b0d9cbe 57#ifdef __GNUC__
58/* Mingw32 defaults to globing command line
59 * So we turn it off like this:
60 */
61int _CRT_glob = 0;
62#endif
63
6890e559 64#define EXECF_EXEC 1
65#define EXECF_SPAWN 2
66#define EXECF_SPAWN_NOWAIT 3
67
2d7a9237 68static DWORD os_id(void);
ce1da67e 69static void get_shell(void);
70static long tokenize(char *str, char **dest, char ***destv);
2d7a9237 71static int do_spawn2(char *cmd, int exectype);
72static BOOL has_redirection(char *ptr);
73static long filetime_to_clock(PFILETIME ft);
ad0751ec 74static BOOL filetime_from_time(PFILETIME ft, time_t t);
2d7a9237 75
2d7a9237 76HANDLE w32_perldll_handle = INVALID_HANDLE_VALUE;
4b556e6c 77static DWORD w32_platform = (DWORD)-1;
0a753a76 78
26618a56 79#ifdef USE_THREADS
80# ifdef USE_DECLSPEC_THREAD
81__declspec(thread) char strerror_buffer[512];
e34ffe5a 82__declspec(thread) char getlogin_buffer[128];
4b556e6c 83__declspec(thread) char w32_perllib_root[MAX_PATH+1];
26618a56 84# ifdef HAVE_DES_FCRYPT
85__declspec(thread) char crypt_buffer[30];
86# endif
87# else
88# define strerror_buffer (thr->i.Wstrerror_buffer)
e34ffe5a 89# define getlogin_buffer (thr->i.Wgetlogin_buffer)
4b556e6c 90# define w32_perllib_root (thr->i.Ww32_perllib_root)
26618a56 91# define crypt_buffer (thr->i.Wcrypt_buffer)
92# endif
93#else
4b556e6c 94static char strerror_buffer[512];
95static char getlogin_buffer[128];
96static char w32_perllib_root[MAX_PATH+1];
26618a56 97# ifdef HAVE_DES_FCRYPT
4b556e6c 98static char crypt_buffer[30];
26618a56 99# endif
100#endif
101
3fe9a6f1 102int
103IsWin95(void) {
2d7a9237 104 return (os_id() == VER_PLATFORM_WIN32_WINDOWS);
3fe9a6f1 105}
106
107int
108IsWinNT(void) {
2d7a9237 109 return (os_id() == VER_PLATFORM_WIN32_NT);
3fe9a6f1 110}
0a753a76 111
68dc0745 112char *
2d7a9237 113win32_perllib_path(char *sfx,...)
68dc0745 114{
4b556e6c 115 dTHR;
acbc2db6 116 va_list ap;
68dc0745 117 char *end;
4b556e6c 118
acbc2db6 119 va_start(ap,sfx);
2d7a9237 120 GetModuleFileName((w32_perldll_handle == INVALID_HANDLE_VALUE)
68dc0745 121 ? GetModuleHandle(NULL)
2d7a9237 122 : w32_perldll_handle,
123 w32_perllib_root,
124 sizeof(w32_perllib_root));
125 *(end = strrchr(w32_perllib_root, '\\')) = '\0';
68dc0745 126 if (stricmp(end-4,"\\bin") == 0)
127 end -= 4;
128 strcpy(end,"\\lib");
acbc2db6 129 while (sfx)
130 {
131 strcat(end,"\\");
132 strcat(end,sfx);
133 sfx = va_arg(ap,char *);
134 }
135 va_end(ap);
2d7a9237 136 return (w32_perllib_root);
68dc0745 137}
0a753a76 138
b4793f7f 139
2d7a9237 140static BOOL
141has_redirection(char *ptr)
68dc0745 142{
143 int inquote = 0;
144 char quote = '\0';
145
146 /*
147 * Scan string looking for redirection (< or >) or pipe
148 * characters (|) that are not in a quoted string
149 */
9404a519 150 while (*ptr) {
68dc0745 151 switch(*ptr) {
152 case '\'':
153 case '\"':
9404a519 154 if (inquote) {
155 if (quote == *ptr) {
68dc0745 156 inquote = 0;
157 quote = '\0';
0a753a76 158 }
68dc0745 159 }
160 else {
161 quote = *ptr;
162 inquote++;
163 }
164 break;
165 case '>':
166 case '<':
167 case '|':
9404a519 168 if (!inquote)
68dc0745 169 return TRUE;
170 default:
171 break;
0a753a76 172 }
68dc0745 173 ++ptr;
174 }
175 return FALSE;
0a753a76 176}
177
68dc0745 178/* since the current process environment is being updated in util.c
179 * the library functions will get the correct environment
180 */
181PerlIO *
182my_popen(char *cmd, char *mode)
0a753a76 183{
184#ifdef FIXCMD
68dc0745 185#define fixcmd(x) { \
186 char *pspace = strchr((x),' '); \
187 if (pspace) { \
188 char *p = (x); \
189 while (p < pspace) { \
190 if (*p == '/') \
191 *p = '\\'; \
192 p++; \
193 } \
194 } \
195 }
0a753a76 196#else
197#define fixcmd(x)
198#endif
68dc0745 199 fixcmd(cmd);
3e3baf6d 200 win32_fflush(stdout);
201 win32_fflush(stderr);
0a753a76 202 return win32_popen(cmd, mode);
0a753a76 203}
204
68dc0745 205long
206my_pclose(PerlIO *fp)
0a753a76 207{
208 return win32_pclose(fp);
209}
210
8b10511d 211static DWORD
2d7a9237 212os_id(void)
0a753a76 213{
8b10511d 214 static OSVERSIONINFO osver;
0a753a76 215
2d7a9237 216 if (osver.dwPlatformId != w32_platform) {
8b10511d 217 memset(&osver, 0, sizeof(OSVERSIONINFO));
218 osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
219 GetVersionEx(&osver);
2d7a9237 220 w32_platform = osver.dwPlatformId;
8b10511d 221 }
2d7a9237 222 return (w32_platform);
0a753a76 223}
224
ce1da67e 225/* Tokenize a string. Words are null-separated, and the list
226 * ends with a doubled null. Any character (except null and
227 * including backslash) may be escaped by preceding it with a
228 * backslash (the backslash will be stripped).
229 * Returns number of words in result buffer.
230 */
231static long
232tokenize(char *str, char **dest, char ***destv)
233{
234 char *retstart = Nullch;
235 char **retvstart = 0;
236 int items = -1;
237 if (str) {
238 int slen = strlen(str);
239 register char *ret;
240 register char **retv;
241 New(1307, ret, slen+2, char);
242 New(1308, retv, (slen+3)/2, char*);
243
244 retstart = ret;
245 retvstart = retv;
246 *retv = ret;
247 items = 0;
248 while (*str) {
249 *ret = *str++;
250 if (*ret == '\\' && *str)
251 *ret = *str++;
252 else if (*ret == ' ') {
253 while (*str == ' ')
254 str++;
255 if (ret == retstart)
256 ret--;
257 else {
258 *ret = '\0';
259 ++items;
260 if (*str)
261 *++retv = ret+1;
262 }
263 }
264 else if (!*str)
265 ++items;
266 ret++;
267 }
268 retvstart[items] = Nullch;
269 *ret++ = '\0';
270 *ret = '\0';
271 }
272 *dest = retstart;
273 *destv = retvstart;
274 return items;
275}
276
277static void
2d7a9237 278get_shell(void)
0a753a76 279{
ce1da67e 280 if (!w32_perlshell_tokens) {
174c211a 281 /* we don't use COMSPEC here for two reasons:
282 * 1. the same reason perl on UNIX doesn't use SHELL--rampant and
283 * uncontrolled unportability of the ensuing scripts.
284 * 2. PERL5SHELL could be set to a shell that may not be fit for
285 * interactive use (which is what most programs look in COMSPEC
286 * for).
287 */
ce1da67e 288 char* defaultshell = (IsWinNT() ? "cmd.exe /x/c" : "command.com /c");
289 char *usershell = getenv("PERL5SHELL");
290 w32_perlshell_items = tokenize(usershell ? usershell : defaultshell,
291 &w32_perlshell_tokens,
292 &w32_perlshell_vec);
68dc0745 293 }
0a753a76 294}
295
68dc0745 296int
2d7a9237 297do_aspawn(void *vreally, void **vmark, void **vsp)
0a753a76 298{
2d7a9237 299 SV *really = (SV*)vreally;
300 SV **mark = (SV**)vmark;
301 SV **sp = (SV**)vsp;
68dc0745 302 char **argv;
2d7a9237 303 char *str;
68dc0745 304 int status;
2d7a9237 305 int flag = P_WAIT;
68dc0745 306 int index = 0;
68dc0745 307
2d7a9237 308 if (sp <= mark)
309 return -1;
68dc0745 310
ce1da67e 311 get_shell();
312 New(1306, argv, (sp - mark) + w32_perlshell_items + 2, char*);
2d7a9237 313
314 if (SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) {
315 ++mark;
316 flag = SvIVx(*mark);
68dc0745 317 }
318
9404a519 319 while (++mark <= sp) {
2d7a9237 320 if (*mark && (str = SvPV(*mark, na)))
321 argv[index++] = str;
322 else
323 argv[index++] = "";
68dc0745 324 }
325 argv[index++] = 0;
326
2d7a9237 327 status = win32_spawnvp(flag,
328 (really ? SvPV(really,na) : argv[0]),
329 (const char* const*)argv);
330
331 if (status < 0 && errno == ENOEXEC) {
332 /* possible shell-builtin, invoke with shell */
ce1da67e 333 int sh_items;
334 sh_items = w32_perlshell_items;
2d7a9237 335 while (--index >= 0)
336 argv[index+sh_items] = argv[index];
ce1da67e 337 while (--sh_items >= 0)
338 argv[sh_items] = w32_perlshell_vec[sh_items];
2d7a9237 339
340 status = win32_spawnvp(flag,
341 (really ? SvPV(really,na) : argv[0]),
342 (const char* const*)argv);
343 }
68dc0745 344
50892819 345 if (flag != P_NOWAIT) {
346 if (status < 0) {
347 if (dowarn)
348 warn("Can't spawn \"%s\": %s", argv[0], strerror(errno));
349 status = 255 * 256;
350 }
351 else
352 status *= 256;
353 statusvalue = status;
5aabfad6 354 }
ce1da67e 355 Safefree(argv);
50892819 356 return (status);
68dc0745 357}
358
2d7a9237 359static int
6890e559 360do_spawn2(char *cmd, int exectype)
68dc0745 361{
362 char **a;
363 char *s;
364 char **argv;
365 int status = -1;
366 BOOL needToTry = TRUE;
2d7a9237 367 char *cmd2;
68dc0745 368
2d7a9237 369 /* Save an extra exec if possible. See if there are shell
370 * metacharacters in it */
9404a519 371 if (!has_redirection(cmd)) {
fc36a67e 372 New(1301,argv, strlen(cmd) / 2 + 2, char*);
373 New(1302,cmd2, strlen(cmd) + 1, char);
68dc0745 374 strcpy(cmd2, cmd);
375 a = argv;
376 for (s = cmd2; *s;) {
377 while (*s && isspace(*s))
378 s++;
379 if (*s)
380 *(a++) = s;
9404a519 381 while (*s && !isspace(*s))
68dc0745 382 s++;
9404a519 383 if (*s)
68dc0745 384 *s++ = '\0';
0a753a76 385 }
68dc0745 386 *a = Nullch;
ce1da67e 387 if (argv[0]) {
6890e559 388 switch (exectype) {
389 case EXECF_SPAWN:
390 status = win32_spawnvp(P_WAIT, argv[0],
391 (const char* const*)argv);
392 break;
393 case EXECF_SPAWN_NOWAIT:
394 status = win32_spawnvp(P_NOWAIT, argv[0],
395 (const char* const*)argv);
396 break;
397 case EXECF_EXEC:
398 status = win32_execvp(argv[0], (const char* const*)argv);
399 break;
400 }
2d7a9237 401 if (status != -1 || errno == 0)
68dc0745 402 needToTry = FALSE;
0a753a76 403 }
0a753a76 404 Safefree(argv);
68dc0745 405 Safefree(cmd2);
406 }
2d7a9237 407 if (needToTry) {
ce1da67e 408 char **argv;
409 int i = -1;
410 get_shell();
411 New(1306, argv, w32_perlshell_items + 2, char*);
412 while (++i < w32_perlshell_items)
413 argv[i] = w32_perlshell_vec[i];
2d7a9237 414 argv[i++] = cmd;
415 argv[i] = Nullch;
6890e559 416 switch (exectype) {
417 case EXECF_SPAWN:
418 status = win32_spawnvp(P_WAIT, argv[0],
419 (const char* const*)argv);
420 break;
421 case EXECF_SPAWN_NOWAIT:
422 status = win32_spawnvp(P_NOWAIT, argv[0],
423 (const char* const*)argv);
424 break;
425 case EXECF_EXEC:
426 status = win32_execvp(argv[0], (const char* const*)argv);
427 break;
428 }
ce1da67e 429 cmd = argv[0];
430 Safefree(argv);
68dc0745 431 }
50892819 432 if (exectype != EXECF_SPAWN_NOWAIT) {
433 if (status < 0) {
434 if (dowarn)
435 warn("Can't %s \"%s\": %s",
436 (exectype == EXECF_EXEC ? "exec" : "spawn"),
437 cmd, strerror(errno));
438 status = 255 * 256;
439 }
440 else
441 status *= 256;
442 statusvalue = status;
5aabfad6 443 }
50892819 444 return (status);
0a753a76 445}
446
6890e559 447int
448do_spawn(char *cmd)
449{
450 return do_spawn2(cmd, EXECF_SPAWN);
451}
452
2d7a9237 453int
454do_spawn_nowait(char *cmd)
455{
456 return do_spawn2(cmd, EXECF_SPAWN_NOWAIT);
457}
458
6890e559 459bool
460do_exec(char *cmd)
461{
462 do_spawn2(cmd, EXECF_EXEC);
463 return FALSE;
464}
465
68dc0745 466/* The idea here is to read all the directory names into a string table
467 * (separated by nulls) and when one of the other dir functions is called
468 * return the pointer to the current file name.
469 */
470DIR *
471opendir(char *filename)
0a753a76 472{
9404a519 473 DIR *p;
474 long len;
475 long idx;
476 char scanname[MAX_PATH+3];
477 struct stat sbuf;
478 WIN32_FIND_DATA FindData;
479 HANDLE fh;
480
481 len = strlen(filename);
482 if (len > MAX_PATH)
483 return NULL;
68dc0745 484
485 /* check to see if filename is a directory */
d55594ae 486 if (win32_stat(filename, &sbuf) < 0 || (sbuf.st_mode & S_IFDIR) == 0) {
c6c1a8fd 487 /* CRT is buggy on sharenames, so make sure it really isn't */
488 DWORD r = GetFileAttributes(filename);
489 if (r == 0xffffffff || !(r & FILE_ATTRIBUTE_DIRECTORY))
490 return NULL;
68dc0745 491 }
492
68dc0745 493 /* Get us a DIR structure */
fc36a67e 494 Newz(1303, p, 1, DIR);
9404a519 495 if (p == NULL)
68dc0745 496 return NULL;
497
498 /* Create the search pattern */
499 strcpy(scanname, filename);
9404a519 500 if (scanname[len-1] != '/' && scanname[len-1] != '\\')
501 scanname[len++] = '/';
502 scanname[len++] = '*';
503 scanname[len] = '\0';
68dc0745 504
505 /* do the FindFirstFile call */
506 fh = FindFirstFile(scanname, &FindData);
9404a519 507 if (fh == INVALID_HANDLE_VALUE) {
68dc0745 508 return NULL;
509 }
510
511 /* now allocate the first part of the string table for
512 * the filenames that we find.
513 */
514 idx = strlen(FindData.cFileName)+1;
fc36a67e 515 New(1304, p->start, idx, char);
9404a519 516 if (p->start == NULL)
65e48ea9 517 croak("opendir: malloc failed!\n");
68dc0745 518 strcpy(p->start, FindData.cFileName);
68dc0745 519 p->nfiles++;
520
521 /* loop finding all the files that match the wildcard
522 * (which should be all of them in this directory!).
523 * the variable idx should point one past the null terminator
524 * of the previous string found.
525 */
526 while (FindNextFile(fh, &FindData)) {
527 len = strlen(FindData.cFileName);
528 /* bump the string table size by enough for the
529 * new name and it's null terminator
530 */
531 Renew(p->start, idx+len+1, char);
9404a519 532 if (p->start == NULL)
65e48ea9 533 croak("opendir: malloc failed!\n");
68dc0745 534 strcpy(&p->start[idx], FindData.cFileName);
9404a519 535 p->nfiles++;
536 idx += len+1;
537 }
538 FindClose(fh);
539 p->size = idx;
540 p->curr = p->start;
541 return p;
0a753a76 542}
543
544
68dc0745 545/* Readdir just returns the current string pointer and bumps the
546 * string pointer to the nDllExport entry.
547 */
548struct direct *
549readdir(DIR *dirp)
0a753a76 550{
68dc0745 551 int len;
552 static int dummy = 0;
0a753a76 553
68dc0745 554 if (dirp->curr) {
555 /* first set up the structure to return */
556 len = strlen(dirp->curr);
557 strcpy(dirp->dirstr.d_name, dirp->curr);
558 dirp->dirstr.d_namlen = len;
0a753a76 559
68dc0745 560 /* Fake an inode */
561 dirp->dirstr.d_ino = dummy++;
0a753a76 562
68dc0745 563 /* Now set up for the nDllExport call to readdir */
564 dirp->curr += len + 1;
565 if (dirp->curr >= (dirp->start + dirp->size)) {
566 dirp->curr = NULL;
567 }
0a753a76 568
68dc0745 569 return &(dirp->dirstr);
570 }
571 else
572 return NULL;
0a753a76 573}
574
68dc0745 575/* Telldir returns the current string pointer position */
576long
577telldir(DIR *dirp)
0a753a76 578{
579 return (long) dirp->curr;
580}
581
582
68dc0745 583/* Seekdir moves the string pointer to a previously saved position
584 *(Saved by telldir).
585 */
586void
587seekdir(DIR *dirp, long loc)
0a753a76 588{
589 dirp->curr = (char *)loc;
590}
591
68dc0745 592/* Rewinddir resets the string pointer to the start */
593void
594rewinddir(DIR *dirp)
0a753a76 595{
596 dirp->curr = dirp->start;
597}
598
68dc0745 599/* free the memory allocated by opendir */
600int
601closedir(DIR *dirp)
0a753a76 602{
603 Safefree(dirp->start);
604 Safefree(dirp);
68dc0745 605 return 1;
0a753a76 606}
607
608
68dc0745 609/*
610 * various stubs
611 */
0a753a76 612
613
68dc0745 614/* Ownership
615 *
616 * Just pretend that everyone is a superuser. NT will let us know if
617 * we don\'t really have permission to do something.
618 */
0a753a76 619
620#define ROOT_UID ((uid_t)0)
621#define ROOT_GID ((gid_t)0)
622
68dc0745 623uid_t
624getuid(void)
0a753a76 625{
68dc0745 626 return ROOT_UID;
0a753a76 627}
628
68dc0745 629uid_t
630geteuid(void)
0a753a76 631{
68dc0745 632 return ROOT_UID;
0a753a76 633}
634
68dc0745 635gid_t
636getgid(void)
0a753a76 637{
68dc0745 638 return ROOT_GID;
0a753a76 639}
640
68dc0745 641gid_t
642getegid(void)
0a753a76 643{
68dc0745 644 return ROOT_GID;
0a753a76 645}
646
68dc0745 647int
22239a37 648setuid(uid_t auid)
0a753a76 649{
22239a37 650 return (auid == ROOT_UID ? 0 : -1);
0a753a76 651}
652
68dc0745 653int
22239a37 654setgid(gid_t agid)
0a753a76 655{
22239a37 656 return (agid == ROOT_GID ? 0 : -1);
0a753a76 657}
658
e34ffe5a 659char *
660getlogin(void)
661{
662 dTHR;
663 char *buf = getlogin_buffer;
664 DWORD size = sizeof(getlogin_buffer);
665 if (GetUserName(buf,&size))
666 return buf;
667 return (char*)NULL;
668}
669
b990f8c8 670int
671chown(const char *path, uid_t owner, gid_t group)
672{
673 /* XXX noop */
1c1c7f20 674 return 0;
b990f8c8 675}
676
68dc0745 677int
678kill(int pid, int sig)
0a753a76 679{
68dc0745 680 HANDLE hProcess= OpenProcess(PROCESS_ALL_ACCESS, TRUE, pid);
0a753a76 681
682 if (hProcess == NULL) {
65e48ea9 683 croak("kill process failed!\n");
68dc0745 684 }
685 else {
686 if (!TerminateProcess(hProcess, sig))
65e48ea9 687 croak("kill process failed!\n");
68dc0745 688 CloseHandle(hProcess);
689 }
690 return 0;
0a753a76 691}
692
68dc0745 693/*
694 * File system stuff
695 */
0a753a76 696
f3986ebb 697DllExport unsigned int
698win32_sleep(unsigned int t)
0a753a76 699{
68dc0745 700 Sleep(t*1000);
701 return 0;
0a753a76 702}
703
68dc0745 704DllExport int
705win32_stat(const char *path, struct stat *buffer)
0a753a76 706{
68dc0745 707 char t[MAX_PATH];
708 const char *p = path;
709 int l = strlen(path);
67fbe06e 710 int res;
0a753a76 711
68dc0745 712 if (l > 1) {
713 switch(path[l - 1]) {
714 case '\\':
715 case '/':
716 if (path[l - 2] != ':') {
717 strncpy(t, path, l - 1);
718 t[l - 1] = 0;
719 p = t;
720 };
721 }
722 }
390b85e7 723 res = stat(p,buffer);
67fbe06e 724#ifdef __BORLANDC__
725 if (res == 0) {
726 if (S_ISDIR(buffer->st_mode))
727 buffer->st_mode |= S_IWRITE | S_IEXEC;
728 else if (S_ISREG(buffer->st_mode)) {
729 if (l >= 4 && path[l-4] == '.') {
730 const char *e = path + l - 3;
731 if (strnicmp(e,"exe",3)
732 && strnicmp(e,"bat",3)
733 && strnicmp(e,"com",3)
734 && (IsWin95() || strnicmp(e,"cmd",3)))
735 buffer->st_mode &= ~S_IEXEC;
736 else
737 buffer->st_mode |= S_IEXEC;
738 }
739 else
740 buffer->st_mode &= ~S_IEXEC;
741 }
742 }
743#endif
744 return res;
0a753a76 745}
746
0551aaa8 747#ifndef USE_WIN32_RTL_ENV
748
749DllExport char *
750win32_getenv(const char *name)
751{
752 static char *curitem = Nullch;
753 static DWORD curlen = 512;
754 DWORD needlen;
755 if (!curitem)
756 New(1305,curitem,curlen,char);
757 if (!(needlen = GetEnvironmentVariable(name,curitem,curlen)))
758 return Nullch;
759 while (needlen > curlen) {
760 Renew(curitem,needlen,char);
761 curlen = needlen;
762 needlen = GetEnvironmentVariable(name,curitem,curlen);
763 }
764 return curitem;
765}
766
767#endif
768
d55594ae 769static long
2d7a9237 770filetime_to_clock(PFILETIME ft)
d55594ae 771{
772 __int64 qw = ft->dwHighDateTime;
773 qw <<= 32;
774 qw |= ft->dwLowDateTime;
775 qw /= 10000; /* File time ticks at 0.1uS, clock at 1mS */
776 return (long) qw;
777}
778
f3986ebb 779DllExport int
780win32_times(struct tms *timebuf)
0a753a76 781{
d55594ae 782 FILETIME user;
783 FILETIME kernel;
784 FILETIME dummy;
785 if (GetProcessTimes(GetCurrentProcess(), &dummy, &dummy,
786 &kernel,&user)) {
2d7a9237 787 timebuf->tms_utime = filetime_to_clock(&user);
788 timebuf->tms_stime = filetime_to_clock(&kernel);
d55594ae 789 timebuf->tms_cutime = 0;
790 timebuf->tms_cstime = 0;
791
792 } else {
793 /* That failed - e.g. Win95 fallback to clock() */
794 clock_t t = clock();
795 timebuf->tms_utime = t;
796 timebuf->tms_stime = 0;
797 timebuf->tms_cutime = 0;
798 timebuf->tms_cstime = 0;
799 }
68dc0745 800 return 0;
0a753a76 801}
802
ad0751ec 803/* fix utime() so it works on directories in NT
804 * thanks to Jan Dubois <jan.dubois@ibm.net>
805 */
806static BOOL
807filetime_from_time(PFILETIME pFileTime, time_t Time)
808{
809 struct tm *pTM = gmtime(&Time);
810 SYSTEMTIME SystemTime;
811
812 if (pTM == NULL)
813 return FALSE;
814
815 SystemTime.wYear = pTM->tm_year + 1900;
816 SystemTime.wMonth = pTM->tm_mon + 1;
817 SystemTime.wDay = pTM->tm_mday;
818 SystemTime.wHour = pTM->tm_hour;
819 SystemTime.wMinute = pTM->tm_min;
820 SystemTime.wSecond = pTM->tm_sec;
821 SystemTime.wMilliseconds = 0;
822
823 return SystemTimeToFileTime(&SystemTime, pFileTime);
824}
825
826DllExport int
3b405fc5 827win32_utime(const char *filename, struct utimbuf *times)
ad0751ec 828{
829 HANDLE handle;
830 FILETIME ftCreate;
831 FILETIME ftAccess;
832 FILETIME ftWrite;
833 struct utimbuf TimeBuffer;
834
835 int rc = utime(filename,times);
836 /* EACCES: path specifies directory or readonly file */
837 if (rc == 0 || errno != EACCES /* || !IsWinNT() */)
838 return rc;
839
840 if (times == NULL) {
841 times = &TimeBuffer;
842 time(&times->actime);
843 times->modtime = times->actime;
844 }
845
846 /* This will (and should) still fail on readonly files */
847 handle = CreateFile(filename, GENERIC_READ | GENERIC_WRITE,
848 FILE_SHARE_READ | FILE_SHARE_DELETE, NULL,
849 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
850 if (handle == INVALID_HANDLE_VALUE)
851 return rc;
852
853 if (GetFileTime(handle, &ftCreate, &ftAccess, &ftWrite) &&
854 filetime_from_time(&ftAccess, times->actime) &&
855 filetime_from_time(&ftWrite, times->modtime) &&
856 SetFileTime(handle, &ftCreate, &ftAccess, &ftWrite))
857 {
858 rc = 0;
859 }
860
861 CloseHandle(handle);
862 return rc;
863}
864
2d7a9237 865DllExport int
866win32_wait(int *status)
867{
4b556e6c 868#ifdef USE_RTL_WAIT
2d7a9237 869 return wait(status);
870#else
871 /* XXX this wait emulation only knows about processes
872 * spawned via win32_spawnvp(P_NOWAIT, ...).
873 */
874 int i, retval;
875 DWORD exitcode, waitcode;
876
877 if (!w32_num_children) {
878 errno = ECHILD;
879 return -1;
880 }
881
882 /* if a child exists, wait for it to die */
883 waitcode = WaitForMultipleObjects(w32_num_children,
884 w32_child_pids,
885 FALSE,
886 INFINITE);
887 if (waitcode != WAIT_FAILED) {
888 if (waitcode >= WAIT_ABANDONED_0
889 && waitcode < WAIT_ABANDONED_0 + w32_num_children)
890 i = waitcode - WAIT_ABANDONED_0;
891 else
892 i = waitcode - WAIT_OBJECT_0;
893 if (GetExitCodeProcess(w32_child_pids[i], &exitcode) ) {
894 CloseHandle(w32_child_pids[i]);
895 *status = (int)((exitcode & 0xff) << 8);
896 retval = (int)w32_child_pids[i];
897 Copy(&w32_child_pids[i+1], &w32_child_pids[i],
898 (w32_num_children-i-1), HANDLE);
899 w32_num_children--;
900 return retval;
901 }
902 }
903
904FAILED:
905 errno = GetLastError();
906 return -1;
907
908#endif
909}
d55594ae 910
2d7a9237 911static UINT timerid = 0;
d55594ae 912
913static VOID CALLBACK TimerProc(HWND win, UINT msg, UINT id, DWORD time)
914{
915 KillTimer(NULL,timerid);
916 timerid=0;
917 sighandler(14);
918}
919
f3986ebb 920DllExport unsigned int
921win32_alarm(unsigned int sec)
0a753a76 922{
d55594ae 923 /*
924 * the 'obvious' implentation is SetTimer() with a callback
925 * which does whatever receiving SIGALRM would do
926 * we cannot use SIGALRM even via raise() as it is not
927 * one of the supported codes in <signal.h>
928 *
929 * Snag is unless something is looking at the message queue
930 * nothing happens :-(
931 */
932 if (sec)
933 {
934 timerid = SetTimer(NULL,timerid,sec*1000,(TIMERPROC)TimerProc);
935 if (!timerid)
936 croak("Cannot set timer");
937 }
938 else
939 {
940 if (timerid)
941 {
942 KillTimer(NULL,timerid);
943 timerid=0;
944 }
945 }
68dc0745 946 return 0;
0a753a76 947}
948
26618a56 949#ifdef HAVE_DES_FCRYPT
950extern char * des_fcrypt(char *cbuf, const char *txt, const char *salt);
951
952DllExport char *
953win32_crypt(const char *txt, const char *salt)
954{
955 dTHR;
956 return des_fcrypt(crypt_buffer, txt, salt);
957}
958#endif
959
f3986ebb 960#ifdef USE_FIXED_OSFHANDLE
390b85e7 961
962EXTERN_C int __cdecl _alloc_osfhnd(void);
963EXTERN_C int __cdecl _set_osfhnd(int fh, long value);
964EXTERN_C void __cdecl _lock_fhandle(int);
965EXTERN_C void __cdecl _unlock_fhandle(int);
966EXTERN_C void __cdecl _unlock(int);
967
968#if (_MSC_VER >= 1000)
969typedef struct {
970 long osfhnd; /* underlying OS file HANDLE */
971 char osfile; /* attributes of file (e.g., open in text mode?) */
972 char pipech; /* one char buffer for handles opened on pipes */
973#if defined (_MT) && !defined (DLL_FOR_WIN32S)
974 int lockinitflag;
975 CRITICAL_SECTION lock;
976#endif /* defined (_MT) && !defined (DLL_FOR_WIN32S) */
977} ioinfo;
978
979EXTERN_C ioinfo * __pioinfo[];
980
981#define IOINFO_L2E 5
982#define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E)
983#define _pioinfo(i) (__pioinfo[i >> IOINFO_L2E] + (i & (IOINFO_ARRAY_ELTS - 1)))
984#define _osfile(i) (_pioinfo(i)->osfile)
985
986#else /* (_MSC_VER >= 1000) */
987extern char _osfile[];
988#endif /* (_MSC_VER >= 1000) */
989
990#define FOPEN 0x01 /* file handle open */
991#define FAPPEND 0x20 /* file handle opened O_APPEND */
992#define FDEV 0x40 /* file handle refers to device */
993#define FTEXT 0x80 /* file handle is in text mode */
994
995#define _STREAM_LOCKS 26 /* Table of stream locks */
996#define _LAST_STREAM_LOCK (_STREAM_LOCKS+_NSTREAM_-1) /* Last stream lock */
997#define _FH_LOCKS (_LAST_STREAM_LOCK+1) /* Table of fh locks */
998
999/***
1000*int my_open_osfhandle(long osfhandle, int flags) - open C Runtime file handle
1001*
1002*Purpose:
1003* This function allocates a free C Runtime file handle and associates
1004* it with the Win32 HANDLE specified by the first parameter. This is a
1005* temperary fix for WIN95's brain damage GetFileType() error on socket
1006* we just bypass that call for socket
1007*
1008*Entry:
1009* long osfhandle - Win32 HANDLE to associate with C Runtime file handle.
1010* int flags - flags to associate with C Runtime file handle.
1011*
1012*Exit:
1013* returns index of entry in fh, if successful
1014* return -1, if no free entry is found
1015*
1016*Exceptions:
1017*
1018*******************************************************************************/
1019
1020static int
1021my_open_osfhandle(long osfhandle, int flags)
1022{
1023 int fh;
1024 char fileflags; /* _osfile flags */
1025
1026 /* copy relevant flags from second parameter */
1027 fileflags = FDEV;
1028
9404a519 1029 if (flags & O_APPEND)
390b85e7 1030 fileflags |= FAPPEND;
1031
9404a519 1032 if (flags & O_TEXT)
390b85e7 1033 fileflags |= FTEXT;
1034
1035 /* attempt to allocate a C Runtime file handle */
9404a519 1036 if ((fh = _alloc_osfhnd()) == -1) {
390b85e7 1037 errno = EMFILE; /* too many open files */
1038 _doserrno = 0L; /* not an OS error */
1039 return -1; /* return error to caller */
1040 }
1041
1042 /* the file is open. now, set the info in _osfhnd array */
1043 _set_osfhnd(fh, osfhandle);
1044
1045 fileflags |= FOPEN; /* mark as open */
1046
1047#if (_MSC_VER >= 1000)
1048 _osfile(fh) = fileflags; /* set osfile entry */
1049 _unlock_fhandle(fh);
1050#else
1051 _osfile[fh] = fileflags; /* set osfile entry */
1052 _unlock(fh+_FH_LOCKS); /* unlock handle */
1053#endif
1054
1055 return fh; /* return handle */
1056}
1057
1058#define _open_osfhandle my_open_osfhandle
f3986ebb 1059#endif /* USE_FIXED_OSFHANDLE */
390b85e7 1060
1061/* simulate flock by locking a range on the file */
1062
1063#define LK_ERR(f,i) ((f) ? (i = 0) : (errno = GetLastError()))
1064#define LK_LEN 0xffff0000
1065
f3986ebb 1066DllExport int
1067win32_flock(int fd, int oper)
390b85e7 1068{
1069 OVERLAPPED o;
1070 int i = -1;
1071 HANDLE fh;
1072
f3986ebb 1073 if (!IsWinNT()) {
1074 croak("flock() unimplemented on this platform");
1075 return -1;
1076 }
390b85e7 1077 fh = (HANDLE)_get_osfhandle(fd);
1078 memset(&o, 0, sizeof(o));
1079
1080 switch(oper) {
1081 case LOCK_SH: /* shared lock */
1082 LK_ERR(LockFileEx(fh, 0, 0, LK_LEN, 0, &o),i);
1083 break;
1084 case LOCK_EX: /* exclusive lock */
1085 LK_ERR(LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, LK_LEN, 0, &o),i);
1086 break;
1087 case LOCK_SH|LOCK_NB: /* non-blocking shared lock */
1088 LK_ERR(LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY, 0, LK_LEN, 0, &o),i);
1089 break;
1090 case LOCK_EX|LOCK_NB: /* non-blocking exclusive lock */
1091 LK_ERR(LockFileEx(fh,
1092 LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY,
1093 0, LK_LEN, 0, &o),i);
1094 break;
1095 case LOCK_UN: /* unlock lock */
1096 LK_ERR(UnlockFileEx(fh, 0, LK_LEN, 0, &o),i);
1097 break;
1098 default: /* unknown */
1099 errno = EINVAL;
1100 break;
1101 }
1102 return i;
1103}
1104
1105#undef LK_ERR
1106#undef LK_LEN
1107
68dc0745 1108/*
1109 * redirected io subsystem for all XS modules
1110 *
1111 */
0a753a76 1112
68dc0745 1113DllExport int *
1114win32_errno(void)
0a753a76 1115{
390b85e7 1116 return (&errno);
0a753a76 1117}
1118
dcb2879a 1119DllExport char ***
1120win32_environ(void)
1121{
390b85e7 1122 return (&(_environ));
dcb2879a 1123}
1124
68dc0745 1125/* the rest are the remapped stdio routines */
1126DllExport FILE *
1127win32_stderr(void)
0a753a76 1128{
390b85e7 1129 return (stderr);
0a753a76 1130}
1131
68dc0745 1132DllExport FILE *
1133win32_stdin(void)
0a753a76 1134{
390b85e7 1135 return (stdin);
0a753a76 1136}
1137
68dc0745 1138DllExport FILE *
1139win32_stdout()
0a753a76 1140{
390b85e7 1141 return (stdout);
0a753a76 1142}
1143
68dc0745 1144DllExport int
1145win32_ferror(FILE *fp)
0a753a76 1146{
390b85e7 1147 return (ferror(fp));
0a753a76 1148}
1149
1150
68dc0745 1151DllExport int
1152win32_feof(FILE *fp)
0a753a76 1153{
390b85e7 1154 return (feof(fp));
0a753a76 1155}
1156
68dc0745 1157/*
1158 * Since the errors returned by the socket error function
1159 * WSAGetLastError() are not known by the library routine strerror
1160 * we have to roll our own.
1161 */
0a753a76 1162
68dc0745 1163DllExport char *
1164win32_strerror(int e)
0a753a76 1165{
3e3baf6d 1166#ifndef __BORLANDC__ /* Borland intolerance */
68dc0745 1167 extern int sys_nerr;
3e3baf6d 1168#endif
68dc0745 1169 DWORD source = 0;
0a753a76 1170
9404a519 1171 if (e < 0 || e > sys_nerr) {
c53bd28a 1172 dTHR;
9404a519 1173 if (e < 0)
68dc0745 1174 e = GetLastError();
0a753a76 1175
9404a519 1176 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, &source, e, 0,
68dc0745 1177 strerror_buffer, sizeof(strerror_buffer), NULL) == 0)
1178 strcpy(strerror_buffer, "Unknown Error");
0a753a76 1179
68dc0745 1180 return strerror_buffer;
1181 }
390b85e7 1182 return strerror(e);
0a753a76 1183}
1184
22fae026 1185DllExport void
3730b96e 1186win32_str_os_error(void *sv, DWORD dwErr)
22fae026 1187{
1188 DWORD dwLen;
1189 char *sMsg;
1190 dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
1191 |FORMAT_MESSAGE_IGNORE_INSERTS
1192 |FORMAT_MESSAGE_FROM_SYSTEM, NULL,
1193 dwErr, 0, (char *)&sMsg, 1, NULL);
1194 if (0 < dwLen) {
1195 while (0 < dwLen && isspace(sMsg[--dwLen]))
1196 ;
1197 if ('.' != sMsg[dwLen])
1198 dwLen++;
1199 sMsg[dwLen]= '\0';
1200 }
1201 if (0 == dwLen) {
1202 sMsg = LocalAlloc(0, 64/**sizeof(TCHAR)*/);
1203 dwLen = sprintf(sMsg,
1204 "Unknown error #0x%lX (lookup 0x%lX)",
1205 dwErr, GetLastError());
1206 }
3730b96e 1207 sv_setpvn((SV*)sv, sMsg, dwLen);
22fae026 1208 LocalFree(sMsg);
1209}
1210
1211
68dc0745 1212DllExport int
1213win32_fprintf(FILE *fp, const char *format, ...)
0a753a76 1214{
68dc0745 1215 va_list marker;
1216 va_start(marker, format); /* Initialize variable arguments. */
0a753a76 1217
390b85e7 1218 return (vfprintf(fp, format, marker));
0a753a76 1219}
1220
68dc0745 1221DllExport int
1222win32_printf(const char *format, ...)
0a753a76 1223{
68dc0745 1224 va_list marker;
1225 va_start(marker, format); /* Initialize variable arguments. */
0a753a76 1226
390b85e7 1227 return (vprintf(format, marker));
0a753a76 1228}
1229
68dc0745 1230DllExport int
1231win32_vfprintf(FILE *fp, const char *format, va_list args)
0a753a76 1232{
390b85e7 1233 return (vfprintf(fp, format, args));
0a753a76 1234}
1235
96e4d5b1 1236DllExport int
1237win32_vprintf(const char *format, va_list args)
1238{
390b85e7 1239 return (vprintf(format, args));
96e4d5b1 1240}
1241
68dc0745 1242DllExport size_t
1243win32_fread(void *buf, size_t size, size_t count, FILE *fp)
0a753a76 1244{
390b85e7 1245 return fread(buf, size, count, fp);
0a753a76 1246}
1247
68dc0745 1248DllExport size_t
1249win32_fwrite(const void *buf, size_t size, size_t count, FILE *fp)
0a753a76 1250{
390b85e7 1251 return fwrite(buf, size, count, fp);
0a753a76 1252}
1253
68dc0745 1254DllExport FILE *
1255win32_fopen(const char *filename, const char *mode)
0a753a76 1256{
68dc0745 1257 if (stricmp(filename, "/dev/null")==0)
390b85e7 1258 return fopen("NUL", mode);
1259 return fopen(filename, mode);
0a753a76 1260}
1261
f3986ebb 1262#ifndef USE_SOCKETS_AS_HANDLES
1263#undef fdopen
1264#define fdopen my_fdopen
1265#endif
1266
68dc0745 1267DllExport FILE *
1268win32_fdopen( int handle, const char *mode)
0a753a76 1269{
390b85e7 1270 return fdopen(handle, (char *) mode);
0a753a76 1271}
1272
68dc0745 1273DllExport FILE *
1274win32_freopen( const char *path, const char *mode, FILE *stream)
0a753a76 1275{
68dc0745 1276 if (stricmp(path, "/dev/null")==0)
390b85e7 1277 return freopen("NUL", mode, stream);
1278 return freopen(path, mode, stream);
0a753a76 1279}
1280
68dc0745 1281DllExport int
1282win32_fclose(FILE *pf)
0a753a76 1283{
f3986ebb 1284 return my_fclose(pf); /* defined in win32sck.c */
0a753a76 1285}
1286
68dc0745 1287DllExport int
1288win32_fputs(const char *s,FILE *pf)
0a753a76 1289{
390b85e7 1290 return fputs(s, pf);
0a753a76 1291}
1292
68dc0745 1293DllExport int
1294win32_fputc(int c,FILE *pf)
0a753a76 1295{
390b85e7 1296 return fputc(c,pf);
0a753a76 1297}
1298
68dc0745 1299DllExport int
1300win32_ungetc(int c,FILE *pf)
0a753a76 1301{
390b85e7 1302 return ungetc(c,pf);
0a753a76 1303}
1304
68dc0745 1305DllExport int
1306win32_getc(FILE *pf)
0a753a76 1307{
390b85e7 1308 return getc(pf);
0a753a76 1309}
1310
68dc0745 1311DllExport int
1312win32_fileno(FILE *pf)
0a753a76 1313{
390b85e7 1314 return fileno(pf);
0a753a76 1315}
1316
68dc0745 1317DllExport void
1318win32_clearerr(FILE *pf)
0a753a76 1319{
390b85e7 1320 clearerr(pf);
68dc0745 1321 return;
0a753a76 1322}
1323
68dc0745 1324DllExport int
1325win32_fflush(FILE *pf)
0a753a76 1326{
390b85e7 1327 return fflush(pf);
0a753a76 1328}
1329
68dc0745 1330DllExport long
1331win32_ftell(FILE *pf)
0a753a76 1332{
390b85e7 1333 return ftell(pf);
0a753a76 1334}
1335
68dc0745 1336DllExport int
1337win32_fseek(FILE *pf,long offset,int origin)
0a753a76 1338{
390b85e7 1339 return fseek(pf, offset, origin);
0a753a76 1340}
1341
68dc0745 1342DllExport int
1343win32_fgetpos(FILE *pf,fpos_t *p)
0a753a76 1344{
390b85e7 1345 return fgetpos(pf, p);
0a753a76 1346}
1347
68dc0745 1348DllExport int
1349win32_fsetpos(FILE *pf,const fpos_t *p)
0a753a76 1350{
390b85e7 1351 return fsetpos(pf, p);
0a753a76 1352}
1353
68dc0745 1354DllExport void
1355win32_rewind(FILE *pf)
0a753a76 1356{
390b85e7 1357 rewind(pf);
68dc0745 1358 return;
0a753a76 1359}
1360
68dc0745 1361DllExport FILE*
1362win32_tmpfile(void)
0a753a76 1363{
390b85e7 1364 return tmpfile();
0a753a76 1365}
1366
68dc0745 1367DllExport void
1368win32_abort(void)
0a753a76 1369{
390b85e7 1370 abort();
68dc0745 1371 return;
0a753a76 1372}
1373
68dc0745 1374DllExport int
22239a37 1375win32_fstat(int fd,struct stat *sbufptr)
0a753a76 1376{
22239a37 1377 return fstat(fd,sbufptr);
0a753a76 1378}
1379
68dc0745 1380DllExport int
1381win32_pipe(int *pfd, unsigned int size, int mode)
0a753a76 1382{
390b85e7 1383 return _pipe(pfd, size, mode);
0a753a76 1384}
1385
50892819 1386/*
1387 * a popen() clone that respects PERL5SHELL
1388 */
1389
68dc0745 1390DllExport FILE*
1391win32_popen(const char *command, const char *mode)
0a753a76 1392{
4b556e6c 1393#ifdef USE_RTL_POPEN
390b85e7 1394 return _popen(command, mode);
50892819 1395#else
1396 int p[2];
1397 int parent, child;
1398 int stdfd, oldfd;
1399 int ourmode;
1400 int childpid;
1401
1402 /* establish which ends read and write */
1403 if (strchr(mode,'w')) {
1404 stdfd = 0; /* stdin */
1405 parent = 1;
1406 child = 0;
1407 }
1408 else if (strchr(mode,'r')) {
1409 stdfd = 1; /* stdout */
1410 parent = 0;
1411 child = 1;
1412 }
1413 else
1414 return NULL;
1415
1416 /* set the correct mode */
1417 if (strchr(mode,'b'))
1418 ourmode = O_BINARY;
1419 else if (strchr(mode,'t'))
1420 ourmode = O_TEXT;
1421 else
1422 ourmode = _fmode & (O_TEXT | O_BINARY);
1423
1424 /* the child doesn't inherit handles */
1425 ourmode |= O_NOINHERIT;
1426
1427 if (win32_pipe( p, 512, ourmode) == -1)
1428 return NULL;
1429
1430 /* save current stdfd */
1431 if ((oldfd = win32_dup(stdfd)) == -1)
1432 goto cleanup;
1433
1434 /* make stdfd go to child end of pipe (implicitly closes stdfd) */
1435 /* stdfd will be inherited by the child */
1436 if (win32_dup2(p[child], stdfd) == -1)
1437 goto cleanup;
1438
1439 /* close the child end in parent */
1440 win32_close(p[child]);
1441
1442 /* start the child */
1443 if ((childpid = do_spawn_nowait((char*)command)) == -1)
1444 goto cleanup;
1445
1446 /* revert stdfd to whatever it was before */
1447 if (win32_dup2(oldfd, stdfd) == -1)
1448 goto cleanup;
1449
1450 /* close saved handle */
1451 win32_close(oldfd);
4b556e6c 1452
1453 sv_setiv(*av_fetch(w32_fdpid, p[parent], TRUE), childpid);
50892819 1454
1455 /* we have an fd, return a file stream */
1456 return (win32_fdopen(p[parent], (char *)mode));
1457
1458cleanup:
1459 /* we don't need to check for errors here */
1460 win32_close(p[0]);
1461 win32_close(p[1]);
1462 if (oldfd != -1) {
1463 win32_dup2(oldfd, stdfd);
1464 win32_close(oldfd);
1465 }
1466 return (NULL);
1467
4b556e6c 1468#endif /* USE_RTL_POPEN */
0a753a76 1469}
1470
50892819 1471/*
1472 * pclose() clone
1473 */
1474
68dc0745 1475DllExport int
1476win32_pclose(FILE *pf)
0a753a76 1477{
4b556e6c 1478#ifdef USE_RTL_POPEN
390b85e7 1479 return _pclose(pf);
50892819 1480#else
50892819 1481
4b556e6c 1482#ifndef USE_RTL_WAIT
e17cb2a9 1483 int child;
1484#endif
1485
1486 int childpid, status;
1487 SV *sv;
1488
4b556e6c 1489 sv = *av_fetch(w32_fdpid, win32_fileno(pf), TRUE);
e17cb2a9 1490 if (SvIOK(sv))
1491 childpid = SvIVX(sv);
1492 else
1493 childpid = 0;
50892819 1494
1495 if (!childpid) {
1496 errno = EBADF;
1497 return -1;
1498 }
1499
1500 win32_fclose(pf);
e17cb2a9 1501 SvIVX(sv) = 0;
1502
4b556e6c 1503#ifndef USE_RTL_WAIT
e17cb2a9 1504 for (child = 0 ; child < w32_num_children ; ++child) {
1505 if (w32_child_pids[child] == (HANDLE)childpid) {
1506 Copy(&w32_child_pids[child+1], &w32_child_pids[child],
1507 (w32_num_children-child-1), HANDLE);
1508 w32_num_children--;
1509 break;
1510 }
1511 }
1512#endif
50892819 1513
1514 /* wait for the child */
1515 if (cwait(&status, childpid, WAIT_CHILD) == -1)
1516 return (-1);
1517 /* cwait() returns differently on Borland */
1518#ifdef __BORLANDC__
1519 return (((status >> 8) & 0xff) | ((status << 8) & 0xff00));
1520#else
1521 return (status);
1522#endif
1523
4b556e6c 1524#endif /* USE_RTL_POPEN */
0a753a76 1525}
1526
68dc0745 1527DllExport int
1528win32_setmode(int fd, int mode)
0a753a76 1529{
390b85e7 1530 return setmode(fd, mode);
0a753a76 1531}
1532
96e4d5b1 1533DllExport long
1534win32_lseek(int fd, long offset, int origin)
1535{
390b85e7 1536 return lseek(fd, offset, origin);
96e4d5b1 1537}
1538
1539DllExport long
1540win32_tell(int fd)
1541{
390b85e7 1542 return tell(fd);
96e4d5b1 1543}
1544
68dc0745 1545DllExport int
1546win32_open(const char *path, int flag, ...)
0a753a76 1547{
68dc0745 1548 va_list ap;
1549 int pmode;
0a753a76 1550
1551 va_start(ap, flag);
1552 pmode = va_arg(ap, int);
1553 va_end(ap);
1554
68dc0745 1555 if (stricmp(path, "/dev/null")==0)
390b85e7 1556 return open("NUL", flag, pmode);
1557 return open(path,flag,pmode);
0a753a76 1558}
1559
68dc0745 1560DllExport int
1561win32_close(int fd)
0a753a76 1562{
390b85e7 1563 return close(fd);
0a753a76 1564}
1565
68dc0745 1566DllExport int
96e4d5b1 1567win32_eof(int fd)
1568{
390b85e7 1569 return eof(fd);
96e4d5b1 1570}
1571
1572DllExport int
68dc0745 1573win32_dup(int fd)
0a753a76 1574{
390b85e7 1575 return dup(fd);
0a753a76 1576}
1577
68dc0745 1578DllExport int
1579win32_dup2(int fd1,int fd2)
0a753a76 1580{
390b85e7 1581 return dup2(fd1,fd2);
0a753a76 1582}
1583
68dc0745 1584DllExport int
3e3baf6d 1585win32_read(int fd, void *buf, unsigned int cnt)
0a753a76 1586{
390b85e7 1587 return read(fd, buf, cnt);
0a753a76 1588}
1589
68dc0745 1590DllExport int
3e3baf6d 1591win32_write(int fd, const void *buf, unsigned int cnt)
0a753a76 1592{
390b85e7 1593 return write(fd, buf, cnt);
0a753a76 1594}
1595
68dc0745 1596DllExport int
5aabfad6 1597win32_mkdir(const char *dir, int mode)
1598{
390b85e7 1599 return mkdir(dir); /* just ignore mode */
5aabfad6 1600}
96e4d5b1 1601
5aabfad6 1602DllExport int
1603win32_rmdir(const char *dir)
1604{
390b85e7 1605 return rmdir(dir);
5aabfad6 1606}
96e4d5b1 1607
5aabfad6 1608DllExport int
1609win32_chdir(const char *dir)
1610{
390b85e7 1611 return chdir(dir);
5aabfad6 1612}
96e4d5b1 1613
5aabfad6 1614DllExport int
3e3baf6d 1615win32_spawnvp(int mode, const char *cmdname, const char *const *argv)
0a753a76 1616{
2d7a9237 1617 int status;
1618
4b556e6c 1619#ifndef USE_RTL_WAIT
e17cb2a9 1620 if (mode == P_NOWAIT && w32_num_children >= MAXIMUM_WAIT_OBJECTS)
1621 return -1;
1622#endif
1623
2d7a9237 1624 status = spawnvp(mode, cmdname, (char * const *) argv);
4b556e6c 1625#ifndef USE_RTL_WAIT
2d7a9237 1626 /* XXX For the P_NOWAIT case, Borland RTL returns pinfo.dwProcessId
1627 * while VC RTL returns pinfo.hProcess. For purposes of the custom
1628 * implementation of win32_wait(), we assume the latter.
1629 */
1630 if (mode == P_NOWAIT && status >= 0)
1631 w32_child_pids[w32_num_children++] = (HANDLE)status;
1632#endif
1633 return status;
0a753a76 1634}
1635
6890e559 1636DllExport int
1637win32_execvp(const char *cmdname, const char *const *argv)
1638{
390b85e7 1639 return execvp(cmdname, (char *const *)argv);
6890e559 1640}
1641
84902520 1642DllExport void
1643win32_perror(const char *str)
1644{
390b85e7 1645 perror(str);
84902520 1646}
1647
1648DllExport void
1649win32_setbuf(FILE *pf, char *buf)
1650{
390b85e7 1651 setbuf(pf, buf);
84902520 1652}
1653
1654DllExport int
1655win32_setvbuf(FILE *pf, char *buf, int type, size_t size)
1656{
390b85e7 1657 return setvbuf(pf, buf, type, size);
84902520 1658}
1659
1660DllExport int
1661win32_flushall(void)
1662{
390b85e7 1663 return flushall();
84902520 1664}
1665
1666DllExport int
1667win32_fcloseall(void)
1668{
390b85e7 1669 return fcloseall();
84902520 1670}
1671
1672DllExport char*
1673win32_fgets(char *s, int n, FILE *pf)
1674{
390b85e7 1675 return fgets(s, n, pf);
84902520 1676}
1677
1678DllExport char*
1679win32_gets(char *s)
1680{
390b85e7 1681 return gets(s);
84902520 1682}
1683
1684DllExport int
1685win32_fgetc(FILE *pf)
1686{
390b85e7 1687 return fgetc(pf);
84902520 1688}
1689
1690DllExport int
1691win32_putc(int c, FILE *pf)
1692{
390b85e7 1693 return putc(c,pf);
84902520 1694}
1695
1696DllExport int
1697win32_puts(const char *s)
1698{
390b85e7 1699 return puts(s);
84902520 1700}
1701
1702DllExport int
1703win32_getchar(void)
1704{
390b85e7 1705 return getchar();
84902520 1706}
1707
1708DllExport int
1709win32_putchar(int c)
1710{
390b85e7 1711 return putchar(c);
84902520 1712}
1713
bbc8f9de 1714#ifdef MYMALLOC
1715
1716#ifndef USE_PERL_SBRK
1717
1718static char *committed = NULL;
1719static char *base = NULL;
1720static char *reserved = NULL;
1721static char *brk = NULL;
1722static DWORD pagesize = 0;
1723static DWORD allocsize = 0;
1724
1725void *
1726sbrk(int need)
1727{
1728 void *result;
1729 if (!pagesize)
1730 {SYSTEM_INFO info;
1731 GetSystemInfo(&info);
1732 /* Pretend page size is larger so we don't perpetually
1733 * call the OS to commit just one page ...
1734 */
1735 pagesize = info.dwPageSize << 3;
1736 allocsize = info.dwAllocationGranularity;
1737 }
1738 /* This scheme fails eventually if request for contiguous
1739 * block is denied so reserve big blocks - this is only
1740 * address space not memory ...
1741 */
1742 if (brk+need >= reserved)
1743 {
1744 DWORD size = 64*1024*1024;
1745 char *addr;
1746 if (committed && reserved && committed < reserved)
1747 {
1748 /* Commit last of previous chunk cannot span allocations */
161b471a 1749 addr = (char *) VirtualAlloc(committed,reserved-committed,MEM_COMMIT,PAGE_READWRITE);
bbc8f9de 1750 if (addr)
1751 committed = reserved;
1752 }
1753 /* Reserve some (more) space
1754 * Note this is a little sneaky, 1st call passes NULL as reserved
1755 * so lets system choose where we start, subsequent calls pass
1756 * the old end address so ask for a contiguous block
1757 */
161b471a 1758 addr = (char *) VirtualAlloc(reserved,size,MEM_RESERVE,PAGE_NOACCESS);
bbc8f9de 1759 if (addr)
1760 {
1761 reserved = addr+size;
1762 if (!base)
1763 base = addr;
1764 if (!committed)
1765 committed = base;
1766 if (!brk)
1767 brk = committed;
1768 }
1769 else
1770 {
1771 return (void *) -1;
1772 }
1773 }
1774 result = brk;
1775 brk += need;
1776 if (brk > committed)
1777 {
1778 DWORD size = ((brk-committed + pagesize -1)/pagesize) * pagesize;
161b471a 1779 char *addr = (char *) VirtualAlloc(committed,size,MEM_COMMIT,PAGE_READWRITE);
bbc8f9de 1780 if (addr)
1781 {
1782 committed += size;
1783 }
1784 else
1785 return (void *) -1;
1786 }
1787 return result;
1788}
1789
1790#endif
1791#endif
1792
84902520 1793DllExport void*
1794win32_malloc(size_t size)
1795{
390b85e7 1796 return malloc(size);
84902520 1797}
1798
1799DllExport void*
1800win32_calloc(size_t numitems, size_t size)
1801{
390b85e7 1802 return calloc(numitems,size);
84902520 1803}
1804
1805DllExport void*
1806win32_realloc(void *block, size_t size)
1807{
390b85e7 1808 return realloc(block,size);
84902520 1809}
1810
1811DllExport void
1812win32_free(void *block)
1813{
390b85e7 1814 free(block);
84902520 1815}
1816
bbc8f9de 1817
68dc0745 1818int
65e48ea9 1819win32_open_osfhandle(long handle, int flags)
0a753a76 1820{
390b85e7 1821 return _open_osfhandle(handle, flags);
0a753a76 1822}
1823
68dc0745 1824long
65e48ea9 1825win32_get_osfhandle(int fd)
0a753a76 1826{
390b85e7 1827 return _get_osfhandle(fd);
0a753a76 1828}
7bac28a0 1829
7bac28a0 1830/*
1831 * Extras.
1832 */
1833
ad2e33dc 1834static
1835XS(w32_GetCwd)
1836{
1837 dXSARGS;
1838 SV *sv = sv_newmortal();
1839 /* Make one call with zero size - return value is required size */
1840 DWORD len = GetCurrentDirectory((DWORD)0,NULL);
1841 SvUPGRADE(sv,SVt_PV);
1842 SvGROW(sv,len);
1843 SvCUR(sv) = GetCurrentDirectory((DWORD) SvLEN(sv), SvPVX(sv));
1844 /*
1845 * If result != 0
1846 * then it worked, set PV valid,
1847 * else leave it 'undef'
1848 */
1849 if (SvCUR(sv))
1850 SvPOK_on(sv);
50892819 1851 EXTEND(SP,1);
ad2e33dc 1852 ST(0) = sv;
1853 XSRETURN(1);
1854}
1855
1856static
1857XS(w32_SetCwd)
1858{
1859 dXSARGS;
1860 if (items != 1)
1861 croak("usage: Win32::SetCurrentDirectory($cwd)");
1862 if (SetCurrentDirectory(SvPV(ST(0),na)))
1863 XSRETURN_YES;
1864
1865 XSRETURN_NO;
1866}
1867
1868static
1869XS(w32_GetNextAvailDrive)
1870{
1871 dXSARGS;
1872 char ix = 'C';
1873 char root[] = "_:\\";
1874 while (ix <= 'Z') {
1875 root[0] = ix++;
1876 if (GetDriveType(root) == 1) {
1877 root[2] = '\0';
1878 XSRETURN_PV(root);
1879 }
1880 }
1881 XSRETURN_UNDEF;
1882}
1883
1884static
1885XS(w32_GetLastError)
1886{
1887 dXSARGS;
1888 XSRETURN_IV(GetLastError());
1889}
1890
1891static
1892XS(w32_LoginName)
1893{
1894 dXSARGS;
e34ffe5a 1895 char *name = getlogin_buffer;
1896 DWORD size = sizeof(getlogin_buffer);
ad2e33dc 1897 if (GetUserName(name,&size)) {
1898 /* size includes NULL */
1899 ST(0) = sv_2mortal(newSVpv(name,size-1));
1900 XSRETURN(1);
1901 }
1902 XSRETURN_UNDEF;
1903}
1904
1905static
1906XS(w32_NodeName)
1907{
1908 dXSARGS;
1909 char name[MAX_COMPUTERNAME_LENGTH+1];
1910 DWORD size = sizeof(name);
1911 if (GetComputerName(name,&size)) {
1912 /* size does NOT include NULL :-( */
1913 ST(0) = sv_2mortal(newSVpv(name,size));
1914 XSRETURN(1);
1915 }
1916 XSRETURN_UNDEF;
1917}
1918
1919
1920static
1921XS(w32_DomainName)
1922{
1923 dXSARGS;
8c9208bc 1924#ifndef HAS_NETWKSTAGETINFO
1925 /* mingw32 (and Win95) don't have NetWksta*(), so do it the old way */
e56670dd 1926 char name[256];
1927 DWORD size = sizeof(name);
1928 if (GetUserName(name,&size)) {
1929 char sid[1024];
1930 DWORD sidlen = sizeof(sid);
1931 char dname[256];
1932 DWORD dnamelen = sizeof(dname);
1933 SID_NAME_USE snu;
1934 if (LookupAccountName(NULL, name, &sid, &sidlen,
1935 dname, &dnamelen, &snu)) {
1936 XSRETURN_PV(dname); /* all that for this */
1937 }
1938 }
1939#else
8c9208bc 1940 /* this way is more reliable, in case user has a local account.
1941 * XXX need dynamic binding of netapi32.dll symbols or this will fail on
1942 * Win95. Probably makes more sense to move it into libwin32. */
9404a519 1943 char dname[256];
1944 DWORD dnamelen = sizeof(dname);
0a2408cf 1945 PWKSTA_INFO_100 pwi;
1946 if (NERR_Success == NetWkstaGetInfo(NULL, 100, (LPBYTE*)&pwi)) {
1947 if (pwi->wki100_langroup && *(pwi->wki100_langroup)) {
1948 WideCharToMultiByte(CP_ACP, NULL, pwi->wki100_langroup,
1949 -1, (LPSTR)dname, dnamelen, NULL, NULL);
1950 }
1951 else {
1952 WideCharToMultiByte(CP_ACP, NULL, pwi->wki100_computername,
1953 -1, (LPSTR)dname, dnamelen, NULL, NULL);
1954 }
1955 NetApiBufferFree(pwi);
9404a519 1956 XSRETURN_PV(dname);
1957 }
e56670dd 1958#endif
ad2e33dc 1959 XSRETURN_UNDEF;
1960}
1961
1962static
1963XS(w32_FsType)
1964{
1965 dXSARGS;
1966 char fsname[256];
1967 DWORD flags, filecomplen;
1968 if (GetVolumeInformation(NULL, NULL, 0, NULL, &filecomplen,
1969 &flags, fsname, sizeof(fsname))) {
1970 if (GIMME == G_ARRAY) {
1971 XPUSHs(sv_2mortal(newSVpv(fsname,0)));
1972 XPUSHs(sv_2mortal(newSViv(flags)));
1973 XPUSHs(sv_2mortal(newSViv(filecomplen)));
1974 PUTBACK;
1975 return;
1976 }
1977 XSRETURN_PV(fsname);
1978 }
1979 XSRETURN_UNDEF;
1980}
1981
1982static
1983XS(w32_GetOSVersion)
1984{
1985 dXSARGS;
1986 OSVERSIONINFO osver;
1987
1988 osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
1989 if (GetVersionEx(&osver)) {
1990 XPUSHs(newSVpv(osver.szCSDVersion, 0));
1991 XPUSHs(newSViv(osver.dwMajorVersion));
1992 XPUSHs(newSViv(osver.dwMinorVersion));
1993 XPUSHs(newSViv(osver.dwBuildNumber));
1994 XPUSHs(newSViv(osver.dwPlatformId));
1995 PUTBACK;
1996 return;
1997 }
1998 XSRETURN_UNDEF;
1999}
2000
2001static
2002XS(w32_IsWinNT)
2003{
2004 dXSARGS;
2005 XSRETURN_IV(IsWinNT());
2006}
2007
2008static
2009XS(w32_IsWin95)
2010{
2011 dXSARGS;
2012 XSRETURN_IV(IsWin95());
2013}
2014
2015static
2016XS(w32_FormatMessage)
2017{
2018 dXSARGS;
2019 DWORD source = 0;
2020 char msgbuf[1024];
2021
2022 if (items != 1)
2023 croak("usage: Win32::FormatMessage($errno)");
2024
2025 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
2026 &source, SvIV(ST(0)), 0,
2027 msgbuf, sizeof(msgbuf)-1, NULL))
2028 XSRETURN_PV(msgbuf);
2029
2030 XSRETURN_UNDEF;
2031}
2032
2033static
2034XS(w32_Spawn)
2035{
2036 dXSARGS;
2037 char *cmd, *args;
2038 PROCESS_INFORMATION stProcInfo;
2039 STARTUPINFO stStartInfo;
2040 BOOL bSuccess = FALSE;
2041
9404a519 2042 if (items != 3)
ad2e33dc 2043 croak("usage: Win32::Spawn($cmdName, $args, $PID)");
2044
2045 cmd = SvPV(ST(0),na);
2046 args = SvPV(ST(1), na);
2047
2048 memset(&stStartInfo, 0, sizeof(stStartInfo)); /* Clear the block */
2049 stStartInfo.cb = sizeof(stStartInfo); /* Set the structure size */
2050 stStartInfo.dwFlags = STARTF_USESHOWWINDOW; /* Enable wShowWindow control */
2051 stStartInfo.wShowWindow = SW_SHOWMINNOACTIVE; /* Start min (normal) */
2052
9404a519 2053 if (CreateProcess(
ad2e33dc 2054 cmd, /* Image path */
2055 args, /* Arguments for command line */
2056 NULL, /* Default process security */
2057 NULL, /* Default thread security */
2058 FALSE, /* Must be TRUE to use std handles */
2059 NORMAL_PRIORITY_CLASS, /* No special scheduling */
2060 NULL, /* Inherit our environment block */
2061 NULL, /* Inherit our currrent directory */
2062 &stStartInfo, /* -> Startup info */
2063 &stProcInfo)) /* <- Process info (if OK) */
2064 {
2065 CloseHandle(stProcInfo.hThread);/* library source code does this. */
2066 sv_setiv(ST(2), stProcInfo.dwProcessId);
2067 bSuccess = TRUE;
2068 }
2069 XSRETURN_IV(bSuccess);
2070}
2071
2072static
2073XS(w32_GetTickCount)
2074{
2075 dXSARGS;
2076 XSRETURN_IV(GetTickCount());
2077}
2078
2079static
2080XS(w32_GetShortPathName)
2081{
2082 dXSARGS;
2083 SV *shortpath;
e8bab181 2084 DWORD len;
ad2e33dc 2085
9404a519 2086 if (items != 1)
ad2e33dc 2087 croak("usage: Win32::GetShortPathName($longPathName)");
2088
2089 shortpath = sv_mortalcopy(ST(0));
2090 SvUPGRADE(shortpath, SVt_PV);
2091 /* src == target is allowed */
e8bab181 2092 do {
2093 len = GetShortPathName(SvPVX(shortpath),
2094 SvPVX(shortpath),
2095 SvLEN(shortpath));
2096 } while (len >= SvLEN(shortpath) && sv_grow(shortpath,len+1));
2097 if (len) {
2098 SvCUR_set(shortpath,len);
ad2e33dc 2099 ST(0) = shortpath;
e8bab181 2100 }
ad2e33dc 2101 else
2102 ST(0) = &sv_undef;
2103 XSRETURN(1);
2104}
2105
ad0751ec 2106static
2107XS(w32_Sleep)
2108{
2109 dXSARGS;
2110 if (items != 1)
2111 croak("usage: Win32::Sleep($milliseconds)");
2112 Sleep(SvIV(ST(0)));
2113 XSRETURN_YES;
2114}
2115
ad2e33dc 2116void
f3986ebb 2117Perl_init_os_extras()
ad2e33dc 2118{
2119 char *file = __FILE__;
2120 dXSUB_SYS;
2121
4b556e6c 2122 w32_perlshell_tokens = Nullch;
2123 w32_perlshell_items = -1;
2124 w32_fdpid = newAV(); /* XXX needs to be in Perl_win32_init()? */
2125#ifndef USE_RTL_WAIT
2126 w32_num_children = 0;
2127#endif
2128
ad2e33dc 2129 /* these names are Activeware compatible */
2130 newXS("Win32::GetCwd", w32_GetCwd, file);
2131 newXS("Win32::SetCwd", w32_SetCwd, file);
2132 newXS("Win32::GetNextAvailDrive", w32_GetNextAvailDrive, file);
2133 newXS("Win32::GetLastError", w32_GetLastError, file);
2134 newXS("Win32::LoginName", w32_LoginName, file);
2135 newXS("Win32::NodeName", w32_NodeName, file);
2136 newXS("Win32::DomainName", w32_DomainName, file);
2137 newXS("Win32::FsType", w32_FsType, file);
2138 newXS("Win32::GetOSVersion", w32_GetOSVersion, file);
2139 newXS("Win32::IsWinNT", w32_IsWinNT, file);
2140 newXS("Win32::IsWin95", w32_IsWin95, file);
2141 newXS("Win32::FormatMessage", w32_FormatMessage, file);
2142 newXS("Win32::Spawn", w32_Spawn, file);
2143 newXS("Win32::GetTickCount", w32_GetTickCount, file);
2144 newXS("Win32::GetShortPathName", w32_GetShortPathName, file);
ad0751ec 2145 newXS("Win32::Sleep", w32_Sleep, file);
ad2e33dc 2146
2147 /* XXX Bloat Alert! The following Activeware preloads really
2148 * ought to be part of Win32::Sys::*, so they're not included
2149 * here.
2150 */
2151 /* LookupAccountName
2152 * LookupAccountSID
2153 * InitiateSystemShutdown
2154 * AbortSystemShutdown
2155 * ExpandEnvrironmentStrings
2156 */
2157}
2158
2159void
2160Perl_win32_init(int *argcp, char ***argvp)
2161{
2162 /* Disable floating point errors, Perl will trap the ones we
2163 * care about. VC++ RTL defaults to switching these off
2164 * already, but the Borland RTL doesn't. Since we don't
2165 * want to be at the vendor's whim on the default, we set
2166 * it explicitly here.
2167 */
a835ef8a 2168#if !defined(_ALPHA_) && !defined(__GNUC__)
ad2e33dc 2169 _control87(MCW_EM, MCW_EM);
3dc9191e 2170#endif
4b556e6c 2171 MALLOC_INIT;
ad2e33dc 2172}
d55594ae 2173
a868473f 2174#ifdef USE_BINMODE_SCRIPTS
2175
2176void
2177win32_strip_return(SV *sv)
2178{
2179 char *s = SvPVX(sv);
2180 char *e = s+SvCUR(sv);
2181 char *d = s;
2182 while (s < e)
2183 {
2184 if (*s == '\r' && s[1] == '\n')
2185 {
2186 *d++ = '\n';
2187 s += 2;
2188 }
2189 else
2190 {
2191 *d++ = *s++;
2192 }
2193 }
2194 SvCUR_set(sv,d-SvPVX(sv));
2195}
2196
2197#endif