I have a C/C++ program, written for Windows, and compiled with Visual Studio. And it's a command-line tool, which means that it could reasonably be run under Cygwin Bash, likely in MinTTY, and some of its users are now doing so.
I'd like to change my program to make it play nicer with Cygwin.
My program currently uses the Windows Console APIs to output pretty colored text and to manage the cursor, and to generally be "interactive" (or "interactive" for a 1980s definition of "interactive"), at least when its output isn't being piped to a file.
To make my program play nicer with Cygwin, I can make it emit ANSI \x1B[...
escape codes instead of calling the Console APIs, but the real problem is knowing when to do so.
There are four cases, I think:
Invoked as an interactive Windows console program. --> (Use Console APIs.)
Invoked as a normal Windows console program, but the user is piping its output somewhere. --> (Emit no stylings or interactive calls at all.)
Invoked as an interactive program by Bash or under MinTTY. --> (Use ANSI escape codes.)
Invoked by Bash, but the user is piping its output somewhere. --> (Emit no stylings or interactive calls at all.)
I can distinguish case 1 by testing whether GetConsoleMode()
succeeds or fails for the stdout
handle; if it succeeds, I definitely have a Windows Console, and this is the case when I turn on the code to use the Console APIs.
I'd like to treat case 3 differently and use the ANSI codes for it, but unfortunately, cases 2, 3, and 4 seem to be mostly indistinguishable:
- The
stdout
handle seems to be just an opaque object ofFILE_TYPE_PIPE
for all three cases. - I can use the
OSTYPE
environment variable and at least guess that I'm under Cygwin, which distinguishes case 2 from cases 3 and 4. - If I could link against
cygwin1.dll
, I could maybe somehow use itsisatty()
, but I can't link against that, since many of my users don't (and won't) have Cygwin installed. (And I'm not at all convinced that'd work even if it was possible.) - MSVC's native
_isatty()
thinks Cygwin Bash is a pipe, not an interactive shell, because it just usesGetFileType()
deep under the hood.
In short, there's no obvious way I can see to separate case 3 from case 4.
Right now, I treat case 3 exactly like cases 2 and 4, and Cygwin users (myself included) get crappy glass teletype interaction instead of a friendly interactive full-screen display, and I'd really like to fix that.
So is there any way I can distinguish an interactive Cygwin invocation from other invocations, so my native-Windows program can behave nicely when invoked by Cygwin Bash or other similar shells?
(Important note: There is one solution that's off the table: The program will not be compiled as a native Cygwin program. This is a Windows program, and it's compiled with the Microsoft tool chain, and it will not be compiled with GCC. The goal is to change/update it to behave as nicely under Cygwin as possible — without actually linking against any of the Cygwin DLLs. I can only reasonably distribute one executable file for Windows, not two.)