Fix typo: Should be SOCKET_ERROR, not SO_ERROR. Noticed by Daniel
authorTor Lillqvist <tml@iki.fi>
Tue, 4 Feb 2003 23:37:04 +0000 (23:37 +0000)
committerTor Lillqvist <tml@src.gnome.org>
Tue, 4 Feb 2003 23:37:04 +0000 (23:37 +0000)
2003-02-04  Tor Lillqvist  <tml@iki.fi>

* glib/giowin32.c (g_io_channel_unix_new): Fix typo: Should be
SOCKET_ERROR, not SO_ERROR. Noticed by Daniel Kaufmann.

Merge from stable branch:

Fix for bug #104014, reported by Alex Shaduri:

* glib/gspawn-win32.c (protect_argv): New function. Add
double-quotes around argv elements that need it, and escape
embedded double-quotes with backslash.
(do_spawn_with_pipes) Call protect_argv().

* glib/gspawn-win32-helper.c (WinMain): Call protect_argv().

* glib/gspawn.c (g_spawn_async_with_pipes): Document argument
vector vs. command line details on Win32.
(g_spawn_command_line_sync): Improve documentation about
backslashes in the command line on Windows.

ChangeLog
ChangeLog.pre-2-10
ChangeLog.pre-2-12
ChangeLog.pre-2-4
ChangeLog.pre-2-6
ChangeLog.pre-2-8
glib/giowin32.c
glib/gspawn-win32-helper.c
glib/gspawn-win32.c
glib/gspawn.c

index 4bb5f78..62f9bd0 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,24 @@
+2003-02-04  Tor Lillqvist  <tml@iki.fi>
+
+       * glib/giowin32.c (g_io_channel_unix_new): Fix typo: Should be
+       SOCKET_ERROR, not SO_ERROR. Noticed by Daniel Kaufmann.
+       
+       Merge from stable branch: 
+
+       Fix for bug #104014, reported by Alex Shaduri:
+       
+       * glib/gspawn-win32.c (protect_argv): New function. Add
+       double-quotes around argv elements that need it, and escape
+       embedded double-quotes with backslash.
+       (do_spawn_with_pipes) Call protect_argv().
+
+       * glib/gspawn-win32-helper.c (WinMain): Call protect_argv().
+
+       * glib/gspawn.c (g_spawn_async_with_pipes): Document argument
+       vector vs. command line details on Win32.
+       (g_spawn_command_line_sync): Improve documentation about
+       backslashes in the command line on Windows.
+
 Thu Jan 30 16:45:13 2003  Owen Taylor  <otaylor@redhat.com>
 
         * Makefile.am: Remove references to glib.spec.
index 4bb5f78..62f9bd0 100644 (file)
@@ -1,3 +1,24 @@
+2003-02-04  Tor Lillqvist  <tml@iki.fi>
+
+       * glib/giowin32.c (g_io_channel_unix_new): Fix typo: Should be
+       SOCKET_ERROR, not SO_ERROR. Noticed by Daniel Kaufmann.
+       
+       Merge from stable branch: 
+
+       Fix for bug #104014, reported by Alex Shaduri:
+       
+       * glib/gspawn-win32.c (protect_argv): New function. Add
+       double-quotes around argv elements that need it, and escape
+       embedded double-quotes with backslash.
+       (do_spawn_with_pipes) Call protect_argv().
+
+       * glib/gspawn-win32-helper.c (WinMain): Call protect_argv().
+
+       * glib/gspawn.c (g_spawn_async_with_pipes): Document argument
+       vector vs. command line details on Win32.
+       (g_spawn_command_line_sync): Improve documentation about
+       backslashes in the command line on Windows.
+
 Thu Jan 30 16:45:13 2003  Owen Taylor  <otaylor@redhat.com>
 
         * Makefile.am: Remove references to glib.spec.
