blob: f3c9000009be1705b85ee455cff389f2e0363901 [file] [log] [blame]
/*
* 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);
}