![]() |
Tulip
4.6.0
Better Visualization Through Research
|
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