index 4bb5f78..62f9bd0 100644 (file)
@@ -1,3 +1,24 @@
+2003-02-04  Tor Lillqvist  <tml@iki.fi>
+
+       * glib/giowin32.c (g_io_channel_unix_new): Fix typo: Should be
+       SOCKET_ERROR, not SO_ERROR. Noticed by Daniel Kaufmann.
+       
+       Merge from stable branch: 
+
+       Fix for bug #104014, reported by Alex Shaduri:
+       
+       * glib/gspawn-win32.c (protect_argv): New function. Add
+       double-quotes around argv elements that need it, and escape
+       embedded double-quotes with backslash.
+       (do_spawn_with_pipes) Call protect_argv().
+
+       * glib/gspawn-win32-helper.c (WinMain): Call protect_argv().
+
+       * glib/gspawn.c (g_spawn_async_with_pipes): Document argument
+       vector vs. command line details on Win32.
+       (g_spawn_command_line_sync): Improve documentation about
+       backslashes in the command line on Windows.
+
 Thu Jan 30 16:45:13 2003  Owen Taylor  <otaylor@redhat.com>
 
         * Makefile.am: Remove references to glib.spec.
index 4bb5f78..62f9bd0 100644 (file)
@@ -1,3 +1,24 @@
+2003-02-04  Tor Lillqvist  <tml@iki.fi>
+
+       * glib/giowin32.c (g_io_channel_unix_new): Fix typo: Should be
+       SOCKET_ERROR, not SO_ERROR. Noticed by Daniel Kaufmann.
+       
+       Merge from stable branch: 
+
+       Fix for bug #104014, reported by Alex Shaduri:
+       
+       * glib/gspawn-win32.c (protect_argv): New function. Add
+       double-quotes around argv elements that need it, and escape
+       embedded double-quotes with backslash.
+       (do_spawn_with_pipes) Call protect_argv().
+
+       * glib/gspawn-win32-helper.c (WinMain): Call protect_argv().
+
+       * glib/gspawn.c (g_spawn_async_with_pipes): Document argument
+       vector vs. command line details on Win32.
+       (g_spawn_command_line_sync): Improve documentation about
+       backslashes in the command line on Windows.
+
 Thu Jan 30 16:45:13 2003  Owen Taylor  <otaylor@redhat.com>
 
         * Makefile.am: Remove references to glib.spec.
index 4bb5f78..62f9bd0 100644 (file)
@@ -1,3 +1,24 @@
+2003-02-04  Tor Lillqvist  <tml@iki.fi>
+
+       * glib/giowin32.c (g_io_channel_unix_new): Fix typo: Should be
+       SOCKET_ERROR, not SO_ERROR. Noticed by Daniel Kaufmann.
+       
+       Merge from stable branch: 
+
+       Fix for bug #104014, reported by Alex Shaduri:
+       
+       * glib/gspawn-win32.c (protect_argv): New function. Add
+       double-quotes around argv elements that need it, and escape
+       embedded double-quotes with backslash.
+       (do_spawn_with_pipes) Call protect_argv().
+
+       * glib/gspawn-win32-helper.c (WinMain): Call protect_argv().
+
+       * glib/gspawn.c (g_spawn_async_with_pipes): Document argument
+       vector vs. command line details on Win32.
+       (g_spawn_command_line_sync): Improve documentation about
+       backslashes in the command line on Windows.
+
 Thu Jan 30 16:45:13 2003  Owen Taylor  <otaylor@redhat.com>
 
         * Makefile.am: Remove references to glib.spec.
index 4bb5f78..62f9bd0 100644 (file)
@@ -1,3 +1,24 @@
+2003-02-04  Tor Lillqvist  <tml@iki.fi>
+
+       * glib/giowin32.c (g_io_channel_unix_new): Fix typo: Should be
+       SOCKET_ERROR, not SO_ERROR. Noticed by Daniel Kaufmann.
+       
+       Merge from stable branch: 
+
+       Fix for bug #104014, reported by Alex Shaduri:
+       
+       * glib/gspawn-win32.c (protect_argv): New function. Add
+       double-quotes around argv elements that need it, and escape
+       embedded double-quotes with backslash.
+       (do_spawn_with_pipes) Call protect_argv().
+
+       * glib/gspawn-win32-helper.c (WinMain): Call protect_argv().
+
+       * glib/gspawn.c (g_spawn_async_with_pipes): Document argument
+       vector vs. command line details on Win32.
+       (g_spawn_command_line_sync): Improve documentation about
+       backslashes in the command line on Windows.
+
 Thu Jan 30 16:45:13 2003  Owen Taylor  <otaylor@redhat.com>
 
         * Makefile.am: Remove references to glib.spec.
index fdf5be5..a7277b7 100644 (file)
@@ -1494,7 +1494,7 @@ g_io_channel_unix_new (gint fd)
   if (fstat (fd, &st) == 0)
     return g_io_channel_win32_new_fd_internal (fd, &st);
   
