Skip to content

Commit 12cd5d6

Browse files
committed
Revert "Merge branch 'mingw-isatty-fixup'"
Prepare to merge the most recent iteration of the mingw-isatty patches. This reverts commit 66d27de, reversing changes made to cf8df3d. Signed-off-by: Johannes Schindelin <[email protected]>
1 parent adc9750 commit 12cd5d6

File tree

2 files changed

+181
-40
lines changed

2 files changed

+181
-40
lines changed

compat/msvc.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ static __inline int strcasecmp (const char *s1, const char *s2)
3131
#ifdef _MSC_VER
3232
#define ftello _ftelli64
3333

34+
#define isatty msc_isatty
35+
int msc_isatty(int);
36+
3437
typedef int sigset_t;
3538
/* open for reading, writing, or both (not in fcntl.h) */
3639
#define O_ACCMODE (_O_RDONLY | _O_WRONLY | _O_RDWR)

compat/winansi.c

Lines changed: 178 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,24 @@
88
#include <winreg.h>
99
#include "win32.h"
1010

11+
#if defined(_MSC_VER)
12+
1113
static int fd_is_interactive[3] = { 0, 0, 0 };
12-
#define FD_CONSOLE 0x1
13-
#define FD_SWAPPED 0x2
14-
#define FD_MSYS 0x4
14+
#define MY_INTERACTIVE_CONSOLE 0x1
15+
#define MY_INTERACTIVE_SWAPPED 0x2
16+
#define MY_INTERACTIVE_MSYS 0x4
17+
18+
/* Accumulate what we know about the inherited console descriptors. */
19+
static void set_interactive(int fd, int bit)
20+
{
21+
if (fd >=0 && fd <= 2)
22+
fd_is_interactive[fd] |= bit;
23+
}
24+
25+
#endif
26+
27+
/* In this file, we actually want to use Windows' own isatty(). */
28+
#undef isatty
1529

1630
/*
1731
ANSI codes used by git: m, K
@@ -82,7 +96,6 @@ static void warn_if_raster_font(void)
8296
static int is_console(int fd)
8397
{
8498
CONSOLE_SCREEN_BUFFER_INFO sbi;
85-
DWORD mode;
8699
HANDLE hcon;
87100

88101
static int initialized = 0;
@@ -97,14 +110,12 @@ static int is_console(int fd)
97110
return 0;
98111

99112
/* check if its a handle to a console output screen buffer */
100-
if (!fd) {
101-
if (!GetConsoleMode(hcon, &mode))
102-
return 0;
103-
} else if (!GetConsoleScreenBufferInfo(hcon, &sbi))
113+
if (!GetConsoleScreenBufferInfo(hcon, &sbi))
104114
return 0;
105115

106-
if (fd >= 0 && fd <= 2)
107-
fd_is_interactive[fd] |= FD_CONSOLE;
116+
#if defined(_MSC_VER)
117+
set_interactive(fd, MY_INTERACTIVE_CONSOLE);
118+
#endif
108119

109120
/* initialize attributes */
110121
if (!initialized) {
@@ -467,52 +478,131 @@ static HANDLE duplicate_handle(HANDLE hnd)
467478
return hresult;
468479
}
469480

