colorprint - An ANSI Escape sequence console writer mini-library I wrote this a long time ago. I came back to it and decided to clean it up a little.

It uses the preprocessor and C99 anon structs to make a flexible python-like API for calling its functions. 

colorprint.c

#include &lt;stdio.h&gt;
#include &lt;string.h&gt;

#include "colorprint.h"

static const char *numch = "0123456789";

static void
apply_effect(char *out, enum fx fx)
{/*{{{*/
    char buf[3] = { numch[fx - 1], ';' };

    strcat(out, buf);
}/*}}}*/

static void
apply_fg(char *out, enum color c)
{/*{{{*/
    char buf[4] = { '3', numch[c - 1], 'm' };

    strcat(out, buf);
}/*}}}*/

static void
apply_bg(char *out, enum color c)
{/*{{{*/
    char buf[4] = { '4', numch[c - 1], ';' };

    strcat(out, buf);
}/*}}}*/

static void
apply_fx(char *out, enum fx *fx)
{/*{{{*/
    for(int i = 0; fx[i]; i++)
        apply_effect(out, fx[i]);
}/*}}}*/

static void
apply_colors(char *out, struct cpoptions *cpo)
{/*{{{*/
    if(cpo-&gt;bg)
        apply_bg(out, cpo-&gt;bg);

    if(cpo-&gt;fg)
        apply_fg(out, cpo-&gt;fg);
}/*}}}*/

void
_cprint(struct cpoptions *cpo)
{/*{{{*/
    char options[30] = "";

    apply_fx(options, cpo-&gt;fx);
    apply_colors(options, cpo);

    if(!cpo-&gt;fg &amp;&amp; !cpo-&gt;bg &amp;&amp; !cpo-&gt;fx[0])
         fputs(cpo-&gt;string, stdout);
    else
        printf("\e[%s%s\e[0m", options, cpo-&gt;string);
}/*}}}*/

void
_cputs(struct cpoptions *cpo)
{/*{{{*/
    _cprint(cpo);
    putchar('\n');
}/*}}}*/


colorprint.h

#define func(name, type, ...) \
    name(&amp;(type){.header = 0, __VA_ARGS__})

enum color {
    color_invalid,
    color_black,
    color_red, 
    color_green,
    color_yellow,
    color_blue,
    color_purple,
    color_aqua, 
    color_white
};

enum fx {
    fx_invalid,
    fx_plain,
    fx_bold,
    fx_dark,
    fx_italic,
    fx_underline,
    fx_light,
    fx_light2,
    fx_reverse,
    fx_blink,
    fx_strike
};

struct cpoptions {
    char header;
    char *string;
    enum fx fx[10];
    enum color fg;
    enum color bg;
};

void _cprint(struct cpoptions *cpo);
void _cputs(struct cpoptions *cpo);

#define cprint(...) func(_cprint, struct cpoptions, __VA_ARGS__)
#define cputs(...) func(_cputs, struct cpoptions, __VA_ARGS__)

/* Example: 
 *      cprint("Hello World", .fg = color_green, .fx = {fx_bold, fx_italic, fx_strike});
 * Or: 
 *      struct cpoptions cpo = {
 *          .string = "Hello World",
 *          .fg = color_green,
 *          .fx = {
 *              fx_bold,
 *              fx_italic,
 *              fx_strike
 *          }
 *      };
 *      _cprint(&amp;cpo);
 */


Its usage ranges in complexity from 

cputs("Hello World"); // prints "Hello World\n"


to

cputs( .string = "Hello World",
       .fg = color_green,
       .bg = color_red,
       .fx = {
           fx_bold,
           fx_strike,
           fx_italic
        }
); // prints "\e[1;9;3;41;32mHello World\e[0m\n", which appears as "Hello World" with a red background, green foreground, with bold+strikethrough+italic effects


In my opinion, this method of function calling is far more type-safe and versatile than the horrid va_args. It's also nice because it allows colorful output without the overhead of ncurses or termcap.
Architecture: IMO, the time for trusting that char * buffers will not overflow is past.  Pass in a size_t size and check for valid sizes in function calls.
static const char *numch = "0123456789"; serves little value and its application can cause UB on unruly input.  Rather than use it convert to digit character, just add '0', offset as needed.  numch[fx - 1] --> fx - 1 + '0'
Global functions that being with _ are reserve for the implementation. Use a different name.

// void _cprint(struct cpoptions *cpo)
void cp_print(struct cpoptions *cpo)

\e is a non-standard escape sequence.  Use \033 or ...

// printf("\e[%s%s\e[0m"
#define ESC 27
printf("%c[%s%s\e[0m", ESC

colorprint.h should have a protective #ifndef  to cope with re-entrantcy.

#ifndef colorprint_h
#define colorprint_h
   ... // existing content
#endif

I found useful enumerating the Nth item

enum color {
    color_invalid,
    color_white,
    color_N  // add
};

if (value &gt;= color_N) Handle_InvalidValue(value);

Nice to have example usage in .h file.  Suggest #if 0 bracketing instead as it does not stop syntax highlighting.
Pedantic: size_t is the type to use for array indexing rather than int.  Code accordingly, remember that size_t is some unsigned type.
Namespace colorprint.h abuses namespace with color_..., fx_..., cp....  Suggest a more uniform prefix.  cp... is not too bad, but then use cp.h.
Avoid magic number - why 30?  Numbers other than -1,0,1,2 and maybe 42 deserve a macro or const object.

char options[30] = "";

Do not include files before "colorprint.h". "colorprint.c" should do this to insure "colorprint.h" is not dependant on some &lt;*.h&gt; file
tidy up, remove /*{{{*/, etc.
Good use of static functions.
Print-like functions should return int.

/// void _cprint(
int  _cprint(
  ...
  int i = printf("\e[%s%s\e[0m", options, cpo-&gt;string);
  return i;
}

func is much too common to use as a macro name

// #define func(name, type, ...) \
#define cp_func(name, type, ...) \