Merge branch 'jk/test-commit-bulk'
[gitweb.git] / compat / mingw.c
index 9b6d2400e1107fa2a65f6ecd7d067809115930b9..738f0a826a51b850fcc93f0cadbf707c7eb0b492 100644 (file)
@@ -1407,7 +1407,7 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
        do_unset_environment_variables();
 
        /* Determine whether or not we are associated to a console */
-       cons = CreateFile("CONOUT$", GENERIC_WRITE,
+       cons = CreateFileW(L"CONOUT$", GENERIC_WRITE,
                        FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
                        FILE_ATTRIBUTE_NORMAL, NULL);
        if (cons == INVALID_HANDLE_VALUE) {
@@ -1437,7 +1437,9 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
        si.hStdOutput = winansi_get_osfhandle(fhout);
        si.hStdError = winansi_get_osfhandle(fherr);
 
-       if (xutftowcs_path(wcmd, cmd) < 0)
+       if (*argv && !strcmp(cmd, *argv))
+               wcmd[0] = L'\0';
+       else if (xutftowcs_path(wcmd, cmd) < 0)
                return -1;
        if (dir && xutftowcs_path(wdir, dir) < 0)
                return -1;
@@ -1466,8 +1468,8 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
        wenvblk = make_environment_block(deltaenv);
 
        memset(&pi, 0, sizeof(pi));
-       ret = CreateProcessW(wcmd, wargs, NULL, NULL, TRUE, flags,
-               wenvblk, dir ? wdir : NULL, &si, &pi);
+       ret = CreateProcessW(*wcmd ? wcmd : NULL, wargs, NULL, NULL, TRUE,
+               flags, wenvblk, dir ? wdir : NULL, &si, &pi);
 
        free(wenvblk);
        free(wargs);
@@ -1553,7 +1555,10 @@ static int try_shell_exec(const char *cmd, char *const *argv)
        if (prog) {
                int exec_id;
                int argc = 0;
-               const char **argv2;
+#ifndef _MSC_VER
+               const
+#endif
+               char **argv2;
                while (argv[argc]) argc++;
                ALLOC_ARRAY(argv2, argc + 1);
                argv2[0] = (char *)cmd; /* full path to the script file */
@@ -1946,13 +1951,19 @@ struct passwd *getpwuid(int uid)
        static unsigned initialized;
        static char user_name[100];
        static struct passwd *p;
+       wchar_t buf[100];
        DWORD len;
 
        if (initialized)
                return p;
 
-       len = sizeof(user_name);
-       if (!GetUserName(user_name, &len)) {
+       len = ARRAY_SIZE(buf);
+       if (!GetUserNameW(buf, &len)) {
+               initialized = 1;
+               return NULL;
+       }
+
+       if (xwcstoutf(user_name, buf, sizeof(user_name)) < 0) {
                initialized = 1;
                return NULL;
        }
@@ -2116,8 +2127,33 @@ int mingw_raise(int sig)
                        sigint_fn(SIGINT);
                return 0;
 
+#if defined(_MSC_VER)
+       case SIGILL:
+       case SIGFPE:
+       case SIGSEGV:
+       case SIGTERM:
+       case SIGBREAK:
+       case SIGABRT:
+       case SIGABRT_COMPAT:
+               /*
+                * The <signal.h> header in the MS C Runtime defines 8 signals
+                * as being supported on the platform. Anything else causes an
+                * "Invalid signal or error" (which in DEBUG builds causes the
+                * Abort/Retry/Ignore dialog). We by-pass the CRT for things we
+                * already know will fail.
+                */
+               return raise(sig);
+       default:
+               errno = EINVAL;
+               return -1;
+
+#else
+
        default:
                return raise(sig);
+
+#endif
+
        }
 }
 
@@ -2299,20 +2335,39 @@ static void setup_windows_environment(void)
        /* simulate TERM to enable auto-color (see color.c) */
        if (!getenv("TERM"))
                setenv("TERM", "cygwin", 1);
+
+       /* calculate HOME if not set */
+       if (!getenv("HOME")) {
+               /*
+                * try $HOMEDRIVE$HOMEPATH - the home share may be a network
+                * location, thus also check if the path exists (i.e. is not
+                * disconnected)
+                */
+               if ((tmp = getenv("HOMEDRIVE"))) {
+                       struct strbuf buf = STRBUF_INIT;
+                       strbuf_addstr(&buf, tmp);
+                       if ((tmp = getenv("HOMEPATH"))) {
+                               strbuf_addstr(&buf, tmp);
+                               if (is_directory(buf.buf))
+                                       setenv("HOME", buf.buf, 1);
+                               else
+                                       tmp = NULL; /* use $USERPROFILE */
+                       }
+                       strbuf_release(&buf);
+               }
+               /* use $USERPROFILE if the home share is not available */
+               if (!tmp && (tmp = getenv("USERPROFILE")))
+                       setenv("HOME", tmp, 1);
+       }
 }
 
+#if !defined(_MSC_VER)
 /*
  * Disable MSVCRT command line wildcard expansion (__getmainargs called from
  * mingw startup code, see init.c in mingw runtime).
  */
 int _CRT_glob = 0;
-
-typedef struct {
-       int newmode;
-} _startupinfo;
-
-extern int __wgetmainargs(int *argc, wchar_t ***argv, wchar_t ***env, int glob,
-               _startupinfo *si);
+#endif
 
 static NORETURN void die_startup(void)
 {
@@ -2390,21 +2445,40 @@ static void maybe_redirect_std_handles(void)
                                  GENERIC_WRITE, FILE_FLAG_NO_BUFFERING);
 }
 
