diff options
author | Jia Tan <jiat0218@gmail.com> | 2023-11-23 22:04:35 +0800 |
---|---|---|
committer | Jia Tan <jiat0218@gmail.com> | 2023-11-23 22:40:20 +0800 |
commit | 584e3a258f32d579b1d07f99b4dc6e856c10ac7e (patch) | |
tree | a891ce6e03d4579de0fd0d00714abfd428bdd0c2 /src | |
parent | tuklib_integer: Fix typo discovered by codespell. (diff) | |
download | xz-584e3a258f32d579b1d07f99b4dc6e856c10ac7e.tar.xz |
xz: Create separate is_tty() function.
The new is_tty() will report if a file descriptor is a terminal or not.
On POSIX systems, it is a wrapper around isatty(). However, the native
Windows implementation of isatty() will return true for all character
devices, not just terminals. So is_tty() has a special case for Windows
so it can use alternative Windows API functions to determine if a file
descriptor is a terminal.
This fixes a bug with MSVC and MinGW-w64 builds that refused to read from
or write to non-terminal character devices because xz thought it was a
terminal. For instance:
xz foo -c > /dev/null
would fail because /dev/null was assumed to be a terminal.
Diffstat (limited to 'src')
-rw-r--r-- | src/xz/util.c | 30 | ||||
-rw-r--r-- | src/xz/util.h | 14 |
2 files changed, 37 insertions, 7 deletions
diff --git a/src/xz/util.c b/src/xz/util.c index 45d3085e..25c20765 100644 --- a/src/xz/util.c +++ b/src/xz/util.c @@ -13,11 +13,6 @@ #include "private.h" #include <stdarg.h> -#ifdef _MSC_VER -# include <io.h> -# define isatty _isatty -#endif - /// Buffers for uint64_to_str() and uint64_to_nicestr() static char bufs[4][128]; @@ -267,9 +262,30 @@ my_snprintf(char **pos, size_t *left, const char *fmt, ...) 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 does not need to be closed based on Windows + // API documentation. + 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 " @@ -282,7 +298,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 6d7e1481..1da40371 100644 --- a/src/xz/util.h +++ b/src/xz/util.h @@ -105,6 +105,20 @@ lzma_attribute((__format__(__printf__, 3, 4))) extern void my_snprintf(char **pos, size_t *left, const char *fmt, ...); +/// \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 |