dockapps/wmcalc/wmcalcfunc.c
Doug Torrance ec62fab633 wmcalc: Null-termitate display string when clearing.
Often, the number currently being displayed has more than 10 digits.
However, when clearing the display, only the first 10 digits were cleared.
When a new number was entered, it would be prepended to any digits that
weren't cleared.  This behavior was invisible to the user, causing
incorrect calculations, e.g., Debian bug #564173:

1814 / 720 * 300 -> 7568.41111

But the correct answer is 755.833333.

The problem was that when the display was cleared, the string that stores
this number was not null-terminated.  Indeed, 1814 / 720 gives us
2.519444444 (6 4's), but only 2.51944444 (5 4's) is displayed.  When we
begin to multiply by 300, the final 4 remained, and so we really were
multiplying by 3004.
2018-08-29 23:14:02 -04:00

530 lines
15 KiB
C

/****************************************************************
* File: wmcalcfunc.c
* Version: 0.21
* Author: Edward H. Flora <ehflora@access1.net>
*
* This file is a part of the wmcalc application. As such, this
* file is licensed under the GNU General Public License, version 2.
* A copy of this license may be found in the file COPYING that should
* have been distributed with this file. If not, please refer to
* http://www.gnu.org/copyleft/gpl.html for details.
*
****************************************************************
Description:
This file contains the code for the actual calculator functions,
such as a add, subt, clear, etc.
Change History:
Date Modification
11/03/00 File Header added
27/12/06 Increased significant digits (Antony Gelberg, antony@wayforth.co.uk)
****************************************************************/
/***** Includes *************************************************/
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#include "wmcalc_c.h"
#include "wmcalc_err.h"
#include "wmcalc_f.h"
/****************************************************************
* Function: clearcalc
****************************************************************
Description:
This function will clear the calculator display, and internal
flags.
Change History:
Date Modification
11/03/00 Function header added
11/04/00 Replaced magic numbers with DISPSIZE
****************************************************************/
void clearcalc(void) {
extern int StrCnt;
extern char PlusMinusFlag;
extern int ExpFlag;
extern int DecFlag;
extern double RegisterA;
extern double RegisterB;
extern char DispString[];
extern char OpFlag;
int i;
RegisterA = 0.0;
RegisterB = 0.0;
ExpFlag = 0;
DecFlag = 0;
PlusMinusFlag = '+';
StrCnt = 0;
for (i=0; i < DISPSIZE; i++) {
DispString[i] = ' ';
}
DispString[DISPSIZE] = '\0';
OpFlag = ' ';
} /***** End of function clearcalc() *****************************/
/****************************************************************
* Function: clearnum
****************************************************************
Description:
Clears the current number being entered.
Change History:
Date Modification
11/03/00 Updated function header
11/04/00 Replaced magic numbers with DISPSIZE
****************************************************************/
void clearnum(void) {
extern int StrCnt;
extern char PlusMinusFlag;
extern int ExpFlag;
extern int DecFlag;
extern double RegisterA;
extern char DispString[];
int i;
RegisterA = 0.0;
ExpFlag = 0;
DecFlag = 0;
PlusMinusFlag = '+';
StrCnt = 0;
for (i=0; i < DISPSIZE; i++) {
DispString[i] = ' ';
}
DispString[DISPSIZE] = '\0';
} /***** End of function clearnum() ******************************/
/****************************************************************
* Function: charkey
****************************************************************
Description:
Add characters to the number being entered.
Change History:
Date Modification
11/03/00 Updated function header
11/04/00 Replaced magic numbers with DISPSIZE
****************************************************************/
void charkey(char ch) {
extern int Verbose;
extern int StrCnt;
extern int DecFlag;
extern double RegisterA, RegisterB;
extern char DispString[];
int i;
if (Verbose) printf("In function charkey\n");
if (StrCnt < DISPSIZE) {
if (ch == '.') {
if (DecFlag == 0) {
for (i = 1; i < DISPSIZE; i++)
DispString[i-1] = DispString[i];
DecFlag = 1;
StrCnt++;
DispString[DISPSIZE - 1] = ch;
}
}
else {
for (i = 1; i < DISPSIZE; i++)
DispString[i-1] = DispString[i];
DispString[9] = ch;
StrCnt++;
}
} /* endif (StrCnt < DISPSIZE) */
else if (StrCnt == CALCDONE) {
RegisterB = RegisterA;
clearnum();
if (ch == '.') {
for (i = 1; i < DISPSIZE; i++)
DispString[i-1] = DispString[i];
DecFlag = 1;
StrCnt++;
DispString[DISPSIZE -1] = ch;
}
else {
for (i = 1; i < DISPSIZE; i++)
DispString[i-1] = DispString[i];
DispString[DISPSIZE - 1] = ch;
StrCnt++;
}
} /* endif (StrCnt == CALCDONE) */
RegisterA = atof(DispString);
} /***** End of Function charkey() *******************************/
/****************************************************************
* Function: chgsignnum
****************************************************************
Description:
Change the sign of the number currently being entered
Change History:
Date Modification
11/03/00 Updated Function header
****************************************************************/
void chgsignnum(void) {
extern int Verbose;
extern double RegisterA;
extern char DispString[];
if (Verbose) printf("In function chgsignnum\n");
RegisterA = -RegisterA;
sprintf(DispString, "%10.5g", RegisterA);
} /***** End of function chgsignnum() *****************************/
/****************************************************************
* Function: sqrnum
****************************************************************
Description:
Square the number in RegisterA
Change History:
Date Modification
11/03/00 Updated Function header
****************************************************************/
void sqrnum(void) {
extern int Verbose;
extern int StrCnt;
extern double RegisterA;
extern char DispString[];
extern int ImgFlag;
if (Verbose) printf("In function sqrnum\n");
RegisterA = atof(DispString);
RegisterA = pow(RegisterA, 2.0);
if (ImgFlag) {
RegisterA = -RegisterA;
ImgFlag = 0;
}
sprintf(DispString, "%10.5g", RegisterA);
StrCnt = CALCDONE;
} /***** End of Function sqrnum() *******************************/
/****************************************************************
* Function: sqrtnum
****************************************************************
Description:
Take the square root of the number in RegisterA
Change History:
Date Modification
11/03/00 Updated function header
11/04/00 Replaced magic numbers with DISPSIZE
****************************************************************/
void sqrtnum(void) {
extern int Verbose;
extern int StrCnt;
extern double RegisterA;
extern int ImgFlag;
extern char ImagChar;
extern char DispString[];
int i;
if (Verbose) printf("In function sqrtnum\n");
RegisterA = atof(DispString);
if (RegisterA >= 0) {
RegisterA = pow(RegisterA, 0.5);
sprintf(DispString, "%10.5g", RegisterA);
}
else {
RegisterA = pow(-RegisterA, 0.5);
ImgFlag = 1;
sprintf(DispString, "%10.4g", RegisterA);
for(i=1; i < DISPSIZE - 1; i++)
DispString[i] = DispString[i+1];
DispString[DISPSIZE - 1] = ImagChar;
}
StrCnt = CALCDONE;
} /***** End of function sqrtnum() ********************************/
/****************************************************************
* Function: addnums
****************************************************************
Description:
Add the number in Registers A to Register B.
Change History:
Date Modification
11/03/00 Updated Function header
****************************************************************/
void addnums(void) {
extern int Verbose;
extern int StrCnt;
extern double RegisterA, RegisterB;
extern char OpFlag;
if(Verbose) printf("In function addnums: ");
if(OpFlag != ' ') {
equalfunc();
}
else {
if(Verbose) printf("%g + ?? = ??\n", RegisterB);
RegisterB = RegisterA;
}
StrCnt = CALCDONE;
OpFlag = '+';
} /***** End of function addnums() *********************************/
/****************************************************************
* Function: subtnums
****************************************************************
Description:
Subtract current number (in RegisterA) from accumulated total.
Change History:
Date Modification
11/03/00 Updated Function header
****************************************************************/
void subtnums(void) {
extern int Verbose;
extern int StrCnt;
extern double RegisterA, RegisterB;
extern char OpFlag;
if(Verbose) printf("In function subtnums: ");
if (OpFlag != ' ') {
equalfunc();
}
else {
if(Verbose) printf("%g - ?? = ??\n", RegisterB);
RegisterB = RegisterA;
}
StrCnt = CALCDONE;
OpFlag = '-';
} /***** End of function subtnums() *****************************/
/****************************************************************
* Function: multnums
****************************************************************
Description:
Multiply number in RegisterA by the accumulated total.
Change History:
Date Modification
11/03/00 Updated function header
****************************************************************/
void multnums(void) {
extern int Verbose;
extern int StrCnt;
extern char OpFlag;
extern double RegisterA, RegisterB;
if(Verbose) printf("In function multnums: ");
if(OpFlag != ' ') {
equalfunc();
}
else {
if(Verbose) printf("%g * ?? = ??\n", RegisterB);
RegisterB = RegisterA;
}
StrCnt = CALCDONE;
OpFlag = '*';
} /***** End of function multnums() *****************************/
/****************************************************************
* Function: divnums
****************************************************************
Description:
Divide the accumulated total by the current number in RegisterA
Change History:
Date Modification
11/04/00 Updated Function Header
****************************************************************/
void divnums(void) {
extern int Verbose;
extern int StrCnt;
extern double RegisterA, RegisterB;
extern char OpFlag;
if(Verbose) printf("In function divnums: ");
if(OpFlag != ' ') {
equalfunc();
}
else {
if(Verbose) printf("%g / ?? = ??\n", RegisterB);
RegisterB = RegisterA;
}
StrCnt = CALCDONE;
OpFlag = '/';
} /* End of Function divnums() ********************************/
/****************************************************************
* Function:
****************************************************************
Description:
Calculate result of entered calculation.
Change History:
Date Modification
11/04/00 Updated Function Header
****************************************************************/
void equalfunc (void) {
extern int Verbose;
extern int StrCnt;
extern char DispString[];
extern double RegisterA, RegisterB;
extern char OpFlag;
if (Verbose) printf("Equal Function: Operation >> %c <<\n", OpFlag);
switch (OpFlag) {
case '+':
RegisterA = RegisterB + RegisterA;
sprintf(DispString, "%10.10g", RegisterA);
break;
case '-':
RegisterA = RegisterB - RegisterA;
sprintf(DispString, "%10.10g", RegisterA);
break;
case '*':
RegisterA = RegisterB * RegisterA;
sprintf(DispString, "%10.10g", RegisterA);
break;
case '/':
RegisterA = RegisterB / RegisterA;
sprintf(DispString, "%10.10g", RegisterA);
break;
default:
break;
}
OpFlag = ' ';
StrCnt = CALCDONE;
} /***** End of function equalfunc() ******************************/
/****************************************************************
* Function: clrallmem
****************************************************************
Description:
Clear all the values in memory
Change History:
Date Modification
11/04/00 Updated Function Header
11/04/00 Incorporated clrmem() function into this one, to
optimize code.
****************************************************************/
void clrallmem(void) {
extern int Verbose;
extern double MemArray[];
extern int MemLock[];
int i;
if (Verbose) printf("Clear All Memory Function\n");
for (i = 0; i < NUM_MEM_CELLS; i++) {
if (MemLock[i] != 1) {
MemArray[i] = 0.0;
if (Verbose) printf(" %f ", MemArray[i]);
}
}
if (Verbose) printf("\n");
write_config();
} /***** End of function clrallmem() ****************************/
/****************************************************************
* Function: stormem
****************************************************************
Description:
Store value to memory cell #N
Change History:
Date Modification
11/04/00 Updated function header
11/05/00 Added Locked Memory capabilities
****************************************************************/
void stormem(int mem_loc) {
extern double MemArray[];
extern int MemLock[];
extern int Verbose;
extern double RegisterA;
int i;
if (Verbose)
printf("Store Value %f in Memory Cell %d\nMemory:", RegisterA, mem_loc);
if (MemLock[mem_loc] != 1) {
MemArray[mem_loc] = RegisterA;
write_config();
}
else {
if (Verbose) printf("Memory location %d Locked at %f\n",
mem_loc, MemArray[mem_loc]);
}
if (Verbose) {
for (i = 0; i < NUM_MEM_CELLS; i++)
printf(" %f ", MemArray[i]);
printf("\n");
}
} /***** End of function stormem() ******************************/
/****************************************************************
* Function: recallmem
****************************************************************
Description:
Store value to memory cell #N
Change History:
Date Modification
11/04/00 Updated function header
****************************************************************/
void recallmem(int mem_loc) {
extern double MemArray[];
extern int Verbose;
extern double RegisterA;
extern char DispString[];
int i;
if (Verbose)
printf("Recall Value in Memory Cell %d\nMemory:", mem_loc);
RegisterA = MemArray[mem_loc];
sprintf(DispString, "%10.5g", RegisterA);
if (Verbose) {
for (i = 0; i < NUM_MEM_CELLS; i++)
printf(" %f ", MemArray[i]);
printf("\n");
}
} /***** End of function recallmem() ***************************/
/****************************************************************
* Function: startcalc
****************************************************************
Description:
Change the sign of the number currently being entered
Change History:
Date Modification
11/04/00 Updated function header
****************************************************************/
void startcalc(void) {
extern int Verbose;
extern char SysCalcCmd[];
if (Verbose)
fprintf(stderr, "Starting external calculator %s\n", SysCalcCmd);
if (system(SysCalcCmd) == -1)
fprintf(stderr, "%s returned an error.\n", SysCalcCmd);
} /***** End of function startcalc *****************************/