/***************************************************************************
 *                                                                         *
 *   ENCTVB.CPP                                                            *
 *                                                                         *
 *   Copyright (c) 1998       Galacticomm, Inc.    All Rights Reserved.    *
 *                                                                         *
 *   Active HTML Encoded Text Variable Classes                             *
 *   Implementation                                                        *
 *                                                                         *
 *                                                - Phil Henning 8/20/98   *
 *                                                                         *
 ***************************************************************************/

#include "gcomm.h"
#include "majorbbs.h"
#include "enctvb.h"
#include <strstrea.h>

#define FILREV "$Revision: 13 $"

#define MAXTRLEN 16

typedef struct tagTransTable {
     CHAR ch;
     CHAR dest[MAXTRLEN];
} TRANSTABLE, *pTRANSTABLE;

MARKSOURCE(enctvb);

#define URLPRELEN 10
struct urlpairs {
     CHAR text[URLPRELEN];
     INT  idx;
};

#define NBSPELEM "&nbsp;"          // HTML code for no-space
#define HTTPELEM "http://"         // http request prefix

enum {URL_HTTP, URL_TELNET, URL_FTP, URL_GOPHER, URL_WAIS, URL_TN3270
     ,URL_MAILTO, URL_NEWS, URL_FILE, URL_WWW};

//
// basicTvb Definitions
//

basicTvb::basicTvb(
CHAR const * pszName) : tvbDefinition(pszName)
                      , m_pValue("")
                      , m_Changed(true)
{
     registerDef();
}


basicTvb::~basicTvb()
{
}

CHAR const *                            //   text to output
basicTvb::resolve(                      // resolve text variable
CHAR const *)                           //   text variable name
{
     if (m_pValue.length() > 0)  {
          m_Changed=false;
          return(m_pValue.c_str());
     }
     return("");
}

string const
basicTvb::str() const                   // get value of tvb as a string
{
     return(m_pValue);
}


CHAR const *
basicTvb::get() const                   // get value of tvb
{
     return(m_pValue.c_str());
}

string&
basicTvb::remove(                       // remove characters from string
size_t pos)                             // starting here
{
     m_Changed=true;
     return(m_pValue.remove(pos));
}

string&
basicTvb::remove(                       // remove characters from string
size_t pos,                             // starting here
size_t n)                               // this many characters
{
     m_Changed=true;
     return(m_pValue.remove(pos,n));
}

size_t
basicTvb::length() const                // get length of the string
{
     return(m_pValue.length());
}


// CHAR const * concat/assign functions

VOID
basicTvb::Concat(
CHAR const * stg)
{
     m_pValue+=stg;
     m_Changed=true;
}

VOID
basicTvb::Assign(
CHAR const * stg)
{
     m_pValue=stg;
     m_Changed=true;
}

// CHAR concat/assign functions

VOID
basicTvb::Concat(
CHAR ch)
{
     m_pValue+=ch;
     m_Changed=true;
}

VOID
basicTvb::Assign(
CHAR ch)
{
     m_pValue=ch;
     m_Changed=true;
}

// string concat/assign functions

VOID
basicTvb::Concat(
string const & str)
{
     m_pValue+=str;
     m_Changed=true;
}

VOID
basicTvb::Assign(
string const & str)
{
     m_pValue=str;
     m_Changed=true;
}

// LONG concat/assign functions

VOID
basicTvb::Concat(
LONG num)
{
     ostrstream ost;
     ost << num << ends;
     *this+=ost.str();
     ost.rdbuf()->freeze(0);
}

VOID
basicTvb::Assign(
LONG num)
{
     ostrstream ost;
     ost << num << ends;
     *this=ost.str();
     ost.rdbuf()->freeze(0);
}

// ULONG concat/assign functions

VOID
basicTvb::Concat(
ULONG num)
{
     ostrstream ost;
     ost << num << ends;
     *this+=ost.str();
     ost.rdbuf()->freeze(0);
}

VOID
basicTvb::Assign(
ULONG num)
{
     ostrstream ost;
     ost << num << ends;
     *this=ost.str();
     ost.rdbuf()->freeze(0);
}

// INT concat/assign functions

VOID
basicTvb::Concat(
INT num)
{
     ostrstream ost;
     ost << num << ends;
     *this+=ost.str();
     ost.rdbuf()->freeze(0);
}