-void mingw_startup(void)
+#ifdef _MSC_VER
+#ifdef _DEBUG
+#include <crtdbg.h>
+#endif
+#endif
+
+/*
+ * We implement wmain() and compile with -municode, which would
+ * normally ignore main(), but we call the latter from the former
+ * so that we can handle non-ASCII command-line parameters
+ * appropriately.
+ *
+ * To be more compatible with the core git code, we convert
+ * argv into UTF8 and pass them directly to main().
+ */
+int wmain(int argc, const wchar_t **wargv)
 {
-       int i, maxlen, argc;
-       char *buffer;
-       wchar_t **wenv, **wargv;
-       _startupinfo si;
+       int i, maxlen, exit_status;
+       char *buffer, **save;
+       const char **argv;
 
        trace2_initialize_clock();
 
-       maybe_redirect_std_handles();
+#ifdef _MSC_VER
+#ifdef _DEBUG
+       _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG);
+#endif
 
-       /* get wide char arguments and environment */
-       si.newmode = 0;
-       if (__wgetmainargs(&argc, &wargv, &wenv, _CRT_glob, &si) < 0)
-               die_startup();
+#ifdef USE_MSVC_CRTDBG
+       _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
+#endif
+#endif
+
+       maybe_redirect_std_handles();
 
        /* determine size of argv and environ conversion buffer */
        maxlen = wcslen(wargv[0]);
@@ -2415,9 +2489,16 @@ void mingw_startup(void)
        maxlen = 3 * maxlen + 1;
        buffer = malloc_startup(maxlen);
 
-       /* convert command line arguments and environment to UTF-8 */
+       /*
+        * Create a UTF-8 version of w_argv. Also create a "save" copy
+        * to remember all the string pointers because parse_options()
+        * will remove claimed items from the argv that we pass down.
+        */
+       ALLOC_ARRAY(argv, argc + 1);
+       ALLOC_ARRAY(save, argc + 1);
        for (i = 0; i < argc; i++)
-               __argv[i] = wcstoutfdup_startup(buffer, wargv[i], maxlen);
+               argv[i] = save[i] = wcstoutfdup_startup(buffer, wargv[i], maxlen);
+       argv[i] = save[i] = NULL;
        free(buffer);
 
        /* fix Windows specific environment settings */
@@ -2436,6 +2517,16 @@ void mingw_startup(void)
 
        /* initialize Unicode console */
        winansi_init();
+
+       /* invoke the real main() using our utf8 version of argv. */
+       exit_status = main(argc, argv);
+
+       for (i = 0; i < argc; i++)
+               free(save[i]);
+       free(save);
+       free(argv);
+
+       return exit_status;
 }
 
 int uname(struct utsname *buf)