88#include <winreg.h>
99#include "win32.h"
1010
11- #if defined(_MSC_VER )
12-
1311static 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)
9682static 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 )
482470static 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
666575int 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
696582void 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 */
751635HANDLE 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