Skip to content

Commit 65f8344

Browse files
committed
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 <[email protected]>
2 parents e5442cd + 39db958 commit 65f8344

File tree

3 files changed

+48
-156
lines changed

3 files changed

+48
-156
lines changed

compat/mingw.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,9 @@ int mingw_raise(int sig);
472472
* ANSI emulation wrappers
473473
*/
474474

475+
int winansi_isatty(int fd);
476+
#define isatty winansi_isatty
477+
475478
void winansi_init(void);
476479
HANDLE winansi_get_osfhandle(int fd);
477480

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: 45 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +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
12+
#define FD_CONSOLE 0x1
13+
#define FD_SWAPPED 0x2
14+
#define FD_MSYS 0x4
2615

2716
/*
2817
ANSI codes used by git: m, K
@@ -93,6 +82,7 @@ static void warn_if_raster_font(void)
9382
static int is_console(int fd)
9483
{
9584
CONSOLE_SCREEN_BUFFER_INFO sbi;
85+
DWORD mode;
9686
HANDLE hcon;
9787

9888
static int initialized = 0;
@@ -107,12 +97,14 @@ static int is_console(int fd)
10797
return 0;
10898

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

113-
#if defined(_MSC_VER)
114-
set_interactive(fd, MY_INTERACTIVE_CONSOLE);
115-
#endif
106+
if (fd >= 0 && fd <= 2)
107+
fd_is_interactive[fd] |= FD_CONSOLE;
116108

117109
/* initialize attributes */
118110
if (!initialized) {
@@ -475,131 +467,49 @@ static HANDLE duplicate_handle(HANDLE hnd)
475467
return hresult;
476468
}
477469

478-
#if defined(_MSC_VER)
479470
static HANDLE swap_osfhnd(int fd, HANDLE new_handle)
480471
{
481-
DWORD key_std = ((fd == 1) ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE);
482-
483472
/*
484473
* Create a copy of the original handle associated with fd
485474
* because the original will get closed when we dup2().
486475
*/
487-
HANDLE h_original = (HANDLE)_get_osfhandle(fd);
488-
HANDLE h_copy_original = duplicate_handle(h_original);
476+
HANDLE handle = (HANDLE)_get_osfhandle(fd);
477+
HANDLE duplicate = duplicate_handle(handle);
489478

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

493482
assert((fd == 1) || (fd == 2));
494483

495484
/*
496485
* Use stock dup2() to re-bind fd to the new handle. Note that
497486
* this will implicitly close(1) and close both fd=1 and the
498487
* originally associated handle. It will open a new fd=1 and
499-
* call DuplicateHandle() on the handle associated with fd_temp.
488+
* call DuplicateHandle() on the handle associated with new_fd.
500489
* It is because of this implicit close() that we created the
501490
* copy of the original.
502491
*
503-
* Note that the OS can recycle HANDLE (numbers) just like it
504-
* recycles fd (numbers), so we must update the cached value
505-
* of "console". You can use GetFileType() to see that
506-
* h_original and _get_osfhandle(fd) may have the same number
507-
* value, but they refer to different actual files now.
492+
* Note that we need to update the cached console handle to the
493+
* duplicated one because the dup2() call will implicitly close
494+
* the original one.
508495
*
509496
* Note that dup2() when given target := {0,1,2} will also
510497
* call SetStdHandle(), so we don't need to worry about that.
511498
*/
512-
dup2(fd_temp, fd);
513-
if (console == h_original)
514-
console = h_copy_original;
515-
h_original = INVALID_HANDLE_VALUE;
499+
if (console == handle)
500+
console = duplicate;
501+
dup2(new_fd, fd);
516502

517503
/* Close the temp fd. This explicitly closes "new_handle"
518504
* (because it has been associated with it).
519505
*/
520-
close(fd_temp);
506+
close(new_fd);
521507

522-
fd_is_interactive[fd] |= MY_INTERACTIVE_SWAPPED;
508+
fd_is_interactive[fd] |= FD_SWAPPED;
523509

524-
return h_copy_original;
510+
return duplicate;
525511
}
526512

