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