-  if (getsockopt (fd, SOL_SOCKET, SO_TYPE, NULL, NULL) != SO_ERROR)
+  if (getsockopt (fd, SOL_SOCKET, SO_TYPE, NULL, NULL) != SOCKET_ERROR)
     return g_io_channel_win32_new_socket(fd);
 
   g_warning (G_STRLOC ": %d is neither a file descriptor or a socket", fd);
index 18a398e..9f9af68 100644 (file)
@@ -76,6 +76,7 @@ WinMain (struct HINSTANCE__ *hInstance,
   int handle;
   int no_error = CHILD_NO_ERROR;
   int zero = 0;
+  gchar **new_argv;
 
   SETUP_DEBUG();
 
@@ -204,6 +205,11 @@ WinMain (struct HINSTANCE__ *hInstance,
    * __argv[ARG_PROGRAM+1]... is its __argv.
    */
 
+  protect_argv (__argv, &new_argv);
+
+  /* For the program name passed to spawnv(), don't use the quoted
+   * version. */
+
   if (debug)
     {
       debugstring = g_string_new ("");
@@ -215,19 +221,19 @@ WinMain (struct HINSTANCE__ *hInstance,
                                        (mode == P_WAIT ?
                                         "P_WAIT" : "P_NOWAIT")));
       i = ARG_PROGRAM+1;
-      while (__argv[i])
+      while (new_argv[i])
        {
-         g_string_append (debugstring, __argv[i++]);
-         if (__argv[i])
+         g_string_append (debugstring, new_argv[i++]);
+         if (new_argv[i])
            g_string_append (debugstring, " ");
        }
       MessageBox (NULL, debugstring->str, "gspawn-win32-helper", 0);
     }
 
-  if (__argv[ARG_USE_PATH][0] == 'y')
-    handle = spawnvp (mode, __argv[ARG_PROGRAM], __argv+ARG_PROGRAM);
+  if (new_argv[ARG_USE_PATH][0] == 'y')
+    handle = spawnvp (mode, __argv[ARG_PROGRAM], new_argv+ARG_PROGRAM);
   else
-    handle = spawnv (mode, __argv[ARG_PROGRAM], __argv+ARG_PROGRAM);
+    handle = spawnv (mode, __argv[ARG_PROGRAM], new_argv+ARG_PROGRAM);
 
   if (debug)
     {
index fc5cb43..66cfe53 100644 (file)
@@ -97,6 +97,84 @@ enum {
   ARG_COUNT = ARG_PROGRAM
 };
 
+static gint
+protect_argv (gchar  **argv,
+             gchar ***new_argv)
+{
+  gint i;
+  gint argc = 0;
+  
+  while (argv[argc])
+    ++argc;
+  *new_argv = g_new (gchar *, argc+1);
+
+  /* Quote each argv element if necessary, so that it will get
+   * reconstructed correctly in the C runtime startup code.  Note that
+   * the unquoting algorithm in the C runtime is really weird, and
+   * rather different than what Unix shells do. See stdargv.c in the C
+   * runtime sources (in the Platform SDK, in src/crt).
+   *
+   * Note that an new_argv[0] constructed by this function should
+   * *not* be passed as the filename argument to a spawn* or exec*
+   * family function. That argument should be the real file name
+   * without any quoting.
+   */
+  for (i = 0; i < argc; i++)
+    {
+      gchar *p = argv[i];
+      gchar *q;
+      gint len = 0;
+      gboolean need_dblquotes = FALSE;
+      while (*p)
+       {
+         if (*p == ' ' || *p == '\t')
+           need_dblquotes = TRUE;
+         else if (*p == '"')
+           len++;
+         else if (*p == '\\')
+           {
+             gchar *pp = p;
+             while (*pp && *pp == '\\')
+               pp++;
+             if (*pp == '"')
+               len++;
+           }
+         len++;
+         p++;
+       }
+
+      q = (*new_argv)[i] = g_malloc (len + need_dblquotes*2 + 1);
+      p = argv[i];
+
+      if (need_dblquotes)
+       *q++ = '"';
+
+      while (*p)
+       {
+         if (*p == '"')
+           *q++ = '\\';
+         else if (*p == '\\')
+           {
+             gchar *pp = p;
+             while (*pp && *pp == '\\')
+               pp++;
+             if (*pp == '"')
+               *q++ = '\\';
+           }
+         *q++ = *p;
+         p++;
+       }
+
+      if (need_dblquotes)
+       *q++ = '"';
+      *q++ = '\0';
+      /* printf ("argv[%d]:%s, need_dblquotes:%s len:%d => %s\n", i, argv[i], need_dblquotes?"TRUE":"FALSE", len, (*new_argv)[i]); */
+    }
+  (*new_argv)[argc] = NULL;
+
+  return argc;
+}
+
 #ifndef GSPAWN_HELPER
 
 static gboolean make_pipe            (gint                  p[2],
@@ -746,6 +824,9 @@ do_spawn_with_pipes (gboolean              dont_wait,
   gint helper = -1;
   gint buf[2];
   gint n_ints = 0;
+  gint i;
+  gint argc;
+  gchar **new_argv;
   
   if (!make_pipe (child_err_report_pipe, error))
     return FALSE;
@@ -759,13 +840,15 @@ do_spawn_with_pipes (gboolean              dont_wait,
   if (standard_error && !make_pipe (stderr_pipe, error))
     goto cleanup_and_fail;
 
+  argc = protect_argv (argv, &new_argv);
+
   helper = do_spawn (dont_wait,
                     child_err_report_pipe[1],
                     stdin_pipe[0],
                     stdout_pipe[1],
                     stderr_pipe[1],
                     working_directory,
-                    argv,
+                    new_argv,
                     envp,
                     close_descriptors,
                     search_path,
@@ -775,6 +858,10 @@ do_spawn_with_pipes (gboolean              dont_wait,
                     child_setup,
                     user_data);
       
+  for (i = 0; i < argc; i++)
+    g_free (new_argv[i]);
+  g_free (new_argv);
+
   /* do_spawn() returns -1 if gspawn-win32-helper couldn't be run */
   if (helper == -1)
     {
index 165d995..be31eed 100644 (file)
@@ -432,6 +432,24 @@ g_spawn_sync (const gchar          *working_directory,
  * the program must be a full path; the <envar>PATH</envar> shell variable 
  * will only be searched if you pass the %G_SPAWN_SEARCH_PATH flag.
  *
+ * On Windows, the low-level child process creation API
+ * (<function>CreateProcess()</function>)doesn't use argument vectors,
+ * but a command line. The C runtime library's
+ * <function>spawn*()</function> family of functions (which
+ * g_spawn_async_with_pipes() eventually calls) paste the argument
+ * vector elements into a command line, and the C runtime startup code
+ * does a corresponding recostruction of an argument vector from the
+ * command line, to be passed to
+ * <function>main()</function>. Complications arise when you have
+ * argument vector elements that contain spaces of double quotes. The
+ * <function>spawn()</function> functions don't do any quoting or
+ * escaping, but on the other hand the startup code does do unquoting
+ * and unescaping in order to enable receiving arguments with embedded
+ * spaces or double quotes. To work around this asymmetry,
+ * g_spawn_async_with_pipes() will do quoting and escaping on argument
+ * vector elements that need it before calling the C runtime
+ * <function>spawn()</function> function.
+ *
  * @envp is a %NULL-terminated array of strings, where each string
  * has the form <literal>KEY=VALUE</literal>. This will become
  * the child's environment. If @envp is %NULL, the child inherits its
@@ -584,11 +602,11 @@ g_spawn_async_with_pipes (const gchar          *working_directory,
  * 
  * On Windows, please note the implications of g_shell_parse_argv()
  * parsing @command_line. Space is a separator, and backslashes are
- * special. Thus you cannot simply pass a @command_line consisting of
- * a canonical Windows path, like "c:\\program files\\app\\app.exe",
- * as the backslashes will be eaten, and the space will act as a
- * separator. You need to enclose the path with single quotes, like
- * "'c:\\program files\\app\\app.exe'".
+ * special. Thus you cannot simply pass a @command_line containing
+ * canonical Windows paths, like "c:\\program files\\app\\app.exe", as
+ * the backslashes will be eaten, and the space will act as a
+ * separator. You need to enclose such paths with single quotes, like
+ * "'c:\\program files\\app\\app.exe' 'e:\\folder\\argument.txt'".
  *
  * Return value: %TRUE on success, %FALSE if an error was set
  **/