VOID
basicTvb::Assign(
INT num)
{
     ostrstream ost;
     ost << num << ends;
     *this=ost.str();
     ost.rdbuf()->freeze(0);
}

// UINT concat/assign functions

VOID
basicTvb::Concat(
UINT num)
{
     ostrstream ost;
     ost << num << ends;
     *this+=ost.str();
     ost.rdbuf()->freeze(0);
}

VOID
basicTvb::Assign(
UINT num)
{
     ostrstream ost;
     ost << num << ends;
     *this=ost.str();
     ost.rdbuf()->freeze(0);
}

// SHORT concat/assign functions

VOID
basicTvb::Concat(
SHORT num)
{
     ostrstream ost;
     ost << num << ends;
     *this+=ost.str();
     ost.rdbuf()->freeze(0);
}

VOID
basicTvb::Assign(
SHORT num)
{
     ostrstream ost;
     ost << num << ends;
     *this=ost.str();
     ost.rdbuf()->freeze(0);
}

// USHORT concat/assign functions

VOID
basicTvb::Concat(
USHORT num)
{
     ostrstream ost;
     ost << num << ends;
     *this+=ost.str();
     ost.rdbuf()->freeze(0);
}

VOID
basicTvb::Assign(
USHORT num)
{
     ostrstream ost;
     ost << num << ends;
     *this=ost.str();
     ost.rdbuf()->freeze(0);
}

// DOUBLE concat/assign functions

VOID
basicTvb::Concat(
double num)
{
     ostrstream ost;
     ost << num << ends;
     *this+=ost.str();
     ost.rdbuf()->freeze(0);
}

VOID
basicTvb::Assign(
double num)
{
     ostrstream ost;
     ost << num << ends;
     *this=ost.str();
     ost.rdbuf()->freeze(0);
}

// assignment operators

basicTvb&
basicTvb::operator= (CHAR const * stg)
{
     Assign(stg);
     return(*this);
}

basicTvb&
basicTvb::operator+= (CHAR const * stg)
{
     Concat(stg);
     return(*this);
}

basicTvb&
basicTvb::operator= (CHAR ch)
{
     Assign(ch);
     return(*this);
}

basicTvb&
basicTvb::operator+= (CHAR ch)
{
     Concat(ch);
     return(*this);
}

basicTvb&
basicTvb::operator= (string const & str)
{
     Assign(str);
     return(*this);
}

basicTvb&
basicTvb::operator+= (string const & str)
{
     Concat(str);
     return(*this);
}

basicTvb&
basicTvb::operator= (LONG num)
{
     Assign(num);
     return(*this);
}

basicTvb&
basicTvb::operator+= (LONG num)
{
     Concat(num);
     return(*this);
}

basicTvb&
basicTvb::operator= (ULONG num)
{
     Assign(num);
     return(*this);
}

basicTvb&
basicTvb::operator+= (ULONG num)
{
     Concat(num);
     return(*this);
}

basicTvb&
basicTvb::operator= (INT num)
{
     Assign(num);
     return(*this);
}

basicTvb&
basicTvb::operator+= (INT num)
{
     Concat(num);
     return(*this);
}

basicTvb&
basicTvb::operator= (UINT num)
{
     Assign(num);
     return(*this);
}

basicTvb&
basicTvb::operator+= (UINT num)
{
     Concat(num);
     return(*this);
}

basicTvb&
basicTvb::operator= (SHORT num)
{
     Assign(num);
     return(*this);
}

basicTvb&
basicTvb::operator+= (SHORT num)
{
     Concat(num);
     return(*this);
}

basicTvb&
basicTvb::operator= (USHORT num)
{
     Assign(num);
     return(*this);
}

basicTvb&
basicTvb::operator+= (USHORT num)
{
     Concat(num);
     return(*this);
}

basicTvb&
basicTvb::operator= (double num)
{
     Assign(num);
     return(*this);
}

basicTvb&
basicTvb::operator+= (double num)
{
     Concat(num);
     return(*this);
}

basicTvb&
basicTvb::operator= (basicTvb const & rhs)
{
     m_pValue=rhs.get();
     m_Changed=true;
     return(*this);
}

basicTvb&
basicTvb::operator+= (basicTvb const & rhs)
{
     m_pValue+=rhs.get();
     m_Changed=true;
     return(*this);
}


//
// encodedTvb definitions
//

