mirror of
https://github.com/git/git.git
synced 2026-02-01 05:20:15 +00:00
Merge branch 'mingw-isatty-fixup-v3'
This is an evil merge: it changes more than the merged commits, as the merged branch replaces part of the MSVC patches. This mess will need to be cleaned up in the next merging rebase, by moving the mingw-isatty-fixup patches in front of the MSVC patches. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This commit is contained in:
@@ -384,6 +384,9 @@ int mingw_raise(int sig);
|
||||
* ANSI emulation wrappers
|
||||
*/
|
||||
|
||||
int winansi_isatty(int fd);
|
||||
#define isatty winansi_isatty
|
||||
|
||||
void winansi_init(void);
|
||||
HANDLE winansi_get_osfhandle(int fd);
|
||||
|
||||
|
||||
170
compat/winansi.c
170
compat/winansi.c
@@ -6,6 +6,12 @@
|
||||
#include "../git-compat-util.h"
|
||||
#include <wingdi.h>
|
||||
#include <winreg.h>
|
||||
#include "win32.h"
|
||||
|
||||
static int fd_is_interactive[3] = { 0, 0, 0 };
|
||||
#define FD_CONSOLE 0x1
|
||||
#define FD_SWAPPED 0x2
|
||||
#define FD_MSYS 0x4
|
||||
|
||||
/*
|
||||
ANSI codes used by git: m, K
|
||||
@@ -81,6 +87,7 @@ static void warn_if_raster_font(void)
|
||||
static int is_console(int fd)
|
||||
{
|
||||
CONSOLE_SCREEN_BUFFER_INFO sbi;
|
||||
DWORD mode;
|
||||
HANDLE hcon;
|
||||
|
||||
static int initialized = 0;
|
||||
@@ -95,9 +102,15 @@ static int is_console(int fd)
|
||||
return 0;
|
||||
|
||||
/* check if its a handle to a console output screen buffer */
|
||||
if (!GetConsoleScreenBufferInfo(hcon, &sbi))
|
||||
if (!fd) {
|
||||
if (!GetConsoleMode(hcon, &mode))
|
||||
return 0;
|
||||
} else if (!GetConsoleScreenBufferInfo(hcon, &sbi))
|
||||
return 0;
|
||||
|
||||
if (fd >= 0 && fd <= 2)
|
||||
fd_is_interactive[fd] |= FD_CONSOLE;
|
||||
|
||||
/* initialize attributes */
|
||||
if (!initialized) {
|
||||
console = hcon;
|
||||
@@ -459,76 +472,47 @@ static HANDLE duplicate_handle(HANDLE hnd)
|
||||
return hresult;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Make MSVCRT's internal file descriptor control structure accessible
|
||||
* so that we can tweak OS handles and flags directly (we need MSVCRT
|
||||
* to treat our pipe handle as if it were a console).
|
||||
*
|
||||
* We assume that the ioinfo structure (exposed by MSVCRT.dll via
|
||||
* __pioinfo) starts with the OS handle and the flags. The exact size
|
||||
* varies between MSVCRT versions, so we try different sizes until
|
||||
* toggling the FDEV bit of _pioinfo(1)->osflags is reflected in
|
||||
* isatty(1).
|
||||
*/
|
||||
typedef struct {
|
||||
HANDLE osfhnd;
|
||||
char osflags;
|
||||
} ioinfo;
|
||||
|
||||
extern __declspec(dllimport) ioinfo *__pioinfo[];
|
||||
|
||||
static size_t sizeof_ioinfo = 0;
|
||||
|
||||
#define IOINFO_L2E 5
|
||||
#define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E)
|
||||
|
||||
#define FPIPE 0x08
|
||||
#define FDEV 0x40
|
||||
|
||||
static inline ioinfo* _pioinfo(int fd)
|
||||
{
|
||||
return (ioinfo*)((char*)__pioinfo[fd >> IOINFO_L2E] +
|
||||
(fd & (IOINFO_ARRAY_ELTS - 1)) * sizeof_ioinfo);
|
||||
}
|
||||
|
||||
static int init_sizeof_ioinfo(void)
|
||||
{
|
||||
int istty, wastty;
|
||||
/* don't init twice */
|
||||
if (sizeof_ioinfo)
|
||||
return sizeof_ioinfo >= 256;
|
||||
|
||||
sizeof_ioinfo = sizeof(ioinfo);
|
||||
wastty = isatty(1);
|
||||
while (sizeof_ioinfo < 256) {
|
||||
/* toggle FDEV flag, check isatty, then toggle back */
|
||||
_pioinfo(1)->osflags ^= FDEV;
|
||||
istty = isatty(1);
|
||||
_pioinfo(1)->osflags ^= FDEV;
|
||||
/* return if we found the correct size */
|
||||
if (istty != wastty)
|
||||
return 0;
|
||||
sizeof_ioinfo += sizeof(void*);
|
||||
}
|
||||
error("Tweaking file descriptors doesn't work with this MSVCRT.dll");
|
||||
return 1;
|
||||
}
|
||||
|
||||
static HANDLE swap_osfhnd(int fd, HANDLE new_handle)
|
||||
{
|
||||
ioinfo *pioinfo;
|
||||
HANDLE old_handle;
|
||||
/*
|
||||
* Create a copy of the original handle associated with fd
|
||||
* because the original will get closed when we dup2().
|
||||
*/
|
||||
HANDLE handle = (HANDLE)_get_osfhandle(fd);
|
||||
HANDLE duplicate = duplicate_handle(handle);
|
||||
|
||||
/* init ioinfo size if we haven't done so */
|
||||
if (init_sizeof_ioinfo())
|
||||
return INVALID_HANDLE_VALUE;
|
||||
/* Create a temp fd associated with the already open "new_handle". */
|
||||
int new_fd = _open_osfhandle((intptr_t)new_handle, O_BINARY);
|
||||
|
||||
/* get ioinfo pointer and change the handles */
|
||||
pioinfo = _pioinfo(fd);
|
||||
old_handle = pioinfo->osfhnd;
|
||||
pioinfo->osfhnd = new_handle;
|
||||
return old_handle;
|
||||
assert((fd == 1) || (fd == 2));
|
||||
|
||||
/*
|
||||
* Use stock dup2() to re-bind fd to the new handle. Note that
|
||||
* this will implicitly close(1) and close both fd=1 and the
|
||||
* originally associated handle. It will open a new fd=1 and
|
||||
* call DuplicateHandle() on the handle associated with new_fd.
|
||||
* It is because of this implicit close() that we created the
|
||||
* copy of the original.
|
||||
*
|
||||
* Note that we need to update the cached console handle to the
|
||||
* duplicated one because the dup2() call will implicitly close
|
||||
* the original one.
|
||||
*
|
||||
* Note that dup2() when given target := {0,1,2} will also
|
||||
* call SetStdHandle(), so we don't need to worry about that.
|
||||
*/
|
||||
if (console == handle)
|
||||
console = duplicate;
|
||||
dup2(new_fd, fd);
|
||||
|
||||
/* Close the temp fd. This explicitly closes "new_handle"
|
||||
* (because it has been associated with it).
|
||||
*/
|
||||
close(new_fd);
|
||||
|
||||
fd_is_interactive[fd] |= FD_SWAPPED;
|
||||
|
||||
return duplicate;
|
||||
}
|
||||
|
||||
#ifdef DETECT_MSYS_TTY
|
||||
@@ -553,23 +537,37 @@ static void detect_msys_tty(int fd)
|
||||
buffer, sizeof(buffer) - 2, &result)))
|
||||
return;
|
||||
name = nameinfo->Name.Buffer;
|
||||
name[nameinfo->Name.Length] = 0;
|
||||
name[nameinfo->Name.Length / sizeof(*name)] = 0;
|
||||
|
||||
/* check if this could be a MSYS2 pty pipe ('msys-XXXX-ptyN-XX') */
|
||||
if (!wcsstr(name, L"msys-") || !wcsstr(name, L"-pty"))
|
||||
/*
|
||||
* Check if this could be a MSYS2 pty pipe ('msys-XXXX-ptyN-XX')
|
||||
* or a cygwin pty pipe ('cygwin-XXXX-ptyN-XX')
|
||||
*/
|
||||
if ((!wcsstr(name, L"msys-") && !wcsstr(name, L"cygwin-")) ||
|
||||
!wcsstr(name, L"-pty"))
|
||||
return;
|
||||
|
||||
/* init ioinfo size if we haven't done so */
|
||||
if (init_sizeof_ioinfo())
|
||||
return;
|
||||
|
||||
/* set FDEV flag, reset FPIPE flag */
|
||||
_pioinfo(fd)->osflags &= ~FPIPE;
|
||||
_pioinfo(fd)->osflags |= FDEV;
|
||||
fd_is_interactive[fd] |= FD_MSYS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Wrapper for isatty(). Most calls in the main git code
|
||||
* call isatty(1 or 2) to see if the instance is interactive
|
||||
* and should: be colored, show progress, paginate output.
|
||||
* We lie and give results for what the descriptor WAS at
|
||||
* startup (and ignore any pipe redirection we internally
|
||||
* do).
|
||||
*/
|
||||
#undef isatty
|
||||
int winansi_isatty(int fd)
|
||||
{
|
||||
if (fd >= 0 && fd <= 2)
|
||||
return fd_is_interactive[fd] != 0;
|
||||
return isatty(fd);
|
||||
}
|
||||
|
||||
void winansi_init(void)
|
||||
{
|
||||
int con1, con2;
|
||||
@@ -578,6 +576,10 @@ void winansi_init(void)
|
||||
/* check if either stdout or stderr is a console output screen buffer */
|
||||
con1 = is_console(1);
|
||||
con2 = is_console(2);
|
||||
|
||||
/* Also compute console bit for fd 0 even though we don't need the result here. */
|
||||
is_console(0);
|
||||
|
||||
if (!con1 && !con2) {
|
||||
#ifdef DETECT_MSYS_TTY
|
||||
/* check if stdin / stdout / stderr are MSYS2 pty pipes */
|
||||
@@ -621,12 +623,10 @@ void winansi_init(void)
|
||||
*/
|
||||
HANDLE winansi_get_osfhandle(int fd)
|
||||
{
|
||||
HANDLE hnd = (HANDLE) _get_osfhandle(fd);
|
||||
if (isatty(fd) && GetFileType(hnd) == FILE_TYPE_PIPE) {
|
||||
if (fd == 1 && hconsole1)
|
||||
return hconsole1;
|
||||
else if (fd == 2 && hconsole2)
|
||||
return hconsole2;
|
||||
}
|
||||
return hnd;
|
||||
if (fd == 1 && (fd_is_interactive[1] & FD_SWAPPED))
|
||||
return hconsole1;
|
||||
if (fd == 2 && (fd_is_interactive[2] & FD_SWAPPED))
|
||||
return hconsole2;
|
||||
|
||||
return (HANDLE)_get_osfhandle(fd);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user