[m-rev.] for review: unicode command line arguments on windows

Julien Fischer juliensf at csse.unimelb.edu.au
Fri Dec 16 04:56:28 AEDT 2011


On Thu, 15 Dec 2011, Peter Wang wrote:

> On Thu, 15 Dec 2011 17:32:06 +1100 (EST), Julien Fischer <juliensf at csse.unimelb.edu.au> wrote:
>>
>> Ok, let me try and get this straight:
>>
>> (1) __wgetmainargs works with MinGW
>> (2) wmain works with MSVC
>
> Yes.
>
>> So let's do that - I would actually make the code conditional on MR_MSVC
>> rather than MR_MINGW though.  I suggest breaking mercury_win32_args in
>> two since the lower part of it should be usable by both of them.
>
> I would make __wgetmainargs conditional on MR_MINGW and wmain
> conditional on MR_MSVC until we know either works with other compilers.
>
>>
>>> It's probably better for you to modify the patch and commit it directly.
>>
>> That's fine with me.
>
> Thanks, I'll leave it to you.

The following diff fixes the problem for MinGW and MSVC.  Cygwin and clang
will currently fall back to not supporting Unicode command-line arguments.
It incoporates your change to use __wgetmainargs for the MinGW case.
There's a tiny bit of code duplication below, but I think keeping the MSVC
version completely separate is an aid to readibility in this case.

Julien.

-----------------------------

Branches: main, 11.07

Fix handling of Unicode command-line arguments on Windows with either MinGW or
MSVC.  (For other compilers on Windows, Unicode command-line arguments are not
currently supported.)

The existing approach using GetCommandLineW and CommandLineToArgW caused the
command-line to be parsed in a weird way, e.g. for

    c:\> "C:\ws"\foo.exe

argv[0] was split in two:

    ["c:\ws", "\foo.exe"]

util/mkinit.c:
 	Use wmain instead of main with MSVC; this gives us direct access
 	to the wide version of the argument vector.

 	Use __wgetmainargs to get the wide version of the command-line
 	arguments with MinGW.  MinGW doesn't support wmain so we can't
 	use that.

 	Don't include shellapi.h on Windows, it's no longer required.

compiler/compile_target_code.m:
 	Use the wide entry point to the C runtime with MSVC so that
 	wmain is invoke isntead of main.

Julien.

Index: compiler/compile_target_code.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/compile_target_code.m,v
retrieving revision 1.180
diff -u -r1.180 compile_target_code.m
--- compiler/compile_target_code.m	7 Dec 2011 09:17:41 -0000	1.180
+++ compiler/compile_target_code.m	15 Dec 2011 17:36:23 -0000
@@ -2449,7 +2449,7 @@
                      "-nologo",
                      "-subsystem:console",
                      "-machine:x86",
-                    "-entry:mainCRTStartup",
+                    "-entry:wmainCRTStartup",
                      "-defaultlib:libcmt"
                  ],
                  join_string_list(ResCmdLinkFlags, "", "", " ", ResCmdLinkOpts)
Index: util/mkinit.c
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/util/mkinit.c,v
retrieving revision 1.126
diff -u -r1.126 mkinit.c
--- util/mkinit.c	14 Dec 2011 05:12:42 -0000	1.126
+++ util/mkinit.c	15 Dec 2011 17:36:36 -0000
@@ -329,7 +329,6 @@
      "#include \"mercury_grade.h\"\n"
      "#ifdef MR_WIN32\n"
      "  #include \"mercury_windows.h\"\n"
-    "  #include <shellapi.h>\n"
      "#endif\n"
      "\n"
      "#define MR_TRACE_ENABLED %d\n"
@@ -539,17 +538,15 @@
      ** Convert wide-character representation of the command line
      ** arguments to UTF-8.
      */
-    "#ifdef MR_WIN32\n"
+    "#if defined(MR_MSVC)\n"
      "static char **\n"
-    "mercury_win32_args(int *argc_ptr)\n"
+    "mercury_msvc_args(int argc, wchar_t **wargv)\n"
      "{\n"
