Skip to content

Commit eddb504

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 2f9bc76 commit eddb504

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
@@ -2956,6 +2956,7 @@ int handle_long_path(wchar_t *path, int len, int max_path, int expand)
29562956
}
29572957
}
29582958

2959+
#if !defined(_MSC_VER)
29592960
/*
29602961
* Disable MSVCRT command line wildcard expansion (__getmainargs called from
29612962
* mingw startup code, see init.c in mingw runtime).
@@ -2968,6 +2969,7 @@ typedef struct {
29682969

29692970
extern int __wgetmainargs(int *argc, wchar_t ***argv, wchar_t ***env, int glob,
29702971
_startupinfo *si);
2972+
#endif
29712973

29722974
static NORETURN void die_startup(void)
29732975
{
@@ -3045,6 +3047,95 @@ static void maybe_redirect_std_handles(void)
30453047
GENERIC_WRITE, FILE_FLAG_NO_BUFFERING);
30463048
}
30473049

3050+
#if defined(_MSC_VER)
3051+
3052+
/*
3053+
* This routine sits between wmain() and "main" in git.exe.
3054+
* We receive UNICODE (wchar_t) values for argv and env.
3055+
*
3056+
* To be more compatible with the core git code, we convert
3057+
* argv into UTF8 and pass them directly to the "main" routine.
3058+
*
3059+
* We don't bother converting the given UNICODE env vector,
3060+
* but rather leave them in the CRT. We replaced the various
3061+
* getenv/putenv routines to pull them directly from the CRT.
3062+
*
3063+
* This is unlike the MINGW version:
3064+
* [] It does the UNICODE-2-UTF8 conversion on both sets and
3065+
* stuffs the values back into the CRT using exported symbols.
3066+
* [] It also maintains a private copy of the environment and
3067+
* tries to track external changes to it.
3068+
*/
3069+
int msc_startup(int argc, wchar_t **w_argv, wchar_t **w_env)
3070+
{
3071+
char **my_utf8_argv = NULL, **save = NULL;
3072+
char *buffer = NULL;
3073+
int maxlen;
3074+
int k, exit_status;
3075+
3076+
#ifdef USE_MSVC_CRTDBG
3077+
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
3078+
#endif
3079+
3080+
maybe_redirect_std_handles();
3081+
3082+
/* determine size of argv conversion buffer */
3083+
maxlen = wcslen(_wpgmptr);
3084+
for (k = 1; k < argc; k++)
3085+
maxlen = max(maxlen, wcslen(w_argv[k]));
3086+
3087+
/* allocate buffer (wchar_t encodes to max 3 UTF-8 bytes) */
3088+
maxlen = 3 * maxlen + 1;
3089+
buffer = malloc_startup(maxlen);
3090+
3091+
/*
3092+
* Create a UTF-8 version of w_argv. Also create a "save" copy
3093+
* to remember all the string pointers because parse_options()
3094+
* will remove claimed items from the argv that we pass down.
3095+
*/
3096+
ALLOC_ARRAY(my_utf8_argv, argc + 1);
3097+
ALLOC_ARRAY(save, argc + 1);
3098+
save[0] = my_utf8_argv[0] = wcstoutfdup_startup(buffer, _wpgmptr, maxlen);
3099+
for (k = 1; k < argc; k++)
3100+
save[k] = my_utf8_argv[k] = wcstoutfdup_startup(buffer, w_argv[k], maxlen);
3101+
save[k] = my_utf8_argv[k] = NULL;
3102+
3103+
free(buffer);
3104+
3105+
/* fix Windows specific environment settings */
3106+
setup_windows_environment();
3107+
3108+
unset_environment_variables = xstrdup("PERL5LIB");
3109+
3110+
/* initialize critical section for waitpid pinfo_t list */
3111+
InitializeCriticalSection(&pinfo_cs);
3112+
InitializeCriticalSection(&phantom_symlinks_cs);
3113+
3114+
/* set up default file mode and file modes for stdin/out/err */
3115+
_fmode = _O_BINARY;
3116+
_setmode(_fileno(stdin), _O_BINARY);
3117+
_setmode(_fileno(stdout), _O_BINARY);
3118+
_setmode(_fileno(stderr), _O_BINARY);
3119+
3120+
/* initialize Unicode console */
3121+
winansi_init();
3122+
3123+
/* init length of current directory for handle_long_path */
3124+
current_directory_len = GetCurrentDirectoryW(0, NULL);
3125+
3126+
/* invoke the real main() using our utf8 version of argv. */
3127+
exit_status = msc_main(argc, my_utf8_argv);
3128+
3129+
for (k = 0; k < argc; k++)
3130+
free(save[k]);
3131+
free(save);
3132+
free(my_utf8_argv);
3133+
3134+
return exit_status;
3135+
}
3136+
3137+
#else
3138+
30483139
void mingw_startup(void)
30493140
{
30503141
int i, maxlen, argc;
@@ -3124,6 +3215,8 @@ void mingw_startup(void)
31243215
current_directory_len = GetCurrentDirectoryW(0, NULL);
31253216
}
31263217

3218+
#endif
3219+
31273220
int uname(struct utsname *buf)
31283221
{
31293222
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)