delorie.com/archives/browse.cgi   search  
Mail Archives: cygwin-developers/1999/01/21/14:25:24

From: cgf AT cygnus DOT com (Christopher Faylor)
Subject: Re: relative path script
21 Jan 1999 14:25:24 -0800 :
Message-ID: <19990121171200.A19658.cygnus.cygwin32.developers@cygnus.com>
References: <ubtjx80o1 DOT fsf AT parvati DOT will DOT or DOT jp>
Mime-Version: 1.0
To: Kazuhiro Fujieda <fujieda AT jaist DOT ac DOT jp>, cygwin32-developers AT cygnus DOT com

Thanks for noticing these inconsistencies and for the patch.  Your
patch didn't quite do it for me.  This one below did, however.
This is against the last snapshot.  Sorry but I forgot to save
my previous version before making this change.

This should incorporate the majority of your changes, however.

-chris

On Thu, Jan 21, 1999 at 07:18:42PM +0900, Kazuhiro Fujieda wrote:
>>>> On Wed, 20 Jan 1999 14:46:59 -0500
>>>> Christopher Faylor <cgf AT cygnus DOT com> said:
>
>> I've actually been checking this out in my spare time.  I've
>> rewritten the section of code that deals with this.  It's a major
>> change, so I could have broken something, but here it is.
>(snip)
>
>There is a bug in this patch.  The argument parser can't convert
>arguments rightly. For example, it convert `foo "bar" foo' to
>`"foo """bar" foo"'. This should be `"foo ""bar"" foo"'.
>
>Then, It should check not only ' ' but also '\n', '\r' and '\t'
>in order to be consistent with build_argv() in dcrt0.cc.
>[snip]

Index: spawn.cc
===================================================================
RCS file: /cvs/cvsfiles/devo/winsup/spawn.cc,v
retrieving revision 1.99
diff -u -p -r1.99 spawn.cc
--- spawn.cc	1999/01/17 06:08:43	1.99
+++ spawn.cc	1999/01/21 22:10:42
@@ -167,12 +167,56 @@ iscmd (const char *argv0, const char *wh
 	 (n == 0 || isdirsep (argv0[n - 1]));
 }
 
