| /* | |
| * msvcrt.dll spawn/exec functions | |
| * | |
| * Copyright 1996,1998 Marcus Meissner | |
| * Copyright 1996 Jukka Iivonen | |
| * Copyright 1997,2000 Uwe Bonnes | |
| * Copyright 2000 Jon Griffiths | |
| * Copyright 2007 Hans Leidekker | |
| * | |
| * This library is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU Lesser General Public | |
| * License as published by the Free Software Foundation; either | |
| * version 2.1 of the License, or (at your option) any later version. | |
| * | |
| * This library is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| * Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; if not, write to the Free Software | |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | |
| * | |
| * FIXME: | |
| * -File handles need some special handling. Sometimes children get | |
| * open file handles, sometimes not. The docs are confusing | |
| * -No check for maximum path/argument/environment size is done | |
| */ | |
| #include "config.h" | |
| #include <stdarg.h> | |
| #include "msvcrt.h" | |
| #include "mtdll.h" | |
| #include "wine/debug.h" | |
| #include "wine/unicode.h" | |
| WINE_DEFAULT_DEBUG_CHANNEL(msvcrt); | |
| static void msvcrt_search_executable(const MSVCRT_wchar_t *name, MSVCRT_wchar_t *fullname, int use_path) | |
| { | |
| static const MSVCRT_wchar_t path[] = {'P','A','T','H',0}; | |
| static const MSVCRT_wchar_t suffix[][5] = | |
| {{'.','c','o','m',0}, {'.','e','x','e',0}, {'.','b','a','t',0}, {'.','c','m','d',0}}; | |
| MSVCRT_wchar_t buffer[MAX_PATH]; | |
| const MSVCRT_wchar_t *env, *p; | |
| unsigned int i, name_len, path_len; | |
| int extension = 1; | |
| *fullname = '\0'; | |
| msvcrt_set_errno(ERROR_FILE_NOT_FOUND); | |
| p = memchrW(name, '\0', MAX_PATH); | |
| if (!p) p = name + MAX_PATH - 1; | |
| name_len = p - name; | |
| /* FIXME extra-long names are silently truncated */ | |
| memcpy(buffer, name, name_len * sizeof(MSVCRT_wchar_t)); | |
| buffer[name_len] = '\0'; | |
| /* try current dir first */ | |
| if (GetFileAttributesW(buffer) != INVALID_FILE_ATTRIBUTES) | |
| { | |
| strcpyW(fullname, buffer); | |
| return; | |
| } | |
| for (p--; p >= name; p--) | |
| if (*p == '\\' || *p == '/' || *p == ':' || *p == '.') break; | |
| /* if there's no extension, try some well-known extensions */ | |
| if ((p < name || *p != '.') && name_len <= MAX_PATH - 5) | |
| { | |
| for (i = 0; i < 4; i++) | |
| { | |
| memcpy(buffer + name_len, suffix[i], 5 * sizeof(MSVCRT_wchar_t)); | |
| if (GetFileAttributesW(buffer) != INVALID_FILE_ATTRIBUTES) | |
| { | |
| strcpyW(fullname, buffer); | |
| return; | |
| } | |
| } | |
| extension = 0; | |
| } | |
| if (!use_path || !(env = MSVCRT__wgetenv(path))) return; | |
| /* now try search path */ | |
| do | |
| { | |
| p = env; | |
| while (*p && *p != ';') p++; | |
| if (p == env) return; | |
| path_len = p - env; | |
| if (path_len + name_len <= MAX_PATH - 2) | |
| { | |
| memcpy(buffer, env, path_len * sizeof(MSVCRT_wchar_t)); | |
| if (buffer[path_len] != '/' && buffer[path_len] != '\\') | |
| { | |
| buffer[path_len++] = '\\'; | |
| buffer[path_len] = '\0'; | |
| } | |
| else buffer[path_len] = '\0'; | |
| strcatW(buffer, name); | |
| if (GetFileAttributesW(buffer) != INVALID_FILE_ATTRIBUTES) | |
| { | |
| strcpyW(fullname, buffer); | |
| return; | |
| } | |
| } | |
| /* again, if there's no extension, try some well-known extensions */ | |
| if (!extension && path_len + name_len <= MAX_PATH - 5) | |
| { | |
| for (i = 0; i < 4; i++) | |
| { | |
| memcpy(buffer + path_len + name_len, suffix[i], 5 * sizeof(MSVCRT_wchar_t)); | |
| if (GetFileAttributesW(buffer) != INVALID_FILE_ATTRIBUTES) | |
| { | |
| strcpyW(fullname, buffer); | |
| return; | |
| } | |
| } | |
| } | |
| env = *p ? p + 1 : p; | |
| } while(1); | |
| } | |
| static MSVCRT_intptr_t msvcrt_spawn(int flags, const MSVCRT_wchar_t* exe, MSVCRT_wchar_t* cmdline, | |
| MSVCRT_wchar_t* env, int use_path) | |
| { | |
| STARTUPINFOW si; | |
| PROCESS_INFORMATION pi; | |
| MSVCRT_wchar_t fullname[MAX_PATH]; | |
| DWORD create_flags = CREATE_UNICODE_ENVIRONMENT; | |
| TRACE("%x %s %s %s %d\n", flags, debugstr_w(exe), debugstr_w(cmdline), debugstr_w(env), use_path); | |
| if ((unsigned)flags > MSVCRT__P_DETACH) | |
| { | |
| *MSVCRT__errno() = MSVCRT_EINVAL; | |
| return -1; | |
| } | |
| msvcrt_search_executable(exe, fullname, use_path); | |
| memset(&si, 0, sizeof(si)); | |
| si.cb = sizeof(si); | |
| msvcrt_create_io_inherit_block(&si.cbReserved2, &si.lpReserved2); | |
| if (flags == MSVCRT__P_DETACH) create_flags |= DETACHED_PROCESS; | |
| if (!CreateProcessW(fullname, cmdline, NULL, NULL, TRUE, | |
| create_flags, env, NULL, &si, &pi)) | |
| { | |
| msvcrt_set_errno(GetLastError()); | |
| MSVCRT_free(si.lpReserved2); | |
| return -1; | |
| } | |
| MSVCRT_free(si.lpReserved2); | |
| switch(flags) | |
| { | |
| case MSVCRT__P_WAIT: | |
| WaitForSingleObject(pi.hProcess, INFINITE); | |
| GetExitCodeProcess(pi.hProcess,&pi.dwProcessId); | |
| CloseHandle(pi.hProcess); | |
| CloseHandle(pi.hThread); | |
| return pi.dwProcessId; | |
| case MSVCRT__P_DETACH: | |
| CloseHandle(pi.hProcess); | |
| pi.hProcess = 0; | |
| /* fall through */ | |
| case MSVCRT__P_NOWAIT: | |
| case MSVCRT__P_NOWAITO: | |
| CloseHandle(pi.hThread); | |
| return (MSVCRT_intptr_t)pi.hProcess; | |
| case MSVCRT__P_OVERLAY: | |
| MSVCRT__exit(0); | |
| } | |
| return -1; /* can't reach here */ | |
| } | |
| /* INTERNAL: Convert wide argv list to a single 'delim'-separated wide string, with an | |
| * extra '\0' to terminate it. | |
| */ | |
| static MSVCRT_wchar_t* msvcrt_argvtos(const MSVCRT_wchar_t* const* arg, MSVCRT_wchar_t delim) | |
| { | |
| const MSVCRT_wchar_t* const* a; | |
| int size; | |
| MSVCRT_wchar_t* p; | |
| MSVCRT_wchar_t* ret; | |
| if (!arg) | |
| { | |
| /* Return NULL for an empty environment list */ | |
| return NULL; | |
| } | |
| /* get length */ | |
| a = arg; | |
| size = 0; | |
| while (*a) | |
| { | |
| size += strlenW(*a) + 1; | |
| a++; | |
| } | |
| ret = MSVCRT_malloc((size + 1) * sizeof(MSVCRT_wchar_t)); | |
| if (!ret) | |
| return NULL; | |
| /* fill string */ | |
| a = arg; | |
| p = ret; | |
| while (*a) | |
| { | |
| int len = strlenW(*a); | |
| memcpy(p,*a,len * sizeof(MSVCRT_wchar_t)); | |
| p += len; | |
| *p++ = delim; | |
| a++; | |
| } | |
| if (delim && p > ret) p[-1] = 0; | |
| else *p = 0; | |
| return ret; | |
| } | |
| /* INTERNAL: Convert ansi argv list to a single 'delim'-separated wide string, with an | |
| * extra '\0' to terminate it. | |
| */ | |
| static MSVCRT_wchar_t *msvcrt_argvtos_aw(const char * const *arg, MSVCRT_wchar_t delim) | |
| { | |
| const char * const *a; | |
| unsigned int len; | |
| MSVCRT_wchar_t *p, *ret; | |
| if (!arg) | |
| { | |
| /* Return NULL for an empty environment list */ | |
| return NULL; | |
| } | |
| /* get length */ | |
| a = arg; | |
| len = 0; | |
| while (*a) | |
| { | |
| len += MultiByteToWideChar(CP_ACP, 0, *a, -1, NULL, 0); | |
| a++; | |
| } | |
| ret = MSVCRT_malloc((len + 1) * sizeof(MSVCRT_wchar_t)); | |
| if (!ret) | |
| return NULL; | |
| /* fill string */ | |
| a = arg; | |
| p = ret; | |
| while (*a) | |
| { | |
| p += MultiByteToWideChar(CP_ACP, 0, *a, strlen(*a), p, len - (p - ret)); | |
| *p++ = delim; | |
| a++; | |
| } | |
| if (delim && p > ret) p[-1] = 0; | |
| else *p = 0; | |
| return ret; | |
| } | |
| /* INTERNAL: Convert wide va_list to a single 'delim'-separated wide string, with an | |
| * extra '\0' to terminate it. | |
| */ | |
| static MSVCRT_wchar_t *msvcrt_valisttos(const MSVCRT_wchar_t *arg0, __ms_va_list alist, MSVCRT_wchar_t delim) | |
| { | |
| unsigned int size = 0, pos = 0; | |
| const MSVCRT_wchar_t *arg; | |
| MSVCRT_wchar_t *new, *ret = NULL; | |
| for (arg = arg0; arg; arg = va_arg( alist, MSVCRT_wchar_t * )) | |
| { | |
| unsigned int len = strlenW( arg ) + 1; | |
| if (pos + len >= size) | |
| { | |
| size = max( 256, size * 2 ); | |
| size = max( size, pos + len + 1 ); | |
| if (!(new = MSVCRT_realloc( ret, size * sizeof(MSVCRT_wchar_t) ))) | |
| { | |
| MSVCRT_free( ret ); | |
| return NULL; | |
| } | |
| ret = new; | |
| } | |
| strcpyW( ret + pos, arg ); | |
| pos += len; | |
| ret[pos - 1] = delim; | |
| } | |
| if (pos) | |
| { | |
| if (delim) ret[pos - 1] = 0; | |
| else ret[pos] = 0; | |
| } | |
| return ret; | |
| } | |
| /* INTERNAL: Convert ansi va_list to a single 'delim'-separated wide string, with an | |
| * extra '\0' to terminate it. | |
| */ | |
| static MSVCRT_wchar_t *msvcrt_valisttos_aw(const char *arg0, __ms_va_list alist, MSVCRT_wchar_t delim) | |
| { | |
| unsigned int size = 0, pos = 0; | |
| const char *arg; | |
| MSVCRT_wchar_t *new, *ret = NULL; | |
| for (arg = arg0; arg; arg = va_arg( alist, char * )) | |
| { | |
| unsigned int len = MultiByteToWideChar( CP_ACP, 0, arg, -1, NULL, 0 ); | |
| if (pos + len >= size) | |
| { | |
| size = max( 256, size * 2 ); | |
| size = max( size, pos + len + 1 ); | |
| if (!(new = MSVCRT_realloc( ret, size * sizeof(MSVCRT_wchar_t) ))) | |
| { | |
| MSVCRT_free( ret ); | |
| return NULL; | |
| } | |
| ret = new; | |
| } | |
| pos += MultiByteToWideChar( CP_ACP, 0, arg, -1, ret + pos, size - pos ); | |
| ret[pos - 1] = delim; | |
| } | |
| if (pos) | |
| { | |
| if (delim) ret[pos - 1] = 0; | |
| else ret[pos] = 0; | |
| } | |
| return ret; | |
| } | |
| /* INTERNAL: retrieve COMSPEC environment variable */ | |
| static MSVCRT_wchar_t *msvcrt_get_comspec(void) | |
| { | |
| static const MSVCRT_wchar_t cmd[] = {'c','m','d',0}; | |
| static const MSVCRT_wchar_t comspec[] = {'C','O','M','S','P','E','C',0}; | |
| MSVCRT_wchar_t *ret; | |
| unsigned int len; | |
| if (!(len = GetEnvironmentVariableW(comspec, NULL, 0))) len = sizeof(cmd)/sizeof(MSVCRT_wchar_t); | |
| if ((ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(MSVCRT_wchar_t)))) | |
| { | |
| if (!GetEnvironmentVariableW(comspec, ret, len)) strcpyW(ret, cmd); | |
| } | |
| return ret; | |
| } | |
| /********************************************************************* | |
| * _cwait (MSVCRT.@) | |
| */ | |
| MSVCRT_intptr_t CDECL _cwait(int *status, MSVCRT_intptr_t pid, int action) | |
| { | |
| HANDLE hPid = (HANDLE)pid; | |
| int doserrno; | |
| if (!WaitForSingleObject(hPid, INFINITE)) | |
| { | |
| if (status) | |
| { | |
| DWORD stat; | |
| GetExitCodeProcess(hPid, &stat); | |
| *status = (int)stat; | |
| } | |
| return pid; | |
| } | |
| doserrno = GetLastError(); | |
| if (doserrno == ERROR_INVALID_HANDLE) | |
| { | |
| *MSVCRT__errno() = MSVCRT_ECHILD; | |
| *MSVCRT___doserrno() = doserrno; | |
| } | |
| else | |
| msvcrt_set_errno(doserrno); | |
| return status ? *status = -1 : -1; | |
| } | |
| /********************************************************************* | |
| * _wexecl (MSVCRT.@) | |
| * | |
| * Unicode version of _execl | |
| */ | |
| MSVCRT_intptr_t CDECL _wexecl(const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* arg0, ...) | |
| { | |
| __ms_va_list ap; | |
| MSVCRT_wchar_t *args; | |
| MSVCRT_intptr_t ret; | |
| __ms_va_start(ap, arg0); | |
| args = msvcrt_valisttos(arg0, ap, ' '); | |
| __ms_va_end(ap); | |
| ret = msvcrt_spawn(MSVCRT__P_OVERLAY, name, args, NULL, 0); | |
| MSVCRT_free(args); | |
| return ret; | |
| } | |
| /********************************************************************* | |
| * _execl (MSVCRT.@) | |
| * | |
| * Like on Windows, this function does not handle arguments with spaces | |
| * or double-quotes. | |
| */ | |
| MSVCRT_intptr_t CDECL _execl(const char* name, const char* arg0, ...) | |
| { | |
| __ms_va_list ap; | |
| MSVCRT_wchar_t *nameW, *args; | |
| MSVCRT_intptr_t ret; | |
| if (!(nameW = msvcrt_wstrdupa(name))) return -1; | |
| __ms_va_start(ap, arg0); | |
| args = msvcrt_valisttos_aw(arg0, ap, ' '); | |
| __ms_va_end(ap); | |
| ret = msvcrt_spawn(MSVCRT__P_OVERLAY, nameW, args, NULL, 0); | |
| MSVCRT_free(nameW); | |
| MSVCRT_free(args); | |
| return ret; | |
| } | |
| /********************************************************************* | |
| * _wexecle (MSVCRT.@) | |
| * | |
| * Unicode version of _execle | |
| */ | |
| MSVCRT_intptr_t CDECL _wexecle(const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* arg0, ...) | |
| { | |
| __ms_va_list ap; | |
| MSVCRT_wchar_t *args, *envs = NULL; | |
| const MSVCRT_wchar_t * const *envp; | |
| MSVCRT_intptr_t ret; | |
| __ms_va_start(ap, arg0); | |
| args = msvcrt_valisttos(arg0, ap, ' '); | |
| __ms_va_end(ap); | |
| __ms_va_start(ap, arg0); | |
| while (va_arg( ap, MSVCRT_wchar_t * ) != NULL) /*nothing*/; | |
| envp = va_arg( ap, const MSVCRT_wchar_t * const * ); | |
| if (envp) envs = msvcrt_argvtos(envp, 0); | |
| __ms_va_end(ap); | |
| ret = msvcrt_spawn(MSVCRT__P_OVERLAY, name, args, envs, 0); | |
| MSVCRT_free(args); | |
| MSVCRT_free(envs); | |
| return ret; | |
| } | |
| /********************************************************************* | |
| * _execle (MSVCRT.@) | |
| */ | |
| MSVCRT_intptr_t CDECL _execle(const char* name, const char* arg0, ...) | |
| { | |
| __ms_va_list ap; | |
| MSVCRT_wchar_t *nameW, *args, *envs = NULL; | |
| const char * const *envp; | |
| MSVCRT_intptr_t ret; | |
| if (!(nameW = msvcrt_wstrdupa(name))) return -1; | |
| __ms_va_start(ap, arg0); | |
| args = msvcrt_valisttos_aw(arg0, ap, ' '); | |
| __ms_va_end(ap); | |
| __ms_va_start(ap, arg0); | |
| while (va_arg( ap, char * ) != NULL) /*nothing*/; | |
| envp = va_arg( ap, const char * const * ); | |
| if (envp) envs = msvcrt_argvtos_aw(envp, 0); | |
| __ms_va_end(ap); | |
| ret = msvcrt_spawn(MSVCRT__P_OVERLAY, nameW, args, envs, 0); | |
| MSVCRT_free(nameW); | |
| MSVCRT_free(args); | |
| MSVCRT_free(envs); | |
| return ret; | |
| } | |
| /********************************************************************* | |
| * _wexeclp (MSVCRT.@) | |
| * | |
| * Unicode version of _execlp | |
| */ | |
| MSVCRT_intptr_t CDECL _wexeclp(const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* arg0, ...) | |
| { | |
| __ms_va_list ap; | |
| MSVCRT_wchar_t *args; | |
| MSVCRT_intptr_t ret; | |
| __ms_va_start(ap, arg0); | |
| args = msvcrt_valisttos(arg0, ap, ' '); | |
| __ms_va_end(ap); | |
| ret = msvcrt_spawn(MSVCRT__P_OVERLAY, name, args, NULL, 1); | |
| MSVCRT_free(args); | |
| return ret; | |
| } | |
| /********************************************************************* | |
| * _execlp (MSVCRT.@) | |
| * | |
| * Like on Windows, this function does not handle arguments with spaces | |
| * or double-quotes. | |
| */ | |
| MSVCRT_intptr_t CDECL _execlp(const char* name, const char* arg0, ...) | |
| { | |
| __ms_va_list ap; | |
| MSVCRT_wchar_t *nameW, *args; | |
| MSVCRT_intptr_t ret; | |
| if (!(nameW = msvcrt_wstrdupa(name))) return -1; | |
| __ms_va_start(ap, arg0); | |
| args = msvcrt_valisttos_aw(arg0, ap, ' '); | |
| __ms_va_end(ap); | |
| ret = msvcrt_spawn(MSVCRT__P_OVERLAY, nameW, args, NULL, 1); | |
| MSVCRT_free(nameW); | |
| MSVCRT_free(args); | |
| return ret; | |
| } | |
| /********************************************************************* | |
| * _wexeclpe (MSVCRT.@) | |
| * | |
| * Unicode version of _execlpe | |
| */ | |
| MSVCRT_intptr_t CDECL _wexeclpe(const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* arg0, ...) | |
| { | |
| __ms_va_list ap; | |
| MSVCRT_wchar_t *args, *envs = NULL; | |
| const MSVCRT_wchar_t * const *envp; | |
| MSVCRT_intptr_t ret; | |
| __ms_va_start(ap, arg0); | |
| args = msvcrt_valisttos(arg0, ap, ' '); | |
| __ms_va_end(ap); | |
| __ms_va_start(ap, arg0); | |
| while (va_arg( ap, MSVCRT_wchar_t * ) != NULL) /*nothing*/; | |
| envp = va_arg( ap, const MSVCRT_wchar_t * const * ); | |
| if (envp) envs = msvcrt_argvtos(envp, 0); | |
| __ms_va_end(ap); | |
| ret = msvcrt_spawn(MSVCRT__P_OVERLAY, name, args, envs, 1); | |
| MSVCRT_free(args); | |
| MSVCRT_free(envs); | |
| return ret; | |
| } | |
| /********************************************************************* | |
| * _execlpe (MSVCRT.@) | |
| */ | |
| MSVCRT_intptr_t CDECL _execlpe(const char* name, const char* arg0, ...) | |
| { | |
| __ms_va_list ap; | |
| MSVCRT_wchar_t *nameW, *args, *envs = NULL; | |
| const char * const *envp; | |
| MSVCRT_intptr_t ret; | |
| if (!(nameW = msvcrt_wstrdupa(name))) return -1; | |
| __ms_va_start(ap, arg0); | |
| args = msvcrt_valisttos_aw(arg0, ap, ' '); | |
| __ms_va_end(ap); | |
| __ms_va_start(ap, arg0); | |
| while (va_arg( ap, char * ) != NULL) /*nothing*/; | |
| envp = va_arg( ap, const char * const * ); | |
| if (envp) envs = msvcrt_argvtos_aw(envp, 0); | |
| __ms_va_end(ap); | |
| ret = msvcrt_spawn(MSVCRT__P_OVERLAY, nameW, args, envs, 1); | |
| MSVCRT_free(nameW); | |
| MSVCRT_free(args); | |
| MSVCRT_free(envs); | |
| return ret; | |
| } | |
| /********************************************************************* | |
| * _wexecv (MSVCRT.@) | |
| * | |
| * Unicode version of _execv | |
| */ | |
| MSVCRT_intptr_t CDECL _wexecv(const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* const* argv) | |
| { | |
| return MSVCRT__wspawnve(MSVCRT__P_OVERLAY, name, argv, NULL); | |
| } | |
| /********************************************************************* | |
| * _execv (MSVCRT.@) | |
| * | |
| * Like on Windows, this function does not handle arguments with spaces | |
| * or double-quotes. | |
| */ | |
| MSVCRT_intptr_t CDECL _execv(const char* name, const char* const* argv) | |
| { | |
| return MSVCRT__spawnve(MSVCRT__P_OVERLAY, name, argv, NULL); | |
| } | |
| /********************************************************************* | |
| * _wexecve (MSVCRT.@) | |
| * | |
| * Unicode version of _execve | |
| */ | |
| MSVCRT_intptr_t CDECL _wexecve(const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* const* argv, const MSVCRT_wchar_t* const* envv) | |
| { | |
| return MSVCRT__wspawnve(MSVCRT__P_OVERLAY, name, argv, envv); | |
| } | |
| /********************************************************************* | |
| * _execve (MSVCRT.@) | |
| * | |
| * Like on Windows, this function does not handle arguments with spaces | |
| * or double-quotes. | |
| */ | |
| MSVCRT_intptr_t CDECL MSVCRT__execve(const char* name, const char* const* argv, const char* const* envv) | |
| { | |
| return MSVCRT__spawnve(MSVCRT__P_OVERLAY, name, argv, envv); | |
| } | |
| /********************************************************************* | |
| * _wexecvpe (MSVCRT.@) | |
| * | |
| * Unicode version of _execvpe | |
| */ | |
| MSVCRT_intptr_t CDECL _wexecvpe(const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* const* argv, const MSVCRT_wchar_t* const* envv) | |
| { | |
| return MSVCRT__wspawnvpe(MSVCRT__P_OVERLAY, name, argv, envv); | |
| } | |
| /********************************************************************* | |
| * _execvpe (MSVCRT.@) | |
| * | |
| * Like on Windows, this function does not handle arguments with spaces | |
| * or double-quotes. | |
| */ | |
| MSVCRT_intptr_t CDECL _execvpe(const char* name, const char* const* argv, const char* const* envv) | |
| { | |
| return MSVCRT__spawnvpe(MSVCRT__P_OVERLAY, name, argv, envv); | |
| } | |
| /********************************************************************* | |
| * _wexecvp (MSVCRT.@) | |
| * | |
| * Unicode version of _execvp | |
| */ | |
| MSVCRT_intptr_t CDECL _wexecvp(const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* const* argv) | |
| { | |
| return _wexecvpe(name, argv, NULL); | |
| } | |
| /********************************************************************* | |
| * _execvp (MSVCRT.@) | |
| * | |
| * Like on Windows, this function does not handle arguments with spaces | |
| * or double-quotes. | |
| */ | |
| MSVCRT_intptr_t CDECL _execvp(const char* name, const char* const* argv) | |
| { | |
| return _execvpe(name, argv, NULL); | |
| } | |
| /********************************************************************* | |
| * _wspawnl (MSVCRT.@) | |
| * | |
| * Unicode version of _spawnl | |
| */ | |
| MSVCRT_intptr_t CDECL _wspawnl(int flags, const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* arg0, ...) | |
| { | |
| __ms_va_list ap; | |
| MSVCRT_wchar_t *args; | |
| MSVCRT_intptr_t ret; | |
| __ms_va_start(ap, arg0); | |
| args = msvcrt_valisttos(arg0, ap, ' '); | |
| __ms_va_end(ap); | |
| ret = msvcrt_spawn(flags, name, args, NULL, 0); | |
| MSVCRT_free(args); | |
| return ret; | |
| } | |
| /********************************************************************* | |
| * _spawnl (MSVCRT.@) | |
| * | |
| * Like on Windows, this function does not handle arguments with spaces | |
| * or double-quotes. | |
| */ | |
| MSVCRT_intptr_t CDECL _spawnl(int flags, const char* name, const char* arg0, ...) | |
| { | |
| __ms_va_list ap; | |
| MSVCRT_wchar_t *nameW, *args; | |
| MSVCRT_intptr_t ret; | |
| if (!(nameW = msvcrt_wstrdupa(name))) return -1; | |
| __ms_va_start(ap, arg0); | |
| args = msvcrt_valisttos_aw(arg0, ap, ' '); | |
| __ms_va_end(ap); | |
| ret = msvcrt_spawn(flags, nameW, args, NULL, 0); | |
| MSVCRT_free(nameW); | |
| MSVCRT_free(args); | |
| return ret; | |
| } | |
| /********************************************************************* | |
| * _wspawnle (MSVCRT.@) | |
| * | |
| * Unicode version of _spawnle | |
| */ | |
| MSVCRT_intptr_t CDECL _wspawnle(int flags, const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* arg0, ...) | |
| { | |
| __ms_va_list ap; | |
| MSVCRT_wchar_t *args, *envs = NULL; | |
| const MSVCRT_wchar_t * const *envp; | |
| MSVCRT_intptr_t ret; | |
| __ms_va_start(ap, arg0); | |
| args = msvcrt_valisttos(arg0, ap, ' '); | |
| __ms_va_end(ap); | |
| __ms_va_start(ap, arg0); | |
| while (va_arg( ap, MSVCRT_wchar_t * ) != NULL) /*nothing*/; | |
| envp = va_arg( ap, const MSVCRT_wchar_t * const * ); | |
| if (envp) envs = msvcrt_argvtos(envp, 0); | |
| __ms_va_end(ap); | |
| ret = msvcrt_spawn(flags, name, args, envs, 0); | |
| MSVCRT_free(args); | |
| MSVCRT_free(envs); | |
| return ret; | |
| } | |
| /********************************************************************* | |
| * _spawnle (MSVCRT.@) | |
| */ | |
| MSVCRT_intptr_t CDECL _spawnle(int flags, const char* name, const char* arg0, ...) | |
| { | |
| __ms_va_list ap; | |
| MSVCRT_wchar_t *nameW, *args, *envs = NULL; | |
| const char * const *envp; | |
| MSVCRT_intptr_t ret; | |
| if (!(nameW = msvcrt_wstrdupa(name))) return -1; | |
| __ms_va_start(ap, arg0); | |
| args = msvcrt_valisttos_aw(arg0, ap, ' '); | |
| __ms_va_end(ap); | |
| __ms_va_start(ap, arg0); | |
| while (va_arg( ap, char * ) != NULL) /*nothing*/; | |
| envp = va_arg( ap, const char * const * ); | |
| if (envp) envs = msvcrt_argvtos_aw(envp, 0); | |
| __ms_va_end(ap); | |
| ret = msvcrt_spawn(flags, nameW, args, envs, 0); | |
| MSVCRT_free(nameW); | |
| MSVCRT_free(args); | |
| MSVCRT_free(envs); | |
| return ret; | |
| } | |
| /********************************************************************* | |
| * _wspawnlp (MSVCRT.@) | |
| * | |
| * Unicode version of _spawnlp | |
| */ | |
| MSVCRT_intptr_t CDECL _wspawnlp(int flags, const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* arg0, ...) | |
| { | |
| __ms_va_list ap; | |
| MSVCRT_wchar_t *args; | |
| MSVCRT_intptr_t ret; | |
| __ms_va_start(ap, arg0); | |
| args = msvcrt_valisttos(arg0, ap, ' '); | |
| __ms_va_end(ap); | |
| ret = msvcrt_spawn(flags, name, args, NULL, 1); | |
| MSVCRT_free(args); | |
| return ret; | |
| } | |
| /********************************************************************* | |
| * _spawnlp (MSVCRT.@) | |
| * | |
| * Like on Windows, this function does not handle arguments with spaces | |
| * or double-quotes. | |
| */ | |
| MSVCRT_intptr_t CDECL _spawnlp(int flags, const char* name, const char* arg0, ...) | |
| { | |
| __ms_va_list ap; | |
| MSVCRT_wchar_t *nameW, *args; | |
| MSVCRT_intptr_t ret; | |
| if (!(nameW = msvcrt_wstrdupa(name))) return -1; | |
| __ms_va_start(ap, arg0); | |
| args = msvcrt_valisttos_aw(arg0, ap, ' '); | |
| __ms_va_end(ap); | |
| ret = msvcrt_spawn(flags, nameW, args, NULL, 1); | |
| MSVCRT_free(nameW); | |
| MSVCRT_free(args); | |
| return ret; | |
| } | |
| /********************************************************************* | |
| * _wspawnlpe (MSVCRT.@) | |
| * | |
| * Unicode version of _spawnlpe | |
| */ | |
| MSVCRT_intptr_t CDECL _wspawnlpe(int flags, const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* arg0, ...) | |
| { | |
| __ms_va_list ap; | |
| MSVCRT_wchar_t *args, *envs = NULL; | |
| const MSVCRT_wchar_t * const *envp; | |
| MSVCRT_intptr_t ret; | |
| __ms_va_start(ap, arg0); | |
| args = msvcrt_valisttos(arg0, ap, ' '); | |
| __ms_va_end(ap); | |
| __ms_va_start(ap, arg0); | |
| while (va_arg( ap, MSVCRT_wchar_t * ) != NULL) /*nothing*/; | |
| envp = va_arg( ap, const MSVCRT_wchar_t * const * ); | |
| if (envp) envs = msvcrt_argvtos(envp, 0); | |
| __ms_va_end(ap); | |
| ret = msvcrt_spawn(flags, name, args, envs, 1); | |
| MSVCRT_free(args); | |
| MSVCRT_free(envs); | |
| return ret; | |
| } | |
| /********************************************************************* | |
| * _spawnlpe (MSVCRT.@) | |
| */ | |
| MSVCRT_intptr_t CDECL _spawnlpe(int flags, const char* name, const char* arg0, ...) | |
| { | |
| __ms_va_list ap; | |
| MSVCRT_wchar_t *nameW, *args, *envs = NULL; | |
| const char * const *envp; | |
| MSVCRT_intptr_t ret; | |
| if (!(nameW = msvcrt_wstrdupa(name))) return -1; | |
| __ms_va_start(ap, arg0); | |
| args = msvcrt_valisttos_aw(arg0, ap, ' '); | |
| __ms_va_end(ap); | |
| __ms_va_start(ap, arg0); | |
| while (va_arg( ap, char * ) != NULL) /*nothing*/; | |
| envp = va_arg( ap, const char * const * ); | |
| if (envp) envs = msvcrt_argvtos_aw(envp, 0); | |
| __ms_va_end(ap); | |
| ret = msvcrt_spawn(flags, nameW, args, envs, 1); | |
| MSVCRT_free(nameW); | |
| MSVCRT_free(args); | |
| MSVCRT_free(envs); | |
| return ret; | |
| } | |
| /********************************************************************* | |
| * _spawnve (MSVCRT.@) | |
| * | |
| * Like on Windows, this function does not handle arguments with spaces | |
| * or double-quotes. | |
| */ | |
| MSVCRT_intptr_t CDECL MSVCRT__spawnve(int flags, const char* name, const char* const* argv, | |
| const char* const* envv) | |
| { | |
| MSVCRT_wchar_t *nameW, *args, *envs; | |
| MSVCRT_intptr_t ret; | |
| if (!(nameW = msvcrt_wstrdupa(name))) return -1; | |
| args = msvcrt_argvtos_aw(argv, ' '); | |
| envs = msvcrt_argvtos_aw(envv, 0); | |
| ret = msvcrt_spawn(flags, nameW, args, envs, 0); | |
| MSVCRT_free(nameW); | |
| MSVCRT_free(args); | |
| MSVCRT_free(envs); | |
| return ret; | |
| } | |
| /********************************************************************* | |
| * _wspawnve (MSVCRT.@) | |
| * | |
| * Unicode version of _spawnve | |
| */ | |
| MSVCRT_intptr_t CDECL MSVCRT__wspawnve(int flags, const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* const* argv, | |
| const MSVCRT_wchar_t* const* envv) | |
| { | |
| MSVCRT_wchar_t *args, *envs; | |
| MSVCRT_intptr_t ret; | |
| args = msvcrt_argvtos(argv, ' '); | |
| envs = msvcrt_argvtos(envv, 0); | |
| ret = msvcrt_spawn(flags, name, args, envs, 0); | |
| MSVCRT_free(args); | |
| MSVCRT_free(envs); | |
| return ret; | |
| } | |
| /********************************************************************* | |
| * _spawnv (MSVCRT.@) | |
| * | |
| * Like on Windows, this function does not handle arguments with spaces | |
| * or double-quotes. | |
| */ | |
| MSVCRT_intptr_t CDECL _spawnv(int flags, const char* name, const char* const* argv) | |
| { | |
| return MSVCRT__spawnve(flags, name, argv, NULL); | |
| } | |
| /********************************************************************* | |
| * _wspawnv (MSVCRT.@) | |
| * | |
| * Unicode version of _spawnv | |
| */ | |
| MSVCRT_intptr_t CDECL _wspawnv(int flags, const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* const* argv) | |
| { | |
| return MSVCRT__wspawnve(flags, name, argv, NULL); | |
| } | |
| /********************************************************************* | |
| * _spawnvpe (MSVCRT.@) | |
| * | |
| * Like on Windows, this function does not handle arguments with spaces | |
| * or double-quotes. | |
| */ | |
| MSVCRT_intptr_t CDECL MSVCRT__spawnvpe(int flags, const char* name, const char* const* argv, | |
| const char* const* envv) | |
| { | |
| MSVCRT_wchar_t *nameW, *args, *envs; | |
| MSVCRT_intptr_t ret; | |
| if (!(nameW = msvcrt_wstrdupa(name))) return -1; | |
| args = msvcrt_argvtos_aw(argv, ' '); | |
| envs = msvcrt_argvtos_aw(envv, 0); | |
| ret = msvcrt_spawn(flags, nameW, args, envs, 1); | |
| MSVCRT_free(nameW); | |
| MSVCRT_free(args); | |
| MSVCRT_free(envs); | |
| return ret; | |
| } | |
| /********************************************************************* | |
| * _wspawnvpe (MSVCRT.@) | |
| * | |
| * Unicode version of _spawnvpe | |
| */ | |
| MSVCRT_intptr_t CDECL MSVCRT__wspawnvpe(int flags, const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* const* argv, | |
| const MSVCRT_wchar_t* const* envv) | |
| { | |
| MSVCRT_wchar_t *args, *envs; | |
| MSVCRT_intptr_t ret; | |
| args = msvcrt_argvtos(argv, ' '); | |
| envs = msvcrt_argvtos(envv, 0); | |
| ret = msvcrt_spawn(flags, name, args, envs, 1); | |
| MSVCRT_free(args); | |
| MSVCRT_free(envs); | |
| return ret; | |
| } | |
| /********************************************************************* | |
| * _spawnvp (MSVCRT.@) | |
| * | |
| * Like on Windows, this function does not handle arguments with spaces | |
| * or double-quotes. | |
| */ | |
| MSVCRT_intptr_t CDECL _spawnvp(int flags, const char* name, const char* const* argv) | |
| { | |
| return MSVCRT__spawnvpe(flags, name, argv, NULL); | |
| } | |
| /********************************************************************* | |
| * _wspawnvp (MSVCRT.@) | |
| * | |
| * Unicode version of _spawnvp | |
| */ | |
| MSVCRT_intptr_t CDECL _wspawnvp(int flags, const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* const* argv) | |
| { | |
| return MSVCRT__wspawnvpe(flags, name, argv, NULL); | |
| } | |
| static struct popen_handle { | |
| MSVCRT_FILE *f; | |
| HANDLE proc; | |
| } *popen_handles; | |
| static DWORD popen_handles_size; | |
| void msvcrt_free_popen_data(void) | |
| { | |
| MSVCRT_free(popen_handles); | |
| } | |
| /********************************************************************* | |
| * _wpopen (MSVCRT.@) | |
| * | |
| * Unicode version of _popen | |
| */ | |
| MSVCRT_FILE* CDECL MSVCRT__wpopen(const MSVCRT_wchar_t* command, const MSVCRT_wchar_t* mode) | |
| { | |
| MSVCRT_FILE *ret; | |
| BOOL readPipe = TRUE; | |
| int textmode, fds[2], fdToDup, fdToOpen, fdStdHandle = -1; | |
| const MSVCRT_wchar_t *p; | |
| MSVCRT_wchar_t *comspec, *fullcmd; | |
| unsigned int len; | |
| static const MSVCRT_wchar_t flag[] = {' ','/','c',' ',0}; | |
| struct popen_handle *container; | |
| DWORD i; | |
| TRACE("(command=%s, mode=%s)\n", debugstr_w(command), debugstr_w(mode)); | |
| if (!command || !mode) | |
| return NULL; | |
| textmode = *__p__fmode() & (MSVCRT__O_BINARY | MSVCRT__O_TEXT); | |
| for (p = mode; *p; p++) | |
| { | |
| switch (*p) | |
| { | |
| case 'W': | |
| case 'w': | |
| readPipe = FALSE; | |
| break; | |
| case 'B': | |
| case 'b': | |
| textmode |= MSVCRT__O_BINARY; | |
| textmode &= ~MSVCRT__O_TEXT; | |
| break; | |
| case 'T': | |
| case 't': | |
| textmode |= MSVCRT__O_TEXT; | |
| textmode &= ~MSVCRT__O_BINARY; | |
| break; | |
| } | |
| } | |
| if (MSVCRT__pipe(fds, 0, textmode) == -1) | |
| return NULL; | |
| fdToDup = readPipe ? 1 : 0; | |
| fdToOpen = readPipe ? 0 : 1; | |
| _mlock(_POPEN_LOCK); | |
| for(i=0; i<popen_handles_size; i++) | |
| { | |
| if (!popen_handles[i].f) | |
| break; | |
| } | |
| if (i==popen_handles_size) | |
| { | |
| i = (popen_handles_size ? popen_handles_size*2 : 8); | |
| container = MSVCRT_realloc(popen_handles, i*sizeof(*container)); | |
| if (!container) goto error; | |
| popen_handles = container; | |
| container = popen_handles+popen_handles_size; | |
| memset(container, 0, (i-popen_handles_size)*sizeof(*container)); | |
| popen_handles_size = i; | |
| } | |
| else container = popen_handles+i; | |
| if ((fdStdHandle = MSVCRT__dup(fdToDup)) == -1) | |
| goto error; | |
| if (MSVCRT__dup2(fds[fdToDup], fdToDup) != 0) | |
| goto error; | |
| MSVCRT__close(fds[fdToDup]); | |
| if (!(comspec = msvcrt_get_comspec())) goto error; | |
| len = strlenW(comspec) + strlenW(flag) + strlenW(command) + 1; | |
| if (!(fullcmd = HeapAlloc(GetProcessHeap(), 0, len * sizeof(MSVCRT_wchar_t)))) | |
| { | |
| HeapFree(GetProcessHeap(), 0, comspec); | |
| goto error; | |
| } | |
| strcpyW(fullcmd, comspec); | |
| strcatW(fullcmd, flag); | |
| strcatW(fullcmd, command); | |
| if ((container->proc = (HANDLE)msvcrt_spawn(MSVCRT__P_NOWAIT, comspec, fullcmd, NULL, 1)) | |
| == INVALID_HANDLE_VALUE) | |
| { | |
| MSVCRT__close(fds[fdToOpen]); | |
| ret = NULL; | |
| } | |
| else | |
| { | |
| ret = MSVCRT__wfdopen(fds[fdToOpen], mode); | |
| if (!ret) | |
| MSVCRT__close(fds[fdToOpen]); | |
| container->f = ret; | |
| } | |
| _munlock(_POPEN_LOCK); | |
| HeapFree(GetProcessHeap(), 0, comspec); | |
| HeapFree(GetProcessHeap(), 0, fullcmd); | |
| MSVCRT__dup2(fdStdHandle, fdToDup); | |
| MSVCRT__close(fdStdHandle); | |
| return ret; | |
| error: | |
| _munlock(_POPEN_LOCK); | |
| if (fdStdHandle != -1) MSVCRT__close(fdStdHandle); | |
| MSVCRT__close(fds[0]); | |
| MSVCRT__close(fds[1]); | |
| return NULL; | |
| } | |
| /********************************************************************* | |
| * _popen (MSVCRT.@) | |
| */ | |
| MSVCRT_FILE* CDECL MSVCRT__popen(const char* command, const char* mode) | |
| { | |
| MSVCRT_FILE *ret; | |
| MSVCRT_wchar_t *cmdW, *modeW; | |
| TRACE("(command=%s, mode=%s)\n", debugstr_a(command), debugstr_a(mode)); | |
| if (!command || !mode) | |
| return NULL; | |
| if (!(cmdW = msvcrt_wstrdupa(command))) return NULL; | |
| if (!(modeW = msvcrt_wstrdupa(mode))) | |
| { | |
| HeapFree(GetProcessHeap(), 0, cmdW); | |
| return NULL; | |
| } | |
| ret = MSVCRT__wpopen(cmdW, modeW); | |
| HeapFree(GetProcessHeap(), 0, cmdW); | |
| HeapFree(GetProcessHeap(), 0, modeW); | |
| return ret; | |
| } | |
| /********************************************************************* | |
| * _pclose (MSVCRT.@) | |
| */ | |
| int CDECL MSVCRT__pclose(MSVCRT_FILE* file) | |
| { | |
| HANDLE h; | |
| DWORD i; | |
| if (!MSVCRT_CHECK_PMT(file != NULL)) return -1; | |
| _mlock(_POPEN_LOCK); | |
| for(i=0; i<popen_handles_size; i++) | |
| { | |
| if (popen_handles[i].f == file) | |
| break; | |
| } | |
| if(i == popen_handles_size) | |
| { | |
| _munlock(_POPEN_LOCK); | |
| *MSVCRT__errno() = MSVCRT_EBADF; | |
| return -1; | |
| } | |
| h = popen_handles[i].proc; | |
| popen_handles[i].f = NULL; | |
| _munlock(_POPEN_LOCK); | |
| MSVCRT_fclose(file); | |
| if(WaitForSingleObject(h, INFINITE)==WAIT_FAILED || !GetExitCodeProcess(h, &i)) | |
| { | |
| msvcrt_set_errno(GetLastError()); | |
| CloseHandle(h); | |
| return -1; | |
| } | |
| CloseHandle(h); | |
| return i; | |
| } | |
| /********************************************************************* | |
| * _wsystem (MSVCRT.@) | |
| * | |
| * Unicode version of system | |
| */ | |
| int CDECL _wsystem(const MSVCRT_wchar_t* cmd) | |
| { | |
| int res; | |
| MSVCRT_wchar_t *comspec, *fullcmd; | |
| unsigned int len; | |
| static const MSVCRT_wchar_t flag[] = {' ','/','c',' ',0}; | |
| comspec = msvcrt_get_comspec(); | |
| if (cmd == NULL) | |
| { | |
| if (comspec == NULL) | |
| { | |
| *MSVCRT__errno() = MSVCRT_ENOENT; | |
| return 0; | |
| } | |
| HeapFree(GetProcessHeap(), 0, comspec); | |
| return 1; | |
| } | |
| if ( comspec == NULL) | |
| return -1; | |
| len = strlenW(comspec) + strlenW(flag) + strlenW(cmd) + 1; | |
| if (!(fullcmd = HeapAlloc(GetProcessHeap(), 0, len * sizeof(MSVCRT_wchar_t)))) | |
| { | |
| HeapFree(GetProcessHeap(), 0, comspec); | |
| return -1; | |
| } | |
| strcpyW(fullcmd, comspec); | |
| strcatW(fullcmd, flag); | |
| strcatW(fullcmd, cmd); | |
| res = msvcrt_spawn(MSVCRT__P_WAIT, comspec, fullcmd, NULL, 1); | |
| HeapFree(GetProcessHeap(), 0, comspec); | |
| HeapFree(GetProcessHeap(), 0, fullcmd); | |
| return res; | |
| } | |
| /********************************************************************* | |
| * system (MSVCRT.@) | |
| */ | |
| int CDECL MSVCRT_system(const char* cmd) | |
| { | |
| int res = -1; | |
| MSVCRT_wchar_t *cmdW; | |
| if (cmd == NULL) | |
| return _wsystem(NULL); | |
| if ((cmdW = msvcrt_wstrdupa(cmd))) | |
| { | |
| res = _wsystem(cmdW); | |
| HeapFree(GetProcessHeap(), 0, cmdW); | |
| } | |
| return res; | |
| } | |
| /********************************************************************* | |
| * _loaddll (MSVCRT.@) | |
| */ | |
| MSVCRT_intptr_t CDECL _loaddll(const char* dllname) | |
| { | |
| return (MSVCRT_intptr_t)LoadLibraryA(dllname); | |
| } | |
| /********************************************************************* | |
| * _unloaddll (MSVCRT.@) | |
| */ | |
| int CDECL _unloaddll(MSVCRT_intptr_t dll) | |
| { | |
| if (FreeLibrary((HMODULE)dll)) | |
| return 0; | |
| else | |
| { | |
| int err = GetLastError(); | |
| msvcrt_set_errno(err); | |
| return err; | |
| } | |
| } | |
| /********************************************************************* | |
| * _getdllprocaddr (MSVCRT.@) | |
| */ | |
| void * CDECL _getdllprocaddr(MSVCRT_intptr_t dll, const char *name, int ordinal) | |
| { | |
| if (name) | |
| { | |
| if (ordinal != -1) return NULL; | |
| return GetProcAddress( (HMODULE)dll, name ); | |
| } | |
| if (HIWORD(ordinal)) return NULL; | |
| return GetProcAddress( (HMODULE)dll, (LPCSTR)(ULONG_PTR)ordinal ); | |
| } | |
| /********************************************************************* | |
| * _getpid (MSVCRT.@) | |
| */ | |
| int CDECL _getpid(void) | |
| { | |
| return GetCurrentProcessId(); | |
| } | |
| /********************************************************************* | |
| * __crtTerminateProcess (MSVCR110.@) | |
| */ | |
| int CDECL MSVCR110__crtTerminateProcess(UINT exit_code) | |
| { | |
| return TerminateProcess(GetCurrentProcess(), exit_code); | |
| } |