Skip to content

Commit ff33aa8

Browse files
committed
mingw: replace mingw_startup() hack
Git for Windows has special code to retrieve the command-line parameters (and even the environment) in UTF-16 encoding, so that they can be converted to UTF-8. This is necessary because Git for Windows wants to use UTF-8 encoded strings throughout its code, and the main() function does not get the parameters in that encoding. To do that, we used the __wgetmainargs() function, which is not even a Win32 API function, but provided by the MINGW "runtime" instead. Obviously, this method would not work with any other compiler than GCC, and in preparation for compiling with Visual C++, we would like to avoid that. Lucky us, there is a much more elegant way: we simply implement wmain() and link with -municode. The command-line parameters are passed to wmain() encoded in UTF-16, as desired, and this method also works with Visual C++ after adjusting the MSVC linker flags to force it to use wmain(). Signed-off-by: Johannes Schindelin <[email protected]>
1 parent 2ca6115 commit ff33aa8

File tree

3 files changed

+47
-31
lines changed

3 files changed

+47
-31
lines changed

compat/mingw.c

Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2473,18 +2473,13 @@ static void setup_windows_environment(void)
24732473
setenv("TERM", "cygwin", 1);
24742474
}
24752475

2476+
#if !defined(_MSC_VER)
24762477
/*
24772478
* Disable MSVCRT command line wildcard expansion (__getmainargs called from
24782479
* mingw startup code, see init.c in mingw runtime).
24792480
*/
24802481
int _CRT_glob = 0;
2481-
2482-
typedef struct {
2483-
int newmode;
2484-
} _startupinfo;
2485-
2486-
extern int __wgetmainargs(int *argc, wchar_t ***argv, wchar_t ***env, int glob,
2487-
_startupinfo *si);
2482+
#endif
24882483

24892484
static NORETURN void die_startup(void)
24902485
{
@@ -2562,22 +2557,25 @@ static void maybe_redirect_std_handles(void)
25622557
GENERIC_WRITE, FILE_FLAG_NO_BUFFERING);
25632558
}
25642559

2565-
void mingw_startup(void)
2560+
/*
2561+
* We implement wmain() and compile with -municode, which would
2562+
* normally ignore main(), but we call the latter from the former
2563+
* so that we can handle non-ASCII command-line parameters
2564+
* appropriately.
2565+
*
2566+
* To be more compatible with the core git code, we convert
2567+
* argv into UTF8 and pass them directly to main().
2568+
*/
2569+
int wmain(int argc, const wchar_t **wargv)
25662570
{
2567-
int i, maxlen, argc;
2568-
char *buffer;
2569-
wchar_t **wenv, **wargv;
2570-
_startupinfo si;
2571+
int i, maxlen, exit_status;
2572+
char *buffer, **save;
2573+
const char **argv;
25712574

25722575
trace2_initialize_clock();
25732576

25742577
maybe_redirect_std_handles();
25752578

2576-
/* get wide char arguments and environment */
2577-
si.newmode = 0;
2578-
if (__wgetmainargs(&argc, &wargv, &wenv, _CRT_glob, &si) < 0)
2579-
die_startup();
2580-
25812579
/* determine size of argv and environ conversion buffer */
25822580
maxlen = wcslen(wargv[0]);
25832581
for (i = 1; i < argc; i++)
@@ -2587,9 +2585,16 @@ void mingw_startup(void)
25872585
maxlen = 3 * maxlen + 1;
25882586
buffer = malloc_startup(maxlen);
25892587

2590-
/* convert command line arguments and environment to UTF-8 */
2588+
/*
2589+
* Create a UTF-8 version of w_argv. Also create a "save" copy
2590+
* to remember all the string pointers because parse_options()
2591+
* will remove claimed items from the argv that we pass down.
2592+
*/
2593+
ALLOC_ARRAY(argv, argc + 1);
2594+
ALLOC_ARRAY(save, argc + 1);
25912595
for (i = 0; i < argc; i++)
2592-
__argv[i] = wcstoutfdup_startup(buffer, wargv[i], maxlen);
2596+
argv[i] = save[i] = wcstoutfdup_startup(buffer, wargv[i], maxlen);
2597+
argv[i] = save[i] = NULL;
25932598
free(buffer);
25942599

25952600
/* fix Windows specific environment settings */
@@ -2608,6 +2613,16 @@ void mingw_startup(void)
26082613

26092614
/* initialize Unicode console */
26102615
winansi_init();
2616+
2617+
/* invoke the real main() using our utf8 version of argv. */
2618+
exit_status = main(argc, argv);
2619+
2620+
for (i = 0; i < argc; i++)
2621+
free(save[i]);
2622+
free(save);
2623+
free(argv);
2624+
2625+
return exit_status;
26112626
}
26122627

26132628
int uname(struct utsname *buf)

compat/mingw.h

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -570,18 +570,18 @@ int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen);
570570
extern CRITICAL_SECTION pinfo_cs;
571571

572572
/*
573-
* A replacement of main() that adds win32 specific initialization.
573+
* Git, like most portable C applications, implements a main() function. On
574+
* Windows, this main() function would receive parameters encoded in the
575+
* current locale, but Git for Windows would prefer UTF-8 encoded parameters.
576+
*
577+
* To make that happen, we still declare main() here, and then declare and
578+
* implement wmain() (which is the Unicode variant of main()) and compile with
579+
* -municode. This wmain() function reencodes the parameters from UTF-16 to
580+
* UTF-8 format, sets up a couple of other things as required on Windows, and
581+
* then hands off to the main() function.
574582
*/
575-
576-
void mingw_startup(void);
577-
#define main(c,v) dummy_decl_mingw_main(void); \
578-
static int mingw_main(c,v); \
579-
int main(int argc, const char **argv) \
580-
{ \
581-
mingw_startup(); \
582-
return mingw_main(__argc, (void *)__argv); \
583-
} \
584-
static int mingw_main(c,v)
583+
int wmain(int argc, const wchar_t **w_argv);
584+
int main(int argc, const char **argv);
585585

586586
/*
587587
* Used by Pthread API implementation for Windows

config.mak.uname

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ ifeq ($(uname_S),Windows)
401401
compat/win32/trace2_win32_process_info.o \
402402
compat/win32/dirent.o
403403
COMPAT_CFLAGS = -D__USE_MINGW_ACCESS -DNOGDI -DHAVE_STRING_H -Icompat -Icompat/regex -Icompat/win32 -DSTRIP_EXTENSION=\".exe\"
404-
BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -SUBSYSTEM:CONSOLE
404+
BASIC_LDFLAGS = -IGNORE:4217 -IGNORE:4049 -NOLOGO -ENTRY:wmainCRTStartup -SUBSYSTEM:CONSOLE
405405
EXTLIBS = user32.lib advapi32.lib shell32.lib wininet.lib ws2_32.lib invalidcontinue.obj
406406
PTHREAD_LIBS =
407407
lib =
@@ -548,6 +548,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
548548
ETAGS_TARGET = ETAGS
549549
NO_POSIX_GOODIES = UnfortunatelyYes
550550
DEFAULT_HELP_FORMAT = html
551+
BASIC_LDFLAGS += -municode
551552
COMPAT_CFLAGS += -DNOGDI -Icompat -Icompat/win32
552553
COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
553554
COMPAT_OBJS += compat/mingw.o compat/winansi.o \

0 commit comments

Comments
 (0)