/*****************************************************************************/
/*                                                                           */
/*   VECTREX HP3000 Software Emulator              Copyright K.Wilkins 1996  */
/*                                                                           */
/*****************************************************************************/
/*                                                                           */
/*   Title      : Vectrex emulator utility functions.                        */
/*                                                                           */
/*   File Name  : UTIL.C                                                     */
/*                                                                           */
/*   Author     : Keith Wilkins                                              */
/*                                                                           */
/*   Version    : 1.00                                                       */
/*                                                                           */
/*   Desciption : This file contains utility functions (mainly text) for     */
/*                the emulator.                                              */
/*                                                                           */
/*   Functions  : fIsWhitespace()    - Is the char passed a whitespace char? */
/*                fCharToInt()       - Convert ASCII char to an integer      */
/*              : fStringToWord()    - Convert ASCII string to a WORD        */
/*                fStringToLongWord()- Convert ASCII string to a LONGWORD    */
/*                fHexStringToByte() - Convert a 2 digit ascii str to a BYTE */
/*                                                                           */
/*****************************************************************************/
/*                                                                           */
/*   Revision History:                                                       */
/*                                                                           */
/*   Version    Date    Who  Description of changes                          */
/*   -------    ----    ---  ----------------------                          */
/*                                                                           */
/*    0.01    11/04/94  K.W  Creation                                        */
/*    1.00    05/08/96  K.W  Public release of DVE V1.0                      */
/*                                                                           */
/*****************************************************************************/

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <i86.h>

#include <standard.h>

#include "util.h"

/*****************************************************************************/
/*                                                                           */
/*   Function    : fHexStringToByte()                                        */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Convert the passed hex format ascii string into a BYTE    */
/*                 accepts the following numeric formats.                    */
/*                                                                           */
/*                 53      - Hexadecimal if 1st char is 0-F                  */
/*                 A2      - Hexadecimal if 1st char is 0-F                  */
/*                                                                           */
/*   Accepts     : Pointer to source string and pointer to dest BYTE         */
/*                                                                           */
/*   Returns     : T_INT T_TRUE/T_FALSE on success/fail                           */
/*                                                                           */
/*****************************************************************************/

T_INT fHexStringToByte(T_UCHAR *pcString,T_UCHAR *pbResult)
{
    T_UCHAR       *pcTextPtr,*pcStartPos;
    T_SWORD       iExponent=0,iMultiplier=0;
    T_SWORD       iTmp,iLoop;
    T_ULONG       lwValue=0;

    /* Step 1 make the string entirely uppercase */

    pcTextPtr=pcString;

    while(*pcTextPtr!=0)
    {
        *pcTextPtr=toupper(*pcTextPtr);
        pcTextPtr++;
    }

    /* Step 2, skip any whitespace on the front of the string */

    while(fIsWhiteSpace(*pcString)==T_TRUE)
    {
        if(*pcString==0) return(T_FALSE);
        pcString++;
    }

    pcStartPos=pcString;

    while(*(pcString+1)!=0) pcString++;

    do
    {
        iTmp=fCharToInt(*pcString);

        /* Test for validity */

        if(iTmp<0 || iTmp>=16) return(T_FALSE);

        /* Calculate the Multiplier */

        iMultiplier=1;
        for(iLoop=0;iLoop<iExponent;iLoop++) iMultiplier*=16;

        lwValue+=(T_ULONG)iTmp*iMultiplier;

        /* Increment the exponent */

        iExponent++;

        /* Test the Value to see if we exceed the WORD limit */

        if(lwValue>256)
        {
            return(T_FALSE);
        }
    }
    while(pcString--!=pcStartPos);

    /* Step 5 Save the value */

    *pbResult=(T_UCHAR)lwValue;

    return(T_TRUE);
}



/*****************************************************************************/
/*                                                                           */
/*   Function    : fStringToWord()                                           */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Convert the passed ascii string to hex WORD. Will         */
/*                 accept the following numeric formats.                     */
/*                                                                           */
/*                 12345   - Decimal                                         */
/*                 A2345   - Hexadecimal if 1st char is A-F                  */
/*                 0X1234  - Hexadecimal                                     */
/*                 $1234   - Hexadecimal                                     */
/*                 01234   - Octal                                           */
/*                 0B01010 - Binary                                          */
/*                                                                           */
/*   Accepts     : Pointer to source string and pointer to dest WORD         */
/*                                                                           */
/*   Returns     : T_INT T_TRUE/T_FALSE on success/fail                           */
/*                                                                           */
/*****************************************************************************/