-    "   LPWSTR  *wargv;\n"
      "   char    **argv;\n"
      "   int     i;\n"
      "\n"
-    "   wargv = CommandLineToArgvW(GetCommandLineW(), argc_ptr);\n"
-    "   argv = MR_GC_NEW_ARRAY(char *, (*argc_ptr + 1));\n"
-    "   for (i = 0; i < (*argc_ptr); i++) {\n"
+    "   argv = MR_GC_NEW_ARRAY(char *, argc + 1);\n"
+    "   for (i = 0; i < argc; i++) {\n"
      "       int bytes = WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1,\n"
      "           NULL, 0, NULL, NULL);\n"
      "       argv[i] = MR_GC_malloc(bytes);\n"
@@ -557,9 +554,36 @@
      "           argv[i], bytes, NULL, NULL);\n"
      "   }\n"
      "   argv[i] = NULL;\n"
-    "   LocalFree(wargv);\n"
      "   return argv;\n"
      "}\n"
+    "#elif defined(MR_MINGW)\n"
+    "extern int __wgetmainargs(int *, wchar_t ***, wchar_t ***, int, int *);\n"
+    "\n"
+    "static void\n"
+    "mercury_win32_args(int *argc_ret, char ***argv_ret)\n"
+    "{\n"
+    "   int     argc;\n"
+    "   char    **argv;\n"
+    "   wchar_t **wargv;\n"
+    "   wchar_t **wenv;\n"
+    "   int     start_info = 0;\n"
+    "   int     i;\n"
+    "\n"
+    "   if (__wgetmainargs(&argc, &wargv, &wenv, 0, &start_info) != 0) {\n"
+    "       return;\n"
+    "   }\n"
+    "   argv = MR_GC_NEW_ARRAY(char *, argc + 1);\n"
+    "   for (i = 0; i < argc; i++) {\n"
+    "       int bytes = WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1,\n"
+    "           NULL, 0, NULL, NULL);\n"
+    "       argv[i] = MR_GC_malloc(bytes);\n"
+    "       WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1,\n"
+    "           argv[i], bytes, NULL, NULL);\n"
+    "   }\n"
+    "   argv[i] = NULL;\n"
+    "   *argc_ret = argc;\n"
+    "   *argv_ret = argv;\n"
+    "}\n"
      "#endif\n"
      "\n"
      ;
@@ -571,6 +595,19 @@
      ;

  static const char main_func[] =
+    "#if defined(MR_MSVC)\n"
+    "\n"
+    "int\n"
+    "wmain(int argc, wchar_t **wargv)\n"
+    "{\n"
+    "    int    result;\n"
+    "    char   **argv;\n"
+    "\n"
+    "    argv = mercury_msvc_args(argc, wargv);\n"
+    "    result = mercury_main(argc, argv);\n"
+    "    return result;\n"
+    "}\n"
+    "#else\n"
      "\n"
      "int\n"
      "main(int argc, char **argv)\n"
@@ -583,8 +620,8 @@
      "#ifdef MR_PROFILE_SBRK\n"
      "   old_break = sbrk(0);\n"
      "#endif\n"
-    "#ifdef MR_WIN32\n"
-    "   argv = mercury_win32_args(&argc);\n"
+    "#ifdef MR_MINGW\n"
+    "   mercury_win32_args(&argc, &argv);\n"
      "#endif\n"
      "   result = mercury_main(argc, argv);\n"
      "#ifdef MR_PROFILE_SBRK\n"
@@ -594,6 +631,7 @@
      "#endif\n"
      "   return result;\n"
      "}\n"
+    "#endif\n"
      ;

  /* --- function prototypes --- */
--------------------------------------------------------------------------
mercury-reviews mailing list
Post messages to:       mercury-reviews at csse.unimelb.edu.au
Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
Subscriptions:          mercury-reviews-request at csse.unimelb.edu.au
--------------------------------------------------------------------------



More information about the reviews mailing list