windows-nt/Source/XPSP1/NT/shell/osshell/accesory/calc/input.c
2020-09-26 16:20:57 +08:00

309 lines
7.5 KiB
C

/****************************Module*Header***********************************\
* Module Name: INPUT.C
*
* Module Descripton: Decimal floating point input
*
* Warnings:
*
* Created:
*
* Author:
\****************************************************************************/
#include "scicalc.h"
#include "unifunc.h"
#include "input.h"
extern BOOL gbRecord;
extern TCHAR szDec[5]; // The decimal point we use
extern INT gcIntDigits;
TCHAR const szZeroInit[] = TEXT("0");
#define CH_BASE_10_EXP TEXT('e')
#define CH_BASE_X_EXP TEXT('^')
/****************************************************************************/
void CIO_vClearNSec( PCALCNUMSEC pcns ) {
pcns->fEmpty = TRUE;
pcns->fNeg = FALSE;
lstrcpy( pcns->szVal, szZeroInit );
pcns->cchVal = lstrlen(pcns->szVal);
}
void CIO_vClear(PCALCINPUTOBJ pcio)
{
CIO_vClearNSec( &(pcio->cnsNum) );
CIO_vClearNSec( &(pcio->cnsExp) );
pcio->fExp = FALSE;
pcio->iDecPt = -1;
}
/****************************************************************************/
void CIO_vConvertToNumObj(PHNUMOBJ phnoNum, PCALCINPUTOBJ pcio)
{
HNUMOBJ hnoValue;
LPTSTR pszExp = NULL;
// ZTerm the strings
pcio->cnsNum.szVal[pcio->cnsNum.cchVal] = TEXT('\0');
if (pcio->fExp ) {
pszExp = pcio->cnsExp.szVal;
pszExp[pcio->cnsExp.cchVal] = TEXT('\0');
}
hnoValue = NumObjMakeNumber( pcio->cnsNum.fNeg, pcio->cnsNum.szVal, pcio->cnsExp.fNeg, pszExp );
NumObjAssign( phnoNum, hnoValue );
return;
}
/****************************************************************************/
void CIO_vConvertToString(LPTSTR *ppszOut, PCALCINPUTOBJ pcio, int nRadix)
{
//In theory both the base and exponent could be C_NUM_MAX_DIGITS long.
TCHAR szTemp[C_NUM_MAX_DIGITS*2+4];
LPTSTR psz;
int i;
// ZTerm the strings
pcio->cnsNum.szVal[pcio->cnsNum.cchVal] = TEXT('\0');
if ( pcio->fExp )
pcio->cnsExp.szVal[pcio->cnsExp.cchVal] = TEXT('\0');
i = 0;
if (pcio->cnsNum.fNeg)
szTemp[i++] = TEXT('-');
lstrcpy( &szTemp[i], pcio->cnsNum.szVal );
i += pcio->cnsNum.cchVal;
// Add a '.' if it is not already there
if (pcio->iDecPt == -1 )
szTemp[i++] = szDec[0];
if (pcio->fExp) {
szTemp[i++] = nRadix == 10 ? CH_BASE_10_EXP : CH_BASE_X_EXP;
if (pcio->cnsExp.fNeg)
szTemp[i++] = TEXT('-');
else
szTemp[i++] = TEXT('+');
lstrcpy( &szTemp[i], pcio->cnsExp.szVal );
i += pcio->cnsExp.cchVal;
}
psz = (LPTSTR)NumObjAllocMem( (lstrlen( szTemp )+1) * sizeof(TCHAR) );
if (psz) {
if (*ppszOut != NULL) {
NumObjFreeMem( *ppszOut );
}
*ppszOut = psz;
}
// Don't show '.' if in int math
if (F_INTMATH() && szTemp[i-1] == szDec[0])
i--;
szTemp[i] = TEXT('\0');
lstrcpy( *ppszOut, szTemp );
return;
}
/****************************************************************************/
BOOL CIO_bAddDigit(PCALCINPUTOBJ pcio, int iValue)
{
PCALCNUMSEC pcns;
TCHAR chDigit;
int cchMaxDigits;
// convert from an integer into a character
chDigit = (iValue < 10)?(TEXT('0')+iValue):(TEXT('A')+iValue-10);
if (pcio->fExp)
{
pcns = &(pcio->cnsExp);
cchMaxDigits = C_EXP_MAX_DIGITS;
}
else
{
pcns = &(pcio->cnsNum);
ASSERT( gcIntDigits <= C_NUM_MAX_DIGITS );
cchMaxDigits = gcIntDigits;
}
// Ignore leading zeros
if ( pcns->fEmpty && (iValue == 0) )
{
return TRUE;
}
if ( pcns->cchVal < cchMaxDigits )
{
if (pcns->fEmpty)
{
pcns->cchVal = 0; // Clobber the default zero
pcns->fEmpty = FALSE;
}
pcns->szVal[pcns->cchVal++] = chDigit;
return TRUE;
}
// if we are in base 8 entering a mantica and we're on the last digit then
// there are special cases where we can actually add one more digit.
if ( nRadix == 8 && pcns->cchVal == cchMaxDigits && !pcio->fExp )
{
BOOL bAllowExtraDigit = FALSE;
switch ( dwWordBitWidth % 3 )
{
case 1:
// in 16bit word size, if the first digit is a 1 we can enter 6 digits
if ( pcns->szVal[0] == TEXT('1') )
bAllowExtraDigit = TRUE;
break;
case 2:
// in 8 or 32bit word size we get an extra digit if the first digit is 3 or less
if ( pcns->szVal[0] <= TEXT('3') )
bAllowExtraDigit = TRUE;
break;
}
if ( bAllowExtraDigit )
{
pcns->szVal[pcns->cchVal++] = chDigit;
return TRUE;
}
}
return FALSE;
}
/****************************************************************************/
void CIO_vToggleSign(PCALCINPUTOBJ pcio)
{
// Zero is always positive
if (pcio->cnsNum.fEmpty)
{
pcio->cnsNum.fNeg = FALSE;
pcio->cnsExp.fNeg = FALSE;
}
else if (pcio->fExp)
{
pcio->cnsExp.fNeg = !pcio->cnsExp.fNeg;
}
else
{
pcio->cnsNum.fNeg = !pcio->cnsNum.fNeg;
}
}
/****************************************************************************/
BOOL CIO_bAddDecimalPt(PCALCINPUTOBJ pcio)
{
ASSERT(gbRecord == TRUE);
if (pcio->iDecPt != -1) // Already have a decimal pt
return FALSE;
if (pcio->fExp) // Entering exponent
return FALSE;
pcio->cnsNum.fEmpty = FALSE; // Zeros become significant
pcio->iDecPt = pcio->cnsNum.cchVal++;
pcio->cnsNum.szVal[pcio->iDecPt] = szDec[0];
return TRUE;
}
/****************************************************************************/
BOOL CIO_bExponent(PCALCINPUTOBJ pcio)
{
ASSERT(gbRecord == TRUE);
// For compatability, add a trailing dec pnt to base num if it doesn't have one
CIO_bAddDecimalPt( pcio );
if (pcio->fExp) // Already entering exponent
return FALSE;
pcio->fExp = TRUE; // Entering exponent
return TRUE;
}
/****************************************************************************/
BOOL CIO_bBackspace(PCALCINPUTOBJ pcio)
{
ASSERT(gbRecord == TRUE);
if (pcio->fExp)
{
if ( !(pcio->cnsExp.fEmpty) )
{
pcio->cnsExp.cchVal--;
if (pcio->cnsExp.cchVal == 0)
{
CIO_vClearNSec( &(pcio->cnsExp) );
}
}
else
{
pcio->fExp = FALSE;
}
}
else
{
if ( !(pcio->cnsNum.fEmpty) )
{
pcio->cnsNum.cchVal--;
}
if ( pcio->cnsNum.cchVal <= pcio->iDecPt )
//Backed up over decimal point
pcio->iDecPt = -1;
if ((pcio->cnsNum.cchVal == 0) || ((pcio->cnsNum.cchVal == 1) && (pcio->cnsNum.szVal[0] == TEXT('0'))))
CIO_vClearNSec( &(pcio->cnsNum) );
}
return TRUE;
}
/****************************************************************************/
void CIO_vUpdateDecimalSymbol(PCALCINPUTOBJ pcio, TCHAR chLastDP)
{
int iDP;
ASSERT(pcio);
iDP = pcio->iDecPt; // Find the DP index
if (iDP == -1)
return;
ASSERT(pcio->cnsNum.szVal[iDP] == chLastDP);
pcio->cnsNum.szVal[iDP] = szDec[0]; // Change to new decimal pt
}
/****************************************************************************/