X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=win32%2Fwin32.c;h=9ae2a7d70fe25cbd44c2836dca056f1dbaf7822b;hb=377729033bd4c3e2f6c0ac6b0d2bde9a83c5da6d;hp=e9e5af2a5f7eed8ef0824df18d6d66e6040f09a1;hpb=0a753a764065f2260004b6e6975085378b850346;p=p5sagit%2Fp5-mst-13.2.git diff --git a/win32/win32.c b/win32/win32.c index e9e5af2..9ae2a7d 100644 --- a/win32/win32.c +++ b/win32/win32.c @@ -1,18 +1,22 @@ -// WIN32.C - -// (c) 1995 Microsoft Corporation. All rights reserved. -// Developed by hip communications inc., http://info.hip.com/info/ -// Portions (c) 1993 Intergraph Corporation. All rights reserved. - -// You may distribute under the terms of either the GNU General Public -// License or the Artistic License, as specified in the README file. +/* WIN32.C + * + * (c) 1995 Microsoft Corporation. All rights reserved. + * Developed by hip communications inc., http://info.hip.com/info/ + * Portions (c) 1993 Intergraph Corporation. All rights reserved. + * + * You may distribute under the terms of either the GNU General Public + * License or the Artistic License, as specified in the README file. + */ #define WIN32_LEAN_AND_MEAN #define WIN32IO_IS_STDIO #include +#ifdef __GNUC__ +#define Win32_Winsock +#endif #include -//#include "config.h" +/* #include "config.h" */ #define PERLIO_NOT_STDIO 0 #if !defined(PERLIO_IS_STDIO) && !defined(USE_SFIO) @@ -21,964 +25,1948 @@ #include "EXTERN.h" #include "perl.h" +#include "XSUB.h" #include #include +#ifndef __GNUC__ +/* assert.h conflicts with #define of assert in perl.h */ #include +#endif #include #include +#include -#define CROAK croak -#define WARN warn +#ifdef __GNUC__ +/* Mingw32 defaults to globing command line + * So we turn it off like this: + */ +int _CRT_glob = 0; +#endif -extern WIN32_IOSUBSYSTEM win32stdio; -__declspec(thread) PWIN32_IOSUBSYSTEM pIOSubSystem = &win32stdio; -//__declspec(thread) PWIN32_IOSUBSYSTEM pIOSubSystem = NULL; +#define EXECF_EXEC 1 +#define EXECF_SPAWN 2 +#define EXECF_SPAWN_NOWAIT 3 + +static DWORD os_id(void); +static void get_shell(void); +static long tokenize(char *str, char **dest, char ***destv); +static int do_spawn2(char *cmd, int exectype); +static BOOL has_redirection(char *ptr); +static long filetime_to_clock(PFILETIME ft); + +char * w32_perlshell_tokens = Nullch; +char ** w32_perlshell_vec; +long w32_perlshell_items = -1; +DWORD w32_platform = (DWORD)-1; +char w32_perllib_root[MAX_PATH+1]; +HANDLE w32_perldll_handle = INVALID_HANDLE_VALUE; +#ifndef __BORLANDC__ +long w32_num_children = 0; +HANDLE w32_child_pids[MAXIMUM_WAIT_OBJECTS]; +#endif -BOOL ProbeEnv = FALSE; -DWORD Win32System; -char szShellPath[MAX_PATH+1]; -char szPerlLibRoot[MAX_PATH+1]; -HANDLE PerlDllHandle = INVALID_HANDLE_VALUE; +#ifdef USE_THREADS +# ifdef USE_DECLSPEC_THREAD +__declspec(thread) char strerror_buffer[512]; +__declspec(thread) char getlogin_buffer[128]; +# 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 crypt_buffer (thr->i.Wcrypt_buffer) +# endif +#else +char strerror_buffer[512]; +char getlogin_buffer[128]; +# ifdef HAVE_DES_FCRYPT +char crypt_buffer[30]; +# endif +#endif -#define IsWin95() (Win32System == VER_PLATFORM_WIN32_WINDOWS) -#define IsWinNT() (Win32System == VER_PLATFORM_WIN32_NT) +int +IsWin95(void) { + return (os_id() == VER_PLATFORM_WIN32_WINDOWS); +} -void *SetIOSubSystem(void *p) +int +IsWinNT(void) { + return (os_id() == VER_PLATFORM_WIN32_NT); +} + +char * +win32_perllib_path(char *sfx,...) { - if (p) { - PWIN32_IOSUBSYSTEM pio = (PWIN32_IOSUBSYSTEM)p; + va_list ap; + char *end; + va_start(ap,sfx); + GetModuleFileName((w32_perldll_handle == INVALID_HANDLE_VALUE) + ? GetModuleHandle(NULL) + : w32_perldll_handle, + w32_perllib_root, + sizeof(w32_perllib_root)); + *(end = strrchr(w32_perllib_root, '\\')) = '\0'; + if (stricmp(end-4,"\\bin") == 0) + end -= 4; + strcpy(end,"\\lib"); + while (sfx) + { + strcat(end,"\\"); + strcat(end,sfx); + sfx = va_arg(ap,char *); + } + va_end(ap); + return (w32_perllib_root); +} - if (pio->signature_begin == 12345678L && pio->signature_end == 87654321L) { - PWIN32_IOSUBSYSTEM pold = pIOSubSystem; - pIOSubSystem = pio; - return pold; - } - } - else { - // re-assign our stuff -// pIOSubSystem = &win32stdio; - pIOSubSystem = NULL; - } - return pIOSubSystem; -} - -char *win32PerlLibPath(void) -{ - - GetModuleFileName((PerlDllHandle == INVALID_HANDLE_VALUE) - ? GetModuleHandle(NULL) : PerlDllHandle, - szPerlLibRoot, - sizeof(szPerlLibRoot)); - - *(strrchr(szPerlLibRoot, '\\')) = '\0'; - strcat(szPerlLibRoot,"\\LIB"); - return (szPerlLibRoot); -} - -BOOL HasRedirection(char *ptr) -{ - int inquote = 0; - char quote = '\0'; - - // - // Scan string looking for redirection (< or >) or pipe - // characters (|) that are not in a quoted string - // - while(*ptr) - { - switch(*ptr) - { - case '\'': - case '\"': - if(inquote) - { - if(quote == *ptr) - { - inquote = 0; - quote = '\0'; - } - } - else - { - quote = *ptr; - inquote++; - } - break; - - case '>': - case '<': - case '|': - if(!inquote) - return TRUE; - - default: - break; +static BOOL +has_redirection(char *ptr) +{ + int inquote = 0; + char quote = '\0'; + + /* + * Scan string looking for redirection (< or >) or pipe + * characters (|) that are not in a quoted string + */ + while(*ptr) { + switch(*ptr) { + case '\'': + case '\"': + if(inquote) { + if(quote == *ptr) { + inquote = 0; + quote = '\0'; } - ++ptr; + } + else { + quote = *ptr; + inquote++; + } + break; + case '>': + case '<': + case '|': + if(!inquote) + return TRUE; + default: + break; } - return FALSE; + ++ptr; + } + return FALSE; } -// since the current process environment is being updated in util.c -// the library functions will get the correct environment -PerlIO *my_popen(char *cmd, char *mode) +/* since the current process environment is being updated in util.c + * the library functions will get the correct environment + */ +PerlIO * +my_popen(char *cmd, char *mode) { #ifdef FIXCMD -#define fixcmd(x) {\ - char *pspace = strchr((x),' ');\ - if (pspace) {\ - char *p = (x);\ - while (p < pspace) {\ - if (*p == '/') *p = '\\';\ - p++;\ - }\ - }\ - } +#define fixcmd(x) { \ + char *pspace = strchr((x),' '); \ + if (pspace) { \ + char *p = (x); \ + while (p < pspace) { \ + if (*p == '/') \ + *p = '\\'; \ + p++; \ + } \ + } \ + } #else #define fixcmd(x) #endif -#ifndef PERLDLL - fixcmd(cmd); + fixcmd(cmd); +#ifdef __BORLANDC__ /* workaround a Borland stdio bug */ + win32_fflush(stdout); + win32_fflush(stderr); +#endif return win32_popen(cmd, mode); -#else -/* - * There seems to be some problems for the _popen call in a DLL - * this trick at the moment seems to work but it is never test - * on NT yet - * - */ -# ifdef __cplusplus -#define EXT_C_FUNC extern "C" -# else -#define EXT_C_FUNC extern -# endif - -EXT_C_FUNC int __cdecl _set_osfhnd(int fh, long value); -EXT_C_FUNC void __cdecl _lock_fhandle(int); -EXT_C_FUNC void __cdecl _unlock_fhandle(int); - - BOOL fSuccess; - PerlIO *pf; // to store the _popen return value - int tm = 0; /* flag indicating tDllExport or binary mode */ - int fhNeeded, fhInherited, fhDup; - int ineeded, iinherited; - DWORD dwDup; - int phdls[2]; /* I/O handles for pipe */ - HANDLE hPIn, - hPOut, - hPErr, - hSaveStdin, - hSaveStdout, - hSaveStderr, - hPNeeded, hPInherited, hPDuped; - - /* first check for errors in the arguments - */ +} - if ( (cmd == NULL) || (mode == NULL) || ((*mode != 'w') && - (*mode != _T('r'))) ) - goto error1; +long +my_pclose(PerlIO *fp) +{ + return win32_pclose(fp); +} - if ( *(mode + 1) == _T('t') ) - tm = _O_TEXT; - else if ( *(mode + 1) == _T('b') ) - tm = _O_BINARY; - else tm = (*mode == 'w' ? _O_BINARY : _O_TEXT); +static DWORD +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 (w32_platform); +} + +/* 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 (!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. + * 2. PERL5SHELL could be set to a shell that may not be fit for + * interactive use (which is what most programs look in COMSPEC + * for). + */ + 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); + } +} + +int +do_aspawn(void *vreally, void **vmark, void **vsp) +{ + SV *really = (SV*)vreally; + SV **mark = (SV**)vmark; + SV **sp = (SV**)vsp; + char **argv; + char *str; + int status; + int flag = P_WAIT; + int index = 0; + + if (sp <= mark) + return -1; + get_shell(); + New(1306, argv, (sp - mark) + w32_perlshell_items + 2, char*); - fixcmd(cmd); - if (&win32stdio != pIOSubSystem) return win32_popen(cmd, mode); + if (SvNIOKp(*(mark+1)) && !SvPOKp(*(mark+1))) { + ++mark; + flag = SvIVx(*mark); + } -#ifdef EFG - if ( _pipe( phdls, 1024, tm ) == -1 ) -#else - if ( win32_pipe( phdls, 1024, tm ) == -1 ) -#endif - goto error1; + while(++mark <= sp) { + if (*mark && (str = SvPV(*mark, na))) + argv[index++] = str; + else + argv[index++] = ""; + } + argv[index++] = 0; + + status = win32_spawnvp(flag, + (really ? SvPV(really,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, + (really ? SvPV(really,na) : argv[0]), + (const char* const*)argv); + } + + if (status < 0) { + if (dowarn) + warn("Can't spawn \"%s\": %s", argv[0], strerror(errno)); + status = 255 * 256; + } + else if (flag != P_NOWAIT) + status *= 256; + Safefree(argv); + return (statusvalue = status); +} + +static int +do_spawn2(char *cmd, int exectype) +{ + char **a; + char *s; + char **argv; + int status = -1; + BOOL needToTry = TRUE; + char *cmd2; + + /* Save an extra exec if possible. See if there are shell + * metacharacters in it */ + if(!has_redirection(cmd)) { + New(1301,argv, strlen(cmd) / 2 + 2, char*); + New(1302,cmd2, strlen(cmd) + 1, char); + strcpy(cmd2, cmd); + a = argv; + for (s = cmd2; *s;) { + while (*s && isspace(*s)) + s++; + if (*s) + *(a++) = s; + while(*s && !isspace(*s)) + s++; + if(*s) + *s++ = '\0'; + } + *a = Nullch; + if (argv[0]) { + switch (exectype) { + case EXECF_SPAWN: + status = win32_spawnvp(P_WAIT, argv[0], + (const char* const*)argv); + break; + case EXECF_SPAWN_NOWAIT: + status = win32_spawnvp(P_NOWAIT, argv[0], + (const char* const*)argv); + break; + case EXECF_EXEC: + status = win32_execvp(argv[0], (const char* const*)argv); + break; + } + if (status != -1 || errno == 0) + needToTry = FALSE; + } + Safefree(argv); + Safefree(cmd2); + } + 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], + (const char* const*)argv); + break; + case EXECF_SPAWN_NOWAIT: + status = win32_spawnvp(P_NOWAIT, argv[0], + (const char* const*)argv); + break; + case EXECF_EXEC: + 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"), + cmd, strerror(errno)); + status = 255 * 256; + } + else if (exectype != EXECF_SPAWN_NOWAIT) + status *= 256; + return (statusvalue = status); +} +int +do_spawn(char *cmd) +{ + return do_spawn2(cmd, EXECF_SPAWN); +} - /* save the current situation */ +int +do_spawn_nowait(char *cmd) +{ + return do_spawn2(cmd, EXECF_SPAWN_NOWAIT); +} - hSaveStdin = GetStdHandle(STD_INPUT_HANDLE); - hSaveStdout = GetStdHandle(STD_OUTPUT_HANDLE); - hSaveStderr = GetStdHandle(STD_ERROR_HANDLE); +bool +do_exec(char *cmd) +{ + do_spawn2(cmd, EXECF_EXEC); + return FALSE; +} - if (*mode == _T('w')) { - ineeded = 1; - dwDup = STD_INPUT_HANDLE; - iinherited = 0; - } - else { - ineeded = 0; - dwDup = STD_OUTPUT_HANDLE; - iinherited = 1; - } +#define PATHLEN 1024 - fhNeeded = phdls[ineeded]; - fhInherited = phdls[iinherited]; +/* 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;*/ + + /* check to see if filename is a directory */ + if (win32_stat(filename, &sbuf) < 0 || (sbuf.st_mode & S_IFDIR) == 0) { + 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) + return NULL; + + /* Create the search pattern */ + strcpy(scanname, filename); + + if(index("/\\", *(scanname + strlen(scanname) - 1)) == NULL) + strcat(scanname, "/*"); + else + strcat(scanname, "*"); + + /* do the FindFirstFile call */ + fh = FindFirstFile(scanname, &FindData); + if(fh == INVALID_HANDLE_VALUE) { + return NULL; + } + + /* now allocate the first part of the string table for + * the filenames that we find. + */ + idx = strlen(FindData.cFileName)+1; + New(1304, p->start, idx, char); + 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 + * (which should be all of them in this directory!). + * the variable idx should point one past the null terminator + * of the previous string found. + */ + while (FindNextFile(fh, &FindData)) { + len = strlen(FindData.cFileName); + /* bump the string table size by enough for the + * new name and it's null terminator + */ + Renew(p->start, idx+len+1, char); + 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; +} - fSuccess = DuplicateHandle(GetCurrentProcess(), - (HANDLE) stolen_get_osfhandle(fhNeeded), - GetCurrentProcess(), - &hPNeeded, - 0, - FALSE, /* not inherited */ - DUPLICATE_SAME_ACCESS); - if (!fSuccess) goto error2; +/* Readdir just returns the current string pointer and bumps the + * string pointer to the nDllExport entry. + */ +struct direct * +readdir(DIR *dirp) +{ + int len; + static int dummy = 0; - fhDup = stolen_open_osfhandle((long) hPNeeded, tm); - win32_dup2(fhDup, fhNeeded); - win32_close(fhDup); + if (dirp->curr) { + /* first set up the structure to return */ + len = strlen(dirp->curr); + strcpy(dirp->dirstr.d_name, dirp->curr); + dirp->dirstr.d_namlen = len; -#ifdef AAA - /* Close the Out pipe, child won't need it */ - hPDuped = (HANDLE) stolen_get_osfhandle(fhNeeded); + /* Fake an inode */ + dirp->dirstr.d_ino = dummy++; - _lock_fhandle(fhNeeded); - _set_osfhnd(fhNeeded, (long) hPNeeded); // put in ours duplicated one - _unlock_fhandle(fhNeeded); + /* Now set up for the nDllExport call to readdir */ + dirp->curr += len + 1; + if (dirp->curr >= (dirp->start + dirp->size)) { + dirp->curr = NULL; + } - CloseHandle(hPDuped); // close the handle first -#endif + return &(dirp->dirstr); + } + else + return NULL; +} - if (!SetStdHandle(dwDup, (HANDLE) stolen_get_osfhandle(fhInherited))) goto error2; +/* Telldir returns the current string pointer position */ +long +telldir(DIR *dirp) +{ + return (long) dirp->curr; +} - // - // make sure the child see the same stderr as the calling program - // - // - if (!SetStdHandle(STD_ERROR_HANDLE, (HANDLE) stolen_get_osfhandle(win32_fileno(win32_stderr())))) goto error2; - pf = win32_popen(cmd, mode); // ask _popen to do the job +/* Seekdir moves the string pointer to a previously saved position + *(Saved by telldir). + */ +void +seekdir(DIR *dirp, long loc) +{ + dirp->curr = (char *)loc; +} - /* restore to where we were */ - SetStdHandle(STD_INPUT_HANDLE, hSaveStdin); - SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdout); - SetStdHandle(STD_ERROR_HANDLE, hSaveStderr); +/* Rewinddir resets the string pointer to the start */ +void +rewinddir(DIR *dirp) +{ + dirp->curr = dirp->start; +} - /* we don't need it any more, that's for the child */ - win32_close(fhInherited); +/* free the memory allocated by opendir */ +int +closedir(DIR *dirp) +{ + Safefree(dirp->start); + Safefree(dirp); + return 1; +} - if (NULL == pf) { - // something wrong - win32_close(fhNeeded); - goto error1; - } - else { - - /* - * here we steal the file handle in pf and stuff ours in - * - */ - win32_dup2(fhNeeded, win32_fileno(pf)); - win32_close(fhNeeded); - } - return (pf); +/* + * various stubs + */ -error2: - win32_close(fhNeeded); - win32_close(fhInherited); -error1: - return (NULL); +/* Ownership + * + * Just pretend that everyone is a superuser. NT will let us know if + * we don\'t really have permission to do something. + */ -#endif +#define ROOT_UID ((uid_t)0) +#define ROOT_GID ((gid_t)0) + +uid_t +getuid(void) +{ + return ROOT_UID; } -long my_pclose(PerlIO *fp) +uid_t +geteuid(void) { - return win32_pclose(fp); + return ROOT_UID; } -static void IdOS(void) +gid_t +getgid(void) { - OSVERSIONINFO osver; + return ROOT_GID; +} - memset(&osver, 0, sizeof(OSVERSIONINFO)); - osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - GetVersionEx(&osver); - Win32System = osver.dwPlatformId; - return; +gid_t +getegid(void) +{ + return ROOT_GID; } -static char *GetShell(void) +int +setuid(uid_t auid) +{ + return (auid == ROOT_UID ? 0 : -1); +} + +int +setgid(gid_t agid) { - static char* szWin95ShellEntry = "Win95Shell"; - static char* szWin95DefaultShell = "Cmd32.exe"; - static char* szWinNTDefaultShell = "cmd.exe"; + return (agid == ROOT_GID ? 0 : -1); +} - if (!ProbeEnv) { - IdOS(), ProbeEnv = TRUE; - if (IsWin95()) { - strcpy(szShellPath, szWin95DefaultShell); - } - else { - strcpy(szShellPath, szWinNTDefaultShell); - } - } +char * +getlogin(void) +{ + dTHR; + char *buf = getlogin_buffer; + DWORD size = sizeof(getlogin_buffer); + if (GetUserName(buf,&size)) + return buf; + return (char*)NULL; +} - return szShellPath; +/* + * pretended kill + */ +int +kill(int pid, int sig) +{ + HANDLE hProcess= OpenProcess(PROCESS_ALL_ACCESS, TRUE, pid); + + if (hProcess == NULL) { + croak("kill process failed!\n"); + } + else { + if (!TerminateProcess(hProcess, sig)) + croak("kill process failed!\n"); + CloseHandle(hProcess); + } + return 0; } + +/* + * File system stuff + */ -int do_aspawn(void* really, void** mark, void** arglast) +DllExport unsigned int +win32_sleep(unsigned int t) { - char **argv; - char *strPtr; - char *cmd; - int status; - unsigned int length; - int index = 0; - SV *sv = (SV*)really; - SV** pSv = (SV**)mark; - - New(1110, argv, (arglast - mark) + 3, char*); - - if(sv != Nullsv) - { - cmd = SvPV(sv, length); + Sleep(t*1000); + return 0; +} + +DllExport int +win32_stat(const char *path, struct stat *buffer) +{ + char t[MAX_PATH]; + const char *p = path; + int l = strlen(path); + int res; + + if (l > 1) { + switch(path[l - 1]) { + case '\\': + case '/': + if (path[l - 2] != ':') { + strncpy(t, path, l - 1); + t[l - 1] = 0; + p = t; + }; } - else - { - cmd = GetShell(); - argv[index++] = "/c"; + } + res = stat(p,buffer); +#ifdef __BORLANDC__ + if (res == 0) { + if (S_ISDIR(buffer->st_mode)) + buffer->st_mode |= S_IWRITE | S_IEXEC; + else if (S_ISREG(buffer->st_mode)) { + if (l >= 4 && path[l-4] == '.') { + const char *e = path + l - 3; + if (strnicmp(e,"exe",3) + && strnicmp(e,"bat",3) + && strnicmp(e,"com",3) + && (IsWin95() || strnicmp(e,"cmd",3))) + buffer->st_mode &= ~S_IEXEC; + else + buffer->st_mode |= S_IEXEC; + } + else + buffer->st_mode &= ~S_IEXEC; } + } +#endif + return res; +} - while(pSv <= (SV**)arglast) - { - sv = *pSv++; - strPtr = SvPV(sv, length); - if(strPtr != NULL && *strPtr != '\0') - argv[index++] = strPtr; - } - argv[index++] = 0; +#ifndef USE_WIN32_RTL_ENV - status = win32_spawnvpe(P_WAIT, cmd, (const char* const*)argv, (const char* const*)environ); +DllExport char * +win32_getenv(const char *name) +{ + static char *curitem = Nullch; + static DWORD curlen = 512; + DWORD needlen; + if (!curitem) + 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); + } + return curitem; +} - Safefree(argv); +#endif - // set statusvalue the perl variable $? - return (statusvalue = status*256); +static long +filetime_to_clock(PFILETIME ft) +{ + __int64 qw = ft->dwHighDateTime; + qw <<= 32; + qw |= ft->dwLowDateTime; + qw /= 10000; /* File time ticks at 0.1uS, clock at 1mS */ + return (long) qw; } -int do_spawn(char *cmd) +DllExport int +win32_times(struct tms *timebuf) { - char **a; - char *s; - char **argv; - int status = -1; - BOOL needToTry = TRUE; - char *shell, *cmd2; - - /* save an extra exec if possible */ - shell = GetShell(); - - /* see if there are shell metacharacters in it */ - if(!HasRedirection(cmd)) - { - New(1102,argv, strlen(cmd) / 2 + 2, char*); - - New(1103,cmd2, strlen(cmd) + 1, char); - strcpy(cmd2, cmd); - a = argv; - for(s = cmd2; *s;) - { - while(*s && isspace(*s)) s++; - if(*s) - *(a++) = s; - while(*s && !isspace(*s)) s++; - if(*s) - *s++ = '\0'; - } - *a = Nullch; - if(argv[0]) - { - status = win32_spawnvpe(P_WAIT, argv[0], (const char* const*)argv, (const char* const*)environ); - if(status != -1 || errno == 0) - needToTry = FALSE; - } - Safefree(argv); - Safefree(cmd2); - } - if(needToTry) - { - status = win32_spawnle(P_WAIT, shell, shell, "/c", cmd, (char*)0, environ); + FILETIME user; + FILETIME kernel; + FILETIME dummy; + if (GetProcessTimes(GetCurrentProcess(), &dummy, &dummy, + &kernel,&user)) { + timebuf->tms_utime = filetime_to_clock(&user); + timebuf->tms_stime = filetime_to_clock(&kernel); + timebuf->tms_cutime = 0; + timebuf->tms_cstime = 0; + + } else { + /* That failed - e.g. Win95 fallback to clock() */ + clock_t t = clock(); + timebuf->tms_utime = t; + timebuf->tms_stime = 0; + timebuf->tms_cutime = 0; + timebuf->tms_cstime = 0; + } + return 0; +} + +DllExport int +win32_wait(int *status) +{ +#ifdef __BORLANDC__ + 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; - // set statusvalue the perl variable $? - return (statusvalue = status*256); +#endif } +static UINT timerid = 0; -#define PATHLEN 1024 +static VOID CALLBACK TimerProc(HWND win, UINT msg, UINT id, DWORD time) +{ + KillTimer(NULL,timerid); + timerid=0; + sighandler(14); +} -// 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) +DllExport unsigned int +win32_alarm(unsigned int sec) { - 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; - - // check to see if filename is a directory - if(stat(filename, &sbuf) < 0 || sbuf.st_mode & _S_IFDIR == 0) - { - return NULL; - } + /* + * the 'obvious' implentation is SetTimer() with a callback + * which does whatever receiving SIGALRM would do + * we cannot use SIGALRM even via raise() as it is not + * one of the supported codes in + * + * Snag is unless something is looking at the message queue + * nothing happens :-( + */ + if (sec) + { + timerid = SetTimer(NULL,timerid,sec*1000,(TIMERPROC)TimerProc); + if (!timerid) + croak("Cannot set timer"); + } + else + { + if (timerid) + { + KillTimer(NULL,timerid); + timerid=0; + } + } + return 0; +} - // 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(1501, p, 1, DIR); - if(p == NULL) - return NULL; - - // Create the search pattern - strcpy(scanname, filename); - - if(index("/\\", *(scanname + strlen(scanname) - 1)) == NULL) - strcat(scanname, "/*"); - else - strcat(scanname, "*"); +#ifdef HAVE_DES_FCRYPT +extern char * des_fcrypt(char *cbuf, const char *txt, const char *salt); - // do the FindFirstFile call - fh = FindFirstFile(scanname, &FindData); - if(fh == INVALID_HANDLE_VALUE) - { - return NULL; - } +DllExport char * +win32_crypt(const char *txt, const char *salt) +{ + dTHR; + return des_fcrypt(crypt_buffer, txt, salt); +} +#endif - // now allocate the first part of the string table for the filenames that we find. - idx = strlen(FindData.cFileName)+1; - New(1502, p->start, idx, char); - 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 - // (which should be all of them in this directory!). - // the variable idx should point one past the null terminator - // of the previous string found. - // - while(FindNextFile(fh, &FindData)) - { - len = strlen(FindData.cFileName); - // bump the string table size by enough for the - // new name and it's null terminator - Renew(p->start, idx+len+1, char); - 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; +#ifdef USE_FIXED_OSFHANDLE + +EXTERN_C int __cdecl _alloc_osfhnd(void); +EXTERN_C int __cdecl _set_osfhnd(int fh, long value); +EXTERN_C void __cdecl _lock_fhandle(int); +EXTERN_C void __cdecl _unlock_fhandle(int); +EXTERN_C void __cdecl _unlock(int); + +#if (_MSC_VER >= 1000) +typedef struct { + long osfhnd; /* underlying OS file HANDLE */ + char osfile; /* attributes of file (e.g., open in text mode?) */ + char pipech; /* one char buffer for handles opened on pipes */ +#if defined (_MT) && !defined (DLL_FOR_WIN32S) + int lockinitflag; + CRITICAL_SECTION lock; +#endif /* defined (_MT) && !defined (DLL_FOR_WIN32S) */ +} ioinfo; + +EXTERN_C ioinfo * __pioinfo[]; + +#define IOINFO_L2E 5 +#define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E) +#define _pioinfo(i) (__pioinfo[i >> IOINFO_L2E] + (i & (IOINFO_ARRAY_ELTS - 1))) +#define _osfile(i) (_pioinfo(i)->osfile) + +#else /* (_MSC_VER >= 1000) */ +extern char _osfile[]; +#endif /* (_MSC_VER >= 1000) */ + +#define FOPEN 0x01 /* file handle open */ +#define FAPPEND 0x20 /* file handle opened O_APPEND */ +#define FDEV 0x40 /* file handle refers to device */ +#define FTEXT 0x80 /* file handle is in text mode */ + +#define _STREAM_LOCKS 26 /* Table of stream locks */ +#define _LAST_STREAM_LOCK (_STREAM_LOCKS+_NSTREAM_-1) /* Last stream lock */ +#define _FH_LOCKS (_LAST_STREAM_LOCK+1) /* Table of fh locks */ + +/*** +*int my_open_osfhandle(long osfhandle, int flags) - open C Runtime file handle +* +*Purpose: +* This function allocates a free C Runtime file handle and associates +* it with the Win32 HANDLE specified by the first parameter. This is a +* temperary fix for WIN95's brain damage GetFileType() error on socket +* we just bypass that call for socket +* +*Entry: +* long osfhandle - Win32 HANDLE to associate with C Runtime file handle. +* int flags - flags to associate with C Runtime file handle. +* +*Exit: +* returns index of entry in fh, if successful +* return -1, if no free entry is found +* +*Exceptions: +* +*******************************************************************************/ + +static int +my_open_osfhandle(long osfhandle, int flags) +{ + int fh; + char fileflags; /* _osfile flags */ + + /* copy relevant flags from second parameter */ + fileflags = FDEV; + + if(flags & O_APPEND) + fileflags |= FAPPEND; + + if(flags & O_TEXT) + fileflags |= FTEXT; + + /* attempt to allocate a C Runtime file handle */ + if((fh = _alloc_osfhnd()) == -1) { + errno = EMFILE; /* too many open files */ + _doserrno = 0L; /* not an OS error */ + return -1; /* return error to caller */ + } + + /* the file is open. now, set the info in _osfhnd array */ + _set_osfhnd(fh, osfhandle); + + fileflags |= FOPEN; /* mark as open */ + +#if (_MSC_VER >= 1000) + _osfile(fh) = fileflags; /* set osfile entry */ + _unlock_fhandle(fh); +#else + _osfile[fh] = fileflags; /* set osfile entry */ + _unlock(fh+_FH_LOCKS); /* unlock handle */ +#endif + + return fh; /* return handle */ } +#define _open_osfhandle my_open_osfhandle +#endif /* USE_FIXED_OSFHANDLE */ + +/* simulate flock by locking a range on the file */ -// Readdir just returns the current string pointer and bumps the -// string pointer to the nDllExport entry. -struct direct *readdir(DIR *dirp) +#define LK_ERR(f,i) ((f) ? (i = 0) : (errno = GetLastError())) +#define LK_LEN 0xffff0000 + +DllExport int +win32_flock(int fd, int oper) { - int len; - static int dummy = 0; + OVERLAPPED o; + int i = -1; + HANDLE fh; - if(dirp->curr) - { // first set up the structure to return - len = strlen(dirp->curr); - strcpy(dirp->dirstr.d_name, dirp->curr); - dirp->dirstr.d_namlen = len; + if (!IsWinNT()) { + croak("flock() unimplemented on this platform"); + return -1; + } + fh = (HANDLE)_get_osfhandle(fd); + memset(&o, 0, sizeof(o)); + + switch(oper) { + case LOCK_SH: /* shared lock */ + LK_ERR(LockFileEx(fh, 0, 0, LK_LEN, 0, &o),i); + break; + case LOCK_EX: /* exclusive lock */ + LK_ERR(LockFileEx(fh, LOCKFILE_EXCLUSIVE_LOCK, 0, LK_LEN, 0, &o),i); + break; + case LOCK_SH|LOCK_NB: /* non-blocking shared lock */ + LK_ERR(LockFileEx(fh, LOCKFILE_FAIL_IMMEDIATELY, 0, LK_LEN, 0, &o),i); + break; + case LOCK_EX|LOCK_NB: /* non-blocking exclusive lock */ + LK_ERR(LockFileEx(fh, + LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY, + 0, LK_LEN, 0, &o),i); + break; + case LOCK_UN: /* unlock lock */ + LK_ERR(UnlockFileEx(fh, 0, LK_LEN, 0, &o),i); + break; + default: /* unknown */ + errno = EINVAL; + break; + } + return i; +} + +#undef LK_ERR +#undef LK_LEN - // Fake an inode - dirp->dirstr.d_ino = dummy++; +/* + * redirected io subsystem for all XS modules + * + */ - // Now set up for the nDllExport call to readdir - dirp->curr += len + 1; - if(dirp->curr >= (dirp->start + dirp->size)) - { - dirp->curr = NULL; - } +DllExport int * +win32_errno(void) +{ + return (&errno); +} - return &(dirp->dirstr); - } - else - return NULL; +DllExport char *** +win32_environ(void) +{ + return (&(_environ)); } -// Telldir returns the current string pointer position -long telldir(DIR *dirp) +/* the rest are the remapped stdio routines */ +DllExport FILE * +win32_stderr(void) { - return (long) dirp->curr; + return (stderr); } +DllExport FILE * +win32_stdin(void) +{ + return (stdin); +} -// Seekdir moves the string pointer to a previously saved position (Saved by telldir). -void seekdir(DIR *dirp, long loc) +DllExport FILE * +win32_stdout() { - dirp->curr = (char *)loc; + return (stdout); } -// Rewinddir resets the string pointer to the start -void rewinddir(DIR *dirp) +DllExport int +win32_ferror(FILE *fp) { - dirp->curr = dirp->start; + return (ferror(fp)); } -// free the memory allocated by opendir -int closedir(DIR *dirp) + +DllExport int +win32_feof(FILE *fp) { - Safefree(dirp->start); - Safefree(dirp); - return 1; + return (feof(fp)); } +/* + * Since the errors returned by the socket error function + * WSAGetLastError() are not known by the library routine strerror + * we have to roll our own. + */ -// -// various stubs -// +DllExport char * +win32_strerror(int e) +{ +#ifndef __BORLANDC__ /* Borland intolerance */ + extern int sys_nerr; +#endif + DWORD source = 0; + if(e < 0 || e > sys_nerr) { + dTHR; + if(e < 0) + e = GetLastError(); -// Ownership -// -// Just pretend that everyone is a superuser. NT will let us know if -// we don\'t really have permission to do something. -// + if(FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, &source, e, 0, + strerror_buffer, sizeof(strerror_buffer), NULL) == 0) + strcpy(strerror_buffer, "Unknown Error"); -#define ROOT_UID ((uid_t)0) -#define ROOT_GID ((gid_t)0) + return strerror_buffer; + } + return strerror(e); +} -uid_t getuid(void) +DllExport void +win32_str_os_error(SV *sv, unsigned long dwErr) { - return ROOT_UID; + 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 = LocalAlloc(0, 64/**sizeof(TCHAR)*/); + dwLen = sprintf(sMsg, + "Unknown error #0x%lX (lookup 0x%lX)", + dwErr, GetLastError()); + } + sv_setpvn(sv, sMsg, dwLen); + LocalFree(sMsg); } -uid_t geteuid(void) + +DllExport int +win32_fprintf(FILE *fp, const char *format, ...) { - return ROOT_UID; + va_list marker; + va_start(marker, format); /* Initialize variable arguments. */ + + return (vfprintf(fp, format, marker)); } -gid_t getgid(void) +DllExport int +win32_printf(const char *format, ...) { - return ROOT_GID; + va_list marker; + va_start(marker, format); /* Initialize variable arguments. */ + + return (vprintf(format, marker)); } -gid_t getegid(void) +DllExport int +win32_vfprintf(FILE *fp, const char *format, va_list args) { - return ROOT_GID; + return (vfprintf(fp, format, args)); } -int setuid(uid_t uid) -{ - return (uid == ROOT_UID ? 0 : -1); +DllExport int +win32_vprintf(const char *format, va_list args) +{ + return (vprintf(format, args)); } -int setgid(gid_t gid) +DllExport size_t +win32_fread(void *buf, size_t size, size_t count, FILE *fp) { - return (gid == ROOT_GID ? 0 : -1); + return fread(buf, size, count, fp); } -// -// pretended kill -// -int kill(int pid, int sig) +DllExport size_t +win32_fwrite(const void *buf, size_t size, size_t count, FILE *fp) { - HANDLE hProcess= OpenProcess(PROCESS_ALL_ACCESS, TRUE, pid); + return fwrite(buf, size, count, fp); +} - if (hProcess == NULL) { - CROAK("kill process failed!\n"); - } - else { - if (!TerminateProcess(hProcess, sig)) CROAK("kill process failed!\n"); - CloseHandle(hProcess); - } - return 0; +DllExport FILE * +win32_fopen(const char *filename, const char *mode) +{ + if (stricmp(filename, "/dev/null")==0) + return fopen("NUL", mode); + return fopen(filename, mode); } - -// -// File system stuff -// -int ioctl(int i, unsigned int u, char *data) +#ifndef USE_SOCKETS_AS_HANDLES +#undef fdopen +#define fdopen my_fdopen +#endif + +DllExport FILE * +win32_fdopen( int handle, const char *mode) { - CROAK("ioctl not implemented!\n"); - return -1; + return fdopen(handle, (char *) mode); } -unsigned int sleep(unsigned int t) +DllExport FILE * +win32_freopen( const char *path, const char *mode, FILE *stream) { - Sleep(t*1000); - return 0; + if (stricmp(path, "/dev/null")==0) + return freopen("NUL", mode, stream); + return freopen(path, mode, stream); } +DllExport int +win32_fclose(FILE *pf) +{ + return my_fclose(pf); /* defined in win32sck.c */ +} -#undef rename +DllExport int +win32_fputs(const char *s,FILE *pf) +{ + return fputs(s, pf); +} -int myrename(char *OldFileName, char *newname) +DllExport int +win32_fputc(int c,FILE *pf) { - if(_access(newname, 0) != -1) - { // file exists - _unlink(newname); - } - return rename(OldFileName, newname); + return fputc(c,pf); } +DllExport int +win32_ungetc(int c,FILE *pf) +{ + return ungetc(c,pf); +} -int win32_stat(const char *path, struct stat *buffer) +DllExport int +win32_getc(FILE *pf) { - char t[MAX_PATH]; - const char *p = path; - int l = strlen(path); + return getc(pf); +} - if (l > 1) { - switch(path[l - 1]) { - case '\\': - case '/': - if (path[l - 2] != ':') { - strncpy(t, path, l - 1); - t[l - 1] = 0; - p = t; - }; - } - } +DllExport int +win32_fileno(FILE *pf) +{ + return fileno(pf); +} - return stat(p, buffer); +DllExport void +win32_clearerr(FILE *pf) +{ + clearerr(pf); + return; } -#undef times -int mytimes(struct tms *timebuf) +DllExport int +win32_fflush(FILE *pf) { - clock_t t = clock(); - timebuf->tms_utime = t; - timebuf->tms_stime = 0; - timebuf->tms_cutime = 0; - timebuf->tms_cstime = 0; + return fflush(pf); +} - return 0; +DllExport long +win32_ftell(FILE *pf) +{ + return ftell(pf); } -#undef alarm -unsigned int myalarm(unsigned int sec) +DllExport int +win32_fseek(FILE *pf,long offset,int origin) { - // we warn the usuage of alarm function - if (sec != 0) - WARN("dummy function alarm called, program might not function as expected\n"); - return 0; + return fseek(pf, offset, origin); } -// -// redirected io subsystem for all XS modules -// -// +DllExport int +win32_fgetpos(FILE *pf,fpos_t *p) +{ + return fgetpos(pf, p); +} -DllExport int * win32_errno(void) +DllExport int +win32_fsetpos(FILE *pf,const fpos_t *p) { - return (pIOSubSystem->pfnerrno()); + return fsetpos(pf, p); } -// the rest are the remapped stdio routines -DllExport FILE *win32_stderr(void) +DllExport void +win32_rewind(FILE *pf) { - return (pIOSubSystem->pfnstderr()); + rewind(pf); + return; } -DllExport FILE *win32_stdin(void) +DllExport FILE* +win32_tmpfile(void) { - return (pIOSubSystem->pfnstdin()); + return tmpfile(); } -DllExport FILE *win32_stdout() +DllExport void +win32_abort(void) { - return (pIOSubSystem->pfnstdout()); + abort(); + return; } -DllExport int win32_ferror(FILE *fp) +DllExport int +win32_fstat(int fd,struct stat *sbufptr) { - return (pIOSubSystem->pfnferror(fp)); + return fstat(fd,sbufptr); } +DllExport int +win32_pipe(int *pfd, unsigned int size, int mode) +{ + return _pipe(pfd, size, mode); +} -DllExport int win32_feof(FILE *fp) +DllExport FILE* +win32_popen(const char *command, const char *mode) { - return (pIOSubSystem->pfnfeof(fp)); + return _popen(command, mode); } -// -// Since the errors returned by the socket error function -// WSAGetLastError() are not known by the library routine strerror -// we have to roll our own. -// +DllExport int +win32_pclose(FILE *pf) +{ + return _pclose(pf); +} -__declspec(thread) char strerror_buffer[512]; +DllExport int +win32_setmode(int fd, int mode) +{ + return setmode(fd, mode); +} -DllExport char *win32_strerror(int e) +DllExport long +win32_lseek(int fd, long offset, int origin) { - extern int sys_nerr; - DWORD source = 0; + return lseek(fd, offset, origin); +} - if(e < 0 || e > sys_nerr) - { - if(e < 0) - e = GetLastError(); +DllExport long +win32_tell(int fd) +{ + return tell(fd); +} - if(FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, &source, e, 0, strerror_buffer, sizeof(strerror_buffer), NULL) == 0) - strcpy(strerror_buffer, "Unknown Error"); +DllExport int +win32_open(const char *path, int flag, ...) +{ + va_list ap; + int pmode; - return strerror_buffer; - } + va_start(ap, flag); + pmode = va_arg(ap, int); + va_end(ap); - return pIOSubSystem->pfnstrerror(e); + if (stricmp(path, "/dev/null")==0) + return open("NUL", flag, pmode); + return open(path,flag,pmode); } -DllExport int win32_fprintf(FILE *fp, const char *format, ...) +DllExport int +win32_close(int fd) { - va_list marker; - va_start(marker, format); /* Initialize variable arguments. */ + return close(fd); +} - return (pIOSubSystem->pfnvfprintf(fp, format, marker)); +DllExport int +win32_eof(int fd) +{ + return eof(fd); } -DllExport int win32_printf(const char *format, ...) +DllExport int +win32_dup(int fd) { - va_list marker; - va_start(marker, format); /* Initialize variable arguments. */ + return dup(fd); +} - return (pIOSubSystem->pfnvprintf(format, marker)); +DllExport int +win32_dup2(int fd1,int fd2) +{ + return dup2(fd1,fd2); } -DllExport int win32_vfprintf(FILE *fp, const char *format, va_list args) +DllExport int +win32_read(int fd, void *buf, unsigned int cnt) { - return (pIOSubSystem->pfnvfprintf(fp, format, args)); + return read(fd, buf, cnt); } -DllExport size_t win32_fread(void *buf, size_t size, size_t count, FILE *fp) +DllExport int +win32_write(int fd, const void *buf, unsigned int cnt) { - return pIOSubSystem->pfnfread(buf, size, count, fp); + return write(fd, buf, cnt); } -DllExport size_t win32_fwrite(const void *buf, size_t size, size_t count, FILE *fp) +DllExport int +win32_mkdir(const char *dir, int mode) { - return pIOSubSystem->pfnfwrite(buf, size, count, fp); + return mkdir(dir); /* just ignore mode */ } -DllExport FILE *win32_fopen(const char *filename, const char *mode) +DllExport int +win32_rmdir(const char *dir) { - if (stricmp(filename, "/dev/null")==0) return pIOSubSystem->pfnfopen("NUL", mode); - return pIOSubSystem->pfnfopen(filename, mode); + return rmdir(dir); } -DllExport FILE *win32_fdopen( int handle, const char *mode) +DllExport int +win32_chdir(const char *dir) { - return pIOSubSystem->pfnfdopen(handle, mode); + return chdir(dir); } -DllExport FILE *win32_freopen( const char *path, const char *mode, FILE *stream) +DllExport int +win32_spawnvp(int mode, const char *cmdname, const char *const *argv) { - if (stricmp(path, "/dev/null")==0) return pIOSubSystem->pfnfreopen("NUL", mode, stream); - return pIOSubSystem->pfnfreopen(path, mode, stream); + int status; + + status = spawnvp(mode, cmdname, (char * const *) argv); +#ifndef __BORLANDC__ + /* 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_fclose(FILE *pf) +DllExport int +win32_execvp(const char *cmdname, const char *const *argv) { - return pIOSubSystem->pfnfclose(pf); + return execvp(cmdname, (char *const *)argv); } -DllExport int win32_fputs(const char *s,FILE *pf) +DllExport void +win32_perror(const char *str) { - return pIOSubSystem->pfnfputs(s, pf); + perror(str); } -DllExport int win32_fputc(int c,FILE *pf) +DllExport void +win32_setbuf(FILE *pf, char *buf) { - return pIOSubSystem->pfnfputc(c,pf); + setbuf(pf, buf); } -DllExport int win32_ungetc(int c,FILE *pf) +DllExport int +win32_setvbuf(FILE *pf, char *buf, int type, size_t size) { - return pIOSubSystem->pfnungetc(c,pf); + return setvbuf(pf, buf, type, size); } -DllExport int win32_getc(FILE *pf) +DllExport int +win32_flushall(void) { - return pIOSubSystem->pfngetc(pf); + return flushall(); } -DllExport int win32_fileno(FILE *pf) +DllExport int +win32_fcloseall(void) { - return pIOSubSystem->pfnfileno(pf); + return fcloseall(); } -DllExport void win32_clearerr(FILE *pf) +DllExport char* +win32_fgets(char *s, int n, FILE *pf) { - pIOSubSystem->pfnclearerr(pf); - return; + return fgets(s, n, pf); } -DllExport int win32_fflush(FILE *pf) +DllExport char* +win32_gets(char *s) { - return pIOSubSystem->pfnfflush(pf); + return gets(s); } -DllExport long win32_ftell(FILE *pf) +DllExport int +win32_fgetc(FILE *pf) { - return pIOSubSystem->pfnftell(pf); + return fgetc(pf); } -DllExport int win32_fseek(FILE *pf,long offset,int origin) +DllExport int +win32_putc(int c, FILE *pf) { - return pIOSubSystem->pfnfseek(pf, offset, origin); + return putc(c,pf); } -DllExport int win32_fgetpos(FILE *pf,fpos_t *p) +DllExport int +win32_puts(const char *s) { - return pIOSubSystem->pfnfgetpos(pf, p); + return puts(s); } -DllExport int win32_fsetpos(FILE *pf,const fpos_t *p) +DllExport int +win32_getchar(void) { - return pIOSubSystem->pfnfsetpos(pf, p); + return getchar(); } -DllExport void win32_rewind(FILE *pf) +DllExport int +win32_putchar(int c) { - pIOSubSystem->pfnrewind(pf); - return; + return putchar(c); } -DllExport FILE* win32_tmpfile(void) +#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) { - return pIOSubSystem->pfntmpfile(); + 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; } -DllExport void win32_abort(void) +#endif +#endif + +DllExport void* +win32_malloc(size_t size) { - pIOSubSystem->pfnabort(); - return; + return malloc(size); } -DllExport int win32_fstat(int fd,struct stat *bufptr) +DllExport void* +win32_calloc(size_t numitems, size_t size) { - return pIOSubSystem->pfnfstat(fd,bufptr); + return calloc(numitems,size); } -DllExport int win32_pipe(int *pfd, unsigned int size, int mode) +DllExport void* +win32_realloc(void *block, size_t size) { - return pIOSubSystem->pfnpipe(pfd, size, mode); + return realloc(block,size); } -DllExport FILE* win32_popen(const char *command, const char *mode) +DllExport void +win32_free(void *block) { - return pIOSubSystem->pfnpopen(command, mode); + free(block); } -DllExport int win32_pclose(FILE *pf) + +int +win32_open_osfhandle(long handle, int flags) { - return pIOSubSystem->pfnpclose(pf); + return _open_osfhandle(handle, flags); } -DllExport int win32_setmode(int fd, int mode) +long +win32_get_osfhandle(int fd) { - return pIOSubSystem->pfnsetmode(fd, mode); + return _get_osfhandle(fd); +} + +/* + * Extras. + */ + +static +XS(w32_GetCwd) +{ + dXSARGS; + SV *sv = sv_newmortal(); + /* Make one call with zero size - return value is required size */ + DWORD len = GetCurrentDirectory((DWORD)0,NULL); + SvUPGRADE(sv,SVt_PV); + SvGROW(sv,len); + SvCUR(sv) = GetCurrentDirectory((DWORD) SvLEN(sv), SvPVX(sv)); + /* + * If result != 0 + * then it worked, set PV valid, + * else leave it 'undef' + */ + if (SvCUR(sv)) + SvPOK_on(sv); + EXTEND(sp,1); + ST(0) = sv; + XSRETURN(1); } -DllExport int win32_open(const char *path, int flag, ...) +static +XS(w32_SetCwd) { - va_list ap; - int pmode; + dXSARGS; + if (items != 1) + croak("usage: Win32::SetCurrentDirectory($cwd)"); + if (SetCurrentDirectory(SvPV(ST(0),na))) + XSRETURN_YES; - va_start(ap, flag); - pmode = va_arg(ap, int); - va_end(ap); + XSRETURN_NO; +} - if (stricmp(path, "/dev/null")==0) return pIOSubSystem->pfnopen("NUL", flag, pmode); - return pIOSubSystem->pfnopen(path,flag,pmode); +static +XS(w32_GetNextAvailDrive) +{ + dXSARGS; + char ix = 'C'; + char root[] = "_:\\"; + while (ix <= 'Z') { + root[0] = ix++; + if (GetDriveType(root) == 1) { + root[2] = '\0'; + XSRETURN_PV(root); + } + } + XSRETURN_UNDEF; } -DllExport int win32_close(int fd) +static +XS(w32_GetLastError) { - return pIOSubSystem->pfnclose(fd); + dXSARGS; + XSRETURN_IV(GetLastError()); } -DllExport int win32_dup(int fd) +static +XS(w32_LoginName) { - return pIOSubSystem->pfndup(fd); + dXSARGS; + char *name = getlogin_buffer; + DWORD size = sizeof(getlogin_buffer); + if (GetUserName(name,&size)) { + /* size includes NULL */ + ST(0) = sv_2mortal(newSVpv(name,size-1)); + XSRETURN(1); + } + XSRETURN_UNDEF; } -DllExport int win32_dup2(int fd1,int fd2) +static +XS(w32_NodeName) { - return pIOSubSystem->pfndup2(fd1,fd2); + dXSARGS; + char name[MAX_COMPUTERNAME_LENGTH+1]; + DWORD size = sizeof(name); + if (GetComputerName(name,&size)) { + /* size does NOT include NULL :-( */ + ST(0) = sv_2mortal(newSVpv(name,size)); + XSRETURN(1); + } + XSRETURN_UNDEF; } -DllExport int win32_read(int fd, char *buf, unsigned int cnt) + +static +XS(w32_DomainName) { - return pIOSubSystem->pfnread(fd, buf, cnt); + dXSARGS; + char name[256]; + DWORD size = sizeof(name); + if (GetUserName(name,&size)) { + char sid[1024]; + DWORD sidlen = sizeof(sid); + char dname[256]; + DWORD dnamelen = sizeof(dname); + SID_NAME_USE snu; + if (LookupAccountName(NULL, name, &sid, &sidlen, + dname, &dnamelen, &snu)) { + XSRETURN_PV(dname); /* all that for this */ + } + } + XSRETURN_UNDEF; +} + +static +XS(w32_FsType) +{ + dXSARGS; + char fsname[256]; + DWORD flags, filecomplen; + if (GetVolumeInformation(NULL, NULL, 0, NULL, &filecomplen, + &flags, fsname, sizeof(fsname))) { + if (GIMME == G_ARRAY) { + XPUSHs(sv_2mortal(newSVpv(fsname,0))); + XPUSHs(sv_2mortal(newSViv(flags))); + XPUSHs(sv_2mortal(newSViv(filecomplen))); + PUTBACK; + return; + } + XSRETURN_PV(fsname); + } + XSRETURN_UNDEF; } -DllExport int win32_write(int fd, const char *buf, unsigned int cnt) +static +XS(w32_GetOSVersion) { - return pIOSubSystem->pfnwrite(fd, buf, cnt); + dXSARGS; + OSVERSIONINFO osver; + + osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + if (GetVersionEx(&osver)) { + XPUSHs(newSVpv(osver.szCSDVersion, 0)); + XPUSHs(newSViv(osver.dwMajorVersion)); + XPUSHs(newSViv(osver.dwMinorVersion)); + XPUSHs(newSViv(osver.dwBuildNumber)); + XPUSHs(newSViv(osver.dwPlatformId)); + PUTBACK; + return; + } + XSRETURN_UNDEF; } -DllExport int win32_spawnvpe(int mode, const char *cmdname, const char *const *argv, const char *const *envp) +static +XS(w32_IsWinNT) { - return pIOSubSystem->pfnspawnvpe(mode, cmdname, argv, envp); + dXSARGS; + XSRETURN_IV(IsWinNT()); } -DllExport int win32_spawnle(int mode, const char *cmdname, const char *arglist,...) +static +XS(w32_IsWin95) { - const char* const* envp; - const char* const* argp; + dXSARGS; + XSRETURN_IV(IsWin95()); +} - argp = &arglist; - while (*argp++) ; +static +XS(w32_FormatMessage) +{ + dXSARGS; + DWORD source = 0; + char msgbuf[1024]; + + if (items != 1) + croak("usage: Win32::FormatMessage($errno)"); - return pIOSubSystem->pfnspawnvpe(mode, cmdname, &arglist, argp); + if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, + &source, SvIV(ST(0)), 0, + msgbuf, sizeof(msgbuf)-1, NULL)) + XSRETURN_PV(msgbuf); + + XSRETURN_UNDEF; +} + +static +XS(w32_Spawn) +{ + dXSARGS; + char *cmd, *args; + PROCESS_INFORMATION stProcInfo; + STARTUPINFO stStartInfo; + BOOL bSuccess = FALSE; + + if(items != 3) + croak("usage: Win32::Spawn($cmdName, $args, $PID)"); + + cmd = SvPV(ST(0),na); + args = SvPV(ST(1), 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( + cmd, /* Image path */ + args, /* Arguments for command line */ + NULL, /* Default process security */ + NULL, /* Default thread security */ + FALSE, /* Must be TRUE to use std handles */ + NORMAL_PRIORITY_CLASS, /* No special scheduling */ + NULL, /* Inherit our environment block */ + NULL, /* Inherit our currrent directory */ + &stStartInfo, /* -> Startup info */ + &stProcInfo)) /* <- Process info (if OK) */ + { + CloseHandle(stProcInfo.hThread);/* library source code does this. */ + sv_setiv(ST(2), stProcInfo.dwProcessId); + bSuccess = TRUE; + } + XSRETURN_IV(bSuccess); +} + +static +XS(w32_GetTickCount) +{ + dXSARGS; + XSRETURN_IV(GetTickCount()); +} + +static +XS(w32_GetShortPathName) +{ + dXSARGS; + SV *shortpath; + DWORD len; + + if(items != 1) + croak("usage: Win32::GetShortPathName($longPathName)"); + + shortpath = sv_mortalcopy(ST(0)); + SvUPGRADE(shortpath, SVt_PV); + /* src == target is allowed */ + do { + len = GetShortPathName(SvPVX(shortpath), + SvPVX(shortpath), + SvLEN(shortpath)); + } while (len >= SvLEN(shortpath) && sv_grow(shortpath,len+1)); + if (len) { + SvCUR_set(shortpath,len); + ST(0) = shortpath; + } + else + ST(0) = &sv_undef; + XSRETURN(1); +} + +void +Perl_init_os_extras() +{ + char *file = __FILE__; + dXSUB_SYS; + + /* XXX should be removed after checking with Nick */ + newXS("Win32::GetCurrentDirectory", w32_GetCwd, file); + + /* these names are Activeware compatible */ + newXS("Win32::GetCwd", w32_GetCwd, file); + newXS("Win32::SetCwd", w32_SetCwd, file); + newXS("Win32::GetNextAvailDrive", w32_GetNextAvailDrive, file); + newXS("Win32::GetLastError", w32_GetLastError, file); + newXS("Win32::LoginName", w32_LoginName, file); + newXS("Win32::NodeName", w32_NodeName, file); + newXS("Win32::DomainName", w32_DomainName, file); + newXS("Win32::FsType", w32_FsType, file); + newXS("Win32::GetOSVersion", w32_GetOSVersion, file); + newXS("Win32::IsWinNT", w32_IsWinNT, file); + newXS("Win32::IsWin95", w32_IsWin95, file); + newXS("Win32::FormatMessage", w32_FormatMessage, file); + newXS("Win32::Spawn", w32_Spawn, file); + newXS("Win32::GetTickCount", w32_GetTickCount, file); + newXS("Win32::GetShortPathName", w32_GetShortPathName, file); + + /* XXX Bloat Alert! The following Activeware preloads really + * ought to be part of Win32::Sys::*, so they're not included + * here. + */ + /* LookupAccountName + * LookupAccountSID + * InitiateSystemShutdown + * AbortSystemShutdown + * ExpandEnvrironmentStrings + */ } -int stolen_open_osfhandle(long handle, int flags) +void +Perl_win32_init(int *argcp, char ***argvp) { - return pIOSubSystem->pfn_open_osfhandle(handle, flags); + /* Disable floating point errors, Perl will trap the ones we + * care about. VC++ RTL defaults to switching these off + * already, but the Borland RTL doesn't. Since we don't + * want to be at the vendor's whim on the default, we set + * it explicitly here. + */ +#if !defined(_ALPHA_) && !defined(__GNUC__) + _control87(MCW_EM, MCW_EM); +#endif + MALLOC_INIT; } -long stolen_get_osfhandle(int fd) +#ifdef USE_BINMODE_SCRIPTS + +void +win32_strip_return(SV *sv) { - return pIOSubSystem->pfn_get_osfhandle(fd); + 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 + + + + + + + +