msvcrt: _wsystem implementation
Jaco Greeff
jaco at puxedo.org
Thu Nov 7 09:39:41 CST 2002
Imnplementation of the _wsystem function. In addition to this, Unicode
versions of the internal spawn function has been created (for use by
_wsystem) and the system call uses _wsystem internally to allow for the
use of the COMSPEC variable in execution.
License:
LGPL
Changelog:
* dlls/msvcrt/msvcrt.spec, dlls/msvcrt/process.c: Jaco Greeff
<jaco at puxedo.org>
- Implementation of the _wsystem call
- system call uses _wsystem internally to allow for the use of COMSPEC
in execution (previous FIXME)
-------------- next part --------------
diff -aurN msvcrt-C00/dlls/msvcrt/msvcrt.spec msvcrt-C01/dlls/msvcrt/msvcrt.spec
--- msvcrt-C00/dlls/msvcrt/msvcrt.spec Thu Nov 7 17:19:32 2002
+++ msvcrt-C01/dlls/msvcrt/msvcrt.spec Thu Nov 7 16:56:42 2002
@@ -556,7 +556,7 @@
@ stub _wstati64 #(wstr ptr)
@ stub _wstrdate #(wstr)
@ stub _wstrtime #(wstr)
-@ stub _wsystem #(wstr)
+@ cdecl _wsystem(wstr) MSVCRT__wsystem
@ cdecl _wtempnam(wstr wstr) _wtempnam
@ stub _wtmpnam #(wstr)
@ forward -noimport _wtoi NTDLL._wtoi
diff -aurN msvcrt-C00/dlls/msvcrt/process.c msvcrt-C01/dlls/msvcrt/process.c
--- msvcrt-C00/dlls/msvcrt/process.c Thu Nov 7 17:14:55 2002
+++ msvcrt-C01/dlls/msvcrt/process.c Thu Nov 7 17:21:11 2002
@@ -5,6 +5,7 @@
* Copyright 1996 Jukka Iivonen
* Copyright 1997,2000 Uwe Bonnes
* Copyright 2000 Jon Griffiths
+ * Copyright 2002 Jaco Greeff
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -36,66 +37,163 @@
#include "msvcrt/stdlib.h"
#include "msvcrt/string.h"
+#include "wine/unicode.h"
+
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
+static const WCHAR wszCOMSPEC[] = {'C','O','M','S','P','E','C', 0};
+
/* FIXME: Check file extensions for app to run */
static const unsigned int EXE = 'e' << 16 | 'x' << 8 | 'e';
static const unsigned int BAT = 'b' << 16 | 'a' << 8 | 't';
static const unsigned int CMD = 'c' << 16 | 'm' << 8 | 'd';
static const unsigned int COM = 'c' << 16 | 'o' << 8 | 'm';
-/* INTERNAL: Spawn a child process */
-static int msvcrt_spawn(int flags, const char* exe, char* cmdline, char* env)
+/*********************************************************************
+ * WideStrToASCII
+ * (internal, non-exported)
+ *
+ * Wrapper to allocate enough memory and convert a LPCWSTR to a normal
+ * LPSTR
+ */
+static inline CHAR *WideToASCIIStr(LPCWSTR lpwszIn, INT nIn)
{
- STARTUPINFOA si;
- PROCESS_INFORMATION pi;
+ INT nLen;
+ CHAR *szOut;
- if (sizeof(HANDLE) != sizeof(int))
- WARN("This call is unsuitable for your architecture\n");
+ if (!lpwszIn || !nIn)
+ return NULL;
- if ((unsigned)flags > _P_DETACH)
- {
- *MSVCRT__errno() = MSVCRT_EINVAL;
- return -1;
- }
+ nLen = WideCharToMultiByte(CP_ACP, 0, lpwszIn, nIn, NULL, 0, NULL, NULL);
+ if ((szOut = (CHAR *)MSVCRT_malloc((nLen+1)*sizeof(CHAR))))
+ {
+ WideCharToMultiByte(CP_ACP, 0, lpwszIn, nIn, szOut, nLen+1, NULL, NULL);
+ szOut[nLen] = '\0';
+ }
- FIXME(":must dup/kill streams for child process\n");
+ return szOut;
+}
- memset(&si, 0, sizeof(si));
- si.cb = sizeof(si);
- if (!CreateProcessA(exe, cmdline, NULL, NULL, TRUE,
- flags == _P_DETACH ? DETACHED_PROCESS : 0,
- env, NULL, &si, &pi))
- {
- MSVCRT__set_errno(GetLastError());
- return -1;
- }
+/*********************************************************************
+ * ASCIIToWideStr
+ * (internal, non-exported)
+ *
+ * Wrapper to allocate enough memory and convert a LPCSTR to a normal
+ * LPWSTR
+ */
+static inline WCHAR *ASCIIToWideStr(LPCSTR lpszIn, INT nIn)
+{
+ INT nLen;
+ WCHAR *szOut;
- switch(flags)
- {
- case _P_WAIT:
- WaitForSingleObject(pi.hProcess,-1); /* wait forvever */
- GetExitCodeProcess(pi.hProcess,&pi.dwProcessId);
- CloseHandle(pi.hProcess);
- CloseHandle(pi.hThread);
- return (int)pi.dwProcessId;
- case _P_DETACH:
- CloseHandle(pi.hProcess);
- pi.hProcess = 0;
- /* fall through */
- case _P_NOWAIT:
- case _P_NOWAITO:
- CloseHandle(pi.hThread);
- return (int)pi.hProcess;
- case _P_OVERLAY:
- MSVCRT__exit(0);
- }
- return -1; /* can't reach here */
+ if (!lpszIn || !nIn)
+ return NULL;
+
+ nLen = MultiByteToWideChar(CP_ACP, 0, lpszIn, nIn, NULL, 0);
+ if ((szOut = (WCHAR *)MSVCRT_malloc((nLen+1)*sizeof(WCHAR))))
+ {
+ MultiByteToWideChar(CP_ACP, 0, lpszIn, nIn, szOut, nLen+1);
+ szOut[nLen] = 0;
+ }
+
+ return szOut;
}
+
+/*********************************************************************
+ * MSVCRT_spawnW
+ * (internal non-exported)
+ *
+ * Spawn a child process using WCHAR arguments
+ * (This is a direct "port" of the original MSVCRT_spawnA
+ * function to support Unicode strings) Internally
+ * MSVCRT_spawnA now call MSVCRT_spawnAW)
+ */
+static int MSVCRT_spawnW(int nFlags, const WCHAR* wszExe, WCHAR *wszCmdline, WCHAR *wszEnv)
+{
+ STARTUPINFOW siStartup;
+ PROCESS_INFORMATION piInfo;
+
+ TRACE("(nFlags == %d, wszExe == %s, wszCmdLine == %s, wszEnv == %s)\n",
+ nFlags, debugstr_w(wszExe), debugstr_w(wszCmdline), debugstr_w(wszEnv));
+
+ /* FIXME: this is not a problem at present, but might become
+ * so in the future when we move to 64 bit and support Win64
+ */
+ if (sizeof(HANDLE) != sizeof(int))
+ WARN("This call is unsuitable for your architecture\n");
+
+ if ((unsigned)nFlags > _P_DETACH)
+ {
+ *MSVCRT__errno() = MSVCRT_EINVAL;
+ return -1;
+ }
+
+ FIXME(":must dup/kill streams for child process\n");
+
+ memset(&siStartup, 0, sizeof(siStartup));
+ siStartup.cb = sizeof(siStartup);
+
+ if (!CreateProcessW(wszExe, wszCmdline, NULL, NULL, TRUE,
+ nFlags == _P_DETACH ? DETACHED_PROCESS : 0,
+ wszEnv, NULL, &siStartup, &piInfo))
+ {
+ MSVCRT__set_errno(GetLastError());
+ return -1;
+ }
+
+ switch (nFlags)
+ {
+ case _P_WAIT:
+ WaitForSingleObject(piInfo.hProcess, -1); /* wait forvever */
+ GetExitCodeProcess(piInfo.hProcess, &piInfo.dwProcessId);
+ CloseHandle(piInfo.hProcess);
+ CloseHandle(piInfo.hThread);
+ return (int)piInfo.dwProcessId;
+
+ case _P_DETACH:
+ CloseHandle(piInfo.hProcess);
+ piInfo.hProcess = 0;
+ /* fall through */
+ case _P_NOWAIT:
+ case _P_NOWAITO:
+ CloseHandle(piInfo.hThread);
+ return (int)piInfo.hProcess;
+
+ case _P_OVERLAY:
+ MSVCRT__exit(0);
+ }
+
+ return -1; /* can't reach here */
+}
+
+
+/*********************************************************************
+ * MSVCRT_spawnA
+ * (internal non-exported)
+ */
+static int MSVCRT_spawnA(int nFlags, const char* szExe, char *szCmdline, char *szEnv)
+{
+ int nRet = 0;
+
+ WCHAR *wszExe = ASCIIToWideStr(szExe, strlen(szExe));
+ WCHAR *wszCmdline = ASCIIToWideStr(szCmdline, strlen(szCmdline));
+ WCHAR *wszEnv = ASCIIToWideStr(szEnv, strlen(szEnv));
+ nRet = MSVCRT_spawnW(nFlags, wszExe, wszCmdline, wszEnv);
+ if (wszExe)
+ MSVCRT_free(wszExe);
+ if (wszCmdline)
+ MSVCRT_free(wszCmdline);
+ if (wszEnv)
+ MSVCRT_free(wszEnv);
+
+ return nRet;
+}
+
+
/* INTERNAL: Convert argv list to a single 'delim'-separated string, with an
* extra '\0' to terminate it
*/
@@ -242,7 +340,7 @@
args = msvcrt_valisttos(arg0, ap, ' ');
va_end(ap);
- ret = msvcrt_spawn(_P_OVERLAY, name, args, NULL);
+ ret = MSVCRT_spawnA(_P_OVERLAY, name, args, NULL);
MSVCRT_free(args);
return ret;
@@ -267,7 +365,7 @@
args = msvcrt_valisttos(arg0, ap, ' ');
va_end(ap);
- ret = msvcrt_spawn(_P_OVERLAY, fullname[0] ? fullname : name, args, NULL);
+ ret = MSVCRT_spawnA(_P_OVERLAY, fullname[0] ? fullname : name, args, NULL);
MSVCRT_free(args);
return ret;
@@ -337,7 +435,7 @@
args = msvcrt_valisttos(arg0, ap, ' ');
va_end(ap);
- ret = msvcrt_spawn(flags, name, args, NULL);
+ ret = MSVCRT_spawnA(flags, name, args, NULL);
MSVCRT_free(args);
return ret;
@@ -362,7 +460,7 @@
args = msvcrt_valisttos(arg0, ap, ' ');
va_end(ap);
- ret = msvcrt_spawn(flags, fullname[0] ? fullname : name, args, NULL);
+ ret = MSVCRT_spawnA(flags, fullname[0] ? fullname : name, args, NULL);
MSVCRT_free(args);
return ret;
@@ -387,7 +485,7 @@
if (args)
{
- ret = msvcrt_spawn(flags, fullname, args, envs);
+ ret = MSVCRT_spawnA(flags, fullname, args, envs);
MSVCRT_free(args);
}
if (envs)
@@ -433,19 +531,58 @@
}
/*********************************************************************
- * system (MSVCRT.@)
+ * _wsystem (MSVCRT.@)
*/
-int MSVCRT_system(const char* cmd)
+int MSVCRT__wsystem(const WCHAR *wszCmd)
{
- char* cmdcopy;
- int res;
+ static const WCHAR wszExec[] = {' ','/','c',' ', 0};
+ WCHAR wszComspec[1024+1];
+ WCHAR *wszCmdcopy;
+ int res, nLen;
+
+ /* Get the value of COMSPEC which should point to our
+ * default command interpreter. If the interpreter is
+ * not available, fail.
+ */
+ if (!GetEnvironmentVariableW(wszCOMSPEC, wszComspec, 1024))
+ {
+ TRACE("COMSPEC not available, _wsystem call fails\n");
+ return -1;
+ }
+
+ /* Allocate enough memory to hold the interpreter + command
+ * string and set it. When using the command interpreter in
+ * this way, it is executed as "comspec /c command"
+ */
+ nLen = strlenW(wszComspec)+strlenW(wszExec)+strlenW(wszCmd);
+ if (!(wszCmdcopy = (WCHAR *)MSVCRT_malloc((nLen+1)*sizeof(WCHAR))))
+ {
+ TRACE("Unable to allocate memory for _wsystem call\n");
+ return -1;
+ }
+ wszCmdcopy[0] = 0;
+ strcatW(wszCmdcopy, wszComspec);
+ strcatW(wszCmdcopy, wszExec);
+ strcatW(wszCmdcopy, wszCmd);
+ res = MSVCRT_spawnW(_P_WAIT, NULL, wszCmdcopy, NULL);
+ MSVCRT_free(wszCmdcopy);
- /* Make a writable copy for CreateProcess */
- cmdcopy=_strdup(cmd);
- /* FIXME: should probably launch cmd interpreter in COMSPEC */
- res=msvcrt_spawn(_P_WAIT, NULL, cmdcopy, NULL);
- MSVCRT_free(cmdcopy);
return res;
+}
+
+/*********************************************************************
+ * system (MSVCRT.@)
+ */
+int MSVCRT_system(const char *szCmd)
+{
+ int nRet = 0;
+
+ WCHAR *wszCmd = ASCIIToWideStr(szCmd, strlen(szCmd));
+ nRet = MSVCRT__wsystem(wszCmd);
+ if (wszCmd)
+ MSVCRT_free(wszCmd);
+
+ return nRet;
}
/*********************************************************************
More information about the wine-patches
mailing list