win32 tweaks
[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>
14#include <windows.h>
15
68dc0745 16/* #include "config.h" */
0a753a76 17
18#define PERLIO_NOT_STDIO 0
19#if !defined(PERLIO_IS_STDIO) && !defined(USE_SFIO)
20#define PerlIO FILE
21#endif
22
23#include "EXTERN.h"
24#include "perl.h"
ad2e33dc 25#include "XSUB.h"
0a753a76 26#include <fcntl.h>
27#include <sys/stat.h>
28#include <assert.h>
29#include <string.h>
30#include <stdarg.h>
ad2e33dc 31#include <float.h>
0a753a76 32
33#define CROAK croak
34#define WARN warn
35
6890e559 36#define EXECF_EXEC 1
37#define EXECF_SPAWN 2
38#define EXECF_SPAWN_NOWAIT 3
39
8b10511d 40static DWORD IdOS(void);
41
0a753a76 42extern WIN32_IOSUBSYSTEM win32stdio;
4dd614da 43static PWIN32_IOSUBSYSTEM pIOSubSystem = &win32stdio;
0a753a76 44
45BOOL ProbeEnv = FALSE;
8b10511d 46DWORD Win32System = (DWORD)-1;
0a753a76 47char szShellPath[MAX_PATH+1];
48char szPerlLibRoot[MAX_PATH+1];
49HANDLE PerlDllHandle = INVALID_HANDLE_VALUE;
50
6890e559 51static int do_spawn2(char *cmd, int exectype);
52
3fe9a6f1 53int
54IsWin95(void) {
8b10511d 55 return (IdOS() == VER_PLATFORM_WIN32_WINDOWS);
3fe9a6f1 56}
57
58int
59IsWinNT(void) {
8b10511d 60 return (IdOS() == VER_PLATFORM_WIN32_NT);
3fe9a6f1 61}
0a753a76 62
68dc0745 63void *
64SetIOSubSystem(void *p)
0a753a76 65{
137443ea 66 PWIN32_IOSUBSYSTEM old = pIOSubSystem;
68dc0745 67 if (p) {
68 PWIN32_IOSUBSYSTEM pio = (PWIN32_IOSUBSYSTEM)p;
68dc0745 69 if (pio->signature_begin == 12345678L
70 && pio->signature_end == 87654321L) {
68dc0745 71 pIOSubSystem = pio;
68dc0745 72 }
73 }
74 else {
137443ea 75 pIOSubSystem = &win32stdio;
68dc0745 76 }
137443ea 77 return old;
68dc0745 78}
79
80char *
81win32PerlLibPath(void)
82{
83 char *end;
84 GetModuleFileName((PerlDllHandle == INVALID_HANDLE_VALUE)
85 ? GetModuleHandle(NULL)
86 : PerlDllHandle,
87 szPerlLibRoot,
88 sizeof(szPerlLibRoot));
89
90 *(end = strrchr(szPerlLibRoot, '\\')) = '\0';
91 if (stricmp(end-4,"\\bin") == 0)
92 end -= 4;
93 strcpy(end,"\\lib");
94 return (szPerlLibRoot);
95}
0a753a76 96
b4793f7f 97char *
98win32SiteLibPath(void)
99{
2bc71ef8 100 static char szPerlSiteLib[MAX_PATH+1];
b4793f7f 101 strcpy(szPerlSiteLib, win32PerlLibPath());
102 strcat(szPerlSiteLib, "\\site");
103 return (szPerlSiteLib);
104}
105
68dc0745 106BOOL
107HasRedirection(char *ptr)
108{
109 int inquote = 0;
110 char quote = '\0';
111
112 /*
113 * Scan string looking for redirection (< or >) or pipe
114 * characters (|) that are not in a quoted string
115 */
116 while(*ptr) {
117 switch(*ptr) {
118 case '\'':
119 case '\"':
120 if(inquote) {
121 if(quote == *ptr) {
122 inquote = 0;
123 quote = '\0';
0a753a76 124 }
68dc0745 125 }
126 else {
127 quote = *ptr;
128 inquote++;
129 }
130 break;
131 case '>':
132 case '<':
133 case '|':
134 if(!inquote)
135 return TRUE;
136 default:
137 break;
0a753a76 138 }
68dc0745 139 ++ptr;
140 }
141 return FALSE;
0a753a76 142}
143
68dc0745 144/* since the current process environment is being updated in util.c
145 * the library functions will get the correct environment
146 */
147PerlIO *
148my_popen(char *cmd, char *mode)
0a753a76 149{
150#ifdef FIXCMD
68dc0745 151#define fixcmd(x) { \
152 char *pspace = strchr((x),' '); \
153 if (pspace) { \
154 char *p = (x); \
155 while (p < pspace) { \
156 if (*p == '/') \
157 *p = '\\'; \
158 p++; \
159 } \
160 } \
161 }
0a753a76 162#else
163#define fixcmd(x)
164#endif
68dc0745 165
166#if 1
167/* was #ifndef PERLDLL, but the #else stuff doesn't work on NT
168 * GSAR 97/03/13
169 */
170 fixcmd(cmd);
3e3baf6d 171#ifdef __BORLANDC__ /* workaround a Borland stdio bug */
172 win32_fflush(stdout);
173 win32_fflush(stderr);
174#endif
0a753a76 175 return win32_popen(cmd, mode);
176#else
177/*
178 * There seems to be some problems for the _popen call in a DLL
179 * this trick at the moment seems to work but it is never test
180 * on NT yet
181 *
182 */
183# ifdef __cplusplus
184#define EXT_C_FUNC extern "C"
185# else
186#define EXT_C_FUNC extern
187# endif
188
68dc0745 189 EXT_C_FUNC int __cdecl _set_osfhnd(int fh, long value);
190 EXT_C_FUNC void __cdecl _lock_fhandle(int);
191 EXT_C_FUNC void __cdecl _unlock_fhandle(int);
192
193 BOOL fSuccess;
194 PerlIO *pf; /* to store the _popen return value */
195 int tm = 0; /* flag indicating tDllExport or binary mode */
196 int fhNeeded, fhInherited, fhDup;
197 int ineeded, iinherited;
198 DWORD dwDup;
199 int phdls[2]; /* I/O handles for pipe */
200 HANDLE hPIn, hPOut, hPErr,
201 hSaveStdin, hSaveStdout, hSaveStderr,
202 hPNeeded, hPInherited, hPDuped;
0a753a76 203
68dc0745 204 /* first check for errors in the arguments */
205 if ( (cmd == NULL) || (mode == NULL)
206 || ((*mode != 'w') && (*mode != _T('r'))) )
207 goto error1;
0a753a76 208
209 if ( *(mode + 1) == _T('t') )
3e3baf6d 210 tm = O_TEXT;
0a753a76 211 else if ( *(mode + 1) == _T('b') )
3e3baf6d 212 tm = O_BINARY;
68dc0745 213 else
3e3baf6d 214 tm = (*mode == 'w' ? O_BINARY : O_TEXT);
0a753a76 215
216
68dc0745 217 fixcmd(cmd);
218 if (&win32stdio != pIOSubSystem)
219 return win32_popen(cmd, mode);
0a753a76 220
221#ifdef EFG
222 if ( _pipe( phdls, 1024, tm ) == -1 )
223#else
224 if ( win32_pipe( phdls, 1024, tm ) == -1 )
225#endif
68dc0745 226 goto error1;
227
228 /* save the current situation */
229 hSaveStdin = GetStdHandle(STD_INPUT_HANDLE);
230 hSaveStdout = GetStdHandle(STD_OUTPUT_HANDLE);
231 hSaveStderr = GetStdHandle(STD_ERROR_HANDLE);
232
233 if (*mode == _T('w')) {
234 ineeded = 1;
235 dwDup = STD_INPUT_HANDLE;
236 iinherited = 0;
237 }
238 else {
239 ineeded = 0;
240 dwDup = STD_OUTPUT_HANDLE;
241 iinherited = 1;
242 }
243
244 fhNeeded = phdls[ineeded];
245 fhInherited = phdls[iinherited];
246
247 fSuccess = DuplicateHandle(GetCurrentProcess(),
248 (HANDLE) stolen_get_osfhandle(fhNeeded),
249 GetCurrentProcess(),
250 &hPNeeded,
251 0,
252 FALSE, /* not inherited */
253 DUPLICATE_SAME_ACCESS);
254
255 if (!fSuccess)
256 goto error2;
257
258 fhDup = stolen_open_osfhandle((long) hPNeeded, tm);
259 win32_dup2(fhDup, fhNeeded);
260 win32_close(fhDup);
0a753a76 261
262#ifdef AAA
68dc0745 263 /* Close the Out pipe, child won't need it */
264 hPDuped = (HANDLE) stolen_get_osfhandle(fhNeeded);
0a753a76 265
68dc0745 266 _lock_fhandle(fhNeeded);
267 _set_osfhnd(fhNeeded, (long)hPNeeded); /* put in ours duplicated one */
268 _unlock_fhandle(fhNeeded);
0a753a76 269
68dc0745 270 CloseHandle(hPDuped); /* close the handle first */
0a753a76 271#endif
272
68dc0745 273 if (!SetStdHandle(dwDup, (HANDLE) stolen_get_osfhandle(fhInherited)))
274 goto error2;
0a753a76 275
68dc0745 276 /*
277 * make sure the child see the same stderr as the calling program
278 */
279 if (!SetStdHandle(STD_ERROR_HANDLE,
280 (HANDLE)stolen_get_osfhandle(win32_fileno(win32_stderr()))))
281 goto error2;
0a753a76 282
68dc0745 283 pf = win32_popen(cmd, mode); /* ask _popen to do the job */
0a753a76 284
68dc0745 285 /* restore to where we were */
0a753a76 286 SetStdHandle(STD_INPUT_HANDLE, hSaveStdin);
287 SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdout);
288 SetStdHandle(STD_ERROR_HANDLE, hSaveStderr);
289
68dc0745 290 /* we don't need it any more, that's for the child */
291 win32_close(fhInherited);
0a753a76 292
68dc0745 293 if (NULL == pf) {
294 /* something wrong */
295 win32_close(fhNeeded);
296 goto error1;
297 }
298 else {
299 /*
300 * here we steal the file handle in pf and stuff ours in
301 */
302 win32_dup2(fhNeeded, win32_fileno(pf));
303 win32_close(fhNeeded);
304 }
305 return (pf);
0a753a76 306
307error2:
68dc0745 308 win32_close(fhNeeded);
309 win32_close(fhInherited);
0a753a76 310
311error1:
68dc0745 312 return (NULL);
0a753a76 313
314#endif
315}
316
68dc0745 317long
318my_pclose(PerlIO *fp)
0a753a76 319{
320 return win32_pclose(fp);
321}
322
8b10511d 323static DWORD
68dc0745 324IdOS(void)
0a753a76 325{
8b10511d 326 static OSVERSIONINFO osver;
0a753a76 327
8b10511d 328 if (osver.dwPlatformId != Win32System) {
329 memset(&osver, 0, sizeof(OSVERSIONINFO));
330 osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
331 GetVersionEx(&osver);
332 Win32System = osver.dwPlatformId;
333 }
334 return (Win32System);
0a753a76 335}
336
68dc0745 337static char *
338GetShell(void)
0a753a76 339{
68dc0745 340 if (!ProbeEnv) {
174c211a 341 char* defaultshell = (IsWinNT() ? "cmd.exe" : "command.com");
342 /* we don't use COMSPEC here for two reasons:
343 * 1. the same reason perl on UNIX doesn't use SHELL--rampant and
344 * uncontrolled unportability of the ensuing scripts.
345 * 2. PERL5SHELL could be set to a shell that may not be fit for
346 * interactive use (which is what most programs look in COMSPEC
347 * for).
348 */
349 char *usershell = getenv("PERL5SHELL");
350
8b10511d 351 ProbeEnv = TRUE;
174c211a 352 strcpy(szShellPath, usershell ? usershell : defaultshell);
68dc0745 353 }
354 return szShellPath;
0a753a76 355}
356
68dc0745 357int
358do_aspawn(void* really, void** mark, void** arglast)
0a753a76 359{
68dc0745 360 char **argv;
361 char *strPtr;
362 char *cmd;
363 int status;
364 unsigned int length;
365 int index = 0;
0a753a76 366 SV *sv = (SV*)really;
68dc0745 367 SV** pSv = (SV**)mark;
368
fc36a67e 369 New(1310, argv, (arglast - mark) + 4, char*);
68dc0745 370
371 if(sv != Nullsv) {
372 cmd = SvPV(sv, length);
373 }
374 else {
3fe9a6f1 375 argv[index++] = cmd = GetShell();
376 argv[index++] = "/x"; /* always enable command extensions */
68dc0745 377 argv[index++] = "/c";
378 }
379
5aabfad6 380 while(++pSv <= (SV**)arglast) {
381 sv = *pSv;
68dc0745 382 strPtr = SvPV(sv, length);
383 if(strPtr != NULL && *strPtr != '\0')
384 argv[index++] = strPtr;
385 }
386 argv[index++] = 0;
387
3e3baf6d 388 status = win32_spawnvp(P_WAIT, cmd, (const char* const*)argv);
68dc0745 389
390 Safefree(argv);
391
5aabfad6 392 if (status < 0) {
393 if (dowarn)
394 warn("Can't spawn \"%s\": %s", cmd, strerror(errno));
395 status = 255 << 8;
396 }
397 return (status);
68dc0745 398}
399
400int
6890e559 401do_spawn2(char *cmd, int exectype)
68dc0745 402{
403 char **a;
404 char *s;
405 char **argv;
406 int status = -1;
407 BOOL needToTry = TRUE;
408 char *shell, *cmd2;
409
410 /* save an extra exec if possible */
411 shell = GetShell();
412
413 /* see if there are shell metacharacters in it */
414 if(!HasRedirection(cmd)) {
fc36a67e 415 New(1301,argv, strlen(cmd) / 2 + 2, char*);
416 New(1302,cmd2, strlen(cmd) + 1, char);
68dc0745 417 strcpy(cmd2, cmd);
418 a = argv;
419 for (s = cmd2; *s;) {
420 while (*s && isspace(*s))
421 s++;
422 if (*s)
423 *(a++) = s;
424 while(*s && !isspace(*s))
425 s++;
426 if(*s)
427 *s++ = '\0';
0a753a76 428 }
68dc0745 429 *a = Nullch;
430 if(argv[0]) {
6890e559 431 switch (exectype) {
432 case EXECF_SPAWN:
433 status = win32_spawnvp(P_WAIT, argv[0],
434 (const char* const*)argv);
435 break;
436 case EXECF_SPAWN_NOWAIT:
437 status = win32_spawnvp(P_NOWAIT, argv[0],
438 (const char* const*)argv);
439 break;
440 case EXECF_EXEC:
441 status = win32_execvp(argv[0], (const char* const*)argv);
442 break;
443 }
68dc0745 444 if(status != -1 || errno == 0)
445 needToTry = FALSE;
0a753a76 446 }
0a753a76 447 Safefree(argv);
68dc0745 448 Safefree(cmd2);
449 }
450 if(needToTry) {
3e3baf6d 451 char *argv[5];
452 argv[0] = shell; argv[1] = "/x"; argv[2] = "/c";
453 argv[3] = cmd; argv[4] = Nullch;
6890e559 454 switch (exectype) {
455 case EXECF_SPAWN:
456 status = win32_spawnvp(P_WAIT, argv[0],
457 (const char* const*)argv);
458 break;
459 case EXECF_SPAWN_NOWAIT:
460 status = win32_spawnvp(P_NOWAIT, argv[0],
461 (const char* const*)argv);
462 break;
463 case EXECF_EXEC:
464 status = win32_execvp(argv[0], (const char* const*)argv);
465 break;
466 }
68dc0745 467 }
5aabfad6 468 if (status < 0) {
469 if (dowarn)
6890e559 470 warn("Can't %s \"%s\": %s",
471 (exectype == EXECF_EXEC ? "exec" : "spawn"),
472 needToTry ? shell : argv[0],
5aabfad6 473 strerror(errno));
474 status = 255 << 8;
475 }
476 return (status);
0a753a76 477}
478
6890e559 479int
480do_spawn(char *cmd)
481{
482 return do_spawn2(cmd, EXECF_SPAWN);
483}
484
485bool
486do_exec(char *cmd)
487{
488 do_spawn2(cmd, EXECF_EXEC);
489 return FALSE;
490}
491
0a753a76 492
493#define PATHLEN 1024
494
68dc0745 495/* The idea here is to read all the directory names into a string table
496 * (separated by nulls) and when one of the other dir functions is called
497 * return the pointer to the current file name.
498 */
499DIR *
500opendir(char *filename)
0a753a76 501{
502 DIR *p;
68dc0745 503 long len;
504 long idx;
505 char scannamespc[PATHLEN];
506 char *scanname = scannamespc;
507 struct stat sbuf;
508 WIN32_FIND_DATA FindData;
509 HANDLE fh;
510/* char root[_MAX_PATH];*/
511/* char volname[_MAX_PATH];*/
512/* DWORD serial, maxname, flags;*/
513/* BOOL downcase;*/
514/* char *dummy;*/
515
516 /* check to see if filename is a directory */
3e3baf6d 517 if(stat(filename, &sbuf) < 0 || sbuf.st_mode & S_IFDIR == 0) {
68dc0745 518 return NULL;
519 }
520
521 /* get the file system characteristics */
522/* if(GetFullPathName(filename, MAX_PATH, root, &dummy)) {
523 * if(dummy = strchr(root, '\\'))
524 * *++dummy = '\0';
525 * if(GetVolumeInformation(root, volname, MAX_PATH, &serial,
526 * &maxname, &flags, 0, 0)) {
527 * downcase = !(flags & FS_CASE_IS_PRESERVED);
528 * }
529 * }
530 * else {
531 * downcase = TRUE;
532 * }
533 */
534 /* Get us a DIR structure */
fc36a67e 535 Newz(1303, p, 1, DIR);
68dc0745 536 if(p == NULL)
537 return NULL;
538
539 /* Create the search pattern */
540 strcpy(scanname, filename);
541
542 if(index("/\\", *(scanname + strlen(scanname) - 1)) == NULL)
543 strcat(scanname, "/*");
544 else
545 strcat(scanname, "*");
546
547 /* do the FindFirstFile call */
548 fh = FindFirstFile(scanname, &FindData);
549 if(fh == INVALID_HANDLE_VALUE) {
550 return NULL;
551 }
552
553 /* now allocate the first part of the string table for
554 * the filenames that we find.
555 */
556 idx = strlen(FindData.cFileName)+1;
fc36a67e 557 New(1304, p->start, idx, char);
68dc0745 558 if(p->start == NULL) {
559 CROAK("opendir: malloc failed!\n");
560 }
561 strcpy(p->start, FindData.cFileName);
562/* if(downcase)
563 * strlwr(p->start);
564 */
565 p->nfiles++;
566
567 /* loop finding all the files that match the wildcard
568 * (which should be all of them in this directory!).
569 * the variable idx should point one past the null terminator
570 * of the previous string found.
571 */
572 while (FindNextFile(fh, &FindData)) {
573 len = strlen(FindData.cFileName);
574 /* bump the string table size by enough for the
575 * new name and it's null terminator
576 */
577 Renew(p->start, idx+len+1, char);
578 if(p->start == NULL) {
579 CROAK("opendir: malloc failed!\n");
0a753a76 580 }
68dc0745 581 strcpy(&p->start[idx], FindData.cFileName);
582/* if (downcase)
583 * strlwr(&p->start[idx]);
584 */
0a753a76 585 p->nfiles++;
586 idx += len+1;
587 }
588 FindClose(fh);
589 p->size = idx;
590 p->curr = p->start;
591 return p;
592}
593
594
68dc0745 595/* Readdir just returns the current string pointer and bumps the
596 * string pointer to the nDllExport entry.
597 */
598struct direct *
599readdir(DIR *dirp)
0a753a76 600{
68dc0745 601 int len;
602 static int dummy = 0;
0a753a76 603
68dc0745 604 if (dirp->curr) {
605 /* first set up the structure to return */
606 len = strlen(dirp->curr);
607 strcpy(dirp->dirstr.d_name, dirp->curr);
608 dirp->dirstr.d_namlen = len;
0a753a76 609
68dc0745 610 /* Fake an inode */
611 dirp->dirstr.d_ino = dummy++;
0a753a76 612
68dc0745 613 /* Now set up for the nDllExport call to readdir */
614 dirp->curr += len + 1;
615 if (dirp->curr >= (dirp->start + dirp->size)) {
616 dirp->curr = NULL;
617 }
0a753a76 618
68dc0745 619 return &(dirp->dirstr);
620 }
621 else
622 return NULL;
0a753a76 623}
624
68dc0745 625/* Telldir returns the current string pointer position */
626long
627telldir(DIR *dirp)
0a753a76 628{
629 return (long) dirp->curr;
630}
631
632
68dc0745 633/* Seekdir moves the string pointer to a previously saved position
634 *(Saved by telldir).
635 */
636void
637seekdir(DIR *dirp, long loc)
0a753a76 638{
639 dirp->curr = (char *)loc;
640}
641
68dc0745 642/* Rewinddir resets the string pointer to the start */
643void
644rewinddir(DIR *dirp)
0a753a76 645{
646 dirp->curr = dirp->start;
647}
648
68dc0745 649/* free the memory allocated by opendir */
650int
651closedir(DIR *dirp)
0a753a76 652{
653 Safefree(dirp->start);
654 Safefree(dirp);
68dc0745 655 return 1;
0a753a76 656}
657
658
68dc0745 659/*
660 * various stubs
661 */
0a753a76 662
663
68dc0745 664/* Ownership
665 *
666 * Just pretend that everyone is a superuser. NT will let us know if
667 * we don\'t really have permission to do something.
668 */
0a753a76 669
670#define ROOT_UID ((uid_t)0)
671#define ROOT_GID ((gid_t)0)
672
68dc0745 673uid_t
674getuid(void)
0a753a76 675{
68dc0745 676 return ROOT_UID;
0a753a76 677}
678
68dc0745 679uid_t
680geteuid(void)
0a753a76 681{
68dc0745 682 return ROOT_UID;
0a753a76 683}
684
68dc0745 685gid_t
686getgid(void)
0a753a76 687{
68dc0745 688 return ROOT_GID;
0a753a76 689}
690
68dc0745 691gid_t
692getegid(void)
0a753a76 693{
68dc0745 694 return ROOT_GID;
0a753a76 695}
696
68dc0745 697int
698setuid(uid_t uid)
0a753a76 699{
68dc0745 700 return (uid == ROOT_UID ? 0 : -1);
0a753a76 701}
702
68dc0745 703int
704setgid(gid_t gid)
0a753a76 705{
68dc0745 706 return (gid == ROOT_GID ? 0 : -1);
0a753a76 707}
708
68dc0745 709/*
710 * pretended kill
711 */
712int
713kill(int pid, int sig)
0a753a76 714{
68dc0745 715 HANDLE hProcess= OpenProcess(PROCESS_ALL_ACCESS, TRUE, pid);
0a753a76 716
717 if (hProcess == NULL) {
68dc0745 718 CROAK("kill process failed!\n");
719 }
720 else {
721 if (!TerminateProcess(hProcess, sig))
722 CROAK("kill process failed!\n");
723 CloseHandle(hProcess);
724 }
725 return 0;
0a753a76 726}
727
68dc0745 728/*
729 * File system stuff
730 */
0a753a76 731
3e3baf6d 732#if 0
68dc0745 733int
734ioctl(int i, unsigned int u, char *data)
0a753a76 735{
68dc0745 736 CROAK("ioctl not implemented!\n");
737 return -1;
0a753a76 738}
3e3baf6d 739#endif
0a753a76 740
68dc0745 741unsigned int
742sleep(unsigned int t)
0a753a76 743{
68dc0745 744 Sleep(t*1000);
745 return 0;
0a753a76 746}
747
748
749#undef rename
750
68dc0745 751int
752myrename(char *OldFileName, char *newname)
0a753a76 753{
68dc0745 754 if(_access(newname, 0) != -1) { /* file exists */
755 _unlink(newname);
756 }
757 return rename(OldFileName, newname);
0a753a76 758}
759
760
68dc0745 761DllExport int
762win32_stat(const char *path, struct stat *buffer)
0a753a76 763{
68dc0745 764 char t[MAX_PATH];
765 const char *p = path;
766 int l = strlen(path);
0a753a76 767
68dc0745 768 if (l > 1) {
769 switch(path[l - 1]) {
770 case '\\':
771 case '/':
772 if (path[l - 2] != ':') {
773 strncpy(t, path, l - 1);
774 t[l - 1] = 0;
775 p = t;
776 };
777 }
778 }
779 return stat(p, buffer);
0a753a76 780}
781
0551aaa8 782#ifndef USE_WIN32_RTL_ENV
783
784DllExport char *
785win32_getenv(const char *name)
786{
787 static char *curitem = Nullch;
788 static DWORD curlen = 512;
789 DWORD needlen;
790 if (!curitem)
791 New(1305,curitem,curlen,char);
792 if (!(needlen = GetEnvironmentVariable(name,curitem,curlen)))
793 return Nullch;
794 while (needlen > curlen) {
795 Renew(curitem,needlen,char);
796 curlen = needlen;
797 needlen = GetEnvironmentVariable(name,curitem,curlen);
798 }
799 return curitem;
800}
801
802#endif
803
0a753a76 804#undef times
68dc0745 805int
806mytimes(struct tms *timebuf)
0a753a76 807{
68dc0745 808 clock_t t = clock();
809 timebuf->tms_utime = t;
810 timebuf->tms_stime = 0;
811 timebuf->tms_cutime = 0;
812 timebuf->tms_cstime = 0;
0a753a76 813
68dc0745 814 return 0;
0a753a76 815}
816
817#undef alarm
68dc0745 818unsigned int
819myalarm(unsigned int sec)
0a753a76 820{
68dc0745 821 /* we warn the usuage of alarm function */
822 if (sec != 0)
823 WARN("dummy function alarm called, program might not function as expected\n");
824 return 0;
0a753a76 825}
826
68dc0745 827/*
828 * redirected io subsystem for all XS modules
829 *
830 */
0a753a76 831
68dc0745 832DllExport int *
833win32_errno(void)
0a753a76 834{
68dc0745 835 return (pIOSubSystem->pfnerrno());
0a753a76 836}
837
dcb2879a 838DllExport char ***
839win32_environ(void)
840{
841 return (pIOSubSystem->pfnenviron());
842}
843
68dc0745 844/* the rest are the remapped stdio routines */
845DllExport FILE *
846win32_stderr(void)
0a753a76 847{
68dc0745 848 return (pIOSubSystem->pfnstderr());
0a753a76 849}
850
68dc0745 851DllExport FILE *
852win32_stdin(void)
0a753a76 853{
68dc0745 854 return (pIOSubSystem->pfnstdin());
0a753a76 855}
856
68dc0745 857DllExport FILE *
858win32_stdout()
0a753a76 859{
68dc0745 860 return (pIOSubSystem->pfnstdout());
0a753a76 861}
862
68dc0745 863DllExport int
864win32_ferror(FILE *fp)
0a753a76 865{
68dc0745 866 return (pIOSubSystem->pfnferror(fp));
0a753a76 867}
868
869
68dc0745 870DllExport int
871win32_feof(FILE *fp)
0a753a76 872{
68dc0745 873 return (pIOSubSystem->pfnfeof(fp));
0a753a76 874}
875
68dc0745 876/*
877 * Since the errors returned by the socket error function
878 * WSAGetLastError() are not known by the library routine strerror
879 * we have to roll our own.
880 */
0a753a76 881
882__declspec(thread) char strerror_buffer[512];
883
68dc0745 884DllExport char *
885win32_strerror(int e)
0a753a76 886{
3e3baf6d 887#ifndef __BORLANDC__ /* Borland intolerance */
68dc0745 888 extern int sys_nerr;
3e3baf6d 889#endif
68dc0745 890 DWORD source = 0;
0a753a76 891
68dc0745 892 if(e < 0 || e > sys_nerr) {
893 if(e < 0)
894 e = GetLastError();
0a753a76 895
68dc0745 896 if(FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, &source, e, 0,
897 strerror_buffer, sizeof(strerror_buffer), NULL) == 0)
898 strcpy(strerror_buffer, "Unknown Error");
0a753a76 899
68dc0745 900 return strerror_buffer;
901 }
902 return pIOSubSystem->pfnstrerror(e);
0a753a76 903}
904
68dc0745 905DllExport int
906win32_fprintf(FILE *fp, const char *format, ...)
0a753a76 907{
68dc0745 908 va_list marker;
909 va_start(marker, format); /* Initialize variable arguments. */
0a753a76 910
68dc0745 911 return (pIOSubSystem->pfnvfprintf(fp, format, marker));
0a753a76 912}
913
68dc0745 914DllExport int
915win32_printf(const char *format, ...)
0a753a76 916{
68dc0745 917 va_list marker;
918 va_start(marker, format); /* Initialize variable arguments. */
0a753a76 919
68dc0745 920 return (pIOSubSystem->pfnvprintf(format, marker));
0a753a76 921}
922
68dc0745 923DllExport int
924win32_vfprintf(FILE *fp, const char *format, va_list args)
0a753a76 925{
68dc0745 926 return (pIOSubSystem->pfnvfprintf(fp, format, args));
0a753a76 927}
928
96e4d5b1 929DllExport int
930win32_vprintf(const char *format, va_list args)
931{
932 return (pIOSubSystem->pfnvprintf(format, args));
933}
934
68dc0745 935DllExport size_t
936win32_fread(void *buf, size_t size, size_t count, FILE *fp)
0a753a76 937{
68dc0745 938 return pIOSubSystem->pfnfread(buf, size, count, fp);
0a753a76 939}
940
68dc0745 941DllExport size_t
942win32_fwrite(const void *buf, size_t size, size_t count, FILE *fp)
0a753a76 943{
68dc0745 944 return pIOSubSystem->pfnfwrite(buf, size, count, fp);
0a753a76 945}
946
68dc0745 947DllExport FILE *
948win32_fopen(const char *filename, const char *mode)
0a753a76 949{
68dc0745 950 if (stricmp(filename, "/dev/null")==0)
951 return pIOSubSystem->pfnfopen("NUL", mode);
952 return pIOSubSystem->pfnfopen(filename, mode);
0a753a76 953}
954
68dc0745 955DllExport FILE *
956win32_fdopen( int handle, const char *mode)
0a753a76 957{
68dc0745 958 return pIOSubSystem->pfnfdopen(handle, mode);
0a753a76 959}
960
68dc0745 961DllExport FILE *
962win32_freopen( const char *path, const char *mode, FILE *stream)
0a753a76 963{
68dc0745 964 if (stricmp(path, "/dev/null")==0)
965 return pIOSubSystem->pfnfreopen("NUL", mode, stream);
966 return pIOSubSystem->pfnfreopen(path, mode, stream);
0a753a76 967}
968
68dc0745 969DllExport int
970win32_fclose(FILE *pf)
0a753a76 971{
68dc0745 972 return pIOSubSystem->pfnfclose(pf);
0a753a76 973}
974
68dc0745 975DllExport int
976win32_fputs(const char *s,FILE *pf)
0a753a76 977{
68dc0745 978 return pIOSubSystem->pfnfputs(s, pf);
0a753a76 979}
980
68dc0745 981DllExport int
982win32_fputc(int c,FILE *pf)
0a753a76 983{
68dc0745 984 return pIOSubSystem->pfnfputc(c,pf);
0a753a76 985}
986
68dc0745 987DllExport int
988win32_ungetc(int c,FILE *pf)
0a753a76 989{
68dc0745 990 return pIOSubSystem->pfnungetc(c,pf);
0a753a76 991}
992
68dc0745 993DllExport int
994win32_getc(FILE *pf)
0a753a76 995{
68dc0745 996 return pIOSubSystem->pfngetc(pf);
0a753a76 997}
998
68dc0745 999DllExport int
1000win32_fileno(FILE *pf)
0a753a76 1001{
68dc0745 1002 return pIOSubSystem->pfnfileno(pf);
0a753a76 1003}
1004
68dc0745 1005DllExport void
1006win32_clearerr(FILE *pf)
0a753a76 1007{
68dc0745 1008 pIOSubSystem->pfnclearerr(pf);
1009 return;
0a753a76 1010}
1011
68dc0745 1012DllExport int
1013win32_fflush(FILE *pf)
0a753a76 1014{
68dc0745 1015 return pIOSubSystem->pfnfflush(pf);
0a753a76 1016}
1017
68dc0745 1018DllExport long
1019win32_ftell(FILE *pf)
0a753a76 1020{
68dc0745 1021 return pIOSubSystem->pfnftell(pf);
0a753a76 1022}
1023
68dc0745 1024DllExport int
1025win32_fseek(FILE *pf,long offset,int origin)
0a753a76 1026{
68dc0745 1027 return pIOSubSystem->pfnfseek(pf, offset, origin);
0a753a76 1028}
1029
68dc0745 1030DllExport int
1031win32_fgetpos(FILE *pf,fpos_t *p)
0a753a76 1032{
68dc0745 1033 return pIOSubSystem->pfnfgetpos(pf, p);
0a753a76 1034}
1035
68dc0745 1036DllExport int
1037win32_fsetpos(FILE *pf,const fpos_t *p)
0a753a76 1038{
68dc0745 1039 return pIOSubSystem->pfnfsetpos(pf, p);
0a753a76 1040}
1041
68dc0745 1042DllExport void
1043win32_rewind(FILE *pf)
0a753a76 1044{
68dc0745 1045 pIOSubSystem->pfnrewind(pf);
1046 return;
0a753a76 1047}
1048
68dc0745 1049DllExport FILE*
1050win32_tmpfile(void)
0a753a76 1051{
68dc0745 1052 return pIOSubSystem->pfntmpfile();
0a753a76 1053}
1054
68dc0745 1055DllExport void
1056win32_abort(void)
0a753a76 1057{
68dc0745 1058 pIOSubSystem->pfnabort();
1059 return;
0a753a76 1060}
1061
68dc0745 1062DllExport int
1063win32_fstat(int fd,struct stat *bufptr)
0a753a76 1064{
68dc0745 1065 return pIOSubSystem->pfnfstat(fd,bufptr);
0a753a76 1066}
1067
68dc0745 1068DllExport int
1069win32_pipe(int *pfd, unsigned int size, int mode)
0a753a76 1070{
68dc0745 1071 return pIOSubSystem->pfnpipe(pfd, size, mode);
0a753a76 1072}
1073
68dc0745 1074DllExport FILE*
1075win32_popen(const char *command, const char *mode)
0a753a76 1076{
68dc0745 1077 return pIOSubSystem->pfnpopen(command, mode);
0a753a76 1078}
1079
68dc0745 1080DllExport int
1081win32_pclose(FILE *pf)
0a753a76 1082{
68dc0745 1083 return pIOSubSystem->pfnpclose(pf);
0a753a76 1084}
1085
68dc0745 1086DllExport int
1087win32_setmode(int fd, int mode)
0a753a76 1088{
68dc0745 1089 return pIOSubSystem->pfnsetmode(fd, mode);
0a753a76 1090}
1091
96e4d5b1 1092DllExport long
1093win32_lseek(int fd, long offset, int origin)
1094{
1095 return pIOSubSystem->pfnlseek(fd, offset, origin);
1096}
1097
1098DllExport long
1099win32_tell(int fd)
1100{
1101 return pIOSubSystem->pfntell(fd);
1102}
1103
68dc0745 1104DllExport int
1105win32_open(const char *path, int flag, ...)
0a753a76 1106{
68dc0745 1107 va_list ap;
1108 int pmode;
0a753a76 1109
1110 va_start(ap, flag);
1111 pmode = va_arg(ap, int);
1112 va_end(ap);
1113
68dc0745 1114 if (stricmp(path, "/dev/null")==0)
1115 return pIOSubSystem->pfnopen("NUL", flag, pmode);
1116 return pIOSubSystem->pfnopen(path,flag,pmode);
0a753a76 1117}
1118
68dc0745 1119DllExport int
1120win32_close(int fd)
0a753a76 1121{
68dc0745 1122 return pIOSubSystem->pfnclose(fd);
0a753a76 1123}
1124
68dc0745 1125DllExport int
96e4d5b1 1126win32_eof(int fd)
1127{
1128 return pIOSubSystem->pfneof(fd);
1129}
1130
1131DllExport int
68dc0745 1132win32_dup(int fd)
0a753a76 1133{
68dc0745 1134 return pIOSubSystem->pfndup(fd);
0a753a76 1135}
1136
68dc0745 1137DllExport int
1138win32_dup2(int fd1,int fd2)
0a753a76 1139{
68dc0745 1140 return pIOSubSystem->pfndup2(fd1,fd2);
0a753a76 1141}
1142
68dc0745 1143DllExport int
3e3baf6d 1144win32_read(int fd, void *buf, unsigned int cnt)
0a753a76 1145{
68dc0745 1146 return pIOSubSystem->pfnread(fd, buf, cnt);
0a753a76 1147}
1148
68dc0745 1149DllExport int
3e3baf6d 1150win32_write(int fd, const void *buf, unsigned int cnt)
0a753a76 1151{
68dc0745 1152 return pIOSubSystem->pfnwrite(fd, buf, cnt);
0a753a76 1153}
1154
68dc0745 1155DllExport int
5aabfad6 1156win32_mkdir(const char *dir, int mode)
1157{
1158 return pIOSubSystem->pfnmkdir(dir); /* just ignore mode */
1159}
96e4d5b1 1160
5aabfad6 1161DllExport int
1162win32_rmdir(const char *dir)
1163{
1164 return pIOSubSystem->pfnrmdir(dir);
1165}
96e4d5b1 1166
5aabfad6 1167DllExport int
1168win32_chdir(const char *dir)
1169{
1170 return pIOSubSystem->pfnchdir(dir);
1171}
96e4d5b1 1172
5aabfad6 1173DllExport int
3e3baf6d 1174win32_spawnvp(int mode, const char *cmdname, const char *const *argv)
0a753a76 1175{
3e3baf6d 1176 return pIOSubSystem->pfnspawnvp(mode, cmdname, argv);
0a753a76 1177}
1178
6890e559 1179DllExport int
1180win32_execvp(const char *cmdname, const char *const *argv)
1181{
1182 return pIOSubSystem->pfnexecvp(cmdname, argv);
1183}
1184
68dc0745 1185int
1186stolen_open_osfhandle(long handle, int flags)
0a753a76 1187{
68dc0745 1188 return pIOSubSystem->pfn_open_osfhandle(handle, flags);
0a753a76 1189}
1190
68dc0745 1191long
1192stolen_get_osfhandle(int fd)
0a753a76 1193{
68dc0745 1194 return pIOSubSystem->pfn_get_osfhandle(fd);
0a753a76 1195}
7bac28a0 1196
7bac28a0 1197/*
1198 * Extras.
1199 */
1200
7bac28a0 1201DllExport int
1202win32_flock(int fd, int oper)
1203{
7bac28a0 1204 if (!IsWinNT()) {
1205 croak("flock() unimplemented on this platform");
1206 return -1;
1207 }
c90c0ff4 1208 return pIOSubSystem->pfnflock(fd, oper);
7bac28a0 1209}
1210
ad2e33dc 1211static
1212XS(w32_GetCwd)
1213{
1214 dXSARGS;
1215 SV *sv = sv_newmortal();
1216 /* Make one call with zero size - return value is required size */
1217 DWORD len = GetCurrentDirectory((DWORD)0,NULL);
1218 SvUPGRADE(sv,SVt_PV);
1219 SvGROW(sv,len);
1220 SvCUR(sv) = GetCurrentDirectory((DWORD) SvLEN(sv), SvPVX(sv));
1221 /*
1222 * If result != 0
1223 * then it worked, set PV valid,
1224 * else leave it 'undef'
1225 */
1226 if (SvCUR(sv))
1227 SvPOK_on(sv);
1228 EXTEND(sp,1);
1229 ST(0) = sv;
1230 XSRETURN(1);
1231}
1232
1233static
1234XS(w32_SetCwd)
1235{
1236 dXSARGS;
1237 if (items != 1)
1238 croak("usage: Win32::SetCurrentDirectory($cwd)");
1239 if (SetCurrentDirectory(SvPV(ST(0),na)))
1240 XSRETURN_YES;
1241
1242 XSRETURN_NO;
1243}
1244
1245static
1246XS(w32_GetNextAvailDrive)
1247{
1248 dXSARGS;
1249 char ix = 'C';
1250 char root[] = "_:\\";
1251 while (ix <= 'Z') {
1252 root[0] = ix++;
1253 if (GetDriveType(root) == 1) {
1254 root[2] = '\0';
1255 XSRETURN_PV(root);
1256 }
1257 }
1258 XSRETURN_UNDEF;
1259}
1260
1261static
1262XS(w32_GetLastError)
1263{
1264 dXSARGS;
1265 XSRETURN_IV(GetLastError());
1266}
1267
1268static
1269XS(w32_LoginName)
1270{
1271 dXSARGS;
1272 char name[256];
1273 DWORD size = sizeof(name);
1274 if (GetUserName(name,&size)) {
1275 /* size includes NULL */
1276 ST(0) = sv_2mortal(newSVpv(name,size-1));
1277 XSRETURN(1);
1278 }
1279 XSRETURN_UNDEF;
1280}
1281
1282static
1283XS(w32_NodeName)
1284{
1285 dXSARGS;
1286 char name[MAX_COMPUTERNAME_LENGTH+1];
1287 DWORD size = sizeof(name);
1288 if (GetComputerName(name,&size)) {
1289 /* size does NOT include NULL :-( */
1290 ST(0) = sv_2mortal(newSVpv(name,size));
1291 XSRETURN(1);
1292 }
1293 XSRETURN_UNDEF;
1294}
1295
1296
1297static
1298XS(w32_DomainName)
1299{
1300 dXSARGS;
1301 char name[256];
1302 DWORD size = sizeof(name);
1303 if (GetUserName(name,&size)) {
1304 char sid[1024];
1305 DWORD sidlen = sizeof(sid);
1306 char dname[256];
1307 DWORD dnamelen = sizeof(dname);
1308 SID_NAME_USE snu;
1309 if (LookupAccountName(NULL, name, &sid, &sidlen,
1310 dname, &dnamelen, &snu)) {
1311 XSRETURN_PV(dname); /* all that for this */
1312 }
1313 }
1314 XSRETURN_UNDEF;
1315}
1316
1317static
1318XS(w32_FsType)
1319{
1320 dXSARGS;
1321 char fsname[256];
1322 DWORD flags, filecomplen;
1323 if (GetVolumeInformation(NULL, NULL, 0, NULL, &filecomplen,
1324 &flags, fsname, sizeof(fsname))) {
1325 if (GIMME == G_ARRAY) {
1326 XPUSHs(sv_2mortal(newSVpv(fsname,0)));
1327 XPUSHs(sv_2mortal(newSViv(flags)));
1328 XPUSHs(sv_2mortal(newSViv(filecomplen)));
1329 PUTBACK;
1330 return;
1331 }
1332 XSRETURN_PV(fsname);
1333 }
1334 XSRETURN_UNDEF;
1335}
1336
1337static
1338XS(w32_GetOSVersion)
1339{
1340 dXSARGS;
1341 OSVERSIONINFO osver;
1342
1343 osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
1344 if (GetVersionEx(&osver)) {
1345 XPUSHs(newSVpv(osver.szCSDVersion, 0));
1346 XPUSHs(newSViv(osver.dwMajorVersion));
1347 XPUSHs(newSViv(osver.dwMinorVersion));
1348 XPUSHs(newSViv(osver.dwBuildNumber));
1349 XPUSHs(newSViv(osver.dwPlatformId));
1350 PUTBACK;
1351 return;
1352 }
1353 XSRETURN_UNDEF;
1354}
1355
1356static
1357XS(w32_IsWinNT)
1358{
1359 dXSARGS;
1360 XSRETURN_IV(IsWinNT());
1361}
1362
1363static
1364XS(w32_IsWin95)
1365{
1366 dXSARGS;
1367 XSRETURN_IV(IsWin95());
1368}
1369
1370static
1371XS(w32_FormatMessage)
1372{
1373 dXSARGS;
1374 DWORD source = 0;
1375 char msgbuf[1024];
1376
1377 if (items != 1)
1378 croak("usage: Win32::FormatMessage($errno)");
1379
1380 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
1381 &source, SvIV(ST(0)), 0,
1382 msgbuf, sizeof(msgbuf)-1, NULL))
1383 XSRETURN_PV(msgbuf);
1384
1385 XSRETURN_UNDEF;
1386}
1387
1388static
1389XS(w32_Spawn)
1390{
1391 dXSARGS;
1392 char *cmd, *args;
1393 PROCESS_INFORMATION stProcInfo;
1394 STARTUPINFO stStartInfo;
1395 BOOL bSuccess = FALSE;
1396
1397 if(items != 3)
1398 croak("usage: Win32::Spawn($cmdName, $args, $PID)");
1399
1400 cmd = SvPV(ST(0),na);
1401 args = SvPV(ST(1), na);
1402
1403 memset(&stStartInfo, 0, sizeof(stStartInfo)); /* Clear the block */
1404 stStartInfo.cb = sizeof(stStartInfo); /* Set the structure size */
1405 stStartInfo.dwFlags = STARTF_USESHOWWINDOW; /* Enable wShowWindow control */
1406 stStartInfo.wShowWindow = SW_SHOWMINNOACTIVE; /* Start min (normal) */
1407
1408 if(CreateProcess(
1409 cmd, /* Image path */
1410 args, /* Arguments for command line */
1411 NULL, /* Default process security */
1412 NULL, /* Default thread security */
1413 FALSE, /* Must be TRUE to use std handles */
1414 NORMAL_PRIORITY_CLASS, /* No special scheduling */
1415 NULL, /* Inherit our environment block */
1416 NULL, /* Inherit our currrent directory */
1417 &stStartInfo, /* -> Startup info */
1418 &stProcInfo)) /* <- Process info (if OK) */
1419 {
1420 CloseHandle(stProcInfo.hThread);/* library source code does this. */
1421 sv_setiv(ST(2), stProcInfo.dwProcessId);
1422 bSuccess = TRUE;
1423 }
1424 XSRETURN_IV(bSuccess);
1425}
1426
1427static
1428XS(w32_GetTickCount)
1429{
1430 dXSARGS;
1431 XSRETURN_IV(GetTickCount());
1432}
1433
1434static
1435XS(w32_GetShortPathName)
1436{
1437 dXSARGS;
1438 SV *shortpath;
1439
1440 if(items != 1)
1441 croak("usage: Win32::GetShortPathName($longPathName)");
1442
1443 shortpath = sv_mortalcopy(ST(0));
1444 SvUPGRADE(shortpath, SVt_PV);
1445 /* src == target is allowed */
1446 if (GetShortPathName(SvPVX(shortpath), SvPVX(shortpath), SvCUR(shortpath)))
1447 ST(0) = shortpath;
1448 else
1449 ST(0) = &sv_undef;
1450 XSRETURN(1);
1451}
1452
1453void
1454init_os_extras()
1455{
1456 char *file = __FILE__;
1457 dXSUB_SYS;
1458
1459 /* XXX should be removed after checking with Nick */
1460 newXS("Win32::GetCurrentDirectory", w32_GetCwd, file);
1461
1462 /* these names are Activeware compatible */
1463 newXS("Win32::GetCwd", w32_GetCwd, file);
1464 newXS("Win32::SetCwd", w32_SetCwd, file);
1465 newXS("Win32::GetNextAvailDrive", w32_GetNextAvailDrive, file);
1466 newXS("Win32::GetLastError", w32_GetLastError, file);
1467 newXS("Win32::LoginName", w32_LoginName, file);
1468 newXS("Win32::NodeName", w32_NodeName, file);
1469 newXS("Win32::DomainName", w32_DomainName, file);
1470 newXS("Win32::FsType", w32_FsType, file);
1471 newXS("Win32::GetOSVersion", w32_GetOSVersion, file);
1472 newXS("Win32::IsWinNT", w32_IsWinNT, file);
1473 newXS("Win32::IsWin95", w32_IsWin95, file);
1474 newXS("Win32::FormatMessage", w32_FormatMessage, file);
1475 newXS("Win32::Spawn", w32_Spawn, file);
1476 newXS("Win32::GetTickCount", w32_GetTickCount, file);
1477 newXS("Win32::GetShortPathName", w32_GetShortPathName, file);
1478
1479 /* XXX Bloat Alert! The following Activeware preloads really
1480 * ought to be part of Win32::Sys::*, so they're not included
1481 * here.
1482 */
1483 /* LookupAccountName
1484 * LookupAccountSID
1485 * InitiateSystemShutdown
1486 * AbortSystemShutdown
1487 * ExpandEnvrironmentStrings
1488 */
1489}
1490
1491void
1492Perl_win32_init(int *argcp, char ***argvp)
1493{
1494 /* Disable floating point errors, Perl will trap the ones we
1495 * care about. VC++ RTL defaults to switching these off
1496 * already, but the Borland RTL doesn't. Since we don't
1497 * want to be at the vendor's whim on the default, we set
1498 * it explicitly here.
1499 */
1500 _control87(MCW_EM, MCW_EM);
1501}