//********************************************************************************
//* File       : AnsiCmdAca.cpp                                                  *
//* Author     : Mahlon R. Smith                                                 *
//*              Copyright (c) 2022-2026 Mahlon R. Smith, The Software Samurai   *
//*                 GNU GPL copyright notice below                               *
//* Date       : 22-Oct-2025                                                     *
//* Version    : (see AnsiCmdVersion string in AnsiCmd.cpp)                      *
//*                                                                              *
//* Description: acaExpand class implementation.                                 *
//* acaExpand manages color attributes for API-level objects such as the         *
//* ACWin class which includes both sdField and skForm user-interface classes.   *
//* Converts between aeSeq color attribute syntax used by the low-level ANSI     *
//* escape sequences and the application-level color-attribute bit fields.       *
//*                                                                              *
//* NOTE: The AnsiCmd class _also_ includes an acaExpand-class data member:      *
//*       "attrBits". For this reason, the members of this class _are not_       *
//*       enclosed within the INCLUDE_API directive. This contributes            *
//*       approximately 25 Kb to the size of the library. The author considers   *
//*       this to be an acceptable size increase in exchange for a               *
//*       significantly-enhanced functionality in managing color attributes.     *
//*                                                                              *
//********************************************************************************

//*****************
//* Include Files *
//*****************
#include "AnsiCmd.hpp"     //* AnsiCmd-class definition
#include "AnsiCmdWin.hpp"  //* AnsiCmd-class window-object definitions

#if DEBUG_ANSICMD != 0 && DEBUG_LOG != 0
extern ofstream ofsdbg ;
extern gString  gsdbg ;
#endif   // DEBUG_ANSICMD && DEBUG_LOG

//***************
//* Definitions *
//***************

//**************
//* Local data *
//**************

//********************
//* Local prototypes *
//********************


//*********************
//*     acaExpand     *
//*********************
//********************************************************************************
//* Default Constructor:                                                         *
//* Initialize all data members to default values.                               *
//*                                                                              *
//* Input  : none                                                                *
//*                                                                              *
//* Returns: nothing                                                             *
//********************************************************************************

acaExpand::acaExpand ( void )
{
   //* Initialize with terminal default foreground/background *
   acAttr acaBits = acaATTR_DFLT ;

   this->decode ( acaBits ) ;

} ;   //* End acaExpand() *

//*********************
//*     acaExpand     *
//*********************
//********************************************************************************
//* Initialization Constructor:                                                  *
//* Decode the specified bitfield value and store the decoded data in the        *
//* data members.                                                                *
//*                                                                              *
//* Input  : acaValue : an initialized acAttr bitfield value                     *
//*                                                                              *
//* Returns: nothing                                                             *
//********************************************************************************

acaExpand::acaExpand ( acAttr acaValue )
{
   if ( acaValue == acaUSEDFLT )          // if placeholder value specified
      acaValue = acaATTR_DFLT ;

   this->decode ( acaValue ) ;

} ;   //* End acaExpand() *

//*********************
//*      decode       *
//*********************
//********************************************************************************
//* Decode the specified bitfield value and store the decoded data in the        *
//* data members.                                                                *
//*                                                                              *
//* The 'acaValue' argument is a bitfield containing the OR'd fields             *
//* describing the foreground and background color attributes and text           *
//* modifiers to be set before writing text to the terminal window.              *
//* -- Note that 'acaVal' is not validated, so if 'acaVal' not a valid attribute *
//*    bitfield (e.g. acaFG_DFLT | acaFG_RGB | acaFG_BLUE), decodeing may produce*
//*    an unexpected result.                                                     *
//* -- Caller should verify that 'acaVal' is not the placeholder value,          *
//*    acaUSEDFLT; however, if it is seen here, it will be converted to:         *
//*    (acaFG_DFLT | acaBG_DFLT).                                                *
//*                                                                              *
//* Input  : acaValue : an initialized acAttr bitfield value                     *
//*                     (This becomes the 'acaVal' member.)                      *
//*                                                                              *
//* Returns: nothing                                                             *
//********************************************************************************
//* Notes:                                                                       *
//* ------                                                                       *
//* Caller provides the OR'd bitfield values for the color attributes,           *
//* text-modifier flags and miscellaneous flags needed to define foregroud       *
//* and background attributes for writing data to the terminal window.           *
//* This method decodes all bitfields into their individual fields, providing    *
//* uniform access to the information without the mainline code having to        *
//* perform error-prone bitfield twiddling.                                      *
//*                                                                              *
//* AnsiCmd (enum acAttr) color-attribute bit fields:                            *
//* 0x000000FF  index for foreground color                                       *
//*             ......00-......0F  16  4-bit color attributes                    *
//*             ......10-......E7  216 8-bit color attributes                    *
//*             ......E8-......FF  24  greyscale color attributes                *
//*             ......00-......FC  232 RGB color attributes                      *
//* 0x0000FF00  index for background color                                       *
//*             ....00..-....0F..  16  4-bit color attributes                    *
//*             ....10..-....E7..  216 8-bit color attributes                    *
//*             ....E8..-....FF..  24  greyscale color attributes                *
//*             ....00..-....FC..  232 RGB color attributes                      *
//* 0x00FF0000  text modifier flags                                              *
//*             ..00....   plain text (no modifiers)                             *
//*             ..01....   bold (intense)                                        *
//*             ..02....   italic                                                *
//*             ..04....   underline                                             *
//*             ..08....   overline                                              *
//*             ..10....   x-out (strike-through)                                *
//*             ..20....   blink                                                 *
//*             ..40....   concealed (invisible)                                 *
//*             ..80....   reversed fg/bg                                        *
//* 0xFF000000  additional flags                                                 *
//*             01......   clear existing modifiers before setting the new ones  *
//*             02......   use terminal default foreground attribute             *
//*                        (foreground index ignored)                            *
//*             04......   if set, it indicates that foreground index is the     *
//*                        index of a "web-safe" RGB foreground color attribute  *
//*                        with a range of: minRGB <= value <= maxRGB            *
//*             08......   use terminal default background attribute             *
//*                        (background index ignored)                            *
//*             10......   if set, it indicates that background index is the     *
//*                        index of a "web-safe" RGB background color attribute  *
//*                        with a range of: minRGB <= value <= maxRGB            *
//*             20......   (reserved)                                            *
//*             40......   (reserved)                                            *
//*             80......   (reserved as internal placeholder value)              *
//*                                                                              *
//* To specify the terminal default foreground attribute, set the acaFG_DFLT     *
//* flag. The foreground index value will be ignored.                            *
//*               Fgnd:  xxxx-x01x-xxxx-xxxx-xxxx-xxxx-....-....                 *
//*                                                                              *
//* To specify the terminal default background attribute, set the acaBG_DFLT     *
//* flag. The background index value will be ignored.                            *
//*               Bgnd:  xxx0-1xxx-xxxx-xxxx-....-....-xxxx-xxxx                 *
//*                                                                              *
//* To specify a 4-bit foreground attribute, _reset_ the acaFG_DFLT and          *
//* acaFG_RGB flags and insert the desired member of enum acAttr in the range:   *
//* acaFG_BLACK through acaFGb_GREY inclusive.                                   *
//*                                                                              *
//* To specify a 4-bit background attribute, _reset_ the acaBG_DFLT and          *
//* acaBG_RGB flags and insert the desired member of enum acAttr in the range:   *
//* acaBG_BLACK through acaBGb_GREY inclusive.                                   *
//*                                                                              *
//* To specify an 8-bit indexed color foreground attribute, initialize the       *
//* foreground index and _reset_ both the acaFG_DFLT and acaFG_RGB flags.        *
//*               Fgnd:  xxxx-x00x-xxxx-xxxx-xxxx-xxxx-nnnn-nnnn                 *
//*                                                                              *
//* To specify an 8-bit indexed color background attribute, initialize the       *
//* background index and _reset_ both the acaBG_DFLT and acaBG_RGB flags.        *
//*               Bgnd:  xxx0-0xxx-xxxx-xxxx-nnnn-nnnn-xxxx-xxxx                 *
//*                                                                              *
//* To specify one of the "web-safe" RGB register combinations, initialize the   *
//* foreground or background index and set the acaFG_RGB or acaBG_RGB flag,      *
//* respectively. Fgnd:  xxxx-x10x-xxxx-xxxx-xxxx-xxxx-nnnn-nnnn                 *
//*               Bgnd:  xxx1-0xxx-xxxx-xxxx-nnnn-nnnn-xxxx-xxxx                 *
//*                                                                              *
//* To set one or more text modifiers, _reset_ the acaCLEAR_MODS flag and        *
//* create a logical OR of the desired attributes. (include existing fg/bg bits.)*
//* Ex: acAttr((fg | bg |acaBOLD | acaITALIC | acaUNDERLINE) & ~acaCLEAR_MODS)   *
//*               Mods:  xxxx-xxx0-xxxx-x111-xxxx-xxxx-xxxx-xxxx                 *
//*                                                                              *
//* To reset one or more text modifier, set the acaCLEAR_MODS flag and _set_     *
//* the flag for the modfier to be reset. (include existing fg/bg bits.)         *
//* Example: acAttr(fg | bg | acaITALIC | acaCLEAR_MODS)                         *
//*               Mods:  xxxx-xxx1-0000-0010-xxxx-xxxx-xxxx-xxxx                 *
//*                                                                              *
//********************************************************************************
//* Notes: The functionality can be tested by enabling:                          *
//*        DEBUG_ANSICMD && DEBUG_LOG && DEBUG_decode, and then use the          *
//*        Test_Sandbox method to repeatedly call decode() to verify that        *
//*        the bitmap is updated correctly.                                      *
//*                                                                              *
//* // This example may be used to test one of the RGB "hue" groups.             *
//* acaExpand acaEx ;                                                            *
//* uint8_t rgbReg ;                                                             *
//* for ( uint8_t shade = wsrgbSHADE_MIN ; shade <= wsrgbSHADE_MAX ; ++shade )   *
//* {                                                                            *
//*    rgbReg = wsrgbRED + shade ;                                               *
//*    gsdbg.compose( "acaEx (fgnd wsrgbRED x%02hhX)", &rgbReg );                *
//*    ofsdbg << gsdbg.ustr() << endl ;                                          *
//*    acaEx.decode( acAttr(acaFG_RGB | acaBG_DFLT | rgbReg) );                  *
//* }                                                                            *
//*                                                                              *
//********************************************************************************

