Tulip  5.3.0
Large graphs analysis and drawing
ConsoleUtils.h
1 /*
2  *
3  * This file is part of Tulip (http://tulip.labri.fr)
4  *
5  * Authors: David Auber and the Tulip development Team
6  * from LaBRI, University of Bordeaux
7  *
8  * Tulip is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation, either version 3
11  * of the License, or (at your option) any later version.
12  *
13  * Tulip is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16  * See the GNU General Public License for more details.
17  *
18  */
19 ///@cond DOXYGEN_HIDDEN
20 
21 #ifndef CONSOLE_UTILS
22 #define CONSOLE_UTILS
23 
24 #include <iostream>
25 #include <string>
26 #include <cstdlib>
27 #include <cstdio>
28 #include <map>
29 
30 #ifdef WIN32
31 #include <windows.h>
32 #include <io.h>
33 #endif
34 
35 #if defined(__unix__) || defined(__APPLE__)
36 
37 #include <termios.h>
38 #include <sys/ioctl.h>
39 #include <unistd.h>
40 
41 static struct termios stored_settings;
42 
43 static void setConsoleSettingsForAnsiRequest(void) {
44  struct termios new_settings;
45  tcgetattr(0, &stored_settings);
46  new_settings = stored_settings;
47  new_settings.c_lflag &= ~ICANON;
48  new_settings.c_lflag &= ~ECHO;
49  tcsetattr(0, TCSANOW, &new_settings);
50 }
51 
52 static void resetConsoleSettings(void) {
53  tcsetattr(0, TCSANOW, &stored_settings);
54 }
55 
56 static bool processInForeground(void) {
57  pid_t fg = tcgetpgrp(STDIN_FILENO);
58  return fg == getpgrp();
59 }
60 
61 static std::pair<int, int> getConsoleCursorPosition() {
62  int row = 0, col = 0;
63 
64  if (isatty(fileno(stdin)) && processInForeground()) {
65  setConsoleSettingsForAnsiRequest();
66  fprintf(stdout, "\x1b[6n");
67 
68  if (fscanf(stdin, "\x1b[%d;%dR", &row, &col)) {
69  }
70 
71  resetConsoleSettings();
72  }
73 
74  return std::make_pair(row, col);
75 }
76 
77 static std::pair<int, int> getConsoleSize() {
78  int rows = -1, cols = -1;
79  struct winsize ws;
80 
81  if (ioctl(0, TIOCGWINSZ, &ws) == 0) {
82  rows = ws.ws_row;
83  cols = ws.ws_col;
84  }
85 
86  return std::make_pair(rows, cols);
87 }
88 
89 #elif defined(WIN32)
90 
91 inline std::pair<int, int> getConsoleCursorPosition() {
92  int row = 0, col = 0;
93  CONSOLE_SCREEN_BUFFER_INFO SBInfo;
94 
95  if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &SBInfo)) {
96  row = SBInfo.dwCursorPosition.Y;
97  col = SBInfo.dwCursorPosition.X;
98  }
99 
100  return std::make_pair(row, col);
101 }
102 
103 inline std::pair<int, int> getConsoleSize() {
104  int rows = 200, cols = 200;
105  CONSOLE_SCREEN_BUFFER_INFO SBInfo;
106 
107  if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &SBInfo)) {
108  rows = SBInfo.dwSize.Y;
109  cols = SBInfo.dwSize.X - 1;
110  }
111 
112  return std::make_pair(rows, cols);
113 }
114 
115 #endif
116 
117 enum TextEffect { NORMAL = 1, BOLD = 2, UNDERLINED = 4, BLINK = 8 };
118 
119 enum TextColor {
120  BLACK,
121  RED,
122  GREEN,
123  YELLOW,
124  BLUE,
125  MAGENTA,
126  CYAN,
127  LIGHT_GRAY,
128  DARK_GRAY,
129  LIGHT_RED,
130  LIGHT_GREEN,
131  LIGHT_YELLOW,
132  LIGHT_BLUE,
133  LIGHT_MAGENTA,
134  LIGHT_CYAN,
135  WHITE
136 };
137 
138 class TextFgColorSetup {
139 
140 public:
141  TextFgColorSetup(TextColor color) : color(color) {}
142 
143  TextColor color;
144 };
145 
146 class TextBgColorSetup {
147 
148 public:
149  TextBgColorSetup(TextColor color) : color(color) {}
150 
151  TextColor color;
152 };
153 
154 class TextEffectSetup {
155 
156 public:
157  TextEffectSetup(int effect) : effect(effect) {}
158 
159  int effect;
160 };
161 
162 static std::map<TextColor, std::string> initAnsiFgColors() {
163  const char *colorterm = getenv("COLORTERM");
164  bool rxvt = colorterm && std::string(colorterm).find("rxvt") != std::string::npos;
165  std::map<TextColor, std::string> ret;
166  ret[BLACK] = "30";
167  ret[RED] = "31";
168  ret[GREEN] = "32";
169  ret[YELLOW] = "33";
170  ret[BLUE] = "34";
171  ret[MAGENTA] = "35";
172  ret[CYAN] = "36";
173  ret[LIGHT_GRAY] = "37";
174  ret[DARK_GRAY] = rxvt ? ret[BLACK] : "90";
175  ret[LIGHT_RED] = rxvt ? ret[RED] : "91";
176  ret[LIGHT_GREEN] = rxvt ? ret[GREEN] : "92";
177  ret[LIGHT_YELLOW] = rxvt ? ret[YELLOW] : "93";
178  ret[LIGHT_BLUE] = rxvt ? ret[BLUE] : "94";
179  ret[LIGHT_MAGENTA] = rxvt ? ret[MAGENTA] : "95";
180  ret[LIGHT_CYAN] = rxvt ? ret[CYAN] : "96";
181  ret[WHITE] = rxvt ? ret[LIGHT_GRAY] : "97";
182  return ret;
183 }
184 
185 static std::map<TextColor, std::string> initAnsiBgColors() {
186  const char *colorterm = getenv("COLORTERM");
187  bool rxvt = colorterm && std::string(colorterm).find("rxvt") != std::string::npos;
188  std::map<TextColor, std::string> ret;
189  ret[BLACK] = "40";
190  ret[RED] = "41";
191  ret[GREEN] = "42";
192  ret[YELLOW] = "43";
193  ret[BLUE] = "44";
194  ret[MAGENTA] = "45";
195  ret[CYAN] = "46";
196  ret[LIGHT_GRAY] = "47";
197  ret[DARK_GRAY] = rxvt ? ret[BLACK] : "100";
198  ret[LIGHT_RED] = rxvt ? ret[RED] : "101";
199  ret[LIGHT_GREEN] = rxvt ? ret[GREEN] : "102";
200  ret[LIGHT_YELLOW] = rxvt ? ret[YELLOW] : "103";
201  ret[LIGHT_BLUE] = rxvt ? ret[BLUE] : "104";
202  ret[LIGHT_MAGENTA] = rxvt ? ret[MAGENTA] : "105";
203  ret[LIGHT_CYAN] = rxvt ? ret[CYAN] : "106";
204  ret[WHITE] = rxvt ? ret[LIGHT_GRAY] : "107";
205  return ret;
206 }
207 
208 static std::map<TextColor, std::string> ansiFgColors = initAnsiFgColors();
209 static std::map<TextColor, std::string> ansiBgColors = initAnsiBgColors();
210 
211 #ifdef WIN32
212 static std::map<TextColor, int> initCrtFgColors() {
213  std::map<TextColor, int> ret;
214  ret[BLACK] = 0;
215  ret[RED] = FOREGROUND_RED;
216  ret[GREEN] = FOREGROUND_GREEN;
217  ret[YELLOW] = FOREGROUND_RED | FOREGROUND_GREEN;
218  ret[BLUE] = FOREGROUND_BLUE;
219  ret[MAGENTA] = FOREGROUND_BLUE | FOREGROUND_RED;
220  ret[CYAN] = FOREGROUND_GREEN | FOREGROUND_BLUE;
221  ret[LIGHT_GRAY] = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
222  ret[DARK_GRAY] = FOREGROUND_INTENSITY;
223  ret[LIGHT_RED] = FOREGROUND_RED | FOREGROUND_INTENSITY;
224  ret[LIGHT_GREEN] = FOREGROUND_GREEN | FOREGROUND_INTENSITY;
225  ret[LIGHT_YELLOW] = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
226  ret[LIGHT_BLUE] = FOREGROUND_BLUE | FOREGROUND_INTENSITY;
227  ret[LIGHT_MAGENTA] = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY;
228  ret[LIGHT_CYAN] = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
229  ret[WHITE] = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
230  return ret;
231 }
232 
233 static std::map<TextColor, int> initCrtBgColors() {
234  std::map<TextColor, int> ret;
235  ret[BLACK] = 0;
236  ret[RED] = BACKGROUND_RED;
237  ret[GREEN] = BACKGROUND_GREEN;
238  ret[YELLOW] = BACKGROUND_RED | BACKGROUND_GREEN;
239  ret[BLUE] = BACKGROUND_BLUE;
240  ret[MAGENTA] = BACKGROUND_BLUE | BACKGROUND_RED;
241  ret[CYAN] = BACKGROUND_GREEN | BACKGROUND_BLUE;
242  ret[LIGHT_GRAY] = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE;
243  ret[DARK_GRAY] = BACKGROUND_INTENSITY;
244  ret[LIGHT_RED] = BACKGROUND_RED | BACKGROUND_INTENSITY;
245  ret[LIGHT_GREEN] = BACKGROUND_GREEN | BACKGROUND_INTENSITY;
246  ret[LIGHT_YELLOW] = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_INTENSITY;
247  ret[LIGHT_BLUE] = BACKGROUND_BLUE | BACKGROUND_INTENSITY;
248  ret[LIGHT_MAGENTA] = BACKGROUND_BLUE | BACKGROUND_RED | BACKGROUND_INTENSITY;
249  ret[LIGHT_CYAN] = BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY;
250  ret[WHITE] = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY;
251  return ret;
252 }
253 
254 static WORD getCurrentBgColor() {
255  HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
256  CONSOLE_SCREEN_BUFFER_INFO info;
257  GetConsoleScreenBufferInfo(hStdout, &info);
258  return info.wAttributes &
259  (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY);
260 }
261 
262 static WORD getCurrentFgColor() {
263  HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
264  CONSOLE_SCREEN_BUFFER_INFO info;
265  GetConsoleScreenBufferInfo(hStdout, &info);
266  return info.wAttributes &
267  (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
268 }
269 static std::map<TextColor, int> crtFgColors = initCrtFgColors();
270 static std::map<TextColor, int> crtBgColors = initCrtBgColors();
271 #endif
272 
273 static void escapeAnsiCode(std::ostream &os, const std::string &ansiCode,
274  const std::string &endEscape = "m") {
275  static const char *stdOutNoAnsiEscapes = getenv("STDOUT_NO_ANSI_ESCAPES");
276  static const char *stdErrNoAnsiEscapes = getenv("STDERR_NO_ANSI_ESCAPES");
277 #ifndef WIN32
278 
279  if ((&os == &std::cout && !stdOutNoAnsiEscapes && isatty(fileno(stdout))) ||
280  (&os == &std::cerr && !stdErrNoAnsiEscapes && isatty(fileno(stderr))))
281 #else
282  if ((&os == &std::cout && !stdOutNoAnsiEscapes) || (&os == &std::cerr && !stdErrNoAnsiEscapes))
283 #endif
284  os << "\x1b[" << ansiCode << endEscape;
285 }
286 
287 /*
288  This set of stream manipulation operators allow to produce
289  a colored console ouput. Except for windows console application (based on cmd.exe),
290  the colors are activated through ANSI escape sequences. The writing of these sequences
291  can be disabled by setting the STDOUT_N0_ANSI_ESCAPES and STDERR_N0_ANSI_ESCAPES
292  environment variables (for instance, when working with a terminal who does not understand
293  these sequences).
294 
295  Below is an example on how to use it :
296 
297  // Output a bold text colored in red on a white background
298  std::cout << setTextEffect(BOLD) << setTextColor(RED) << setTextBackgroundColor(WHITE) << "Hello
299  World!" << std::endl;
300 
301  // Reset the text colors to the default ones
302  std::cout << defaultTextColor;
303 
304  // You can also use some predefined color schemes (only affects text color) : black, white, red,
305  green,
306  // blue, yellow, white, cyan, magenta, darkGray, lightGray, lightRed, lightGreen, ...
307  std::cout << red << "Hello " << blue << World !!" << defaulTextColor << std::endl;
308 
309  */
310 
311 inline std::ostream &defaultTextColor(std::ostream &s) {
312  if (&s == &std::cout || &s == &std::cerr) {
313 #ifndef WIN32
314  escapeAnsiCode(s, "0");
315  escapeAnsiCode(s, "39");
316  escapeAnsiCode(s, "49");
317 #else
318  // on windows, if the TERM environment variable is not defined
319  // it means that the shell used is cmd.exe, whose does not understand ANSI escape sequences
320  static const char *term = getenv("TERM");
321 
322  if (term && std::string(term) != "cygwin") {
323  escapeAnsiCode(s, "0");
324  escapeAnsiCode(s, "39");
325  escapeAnsiCode(s, "49");
326  } else {
327  HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
328  SetConsoleTextAttribute(hStdout, crtBgColors[BLACK] | crtFgColors[WHITE]);
329  }
330 
331 #endif
332  }
333 
334  return s;
335 }
336 
337 inline std::ostream &operator<<(std::ostream &s, const TextFgColorSetup &tgfcs) {
338  if (&s == &std::cout || &s == &std::cerr) {
339 #ifndef WIN32
340  escapeAnsiCode(s, ansiFgColors[tgfcs.color]);
341 #else
342  // on windows, if the TERM environment variable is not defined
343  // it means that the shell used is cmd.exe, whose does not understand ANSI escape sequences
344  static const char *term = getenv("TERM");
345 
346  if (term && std::string(term) != "cygwin") {
347  escapeAnsiCode(s, ansiFgColors[tgfcs.color]);
348  } else {
349  HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
350  SetConsoleTextAttribute(hStdout, crtFgColors[tgfcs.color] | getCurrentBgColor());
351  }
352 
353 #endif
354  }
355 
356  return s;
357 }
358 
359 inline std::ostream &operator<<(std::ostream &s, const TextBgColorSetup &tbgcs) {
360  if (&s == &std::cout || &s == &std::cerr) {
361 #ifndef WIN32
362  escapeAnsiCode(s, ansiBgColors[tbgcs.color]);
363 #else
364  // on windows, if the TERM environment variable is not defined
365  // it means that the shell used is cmd.exe, whose does not understand ANSI escape sequences
366  static const char *term = getenv("TERM");
367 
368  if (term && std::string(term) != "cygwin") {
369  escapeAnsiCode(s, ansiBgColors[tbgcs.color]);
370  } else {
371  HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
372  SetConsoleTextAttribute(hStdout, getCurrentFgColor() | crtBgColors[tbgcs.color]);
373  }
374 
375 #endif
376  }
377 
378  return s;
379 }
380 
381 inline void setEffects(std::ostream &s, const int &effect) {
382  if (effect & NORMAL)
383  escapeAnsiCode(s, "0");
384 
385  if (effect & BOLD)
386  escapeAnsiCode(s, "1");
387 
388  if (effect & UNDERLINED)
389  escapeAnsiCode(s, "4");
390 
391  if (effect & BLINK)
392  escapeAnsiCode(s, "5");
393 }
394 
395 inline std::ostream &operator<<(std::ostream &s, const TextEffectSetup &tes) {
396  if (&s == &std::cout || &s == &std::cerr) {
397 #ifndef WIN32
398  setEffects(s, tes.effect);
399 #else
400  static const char *term = getenv("TERM");
401 
402  if (term && std::string(term) != "cygwin") {
403  setEffects(s, tes.effect);
404  }
405 
406 #endif
407  }
408 
409  return s;
410 }
411 
412 inline TextBgColorSetup setTextBackgroundColor(TextColor color) {
413  return TextBgColorSetup(color);
414 }
415 
416 inline TextFgColorSetup setTextColor(TextColor color) {
417  return TextFgColorSetup(color);
418 }
419 
420 inline TextEffectSetup setTextEffect(int effect) {
421  return TextEffectSetup(effect);
422 }
423 
424 inline std::ostream &bold(std::ostream &s) {
425  return s << setTextEffect(BOLD);
426 }
427 
428 inline std::ostream &underlined(std::ostream &s) {
429  return s << setTextEffect(UNDERLINED);
430 }
431 
432 inline std::ostream &red(std::ostream &s) {
433  return s << setTextColor(RED);
434 }
435 
436 inline std::ostream &green(std::ostream &s) {
437  return s << setTextColor(GREEN);
438 }
439 
440 inline std::ostream &blue(std::ostream &s) {
441  return s << setTextColor(BLUE);
442 }
443 
444 inline std::ostream &yellow(std::ostream &s) {
445  return s << setTextColor(YELLOW);
446 }
447 
448 inline std::ostream &white(std::ostream &s) {
449  return s << setTextColor(WHITE);
450 }
451 
452 inline std::ostream &black(std::ostream &s) {
453  return s << setTextColor(BLACK);
454 }
455 
456 inline std::ostream &magenta(std::ostream &s) {
457  return s << setTextColor(MAGENTA);
458 }
459 
460 inline std::ostream &cyan(std::ostream &s) {
461  return s << setTextColor(CYAN);
462 }
463 
464 inline std::ostream &lightRed(std::ostream &s) {
465  return s << setTextColor(LIGHT_RED);
466 }
467 
468 inline std::ostream &lightGreen(std::ostream &s) {
469  return s << setTextColor(LIGHT_GREEN);
470 }
471 
472 inline std::ostream &lightBlue(std::ostream &s) {
473  return s << setTextColor(LIGHT_BLUE);
474 }
475 
476 inline std::ostream &lightYellow(std::ostream &s) {
477  return s << setTextColor(LIGHT_YELLOW);
478 }
479 
480 inline std::ostream &lightGray(std::ostream &s) {
481  return s << setTextColor(LIGHT_GRAY);
482 }
483 
484 inline std::ostream &darkGray(std::ostream &s) {
485  return s << setTextColor(DARK_GRAY);
486 }
487 
488 inline std::ostream &lightMagenta(std::ostream &s) {
489  return s << setTextColor(LIGHT_MAGENTA);
490 }
491 
492 inline std::ostream &lightCyan(std::ostream &s) {
493  return s << setTextColor(LIGHT_CYAN);
494 }
495 
496 // Fill the current line of the terminal with space characters from the
497 // current cursor position to the end of the line.
498 // The purpose is to have a constant background color on the line.
499 inline std::ostream &fillToEndOfLine(std::ostream &s) {
500 #ifndef WIN32
501 
502  if (processInForeground() && ((&s == &std::cout && isatty(fileno(stdout))) ||
503  (&s == &std::cerr && isatty(fileno(stderr))))) {
504 #endif
505  std::pair<int, int> cursorPos = getConsoleCursorPosition();
506  std::pair<int, int> consoleSize = getConsoleSize();
507 
508  if ((cursorPos.second + consoleSize.second) != 0) {
509  for (int i = cursorPos.second; i <= consoleSize.second; ++i) {
510  s << " ";
511  }
512  } else {
513  s << std::endl;
514  }
515 
516 #ifndef WIN32
517  }
518 
519 #endif
520 
521  if ((&s == &std::cout && !isatty(fileno(stdout))) ||
522  (&s == &std::cerr && !isatty(fileno(stderr)))) {
523  s << std::endl;
524  }
525 
526 #ifndef WIN32
527 
528  if (!processInForeground()) {
529  s << defaultTextColor << std::endl;
530  }
531 
532 #endif
533 
534  return s;
535 }
536 
537 #endif
538 ///@endcond
std::ostream & operator<<(std::ostream &os, const Array< T, N > &array)
operator << stream operator to easily print an array, or save it to a file.