/*
Calisto (c) 1998-1999 Peter Howkins, Matthew Howkins, Simon Howkins
$Id: colours.c,v 1.5 2000/03/07 21:02:58 peter Exp $
$Log: colours.c,v $
Revision 1.5 2000/03/07 21:02:58 peter
fixed minor bug
Revision 1.4 2000/03/07 20:47:48 peter
Felt like a total rewrite.
Modified to handle buffer safety properly, added new functions
cvsnprintf() and csnprintf()
Revision 1.3 1999/12/11 23:08:53 peter
minor code tidying, including const's, static's and removing one function
Revision 1.2 1999/12/06 21:19:13 peter
Moved #define's and typedef into .c file
Revision 1.1 1999/11/23 22:23:40 peter
Initial revision
*/
static char rcsid[] = "$Id: colours.c,v 1.5 2000/03/07 21:02:58 peter Exp $";
/* Emacs mode style select: -*- C++ -*- */
/**************************************************************************\
* Filename: colours.c *
* Description: ANSI Colour handling module. *
* Author: Mo McKinlay [Cirrus]. *
* Date: [0.0.1] 4-Dec-1997 - Original. *
* [0.0.2] 5-Dec-1997 - Changes: *
* - Added colours.h header file. *
* - Added c..printf() functions. *
**************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include "colours.h"
#include "msnprintf.h"
#include "strplus.h"
#include "structs.h"
#define DEF_FG -1
#define DEF_BG -1
#define cfBold 0x01
#define cfItalics 0x02
#define cfFlash 0x04
#define cfUnderline 0x08
#define cfReverse 0x10
#define MAX_BUF_LEN 10240
typedef struct {
unsigned char flags;
int fgColour;
int bgColour;
} ColRec;
static void writeColRec(char *dest, size_t size, const ColRec *colRec)
{
int fg, bg;
char temp[16];
STRNCOPY(dest, "\033[0m", size);
if (colRec->flags & cfFlash) STRNAPPEND(dest, "\033[5m", size);
if (colRec->flags & cfBold) STRNAPPEND(dest, "\033[1m", size);
/* Unimplemented: cfUnderline & cfItalics */
if (colRec->flags & cfUnderline) STRNAPPEND(dest, "\033[4m", size);
if (colRec->flags & cfItalics) STRNAPPEND(dest, "\033[4m", size);
if (colRec->flags & cfReverse) {
fg = colRec->bgColour;
bg = colRec->fgColour;
} else {
fg = colRec->fgColour;
bg = colRec->bgColour;
}
if (fg != -1) {
fg &= 15;
if (fg > 7) {
msnprintf(temp, sizeof(temp), "\033[1m\033[%dm", 22 + fg);
} else {
msnprintf(temp, sizeof(temp), "\033[%dm", 30 + fg);
}
STRNAPPEND(dest, temp, size);
}
if (bg != -1) {
bg &= 7;
msnprintf(temp, sizeof(temp), "\033[%dm", 40 + bg);
STRNAPPEND(dest, temp, size);
}
}
static void setColour(char *dest, size_t size, ColRec *colRec, char colour)
{
char tempBuf[MAX_BUF_LEN];
if (!(colRec->flags & cfReverse)) {
colRec->fgColour = colour;
} else {
colRec->bgColour = colour;
}
writeColRec(tempBuf, sizeof(tempBuf), colRec);
STRNAPPEND(dest, tempBuf, size);
}
static void setBackground(char *dest, size_t size, ColRec *colRec, char colour)
{
char tempBuf[MAX_BUF_LEN];
if (!(colRec->flags & cfReverse)) {
colRec->bgColour = colour;
} else {
colRec->fgColour = colour;
}
writeColRec(tempBuf, sizeof(tempBuf), colRec);
STRNAPPEND(dest, tempBuf, size);
}
static void addColourCode(char *dest, size_t size, ColRec *colRec, char code)
{
char temp[128];
switch (code) {
case '^':
STRNAPPEND(dest, "^", size);
break;
case 'n':
case 'N':
colRec->flags = 0;
colRec->fgColour = DEF_FG;
colRec->bgColour = DEF_BG;
writeColRec(temp, sizeof(temp), colRec);
STRNAPPEND(dest, temp, size);
break;
case 'H':
colRec->flags |= cfBold;
writeColRec(temp, sizeof(temp), colRec);
STRNAPPEND(dest, temp, size);
break;
case 'h':
colRec->flags &= ~cfBold;
writeColRec(temp, sizeof(temp), colRec);
STRNAPPEND(dest, temp, size);
break;
case 'U':
colRec->flags |= cfUnderline;
writeColRec(temp, sizeof(temp), colRec);
STRNAPPEND(dest, temp, size);
break;
case 'u':
colRec->flags &= ~cfUnderline;
writeColRec(temp, sizeof(temp), colRec);
STRNAPPEND(dest, temp, size);
break;
case 'L':
colRec->flags |= cfItalics;
writeColRec(temp, sizeof(temp), colRec);
STRNAPPEND(dest, temp, size);
break;
case 'l':
colRec->flags &= ~cfItalics;
writeColRec(temp, sizeof(temp), colRec);
STRNAPPEND(dest, temp, size);
break;
case 'K':
colRec->flags |= cfFlash;
writeColRec(temp, sizeof(temp), colRec);
STRNAPPEND(dest, temp, size);
break;
case 'k':
colRec->flags &= ~cfFlash;
writeColRec(temp, sizeof(temp), colRec);
STRNAPPEND(dest, temp, size);
break;
case 'I':
colRec->flags |= cfReverse;
writeColRec(temp, sizeof(temp), colRec);
STRNAPPEND(dest, temp, size);
break;
case 'i':
colRec->flags &= ~cfReverse;
writeColRec(temp, sizeof(temp), colRec);
STRNAPPEND(dest, temp, size);
break;
case 'd':
setColour(dest, size, colRec, 0);
break;
case 'D':
setColour(dest, size, colRec, 8);
break;
case 's':
case 'S':
setBackground(dest, size, colRec, 0);
break;
case 'r':
setColour(dest, size, colRec, 1);
break;
case 'R':
setColour(dest, size, colRec, 9);
break;
case 'e':
case 'E':
setBackground(dest, size, colRec, 1);
break;
case 'g':
setColour(dest, size, colRec, 2);
break;
case 'G':
setColour(dest, size, colRec, 10);
break;
case 'f':
case 'F':
setBackground(dest, size, colRec, 2);
break;
case 'y':
setColour(dest, size, colRec, 3);
break;
case 'Y':
setColour(dest, size, colRec, 11);
break;
case 't':
case 'T':
setBackground(dest, size, colRec, 3);
break;
case 'b':
setColour(dest, size, colRec, 4);
break;
case 'B':
setColour(dest, size, colRec, 12);
break;
case 'v':
case 'V':
setBackground(dest, size, colRec, 4);
break;
case 'p':
setColour(dest, size, colRec, 5);
break;
case 'P':
setColour(dest, size, colRec, 13);
break;
case 'o':
case 'O':
setBackground(dest, size, colRec, 5);
break;
case 'c':
setColour(dest, size, colRec, 6);
break;
case 'C':
setColour(dest, size, colRec, 14);
break;
case 'x':
case 'X':
setBackground(dest, size, colRec, 6);
break;
case 'w':
setColour(dest, size, colRec, 7);
break;
case 'W':
setColour(dest, size, colRec, 15);
break;
case 'q':
case 'Q':
setBackground(dest, size, colRec, 7);
break;
}
}
static void codesToAnsi(char *dest, size_t size, const char *src)
{
char temp[128] = "";
ColRec colRec;
*dest = '\0';
if (!src)
return;
colRec.flags = 0;
colRec.fgColour = DEF_FG;
colRec.bgColour = DEF_BG;
while(*src) {
switch(*src) {
case '^':
src++;
if (*src)
addColourCode(dest, size, &colRec, *src);
break;
case '\n':
colRec.flags = 0;
colRec.fgColour = DEF_FG;
colRec.bgColour = DEF_BG;
writeColRec(temp, sizeof(temp), &colRec);
STRNAPPEND(dest, temp, size);
default:
temp[0] = *src;
temp[1] = '\0';
STRNAPPEND(dest, temp, size);
}
src++;
}
}
int cvsprintf(char *buf, const char *fmt, va_list ap)
{
char temp[MAX_BUF_LEN];
int result = vsprintf(temp, fmt, ap);
codesToAnsi(buf, sizeof(temp), temp);
return result;
}
int csprintf(char *buf, const char *fmt, ...)
{
va_list ap;
int result;
va_start(ap, fmt);
result = cvsprintf(buf, fmt, ap);
va_end(ap);
return result;
}
int cvprintf(const char *fmt, va_list ap)
{
char temp[MAX_BUF_LEN];
int result = cvsprintf(temp, fmt, ap);
printf("%s", temp);
return result;
}
void stripCodes(char *dest, const char *src)
{
int cmode = 0;
if(!src) return;
if(!dest) return;
while (*src) {
if (*src== '^') {
if (cmode) {
*dest++ = '^';
cmode = 0;
} else {
cmode = 1;
};
} else {
if (!cmode) {
*dest++ = *src;
} else {
cmode = 0;
}
}
src++;
}
*dest = '\0';
}
int cprintf(const char *fmt, ...)
{
int result;
va_list ap;
va_start(ap, fmt);
result = cvprintf(fmt, ap);
va_end(ap);
return result;
}
int cvsnprintf(char *buf, size_t size, const char *fmt, va_list ap)
{
char temp[OUTPUT_BUFFER]; /* arbitrary maximum size, but won't overrun */
int result;
result = mvsnprintf(temp, sizeof(temp), fmt, ap);
codesToAnsi(buf, size, temp);
return result;
}
int csnprintf(char *buf, size_t size, const char *fmt, ...)
{
va_list ap;
int result;
va_start(ap, fmt);
result = cvsnprintf(buf, size, fmt, ap);
va_end(ap);
return result;
}