void acaExpand::decode ( acAttr acaValue )
{
   #define DEBUG_decode (0)   // for debugging only

   //* Placeholders are not valid bit fields. (see note) *
   if ( (acaValue & acaUSEDFLT) || (acaValue == acaPLAINTXT) )
      acaValue = acaATTR_DFLT ;

   this->acaVal    = acaValue ;                       // full, encoded value
   this->fgBits    = this->acaVal & acaFG_MASK ;      // all foreground bits
   this->bgBits    = this->acaVal & acaBG_MASK ;      // all background bits
   this->allFlags  = this->acaVal & acaFLAG_MASK ;    // all binary flags
   this->modFlags  = this->acaVal & acaMOD_MASK ;     // text-modifier flags
   this->acaFgnd   = acAttr(this->acaVal & acaFG_INDEX) ; // fgnd acAttr member
   this->acaBgnd   = acAttr(this->acaVal & acaBG_INDEX) ; // bgnd acAttr member
   this->fgIndex   = this->acaFgnd ;                  // fgnd byte index into lookup table
   this->bgIndex   = this->acaBgnd >> 8 ;             // bgnd byte index into lookup table

   //* Text-modifier flags *
   this->boldMod   = bool(this->acaVal & acaBOLD) ;   // bold-text flag
   this->italicMod = bool(this->acaVal & acaITALIC) ; // italic-text flag
   this->ulineMod  = bool(this->acaVal & acaUNDERLINE) ; // underlined-text flag
   this->olineMod  = bool(this->acaVal & acaOVERLINE) ;  // overlined-text flag
   this->xoutMod   = bool(this->acaVal & acaXOUT) ;   // strikethrough-text flag
   this->blinkMod  = bool(this->acaVal & acaBLINK) ;  // blinking-text flag
   this->invisMod  = bool(this->acaVal & acaCONCEAL) ;// invisible-text (concealed) flag
   this->revMod    = bool(this->acaVal & acaREVERSE) ;// reversed fgnd/bgnd flag
   //* Miscellaneous flags *
   this->fgDflt    = bool(this->acaVal & acaFG_DFLT) ;// foreground-default flag
   this->bgDflt    = bool(this->acaVal & acaBG_DFLT) ;// background-default flag
   this->clrMods   = bool(this->acaVal & acaCLEAR_MODS) ;// clear-mods flag

   //* If RGB background specified, call the low-level conversion method   *
   //* to set the 'rgbBgR', 'rgbBgG' and 'rgbBgB' register values.         *
   //* If 'bgIndex' is out-of-range, registers set for wsrgbMIN (black)    *
   //* Note that the following data members are also initialized:          *
   //*    bgRgb, bgIndex, 'aesBgnd', 'aesBgType' (bgDflt is reset)         *
   if ( (this->bgRgb = bool(this->acaVal & acaBG_RGB)) != false )
   {
      this->web2regs ( this->bgIndex, false ) ;
   }
   //* If not RGB, initialize the background RGB register values to zero.  *
   //* 'bgIndex' contains the 4-bit/8-bit index value.                     *
   else
   {
      this->bgHue   = wsrgbMIN ;
      this->bgShade = wsrgbSHADE_MIN ;
      this->rgbBgR = this->rgbBgG = this->rgbBgB = ZERO ;
      this->aesBgnd = this->bits2aeseq ( acAttr(this->bgBits), this->bgIndex, false ) ;
      //* Indicate which Bg color-attribute type is active.*
      if ( (this->aesBgnd >= aesBG_BLACK) && (this->aesBgnd <= aesBG_DFLT) )
         this->aesBgType = aesBG_DFLT ;
      else
         this->aesBgType = aesBG_INDEX ;
   }

   //* If RGB foreground specified, call the low-level conversion method   *
   //* to set the 'rgbFgR', 'rgbFgG' and 'rgbFgB' register values.         *
   //* If 'fgIndex' is out-of-range, registers set for wsrgbMIN (black)    *
   //* Note that the following data members are also initialized:          *
   //*    fgRgb, fgIndex, 'aesFgnd', 'aesFgType' (fgDflt is reset)         *
   if ( (this->fgRgb = bool(this->acaVal & acaFG_RGB)) != false )
   {
      this->web2regs ( this->fgIndex, true ) ;
   }

   //* If not RGB, initialize the foreground RGB register values to zero.  *
   //* 'fgIndex' contains the 4-bit/8-bit index value.                     *
   else
   {
      this->fgHue   = wsrgbMIN ;
      this->fgShade = wsrgbSHADE_MIN ;
      this->rgbFgR = this->rgbFgG = this->rgbFgB = ZERO ;
      this->aesFgnd = this->bits2aeseq ( acAttr(this->fgBits), this->fgIndex, true ) ;
      //* Indicate which Fg color-attribute type is active.*
      if ( (this->aesFgnd >= aesFG_BLACK) && (this->aesFgnd <= aesFG_DFLT) )
         this->aesFgType = aesFG_DFLT ;
      else
         this->aesFgType = aesFG_INDEX ;
   }

   #if DEBUG_ANSICMD != 0 && DEBUG_LOG != 0 && DEBUG_decode != 0
   if ( ofsdbg.is_open() )
   {
      gsdbg.compose( "decode( fgIndex:%02hhX hue:%02hhX shade:%02hhX r:%hhu g:%hhu b:%hhu )\n"
                     "      ( bgIndex:%02hhX hue:%02hhX shade:%02hhX r:%hhu g:%hhu b:%hhu )\n"
                     "        ---r brfc --mods--- --bgnd--- --fgnd---\n"
                     "       %#-b",
                     &this->fgIndex, &this->fgHue, &this->fgShade, 
                     &this->rgbFgR,  &this->rgbFgG, &this->rgbFgB, 
                     &this->bgIndex, &this->bgHue, &this->bgShade, 
                     &this->rgbBgR,  &this->rgbBgG, &this->rgbBgB, 
                     &this->acaVal) ;
      ofsdbg << gsdbg.ustr() << endl ;
   }
   #endif   // DEBUG_ANSICMD && DEBUG_LOG && DEBUG_decode

}  //* End decode() *

//*************************
//*        update         *
//*************************
//********************************************************************************
//* Update attribute tracking data by converting the provided member of          *
//* enum aeSeq to the equivalent acAttr bitfield value.                          *
//*                                                                              *
//* Called by the methods which directly issue ANSI escape sequences:            *
//* acSetFg(), acSetBg(), acSetMod(), acSet8bit() acSetGreyscale(), setRgbWeb(). *
//*                                                                              *
//* Input  : aesValue : member of enum aeSeq indicating the color attribute or   *
//*                     text modifier which caller has just changed.             *
//*          colorIndx: (optional)                                               *
//*                  -- lookup-table index for 8-bit color attribute             *
//*                     when: aesValue == aesFG_INDEX or                         *
//*                           aesValue == aesBG_INDEX                            *
//*                           Range: min8BIT <= colorIndx <= max8BIT             *
//*                  -- lookup-table index for "web-safe" RGB color attribute    *
//*                     when: aesValue == aesFG_RGB or                           *
//*                           aesValue == aesBG_RGB                              *
//*                           Range: minRGB <= colorIndx <= maxRGB               *
//*                                                                              *
//* Returns: nothing                                                             *
//********************************************************************************

