6
6
#include "../git-compat-util.h"
7
7
#include <wingdi.h>
8
8
#include <winreg.h>
9
+ #include "win32.h"
10
+
11
+ static int fd_is_interactive [3 ] = { 0 , 0 , 0 };
12
+ #define FD_CONSOLE 0x1
13
+ #define FD_SWAPPED 0x2
14
+ #define FD_MSYS 0x4
9
15
10
16
/*
11
17
ANSI codes used by git: m, K
@@ -102,6 +108,9 @@ static int is_console(int fd)
102
108
} else if (!GetConsoleScreenBufferInfo (hcon , & sbi ))
103
109
return 0 ;
104
110
111
+ if (fd >= 0 && fd <= 2 )
112
+ fd_is_interactive [fd ] |= FD_CONSOLE ;
113
+
105
114
/* initialize attributes */
106
115
if (!initialized ) {
107
116
console = hcon ;
@@ -463,76 +472,47 @@ static HANDLE duplicate_handle(HANDLE hnd)
463
472
return hresult ;
464
473
}
465
474
475
+ static HANDLE swap_osfhnd (int fd , HANDLE new_handle )
476
+ {
477
+ /*
478
+ * Create a copy of the original handle associated with fd
479
+ * because the original will get closed when we dup2().
480
+ */
481
+ HANDLE handle = (HANDLE )_get_osfhandle (fd );
482
+ HANDLE duplicate = duplicate_handle (handle );
466
483
467
- /*
468
- * Make MSVCRT's internal file descriptor control structure accessible
469
- * so that we can tweak OS handles and flags directly (we need MSVCRT
470
- * to treat our pipe handle as if it were a console).
471
- *
472
- * We assume that the ioinfo structure (exposed by MSVCRT.dll via
473
- * __pioinfo) starts with the OS handle and the flags. The exact size
474
- * varies between MSVCRT versions, so we try different sizes until
475
- * toggling the FDEV bit of _pioinfo(1)->osflags is reflected in
476
- * isatty(1).
477
- */
478
- typedef struct {
479
- HANDLE osfhnd ;
480
- char osflags ;
481
- } ioinfo ;
484
+ /* Create a temp fd associated with the already open "new_handle". */
485
+ int new_fd = _open_osfhandle ((intptr_t )new_handle , O_BINARY );
482
486
483
- extern __declspec( dllimport ) ioinfo * __pioinfo [] ;
487
+ assert (( fd == 1 ) || ( fd == 2 )) ;
484
488
485
- static size_t sizeof_ioinfo = 0 ;
489
+ /*
490
+ * Use stock dup2() to re-bind fd to the new handle. Note that
491
+ * this will implicitly close(1) and close both fd=1 and the
492
+ * originally associated handle. It will open a new fd=1 and
493
+ * call DuplicateHandle() on the handle associated with new_fd.
494
+ * It is because of this implicit close() that we created the
495
+ * copy of the original.
496
+ *
497
+ * Note that we need to update the cached console handle to the
498
+ * duplicated one because the dup2() call will implicitly close
499
+ * the original one.
500
+ *
501
+ * Note that dup2() when given target := {0,1,2} will also
502
+ * call SetStdHandle(), so we don't need to worry about that.
503
+ */
504
+ if (console == handle )
505
+ console = duplicate ;
506
+ dup2 (new_fd , fd );
486
507
487
- #define IOINFO_L2E 5
488
- #define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E)
508
+ /* Close the temp fd. This explicitly closes "new_handle"
509
+ * (because it has been associated with it).
510
+ */
511
+ close (new_fd );
489
512
490
- #define FPIPE 0x08
491
- #define FDEV 0x40
513
+ fd_is_interactive [fd ] |= FD_SWAPPED ;
492
514
493
- static inline ioinfo * _pioinfo (int fd )
494
- {
495
- return (ioinfo * )((char * )__pioinfo [fd >> IOINFO_L2E ] +
496
- (fd & (IOINFO_ARRAY_ELTS - 1 )) * sizeof_ioinfo );
497
- }
498
-
499
- static int init_sizeof_ioinfo (void )
500
- {
501
- int istty , wastty ;
502
- /* don't init twice */
503
- if (sizeof_ioinfo )
504
- return sizeof_ioinfo >= 256 ;
505
-
506
- sizeof_ioinfo = sizeof (ioinfo );
507
- wastty = isatty (1 );
508
- while (sizeof_ioinfo < 256 ) {
509
- /* toggle FDEV flag, check isatty, then toggle back */
510
- _pioinfo (1 )-> osflags ^= FDEV ;
511
- istty = isatty (1 );
512
- _pioinfo (1 )-> osflags ^= FDEV ;
513
- /* return if we found the correct size */
514
- if (istty != wastty )
515
- return 0 ;
516
- sizeof_ioinfo += sizeof (void * );
517
- }
518
- error ("Tweaking file descriptors doesn't work with this MSVCRT.dll" );
519
- return 1 ;
520
- }
521
-
522
- static HANDLE swap_osfhnd (int fd , HANDLE new_handle )
523
- {
524
- ioinfo * pioinfo ;
525
- HANDLE old_handle ;
526
-
527
- /* init ioinfo size if we haven't done so */
528
- if (init_sizeof_ioinfo ())
529
- return INVALID_HANDLE_VALUE ;
530
-
531
- /* get ioinfo pointer and change the handles */
532
- pioinfo = _pioinfo (fd );
533
- old_handle = pioinfo -> osfhnd ;
534
- pioinfo -> osfhnd = new_handle ;
535
- return old_handle ;
515
+ return duplicate ;
536
516
}
537
517
538
518
#ifdef DETECT_MSYS_TTY
@@ -567,17 +547,27 @@ static void detect_msys_tty(int fd)
567
547
!wcsstr (name , L"-pty" ))
568
548
return ;
569
549
570
- /* init ioinfo size if we haven't done so */
571
- if (init_sizeof_ioinfo ())
572
- return ;
573
-
574
- /* set FDEV flag, reset FPIPE flag */
575
- _pioinfo (fd )-> osflags &= ~FPIPE ;
576
- _pioinfo (fd )-> osflags |= FDEV ;
550
+ fd_is_interactive [fd ] |= FD_MSYS ;
577
551
}
578
552
579
553
#endif
580
554
555
+ /*
556
+ * Wrapper for isatty(). Most calls in the main git code
557
+ * call isatty(1 or 2) to see if the instance is interactive
558
+ * and should: be colored, show progress, paginate output.
559
+ * We lie and give results for what the descriptor WAS at
560
+ * startup (and ignore any pipe redirection we internally
561
+ * do).
562
+ */
563
+ #undef isatty
564
+ int winansi_isatty (int fd )
565
+ {
566
+ if (fd >= 0 && fd <= 2 )
567
+ return fd_is_interactive [fd ] != 0 ;
568
+ return isatty (fd );
569
+ }
570
+
581
571
void winansi_init (void )
582
572
{
583
573
int con1 , con2 ;
@@ -586,6 +576,10 @@ void winansi_init(void)
586
576
/* check if either stdout or stderr is a console output screen buffer */
587
577
con1 = is_console (1 );
588
578
con2 = is_console (2 );
579
+
580
+ /* Also compute console bit for fd 0 even though we don't need the result here. */
581
+ is_console (0 );
582
+
589
583
if (!con1 && !con2 ) {
590
584
#ifdef DETECT_MSYS_TTY
591
585
/* check if stdin / stdout / stderr are MSYS2 pty pipes */
@@ -629,12 +623,10 @@ void winansi_init(void)
629
623
*/
630
624
HANDLE winansi_get_osfhandle (int fd )
631
625
{
632
- HANDLE hnd = (HANDLE ) _get_osfhandle (fd );
633
- if (isatty (fd ) && GetFileType (hnd ) == FILE_TYPE_PIPE ) {
634
- if (fd == 1 && hconsole1 )
635
- return hconsole1 ;
636
- else if (fd == 2 && hconsole2 )
637
- return hconsole2 ;
638
- }
639
- return hnd ;
626
+ if (fd == 1 && (fd_is_interactive [1 ] & FD_SWAPPED ))
627
+ return hconsole1 ;
628
+ if (fd == 2 && (fd_is_interactive [2 ] & FD_SWAPPED ))
629
+ return hconsole2 ;
630
+
631
+ return (HANDLE )_get_osfhandle (fd );
640
632
}
0 commit comments