Handle quotes in command lines

Uwe Bonnes bon at elektron.ikp.physik.tu-darmstadt.de
Thu Jan 10 06:45:33 CST 2002


Hallo,

some application builds a commandline with arguments enclosed by quotes '"',
starts a daughter process with this commandline and relies on the quotes
being intact in the daughter process. Wine happily removed the quotes and so
the daughter process failed.
Appended patch keeps quotes intact, tested via CreateProcess and calling a
programm from the shell. When invoking wine from the shell, quotes need to
be escaped, like any other special characters.

Changelog:
	loader/module.c: get_file_name
	memory/environ.c: ENV_BuildCommandLine
	Handle quotes in Commandlines
-- 
Uwe Bonnes                bon at elektron.ikp.physik.tu-darmstadt.de

Institut fuer Kernphysik  Schlossgartenstrasse 9  64289 Darmstadt
--------- Tel. 06151 162516 -------- Fax. 06151 164321 ----------
Index: wine/memory/environ.c
===================================================================
RCS file: /home/wine/wine/memory/environ.c,v
retrieving revision 1.27
diff -u -r1.27 environ.c
--- wine/memory/environ.c	2 Oct 2001 17:49:20 -0000	1.27
+++ wine/memory/environ.c	10 Jan 2002 12:30:18 -0000
@@ -179,12 +179,9 @@
  * from the command line:
  * - spaces and tabs must be quoted
  *   'a b'   -> '"a b"'
- * - quotes must be escaped
- *   '"'     -> '\"'
- * - if '\'s are followed by a '"', they must be doubled and followed by '\"', 
- *   resulting in an odd number of '\' followed by a '"'
- *   '\"'    -> '\\\"'
- *   '\\"'   -> '\\\\\"'
+ * - if '\'s are followed by a '"', they must be doubled 
+ *   '\"'    -> '\\"'
+ *   '\\"'   -> '\\\\"'
  * - '\'s that are not followed by a '"' can be left as is
  *   'a\b'   == 'a\b'
  *   'a\\b'  == 'a\\b'
@@ -211,9 +208,8 @@
                     has_space=1;
                 } else if (*a=='"') {
                     /* doubling of '\' preceeding a '"', 
-                     * plus escaping of said '"'
                      */
-                    len+=2*bcount+1;
+                    len+=2*bcount;
                 }
                 bcount=0;
             }
@@ -266,8 +262,8 @@
                     if (*a=='"') {
                         int i;
 
-                        /* Double all the '\\' preceeding this '"', plus one */
-                        for (i=0;i<=bcount;i++)
+                        /* Double all the '\\' preceeding this '"'*/
+                        for (i=0;i<bcount;i++)
                             *p++='\\';
                         *p++='"';
                     } else {
Index: wine/loader/module.c
===================================================================
RCS file: /home/wine/wine/loader/module.c,v
retrieving revision 1.144
diff -u -r1.144 module.c
--- wine/loader/module.c	20 Dec 2001 00:19:42 -0000	1.144
+++ wine/loader/module.c	10 Jan 2002 12:30:21 -0000
@@ -954,8 +954,9 @@
  */
 static LPSTR get_file_name( LPCSTR appname, LPSTR cmdline, LPSTR buffer, int buflen )
 {
-    char *name, *pos, *ret = NULL;
-    const char *p;
+    char *name, *pos, *pos1, *ret = NULL;
+    const char *p,*q;
+    int quotes=0,extend=0;
 
     /* if we have an app name, everything is easy */
 
@@ -969,6 +970,26 @@
             if ((ret = HeapAlloc( GetProcessHeap(), 0, strlen(appname) + 3 )))
                 sprintf( ret, "\"%s\"", appname );
         }
+	else
+	  {
+	    /* beside escaping quotes, keep the given cmdline*/
+	    for(q=cmdline; *q; q++)
+	      if (*q == '"')
+		quotes++;
+	    if (quotes &&
+		((ret = HeapAlloc( GetProcessHeap(), 0, strlen(cmdline) + quotes + 1 ))))
+	      {
+		pos1=ret;
+		for (pos=cmdline;*pos; pos++)
+		  {
+		    if (*pos == '"')
+		      *pos1++='\\';
+		    *pos1++=*pos;
+		  }
+		*pos1=0;
+	      }
+	  }
+	TRACE("returning '%s'\n",ret);
         return ret;
     }
 
@@ -1013,15 +1034,40 @@
         }
     }
 
-    if (!ret || !strchr( name, ' ' )) goto done;  /* no change necessary */
+    for(q=cmdline; *q; q++)
+      if (*q == '"')
+	quotes++;
 
-    /* now build a new command-line with quotes */
-
-    if (!(ret = HeapAlloc( GetProcessHeap(), 0, strlen(cmdline) + 3 ))) goto done;
-    sprintf( ret, "\"%s\"%s", name, p );
+    if (ret && strchr( name, ' ' )) 
+      extend=2;  /* change because of a filename with spaces needed*/
 
+    /* now build a new command-line with quotes */
+    
+    if ((ret) && (quotes || extend) &&
+	(ret = HeapAlloc( GetProcessHeap(), 0, strlen(cmdline) + quotes + extend + 1 ))) 
+      {
+	  pos1=ret;
+	  if (extend)
+	    *pos1++='"';
+	  for (pos=name;*pos; pos++)
+	    {
+	      if (*pos == '"')
+		*pos1++='\\';
+	      *pos1++=*pos;
+	    }
+	  if (extend)
+	    *pos1++='"';
+	  for (q=p; *q; q++)
+	    {
+	      if (*q == '"')
+		*pos1++='\\';
+	      *pos1++=*q;
+	    }
+	  *pos1=0;
+      }
  done:
     HeapFree( GetProcessHeap(), 0, name );
+    TRACE("returning '%s'\n", ret );
     return ret;
 }
 




More information about the wine-patches mailing list