Command line arguments parsing problem

bogus@technologist.com bogus@technologist.com
Tue May 30 20:16:00 GMT 2000


I have many troubles with command line arguments parsing when I run a
non-cygwin program from bash. The problems occurs when I try to put
literal double quotation marks in arguments.
Here is a simple example that demonstrates the problem:

/tmp $ cat <<EOF > print_args.c
> #include <stdio.h>
>
> int
> main(int argc, char** argv) {
>   int i;
>   for(i = 1; i < argc; i++) {
>     printf("%d: %s\n", i, argv[i]);
>   }
>   exit(0);
> }
> EOF
/tmp $ gcc -o print_args_cygwin print_args.c
/tmp $ gcc -o print_args_nocygwin -mno-cygwin print_args.c
/tmp $ ./print_args_cygwin.exe '" "'
1: " "
/tmp $ ./print_args_nocygwin.exe '" "'
1: "
2: "

As you can see the non-cygwin program gets an inconsistent argv.

After some investigations, I discovered that a spawned windows
process doesn't get directly an array of disjointed arguments but a
command line it has to parse itself in order to build argv.
To build the command line that will be given to a sub-process, the
current cygwin implementation uses double quote marks to enclose
arguments while literal double quote marks are doubled.
For some unknown reasons, it appears that the non-cygwin programs
don't parse that syntax properly, but instead they seem to handle
correctly another syntax that uses backslashes to protect literal
double quote marks.
Eventually, I wrote the small patch below, so that cygwin uses the
backslash syntax. It seems to work fine, but as I'm a cygwin newbie,
it might actually be completly broken, and maybe there are good reasons
for using the double double quote marks syntax instead of the backslash
syntax. I'm waiting for your comments.

Regards,

Pierre Bogossian

PS: This patch doesn't fix the symmetrical problem: when a cygwin
program is called from a windows shell. But as I'm not using windows
shells anymore, that doesn't bother me that much ;-)

---

diff -r -up winsup-src-20000527-orig/cygwin/dcrt0.cc winsup-src-20000527-patched/cygwin/dcrt0.cc
--- winsup-src-20000527-orig/cygwin/dcrt0.cc	Mon May 22 05:55:16 2000
+++ winsup-src-20000527-patched/cygwin/dcrt0.cc	Mon May 29 04:19:34 2000
@@ -281,17 +281,21 @@ quoted (char *cmd, int winshell)
   /* When running as a child of a cygwin process, the quoted
      characters should have been placed here by spawn_guts, so
      we'll just pinch them out of the command string unless
-     they're quoted with a preceding \ */
+     they're quoted with an odd number of preceding \ */
   strcpy (cmd, cmd + 1);
-  while (*cmd)
+  while (1)
     {
-      if (*cmd != quote)
-	cmd++;
-      else if (cmd[1] == quote)
-	strcpy (cmd++, cmd + 1);
+      char *fpbs;           /* The first preceding backslash */
+      int bs_count;
+      p = strchr (cmd, quote);
+      for (fpbs = p; fpbs != cmd && fpbs[-1] == '\\'; fpbs--);
+      bs_count = p - fpbs;
+      cmd = p - bs_count / 2;
+      if (bs_count % 2)
+	  strcpy (cmd - 1, p);
       else
 	{
-	  strcpy (cmd, cmd + 1);
+	  strcpy (cmd, p + 1);
 	  break;
 	}
     }
diff -r -up winsup-src-20000527-orig/cygwin/spawn.cc winsup-src-20000527-patched/cygwin/spawn.cc
--- winsup-src-20000527-orig/cygwin/spawn.cc	Wed Apr 26 07:20:04 2000
+++ winsup-src-20000527-patched/cygwin/spawn.cc	Mon May 29 02:06:32 2000
@@ -407,19 +407,23 @@ spawn_guts (HANDLE hToken, const char * 
 
       newargv0 = NULL;
       int len = strlen (a);
-      if (len != 0 && !(p = strpbrk (a, " \t\n\r\"")))
+      if (len != 0 && !strpbrk (a, " \t\n\r\""))
 	one_line.add (a, len);
       else
 	{
+	  char *fpbs;           /* The first preceding backslash */
 	  one_line.add ("\"", 1);
-	  for (; p; a = p, p = strchr (p, '"'))
+	  for (; (p = strchr (a, '"')); a = p + 1)
 	    {
-	      one_line.add (a, ++p - a);
-	      if (p[-1] == '"')
-		one_line.add ("\"", 1);
+	      one_line.add (a, p - a);
+	      for (fpbs = p; fpbs != a && fpbs[-1] == '\\'; fpbs--);
+	      one_line.add (fpbs, p - fpbs);
+	      one_line.add ("\\\"", 2);
 	    }
-	  if (*a)
-	    one_line.add (a);
+	  p = strchr (a, '\0');
+	  one_line.add (a, p - a);
+	  for (fpbs = p; fpbs[-1] == '\\'; fpbs--);
+	  one_line.add (fpbs, p - fpbs);
 	  one_line.add ("\"", 1);
 	}
       MALLOC_CHECK;

---------------------------------------------------
Get free personalized email at http://www.iname.com

--
Want to unsubscribe from this list?
Send a message to cygwin-unsubscribe@sourceware.cygnus.com



More information about the Cygwin mailing list