void acaExpand::update ( aeSeq aesValue, uint8_t colorIndx )
{
   #define DEBUG_update (0)         // for debugging only

   bool setFlag = true ;            // for binary flags, indicate set vs. reset

   //* Convert the aeSeq value to acAttr value.  *
   //* For text modifiers, 'setFlag' reports     *
   //* whether the modifer flag s/b set or reset.*
   acAttr acaBits = this->aeseq2bits ( aesValue, setFlag ) ;

   #if DEBUG_ANSICMD != 0 && DEBUG_LOG != 0 && DEBUG_update != 0
   if ( ofsdbg.is_open() )
   {
      gsdbg = "          update(        ---r brfc --mods--- --bgnd--- --fgnd---\n" ;
      if ( acaBits != acaPLAINTXT )
         gsdbg.append( "                  init :%#-b \n", &acaBits ) ;
   }
   #endif   // DEBUG_ANSICMD && DEBUG_LOG && DEBUG_update

   //* If adding or removing one of the text modifiers  *
   if ( (aesValue >= aesBOLD) && (aesValue <=aesOVERLINE_OFF) )
   {
      #if DEBUG_ANSICMD != 0 && DEBUG_LOG != 0 && DEBUG_update != 0
      wchar_t t = L't', f = L'f' ;
      if ( ofsdbg.is_open() )
      { gsdbg.append( "                mods(%C):%#-b \n", (setFlag ? &t : &f), &acaBits ) ; }
      #endif   // DEBUG_ANSICMD && DEBUG_LOG && DEBUG_update

      if ( setFlag )       // set the specified modifier bit
         acaBits = acAttr(this->modFlags | acaBits) ;
      else                 // reset the specified modifier bit
         setFlag = false ;

      //* Insert both foreground and background bits.*
      acaBits = acAttr(acaBits | (this->fgBits | this->bgBits)) ;

      #if DEBUG_ANSICMD != 0 && DEBUG_LOG != 0 && DEBUG_update != 0
      if ( ofsdbg.is_open() )
      { gsdbg.append( "                mods   :%#-b \n", &acaBits ) ; }
      #endif   // DEBUG_ANSICMD && DEBUG_LOG && DEBUG_update
   }

   //* If updating the foreground attribute, insert the    *
   //* current background attribute, OR if updating the    *
   //* background attribute, insert the current foreground *
   //* attribute. This prevents accidental modification of *
   //* the attribute which was not specified.              *
   else
   {
      //* If a new 4-bit background attribute specified,  *
      //* insert the current foreground into the bitfield.*
      if ( (aesValue >= aesBG_BLACK) && (aesValue <= aesBG_DFLT) )
         acaBits = acAttr(acaBits | this->fgBits) ;
      //* If a new 4-bit foreground attribute specified,  *
      //* insert the current background into the bitfield.*
      if ( (aesValue >= aesFG_BLACK) && (aesValue <= aesFG_DFLT) )
         acaBits = acAttr(acaBits | this->bgBits) ;

      //* If a new 8-bit background index specified *
      if ( (aesValue == aesBG_INDEX) && 
           (((colorIndx >= min8BIT) && (colorIndx <= max8BIT)) ||
            ((colorIndx >= minGSCALE) && (colorIndx <= maxGSCALE))) )
      {
         acaBits = acAttr(acaBits | this->fgBits | (colorIndx << 8)) ;

         #if DEBUG_ANSICMD != 0 && DEBUG_LOG != 0 && DEBUG_update != 0
         if ( ofsdbg.is_open() )
         { gsdbg.append( "                 indBG :%#-b \n", &acaBits ) ; }
         #endif   // DEBUG_ANSICMD && DEBUG_LOG && DEBUG_update
      }

      //* If a new 8-bit foreground index specified *
      else if ( (aesValue == aesFG_INDEX) && 
                (((colorIndx >= min8BIT) && (colorIndx <= max8BIT)) ||
                 ((colorIndx >= minGSCALE) && (colorIndx <= maxGSCALE))) )
      {
         acaBits = acAttr(acaBits | this->bgBits | colorIndx) ;

         #if DEBUG_ANSICMD != 0 && DEBUG_LOG != 0 && DEBUG_update != 0
         if ( ofsdbg.is_open() )
         { gsdbg.append( "                 indFG :%#-b \n", &acaBits ) ; }
         #endif   // DEBUG_ANSICMD && DEBUG_LOG && DEBUG_update
      }

      //* If a new RGB "web-safe" background specified *
      else if ( (aesValue == aesBG_RGB) &&
                ((colorIndx >= wsrgbMIN) && (colorIndx <= wsrgbMAX)) )
      {
         acaBits = acAttr(acaBits | this->fgBits | (colorIndx << 8) | acaBG_RGB) ;

         #if DEBUG_ANSICMD != 0 && DEBUG_LOG != 0 && DEBUG_update != 0
         if ( ofsdbg.is_open() )
         { gsdbg.append( "                 rgbBG :%#-b \n", &acaBits ) ; }
         #endif   // DEBUG_ANSICMD && DEBUG_LOG && DEBUG_update
      }

      //* If a new RGB "web-safe" foreground specified *
      else if ( (aesValue == aesFG_RGB) &&
                ((colorIndx >= wsrgbMIN) && (colorIndx <= wsrgbMAX)) )
      {
         acaBits = acAttr(acaBits | this->bgBits | colorIndx | acaFG_RGB) ;

         #if DEBUG_ANSICMD != 0 && DEBUG_LOG != 0 && DEBUG_update != 0
         if ( ofsdbg.is_open() )
         { gsdbg.append( "                 rgbFG :%#-b \n", &acaBits ) ; }
         #endif   // DEBUG_ANSICMD && DEBUG_LOG && DEBUG_update
      }
   }

   //* Modify the target field *
   this->modify ( acaBits, setFlag ) ;

   #if DEBUG_ANSICMD != 0 && DEBUG_LOG != 0 && DEBUG_update != 0
   if ( ofsdbg.is_open() )
   {
      gsdbg.append( "                 newval:%#-b )", &this->acaVal ) ;
      ofsdbg << gsdbg.ustr() << endl ;
   }
   #endif   // DEBUG_ANSICMD && DEBUG_LOG && DEBUG_update

}  //* End update() *

//*********************
//*      modify       *
//*********************
//********************************************************************************
//* Update one or more data-member bitfields which track color attributes and    *
//* text-modification options.                                                   *
//* The caller is responsible for actually issuing the command to the terminal.  *
//* This method updates the attribute tracking data to reflect that change.      *
//*                                                                              *
//* 1) Specify a foreground color attribute, OR                                  *
//* 2) Specify a background color attribute, OR                                  *
//* 3) Specify both a foreground and background color attributes, OR             *
//* 4) Specify setting one or more text modifiers OR'd together, OR              *
//* 5) Specify resetting one or more text modifiers OR'd together.               *
//* 6) Specify both attribute and text modifiers.                                *
//*                                                                              *
//* Input  : acaValue : one or more members of enum acAttr OR'd together.        *
//*                     -- if 'add' is set, OR the value with the existing       *
//*                        data and recalculate all data members.                *
//*                     -- if 'add' is reset, then XOR the inverted value with   *
//*                        the existing data and recalculate all data members.   *
//*          add      : for text-modifier flags only (ignored for color attr.).  *
//*                   : if 'true'  set the specified modifier flags              *
//*                     if 'false' reset the specified modifier flags            *
//*                                existing data.                                *
//*                                                                              *
//* Returns: the modified acAttr value                                           *
//********************************************************************************
//* Notes: The functionality can be tested by enabling:                          *
//*        DEBUG_ANSICMD && DEBUG_LOG && DEBUG_modify, and then use the          *
//*        Test_Sandbox method to repeatedly call modify() to verify that        *
//*        the bitmap is updated correctly. Example:                             *
//*                                                                              *
//* acaExpand acaEx( acaPLAINTXT ) ;                                             *
//* ofsdbg << "Test( set acaXOUT | acaBLINK | acaCONCEAL | acaREVERSE )" << endl;*
//* acaEx.modify( acAttr(acaXOUT | acaBLINK | acaCONCEAL | acaREVERSE), true );  *
//*                                                                              *
//* ofsdbg << "\nSandbox( set acaBOLD )" << endl ;                               *
//* acaEx.modify( acaBOLD, true ) ;                                              *
//*                                                                              *
//* ofsdbg << "\nSandbox( reset acaBOLD )" << endl;                              *
//* acaEx.modify( acaBOLD, false );                                              *
//*                                                                              *
//* ofsdbg << "\nSandbox( set 4-bit fg/bg )" << endl ;                           *
//* acaEx.modify( acaFGb_RED | acaBG_BLUE );                                     *
//*                                                                              *
//* ofsdbg << "\nSandbox( set 8-bit fg/bg )" << endl ;                           *
//* acAttr acattr =                                                              *
//*             acComposeAttributes( (min8BIT + 4), (max8BIT-2), false, false ); *
//* acaEx.modify( acattr ) ;                                                     *
//*                                                                              *
//* ofsdbg << "\nSandbox( set RGB fg/bg )" << endl ;                             *
//* acAttr acattr =                                                              *
//*         acComposeAttributes( (wsrgbGREEN + 12), (wsrgbRED + 2), true, true );*
//* acaEx.modify( acattr ) ;                                                     *
//*                                                                              *
//* ofsdbg << "\nSandbox( set RGB fg and 8-bit bg )" << endl ;                   *
//* acAttr acattr = acComposeAttributes( (wsrgbGREEN + 2), (42), true, false );  *
//* acaEx.modify( acattr ) ;                                                     *
//*                                                                              *
//*                                                                              *
//********************************************************************************