481+
#if defined(_MSC_VER)
470482
static HANDLE swap_osfhnd(int fd, HANDLE new_handle)
471483
{
484+
DWORD key_std = ((fd == 1) ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE);
485+
472486
/*
473487
* Create a copy of the original handle associated with fd
474488
* because the original will get closed when we dup2().
475489
*/
476-
HANDLE handle = (HANDLE)_get_osfhandle(fd);
477-
HANDLE duplicate = duplicate_handle(handle);
490+
HANDLE h_original = (HANDLE)_get_osfhandle(fd);
491+
HANDLE h_copy_original = duplicate_handle(h_original);
478492

479493
/* Create a temp fd associated with the already open "new_handle". */
480-
int new_fd = _open_osfhandle((intptr_t)new_handle, O_BINARY);
494+
int fd_temp = _open_osfhandle((intptr_t)new_handle, O_BINARY);
481495

482496
assert((fd == 1) || (fd == 2));
483497

484498
/*
485499
* Use stock dup2() to re-bind fd to the new handle. Note that
486500
* this will implicitly close(1) and close both fd=1 and the
487501
* originally associated handle. It will open a new fd=1 and
488-
* call DuplicateHandle() on the handle associated with new_fd.
502+
* call DuplicateHandle() on the handle associated with fd_temp.
489503
* It is because of this implicit close() that we created the
490504
* copy of the original.
491505
*
492506
* Note that the OS can recycle HANDLE (numbers) just like it
493507
* recycles fd (numbers), so we must update the cached value
494508
* of "console". You can use GetFileType() to see that
495-
* handle and _get_osfhandle(fd) may have the same number
509+
* h_original and _get_osfhandle(fd) may have the same number
496510
* value, but they refer to different actual files now.
497511
*
498512
* Note that dup2() when given target := {0,1,2} will also
499513
* call SetStdHandle(), so we don't need to worry about that.
500514
*/
501-
dup2(new_fd, fd);
502-
if (console == handle)
503-
console = duplicate;
504-
handle = INVALID_HANDLE_VALUE;
515+
dup2(fd_temp, fd);
516+
if (console == h_original)
517+
console = h_copy_original;
518+
h_original = INVALID_HANDLE_VALUE;
505519

506520
/* Close the temp fd. This explicitly closes "new_handle"
507521
* (because it has been associated with it).
508522
*/
509-
close(new_fd);
523+
close(fd_temp);
524+
525+
fd_is_interactive[fd] |= MY_INTERACTIVE_SWAPPED;
526+
527+
return h_copy_original;
528+
}
529+
530+
#else
531+
532+
/*
533+
* Make MSVCRT's internal file descriptor control structure accessible
534+
* so that we can tweak OS handles and flags directly (we need MSVCRT
535+
* to treat our pipe handle as if it were a console).
536+
*
537+
* We assume that the ioinfo structure (exposed by MSVCRT.dll via
538+
* __pioinfo) starts with the OS handle and the flags. The exact size
539+
* varies between MSVCRT versions, so we try different sizes until
540+
* toggling the FDEV bit of _pioinfo(1)->osflags is reflected in
541+
* isatty(1).
542+
*/
543+
typedef struct {
544+
HANDLE osfhnd;
545+
char osflags;
546+
} ioinfo;
547+
548+
extern __declspec(dllimport) ioinfo *__pioinfo[];
549+
550+
static size_t sizeof_ioinfo = 0;
551+
552+
#define IOINFO_L2E 5
553+
#define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E)
554+
555+
#define FPIPE 0x08
556+
#define FDEV 0x40
557+
558+
static inline ioinfo* _pioinfo(int fd)
559+
{
560+
return (ioinfo*)((char*)__pioinfo[fd >> IOINFO_L2E] +
561+
(fd & (IOINFO_ARRAY_ELTS - 1)) * sizeof_ioinfo);
562+
}
510563

511-
fd_is_interactive[fd] |= FD_SWAPPED;
564+
static int init_sizeof_ioinfo(void)
565+
{
566+
int istty, wastty;
567+
/* don't init twice */
568+
if (sizeof_ioinfo)
569+
return sizeof_ioinfo >= 256;
570+
571+
sizeof_ioinfo = sizeof(ioinfo);
572+
wastty = isatty(1);
573+
while (sizeof_ioinfo < 256) {
574+
/* toggle FDEV flag, check isatty, then toggle back */
575+
_pioinfo(1)->osflags ^= FDEV;
576+
istty = isatty(1);
577+
_pioinfo(1)->osflags ^= FDEV;
578+
/* return if we found the correct size */
579+
if (istty != wastty)
580+
return 0;
581+
sizeof_ioinfo += sizeof(void*);
582+
}
583+
error("Tweaking file descriptors doesn't work with this MSVCRT.dll");
584+
return 1;
585+
}
512586

513-
return duplicate;
587+
static HANDLE swap_osfhnd(int fd, HANDLE new_handle)
588+
{
589+
ioinfo *pioinfo;
590+
HANDLE old_handle;
591+
592+
/* init ioinfo size if we haven't done so */
593+
if (init_sizeof_ioinfo())
594+
return INVALID_HANDLE_VALUE;
595+
596+
/* get ioinfo pointer and change the handles */
597+
pioinfo = _pioinfo(fd);
598+
old_handle = pioinfo->osfhnd;
599+
pioinfo->osfhnd = new_handle;
600+
return old_handle;
514601
}
515602

