diff --git a/src/xz/util.c b/src/xz/util.c index a1339f4f..69e0cd3c 100644 --- a/src/xz/util.c +++ b/src/xz/util.c @@ -272,10 +272,31 @@ is_empty_filename(const char *filename) } +extern bool +is_tty(int fd) +{ +#if defined(_WIN32) && !defined(__CYGWIN__) + // There is no need to check if handle == INVALID_HANDLE_VALUE + // because it will return false anyway when used in GetConsoleMode(). + // The resulting HANDLE is owned by the file descriptor. + // The HANDLE must not be closed here. + intptr_t handle = _get_osfhandle(fd); + DWORD mode; + + // GetConsoleMode() is an easy way to tell if the HANDLE is a + // console or not. We do not care about the value of mode since we + // do not plan to use any further Windows console functions. + return GetConsoleMode((HANDLE)handle, &mode); +#else + return isatty(fd); +#endif +} + + extern bool is_tty_stdin(void) { - const bool ret = isatty(STDIN_FILENO); + const bool ret = is_tty(STDIN_FILENO); if (ret) message_error(_("Compressed data cannot be read from " @@ -288,7 +309,7 @@ is_tty_stdin(void) extern bool is_tty_stdout(void) { - const bool ret = isatty(STDOUT_FILENO); + const bool ret = is_tty(STDOUT_FILENO); if (ret) message_error(_("Compressed data cannot be written to " diff --git a/src/xz/util.h b/src/xz/util.h index 7aa9caee..995c2444 100644 --- a/src/xz/util.h +++ b/src/xz/util.h @@ -109,6 +109,20 @@ extern void my_snprintf(char **pos, size_t *left, const char *fmt, ...); extern bool is_empty_filename(const char *filename); +/// \brief Test if file descriptor is a terminal +/// +/// For POSIX systems, this is a simple wrapper around isatty(). However on +/// Windows, isatty() returns true for all character devices, not just +/// terminals. +/// +/// \param fd File descriptor to test +/// +/// \return bool: +/// - true if file descriptor is a terminal +/// - false otherwise +extern bool is_tty(int fd); + + /// \brief Test if stdin is a terminal /// /// If stdin is a terminal, an error message is printed and exit status set