//! //! termcolor //! ~~~~~~~~~ //! //! termcolor is a header-only c++ library for printing colored messages //! to the terminal. Written just for fun with a help of the Force. //! //! :copyright: (c) 2013 by Ihor Kalnytskyi //! :license: BSD, see LICENSE for details //! #ifndef TERMCOLOR_HPP_ #define TERMCOLOR_HPP_ #include #include // Detect target's platform and set some macros in order to wrap platform // specific code this library depends on. #if defined(_WIN32) || defined(_WIN64) # define TERMCOLOR_TARGET_WINDOWS #elif defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)) # define TERMCOLOR_TARGET_POSIX #endif // If implementation has not been explicitly set, try to choose one based on // target platform. #if !defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) && !defined(TERMCOLOR_USE_WINDOWS_API) && !defined(TERMCOLOR_USE_NOOP) # if defined(TERMCOLOR_TARGET_POSIX) # define TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES # define TERMCOLOR_AUTODETECTED_IMPLEMENTATION # elif defined(TERMCOLOR_TARGET_WINDOWS) # define TERMCOLOR_USE_WINDOWS_API # define TERMCOLOR_AUTODETECTED_IMPLEMENTATION # endif #endif // These headers provide isatty()/fileno() functions, which are used for // testing whether a standard stream refers to the terminal. #if defined(TERMCOLOR_TARGET_POSIX) # include #elif defined(TERMCOLOR_TARGET_WINDOWS) # include # include #endif namespace termcolor { // Forward declaration of the `_internal` namespace. // All comments are below. namespace _internal { inline int colorize_index(); inline FILE* get_standard_stream(const std::ostream& stream); inline bool is_colorized(std::ostream& stream); inline bool is_atty(const std::ostream& stream); #if defined(TERMCOLOR_TARGET_WINDOWS) inline void win_change_attributes(std::ostream& stream, int foreground, int background=-1); #endif } inline std::ostream& colorize(std::ostream& stream) { stream.iword(_internal::colorize_index()) = 1L; return stream; } inline std::ostream& nocolorize(std::ostream& stream) { stream.iword(_internal::colorize_index()) = 0L; return stream; } inline std::ostream& reset(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) stream << "\033[00m"; #elif defined(TERMCOLOR_USE_WINDOWS_API) _internal::win_change_attributes(stream, -1, -1); #endif } return stream; } inline std::ostream& bold(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) stream << "\033[1m"; #elif defined(TERMCOLOR_USE_WINDOWS_API) #endif } return stream; } inline std::ostream& dark(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) stream << "\033[2m"; #elif defined(TERMCOLOR_USE_WINDOWS_API) #endif } return stream; } inline std::ostream& italic(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) stream << "\033[3m"; #elif defined(TERMCOLOR_USE_WINDOWS_API) #endif } return stream; } inline std::ostream& underline(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) stream << "\033[4m"; #elif defined(TERMCOLOR_USE_WINDOWS_API) _internal::win_change_attributes(stream, -1, COMMON_LVB_UNDERSCORE); #endif } return stream; } inline std::ostream& blink(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) stream << "\033[5m"; #elif defined(TERMCOLOR_USE_WINDOWS_API) #endif } return stream; } inline std::ostream& reverse(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) stream << "\033[7m"; #elif defined(TERMCOLOR_USE_WINDOWS_API) #endif } return stream; } inline std::ostream& concealed(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) stream << "\033[8m"; #elif defined(TERMCOLOR_USE_WINDOWS_API) #endif } return stream; } inline std::ostream& crossed(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) stream << "\033[9m"; #elif defined(TERMCOLOR_USE_WINDOWS_API) #endif } return stream; } template inline std::ostream& color(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) char command[12]; std::snprintf(command, sizeof(command), "\033[38;5;%dm", code); stream << command; #elif defined(TERMCOLOR_USE_WINDOWS_API) #endif } return stream; } template inline std::ostream& on_color(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) char command[12]; std::snprintf(command, sizeof(command), "\033[48;5;%dm", code); stream << command; #elif defined(TERMCOLOR_USE_WINDOWS_API) #endif } return stream; } template inline std::ostream& color(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) char command[20]; std::snprintf(command, sizeof(command), "\033[38;2;%d;%d;%dm", r, g, b); stream << command; #elif defined(TERMCOLOR_USE_WINDOWS_API) #endif } return stream; } template inline std::ostream& on_color(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) char command[20]; std::snprintf(command, sizeof(command), "\033[48;2;%d;%d;%dm", r, g, b); stream << command; #elif defined(TERMCOLOR_USE_WINDOWS_API) #endif } return stream; } inline std::ostream& grey(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) stream << "\033[30m"; #elif defined(TERMCOLOR_USE_WINDOWS_API) _internal::win_change_attributes(stream, 0 // grey (black) ); #endif } return stream; } inline std::ostream& red(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) stream << "\033[31m"; #elif defined(TERMCOLOR_USE_WINDOWS_API) _internal::win_change_attributes(stream, FOREGROUND_RED ); #endif } return stream; } inline std::ostream& green(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) stream << "\033[32m"; #elif defined(TERMCOLOR_USE_WINDOWS_API) _internal::win_change_attributes(stream, FOREGROUND_GREEN ); #endif } return stream; } inline std::ostream& yellow(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) stream << "\033[33m"; #elif defined(TERMCOLOR_USE_WINDOWS_API) _internal::win_change_attributes(stream, FOREGROUND_GREEN | FOREGROUND_RED ); #endif } return stream; } inline std::ostream& blue(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) stream << "\033[34m"; #elif defined(TERMCOLOR_USE_WINDOWS_API) _internal::win_change_attributes(stream, FOREGROUND_BLUE ); #endif } return stream; } inline std::ostream& magenta(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) stream << "\033[35m"; #elif defined(TERMCOLOR_USE_WINDOWS_API) _internal::win_change_attributes(stream, FOREGROUND_BLUE | FOREGROUND_RED ); #endif } return stream; } inline std::ostream& cyan(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) stream << "\033[36m"; #elif defined(TERMCOLOR_USE_WINDOWS_API) _internal::win_change_attributes(stream, FOREGROUND_BLUE | FOREGROUND_GREEN ); #endif } return stream; } inline std::ostream& white(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) stream << "\033[37m"; #elif defined(TERMCOLOR_USE_WINDOWS_API) _internal::win_change_attributes(stream, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED ); #endif } return stream; } inline std::ostream& bright_grey(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) stream << "\033[90m"; #elif defined(TERMCOLOR_USE_WINDOWS_API) _internal::win_change_attributes(stream, 0 | FOREGROUND_INTENSITY // grey (black) ); #endif } return stream; } inline std::ostream& bright_red(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) stream << "\033[91m"; #elif defined(TERMCOLOR_USE_WINDOWS_API) _internal::win_change_attributes(stream, FOREGROUND_RED | FOREGROUND_INTENSITY ); #endif } return stream; } inline std::ostream& bright_green(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) stream << "\033[92m"; #elif defined(TERMCOLOR_USE_WINDOWS_API) _internal::win_change_attributes(stream, FOREGROUND_GREEN | FOREGROUND_INTENSITY ); #endif } return stream; } inline std::ostream& bright_yellow(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) stream << "\033[93m"; #elif defined(TERMCOLOR_USE_WINDOWS_API) _internal::win_change_attributes(stream, FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY ); #endif } return stream; } inline std::ostream& bright_blue(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) stream << "\033[94m"; #elif defined(TERMCOLOR_USE_WINDOWS_API) _internal::win_change_attributes(stream, FOREGROUND_BLUE | FOREGROUND_INTENSITY ); #endif } return stream; } inline std::ostream& bright_magenta(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) stream << "\033[95m"; #elif defined(TERMCOLOR_USE_WINDOWS_API) _internal::win_change_attributes(stream, FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY ); #endif } return stream; } inline std::ostream& bright_cyan(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) stream << "\033[96m"; #elif defined(TERMCOLOR_USE_WINDOWS_API) _internal::win_change_attributes(stream, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY ); #endif } return stream; } inline std::ostream& bright_white(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) stream << "\033[97m"; #elif defined(TERMCOLOR_USE_WINDOWS_API) _internal::win_change_attributes(stream, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY ); #endif } return stream; } inline std::ostream& on_grey(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) stream << "\033[40m"; #elif defined(TERMCOLOR_USE_WINDOWS_API) _internal::win_change_attributes(stream, -1, 0 // grey (black) ); #endif } return stream; } inline std::ostream& on_red(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) stream << "\033[41m"; #elif defined(TERMCOLOR_USE_WINDOWS_API) _internal::win_change_attributes(stream, -1, BACKGROUND_RED ); #endif } return stream; } inline std::ostream& on_green(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) stream << "\033[42m"; #elif defined(TERMCOLOR_USE_WINDOWS_API) _internal::win_change_attributes(stream, -1, BACKGROUND_GREEN ); #endif } return stream; } inline std::ostream& on_yellow(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) stream << "\033[43m"; #elif defined(TERMCOLOR_USE_WINDOWS_API) _internal::win_change_attributes(stream, -1, BACKGROUND_GREEN | BACKGROUND_RED ); #endif } return stream; } inline std::ostream& on_blue(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) stream << "\033[44m"; #elif defined(TERMCOLOR_USE_WINDOWS_API) _internal::win_change_attributes(stream, -1, BACKGROUND_BLUE ); #endif } return stream; } inline std::ostream& on_magenta(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) stream << "\033[45m"; #elif defined(TERMCOLOR_USE_WINDOWS_API) _internal::win_change_attributes(stream, -1, BACKGROUND_BLUE | BACKGROUND_RED ); #endif } return stream; } inline std::ostream& on_cyan(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) stream << "\033[46m"; #elif defined(TERMCOLOR_USE_WINDOWS_API) _internal::win_change_attributes(stream, -1, BACKGROUND_GREEN | BACKGROUND_BLUE ); #endif } return stream; } inline std::ostream& on_white(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) stream << "\033[47m"; #elif defined(TERMCOLOR_USE_WINDOWS_API) _internal::win_change_attributes(stream, -1, BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED ); #endif } return stream; } inline std::ostream& on_bright_grey(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) stream << "\033[100m"; #elif defined(TERMCOLOR_USE_WINDOWS_API) _internal::win_change_attributes(stream, -1, 0 | BACKGROUND_INTENSITY // grey (black) ); #endif } return stream; } inline std::ostream& on_bright_red(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) stream << "\033[101m"; #elif defined(TERMCOLOR_USE_WINDOWS_API) _internal::win_change_attributes(stream, -1, BACKGROUND_RED | BACKGROUND_INTENSITY ); #endif } return stream; } inline std::ostream& on_bright_green(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) stream << "\033[102m"; #elif defined(TERMCOLOR_USE_WINDOWS_API) _internal::win_change_attributes(stream, -1, BACKGROUND_GREEN | BACKGROUND_INTENSITY ); #endif } return stream; } inline std::ostream& on_bright_yellow(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) stream << "\033[103m"; #elif defined(TERMCOLOR_USE_WINDOWS_API) _internal::win_change_attributes(stream, -1, BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY ); #endif } return stream; } inline std::ostream& on_bright_blue(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) stream << "\033[104m"; #elif defined(TERMCOLOR_USE_WINDOWS_API) _internal::win_change_attributes(stream, -1, BACKGROUND_BLUE | BACKGROUND_INTENSITY ); #endif } return stream; } inline std::ostream& on_bright_magenta(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) stream << "\033[105m"; #elif defined(TERMCOLOR_USE_WINDOWS_API) _internal::win_change_attributes(stream, -1, BACKGROUND_BLUE | BACKGROUND_RED | BACKGROUND_INTENSITY ); #endif } return stream; } inline std::ostream& on_bright_cyan(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) stream << "\033[106m"; #elif defined(TERMCOLOR_USE_WINDOWS_API) _internal::win_change_attributes(stream, -1, BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY ); #endif } return stream; } inline std::ostream& on_bright_white(std::ostream& stream) { if (_internal::is_colorized(stream)) { #if defined(TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES) stream << "\033[107m"; #elif defined(TERMCOLOR_USE_WINDOWS_API) _internal::win_change_attributes(stream, -1, BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED | BACKGROUND_INTENSITY ); #endif } return stream; } //! Since C++ hasn't a way to hide something in the header from //! the outer access, I have to introduce this namespace which //! is used for internal purpose and should't be access from //! the user code. namespace _internal { // An index to be used to access a private storage of I/O streams. See // colorize / nocolorize I/O manipulators for details. Due to the fact // that static variables ain't shared between translation units, inline // function with local static variable is used to do the trick and share // the variable value between translation units. inline int colorize_index() { static int colorize_index = std::ios_base::xalloc(); return colorize_index; } //! Since C++ hasn't a true way to extract stream handler //! from the a given `std::ostream` object, I have to write //! this kind of hack. inline FILE* get_standard_stream(const std::ostream& stream) { if (&stream == &std::cout) return stdout; else if ((&stream == &std::cerr) || (&stream == &std::clog)) return stderr; return nullptr; } // Say whether a given stream should be colorized or not. It's always // true for ATTY streams and may be true for streams marked with // colorize flag. inline bool is_colorized(std::ostream& stream) { return is_atty(stream) || static_cast(stream.iword(colorize_index())); } //! Test whether a given `std::ostream` object refers to //! a terminal. inline bool is_atty(const std::ostream& stream) { FILE* std_stream = get_standard_stream(stream); // Unfortunately, fileno() ends with segmentation fault // if invalid file descriptor is passed. So we need to // handle this case gracefully and assume it's not a tty // if standard stream is not detected, and 0 is returned. if (!std_stream) return false; #if defined(TERMCOLOR_TARGET_POSIX) return ::isatty(fileno(std_stream)); #elif defined(TERMCOLOR_TARGET_WINDOWS) return ::_isatty(_fileno(std_stream)); #else return false; #endif } #if defined(TERMCOLOR_TARGET_WINDOWS) //! Change Windows Terminal colors attribute. If some //! parameter is `-1` then attribute won't changed. inline void win_change_attributes(std::ostream& stream, int foreground, int background) { // yeah, i know.. it's ugly, it's windows. static WORD defaultAttributes = 0; // Windows doesn't have ANSI escape sequences and so we use special // API to change Terminal output color. That means we can't // manipulate colors by means of "std::stringstream" and hence // should do nothing in this case. if (!_internal::is_atty(stream)) return; // get terminal handle HANDLE hTerminal = INVALID_HANDLE_VALUE; if (&stream == &std::cout) hTerminal = GetStdHandle(STD_OUTPUT_HANDLE); else if (&stream == &std::cerr) hTerminal = GetStdHandle(STD_ERROR_HANDLE); // save default terminal attributes if it unsaved if (!defaultAttributes) { CONSOLE_SCREEN_BUFFER_INFO info; if (!GetConsoleScreenBufferInfo(hTerminal, &info)) return; defaultAttributes = info.wAttributes; } // restore all default settings if (foreground == -1 && background == -1) { SetConsoleTextAttribute(hTerminal, defaultAttributes); return; } // get current settings CONSOLE_SCREEN_BUFFER_INFO info; if (!GetConsoleScreenBufferInfo(hTerminal, &info)) return; if (foreground != -1) { info.wAttributes &= ~(info.wAttributes & 0x0F); info.wAttributes |= static_cast(foreground); } if (background != -1) { info.wAttributes &= ~(info.wAttributes & 0xF0); info.wAttributes |= static_cast(background); } SetConsoleTextAttribute(hTerminal, info.wAttributes); } #endif // TERMCOLOR_TARGET_WINDOWS } // namespace _internal } // namespace termcolor #undef TERMCOLOR_TARGET_POSIX #undef TERMCOLOR_TARGET_WINDOWS #if defined(TERMCOLOR_AUTODETECTED_IMPLEMENTATION) # undef TERMCOLOR_USE_ANSI_ESCAPE_SEQUENCES # undef TERMCOLOR_USE_WINDOWS_API #endif #endif // TERMCOLOR_HPP_