Colored Output in C/C++ (Part 2)

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.

Posted Sunday, April 24th, 2011 under c, programming, tips and tricks.

Leave a Reply