diff options
Diffstat (limited to 'llvm/lib/Support')
-rw-r--r-- | llvm/lib/Support/CMakeLists.txt | 11 | ||||
-rw-r--r-- | llvm/lib/Support/Unix/Process.inc | 60 |
2 files changed, 67 insertions, 4 deletions
diff --git a/llvm/lib/Support/CMakeLists.txt b/llvm/lib/Support/CMakeLists.txt index be4badc..03e8889 100644 --- a/llvm/lib/Support/CMakeLists.txt +++ b/llvm/lib/Support/CMakeLists.txt @@ -56,6 +56,9 @@ elseif( CMAKE_HOST_UNIX ) STRING(REGEX REPLACE "^lib" "" Backtrace_LIBFILE ${Backtrace_LIBFILE}) set(system_libs ${system_libs} ${Backtrace_LIBFILE}) endif() + if( LLVM_ENABLE_TERMINFO ) + set(imported_libs ${imported_libs} Terminfo::terminfo) + endif() set(system_libs ${system_libs} ${LLVM_ATOMIC_LIB}) set(system_libs ${system_libs} ${LLVM_PTHREAD_LIB}) if( UNIX AND NOT (BEOS OR HAIKU) ) @@ -322,6 +325,14 @@ if(LLVM_ENABLE_ZSTD) set(llvm_system_libs ${llvm_system_libs} "${zstd_library}") endif() +if(LLVM_ENABLE_TERMINFO) + if(NOT terminfo_library) + get_property(terminfo_library TARGET Terminfo::terminfo PROPERTY LOCATION) + endif() + get_library_name(${terminfo_library} terminfo_library) + set(llvm_system_libs ${llvm_system_libs} "${terminfo_library}") +endif() + set_property(TARGET LLVMSupport PROPERTY LLVM_SYSTEM_LIBS "${llvm_system_libs}") diff --git a/llvm/lib/Support/Unix/Process.inc b/llvm/lib/Support/Unix/Process.inc index 84b10ff..ae90924 100644 --- a/llvm/lib/Support/Unix/Process.inc +++ b/llvm/lib/Support/Unix/Process.inc @@ -341,9 +341,17 @@ unsigned Process::StandardErrColumns() { return getColumns(); } -static bool terminalHasColors() { - // Check if the current terminal is one of terminals that are known to support - // ANSI color escape codes. +#ifdef LLVM_ENABLE_TERMINFO +// We manually declare these extern functions because finding the correct +// headers from various terminfo, curses, or other sources is harder than +// writing their specs down. +extern "C" int setupterm(char *term, int filedes, int *errret); +extern "C" struct term *set_curterm(struct term *termp); +extern "C" int del_curterm(struct term *termp); +extern "C" int tigetnum(char *capname); +#endif + +bool checkTerminalEnvironmentForColors() { if (const char *TermStr = std::getenv("TERM")) { return StringSwitch<bool>(TermStr) .Case("ansi", true) @@ -360,10 +368,54 @@ static bool terminalHasColors() { return false; } +static bool terminalHasColors(int fd) { +#ifdef LLVM_ENABLE_TERMINFO + // First, acquire a global lock because these C routines are thread hostile. + static std::mutex TermColorMutex; + std::lock_guard<std::mutex> G(TermColorMutex); + + struct term *previous_term = set_curterm(nullptr); + int errret = 0; + if (setupterm(nullptr, fd, &errret) != 0) + // Regardless of why, if we can't get terminfo, we shouldn't try to print + // colors. + return false; + + // Test whether the terminal as set up supports color output. How to do this + // isn't entirely obvious. We can use the curses routine 'has_colors' but it + // would be nice to avoid a dependency on curses proper when we can make do + // with a minimal terminfo parsing library. Also, we don't really care whether + // the terminal supports the curses-specific color changing routines, merely + // if it will interpret ANSI color escape codes in a reasonable way. Thus, the + // strategy here is just to query the baseline colors capability and if it + // supports colors at all to assume it will translate the escape codes into + // whatever range of colors it does support. We can add more detailed tests + // here if users report them as necessary. + // + // The 'tigetnum' routine returns -2 or -1 on errors, and might return 0 if + // the terminfo says that no colors are supported. + int colors_ti = tigetnum(const_cast<char *>("colors")); + bool HasColors = + colors_ti >= 0 ? colors_ti : checkTerminalEnvironmentForColors(); + + // Now extract the structure allocated by setupterm and free its memory + // through a really silly dance. + struct term *termp = set_curterm(previous_term); + (void)del_curterm(termp); // Drop any errors here. + + // Return true if we found a color capabilities for the current terminal. + return HasColors; +#else + // When the terminfo database is not available, check if the current terminal + // is one of terminals that are known to support ANSI color escape codes. + return checkTerminalEnvironmentForColors(); +#endif +} + bool Process::FileDescriptorHasColors(int fd) { // A file descriptor has colors if it is displayed and the terminal has // colors. - return FileDescriptorIsDisplayed(fd) && terminalHasColors(); + return FileDescriptorIsDisplayed(fd) && terminalHasColors(fd); } bool Process::StandardOutHasColors() { |