Skip to content

Commit 66d27de

Browse files
committed
Merge branch 'mingw-isatty-fixup'
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 into the mingw-isatty branch and then rebasing the MSVC patches on top of the mingw-isatty branch. Signed-off-by: Johannes Schindelin <[email protected]>
2 parents cf8df3d + 087cc33 commit 66d27de

File tree

2 files changed

+40
-181
lines changed

2 files changed

+40
-181
lines changed

compat/msvc.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,6 @@ 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-
3734
typedef int sigset_t;
3835
/* open for reading, writing, or both (not in fcntl.h) */
3936
#define O_ACCMODE (_O_RDONLY | _O_WRONLY | _O_RDWR)

compat/winansi.c

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

11-
#if defined(_MSC_VER)
12-
1311
static int fd_is_interactive[3] = { 0, 0, 0 };
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
12+
#define FD_CONSOLE 0x1
13+
#define FD_SWAPPED 0x2
14+
#define FD_MSYS 0x4
2915

3016
/*
3117
ANSI codes used by git: m, K
@@ -96,6 +82,7 @@ static void warn_if_raster_font(void)
9682
static int is_console(int fd)
9783
{
9884
CONSOLE_SCREEN_BUFFER_INFO sbi;
85+
DWORD mode;
9986
HANDLE hcon;
10087

10188
static int initialized = 0;
@@ -110,12 +97,14 @@ static int is_console(int fd)
11097
return 0;
11198

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

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

120109
/* initialize attributes */
121110
if (!initialized) {
@@ -478,131 +467,52 @@ static HANDLE duplicate_handle(HANDLE hnd)
478467
return hresult;
479468
}
480469

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

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

496482
assert((fd == 1) || (fd == 2));
497483

498484
/*
499485
* Use stock dup2() to re-bind fd to the new handle. Note that
500486
* this will implicitly close(1) and close both fd=1 and the
501487
* originally associated handle. It will open a new fd=1 and
502-
* call DuplicateHandle() on the handle associated with fd_temp.
488+
* call DuplicateHandle() on the handle associated with new_fd.
503489
* It is because of this implicit close() that we created the
504490
* copy of the original.
505491
*
506492
* Note that the OS can recycle HANDLE (numbers) just like it
507493
* recycles fd (numbers), so we must update the cached value
508494
* of "console". You can use GetFileType() to see that
509-
* h_original and _get_osfhandle(fd) may have the same number
495+
* handle and _get_osfhandle(fd) may have the same number
510496
* value, but they refer to different actual files now.
511497
*
512498
* Note that dup2() when given target := {0,1,2} will also
513499
* call SetStdHandle(), so we don't need to worry about that.
514500
*/
515-
dup2(fd_temp, fd);
516-
if (console == h_original)
517-
console = h_copy_original;
518-
h_original = INVALID_HANDLE_VALUE;
501+
dup2(new_fd, fd);
502+
if (console == handle)
503+
console = duplicate;
504+
handle = INVALID_HANDLE_VALUE;
519505

520506
/* Close the temp fd. This explicitly closes "new_handle"
521507
* (because it has been associated with it).
522508
*/
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-
}
509+
close(new_fd);
563510

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-
}
511+
fd_is_interactive[fd] |= FD_SWAPPED;
586512

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;
513+
return duplicate;
601514
}
602515

603-
#endif
604-
605-
606516
#ifdef DETECT_MSYS_TTY
607517

608518
#include <winternl.h>
@@ -648,49 +558,25 @@ static void detect_msys_tty(int fd)
648558
!wcsstr(name, L"-pty"))
649559
return;
650560

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
561+
fd_is_interactive[fd] |= FD_MSYS;
662562
}
663563

664564
#endif
665565

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
666575
int winansi_isatty(int fd)
667576
{
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;
577+
if (fd >= 0 && fd <= 2)
578+
return fd_is_interactive[fd] != 0;
579+
return isatty(fd);
694580
}
695581

696582
void winansi_init(void)
@@ -702,10 +588,8 @@ void winansi_init(void)
702588
con1 = is_console(1);
703589
con2 = is_console(2);
704590

705-
#if defined(_MSC_VER)
706591
/* Also compute console bit for fd 0 even though we don't need the result here. */
707592
is_console(0);
708-
#endif
709593

710594
if (!con1 && !con2) {
711595
#ifdef DETECT_MSYS_TTY
@@ -750,32 +634,10 @@ void winansi_init(void)
750634
*/
751635
HANDLE winansi_get_osfhandle(int fd)
752636
{
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
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;
764641

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);
642+
return (HANDLE)_get_osfhandle(fd);
779643
}
780-
781-
#endif

0 commit comments

Comments
 (0)