acAttr acaExpand::modify ( acAttr acaValue, bool add )
{
   #define DEBUG_modify (0)            // for debugging only
   #if DEBUG_ANSICMD != 0 && DEBUG_LOG != 0 && DEBUG_modify != 0
   if ( ofsdbg.is_open() )
   {
      gsdbg.compose( "modify( acaValue:%08X add:%hhd\n"
                     "                         ---r brfc --mods--- --bgnd--- --fgnd---\n"
                     "                 acaVal:%#-b ",
                     &acaValue, &add, &this->acaVal ) ;
      ofsdbg << gsdbg.ustr() << endl ;
   }
   #endif   // DEBUG_ANSICMD && DEBUG_LOG && DEBUG_modify

   acAttr acamods = acAttr(acaValue & acaMOD_MASK) ;  // isolate modifier flags
   bool modsUpdate = false,            // set if modifier update
        fgndUpdate = false,            // set if foreground update
        bgndUpdate = false ;           // set if background update

   //*******************************
   //* Toggle a text modifier flag *
   //*******************************
   if ( acaValue & acaCLEAR_MODS )
   {
      acamods = acaMOD_MASK ;
      add = false ;
      modsUpdate = true ;
   }
   else if ( acamods & acaMOD_MASK )
      modsUpdate = true ;

   if ( modsUpdate )
   {
      this->acaVal = acAttr(add ? (this->acaVal | acamods) : (this->acaVal & ~acamods)) ;

      #if DEBUG_ANSICMD != 0 && DEBUG_LOG != 0 && DEBUG_modify != 0
      if ( ofsdbg.is_open() )
      {
         gsdbg.compose( " modify( mods: acaValue:%#-b\n"
                        "                 acaVal:%#-b", &acaValue, &this->acaVal ) ;
         ofsdbg << gsdbg.ustr() << endl ;
      }
      #endif   // DEBUG_ANSICMD && DEBUG_LOG && DEBUG_modify
   }

   //****************************
   //* Modify a color attribute *
   //****************************

   //* Seperate the fgnd and bgnd bitfields *
   acAttr newFg = acAttr(acaValue & acaFG_MASK),
          newBg = acAttr(acaValue & acaBG_MASK) ;

   //* RGB foreground and/or background attribute specified *
   if ( (acaValue & acaFG_RGB) || (acaValue & acaBG_RGB) )
   {
      if ( (acaValue & acaFG_RGB) && (!this->fgRgb || (this->fgIndex != newFg)) )
      {
         //* Clear the current fgnd bits and integrate the new fgnd bits.*
         this->acaVal = acAttr(this->acaVal & ~acaFG_MASK) ;
         this->acaVal = acAttr(this->acaVal | newFg) ;
         fgndUpdate = true ;
      }
      if ( (acaValue & acaBG_RGB) && (!this->bgRgb || (this->bgIndex != newBg)) )
      {
         //* Clear the current bgnd bits and integrate the new bgnd bits.*
         this->acaVal = acAttr(this->acaVal & ~acaBG_MASK) ;
         this->acaVal = acAttr(this->acaVal | newBg) ;
         bgndUpdate = true ;
      }

      #if DEBUG_ANSICMD != 0 && DEBUG_LOG != 0 && DEBUG_modify != 0
      if ( (ofsdbg.is_open()) && (fgndUpdate || bgndUpdate) )
      {
         gsdbg.compose( " modify(  rgb: acaValue:%#-b\n"
                        "                 acaVal:%#-b", &acaValue, &this->acaVal ) ;
         ofsdbg << gsdbg.ustr() << endl ;
      }
      #endif   // DEBUG_ANSICMD && DEBUG_LOG && DEBUG_modify
   }

   //* Indexed foreground and/or background attribute *
   if ( !fgndUpdate || !bgndUpdate )
   {
      #if DEBUG_ANSICMD != 0 && DEBUG_LOG != 0 && DEBUG_modify != 0
      bool ftmp = fgndUpdate, btmp = bgndUpdate ;
      #endif   // DEBUG_ANSICMD && DEBUG_LOG && DEBUG_modify

      //* If new fgnd bits != existing fgnd bits, replace fgnd *
      if ( !fgndUpdate && (newFg != this->fgBits) )
      {
         //* Clear the current fgnd bits *
         this->acaVal = acAttr(this->acaVal & ~acaFG_MASK ) ;

         //* Set the new value for fgnd bitfield *
         this->acaVal = acAttr(this->acaVal | newFg) ;
         fgndUpdate = true ;
      }

      //* If new bgnd bits != existing bgnd bits, replace bgnd *
      if ( !bgndUpdate && (newBg != this->bgBits) )
      {
         //* Clear the current bgnd bits *
         this->acaVal = acAttr(this->acaVal & ~acaBG_MASK) ;

         //* Set the new value for bgnd bitfield *
         this->acaVal = acAttr(this->acaVal | newBg) ;
         bgndUpdate = true ;
      }

      #if DEBUG_ANSICMD != 0 && DEBUG_LOG != 0 && DEBUG_modify != 0
      if ( (ofsdbg.is_open()) && ((fgndUpdate != ftmp) || (bgndUpdate != btmp)) )
      {
         gsdbg.compose( " modify( indx: acaValue:%#-b\n"
                        "                 acaVal:%#-b", &acaValue, &this->acaVal ) ;
         ofsdbg << gsdbg.ustr() << endl ;
      }
      #endif   // DEBUG_ANSICMD && DEBUG_LOG && DEBUG_modify
   }

   //* If bitfields modified, decode them *
   if ( modsUpdate || fgndUpdate || bgndUpdate )
      this->decode ( this->acaVal ) ;

   return ( this->acaVal ) ;

}  //* End modify() *

//*************************
//*        compose        *
//*************************
//********************************************************************************
//* Construct an acAttr attribute bitmap from component values:                  *
//* This method is used when specifying an 8-bit fgnd/bgnd or an RGB fgnd/bgnd   *
//* attribute.                                                                   *
//* See also the API-level method acComposeAttributes() which calls this method  *
//* without the application having to know anything about bit fields.            *
//*                                                                              *
//* Note on 4-bit values:                                                        *
//* ---------------------                                                        *
//* The 4-bit color attributes are individually named, so the attributes may be  *
//* specified directly.                                                          *
//*    Examples: acSetAttributes( acAttr(acaFG_BLUE | acaBGb_BROWN) );           *
//*              acSetAttributes( acAttr(acaFG_DFLT | acaBGb_BLUE) );            *
//* In any case, 4-bit data are handled here to avoid problems.                  *
//*                                                                              *
//* Interpretation of 'fgIndex' field is based on 'fgRgb' flag:                  *
//*    If fgRgb set, then fgIndex contains web-safe RGB index.                   *
//*    If fgRgb reset, then fgIndex contains 8-bit color index                   *
//*    Special Case: fgRgb reset AND fgIndex < min8BIT, then 4-bit color assumed *
//* Interpretation of 'bgIndex' field is based on 'bgRgb' flag:                  *
//*    If bgRgb set, then bgIndex contains web-safe RGB index.                   *
//*    If bgRgb reset, then bgIndex contains 8-bit color index                   *
//*    Special Case: bgRgb reset AND bgIndex < min8BIT, then 4-bit color assumed *
//*                                                                              *
//* Text-modifier flags may be set if desired.                                   *
//* Modifiers may be specified either by placing the logical OR of the flags in  *
//* the 'modFlags' member, or by setting the individual modifier flags.          *
//* Note that if modFlags != acaPLAINTXT, it overrides the individual flags.     *
//*                                                                              *
//* Input  : none (data members have been initialized by caller):                *
//*            fgIndex, bgIndex, fgRgb, bgRgb, and                               *
//*            either modFlags or individual modifier flags                      *
//*                                                                              *
//* Returns: the constructed acAttr value                                        *
//********************************************************************************
//* Notes: The functionality can be tested by enabling:                          *
//*        DEBUG_ANSICMD && DEBUG_LOG && DEBUG_compose, and then use the         *
//*        Test_Sandbox method to repeatedly call compose() via the public       *
//*        acComposeAttributes() method to verify that the bitmap is updated     *
//*        correctly. Example:                                                   *
//*                                                                              *
//* // 4-bit fgnd, 8-bit bgnd, with modifiers                                    *
//* this->acComposeAttributes ( 0x03, 0xC0, false, false,                        *
//*                  acAttr(acaBOLD | acaITALIC | acaUNDERLINE | acaOVERLINE) ); *
//* // Intentional out-of-range RGB fgnd/bgnd, with modifiers                    *
//* this->acComposeAttributes ( 0xFF, 0xFF, true, true,                          *
//*                      acAttr(acaXOUT | acaBLINK | acaCONCEAL | acaREVERSE) ); *
//* // 8-bit fgnd/bgnd                                                           *
//* this->acComposeAttributes ( 0x22, 0x33, false, false ) ;                     *
//* // RGB fgnd/bgnd                                                             *
//* this->acComposeAttributes ( 0x44, 0x11, true, true ) ;                       *
//********************************************************************************

acAttr acaExpand::compose ( void )
{
   #define DEBUG_compose (0)     // for debugging only

   #if DEBUG_ANSICMD != 0 && DEBUG_LOG != 0 && DEBUG_compose != 0
   if ( ofsdbg.is_open() )
   {
      gsdbg.compose( "compose( acaVal:%08X fgIndex:%02hhX bgIndex:%02hhX "
                     "fgRgb:%hhd bgRgb:%hhd modFlags:%08X )\n" 
                     "          ---r brfc --mods--- --bgnd--- --fgnd---\n"
                     "  acaVal:%#-b ",
                     &this->acaVal, &this->fgIndex, &this->bgIndex, 
                     &this->fgRgb, &this->bgRgb, &this->modFlags, &this->acaVal ) ;
      ofsdbg << gsdbg.ustr() << endl ;
   }
   #endif    // DEBUG_ANSICMD && DEBUG_LOG && DEBUG_compose

   //* Concatenate foreground and background indices. *
   acAttr newVal = acAttr(this->fgIndex | (this->bgIndex << 8)) ;

   if ( this->fgRgb )                  // if RGB foreground
      newVal = acAttr(newVal | acaFG_RGB) ;
   else if ( this->fgDflt )            // default (4-bit) foreground
   {
      newVal = acAttr(newVal | acaFG_DFLT) ;
      newVal = acAttr(newVal & ~acaFG_INDEX) ; // (force to zero index for default)
   }
   if ( this->bgRgb )                  // if RGB background
      newVal = acAttr(newVal | acaBG_RGB) ;
   else if ( this->bgDflt )            // default (4-bit) background
   {
      newVal = acAttr(newVal | acaBG_DFLT) ;
      newVal = acAttr(newVal & ~acaBG_INDEX) ; // (force to zero index for default)
   }

   #if DEBUG_ANSICMD != 0 && DEBUG_LOG != 0 && DEBUG_compose != 0
   if ( ofsdbg.is_open() )
   {
      gsdbg.compose( "  fg/bg :%#-b ", &newVal ) ;
      ofsdbg << gsdbg.ustr() << endl ;
   }
   #endif    // DEBUG_ANSICMD && DEBUG_LOG && DEBUG_compose

   //* If modifier flag(s) set, concatenate them into the new value.  *
   //* Modifiers may be specified using either the 'modFlags' member, *
   //* or by setting the individual modifier flags.                   *
   if ( this->modFlags != acaPLAINTXT)
   { newVal = acAttr(newVal | this->modFlags) ; }
   else
   {
      if ( this->boldMod )    newVal = acAttr(newVal | acaBOLD) ;
      if ( this->italicMod )  newVal = acAttr(newVal | acaITALIC) ;
      if ( this->ulineMod )   newVal = acAttr(newVal | acaUNDERLINE) ;
      if ( this->olineMod )   newVal = acAttr(newVal | acaOVERLINE) ;
      if ( this->xoutMod )    newVal = acAttr(newVal | acaXOUT) ;
      if ( this->blinkMod )   newVal = acAttr(newVal | acaBLINK) ;
      if ( this->invisMod )   newVal = acAttr(newVal | acaCONCEAL) ;
      if ( this->revMod )     newVal = acAttr(newVal | acaREVERSE) ;
   }

   #if DEBUG_ANSICMD != 0 && DEBUG_LOG != 0 && DEBUG_compose != 0
   if ( ofsdbg.is_open() )
   {
      gsdbg.compose( "   mods :%#-b ", &newVal ) ;
      ofsdbg << gsdbg.ustr() << endl ;
   }
   #endif    // DEBUG_ANSICMD && DEBUG_LOG && DEBUG_compose

   //* Re-decode to initialize remaining data members.*
   this->decode ( newVal ) ;

   #if DEBUG_ANSICMD != 0 && DEBUG_LOG != 0 && DEBUG_compose != 0
   if ( ofsdbg.is_open() )
   {
      gsdbg.compose( "  acaVal:%#-b ", &this->acaVal ) ;
      ofsdbg << gsdbg.ustr() << endl ;
   }
   #endif    // DEBUG_ANSICMD && DEBUG_LOG && DEBUG_compose

   return this->acaVal ;

}  //* End compose() *

