aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Support
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Support')
-rw-r--r--llvm/lib/Support/CMakeLists.txt11
-rw-r--r--llvm/lib/Support/Unix/Process.inc60
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() {