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.
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.
10 #define PERLIO_NOT_STDIO 0
11 #define WIN32_LEAN_AND_MEAN
12 #define WIN32IO_IS_STDIO
19 # define HWND_MESSAGE ((HWND)-3)
21 #ifndef WC_NO_BEST_FIT_CHARS
22 # define WC_NO_BEST_FIT_CHARS 0x00000400
28 /* #include "config.h" */
30 #if !defined(PERLIO_IS_STDIO) && !defined(USE_SFIO)
38 /* GCC-2.95.2/Mingw32-1.1 forgot the WINAPI on CommandLineToArgvW() */
39 #if defined(__MINGW32__) && (__MINGW32_MAJOR_VERSION==1)
40 # include <shellapi.h>
42 EXTERN_C LPWSTR* WINAPI CommandLineToArgvW(LPCWSTR lpCommandLine, int * pNumArgs);
46 #define PERL_NO_GET_CONTEXT
52 /* assert.h conflicts with #define of assert in perl.h */
59 #if defined(_MSC_VER) || defined(__MINGW32__)
60 #include <sys/utime.h>
65 /* Mingw32 defaults to globing command line
66 * So we turn it off like this:
71 #if defined(__MINGW32__) && (__MINGW32_MAJOR_VERSION==1)
72 /* Mingw32-1.1 is missing some prototypes */
74 FILE * _wfopen(LPCWSTR wszFileName, LPCWSTR wszMode);
75 FILE * _wfdopen(int nFd, LPCWSTR wszMode);
76 FILE * _freopen(LPCWSTR wszFileName, LPCWSTR wszMode, FILE * pOldStream);
82 #if defined(__BORLANDC__)
84 # define _utimbuf utimbuf
89 #define EXECF_SPAWN_NOWAIT 3
91 #if defined(PERL_IMPLICIT_SYS)
92 # undef win32_get_privlib
93 # define win32_get_privlib g_win32_get_privlib
94 # undef win32_get_sitelib
95 # define win32_get_sitelib g_win32_get_sitelib
96 # undef win32_get_vendorlib
97 # define win32_get_vendorlib g_win32_get_vendorlib
99 # define getlogin g_getlogin
102 static void get_shell(void);
103 static long tokenize(const char *str, char **dest, char ***destv);
104 static int do_spawn2(pTHX_ const char *cmd, int exectype);
105 static BOOL has_shell_metachars(const char *ptr);
106 static long filetime_to_clock(PFILETIME ft);
107 static BOOL filetime_from_time(PFILETIME ft, time_t t);
108 static char * get_emd_part(SV **leading, char *trailing, ...);
109 static void remove_dead_process(long deceased);
110 static long find_pid(int pid);
111 static char * qualified_path(const char *cmd);
112 static char * win32_get_xlib(const char *pl, const char *xlib,
113 const char *libname);
116 static void remove_dead_pseudo_process(long child);
117 static long find_pseudo_pid(int pid);
121 HANDLE w32_perldll_handle = INVALID_HANDLE_VALUE;
122 char w32_module_name[MAX_PATH+1];
125 static OSVERSIONINFO g_osver = {0, 0, 0, 0, 0, ""};
128 /* Silence STDERR grumblings from Borland's math library. */
130 _matherr(struct _exception *a)
138 void my_invalid_parameter_handler(const wchar_t* expression,
139 const wchar_t* function,
145 wprintf(L"Invalid parameter detected in function %s."
146 L" File: %s Line: %d\n", function, file, line);
147 wprintf(L"Expression: %s\n", expression);
155 return (g_osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
161 return (g_osver.dwPlatformId == VER_PLATFORM_WIN32_NT);
165 set_w32_module_name(void)
168 GetModuleFileName((HMODULE)((w32_perldll_handle == INVALID_HANDLE_VALUE)
169 ? GetModuleHandle(NULL)
170 : w32_perldll_handle),
171 w32_module_name, sizeof(w32_module_name));
173 /* remove \\?\ prefix */
174 if (memcmp(w32_module_name, "\\\\?\\", 4) == 0)
175 memmove(w32_module_name, w32_module_name+4, strlen(w32_module_name+4)+1);
177 /* try to get full path to binary (which may be mangled when perl is
178 * run from a 16-bit app) */
179 /*PerlIO_printf(Perl_debug_log, "Before %s\n", w32_module_name);*/
180 (void)win32_longpath(w32_module_name);
181 /*PerlIO_printf(Perl_debug_log, "After %s\n", w32_module_name);*/
183 /* normalize to forward slashes */
184 ptr = w32_module_name;
192 /* *svp (if non-NULL) is expected to be POK (valid allocated SvPVX(*svp)) */
194 get_regstr_from(HKEY hkey, const char *valuename, SV **svp)
196 /* Retrieve a REG_SZ or REG_EXPAND_SZ from the registry */
199 const char *subkey = "Software\\Perl";
203 retval = RegOpenKeyEx(hkey, subkey, 0, KEY_READ, &handle);
204 if (retval == ERROR_SUCCESS) {
206 retval = RegQueryValueEx(handle, valuename, 0, &type, NULL, &datalen);
207 if (retval == ERROR_SUCCESS
208 && (type == REG_SZ || type == REG_EXPAND_SZ))
212 *svp = sv_2mortal(newSVpvn("",0));
213 SvGROW(*svp, datalen);
214 retval = RegQueryValueEx(handle, valuename, 0, NULL,
215 (PBYTE)SvPVX(*svp), &datalen);
216 if (retval == ERROR_SUCCESS) {
218 SvCUR_set(*svp,datalen-1);
226 /* *svp (if non-NULL) is expected to be POK (valid allocated SvPVX(*svp)) */
228 get_regstr(const char *valuename, SV **svp)
230 char *str = get_regstr_from(HKEY_CURRENT_USER, valuename, svp);
232 str = get_regstr_from(HKEY_LOCAL_MACHINE, valuename, svp);
236 /* *prev_pathp (if non-NULL) is expected to be POK (valid allocated SvPVX(sv)) */
238 get_emd_part(SV **prev_pathp, char *trailing_path, ...)
242 char mod_name[MAX_PATH+1];
248 va_start(ap, trailing_path);
249 strip = va_arg(ap, char *);
251 sprintf(base, "%d.%d", (int)PERL_REVISION, (int)PERL_VERSION);
252 baselen = strlen(base);
254 if (!*w32_module_name) {
255 set_w32_module_name();
257 strcpy(mod_name, w32_module_name);
258 ptr = strrchr(mod_name, '/');
259 while (ptr && strip) {
260 /* look for directories to skip back */
263 ptr = strrchr(mod_name, '/');
264 /* avoid stripping component if there is no slash,
265 * or it doesn't match ... */
266 if (!ptr || stricmp(ptr+1, strip) != 0) {
267 /* ... but not if component matches m|5\.$patchlevel.*| */
268 if (!ptr || !(*strip == '5' && *(ptr+1) == '5'
269 && strncmp(strip, base, baselen) == 0
270 && strncmp(ptr+1, base, baselen) == 0))
276 strip = va_arg(ap, char *);
284 strcpy(++ptr, trailing_path);
286 /* only add directory if it exists */
287 if (GetFileAttributes(mod_name) != (DWORD) -1) {
288 /* directory exists */
291 *prev_pathp = sv_2mortal(newSVpvn("",0));
292 else if (SvPVX(*prev_pathp))
293 sv_catpvn(*prev_pathp, ";", 1);
294 sv_catpv(*prev_pathp, mod_name);
295 return SvPVX(*prev_pathp);
302 win32_get_privlib(const char *pl)
305 char *stdlib = "lib";
306 char buffer[MAX_PATH+1];
309 /* $stdlib = $HKCU{"lib-$]"} || $HKLM{"lib-$]"} || $HKCU{"lib"} || $HKLM{"lib"} || ""; */
310 sprintf(buffer, "%s-%s", stdlib, pl);
311 if (!get_regstr(buffer, &sv))
312 (void)get_regstr(stdlib, &sv);
314 /* $stdlib .= ";$EMD/../../lib" */
315 return get_emd_part(&sv, stdlib, ARCHNAME, "bin", Nullch);
319 win32_get_xlib(const char *pl, const char *xlib, const char *libname)
323 char pathstr[MAX_PATH+1];
327 /* $HKCU{"$xlib-$]"} || $HKLM{"$xlib-$]"} . ---; */
328 sprintf(regstr, "%s-%s", xlib, pl);
329 (void)get_regstr(regstr, &sv1);
332 * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/$libname/$]/lib"; */
333 sprintf(pathstr, "%s/%s/lib", libname, pl);
334 (void)get_emd_part(&sv1, pathstr, ARCHNAME, "bin", pl, Nullch);
336 /* $HKCU{$xlib} || $HKLM{$xlib} . ---; */
337 (void)get_regstr(xlib, &sv2);
340 * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/$libname/lib"; */
341 sprintf(pathstr, "%s/lib", libname);
342 (void)get_emd_part(&sv2, pathstr, ARCHNAME, "bin", pl, Nullch);
351 sv_catpvn(sv1, ";", 1);
358 win32_get_sitelib(const char *pl)
360 return win32_get_xlib(pl, "sitelib", "site");
363 #ifndef PERL_VENDORLIB_NAME
364 # define PERL_VENDORLIB_NAME "vendor"
368 win32_get_vendorlib(const char *pl)
370 return win32_get_xlib(pl, "vendorlib", PERL_VENDORLIB_NAME);
374 has_shell_metachars(const char *ptr)
380 * Scan string looking for redirection (< or >) or pipe
381 * characters (|) that are not in a quoted string.
382 * Shell variable interpolation (%VAR%) can also happen inside strings.
414 #if !defined(PERL_IMPLICIT_SYS)
415 /* since the current process environment is being updated in util.c
416 * the library functions will get the correct environment
419 Perl_my_popen(pTHX_ const char *cmd, const char *mode)
422 #define fixcmd(x) { \
423 char *pspace = strchr((x),' '); \
426 while (p < pspace) { \
437 PERL_FLUSHALL_FOR_CHILD;
438 return win32_popen(cmd, mode);
442 Perl_my_pclose(pTHX_ PerlIO *fp)
444 return win32_pclose(fp);
448 DllExport unsigned long
451 return (unsigned long)g_osver.dwPlatformId;
461 return -((int)w32_pseudo_id);
464 /* Windows 9x appears to always reports a pid for threads and processes
465 * that has the high bit set. So we treat the lower 31 bits as the
466 * "real" PID for Perl's purposes. */
467 if (IsWin95() && pid < 0)
472 /* Tokenize a string. Words are null-separated, and the list
473 * ends with a doubled null. Any character (except null and
474 * including backslash) may be escaped by preceding it with a
475 * backslash (the backslash will be stripped).
476 * Returns number of words in result buffer.
479 tokenize(const char *str, char **dest, char ***destv)
481 char *retstart = Nullch;
482 char **retvstart = 0;
486 int slen = strlen(str);
488 register char **retv;
489 Newx(ret, slen+2, char);
490 Newx(retv, (slen+3)/2, char*);
498 if (*ret == '\\' && *str)
500 else if (*ret == ' ') {
516 retvstart[items] = Nullch;
529 if (!w32_perlshell_tokens) {
530 /* we don't use COMSPEC here for two reasons:
531 * 1. the same reason perl on UNIX doesn't use SHELL--rampant and
532 * uncontrolled unportability of the ensuing scripts.
533 * 2. PERL5SHELL could be set to a shell that may not be fit for
534 * interactive use (which is what most programs look in COMSPEC
537 const char* defaultshell = (IsWinNT()
538 ? "cmd.exe /x/d/c" : "command.com /c");
539 const char *usershell = PerlEnv_getenv("PERL5SHELL");
540 w32_perlshell_items = tokenize(usershell ? usershell : defaultshell,
541 &w32_perlshell_tokens,
547 Perl_do_aspawn(pTHX_ SV *really, SV **mark, SV **sp)
559 Newx(argv, (sp - mark) + w32_perlshell_items + 2, char*);
561 if (SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) {
566 while (++mark <= sp) {
567 if (*mark && (str = SvPV_nolen(*mark)))
574 status = win32_spawnvp(flag,
575 (const char*)(really ? SvPV_nolen(really) : argv[0]),
576 (const char* const*)argv);
578 if (status < 0 && (errno == ENOEXEC || errno == ENOENT)) {
579 /* possible shell-builtin, invoke with shell */
581 sh_items = w32_perlshell_items;
583 argv[index+sh_items] = argv[index];
584 while (--sh_items >= 0)
585 argv[sh_items] = w32_perlshell_vec[sh_items];
587 status = win32_spawnvp(flag,
588 (const char*)(really ? SvPV_nolen(really) : argv[0]),
589 (const char* const*)argv);
592 if (flag == P_NOWAIT) {
594 PL_statusvalue = -1; /* >16bits hint for pp_system() */
598 if (ckWARN(WARN_EXEC))
599 Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't spawn \"%s\": %s", argv[0], strerror(errno));
604 PL_statusvalue = status;
610 /* returns pointer to the next unquoted space or the end of the string */
612 find_next_space(const char *s)
614 bool in_quotes = FALSE;
616 /* ignore doubled backslashes, or backslash+quote */
617 if (*s == '\\' && (s[1] == '\\' || s[1] == '"')) {
620 /* keep track of when we're within quotes */
621 else if (*s == '"') {
623 in_quotes = !in_quotes;
625 /* break it up only at spaces that aren't in quotes */
626 else if (!in_quotes && isSPACE(*s))
635 do_spawn2(pTHX_ const char *cmd, int exectype)
641 BOOL needToTry = TRUE;
644 /* Save an extra exec if possible. See if there are shell
645 * metacharacters in it */
646 if (!has_shell_metachars(cmd)) {
647 Newx(argv, strlen(cmd) / 2 + 2, char*);
648 Newx(cmd2, strlen(cmd) + 1, char);
651 for (s = cmd2; *s;) {
652 while (*s && isSPACE(*s))
656 s = find_next_space(s);
664 status = win32_spawnvp(P_WAIT, argv[0],
665 (const char* const*)argv);
667 case EXECF_SPAWN_NOWAIT:
668 status = win32_spawnvp(P_NOWAIT, argv[0],
669 (const char* const*)argv);
672 status = win32_execvp(argv[0], (const char* const*)argv);
675 if (status != -1 || errno == 0)
685 Newx(argv, w32_perlshell_items + 2, char*);
686 while (++i < w32_perlshell_items)
687 argv[i] = w32_perlshell_vec[i];
688 argv[i++] = (char *)cmd;
692 status = win32_spawnvp(P_WAIT, argv[0],
693 (const char* const*)argv);
695 case EXECF_SPAWN_NOWAIT:
696 status = win32_spawnvp(P_NOWAIT, argv[0],
697 (const char* const*)argv);
700 status = win32_execvp(argv[0], (const char* const*)argv);
706 if (exectype == EXECF_SPAWN_NOWAIT) {
708 PL_statusvalue = -1; /* >16bits hint for pp_system() */
712 if (ckWARN(WARN_EXEC))
713 Perl_warner(aTHX_ packWARN(WARN_EXEC), "Can't %s \"%s\": %s",
714 (exectype == EXECF_EXEC ? "exec" : "spawn"),
715 cmd, strerror(errno));
720 PL_statusvalue = status;
726 Perl_do_spawn(pTHX_ char *cmd)
728 return do_spawn2(aTHX_ cmd, EXECF_SPAWN);
732 Perl_do_spawn_nowait(pTHX_ char *cmd)
734 return do_spawn2(aTHX_ cmd, EXECF_SPAWN_NOWAIT);
738 Perl_do_exec(pTHX_ const char *cmd)
740 do_spawn2(aTHX_ cmd, EXECF_EXEC);
744 /* The idea here is to read all the directory names into a string table
745 * (separated by nulls) and when one of the other dir functions is called
746 * return the pointer to the current file name.
749 win32_opendir(const char *filename)
755 char scanname[MAX_PATH+3];
757 WIN32_FIND_DATAA aFindData;
758 WIN32_FIND_DATAW wFindData;
760 char buffer[MAX_PATH*2];
763 len = strlen(filename);
767 /* check to see if filename is a directory */
768 if (win32_stat(filename, &sbuf) < 0 || !S_ISDIR(sbuf.st_mode))
771 /* Get us a DIR structure */
774 /* Create the search pattern */
775 strcpy(scanname, filename);
777 /* bare drive name means look in cwd for drive */
778 if (len == 2 && isALPHA(scanname[0]) && scanname[1] == ':') {
779 scanname[len++] = '.';
780 scanname[len++] = '/';
782 else if (scanname[len-1] != '/' && scanname[len-1] != '\\') {
783 scanname[len++] = '/';
785 scanname[len++] = '*';
786 scanname[len] = '\0';
788 /* do the FindFirstFile call */
790 WCHAR wscanname[sizeof(scanname)];
791 MultiByteToWideChar(CP_ACP, 0, scanname, -1, wscanname, sizeof(wscanname)/sizeof(WCHAR));
792 dirp->handle = FindFirstFileW(PerlDir_mapW(wscanname), &wFindData);
796 dirp->handle = FindFirstFileA(PerlDir_mapA(scanname), &aFindData);
798 if (dirp->handle == INVALID_HANDLE_VALUE) {
799 DWORD err = GetLastError();
800 /* FindFirstFile() fails on empty drives! */
802 case ERROR_FILE_NOT_FOUND:
804 case ERROR_NO_MORE_FILES:
805 case ERROR_PATH_NOT_FOUND:
808 case ERROR_NOT_ENOUGH_MEMORY:
820 BOOL use_default = FALSE;
821 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS,
822 wFindData.cFileName, -1,
823 buffer, sizeof(buffer), NULL, &use_default);
824 if (use_default && *wFindData.cAlternateFileName) {
825 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS,
826 wFindData.cAlternateFileName, -1,
827 buffer, sizeof(buffer), NULL, NULL);
832 ptr = aFindData.cFileName;
834 /* now allocate the first part of the string table for
835 * the filenames that we find.
842 Newx(dirp->start, dirp->size, char);
843 strcpy(dirp->start, ptr);
845 dirp->end = dirp->curr = dirp->start;
851 /* Readdir just returns the current string pointer and bumps the
852 * string pointer to the nDllExport entry.
854 DllExport struct direct *
855 win32_readdir(DIR *dirp)
860 /* first set up the structure to return */
861 len = strlen(dirp->curr);
862 strcpy(dirp->dirstr.d_name, dirp->curr);
863 dirp->dirstr.d_namlen = len;
866 dirp->dirstr.d_ino = dirp->curr - dirp->start;
868 /* Now set up for the next call to readdir */
869 dirp->curr += len + 1;
870 if (dirp->curr >= dirp->end) {
873 WIN32_FIND_DATAA aFindData;
874 char buffer[MAX_PATH*2];
877 /* finding the next file that matches the wildcard
878 * (which should be all of them in this directory!).
881 WIN32_FIND_DATAW wFindData;
882 res = FindNextFileW(dirp->handle, &wFindData);
884 BOOL use_default = FALSE;
885 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS,
886 wFindData.cFileName, -1,
887 buffer, sizeof(buffer), NULL, &use_default);
888 if (use_default && *wFindData.cAlternateFileName) {
889 WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS,
890 wFindData.cAlternateFileName, -1,
891 buffer, sizeof(buffer), NULL, NULL);
897 res = FindNextFileA(dirp->handle, &aFindData);
898 ptr = aFindData.cFileName;
901 long endpos = dirp->end - dirp->start;
902 long newsize = endpos + strlen(ptr) + 1;
903 /* bump the string table size by enough for the
904 * new name and its null terminator */
905 while (newsize > dirp->size) {
906 long curpos = dirp->curr - dirp->start;
908 Renew(dirp->start, dirp->size, char);
909 dirp->curr = dirp->start + curpos;
911 strcpy(dirp->start + endpos, ptr);
912 dirp->end = dirp->start + newsize;
918 return &(dirp->dirstr);
924 /* Telldir returns the current string pointer position */
926 win32_telldir(DIR *dirp)
928 return (dirp->curr - dirp->start);
932 /* Seekdir moves the string pointer to a previously saved position
933 * (returned by telldir).
936 win32_seekdir(DIR *dirp, long loc)
938 dirp->curr = dirp->start + loc;
941 /* Rewinddir resets the string pointer to the start */
943 win32_rewinddir(DIR *dirp)
945 dirp->curr = dirp->start;
948 /* free the memory allocated by opendir */
950 win32_closedir(DIR *dirp)
953 if (dirp->handle != INVALID_HANDLE_VALUE)
954 FindClose(dirp->handle);
955 Safefree(dirp->start);
968 * Just pretend that everyone is a superuser. NT will let us know if
969 * we don\'t really have permission to do something.
972 #define ROOT_UID ((uid_t)0)
973 #define ROOT_GID ((gid_t)0)
1002 return (auid == ROOT_UID ? 0 : -1);
1008 return (agid == ROOT_GID ? 0 : -1);
1015 char *buf = w32_getlogin_buffer;
1016 DWORD size = sizeof(w32_getlogin_buffer);
1017 if (GetUserName(buf,&size))
1023 chown(const char *path, uid_t owner, gid_t group)
1030 * XXX this needs strengthening (for PerlIO)
1033 int mkstemp(const char *path)
1036 char buf[MAX_PATH+1];
1040 if (i++ > 10) { /* give up */
1044 if (!GetTempFileNameA((LPCSTR)path, "plr", 1, buf)) {
1048 fd = PerlLIO_open3(buf, O_CREAT|O_RDWR|O_EXCL, 0600);
1058 long child = w32_num_children;
1059 while (--child >= 0) {
1060 if ((int)w32_child_pids[child] == pid)
1067 remove_dead_process(long child)
1071 CloseHandle(w32_child_handles[child]);
1072 Move(&w32_child_handles[child+1], &w32_child_handles[child],
1073 (w32_num_children-child-1), HANDLE);
1074 Move(&w32_child_pids[child+1], &w32_child_pids[child],
1075 (w32_num_children-child-1), DWORD);
1082 find_pseudo_pid(int pid)
1085 long child = w32_num_pseudo_children;
1086 while (--child >= 0) {
1087 if ((int)w32_pseudo_child_pids[child] == pid)
1094 remove_dead_pseudo_process(long child)
1098 CloseHandle(w32_pseudo_child_handles[child]);
1099 Move(&w32_pseudo_child_handles[child+1], &w32_pseudo_child_handles[child],
1100 (w32_num_pseudo_children-child-1), HANDLE);
1101 Move(&w32_pseudo_child_pids[child+1], &w32_pseudo_child_pids[child],
1102 (w32_num_pseudo_children-child-1), DWORD);
1103 Move(&w32_pseudo_child_message_hwnds[child+1], &w32_pseudo_child_message_hwnds[child],
1104 (w32_num_pseudo_children-child-1), HWND);
1105 w32_num_pseudo_children--;
1111 win32_kill(int pid, int sig)
1119 /* it is a pseudo-forked child */
1120 child = find_pseudo_pid(-pid);
1122 HWND hwnd = w32_pseudo_child_message_hwnds[child];
1123 hProcess = w32_pseudo_child_handles[child];
1126 /* "Does process exist?" use of kill */
1130 /* kill -9 style un-graceful exit */
1131 if (TerminateThread(hProcess, sig)) {
1132 remove_dead_pseudo_process(child);
1139 /* pseudo-process has not yet properly initialized if hwnd isn't set */
1140 while (hwnd == INVALID_HANDLE_VALUE && count < 5) {
1141 /* Yield and wait for the other thread to send us its message_hwnd */
1143 win32_async_check(aTHX);
1146 if (hwnd != INVALID_HANDLE_VALUE) {
1147 /* We fake signals to pseudo-processes using Win32
1148 * message queue. In Win9X the pids are negative already. */
1149 if ((hwnd != NULL && PostMessage(hwnd, WM_USER_KILL, sig, 0)) ||
1150 PostThreadMessage(IsWin95() ? pid : -pid, WM_USER_KILL, sig, 0))
1152 /* It might be us ... */
1161 else if (IsWin95()) {
1169 child = find_pid(pid);
1171 hProcess = w32_child_handles[child];
1174 /* "Does process exist?" use of kill */
1177 if (GenerateConsoleCtrlEvent(CTRL_C_EVENT,pid))
1182 if (GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,pid))
1185 default: /* For now be backwards compatible with perl5.6 */
1187 if (TerminateProcess(hProcess, sig)) {
1188 remove_dead_process(child);
1197 hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE,
1198 (IsWin95() ? -pid : pid));
1202 /* "Does process exist?" use of kill */
1206 if (GenerateConsoleCtrlEvent(CTRL_C_EVENT,pid))
1211 if (GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,pid))
1214 default: /* For now be backwards compatible with perl5.6 */
1216 if (TerminateProcess(hProcess, sig))
1221 CloseHandle(hProcess);
1231 win32_stat(const char *path, Stat_t *sbuf)
1234 char buffer[MAX_PATH+1];
1235 int l = strlen(path);
1238 BOOL expect_dir = FALSE;
1240 GV *gv_sloppy = gv_fetchpvs("\027IN32_SLOPPY_STAT",
1241 GV_NOTQUAL, SVt_PV);
1242 BOOL sloppy = gv_sloppy && SvTRUE(GvSV(gv_sloppy));
1245 switch(path[l - 1]) {
1246 /* FindFirstFile() and stat() are buggy with a trailing
1247 * slashes, except for the root directory of a drive */
1250 if (l > sizeof(buffer)) {
1251 errno = ENAMETOOLONG;
1255 strncpy(buffer, path, l);
1256 /* remove additional trailing slashes */
1257 while (l > 1 && (buffer[l-1] == '/' || buffer[l-1] == '\\'))
1259 /* add back slash if we otherwise end up with just a drive letter */
1260 if (l == 2 && isALPHA(buffer[0]) && buffer[1] == ':')
1267 /* FindFirstFile() is buggy with "x:", so add a dot :-( */
1269 if (l == 2 && isALPHA(path[0])) {
1270 buffer[0] = path[0];
1281 path = PerlDir_mapA(path);
1285 /* We must open & close the file once; otherwise file attribute changes */
1286 /* might not yet have propagated to "other" hard links of the same file. */
1287 /* This also gives us an opportunity to determine the number of links. */
1288 HANDLE handle = CreateFileA(path, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
1289 if (handle != INVALID_HANDLE_VALUE) {
1290 BY_HANDLE_FILE_INFORMATION bhi;
1291 if (GetFileInformationByHandle(handle, &bhi))
1292 nlink = bhi.nNumberOfLinks;
1293 CloseHandle(handle);
1297 /* path will be mapped correctly above */
1298 #if defined(WIN64) || defined(USE_LARGE_FILES)
1299 res = _stati64(path, sbuf);
1301 res = stat(path, sbuf);
1303 sbuf->st_nlink = nlink;
1306 /* CRT is buggy on sharenames, so make sure it really isn't.
1307 * XXX using GetFileAttributesEx() will enable us to set
1308 * sbuf->st_*time (but note that's not available on the
1309 * Windows of 1995) */
1310 DWORD r = GetFileAttributesA(path);
1311 if (r != 0xffffffff && (r & FILE_ATTRIBUTE_DIRECTORY)) {
1312 /* sbuf may still contain old garbage since stat() failed */
1313 Zero(sbuf, 1, Stat_t);
1314 sbuf->st_mode = S_IFDIR | S_IREAD;
1316 if (!(r & FILE_ATTRIBUTE_READONLY))
1317 sbuf->st_mode |= S_IWRITE | S_IEXEC;
1322 if (l == 3 && isALPHA(path[0]) && path[1] == ':'
1323 && (path[2] == '\\' || path[2] == '/'))
1325 /* The drive can be inaccessible, some _stat()s are buggy */
1326 if (!GetVolumeInformationA(path,NULL,0,NULL,NULL,NULL,NULL,0)) {
1331 if (expect_dir && !S_ISDIR(sbuf->st_mode)) {
1336 if (S_ISDIR(sbuf->st_mode))
1337 sbuf->st_mode |= S_IWRITE | S_IEXEC;
1338 else if (S_ISREG(sbuf->st_mode)) {
1340 if (l >= 4 && path[l-4] == '.') {
1341 const char *e = path + l - 3;
1342 if (strnicmp(e,"exe",3)
1343 && strnicmp(e,"bat",3)
1344 && strnicmp(e,"com",3)
1345 && (IsWin95() || strnicmp(e,"cmd",3)))
1346 sbuf->st_mode &= ~S_IEXEC;
1348 sbuf->st_mode |= S_IEXEC;
1351 sbuf->st_mode &= ~S_IEXEC;
1352 /* Propagate permissions to _group_ and _others_ */
1353 perms = sbuf->st_mode & (S_IREAD|S_IWRITE|S_IEXEC);
1354 sbuf->st_mode |= (perms>>3) | (perms>>6);
1361 #define isSLASH(c) ((c) == '/' || (c) == '\\')
1362 #define SKIP_SLASHES(s) \
1364 while (*(s) && isSLASH(*(s))) \
1367 #define COPY_NONSLASHES(d,s) \
1369 while (*(s) && !isSLASH(*(s))) \
1373 /* Find the longname of a given path. path is destructively modified.
1374 * It should have space for at least MAX_PATH characters. */
1376 win32_longpath(char *path)
1378 WIN32_FIND_DATA fdata;
1380 char tmpbuf[MAX_PATH+1];
1381 char *tmpstart = tmpbuf;
1388 if (isALPHA(path[0]) && path[1] == ':') {
1390 *tmpstart++ = path[0];
1394 else if (isSLASH(path[0]) && isSLASH(path[1])) {
1396 *tmpstart++ = path[0];
1397 *tmpstart++ = path[1];
1398 SKIP_SLASHES(start);
1399 COPY_NONSLASHES(tmpstart,start); /* copy machine name */
1401 *tmpstart++ = *start++;
1402 SKIP_SLASHES(start);
1403 COPY_NONSLASHES(tmpstart,start); /* copy share name */
1408 /* copy initial slash, if any */
1409 if (isSLASH(*start)) {
1410 *tmpstart++ = *start++;
1412 SKIP_SLASHES(start);
1415 /* FindFirstFile() expands "." and "..", so we need to pass
1416 * those through unmolested */
1418 && (!start[1] || isSLASH(start[1])
1419 || (start[1] == '.' && (!start[2] || isSLASH(start[2])))))
1421 COPY_NONSLASHES(tmpstart,start); /* copy "." or ".." */
1426 /* if this is the end, bust outta here */
1430 /* now we're at a non-slash; walk up to next slash */
1431 while (*start && !isSLASH(*start))
1434 /* stop and find full name of component */
1437 fhand = FindFirstFile(path,&fdata);
1439 if (fhand != INVALID_HANDLE_VALUE) {
1440 STRLEN len = strlen(fdata.cFileName);
1441 if ((STRLEN)(tmpbuf + sizeof(tmpbuf) - tmpstart) > len) {
1442 strcpy(tmpstart, fdata.cFileName);
1453 /* failed a step, just return without side effects */
1454 /*PerlIO_printf(Perl_debug_log, "Failed to find %s\n", path);*/
1459 strcpy(path,tmpbuf);
1464 win32_getenv(const char *name)
1468 SV *curitem = Nullsv;
1470 needlen = GetEnvironmentVariableA(name,NULL,0);
1472 curitem = sv_2mortal(newSVpvn("", 0));
1474 SvGROW(curitem, needlen+1);
1475 needlen = GetEnvironmentVariableA(name,SvPVX(curitem),
1477 } while (needlen >= SvLEN(curitem));
1478 SvCUR_set(curitem, needlen);
1481 /* allow any environment variables that begin with 'PERL'
1482 to be stored in the registry */
1483 if (strncmp(name, "PERL", 4) == 0)
1484 (void)get_regstr(name, &curitem);
1486 if (curitem && SvCUR(curitem))
1487 return SvPVX(curitem);
1493 win32_putenv(const char *name)
1501 Newx(curitem,strlen(name)+1,char);
1502 strcpy(curitem, name);
1503 val = strchr(curitem, '=');
1505 /* The sane way to deal with the environment.
1506 * Has these advantages over putenv() & co.:
1507 * * enables us to store a truly empty value in the
1508 * environment (like in UNIX).
1509 * * we don't have to deal with RTL globals, bugs and leaks.
1511 * Why you may want to enable USE_WIN32_RTL_ENV:
1512 * * environ[] and RTL functions will not reflect changes,
1513 * which might be an issue if extensions want to access
1514 * the env. via RTL. This cuts both ways, since RTL will
1515 * not see changes made by extensions that call the Win32
1516 * functions directly, either.
1520 if (SetEnvironmentVariableA(curitem, *val ? val : NULL))
1529 filetime_to_clock(PFILETIME ft)
1531 __int64 qw = ft->dwHighDateTime;
1533 qw |= ft->dwLowDateTime;
1534 qw /= 10000; /* File time ticks at 0.1uS, clock at 1mS */
1539 win32_times(struct tms *timebuf)
1544 clock_t process_time_so_far = clock();
1545 if (GetProcessTimes(GetCurrentProcess(), &dummy, &dummy,
1547 timebuf->tms_utime = filetime_to_clock(&user);
1548 timebuf->tms_stime = filetime_to_clock(&kernel);
1549 timebuf->tms_cutime = 0;
1550 timebuf->tms_cstime = 0;
1552 /* That failed - e.g. Win95 fallback to clock() */
1553 timebuf->tms_utime = process_time_so_far;
1554 timebuf->tms_stime = 0;
1555 timebuf->tms_cutime = 0;
1556 timebuf->tms_cstime = 0;
1558 return process_time_so_far;
1561 /* fix utime() so it works on directories in NT */
1563 filetime_from_time(PFILETIME pFileTime, time_t Time)
1565 struct tm *pTM = localtime(&Time);
1566 SYSTEMTIME SystemTime;
1572 SystemTime.wYear = pTM->tm_year + 1900;
1573 SystemTime.wMonth = pTM->tm_mon + 1;
1574 SystemTime.wDay = pTM->tm_mday;
1575 SystemTime.wHour = pTM->tm_hour;
1576 SystemTime.wMinute = pTM->tm_min;
1577 SystemTime.wSecond = pTM->tm_sec;
1578 SystemTime.wMilliseconds = 0;
1580 return SystemTimeToFileTime(&SystemTime, &LocalTime) &&
1581 LocalFileTimeToFileTime(&LocalTime, pFileTime);
1585 win32_unlink(const char *filename)
1591 filename = PerlDir_mapA(filename);
1592 attrs = GetFileAttributesA(filename);
1593 if (attrs == 0xFFFFFFFF) {
1597 if (attrs & FILE_ATTRIBUTE_READONLY) {
1598 (void)SetFileAttributesA(filename, attrs & ~FILE_ATTRIBUTE_READONLY);
1599 ret = unlink(filename);
1601 (void)SetFileAttributesA(filename, attrs);
1604 ret = unlink(filename);
1609 win32_utime(const char *filename, struct utimbuf *times)
1616 struct utimbuf TimeBuffer;
1619 filename = PerlDir_mapA(filename);
1620 rc = utime(filename, times);
1622 /* EACCES: path specifies directory or readonly file */
1623 if (rc == 0 || errno != EACCES /* || !IsWinNT() */)
1626 if (times == NULL) {
1627 times = &TimeBuffer;
1628 time(×->actime);
1629 times->modtime = times->actime;
1632 /* This will (and should) still fail on readonly files */
1633 handle = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE,
1634 FILE_SHARE_READ | FILE_SHARE_DELETE, NULL,
1635 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
1636 if (handle == INVALID_HANDLE_VALUE)
1639 if (GetFileTime(handle, &ftCreate, &ftAccess, &ftWrite) &&
1640 filetime_from_time(&ftAccess, times->actime) &&
1641 filetime_from_time(&ftWrite, times->modtime) &&
1642 SetFileTime(handle, &ftCreate, &ftAccess, &ftWrite))
1647 CloseHandle(handle);
1652 unsigned __int64 ft_i64;
1657 #define Const64(x) x##LL
1659 #define Const64(x) x##i64
1661 /* Number of 100 nanosecond units from 1/1/1601 to 1/1/1970 */
1662 #define EPOCH_BIAS Const64(116444736000000000)
1664 /* NOTE: This does not compute the timezone info (doing so can be expensive,
1665 * and appears to be unsupported even by glibc) */
1667 win32_gettimeofday(struct timeval *tp, void *not_used)
1671 /* this returns time in 100-nanosecond units (i.e. tens of usecs) */
1672 GetSystemTimeAsFileTime(&ft.ft_val);
1674 /* seconds since epoch */
1675 tp->tv_sec = (long)((ft.ft_i64 - EPOCH_BIAS) / Const64(10000000));
1677 /* microseconds remaining */
1678 tp->tv_usec = (long)((ft.ft_i64 / Const64(10)) % Const64(1000000));
1684 win32_uname(struct utsname *name)
1686 struct hostent *hep;
1687 STRLEN nodemax = sizeof(name->nodename)-1;
1690 switch (g_osver.dwPlatformId) {
1691 case VER_PLATFORM_WIN32_WINDOWS:
1692 strcpy(name->sysname, "Windows");
1694 case VER_PLATFORM_WIN32_NT:
1695 strcpy(name->sysname, "Windows NT");
1697 case VER_PLATFORM_WIN32s:
1698 strcpy(name->sysname, "Win32s");
1701 strcpy(name->sysname, "Win32 Unknown");
1706 sprintf(name->release, "%d.%d",
1707 g_osver.dwMajorVersion, g_osver.dwMinorVersion);
1710 sprintf(name->version, "Build %d",
1711 g_osver.dwPlatformId == VER_PLATFORM_WIN32_NT
1712 ? g_osver.dwBuildNumber : (g_osver.dwBuildNumber & 0xffff));
1713 if (g_osver.szCSDVersion[0]) {
1714 char *buf = name->version + strlen(name->version);
1715 sprintf(buf, " (%s)", g_osver.szCSDVersion);
1719 hep = win32_gethostbyname("localhost");
1721 STRLEN len = strlen(hep->h_name);
1722 if (len <= nodemax) {
1723 strcpy(name->nodename, hep->h_name);
1726 strncpy(name->nodename, hep->h_name, nodemax);
1727 name->nodename[nodemax] = '\0';
1732 if (!GetComputerName(name->nodename, &sz))
1733 *name->nodename = '\0';
1736 /* machine (architecture) */
1741 GetSystemInfo(&info);
1743 #if (defined(__BORLANDC__)&&(__BORLANDC__<=0x520)) \
1744 || (defined(__MINGW32__) && !defined(_ANONYMOUS_UNION))
1745 procarch = info.u.s.wProcessorArchitecture;
1747 procarch = info.wProcessorArchitecture;
1750 case PROCESSOR_ARCHITECTURE_INTEL:
1751 arch = "x86"; break;
1752 case PROCESSOR_ARCHITECTURE_MIPS:
1753 arch = "mips"; break;
1754 case PROCESSOR_ARCHITECTURE_ALPHA:
1755 arch = "alpha"; break;
1756 case PROCESSOR_ARCHITECTURE_PPC:
1757 arch = "ppc"; break;
1758 #ifdef PROCESSOR_ARCHITECTURE_SHX
1759 case PROCESSOR_ARCHITECTURE_SHX:
1760 arch = "shx"; break;
1762 #ifdef PROCESSOR_ARCHITECTURE_ARM
1763 case PROCESSOR_ARCHITECTURE_ARM:
1764 arch = "arm"; break;
1766 #ifdef PROCESSOR_ARCHITECTURE_IA64
1767 case PROCESSOR_ARCHITECTURE_IA64:
1768 arch = "ia64"; break;
1770 #ifdef PROCESSOR_ARCHITECTURE_ALPHA64
1771 case PROCESSOR_ARCHITECTURE_ALPHA64:
1772 arch = "alpha64"; break;
1774 #ifdef PROCESSOR_ARCHITECTURE_MSIL
1775 case PROCESSOR_ARCHITECTURE_MSIL:
1776 arch = "msil"; break;
1778 #ifdef PROCESSOR_ARCHITECTURE_AMD64
1779 case PROCESSOR_ARCHITECTURE_AMD64:
1780 arch = "amd64"; break;
1782 #ifdef PROCESSOR_ARCHITECTURE_IA32_ON_WIN64
1783 case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64:
1784 arch = "ia32-64"; break;
1786 #ifdef PROCESSOR_ARCHITECTURE_UNKNOWN
1787 case PROCESSOR_ARCHITECTURE_UNKNOWN:
1788 arch = "unknown"; break;
1791 sprintf(name->machine, "unknown(0x%x)", procarch);
1792 arch = name->machine;
1795 if (name->machine != arch)
1796 strcpy(name->machine, arch);
1801 /* Timing related stuff */
1804 do_raise(pTHX_ int sig)
1806 if (sig < SIG_SIZE) {
1807 Sighandler_t handler = w32_sighandler[sig];
1808 if (handler == SIG_IGN) {
1811 else if (handler != SIG_DFL) {
1816 /* Choose correct default behaviour */
1832 /* Tell caller to exit thread/process as approriate */
1837 sig_terminate(pTHX_ int sig)
1839 Perl_warn(aTHX_ "Terminating on signal SIG%s(%d)\n",PL_sig_name[sig], sig);
1840 /* exit() seems to be safe, my_exit() or die() is a problem in ^C
1847 win32_async_check(pTHX)
1850 HWND hwnd = w32_message_hwnd;
1854 if (hwnd == INVALID_HANDLE_VALUE) {
1855 /* Call PeekMessage() to mark all pending messages in the queue as "old".
1856 * This is necessary when we are being called by win32_msgwait() to
1857 * make sure MsgWaitForMultipleObjects() stops reporting the same waiting
1858 * message over and over. An example how this can happen is when
1859 * Perl is calling win32_waitpid() inside a GUI application and the GUI
1860 * is generating messages before the process terminated.
1862 PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE|PM_NOYIELD);
1868 /* Passing PeekMessage -1 as HWND (2nd arg) only get PostThreadMessage() messages
1869 * and ignores window messages - should co-exist better with windows apps e.g. Tk
1874 while (PeekMessage(&msg, hwnd, WM_TIMER, WM_TIMER, PM_REMOVE|PM_NOYIELD) ||
1875 PeekMessage(&msg, hwnd, WM_USER_MIN, WM_USER_MAX, PM_REMOVE|PM_NOYIELD))
1877 switch (msg.message) {
1879 case WM_USER_MESSAGE: {
1880 int child = find_pseudo_pid(msg.wParam);
1882 w32_pseudo_child_message_hwnds[child] = (HWND)msg.lParam;
1887 case WM_USER_KILL: {
1888 /* We use WM_USER to fake kill() with other signals */
1889 int sig = msg.wParam;
1890 if (do_raise(aTHX_ sig))
1891 sig_terminate(aTHX_ sig);
1896 /* alarm() is a one-shot but SetTimer() repeats so kill it */
1897 if (w32_timerid && w32_timerid==msg.wParam) {
1898 KillTimer(w32_message_hwnd, w32_timerid);
1901 /* Now fake a call to signal handler */
1902 if (do_raise(aTHX_ 14))
1903 sig_terminate(aTHX_ 14);
1910 /* Above or other stuff may have set a signal flag */
1911 if (PL_sig_pending) {
1917 /* This function will not return until the timeout has elapsed, or until
1918 * one of the handles is ready. */
1920 win32_msgwait(pTHX_ DWORD count, LPHANDLE handles, DWORD timeout, LPDWORD resultp)
1922 /* We may need several goes at this - so compute when we stop */
1924 if (timeout != INFINITE) {
1925 ticks = GetTickCount();
1929 DWORD result = MsgWaitForMultipleObjects(count,handles,FALSE,timeout-ticks, QS_ALLEVENTS);
1932 if (result == WAIT_TIMEOUT) {
1933 /* Ran out of time - explicit return of zero to avoid -ve if we
1934 have scheduling issues
1938 if (timeout != INFINITE) {
1939 ticks = GetTickCount();
1941 if (result == WAIT_OBJECT_0 + count) {
1942 /* Message has arrived - check it */
1943 (void)win32_async_check(aTHX);
1946 /* Not timeout or message - one of handles is ready */
1950 /* compute time left to wait */
1951 ticks = timeout - ticks;
1952 /* If we are past the end say zero */
1953 return (ticks > 0) ? ticks : 0;
1957 win32_internal_wait(int *status, DWORD timeout)
1959 /* XXX this wait emulation only knows about processes
1960 * spawned via win32_spawnvp(P_NOWAIT, ...).
1964 DWORD exitcode, waitcode;
1967 if (w32_num_pseudo_children) {
1968 win32_msgwait(aTHX_ w32_num_pseudo_children, w32_pseudo_child_handles,
1969 timeout, &waitcode);
1970 /* Time out here if there are no other children to wait for. */
1971 if (waitcode == WAIT_TIMEOUT) {
1972 if (!w32_num_children) {
1976 else if (waitcode != WAIT_FAILED) {
1977 if (waitcode >= WAIT_ABANDONED_0
1978 && waitcode < WAIT_ABANDONED_0 + w32_num_pseudo_children)
1979 i = waitcode - WAIT_ABANDONED_0;
1981 i = waitcode - WAIT_OBJECT_0;
1982 if (GetExitCodeThread(w32_pseudo_child_handles[i], &exitcode)) {
1983 *status = (int)((exitcode & 0xff) << 8);
1984 retval = (int)w32_pseudo_child_pids[i];
1985 remove_dead_pseudo_process(i);
1992 if (!w32_num_children) {
1997 /* if a child exists, wait for it to die */
1998 win32_msgwait(aTHX_ w32_num_children, w32_child_handles, timeout, &waitcode);
1999 if (waitcode == WAIT_TIMEOUT) {
2002 if (waitcode != WAIT_FAILED) {
2003 if (waitcode >= WAIT_ABANDONED_0
2004 && waitcode < WAIT_ABANDONED_0 + w32_num_children)
2005 i = waitcode - WAIT_ABANDONED_0;
2007 i = waitcode - WAIT_OBJECT_0;
2008 if (GetExitCodeProcess(w32_child_handles[i], &exitcode) ) {
2009 *status = (int)((exitcode & 0xff) << 8);
2010 retval = (int)w32_child_pids[i];
2011 remove_dead_process(i);
2016 errno = GetLastError();
2021 win32_waitpid(int pid, int *status, int flags)
2024 DWORD timeout = (flags & WNOHANG) ? 0 : INFINITE;
2027 if (pid == -1) /* XXX threadid == 1 ? */
2028 return win32_internal_wait(status, timeout);
2031 child = find_pseudo_pid(-pid);
2033 HANDLE hThread = w32_pseudo_child_handles[child];
2035 win32_msgwait(aTHX_ 1, &hThread, timeout, &waitcode);
2036 if (waitcode == WAIT_TIMEOUT) {
2039 else if (waitcode == WAIT_OBJECT_0) {
2040 if (GetExitCodeThread(hThread, &waitcode)) {
2041 *status = (int)((waitcode & 0xff) << 8);
2042 retval = (int)w32_pseudo_child_pids[child];
2043 remove_dead_pseudo_process(child);
2050 else if (IsWin95()) {
2059 child = find_pid(pid);
2061 hProcess = w32_child_handles[child];
2062 win32_msgwait(aTHX_ 1, &hProcess, timeout, &waitcode);
2063 if (waitcode == WAIT_TIMEOUT) {
2066 else if (waitcode == WAIT_OBJECT_0) {
2067 if (GetExitCodeProcess(hProcess, &waitcode)) {
2068 *status = (int)((waitcode & 0xff) << 8);
2069 retval = (int)w32_child_pids[child];
2070 remove_dead_process(child);
2079 hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE,
2080 (IsWin95() ? -pid : pid));
2082 win32_msgwait(aTHX_ 1, &hProcess, timeout, &waitcode);
2083 if (waitcode == WAIT_TIMEOUT) {
2084 CloseHandle(hProcess);
2087 else if (waitcode == WAIT_OBJECT_0) {
2088 if (GetExitCodeProcess(hProcess, &waitcode)) {
2089 *status = (int)((waitcode & 0xff) << 8);
2090 CloseHandle(hProcess);
2094 CloseHandle(hProcess);
2100 return retval >= 0 ? pid : retval;
2104 win32_wait(int *status)
2106 return win32_internal_wait(status, INFINITE);
2109 DllExport unsigned int
2110 win32_sleep(unsigned int t)
2113 /* Win32 times are in ms so *1000 in and /1000 out */
2114 return win32_msgwait(aTHX_ 0, NULL, t*1000, NULL)/1000;
2117 DllExport unsigned int
2118 win32_alarm(unsigned int sec)
2121 * the 'obvious' implentation is SetTimer() with a callback
2122 * which does whatever receiving SIGALRM would do
2123 * we cannot use SIGALRM even via raise() as it is not
2124 * one of the supported codes in <signal.h>
2128 if (w32_message_hwnd == INVALID_HANDLE_VALUE)
2129 w32_message_hwnd = win32_create_message_window();
2132 if (w32_message_hwnd == NULL)
2133 w32_timerid = SetTimer(NULL, w32_timerid, sec*1000, NULL);
2136 SetTimer(w32_message_hwnd, w32_timerid, sec*1000, NULL);
2141 KillTimer(w32_message_hwnd, w32_timerid);
2148 #ifdef HAVE_DES_FCRYPT
2149 extern char * des_fcrypt(const char *txt, const char *salt, char *cbuf);
2153 win32_crypt(const char *txt, const char *salt)
2156 #ifdef HAVE_DES_FCRYPT
2157 return des_fcrypt(txt, salt, w32_crypt_buffer);
2159 Perl_croak(aTHX_ "The crypt() function is unimplemented due to excessive paranoia.");
2164 #ifdef USE_FIXED_OSFHANDLE
2166 #define FOPEN 0x01 /* file handle open */
2167 #define FNOINHERIT 0x10 /* file handle opened O_NOINHERIT */
2168 #define FAPPEND 0x20 /* file handle opened O_APPEND */
2169 #define FDEV 0x40 /* file handle refers to device */
2170 #define FTEXT 0x80 /* file handle is in text mode */
2173 *int my_open_osfhandle(intptr_t osfhandle, int flags) - open C Runtime file handle
2176 * This function allocates a free C Runtime file handle and associates
2177 * it with the Win32 HANDLE specified by the first parameter. This is a
2178 * temperary fix for WIN95's brain damage GetFileType() error on socket
2179 * we just bypass that call for socket
2181 * This works with MSVC++ 4.0+ or GCC/Mingw32
2184 * intptr_t osfhandle - Win32 HANDLE to associate with C Runtime file handle.
2185 * int flags - flags to associate with C Runtime file handle.
2188 * returns index of entry in fh, if successful
2189 * return -1, if no free entry is found
2193 *******************************************************************************/
2196 * we fake up some parts of the CRT that aren't exported by MSVCRT.dll
2197 * this lets sockets work on Win9X with GCC and should fix the problems
2202 /* create an ioinfo entry, kill its handle, and steal the entry */
2207 HANDLE hF = CreateFile("NUL", 0, 0, NULL, OPEN_ALWAYS, 0, NULL);
2208 int fh = _open_osfhandle((intptr_t)hF, 0);
2212 EnterCriticalSection(&(_pioinfo(fh)->lock));
2217 my_open_osfhandle(intptr_t osfhandle, int flags)
2220 char fileflags; /* _osfile flags */
2222 /* copy relevant flags from second parameter */
2225 if (flags & O_APPEND)
2226 fileflags |= FAPPEND;
2231 if (flags & O_NOINHERIT)
2232 fileflags |= FNOINHERIT;
2234 /* attempt to allocate a C Runtime file handle */
2235 if ((fh = _alloc_osfhnd()) == -1) {
2236 errno = EMFILE; /* too many open files */
2237 _doserrno = 0L; /* not an OS error */
2238 return -1; /* return error to caller */
2241 /* the file is open. now, set the info in _osfhnd array */
2242 _set_osfhnd(fh, osfhandle);
2244 fileflags |= FOPEN; /* mark as open */
2246 _osfile(fh) = fileflags; /* set osfile entry */
2247 LeaveCriticalSection(&_pioinfo(fh)->lock);
2249 return fh; /* return handle */
2252 #endif /* USE_FIXED_OSFHANDLE */
2254 /* simulate flock by locking a range on the file */
2256 #define LK_ERR(f,i) ((f) ? (i = 0) : (errno = GetLastError()))
2257 #define LK_LEN 0xffff0000
2260 win32_flock(int fd, int oper)
2268 Perl_croak_nocontext("flock() unimplemented on this platform");
2271 fh = (HANDLE)_get_osfhandle(fd);
2272 memset(&o, 0, sizeof(o));
2275 case LOCK_SH: /* shared lock */
2276 LK_ERR(LockFileEx(fh, 0, 0, LK_LEN, 0, &o),i);
2278 case LOCK_EX: /* exclusive lock */
2279 LK_ERR(LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, LK_LEN, 0, &o),i);
2281 case LOCK_SH|LOCK_NB: /* non-blocking shared lock */
2282 LK_ERR(LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY, 0, LK_LEN, 0, &o),i);
2284 case LOCK_EX|LOCK_NB: /* non-blocking exclusive lock */
2285 LK_ERR(LockFileEx(fh,
2286 LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY,
2287 0, LK_LEN, 0, &o),i);
2289 case LOCK_UN: /* unlock lock */
2290 LK_ERR(UnlockFileEx(fh, 0, LK_LEN, 0, &o),i);
2292 default: /* unknown */
2303 * redirected io subsystem for all XS modules
2316 return (&(_environ));
2319 /* the rest are the remapped stdio routines */
2339 win32_ferror(FILE *fp)
2341 return (ferror(fp));
2346 win32_feof(FILE *fp)
2352 * Since the errors returned by the socket error function
2353 * WSAGetLastError() are not known by the library routine strerror
2354 * we have to roll our own.
2358 win32_strerror(int e)
2360 #if !defined __BORLANDC__ && !defined __MINGW32__ /* compiler intolerance */
2361 extern int sys_nerr;
2365 if (e < 0 || e > sys_nerr) {
2370 if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, &source, e, 0,
2371 w32_strerror_buffer,
2372 sizeof(w32_strerror_buffer), NULL) == 0)
2373 strcpy(w32_strerror_buffer, "Unknown Error");
2375 return w32_strerror_buffer;
2381 win32_str_os_error(void *sv, DWORD dwErr)
2385 dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER
2386 |FORMAT_MESSAGE_IGNORE_INSERTS
2387 |FORMAT_MESSAGE_FROM_SYSTEM, NULL,
2388 dwErr, 0, (char *)&sMsg, 1, NULL);
2389 /* strip trailing whitespace and period */
2392 --dwLen; /* dwLen doesn't include trailing null */
2393 } while (0 < dwLen && isSPACE(sMsg[dwLen]));
2394 if ('.' != sMsg[dwLen])
2399 sMsg = (char*)LocalAlloc(0, 64/**sizeof(TCHAR)*/);
2401 dwLen = sprintf(sMsg,
2402 "Unknown error #0x%lX (lookup 0x%lX)",
2403 dwErr, GetLastError());
2407 sv_setpvn((SV*)sv, sMsg, dwLen);
2413 win32_fprintf(FILE *fp, const char *format, ...)
2416 va_start(marker, format); /* Initialize variable arguments. */
2418 return (vfprintf(fp, format, marker));
2422 win32_printf(const char *format, ...)
2425 va_start(marker, format); /* Initialize variable arguments. */
2427 return (vprintf(format, marker));
2431 win32_vfprintf(FILE *fp, const char *format, va_list args)
2433 return (vfprintf(fp, format, args));
2437 win32_vprintf(const char *format, va_list args)
2439 return (vprintf(format, args));
2443 win32_fread(void *buf, size_t size, size_t count, FILE *fp)
2445 return fread(buf, size, count, fp);
2449 win32_fwrite(const void *buf, size_t size, size_t count, FILE *fp)
2451 return fwrite(buf, size, count, fp);
2454 #define MODE_SIZE 10
2457 win32_fopen(const char *filename, const char *mode)
2465 if (stricmp(filename, "/dev/null")==0)
2468 f = fopen(PerlDir_mapA(filename), mode);
2469 /* avoid buffering headaches for child processes */
2470 if (f && *mode == 'a')
2471 win32_fseek(f, 0, SEEK_END);
2475 #ifndef USE_SOCKETS_AS_HANDLES
2477 #define fdopen my_fdopen
2481 win32_fdopen(int handle, const char *mode)
2485 f = fdopen(handle, (char *) mode);
2486 /* avoid buffering headaches for child processes */
2487 if (f && *mode == 'a')
2488 win32_fseek(f, 0, SEEK_END);
2493 win32_freopen(const char *path, const char *mode, FILE *stream)
2496 if (stricmp(path, "/dev/null")==0)
2499 return freopen(PerlDir_mapA(path), mode, stream);
2503 win32_fclose(FILE *pf)
2505 return my_fclose(pf); /* defined in win32sck.c */
2509 win32_fputs(const char *s,FILE *pf)
2511 return fputs(s, pf);
2515 win32_fputc(int c,FILE *pf)
2521 win32_ungetc(int c,FILE *pf)
2523 return ungetc(c,pf);
2527 win32_getc(FILE *pf)
2533 win32_fileno(FILE *pf)
2539 win32_clearerr(FILE *pf)
2546 win32_fflush(FILE *pf)
2552 win32_ftell(FILE *pf)
2554 #if defined(WIN64) || defined(USE_LARGE_FILES)
2555 #if defined(__BORLANDC__) /* buk */
2556 return win32_tell( fileno( pf ) );
2559 if (fgetpos(pf, &pos))
2569 win32_fseek(FILE *pf, Off_t offset,int origin)
2571 #if defined(WIN64) || defined(USE_LARGE_FILES)
2572 #if defined(__BORLANDC__) /* buk */
2582 if (fgetpos(pf, &pos))
2587 fseek(pf, 0, SEEK_END);
2588 pos = _telli64(fileno(pf));
2597 return fsetpos(pf, &offset);
2600 return fseek(pf, (long)offset, origin);
2605 win32_fgetpos(FILE *pf,fpos_t *p)
2607 #if defined(__BORLANDC__) && defined(USE_LARGE_FILES) /* buk */
2608 if( win32_tell(fileno(pf)) == -1L ) {
2614 return fgetpos(pf, p);
2619 win32_fsetpos(FILE *pf,const fpos_t *p)
2621 #if defined(__BORLANDC__) && defined(USE_LARGE_FILES) /* buk */
2622 return win32_lseek(fileno(pf), *p, SEEK_CUR);
2624 return fsetpos(pf, p);
2629 win32_rewind(FILE *pf)
2639 char prefix[MAX_PATH+1];
2640 char filename[MAX_PATH+1];
2641 DWORD len = GetTempPath(MAX_PATH, prefix);
2642 if (len && len < MAX_PATH) {
2643 if (GetTempFileName(prefix, "plx", 0, filename)) {
2644 HANDLE fh = CreateFile(filename,
2645 DELETE | GENERIC_READ | GENERIC_WRITE,
2649 FILE_ATTRIBUTE_NORMAL
2650 | FILE_FLAG_DELETE_ON_CLOSE,
2652 if (fh != INVALID_HANDLE_VALUE) {
2653 int fd = win32_open_osfhandle((intptr_t)fh, 0);
2655 #if defined(__BORLANDC__)
2656 setmode(fd,O_BINARY);
2658 DEBUG_p(PerlIO_printf(Perl_debug_log,
2659 "Created tmpfile=%s\n",filename));
2671 int fd = win32_tmpfd();
2673 return win32_fdopen(fd, "w+b");
2685 win32_fstat(int fd, Stat_t *sbufptr)
2688 /* A file designated by filehandle is not shown as accessible
2689 * for write operations, probably because it is opened for reading.
2692 BY_HANDLE_FILE_INFORMATION bhfi;
2693 #if defined(WIN64) || defined(USE_LARGE_FILES)
2694 /* Borland 5.5.1 has a 64-bit stat, but only a 32-bit fstat */
2696 int rc = fstat(fd,&tmp);
2698 sbufptr->st_dev = tmp.st_dev;
2699 sbufptr->st_ino = tmp.st_ino;
2700 sbufptr->st_mode = tmp.st_mode;
2701 sbufptr->st_nlink = tmp.st_nlink;
2702 sbufptr->st_uid = tmp.st_uid;
2703 sbufptr->st_gid = tmp.st_gid;
2704 sbufptr->st_rdev = tmp.st_rdev;
2705 sbufptr->st_size = tmp.st_size;
2706 sbufptr->st_atime = tmp.st_atime;
2707 sbufptr->st_mtime = tmp.st_mtime;
2708 sbufptr->st_ctime = tmp.st_ctime;
2710 int rc = fstat(fd,sbufptr);
2713 if (GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &bhfi)) {
2714 #if defined(WIN64) || defined(USE_LARGE_FILES)
2715 sbufptr->st_size = (bhfi.nFileSizeHigh << 32) + bhfi.nFileSizeLow ;
2717 sbufptr->st_mode &= 0xFE00;
2718 if (bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
2719 sbufptr->st_mode |= (S_IREAD + (S_IREAD >> 3) + (S_IREAD >> 6));
2721 sbufptr->st_mode |= ((S_IREAD|S_IWRITE) + ((S_IREAD|S_IWRITE) >> 3)
2722 + ((S_IREAD|S_IWRITE) >> 6));
2726 return my_fstat(fd,sbufptr);
2731 win32_pipe(int *pfd, unsigned int size, int mode)
2733 return _pipe(pfd, size, mode);
2737 win32_popenlist(const char *mode, IV narg, SV **args)
2740 Perl_croak(aTHX_ "List form of pipe open not implemented");
2745 * a popen() clone that respects PERL5SHELL
2747 * changed to return PerlIO* rather than FILE * by BKS, 11-11-2000
2751 win32_popen(const char *command, const char *mode)
2753 #ifdef USE_RTL_POPEN
2754 return _popen(command, mode);
2766 /* establish which ends read and write */
2767 if (strchr(mode,'w')) {
2768 stdfd = 0; /* stdin */
2771 nhandle = STD_INPUT_HANDLE;
2773 else if (strchr(mode,'r')) {
2774 stdfd = 1; /* stdout */
2777 nhandle = STD_OUTPUT_HANDLE;
2782 /* set the correct mode */
2783 if (strchr(mode,'b'))
2785 else if (strchr(mode,'t'))
2788 ourmode = _fmode & (O_TEXT | O_BINARY);
2790 /* the child doesn't inherit handles */
2791 ourmode |= O_NOINHERIT;
2793 if (win32_pipe(p, 512, ourmode) == -1)
2796 /* save the old std handle (this needs to happen before the
2797 * dup2(), since that might call SetStdHandle() too) */
2800 old_h = GetStdHandle(nhandle);
2802 /* save current stdfd */
2803 if ((oldfd = win32_dup(stdfd)) == -1)
2806 /* make stdfd go to child end of pipe (implicitly closes stdfd) */
2807 /* stdfd will be inherited by the child */
2808 if (win32_dup2(p[child], stdfd) == -1)
2811 /* close the child end in parent */
2812 win32_close(p[child]);
2814 /* set the new std handle (in case dup2() above didn't) */
2815 SetStdHandle(nhandle, (HANDLE)_get_osfhandle(stdfd));
2817 /* start the child */
2820 if ((childpid = do_spawn_nowait((char*)command)) == -1)
2823 /* revert stdfd to whatever it was before */
2824 if (win32_dup2(oldfd, stdfd) == -1)
2827 /* close saved handle */
2830 /* restore the old std handle (this needs to happen after the
2831 * dup2(), since that might call SetStdHandle() too */
2833 SetStdHandle(nhandle, old_h);
2839 sv_setiv(*av_fetch(w32_fdpid, p[parent], TRUE), childpid);
2842 /* set process id so that it can be returned by perl's open() */
2843 PL_forkprocess = childpid;
2846 /* we have an fd, return a file stream */
2847 return (PerlIO_fdopen(p[parent], (char *)mode));
2850 /* we don't need to check for errors here */
2854 win32_dup2(oldfd, stdfd);
2858 SetStdHandle(nhandle, old_h);
2864 #endif /* USE_RTL_POPEN */
2872 win32_pclose(PerlIO *pf)
2874 #ifdef USE_RTL_POPEN
2878 int childpid, status;
2882 sv = *av_fetch(w32_fdpid, PerlIO_fileno(pf), TRUE);
2885 childpid = SvIVX(sv);
2903 if (win32_waitpid(childpid, &status, 0) == -1)
2908 #endif /* USE_RTL_POPEN */
2914 LPCWSTR lpExistingFileName,
2915 LPSECURITY_ATTRIBUTES lpSecurityAttributes)
2918 WCHAR wFullName[MAX_PATH+1];
2919 LPVOID lpContext = NULL;
2920 WIN32_STREAM_ID StreamId;
2921 DWORD dwSize = (char*)&StreamId.cStreamName - (char*)&StreamId;
2926 BOOL (__stdcall *pfnBackupWrite)(HANDLE, LPBYTE, DWORD, LPDWORD,
2927 BOOL, BOOL, LPVOID*) =
2928 (BOOL (__stdcall *)(HANDLE, LPBYTE, DWORD, LPDWORD,
2929 BOOL, BOOL, LPVOID*))
2930 GetProcAddress(GetModuleHandle("kernel32.dll"), "BackupWrite");
2931 if (pfnBackupWrite == NULL)
2934 dwLen = GetFullPathNameW(lpFileName, MAX_PATH, wFullName, NULL);
2937 dwLen = (dwLen+1)*sizeof(WCHAR);
2939 handle = CreateFileW(lpExistingFileName, FILE_WRITE_ATTRIBUTES,
2940 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
2941 NULL, OPEN_EXISTING, 0, NULL);
2942 if (handle == INVALID_HANDLE_VALUE)
2945 StreamId.dwStreamId = BACKUP_LINK;
2946 StreamId.dwStreamAttributes = 0;
2947 StreamId.dwStreamNameSize = 0;
2948 #if defined(__BORLANDC__) \
2949 ||(defined(__MINGW32__) && !defined(_ANONYMOUS_UNION))
2950 StreamId.Size.u.HighPart = 0;
2951 StreamId.Size.u.LowPart = dwLen;
2953 StreamId.Size.HighPart = 0;
2954 StreamId.Size.LowPart = dwLen;
2957 bSuccess = pfnBackupWrite(handle, (LPBYTE)&StreamId, dwSize, &dwWritten,
2958 FALSE, FALSE, &lpContext);
2960 bSuccess = pfnBackupWrite(handle, (LPBYTE)wFullName, dwLen, &dwWritten,
2961 FALSE, FALSE, &lpContext);
2962 pfnBackupWrite(handle, NULL, 0, &dwWritten, TRUE, FALSE, &lpContext);
2965 CloseHandle(handle);
2970 win32_link(const char *oldname, const char *newname)
2973 BOOL (__stdcall *pfnCreateHardLinkW)(LPCWSTR,LPCWSTR,LPSECURITY_ATTRIBUTES);
2974 WCHAR wOldName[MAX_PATH+1];
2975 WCHAR wNewName[MAX_PATH+1];
2978 Perl_croak(aTHX_ PL_no_func, "link");
2980 pfnCreateHardLinkW =
2981 (BOOL (__stdcall *)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES))
2982 GetProcAddress(GetModuleHandle("kernel32.dll"), "CreateHardLinkW");
2983 if (pfnCreateHardLinkW == NULL)
2984 pfnCreateHardLinkW = Nt4CreateHardLinkW;
2986 if (MultiByteToWideChar(CP_ACP, 0, oldname, -1, wOldName, MAX_PATH+1) &&
2987 MultiByteToWideChar(CP_ACP, 0, newname, -1, wNewName, MAX_PATH+1) &&
2988 (wcscpy(wOldName, PerlDir_mapW(wOldName)),
2989 pfnCreateHardLinkW(PerlDir_mapW(wNewName), wOldName, NULL)))
2993 errno = (GetLastError() == ERROR_FILE_NOT_FOUND) ? ENOENT : EINVAL;
2998 win32_rename(const char *oname, const char *newname)
3000 char szOldName[MAX_PATH+1];
3001 char szNewName[MAX_PATH+1];
3005 /* XXX despite what the documentation says about MoveFileEx(),
3006 * it doesn't work under Windows95!
3009 DWORD dwFlags = MOVEFILE_COPY_ALLOWED;
3010 if (stricmp(newname, oname))
3011 dwFlags |= MOVEFILE_REPLACE_EXISTING;
3012 strcpy(szOldName, PerlDir_mapA(oname));
3013 bResult = MoveFileExA(szOldName,PerlDir_mapA(newname), dwFlags);
3015 DWORD err = GetLastError();
3017 case ERROR_BAD_NET_NAME:
3018 case ERROR_BAD_NETPATH:
3019 case ERROR_BAD_PATHNAME:
3020 case ERROR_FILE_NOT_FOUND:
3021 case ERROR_FILENAME_EXCED_RANGE:
3022 case ERROR_INVALID_DRIVE:
3023 case ERROR_NO_MORE_FILES:
3024 case ERROR_PATH_NOT_FOUND:
3037 char szTmpName[MAX_PATH+1];
3038 char dname[MAX_PATH+1];
3039 char *endname = Nullch;
3041 DWORD from_attr, to_attr;
3043 strcpy(szOldName, PerlDir_mapA(oname));
3044 strcpy(szNewName, PerlDir_mapA(newname));
3046 /* if oname doesn't exist, do nothing */
3047 from_attr = GetFileAttributes(szOldName);
3048 if (from_attr == 0xFFFFFFFF) {
3053 /* if newname exists, rename it to a temporary name so that we
3054 * don't delete it in case oname happens to be the same file
3055 * (but perhaps accessed via a different path)
3057 to_attr = GetFileAttributes(szNewName);
3058 if (to_attr != 0xFFFFFFFF) {
3059 /* if newname is a directory, we fail
3060 * XXX could overcome this with yet more convoluted logic */
3061 if (to_attr & FILE_ATTRIBUTE_DIRECTORY) {
3065 tmplen = strlen(szNewName);
3066 strcpy(szTmpName,szNewName);
3067 endname = szTmpName+tmplen;
3068 for (; endname > szTmpName ; --endname) {
3069 if (*endname == '/' || *endname == '\\') {
3074 if (endname > szTmpName)
3075 endname = strcpy(dname,szTmpName);
3079 /* get a temporary filename in same directory
3080 * XXX is this really the best we can do? */
3081 if (!GetTempFileName((LPCTSTR)endname, "plr", 0, szTmpName)) {
3085 DeleteFile(szTmpName);
3087 retval = rename(szNewName, szTmpName);
3094 /* rename oname to newname */
3095 retval = rename(szOldName, szNewName);
3097 /* if we created a temporary file before ... */
3098 if (endname != Nullch) {
3099 /* ...and rename succeeded, delete temporary file/directory */
3101 DeleteFile(szTmpName);
3102 /* else restore it to what it was */
3104 (void)rename(szTmpName, szNewName);
3111 win32_setmode(int fd, int mode)
3113 return setmode(fd, mode);
3117 win32_chsize(int fd, Off_t size)
3119 #if defined(WIN64) || defined(USE_LARGE_FILES)
3121 Off_t cur, end, extend;
3123 cur = win32_tell(fd);
3126 end = win32_lseek(fd, 0, SEEK_END);
3129 extend = size - end;
3133 else if (extend > 0) {
3134 /* must grow the file, padding with nulls */
3136 int oldmode = win32_setmode(fd, O_BINARY);
3138 memset(b, '\0', sizeof(b));
3140 count = extend >= sizeof(b) ? sizeof(b) : (size_t)extend;
3141 count = win32_write(fd, b, count);
3142 if ((int)count < 0) {
3146 } while ((extend -= count) > 0);
3147 win32_setmode(fd, oldmode);
3150 /* shrink the file */
3151 win32_lseek(fd, size, SEEK_SET);
3152 if (!SetEndOfFile((HANDLE)_get_osfhandle(fd))) {
3158 win32_lseek(fd, cur, SEEK_SET);
3161 return chsize(fd, (long)size);
3166 win32_lseek(int fd, Off_t offset, int origin)
3168 #if defined(WIN64) || defined(USE_LARGE_FILES)
3169 #if defined(__BORLANDC__) /* buk */
3171 pos.QuadPart = offset;
3172 pos.LowPart = SetFilePointer(
3173 (HANDLE)_get_osfhandle(fd),
3178 if (pos.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
3182 return pos.QuadPart;
3184 return _lseeki64(fd, offset, origin);
3187 return lseek(fd, (long)offset, origin);
3194 #if defined(WIN64) || defined(USE_LARGE_FILES)
3195 #if defined(__BORLANDC__) /* buk */
3198 pos.LowPart = SetFilePointer(
3199 (HANDLE)_get_osfhandle(fd),
3204 if (pos.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
3208 return pos.QuadPart;
3209 /* return tell(fd); */
3211 return _telli64(fd);
3219 win32_open(const char *path, int flag, ...)
3226 pmode = va_arg(ap, int);
3229 if (stricmp(path, "/dev/null")==0)
3232 return open(PerlDir_mapA(path), flag, pmode);
3235 /* close() that understands socket */
3236 extern int my_close(int); /* in win32sck.c */
3241 return my_close(fd);
3257 win32_dup2(int fd1,int fd2)
3259 return dup2(fd1,fd2);
3262 #ifdef PERL_MSVCRT_READFIX
3264 #define LF 10 /* line feed */
3265 #define CR 13 /* carriage return */
3266 #define CTRLZ 26 /* ctrl-z means eof for text */
3267 #define FOPEN 0x01 /* file handle open */
3268 #define FEOFLAG 0x02 /* end of file has been encountered */
3269 #define FCRLF 0x04 /* CR-LF across read buffer (in text mode) */
3270 #define FPIPE 0x08 /* file handle refers to a pipe */
3271 #define FAPPEND 0x20 /* file handle opened O_APPEND */
3272 #define FDEV 0x40 /* file handle refers to device */
3273 #define FTEXT 0x80 /* file handle is in text mode */
3274 #define MAX_DESCRIPTOR_COUNT (64*32) /* this is the maximun that MSVCRT can handle */
3277 _fixed_read(int fh, void *buf, unsigned cnt)
3279 int bytes_read; /* number of bytes read */
3280 char *buffer; /* buffer to read to */
3281 int os_read; /* bytes read on OS call */
3282 char *p, *q; /* pointers into buffer */
3283 char peekchr; /* peek-ahead character */
3284 ULONG filepos; /* file position after seek */
3285 ULONG dosretval; /* o.s. return value */
3287 /* validate handle */
3288 if (((unsigned)fh >= (unsigned)MAX_DESCRIPTOR_COUNT) ||
3289 !(_osfile(fh) & FOPEN))
3291 /* out of range -- return error */
3293 _doserrno = 0; /* not o.s. error */
3298 * If lockinitflag is FALSE, assume fd is device
3299 * lockinitflag is set to TRUE by open.
3301 if (_pioinfo(fh)->lockinitflag)
3302 EnterCriticalSection(&(_pioinfo(fh)->lock)); /* lock file */
3304 bytes_read = 0; /* nothing read yet */
3305 buffer = (char*)buf;
3307 if (cnt == 0 || (_osfile(fh) & FEOFLAG)) {
3308 /* nothing to read or at EOF, so return 0 read */
3312 if ((_osfile(fh) & (FPIPE|FDEV)) && _pipech(fh) != LF) {
3313 /* a pipe/device and pipe lookahead non-empty: read the lookahead
3315 *buffer++ = _pipech(fh);
3318 _pipech(fh) = LF; /* mark as empty */
3323 if (!ReadFile((HANDLE)_osfhnd(fh), buffer, cnt, (LPDWORD)&os_read, NULL))
3325 /* ReadFile has reported an error. recognize two special cases.
3327 * 1. map ERROR_ACCESS_DENIED to EBADF
3329 * 2. just return 0 if ERROR_BROKEN_PIPE has occurred. it
3330 * means the handle is a read-handle on a pipe for which
3331 * all write-handles have been closed and all data has been
3334 if ((dosretval = GetLastError()) == ERROR_ACCESS_DENIED) {
3335 /* wrong read/write mode should return EBADF, not EACCES */
3337 _doserrno = dosretval;
3341 else if (dosretval == ERROR_BROKEN_PIPE) {
3351 bytes_read += os_read; /* update bytes read */
3353 if (_osfile(fh) & FTEXT) {
3354 /* now must translate CR-LFs to LFs in the buffer */
3356 /* set CRLF flag to indicate LF at beginning of buffer */
3357 /* if ((os_read != 0) && (*(char *)buf == LF)) */
3358 /* _osfile(fh) |= FCRLF; */
3360 /* _osfile(fh) &= ~FCRLF; */
3362 _osfile(fh) &= ~FCRLF;
3364 /* convert chars in the buffer: p is src, q is dest */
3366 while (p < (char *)buf + bytes_read) {
3368 /* if fh is not a device, set ctrl-z flag */
3369 if (!(_osfile(fh) & FDEV))
3370 _osfile(fh) |= FEOFLAG;
3371 break; /* stop translating */
3376 /* *p is CR, so must check next char for LF */
3377 if (p < (char *)buf + bytes_read - 1) {
3380 *q++ = LF; /* convert CR-LF to LF */
3383 *q++ = *p++; /* store char normally */
3386 /* This is the hard part. We found a CR at end of
3387 buffer. We must peek ahead to see if next char
3392 if (!ReadFile((HANDLE)_osfhnd(fh), &peekchr, 1,
3393 (LPDWORD)&os_read, NULL))
3394 dosretval = GetLastError();
3396 if (dosretval != 0 || os_read == 0) {
3397 /* couldn't read ahead, store CR */
3401 /* peekchr now has the extra character -- we now
3402 have several possibilities:
3403 1. disk file and char is not LF; just seek back
3405 2. disk file and char is LF; store LF, don't seek back
3406 3. pipe/device and char is LF; store LF.
3407 4. pipe/device and char isn't LF, store CR and
3408 put char in pipe lookahead buffer. */
3409 if (_osfile(fh) & (FDEV|FPIPE)) {
3410 /* non-seekable device */
3415 _pipech(fh) = peekchr;
3420 if (peekchr == LF) {
3421 /* nothing read yet; must make some
3424 /* turn on this flag for tell routine */
3425 _osfile(fh) |= FCRLF;
3428 HANDLE osHandle; /* o.s. handle value */
3430 if ((osHandle = (HANDLE)_get_osfhandle(fh)) != (HANDLE)-1)
3432 if ((filepos = SetFilePointer(osHandle, -1, NULL, FILE_CURRENT)) == -1)
3433 dosretval = GetLastError();
3444 /* we now change bytes_read to reflect the true number of chars
3446 bytes_read = q - (char *)buf;
3450 if (_pioinfo(fh)->lockinitflag)
3451 LeaveCriticalSection(&(_pioinfo(fh)->lock)); /* unlock file */
3456 #endif /* PERL_MSVCRT_READFIX */
3459 win32_read(int fd, void *buf, unsigned int cnt)
3461 #ifdef PERL_MSVCRT_READFIX
3462 return _fixed_read(fd, buf, cnt);
3464 return read(fd, buf, cnt);
3469 win32_write(int fd, const void *buf, unsigned int cnt)
3471 return write(fd, buf, cnt);
3475 win32_mkdir(const char *dir, int mode)
3478 return mkdir(PerlDir_mapA(dir)); /* just ignore mode */
3482 win32_rmdir(const char *dir)
3485 return rmdir(PerlDir_mapA(dir));
3489 win32_chdir(const char *dir)
3500 win32_access(const char *path, int mode)
3503 return access(PerlDir_mapA(path), mode);
3507 win32_chmod(const char *path, int mode)
3510 return chmod(PerlDir_mapA(path), mode);
3515 create_command_line(char *cname, STRLEN clen, const char * const *args)
3522 bool bat_file = FALSE;
3523 bool cmd_shell = FALSE;
3524 bool dumb_shell = FALSE;
3525 bool extra_quotes = FALSE;
3526 bool quote_next = FALSE;
3529 cname = (char*)args[0];
3531 /* The NT cmd.exe shell has the following peculiarity that needs to be
3532 * worked around. It strips a leading and trailing dquote when any
3533 * of the following is true:
3534 * 1. the /S switch was used
3535 * 2. there are more than two dquotes
3536 * 3. there is a special character from this set: &<>()@^|
3537 * 4. no whitespace characters within the two dquotes
3538 * 5. string between two dquotes isn't an executable file
3539 * To work around this, we always add a leading and trailing dquote
3540 * to the string, if the first argument is either "cmd.exe" or "cmd",
3541 * and there were at least two or more arguments passed to cmd.exe
3542 * (not including switches).
3543 * XXX the above rules (from "cmd /?") don't seem to be applied
3544 * always, making for the convolutions below :-(
3548 clen = strlen(cname);
3551 && (stricmp(&cname[clen-4], ".bat") == 0
3552 || (IsWinNT() && stricmp(&cname[clen-4], ".cmd") == 0)))
3559 char *exe = strrchr(cname, '/');
3560 char *exe2 = strrchr(cname, '\\');
3567 if (stricmp(exe, "cmd.exe") == 0 || stricmp(exe, "cmd") == 0) {
3571 else if (stricmp(exe, "command.com") == 0
3572 || stricmp(exe, "command") == 0)
3579 DEBUG_p(PerlIO_printf(Perl_debug_log, "Args "));
3580 for (index = 0; (arg = (char*)args[index]) != NULL; ++index) {
3581 STRLEN curlen = strlen(arg);
3582 if (!(arg[0] == '"' && arg[curlen-1] == '"'))
3583 len += 2; /* assume quoting needed (worst case) */
3585 DEBUG_p(PerlIO_printf(Perl_debug_log, "[%s]",arg));
3587 DEBUG_p(PerlIO_printf(Perl_debug_log, "\n"));
3590 Newx(cmd, len, char);
3593 if (bat_file && !IsWin95()) {
3595 extra_quotes = TRUE;
3598 for (index = 0; (arg = (char*)args[index]) != NULL; ++index) {
3600 STRLEN curlen = strlen(arg);
3602 /* we want to protect empty arguments and ones with spaces with
3603 * dquotes, but only if they aren't already there */
3608 else if (quote_next) {
3609 /* see if it really is multiple arguments pretending to
3610 * be one and force a set of quotes around it */
3611 if (*find_next_space(arg))
3614 else if (!(arg[0] == '"' && curlen > 1 && arg[curlen-1] == '"')) {
3616 while (i < curlen) {
3617 if (isSPACE(arg[i])) {
3620 else if (arg[i] == '"') {
3644 && *arg == '/' /* see if arg is "/c", "/x/c", "/x/d/c" etc. */
3645 && stricmp(arg+curlen-2, "/c") == 0)
3647 /* is there a next argument? */
3648 if (args[index+1]) {
3649 /* are there two or more next arguments? */
3650 if (args[index+2]) {
3652 extra_quotes = TRUE;
3655 /* single argument, force quoting if it has spaces */
3671 qualified_path(const char *cmd)
3675 char *fullcmd, *curfullcmd;
3681 fullcmd = (char*)cmd;
3683 if (*fullcmd == '/' || *fullcmd == '\\')
3690 pathstr = PerlEnv_getenv("PATH");
3692 /* worst case: PATH is a single directory; we need additional space
3693 * to append "/", ".exe" and trailing "\0" */
3694 Newx(fullcmd, (pathstr ? strlen(pathstr) : 0) + cmdlen + 6, char);
3695 curfullcmd = fullcmd;
3700 /* start by appending the name to the current prefix */
3701 strcpy(curfullcmd, cmd);
3702 curfullcmd += cmdlen;
3704 /* if it doesn't end with '.', or has no extension, try adding
3705 * a trailing .exe first */
3706 if (cmd[cmdlen-1] != '.'
3707 && (cmdlen < 4 || cmd[cmdlen-4] != '.'))
3709 strcpy(curfullcmd, ".exe");
3710 res = GetFileAttributes(fullcmd);
3711 if (res != 0xFFFFFFFF && !(res & FILE_ATTRIBUTE_DIRECTORY))
3716 /* that failed, try the bare name */
3717 res = GetFileAttributes(fullcmd);
3718 if (res != 0xFFFFFFFF && !(res & FILE_ATTRIBUTE_DIRECTORY))
3721 /* quit if no other path exists, or if cmd already has path */
3722 if (!pathstr || !*pathstr || has_slash)
3725 /* skip leading semis */
3726 while (*pathstr == ';')
3729 /* build a new prefix from scratch */
3730 curfullcmd = fullcmd;
3731 while (*pathstr && *pathstr != ';') {
3732 if (*pathstr == '"') { /* foo;"baz;etc";bar */
3733 pathstr++; /* skip initial '"' */
3734 while (*pathstr && *pathstr != '"') {
3735 *curfullcmd++ = *pathstr++;
3738 pathstr++; /* skip trailing '"' */
3741 *curfullcmd++ = *pathstr++;
3745 pathstr++; /* skip trailing semi */
3746 if (curfullcmd > fullcmd /* append a dir separator */
3747 && curfullcmd[-1] != '/' && curfullcmd[-1] != '\\')
3749 *curfullcmd++ = '\\';
3757 /* The following are just place holders.
3758 * Some hosts may provide and environment that the OS is
3759 * not tracking, therefore, these host must provide that
3760 * environment and the current directory to CreateProcess
3764 win32_get_childenv(void)
3770 win32_free_childenv(void* d)
3775 win32_clearenv(void)
3777 char *envv = GetEnvironmentStrings();
3781 char *end = strchr(cur,'=');
3782 if (end && end != cur) {
3784 SetEnvironmentVariable(cur, NULL);
3786 cur = end + strlen(end+1)+2;
3788 else if ((len = strlen(cur)))
3791 FreeEnvironmentStrings(envv);
3795 win32_get_childdir(void)
3799 char szfilename[MAX_PATH+1];
3801 GetCurrentDirectoryA(MAX_PATH+1, szfilename);
3802 Newx(ptr, strlen(szfilename)+1, char);
3803 strcpy(ptr, szfilename);
3808 win32_free_childdir(char* d)
3815 /* XXX this needs to be made more compatible with the spawnvp()
3816 * provided by the various RTLs. In particular, searching for
3817 * *.{com,bat,cmd} files (as done by the RTLs) is unimplemented.
3818 * This doesn't significantly affect perl itself, because we
3819 * always invoke things using PERL5SHELL if a direct attempt to
3820 * spawn the executable fails.
3822 * XXX splitting and rejoining the commandline between do_aspawn()
3823 * and win32_spawnvp() could also be avoided.
3827 win32_spawnvp(int mode, const char *cmdname, const char *const *argv)
3829 #ifdef USE_RTL_SPAWNVP
3830 return spawnvp(mode, cmdname, (char * const *)argv);
3837 STARTUPINFO StartupInfo;
3838 PROCESS_INFORMATION ProcessInformation;
3841 char *fullcmd = Nullch;
3842 char *cname = (char *)cmdname;
3846 clen = strlen(cname);
3847 /* if command name contains dquotes, must remove them */
3848 if (strchr(cname, '"')) {
3850 Newx(cname,clen+1,char);
3863 cmd = create_command_line(cname, clen, argv);
3865 env = PerlEnv_get_childenv();
3866 dir = PerlEnv_get_childdir();
3869 case P_NOWAIT: /* asynch + remember result */
3870 if (w32_num_children >= MAXIMUM_WAIT_OBJECTS) {
3875 /* Create a new process group so we can use GenerateConsoleCtrlEvent()
3878 create |= CREATE_NEW_PROCESS_GROUP;
3881 case P_WAIT: /* synchronous execution */
3883 default: /* invalid mode */
3888 memset(&StartupInfo,0,sizeof(StartupInfo));
3889 StartupInfo.cb = sizeof(StartupInfo);
3890 memset(&tbl,0,sizeof(tbl));
3891 PerlEnv_get_child_IO(&tbl);
3892 StartupInfo.dwFlags = tbl.dwFlags;
3893 StartupInfo.dwX = tbl.dwX;
3894 StartupInfo.dwY = tbl.dwY;
3895 StartupInfo.dwXSize = tbl.dwXSize;
3896 StartupInfo.dwYSize = tbl.dwYSize;
3897 StartupInfo.dwXCountChars = tbl.dwXCountChars;
3898 StartupInfo.dwYCountChars = tbl.dwYCountChars;
3899 StartupInfo.dwFillAttribute = tbl.dwFillAttribute;
3900 StartupInfo.wShowWindow = tbl.wShowWindow;
3901 StartupInfo.hStdInput = tbl.childStdIn;
3902 StartupInfo.hStdOutput = tbl.childStdOut;
3903 StartupInfo.hStdError = tbl.childStdErr;
3904 if (StartupInfo.hStdInput == INVALID_HANDLE_VALUE &&
3905 StartupInfo.hStdOutput == INVALID_HANDLE_VALUE &&
3906 StartupInfo.hStdError == INVALID_HANDLE_VALUE)
3908 create |= CREATE_NEW_CONSOLE;
3911 StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
3913 if (w32_use_showwindow) {
3914 StartupInfo.dwFlags |= STARTF_USESHOWWINDOW;
3915 StartupInfo.wShowWindow = w32_showwindow;
3918 DEBUG_p(PerlIO_printf(Perl_debug_log, "Spawning [%s] with [%s]\n",
3921 if (!CreateProcess(cname, /* search PATH to find executable */
3922 cmd, /* executable, and its arguments */
3923 NULL, /* process attributes */
3924 NULL, /* thread attributes */
3925 TRUE, /* inherit handles */
3926 create, /* creation flags */
3927 (LPVOID)env, /* inherit environment */
3928 dir, /* inherit cwd */
3930 &ProcessInformation))
3932 /* initial NULL argument to CreateProcess() does a PATH
3933 * search, but it always first looks in the directory
3934 * where the current process was started, which behavior
3935 * is undesirable for backward compatibility. So we
3936 * jump through our own hoops by picking out the path
3937 * we really want it to use. */
3939 fullcmd = qualified_path(cname);
3941 if (cname != cmdname)
3944 DEBUG_p(PerlIO_printf(Perl_debug_log,
3945 "Retrying [%s] with same args\n",
3955 if (mode == P_NOWAIT) {
3956 /* asynchronous spawn -- store handle, return PID */
3957 ret = (int)ProcessInformation.dwProcessId;
3958 if (IsWin95() && ret < 0)
3961 w32_child_handles[w32_num_children] = ProcessInformation.hProcess;
3962 w32_child_pids[w32_num_children] = (DWORD)ret;
3967 win32_msgwait(aTHX_ 1, &ProcessInformation.hProcess, INFINITE, NULL);
3968 /* FIXME: if msgwait returned due to message perhaps forward the
3969 "signal" to the process
3971 GetExitCodeProcess(ProcessInformation.hProcess, &status);
3973 CloseHandle(ProcessInformation.hProcess);
3976 CloseHandle(ProcessInformation.hThread);
3979 PerlEnv_free_childenv(env);
3980 PerlEnv_free_childdir(dir);
3982 if (cname != cmdname)
3989 win32_execv(const char *cmdname, const char *const *argv)
3993 /* if this is a pseudo-forked child, we just want to spawn
3994 * the new program, and return */
3996 # ifdef __BORLANDC__
3997 return spawnv(P_WAIT, cmdname, (char *const *)argv);
3999 return spawnv(P_WAIT, cmdname, argv);
4003 return execv(cmdname, (char *const *)argv);
4005 return execv(cmdname, argv);
4010 win32_execvp(const char *cmdname, const char *const *argv)
4014 /* if this is a pseudo-forked child, we just want to spawn
4015 * the new program, and return */
4016 if (w32_pseudo_id) {
4017 int status = win32_spawnvp(P_WAIT, cmdname, (const char *const *)argv);
4027 return execvp(cmdname, (char *const *)argv);
4029 return execvp(cmdname, argv);
4034 win32_perror(const char *str)
4040 win32_setbuf(FILE *pf, char *buf)
4046 win32_setvbuf(FILE *pf, char *buf, int type, size_t size)
4048 return setvbuf(pf, buf, type, size);
4052 win32_flushall(void)
4058 win32_fcloseall(void)
4064 win32_fgets(char *s, int n, FILE *pf)
4066 return fgets(s, n, pf);
4076 win32_fgetc(FILE *pf)
4082 win32_putc(int c, FILE *pf)
4088 win32_puts(const char *s)
4100 win32_putchar(int c)
4107 #ifndef USE_PERL_SBRK
4109 static char *committed = NULL; /* XXX threadead */
4110 static char *base = NULL; /* XXX threadead */
4111 static char *reserved = NULL; /* XXX threadead */
4112 static char *brk = NULL; /* XXX threadead */
4113 static DWORD pagesize = 0; /* XXX threadead */
4116 sbrk(ptrdiff_t need)
4121 GetSystemInfo(&info);
4122 /* Pretend page size is larger so we don't perpetually
4123 * call the OS to commit just one page ...
4125 pagesize = info.dwPageSize << 3;
4127 if (brk+need >= reserved)
4129 DWORD size = brk+need-reserved;
4131 char *prev_committed = NULL;
4132 if (committed && reserved && committed < reserved)
4134 /* Commit last of previous chunk cannot span allocations */
4135 addr = (char *) VirtualAlloc(committed,reserved-committed,MEM_COMMIT,PAGE_READWRITE);
4138 /* Remember where we committed from in case we want to decommit later */
4139 prev_committed = committed;
4140 committed = reserved;
4143 /* Reserve some (more) space
4144 * Contiguous blocks give us greater efficiency, so reserve big blocks -
4145 * this is only address space not memory...
4146 * Note this is a little sneaky, 1st call passes NULL as reserved
4147 * so lets system choose where we start, subsequent calls pass
4148 * the old end address so ask for a contiguous block
4151 if (size < 64*1024*1024)
4152 size = 64*1024*1024;
4153 size = ((size + pagesize - 1) / pagesize) * pagesize;
4154 addr = (char *) VirtualAlloc(reserved,size,MEM_RESERVE,PAGE_NOACCESS);
4157 reserved = addr+size;
4167 /* The existing block could not be extended far enough, so decommit
4168 * anything that was just committed above and start anew */
4171 if (!VirtualFree(prev_committed,reserved-prev_committed,MEM_DECOMMIT))
4174 reserved = base = committed = brk = NULL;
4185 if (brk > committed)
4187 DWORD size = ((brk-committed + pagesize -1)/pagesize) * pagesize;
4189 if (committed+size > reserved)
4190 size = reserved-committed;
4191 addr = (char *) VirtualAlloc(committed,size,MEM_COMMIT,PAGE_READWRITE);
4204 win32_malloc(size_t size)
4206 return malloc(size);
4210 win32_calloc(size_t numitems, size_t size)
4212 return calloc(numitems,size);
4216 win32_realloc(void *block, size_t size)
4218 return realloc(block,size);
4222 win32_free(void *block)
4229 win32_open_osfhandle(intptr_t handle, int flags)
4231 #ifdef USE_FIXED_OSFHANDLE
4233 return my_open_osfhandle(handle, flags);
4235 return _open_osfhandle(handle, flags);
4239 win32_get_osfhandle(int fd)
4241 return (intptr_t)_get_osfhandle(fd);
4245 win32_fdupopen(FILE *pf)
4250 int fileno = win32_dup(win32_fileno(pf));
4252 /* open the file in the same mode */
4254 if((pf)->flags & _F_READ) {
4258 else if((pf)->flags & _F_WRIT) {
4262 else if((pf)->flags & _F_RDWR) {
4268 if((pf)->_flag & _IOREAD) {
4272 else if((pf)->_flag & _IOWRT) {
4276 else if((pf)->_flag & _IORW) {
4283 /* it appears that the binmode is attached to the
4284 * file descriptor so binmode files will be handled
4287 pfdup = win32_fdopen(fileno, mode);
4289 /* move the file pointer to the same position */
4290 if (!fgetpos(pf, &pos)) {
4291 fsetpos(pfdup, &pos);
4297 win32_dynaload(const char* filename)
4300 char buf[MAX_PATH+1];
4303 /* LoadLibrary() doesn't recognize forward slashes correctly,
4304 * so turn 'em back. */
4305 first = strchr(filename, '/');
4307 STRLEN len = strlen(filename);
4308 if (len <= MAX_PATH) {
4309 strcpy(buf, filename);
4310 filename = &buf[first - filename];
4312 if (*filename == '/')
4313 *(char*)filename = '\\';
4319 return LoadLibraryExA(PerlDir_mapA(filename), NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
4322 XS(w32_SetChildShowWindow)
4325 BOOL use_showwindow = w32_use_showwindow;
4326 /* use "unsigned short" because Perl has redefined "WORD" */
4327 unsigned short showwindow = w32_showwindow;
4330 Perl_croak(aTHX_ "usage: Win32::SetChildShowWindow($showwindow)");
4332 if (items == 0 || !SvOK(ST(0)))
4333 w32_use_showwindow = FALSE;
4335 w32_use_showwindow = TRUE;
4336 w32_showwindow = (unsigned short)SvIV(ST(0));
4341 ST(0) = sv_2mortal(newSViv(showwindow));
4343 ST(0) = &PL_sv_undef;
4348 forward(pTHX_ const char *function)
4351 Perl_load_module(aTHX_ PERL_LOADMOD_NOIMPORT, newSVpvn("Win32",5), newSVnv(0.27));
4354 call_pv(function, GIMME_V);
4357 #define FORWARD(function) XS(w32_##function){ forward(aTHX_ "Win32::"#function); }
4360 FORWARD(GetNextAvailDrive)
4361 FORWARD(GetLastError)
4362 FORWARD(SetLastError)
4367 FORWARD(GetOSVersion)
4370 FORWARD(FormatMessage)
4372 FORWARD(GetTickCount)
4373 FORWARD(GetShortPathName)
4374 FORWARD(GetFullPathName)
4375 FORWARD(GetLongPathName)
4379 /* Don't forward Win32::SetChildShowWindow(). It accesses the internal variable
4380 * w32_showwindow in thread_intern and is therefore not implemented in Win32.xs.
4382 /* FORWARD(SetChildShowWindow) */
4387 Perl_init_os_extras(void)
4390 char *file = __FILE__;
4393 /* these names are Activeware compatible */
4394 newXS("Win32::GetCwd", w32_GetCwd, file);
4395 newXS("Win32::SetCwd", w32_SetCwd, file);
4396 newXS("Win32::GetNextAvailDrive", w32_GetNextAvailDrive, file);
4397 newXS("Win32::GetLastError", w32_GetLastError, file);
4398 newXS("Win32::SetLastError", w32_SetLastError, file);
4399 newXS("Win32::LoginName", w32_LoginName, file);
4400 newXS("Win32::NodeName", w32_NodeName, file);
4401 newXS("Win32::DomainName", w32_DomainName, file);
4402 newXS("Win32::FsType", w32_FsType, file);
4403 newXS("Win32::GetOSVersion", w32_GetOSVersion, file);
4404 newXS("Win32::IsWinNT", w32_IsWinNT, file);
4405 newXS("Win32::IsWin95", w32_IsWin95, file);
4406 newXS("Win32::FormatMessage", w32_FormatMessage, file);
4407 newXS("Win32::Spawn", w32_Spawn, file);
4408 newXS("Win32::GetTickCount", w32_GetTickCount, file);
4409 newXS("Win32::GetShortPathName", w32_GetShortPathName, file);
4410 newXS("Win32::GetFullPathName", w32_GetFullPathName, file);
4411 newXS("Win32::GetLongPathName", w32_GetLongPathName, file);
4412 newXS("Win32::CopyFile", w32_CopyFile, file);
4413 newXS("Win32::Sleep", w32_Sleep, file);
4414 newXS("Win32::SetChildShowWindow", w32_SetChildShowWindow, file);
4418 win32_signal_context(void)
4423 my_perl = PL_curinterp;
4424 PERL_SET_THX(my_perl);
4428 return PL_curinterp;
4434 win32_ctrlhandler(DWORD dwCtrlType)
4437 dTHXa(PERL_GET_SIG_CONTEXT);
4443 switch(dwCtrlType) {
4444 case CTRL_CLOSE_EVENT:
4445 /* A signal that the system sends to all processes attached to a console when
4446 the user closes the console (either by choosing the Close command from the
4447 console window's System menu, or by choosing the End Task command from the
4450 if (do_raise(aTHX_ 1)) /* SIGHUP */
4451 sig_terminate(aTHX_ 1);
4455 /* A CTRL+c signal was received */
4456 if (do_raise(aTHX_ SIGINT))
4457 sig_terminate(aTHX_ SIGINT);
4460 case CTRL_BREAK_EVENT:
4461 /* A CTRL+BREAK signal was received */
4462 if (do_raise(aTHX_ SIGBREAK))
4463 sig_terminate(aTHX_ SIGBREAK);
4466 case CTRL_LOGOFF_EVENT:
4467 /* A signal that the system sends to all console processes when a user is logging
4468 off. This signal does not indicate which user is logging off, so no
4469 assumptions can be made.
4472 case CTRL_SHUTDOWN_EVENT:
4473 /* A signal that the system sends to all console processes when the system is
4476 if (do_raise(aTHX_ SIGTERM))
4477 sig_terminate(aTHX_ SIGTERM);
4486 #if _MSC_VER >= 1400
4487 # include <crtdbg.h>
4491 Perl_win32_init(int *argcp, char ***argvp)
4493 #if _MSC_VER >= 1400
4494 _invalid_parameter_handler oldHandler, newHandler;
4495 newHandler = my_invalid_parameter_handler;
4496 oldHandler = _set_invalid_parameter_handler(newHandler);
4497 _CrtSetReportMode(_CRT_ASSERT, 0);
4499 /* Disable floating point errors, Perl will trap the ones we
4500 * care about. VC++ RTL defaults to switching these off
4501 * already, but the Borland RTL doesn't. Since we don't
4502 * want to be at the vendor's whim on the default, we set
4503 * it explicitly here.
4505 #if !defined(_ALPHA_) && !defined(__GNUC__)
4506 _control87(MCW_EM, MCW_EM);
4512 Perl_win32_term(void)
4522 win32_get_child_IO(child_IO_table* ptbl)
4524 ptbl->childStdIn = GetStdHandle(STD_INPUT_HANDLE);
4525 ptbl->childStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
4526 ptbl->childStdErr = GetStdHandle(STD_ERROR_HANDLE);
4530 win32_signal(int sig, Sighandler_t subcode)
4533 if (sig < SIG_SIZE) {
4534 int save_errno = errno;
4535 Sighandler_t result = signal(sig, subcode);
4536 if (result == SIG_ERR) {
4537 result = w32_sighandler[sig];
4540 w32_sighandler[sig] = subcode;
4550 #ifdef HAVE_INTERP_INTERN
4554 win32_csighandler(int sig)
4557 dTHXa(PERL_GET_SIG_CONTEXT);
4558 Perl_warn(aTHX_ "Got signal %d",sig);
4564 win32_create_message_window()
4566 /* "message-only" windows have been implemented in Windows 2000 and later.
4567 * On earlier versions we'll continue to post messages to a specific
4568 * thread and use hwnd==NULL. This is brittle when either an embedding
4569 * application or an XS module is also posting messages to hwnd=NULL
4570 * because once removed from the queue they cannot be delivered to the
4571 * "right" place with DispatchMessage() anymore, as there is no WindowProc
4572 * if there is no window handle.
4574 if (g_osver.dwMajorVersion < 5)
4577 return CreateWindow("Static", "", 0, 0, 0, 0, 0, HWND_MESSAGE, 0, 0, NULL);
4580 #if defined(__MINGW32__) && defined(__cplusplus)
4581 #define CAST_HWND__(x) (HWND__*)(x)
4583 #define CAST_HWND__(x) x
4587 Perl_sys_intern_init(pTHX)
4591 if (g_osver.dwOSVersionInfoSize == 0) {
4592 g_osver.dwOSVersionInfoSize = sizeof(g_osver);
4593 GetVersionEx(&g_osver);
4596 w32_perlshell_tokens = Nullch;
4597 w32_perlshell_vec = (char**)NULL;
4598 w32_perlshell_items = 0;
4599 w32_fdpid = newAV();
4600 Newx(w32_children, 1, child_tab);
4601 w32_num_children = 0;
4602 # ifdef USE_ITHREADS
4604 Newx(w32_pseudo_children, 1, pseudo_child_tab);
4605 w32_num_pseudo_children = 0;
4608 w32_message_hwnd = CAST_HWND__(INVALID_HANDLE_VALUE);
4610 for (i=0; i < SIG_SIZE; i++) {
4611 w32_sighandler[i] = SIG_DFL;
4614 if (my_perl == PL_curinterp) {
4618 /* Force C runtime signal stuff to set its console handler */
4619 signal(SIGINT,win32_csighandler);
4620 signal(SIGBREAK,win32_csighandler);
4621 /* Push our handler on top */
4622 SetConsoleCtrlHandler(win32_ctrlhandler,TRUE);
4627 Perl_sys_intern_clear(pTHX)
4629 Safefree(w32_perlshell_tokens);
4630 Safefree(w32_perlshell_vec);
4631 /* NOTE: w32_fdpid is freed by sv_clean_all() */
4632 Safefree(w32_children);
4634 KillTimer(w32_message_hwnd, w32_timerid);
4637 if (w32_message_hwnd != NULL && w32_message_hwnd != INVALID_HANDLE_VALUE)
4638 DestroyWindow(w32_message_hwnd);
4639 # ifdef MULTIPLICITY
4640 if (my_perl == PL_curinterp) {
4644 SetConsoleCtrlHandler(win32_ctrlhandler,FALSE);
4646 # ifdef USE_ITHREADS
4647 Safefree(w32_pseudo_children);
4651 # ifdef USE_ITHREADS
4654 Perl_sys_intern_dup(pTHX_ struct interp_intern *src, struct interp_intern *dst)
4656 dst->perlshell_tokens = Nullch;
4657 dst->perlshell_vec = (char**)NULL;
4658 dst->perlshell_items = 0;
4659 dst->fdpid = newAV();
4660 Newxz(dst->children, 1, child_tab);
4662 Newxz(dst->pseudo_children, 1, pseudo_child_tab);
4664 dst->message_hwnd = CAST_HWND__(INVALID_HANDLE_VALUE);
4665 dst->poll_count = 0;
4666 Copy(src->sigtable,dst->sigtable,SIG_SIZE,Sighandler_t);
4668 # endif /* USE_ITHREADS */
4669 #endif /* HAVE_INTERP_INTERN */
4672 win32_free_argvw(pTHX_ void *ptr)
4674 char** argv = (char**)ptr;
4682 win32_argv2utf8(int argc, char** argv)
4687 LPWSTR* lpwStr = CommandLineToArgvW(GetCommandLineW(), &wargc);
4688 if (lpwStr && argc) {
4690 length = WideCharToMultiByte(CP_UTF8, 0, lpwStr[--wargc], -1, NULL, 0, NULL, NULL);
4691 Newxz(psz, length, char);
4692 WideCharToMultiByte(CP_UTF8, 0, lpwStr[wargc], -1, psz, length, NULL, NULL);
4695 call_atexit(win32_free_argvw, argv);
4697 GlobalFree((HGLOBAL)lpwStr);