Create a struct for all perls globals (as an option)
[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
68dc0745 19/* #include "config.h" */
0a753a76 20
21#define PERLIO_NOT_STDIO 0
22#if !defined(PERLIO_IS_STDIO) && !defined(USE_SFIO)
23#define PerlIO FILE
24#endif
25
26#include "EXTERN.h"
27#include "perl.h"
ad2e33dc 28#include "XSUB.h"
0a753a76 29#include <fcntl.h>
30#include <sys/stat.h>
5b0d9cbe 31#ifndef __GNUC__
32/* assert.h conflicts with #define of assert in perl.h */
0a753a76 33#include <assert.h>
5b0d9cbe 34#endif
0a753a76 35#include <string.h>
36#include <stdarg.h>
ad2e33dc 37#include <float.h>
0a753a76 38
5b0d9cbe 39#ifdef __GNUC__
40/* Mingw32 defaults to globing command line
41 * So we turn it off like this:
42 */
43int _CRT_glob = 0;
44#endif
45
6890e559 46#define EXECF_EXEC 1
47#define EXECF_SPAWN 2
48#define EXECF_SPAWN_NOWAIT 3
49
8b10511d 50static DWORD IdOS(void);
51
0a753a76 52BOOL ProbeEnv = FALSE;
8b10511d 53DWORD Win32System = (DWORD)-1;
0a753a76 54char szShellPath[MAX_PATH+1];
55char szPerlLibRoot[MAX_PATH+1];
56HANDLE PerlDllHandle = INVALID_HANDLE_VALUE;
57
6890e559 58static int do_spawn2(char *cmd, int exectype);
59
3fe9a6f1 60int
61IsWin95(void) {
8b10511d 62 return (IdOS() == VER_PLATFORM_WIN32_WINDOWS);
3fe9a6f1 63}
64
65int
66IsWinNT(void) {
8b10511d 67 return (IdOS() == VER_PLATFORM_WIN32_NT);
3fe9a6f1 68}
0a753a76 69
68dc0745 70char *
acbc2db6 71win32PerlLibPath(char *sfx,...)
68dc0745 72{
acbc2db6 73 va_list ap;
68dc0745 74 char *end;
acbc2db6 75 va_start(ap,sfx);
68dc0745 76 GetModuleFileName((PerlDllHandle == INVALID_HANDLE_VALUE)
77 ? GetModuleHandle(NULL)
78 : PerlDllHandle,
79 szPerlLibRoot,
80 sizeof(szPerlLibRoot));
68dc0745 81 *(end = strrchr(szPerlLibRoot, '\\')) = '\0';
82 if (stricmp(end-4,"\\bin") == 0)
83 end -= 4;
84 strcpy(end,"\\lib");
acbc2db6 85 while (sfx)
86 {
87 strcat(end,"\\");
88 strcat(end,sfx);
89 sfx = va_arg(ap,char *);
90 }
91 va_end(ap);
68dc0745 92 return (szPerlLibRoot);
93}
0a753a76 94
b4793f7f 95
68dc0745 96BOOL
97HasRedirection(char *ptr)
98{
99 int inquote = 0;
100 char quote = '\0';
101
102 /*
103 * Scan string looking for redirection (< or >) or pipe
104 * characters (|) that are not in a quoted string
105 */
106 while(*ptr) {
107 switch(*ptr) {
108 case '\'':
109 case '\"':
110 if(inquote) {
111 if(quote == *ptr) {
112 inquote = 0;
113 quote = '\0';
0a753a76 114 }
68dc0745 115 }
116 else {
117 quote = *ptr;
118 inquote++;
119 }
120 break;
121 case '>':
122 case '<':
123 case '|':
124 if(!inquote)
125 return TRUE;
126 default:
127 break;
0a753a76 128 }
68dc0745 129 ++ptr;
130 }
131 return FALSE;
0a753a76 132}
133
68dc0745 134/* since the current process environment is being updated in util.c
135 * the library functions will get the correct environment
136 */
137PerlIO *
138my_popen(char *cmd, char *mode)
0a753a76 139{
140#ifdef FIXCMD
68dc0745 141#define fixcmd(x) { \
142 char *pspace = strchr((x),' '); \
143 if (pspace) { \
144 char *p = (x); \
145 while (p < pspace) { \
146 if (*p == '/') \
147 *p = '\\'; \
148 p++; \
149 } \
150 } \
151 }
0a753a76 152#else
153#define fixcmd(x)
154#endif
68dc0745 155 fixcmd(cmd);
3e3baf6d 156#ifdef __BORLANDC__ /* workaround a Borland stdio bug */
157 win32_fflush(stdout);
158 win32_fflush(stderr);
159#endif
0a753a76 160 return win32_popen(cmd, mode);
0a753a76 161}
162
68dc0745 163long
164my_pclose(PerlIO *fp)
0a753a76 165{
166 return win32_pclose(fp);
167}
168
8b10511d 169static DWORD
68dc0745 170IdOS(void)
0a753a76 171{
8b10511d 172 static OSVERSIONINFO osver;
0a753a76 173
8b10511d 174 if (osver.dwPlatformId != Win32System) {
175 memset(&osver, 0, sizeof(OSVERSIONINFO));
176 osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
177 GetVersionEx(&osver);
178 Win32System = osver.dwPlatformId;
179 }
180 return (Win32System);
0a753a76 181}
182
68dc0745 183static char *
184GetShell(void)
0a753a76 185{
68dc0745 186 if (!ProbeEnv) {
174c211a 187 char* defaultshell = (IsWinNT() ? "cmd.exe" : "command.com");
188 /* we don't use COMSPEC here for two reasons:
189 * 1. the same reason perl on UNIX doesn't use SHELL--rampant and
190 * uncontrolled unportability of the ensuing scripts.
191 * 2. PERL5SHELL could be set to a shell that may not be fit for
192 * interactive use (which is what most programs look in COMSPEC
193 * for).
194 */
195 char *usershell = getenv("PERL5SHELL");
196
8b10511d 197 ProbeEnv = TRUE;
174c211a 198 strcpy(szShellPath, usershell ? usershell : defaultshell);
68dc0745 199 }
200 return szShellPath;
0a753a76 201}
202
68dc0745 203int
d55594ae 204do_aspawn(void* really, void ** mark, void ** arglast)
0a753a76 205{
68dc0745 206 char **argv;
207 char *strPtr;
208 char *cmd;
209 int status;
210 unsigned int length;
211 int index = 0;
0a753a76 212 SV *sv = (SV*)really;
68dc0745 213 SV** pSv = (SV**)mark;
214
fc36a67e 215 New(1310, argv, (arglast - mark) + 4, char*);
68dc0745 216
217 if(sv != Nullsv) {
218 cmd = SvPV(sv, length);
219 }
220 else {
3fe9a6f1 221 argv[index++] = cmd = GetShell();
0a9a032c 222 if (IsWinNT())
223 argv[index++] = "/x"; /* always enable command extensions */
68dc0745 224 argv[index++] = "/c";
225 }
226
5aabfad6 227 while(++pSv <= (SV**)arglast) {
228 sv = *pSv;
68dc0745 229 strPtr = SvPV(sv, length);
230 if(strPtr != NULL && *strPtr != '\0')
231 argv[index++] = strPtr;
232 }
233 argv[index++] = 0;
234
3e3baf6d 235 status = win32_spawnvp(P_WAIT, cmd, (const char* const*)argv);
68dc0745 236
237 Safefree(argv);
238
5aabfad6 239 if (status < 0) {
240 if (dowarn)
241 warn("Can't spawn \"%s\": %s", cmd, strerror(errno));
242 status = 255 << 8;
243 }
244 return (status);
68dc0745 245}
246
247int
6890e559 248do_spawn2(char *cmd, int exectype)
68dc0745 249{
250 char **a;
251 char *s;
252 char **argv;
253 int status = -1;
254 BOOL needToTry = TRUE;
255 char *shell, *cmd2;
256
257 /* save an extra exec if possible */
258 shell = GetShell();
259
260 /* see if there are shell metacharacters in it */
261 if(!HasRedirection(cmd)) {
fc36a67e 262 New(1301,argv, strlen(cmd) / 2 + 2, char*);
263 New(1302,cmd2, strlen(cmd) + 1, char);
68dc0745 264 strcpy(cmd2, cmd);
265 a = argv;
266 for (s = cmd2; *s;) {
267 while (*s && isspace(*s))
268 s++;
269 if (*s)
270 *(a++) = s;
271 while(*s && !isspace(*s))
272 s++;
273 if(*s)
274 *s++ = '\0';
0a753a76 275 }
68dc0745 276 *a = Nullch;
277 if(argv[0]) {
6890e559 278 switch (exectype) {
279 case EXECF_SPAWN:
280 status = win32_spawnvp(P_WAIT, argv[0],
281 (const char* const*)argv);
282 break;
283 case EXECF_SPAWN_NOWAIT:
284 status = win32_spawnvp(P_NOWAIT, argv[0],
285 (const char* const*)argv);
286 break;
287 case EXECF_EXEC:
288 status = win32_execvp(argv[0], (const char* const*)argv);
289 break;
290 }
68dc0745 291 if(status != -1 || errno == 0)
292 needToTry = FALSE;
0a753a76 293 }
0a753a76 294 Safefree(argv);
68dc0745 295 Safefree(cmd2);
296 }
297 if(needToTry) {
3e3baf6d 298 char *argv[5];
0a9a032c 299 int i = 0;
300 argv[i++] = shell;
301 if (IsWinNT())
302 argv[i++] = "/x";
303 argv[i++] = "/c"; argv[i++] = cmd; argv[i] = Nullch;
6890e559 304 switch (exectype) {
305 case EXECF_SPAWN:
306 status = win32_spawnvp(P_WAIT, argv[0],
307 (const char* const*)argv);
308 break;
309 case EXECF_SPAWN_NOWAIT:
310 status = win32_spawnvp(P_NOWAIT, argv[0],
311 (const char* const*)argv);
312 break;
313 case EXECF_EXEC:
314 status = win32_execvp(argv[0], (const char* const*)argv);
315 break;
316 }
68dc0745 317 }
5aabfad6 318 if (status < 0) {
319 if (dowarn)
6890e559 320 warn("Can't %s \"%s\": %s",
321 (exectype == EXECF_EXEC ? "exec" : "spawn"),
322 needToTry ? shell : argv[0],
5aabfad6 323 strerror(errno));
324 status = 255 << 8;
325 }
326 return (status);
0a753a76 327}
328
6890e559 329int
330do_spawn(char *cmd)
331{
332 return do_spawn2(cmd, EXECF_SPAWN);
333}
334
335bool
336do_exec(char *cmd)
337{
338 do_spawn2(cmd, EXECF_EXEC);
339 return FALSE;
340}
341
0a753a76 342
343#define PATHLEN 1024
344
68dc0745 345/* The idea here is to read all the directory names into a string table
346 * (separated by nulls) and when one of the other dir functions is called
347 * return the pointer to the current file name.
348 */
349DIR *
350opendir(char *filename)
0a753a76 351{
352 DIR *p;
68dc0745 353 long len;
354 long idx;
355 char scannamespc[PATHLEN];
356 char *scanname = scannamespc;
357 struct stat sbuf;
358 WIN32_FIND_DATA FindData;
359 HANDLE fh;
360/* char root[_MAX_PATH];*/
361/* char volname[_MAX_PATH];*/
362/* DWORD serial, maxname, flags;*/
363/* BOOL downcase;*/
364/* char *dummy;*/
365
366 /* check to see if filename is a directory */
d55594ae 367 if (win32_stat(filename, &sbuf) < 0 || (sbuf.st_mode & S_IFDIR) == 0) {
68dc0745 368 return NULL;
369 }
370
371 /* get the file system characteristics */
372/* if(GetFullPathName(filename, MAX_PATH, root, &dummy)) {
373 * if(dummy = strchr(root, '\\'))
374 * *++dummy = '\0';
375 * if(GetVolumeInformation(root, volname, MAX_PATH, &serial,
376 * &maxname, &flags, 0, 0)) {
377 * downcase = !(flags & FS_CASE_IS_PRESERVED);
378 * }
379 * }
380 * else {
381 * downcase = TRUE;
382 * }
383 */
384 /* Get us a DIR structure */
fc36a67e 385 Newz(1303, p, 1, DIR);
68dc0745 386 if(p == NULL)
387 return NULL;
388
389 /* Create the search pattern */
390 strcpy(scanname, filename);
391
392 if(index("/\\", *(scanname + strlen(scanname) - 1)) == NULL)
393 strcat(scanname, "/*");
394 else
395 strcat(scanname, "*");
396
397 /* do the FindFirstFile call */
398 fh = FindFirstFile(scanname, &FindData);
399 if(fh == INVALID_HANDLE_VALUE) {
400 return NULL;
401 }
402
403 /* now allocate the first part of the string table for
404 * the filenames that we find.
405 */
406 idx = strlen(FindData.cFileName)+1;
fc36a67e 407 New(1304, p->start, idx, char);
68dc0745 408 if(p->start == NULL) {
65e48ea9 409 croak("opendir: malloc failed!\n");
68dc0745 410 }
411 strcpy(p->start, FindData.cFileName);
412/* if(downcase)
413 * strlwr(p->start);
414 */
415 p->nfiles++;
416
417 /* loop finding all the files that match the wildcard
418 * (which should be all of them in this directory!).
419 * the variable idx should point one past the null terminator
420 * of the previous string found.
421 */
422 while (FindNextFile(fh, &FindData)) {
423 len = strlen(FindData.cFileName);
424 /* bump the string table size by enough for the
425 * new name and it's null terminator
426 */
427 Renew(p->start, idx+len+1, char);
428 if(p->start == NULL) {
65e48ea9 429 croak("opendir: malloc failed!\n");
0a753a76 430 }
68dc0745 431 strcpy(&p->start[idx], FindData.cFileName);
432/* if (downcase)
433 * strlwr(&p->start[idx]);
434 */
0a753a76 435 p->nfiles++;
436 idx += len+1;
437 }
438 FindClose(fh);
439 p->size = idx;
440 p->curr = p->start;
441 return p;
442}
443
444
68dc0745 445/* Readdir just returns the current string pointer and bumps the
446 * string pointer to the nDllExport entry.
447 */
448struct direct *
449readdir(DIR *dirp)
0a753a76 450{
68dc0745 451 int len;
452 static int dummy = 0;
0a753a76 453
68dc0745 454 if (dirp->curr) {
455 /* first set up the structure to return */
456 len = strlen(dirp->curr);
457 strcpy(dirp->dirstr.d_name, dirp->curr);
458 dirp->dirstr.d_namlen = len;
0a753a76 459
68dc0745 460 /* Fake an inode */
461 dirp->dirstr.d_ino = dummy++;
0a753a76 462
68dc0745 463 /* Now set up for the nDllExport call to readdir */
464 dirp->curr += len + 1;
465 if (dirp->curr >= (dirp->start + dirp->size)) {
466 dirp->curr = NULL;
467 }
0a753a76 468
68dc0745 469 return &(dirp->dirstr);
470 }
471 else
472 return NULL;
0a753a76 473}
474
68dc0745 475/* Telldir returns the current string pointer position */
476long
477telldir(DIR *dirp)
0a753a76 478{
479 return (long) dirp->curr;
480}
481
482
68dc0745 483/* Seekdir moves the string pointer to a previously saved position
484 *(Saved by telldir).
485 */
486void
487seekdir(DIR *dirp, long loc)
0a753a76 488{
489 dirp->curr = (char *)loc;
490}
491
68dc0745 492/* Rewinddir resets the string pointer to the start */
493void
494rewinddir(DIR *dirp)
0a753a76 495{
496 dirp->curr = dirp->start;
497}
498
68dc0745 499/* free the memory allocated by opendir */
500int
501closedir(DIR *dirp)
0a753a76 502{
503 Safefree(dirp->start);
504 Safefree(dirp);
68dc0745 505 return 1;
0a753a76 506}
507
508
68dc0745 509/*
510 * various stubs
511 */
0a753a76 512
513
68dc0745 514/* Ownership
515 *
516 * Just pretend that everyone is a superuser. NT will let us know if
517 * we don\'t really have permission to do something.
518 */
0a753a76 519
520#define ROOT_UID ((uid_t)0)
521#define ROOT_GID ((gid_t)0)
522
68dc0745 523uid_t
524getuid(void)
0a753a76 525{
68dc0745 526 return ROOT_UID;
0a753a76 527}
528
68dc0745 529uid_t
530geteuid(void)
0a753a76 531{
68dc0745 532 return ROOT_UID;
0a753a76 533}
534
68dc0745 535gid_t
536getgid(void)
0a753a76 537{
68dc0745 538 return ROOT_GID;
0a753a76 539}
540
68dc0745 541gid_t
542getegid(void)
0a753a76 543{
68dc0745 544 return ROOT_GID;
0a753a76 545}
546
68dc0745 547int
22239a37 548setuid(uid_t auid)
0a753a76 549{
22239a37 550 return (auid == ROOT_UID ? 0 : -1);
0a753a76 551}
552
68dc0745 553int
22239a37 554setgid(gid_t agid)
0a753a76 555{
22239a37 556 return (agid == ROOT_GID ? 0 : -1);
0a753a76 557}
558
68dc0745 559/*
560 * pretended kill
561 */
562int
563kill(int pid, int sig)
0a753a76 564{
68dc0745 565 HANDLE hProcess= OpenProcess(PROCESS_ALL_ACCESS, TRUE, pid);
0a753a76 566
567 if (hProcess == NULL) {
65e48ea9 568 croak("kill process failed!\n");
68dc0745 569 }
570 else {
571 if (!TerminateProcess(hProcess, sig))
65e48ea9 572 croak("kill process failed!\n");
68dc0745 573 CloseHandle(hProcess);
574 }
575 return 0;
0a753a76 576}
577
68dc0745 578/*
579 * File system stuff
580 */
0a753a76 581
3e3baf6d 582#if 0
68dc0745 583int
584ioctl(int i, unsigned int u, char *data)
0a753a76 585{
65e48ea9 586 croak("ioctl not implemented!\n");
68dc0745 587 return -1;
0a753a76 588}
3e3baf6d 589#endif
0a753a76 590
f3986ebb 591DllExport unsigned int
592win32_sleep(unsigned int t)
0a753a76 593{
68dc0745 594 Sleep(t*1000);
595 return 0;
0a753a76 596}
597
68dc0745 598DllExport int
599win32_stat(const char *path, struct stat *buffer)
0a753a76 600{
68dc0745 601 char t[MAX_PATH];
602 const char *p = path;
603 int l = strlen(path);
67fbe06e 604 int res;
0a753a76 605
68dc0745 606 if (l > 1) {
607 switch(path[l - 1]) {
608 case '\\':
609 case '/':
610 if (path[l - 2] != ':') {
611 strncpy(t, path, l - 1);
612 t[l - 1] = 0;
613 p = t;
614 };
615 }
616 }
390b85e7 617 res = stat(p,buffer);
67fbe06e 618#ifdef __BORLANDC__
619 if (res == 0) {
620 if (S_ISDIR(buffer->st_mode))
621 buffer->st_mode |= S_IWRITE | S_IEXEC;
622 else if (S_ISREG(buffer->st_mode)) {
623 if (l >= 4 && path[l-4] == '.') {
624 const char *e = path + l - 3;
625 if (strnicmp(e,"exe",3)
626 && strnicmp(e,"bat",3)
627 && strnicmp(e,"com",3)
628 && (IsWin95() || strnicmp(e,"cmd",3)))
629 buffer->st_mode &= ~S_IEXEC;
630 else
631 buffer->st_mode |= S_IEXEC;
632 }
633 else
634 buffer->st_mode &= ~S_IEXEC;
635 }
636 }
637#endif
638 return res;
0a753a76 639}
640
0551aaa8 641#ifndef USE_WIN32_RTL_ENV
642
643DllExport char *
644win32_getenv(const char *name)
645{
646 static char *curitem = Nullch;
647 static DWORD curlen = 512;
648 DWORD needlen;
649 if (!curitem)
650 New(1305,curitem,curlen,char);
651 if (!(needlen = GetEnvironmentVariable(name,curitem,curlen)))
652 return Nullch;
653 while (needlen > curlen) {
654 Renew(curitem,needlen,char);
655 curlen = needlen;
656 needlen = GetEnvironmentVariable(name,curitem,curlen);
657 }
658 return curitem;
659}
660
661#endif
662
d55594ae 663static long
664FileTimeToClock(PFILETIME ft)
665{
666 __int64 qw = ft->dwHighDateTime;
667 qw <<= 32;
668 qw |= ft->dwLowDateTime;
669 qw /= 10000; /* File time ticks at 0.1uS, clock at 1mS */
670 return (long) qw;
671}
672
f3986ebb 673DllExport int
674win32_times(struct tms *timebuf)
0a753a76 675{
d55594ae 676 FILETIME user;
677 FILETIME kernel;
678 FILETIME dummy;
679 if (GetProcessTimes(GetCurrentProcess(), &dummy, &dummy,
680 &kernel,&user)) {
681 timebuf->tms_utime = FileTimeToClock(&user);
682 timebuf->tms_stime = FileTimeToClock(&kernel);
683 timebuf->tms_cutime = 0;
684 timebuf->tms_cstime = 0;
685
686 } else {
687 /* That failed - e.g. Win95 fallback to clock() */
688 clock_t t = clock();
689 timebuf->tms_utime = t;
690 timebuf->tms_stime = 0;
691 timebuf->tms_cutime = 0;
692 timebuf->tms_cstime = 0;
693 }
68dc0745 694 return 0;
0a753a76 695}
696
d55594ae 697static UINT timerid = 0;
698
699
700static VOID CALLBACK TimerProc(HWND win, UINT msg, UINT id, DWORD time)
701{
702 KillTimer(NULL,timerid);
703 timerid=0;
704 sighandler(14);
705}
706
f3986ebb 707DllExport unsigned int
708win32_alarm(unsigned int sec)
0a753a76 709{
d55594ae 710 /*
711 * the 'obvious' implentation is SetTimer() with a callback
712 * which does whatever receiving SIGALRM would do
713 * we cannot use SIGALRM even via raise() as it is not
714 * one of the supported codes in <signal.h>
715 *
716 * Snag is unless something is looking at the message queue
717 * nothing happens :-(
718 */
719 if (sec)
720 {
721 timerid = SetTimer(NULL,timerid,sec*1000,(TIMERPROC)TimerProc);
722 if (!timerid)
723 croak("Cannot set timer");
724 }
725 else
726 {
727 if (timerid)
728 {
729 KillTimer(NULL,timerid);
730 timerid=0;
731 }
732 }
68dc0745 733 return 0;
0a753a76 734}
735
f3986ebb 736#ifdef USE_FIXED_OSFHANDLE
390b85e7 737
738EXTERN_C int __cdecl _alloc_osfhnd(void);
739EXTERN_C int __cdecl _set_osfhnd(int fh, long value);
740EXTERN_C void __cdecl _lock_fhandle(int);
741EXTERN_C void __cdecl _unlock_fhandle(int);
742EXTERN_C void __cdecl _unlock(int);
743
744#if (_MSC_VER >= 1000)
745typedef struct {
746 long osfhnd; /* underlying OS file HANDLE */
747 char osfile; /* attributes of file (e.g., open in text mode?) */
748 char pipech; /* one char buffer for handles opened on pipes */
749#if defined (_MT) && !defined (DLL_FOR_WIN32S)
750 int lockinitflag;
751 CRITICAL_SECTION lock;
752#endif /* defined (_MT) && !defined (DLL_FOR_WIN32S) */
753} ioinfo;
754
755EXTERN_C ioinfo * __pioinfo[];
756
757#define IOINFO_L2E 5
758#define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E)
759#define _pioinfo(i) (__pioinfo[i >> IOINFO_L2E] + (i & (IOINFO_ARRAY_ELTS - 1)))
760#define _osfile(i) (_pioinfo(i)->osfile)
761
762#else /* (_MSC_VER >= 1000) */
763extern char _osfile[];
764#endif /* (_MSC_VER >= 1000) */
765
766#define FOPEN 0x01 /* file handle open */
767#define FAPPEND 0x20 /* file handle opened O_APPEND */
768#define FDEV 0x40 /* file handle refers to device */
769#define FTEXT 0x80 /* file handle is in text mode */
770
771#define _STREAM_LOCKS 26 /* Table of stream locks */
772#define _LAST_STREAM_LOCK (_STREAM_LOCKS+_NSTREAM_-1) /* Last stream lock */
773#define _FH_LOCKS (_LAST_STREAM_LOCK+1) /* Table of fh locks */
774
775/***
776*int my_open_osfhandle(long osfhandle, int flags) - open C Runtime file handle
777*
778*Purpose:
779* This function allocates a free C Runtime file handle and associates
780* it with the Win32 HANDLE specified by the first parameter. This is a
781* temperary fix for WIN95's brain damage GetFileType() error on socket
782* we just bypass that call for socket
783*
784*Entry:
785* long osfhandle - Win32 HANDLE to associate with C Runtime file handle.
786* int flags - flags to associate with C Runtime file handle.
787*
788*Exit:
789* returns index of entry in fh, if successful
790* return -1, if no free entry is found
791*
792*Exceptions:
793*
794*******************************************************************************/
795
796static int
797my_open_osfhandle(long osfhandle, int flags)
798{
799 int fh;
800 char fileflags; /* _osfile flags */
801
802 /* copy relevant flags from second parameter */
803 fileflags = FDEV;
804
805 if(flags & O_APPEND)
806 fileflags |= FAPPEND;
807
808 if(flags & O_TEXT)
809 fileflags |= FTEXT;
810
811 /* attempt to allocate a C Runtime file handle */
812 if((fh = _alloc_osfhnd()) == -1) {
813 errno = EMFILE; /* too many open files */
814 _doserrno = 0L; /* not an OS error */
815 return -1; /* return error to caller */
816 }
817
818 /* the file is open. now, set the info in _osfhnd array */
819 _set_osfhnd(fh, osfhandle);
820
821 fileflags |= FOPEN; /* mark as open */
822
823#if (_MSC_VER >= 1000)
824 _osfile(fh) = fileflags; /* set osfile entry */
825 _unlock_fhandle(fh);
826#else
827 _osfile[fh] = fileflags; /* set osfile entry */
828 _unlock(fh+_FH_LOCKS); /* unlock handle */
829#endif
830
831 return fh; /* return handle */
832}
833
834#define _open_osfhandle my_open_osfhandle
f3986ebb 835#endif /* USE_FIXED_OSFHANDLE */
390b85e7 836
837/* simulate flock by locking a range on the file */
838
839#define LK_ERR(f,i) ((f) ? (i = 0) : (errno = GetLastError()))
840#define LK_LEN 0xffff0000
841
f3986ebb 842DllExport int
843win32_flock(int fd, int oper)
390b85e7 844{
845 OVERLAPPED o;
846 int i = -1;
847 HANDLE fh;
848
f3986ebb 849 if (!IsWinNT()) {
850 croak("flock() unimplemented on this platform");
851 return -1;
852 }
390b85e7 853 fh = (HANDLE)_get_osfhandle(fd);
854 memset(&o, 0, sizeof(o));
855
856 switch(oper) {
857 case LOCK_SH: /* shared lock */
858 LK_ERR(LockFileEx(fh, 0, 0, LK_LEN, 0, &o),i);
859 break;
860 case LOCK_EX: /* exclusive lock */
861 LK_ERR(LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, LK_LEN, 0, &o),i);
862 break;
863 case LOCK_SH|LOCK_NB: /* non-blocking shared lock */
864 LK_ERR(LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY, 0, LK_LEN, 0, &o),i);
865 break;
866 case LOCK_EX|LOCK_NB: /* non-blocking exclusive lock */
867 LK_ERR(LockFileEx(fh,
868 LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY,
869 0, LK_LEN, 0, &o),i);
870 break;
871 case LOCK_UN: /* unlock lock */
872 LK_ERR(UnlockFileEx(fh, 0, LK_LEN, 0, &o),i);
873 break;
874 default: /* unknown */
875 errno = EINVAL;
876 break;
877 }
878 return i;
879}
880
881#undef LK_ERR
882#undef LK_LEN
883
68dc0745 884/*
885 * redirected io subsystem for all XS modules
886 *
887 */
0a753a76 888
68dc0745 889DllExport int *
890win32_errno(void)
0a753a76 891{
390b85e7 892 return (&errno);
0a753a76 893}
894
dcb2879a 895DllExport char ***
896win32_environ(void)
897{
390b85e7 898 return (&(_environ));
dcb2879a 899}
900
68dc0745 901/* the rest are the remapped stdio routines */
902DllExport FILE *
903win32_stderr(void)
0a753a76 904{
390b85e7 905 return (stderr);
0a753a76 906}
907
68dc0745 908DllExport FILE *
909win32_stdin(void)
0a753a76 910{
390b85e7 911 return (stdin);
0a753a76 912}
913
68dc0745 914DllExport FILE *
915win32_stdout()
0a753a76 916{
390b85e7 917 return (stdout);
0a753a76 918}
919
68dc0745 920DllExport int
921win32_ferror(FILE *fp)
0a753a76 922{
390b85e7 923 return (ferror(fp));
0a753a76 924}
925
926
68dc0745 927DllExport int
928win32_feof(FILE *fp)
0a753a76 929{
390b85e7 930 return (feof(fp));
0a753a76 931}
932
68dc0745 933/*
934 * Since the errors returned by the socket error function
935 * WSAGetLastError() are not known by the library routine strerror
936 * we have to roll our own.
937 */
0a753a76 938
c53bd28a 939#ifdef USE_THREADS
940#ifdef USE_DECLSPEC_THREAD
0a753a76 941__declspec(thread) char strerror_buffer[512];
c53bd28a 942#else
943#define strerror_buffer (thr->i.Wstrerror_buffer)
944#endif
945#else
946char strerror_buffer[512];
947#endif
0a753a76 948
68dc0745 949DllExport char *
950win32_strerror(int e)
0a753a76 951{
3e3baf6d 952#ifndef __BORLANDC__ /* Borland intolerance */
68dc0745 953 extern int sys_nerr;
3e3baf6d 954#endif
68dc0745 955 DWORD source = 0;
0a753a76 956
68dc0745 957 if(e < 0 || e > sys_nerr) {
c53bd28a 958 dTHR;
68dc0745 959 if(e < 0)
960 e = GetLastError();
0a753a76 961
68dc0745 962 if(FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, &source, e, 0,
963 strerror_buffer, sizeof(strerror_buffer), NULL) == 0)
964 strcpy(strerror_buffer, "Unknown Error");
0a753a76 965
68dc0745 966 return strerror_buffer;
967 }
390b85e7 968 return strerror(e);
0a753a76 969}
970
68dc0745 971DllExport int
972win32_fprintf(FILE *fp, const char *format, ...)
0a753a76 973{
68dc0745 974 va_list marker;
975 va_start(marker, format); /* Initialize variable arguments. */
0a753a76 976
390b85e7 977 return (vfprintf(fp, format, marker));
0a753a76 978}
979
68dc0745 980DllExport int
981win32_printf(const char *format, ...)
0a753a76 982{
68dc0745 983 va_list marker;
984 va_start(marker, format); /* Initialize variable arguments. */
0a753a76 985
390b85e7 986 return (vprintf(format, marker));
0a753a76 987}
988
68dc0745 989DllExport int
990win32_vfprintf(FILE *fp, const char *format, va_list args)
0a753a76 991{
390b85e7 992 return (vfprintf(fp, format, args));
0a753a76 993}
994
96e4d5b1 995DllExport int
996win32_vprintf(const char *format, va_list args)
997{
390b85e7 998 return (vprintf(format, args));
96e4d5b1 999}
1000
68dc0745 1001DllExport size_t
1002win32_fread(void *buf, size_t size, size_t count, FILE *fp)
0a753a76 1003{
390b85e7 1004 return fread(buf, size, count, fp);
0a753a76 1005}
1006
68dc0745 1007DllExport size_t
1008win32_fwrite(const void *buf, size_t size, size_t count, FILE *fp)
0a753a76 1009{
390b85e7 1010 return fwrite(buf, size, count, fp);
0a753a76 1011}
1012
68dc0745 1013DllExport FILE *
1014win32_fopen(const char *filename, const char *mode)
0a753a76 1015{
68dc0745 1016 if (stricmp(filename, "/dev/null")==0)
390b85e7 1017 return fopen("NUL", mode);
1018 return fopen(filename, mode);
0a753a76 1019}
1020
f3986ebb 1021#ifndef USE_SOCKETS_AS_HANDLES
1022#undef fdopen
1023#define fdopen my_fdopen
1024#endif
1025
68dc0745 1026DllExport FILE *
1027win32_fdopen( int handle, const char *mode)
0a753a76 1028{
390b85e7 1029 return fdopen(handle, (char *) mode);
0a753a76 1030}
1031
68dc0745 1032DllExport FILE *
1033win32_freopen( const char *path, const char *mode, FILE *stream)
0a753a76 1034{
68dc0745 1035 if (stricmp(path, "/dev/null")==0)
390b85e7 1036 return freopen("NUL", mode, stream);
1037 return freopen(path, mode, stream);
0a753a76 1038}
1039
68dc0745 1040DllExport int
1041win32_fclose(FILE *pf)
0a753a76 1042{
f3986ebb 1043 return my_fclose(pf); /* defined in win32sck.c */
0a753a76 1044}
1045
68dc0745 1046DllExport int
1047win32_fputs(const char *s,FILE *pf)
0a753a76 1048{
390b85e7 1049 return fputs(s, pf);
0a753a76 1050}
1051
68dc0745 1052DllExport int
1053win32_fputc(int c,FILE *pf)
0a753a76 1054{
390b85e7 1055 return fputc(c,pf);
0a753a76 1056}
1057
68dc0745 1058DllExport int
1059win32_ungetc(int c,FILE *pf)
0a753a76 1060{
390b85e7 1061 return ungetc(c,pf);
0a753a76 1062}
1063
68dc0745 1064DllExport int
1065win32_getc(FILE *pf)
0a753a76 1066{
390b85e7 1067 return getc(pf);
0a753a76 1068}
1069
68dc0745 1070DllExport int
1071win32_fileno(FILE *pf)
0a753a76 1072{
390b85e7 1073 return fileno(pf);
0a753a76 1074}
1075
68dc0745 1076DllExport void
1077win32_clearerr(FILE *pf)
0a753a76 1078{
390b85e7 1079 clearerr(pf);
68dc0745 1080 return;
0a753a76 1081}
1082
68dc0745 1083DllExport int
1084win32_fflush(FILE *pf)
0a753a76 1085{
390b85e7 1086 return fflush(pf);
0a753a76 1087}
1088
68dc0745 1089DllExport long
1090win32_ftell(FILE *pf)
0a753a76 1091{
390b85e7 1092 return ftell(pf);
0a753a76 1093}
1094
68dc0745 1095DllExport int
1096win32_fseek(FILE *pf,long offset,int origin)
0a753a76 1097{
390b85e7 1098 return fseek(pf, offset, origin);
0a753a76 1099}
1100
68dc0745 1101DllExport int
1102win32_fgetpos(FILE *pf,fpos_t *p)
0a753a76 1103{
390b85e7 1104 return fgetpos(pf, p);
0a753a76 1105}
1106
68dc0745 1107DllExport int
1108win32_fsetpos(FILE *pf,const fpos_t *p)
0a753a76 1109{
390b85e7 1110 return fsetpos(pf, p);
0a753a76 1111}
1112
68dc0745 1113DllExport void
1114win32_rewind(FILE *pf)
0a753a76 1115{
390b85e7 1116 rewind(pf);
68dc0745 1117 return;
0a753a76 1118}
1119
68dc0745 1120DllExport FILE*
1121win32_tmpfile(void)
0a753a76 1122{
390b85e7 1123 return tmpfile();
0a753a76 1124}
1125
68dc0745 1126DllExport void
1127win32_abort(void)
0a753a76 1128{
390b85e7 1129 abort();
68dc0745 1130 return;
0a753a76 1131}
1132
68dc0745 1133DllExport int
22239a37 1134win32_fstat(int fd,struct stat *sbufptr)
0a753a76 1135{
22239a37 1136 return fstat(fd,sbufptr);
0a753a76 1137}
1138
68dc0745 1139DllExport int
1140win32_pipe(int *pfd, unsigned int size, int mode)
0a753a76 1141{
390b85e7 1142 return _pipe(pfd, size, mode);
0a753a76 1143}
1144
68dc0745 1145DllExport FILE*
1146win32_popen(const char *command, const char *mode)
0a753a76 1147{
390b85e7 1148 return _popen(command, mode);
0a753a76 1149}
1150
68dc0745 1151DllExport int
1152win32_pclose(FILE *pf)
0a753a76 1153{
390b85e7 1154 return _pclose(pf);
0a753a76 1155}
1156
68dc0745 1157DllExport int
1158win32_setmode(int fd, int mode)
0a753a76 1159{
390b85e7 1160 return setmode(fd, mode);
0a753a76 1161}
1162
96e4d5b1 1163DllExport long
1164win32_lseek(int fd, long offset, int origin)
1165{
390b85e7 1166 return lseek(fd, offset, origin);
96e4d5b1 1167}
1168
1169DllExport long
1170win32_tell(int fd)
1171{
390b85e7 1172 return tell(fd);
96e4d5b1 1173}
1174
68dc0745 1175DllExport int
1176win32_open(const char *path, int flag, ...)
0a753a76 1177{
68dc0745 1178 va_list ap;
1179 int pmode;
0a753a76 1180
1181 va_start(ap, flag);
1182 pmode = va_arg(ap, int);
1183 va_end(ap);
1184
68dc0745 1185 if (stricmp(path, "/dev/null")==0)
390b85e7 1186 return open("NUL", flag, pmode);
1187 return open(path,flag,pmode);
0a753a76 1188}
1189
68dc0745 1190DllExport int
1191win32_close(int fd)
0a753a76 1192{
390b85e7 1193 return close(fd);
0a753a76 1194}
1195
68dc0745 1196DllExport int
96e4d5b1 1197win32_eof(int fd)
1198{
390b85e7 1199 return eof(fd);
96e4d5b1 1200}
1201
1202DllExport int
68dc0745 1203win32_dup(int fd)
0a753a76 1204{
390b85e7 1205 return dup(fd);
0a753a76 1206}
1207
68dc0745 1208DllExport int
1209win32_dup2(int fd1,int fd2)
0a753a76 1210{
390b85e7 1211 return dup2(fd1,fd2);
0a753a76 1212}
1213
68dc0745 1214DllExport int
3e3baf6d 1215win32_read(int fd, void *buf, unsigned int cnt)
0a753a76 1216{
390b85e7 1217 return read(fd, buf, cnt);
0a753a76 1218}
1219
68dc0745 1220DllExport int
3e3baf6d 1221win32_write(int fd, const void *buf, unsigned int cnt)
0a753a76 1222{
390b85e7 1223 return write(fd, buf, cnt);
0a753a76 1224}
1225
68dc0745 1226DllExport int
5aabfad6 1227win32_mkdir(const char *dir, int mode)
1228{
390b85e7 1229 return mkdir(dir); /* just ignore mode */
5aabfad6 1230}
96e4d5b1 1231
5aabfad6 1232DllExport int
1233win32_rmdir(const char *dir)
1234{
390b85e7 1235 return rmdir(dir);
5aabfad6 1236}
96e4d5b1 1237
5aabfad6 1238DllExport int
1239win32_chdir(const char *dir)
1240{
390b85e7 1241 return chdir(dir);
5aabfad6 1242}
96e4d5b1 1243
5aabfad6 1244DllExport int
3e3baf6d 1245win32_spawnvp(int mode, const char *cmdname, const char *const *argv)
0a753a76 1246{
390b85e7 1247 return spawnvp(mode, cmdname, (char * const *) argv);
0a753a76 1248}
1249
6890e559 1250DllExport int
1251win32_execvp(const char *cmdname, const char *const *argv)
1252{
390b85e7 1253 return execvp(cmdname, (char *const *)argv);
6890e559 1254}
1255
84902520 1256DllExport void
1257win32_perror(const char *str)
1258{
390b85e7 1259 perror(str);
84902520 1260}
1261
1262DllExport void
1263win32_setbuf(FILE *pf, char *buf)
1264{
390b85e7 1265 setbuf(pf, buf);
84902520 1266}
1267
1268DllExport int
1269win32_setvbuf(FILE *pf, char *buf, int type, size_t size)
1270{
390b85e7 1271 return setvbuf(pf, buf, type, size);
84902520 1272}
1273
1274DllExport int
1275win32_flushall(void)
1276{
390b85e7 1277 return flushall();
84902520 1278}
1279
1280DllExport int
1281win32_fcloseall(void)
1282{
390b85e7 1283 return fcloseall();
84902520 1284}
1285
1286DllExport char*
1287win32_fgets(char *s, int n, FILE *pf)
1288{
390b85e7 1289 return fgets(s, n, pf);
84902520 1290}
1291
1292DllExport char*
1293win32_gets(char *s)
1294{
390b85e7 1295 return gets(s);
84902520 1296}
1297
1298DllExport int
1299win32_fgetc(FILE *pf)
1300{
390b85e7 1301 return fgetc(pf);
84902520 1302}
1303
1304DllExport int
1305win32_putc(int c, FILE *pf)
1306{
390b85e7 1307 return putc(c,pf);
84902520 1308}
1309
1310DllExport int
1311win32_puts(const char *s)
1312{
390b85e7 1313 return puts(s);
84902520 1314}
1315
1316DllExport int
1317win32_getchar(void)
1318{
390b85e7 1319 return getchar();
84902520 1320}
1321
1322DllExport int
1323win32_putchar(int c)
1324{
390b85e7 1325 return putchar(c);
84902520 1326}
1327
bbc8f9de 1328#ifdef MYMALLOC
1329
1330#ifndef USE_PERL_SBRK
1331
1332static char *committed = NULL;
1333static char *base = NULL;
1334static char *reserved = NULL;
1335static char *brk = NULL;
1336static DWORD pagesize = 0;
1337static DWORD allocsize = 0;
1338
1339void *
1340sbrk(int need)
1341{
1342 void *result;
1343 if (!pagesize)
1344 {SYSTEM_INFO info;
1345 GetSystemInfo(&info);
1346 /* Pretend page size is larger so we don't perpetually
1347 * call the OS to commit just one page ...
1348 */
1349 pagesize = info.dwPageSize << 3;
1350 allocsize = info.dwAllocationGranularity;
1351 }
1352 /* This scheme fails eventually if request for contiguous
1353 * block is denied so reserve big blocks - this is only
1354 * address space not memory ...
1355 */
1356 if (brk+need >= reserved)
1357 {
1358 DWORD size = 64*1024*1024;
1359 char *addr;
1360 if (committed && reserved && committed < reserved)
1361 {
1362 /* Commit last of previous chunk cannot span allocations */
161b471a 1363 addr = (char *) VirtualAlloc(committed,reserved-committed,MEM_COMMIT,PAGE_READWRITE);
bbc8f9de 1364 if (addr)
1365 committed = reserved;
1366 }
1367 /* Reserve some (more) space
1368 * Note this is a little sneaky, 1st call passes NULL as reserved
1369 * so lets system choose where we start, subsequent calls pass
1370 * the old end address so ask for a contiguous block
1371 */
161b471a 1372 addr = (char *) VirtualAlloc(reserved,size,MEM_RESERVE,PAGE_NOACCESS);
bbc8f9de 1373 if (addr)
1374 {
1375 reserved = addr+size;
1376 if (!base)
1377 base = addr;
1378 if (!committed)
1379 committed = base;
1380 if (!brk)
1381 brk = committed;
1382 }
1383 else
1384 {
1385 return (void *) -1;
1386 }
1387 }
1388 result = brk;
1389 brk += need;
1390 if (brk > committed)
1391 {
1392 DWORD size = ((brk-committed + pagesize -1)/pagesize) * pagesize;
161b471a 1393 char *addr = (char *) VirtualAlloc(committed,size,MEM_COMMIT,PAGE_READWRITE);
bbc8f9de 1394 if (addr)
1395 {
1396 committed += size;
1397 }
1398 else
1399 return (void *) -1;
1400 }
1401 return result;
1402}
1403
1404#endif
1405#endif
1406
84902520 1407DllExport void*
1408win32_malloc(size_t size)
1409{
390b85e7 1410 return malloc(size);
84902520 1411}
1412
1413DllExport void*
1414win32_calloc(size_t numitems, size_t size)
1415{
390b85e7 1416 return calloc(numitems,size);
84902520 1417}
1418
1419DllExport void*
1420win32_realloc(void *block, size_t size)
1421{
390b85e7 1422 return realloc(block,size);
84902520 1423}
1424
1425DllExport void
1426win32_free(void *block)
1427{
390b85e7 1428 free(block);
84902520 1429}
1430
bbc8f9de 1431
68dc0745 1432int
65e48ea9 1433win32_open_osfhandle(long handle, int flags)
0a753a76 1434{
390b85e7 1435 return _open_osfhandle(handle, flags);
0a753a76 1436}
1437
68dc0745 1438long
65e48ea9 1439win32_get_osfhandle(int fd)
0a753a76 1440{
390b85e7 1441 return _get_osfhandle(fd);
0a753a76 1442}
7bac28a0 1443
7bac28a0 1444/*
1445 * Extras.
1446 */
1447
ad2e33dc 1448static
1449XS(w32_GetCwd)
1450{
1451 dXSARGS;
1452 SV *sv = sv_newmortal();
1453 /* Make one call with zero size - return value is required size */
1454 DWORD len = GetCurrentDirectory((DWORD)0,NULL);
1455 SvUPGRADE(sv,SVt_PV);
1456 SvGROW(sv,len);
1457 SvCUR(sv) = GetCurrentDirectory((DWORD) SvLEN(sv), SvPVX(sv));
1458 /*
1459 * If result != 0
1460 * then it worked, set PV valid,
1461 * else leave it 'undef'
1462 */
1463 if (SvCUR(sv))
1464 SvPOK_on(sv);
1465 EXTEND(sp,1);
1466 ST(0) = sv;
1467 XSRETURN(1);
1468}
1469
1470static
1471XS(w32_SetCwd)
1472{
1473 dXSARGS;
1474 if (items != 1)
1475 croak("usage: Win32::SetCurrentDirectory($cwd)");
1476 if (SetCurrentDirectory(SvPV(ST(0),na)))
1477 XSRETURN_YES;
1478
1479 XSRETURN_NO;
1480}
1481
1482static
1483XS(w32_GetNextAvailDrive)
1484{
1485 dXSARGS;
1486 char ix = 'C';
1487 char root[] = "_:\\";
1488 while (ix <= 'Z') {
1489 root[0] = ix++;
1490 if (GetDriveType(root) == 1) {
1491 root[2] = '\0';
1492 XSRETURN_PV(root);
1493 }
1494 }
1495 XSRETURN_UNDEF;
1496}
1497
1498static
1499XS(w32_GetLastError)
1500{
1501 dXSARGS;
1502 XSRETURN_IV(GetLastError());
1503}
1504
1505static
1506XS(w32_LoginName)
1507{
1508 dXSARGS;
1509 char name[256];
1510 DWORD size = sizeof(name);
1511 if (GetUserName(name,&size)) {
1512 /* size includes NULL */
1513 ST(0) = sv_2mortal(newSVpv(name,size-1));
1514 XSRETURN(1);
1515 }
1516 XSRETURN_UNDEF;
1517}
1518
1519static
1520XS(w32_NodeName)
1521{
1522 dXSARGS;
1523 char name[MAX_COMPUTERNAME_LENGTH+1];
1524 DWORD size = sizeof(name);
1525 if (GetComputerName(name,&size)) {
1526 /* size does NOT include NULL :-( */
1527 ST(0) = sv_2mortal(newSVpv(name,size));
1528 XSRETURN(1);
1529 }
1530 XSRETURN_UNDEF;
1531}
1532
1533
1534static
1535XS(w32_DomainName)
1536{
1537 dXSARGS;
1538 char name[256];
1539 DWORD size = sizeof(name);
1540 if (GetUserName(name,&size)) {
1541 char sid[1024];
1542 DWORD sidlen = sizeof(sid);
1543 char dname[256];
1544 DWORD dnamelen = sizeof(dname);
1545 SID_NAME_USE snu;
1546 if (LookupAccountName(NULL, name, &sid, &sidlen,
1547 dname, &dnamelen, &snu)) {
1548 XSRETURN_PV(dname); /* all that for this */
1549 }
1550 }
1551 XSRETURN_UNDEF;
1552}
1553
1554static
1555XS(w32_FsType)
1556{
1557 dXSARGS;
1558 char fsname[256];
1559 DWORD flags, filecomplen;
1560 if (GetVolumeInformation(NULL, NULL, 0, NULL, &filecomplen,
1561 &flags, fsname, sizeof(fsname))) {
1562 if (GIMME == G_ARRAY) {
1563 XPUSHs(sv_2mortal(newSVpv(fsname,0)));
1564 XPUSHs(sv_2mortal(newSViv(flags)));
1565 XPUSHs(sv_2mortal(newSViv(filecomplen)));
1566 PUTBACK;
1567 return;
1568 }
1569 XSRETURN_PV(fsname);
1570 }
1571 XSRETURN_UNDEF;
1572}
1573
1574static
1575XS(w32_GetOSVersion)
1576{
1577 dXSARGS;
1578 OSVERSIONINFO osver;
1579
1580 osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
1581 if (GetVersionEx(&osver)) {
1582 XPUSHs(newSVpv(osver.szCSDVersion, 0));
1583 XPUSHs(newSViv(osver.dwMajorVersion));
1584 XPUSHs(newSViv(osver.dwMinorVersion));
1585 XPUSHs(newSViv(osver.dwBuildNumber));
1586 XPUSHs(newSViv(osver.dwPlatformId));
1587 PUTBACK;
1588 return;
1589 }
1590 XSRETURN_UNDEF;
1591}
1592
1593static
1594XS(w32_IsWinNT)
1595{
1596 dXSARGS;
1597 XSRETURN_IV(IsWinNT());
1598}
1599
1600static
1601XS(w32_IsWin95)
1602{
1603 dXSARGS;
1604 XSRETURN_IV(IsWin95());
1605}
1606
1607static
1608XS(w32_FormatMessage)
1609{
1610 dXSARGS;
1611 DWORD source = 0;
1612 char msgbuf[1024];
1613
1614 if (items != 1)
1615 croak("usage: Win32::FormatMessage($errno)");
1616
1617 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
1618 &source, SvIV(ST(0)), 0,
1619 msgbuf, sizeof(msgbuf)-1, NULL))
1620 XSRETURN_PV(msgbuf);
1621
1622 XSRETURN_UNDEF;
1623}
1624
1625static
1626XS(w32_Spawn)
1627{
1628 dXSARGS;
1629 char *cmd, *args;
1630 PROCESS_INFORMATION stProcInfo;
1631 STARTUPINFO stStartInfo;
1632 BOOL bSuccess = FALSE;
1633
1634 if(items != 3)
1635 croak("usage: Win32::Spawn($cmdName, $args, $PID)");
1636
1637 cmd = SvPV(ST(0),na);
1638 args = SvPV(ST(1), na);
1639
1640 memset(&stStartInfo, 0, sizeof(stStartInfo)); /* Clear the block */
1641 stStartInfo.cb = sizeof(stStartInfo); /* Set the structure size */
1642 stStartInfo.dwFlags = STARTF_USESHOWWINDOW; /* Enable wShowWindow control */
1643 stStartInfo.wShowWindow = SW_SHOWMINNOACTIVE; /* Start min (normal) */
1644
1645 if(CreateProcess(
1646 cmd, /* Image path */
1647 args, /* Arguments for command line */
1648 NULL, /* Default process security */
1649 NULL, /* Default thread security */
1650 FALSE, /* Must be TRUE to use std handles */
1651 NORMAL_PRIORITY_CLASS, /* No special scheduling */
1652 NULL, /* Inherit our environment block */
1653 NULL, /* Inherit our currrent directory */
1654 &stStartInfo, /* -> Startup info */
1655 &stProcInfo)) /* <- Process info (if OK) */
1656 {
1657 CloseHandle(stProcInfo.hThread);/* library source code does this. */
1658 sv_setiv(ST(2), stProcInfo.dwProcessId);
1659 bSuccess = TRUE;
1660 }
1661 XSRETURN_IV(bSuccess);
1662}
1663
1664static
1665XS(w32_GetTickCount)
1666{
1667 dXSARGS;
1668 XSRETURN_IV(GetTickCount());
1669}
1670
1671static
1672XS(w32_GetShortPathName)
1673{
1674 dXSARGS;
1675 SV *shortpath;
e8bab181 1676 DWORD len;
ad2e33dc 1677
1678 if(items != 1)
1679 croak("usage: Win32::GetShortPathName($longPathName)");
1680
1681 shortpath = sv_mortalcopy(ST(0));
1682 SvUPGRADE(shortpath, SVt_PV);
1683 /* src == target is allowed */
e8bab181 1684 do {
1685 len = GetShortPathName(SvPVX(shortpath),
1686 SvPVX(shortpath),
1687 SvLEN(shortpath));
1688 } while (len >= SvLEN(shortpath) && sv_grow(shortpath,len+1));
1689 if (len) {
1690 SvCUR_set(shortpath,len);
ad2e33dc 1691 ST(0) = shortpath;
e8bab181 1692 }
ad2e33dc 1693 else
1694 ST(0) = &sv_undef;
1695 XSRETURN(1);
1696}
1697
1698void
f3986ebb 1699Perl_init_os_extras()
ad2e33dc 1700{
1701 char *file = __FILE__;
1702 dXSUB_SYS;
1703
1704 /* XXX should be removed after checking with Nick */
1705 newXS("Win32::GetCurrentDirectory", w32_GetCwd, file);
1706
1707 /* these names are Activeware compatible */
1708 newXS("Win32::GetCwd", w32_GetCwd, file);
1709 newXS("Win32::SetCwd", w32_SetCwd, file);
1710 newXS("Win32::GetNextAvailDrive", w32_GetNextAvailDrive, file);
1711 newXS("Win32::GetLastError", w32_GetLastError, file);
1712 newXS("Win32::LoginName", w32_LoginName, file);
1713 newXS("Win32::NodeName", w32_NodeName, file);
1714 newXS("Win32::DomainName", w32_DomainName, file);
1715 newXS("Win32::FsType", w32_FsType, file);
1716 newXS("Win32::GetOSVersion", w32_GetOSVersion, file);
1717 newXS("Win32::IsWinNT", w32_IsWinNT, file);
1718 newXS("Win32::IsWin95", w32_IsWin95, file);
1719 newXS("Win32::FormatMessage", w32_FormatMessage, file);
1720 newXS("Win32::Spawn", w32_Spawn, file);
1721 newXS("Win32::GetTickCount", w32_GetTickCount, file);
1722 newXS("Win32::GetShortPathName", w32_GetShortPathName, file);
1723
1724 /* XXX Bloat Alert! The following Activeware preloads really
1725 * ought to be part of Win32::Sys::*, so they're not included
1726 * here.
1727 */
1728 /* LookupAccountName
1729 * LookupAccountSID
1730 * InitiateSystemShutdown
1731 * AbortSystemShutdown
1732 * ExpandEnvrironmentStrings
1733 */
1734}
1735
1736void
1737Perl_win32_init(int *argcp, char ***argvp)
1738{
1739 /* Disable floating point errors, Perl will trap the ones we
1740 * care about. VC++ RTL defaults to switching these off
1741 * already, but the Borland RTL doesn't. Since we don't
1742 * want to be at the vendor's whim on the default, we set
1743 * it explicitly here.
1744 */
a835ef8a 1745#if !defined(_ALPHA_) && !defined(__GNUC__)
ad2e33dc 1746 _control87(MCW_EM, MCW_EM);
3dc9191e 1747#endif
dc86dda3 1748 MALLOC_INIT;
ad2e33dc 1749}
d55594ae 1750
a868473f 1751#ifdef USE_BINMODE_SCRIPTS
1752
1753void
1754win32_strip_return(SV *sv)
1755{
1756 char *s = SvPVX(sv);
1757 char *e = s+SvCUR(sv);
1758 char *d = s;
1759 while (s < e)
1760 {
1761 if (*s == '\r' && s[1] == '\n')
1762 {
1763 *d++ = '\n';
1764 s += 2;
1765 }
1766 else
1767 {
1768 *d++ = *s++;
1769 }
1770 }
1771 SvCUR_set(sv,d-SvPVX(sv));
1772}
1773
1774#endif
1775
1776
d55594ae 1777
1778
1779
161b471a 1780
a835ef8a 1781
22239a37 1782