527-
#else
528-
529-
/*
530-
* Make MSVCRT's internal file descriptor control structure accessible
531-
* so that we can tweak OS handles and flags directly (we need MSVCRT
532-
* to treat our pipe handle as if it were a console).
533-
*
534-
* We assume that the ioinfo structure (exposed by MSVCRT.dll via
535-
* __pioinfo) starts with the OS handle and the flags. The exact size
536-
* varies between MSVCRT versions, so we try different sizes until
537-
* toggling the FDEV bit of _pioinfo(1)->osflags is reflected in
538-
* isatty(1).
539-
*/
540-
typedef struct {
541-
HANDLE osfhnd;
542-
char osflags;
543-
} ioinfo;
544-
545-
extern __declspec(dllimport) ioinfo *__pioinfo[];
546-
547-
static size_t sizeof_ioinfo = 0;
548-
549-
#define IOINFO_L2E 5
550-
#define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E)
551-
552-
#define FPIPE 0x08
553-
#define FDEV 0x40
554-
555-
static inline ioinfo* _pioinfo(int fd)
556-
{
557-
return (ioinfo*)((char*)__pioinfo[fd >> IOINFO_L2E] +
558-
(fd & (IOINFO_ARRAY_ELTS - 1)) * sizeof_ioinfo);
559-
}
560-
561-
static int init_sizeof_ioinfo(void)
562-
{
563-
int istty, wastty;
564-
/* don't init twice */
565-
if (sizeof_ioinfo)
566-
return sizeof_ioinfo >= 256;
567-
568-
sizeof_ioinfo = sizeof(ioinfo);
569-
wastty = isatty(1);
570-
while (sizeof_ioinfo < 256) {
571-
/* toggle FDEV flag, check isatty, then toggle back */
572-
_pioinfo(1)->osflags ^= FDEV;
573-
istty = isatty(1);
574-
_pioinfo(1)->osflags ^= FDEV;
575-
/* return if we found the correct size */
576-
if (istty != wastty)
577-
return 0;
578-
sizeof_ioinfo += sizeof(void*);
579-
}
580-
error("Tweaking file descriptors doesn't work with this MSVCRT.dll");
581-
return 1;
582-
}
583-
584-
static HANDLE swap_osfhnd(int fd, HANDLE new_handle)
585-
{
586-
ioinfo *pioinfo;
587-
HANDLE old_handle;
588-
589-
/* init ioinfo size if we haven't done so */
590-
if (init_sizeof_ioinfo())
591-
return INVALID_HANDLE_VALUE;
592-
593-
/* get ioinfo pointer and change the handles */
594-
pioinfo = _pioinfo(fd);
595-
old_handle = pioinfo->osfhnd;
596-
pioinfo->osfhnd = new_handle;
597-
return old_handle;
598-
}
599-
600-
#endif
601-
602-
603513
#ifdef DETECT_MSYS_TTY
604514

605515
#include <winternl.h>
@@ -645,21 +555,27 @@ static void detect_msys_tty(int fd)
645555
!wcsstr(name, L"-pty"))
646556
return;
647557

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

661561
#endif
662562

563+
/*
564+
* Wrapper for isatty(). Most calls in the main git code
565+
* call isatty(1 or 2) to see if the instance is interactive
566+
* and should: be colored, show progress, paginate output.
567+
* We lie and give results for what the descriptor WAS at
568+
* startup (and ignore any pipe redirection we internally
569+
* do).
570+
*/
571+
#undef isatty
572+
int winansi_isatty(int fd)
573+
{
574+
if (fd >= 0 && fd <= 2)
575+
return fd_is_interactive[fd] != 0;
576+
return isatty(fd);
577+
}
578+
663579
void winansi_init(void)
664580
{
665581
int con1, con2;
@@ -669,10 +585,8 @@ void winansi_init(void)
669585
con1 = is_console(1);
670586
con2 = is_console(2);
671587

672-
#if defined(_MSC_VER)
673588
/* Also compute console bit for fd 0 even though we don't need the result here. */
674589
is_console(0);
675-
#endif
676590

677591
if (!con1 && !con2) {
678592
#ifdef DETECT_MSYS_TTY
@@ -717,32 +631,10 @@ void winansi_init(void)
717631
*/
718632
HANDLE winansi_get_osfhandle(int fd)
719633
{
720-
HANDLE hnd = (HANDLE) _get_osfhandle(fd);
721-
if (isatty(fd) && GetFileType(hnd) == FILE_TYPE_PIPE) {
722-
if (fd == 1 && hconsole1)
723-
return hconsole1;
724-
else if (fd == 2 && hconsole2)
725-
return hconsole2;
726-
}
727-
return hnd;
728-
}
634+
if (fd == 1 && (fd_is_interactive[1] & FD_SWAPPED))
635+
return hconsole1;
636+
if (fd == 2 && (fd_is_interactive[2] & FD_SWAPPED))
637+
return hconsole2;
729638

730-
#ifdef _MSC_VER
731-
732-
/* Wrapper for isatty(). Most calls in the main git code
733-
* call isatty(1 or 2) to see if the instance is interactive
734-
* and should: be colored, show progress, paginate output.
735-
* We lie and give results for what the descriptor WAS at
736-
* startup (and ignore any pipe redirection we internally
737-
* do).
738-
*/
739-
#undef isatty
740-
int msc_isatty(fd)
741-
{
742-
if (fd >=0 && fd <= 2)
743-
return fd_is_interactive[fd] != 0;
744-
else
745-
return isatty(fd);
639+
return (HANDLE)_get_osfhandle(fd);
746640
}
747-
748-
#endif

0 commit comments

Comments
 (0)