encodedTvb::encodedTvb(
CHAR const * pszName) : basicTvb(pszName)
                      , m_pEncodedString(NULL)
                      , m_doencode(true)
{
     m_pEncodedString=new string("");
}


encodedTvb::~encodedTvb()
{
     if (m_pEncodedString != NULL) {
          delete m_pEncodedString;
     }
}

VOID
encodedTvb::toggleEncode(               // toggle encoding on/off
bool enc)
{
     m_doencode=enc;
     m_Changed=true;
}

CHAR const *                            //   text to output
encodedTvb::resolve(                    // resolve tvb
CHAR const *)                           //   name of tvb
{
     if (m_pValue.length() > 0) {
          if (m_Changed) {
               m_Changed=false;
               // call derived encoding method
               return(encode());
          }
          return(m_pEncodedString->c_str());
     }
     return("");
}

//
// htmlEncodedTvb definitions
//

htmlEncodedTvb::htmlEncodedTvb(
CHAR const * pszName) : encodedTvb(pszName)
{
}

htmlEncodedTvb::~htmlEncodedTvb()
{
}


CHAR const *
htmlEncodedTvb::encode()                // encoding method
{
     if (m_doencode) {
          *m_pEncodedString=::htmlEncode(m_pValue);
     }
     else {
          *m_pEncodedString=(m_pValue);
      }
     return(m_pEncodedString->c_str());
}

// assignment operators

htmlEncodedTvb&
htmlEncodedTvb::operator= (CHAR const * stg)
{
     Assign(stg);
     return(*this);
}

htmlEncodedTvb&
htmlEncodedTvb::operator+= (CHAR const * stg)
{
     Concat(stg);
     return(*this);
}

htmlEncodedTvb&
htmlEncodedTvb::operator= (CHAR ch)
{
     Assign(ch);
     return(*this);
}

htmlEncodedTvb&
htmlEncodedTvb::operator+= (CHAR ch)
{
     Concat(ch);
     return(*this);
}

htmlEncodedTvb&
htmlEncodedTvb::operator= (string const & str)
{
     Assign(str);
     return(*this);
}

htmlEncodedTvb&
htmlEncodedTvb::operator+= (string const & str)
{
     Concat(str);
     return(*this);
}

htmlEncodedTvb&
htmlEncodedTvb::operator= (LONG num)
{
     Assign(num);
     return(*this);
}

htmlEncodedTvb&
htmlEncodedTvb::operator+= (LONG num)
{
     Concat(num);
     return(*this);
}

htmlEncodedTvb&
htmlEncodedTvb::operator= (ULONG num)
{
     Assign(num);
     return(*this);
}

htmlEncodedTvb&
htmlEncodedTvb::operator+= (ULONG num)
{
     Concat(num);
     return(*this);
}

htmlEncodedTvb&
htmlEncodedTvb::operator= (INT num)
{
     Assign(num);
     return(*this);
}

htmlEncodedTvb&
htmlEncodedTvb::operator+= (INT num)
{
     Concat(num);
     return(*this);
}

htmlEncodedTvb&
htmlEncodedTvb::operator= (UINT num)
{
     Assign(num);
     return(*this);
}

htmlEncodedTvb&
htmlEncodedTvb::operator+= (UINT num)
{
     Concat(num);
     return(*this);
}

htmlEncodedTvb&
htmlEncodedTvb::operator= (SHORT num)
{
     Assign(num);
     return(*this);
}

htmlEncodedTvb&
htmlEncodedTvb::operator+= (SHORT num)
{
     Concat(num);
     return(*this);
}

htmlEncodedTvb&
htmlEncodedTvb::operator= (USHORT num)
{
     Assign(num);
     return(*this);
}

htmlEncodedTvb&
htmlEncodedTvb::operator+= (USHORT num)
{
     Concat(num);
     return(*this);
}

htmlEncodedTvb&
htmlEncodedTvb::operator= (double num)
{
     Assign(num);
     return(*this);
}

htmlEncodedTvb&
htmlEncodedTvb::operator+= (double num)
{
     Concat(num);
     return(*this);
}

htmlEncodedTvb&
htmlEncodedTvb::operator= (basicTvb const & rhs)
{
     m_pValue=rhs.get();
     m_Changed=true;
     return(*this);
}