T_INT fStringToWord(T_UCHAR *pcString,T_UWORD *pwResult)
{
    T_UCHAR *pcTextPtr,*pcStartPos;
    T_SWORD iRadix=0,iExponent=0,iMultiplier=0;
    T_SWORD iTmp,iLoop;
    T_ULONG lwValue=0;

    /* Step 1 make the string entirely uppercase */

    pcTextPtr=pcString;

    while(*pcTextPtr!=0)
    {
        *pcTextPtr=toupper(*pcTextPtr);
        pcTextPtr++;
    }

    /* Step 2, skip any whitespace on the front of the string */

    while(fIsWhiteSpace(*pcString)==T_TRUE)
    {
        if(*pcString==0) return(T_FALSE);
        pcString++;
    }

    /* Step 3 identify the 1st valid char and switch on it */

    switch(*pcString)
    {
        case'$':
            iRadix=16;
            pcString++;
            break;

        case'0':
            if(*(pcString+1)=='X')
            {
                iRadix=16;
                pcString+=2;
            }
            else if(*(pcString+1)=='B')
            {
                iRadix=2;
                pcString+=2;
            }
            else if(*(pcString+1)>='0' && *(pcString+1)<='7')
            {
                iRadix=8;
            }
            else if(*(pcString+1)>='8' && *(pcString+1)<='9')
            {
                iRadix=10;
            }
            else if(*(pcString+1)=='\0')
            {
                /* Special case of the lone zero */
                *pwResult=0;
                return(T_TRUE);
            }
            else
            {
                return(T_FALSE);
            }
            break;

        case'1': case'2': case'3': case'4': case'5':
        case'6': case'7': case'8': case'9':
            iRadix=10;
            break;

        case'A': case'B': case'C': case'D': case'E': case 'F':
            iRadix=16;
            break;

        default:
            return(T_FALSE);
    }

    /* Step 4 decode the string backwards */

    pcStartPos=pcString;

    while(*(pcString+1)!=0) pcString++;

    do
    {
        iTmp=fCharToInt(*pcString);

        /* Test for validity */

        if(iTmp<0 || iTmp>=iRadix) return(T_FALSE);

        /* Calculate the Multiplier */

        iMultiplier=1;
        for(iLoop=0;iLoop<iExponent;iLoop++) iMultiplier*=iRadix;

        lwValue+=(T_ULONG)iTmp*iMultiplier;

        /* Increment the exponent */

        iExponent++;

        /* Test the Value to see if we exceed the WORD limit */

        if(lwValue>65535)
        {
            return(T_FALSE);
        }
    }
    while(pcString--!=pcStartPos);

    /* Step 5 Save the value */

    *pwResult=(T_UWORD)lwValue;

    return(T_TRUE);
}




/*****************************************************************************/
/*                                                                           */
/*   Function    : fStringToLongWord()                                       */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Convert the passed ascii string to a LONGWORD. Will       */
/*                 accept the following numeric formats.                     */
/*                                                                           */
/*                 12345   - Decimal                                         */
/*                 A2345   - Hexadecimal if 1st char is A-F                  */
/*                 0X1234  - Hexadecimal                                     */
/*                 $1234   - Hexadecimal                                     */
/*                 01234   - Octal                                           */
/*                 0B01010 - Binary                                          */
/*                                                                           */
/*   Accepts     : Pointer to source string and pointer to dest LONGWORD     */
/*                                                                           */
/*   Returns     : T_INT T_TRUE/T_FALSE on success/fail                           */
/*                                                                           */
/*****************************************************************************/

