/*==============================start==================================*/
/*  aprintf():  printf()-like function that provides attribute control;*/
/*  useful for both mono and color monitors in textmode; provides for  */
/*  visibility, underscore, reverse video, blinking, intensity and     */
/*  color control; requires DEVICE=ANSI.SYS in CONFIG.SYS; suitable    */
/*  for use with any Microsoft (MSC) or Borland (BC) C compiler,       */
/*  and for any memory model (T,S,M,C,L,H); software adapted from the  */
/*  book ENCYCLOPEDIA C, by R.Radcliffe (Sybex/1991), Pg 951-952.      */
/*=====================================================================*/
#include <stdarg.h>                 /* va_list, va_start()             */
#include <stdio.h>                  /* printf(), scanf(), vsprintf()   */
#include <string.h>                 /* strcat(), strcpy(), strlen()    */
/*-------------------------custom prototypes---------------------------*/
int aprintf(unsigned char, const char *, ...);

/*---------helpful defined items/ perhaps create a header file---------*/
#define BLINKON         0x80u

#define BACK_BLACK      0x00u
#define BACK_BLUE       0x10u
#define BACK_GREEN      0x20u
#define BACK_CYAN       0x30u
#define BACK_RED        0x40u
#define BACK_MAGENTA    0x50u
#define BACK_YELLOW     0x60u
#define BACK_WHITE      0x70u

#define BOLDON          0x08u

#define FORE_BLACK      0x00u
#define FORE_BLUE       0x01u
#define FORE_GREEN      0x02u
#define FORE_CYAN       0x03u
#define FORE_RED        0x04u
#define FORE_MAGENTA    0x05u
#define FORE_YELLOW     0x06u
#define FORE_WHITE      0x07u

#define INVISIBLE       0x00u
#define UNDERLINE       0x01u
#define NORMAL          0x07u
#define REVERSE         0x70u

#if (0)                             /* begin comments by preprocessor */
/*------------------------attribute byte details----------------------*/
To create the attribute byte, bit-wise OR together a desired effect
from each of the following categories: (1) Blinking Control,
(2) Background Color, (3) Intensity Control and (4) Foreground Color

For Example:
              (1)         (2)        (3)         (4)
attribute = BLINKON  | BACK_BLACK | BOLDON  | FORE_WHITE
attribute =   0x80   |    0x00    |  0x08   |   0x07
attribute ==> 0x8F

---------------------------------------------
Attribute Byte Bit Settings
---------------------------------------------
bit-7   Blink Control           (0=OFF, 1=ON)
bit-6   Background Red-gun      (0=OFF, 1=ON)
bit-5   Background Green-gun    (0=OFF, 1=ON)
bit-4   Background Blue-gun     (0=OFF, 1=ON)

bit-3   Intensity Control       (0=LOW, 1=HI)
bit-2   Foreground Red-gun      (0=OFF, 1=ON)
bit-1   Foreground Green-gun    (0=OFF, 1=ON)
bit-0   Foreground Blue-gun     (0=OFF, 1=ON)

----------------------------------------------------
RGB (Red:Green:Blue)    Bit--Settings    SGR     SGR
Red:Green:Blue  Color   Bits  Decimal   Back    Fore
----------------------------------------------------
OFF:  OFF: OFF  BLACK   [000]   0       "40"   "30"
OFF:  OFF: ON   BLUE    [001]   1       "44"   "34"
OFF:  ON : OFF  GREEN   [010]   2       "42"   "32"
OFF:  ON : ON   CYAN    [011]   3       "46"   "36"
ON:   OFF: OFF  RED     [100]   4       "41"   "31"
ON:   OFF: ON   MAGENTA [101]   5       "45"   "35"
ON:   ON : OFF  YELLOW  [110]   6       "43"   "33"
ON:   ON : ON   WHITE   [111]   7       "47"   "37"