htmlEncodedTvb&
htmlEncodedTvb::operator+= (basicTvb const & rhs)
{
     m_pValue+=rhs.get();
     m_Changed=true;
     return(*this);
}


//
// urlEncodedTvb definitions
//

urlEncodedTvb::urlEncodedTvb(
CHAR const * pszName) : encodedTvb(pszName)
{
}

urlEncodedTvb::~urlEncodedTvb()
{
}

CHAR const *
urlEncodedTvb::encode()               // encoding method
{
     if (m_doencode) {
          *m_pEncodedString=::urlEncode(m_pValue);
     }
     else {
          *m_pEncodedString=(m_pValue);
     }
     return(m_pEncodedString->c_str());
}

// assingment operators

urlEncodedTvb&
urlEncodedTvb::operator= (CHAR const * stg)
{
     Assign(stg);
     return(*this);
}

urlEncodedTvb&
urlEncodedTvb::operator+= (CHAR const * stg)
{
     Concat(stg);
     return(*this);
}

urlEncodedTvb&
urlEncodedTvb::operator= (CHAR ch)
{
     Assign(ch);
     return(*this);
}

urlEncodedTvb&
urlEncodedTvb::operator+= (CHAR ch)
{
     Concat(ch);
     return(*this);
}

urlEncodedTvb&
urlEncodedTvb::operator= (string const & str)
{
     Assign(str);
     return(*this);
}

urlEncodedTvb&
urlEncodedTvb::operator+= (string const & str)
{
     Concat(str);
     return(*this);
}

urlEncodedTvb&
urlEncodedTvb::operator= (LONG num)
{
     Assign(num);
     return(*this);
}

urlEncodedTvb&
urlEncodedTvb::operator+= (LONG num)
{
     Concat(num);
     return(*this);
}

urlEncodedTvb&
urlEncodedTvb::operator= (ULONG num)
{
     Assign(num);
     return(*this);
}

urlEncodedTvb&
urlEncodedTvb::operator+= (ULONG num)
{
     Concat(num);
     return(*this);
}

urlEncodedTvb&
urlEncodedTvb::operator= (INT num)
{
     Assign(num);
     return(*this);
}

urlEncodedTvb&
urlEncodedTvb::operator+= (INT num)
{
     Concat(num);
     return(*this);
}

urlEncodedTvb&
urlEncodedTvb::operator= (UINT num)
{
     Assign(num);
     return(*this);
}

urlEncodedTvb&
urlEncodedTvb::operator+= (UINT num)
{
     Concat(num);
     return(*this);
}

urlEncodedTvb&
urlEncodedTvb::operator= (SHORT num)
{
     Assign(num);
     return(*this);
}

urlEncodedTvb&
urlEncodedTvb::operator+= (SHORT num)
{
     Concat(num);
     return(*this);
}

urlEncodedTvb&
urlEncodedTvb::operator= (USHORT num)
{
     Assign(num);
     return(*this);
}

urlEncodedTvb&
urlEncodedTvb::operator+= (USHORT num)
{
     Concat(num);
     return(*this);
}

urlEncodedTvb&
urlEncodedTvb::operator= (double num)
{
     Assign(num);
     return(*this);
}

urlEncodedTvb&
urlEncodedTvb::operator+= (double num)
{
     Concat(num);
     return(*this);
}

urlEncodedTvb&
urlEncodedTvb::operator= (basicTvb const & rhs)
{
     m_pValue=rhs.get();
     m_Changed=true;
     return(*this);
}

urlEncodedTvb&
urlEncodedTvb::operator+= (basicTvb const & rhs)
{
     m_pValue+=rhs.get();
     m_Changed=true;
     return(*this);
}

//
// linkedHtmlEncodedTvb definitions
//

linkedHtmlEncodedTvb::linkedHtmlEncodedTvb(
CHAR const * pszName,
CHAR const * pszAnchor) : htmlEncodedTvb(pszName)
                        , m_dolink(true)

{
     ASSERT(pszAnchor != NULL);
     m_Anchor=pszAnchor;
}

linkedHtmlEncodedTvb::~linkedHtmlEncodedTvb()
{
}

VOID
linkedHtmlEncodedTvb::toggleLink(       // toggle URL linking
bool link)
{
     m_dolink=link;
     m_Changed=true;
}

