/* 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; }