[PATCH 3/6] CMD.EXE: Handle command line as Unicode

Jason Edmeades jason.edmeades at googlemail.com
Fri May 25 16:17:40 CDT 2007


Note: Temporarily duplicate the command line and create an ANSI
version for the rest of the processing.
---
 programs/cmd/wcmd.h     |    1 +
 programs/cmd/wcmdmain.c |   92 ++++++++++++++++++++++++++++++----------------
 2 files changed, 61 insertions(+), 32 deletions(-)

diff --git a/programs/cmd/wcmd.h b/programs/cmd/wcmd.h
index 78db858..ab13595 100644
--- a/programs/cmd/wcmd.h
+++ b/programs/cmd/wcmd.h
@@ -26,6 +26,7 @@
 #include <stdarg.h>
 #include <stdio.h>
 #include <ctype.h>
+#include <wine/unicode.h>
 
 void WCMD_assoc (char *, BOOL);
 void WCMD_batch (char *, char *, int, char *, HANDLE);
diff --git a/programs/cmd/wcmdmain.c b/programs/cmd/wcmdmain.c
index d0a08ec..85fe005 100644
--- a/programs/cmd/wcmdmain.c
+++ b/programs/cmd/wcmdmain.c
@@ -59,6 +59,9 @@ static char *WCMD_expand_envvar(char *start);
 
 int main (int argc, char *argv[])
 {
+  LPWSTR *argvW = NULL;
+  int     args;
+  WCHAR  *cmdW  = NULL;
   char string[1024];
   char envvar[4];
   char* cmd=NULL;
@@ -67,34 +70,44 @@ int main (int argc, char *argv[])
   int opt_q;
   int opt_t = 0;
 
+  /* Get a Unicode command line */
+  argvW = CommandLineToArgvW( GetCommandLineW(), &argc );
+  args  = argc;
+
   opt_c=opt_k=opt_q=opt_s=0;
-  while (*argv!=NULL)
+  while (args > 0)
   {
-      char c;
-      if ((*argv)[0]!='/' || (*argv)[1]=='\0') {
-          argv++;
+      WCHAR c;
+      WINE_TRACE("Command line parm: '%s'\n", wine_dbgstr_w(*argvW));
+      if ((*argvW)[0]!='/' || (*argvW)[1]=='\0') {
+          argvW++;
+          args--;
           continue;
       }
 
-      c=(*argv)[1];
-      if (tolower(c)=='c') {
+      c=(*argvW)[1];
+      if (tolowerW(c)=='c') {
           opt_c=1;
-      } else if (tolower(c)=='q') {
+      } else if (tolowerW(c)=='q') {
           opt_q=1;
-      } else if (tolower(c)=='k') {
+      } else if (tolowerW(c)=='k') {
           opt_k=1;
-      } else if (tolower(c)=='s') {
+      } else if (tolowerW(c)=='s') {
           opt_s=1;
-      } else if (tolower(c)=='t' && (*argv)[2]==':') {
-          opt_t=strtoul(&(*argv)[3], NULL, 16);
-      } else if (tolower(c)=='x' || tolower(c)=='y') {
+      } else if (tolowerW(c)=='t' && (*argvW)[2]==':') {
+          opt_t=strtoulW(&(*argvW)[3], NULL, 16);
+      } else if (tolowerW(c)=='x' || tolowerW(c)=='y') {
           /* Ignored for compatibility with Windows */
       }
 
-      if ((*argv)[2]==0)
-          argv++;
+      if ((*argvW)[2]==0) {
+          argvW++;
+          args--;
+      }
       else /* handle `cmd /cnotepad.exe` and `cmd /x/c ...` */
-          *argv+=2;
+      {
+          *argvW+=2;
+      }
 
       if (opt_c || opt_k) /* break out of parsing immediately after c or k */
           break;
@@ -105,9 +118,10 @@ int main (int argc, char *argv[])
   }
 
   if (opt_c || opt_k) {
-      int len,qcount;
-      char** arg;
-      char* p;
+      int     len,qcount;
+      WCHAR** arg;
+      int     argsLeft;
+      WCHAR*  p;
 
       /* opt_s left unflagged if the command starts with and contains exactly
        * one quoted string (exactly two quote characters). The quoted string
@@ -117,10 +131,11 @@ int main (int argc, char *argv[])
       /* Build the command to execute */
       len = 0;
       qcount = 0;
-      for (arg = argv; *arg; arg++)
+      argsLeft = args;
+      for (arg = argvW; argsLeft>0; arg++,argsLeft--)
       {
           int has_space,bcount;
-          char* a;
+          WCHAR* a;
 
           has_space=0;
           bcount=0;
@@ -143,7 +158,7 @@ int main (int argc, char *argv[])
               }
               a++;
           }
-          len+=(a-*arg)+1 /* for the separating space */;
+          len+=(a-*arg) + 1; /* for the separating space */
           if (has_space)
           {
               len+=2; /* for the quotes */
@@ -154,10 +169,10 @@ int main (int argc, char *argv[])
       if (qcount!=2)
           opt_s=1;
 
-      /* check argv[0] for a space and invalid characters */
+      /* check argvW[0] for a space and invalid characters */
       if (!opt_s) {
           opt_s=1;
-          p=*argv;
+          p=*argvW;
           while (*p!='\0') {
               if (*p=='&' || *p=='<' || *p=='>' || *p=='(' || *p==')'
                   || *p=='@' || *p=='^' || *p=='|') {
@@ -170,15 +185,16 @@ int main (int argc, char *argv[])
           }
       }
 
-      cmd = HeapAlloc(GetProcessHeap(), 0, len);
-      if (!cmd)
+      cmdW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+      if (!cmdW)
           exit(1);
 
-      p = cmd;
-      for (arg = argv; *arg; arg++)
+      p = cmdW;
+      argsLeft = args;
+      for (arg = argvW; argsLeft>0; arg++,argsLeft--)
       {
           int has_space,has_quote;
-          char* a;
+          WCHAR* a;
 
           /* Check for quotes and spaces in this argument */
           has_space=has_quote=0;
@@ -202,7 +218,7 @@ int main (int argc, char *argv[])
               *p++='"';
           if (has_quote) {
               int bcount;
-              char* a;
+              WCHAR* a;
 
               bcount=0;
               a=*arg;
@@ -226,17 +242,27 @@ int main (int argc, char *argv[])
                   a++;
               }
           } else {
-              strcpy(p,*arg);
-              p+=strlen(*arg);
+              strcpyW(p,*arg);
+              p+=strlenW(*arg);
           }
           if (has_space)
               *p++='"';
           *p++=' ';
       }
-      if (p > cmd)
+      if (p > cmdW)
           p--;  /* remove last space */
       *p = '\0';
 
+      /* FIXME: Convert back to ansi until more is in unicode */
+      cmd = HeapAlloc(GetProcessHeap(), 0, len);
+      if (!cmd) {
+        exit(1);
+      } else {
+        WideCharToMultiByte(CP_ACP, 0, cmdW, len, cmd, len, NULL, NULL);
+      }
+      WINE_TRACE("Input (U): '%s'\n", wine_dbgstr_w(cmdW));
+      WINE_TRACE("Input (A): '%s'\n", cmd);
+
       /* strip first and last quote characters if opt_s; check for invalid
        * executable is done later */
       if (opt_s && *cmd=='\"')
@@ -254,6 +280,7 @@ int main (int argc, char *argv[])
       else
           WCMD_process_command(cmd);
       HeapFree(GetProcessHeap(), 0, cmd);
+      HeapFree(GetProcessHeap(), 0, cmdW);
       return errorlevel;
   }
 
@@ -338,6 +365,7 @@ int main (int argc, char *argv[])
   if (opt_k) {
       WCMD_process_command(cmd);
       HeapFree(GetProcessHeap(), 0, cmd);
+      HeapFree(GetProcessHeap(), 0, cmdW);
   }
 
 /*
-- 
1.5.0




More information about the wine-patches mailing list