completion: use __gitcomp_builtin in _git_apply
[gitweb.git] / compat / mingw.c
index 3fbfda5978b7bb715ab132283a69fa49384896e9..2d44d21aca8d31f67b16cb9a90245b4db526ff76 100644 (file)
@@ -423,6 +423,8 @@ FILE *mingw_fopen (const char *filename, const char *otype)
                return NULL;
        }
        file = _wfopen(wfilename, wotype);
+       if (!file && GetLastError() == ERROR_INVALID_NAME)
+               errno = ENOENT;
        if (file && hide && set_hidden_flag(wfilename, 1))
                warning("could not mark '%s' as hidden.", filename);
        return file;
@@ -940,65 +942,15 @@ static const char *parse_interpreter(const char *cmd)
        return p+1;
 }
 
-/*
- * Splits the PATH into parts.
- */
-static char **get_path_split(void)
-{
-       char *p, **path, *envpath = mingw_getenv("PATH");
-       int i, n = 0;
-
-       if (!envpath || !*envpath)
-               return NULL;
-
-       envpath = xstrdup(envpath);
-       p = envpath;
-       while (p) {
-               char *dir = p;
-               p = strchr(p, ';');
-               if (p) *p++ = '\0';
-               if (*dir) {     /* not earlier, catches series of ; */
-                       ++n;
-               }
-       }
-       if (!n)
-               return NULL;
-
-       ALLOC_ARRAY(path, n + 1);
-       p = envpath;
-       i = 0;
-       do {
-               if (*p)
-                       path[i++] = xstrdup(p);
-               p = p+strlen(p)+1;
-       } while (i < n);
-       path[i] = NULL;
-
-       free(envpath);
-
-       return path;
-}
-
-static void free_path_split(char **path)
-{
-       char **p = path;
-
-       if (!path)
-               return;
-
-       while (*p)
-               free(*p++);
-       free(path);
-}
-
 /*
  * exe_only means that we only want to detect .exe files, but not scripts
  * (which do not have an extension)
  */
-static char *lookup_prog(const char *dir, const char *cmd, int isexe, int exe_only)
+static char *lookup_prog(const char *dir, int dirlen, const char *cmd,
+                        int isexe, int exe_only)
 {
        char path[MAX_PATH];
-       snprintf(path, sizeof(path), "%s/%s.exe", dir, cmd);
+       snprintf(path, sizeof(path), "%.*s\\%s.exe", dirlen, dir, cmd);
 
        if (!isexe && access(path, F_OK) == 0)
                return xstrdup(path);
@@ -1013,17 +965,29 @@ static char *lookup_prog(const char *dir, const char *cmd, int isexe, int exe_on
  * Determines the absolute path of cmd using the split path in path.
  * If cmd contains a slash or backslash, no lookup is performed.
  */
-static char *path_lookup(const char *cmd, char **path, int exe_only)
+static char *path_lookup(const char *cmd, int exe_only)
 {
+       const char *path;
        char *prog = NULL;
        int len = strlen(cmd);
        int isexe = len >= 4 && !strcasecmp(cmd+len-4, ".exe");
 
        if (strchr(cmd, '/') || strchr(cmd, '\\'))
-               prog = xstrdup(cmd);
+               return xstrdup(cmd);
 
-       while (!prog && *path)
-               prog = lookup_prog(*path++, cmd, isexe, exe_only);
+       path = mingw_getenv("PATH");
+       if (!path)
+               return NULL;
+
+       while (!prog) {
+               const char *sep = strchrnul(path, ';');
+               int dirlen = sep - path;
+               if (dirlen)
+                       prog = lookup_prog(path, dirlen, cmd, isexe, exe_only);
+               if (!*sep)
+                       break;
+               path = sep + 1;
+       }
 
        return prog;
 }
@@ -1190,8 +1154,7 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **deltaenv,
                     int fhin, int fhout, int fherr)
 {
        pid_t pid;
-       char **path = get_path_split();
-       char *prog = path_lookup(cmd, path, 0);
+       char *prog = path_lookup(cmd, 0);
 
        if (!prog) {
                errno = ENOENT;
@@ -1202,7 +1165,7 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **deltaenv,
 
                if (interpr) {
                        const char *argv0 = argv[0];
-                       char *iprog = path_lookup(interpr, path, 1);
+                       char *iprog = path_lookup(interpr, 1);
                        argv[0] = prog;
                        if (!iprog) {
                                errno = ENOENT;
@@ -1220,21 +1183,18 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **deltaenv,
                                               fhin, fhout, fherr);
                free(prog);
        }
-       free_path_split(path);
        return pid;
 }
 
 static int try_shell_exec(const char *cmd, char *const *argv)
 {
        const char *interpr = parse_interpreter(cmd);
-       char **path;
        char *prog;
        int pid = 0;
 
        if (!interpr)
                return 0;
-       path = get_path_split();
-       prog = path_lookup(interpr, path, 1);
+       prog = path_lookup(interpr, 1);
        if (prog) {
                int argc = 0;
                const char **argv2;
@@ -1253,7 +1213,6 @@ static int try_shell_exec(const char *cmd, char *const *argv)
                free(prog);
                free(argv2);
        }
-       free_path_split(path);
        return pid;
 }
 
@@ -1275,8 +1234,7 @@ int mingw_execv(const char *cmd, char *const *argv)
 
 int mingw_execvp(const char *cmd, char *const *argv)
 {
-       char **path = get_path_split();
-       char *prog = path_lookup(cmd, path, 0);
+       char *prog = path_lookup(cmd, 0);
 
        if (prog) {
                mingw_execv(prog, argv);
@@ -1284,7 +1242,6 @@ int mingw_execvp(const char *cmd, char *const *argv)
        } else
                errno = ENOENT;
 
-       free_path_split(path);
        return -1;
 }
 
@@ -2182,6 +2139,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;
@@ -2189,6 +2202,8 @@ 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)