CHAR const *
linkedHtmlEncodedTvb::encode()          // encoding method
{
     string tmpstg=htmlEncodedTvb::encode();
     if (m_dolink)  {
          *m_pEncodedString=linkURLs(tmpstg,m_Anchor);
     }
     return(m_pEncodedString->c_str());
}

// assignment operators

linkedHtmlEncodedTvb&
linkedHtmlEncodedTvb::operator= (CHAR const * stg)
{
     Assign(stg);
     return(*this);
}

linkedHtmlEncodedTvb&
linkedHtmlEncodedTvb::operator+= (CHAR const * stg)
{
     Concat(stg);
     return(*this);
}

linkedHtmlEncodedTvb&
linkedHtmlEncodedTvb::operator= (CHAR ch)
{
     Assign(ch);
     return(*this);
}

linkedHtmlEncodedTvb&
linkedHtmlEncodedTvb::operator+= (CHAR ch)
{
     Concat(ch);
     return(*this);
}

linkedHtmlEncodedTvb&
linkedHtmlEncodedTvb::operator= (string const & str)
{
     Assign(str);
     return(*this);
}

linkedHtmlEncodedTvb&
linkedHtmlEncodedTvb::operator+= (string const & str)
{
     Concat(str);
     return(*this);
}

linkedHtmlEncodedTvb&
linkedHtmlEncodedTvb::operator= (LONG num)
{
     Assign(num);
     return(*this);
}

linkedHtmlEncodedTvb&
linkedHtmlEncodedTvb::operator+= (LONG num)
{
     Concat(num);
     return(*this);
}

linkedHtmlEncodedTvb&
linkedHtmlEncodedTvb::operator= (ULONG num)
{
     Assign(num);
     return(*this);
}

linkedHtmlEncodedTvb&
linkedHtmlEncodedTvb::operator+= (ULONG num)
{
     Concat(num);
     return(*this);
}

linkedHtmlEncodedTvb&
linkedHtmlEncodedTvb::operator= (INT num)
{
     Assign(num);
     return(*this);
}

linkedHtmlEncodedTvb&
linkedHtmlEncodedTvb::operator+= (INT num)
{
     Concat(num);
     return(*this);
}

linkedHtmlEncodedTvb&
linkedHtmlEncodedTvb::operator= (UINT num)
{
     Assign(num);
     return(*this);
}

linkedHtmlEncodedTvb&
linkedHtmlEncodedTvb::operator+= (UINT num)
{
     Concat(num);
     return(*this);
}

linkedHtmlEncodedTvb&
linkedHtmlEncodedTvb::operator= (SHORT num)
{
     Assign(num);
     return(*this);
}

linkedHtmlEncodedTvb&
linkedHtmlEncodedTvb::operator+= (SHORT num)
{
     Concat(num);
     return(*this);
}

linkedHtmlEncodedTvb&
linkedHtmlEncodedTvb::operator= (USHORT num)
{
     Assign(num);
     return(*this);
}

linkedHtmlEncodedTvb&
linkedHtmlEncodedTvb::operator+= (USHORT num)
{
     Concat(num);
     return(*this);
}

linkedHtmlEncodedTvb&
linkedHtmlEncodedTvb::operator= (double num)
{
     Assign(num);
     return(*this);
}

linkedHtmlEncodedTvb&
linkedHtmlEncodedTvb::operator+= (double num)
{
     Concat(num);
     return(*this);
}

linkedHtmlEncodedTvb&
linkedHtmlEncodedTvb::operator= (basicTvb const & rhs)
{
     m_pValue=rhs.get();
     m_Changed=true;
     return(*this);
}

linkedHtmlEncodedTvb&
linkedHtmlEncodedTvb::operator+= (basicTvb const & rhs)
{
     m_pValue+=rhs.get();
     m_Changed=true;
     return(*this);
}


//
// global functions
//

string                             //   new, encoded string
htmlEncode(                             // html encode a string
string const & str)                //   string to encode
{
     static TRANSTABLE g_htmlTable[]={
          {'<',"&lt;"},
          {'>',"&gt;"},
          {'&',"&amp;"},
          {'\"',"&quot;"},
          {'\'',"&#39;"},
          {'\0',""}
     };

     string dest("");
     CHAR const * ptr=str.c_str();
     while (*ptr != '\0') {
          pTRANSTABLE table=g_htmlTable;
          bool trans=false;
          while (table->ch != '\0') {
               if (table->ch == *ptr) {
                    dest+=table->dest;
                    trans=true;
                    break;
               }
               ++table;
          }
          if (!trans) {
               dest+=*ptr;
          }
          ++ptr;
     }
     return(dest);
}