+class linebuf
+{
+  size_t alloc;
+public:
+  size_t ix;
+  char *buf;
+  linebuf ()
+  {
+    ix = 0;
+    alloc = 0;
+    buf = NULL;
+  }
+  ~linebuf () {if (buf) free (buf);}
+  void add (const char *what, int len);
+  void add (const char *what) {add (what, strlen (what));}
+  void prepend (const char *what, int len);
+};
+
+void
+linebuf::add (const char *what, int len)
+{
+  size_t newix;
+  if ((newix = ix + len) >= alloc)
+    {
+      alloc += MAX_PATH * 2;
+      buf = (char *) realloc (buf, alloc + 1);
+    }
+  memcpy (buf + ix, what, len);
+  ix = newix;
+}
+
+void
+linebuf::prepend (const char *what, int len)
+{
+  size_t newix;
+  if ((newix = ix + len) >= alloc)
+    {
+      alloc += MAX_PATH * 2;
+      buf = (char *) realloc (buf, alloc + 1);
+    }
+  memmove (buf + len, buf, strlen (buf));
+  memcpy (buf, what, len);
+  ix += len;
+}
+
 int
 spawn_guts (HANDLE hToken, const char * prog_arg, const char *const *argv,
 	    const char *const envp[], pinfo *child, int mode)
 {
   int i;
-  char *copy;
   BOOL rc;
   int argc;
 
@@ -196,36 +240,23 @@ spawn_guts (HANDLE hToken, const char * 
 
   /* CreateProcess takes one long string that is the command line (sigh).
      We need to quote any argument that has whitespace or embedded "'s.  */
-    int clen, last_clen;
 
   for (argc = 0; argv[argc]; argc++)
-debug_printf ("argv[%d] = '%s'", argc, argv[argc]);
     /* nothing */;
 
-  /* See how much space we need.  Note that "'s are doubled. */
-  clen = 0;
-  if (argc == 0)
-    {
-      /* Hmm - nasty - no prog name, - fill one up for us */
-      /* FIXME: what about argv[1]??? */
-      small_printf ("spawn_guts: NO ARG0");
-      char **tmp;
-      tmp = (char **) &argv[0];
-      *tmp = (char *) prog_arg;
-    }
-
   char *real_path;
   char real_path_buf[MAX_PATH];
+
+  sig_protect (starting_here, 0);
+  linebuf one_line;
+
   if (argc == 3 && argv[1][0] == '/' && argv[1][1] == 'c' &&
       (iscmd (argv[0], "command.com") || iscmd (argv[0], "cmd.exe")))
     {
-      copy = (char *) alloca (strlen (argv[0]) + strlen (argv[1]) +
-			      strlen (argv[2]) + 3);
-      strcpy (copy, argv[0]);
-      strcat (copy, " ");
-      strcat (copy, argv[1]);
-      strcat (copy, " ");
-      strcat (copy, argv[2]);
+      one_line.add (argv[0]);
+      one_line.add (" ");
+      one_line.add (argv[1]);
+      one_line.add (" ");
       real_path = NULL;
       strcpy (real_path_buf, argv[0]);
       goto skip_arg_parsing;
@@ -233,83 +264,21 @@ debug_printf ("argv[%d] = '%s'", argc, a
 
   real_path = real_path_buf;
 
-  for (argc = 0; argv[argc]; argc++)
-    {
-      int needquote = 0;
-      const char *str;
-      /* Zero length args need quotes. */
-      if (!argv[argc][0])
-	needquote = 1;
-
-      for (str = argv[argc]; *str; str++)
-	{
-	  if (*str == '"')
-	    clen++;
-	  if (issep (*str) || *str == '"')
-	    needquote = 1;
-	  clen++;
-	}
-      if (needquote)
-	clen += 2;		/* space for quotes */
-      clen++;			/* space for separating space */
-    }
-
-  if ((copy = (char *) alloca (clen + 1)) == NULL)
-    {
-      syscall_printf ("couldn't allocate %d characters", clen + 1);
-      set_errno (ENAMETOOLONG);
-      return -1;
-    }
-  syscall_printf ("total arg length %d, copy %p", clen, copy);
-  last_clen = clen + 1;
-  clen = 0;
-
-  for (i = 0, argc--; i <= argc; i++)
-    {
-      int needquote = 0;
-      const char *str;
-
-      /* Extra space after `in' intentional. */
-      syscall_printf ("argv[%d] in  `%s'", i, argv[i]);
-
-      if (!argv[i][0])
-	needquote = 1;
-
-      for (str = argv[i]; *str; str++)
-	if (issep (*str) || *str == '"')
-	  needquote = 1;
-
-      if (needquote)
-	copy[clen++] = '"';
-
-      for (str = argv[i]; *str; str++)
-	{
-	  if (*str=='"')
-	    copy[clen++] = '"';
-	  copy[clen++] = *str;
-	}
-
-      if (needquote)
-	copy[clen++] = '"';
-      copy[clen++] = (i == argc) ? '\0' : ' ';
-      syscall_printf ("argv[%d] out`%s'", i, argv[i]);
-    }
-  if (clen > last_clen)
-    system_printf ("Hey! clen %d, last_clen %d", clen, last_clen);
-
   const char *saved_prog_arg;
+  const char *newargv0, **firstarg;
   const char *ext;
 
-  saved_prog_arg = prog_arg;
   if ((ext = perhaps_suffix (prog_arg, real_path)) == NULL)
     {
       set_errno (ENOENT);
       return -1;
     }
 
-  /* Check if it's a script.  */
+  saved_prog_arg = prog_arg;
+  newargv0 = argv[0];
+  firstarg = &newargv0;
 
-  /* if the file name ends in either .exe, .com, .bat, or .cmd we assume
+  /* If the file name ends in either .exe, .com, .bat, or .cmd we assume
      that it is NOT a script file */
   while (*ext == '\0')
     {
@@ -355,46 +324,42 @@ debug_printf ("argv[%d] = '%s'", argc, a
       else
 	{
 	  pgm = buf + 2;
-	  pgm += strspn(pgm, " \t");
+	  pgm += strspn (pgm, " \t");
 	  for (ptr = pgm, arg1 = NULL;
 	       *ptr && *ptr != '\r' && *ptr != '\n';
 	       ptr++)
 	    if (!arg1 && (*ptr == ' ' || *ptr == '\t'))
 	      {
-		*ptr = '\0';
-		do
-		  arg1 = ++ptr;
-		while (*ptr && (*ptr == ' ' || *ptr == '\t'));
-		ptr--;
+		arg1 = ptr;
+		*arg1++ = '\0';
+		ptr = (arg1 += strspn (arg1, " \t"));
 	      }
 
 	
 	  *ptr = '\0';
-	  if (arg1 == NULL)
-	    arg1 = ptr;
 	}
 
-      char prog_arg1[MAX_PATH];
+      char buf2[MAX_PATH + 1];
 
       /* pointers:
        * pgm	interpreter name
        * arg1	optional string
        * ptr	end of string
        */ 
-      find_exec (pgm, (char *) real_path, "PATH=", 0, &ext);
-      cygwin_conv_to_posix_path (real_path, prog_arg1);
-      char *f = (char *) alloca (strlen (copy) + strlen (prog_arg1) +
-				 (ptr - arg1) + 8 + strlen (saved_prog_arg));
-      strcpy (f, prog_arg1);
-      if (ptr == arg1)
-	strcat (f, " ");
+
+      if (!arg1)
+	one_line.prepend (" ", 1);
       else
 	{
-	  strcat (f, " \"");
-	  strcat (f, arg1);
-	  strcat (f, "\" ");
+	  one_line.prepend ("\" ", 1);
+	  one_line.prepend (arg1, strlen (arg1));
+	  one_line.prepend (" \"", 2);
 	}
 
+      find_exec (pgm, real_path, "PATH=", 0, &ext);
+      cygwin_conv_to_posix_path (real_path, buf2);
+      one_line.prepend (buf2, strlen (buf2));
+
       /* If script had absolute path, add it to script name now!
        * This is necessary if script has been found via PATH.
        * For example, /usr/local/bin/tkman started as "tkman":
@@ -404,19 +369,43 @@ debug_printf ("argv[%d] = '%s'", argc, a
        * but not /usr/local/bin/wish -f tkman!
        * We don't modify anything, if script has qulified path.
        */
-      if (strpbrk (saved_prog_arg, "\\/") && !isabspath (copy))
+      if (firstarg)
+	*firstarg = saved_prog_arg;
+
+      debug_printf ("prog_arg '%s', copy '%s'", prog_arg, one_line.buf);
+      firstarg = NULL;
+    }
+  
+  for (; *argv; argv++)
+    {
+      char *p = NULL;
+      const char *a = newargv0 ?: *argv;
+
+      newargv0 = NULL;
+      int len = strlen (a);
+      if (len != 0 && !(p = strpbrk (a, " \t\n\r\"")))
+	one_line.add (a, len);
+      else
 	{
-	  debug_printf ("getting path of %s, copy %s", saved_prog_arg, buf);
-	  cygwin_split_path (saved_prog_arg, strchr(f, '\0'), buf);
-	  strcat (f, "/");
+	  one_line.add ("\"", 1);
+	  for (; p; a = p, p = strchr (p, '"'))
+	    {
+	      one_line.add (a, ++p - a);
+	      if (p[-1] == '"')
+		one_line.add ("\"", 1);
+	    }
+	  if (*a)
+	    one_line.add (a);
+	  one_line.add ("\"", 1);
 	}
-
-      strcat (f, copy);
-      copy = f;
-
-      debug_printf ("prog_arg '%s', copy '%s'", prog_arg, copy);
+      one_line.add (" ", 1);
     }
 
+  if (one_line.ix)
+    one_line.buf[one_line.ix - 1] = '\0';
+  else
+    one_line.add ("", 1);
+
 skip_arg_parsing:
   PROCESS_INFORMATION pi = {0};
 
@@ -472,7 +461,7 @@ skip_arg_parsing:
 
   /* We print the translated program and arguments here so the user can see
      what was done to it.  */
-  syscall_printf ("spawn_guts (%s, %.132s)", real_path, copy);
+  syscall_printf ("spawn_guts (%s, %.132s)", real_path, one_line.buf);
 
   int flags = CREATE_DEFAULT_ERROR_MODE | CREATE_SUSPENDED |
 	      GetPriorityClass (GetCurrentProcess ());
@@ -494,8 +483,6 @@ skip_arg_parsing:
 	flags |= DETACHED_PROCESS;
     }
 
-  sig_protect (starting_here, 0);
-
   /* Build windows style environment list */
   char *envblock = winenv (envp);
 
@@ -521,7 +508,7 @@ skip_arg_parsing:
       myself->uid = USHRT_MAX;
       rc = CreateProcessAsUser (hToken,
 		       real_path,	/* image name - with full path */
-		       copy,	/* what was passed to exec */
+		       one_line.buf,	/* what was passed to exec */
 		       &sec_all_nih,	/* process security attrs */
 		       &sec_all_nih,	/* thread security attrs */
 		       TRUE,	/* inherit handles from parent */
@@ -533,7 +520,7 @@ skip_arg_parsing:
     }
   else
     rc = CreateProcessA (real_path,	/* image name - with full path */
-		       copy,	/* what was passed to exec */
+		       one_line.buf,	/* what was passed to exec */
 		       &sec_all_nih,	/* process security attrs */
 		       &sec_all_nih,	/* thread security attrs */
 		       TRUE,	/* inherit handles from parent */
@@ -557,7 +544,7 @@ skip_arg_parsing:
   /* We print the original program name here so the user can see that too.  */
   syscall_printf ("%d = spawn_guts (%s, %.132s)",
 		  rc ? pi.dwProcessId : (unsigned int) -1,
-		  prog_arg, copy);
+		  prog_arg, one_line.buf);
 
   if (!rc)
     {

- Raw text -


  webmaster     delorie software   privacy  
  Copyright 2019   by DJ Delorie     Updated Jul 2019