//*************************
//*          swap         *
//*************************
//********************************************************************************
//* Swap foreground and background attributes.                                   *
//*                                                                              *
//* 1) For indexed color attributes, swap the fg/bg indices.                     *
//*    We COULD just toggle the 'revMod' flag, but this is often visually        *
//*    ineffective due to differences in the system's interpretation of          *
//*    "Bold" vs. "Intense" color attributes.                                    *
//* 2) For RGB color attributes, swap the fg/bg indices.                         *
//* 3) If mixed RGB and indexed attributes, reversing fg/bg is not a simple      *
//*    byte-swap. Like the other configurations, the fg/bg indices are swapped,  *
//*    but in addition, it requires reinitializing a subset of the flags:        *
//*             fgDflt, bgDflt, fgRgb, bgRgb                                     *
//*                                                                              *
//* None of the above scenarios require modification of the text-modifier flags, *
//* which are applied to whatever foreground attribute is selected.              *
//*                                                                              *
//* Input  : none                                                                *
//*                                                                              *
//* Returns: 'true'  if successful, or 'false' if error                          *
//*                  (Note that no error conditions are currently defined.)      *
//********************************************************************************

bool acaExpand::swap ( void )
{
   #define DEBUG_swap (0)        // for debugging only

   bool    status = true ;                // return value

   #if DEBUG_ANSICMD != 0 && DEBUG_LOG != 0 && DEBUG_swap != 0
   gString gsBin ;
   if ( ofsdbg.is_open() )
   { gsBin.compose( "swap( %.B )\n      ", &this->acaVal ) ; }
   #endif   // DEBUG_ANSICMD && DEBUG_LOG && DEBUG_swap

   //* If both fgnd and bgnd are 'web-safe' RGB values, *
   //* swap the indices and re-encode the data.         *
   if ( this->fgRgb && this->bgRgb )
   {
      uint32_t tmpval = this->acaVal & ~(acaFG_INDEX | acaBG_INDEX) ;
      tmpval |= ((this->fgIndex << 8) | this->bgIndex) ;
      this->decode( acAttr(tmpval) ) ;
   }
   //* If both fgnd and bgnd are indexed values (3/4/8-bit indices), *
   //* swap the indices and the flags indicating terminal defaults.  *
   else if ( !this->fgRgb && !this->bgRgb )
   {
      uint32_t tmpval = this->acaVal & ~(acaFG_INDEX | acaBG_INDEX) ;
      tmpval |= ((this->fgIndex << 8) | this->bgIndex) ;
      if ( this->fgDflt != this->bgDflt )
      {
         tmpval &= ~(acaATTR_DFLT) ;
         if ( this->fgDflt ) { tmpval |= acaBG_DFLT ; }
         else                { tmpval |= acaFG_DFLT ; }
      }
      this->decode( acAttr(tmpval) ) ;
   }
   //* Mixed Indexed and RGB attributes. *
   else
   {
      uint32_t tmpval = this->modFlags ;
      uint8_t rgbi, indi ;
      if ( this->fgRgb )                  // foreground attribute is RGB
      {
         rgbi = this->fgIndex ;
         indi = this->bgIndex ;
         tmpval |= ( indi | (rgbi << 8) | acaBG_RGB ) ;
         if ( this->fgDflt ) { tmpval |= acaBG_DFLT ; }
      }
      else                                // background attribute is RGB
      {
         rgbi = this->bgIndex ;
         indi = this->fgIndex ;
         tmpval |= ( rgbi | (indi << 8) | acaFG_RGB ) ;
         if ( this->bgDflt ) { tmpval |= acaFG_DFLT ; }
      }
      this->decode( acAttr(tmpval) ) ;
   }

   #if DEBUG_ANSICMD != 0 && DEBUG_LOG != 0 && DEBUG_swap != 0
   if ( ofsdbg.is_open() )
   { gsBin.append( "%.B", &this->acaVal ) ; ofsdbg << gsBin.ustr() << endl ; }
   #endif   // DEBUG_ANSICMD && DEBUG_LOG && DEBUG_swap

   return status ;

   #undef DEBUG_swap
}  //* End swap() *

//*************************
//*      bits2aeseq       *
//*************************
//********************************************************************************
//* Convert the color index information into a member of enum aeSeq              *
//* corresponding to the ANSI escape sequence for that color attribute.          *
//*                                                                              *
//* Note: If the aeSeq value is one of the 4-bit "bold" foreground attributes,   *
//* the 'boldMod' flag is set. Otherwise the flag is not modified.               *
//*                                                                              *
//* Input  : acaBits  : member of enum acAttr                                    *
//*          byteIndx : byte index value (fg or bg) UNUSED                       *
//*          isFgnd   : 'true'  if foreground target                             *
//*                     'false' if background target                             *
//*          isRgb    : (optional, 'false' by default)                           *
//*                     'true'  if 'acaBits' references one of the web-safe      *
//*                             RGB register indices                             *
//*                     'false' if 'acaBits' is a lookup table index:            *
//*                                0-15 : 4-bit color index                      *
//*                              16-231 : 8-bit color index                      *
//*                             232-255 : greyscale index                        *
//*                                                                              *
//* Returns: member of enum aeSeq                                                *
//********************************************************************************

aeSeq acaExpand::bits2aeseq ( acAttr acaBits, uint8_t byteIndx, bool isFgnd, bool isRgb )
{
   aeSeq aesCmd = aesFG_DFLT ;            // return value

   //* If value specifies one of the web-safe RGB color attributes.*
   if ( isRgb )
   {
      if ( isFgnd )  aesCmd = aesFG_RGB ;    // RGB foreground
      else           aesCmd = aesBG_RGB ;    // RGB background
   }

   //* Else, is a lookup table index *
   else
   {
      //* If 4-bit foreground code *
      if ( isFgnd && ((acaBits == acaFG_DFLT) ||
           ((acaBits >= acaFG_BLACK) && (acaBits <= acaFGb_GREY))) )
      {
         switch ( acaBits )
         {
            case acaFG_BLACK:    aesCmd = aesFG_BLACK ;        break ;
            case acaFG_RED:      aesCmd = aesFG_RED ;          break ;
            case acaFG_GREEN:    aesCmd = aesFG_GREEN ;        break ;
            case acaFG_BROWN:    aesCmd = aesFG_BROWN ;        break ;
            case acaFG_BLUE:     aesCmd = aesFG_BLUE ;         break ;
            case acaFG_MAGENTA:  aesCmd = aesFG_MAGENTA ;      break ;
            case acaFG_CYAN:     aesCmd = aesFG_CYAN ;         break ;
            case acaFG_GREY:     aesCmd = aesFG_GREY ;         break ;

            case acaFGb_BLACK:   aesCmd = aesFGb_BLACK ;       break ;
            case acaFGb_RED:     aesCmd = aesFGb_RED ;         break ;
            case acaFGb_GREEN:   aesCmd = aesFGb_GREEN ;       break ;
            case acaFGb_BROWN:   aesCmd = aesFGb_BROWN ;       break ;
            case acaFGb_BLUE:    aesCmd = aesFGb_BLUE ;        break ;
            case acaFGb_MAGENTA: aesCmd = aesFGb_MAGENTA ;     break ;
            case acaFGb_CYAN:    aesCmd = aesFGb_CYAN ;        break ;
            case acaFGb_GREY:    aesCmd = aesFGb_GREY ;        break ;
            default:             aesCmd = aesFG_DFLT ;         break ;
         } ;
         if ( (aesCmd >= aesFGb_BLACK) && (aesCmd <= aesFGb_GREY) )
            this->boldMod = true ;
      }

      //* If 4-bit background code *
      else if ( !isFgnd && ((acaBits == acaBG_DFLT) ||
                ((acaBits >= acaBG_BLACK) && (acaBits <= acaBGb_GREY))) )
      {
         switch ( acaBits )
         {
            case acaBG_BLACK:    aesCmd = aesBG_BLACK ;        break ;
            case acaBG_RED:      aesCmd = aesBG_RED ;          break ;
            case acaBG_GREEN:    aesCmd = aesBG_GREEN ;        break ;
            case acaBG_BROWN:    aesCmd = aesBG_BROWN ;        break ;
            case acaBG_BLUE:     aesCmd = aesBG_BLUE ;         break ;
            case acaBG_MAGENTA:  aesCmd = aesBG_MAGENTA ;      break ;
            case acaBG_CYAN:     aesCmd = aesBG_CYAN ;         break ;
            case acaBG_GREY:     aesCmd = aesBG_GREY ;         break ;

            case acaBGb_BLACK:   aesCmd = aesBGb_BLACK ;       break ;
            case acaBGb_RED:     aesCmd = aesBGb_RED ;         break ;
            case acaBGb_GREEN:   aesCmd = aesBGb_GREEN ;       break ;
            case acaBGb_BROWN:   aesCmd = aesBGb_BROWN ;       break ;
            case acaBGb_BLUE:    aesCmd = aesBGb_BLUE ;        break ;
            case acaBGb_MAGENTA: aesCmd = aesBGb_MAGENTA ;     break ;
            case acaBGb_CYAN:    aesCmd = aesBGb_CYAN ;        break ;
            case acaBGb_GREY:    aesCmd = aesBGb_GREY ;        break ;
            default:             aesCmd = aesBG_DFLT ;         break ;
         } ;
      }

      //* Else, is a non-RGB 8-bit index code (8-bit color or greyscale) *
      else if ( isFgnd )
         aesCmd = aesFG_INDEX ;         // 8-bit foreground
      else
         aesCmd = aesBG_INDEX ;         // 8-bit background
   }
   return aesCmd ;

}  //* End bits2aeseq() *

