X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=win32%2Fwin32.c;h=5f7d4873bef34744b6c1dbe465897cace3f671cd;hb=df0003d4dd97bb27e464c2adb8c54893f719ec3c;hp=a73d9e65b6792dda143e6eaf7e4958341693645c;hpb=390b85e7c411323845dca16b7882a5a5754a433e;p=p5sagit%2Fp5-mst-13.2.git diff --git a/win32/win32.c b/win32/win32.c index a73d9e6..5f7d487 100644 --- a/win32/win32.c +++ b/win32/win32.c @@ -11,8 +11,23 @@ #define WIN32_LEAN_AND_MEAN #define WIN32IO_IS_STDIO #include +#ifdef __GNUC__ +#define Win32_Winsock +#endif #include +#ifndef __MINGW32__ +#include +#include +/* ugliness to work around a buggy struct definition in lmwksta.h */ +#undef LPTSTR +#define LPTSTR LPWSTR +#include +#undef LPTSTR +#define LPTSTR LPSTR +#include +#endif /* __MINGW32__ */ + /* #include "config.h" */ #define PERLIO_NOT_STDIO 0 @@ -22,80 +37,276 @@ #include "EXTERN.h" #include "perl.h" + +#define NO_XSLOCKS +#ifdef PERL_OBJECT +extern CPerlObj* pPerl; +#endif #include "XSUB.h" + +#include "Win32iop.h" #include #include +#ifndef __GNUC__ +/* assert.h conflicts with #define of assert in perl.h */ #include +#endif #include #include #include +#include +#if defined(_MSC_VER) || defined(__MINGW32__) +#include +#else +#include +#endif + +#ifdef __GNUC__ +/* Mingw32 defaults to globing command line + * So we turn it off like this: + */ +int _CRT_glob = 0; +#endif #define EXECF_EXEC 1 #define EXECF_SPAWN 2 #define EXECF_SPAWN_NOWAIT 3 -static DWORD IdOS(void); - -BOOL ProbeEnv = FALSE; -DWORD Win32System = (DWORD)-1; -char szShellPath[MAX_PATH+1]; -char szPerlLibRoot[MAX_PATH+1]; -HANDLE PerlDllHandle = INVALID_HANDLE_VALUE; +#if defined(PERL_OBJECT) +#undef win32_get_privlib +#define win32_get_privlib g_win32_get_privlib +#undef win32_get_sitelib +#define win32_get_sitelib g_win32_get_sitelib +#undef do_aspawn +#define do_aspawn g_do_aspawn +#undef do_spawn +#define do_spawn g_do_spawn +#undef do_exec +#define do_exec g_do_exec +#undef getlogin +#define getlogin g_getlogin +#endif -static int do_spawn2(char *cmd, int exectype); +static DWORD os_id(void); +static void get_shell(void); +static long tokenize(char *str, char **dest, char ***destv); + int do_spawn2(char *cmd, int exectype); +static BOOL has_shell_metachars(char *ptr); +static long filetime_to_clock(PFILETIME ft); +static BOOL filetime_from_time(PFILETIME ft, time_t t); +static char * get_emd_part(char *leading, char *trailing, ...); +static void remove_dead_process(HANDLE deceased); + +HANDLE w32_perldll_handle = INVALID_HANDLE_VALUE; +static DWORD w32_platform = (DWORD)-1; + +#ifdef USE_THREADS +# ifdef USE_DECLSPEC_THREAD +__declspec(thread) char strerror_buffer[512]; +__declspec(thread) char getlogin_buffer[128]; +__declspec(thread) char w32_perllib_root[MAX_PATH+1]; +# ifdef HAVE_DES_FCRYPT +__declspec(thread) char crypt_buffer[30]; +# endif +# else +# define strerror_buffer (thr->i.Wstrerror_buffer) +# define getlogin_buffer (thr->i.Wgetlogin_buffer) +# define w32_perllib_root (thr->i.Ww32_perllib_root) +# define crypt_buffer (thr->i.Wcrypt_buffer) +# endif +#else +static char strerror_buffer[512]; +static char getlogin_buffer[128]; +static char w32_perllib_root[MAX_PATH+1]; +# ifdef HAVE_DES_FCRYPT +static char crypt_buffer[30]; +# endif +#endif int IsWin95(void) { - return (IdOS() == VER_PLATFORM_WIN32_WINDOWS); + return (os_id() == VER_PLATFORM_WIN32_WINDOWS); } int IsWinNT(void) { - return (IdOS() == VER_PLATFORM_WIN32_NT); + return (os_id() == VER_PLATFORM_WIN32_NT); +} + +char* +GetRegStrFromKey(HKEY hkey, const char *lpszValueName, char** ptr, DWORD* lpDataLen) +{ /* Retrieve a REG_SZ or REG_EXPAND_SZ from the registry */ + HKEY handle; + DWORD type; + const char *subkey = "Software\\Perl"; + long retval; + + retval = RegOpenKeyEx(hkey, subkey, 0, KEY_READ, &handle); + if (retval == ERROR_SUCCESS){ + retval = RegQueryValueEx(handle, lpszValueName, 0, &type, NULL, lpDataLen); + if (retval == ERROR_SUCCESS && type == REG_SZ) { + if (*ptr) { + Renew(*ptr, *lpDataLen, char); + } + else { + New(1312, *ptr, *lpDataLen, char); + } + retval = RegQueryValueEx(handle, lpszValueName, 0, NULL, (PBYTE)*ptr, lpDataLen); + if (retval != ERROR_SUCCESS) { + Safefree(*ptr); + *ptr = Nullch; + } + } + RegCloseKey(handle); + } + return *ptr; } -char * -win32PerlLibPath(void) +char* +GetRegStr(const char *lpszValueName, char** ptr, DWORD* lpDataLen) +{ + *ptr = GetRegStrFromKey(HKEY_CURRENT_USER, lpszValueName, ptr, lpDataLen); + if (*ptr == Nullch) + { + *ptr = GetRegStrFromKey(HKEY_LOCAL_MACHINE, lpszValueName, ptr, lpDataLen); + } + return *ptr; +} + +static char * +get_emd_part(char *prev_path, char *trailing_path, ...) { - char *end; - GetModuleFileName((PerlDllHandle == INVALID_HANDLE_VALUE) + va_list ap; + char mod_name[MAX_PATH+1]; + char *ptr; + char *optr; + char *strip; + int oldsize, newsize; + + va_start(ap, trailing_path); + strip = va_arg(ap, char *); + + GetModuleFileName((w32_perldll_handle == INVALID_HANDLE_VALUE) ? GetModuleHandle(NULL) - : PerlDllHandle, - szPerlLibRoot, - sizeof(szPerlLibRoot)); + : w32_perldll_handle, mod_name, sizeof(mod_name)); + ptr = strrchr(mod_name, '\\'); + while (ptr && strip) { + /* look for directories to skip back */ + optr = ptr; + *ptr = '\0'; + ptr = strrchr(mod_name, '\\'); + if (!ptr || stricmp(ptr+1, strip) != 0) { + *optr = '\\'; + ptr = optr; + } + strip = va_arg(ap, char *); + } + if (!ptr) { + ptr = mod_name; + *ptr++ = '.'; + *ptr = '\\'; + } + va_end(ap); + strcpy(++ptr, trailing_path); + + newsize = strlen(mod_name) + 1; + if (prev_path) { + oldsize = strlen(prev_path) + 1; + newsize += oldsize; /* includes plus 1 for ';' */ + Renew(prev_path, newsize, char); + prev_path[oldsize-1] = ';'; + strcpy(&prev_path[oldsize], mod_name); + } + else { + New(1311, prev_path, newsize, char); + strcpy(prev_path, mod_name); + } + + return prev_path; +} + +char * +win32_get_privlib(char *pl) +{ + char *stdlib = "lib"; + char buffer[MAX_PATH+1]; + char *path = Nullch; + DWORD datalen; + + /* $stdlib = $HKCU{"lib-$]"} || $HKLM{"lib-$]"} || $HKCU{"lib"} || $HKLM{"lib"} || ""; */ + sprintf(buffer, "%s-%s", stdlib, pl); + path = GetRegStr(buffer, &path, &datalen); + if (!path) + path = GetRegStr(stdlib, &path, &datalen); - *(end = strrchr(szPerlLibRoot, '\\')) = '\0'; - if (stricmp(end-4,"\\bin") == 0) - end -= 4; - strcpy(end,"\\lib"); - return (szPerlLibRoot); + /* $stdlib .= ";$EMD/../../lib" */ + return get_emd_part(path, stdlib, ARCHNAME, "bin", Nullch); } char * -win32SiteLibPath(void) +win32_get_sitelib(char *pl) { - static char szPerlSiteLib[MAX_PATH+1]; - strcpy(szPerlSiteLib, win32PerlLibPath()); - strcat(szPerlSiteLib, "\\site"); - return (szPerlSiteLib); + char *sitelib = "sitelib"; + char regstr[40]; + char pathstr[MAX_PATH+1]; + DWORD datalen; + char *path1 = Nullch; + char *path2 = Nullch; + int len, newsize; + + /* $HKCU{"sitelib-$]"} || $HKLM{"sitelib-$]"} . ---; */ + sprintf(regstr, "%s-%s", sitelib, pl); + path1 = GetRegStr(regstr, &path1, &datalen); + + /* $sitelib .= + * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/site/$]/lib"; */ + sprintf(pathstr, "site\\%s\\lib", pl); + path1 = get_emd_part(path1, pathstr, ARCHNAME, "bin", pl, Nullch); + + /* $HKCU{'sitelib'} || $HKLM{'sitelib'} . ---; */ + path2 = GetRegStr(sitelib, &path2, &datalen); + + /* $sitelib .= + * ";$EMD/" . ((-d $EMD/../../../$]) ? "../../.." : "../.."). "/site/lib"; */ + path2 = get_emd_part(path2, "site\\lib", ARCHNAME, "bin", pl, Nullch); + + if (!path1) + return path2; + + if (!path2) + return path1; + + len = strlen(path1); + newsize = len + strlen(path2) + 2; /* plus one for ';' */ + + Renew(path1, newsize, char); + path1[len++] = ';'; + strcpy(&path1[len], path2); + + Safefree(path2); + return path1; } -BOOL -HasRedirection(char *ptr) + +static BOOL +has_shell_metachars(char *ptr) { int inquote = 0; char quote = '\0'; /* * Scan string looking for redirection (< or >) or pipe - * characters (|) that are not in a quoted string + * characters (|) that are not in a quoted string. + * Shell variable interpolation (%VAR%) can also happen inside strings. */ - while(*ptr) { + while (*ptr) { switch(*ptr) { + case '%': + return TRUE; case '\'': case '\"': - if(inquote) { - if(quote == *ptr) { + if (inquote) { + if (quote == *ptr) { inquote = 0; quote = '\0'; } @@ -108,7 +319,7 @@ HasRedirection(char *ptr) case '>': case '<': case '|': - if(!inquote) + if (!inquote) return TRUE; default: break; @@ -118,6 +329,7 @@ HasRedirection(char *ptr) return FALSE; } +#if !defined(PERL_OBJECT) /* since the current process environment is being updated in util.c * the library functions will get the correct environment */ @@ -140,10 +352,8 @@ my_popen(char *cmd, char *mode) #define fixcmd(x) #endif fixcmd(cmd); -#ifdef __BORLANDC__ /* workaround a Borland stdio bug */ win32_fflush(stdout); win32_fflush(stderr); -#endif return win32_popen(cmd, mode); } @@ -152,26 +362,78 @@ my_pclose(PerlIO *fp) { return win32_pclose(fp); } +#endif static DWORD -IdOS(void) +os_id(void) { static OSVERSIONINFO osver; - if (osver.dwPlatformId != Win32System) { + if (osver.dwPlatformId != w32_platform) { memset(&osver, 0, sizeof(OSVERSIONINFO)); osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&osver); - Win32System = osver.dwPlatformId; + w32_platform = osver.dwPlatformId; } - return (Win32System); + return (w32_platform); } -static char * -GetShell(void) +/* Tokenize a string. Words are null-separated, and the list + * ends with a doubled null. Any character (except null and + * including backslash) may be escaped by preceding it with a + * backslash (the backslash will be stripped). + * Returns number of words in result buffer. + */ +static long +tokenize(char *str, char **dest, char ***destv) +{ + char *retstart = Nullch; + char **retvstart = 0; + int items = -1; + if (str) { + int slen = strlen(str); + register char *ret; + register char **retv; + New(1307, ret, slen+2, char); + New(1308, retv, (slen+3)/2, char*); + + retstart = ret; + retvstart = retv; + *retv = ret; + items = 0; + while (*str) { + *ret = *str++; + if (*ret == '\\' && *str) + *ret = *str++; + else if (*ret == ' ') { + while (*str == ' ') + str++; + if (ret == retstart) + ret--; + else { + *ret = '\0'; + ++items; + if (*str) + *++retv = ret+1; + } + } + else if (!*str) + ++items; + ret++; + } + retvstart[items] = Nullch; + *ret++ = '\0'; + *ret = '\0'; + } + *dest = retstart; + *destv = retvstart; + return items; +} + +static void +get_shell(void) { - if (!ProbeEnv) { - char* defaultshell = (IsWinNT() ? "cmd.exe" : "command.com"); + if (!w32_perlshell_tokens) { /* we don't use COMSPEC here for two reasons: * 1. the same reason perl on UNIX doesn't use SHELL--rampant and * uncontrolled unportability of the ensuing scripts. @@ -179,55 +441,74 @@ GetShell(void) * interactive use (which is what most programs look in COMSPEC * for). */ - char *usershell = getenv("PERL5SHELL"); - - ProbeEnv = TRUE; - strcpy(szShellPath, usershell ? usershell : defaultshell); + char* defaultshell = (IsWinNT() ? "cmd.exe /x/c" : "command.com /c"); + char *usershell = getenv("PERL5SHELL"); + w32_perlshell_items = tokenize(usershell ? usershell : defaultshell, + &w32_perlshell_tokens, + &w32_perlshell_vec); } - return szShellPath; } int -do_aspawn(void* really, void ** mark, void ** arglast) +do_aspawn(void *vreally, void **vmark, void **vsp) { + SV *really = (SV*)vreally; + SV **mark = (SV**)vmark; + SV **sp = (SV**)vsp; char **argv; - char *strPtr; - char *cmd; + char *str; int status; - unsigned int length; + int flag = P_WAIT; int index = 0; - SV *sv = (SV*)really; - SV** pSv = (SV**)mark; - New(1310, argv, (arglast - mark) + 4, char*); + if (sp <= mark) + return -1; - if(sv != Nullsv) { - cmd = SvPV(sv, length); - } - else { - argv[index++] = cmd = GetShell(); - if (IsWinNT()) - argv[index++] = "/x"; /* always enable command extensions */ - argv[index++] = "/c"; + get_shell(); + New(1306, argv, (sp - mark) + w32_perlshell_items + 2, char*); + + if (SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) { + ++mark; + flag = SvIVx(*mark); } - while(++pSv <= (SV**)arglast) { - sv = *pSv; - strPtr = SvPV(sv, length); - if(strPtr != NULL && *strPtr != '\0') - argv[index++] = strPtr; + while (++mark <= sp) { + if (*mark && (str = SvPV(*mark, PL_na))) + argv[index++] = str; + else + argv[index++] = ""; } argv[index++] = 0; - status = win32_spawnvp(P_WAIT, cmd, (const char* const*)argv); - - Safefree(argv); + status = win32_spawnvp(flag, + (const char*)(really ? SvPV(really,PL_na) : argv[0]), + (const char* const*)argv); + + if (status < 0 && errno == ENOEXEC) { + /* possible shell-builtin, invoke with shell */ + int sh_items; + sh_items = w32_perlshell_items; + while (--index >= 0) + argv[index+sh_items] = argv[index]; + while (--sh_items >= 0) + argv[sh_items] = w32_perlshell_vec[sh_items]; + + status = win32_spawnvp(flag, + (const char*)(really ? SvPV(really,PL_na) : argv[0]), + (const char* const*)argv); + } - if (status < 0) { - if (dowarn) - warn("Can't spawn \"%s\": %s", cmd, strerror(errno)); - status = 255 << 8; + if (flag != P_NOWAIT) { + if (status < 0) { + if (PL_dowarn) + warn("Can't spawn \"%s\": %s", argv[0], strerror(errno)); + status = 255 * 256; + } + else + status *= 256; + PL_statusvalue = status; } + Safefree(argv); return (status); } @@ -239,13 +520,11 @@ do_spawn2(char *cmd, int exectype) char **argv; int status = -1; BOOL needToTry = TRUE; - char *shell, *cmd2; - - /* save an extra exec if possible */ - shell = GetShell(); + char *cmd2; - /* see if there are shell metacharacters in it */ - if(!HasRedirection(cmd)) { + /* 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); strcpy(cmd2, cmd); @@ -255,13 +534,13 @@ do_spawn2(char *cmd, int exectype) s++; if (*s) *(a++) = s; - while(*s && !isspace(*s)) + while (*s && !isspace(*s)) s++; - if(*s) + if (*s) *s++ = '\0'; } *a = Nullch; - if(argv[0]) { + if (argv[0]) { switch (exectype) { case EXECF_SPAWN: status = win32_spawnvp(P_WAIT, argv[0], @@ -275,19 +554,21 @@ do_spawn2(char *cmd, int exectype) status = win32_execvp(argv[0], (const char* const*)argv); break; } - if(status != -1 || errno == 0) + if (status != -1 || errno == 0) needToTry = FALSE; } Safefree(argv); Safefree(cmd2); } - if(needToTry) { - char *argv[5]; - int i = 0; - argv[i++] = shell; - if (IsWinNT()) - argv[i++] = "/x"; - argv[i++] = "/c"; argv[i++] = cmd; argv[i] = Nullch; + if (needToTry) { + char **argv; + int i = -1; + get_shell(); + New(1306, argv, w32_perlshell_items + 2, char*); + while (++i < w32_perlshell_items) + argv[i] = w32_perlshell_vec[i]; + argv[i++] = cmd; + argv[i] = Nullch; switch (exectype) { case EXECF_SPAWN: status = win32_spawnvp(P_WAIT, argv[0], @@ -301,14 +582,20 @@ do_spawn2(char *cmd, int exectype) status = win32_execvp(argv[0], (const char* const*)argv); break; } + cmd = argv[0]; + Safefree(argv); } - if (status < 0) { - if (dowarn) - warn("Can't %s \"%s\": %s", - (exectype == EXECF_EXEC ? "exec" : "spawn"), - needToTry ? shell : argv[0], - strerror(errno)); - status = 255 << 8; + if (exectype != EXECF_SPAWN_NOWAIT) { + if (status < 0) { + if (PL_dowarn) + warn("Can't %s \"%s\": %s", + (exectype == EXECF_EXEC ? "exec" : "spawn"), + cmd, strerror(errno)); + status = 255 * 256; + } + else + status *= 256; + PL_statusvalue = status; } return (status); } @@ -319,6 +606,12 @@ do_spawn(char *cmd) return do_spawn2(cmd, EXECF_SPAWN); } +int +do_spawn_nowait(char *cmd) +{ + return do_spawn2(cmd, EXECF_SPAWN_NOWAIT); +} + bool do_exec(char *cmd) { @@ -326,64 +619,44 @@ do_exec(char *cmd) return FALSE; } - -#define PATHLEN 1024 - /* The idea here is to read all the directory names into a string table * (separated by nulls) and when one of the other dir functions is called * return the pointer to the current file name. */ DIR * -opendir(char *filename) -{ - DIR *p; - long len; - long idx; - char scannamespc[PATHLEN]; - char *scanname = scannamespc; - struct stat sbuf; - WIN32_FIND_DATA FindData; - HANDLE fh; -/* char root[_MAX_PATH];*/ -/* char volname[_MAX_PATH];*/ -/* DWORD serial, maxname, flags;*/ -/* BOOL downcase;*/ -/* char *dummy;*/ +win32_opendir(char *filename) +{ + DIR *p; + long len; + long idx; + char scanname[MAX_PATH+3]; + struct stat sbuf; + WIN32_FIND_DATA FindData; + HANDLE fh; + + len = strlen(filename); + if (len > MAX_PATH) + return NULL; /* check to see if filename is a directory */ - if (win32_stat(filename, &sbuf) < 0 || (sbuf.st_mode & S_IFDIR) == 0) { + if (win32_stat(filename, &sbuf) < 0 || !S_ISDIR(sbuf.st_mode)) return NULL; - } - /* get the file system characteristics */ -/* if(GetFullPathName(filename, MAX_PATH, root, &dummy)) { - * if(dummy = strchr(root, '\\')) - * *++dummy = '\0'; - * if(GetVolumeInformation(root, volname, MAX_PATH, &serial, - * &maxname, &flags, 0, 0)) { - * downcase = !(flags & FS_CASE_IS_PRESERVED); - * } - * } - * else { - * downcase = TRUE; - * } - */ /* Get us a DIR structure */ Newz(1303, p, 1, DIR); - if(p == NULL) + if (p == NULL) return NULL; /* Create the search pattern */ strcpy(scanname, filename); - - if(index("/\\", *(scanname + strlen(scanname) - 1)) == NULL) - strcat(scanname, "/*"); - else - strcat(scanname, "*"); + if (scanname[len-1] != '/' && scanname[len-1] != '\\') + scanname[len++] = '/'; + scanname[len++] = '*'; + scanname[len] = '\0'; /* do the FindFirstFile call */ fh = FindFirstFile(scanname, &FindData); - if(fh == INVALID_HANDLE_VALUE) { + if (fh == INVALID_HANDLE_VALUE) { return NULL; } @@ -392,13 +665,9 @@ opendir(char *filename) */ idx = strlen(FindData.cFileName)+1; New(1304, p->start, idx, char); - if(p->start == NULL) { + if (p->start == NULL) croak("opendir: malloc failed!\n"); - } strcpy(p->start, FindData.cFileName); -/* if(downcase) - * strlwr(p->start); - */ p->nfiles++; /* loop finding all the files that match the wildcard @@ -412,20 +681,16 @@ opendir(char *filename) * new name and it's null terminator */ Renew(p->start, idx+len+1, char); - if(p->start == NULL) { + if (p->start == NULL) croak("opendir: malloc failed!\n"); - } strcpy(&p->start[idx], FindData.cFileName); -/* if (downcase) - * strlwr(&p->start[idx]); - */ - p->nfiles++; - idx += len+1; - } - FindClose(fh); - p->size = idx; - p->curr = p->start; - return p; + p->nfiles++; + idx += len+1; + } + FindClose(fh); + p->size = idx; + p->curr = p->start; + return p; } @@ -433,7 +698,7 @@ opendir(char *filename) * string pointer to the nDllExport entry. */ struct direct * -readdir(DIR *dirp) +win32_readdir(DIR *dirp) { int len; static int dummy = 0; @@ -461,7 +726,7 @@ readdir(DIR *dirp) /* Telldir returns the current string pointer position */ long -telldir(DIR *dirp) +win32_telldir(DIR *dirp) { return (long) dirp->curr; } @@ -471,21 +736,21 @@ telldir(DIR *dirp) *(Saved by telldir). */ void -seekdir(DIR *dirp, long loc) +win32_seekdir(DIR *dirp, long loc) { dirp->curr = (char *)loc; } /* Rewinddir resets the string pointer to the start */ void -rewinddir(DIR *dirp) +win32_rewinddir(DIR *dirp) { dirp->curr = dirp->start; } /* free the memory allocated by opendir */ int -closedir(DIR *dirp) +win32_closedir(DIR *dirp) { Safefree(dirp->start); Safefree(dirp); @@ -532,24 +797,59 @@ getegid(void) } int -setuid(uid_t uid) +setuid(uid_t auid) { - return (uid == ROOT_UID ? 0 : -1); + return (auid == ROOT_UID ? 0 : -1); } int -setgid(gid_t gid) +setgid(gid_t agid) { - return (gid == ROOT_GID ? 0 : -1); + return (agid == ROOT_GID ? 0 : -1); +} + +char * +getlogin(void) +{ + dTHR; + char *buf = getlogin_buffer; + DWORD size = sizeof(getlogin_buffer); + if (GetUserName(buf,&size)) + return buf; + return (char*)NULL; } -/* - * pretended kill - */ int -kill(int pid, int sig) +chown(const char *path, uid_t owner, gid_t group) +{ + /* XXX noop */ + return 0; +} + +static void +remove_dead_process(HANDLE deceased) +{ +#ifndef USE_RTL_WAIT + int child; + for (child = 0 ; child < w32_num_children ; ++child) { + if (w32_child_pids[child] == deceased) { + Copy(&w32_child_pids[child+1], &w32_child_pids[child], + (w32_num_children-child-1), HANDLE); + w32_num_children--; + break; + } + } +#endif +} + +DllExport int +win32_kill(int pid, int sig) { +#ifdef USE_RTL_WAIT HANDLE hProcess= OpenProcess(PROCESS_ALL_ACCESS, TRUE, pid); +#else + HANDLE hProcess = (HANDLE) pid; +#endif if (hProcess == NULL) { croak("kill process failed!\n"); @@ -558,47 +858,29 @@ kill(int pid, int sig) if (!TerminateProcess(hProcess, sig)) croak("kill process failed!\n"); CloseHandle(hProcess); + + /* WaitForMultipleObjects() on a pid that was killed returns error + * so if we know the pid is gone we remove it from process list */ + remove_dead_process(hProcess); } return 0; } - + /* * File system stuff */ -#if 0 -int -ioctl(int i, unsigned int u, char *data) -{ - croak("ioctl not implemented!\n"); - return -1; -} -#endif - -unsigned int -sleep(unsigned int t) +DllExport unsigned int +win32_sleep(unsigned int t) { Sleep(t*1000); return 0; } - -#undef rename - -int -myrename(char *OldFileName, char *newname) -{ - if(_access(newname, 0) != -1) { /* file exists */ - _unlink(newname); - } - return rename(OldFileName, newname); -} - - DllExport int win32_stat(const char *path, struct stat *buffer) { - char t[MAX_PATH]; + char t[MAX_PATH+1]; const char *p = path; int l = strlen(path); int res; @@ -615,8 +897,22 @@ win32_stat(const char *path, struct stat *buffer) } } res = stat(p,buffer); + if (res < 0) { + /* CRT is buggy on sharenames, so make sure it really isn't. + * XXX using GetFileAttributesEx() will enable us to set + * buffer->st_*time (but note that's not available on the + * Windows of 1995) */ + DWORD r = GetFileAttributes(p); + if (r != 0xffffffff && (r & FILE_ATTRIBUTE_DIRECTORY)) { + buffer->st_mode |= S_IFDIR | S_IREAD; + errno = 0; + if (!(r & FILE_ATTRIBUTE_READONLY)) + buffer->st_mode |= S_IWRITE | S_IEXEC; + return 0; + } + } #ifdef __BORLANDC__ - if (res == 0) { + else { if (S_ISDIR(buffer->st_mode)) buffer->st_mode |= S_IWRITE | S_IEXEC; else if (S_ISREG(buffer->st_mode)) { @@ -643,25 +939,47 @@ win32_stat(const char *path, struct stat *buffer) DllExport char * win32_getenv(const char *name) { - static char *curitem = Nullch; - static DWORD curlen = 512; + static char *curitem = Nullch; /* XXX threadead */ + static DWORD curlen = 0; /* XXX threadead */ DWORD needlen; - if (!curitem) + if (!curitem) { + curlen = 512; New(1305,curitem,curlen,char); - if (!(needlen = GetEnvironmentVariable(name,curitem,curlen))) - return Nullch; - while (needlen > curlen) { - Renew(curitem,needlen,char); - curlen = needlen; - needlen = GetEnvironmentVariable(name,curitem,curlen); } + + needlen = GetEnvironmentVariable(name,curitem,curlen); + if (needlen != 0) { + while (needlen > curlen) { + Renew(curitem,needlen,char); + curlen = needlen; + needlen = GetEnvironmentVariable(name,curitem,curlen); + } + } + else { + /* allow any environment variables that begin with 'PERL' + to be stored in the registry */ + if (curitem) + *curitem = '\0'; + + if (strncmp(name, "PERL", 4) == 0) { + if (curitem) { + Safefree(curitem); + curitem = Nullch; + curlen = 0; + } + curitem = GetRegStr(name, &curitem, &curlen); + } + } + if (curitem && *curitem == '\0') + return Nullch; + return curitem; } #endif static long -FileTimeToClock(PFILETIME ft) +filetime_to_clock(PFILETIME ft) { __int64 qw = ft->dwHighDateTime; qw <<= 32; @@ -670,17 +988,16 @@ FileTimeToClock(PFILETIME ft) return (long) qw; } -#undef times -int -my_times(struct tms *timebuf) +DllExport int +win32_times(struct tms *timebuf) { FILETIME user; FILETIME kernel; FILETIME dummy; if (GetProcessTimes(GetCurrentProcess(), &dummy, &dummy, &kernel,&user)) { - timebuf->tms_utime = FileTimeToClock(&user); - timebuf->tms_stime = FileTimeToClock(&kernel); + timebuf->tms_utime = filetime_to_clock(&user); + timebuf->tms_stime = filetime_to_clock(&kernel); timebuf->tms_cutime = 0; timebuf->tms_cstime = 0; @@ -695,8 +1012,133 @@ my_times(struct tms *timebuf) return 0; } -static UINT timerid = 0; +/* fix utime() so it works on directories in NT + * thanks to Jan Dubois + */ +static BOOL +filetime_from_time(PFILETIME pFileTime, time_t Time) +{ + struct tm *pTM = gmtime(&Time); + SYSTEMTIME SystemTime; + + if (pTM == NULL) + return FALSE; + + SystemTime.wYear = pTM->tm_year + 1900; + SystemTime.wMonth = pTM->tm_mon + 1; + SystemTime.wDay = pTM->tm_mday; + SystemTime.wHour = pTM->tm_hour; + SystemTime.wMinute = pTM->tm_min; + SystemTime.wSecond = pTM->tm_sec; + SystemTime.wMilliseconds = 0; + + return SystemTimeToFileTime(&SystemTime, pFileTime); +} + +DllExport int +win32_utime(const char *filename, struct utimbuf *times) +{ + HANDLE handle; + FILETIME ftCreate; + FILETIME ftAccess; + FILETIME ftWrite; + struct utimbuf TimeBuffer; + + int rc = utime(filename,times); + /* EACCES: path specifies directory or readonly file */ + if (rc == 0 || errno != EACCES /* || !IsWinNT() */) + return rc; + + if (times == NULL) { + times = &TimeBuffer; + time(×->actime); + times->modtime = times->actime; + } + + /* This will (and should) still fail on readonly files */ + handle = CreateFile(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; + + if (GetFileTime(handle, &ftCreate, &ftAccess, &ftWrite) && + filetime_from_time(&ftAccess, times->actime) && + filetime_from_time(&ftWrite, times->modtime) && + SetFileTime(handle, &ftCreate, &ftAccess, &ftWrite)) + { + rc = 0; + } + + CloseHandle(handle); + return rc; +} + +DllExport int +win32_waitpid(int pid, int *status, int flags) +{ + int rc; + if (pid == -1) + return win32_wait(status); + else { + rc = cwait(status, pid, WAIT_CHILD); + /* cwait() returns differently on Borland */ +#ifdef __BORLANDC__ + if (status) + *status = (((*status >> 8) & 0xff) | ((*status << 8) & 0xff00)); +#endif + remove_dead_process((HANDLE)pid); + } + return rc >= 0 ? pid : rc; +} + +DllExport int +win32_wait(int *status) +{ +#ifdef USE_RTL_WAIT + return wait(status); +#else + /* XXX this wait emulation only knows about processes + * spawned via win32_spawnvp(P_NOWAIT, ...). + */ + int i, retval; + DWORD exitcode, waitcode; + + if (!w32_num_children) { + errno = ECHILD; + return -1; + } + /* if a child exists, wait for it to die */ + waitcode = WaitForMultipleObjects(w32_num_children, + w32_child_pids, + FALSE, + INFINITE); + if (waitcode != WAIT_FAILED) { + if (waitcode >= WAIT_ABANDONED_0 + && waitcode < WAIT_ABANDONED_0 + w32_num_children) + i = waitcode - WAIT_ABANDONED_0; + else + i = waitcode - WAIT_OBJECT_0; + if (GetExitCodeProcess(w32_child_pids[i], &exitcode) ) { + CloseHandle(w32_child_pids[i]); + *status = (int)((exitcode & 0xff) << 8); + retval = (int)w32_child_pids[i]; + Copy(&w32_child_pids[i+1], &w32_child_pids[i], + (w32_num_children-i-1), HANDLE); + w32_num_children--; + return retval; + } + } + +FAILED: + errno = GetLastError(); + return -1; + +#endif +} + +static UINT timerid = 0; static VOID CALLBACK TimerProc(HWND win, UINT msg, UINT id, DWORD time) { @@ -705,9 +1147,8 @@ static VOID CALLBACK TimerProc(HWND win, UINT msg, UINT id, DWORD time) sighandler(14); } -#undef alarm -unsigned int -my_alarm(unsigned int sec) +DllExport unsigned int +win32_alarm(unsigned int sec) { /* * the 'obvious' implentation is SetTimer() with a callback @@ -735,14 +1176,25 @@ my_alarm(unsigned int sec) return 0; } -#if defined(_DLL) || !defined(_MSC_VER) -/* It may or may not be fixed (ok on NT), but DLL runtime - does not export the functions used in the workround -*/ -#define WIN95_OSFHANDLE_FIXED +#if defined(HAVE_DES_FCRYPT) || defined(PERL_OBJECT) +#ifdef HAVE_DES_FCRYPT +extern char * des_fcrypt(const char *txt, const char *salt, char *cbuf); +#endif + +DllExport char * +win32_crypt(const char *txt, const char *salt) +{ +#ifdef HAVE_DES_FCRYPT + dTHR; + return des_fcrypt(txt, salt, crypt_buffer); +#else + die("The crypt() function is unimplemented due to excessive paranoia."); + return Nullch; +#endif +} #endif -#if defined(_WIN32) && !defined(WIN95_OSFHANDLE_FIXED) && defined(_M_IX86) +#ifdef USE_FIXED_OSFHANDLE EXTERN_C int __cdecl _alloc_osfhnd(void); EXTERN_C int __cdecl _set_osfhnd(int fh, long value); @@ -811,14 +1263,14 @@ my_open_osfhandle(long osfhandle, int flags) /* copy relevant flags from second parameter */ fileflags = FDEV; - if(flags & O_APPEND) + if (flags & O_APPEND) fileflags |= FAPPEND; - if(flags & O_TEXT) + if (flags & O_TEXT) fileflags |= FTEXT; /* attempt to allocate a C Runtime file handle */ - if((fh = _alloc_osfhnd()) == -1) { + if ((fh = _alloc_osfhnd()) == -1) { errno = EMFILE; /* too many open files */ _doserrno = 0L; /* not an OS error */ return -1; /* return error to caller */ @@ -841,20 +1293,24 @@ my_open_osfhandle(long osfhandle, int flags) } #define _open_osfhandle my_open_osfhandle -#endif /* _M_IX86 */ +#endif /* USE_FIXED_OSFHANDLE */ /* simulate flock by locking a range on the file */ #define LK_ERR(f,i) ((f) ? (i = 0) : (errno = GetLastError())) #define LK_LEN 0xffff0000 -int -my_flock(int fd, int oper) +DllExport int +win32_flock(int fd, int oper) { OVERLAPPED o; int i = -1; HANDLE fh; + if (!IsWinNT()) { + croak("flock() unimplemented on this platform"); + return -1; + } fh = (HANDLE)_get_osfhandle(fd); memset(&o, 0, sizeof(o)); @@ -941,8 +1397,6 @@ win32_feof(FILE *fp) * we have to roll our own. */ -__declspec(thread) char strerror_buffer[512]; - DllExport char * win32_strerror(int e) { @@ -951,11 +1405,12 @@ win32_strerror(int e) #endif DWORD source = 0; - if(e < 0 || e > sys_nerr) { - if(e < 0) + if (e < 0 || e > sys_nerr) { + dTHR; + if (e < 0) e = GetLastError(); - if(FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, &source, e, 0, + if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, &source, e, 0, strerror_buffer, sizeof(strerror_buffer), NULL) == 0) strcpy(strerror_buffer, "Unknown Error"); @@ -964,6 +1419,33 @@ win32_strerror(int e) return strerror(e); } +DllExport void +win32_str_os_error(void *sv, DWORD dwErr) +{ + DWORD dwLen; + char *sMsg; + dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER + |FORMAT_MESSAGE_IGNORE_INSERTS + |FORMAT_MESSAGE_FROM_SYSTEM, NULL, + dwErr, 0, (char *)&sMsg, 1, NULL); + if (0 < dwLen) { + while (0 < dwLen && isspace(sMsg[--dwLen])) + ; + if ('.' != sMsg[dwLen]) + dwLen++; + sMsg[dwLen]= '\0'; + } + if (0 == dwLen) { + sMsg = (char*)LocalAlloc(0, 64/**sizeof(TCHAR)*/); + dwLen = sprintf(sMsg, + "Unknown error #0x%lX (lookup 0x%lX)", + dwErr, GetLastError()); + } + sv_setpvn((SV*)sv, sMsg, dwLen); + LocalFree(sMsg); +} + + DllExport int win32_fprintf(FILE *fp, const char *format, ...) { @@ -1014,6 +1496,11 @@ win32_fopen(const char *filename, const char *mode) return fopen(filename, mode); } +#ifndef USE_SOCKETS_AS_HANDLES +#undef fdopen +#define fdopen my_fdopen +#endif + DllExport FILE * win32_fdopen( int handle, const char *mode) { @@ -1031,7 +1518,7 @@ win32_freopen( const char *path, const char *mode, FILE *stream) DllExport int win32_fclose(FILE *pf) { - return my_fclose(pf); + return my_fclose(pf); /* defined in win32sck.c */ } DllExport int @@ -1122,9 +1609,9 @@ win32_abort(void) } DllExport int -win32_fstat(int fd,struct stat *bufptr) +win32_fstat(int fd,struct stat *sbufptr) { - return fstat(fd,bufptr); + return fstat(fd,sbufptr); } DllExport int @@ -1133,16 +1620,182 @@ win32_pipe(int *pfd, unsigned int size, int mode) return _pipe(pfd, size, mode); } +/* + * a popen() clone that respects PERL5SHELL + */ + DllExport FILE* win32_popen(const char *command, const char *mode) { +#ifdef USE_RTL_POPEN return _popen(command, mode); +#else + int p[2]; + int parent, child; + int stdfd, oldfd; + int ourmode; + int childpid; + + /* establish which ends read and write */ + if (strchr(mode,'w')) { + stdfd = 0; /* stdin */ + parent = 1; + child = 0; + } + else if (strchr(mode,'r')) { + stdfd = 1; /* stdout */ + parent = 0; + child = 1; + } + else + return NULL; + + /* set the correct mode */ + if (strchr(mode,'b')) + ourmode = O_BINARY; + else if (strchr(mode,'t')) + ourmode = O_TEXT; + else + ourmode = _fmode & (O_TEXT | O_BINARY); + + /* the child doesn't inherit handles */ + ourmode |= O_NOINHERIT; + + if (win32_pipe( p, 512, ourmode) == -1) + return NULL; + + /* save current stdfd */ + if ((oldfd = win32_dup(stdfd)) == -1) + goto cleanup; + + /* 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) + goto cleanup; + + /* close the child end in parent */ + win32_close(p[child]); + + /* start the child */ + if ((childpid = do_spawn_nowait((char*)command)) == -1) + goto cleanup; + + /* revert stdfd to whatever it was before */ + if (win32_dup2(oldfd, stdfd) == -1) + goto cleanup; + + /* close saved handle */ + win32_close(oldfd); + + sv_setiv(*av_fetch(w32_fdpid, p[parent], TRUE), childpid); + + /* we have an fd, return a file stream */ + return (win32_fdopen(p[parent], (char *)mode)); + +cleanup: + /* we don't need to check for errors here */ + win32_close(p[0]); + win32_close(p[1]); + if (oldfd != -1) { + win32_dup2(oldfd, stdfd); + win32_close(oldfd); + } + return (NULL); + +#endif /* USE_RTL_POPEN */ } +/* + * pclose() clone + */ + DllExport int win32_pclose(FILE *pf) { +#ifdef USE_RTL_POPEN return _pclose(pf); +#else + + int childpid, status; + SV *sv; + + sv = *av_fetch(w32_fdpid, win32_fileno(pf), TRUE); + if (SvIOK(sv)) + childpid = SvIVX(sv); + else + childpid = 0; + + if (!childpid) { + errno = EBADF; + return -1; + } + + win32_fclose(pf); + SvIVX(sv) = 0; + + remove_dead_process((HANDLE)childpid); + + /* wait for the child */ + if (cwait(&status, childpid, WAIT_CHILD) == -1) + return (-1); + /* cwait() returns differently on Borland */ +#ifdef __BORLANDC__ + return (((status >> 8) & 0xff) | ((status << 8) & 0xff00)); +#else + return (status); +#endif + +#endif /* USE_RTL_POPEN */ +} + +DllExport int +win32_rename(const char *oname, const char *newname) +{ + char szNewWorkName[MAX_PATH+1]; + WIN32_FIND_DATA fdOldFile, fdNewFile; + HANDLE handle; + char *ptr; + + if ((strchr(oname, '\\') || strchr(oname, '/')) + && strchr(newname, '\\') == NULL + && strchr(newname, '/') == NULL) + { + strcpy(szNewWorkName, oname); + if ((ptr = strrchr(szNewWorkName, '\\')) == NULL) + ptr = strrchr(szNewWorkName, '/'); + strcpy(++ptr, newname); + } + else + strcpy(szNewWorkName, newname); + + if (stricmp(oname, szNewWorkName) != 0) { + // check that we're not being fooled by relative paths + // and only delete the new file + // 1) if it exists + // 2) it is not the same file as the old file + // 3) old file exist + // GetFullPathName does not return the long file name on some systems + handle = FindFirstFile(oname, &fdOldFile); + if (handle != INVALID_HANDLE_VALUE) { + FindClose(handle); + + handle = FindFirstFile(szNewWorkName, &fdNewFile); + + if (handle != INVALID_HANDLE_VALUE) + FindClose(handle); + else + fdNewFile.cFileName[0] = '\0'; + + if (strcmp(fdOldFile.cAlternateFileName, + fdNewFile.cAlternateFileName) != 0 + && strcmp(fdOldFile.cFileName, fdNewFile.cFileName) != 0) + { + // file exists and not same file + DeleteFile(szNewWorkName); + } + } + } + return rename(oname, newname); } DllExport int @@ -1235,7 +1888,29 @@ win32_chdir(const char *dir) DllExport int win32_spawnvp(int mode, const char *cmdname, const char *const *argv) { - return spawnvp(mode, cmdname, (char * const *) argv); + int status; + +#ifndef USE_RTL_WAIT + if (mode == P_NOWAIT && w32_num_children >= MAXIMUM_WAIT_OBJECTS) + return -1; +#endif + + status = spawnvp(mode, cmdname, (char * const *) argv); +#ifndef USE_RTL_WAIT + /* XXX For the P_NOWAIT case, Borland RTL returns pinfo.dwProcessId + * while VC RTL returns pinfo.hProcess. For purposes of the custom + * implementation of win32_wait(), we assume the latter. + */ + if (mode == P_NOWAIT && status >= 0) + w32_child_pids[w32_num_children++] = (HANDLE)status; +#endif + return status; +} + +DllExport int +win32_execv(const char *cmdname, const char *const *argv) +{ + return execv(cmdname, (char *const *)argv); } DllExport int @@ -1316,6 +1991,85 @@ win32_putchar(int c) return putchar(c); } +#ifdef MYMALLOC + +#ifndef USE_PERL_SBRK + +static char *committed = NULL; +static char *base = NULL; +static char *reserved = NULL; +static char *brk = NULL; +static DWORD pagesize = 0; +static DWORD allocsize = 0; + +void * +sbrk(int need) +{ + void *result; + if (!pagesize) + {SYSTEM_INFO info; + GetSystemInfo(&info); + /* Pretend page size is larger so we don't perpetually + * 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; + char *addr; + 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) + committed = reserved; + } + /* Reserve some (more) space + * 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 + */ + addr = (char *) VirtualAlloc(reserved,size,MEM_RESERVE,PAGE_NOACCESS); + if (addr) + { + reserved = addr+size; + if (!base) + base = addr; + if (!committed) + committed = base; + if (!brk) + brk = committed; + } + else + { + return (void *) -1; + } + } + result = brk; + brk += need; + if (brk > committed) + { + DWORD size = ((brk-committed + pagesize -1)/pagesize) * pagesize; + char *addr = (char *) VirtualAlloc(committed,size,MEM_COMMIT,PAGE_READWRITE); + if (addr) + { + committed += size; + } + else + return (void *) -1; + } + return result; +} + +#endif +#endif + DllExport void* win32_malloc(size_t size) { @@ -1340,6 +2094,7 @@ win32_free(void *block) free(block); } + int win32_open_osfhandle(long handle, int flags) { @@ -1356,16 +2111,6 @@ win32_get_osfhandle(int fd) * Extras. */ -DllExport int -win32_flock(int fd, int oper) -{ - if (!IsWinNT()) { - croak("flock() unimplemented on this platform"); - return -1; - } - return my_flock(fd, oper); -} - static XS(w32_GetCwd) { @@ -1383,7 +2128,7 @@ XS(w32_GetCwd) */ if (SvCUR(sv)) SvPOK_on(sv); - EXTEND(sp,1); + EXTEND(SP,1); ST(0) = sv; XSRETURN(1); } @@ -1394,7 +2139,7 @@ XS(w32_SetCwd) dXSARGS; if (items != 1) croak("usage: Win32::SetCurrentDirectory($cwd)"); - if (SetCurrentDirectory(SvPV(ST(0),na))) + if (SetCurrentDirectory(SvPV(ST(0),PL_na))) XSRETURN_YES; XSRETURN_NO; @@ -1427,8 +2172,8 @@ static XS(w32_LoginName) { dXSARGS; - char name[256]; - DWORD size = sizeof(name); + char *name = getlogin_buffer; + DWORD size = sizeof(getlogin_buffer); if (GetUserName(name,&size)) { /* size includes NULL */ ST(0) = sv_2mortal(newSVpv(name,size-1)); @@ -1456,6 +2201,8 @@ static XS(w32_DomainName) { dXSARGS; +#ifndef HAS_NETWKSTAGETINFO + /* mingw32 (and Win95) don't have NetWksta*(), so do it the old way */ char name[256]; DWORD size = sizeof(name); if (GetUserName(name,&size)) { @@ -1464,11 +2211,31 @@ XS(w32_DomainName) char dname[256]; DWORD dnamelen = sizeof(dname); SID_NAME_USE snu; - if (LookupAccountName(NULL, name, &sid, &sidlen, + if (LookupAccountName(NULL, name, (PSID)&sid, &sidlen, dname, &dnamelen, &snu)) { XSRETURN_PV(dname); /* all that for this */ } } +#else + /* this way is more reliable, in case user has a local account. + * XXX need dynamic binding of netapi32.dll symbols or this will fail on + * Win95. Probably makes more sense to move it into libwin32. */ + char dname[256]; + DWORD dnamelen = sizeof(dname); + PWKSTA_INFO_100 pwi; + if (NERR_Success == NetWkstaGetInfo(NULL, 100, (LPBYTE*)&pwi)) { + if (pwi->wki100_langroup && *(pwi->wki100_langroup)) { + WideCharToMultiByte(CP_ACP, NULL, pwi->wki100_langroup, + -1, (LPSTR)dname, dnamelen, NULL, NULL); + } + else { + WideCharToMultiByte(CP_ACP, NULL, pwi->wki100_computername, + -1, (LPSTR)dname, dnamelen, NULL, NULL); + } + NetApiBufferFree(pwi); + XSRETURN_PV(dname); + } +#endif XSRETURN_UNDEF; } @@ -1552,18 +2319,18 @@ XS(w32_Spawn) STARTUPINFO stStartInfo; BOOL bSuccess = FALSE; - if(items != 3) + if (items != 3) croak("usage: Win32::Spawn($cmdName, $args, $PID)"); - cmd = SvPV(ST(0),na); - args = SvPV(ST(1), na); + cmd = SvPV(ST(0),PL_na); + args = SvPV(ST(1), PL_na); memset(&stStartInfo, 0, sizeof(stStartInfo)); /* Clear the block */ stStartInfo.cb = sizeof(stStartInfo); /* Set the structure size */ stStartInfo.dwFlags = STARTF_USESHOWWINDOW; /* Enable wShowWindow control */ stStartInfo.wShowWindow = SW_SHOWMINNOACTIVE; /* Start min (normal) */ - if(CreateProcess( + if (CreateProcess( cmd, /* Image path */ args, /* Arguments for command line */ NULL, /* Default process security */ @@ -1596,7 +2363,7 @@ XS(w32_GetShortPathName) SV *shortpath; DWORD len; - if(items != 1) + if (items != 1) croak("usage: Win32::GetShortPathName($longPathName)"); shortpath = sv_mortalcopy(ST(0)); @@ -1612,18 +2379,32 @@ XS(w32_GetShortPathName) ST(0) = shortpath; } else - ST(0) = &sv_undef; + ST(0) = &PL_sv_undef; XSRETURN(1); } +static +XS(w32_Sleep) +{ + dXSARGS; + if (items != 1) + croak("usage: Win32::Sleep($milliseconds)"); + Sleep(SvIV(ST(0))); + XSRETURN_YES; +} + void -init_os_extras() +Perl_init_os_extras() { char *file = __FILE__; dXSUB_SYS; - /* XXX should be removed after checking with Nick */ - newXS("Win32::GetCurrentDirectory", w32_GetCwd, file); + w32_perlshell_tokens = Nullch; + w32_perlshell_items = -1; + w32_fdpid = newAV(); /* XXX needs to be in Perl_win32_init()? */ +#ifndef USE_RTL_WAIT + w32_num_children = 0; +#endif /* these names are Activeware compatible */ newXS("Win32::GetCwd", w32_GetCwd, file); @@ -1641,6 +2422,7 @@ init_os_extras() newXS("Win32::Spawn", w32_Spawn, file); newXS("Win32::GetTickCount", w32_GetTickCount, file); newXS("Win32::GetShortPathName", w32_GetShortPathName, file); + newXS("Win32::Sleep", w32_Sleep, file); /* XXX Bloat Alert! The following Activeware preloads really * ought to be part of Win32::Sys::*, so they're not included @@ -1663,11 +2445,33 @@ Perl_win32_init(int *argcp, char ***argvp) * want to be at the vendor's whim on the default, we set * it explicitly here. */ -#if !defined(_ALPHA_) +#if !defined(_ALPHA_) && !defined(__GNUC__) _control87(MCW_EM, MCW_EM); #endif + MALLOC_INIT; } +#ifdef USE_BINMODE_SCRIPTS +void +win32_strip_return(SV *sv) +{ + char *s = SvPVX(sv); + char *e = s+SvCUR(sv); + char *d = s; + while (s < e) + { + if (*s == '\r' && s[1] == '\n') + { + *d++ = '\n'; + s += 2; + } + else + { + *d++ = *s++; + } + } + SvCUR_set(sv,d-SvPVX(sv)); +} - +#endif