1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
/* colorout.hpp
 * (c) 2012 Daniel S. Roche, USNA
 *
 * The class colorout below provides the functionality of
 * cout or cerr (depending on the first constructor argument being
 * 1 or 2, respectively). The only difference is that the output
 * is printed in the color corresponding to the second argument.
 * You use it by first calling the constructor to make a new object:
colorout out(1, 'r'); // r is for red
 * and then you can use that just like cout:
out << "This is " << "all red!\n";
 * Note that cout still prints in the default color.
 */
 
#include <unistd.h> // for isatty
#include <cstdlib>  // for exit
#include <iostream>
 
class colorbuf : public std::streambuf {
 private:
  int filedes;
  std::streambuf *dest;
  bool tty;
  char magic[7];
 public:
  colorbuf (int fd, char color) {
    filedes = fd;
    if (filedes == 1) dest = std::cout.rdbuf();
    else if (filedes == 2) dest = std::cerr.rdbuf();
    else {
      std::cerr << "Illegal file descriptor in colorbuf constructor" << std::endl;
      exit(11);
    }
    tty = isatty(filedes);
 
    int colorcode;
    switch(color) {
      case 'b': colorcode = 30; break; // black
      case 'r': colorcode = 31; break; // red
      case 'g': colorcode = 32; break; // green
      case 'y': colorcode = 33; break; // yellow
      case 'u': colorcode = 34; break; // blue
      case 'w': colorcode = 37; break; // white
      default:
        std::cerr << "Illegal color for colorbuf" << std::endl;
        exit(12);
    }
 
    magic[0] = '\033';
    magic[1] = '[';
    magic[2] = colorcode / 10 + '0';
    magic[3] = colorcode % 10 + '0';
    magic[4] = ';';
    magic[5] = '1';
    magic[6] = 'm';
  }
 
 protected:
  virtual int overflow(int ch) {
    if (tty) dest->sputn(magic, 7);
    dest->sputc(ch);
    if (tty) dest->sputn("\033[0m", 4);
  }
};
 
class colorout : public std::ostream {
 private:
  colorbuf buf;
 public:
  colorout(int fd, int cc)
    :buf(fd,cc), std::ostream(&buf)
    { }
};