//*************************
//*      aeseq2bits       *
//*************************
//********************************************************************************
//* Convert between aeSeq (ANSI escape sequence name) and acAttr (bitfield).     *
//* For named escape sequences only; specifically:                               *
//*   a) 4-bit foreground                                                        *
//*   b) 4-bit background                                                        *
//*   c) text modifier flags                                                     *
//* All other aeSeq values return acaPLAINTXT (i.e. zero).                       *
//*                                                                              *
//* Note: If the aeSeq value is one of the 4-bit "bold" foreground or            *
//*       background attributes, the 'boldMod' flag is set. Otherwise the        *
//*       flag is not modified.                                                  *
//*                                                                              *
//* Input  : aesCmd  : member of enum aeSeq                                      *
//*          setFlag : (by reference) for binary tracking flags, receives        *
//*                    the state for setting/resetting the flag                  *
//*                    'true'  set the target flag                               *
//*                    'false' reset the target flag                             *
//*                    (For non-flag commands, this is always 'false' and )      *
//*                    (should be ignored.                                )      *
//*                                                                              *
//* Returns: member of enum acAttr                                               *
//********************************************************************************

acAttr acaExpand::aeseq2bits ( aeSeq aesCmd, bool& setFlag )
{
   acAttr newBits = acaPLAINTXT ;   // return value (initially ZERO)
   bool handled = true ;            // test control

   setFlag = false ;                // initialize caller's flag

   //* Test for text-modifier commands and indicate *
   //* whether the flag is to be set or reset.      *
   switch ( aesCmd )
   {
      case aesBOLD:
      case aesFAINT:
      case aesBOLD_OFF:
         newBits = acaBOLD ;
         setFlag = aesCmd == aesBOLD_OFF ? false : true ;
         break ;

      case aesITALIC:
      case aesFRACTUR:           // unsupported "fractur" is redirected as italic
      case aesITALIC_OFF:
         newBits = acaITALIC ;
         setFlag = aesCmd == aesITALIC_OFF ? false : true ;
         break ;

      case aesUNDERLINE:
      case aesDBL_UNDERLINE:
      case aesUNDERLINE_OFF:
         newBits = acaUNDERLINE ;
         setFlag = aesCmd == aesUNDERLINE_OFF ? false : true ;
         break ;

      case aesBLINK_SLOW:
      case aesBLINK_FAST:
      case aesBLINK_OFF:
         newBits = acaBLINK ;
         setFlag = aesCmd == aesBLINK_OFF ? false : true ;
         break ;

      case aesREVERSE:
      case aesREVERSE_OFF:
         newBits = acaREVERSE ;
         setFlag = aesCmd == aesREVERSE ? true : false ;
         break ;

      case aesXOUT:
      case aesXOUT_OFF:
         newBits = acaXOUT ;
         setFlag = aesCmd == aesXOUT ? true : false ;
         break ;

      case aesOVERLINE:
      case aesOVERLINE_OFF:
         newBits = acaOVERLINE ;
         setFlag = aesCmd == aesOVERLINE ? true : false ;
         break ;

      case aesCONCEAL:
      case aesCONCEAL_OFF:
         newBits = acaCONCEAL ;
         setFlag = aesCmd == aesCONCEAL ? true : false ;
         break ;

      case aesFRAMED:
      case aesENCIRCLE:
      case aesFRM_ENC_OFF:
         setFlag = aesCmd == aesFRM_ENC_OFF ? false : true ;
         break ;

      default:
         handled = false ;
         break ;
   } ;

   //* If command was not a text modifier, test for  *
   //* 4-bit foreground/background attribute command.*
   if ( ! handled )
   {
      switch ( aesCmd )
      {
         case aesFG_DFLT:     newBits = acaFG_DFLT ;                       break ;
         case aesFG_BLACK:    newBits = acaFG_BLACK ;                      break ;
         case aesFG_RED:      newBits = acaFG_RED ;                        break ;
         case aesFG_GREEN:    newBits = acaFG_GREEN ;                      break ;
         case aesFG_BROWN:    newBits = acaFG_BROWN ;                      break ;
         case aesFG_BLUE:     newBits = acaFG_BLUE ;                       break ;
         case aesFG_MAGENTA:  newBits = acaFG_MAGENTA ;                    break ;
         case aesFG_CYAN:     newBits = acaFG_CYAN ;                       break ;
         case aesFG_GREY:     newBits = acaFG_GREY ;                       break ;
         case aesFGb_BLACK:   newBits = acaFGb_BLACK ;                     break ;
         case aesFGb_RED:     newBits = acaFGb_RED ;                       break ;
         case aesFGb_GREEN:   newBits = acaFGb_GREEN ;                     break ;
         case aesFGb_BROWN:   newBits = acaFGb_BROWN ;                     break ;
         case aesFGb_BLUE:    newBits = acaFGb_BLUE ;                      break ;
         case aesFGb_MAGENTA: newBits = acaFGb_MAGENTA ;                   break ;
         case aesFGb_CYAN:    newBits = acaFGb_CYAN ;                      break ;
         case aesFGb_GREY:    newBits = acaFGb_GREY ;                      break ;

         case aesBG_DFLT:     newBits = acaBG_DFLT ;                       break ;
         case aesBG_BLACK:    newBits = acaBG_BLACK ;                      break ;
         case aesBG_RED:      newBits = acaBG_RED ;                        break ;
         case aesBG_GREEN:    newBits = acaBG_GREEN ;                      break ;
         case aesBG_BROWN:    newBits = acaBG_BROWN ;                      break ;
         case aesBG_BLUE:     newBits = acaBG_BLUE ;                       break ;
         case aesBG_MAGENTA:  newBits = acaBG_MAGENTA ;                    break ;
         case aesBG_CYAN:     newBits = acaBG_CYAN ;                       break ;
         case aesBG_GREY:     newBits = acaBG_GREY ;                       break ;
         case aesBGb_BLACK:   newBits = acaBGb_BLACK ;                     break ;
         case aesBGb_RED:     newBits = acaBGb_RED ;                       break ;
         case aesBGb_GREEN:   newBits = acaBGb_GREEN ;                     break ;
         case aesBGb_BROWN:   newBits = acaBGb_BROWN ;                     break ;
         case aesBGb_BLUE:    newBits = acaBGb_BLUE ;                      break ;
         case aesBGb_MAGENTA: newBits = acaBGb_MAGENTA ;                   break ;
         case aesBGb_CYAN:    newBits = acaBGb_CYAN ;                      break ;
         case aesBGb_GREY:    newBits = acaBGb_GREY ;                      break ;
         default:       // un-handled aeSeq member
            break ;
      } ;
   }

   return newBits ;

}  //* End aeseq2bits() *

//*********************
//*     web2regs      *
//*********************
//********************************************************************************
//* Convert web-safe RGB index into RGB component values.                        *
//* For foreground value, the following are initialized:                         *
//*  fgRgb, fgHue, fgShade, rgbFgR, rgbFgG, rgbFgB, aesFgnd, aesFgType, fgDflt.  *
//* For background value, the following are initialized:                         *
//*  bgRgb, bgHue, bgShade, rgbBgR, rgbBgG, rgbBgB, aesBgnd, aesBgType, bgDflt.  *
//*                                                                              *
//* Note: If webrgb out-of-range, then target members                            *
//*       will default to settings for wsrgbBLACK.                               *
//*                                                                              *
//* Input  : webrgb  : value indicating one of the web-safe RGB register groups  *
//*                    in the range: wsrgbMIN <= webrgb <= wsrgbMAX.             *
//*                    See chart below.                                          *
//*          fgnd    : if true,  'wsrgb' contains foreground data                *
//*                    if false, 'wsrgb' contains background data                *
//*                                                                              *
//* Returns: 'true'  if valid parameters,                                        *
//*          'false' if invalid parameters (defaults used)                       *
//********************************************************************************
//* Specify the value component values representing one of the 216 "web-safe"    *
//* RGB attributes. These include:                                               *
//*  -- "hue" This is one of the eight)8) color groups: black, red, green, blue  *
//*     brown, magenta, cyan and grey.                                           *
//*  -- "shade" This is the gradient within the specified color group. Smaller   *
//*     values of shade result in darker or less intense colors, while larger    *
//*     values result in lighter or more intense colors.                         *
//*  -- R/G/B register values are the indices into the system's 256-element      *
//*     color lookup table.                                                      *
//*                                                                              *
//* The "hue" and "shade" are parameters used to call the ANSI methods:          *
//* acSetWebFg() and acSetWebBg(). The range for these values is define in       *
//* enum WebSafeRGB.                                                             *
//* Because the API-level methods use only the "web-safe" RGB colors, the R/G/B  *
//* register values corresponding to the hue and shade are not actually needed   *
//* within the acaExpand class; however, we record them here in case we decide   *
//* to support the full R/G/B range in a later release.                          *
//*                                                                              *
//*                DARK >>>> LIGHT   CORRESPONDING RGB REGISTER INDICES          *
//* Black        :    0               16;16;16                                   *
//* Red group    :    1      36       22;16;16  >>>>  231;16;16                  *
//* Green group  :   37      72       16;22;16  >>>>  16;231;16                  *
//* Blue group   :   73     108       16;16;22  >>>>  16;16;231                  *
//* Brown group  :  109     144       22;22;16  >>>>  231;231;16                 *
//* Magenta group:  145     180       22;16;22  >>>>  231;16;231                 *
//* Cyan group   :  181     216       16;22;22  >>>>  16;231;231                 *
//* Grey group   :  217     231       22;22;22  >>>>  231;231;231                *
//*                                                                              *
//********************************************************************************