603+
#endif
604+
605+
516606
#ifdef DETECT_MSYS_TTY
517607

518608
#include <winternl.h>
@@ -558,25 +648,49 @@ static void detect_msys_tty(int fd)
558648
!wcsstr(name, L"-pty"))
559649
return;
560650

561-
fd_is_interactive[fd] |= FD_MSYS;
651+
#if defined(_MSC_VER)
652+
fd_is_interactive[fd] |= MY_INTERACTIVE_MSYS;
653+
#else
654+
/* init ioinfo size if we haven't done so */
655+
if (init_sizeof_ioinfo())
656+
return;
657+
658+
/* set FDEV flag, reset FPIPE flag */
659+
_pioinfo(fd)->osflags &= ~FPIPE;
660+
_pioinfo(fd)->osflags |= FDEV;
661+
#endif
562662
}
563663

564664
#endif
565665

566-
/*
567-
* Wrapper for isatty(). Most calls in the main git code
568-
* call isatty(1 or 2) to see if the instance is interactive
569-
* and should: be colored, show progress, paginate output.
570-
* We lie and give results for what the descriptor WAS at
571-
* startup (and ignore any pipe redirection we internally
572-
* do).
573-
*/
574-
#undef isatty
575666
int winansi_isatty(int fd)
576667
{
577-
if (fd >= 0 && fd <= 2)
578-
return fd_is_interactive[fd] != 0;
579-
return isatty(fd);
668+
int res = isatty(fd);
669+
670+
if (res) {
671+
/*
672+
* Make sure that /dev/null is not fooling Git into believing
673+
* that we are connected to a terminal, as "_isatty() returns a
674+
* nonzero value if the descriptor is associated with a
675+
* character device."; for more information, see
676+
*
677+
* https://msdn.microsoft.com/en-us/library/f4s0ddew.aspx
678+
*/
679+
HANDLE handle = (HANDLE)_get_osfhandle(fd);
680+
if (fd == STDIN_FILENO) {
681+
DWORD dummy;
682+
683+
if (!GetConsoleMode(handle, &dummy))
684+
res = 0;
685+
} else if (fd == STDOUT_FILENO || fd == STDERR_FILENO) {
686+
CONSOLE_SCREEN_BUFFER_INFO dummy;
687+
688+
if (!GetConsoleScreenBufferInfo(handle, &dummy))
689+
res = 0;
690+
}
691+
}
692+
693+
return res;
580694
}
581695

582696
void winansi_init(void)
@@ -588,8 +702,10 @@ void winansi_init(void)
588702
con1 = is_console(1);
589703
con2 = is_console(2);
590704

705+
#if defined(_MSC_VER)
591706
/* Also compute console bit for fd 0 even though we don't need the result here. */
592707
is_console(0);
708+
#endif
593709

594710
if (!con1 && !con2) {
595711
#ifdef DETECT_MSYS_TTY
@@ -634,10 +750,32 @@ void winansi_init(void)
634750
*/
635751
HANDLE winansi_get_osfhandle(int fd)
636752
{
637-
if (fd == 1 && (fd_is_interactive[1] & FD_SWAPPED))
638-
return hconsole1;
639-
if (fd == 2 && (fd_is_interactive[2] & FD_SWAPPED))
640-
return hconsole2;
753+
HANDLE hnd = (HANDLE) _get_osfhandle(fd);
754+
if (isatty(fd) && GetFileType(hnd) == FILE_TYPE_PIPE) {
755+
if (fd == 1 && hconsole1)
756+
return hconsole1;
757+
else if (fd == 2 && hconsole2)
758+
return hconsole2;
759+
}
760+
return hnd;
761+
}
762+
763+
#ifdef _MSC_VER
641764

642-
return (HANDLE)_get_osfhandle(fd);
765+
/* Wrapper for isatty(). Most calls in the main git code
766+
* call isatty(1 or 2) to see if the instance is interactive
767+
* and should: be colored, show progress, paginate output.
768+
* We lie and give results for what the descriptor WAS at
769+
* startup (and ignore any pipe redirection we internally
770+
* do).
771+
*/
772+
#undef isatty
773+
int msc_isatty(fd)
774+
{
775+
if (fd >=0 && fd <= 2)
776+
return fd_is_interactive[fd] != 0;
777+
else
778+
return isatty(fd);
643779
}
780+
781+
#endif

0 commit comments

Comments
 (0)