---------------------------------------------
Typical Attribute Byte Settings
---------------------------------------------
0x00    non-display (invisible)
0x01    underline (monochrome only)
0x07    normal display (white on black)
0x70    reverse video (black on white)
0x87    blinking normal display
0xF0    blinking normal reverse video display
---------------------------------------------
#endif                              /* end preprocessor comments       */

/*-------------------------function aprintf()--------------------------*/
int aprintf( unsigned char attr, const char *format, ... )
{
int size;                           /* string length                   */
int ret;                            /* aprintf() return count          */
va_list ptr;                        /* va_start() address              */
char buffer[0x80];                  /* workspace for attr + string     */

/* ansi.sys SGR (Set Graphics Rendition) Control Sequences             */
/* bold/ underscore/ blink/ reverse/ invisible                         */
static const char *control[] =
    { "1;", "4;", "5;", "7;", "8;" };
/* see SGR Back Table above                                            */
static const char *back[] =
    { "40;", "44;", "42;", "46;", "41;", "45;", "43;", "47;" };
/* see SGR Fore Table above                                            */
static const char *fore[] =
    { "30;", "34;", "32;", "36;", "31;", "35;", "33;", "37;" };

/* start graphics rendition prologue                                   */
strcpy(buffer,"\x1b[?7l\x1b[0;");   /* no line wrap; reset attr        */

/* test/set blinking attribute bit                                     */
if (attr >> 7) strcat(buffer, control[2]);

/* test/set background color attribute bits                            */
strcat(buffer, back[(unsigned char)(attr << 1) >> 5]);

/* test/set intensity attribute bit                                    */
if ((unsigned char)(attr << 4) >> 7) strcat(buffer, control[0]);

/* test/set foreground color attribute bits                            */
strcat(buffer, fore[(unsigned char)(attr << 5) >> 5]);

/* test special attribute bit cases                                    */
/* --> invisible criteria                                              */
if ( ((unsigned char)(attr << 1) >> 5) == (BACK_BLACK >> 4) &&
     ((unsigned char)(attr << 5) >> 5) == FORE_BLACK )
     strcat(buffer, control[4]);

/* --> underline criteria                                              */
if ( ((unsigned char)(attr << 5) >> 5) == UNDERLINE )
     strcat(buffer, control[1]);

/* --> reverse video criteria                                          */
if ( ((unsigned char)(attr << 1) >> 5) == (BACK_WHITE >> 4) &&
     ((unsigned char)(attr << 5) >> 5) == FORE_BLACK )
     strcat(buffer, control[3]);

size = strlen(buffer);              /* overwrite very last semi-colon  */
strcpy(&buffer[size-1], "m");       /* end graphics rendition prologue */
size = strlen(buffer);

va_start(ptr, format);              /* format variable to buffer       */
ret = vsprintf(&buffer[size], format, ptr);
strcat(buffer, "\x1b[0m\x1b[K");    /* reset attr; blank to EOL        */
printf(buffer);                     /* display attr control & text     */
fflush(stdout);                     /* flush output buffer             */
return (ret);                       /* count of characters displayed   */
}                                   /* end function aprintf()          */

/*----------------------embedded test driver main()--------------------*/
#if !defined(NDEBUG)                /* conditional compilation         */
int main( void)                     /* embedded test driver main()     */
{
int retval;                         /* aprintf() count of characters   */
unsigned char attr;                 /* attribute control byte          */
while (1) {
    aprintf(NORMAL|BOLDON,"\nEnter Attribute as 0xhh (0x00 to END): ");
    fflush(stdin);                  /* clear the input buffer          */
    scanf("%x", &attr);             /* get attribute from user         */
    if (!attr) break;               /* test to end                     */
    retval = aprintf(attr, "%d %f %s", 33, -100.25F, "Sample String!");
    aprintf(NORMAL, "\nCharacters written = %d", retval);
    }
aprintf(INVISIBLE, "\nYou will not see this message\n");
 }                                  /* end function main()             */
#endif
/*===============================stop==================================*/