T_INT fStringToLongWord(T_PUCHAR pcString,T_PULONG plwResult)
{
    T_PUCHAR pcTextPtr;
    T_PUCHAR pcStartPos;
    T_ULONG lwRadix=0,lwExponent=0,lwMultiplier=0;
    T_ULONG lwTmp,lwLoop;
    T_ULONG lwValue=0;

    /* Step 1 make the string entirely uppercase */

    pcTextPtr=pcString;

    while(*pcTextPtr!=0)
    {
        *pcTextPtr=toupper(*pcTextPtr);
        pcTextPtr++;
    }

    /* Step 2, skip any whitespace on the front of the string */

    while(fIsWhiteSpace(*pcString)==T_TRUE)
    {
        if(*pcString==0) return(T_FALSE);
        pcString++;
    }

    /* Step 3 identify the 1st valid char and switch on it */

    switch(*pcString)
    {
        case'$':
            lwRadix=16;
            pcString++;
            break;

        case'0':
            if(*(pcString+1)=='X')
            {
                lwRadix=16;
                pcString+=2;
            }
            else if(*(pcString+1)=='B')
            {
                lwRadix=2;
                pcString+=2;
            }
            else if(*(pcString+1)>='0' && *(pcString+1)<='7')
            {
                lwRadix=8;
            }
            else if(*(pcString+1)>='8' && *(pcString+1)<='9')
            {
                lwRadix=10;
            }
            else if(*(pcString+1)=='\0')
            {
                /* Special case of the lone zero */
                *plwResult=0;
                return(T_TRUE);
            }
            else
            {
                return(T_FALSE);
            }
            break;

        case'1': case'2': case'3': case'4': case'5':
        case'6': case'7': case'8': case'9':
            lwRadix=10;
            break;

        case'A': case'B': case'C': case'D': case'E': case 'F':
            lwRadix=16;
            break;

        default:
            return(T_FALSE);
    }

    /* Step 4 decode the string backwards */

    pcStartPos=pcString;

    while(*(pcString+1)!=0) pcString++;

    do
    {
        lwTmp=(T_ULONG)fCharToInt(*pcString);

        /* Test for validity */

//        if(lwTmp<0 || lwTmp>=lwRadix) return(T_FALSE);
        if(lwTmp>=lwRadix) return(T_FALSE);


        /* Calculate the Multiplier */

        lwMultiplier=1;
        for(lwLoop=0;lwLoop<lwExponent;lwLoop++) lwMultiplier*=lwRadix;

        lwValue+=(T_ULONG)lwTmp*lwMultiplier;

        /* Increment the exponent */

        lwExponent++;

    }
    while(pcString--!=pcStartPos);

    /* Step 5 Save the value */

    *plwResult=lwValue;

    return(T_TRUE);
}




/*****************************************************************************/
/*                                                                           */
/*   Function    : fIsWhitespace()                                           */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Tests if the passed char is a whitespace char.            */
/*                                                                           */
/*   Accepts     : char to be tested                                         */
/*                                                                           */
/*   Returns     : T_TRUE/T_FALSE depeding if whitespece or not                  */
/*                                                                           */
/*****************************************************************************/

T_UCHAR fIsWhiteSpace(T_UCHAR tData)
{
    if(tData==' ' || tData==',' || tData=='\t') return(T_TRUE); else return(T_FALSE);
}




/*****************************************************************************/
/*                                                                           */
/*   Function    : fCharToInt()                                              */
/*                                                                           */
/*   Author      : K.W                                                       */
/*                                                                           */
/*   Description : Convert a char to an int in the range 0-15 as hex is      */
/*                 also valid as numerals.                                   */
/*                                                                           */
/*   Accepts     : char                                                      */
/*                                                                           */
/*   Returns     : int                                                       */
/*                                                                           */
/*****************************************************************************/

T_SWORD fCharToInt(T_UCHAR cWork)
{
    cWork=toupper(cWork);
    if(cWork>='0' && cWork<='9') return((T_SWORD)cWork-'0');
    else
    if(cWork>='A' && cWork<='F') return((T_SWORD)cWork-'A'+10);
    else
    return(-1);
}

/************************************************************/
/* Allocate a region of DOS memory.                         */
/************************************************************/

T_VOID far *fDOSmalloc(REALPTR * rp,T_ULONG bytes_to_allocate)
{
 T_VOID far *ptr=NULL;
 union REGS regs;

 bytes_to_allocate = ((bytes_to_allocate + 15) & 0xfffffff0);
 memset(&regs,0,sizeof(regs));
 regs.w.ax = 0x100;
 regs.w.bx = (T_UWORD)(bytes_to_allocate >> 4);            //Allocate dos
 int386(0x31,&regs,&regs);
 if(regs.x.cflag == 0)
 {       //Everything OK.
   rp->Segment = regs.w.ax;
   rp->Selector = regs.w.dx;
   ptr = MK_FP(regs.w.dx,0);
 }
 return(ptr);
}

/********************************************/
/* Free an area of DOS memory.              */
/********************************************/

T_VOID fDOSfree(REALPTR * rp)
{
  union   REGS            regs;

  regs.w.ax = 0x101;
  regs.w.dx = rp->Selector;
  int386(0x31,&regs,&regs);
}