bool acaExpand::web2regs ( uint8_t webrgb, bool fgnd )
{
   bool status = true ;                // return value

   if ( (webrgb < wsrgbMIN) || (webrgb > wsrgbMAX) )  // range check
      webrgb = wsrgbMIN ;
   else
      status = false ;

   //* Initialize the target values.*
   if ( fgnd )    // foreground
   {
      this->fgIndex = webrgb ;
      this->fgRgb = true ;
      this->fgDflt = false ;
      this->aesFgnd = this->aesFgType = aesFG_RGB ;
   }
   else           // background
   {
      this->bgIndex = webrgb ;
      this->bgRgb = true ;
      this->bgDflt = false ;
      this->aesBgnd = this->aesBgType = aesBG_RGB ;
   }

   if ( webrgb == wsrgbBLACK )
   {
      if ( fgnd )    // foreground
      {
         this->rgbFgR = this->rgbFgG = this->rgbFgB = minRGB ;
         this->fgHue = wsrgbBLACK ;
         this->fgShade = wsrgbSHADE_MIN ;
      }
      else           // background
      {
         this->rgbBgR = this->rgbBgG = this->rgbBgB = minRGB ;
         this->bgHue = wsrgbBLACK ;
         this->bgShade = wsrgbSHADE_MIN ;
      }
   }
   else if ( webrgb < wsrgbGREEN )     // RED shades
   {
      if ( fgnd )    // foreground
      {
         this->rgbFgG = this->rgbFgB = minRGB ;
         this->rgbFgR = minRGB + webrgb * wsrgbSTEP ;
         if ( this->rgbFgR > maxRGB ) this->rgbFgR = maxRGB ;
         this->fgHue = wsrgbRED ;
         //* "shade" is the specified index - base color index * 
         this->fgShade = webrgb - wsrgbRED ; 
      }
      else           // background
      {
         this->rgbBgG = this->rgbBgB = minRGB ;
         this->rgbBgR = minRGB + webrgb * wsrgbSTEP ;
         if ( this->rgbBgR > maxRGB ) this->rgbBgR = maxRGB ;
         this->bgHue = wsrgbRED ;
         this->bgShade = webrgb - wsrgbRED ; 
      }
   }
   else if ( webrgb < wsrgbBLUE )      // GREEN shades
   {
      if ( fgnd )    // foreground
      {
         this->rgbFgR = this->rgbFgB = minRGB ;
         this->rgbFgG = minRGB + ((webrgb - wsrgbGREEN + 1) * wsrgbSTEP) ;
         if ( this->rgbFgG > maxRGB ) this->rgbFgG = maxRGB ;
         this->fgHue = wsrgbGREEN ;
         this->fgShade = webrgb - wsrgbGREEN ; 
      }
      else           // background
      {
         this->rgbBgR = this->rgbBgB = minRGB ;
         this->rgbBgG = minRGB + ((webrgb - wsrgbGREEN + 1) * wsrgbSTEP) ;
         if ( this->rgbBgG > maxRGB ) this->rgbBgG = maxRGB ;
         this->bgHue = wsrgbGREEN ;
         this->bgShade = webrgb - wsrgbGREEN ; 
      }
   }
   else if ( webrgb < wsrgbBROWN )     // BLUE shades
   {
      if ( fgnd )    // foreground
      {
         this->rgbFgR = this->rgbFgG = minRGB ;
         this->rgbFgB = minRGB + ((webrgb - wsrgbBLUE + 1) * wsrgbSTEP) ;
         if ( this->rgbFgB > maxRGB ) this->rgbFgB = maxRGB ;
         this->fgHue = wsrgbBLUE ;
         this->fgShade = webrgb - wsrgbBLUE ; 
      }
      else           // background
      {
         this->rgbBgR = this->rgbBgG = minRGB ;
         this->rgbBgB = minRGB + ((webrgb - wsrgbBLUE + 1) * wsrgbSTEP) ;
         if ( this->rgbBgB > maxRGB ) this->rgbBgB = maxRGB ;
         this->bgHue = wsrgbBLUE ;
         this->bgShade = webrgb - wsrgbBLUE ; 
      }
   }
   else if ( webrgb < wsrgbMAGENTA )   // BROWN shades
   {
      if ( fgnd )    // foreground
      {
         this->rgbFgB = minRGB ;
         this->rgbFgR = this->rgbFgG = 
                              minRGB + ((webrgb - wsrgbBROWN + 1) * wsrgbSTEP) ;
         if ( this->rgbFgR > maxRGB )
            this->rgbFgR = this->rgbFgG = maxRGB ;
         this->fgHue = wsrgbBROWN ;
         this->fgShade = webrgb - wsrgbBROWN ;
      }
      else           // background
      {
         this->rgbBgB = minRGB ;
         this->rgbBgR = this->rgbBgG = 
                              minRGB + ((webrgb - wsrgbBROWN + 1) * wsrgbSTEP) ;
         if ( this->rgbBgR > maxRGB )
            this->rgbBgR = this->rgbBgG = maxRGB ;
         this->bgHue = wsrgbBROWN ;
         this->bgShade = webrgb - wsrgbBROWN ; 
      }
   }
   else if ( webrgb < wsrgbCYAN )      // MAGENTA shades
   {
      if ( fgnd )    // foreground
      {
         this->rgbFgG = minRGB ;
         this->rgbFgR = this->rgbFgB = 
                              minRGB + ((webrgb - wsrgbMAGENTA + 1) * wsrgbSTEP) ;
         if ( this->rgbFgR > maxRGB )
            this->rgbFgR = this->rgbFgB = maxRGB ;
         this->fgHue = wsrgbMAGENTA ;
         this->fgShade = webrgb - wsrgbMAGENTA ; 
      }
      else           // background
      {
         this->rgbBgG = minRGB ;
         this->rgbBgR = this->rgbBgB = 
                              minRGB + ((webrgb - wsrgbMAGENTA + 1) * wsrgbSTEP) ;
         if ( this->rgbBgR > maxRGB )
            this->rgbBgR = this->rgbBgB = maxRGB ;
         this->bgHue = wsrgbMAGENTA ;
         this->bgShade = webrgb - wsrgbMAGENTA ; 
      }
   }
   else if ( webrgb < wsrgbGREY )      // CYAN shades
   {
      if ( fgnd )    // foreground
      {
         this->rgbFgR = minRGB ;
         this->rgbFgG = this->rgbFgB = 
                              minRGB + ((webrgb - wsrgbCYAN + 1) * wsrgbSTEP) ;
         if ( this->rgbFgG > maxRGB )
            this->rgbFgG = this->rgbFgB = maxRGB ;
         this->fgHue = wsrgbCYAN ;
         this->fgShade = webrgb - wsrgbCYAN ; 
      }
      else           // background
      {
         this->rgbBgR = minRGB ;
         this->rgbBgG = this->rgbBgB = 
                              minRGB + ((webrgb - wsrgbCYAN + 1) * wsrgbSTEP) ;
         if ( this->rgbBgG > maxRGB )
            this->rgbBgG = this->rgbBgB = maxRGB ;
         this->bgHue = wsrgbCYAN ;
         this->bgShade = webrgb - wsrgbCYAN ; 
      }
   }
   else if ( webrgb <= wsrgbMAX )      // GREYSCALE group
   {
      if ( fgnd )    // foreground
      {
         this->rgbFgR = this->rgbFgG = this->rgbFgB = 
                              minRGB + ((webrgb - wsrgbGREY + 1) * wsrgbSTEP) ;
         if ( this->rgbFgR > maxRGB )
            this->rgbFgR = this->rgbFgG = this->rgbFgB = maxRGB ;
         this->fgHue = wsrgbGREY ;
         this->fgShade = webrgb - wsrgbGREY ; 
      }
      else           // background
      {
         this->rgbBgR = this->rgbBgG = this->rgbBgB = 
                              minRGB + ((webrgb - wsrgbGREY + 1) * wsrgbSTEP) ;
         if ( this->rgbBgR > maxRGB )
            this->rgbBgR = this->rgbBgG = this->rgbBgB = maxRGB ;
         this->bgHue = wsrgbGREY ;
         this->bgShade = webrgb - wsrgbGREY ; 
      }
   }
   return status ;

}  //* End web2regs() *

