Skip to content

Commit b502ee2

Browse files
committed
msvc: provide a main() wrapper similar to mingw_main()
The MINGW version of the main() wrapper gets away with declaring symbols that were intentionally not exported. However, some of these symbols do not actually exist in MSVC's UCRT. So let's add an MSVC version of the main() wrapper that uses wmain() and imports the UNICODE argv and environment. While at it, we pass our UTF-8 version of ARGV to the real main -- rather than overwriting __argv as is done in the MINGW Version. Signed-off-by: Jeff Hostetler <[email protected]>
1 parent 35131b3 commit b502ee2

File tree

2 files changed

+114
-0
lines changed

2 files changed

+114
-0
lines changed

compat/mingw.c

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2913,6 +2913,7 @@ int handle_long_path(wchar_t *path, int len, int max_path, int expand)
29132913
}
29142914
}
29152915

2916+
#if !defined(_MSC_VER)
29162917
/*
29172918
* Disable MSVCRT command line wildcard expansion (__getmainargs called from
29182919
* mingw startup code, see init.c in mingw runtime).
@@ -2925,6 +2926,7 @@ typedef struct {
29252926

29262927
extern int __wgetmainargs(int *argc, wchar_t ***argv, wchar_t ***env, int glob,
29272928
_startupinfo *si);
2929+
#endif
29282930

29292931
static NORETURN void die_startup(void)
29302932
{
@@ -3002,6 +3004,95 @@ static void maybe_redirect_std_handles(void)
30023004
GENERIC_WRITE, FILE_FLAG_NO_BUFFERING);
30033005
}
30043006

3007+
#if defined(_MSC_VER)
3008+
3009+
/*
3010+
* This routine sits between wmain() and "main" in git.exe.
3011+
* We receive UNICODE (wchar_t) values for argv and env.
3012+
*
3013+
* To be more compatible with the core git code, we convert
3014+
* argv into UTF8 and pass them directly to the "main" routine.
3015+
*
3016+
* We don't bother converting the given UNICODE env vector,
3017+
* but rather leave them in the CRT. We replaced the various
3018+
* getenv/putenv routines to pull them directly from the CRT.
3019+
*
3020+
* This is unlike the MINGW version:
3021+
* [] It does the UNICODE-2-UTF8 conversion on both sets and
3022+
* stuffs the values back into the CRT using exported symbols.
3023+
* [] It also maintains a private copy of the environment and
3024+
* tries to track external changes to it.
3025+
*/
3026+
int msc_startup(int argc, wchar_t **w_argv, wchar_t **w_env)
3027+
{
3028+
char **my_utf8_argv = NULL, **save = NULL;
3029+
char *buffer = NULL;
3030+
int maxlen;
3031+
int k, exit_status;
3032+
3033+
#ifdef USE_MSVC_CRTDBG
3034+
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
3035+
#endif
3036+
3037+
maybe_redirect_std_handles();
3038+
3039+
/* determine size of argv conversion buffer */
3040+
maxlen = wcslen(_wpgmptr);
3041+
for (k = 1; k < argc; k++)
3042+
maxlen = max(maxlen, wcslen(w_argv[k]));
3043+
3044+
/* allocate buffer (wchar_t encodes to max 3 UTF-8 bytes) */
3045+
maxlen = 3 * maxlen + 1;
3046+
buffer = malloc_startup(maxlen);
3047+
3048+
/*
3049+
* Create a UTF-8 version of w_argv. Also create a "save" copy
3050+
* to remember all the string pointers because parse_options()
3051+
* will remove claimed items from the argv that we pass down.
3052+
*/
3053+
ALLOC_ARRAY(my_utf8_argv, argc + 1);
3054+
ALLOC_ARRAY(save, argc + 1);
3055+
save[0] = my_utf8_argv[0] = wcstoutfdup_startup(buffer, _wpgmptr, maxlen);
3056+
for (k = 1; k < argc; k++)
3057+
save[k] = my_utf8_argv[k] = wcstoutfdup_startup(buffer, w_argv[k], maxlen);
3058+
save[k] = my_utf8_argv[k] = NULL;
3059+
3060+
free(buffer);
3061+
3062+
/* fix Windows specific environment settings */
3063+
setup_windows_environment();
3064+
3065+
unset_environment_variables = xstrdup("PERL5LIB");
3066+
3067+
/* initialize critical section for waitpid pinfo_t list */
3068+
InitializeCriticalSection(&pinfo_cs);
3069+
InitializeCriticalSection(&phantom_symlinks_cs);
3070+
3071+
/* set up default file mode and file modes for stdin/out/err */
3072+
_fmode = _O_BINARY;
3073+
_setmode(_fileno(stdin), _O_BINARY);
3074+
_setmode(_fileno(stdout), _O_BINARY);
3075+
_setmode(_fileno(stderr), _O_BINARY);
3076+
3077+
/* initialize Unicode console */
3078+
winansi_init();
3079+
3080+
/* init length of current directory for handle_long_path */
3081+
current_directory_len = GetCurrentDirectoryW(0, NULL);
3082+
3083+
/* invoke the real main() using our utf8 version of argv. */
3084+
exit_status = msc_main(argc, my_utf8_argv);
3085+
3086+
for (k = 0; k < argc; k++)
3087+
free(save[k]);
3088+
free(save);
3089+
free(my_utf8_argv);
3090+
3091+
return exit_status;
3092+
}
3093+
3094+
#else
3095+
30053096
void mingw_startup(void)
30063097
{
30073098
int i, maxlen, argc;
@@ -3081,6 +3172,8 @@ void mingw_startup(void)
30813172
current_directory_len = GetCurrentDirectoryW(0, NULL);
30823173
}
30833174

3175+
#endif
3176+
30843177
int uname(struct utsname *buf)
30853178
{
30863179
unsigned v = (unsigned)GetVersion();

compat/mingw.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -693,7 +693,26 @@ extern CRITICAL_SECTION pinfo_cs;
693693

694694
/*
695695
* A replacement of main() that adds win32 specific initialization.
696+
*
697+
* Note that the end of these macros are unterminated so that the
698+
* brace group following the use of the macro is the body of the
699+
* function.
696700
*/
701+
#if defined(_MSC_VER)
702+
703+
int msc_startup(int argc, wchar_t **w_argv, wchar_t **w_env);
704+
extern int msc_main(int argc, const char **argv);
705+
706+
#define main(c,v) dummy_decl_msc_main(void); \
707+
int wmain(int my_argc, \
708+
wchar_t **my_w_argv, \
709+
wchar_t **my_w_env) \
710+
{ \
711+
return msc_startup(my_argc, my_w_argv, my_w_env); \
712+
} \
713+
int msc_main(c, v)
714+
715+
#else
697716

698717
void mingw_startup(void);
699718
#define main(c,v) dummy_decl_mingw_main(void); \
@@ -705,6 +724,8 @@ int main(int argc, const char **argv) \
705724
} \
706725
static int mingw_main(c,v)
707726

727+
#endif
728+
708729
/*
709730
* Used by Pthread API implementation for Windows
710731
*/

0 commit comments

Comments
 (0)