# HG changeset patch
# User Markus Mützel <markus.muetzel@gmx.de>
# Date 1620298803 -7200
#      Thu May 06 13:00:03 2021 +0200
# Node ID c7acf5dc6a3856bab19195eb0ec903b8591ba69b
# Parent  a49e8c0ce9a3e0206998e097f2c5b5bc6ff61322
unistd-wrappers.c: Use prepare_spawn from upstream gnulib (bug #60535).

* liboctave/wrappers/unistd-wrappers.c (prepare_spawn): Remove function.
  (octave_execv_wrapper): Use upstream "prepare_spawn". Add support for
  non-ASCII characters in command line arguments on Windows.
* bootstrap.conf: Add module "windows-spawn" to list.

diff -r a49e8c0ce9a3 -r c7acf5dc6a38 bootstrap.conf
--- a/bootstrap.conf	Thu May 06 11:55:51 2021 +0200
+++ b/bootstrap.conf	Thu May 06 13:00:03 2021 +0200
@@ -130,6 +130,7 @@
   unsetenv
   vasprintf
   waitpid
+  windows-spawn
 "
 
 # Additional gnulib files and scripts used by Octave's buildsystem.
diff -r a49e8c0ce9a3 -r c7acf5dc6a38 liboctave/wrappers/unistd-wrappers.c
--- a/liboctave/wrappers/unistd-wrappers.c	Thu May 06 11:55:51 2021 +0200
+++ b/liboctave/wrappers/unistd-wrappers.c	Thu May 06 13:00:03 2021 +0200
@@ -46,6 +46,10 @@
 #  include <wchar.h>
 #endif
 
+#if defined (__WIN32__) && ! defined (__CYGWIN__)
+#  include "windows-spawn.h"
+#endif
+
 #include "uniconv-wrappers.h"
 #include "unistd-wrappers.h"
 
@@ -114,152 +118,52 @@
   return dup2 (fd1, fd2);
 }
 
-#if defined (__WIN32__) && ! defined (__CYGWIN__)
-
-// Adapted from libtool wrapper.
-
-/* Prepares an argument vector before calling spawn().
-
-   Note that spawn() does not by itself call the command interpreter
-     (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") :
-      ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
-         GetVersionEx(&v);
-         v.dwPlatformId == VER_PLATFORM_WIN32_NT;
-      }) ? "cmd.exe" : "command.com").
-
-   Instead it simply concatenates the arguments, separated by ' ', and calls
-   CreateProcess().  We must quote the arguments since Win32 CreateProcess()
-   interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a
-   special way:
-
-   - Space and tab are interpreted as delimiters. They are not treated as
-     delimiters if they are surrounded by double quotes: "...".
-
-   - Unescaped double quotes are removed from the input. Their only effect is
-     that within double quotes, space and tab are treated like normal
-     characters.
-
-   - Backslashes not followed by double quotes are not special.
-
-   - But 2*n+1 backslashes followed by a double quote become
-     n backslashes followed by a double quote (n >= 0):
-       \" -> "
-       \\\" -> \"
-       \\\\\" -> \\"
- */
-
-#define SHELL_SPECIAL_CHARS \
-  "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
-
-#define SHELL_SPACE_CHARS \
-  " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
-
-static char **
-prepare_spawn (char *const *argv)
-{
-  size_t argc;
-  char **new_argv;
-  size_t i;
-
-  /* Count number of arguments.  */
-  for (argc = 0; argv[argc] != NULL; argc++)
-    ;
-
-  /* Allocate new argument vector.  */
-  new_argv = (char **) malloc ((argc + 1) * sizeof (char *));
-
-  /* Put quoted arguments into the new argument vector.  */
-  for (i = 0; i < argc; i++)
-    {
-      const char *string = argv[i];
-
-      if (string[0] == '\0')
-        new_argv[i] = strdup ("\"\"");
-      else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL)
-        {
-          int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL);
-          size_t length;
-          unsigned int backslashes;
-          const char *s;
-          char *quoted_string;
-          char *p;
-
-          length = 0;
-          backslashes = 0;
-          if (quote_around)
-            length++;
-          for (s = string; *s != '\0'; s++)
-            {
-              char c = *s;
-              if (c == '"')
-                length += backslashes + 1;
-              length++;
-              if (c == '\\')
-                backslashes++;
-              else
-                backslashes = 0;
-            }
-          if (quote_around)
-            length += backslashes + 1;
-
-          quoted_string = (char *) malloc (length + 1);
-
-          p = quoted_string;
-          backslashes = 0;
-          if (quote_around)
-            *p++ = '"';
-          for (s = string; *s != '\0'; s++)
-            {
-              char c = *s;
-              if (c == '"')
-                {
-                  unsigned int j;
-                  for (j = backslashes + 1; j > 0; j--)
-                    *p++ = '\\';
-                }
-              *p++ = c;
-              if (c == '\\')
-                backslashes++;
-              else
-                backslashes = 0;
-            }
-          if (quote_around)
-            {
-              unsigned int j;
-              for (j = backslashes; j > 0; j--)
-                *p++ = '\\';
-              *p++ = '"';
-            }
-          *p = '\0';
-
-          new_argv[i] = quoted_string;
-        }
-      else
-        new_argv[i] = strdup (string);
-    }
-
-  new_argv[argc] = NULL;
-
-  return new_argv;
-}
-
-#endif
-
 int
 octave_execv_wrapper (const char *file, char *const *argv)
 {
 #if defined (__WIN32__) && ! defined (__CYGWIN__)
 
-  char **sanitized_argv = prepare_spawn (argv);
+  char *argv_mem_to_free;
+  char **sanitized_argv = prepare_spawn (argv, &argv_mem_to_free);
+
+#  if defined (OCTAVE_USE_WINDOWS_API) && defined (_UNICODE)
+
+  // count number of arguments
+  size_t argc;
+  for (argc = 0; sanitized_argv[argc] != NULL; argc++)
+    ;
+
+  wchar_t *wfile = u8_to_wchar (file);
+  wchar_t **wargv = new wchar_t * [argc + 1];
+
+  // convert multibyte UTF-8 strings to wide character strings
+  for (int i_arg = 0; i_arg < argc; i_arg++)
+    wargv[i_arg] = u8_to_wchar (sanitized_argv[i_arg]);
+
+  wargv[argc] = nullptr;
+  free (sanitized_argv);
+  free (argv_mem_to_free);
+
+  int status = _wspawnv (P_OVERLAY, wfile, wargv);
+
+  // This only happens if _wspawnv fails.
+
+  free (wfile);
+  wchar_t **p = wargv;
+  while (*p)
+    free (*p++);
+  free (wargv);
+
+#  else
 
   int status = spawnv (P_OVERLAY, file, sanitized_argv);
 
   // This only happens if spawnv fails.
 
-  char **p = sanitized_argv;
-  while (*p)
-    free (*p++);
   free (sanitized_argv);
+  free (argv_mem_to_free);
+
+#  endif
 
   return status;
 