//*************************
//*       buildRgb        *
//*************************
//********************************************************************************
//* Construct an acAttr bitfield from web-safe RGB color indices.                *
//* Specify RGB values for foreground and/or background color attributes.        *
//* The values are members of enum WebSafeRGB which encode the RGB 'hue' and     *
//* 'shade' used to initialize the Red/Green/Blue register values.               *
//*                                                                              *
//* The constructed value may then be used as a parameter for initializing an    *
//* acaExpand object. Example:                                                   *
//* Example: Construct a bitfield for a medium Red foreground and                *
//*          dark Blue background.                                               *
//*   acaExpand aca ;                                                            *
//*   acAttr newVal =                                                            *
//*             aca.buildRgbVal ( true, WebSafeRGB(wsrgbRED + wsrgbSHADE_MED),   *
//*                               true, wsrgbBLUE );                             *
//*   aca.decode( newVal );                                                      *
//*                                                                              *
//* Example: Construct a bitfield for a bright Cyan background, with             *
//*          a standard 4-bit (non-RGB) blue foreground.                         *
//*   acaExpand aca ;                                                            *
//*   acAttr newVal =                                                            *
//*            aca.buildRgbVal ( false, wsrgbMIN,                                *
//*                              true, WebSafeRGB(wsrgbCYAN + wsrgbSHADES - 1) );*
//*   newVal = acAttr(newVal | acaFG_BLUE);                                      *
//*   aca.decode( newVal );                                                      *
//*                                                                              *
//*  (See AnsiCmd documentation for additional examples.)                        *
//*                                                                              *
//*                                                                              *
//* Input  : fg    : 'true'  if foreground value specified in 'fgVal'            *
//*                  'false' if 'fgVal' is to be ignored                         *
//*          fgVal : member of enum WebSafeRGB                                   *
//*                  if 'fg' flag is set, web-safe RGB foreground value          *
//*                  if 'fg' flag is reset, this value is ignored                *
//*          bg     : (optional, 'false' by default)                             *
//*                   'true'  if background value specified in 'bgIndx'          *
//*                   'false' if 'bgIndx' is to be ignored                       *
//*          bgVal : (optional, wsrgbMIN by default) member of enum WebSafeRGB   *
//*                  if 'bg' flag is set, web-safe RGB background value          *
//*                  if 'bg' flag is reset, this value is ignored                *
//*                        and background bits are initialized as reset          *
//*                                                                              *
//* Returns: the constructed acAttr bitfield                                     *
//*          if one or more parameters out-of-range, acaATTR_DFLT is returned    *
//********************************************************************************

acAttr acaExpand::buildRgb ( bool fg, WebSafeRGB fgVal, bool bg, WebSafeRGB bgVal ) const
{
   #define DEBUG_buildRgb (0)    // for debugging only

   acAttr newVal = acAttr(ZERO) ;         // return value
   bool   valid = true ;                  // set if valid parameters

   #if DEBUG_ANSICMD != 0 && DEBUG_LOG != 0 && DEBUG_buildRgb != 0
   if ( ofsdbg.is_open() )
   { gsdbg.compose( "buildRgb( %hhd %02hX %hhu %02hX )  ", &fg, &fgVal, &bg, &bgVal ) ; }
   #endif   // DEBUG_ANSICMD && DEBUG_LOG && DEBUG_buildRgb

   if ( fg )
   {
      if ( (fgVal >= wsrgbMIN) && (fgVal <= wsrgbMAX) )
         newVal = acAttr(fgVal | acaFG_RGB) ;
      else
         valid = false ;
   }

   if ( valid && bg )
   {
      if ( (bgVal >= wsrgbMIN) && (bgVal <= wsrgbMAX) )
         newVal = acAttr(newVal | (bgVal << 8) | acaBG_RGB) ;
      else
         valid = false ;
   }

   if ( ! valid ) { newVal = acaATTR_DFLT ; }   // if parameter out-of-range

   #if DEBUG_ANSICMD != 0 && DEBUG_LOG != 0 && DEBUG_buildRgb != 0
   if ( ofsdbg.is_open() )
   {
      gString gsBin ;                           // format binary bitfield
      gsBin.compose( L"'% B'", &newVal ) ;

      // Programmer's Note: This is fancy and completely unnecessary (but fun).
      short i = gsBin.findlast ( wcsSPACE ) ;   // concatenate the 8 fg bits
      gsBin.erase( i, 1 ) ;
      i = gsBin.findlast ( wcsSPACE ) ;         // concatenate the 8 bg bits
      gsBin.replace( wcsSPACE, DASH, i ) ;
      i = gsBin.findlast ( wcsSPACE ) ;         // concatenate the 8 bg bits
      gsBin.erase( i, 1 ) ;

      gsdbg.append( gsBin.gstr() ) ;
      ofsdbg << gsdbg.ustr() << endl ;
   }
   #endif   // DEBUG_ANSICMD && DEBUG_LOG && DEBUG_buildRgb

   return newVal ;

   #undef DEBUG_buildRgb
}  //* End buildRgb() *

//*************************
//*       build8Bit       *
//*************************
//********************************************************************************
//* Construct an acAttr bitfield from 8-bit color indices.                       *
//* Specify 8-bit values for foreground and/or background color attributes.      *
//* The parameters are any 8-bit value between min8BIT and max8BIT, inclusive.   *
//*                                                                              *
//* As an example, construct attributes to approximate the GNOME Terminal's      *
//* default attributes of black text on an off-white background:                 *
//*      acaExpand acax ;                                                        *
//*      acax.build8Bit( true, min8BIT, true, max8BIT ) ;                        *
//*                                                                              *
//*                                                                              *
//* Input  : fg    : 'true'  if foreground value specified in 'fgVal'            *
//*                  'false' if 'fgVal' is to be ignored                         *
//*          fgVal : index of foreground attribute, range: min8BIT - max8BIT     *
//*                  if 'fg' flag is set, calculate foreground bitfield          *
//*                  if 'fg' flag is reset, this value is ignored                *
//*                          and foreground bits are initialized as reset        *
//*          bg     : (optional, 'false' by default)                             *
//*                   'true'  if background value specified in 'bgVal'           *
//*                   'false' if 'bgVal' is to be ignored                        *
//*          bgVal : (optional, min8BIT by default)                              *
//*                  index of background attribute, range: min8BIT - max8BIT     *
//*                  if 'bg' flag is set, calculate background bitfield          *
//*                  if 'bg' flag is reset, this value is ignored                *
//*                          and background bits are initialized as reset        *
//*                                                                              *
//* Returns: the constructed acAttr bitfield                                     *
//********************************************************************************

acAttr acaExpand::build8Bit ( bool fg, uint8_t fgVal, bool bg, uint8_t bgVal ) const
{
   #define DEBUG_build8bit (0)   // for debugging only

   acAttr newVal = acAttr(ZERO) ;         // return value
   bool   valid = true ;                  // set if valid parameters

   #if DEBUG_ANSICMD != 0 && DEBUG_LOG != 0 && DEBUG_build8bit != 0
   if ( ofsdbg.is_open() )
   { gsdbg.compose( "build8Bit( %hhd %02hX %hhu %02hX )  ", &fg, &fgVal, &bg, &bgVal ) ; }
   #endif   // DEBUG_ANSICMD && DEBUG_LOG && DEBUG_build8bit

   if ( fg )
   {
      if ( (fgVal >= min8BIT) && (fgVal <= max8BIT) )
         newVal = acAttr(fgVal) ;
      else
         valid = false ;
   }

   if ( valid && bg )
   {
      if ( (bgVal >= min8BIT) && (bgVal <= max8BIT) )
         newVal = acAttr(newVal | (bgVal << 8)) ;
      else
         valid = false ;
   }

   if ( ! valid ) { newVal = acaATTR_DFLT ; }   // if parameter out-of-range


   #if DEBUG_ANSICMD != 0 && DEBUG_LOG != 0 && DEBUG_build8bit != 0
   if ( ofsdbg.is_open() )
   {
      gString gsBin ;                           // format binary bitfield
      gsBin.compose( L"'% B'", &newVal ) ;

      // Programmer's Note: This is fancy and completely unnecessary (but fun).
      short i = gsBin.findlast ( wcsSPACE ) ;   // concatenate the 8 fg bits
      gsBin.erase( i, 1 ) ;
      i = gsBin.findlast ( wcsSPACE ) ;         // concatenate the 8 bg bits
      gsBin.replace( wcsSPACE, DASH, i ) ;
      i = gsBin.findlast ( wcsSPACE ) ;         // concatenate the 8 bg bits
      gsBin.erase( i, 1 ) ;

      gsdbg.append( gsBin.gstr() ) ;
      ofsdbg << gsdbg.ustr() << endl ;
   }
   #endif   // DEBUG_ANSICMD && DEBUG_LOG && DEBUG_build8bit

   return newVal ;

   #undef DEBUG_build8bit
}  //* End build8Bit() *

//*********************
//*       reset       *
//*********************
//********************************************************************************
//* Reset (clear) all data members (or text-modifier flags only).                *
//*                                                                              *
//* 1) All data members:                                                         *
//*    The new settings will reflect terminal-default foreground and background  *
//*    attributes with no text modifiers.                                        *
//* 2) Text modifiers only:                                                      *
//*    All text-modifier flags will be reset, and other data will be unchanged.  *
//*                                                                              *
//* Input  : modsOnly : (optional, 'false' by default)                           *
//*                     if 'false', reset all data members                       *
//*                     if 'true',  reset text-modifier flags only               *
//*                                                                              *
//* Returns: nothing                                                             *
//********************************************************************************

void acaExpand::reset ( bool modsOnly )
{
   acAttr newBits ;

   if ( modsOnly )
      newBits = acAttr(this->acaVal & ~(acaMOD_MASK)) ;
   
   //* Reset all members to default fgnd/bgnd with no modifiers *
   else
      newBits = acaATTR_DFLT ;

   this->decode ( newBits ) ;

}  //* End reset() *

//*************************
//*                       *
//*************************
//********************************************************************************
//*                                                                              *
//*                                                                              *
//*                                                                              *
//* Input  :                                                                     *
//*                                                                              *
//* Returns:                                                                     *
//********************************************************************************