string                             //   new, encoded string
urlEncode(                              // url encode a string
string const & str)                //   string to encode
{
     string dest("");
     for (INT count=0; count < str.length(); ++count ) {
          BYTE ch=str[count];
          if (ch == ' ') {
               dest+='+';
          }
          else if (::isUrlEncChar(ch)) {
               dest+='%';
               dest+=::hexdig((ch>>4)&0x0F);
               dest+=::hexdig(ch&0x0F);
          }
          else {
               dest+=(char)ch;
          }
     }
     return(dest);
}

bool                               // TRUE if char should be encoded
isUrlEncChar(                      // is character a URL "special" char
unsigned char c)                   // character to check
{
     return(c <= ' ' || c >= '~' || strchr("+\"#%<>?&[\\]^`'{|}",c) != NULL);
}

string                        // linked string
linkURLs(                          // parse URLs, and create links
string const & txt,           // text to check for URLS
string const & anchor)        // anchor tag to use for linking
{
     string dest("");
     static struct urlpairs urls[]={
          {"http:",URL_HTTP},
          {"telnet:",URL_TELNET},
          {"ftp:",URL_FTP},
          {"gopher:",URL_GOPHER},
          {"wais:",URL_WAIS},
          {"tn3270:",URL_TN3270},
          {"mailto:",URL_MAILTO},
          {"news:",URL_NEWS},
          {"file:",URL_FILE},
          {"www.",URL_WWW},
          {"",0}
     };
     CHAR const * ptr=txt.c_str();

     while (*ptr != '\0') {
          GBOOL isurl=FALSE;
          INT i=0;
          while (*(urls[i].text) != '\0') {
               if (sameto(urls[i].text,ptr)) {
                   CHAR const * bstr=txt.c_str();
                   if (((ptr == bstr) || (ptr > bstr && *(ptr-1) == ' '))
                    && (isalnum(*(ptr+1)))) {
                         isurl=TRUE;
                         break;
                   }
              }
              i++;
          }
          if (isurl) {
               INT bufLen=0;
               string linkbuf("");
               if (urls[i].idx == URL_WWW) {
                    bufLen+=strlen(HTTPELEM);
                    linkbuf+=HTTPELEM;
               }
               CHAR const * sp=strchr(ptr,' ');
               size_t len=strlen(ptr);
               if (sp != NULL) {
                    len=(sp-ptr);
                    while (len > 0  && !isalnum(*(ptr+len-1))) {
                         --len;
                    }
               }
               linkbuf.append(ptr,0,len);
               bufLen+=(2*len)+strlen("</A>")+anchor.length()+1;
               CHAR* tmpBuf=new CHAR[bufLen];
               sprintf(tmpBuf,anchor.c_str(),linkbuf.c_str());
               ASSERT(strlen(tmpBuf)+len < bufLen);
               dest+=tmpBuf;
               dest+=linkbuf;
               dest+="</A>";
               ptr+=len;
               delete [] tmpBuf;
          }
          else {
               if (*ptr == ' ' && *(ptr+1) == ' ') {
                    dest+="&nbsp;";
               }
               else {
                    dest+=(*(ptr));
               }
               ptr++;
          }
     }
     return(dest);
}

string                            // decoded String
urlDecode(                        // decode a String for CGI "safety"
const string& str)                // original String
{
     string result("");

     ASSERT(str != NULL);
     for (int count = 0; count < str.length(); ++count ) {
          BYTE ch=str[count] ;
          if (ch == '+') {
               result+=' ';
          }
          else if ((ch == '%')
           && (count < (str.length() - 2))
           && isxdigit( str[count+1] )
           && isxdigit( str[count+2] )) {
               ch=(hexVal(str[count+1] ) << 4)|(hexVal(str[count+2]));
               result+=ch;
               count+=2;
          }
          else {
               result+=(char)ch;
          }
     }
     return(result);
}

BYTE                               // value of the hex digit
hexVal(                            // get the value of a hex character
CHAR ch)                           // char to evaluate
{
     BYTE result=isdigit(ch ) ? (ch - '0') :
                 ((tolower( ch ) - 'a') + 10);

     ASSERT(result <= 15);
     return(result);
}


