Tulip  4.6.0
Better Visualization Through Research
library/tulip-core/include/tulip/ConsoleUtils.h
00001 /*
00002  *
00003  * This file is part of Tulip (www.tulip-software.org)
00004  *
00005  * Authors: David Auber and the Tulip development Team
00006  * from LaBRI, University of Bordeaux
00007  *
00008  * Tulip is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU Lesser General Public License
00010  * as published by the Free Software Foundation, either version 3
00011  * of the License, or (at your option) any later version.
00012  *
00013  * Tulip is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00016  * See the GNU General Public License for more details.
00017  *
00018  */
00019 ///@cond DOXYGEN_HIDDEN
00020 
00021 
00022 #ifndef CONSOLE_UTILS
00023 #define CONSOLE_UTILS
00024 
00025 #include <iostream>
00026 #include <string>
00027 #include <cstdlib>
00028 #include <cstdio>
00029 #include <map>
00030 
00031 #ifdef WIN32
00032 #include <windows.h>
00033 #include <io.h>
00034 #endif
00035 
00036 #if defined(__unix__) || defined(__APPLE__)
00037 
00038 #include <termios.h>
00039 #include <sys/ioctl.h>
00040 #include <unistd.h>
00041 
00042 static struct termios stored_settings;
00043 
00044 static void setConsoleSettingsForAnsiRequest(void) {
00045   struct termios new_settings;
00046   tcgetattr(0, &stored_settings);
00047   new_settings = stored_settings;
00048   new_settings.c_lflag &= ~ICANON;
00049   new_settings.c_lflag &= ~ECHO;
00050   tcsetattr(0, TCSANOW, &new_settings);
00051 }
00052 
00053 static void resetConsoleSettings(void) {
00054   tcsetattr(0, TCSANOW, &stored_settings);
00055 }
00056 
00057 static bool processInForeground(void) {
00058   pid_t fg = tcgetpgrp(STDIN_FILENO);
00059   return fg == getpgrp();
00060 }
00061 
00062 
00063 static std::pair<int, int> getConsoleCursorPosition() {
00064   int row=0, col=0;
00065 
00066   if (isatty(fileno(stdin)) && processInForeground()) {
00067     setConsoleSettingsForAnsiRequest();
00068     fprintf(stdout, "\x1b[6n");
00069 
00070     if (fscanf(stdin, "\x1b[%d;%dR", &row, &col)) {}
00071 
00072     resetConsoleSettings();
00073   }
00074 
00075   return std::make_pair(row, col);
00076 }
00077 
00078 static std::pair<int, int> getConsoleSize() {
00079   int rows=-1, cols=-1;
00080   struct winsize ws;
00081 
00082   if (ioctl(0,TIOCGWINSZ,&ws)==0) {
00083     rows = ws.ws_row;
00084     cols =  ws.ws_col;
00085   }
00086 
00087   return std::make_pair(rows, cols);
00088 }
00089 
00090 #elif defined(WIN32)
00091 
00092 inline std::pair<int, int> getConsoleCursorPosition() {
00093   int row=0, col=0;
00094   CONSOLE_SCREEN_BUFFER_INFO SBInfo;
00095 
00096   if(GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &SBInfo)) {
00097     row = SBInfo.dwCursorPosition.Y;
00098     col = SBInfo.dwCursorPosition.X;
00099   }
00100 
00101   return std::make_pair(row, col);
00102 }
00103 
00104 inline std::pair<int, int> getConsoleSize() {
00105   int rows=200, cols=200;
00106   CONSOLE_SCREEN_BUFFER_INFO SBInfo;
00107 
00108   if(GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &SBInfo)) {
00109     rows = SBInfo.dwSize.Y;
00110     cols = SBInfo.dwSize.X-1;
00111   }
00112 
00113   return std::make_pair(rows, cols);
00114 }
00115 
00116 #endif
00117 
00118 enum TextEffect {NORMAL=1, BOLD=2, UNDERLINED=4, BLINK=8};
00119 
00120 enum TextColor {BLACK, RED, GREEN, YELLOW, BLUE,
00121                 MAGENTA, CYAN, LIGHT_GRAY, DARK_GRAY,
00122                 LIGHT_RED, LIGHT_GREEN, LIGHT_YELLOW,
00123                 LIGHT_BLUE, LIGHT_MAGENTA, LIGHT_CYAN, WHITE
00124                };
00125 
00126 class TextFgColorSetup {
00127 
00128 public :
00129 
00130   TextFgColorSetup(TextColor color) :
00131     color(color) {}
00132 
00133   TextColor color;
00134 };
00135 
00136 class TextBgColorSetup {
00137 
00138 public :
00139 
00140   TextBgColorSetup(TextColor color) :
00141     color(color) {}
00142 
00143   TextColor color;
00144 };
00145 
00146 class TextEffectSetup {
00147 
00148 public :
00149 
00150   TextEffectSetup(int effect) :
00151     effect(effect) {}
00152 
00153   int effect;
00154 };
00155 
00156 
00157 
00158 static std::map<TextColor, std::string> initAnsiFgColors() {
00159   const char *colorterm = getenv("COLORTERM");
00160   bool rxvt = colorterm && std::string(colorterm).find("rxvt") != std::string::npos;
00161   std::map<TextColor, std::string> ret;
00162   ret[BLACK] = "30";
00163   ret[RED] = "31";
00164   ret[GREEN] = "32";
00165   ret[YELLOW] = "33";
00166   ret[BLUE] = "34";
00167   ret[MAGENTA] = "35";
00168   ret[CYAN] = "36";
00169   ret[LIGHT_GRAY] = "37";
00170   ret[DARK_GRAY] = rxvt ? ret[BLACK] : "90";
00171   ret[LIGHT_RED] = rxvt ? ret[RED] : "91";
00172   ret[LIGHT_GREEN] = rxvt ? ret[GREEN] : "92";
00173   ret[LIGHT_YELLOW] = rxvt ? ret[YELLOW] : "93";
00174   ret[LIGHT_BLUE] = rxvt ? ret[BLUE] : "94";
00175   ret[LIGHT_MAGENTA] = rxvt ? ret[MAGENTA] : "95";
00176   ret[LIGHT_CYAN] = rxvt ? ret[CYAN] : "96";
00177   ret[WHITE] = rxvt ? ret[LIGHT_GRAY] : "97";
00178   return ret;
00179 }
00180 
00181 static std::map<TextColor, std::string> initAnsiBgColors() {
00182   const char *colorterm = getenv("COLORTERM");
00183   bool rxvt = colorterm && std::string(colorterm).find("rxvt") != std::string::npos;
00184   std::map<TextColor, std::string> ret;
00185   ret[BLACK] = "40";
00186   ret[RED] = "41";
00187   ret[GREEN] = "42";
00188   ret[YELLOW] = "43";
00189   ret[BLUE] = "44";
00190   ret[MAGENTA] = "45";
00191   ret[CYAN] = "46";
00192   ret[LIGHT_GRAY] = "47";
00193   ret[DARK_GRAY] = rxvt ? ret[BLACK] : "100";
00194   ret[LIGHT_RED] = rxvt ? ret[RED] : "101";
00195   ret[LIGHT_GREEN] = rxvt ? ret[GREEN] : "102";
00196   ret[LIGHT_YELLOW] = rxvt ? ret[YELLOW] : "103";
00197   ret[LIGHT_BLUE] = rxvt ? ret[BLUE] : "104";
00198   ret[LIGHT_MAGENTA] = rxvt ? ret[MAGENTA] : "105";
00199   ret[LIGHT_CYAN] = rxvt ? ret[CYAN] : "106";
00200   ret[WHITE] = rxvt ? ret[LIGHT_GRAY] : "107";
00201   return ret;
00202 }
00203 
00204 static std::map<TextColor, std::string> ansiFgColors = initAnsiFgColors();
00205 static std::map<TextColor, std::string> ansiBgColors = initAnsiBgColors();
00206 
00207 #ifdef WIN32
00208 static std::map<TextColor, int> initCrtFgColors() {
00209   std::map<TextColor, int> ret;
00210   ret[BLACK] = 0;
00211   ret[RED] = FOREGROUND_RED;
00212   ret[GREEN] = FOREGROUND_GREEN;
00213   ret[YELLOW] = FOREGROUND_RED | FOREGROUND_GREEN;
00214   ret[BLUE] = FOREGROUND_BLUE;
00215   ret[MAGENTA] = FOREGROUND_BLUE | FOREGROUND_RED;
00216   ret[CYAN] = FOREGROUND_GREEN | FOREGROUND_BLUE;
00217   ret[LIGHT_GRAY]= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
00218   ret[DARK_GRAY] = FOREGROUND_INTENSITY;
00219   ret[LIGHT_RED] = FOREGROUND_RED | FOREGROUND_INTENSITY;
00220   ret[LIGHT_GREEN] = FOREGROUND_GREEN | FOREGROUND_INTENSITY;
00221   ret[LIGHT_YELLOW] = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
00222   ret[LIGHT_BLUE] = FOREGROUND_BLUE | FOREGROUND_INTENSITY;
00223   ret[LIGHT_MAGENTA] = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY;
00224   ret[LIGHT_CYAN] = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
00225   ret[WHITE] = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
00226   return ret;
00227 }
00228 
00229 static std::map<TextColor, int> initCrtBgColors() {
00230   std::map<TextColor, int> ret;
00231   ret[BLACK] = 0;
00232   ret[RED] = BACKGROUND_RED;
00233   ret[GREEN] = BACKGROUND_GREEN;
00234   ret[YELLOW] = BACKGROUND_RED | BACKGROUND_GREEN;
00235   ret[BLUE] = BACKGROUND_BLUE;
00236   ret[MAGENTA] = BACKGROUND_BLUE | BACKGROUND_RED;
00237   ret[CYAN] = BACKGROUND_GREEN | BACKGROUND_BLUE;
00238   ret[LIGHT_GRAY]= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE;
00239   ret[DARK_GRAY] = BACKGROUND_INTENSITY;
00240   ret[LIGHT_RED] = BACKGROUND_RED | BACKGROUND_INTENSITY;
00241   ret[LIGHT_GREEN] = BACKGROUND_GREEN | BACKGROUND_INTENSITY;
00242   ret[LIGHT_YELLOW] = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_INTENSITY;
00243   ret[LIGHT_BLUE] = BACKGROUND_BLUE | BACKGROUND_INTENSITY;
00244   ret[LIGHT_MAGENTA] = BACKGROUND_BLUE | BACKGROUND_RED | BACKGROUND_INTENSITY;
00245   ret[LIGHT_CYAN] = BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY;
00246   ret[WHITE] = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY;
00247   return ret;
00248 }
00249 
00250 static WORD getCurrentBgColor() {
00251   HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
00252   CONSOLE_SCREEN_BUFFER_INFO info;
00253   GetConsoleScreenBufferInfo(hStdout, &info);
00254   return info.wAttributes & (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY);
00255 }
00256 
00257 static WORD getCurrentFgColor() {
00258   HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
00259   CONSOLE_SCREEN_BUFFER_INFO info;
00260   GetConsoleScreenBufferInfo(hStdout, &info);
00261   return info.wAttributes & (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
00262 }
00263 static std::map<TextColor, int> crtFgColors = initCrtFgColors();
00264 static std::map<TextColor, int> crtBgColors = initCrtBgColors();
00265 #endif
00266 
00267 static void escapeAnsiCode(std::ostream &os, const std::string &ansiCode, const std::string &endEscape ="m") {
00268   static const char *stdOutNoAnsiEscapes = getenv("STDOUT_NO_ANSI_ESCAPES");
00269   static const char *stdErrNoAnsiEscapes = getenv("STDERR_NO_ANSI_ESCAPES");
00270 #ifndef WIN32
00271 
00272   if ((&os == &std::cout && !stdOutNoAnsiEscapes && isatty(fileno(stdout))) ||
00273       (&os == &std::cerr && !stdErrNoAnsiEscapes && isatty(fileno(stderr))))
00274 #else
00275   if ((&os == &std::cout && !stdOutNoAnsiEscapes) ||
00276       (&os == &std::cerr && !stdErrNoAnsiEscapes))
00277 #endif
00278     os << "\x1b[" << ansiCode << endEscape;
00279 }
00280 
00281 /*
00282   This set of stream manipulation operators allow to produce
00283   a colored console ouput. Except for windows console application (based on cmd.exe),
00284   the colors are activated through ANSI escape sequences. The writing of these sequences
00285   can be disabled by setting the STDOUT_N0_ANSI_ESCAPES and STDERR_N0_ANSI_ESCAPES
00286   environment variables (for instance, when working with a terminal who does not understand
00287   these sequences).
00288 
00289   Below is an example on how to use it :
00290 
00291   // Output a bold text colored in red on a white background
00292   std::cout << setTextEffect(BOLD) << setTextColor(RED) << setTextBackgroundColor(WHITE) << "Hello World!" << std::endl;
00293 
00294   // Reset the text colors to the default ones
00295   std::cout << defaultTextColor;
00296 
00297   // You can also use some predefined color schemes (only affects text color) : black, white, red, green,
00298   // blue, yellow, white, cyan, magenta, darkGray, lightGray, lightRed, lightGreen, ...
00299   std::cout << red << "Hello " << blue << World !!" << defaulTextColor << std::endl;
00300 
00301  */
00302 
00303 inline std::ostream& defaultTextColor(std::ostream &s) {
00304   if (&s == &std::cout || &s == &std::cerr) {
00305 #ifndef WIN32
00306     escapeAnsiCode(s, "0");
00307     escapeAnsiCode(s, "39");
00308     escapeAnsiCode(s, "49");
00309 #else
00310     // on windows, if the TERM environment variable is not defined
00311     // it means that the shell used is cmd.exe, whose does not understand ANSI escape sequences
00312     static const char *term = getenv("TERM");
00313 
00314     if (term && std::string(term) != "cygwin") {
00315       escapeAnsiCode(s, "0");
00316       escapeAnsiCode(s, "39");
00317       escapeAnsiCode(s, "49");
00318     }
00319     else {
00320       HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
00321       SetConsoleTextAttribute(hStdout, crtBgColors[BLACK] | crtFgColors[WHITE]);
00322     }
00323 
00324 #endif
00325   }
00326 
00327   return s;
00328 }
00329 
00330 inline std::ostream& operator<<(std::ostream &s, const TextFgColorSetup &tgfcs) {
00331   if (&s == &std::cout || &s == &std::cerr) {
00332 #ifndef WIN32
00333     escapeAnsiCode(s, ansiFgColors[tgfcs.color]);
00334 #else
00335     // on windows, if the TERM environment variable is not defined
00336     // it means that the shell used is cmd.exe, whose does not understand ANSI escape sequences
00337     static const char *term = getenv("TERM");
00338 
00339     if (term && std::string(term) != "cygwin") {
00340       escapeAnsiCode(s, ansiFgColors[tgfcs.color]);
00341     }
00342     else {
00343       HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
00344       SetConsoleTextAttribute(hStdout, crtFgColors[tgfcs.color] | getCurrentBgColor());
00345     }
00346 
00347 #endif
00348   }
00349 
00350   return s;
00351 }
00352 
00353 inline std::ostream& operator<<(std::ostream &s, const TextBgColorSetup &tbgcs) {
00354   if (&s == &std::cout || &s == &std::cerr) {
00355 #ifndef WIN32
00356     escapeAnsiCode(s, ansiBgColors[tbgcs.color]);
00357 #else
00358     // on windows, if the TERM environment variable is not defined
00359     // it means that the shell used is cmd.exe, whose does not understand ANSI escape sequences
00360     static const char *term = getenv("TERM");
00361 
00362     if (term && std::string(term) != "cygwin") {
00363       escapeAnsiCode(s, ansiBgColors[tbgcs.color]);
00364     }
00365     else {
00366       HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
00367       SetConsoleTextAttribute(hStdout, getCurrentFgColor() | crtBgColors[tbgcs.color]);
00368     }
00369 
00370 #endif
00371   }
00372 
00373   return s;
00374 }
00375 
00376 inline void setEffects(std::ostream &s, const int &effect) {
00377   if (effect & NORMAL)
00378     escapeAnsiCode(s, "0");
00379 
00380   if (effect & BOLD)
00381     escapeAnsiCode(s, "1");
00382 
00383   if (effect & UNDERLINED)
00384     escapeAnsiCode(s, "4");
00385 
00386   if (effect & BLINK)
00387     escapeAnsiCode(s, "5");
00388 }
00389 
00390 inline std::ostream& operator<<(std::ostream &s, const TextEffectSetup &tes) {
00391   if (&s == &std::cout || &s == &std::cerr) {
00392 #ifndef WIN32
00393     setEffects(s, tes.effect);
00394 #else
00395     static const char *term = getenv("TERM");
00396 
00397     if (term && std::string(term) != "cygwin") {
00398       setEffects(s, tes.effect);
00399     }
00400 
00401 #endif
00402   }
00403 
00404   return s;
00405 }
00406 
00407 inline TextBgColorSetup setTextBackgroundColor(TextColor color) {
00408   return TextBgColorSetup(color);
00409 }
00410 
00411 inline TextFgColorSetup setTextColor(TextColor color) {
00412   return TextFgColorSetup(color);
00413 }
00414 
00415 inline TextEffectSetup setTextEffect(int effect) {
00416   return TextEffectSetup(effect);
00417 }
00418 
00419 inline std::ostream& bold(std::ostream& s) {
00420   return s << setTextEffect(BOLD);
00421 }
00422 
00423 inline std::ostream& underlined(std::ostream& s) {
00424   return s << setTextEffect(UNDERLINED);
00425 }
00426 
00427 inline std::ostream& red(std::ostream& s) {
00428   return s << setTextColor(RED);
00429 }
00430 
00431 inline std::ostream& green(std::ostream& s) {
00432   return s << setTextColor(GREEN);
00433 }
00434 
00435 inline std::ostream& blue(std::ostream& s) {
00436   return s << setTextColor(BLUE);
00437 }
00438 
00439 inline std::ostream& yellow(std::ostream& s) {
00440   return s << setTextColor(YELLOW);
00441 }
00442 
00443 inline std::ostream& white(std::ostream& s) {
00444   return s << setTextColor(WHITE);
00445 }
00446 
00447 inline std::ostream& black(std::ostream& s) {
00448   return s << setTextColor(BLACK);
00449 }
00450 
00451 inline std::ostream& magenta(std::ostream& s) {
00452   return s << setTextColor(MAGENTA);
00453 }
00454 
00455 inline std::ostream& cyan(std::ostream& s) {
00456   return s << setTextColor(CYAN);
00457 }
00458 
00459 inline std::ostream& lightRed(std::ostream& s) {
00460   return s << setTextColor(LIGHT_RED);
00461 }
00462 
00463 inline std::ostream& lightGreen(std::ostream& s) {
00464   return s << setTextColor(LIGHT_GREEN);
00465 }
00466 
00467 inline std::ostream& lightBlue(std::ostream& s) {
00468   return s << setTextColor(LIGHT_BLUE);
00469 }
00470 
00471 inline std::ostream& lightYellow(std::ostream& s) {
00472   return s << setTextColor(LIGHT_YELLOW);
00473 }
00474 
00475 inline std::ostream& lightGray(std::ostream& s) {
00476   return s << setTextColor(LIGHT_GRAY);
00477 }
00478 
00479 inline std::ostream& darkGray(std::ostream& s) {
00480   return s << setTextColor(DARK_GRAY);
00481 }
00482 
00483 inline std::ostream& lightMagenta(std::ostream& s) {
00484   return s << setTextColor(LIGHT_MAGENTA);
00485 }
00486 
00487 inline std::ostream& lightCyan(std::ostream& s) {
00488   return s << setTextColor(LIGHT_CYAN);
00489 }
00490 
00491 // Fill the current line of the terminal with space characters from the
00492 // current cursor position to the end of the line.
00493 // The purpose is to have a constant background color on the line.
00494 inline std::ostream& fillToEndOfLine(std::ostream& s) {
00495 #ifndef WIN32
00496 
00497   if (processInForeground() && ((&s == &std::cout && isatty(fileno(stdout))) || (&s == &std::cerr && isatty(fileno(stderr))))) {
00498 #endif
00499     std::pair<int, int> cursorPos = getConsoleCursorPosition();
00500     std::pair<int, int> consoleSize = getConsoleSize();
00501 
00502     if ((cursorPos.second + consoleSize.second) != 0) {
00503       for (int i = cursorPos.second ; i <= consoleSize.second ; ++i) {
00504         s << " ";
00505       }
00506     }
00507     else {
00508       s << std::endl;
00509     }
00510 
00511 #ifndef WIN32
00512   }
00513 
00514 #endif
00515 
00516   if ((&s == &std::cout && !isatty(fileno(stdout))) || (&s == &std::cerr && !isatty(fileno(stderr)))) {
00517     s << std::endl;
00518   }
00519 
00520 #ifndef WIN32
00521 
00522   if (!processInForeground()) {
00523     s << defaultTextColor << std::endl;
00524   }
00525 
00526 #endif
00527 
00528   return s;
00529 }
00530 
00531 #endif
00532 ///@endcond
 All Classes Files Functions Variables Enumerations Enumerator Properties