This is part 3 of a 3 part series in printing in color in C/C++
(Continued from Part 2)
cprintf.h
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// (C)2011 Edwards Research Group
// You are licensed to use this work under a CC-BY-SA License.
// See: http://blog.edwards-research.com/about/
// http://creativecommons.org/licenses/by-sa/3.0/us/
//
////////////////////////////////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <stdarg.h>
enum CP_ColorType {BLACK = 0,
RED = 1,
GREEN = 2,
YELLOW = 3,
BLUE = 4,
MAGENTA = 5,
CYAN = 6,
WHITE = 7,
UNDEF = -1};
enum CP_AttrType {NONE = 0,
BOLD = 1,
DIM = 2,
UNDERLINE = 4,
BLINK = 5,
REVERSE = 7};
class ColorSet
{
public:
CP_ColorType _fg;
CP_ColorType _bg;
CP_AttrType _attr;
// Default Constructor
ColorSet(){ set(UNDEF,UNDEF,NONE); }
// 1 param constructor
ColorSet(CP_ColorType fg){ set(fg,UNDEF,NONE); }
// 2 param constructors
ColorSet(CP_ColorType fg, CP_AttrType attr){ set(fg,UNDEF,attr); }
ColorSet(CP_ColorType fg, CP_ColorType bg) { set(fg,bg,NONE); }
// 3 param constructor
ColorSet(CP_ColorType fg, CP_ColorType bg, CP_AttrType attr){ set(fg,bg,attr); }
void set(CP_ColorType fg, CP_ColorType bg, CP_AttrType attr)
{
_fg = fg;
_bg = bg;
_attr = attr;
}
// Cool Wrapper
void cprintf(const char * fmt, ...)
{
va_list args;
va_start(args, fmt);
cp_init();
vprintf(fmt, args);
cp_rst();
va_end(args);
}
private:
void cp_init(void)
{
if(_bg != -1){
printf("%c[%d;%d;%dm",27,_attr,(30+_fg),(40+_bg));
}
else{
printf("%c[%d;%dm",27,_attr,(30+_fg));
}
}
void cp_rst(void)
{
printf("%c[%dm", 27, 0);
}
};
cprintf_test.cpp
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// (C)2011 Edwards Research Group
// You are licensed to use this work under a CC-BY-SA License.
// See: http://blog.edwards-research.com/about/
// http://creativecommons.org/licenses/by-sa/3.0/us/
//
////////////////////////////////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include "cprintf.h"
int main(void)
{
ColorSet alert(RED, BOLD);
ColorSet warn(YELLOW, UNDERLINE);
printf("\n");
printf("Unformatted...\n");
alert.cprintf("THIS IS AN ALERT!\n");
warn.cprintf("THIS IS A WARNING.\n");
printf("\n");
int i,j;
for(i=0; i<8; i++)
{
for(j=0; j<8; j++)
{
if(j == 3 | j == 6){ continue; }
ColorSet((CP_ColorType)i, (CP_AttrType)j).cprintf("FG=%d,A=%d", i, j);
printf(" ");
}
printf("\n");
}
printf("\n");
warn.cprintf("Much later, I can simply use warn without having to lookup the style I last used.\n");
// Example Showing real-time definition and overloaded constructors
ColorSet(YELLOW, RED).cprintf("Yellow on Red...");
printf("\n");
ColorSet(BLUE, REVERSE).cprintf("Reversed Blue...");
printf("\n");
return 0;
}
Which looks like this in gnome-terminal:

Leveraging some of the benefits of c++, I was able to streamline some of the ColorSet construction that took up an annoying amount of lines with the struct style.
I also changed the #defines to an enum to make the compile-time checking more intelligent.
Lastly, the overloaded constructors allow me to use a 2-parameter constructor for both (FOREGROUND, BACKGROUND) and (FOREGROUND, ATTRIBUTE) style.
Now, if I were to make this production code, I’d hide my member variables, expose getter and setter interfaces (if necessary), re-prefix the enum’s to avoid conflicts, and separate out the implementation into a .cpp file — but this was really just a proof-of-concept thing.
RSS Feed