Merge branch 'jh/trace2-pretty-output'
[gitweb.git] / compat / mingw.c
index 1047427cb559efc2f3c1d932f94e25d35da5d45d..7a0d619fb6b59641191d819d2c43d4ced8b93df2 100644 (file)
@@ -1161,14 +1161,21 @@ static char *lookup_prog(const char *dir, int dirlen, const char *cmd,
                         int isexe, int exe_only)
 {
        char path[MAX_PATH];
+       wchar_t wpath[MAX_PATH];
        snprintf(path, sizeof(path), "%.*s\\%s.exe", dirlen, dir, cmd);
 
-       if (!isexe && access(path, F_OK) == 0)
+       if (xutftowcs_path(wpath, path) < 0)
+               return NULL;
+
+       if (!isexe && _waccess(wpath, F_OK) == 0)
                return xstrdup(path);
-       path[strlen(path)-4] = '\0';
-       if ((!exe_only || isexe) && access(path, F_OK) == 0)
-               if (!(GetFileAttributes(path) & FILE_ATTRIBUTE_DIRECTORY))
+       wpath[wcslen(wpath)-4] = '\0';
+       if ((!exe_only || isexe) && _waccess(wpath, F_OK) == 0) {
+               if (!(GetFileAttributesW(wpath) & FILE_ATTRIBUTE_DIRECTORY)) {
+                       path[strlen(path)-4] = '\0';
                        return xstrdup(path);
+               }
+       }
        return NULL;
 }
 
@@ -1265,7 +1272,7 @@ static wchar_t *make_environment_block(char **deltaenv)
                }
 
                ALLOC_ARRAY(result, size);
-               memcpy(result, wenv, size * sizeof(*wenv));
+               COPY_ARRAY(result, wenv, size);
                FreeEnvironmentStringsW(wenv);
                return result;
        }
@@ -1309,7 +1316,7 @@ static wchar_t *make_environment_block(char **deltaenv)
                        continue;
 
                size = wcslen(array[i]) + 1;
-               memcpy(p, array[i], size * sizeof(*p));
+               COPY_ARRAY(p, array[i], size);
                p += size;
        }
        *p = L'\0';
@@ -1407,7 +1414,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 +1444,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 +1475,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 +1562,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 +1958,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 +2134,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
+
        }
 }
 
@@ -2325,18 +2368,13 @@ static void setup_windows_environment(void)
        }
 }
 
+#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)
 {
@@ -2414,21 +2452,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]);
@@ -2439,9 +2496,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 */
@@ -2460,6 +2524,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)