This is part 2 of a 3 part series in printing in color in C/C++
(Continued from Part 1)
In order to be able to specify a “color set”, and avoid having to define parameters I didn’t want, my next iteration was to move to a structure-based approach:
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>
#define CLR_BLACK 0
#define CLR_RED 1
#define CLR_GREEN 2
#define CLR_YELLOW 3
#define CLR_BLUE 4
#define CLR_MAGENTA 5
#define CLR_CYAN 6
#define CLR_WHITE 7
#define ATTR_NONE 0
#define ATTR_BOLD 1
#define ATTR_DIM 2
#define ATTR_UNDERLINE 4
#define ATTR_BLINK 5
#define ATTR_REVERSE 7
typedef struct{
int fg;
int bg;
int attr;
} cset_t;
cset_t * cset_init(cset_t * cs)
{
cs->fg = -1;
cs->bg = -1;
cs->attr = -1;
return cs;
}
cset_t * cset_setfg(cset_t * cs, int fg)
{
cs->fg = fg;
return cs;
}
cset_t * cset_setbg(cset_t * cs, int bg)
{
cs->bg = bg;
return cs;
}
cset_t * cset_setattr(cset_t * cs, int attr){
cs->attr = attr;
return cs;
}
void cprint_init(cset_t * cs)
{
if(cs->bg != -1){
printf("%c[%d;%d;%dm",27,cs->attr,(30+cs->fg),(40+cs->bg));
}
else{
printf("%c[%d;%dm",27,cs->attr,(30+cs->fg));
}
}
void cprint_rst(void)
{
printf("%c[%dm", 27, 0);
}
int cprintf(cset_t * cs, char * fmt, ...)
{
va_list args;
va_start(args, fmt);
cprint_init(cs);
vprintf(fmt, args);
cprint_rst();
va_end(args);
}
cprintf_test.c
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// (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"
void main(void)
{
// Example Showing Individual Configuration
cset_t alert;
cset_init(&alert);
cset_setfg(&alert, CLR_RED);
cset_setattr(&alert, ATTR_BOLD);
// Example Showing Cascaded Configuration
cset_t warn;
cset_setattr(cset_setfg(cset_init(&warn), CLR_YELLOW), ATTR_UNDERLINE);
printf("Unformatted...\n");
cprintf(&alert, "THIS IS AN ALERT!\n");
cprintf(&warn, "THIS IS A WARNING.\n");
printf("\n");
cset_t loop;
cset_init(&loop);
int i,j;
for(i=0; i<8; i++)
{
for(j=0; j<8; j++)
{
if(j == 3 | j == 6){ continue; }
cset_setfg(&loop, i);
cset_setattr(&loop, j);
cprintf(&loop, "FG=%d,A=%d", i, j);
printf(" ");
}
printf("\n");
}
printf("\n");
cprintf(&warn, "Much later, I can simply use &warn without having to lookup the style I last used.\n");
return;
}
Which turned out like this (in PuTTY):

I liked this solution better than my first. Here I was able to define program-wide color schemes (e.g. alert, warn) and simply reference them on future calls to cprintf(). I could have also added a one-time-use “constructor” that would return a static pointer to a structure of type cset_t based off 3 integers for inline coding.
Something like:
cset_t onu;
cset_t * cset(int fg, int bg, int attr)
{
onu.fg = fg;
onu.bg = bg;
onu.attr = attr;
return &onu;
}
So that I could also do something like the following in my main program:
cprintf(cset(CLR_YELLOW, CLR_RED, ATTR_NONE), "Yellow on Red...");
As for my C version, this is where I left it — my next iteration was in C++.
Continue to Part 3.
RSS Feed