calisto-20000323/
calisto-20000323/lib/
calisto-20000323/lib/etc/
calisto-20000323/lib/players/
calisto-20000323/lib/text/
calisto-20000323/log/
/*
 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;
}