[glib: 1/2] W32: swap special g_get_prgname() for platform_get_argv0()



commit cf39fbd08d063954f801aef23145dbf00290d9bb
Author: LRN <lrn1986 gmail com>
Date:   Tue Apr 16 08:40:55 2019 +0000

    W32: swap special g_get_prgname() for platform_get_argv0()
    
    Commit 398008da added a W32-only code (from commit 7e0e251a)
    to g_get_prgname() that makes this function never return NULL. This
    is inconsistent with the other platforms. Revert the change, and add an
    implementation for platform_get_argv0(), which is used by GOption when
    g_get_prgname() == NULL.
    
    The W32 platform_get_argv0() code is different from the one that was in
    g_get_prgname(), because it should be getting argv0, not the name
    of the executable that is being run (although most of the time they are
    one and the same).
    
    Adjust thest option-argv0 test to expect it to pass on W32.

 glib/goption.c            | 49 +++++++++++++++++++++++++++++++++++++++++++++++
 glib/gutils.c             | 23 ----------------------
 glib/tests/option-argv0.c |  8 ++++++--
 3 files changed, 55 insertions(+), 25 deletions(-)
---
diff --git a/glib/goption.c b/glib/goption.c
index 8494ca739..183e9d9d3 100644
--- a/glib/goption.c
+++ b/glib/goption.c
@@ -194,6 +194,10 @@
 #include "gprintf.h"
 #include "glibintl.h"
 
+#if defined G_OS_WIN32
+#include <windows.h>
+#endif
+
 #define TRANSLATE(group, str) (((group)->translate_func ? (* (group)->translate_func) ((str), 
(group)->translate_data) : (str)))
 
 #define NO_ARG(entry) ((entry)->arg == G_OPTION_ARG_NONE ||       \
@@ -1860,6 +1864,51 @@ platform_get_argv0 (void)
   base_arg0 = g_path_get_basename (*cmdline);
   g_free (cmdline);
   return base_arg0;
+#elif defined G_OS_WIN32
+  const wchar_t *cmdline;
+  wchar_t **wargv;
+  int wargc;
+  gchar *utf8_buf = NULL;
+  char *base_arg0 = NULL;
+
+  /* Pretend it's const, since we're not allowed to free it */
+  cmdline = (const wchar_t *) GetCommandLineW ();
+  if (G_UNLIKELY (cmdline == NULL))
+    return NULL;
+
+  /* Skip leading whitespace. CommandLineToArgvW() is documented
+   * to behave weirdly with that. The character codes below
+   * correspond to the *only* unicode characters that are
+   * considered to be spaces by CommandLineToArgvW(). The rest
+   * (such as 0xa0 - NO-BREAK SPACE) are treated as
+   * normal characters.
+   */
+  while (cmdline[0] == 0x09 ||
+         cmdline[0] == 0x0a ||
+         cmdline[0] == 0x0c ||
+         cmdline[0] == 0x0d ||
+         cmdline[0] == 0x20)
+    cmdline++;
+
+  wargv = CommandLineToArgvW (cmdline, &wargc);
+  if (G_UNLIKELY (wargv == NULL))
+    return NULL;
+
+  if (wargc > 0)
+    utf8_buf = g_utf16_to_utf8 (wargv[0], -1, NULL, NULL, NULL);
+
+  LocalFree (wargv);
+
+  if (G_UNLIKELY (utf8_buf == NULL))
+    return NULL;
+
+  /* We could just return cmdline, but I think it's better
+   * to hold on to a smaller malloc block; the arguments
+   * could be large.
+   */
+  base_arg0 = g_path_get_basename (utf8_buf);
+  g_free (utf8_buf);
+  return base_arg0;
 #endif
 
   return NULL;
diff --git a/glib/gutils.c b/glib/gutils.c
index b4ca1cc3f..766248dec 100644
--- a/glib/gutils.c
+++ b/glib/gutils.c
@@ -1047,29 +1047,6 @@ g_get_prgname (void)
   gchar* retval;
 
   G_LOCK (g_prgname);
-#ifdef G_OS_WIN32
-  if (g_prgname == NULL)
-    {
-      static gboolean beenhere = FALSE;
-
-      if (!beenhere)
-       {
-         gchar *utf8_buf = NULL;
-         wchar_t buf[MAX_PATH+1];
-
-         beenhere = TRUE;
-         if (GetModuleFileNameW (GetModuleHandle (NULL),
-                                 buf, G_N_ELEMENTS (buf)) > 0)
-           utf8_buf = g_utf16_to_utf8 (buf, -1, NULL, NULL, NULL);
-
-         if (utf8_buf)
-           {
-             g_prgname = g_path_get_basename (utf8_buf);
-             g_free (utf8_buf);
-           }
-       }
-    }
-#endif
   retval = g_prgname;
   G_UNLOCK (g_prgname);
 
diff --git a/glib/tests/option-argv0.c b/glib/tests/option-argv0.c
index f977625b5..5b626df70 100644
--- a/glib/tests/option-argv0.c
+++ b/glib/tests/option-argv0.c
@@ -51,7 +51,8 @@ test_platform_argv0 (void)
   /* This test must pass on platforms where platform_get_argv0()
    * is implemented. At the moment that means Linux/Cygwin,
    * (which uses /proc/self/cmdline) or OpenBSD (which uses
-   * sysctl and KERN_PROC_ARGS). On other platforms the test
+   * sysctl and KERN_PROC_ARGS) or Windows (which uses
+   * GetCommandlineW ()). On other platforms the test
    * is not expected to pass, but we'd still want to know
    * how it does (the test code itself doesn't use any platform-specific
    * functionality, the difference is internal to glib, so it's quite
@@ -60,7 +61,10 @@ test_platform_argv0 (void)
    * to prevent them from crashing hard on failed assertions,
    * and make them call g_test_skip() instead.
    */
-#if !defined HAVE_PROC_SELF_CMDLINE && !defined __OpenBSD__ && !defined __linux
+#if !defined HAVE_PROC_SELF_CMDLINE && \
+    !defined __OpenBSD__ && \
+    !defined __linux && \
+    !defined G_OS_WIN32
   fatal_errors = FALSE;
 #endif
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]