36 #if defined(__linux) || defined(__APPLE__) 
   39 #include <sys/ioctl.h> 
   42 static struct termios stored_settings;
 
   44 static void setConsoleSettingsForAnsiRequest(
void) {
 
   45   struct termios new_settings;
 
   46   tcgetattr(0, &stored_settings);
 
   47   new_settings = stored_settings;
 
   48   new_settings.c_lflag &= ~ICANON;
 
   49   new_settings.c_lflag &= ~ECHO;
 
   50   tcsetattr(0, TCSANOW, &new_settings);
 
   53 static void resetConsoleSettings(
void) {
 
   54   tcsetattr(0, TCSANOW, &stored_settings);
 
   57 static bool processInForeground(
void) {
 
   58   pid_t fg = tcgetpgrp(STDIN_FILENO);
 
   59   return fg == getpgrp();
 
   63 static std::pair<int, int> getConsoleCursorPosition() {
 
   66   if (isatty(fileno(stdin)) && processInForeground()) {
 
   67     setConsoleSettingsForAnsiRequest();
 
   68     fprintf(stdout, 
"\x1b[6n");
 
   70     if (fscanf(stdin, 
"\x1b[%d;%dR", &row, &col)) {}
 
   72     resetConsoleSettings();
 
   75   return std::make_pair(row, col);
 
   78 static std::pair<int, int> getConsoleSize() {
 
   82   if (ioctl(0,TIOCGWINSZ,&ws)==0) {
 
   87   return std::make_pair(rows, cols);
 
   92 inline std::pair<int, int> getConsoleCursorPosition() {
 
   94   CONSOLE_SCREEN_BUFFER_INFO SBInfo;
 
   96   if(GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &SBInfo)) {
 
   97     row = SBInfo.dwCursorPosition.Y;
 
   98     col = SBInfo.dwCursorPosition.X;
 
  101   return std::make_pair(row, col);
 
  104 inline std::pair<int, int> getConsoleSize() {
 
  105   int rows=200, cols=200;
 
  106   CONSOLE_SCREEN_BUFFER_INFO SBInfo;
 
  108   if(GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &SBInfo)) {
 
  109     rows = SBInfo.dwSize.Y;
 
  110     cols = SBInfo.dwSize.X-1;
 
  113   return std::make_pair(rows, cols);
 
  118 enum TextEffect {NORMAL=1, BOLD=2, UNDERLINED=4, BLINK=8};
 
  120 enum TextColor {BLACK, RED, GREEN, YELLOW, BLUE,
 
  121                 MAGENTA, CYAN, LIGHT_GRAY, DARK_GRAY,
 
  122                 LIGHT_RED, LIGHT_GREEN, LIGHT_YELLOW,
 
  123                 LIGHT_BLUE, LIGHT_MAGENTA, LIGHT_CYAN, WHITE
 
  126 class TextFgColorSetup {
 
  130   TextFgColorSetup(TextColor color) :
 
  136 class TextBgColorSetup {
 
  140   TextBgColorSetup(TextColor color) :
 
  146 class TextEffectSetup {
 
  150   TextEffectSetup(
int effect) :
 
  158 static std::map<TextColor, std::string> initAnsiFgColors() {
 
  159   const char *colorterm = getenv(
"COLORTERM");
 
  160   bool rxvt = colorterm && std::string(colorterm).find(
"rxvt") != std::string::npos;
 
  161   std::map<TextColor, std::string> ret;
 
  169   ret[LIGHT_GRAY] = 
"37";
 
  170   ret[DARK_GRAY] = rxvt ? ret[BLACK] : 
"90";
 
  171   ret[LIGHT_RED] = rxvt ? ret[RED] : 
"91";
 
  172   ret[LIGHT_GREEN] = rxvt ? ret[GREEN] : 
"92";
 
  173   ret[LIGHT_YELLOW] = rxvt ? ret[YELLOW] : 
"93";
 
  174   ret[LIGHT_BLUE] = rxvt ? ret[BLUE] : 
"94";
 
  175   ret[LIGHT_MAGENTA] = rxvt ? ret[MAGENTA] : 
"95";
 
  176   ret[LIGHT_CYAN] = rxvt ? ret[CYAN] : 
"96";
 
  177   ret[WHITE] = rxvt ? ret[LIGHT_GRAY] : 
"97";
 
  181 static std::map<TextColor, std::string> initAnsiBgColors() {
 
  182   const char *colorterm = getenv(
"COLORTERM");
 
  183   bool rxvt = colorterm && std::string(colorterm).find(
"rxvt") != std::string::npos;
 
  184   std::map<TextColor, std::string> ret;
 
  192   ret[LIGHT_GRAY] = 
"47";
 
  193   ret[DARK_GRAY] = rxvt ? ret[BLACK] : 
"100";
 
  194   ret[LIGHT_RED] = rxvt ? ret[RED] : 
"101";
 
  195   ret[LIGHT_GREEN] = rxvt ? ret[GREEN] : 
"102";
 
  196   ret[LIGHT_YELLOW] = rxvt ? ret[YELLOW] : 
"103";
 
  197   ret[LIGHT_BLUE] = rxvt ? ret[BLUE] : 
"104";
 
  198   ret[LIGHT_MAGENTA] = rxvt ? ret[MAGENTA] : 
"105";
 
  199   ret[LIGHT_CYAN] = rxvt ? ret[CYAN] : 
"106";
 
  200   ret[WHITE] = rxvt ? ret[LIGHT_GRAY] : 
"107";
 
  204 static std::map<TextColor, std::string> ansiFgColors = initAnsiFgColors();
 
  205 static std::map<TextColor, std::string> ansiBgColors = initAnsiBgColors();
 
  208 static std::map<TextColor, int> initCrtFgColors() {
 
  209   std::map<TextColor, int> ret;
 
  211   ret[RED] = FOREGROUND_RED;
 
  212   ret[GREEN] = FOREGROUND_GREEN;
 
  213   ret[YELLOW] = FOREGROUND_RED | FOREGROUND_GREEN;
 
  214   ret[BLUE] = FOREGROUND_BLUE;
 
  215   ret[MAGENTA] = FOREGROUND_BLUE | FOREGROUND_RED;
 
  216   ret[CYAN] = FOREGROUND_GREEN | FOREGROUND_BLUE;
 
  217   ret[LIGHT_GRAY]= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
 
  218   ret[DARK_GRAY] = FOREGROUND_INTENSITY;
 
  219   ret[LIGHT_RED] = FOREGROUND_RED | FOREGROUND_INTENSITY;
 
  220   ret[LIGHT_GREEN] = FOREGROUND_GREEN | FOREGROUND_INTENSITY;
 
  221   ret[LIGHT_YELLOW] = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
 
  222   ret[LIGHT_BLUE] = FOREGROUND_BLUE | FOREGROUND_INTENSITY;
 
  223   ret[LIGHT_MAGENTA] = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY;
 
  224   ret[LIGHT_CYAN] = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
 
  225   ret[WHITE] = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
 
  229 static std::map<TextColor, int> initCrtBgColors() {
 
  230   std::map<TextColor, int> ret;
 
  232   ret[RED] = BACKGROUND_RED;
 
  233   ret[GREEN] = BACKGROUND_GREEN;
 
  234   ret[YELLOW] = BACKGROUND_RED | BACKGROUND_GREEN;
 
  235   ret[BLUE] = BACKGROUND_BLUE;
 
  236   ret[MAGENTA] = BACKGROUND_BLUE | BACKGROUND_RED;
 
  237   ret[CYAN] = BACKGROUND_GREEN | BACKGROUND_BLUE;
 
  238   ret[LIGHT_GRAY]= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE;
 
  239   ret[DARK_GRAY] = BACKGROUND_INTENSITY;
 
  240   ret[LIGHT_RED] = BACKGROUND_RED | BACKGROUND_INTENSITY;
 
  241   ret[LIGHT_GREEN] = BACKGROUND_GREEN | BACKGROUND_INTENSITY;
 
  242   ret[LIGHT_YELLOW] = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_INTENSITY;
 
  243   ret[LIGHT_BLUE] = BACKGROUND_BLUE | BACKGROUND_INTENSITY;
 
  244   ret[LIGHT_MAGENTA] = BACKGROUND_BLUE | BACKGROUND_RED | BACKGROUND_INTENSITY;
 
  245   ret[LIGHT_CYAN] = BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY;
 
  246   ret[WHITE] = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY;
 
  250 static WORD getCurrentBgColor() {
 
  251   HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
 
  252   CONSOLE_SCREEN_BUFFER_INFO info;
 
  253   GetConsoleScreenBufferInfo(hStdout, &info);
 
  254   return info.wAttributes & (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY);
 
  257 static WORD getCurrentFgColor() {
 
  258   HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
 
  259   CONSOLE_SCREEN_BUFFER_INFO info;
 
  260   GetConsoleScreenBufferInfo(hStdout, &info);
 
  261   return info.wAttributes & (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
 
  263 static std::map<TextColor, int> crtFgColors = initCrtFgColors();
 
  264 static std::map<TextColor, int> crtBgColors = initCrtBgColors();
 
  267 static void escapeAnsiCode(std::ostream &os, 
const std::string &ansiCode, 
const std::string &endEscape =
"m") {
 
  268   static const char *stdOutNoAnsiEscapes = getenv(
"STDOUT_NO_ANSI_ESCAPES");
 
  269   static const char *stdErrNoAnsiEscapes = getenv(
"STDERR_NO_ANSI_ESCAPES");
 
  272   if ((os == std::cout && !stdOutNoAnsiEscapes && isatty(fileno(stdout))) ||
 
  273       (os == std::cerr && !stdErrNoAnsiEscapes && isatty(fileno(stderr))))
 
  275   if ((os == std::cout && !stdOutNoAnsiEscapes) ||
 
  276       (os == std::cerr && !stdErrNoAnsiEscapes))
 
  278     os << 
"\x1b[" << ansiCode << endEscape;
 
  303 inline std::ostream& defaultTextColor(std::ostream &s) {
 
  304   if (s == std::cout || s == std::cerr) {
 
  306     escapeAnsiCode(s, 
"0");
 
  307     escapeAnsiCode(s, 
"39");
 
  308     escapeAnsiCode(s, 
"49");
 
  312     static const char *term = getenv(
"TERM");
 
  314     if (term && std::string(term) != 
"cygwin") {
 
  315       escapeAnsiCode(s, 
"0");
 
  316       escapeAnsiCode(s, 
"39");
 
  317       escapeAnsiCode(s, 
"49");
 
  320       HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
 
  321       SetConsoleTextAttribute(hStdout, crtBgColors[BLACK] | crtFgColors[WHITE]);
 
  330 inline std::ostream& 
operator<<(std::ostream &s, 
const TextFgColorSetup &tgfcs) {
 
  331   if (s == std::cout || s == std::cerr) {
 
  333     escapeAnsiCode(s, ansiFgColors[tgfcs.color]);
 
  337     static const char *term = getenv(
"TERM");
 
  339     if (term && std::string(term) != 
"cygwin") {
 
  340       escapeAnsiCode(s, ansiFgColors[tgfcs.color]);
 
  343       HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
 
  344       SetConsoleTextAttribute(hStdout, crtFgColors[tgfcs.color] | getCurrentBgColor());
 
  353 inline std::ostream& 
operator<<(std::ostream &s, 
const TextBgColorSetup &tbgcs) {
 
  354   if (s == std::cout || s == std::cerr) {
 
  356     escapeAnsiCode(s, ansiBgColors[tbgcs.color]);
 
  360     static const char *term = getenv(
"TERM");
 
  362     if (term && std::string(term) != 
"cygwin") {
 
  363       escapeAnsiCode(s, ansiBgColors[tbgcs.color]);
 
  366       HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
 
  367       SetConsoleTextAttribute(hStdout, getCurrentFgColor() | crtBgColors[tbgcs.color]);
 
  376 inline void setEffects(std::ostream &s, 
const int &effect) {
 
  378     escapeAnsiCode(s, 
"0");
 
  381     escapeAnsiCode(s, 
"1");
 
  383   if (effect & UNDERLINED)
 
  384     escapeAnsiCode(s, 
"4");
 
  387     escapeAnsiCode(s, 
"5");
 
  390 inline std::ostream& 
operator<<(std::ostream &s, 
const TextEffectSetup &tes) {
 
  391   if (s == std::cout || s == std::cerr) {
 
  393     setEffects(s, tes.effect);
 
  395     static const char *term = getenv(
"TERM");
 
  397     if (term && std::string(term) != 
"cygwin") {
 
  398       setEffects(s, tes.effect);
 
  407 inline TextBgColorSetup setTextBackgroundColor(TextColor color) {
 
  408   return TextBgColorSetup(color);
 
  411 inline TextFgColorSetup setTextColor(TextColor color) {
 
  412   return TextFgColorSetup(color);
 
  415 inline TextEffectSetup setTextEffect(
int effect) {
 
  416   return TextEffectSetup(effect);
 
  419 inline std::ostream& bold(std::ostream& s) {
 
  420   return s << setTextEffect(BOLD);
 
  423 inline std::ostream& underlined(std::ostream& s) {
 
  424   return s << setTextEffect(UNDERLINED);
 
  427 inline std::ostream& red(std::ostream& s) {
 
  428   return s << setTextColor(RED);
 
  431 inline std::ostream& green(std::ostream& s) {
 
  432   return s << setTextColor(GREEN);
 
  435 inline std::ostream& blue(std::ostream& s) {
 
  436   return s << setTextColor(BLUE);
 
  439 inline std::ostream& yellow(std::ostream& s) {
 
  440   return s << setTextColor(YELLOW);
 
  443 inline std::ostream& white(std::ostream& s) {
 
  444   return s << setTextColor(WHITE);
 
  447 inline std::ostream& black(std::ostream& s) {
 
  448   return s << setTextColor(BLACK);
 
  451 inline std::ostream& magenta(std::ostream& s) {
 
  452   return s << setTextColor(MAGENTA);
 
  455 inline std::ostream& cyan(std::ostream& s) {
 
  456   return s << setTextColor(CYAN);
 
  459 inline std::ostream& lightRed(std::ostream& s) {
 
  460   return s << setTextColor(LIGHT_RED);
 
  463 inline std::ostream& lightGreen(std::ostream& s) {
 
  464   return s << setTextColor(LIGHT_GREEN);
 
  467 inline std::ostream& lightBlue(std::ostream& s) {
 
  468   return s << setTextColor(LIGHT_BLUE);
 
  471 inline std::ostream& lightYellow(std::ostream& s) {
 
  472   return s << setTextColor(LIGHT_YELLOW);
 
  475 inline std::ostream& lightGray(std::ostream& s) {
 
  476   return s << setTextColor(LIGHT_GRAY);
 
  479 inline std::ostream& darkGray(std::ostream& s) {
 
  480   return s << setTextColor(DARK_GRAY);
 
  483 inline std::ostream& lightMagenta(std::ostream& s) {
 
  484   return s << setTextColor(LIGHT_MAGENTA);
 
  487 inline std::ostream& lightCyan(std::ostream& s) {
 
  488   return s << setTextColor(LIGHT_CYAN);
 
  494 inline std::ostream& fillToEndOfLine(std::ostream& s) {
 
  497   if (processInForeground() && ((s == std::cout && isatty(fileno(stdout))) || (s == std::cerr && isatty(fileno(stderr))))) {
 
  499     std::pair<int, int> cursorPos = getConsoleCursorPosition();
 
  500     std::pair<int, int> consoleSize = getConsoleSize();
 
  502     if ((cursorPos.second + consoleSize.second) != 0) {
 
  503       for (
int i = cursorPos.second ; i <= consoleSize.second ; ++i) {
 
  516   if ((s == std::cout && !isatty(fileno(stdout))) || (s == std::cerr && !isatty(fileno(stderr)))) {
 
  522   if (!processInForeground()) {
 
  523     s << defaultTextColor << std::endl;