Merge branch 'master' of git://github.com/git-l10n/git-po
[gitweb.git] / compat / mingw.c
index 8b6fa0db446aee9888ff6484560131143c7e22e5..6ded1c859f1b5ae1ffe035ac228c0f8a5298097a 100644 (file)
@@ -761,6 +761,17 @@ int mingw_utime (const char *file_name, const struct utimbuf *times)
        return rc;
 }
 
+#undef strftime
+size_t mingw_strftime(char *s, size_t max,
+                     const char *format, const struct tm *tm)
+{
+       size_t ret = strftime(s, max, format, tm);
+
+       if (!ret && errno == EINVAL)
+               die("invalid strftime format: '%s'", format);
+       return ret;
+}
+
 unsigned int sleep (unsigned int seconds)
 {
        Sleep(seconds*1000);
@@ -2139,6 +2150,62 @@ static char *wcstoutfdup_startup(char *buffer, const wchar_t *wcs, size_t len)
        return memcpy(malloc_startup(len), buffer, len);
 }
 
+static void maybe_redirect_std_handle(const wchar_t *key, DWORD std_id, int fd,
+                                     DWORD desired_access, DWORD flags)
+{
+       DWORD create_flag = fd ? OPEN_ALWAYS : OPEN_EXISTING;
+       wchar_t buf[MAX_PATH];
+       DWORD max = ARRAY_SIZE(buf);
+       HANDLE handle;
+       DWORD ret = GetEnvironmentVariableW(key, buf, max);
+
+       if (!ret || ret >= max)
+               return;
+
+       /* make sure this does not leak into child processes */
+       SetEnvironmentVariableW(key, NULL);
+       if (!wcscmp(buf, L"off")) {
+               close(fd);
+               handle = GetStdHandle(std_id);
+               if (handle != INVALID_HANDLE_VALUE)
+                       CloseHandle(handle);
+               return;
+       }
+       if (std_id == STD_ERROR_HANDLE && !wcscmp(buf, L"2>&1")) {
+               handle = GetStdHandle(STD_OUTPUT_HANDLE);
+               if (handle == INVALID_HANDLE_VALUE) {
+                       close(fd);
+                       handle = GetStdHandle(std_id);
+                       if (handle != INVALID_HANDLE_VALUE)
+                               CloseHandle(handle);
+               } else {
+                       int new_fd = _open_osfhandle((intptr_t)handle, O_BINARY);
+                       SetStdHandle(std_id, handle);
+                       dup2(new_fd, fd);
+                       /* do *not* close the new_fd: that would close stdout */
+               }
+               return;
+       }
+       handle = CreateFileW(buf, desired_access, 0, NULL, create_flag,
+                            flags, NULL);
+       if (handle != INVALID_HANDLE_VALUE) {
+               int new_fd = _open_osfhandle((intptr_t)handle, O_BINARY);
+               SetStdHandle(std_id, handle);
+               dup2(new_fd, fd);
+               close(new_fd);
+       }
+}
+
+static void maybe_redirect_std_handles(void)
+{
+       maybe_redirect_std_handle(L"GIT_REDIRECT_STDIN", STD_INPUT_HANDLE, 0,
+                                 GENERIC_READ, FILE_ATTRIBUTE_NORMAL);
+       maybe_redirect_std_handle(L"GIT_REDIRECT_STDOUT", STD_OUTPUT_HANDLE, 1,
+                                 GENERIC_WRITE, FILE_ATTRIBUTE_NORMAL);
+       maybe_redirect_std_handle(L"GIT_REDIRECT_STDERR", STD_ERROR_HANDLE, 2,
+                                 GENERIC_WRITE, FILE_FLAG_NO_BUFFERING);
+}
+
 void mingw_startup(void)
 {
        int i, maxlen, argc;
@@ -2146,13 +2213,15 @@ void mingw_startup(void)
        wchar_t **wenv, **wargv;
        _startupinfo si;
 
+       maybe_redirect_std_handles();
+
        /* get wide char arguments and environment */
        si.newmode = 0;
        if (__wgetmainargs(&argc, &wargv, &wenv, _CRT_glob, &si) < 0)
                die_startup();
 
        /* determine size of argv and environ conversion buffer */
-       maxlen = wcslen(_wpgmptr);
+       maxlen = wcslen(wargv[0]);
        for (i = 1; i < argc; i++)
                maxlen = max(maxlen, wcslen(wargv[i]));
        for (i = 0; wenv[i]; i++)
@@ -2172,8 +2241,7 @@ void mingw_startup(void)
        buffer = malloc_startup(maxlen);
 
        /* convert command line arguments and environment to UTF-8 */
-       __argv[0] = wcstoutfdup_startup(buffer, _wpgmptr, maxlen);
-       for (i = 1; i < argc; i++)
+       for (i = 0; i < argc; i++)
                __argv[i] = wcstoutfdup_startup(buffer, wargv[i], maxlen);
        for (i = 0; wenv[i]; i++)
                environ[i] = wcstoutfdup_startup(buffer, wenv[i], maxlen);