X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=win32%2Fwin32.c;h=7c0af0f11d71e929e22a14d0473ff9537b0de523;hb=f3c90b3644a4d1b01ee1a6fe678bc1357e85a56a;hp=67aeae68ecab0b164ebcdf02c0e8dd1f4af1457b;hpb=c623ac675720b3145d48cc2ea9474a0f3e0cbbca;p=p5sagit%2Fp5-mst-13.2.git diff --git a/win32/win32.c b/win32/win32.c index 67aeae6..7c0af0f 100644 --- a/win32/win32.c +++ b/win32/win32.c @@ -15,7 +15,11 @@ #define Win32_Winsock #endif #include -#ifndef __MINGW32__ /* GCC/Mingw32-2.95.2 forgot the WINAPI on CommandLineToArgvW() */ +#ifndef HWND_MESSAGE +# define HWND_MESSAGE ((HWND)-3) +#endif +/* GCC-2.95.2/Mingw32-1.1 forgot the WINAPI on CommandLineToArgvW() */ +#if defined(__MINGW32__) && (__MINGW32_MAJOR_VERSION==1) # include #else LPWSTR* WINAPI CommandLineToArgvW(LPCWSTR lpCommandLine, int * pNumArgs); @@ -60,8 +64,8 @@ int _CRT_glob = 0; #endif -#if defined(__MINGW32__) -/* Mingw32 is missing some prototypes */ +#if defined(__MINGW32__) && (__MINGW32_MAJOR_VERSION==1) +/* Mingw32-1.1 is missing some prototypes */ FILE * _wfopen(LPCWSTR wszFileName, LPCWSTR wszMode); FILE * _wfdopen(int nFd, LPCWSTR wszMode); FILE * _freopen(LPCWSTR wszFileName, LPCWSTR wszMode, FILE * pOldStream); @@ -85,16 +89,14 @@ int _fcloseall(); # define win32_get_sitelib g_win32_get_sitelib # undef win32_get_vendorlib # define win32_get_vendorlib g_win32_get_vendorlib -# undef do_spawn -# define do_spawn g_do_spawn # undef getlogin # define getlogin g_getlogin #endif static void get_shell(void); static long tokenize(const char *str, char **dest, char ***destv); - int do_spawn2(char *cmd, int exectype); -static BOOL has_shell_metachars(char *ptr); +static int do_spawn2(pTHX_ const char *cmd, int exectype); +static BOOL has_shell_metachars(const char *ptr); static long filetime_to_clock(PFILETIME ft); static BOOL filetime_from_time(PFILETIME ft, time_t t); static char * get_emd_part(SV **leading, char *trailing, ...); @@ -114,20 +116,30 @@ HANDLE w32_perldll_handle = INVALID_HANDLE_VALUE; char w32_module_name[MAX_PATH+1]; END_EXTERN_C -static DWORD w32_platform = (DWORD)-1; +static OSVERSIONINFO g_osver = {0, 0, 0, 0, 0, ""}; #define ONE_K_BUFSIZE 1024 +#ifdef __BORLANDC__ +/* Silence STDERR grumblings from Borland's math library. */ +DllExport int +_matherr(struct _exception *a) +{ + PERL_UNUSED_VAR(a); + return 1; +} +#endif + int IsWin95(void) { - return (win32_os_id() == VER_PLATFORM_WIN32_WINDOWS); + return (g_osver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS); } int IsWinNT(void) { - return (win32_os_id() == VER_PLATFORM_WIN32_NT); + return (g_osver.dwPlatformId == VER_PLATFORM_WIN32_NT); } EXTERN_C void @@ -139,6 +151,10 @@ set_w32_module_name(void) : w32_perldll_handle), w32_module_name, sizeof(w32_module_name)); + /* remove \\?\ prefix */ + if (memcmp(w32_module_name, "\\\\?\\", 4) == 0) + memmove(w32_module_name, w32_module_name+4, strlen(w32_module_name+4)+1); + /* try to get full path to binary (which may be mangled when perl is * run from a 16-bit app) */ /*PerlIO_printf(Perl_debug_log, "Before %s\n", w32_module_name);*/ @@ -208,7 +224,6 @@ get_emd_part(SV **prev_pathp, char *trailing_path, ...) char *ptr; char *optr; char *strip; - int oldsize, newsize; STRLEN baselen; va_start(ap, trailing_path); @@ -255,7 +270,8 @@ get_emd_part(SV **prev_pathp, char *trailing_path, ...) dTHX; if (!*prev_pathp) *prev_pathp = sv_2mortal(newSVpvn("",0)); - sv_catpvn(*prev_pathp, ";", 1); + else if (SvPVX(*prev_pathp)) + sv_catpvn(*prev_pathp, ";", 1); sv_catpv(*prev_pathp, mod_name); return SvPVX(*prev_pathp); } @@ -286,8 +302,6 @@ win32_get_xlib(const char *pl, const char *xlib, const char *libname) dTHX; char regstr[40]; char pathstr[MAX_PATH+1]; - DWORD datalen; - int len, newsize; SV *sv1 = Nullsv; SV *sv2 = Nullsv; @@ -338,7 +352,7 @@ win32_get_vendorlib(const char *pl) } static BOOL -has_shell_metachars(char *ptr) +has_shell_metachars(const char *ptr) { int inquote = 0; char quote = '\0'; @@ -383,7 +397,7 @@ has_shell_metachars(char *ptr) * the library functions will get the correct environment */ PerlIO * -Perl_my_popen(pTHX_ char *cmd, char *mode) +Perl_my_popen(pTHX_ const char *cmd, const char *mode) { #ifdef FIXCMD #define fixcmd(x) { \ @@ -415,15 +429,7 @@ Perl_my_pclose(pTHX_ PerlIO *fp) DllExport unsigned long win32_os_id(void) { - static OSVERSIONINFO osver; - - if (osver.dwPlatformId != w32_platform) { - memset(&osver, 0, sizeof(OSVERSIONINFO)); - osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - GetVersionEx(&osver); - w32_platform = osver.dwPlatformId; - } - return (unsigned long)w32_platform; + return (unsigned long)g_osver.dwPlatformId; } DllExport int @@ -461,8 +467,8 @@ tokenize(const char *str, char **dest, char ***destv) int slen = strlen(str); register char *ret; register char **retv; - New(1307, ret, slen+2, char); - New(1308, retv, (slen+3)/2, char*); + Newx(ret, slen+2, char); + Newx(retv, (slen+3)/2, char*); retstart = ret; retvstart = retv; @@ -510,7 +516,7 @@ get_shell(void) * for). */ const char* defaultshell = (IsWinNT() - ? "cmd.exe /x/c" : "command.com /c"); + ? "cmd.exe /x/d/c" : "command.com /c"); const char *usershell = PerlEnv_getenv("PERL5SHELL"); w32_perlshell_items = tokenize(usershell ? usershell : defaultshell, &w32_perlshell_tokens, @@ -519,12 +525,8 @@ get_shell(void) } int -do_aspawn(void *vreally, void **vmark, void **vsp) +Perl_do_aspawn(pTHX_ SV *really, SV **mark, SV **sp) { - dTHX; - SV *really = (SV*)vreally; - SV **mark = (SV**)vmark; - SV **sp = (SV**)vsp; char **argv; char *str; int status; @@ -535,7 +537,7 @@ do_aspawn(void *vreally, void **vmark, void **vsp) return -1; get_shell(); - New(1306, argv, (sp - mark) + w32_perlshell_items + 2, char*); + Newx(argv, (sp - mark) + w32_perlshell_items + 2, char*); if (SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) { ++mark; @@ -610,10 +612,9 @@ find_next_space(const char *s) return (char*)s; } -int -do_spawn2(char *cmd, int exectype) +static int +do_spawn2(pTHX_ const char *cmd, int exectype) { - dTHX; char **a; char *s; char **argv; @@ -624,8 +625,8 @@ do_spawn2(char *cmd, int exectype) /* Save an extra exec if possible. See if there are shell * metacharacters in it */ if (!has_shell_metachars(cmd)) { - New(1301,argv, strlen(cmd) / 2 + 2, char*); - New(1302,cmd2, strlen(cmd) + 1, char); + Newx(argv, strlen(cmd) / 2 + 2, char*); + Newx(cmd2, strlen(cmd) + 1, char); strcpy(cmd2, cmd); a = argv; for (s = cmd2; *s;) { @@ -662,10 +663,10 @@ do_spawn2(char *cmd, int exectype) char **argv; int i = -1; get_shell(); - New(1306, argv, w32_perlshell_items + 2, char*); + Newx(argv, w32_perlshell_items + 2, char*); while (++i < w32_perlshell_items) argv[i] = w32_perlshell_vec[i]; - argv[i++] = cmd; + argv[i++] = (char *)cmd; argv[i] = Nullch; switch (exectype) { case EXECF_SPAWN: @@ -703,21 +704,21 @@ do_spawn2(char *cmd, int exectype) } int -do_spawn(char *cmd) +Perl_do_spawn(pTHX_ char *cmd) { - return do_spawn2(cmd, EXECF_SPAWN); + return do_spawn2(aTHX_ cmd, EXECF_SPAWN); } int -do_spawn_nowait(char *cmd) +Perl_do_spawn_nowait(pTHX_ char *cmd) { - return do_spawn2(cmd, EXECF_SPAWN_NOWAIT); + return do_spawn2(aTHX_ cmd, EXECF_SPAWN_NOWAIT); } bool -Perl_do_exec(pTHX_ char *cmd) +Perl_do_exec(pTHX_ const char *cmd) { - do_spawn2(cmd, EXECF_EXEC); + do_spawn2(aTHX_ cmd, EXECF_EXEC); return FALSE; } @@ -726,7 +727,7 @@ Perl_do_exec(pTHX_ char *cmd) * return the pointer to the current file name. */ DllExport DIR * -win32_opendir(char *filename) +win32_opendir(const char *filename) { dTHX; DIR *dirp; @@ -735,11 +736,6 @@ win32_opendir(char *filename) char scanname[MAX_PATH+3]; Stat_t sbuf; WIN32_FIND_DATAA aFindData; - WIN32_FIND_DATAW wFindData; - HANDLE fh; - char buffer[MAX_PATH*2]; - WCHAR wbuffer[MAX_PATH+1]; - char* ptr; len = strlen(filename); if (len > MAX_PATH) @@ -750,7 +746,7 @@ win32_opendir(char *filename) return NULL; /* Get us a DIR structure */ - Newz(1303, dirp, 1, DIR); + Newxz(dirp, 1, DIR); /* Create the search pattern */ strcpy(scanname, filename); @@ -767,15 +763,8 @@ win32_opendir(char *filename) scanname[len] = '\0'; /* do the FindFirstFile call */ - if (USING_WIDE()) { - A2WHELPER(scanname, wbuffer, sizeof(wbuffer)); - fh = FindFirstFileW(PerlDir_mapW(wbuffer), &wFindData); - } - else { - fh = FindFirstFileA(PerlDir_mapA(scanname), &aFindData); - } - dirp->handle = fh; - if (fh == INVALID_HANDLE_VALUE) { + dirp->handle = FindFirstFileA(PerlDir_mapA(scanname), &aFindData); + if (dirp->handle == INVALID_HANDLE_VALUE) { DWORD err = GetLastError(); /* FindFirstFile() fails on empty drives! */ switch (err) { @@ -799,20 +788,13 @@ win32_opendir(char *filename) /* now allocate the first part of the string table for * the filenames that we find. */ - if (USING_WIDE()) { - W2AHELPER(wFindData.cFileName, buffer, sizeof(buffer)); - ptr = buffer; - } - else { - ptr = aFindData.cFileName; - } - idx = strlen(ptr)+1; + idx = strlen(aFindData.cFileName)+1; if (idx < 256) dirp->size = 128; else dirp->size = idx; - New(1304, dirp->start, dirp->size, char); - strcpy(dirp->start, ptr); + Newx(dirp->start, dirp->size, char); + strcpy(dirp->start, aFindData.cFileName); dirp->nfiles++; dirp->end = dirp->curr = dirp->start; dirp->end += idx; @@ -841,30 +823,16 @@ win32_readdir(DIR *dirp) dirp->curr += len + 1; if (dirp->curr >= dirp->end) { dTHX; - char* ptr; BOOL res; - WIN32_FIND_DATAW wFindData; WIN32_FIND_DATAA aFindData; - char buffer[MAX_PATH*2]; /* finding the next file that matches the wildcard * (which should be all of them in this directory!). */ - if (USING_WIDE()) { - res = FindNextFileW(dirp->handle, &wFindData); - if (res) { - W2AHELPER(wFindData.cFileName, buffer, sizeof(buffer)); - ptr = buffer; - } - } - else { - res = FindNextFileA(dirp->handle, &aFindData); - if (res) - ptr = aFindData.cFileName; - } + res = FindNextFileA(dirp->handle, &aFindData); if (res) { long endpos = dirp->end - dirp->start; - long newsize = endpos + strlen(ptr) + 1; + long newsize = endpos + strlen(aFindData.cFileName) + 1; /* bump the string table size by enough for the * new name and its null terminator */ while (newsize > dirp->size) { @@ -873,7 +841,7 @@ win32_readdir(DIR *dirp) Renew(dirp->start, dirp->size, char); dirp->curr = dirp->start + curpos; } - strcpy(dirp->start + endpos, ptr); + strcpy(dirp->start + endpos, aFindData.cFileName); dirp->end = dirp->start + newsize; dirp->nfiles++; } @@ -1022,7 +990,7 @@ find_pid(int pid) dTHX; long child = w32_num_children; while (--child >= 0) { - if (w32_child_pids[child] == pid) + if ((int)w32_child_pids[child] == pid) return child; } return -1; @@ -1049,7 +1017,7 @@ find_pseudo_pid(int pid) dTHX; long child = w32_num_pseudo_children; while (--child >= 0) { - if (w32_pseudo_child_pids[child] == pid) + if ((int)w32_pseudo_child_pids[child] == pid) return child; } return -1; @@ -1065,6 +1033,8 @@ remove_dead_pseudo_process(long child) (w32_num_pseudo_children-child-1), HANDLE); Move(&w32_pseudo_child_pids[child+1], &w32_pseudo_child_pids[child], (w32_num_pseudo_children-child-1), DWORD); + Move(&w32_pseudo_child_message_hwnds[child+1], &w32_pseudo_child_message_hwnds[child], + (w32_num_pseudo_children-child-1), HWND); w32_num_pseudo_children--; } } @@ -1076,16 +1046,19 @@ win32_kill(int pid, int sig) dTHX; HANDLE hProcess; long child; + int retval; #ifdef USE_ITHREADS if (pid < 0) { /* it is a pseudo-forked child */ child = find_pseudo_pid(-pid); if (child >= 0) { + HWND hwnd = w32_pseudo_child_message_hwnds[child]; hProcess = w32_pseudo_child_handles[child]; switch (sig) { case 0: /* "Does process exist?" use of kill */ return 0; + case 9: /* kill -9 style un-graceful exit */ if (TerminateThread(hProcess, sig)) { @@ -1093,16 +1066,30 @@ win32_kill(int pid, int sig) return 0; } break; - default: - /* We fake signals to pseudo-processes using Win32 - * message queue. In Win9X the pids are negative already. */ - if (PostThreadMessage(IsWin95() ? pid : -pid,WM_USER,sig,0)) { - /* It might be us ... */ - PERL_ASYNC_CHECK(); - return 0; - } + + default: { + int count = 0; + /* pseudo-process has not yet properly initialized if hwnd isn't set */ + while (hwnd == INVALID_HANDLE_VALUE && count < 5) { + /* Yield and wait for the other thread to send us its message_hwnd */ + Sleep(0); + win32_async_check(aTHX); + ++count; + } + if (hwnd != INVALID_HANDLE_VALUE) { + /* We fake signals to pseudo-processes using Win32 + * message queue. In Win9X the pids are negative already. */ + if ((hwnd != NULL && PostMessage(hwnd, WM_USER_KILL, sig, 0)) || + PostThreadMessage(IsWin95() ? pid : -pid, WM_USER_KILL, sig, 0)) + { + /* It might be us ... */ + PERL_ASYNC_CHECK(); + return 0; + } + } break; } + } /* switch */ } else if (IsWin95()) { pid = -pid; @@ -1123,6 +1110,11 @@ win32_kill(int pid, int sig) if (GenerateConsoleCtrlEvent(CTRL_C_EVENT,pid)) return 0; break; + case SIGBREAK: + case SIGTERM: + if (GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,pid)) + return 0; + break; default: /* For now be backwards compatible with perl5.6 */ case 9: if (TerminateProcess(hProcess, sig)) { @@ -1134,25 +1126,34 @@ win32_kill(int pid, int sig) } else { alien_process: + retval = -1; hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE, (IsWin95() ? -pid : pid)); if (hProcess) { switch(sig) { case 0: /* "Does process exist?" use of kill */ - return 0; + retval = 0; + break; case 2: if (GenerateConsoleCtrlEvent(CTRL_C_EVENT,pid)) - return 0; + retval = 0; break; + case SIGBREAK: + case SIGTERM: + if (GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,pid)) + retval = 0; + break; default: /* For now be backwards compatible with perl5.6 */ case 9: - if (TerminateProcess(hProcess, sig)) { - CloseHandle(hProcess); - return 0; - } + if (TerminateProcess(hProcess, sig)) + retval = 0; + break; } } + CloseHandle(hProcess); + if (retval == 0) + return 0; } } errno = EINVAL; @@ -1166,21 +1167,36 @@ win32_stat(const char *path, Stat_t *sbuf) char buffer[MAX_PATH+1]; int l = strlen(path); int res; - WCHAR wbuffer[MAX_PATH+1]; - WCHAR* pwbuffer; - HANDLE handle; int nlink = 1; + BOOL expect_dir = FALSE; + + GV *gv_sloppy = gv_fetchpvs("\027IN32_SLOPPY_STAT", + GV_NOTQUAL, SVt_PV); + BOOL sloppy = gv_sloppy && SvTRUE(GvSV(gv_sloppy)); if (l > 1) { switch(path[l - 1]) { /* FindFirstFile() and stat() are buggy with a trailing - * backslash, so change it to a forward slash :-( */ + * slashes, except for the root directory of a drive */ case '\\': - strncpy(buffer, path, l-1); - buffer[l - 1] = '/'; - buffer[l] = '\0'; - path = buffer; + case '/': + if (l > sizeof(buffer)) { + errno = ENAMETOOLONG; + return -1; + } + --l; + strncpy(buffer, path, l); + /* remove additional trailing slashes */ + while (l > 1 && (buffer[l-1] == '/' || buffer[l-1] == '\\')) + --l; + /* add back slash if we otherwise end up with just a drive letter */ + if (l == 2 && isALPHA(buffer[0]) && buffer[1] == ':') + buffer[l++] = '\\'; + buffer[l] = '\0'; + path = buffer; + expect_dir = TRUE; break; + /* FindFirstFile() is buggy with "x:", so add a dot :-( */ case ':': if (l == 2 && isALPHA(path[0])) { @@ -1195,41 +1211,28 @@ win32_stat(const char *path, Stat_t *sbuf) } } - /* We *must* open & close the file once; otherwise file attribute changes */ - /* might not yet have propagated to "other" hard links of the same file. */ - /* This also gives us an opportunity to determine the number of links. */ - if (USING_WIDE()) { - A2WHELPER(path, wbuffer, sizeof(wbuffer)); - pwbuffer = PerlDir_mapW(wbuffer); - handle = CreateFileW(pwbuffer, 0, 0, NULL, OPEN_EXISTING, 0, NULL); - } - else { - path = PerlDir_mapA(path); - l = strlen(path); - handle = CreateFileA(path, 0, 0, NULL, OPEN_EXISTING, 0, NULL); - } - if (handle != INVALID_HANDLE_VALUE) { - BY_HANDLE_FILE_INFORMATION bhi; - if (GetFileInformationByHandle(handle, &bhi)) - nlink = bhi.nNumberOfLinks; - CloseHandle(handle); - } + path = PerlDir_mapA(path); + l = strlen(path); - /* pwbuffer or path will be mapped correctly above */ - if (USING_WIDE()) { -#if defined(WIN64) || defined(USE_LARGE_FILES) - res = _wstati64(pwbuffer, sbuf); -#else - res = _wstat(pwbuffer, sbuf); -#endif + if (!sloppy) { + /* We must open & close the file once; otherwise file attribute changes */ + /* might not yet have propagated to "other" hard links of the same file. */ + /* This also gives us an opportunity to determine the number of links. */ + HANDLE handle = CreateFileA(path, 0, 0, NULL, OPEN_EXISTING, 0, NULL); + if (handle != INVALID_HANDLE_VALUE) { + BY_HANDLE_FILE_INFORMATION bhi; + if (GetFileInformationByHandle(handle, &bhi)) + nlink = bhi.nNumberOfLinks; + CloseHandle(handle); + } } - else { + + /* path will be mapped correctly above */ #if defined(WIN64) || defined(USE_LARGE_FILES) - res = _stati64(path, sbuf); + res = _stati64(path, sbuf); #else - res = stat(path, sbuf); + res = stat(path, sbuf); #endif - } sbuf->st_nlink = nlink; if (res < 0) { @@ -1237,13 +1240,7 @@ win32_stat(const char *path, Stat_t *sbuf) * XXX using GetFileAttributesEx() will enable us to set * sbuf->st_*time (but note that's not available on the * Windows of 1995) */ - DWORD r; - if (USING_WIDE()) { - r = GetFileAttributesW(pwbuffer); - } - else { - r = GetFileAttributesA(path); - } + DWORD r = GetFileAttributesA(path); if (r != 0xffffffff && (r & FILE_ATTRIBUTE_DIRECTORY)) { /* sbuf may still contain old garbage since stat() failed */ Zero(sbuf, 1, Stat_t); @@ -1259,13 +1256,15 @@ win32_stat(const char *path, Stat_t *sbuf) && (path[2] == '\\' || path[2] == '/')) { /* The drive can be inaccessible, some _stat()s are buggy */ - if (USING_WIDE() - ? !GetVolumeInformationW(pwbuffer,NULL,0,NULL,NULL,NULL,NULL,0) - : !GetVolumeInformationA(path,NULL,0,NULL,NULL,NULL,NULL,0)) { + if (!GetVolumeInformationA(path,NULL,0,NULL,NULL,NULL,NULL,0)) { errno = ENOENT; return -1; } } + if (expect_dir && !S_ISDIR(sbuf->st_mode)) { + errno = ENOTDIR; + return -1; + } #ifdef __BORLANDC__ if (S_ISDIR(sbuf->st_mode)) sbuf->st_mode |= S_IWRITE | S_IEXEC; @@ -1398,38 +1397,18 @@ DllExport char * win32_getenv(const char *name) { dTHX; - WCHAR wBuffer[MAX_PATH+1]; DWORD needlen; SV *curitem = Nullsv; - if (USING_WIDE()) { - A2WHELPER(name, wBuffer, sizeof(wBuffer)); - needlen = GetEnvironmentVariableW(wBuffer, NULL, 0); - } - else - needlen = GetEnvironmentVariableA(name,NULL,0); + needlen = GetEnvironmentVariableA(name,NULL,0); if (needlen != 0) { curitem = sv_2mortal(newSVpvn("", 0)); - if (USING_WIDE()) { - SV *acuritem; - do { - SvGROW(curitem, (needlen+1)*sizeof(WCHAR)); - needlen = GetEnvironmentVariableW(wBuffer, - (WCHAR*)SvPVX(curitem), - needlen); - } while (needlen >= SvLEN(curitem)/sizeof(WCHAR)); - SvCUR_set(curitem, (needlen*sizeof(WCHAR))+1); - acuritem = sv_2mortal(newSVsv(curitem)); - W2AHELPER((WCHAR*)SvPVX(acuritem), SvPVX(curitem), SvCUR(curitem)); - } - else { - do { - SvGROW(curitem, needlen+1); - needlen = GetEnvironmentVariableA(name,SvPVX(curitem), - needlen); - } while (needlen >= SvLEN(curitem)); - SvCUR_set(curitem, needlen); - } + do { + SvGROW(curitem, needlen+1); + needlen = GetEnvironmentVariableA(name,SvPVX(curitem), + needlen); + } while (needlen >= SvLEN(curitem)); + SvCUR_set(curitem, needlen); } else { /* allow any environment variables that begin with 'PERL' @@ -1449,48 +1428,32 @@ win32_putenv(const char *name) dTHX; char* curitem; char* val; - WCHAR* wCuritem; - WCHAR* wVal; - int length, relval = -1; + int relval = -1; if (name) { - if (USING_WIDE()) { - length = strlen(name)+1; - New(1309,wCuritem,length,WCHAR); - A2WHELPER(name, wCuritem, length*sizeof(WCHAR)); - wVal = wcschr(wCuritem, '='); - if (wVal) { - *wVal++ = '\0'; - if (SetEnvironmentVariableW(wCuritem, *wVal ? wVal : NULL)) - relval = 0; - } - Safefree(wCuritem); - } - else { - New(1309,curitem,strlen(name)+1,char); - strcpy(curitem, name); - val = strchr(curitem, '='); - if (val) { - /* The sane way to deal with the environment. - * Has these advantages over putenv() & co.: - * * enables us to store a truly empty value in the - * environment (like in UNIX). - * * we don't have to deal with RTL globals, bugs and leaks. - * * Much faster. - * Why you may want to enable USE_WIN32_RTL_ENV: - * * environ[] and RTL functions will not reflect changes, - * which might be an issue if extensions want to access - * the env. via RTL. This cuts both ways, since RTL will - * not see changes made by extensions that call the Win32 - * functions directly, either. - * GSAR 97-06-07 - */ - *val++ = '\0'; - if (SetEnvironmentVariableA(curitem, *val ? val : NULL)) - relval = 0; - } - Safefree(curitem); - } + Newx(curitem,strlen(name)+1,char); + strcpy(curitem, name); + val = strchr(curitem, '='); + if (val) { + /* The sane way to deal with the environment. + * Has these advantages over putenv() & co.: + * * enables us to store a truly empty value in the + * environment (like in UNIX). + * * we don't have to deal with RTL globals, bugs and leaks. + * * Much faster. + * Why you may want to enable USE_WIN32_RTL_ENV: + * * environ[] and RTL functions will not reflect changes, + * which might be an issue if extensions want to access + * the env. via RTL. This cuts both ways, since RTL will + * not see changes made by extensions that call the Win32 + * functions directly, either. + * GSAR 97-06-07 + */ + *val++ = '\0'; + if (SetEnvironmentVariableA(curitem, *val ? val : NULL)) + relval = 0; + } + Safefree(curitem); } return relval; } @@ -1558,42 +1521,21 @@ win32_unlink(const char *filename) int ret; DWORD attrs; - if (USING_WIDE()) { - WCHAR wBuffer[MAX_PATH+1]; - WCHAR* pwBuffer; - - A2WHELPER(filename, wBuffer, sizeof(wBuffer)); - pwBuffer = PerlDir_mapW(wBuffer); - attrs = GetFileAttributesW(pwBuffer); - if (attrs == 0xFFFFFFFF) - goto fail; - if (attrs & FILE_ATTRIBUTE_READONLY) { - (void)SetFileAttributesW(pwBuffer, attrs & ~FILE_ATTRIBUTE_READONLY); - ret = _wunlink(pwBuffer); - if (ret == -1) - (void)SetFileAttributesW(pwBuffer, attrs); - } - else - ret = _wunlink(pwBuffer); + filename = PerlDir_mapA(filename); + attrs = GetFileAttributesA(filename); + if (attrs == 0xFFFFFFFF) { + errno = ENOENT; + return -1; } - else { - filename = PerlDir_mapA(filename); - attrs = GetFileAttributesA(filename); - if (attrs == 0xFFFFFFFF) - goto fail; - if (attrs & FILE_ATTRIBUTE_READONLY) { - (void)SetFileAttributesA(filename, attrs & ~FILE_ATTRIBUTE_READONLY); - ret = unlink(filename); - if (ret == -1) - (void)SetFileAttributesA(filename, attrs); - } - else - ret = unlink(filename); + if (attrs & FILE_ATTRIBUTE_READONLY) { + (void)SetFileAttributesA(filename, attrs & ~FILE_ATTRIBUTE_READONLY); + ret = unlink(filename); + if (ret == -1) + (void)SetFileAttributesA(filename, attrs); } + else + ret = unlink(filename); return ret; -fail: - errno = ENOENT; - return -1; } DllExport int @@ -1605,19 +1547,11 @@ win32_utime(const char *filename, struct utimbuf *times) FILETIME ftAccess; FILETIME ftWrite; struct utimbuf TimeBuffer; - WCHAR wbuffer[MAX_PATH+1]; - WCHAR* pwbuffer; - int rc; - if (USING_WIDE()) { - A2WHELPER(filename, wbuffer, sizeof(wbuffer)); - pwbuffer = PerlDir_mapW(wbuffer); - rc = _wutime(pwbuffer, (struct _utimbuf*)times); - } - else { - filename = PerlDir_mapA(filename); - rc = utime(filename, times); - } + + filename = PerlDir_mapA(filename); + rc = utime(filename, times); + /* EACCES: path specifies directory or readonly file */ if (rc == 0 || errno != EACCES /* || !IsWinNT() */) return rc; @@ -1629,16 +1563,9 @@ win32_utime(const char *filename, struct utimbuf *times) } /* This will (and should) still fail on readonly files */ - if (USING_WIDE()) { - handle = CreateFileW(pwbuffer, GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, - OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); - } - else { - handle = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, - OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); - } + handle = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); if (handle == INVALID_HANDLE_VALUE) return rc; @@ -1654,49 +1581,71 @@ win32_utime(const char *filename, struct utimbuf *times) return rc; } +typedef union { + unsigned __int64 ft_i64; + FILETIME ft_val; +} FT_t; + +#ifdef __GNUC__ +#define Const64(x) x##LL +#else +#define Const64(x) x##i64 +#endif +/* Number of 100 nanosecond units from 1/1/1601 to 1/1/1970 */ +#define EPOCH_BIAS Const64(116444736000000000) + +/* NOTE: This does not compute the timezone info (doing so can be expensive, + * and appears to be unsupported even by glibc) */ +DllExport int +win32_gettimeofday(struct timeval *tp, void *not_used) +{ + FT_t ft; + + /* this returns time in 100-nanosecond units (i.e. tens of usecs) */ + GetSystemTimeAsFileTime(&ft.ft_val); + + /* seconds since epoch */ + tp->tv_sec = (long)((ft.ft_i64 - EPOCH_BIAS) / Const64(10000000)); + + /* microseconds remaining */ + tp->tv_usec = (long)((ft.ft_i64 / Const64(10)) % Const64(1000000)); + + return 0; +} + DllExport int win32_uname(struct utsname *name) { struct hostent *hep; STRLEN nodemax = sizeof(name->nodename)-1; - OSVERSIONINFO osver; - - memset(&osver, 0, sizeof(OSVERSIONINFO)); - osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - if (GetVersionEx(&osver)) { - /* sysname */ - switch (osver.dwPlatformId) { - case VER_PLATFORM_WIN32_WINDOWS: - strcpy(name->sysname, "Windows"); - break; - case VER_PLATFORM_WIN32_NT: - strcpy(name->sysname, "Windows NT"); - break; - case VER_PLATFORM_WIN32s: - strcpy(name->sysname, "Win32s"); - break; - default: - strcpy(name->sysname, "Win32 Unknown"); - break; - } - /* release */ - sprintf(name->release, "%d.%d", - osver.dwMajorVersion, osver.dwMinorVersion); - - /* version */ - sprintf(name->version, "Build %d", - osver.dwPlatformId == VER_PLATFORM_WIN32_NT - ? osver.dwBuildNumber : (osver.dwBuildNumber & 0xffff)); - if (osver.szCSDVersion[0]) { - char *buf = name->version + strlen(name->version); - sprintf(buf, " (%s)", osver.szCSDVersion); - } + /* sysname */ + switch (g_osver.dwPlatformId) { + case VER_PLATFORM_WIN32_WINDOWS: + strcpy(name->sysname, "Windows"); + break; + case VER_PLATFORM_WIN32_NT: + strcpy(name->sysname, "Windows NT"); + break; + case VER_PLATFORM_WIN32s: + strcpy(name->sysname, "Win32s"); + break; + default: + strcpy(name->sysname, "Win32 Unknown"); + break; } - else { - *name->sysname = '\0'; - *name->version = '\0'; - *name->release = '\0'; + + /* release */ + sprintf(name->release, "%d.%d", + g_osver.dwMajorVersion, g_osver.dwMinorVersion); + + /* version */ + sprintf(name->version, "Build %d", + g_osver.dwPlatformId == VER_PLATFORM_WIN32_NT + ? g_osver.dwBuildNumber : (g_osver.dwBuildNumber & 0xffff)); + if (g_osver.szCSDVersion[0]) { + char *buf = name->version + strlen(name->version); + sprintf(buf, " (%s)", g_osver.szCSDVersion); } /* nodename */ @@ -1720,15 +1669,17 @@ win32_uname(struct utsname *name) /* machine (architecture) */ { SYSTEM_INFO info; + DWORD procarch; char *arch; GetSystemInfo(&info); #if (defined(__BORLANDC__)&&(__BORLANDC__<=0x520)) \ || (defined(__MINGW32__) && !defined(_ANONYMOUS_UNION)) - switch (info.u.s.wProcessorArchitecture) { + procarch = info.u.s.wProcessorArchitecture; #else - switch (info.wProcessorArchitecture) { + procarch = info.wProcessorArchitecture; #endif + switch (procarch) { case PROCESSOR_ARCHITECTURE_INTEL: arch = "x86"; break; case PROCESSOR_ARCHITECTURE_MIPS: @@ -1737,10 +1688,45 @@ win32_uname(struct utsname *name) arch = "alpha"; break; case PROCESSOR_ARCHITECTURE_PPC: arch = "ppc"; break; - default: +#ifdef PROCESSOR_ARCHITECTURE_SHX + case PROCESSOR_ARCHITECTURE_SHX: + arch = "shx"; break; +#endif +#ifdef PROCESSOR_ARCHITECTURE_ARM + case PROCESSOR_ARCHITECTURE_ARM: + arch = "arm"; break; +#endif +#ifdef PROCESSOR_ARCHITECTURE_IA64 + case PROCESSOR_ARCHITECTURE_IA64: + arch = "ia64"; break; +#endif +#ifdef PROCESSOR_ARCHITECTURE_ALPHA64 + case PROCESSOR_ARCHITECTURE_ALPHA64: + arch = "alpha64"; break; +#endif +#ifdef PROCESSOR_ARCHITECTURE_MSIL + case PROCESSOR_ARCHITECTURE_MSIL: + arch = "msil"; break; +#endif +#ifdef PROCESSOR_ARCHITECTURE_AMD64 + case PROCESSOR_ARCHITECTURE_AMD64: + arch = "amd64"; break; +#endif +#ifdef PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 + case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64: + arch = "ia32-64"; break; +#endif +#ifdef PROCESSOR_ARCHITECTURE_UNKNOWN + case PROCESSOR_ARCHITECTURE_UNKNOWN: arch = "unknown"; break; +#endif + default: + sprintf(name->machine, "unknown(0x%x)", procarch); + arch = name->machine; + break; } - strcpy(name->machine, arch); + if (name->machine != arch) + strcpy(name->machine, arch); } return 0; } @@ -1794,64 +1780,75 @@ DllExport int win32_async_check(pTHX) { MSG msg; - int ours = 1; + HWND hwnd = w32_message_hwnd; + + w32_poll_count = 0; + + if (hwnd == INVALID_HANDLE_VALUE) { + /* Call PeekMessage() to mark all pending messages in the queue as "old". + * This is necessary when we are being called by win32_msgwait() to + * make sure MsgWaitForMultipleObjects() stops reporting the same waiting + * message over and over. An example how this can happen is when + * Perl is calling win32_waitpid() inside a GUI application and the GUI + * is generating messages before the process terminated. + */ + PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE|PM_NOYIELD); + if (PL_sig_pending) + despatch_signals(); + return 1; + } + /* Passing PeekMessage -1 as HWND (2nd arg) only get PostThreadMessage() messages * and ignores window messages - should co-exist better with windows apps e.g. Tk */ - while (PeekMessage(&msg, (HWND)-1, 0, 0, PM_REMOVE|PM_NOYIELD)) { - int sig; - switch(msg.message) { + if (hwnd == NULL) + hwnd = (HWND)-1; -#if 0 - /* Perhaps some other messages could map to signals ? ... */ - case WM_CLOSE: - case WM_QUIT: - /* Treat WM_QUIT like SIGHUP? */ - sig = SIGHUP; - goto Raise; - break; + while (PeekMessage(&msg, hwnd, WM_TIMER, WM_TIMER, PM_REMOVE|PM_NOYIELD) || + PeekMessage(&msg, hwnd, WM_USER_MIN, WM_USER_MAX, PM_REMOVE|PM_NOYIELD)) + { + switch (msg.message) { +#ifdef USE_ITHREADS + case WM_USER_MESSAGE: { + int child = find_pseudo_pid(msg.wParam); + if (child >= 0) + w32_pseudo_child_message_hwnds[child] = (HWND)msg.lParam; + break; + } #endif - /* We use WM_USER to fake kill() with other signals */ - case WM_USER: { - sig = msg.wParam; - Raise: - if (do_raise(aTHX_ sig)) { - sig_terminate(aTHX_ sig); - } + case WM_USER_KILL: { + /* We use WM_USER to fake kill() with other signals */ + int sig = msg.wParam; + if (do_raise(aTHX_ sig)) + sig_terminate(aTHX_ sig); break; } case WM_TIMER: { /* alarm() is a one-shot but SetTimer() repeats so kill it */ - if (w32_timerid) { - KillTimer(NULL,w32_timerid); + if (w32_timerid && w32_timerid==msg.wParam) { + KillTimer(w32_message_hwnd, w32_timerid); w32_timerid=0; - } - /* Now fake a call to signal handler */ - if (do_raise(aTHX_ 14)) { - sig_terminate(aTHX_ 14); - } - break; - } - /* Otherwise do normal Win32 thing - in case it is useful */ - default: - TranslateMessage(&msg); - DispatchMessage(&msg); - ours = 0; + /* Now fake a call to signal handler */ + if (do_raise(aTHX_ 14)) + sig_terminate(aTHX_ 14); + } break; } + } /* switch */ } - w32_poll_count = 0; /* Above or other stuff may have set a signal flag */ if (PL_sig_pending) { despatch_signals(); } - return ours; + return 1; } +/* This function will not return until the timeout has elapsed, or until + * one of the handles is ready. */ DllExport DWORD win32_msgwait(pTHX_ DWORD count, LPHANDLE handles, DWORD timeout, LPDWORD resultp) { @@ -1876,10 +1873,7 @@ win32_msgwait(pTHX_ DWORD count, LPHANDLE handles, DWORD timeout, LPDWORD result } if (result == WAIT_OBJECT_0 + count) { /* Message has arrived - check it */ - if (win32_async_check(aTHX)) { - /* was one of ours */ - break; - } + (void)win32_async_check(aTHX); } else { /* Not timeout or message - one of handles is ready */ @@ -1952,7 +1946,6 @@ win32_internal_wait(int *status, DWORD timeout) } } -FAILED: errno = GetLastError(); return -1; } @@ -2021,6 +2014,7 @@ alien_process: if (hProcess) { win32_msgwait(aTHX_ 1, &hProcess, timeout, &waitcode); if (waitcode == WAIT_TIMEOUT) { + CloseHandle(hProcess); return 0; } else if (waitcode == WAIT_OBJECT_0) { @@ -2063,13 +2057,22 @@ win32_alarm(unsigned int sec) * one of the supported codes in */ dTHX; + + if (w32_message_hwnd == INVALID_HANDLE_VALUE) + w32_message_hwnd = win32_create_message_window(); + if (sec) { - w32_timerid = SetTimer(NULL,w32_timerid,sec*1000,NULL); + if (w32_message_hwnd == NULL) + w32_timerid = SetTimer(NULL, w32_timerid, sec*1000, NULL); + else { + w32_timerid = 1; + SetTimer(w32_message_hwnd, w32_timerid, sec*1000, NULL); + } } else { if (w32_timerid) { - KillTimer(NULL,w32_timerid); - w32_timerid=0; + KillTimer(w32_message_hwnd, w32_timerid); + w32_timerid = 0; } } return 0; @@ -2387,7 +2390,6 @@ DllExport FILE * win32_fopen(const char *filename, const char *mode) { dTHX; - WCHAR wMode[MODE_SIZE], wBuffer[MAX_PATH+1]; FILE *f; if (!*filename) @@ -2396,13 +2398,7 @@ win32_fopen(const char *filename, const char *mode) if (stricmp(filename, "/dev/null")==0) filename = "NUL"; - if (USING_WIDE()) { - A2WHELPER(mode, wMode, sizeof(wMode)); - A2WHELPER(filename, wBuffer, sizeof(wBuffer)); - f = _wfopen(PerlDir_mapW(wBuffer), wMode); - } - else - f = fopen(PerlDir_mapA(filename), mode); + f = fopen(PerlDir_mapA(filename), mode); /* avoid buffering headaches for child processes */ if (f && *mode == 'a') win32_fseek(f, 0, SEEK_END); @@ -2418,14 +2414,8 @@ DllExport FILE * win32_fdopen(int handle, const char *mode) { dTHX; - WCHAR wMode[MODE_SIZE]; FILE *f; - if (USING_WIDE()) { - A2WHELPER(mode, wMode, sizeof(wMode)); - f = _wfdopen(handle, wMode); - } - else - f = fdopen(handle, (char *) mode); + f = fdopen(handle, (char *) mode); /* avoid buffering headaches for child processes */ if (f && *mode == 'a') win32_fseek(f, 0, SEEK_END); @@ -2436,15 +2426,9 @@ DllExport FILE * win32_freopen(const char *path, const char *mode, FILE *stream) { dTHX; - WCHAR wMode[MODE_SIZE], wBuffer[MAX_PATH+1]; if (stricmp(path, "/dev/null")==0) path = "NUL"; - if (USING_WIDE()) { - A2WHELPER(mode, wMode, sizeof(wMode)); - A2WHELPER(path, wBuffer, sizeof(wBuffer)); - return _wfreopen(PerlDir_mapW(wBuffer), wMode, stream); - } return freopen(PerlDir_mapA(path), mode, stream); } @@ -2501,10 +2485,14 @@ DllExport Off_t win32_ftell(FILE *pf) { #if defined(WIN64) || defined(USE_LARGE_FILES) +#if defined(__BORLANDC__) /* buk */ + return win32_tell( fileno( pf ) ); +#else fpos_t pos; if (fgetpos(pf, &pos)) return -1; return (Off_t)pos; +#endif #else return ftell(pf); #endif @@ -2514,6 +2502,13 @@ DllExport int win32_fseek(FILE *pf, Off_t offset,int origin) { #if defined(WIN64) || defined(USE_LARGE_FILES) +#if defined(__BORLANDC__) /* buk */ + return win32_lseek( + fileno(pf), + offset, + origin + ); +#else fpos_t pos; switch (origin) { case SEEK_CUR: @@ -2533,21 +2528,34 @@ win32_fseek(FILE *pf, Off_t offset,int origin) return -1; } return fsetpos(pf, &offset); +#endif #else - return fseek(pf, offset, origin); + return fseek(pf, (long)offset, origin); #endif } DllExport int win32_fgetpos(FILE *pf,fpos_t *p) { +#if defined(__BORLANDC__) && defined(USE_LARGE_FILES) /* buk */ + if( win32_tell(fileno(pf)) == -1L ) { + errno = EBADF; + return -1; + } + return 0; +#else return fgetpos(pf, p); +#endif } DllExport int win32_fsetpos(FILE *pf,const fpos_t *p) { +#if defined(__BORLANDC__) && defined(USE_LARGE_FILES) /* buk */ + return win32_lseek(fileno(pf), *p, SEEK_CUR); +#else return fsetpos(pf, p); +#endif } DllExport void @@ -2557,8 +2565,8 @@ win32_rewind(FILE *pf) return; } -DllExport FILE* -win32_tmpfile(void) +DllExport int +win32_tmpfd(void) { dTHX; char prefix[MAX_PATH+1]; @@ -2582,11 +2590,20 @@ win32_tmpfile(void) #endif DEBUG_p(PerlIO_printf(Perl_debug_log, "Created tmpfile=%s\n",filename)); - return fdopen(fd, "w+b"); + return fd; } } } } + return -1; +} + +DllExport FILE* +win32_tmpfile(void) +{ + int fd = win32_tmpfd(); + if (fd >= 0) + return win32_fdopen(fd, "w+b"); return NULL; } @@ -2605,9 +2622,31 @@ win32_fstat(int fd, Stat_t *sbufptr) * for write operations, probably because it is opened for reading. * --Vadim Konovalov */ - int rc = fstat(fd,sbufptr); BY_HANDLE_FILE_INFORMATION bhfi; +#if defined(WIN64) || defined(USE_LARGE_FILES) + /* Borland 5.5.1 has a 64-bit stat, but only a 32-bit fstat */ + struct stat tmp; + int rc = fstat(fd,&tmp); + + sbufptr->st_dev = tmp.st_dev; + sbufptr->st_ino = tmp.st_ino; + sbufptr->st_mode = tmp.st_mode; + sbufptr->st_nlink = tmp.st_nlink; + sbufptr->st_uid = tmp.st_uid; + sbufptr->st_gid = tmp.st_gid; + sbufptr->st_rdev = tmp.st_rdev; + sbufptr->st_size = tmp.st_size; + sbufptr->st_atime = tmp.st_atime; + sbufptr->st_mtime = tmp.st_mtime; + sbufptr->st_ctime = tmp.st_ctime; +#else + int rc = fstat(fd,sbufptr); +#endif + if (GetFileInformationByHandle((HANDLE)_get_osfhandle(fd), &bhfi)) { +#if defined(WIN64) || defined(USE_LARGE_FILES) + sbufptr->st_size = (bhfi.nFileSizeHigh << 32) + bhfi.nFileSizeLow ; +#endif sbufptr->st_mode &= 0xFE00; if (bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY) sbufptr->st_mode |= (S_IREAD + (S_IREAD >> 3) + (S_IREAD >> 6)); @@ -2647,22 +2686,28 @@ win32_popen(const char *command, const char *mode) #ifdef USE_RTL_POPEN return _popen(command, mode); #else + dTHX; int p[2]; int parent, child; int stdfd, oldfd; int ourmode; int childpid; + DWORD nhandle; + HANDLE old_h; + int lock_held = 0; /* establish which ends read and write */ if (strchr(mode,'w')) { stdfd = 0; /* stdin */ parent = 1; child = 0; + nhandle = STD_INPUT_HANDLE; } else if (strchr(mode,'r')) { stdfd = 1; /* stdout */ parent = 0; child = 1; + nhandle = STD_OUTPUT_HANDLE; } else return NULL; @@ -2678,13 +2723,19 @@ win32_popen(const char *command, const char *mode) /* the child doesn't inherit handles */ ourmode |= O_NOINHERIT; - if (win32_pipe( p, 512, ourmode) == -1) + if (win32_pipe(p, 512, ourmode) == -1) return NULL; /* save current stdfd */ if ((oldfd = win32_dup(stdfd)) == -1) goto cleanup; + /* save the old std handle (this needs to happen before the + * dup2(), since that might call SetStdHandle() too) */ + OP_REFCNT_LOCK; + lock_held = 1; + old_h = GetStdHandle(nhandle); + /* make stdfd go to child end of pipe (implicitly closes stdfd) */ /* stdfd will be inherited by the child */ if (win32_dup2(p[child], stdfd) == -1) @@ -2693,6 +2744,9 @@ win32_popen(const char *command, const char *mode) /* close the child end in parent */ win32_close(p[child]); + /* set the new std handle (in case dup2() above didn't) */ + SetStdHandle(nhandle, (HANDLE)_get_osfhandle(stdfd)); + /* start the child */ { dTHX; @@ -2703,6 +2757,14 @@ win32_popen(const char *command, const char *mode) if (win32_dup2(oldfd, stdfd) == -1) goto cleanup; + /* restore the old std handle (this needs to happen after the + * dup2(), since that might call SetStdHandle() too */ + if (lock_held) { + SetStdHandle(nhandle, old_h); + OP_REFCNT_UNLOCK; + lock_held = 0; + } + /* close saved handle */ win32_close(oldfd); @@ -2721,6 +2783,11 @@ cleanup: /* we don't need to check for errors here */ win32_close(p[0]); win32_close(p[1]); + if (lock_held) { + SetStdHandle(nhandle, old_h); + OP_REFCNT_UNLOCK; + lock_held = 0; + } if (oldfd != -1) { win32_dup2(oldfd, stdfd); win32_close(oldfd); @@ -2753,6 +2820,7 @@ win32_pclose(PerlIO *pf) childpid = 0; if (!childpid) { + UNLOCK_FDPID_MUTEX; errno = EBADF; return -1; } @@ -2848,10 +2916,10 @@ win32_link(const char *oldname, const char *newname) if (pfnCreateHardLinkW == NULL) pfnCreateHardLinkW = Nt4CreateHardLinkW; - if ((A2WHELPER(oldname, wOldName, sizeof(wOldName))) && - (A2WHELPER(newname, wNewName, sizeof(wNewName))) && + if (MultiByteToWideChar(CP_ACP, 0, oldname, -1, wOldName, MAX_PATH+1) && + MultiByteToWideChar(CP_ACP, 0, newname, -1, wNewName, MAX_PATH+1) && (wcscpy(wOldName, PerlDir_mapW(wOldName)), - pfnCreateHardLinkW(PerlDir_mapW(wNewName), wOldName, NULL))) + pfnCreateHardLinkW(PerlDir_mapW(wNewName), wOldName, NULL))) { return 0; } @@ -2862,8 +2930,6 @@ win32_link(const char *oldname, const char *newname) DllExport int win32_rename(const char *oname, const char *newname) { - WCHAR wOldName[MAX_PATH+1]; - WCHAR wNewName[MAX_PATH+1]; char szOldName[MAX_PATH+1]; char szNewName[MAX_PATH+1]; BOOL bResult; @@ -2874,20 +2940,10 @@ win32_rename(const char *oname, const char *newname) */ if (IsWinNT()) { DWORD dwFlags = MOVEFILE_COPY_ALLOWED; - if (USING_WIDE()) { - A2WHELPER(oname, wOldName, sizeof(wOldName)); - A2WHELPER(newname, wNewName, sizeof(wNewName)); - if (wcsicmp(wNewName, wOldName)) - dwFlags |= MOVEFILE_REPLACE_EXISTING; - wcscpy(wOldName, PerlDir_mapW(wOldName)); - bResult = MoveFileExW(wOldName,PerlDir_mapW(wNewName), dwFlags); - } - else { - if (stricmp(newname, oname)) - dwFlags |= MOVEFILE_REPLACE_EXISTING; - strcpy(szOldName, PerlDir_mapA(oname)); - bResult = MoveFileExA(szOldName,PerlDir_mapA(newname), dwFlags); - } + if (stricmp(newname, oname)) + dwFlags |= MOVEFILE_REPLACE_EXISTING; + strcpy(szOldName, PerlDir_mapA(oname)); + bResult = MoveFileExA(szOldName,PerlDir_mapA(newname), dwFlags); if (!bResult) { DWORD err = GetLastError(); switch (err) { @@ -2990,13 +3046,78 @@ win32_setmode(int fd, int mode) return setmode(fd, mode); } +DllExport int +win32_chsize(int fd, Off_t size) +{ +#if defined(WIN64) || defined(USE_LARGE_FILES) + int retval = 0; + Off_t cur, end, extend; + + cur = win32_tell(fd); + if (cur < 0) + return -1; + end = win32_lseek(fd, 0, SEEK_END); + if (end < 0) + return -1; + extend = size - end; + if (extend == 0) { + /* do nothing */ + } + else if (extend > 0) { + /* must grow the file, padding with nulls */ + char b[4096]; + int oldmode = win32_setmode(fd, O_BINARY); + size_t count; + memset(b, '\0', sizeof(b)); + do { + count = extend >= sizeof(b) ? sizeof(b) : (size_t)extend; + count = win32_write(fd, b, count); + if ((int)count < 0) { + retval = -1; + break; + } + } while ((extend -= count) > 0); + win32_setmode(fd, oldmode); + } + else { + /* shrink the file */ + win32_lseek(fd, size, SEEK_SET); + if (!SetEndOfFile((HANDLE)_get_osfhandle(fd))) { + errno = EACCES; + retval = -1; + } + } +finish: + win32_lseek(fd, cur, SEEK_SET); + return retval; +#else + return chsize(fd, (long)size); +#endif +} + DllExport Off_t win32_lseek(int fd, Off_t offset, int origin) { #if defined(WIN64) || defined(USE_LARGE_FILES) +#if defined(__BORLANDC__) /* buk */ + LARGE_INTEGER pos; + pos.QuadPart = offset; + pos.LowPart = SetFilePointer( + (HANDLE)_get_osfhandle(fd), + pos.LowPart, + &pos.HighPart, + origin + ); + if (pos.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) { + pos.QuadPart = -1; + } + + return pos.QuadPart; +#else return _lseeki64(fd, offset, origin); +#endif #else - return lseek(fd, offset, origin); + return lseek(fd, (long)offset, origin); #endif } @@ -3004,7 +3125,24 @@ DllExport Off_t win32_tell(int fd) { #if defined(WIN64) || defined(USE_LARGE_FILES) +#if defined(__BORLANDC__) /* buk */ + LARGE_INTEGER pos; + pos.QuadPart = 0; + pos.LowPart = SetFilePointer( + (HANDLE)_get_osfhandle(fd), + pos.LowPart, + &pos.HighPart, + FILE_CURRENT + ); + if (pos.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) { + pos.QuadPart = -1; + } + + return pos.QuadPart; + /* return tell(fd); */ +#else return _telli64(fd); +#endif #else return tell(fd); #endif @@ -3016,7 +3154,6 @@ win32_open(const char *path, int flag, ...) dTHX; va_list ap; int pmode; - WCHAR wBuffer[MAX_PATH+1]; va_start(ap, flag); pmode = va_arg(ap, int); @@ -3025,10 +3162,6 @@ win32_open(const char *path, int flag, ...) if (stricmp(path, "/dev/null")==0) path = "NUL"; - if (USING_WIDE()) { - A2WHELPER(path, wBuffer, sizeof(wBuffer)); - return _wopen(PerlDir_mapW(wBuffer), flag, pmode); - } return open(PerlDir_mapA(path), flag, pmode); } @@ -3275,11 +3408,6 @@ DllExport int win32_mkdir(const char *dir, int mode) { dTHX; - if (USING_WIDE()) { - WCHAR wBuffer[MAX_PATH+1]; - A2WHELPER(dir, wBuffer, sizeof(wBuffer)); - return _wmkdir(PerlDir_mapW(wBuffer)); - } return mkdir(PerlDir_mapA(dir)); /* just ignore mode */ } @@ -3287,11 +3415,6 @@ DllExport int win32_rmdir(const char *dir) { dTHX; - if (USING_WIDE()) { - WCHAR wBuffer[MAX_PATH+1]; - A2WHELPER(dir, wBuffer, sizeof(wBuffer)); - return _wrmdir(PerlDir_mapW(wBuffer)); - } return rmdir(PerlDir_mapA(dir)); } @@ -3303,11 +3426,6 @@ win32_chdir(const char *dir) errno = ENOENT; return -1; } - if (USING_WIDE()) { - WCHAR wBuffer[MAX_PATH+1]; - A2WHELPER(dir, wBuffer, sizeof(wBuffer)); - return _wchdir(wBuffer); - } return chdir(dir); } @@ -3315,11 +3433,6 @@ DllExport int win32_access(const char *path, int mode) { dTHX; - if (USING_WIDE()) { - WCHAR wBuffer[MAX_PATH+1]; - A2WHELPER(path, wBuffer, sizeof(wBuffer)); - return _waccess(PerlDir_mapW(wBuffer), mode); - } return access(PerlDir_mapA(path), mode); } @@ -3327,11 +3440,6 @@ DllExport int win32_chmod(const char *path, int mode) { dTHX; - if (USING_WIDE()) { - WCHAR wBuffer[MAX_PATH+1]; - A2WHELPER(path, wBuffer, sizeof(wBuffer)); - return _wchmod(PerlDir_mapW(wBuffer), mode); - } return chmod(PerlDir_mapA(path), mode); } @@ -3377,7 +3485,8 @@ create_command_line(char *cname, STRLEN clen, const char * const *args) || (IsWinNT() && stricmp(&cname[clen-4], ".cmd") == 0))) { bat_file = TRUE; - len += 3; + if (!IsWin95()) + len += 3; } else { char *exe = strrchr(cname, '/'); @@ -3411,10 +3520,10 @@ create_command_line(char *cname, STRLEN clen, const char * const *args) DEBUG_p(PerlIO_printf(Perl_debug_log, "\n")); argc = index; - New(1310, cmd, len, char); + Newx(cmd, len, char); ptr = cmd; - if (bat_file) { + if (bat_file && !IsWin95()) { *ptr++ = '"'; extra_quotes = TRUE; } @@ -3464,7 +3573,9 @@ create_command_line(char *cname, STRLEN clen, const char * const *args) if (!extra_quotes && cmd_shell - && (stricmp(arg, "/x/c") == 0 || stricmp(arg, "/c") == 0)) + && curlen >= 2 + && *arg == '/' /* see if arg is "/c", "/x/c", "/x/d/c" etc. */ + && stricmp(arg+curlen-2, "/c") == 0) { /* is there a next argument? */ if (args[index+1]) { @@ -3510,7 +3621,10 @@ qualified_path(const char *cmd) /* look in PATH */ pathstr = PerlEnv_getenv("PATH"); - New(0, fullcmd, MAX_PATH+1, char); + + /* worst case: PATH is a single directory; we need additional space + * to append "/", ".exe" and trailing "\0" */ + Newx(fullcmd, (pathstr ? strlen(pathstr) : 0) + cmdlen + 6, char); curfullcmd = fullcmd; while (1) { @@ -3551,17 +3665,13 @@ qualified_path(const char *cmd) if (*pathstr == '"') { /* foo;"baz;etc";bar */ pathstr++; /* skip initial '"' */ while (*pathstr && *pathstr != '"') { - if (curfullcmd-fullcmd < MAX_PATH-cmdlen-5) - *curfullcmd++ = *pathstr; - pathstr++; + *curfullcmd++ = *pathstr++; } if (*pathstr) pathstr++; /* skip trailing '"' */ } else { - if (curfullcmd-fullcmd < MAX_PATH-cmdlen-5) - *curfullcmd++ = *pathstr; - pathstr++; + *curfullcmd++ = *pathstr++; } } if (*pathstr) @@ -3572,7 +3682,7 @@ qualified_path(const char *cmd) *curfullcmd++ = '\\'; } } -GIVE_UP: + Safefree(fullcmd); return Nullch; } @@ -3619,17 +3729,10 @@ win32_get_childdir(void) { dTHX; char* ptr; - char szfilename[(MAX_PATH+1)*2]; - if (USING_WIDE()) { - WCHAR wfilename[MAX_PATH+1]; - GetCurrentDirectoryW(MAX_PATH+1, wfilename); - W2AHELPER(wfilename, szfilename, sizeof(szfilename)); - } - else { - GetCurrentDirectoryA(MAX_PATH+1, szfilename); - } + char szfilename[MAX_PATH+1]; - New(0, ptr, strlen(szfilename)+1, char); + GetCurrentDirectoryA(MAX_PATH+1, szfilename); + Newx(ptr, strlen(szfilename)+1, char); strcpy(ptr, szfilename); return ptr; } @@ -3677,7 +3780,7 @@ win32_spawnvp(int mode, const char *cmdname, const char *const *argv) /* if command name contains dquotes, must remove them */ if (strchr(cname, '"')) { cmd = cname; - New(0,cname,clen+1,char); + Newx(cname,clen+1,char); clen = 0; while (*cmd) { if (*cmd != '"') { @@ -3731,14 +3834,14 @@ win32_spawnvp(int mode, const char *cmdname, const char *const *argv) StartupInfo.hStdInput = tbl.childStdIn; StartupInfo.hStdOutput = tbl.childStdOut; StartupInfo.hStdError = tbl.childStdErr; - if (StartupInfo.hStdInput != INVALID_HANDLE_VALUE && - StartupInfo.hStdOutput != INVALID_HANDLE_VALUE && - StartupInfo.hStdError != INVALID_HANDLE_VALUE) + if (StartupInfo.hStdInput == INVALID_HANDLE_VALUE && + StartupInfo.hStdOutput == INVALID_HANDLE_VALUE && + StartupInfo.hStdError == INVALID_HANDLE_VALUE) { - StartupInfo.dwFlags |= STARTF_USESTDHANDLES; + create |= CREATE_NEW_CONSOLE; } else { - create |= CREATE_NEW_CONSOLE; + StartupInfo.dwFlags |= STARTF_USESTDHANDLES; } if (w32_use_showwindow) { StartupInfo.dwFlags |= STARTF_USESHOWWINDOW; @@ -3823,9 +3926,17 @@ win32_execv(const char *cmdname, const char *const *argv) /* if this is a pseudo-forked child, we just want to spawn * the new program, and return */ if (w32_pseudo_id) +# ifdef __BORLANDC__ return spawnv(P_WAIT, cmdname, (char *const *)argv); +# else + return spawnv(P_WAIT, cmdname, argv); +# endif #endif +#ifdef __BORLANDC__ return execv(cmdname, (char *const *)argv); +#else + return execv(cmdname, argv); +#endif } DllExport int @@ -3836,7 +3947,7 @@ win32_execvp(const char *cmdname, const char *const *argv) /* if this is a pseudo-forked child, we just want to spawn * the new program, and return */ if (w32_pseudo_id) { - int status = win32_spawnvp(P_WAIT, cmdname, (char *const *)argv); + int status = win32_spawnvp(P_WAIT, cmdname, (const char *const *)argv); if (status != -1) { my_exit(status); return 0; @@ -3845,7 +3956,11 @@ win32_execvp(const char *cmdname, const char *const *argv) return status; } #endif +#ifdef __BORLANDC__ return execvp(cmdname, (char *const *)argv); +#else + return execvp(cmdname, argv); +#endif } DllExport void @@ -3929,7 +4044,6 @@ static char *base = NULL; /* XXX threadead */ static char *reserved = NULL; /* XXX threadead */ static char *brk = NULL; /* XXX threadead */ static DWORD pagesize = 0; /* XXX threadead */ -static DWORD allocsize = 0; /* XXX threadead */ void * sbrk(ptrdiff_t need) @@ -3942,28 +4056,34 @@ sbrk(ptrdiff_t need) * call the OS to commit just one page ... */ pagesize = info.dwPageSize << 3; - allocsize = info.dwAllocationGranularity; } - /* This scheme fails eventually if request for contiguous - * block is denied so reserve big blocks - this is only - * address space not memory ... - */ if (brk+need >= reserved) { - DWORD size = 64*1024*1024; + DWORD size = brk+need-reserved; char *addr; + char *prev_committed = NULL; if (committed && reserved && committed < reserved) { /* Commit last of previous chunk cannot span allocations */ addr = (char *) VirtualAlloc(committed,reserved-committed,MEM_COMMIT,PAGE_READWRITE); if (addr) + { + /* Remember where we committed from in case we want to decommit later */ + prev_committed = committed; committed = reserved; + } } /* Reserve some (more) space + * Contiguous blocks give us greater efficiency, so reserve big blocks - + * this is only address space not memory... * Note this is a little sneaky, 1st call passes NULL as reserved * so lets system choose where we start, subsequent calls pass * the old end address so ask for a contiguous block */ +sbrk_reserve: + if (size < 64*1024*1024) + size = 64*1024*1024; + size = ((size + pagesize - 1) / pagesize) * pagesize; addr = (char *) VirtualAlloc(reserved,size,MEM_RESERVE,PAGE_NOACCESS); if (addr) { @@ -3975,6 +4095,19 @@ sbrk(ptrdiff_t need) if (!brk) brk = committed; } + else if (reserved) + { + /* The existing block could not be extended far enough, so decommit + * anything that was just committed above and start anew */ + if (prev_committed) + { + if (!VirtualFree(prev_committed,reserved-prev_committed,MEM_DECOMMIT)) + return (void *) -1; + } + reserved = base = committed = brk = NULL; + size = need; + goto sbrk_reserve; + } else { return (void *) -1; @@ -3985,11 +4118,12 @@ sbrk(ptrdiff_t need) if (brk > committed) { DWORD size = ((brk-committed + pagesize -1)/pagesize) * pagesize; - char *addr = (char *) VirtualAlloc(committed,size,MEM_COMMIT,PAGE_READWRITE); + char *addr; + if (committed+size > reserved) + size = reserved-committed; + addr = (char *) VirtualAlloc(committed,size,MEM_COMMIT,PAGE_READWRITE); if (addr) - { - committed += size; - } + committed += size; else return (void *) -1; } @@ -4024,7 +4158,7 @@ win32_free(void *block) } -int +DllExport int win32_open_osfhandle(intptr_t handle, int flags) { #ifdef USE_FIXED_OSFHANDLE @@ -4034,17 +4168,68 @@ win32_open_osfhandle(intptr_t handle, int flags) return _open_osfhandle(handle, flags); } -intptr_t +DllExport intptr_t win32_get_osfhandle(int fd) { return (intptr_t)_get_osfhandle(fd); } +DllExport FILE * +win32_fdupopen(FILE *pf) +{ + FILE* pfdup; + fpos_t pos; + char mode[3]; + int fileno = win32_dup(win32_fileno(pf)); + + /* open the file in the same mode */ +#ifdef __BORLANDC__ + if((pf)->flags & _F_READ) { + mode[0] = 'r'; + mode[1] = 0; + } + else if((pf)->flags & _F_WRIT) { + mode[0] = 'a'; + mode[1] = 0; + } + else if((pf)->flags & _F_RDWR) { + mode[0] = 'r'; + mode[1] = '+'; + mode[2] = 0; + } +#else + if((pf)->_flag & _IOREAD) { + mode[0] = 'r'; + mode[1] = 0; + } + else if((pf)->_flag & _IOWRT) { + mode[0] = 'a'; + mode[1] = 0; + } + else if((pf)->_flag & _IORW) { + mode[0] = 'r'; + mode[1] = '+'; + mode[2] = 0; + } +#endif + + /* it appears that the binmode is attached to the + * file descriptor so binmode files will be handled + * correctly + */ + pfdup = win32_fdopen(fileno, mode); + + /* move the file pointer to the same position */ + if (!fgetpos(pf, &pos)) { + fsetpos(pfdup, &pos); + } + return pfdup; +} + DllExport void* win32_dynaload(const char* filename) { dTHX; - HMODULE hModule; char buf[MAX_PATH+1]; char *first; @@ -4064,15 +4249,7 @@ win32_dynaload(const char* filename) filename = buf; } } - if (USING_WIDE()) { - WCHAR wfilename[MAX_PATH+1]; - A2WHELPER(filename, wfilename, sizeof(wfilename)); - hModule = LoadLibraryExW(PerlDir_mapW(wfilename), NULL, LOAD_WITH_ALTERED_SEARCH_PATH); - } - else { - hModule = LoadLibraryExA(PerlDir_mapA(filename), NULL, LOAD_WITH_ALTERED_SEARCH_PATH); - } - return hModule; + return LoadLibraryExA(PerlDir_mapA(filename), NULL, LOAD_WITH_ALTERED_SEARCH_PATH); } /* @@ -4242,11 +4419,11 @@ XS(w32_DomainName) /* NERR_Success *is* 0*/ if (0 == pfnNetWkstaGetInfo(NULL, 100, &pwi)) { if (pwi->wki100_langroup && *(pwi->wki100_langroup)) { - WideCharToMultiByte(CP_ACP, NULL, pwi->wki100_langroup, + WideCharToMultiByte(CP_ACP, 0, pwi->wki100_langroup, -1, (LPSTR)dname, dnamelen, NULL, NULL); } else { - WideCharToMultiByte(CP_ACP, NULL, pwi->wki100_computername, + WideCharToMultiByte(CP_ACP, 0, pwi->wki100_computername, -1, (LPSTR)dname, dnamelen, NULL, NULL); } pfnNetApiBufferFree(pwi); @@ -4301,33 +4478,49 @@ static XS(w32_GetOSVersion) { dXSARGS; - OSVERSIONINFOA osver; - - if (USING_WIDE()) { - OSVERSIONINFOW osverw; - char szCSDVersion[sizeof(osverw.szCSDVersion)]; - osverw.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW); - if (!GetVersionExW(&osverw)) { - XSRETURN_EMPTY; - } - W2AHELPER(osverw.szCSDVersion, szCSDVersion, sizeof(szCSDVersion)); - XPUSHs(newSVpvn(szCSDVersion, strlen(szCSDVersion))); - osver.dwMajorVersion = osverw.dwMajorVersion; - osver.dwMinorVersion = osverw.dwMinorVersion; - osver.dwBuildNumber = osverw.dwBuildNumber; - osver.dwPlatformId = osverw.dwPlatformId; + /* Use explicit struct definition because wSuiteMask and + * wProductType are not defined in the VC++ 6.0 headers. + * WORD type has been replaced by unsigned short because + * WORD is already used by Perl itself. + */ + struct { + DWORD dwOSVersionInfoSize; + DWORD dwMajorVersion; + DWORD dwMinorVersion; + DWORD dwBuildNumber; + DWORD dwPlatformId; + CHAR szCSDVersion[128]; + unsigned short wServicePackMajor; + unsigned short wServicePackMinor; + unsigned short wSuiteMask; + BYTE wProductType; + BYTE wReserved; + } osver; + BOOL bEx = TRUE; + + osver.dwOSVersionInfoSize = sizeof(osver); + if (!GetVersionExA((OSVERSIONINFOA*)&osver)) { + bEx = FALSE; + osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); + if (!GetVersionExA((OSVERSIONINFOA*)&osver)) { + XSRETURN_EMPTY; + } } - else { - osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); - if (!GetVersionExA(&osver)) { - XSRETURN_EMPTY; - } - XPUSHs(newSVpvn(osver.szCSDVersion, strlen(osver.szCSDVersion))); + if (GIMME_V == G_SCALAR) { + XSRETURN_IV(osver.dwPlatformId); } + XPUSHs(newSVpvn(osver.szCSDVersion, strlen(osver.szCSDVersion))); + XPUSHs(newSViv(osver.dwMajorVersion)); XPUSHs(newSViv(osver.dwMinorVersion)); XPUSHs(newSViv(osver.dwBuildNumber)); XPUSHs(newSViv(osver.dwPlatformId)); + if (bEx) { + XPUSHs(newSViv(osver.wServicePackMajor)); + XPUSHs(newSViv(osver.wServicePackMinor)); + XPUSHs(newSViv(osver.wSuiteMask)); + XPUSHs(newSViv(osver.wProductType)); + } PUTBACK; } @@ -4357,21 +4550,11 @@ XS(w32_FormatMessage) if (items != 1) Perl_croak(aTHX_ "usage: Win32::FormatMessage($errno)"); - if (USING_WIDE()) { - WCHAR wmsgbuf[ONE_K_BUFSIZE]; - if (FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, - &source, SvIV(ST(0)), 0, - wmsgbuf, ONE_K_BUFSIZE-1, NULL)) - { - W2AHELPER(wmsgbuf, msgbuf, sizeof(msgbuf)); - XSRETURN_PV(msgbuf); - } - } - else { - if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, - &source, SvIV(ST(0)), 0, - msgbuf, sizeof(msgbuf)-1, NULL)) - XSRETURN_PV(msgbuf); + if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, + &source, SvIV(ST(0)), 0, + msgbuf, sizeof(msgbuf)-1, NULL)) + { + XSRETURN_PV(msgbuf); } XSRETURN_UNDEF; @@ -4460,6 +4643,7 @@ XS(w32_GetShortPathName) } while (len >= SvLEN(shortpath) && sv_grow(shortpath,len+1)); if (len) { SvCUR_set(shortpath,len); + *SvEND(shortpath) = '\0'; ST(0) = shortpath; XSRETURN(1); } @@ -4474,13 +4658,15 @@ XS(w32_GetFullPathName) SV *fullpath; char *filepart; DWORD len; + STRLEN filename_len; + char *filename_p; if (items != 1) Perl_croak(aTHX_ "usage: Win32::GetFullPathName($filename)"); filename = ST(0); - fullpath = sv_mortalcopy(filename); - SvUPGRADE(fullpath, SVt_PV); + filename_p = SvPV(filename, filename_len); + fullpath = sv_2mortal(newSVpvn(filename_p, filename_len)); if (!SvPVX(fullpath) || !SvLEN(fullpath)) XSRETURN_UNDEF; @@ -4493,11 +4679,17 @@ XS(w32_GetFullPathName) if (len) { if (GIMME_V == G_ARRAY) { EXTEND(SP,1); - XST_mPV(1,filepart); - len = filepart - SvPVX(fullpath); + if (filepart) { + XST_mPV(1,filepart); + len = filepart - SvPVX(fullpath); + } + else { + XST_mPVN(1,"",0); + } items = 2; } SvCUR_set(fullpath,len); + *SvEND(fullpath) = '\0'; ST(0) = fullpath; XSRETURN(items); } @@ -4542,22 +4734,12 @@ XS(w32_CopyFile) { dXSARGS; BOOL bResult; + char szSourceFile[MAX_PATH+1]; + if (items != 3) Perl_croak(aTHX_ "usage: Win32::CopyFile($from, $to, $overwrite)"); - if (USING_WIDE()) { - WCHAR wSourceFile[MAX_PATH+1]; - WCHAR wDestFile[MAX_PATH+1]; - A2WHELPER(SvPV_nolen(ST(0)), wSourceFile, sizeof(wSourceFile)); - wcscpy(wSourceFile, PerlDir_mapW(wSourceFile)); - A2WHELPER(SvPV_nolen(ST(1)), wDestFile, sizeof(wDestFile)); - bResult = CopyFileW(wSourceFile, PerlDir_mapW(wDestFile), !SvTRUE(ST(2))); - } - else { - char szSourceFile[MAX_PATH+1]; - strcpy(szSourceFile, PerlDir_mapA(SvPV_nolen(ST(0)))); - bResult = CopyFileA(szSourceFile, PerlDir_mapA(SvPV_nolen(ST(1))), !SvTRUE(ST(2))); - } - + strcpy(szSourceFile, PerlDir_mapA(SvPV_nolen(ST(0)))); + bResult = CopyFileA(szSourceFile, PerlDir_mapA(SvPV_nolen(ST(1))), !SvTRUE(ST(2))); if (bResult) XSRETURN_YES; XSRETURN_NO; @@ -4605,20 +4787,21 @@ Perl_init_os_extras(void) */ } -#ifdef MULTIPLICITY - -PerlInterpreter * +void * win32_signal_context(void) { dTHX; +#ifdef MULTIPLICITY if (!my_perl) { my_perl = PL_curinterp; PERL_SET_THX(my_perl); } return my_perl; +#else + return PL_curinterp; +#endif } -#endif BOOL WINAPI win32_ctrlhandler(DWORD dwCtrlType) @@ -4689,6 +4872,14 @@ Perl_win32_init(int *argcp, char ***argvp) } void +Perl_win32_term(void) +{ + HINTS_REFCNT_TERM; + OP_REFCNT_TERM; + MALLOC_TERM; +} + +void win32_get_child_IO(child_IO_table* ptbl) { ptbl->childStdIn = GetStdHandle(STD_INPUT_HANDLE); @@ -4730,23 +4921,46 @@ win32_csighandler(int sig) /* Does nothing */ } +HWND +win32_create_message_window() +{ + /* "message-only" windows have been implemented in Windows 2000 and later. + * On earlier versions we'll continue to post messages to a specific + * thread and use hwnd==NULL. This is brittle when either an embedding + * application or an XS module is also posting messages to hwnd=NULL + * because once removed from the queue they cannot be delivered to the + * "right" place with DispatchMessage() anymore, as there is no WindowProc + * if there is no window handle. + */ + if (g_osver.dwMajorVersion < 5) + return NULL; + + return CreateWindow("Static", "", 0, 0, 0, 0, 0, HWND_MESSAGE, 0, 0, NULL); +} + void Perl_sys_intern_init(pTHX) { int i; + + if (g_osver.dwOSVersionInfoSize == 0) { + g_osver.dwOSVersionInfoSize = sizeof(g_osver); + GetVersionEx(&g_osver); + } + w32_perlshell_tokens = Nullch; w32_perlshell_vec = (char**)NULL; w32_perlshell_items = 0; w32_fdpid = newAV(); - New(1313, w32_children, 1, child_tab); + Newx(w32_children, 1, child_tab); w32_num_children = 0; # ifdef USE_ITHREADS w32_pseudo_id = 0; - New(1313, w32_pseudo_children, 1, child_tab); + Newx(w32_pseudo_children, 1, pseudo_child_tab); w32_num_pseudo_children = 0; # endif - w32_init_socktype = 0; w32_timerid = 0; + w32_message_hwnd = INVALID_HANDLE_VALUE; w32_poll_count = 0; for (i=0; i < SIG_SIZE; i++) { w32_sighandler[i] = SIG_DFL; @@ -4757,8 +4971,8 @@ Perl_sys_intern_init(pTHX) { # endif /* Force C runtime signal stuff to set its console handler */ - signal(SIGINT,&win32_csighandler); - signal(SIGBREAK,&win32_csighandler); + signal(SIGINT,win32_csighandler); + signal(SIGBREAK,win32_csighandler); /* Push our handler on top */ SetConsoleCtrlHandler(win32_ctrlhandler,TRUE); } @@ -4772,9 +4986,11 @@ Perl_sys_intern_clear(pTHX) /* NOTE: w32_fdpid is freed by sv_clean_all() */ Safefree(w32_children); if (w32_timerid) { - KillTimer(NULL,w32_timerid); - w32_timerid=0; + KillTimer(w32_message_hwnd, w32_timerid); + w32_timerid = 0; } + if (w32_message_hwnd != NULL && w32_message_hwnd != INVALID_HANDLE_VALUE) + DestroyWindow(w32_message_hwnd); # ifdef MULTIPLICITY if (my_perl == PL_curinterp) { # else @@ -4796,12 +5012,12 @@ Perl_sys_intern_dup(pTHX_ struct interp_intern *src, struct interp_intern *dst) dst->perlshell_vec = (char**)NULL; dst->perlshell_items = 0; dst->fdpid = newAV(); - Newz(1313, dst->children, 1, child_tab); + Newxz(dst->children, 1, child_tab); dst->pseudo_id = 0; - Newz(1313, dst->pseudo_children, 1, child_tab); - dst->thr_intern.Winit_socktype = 0; - dst->timerid = 0; - dst->poll_count = 0; + Newxz(dst->pseudo_children, 1, pseudo_child_tab); + dst->timerid = 0; + dst->message_hwnd = INVALID_HANDLE_VALUE; + dst->poll_count = 0; Copy(src->sigtable,dst->sigtable,SIG_SIZE,Sighandler_t); } # endif /* USE_ITHREADS */ @@ -4827,7 +5043,7 @@ win32_argv2utf8(int argc, char** argv) if (lpwStr && argc) { while (argc--) { length = WideCharToMultiByte(CP_UTF8, 0, lpwStr[--wargc], -1, NULL, 0, NULL, NULL); - Newz(0, psz, length, char); + Newxz(psz, length, char); WideCharToMultiByte(CP_UTF8, 0, lpwStr[wargc], -1, psz, length, NULL, NULL); argv[argc] = psz; }