Logo Search packages:      
Sourcecode: xabacus version File versions

AbacusC.c

/*-
# X-BASED ABACUS
#
#  AbacusC.c
#
###
#
#  Copyright (c) 1992 - 2005  David Albert Bagley, bagleyd@tux.org
#
#                   All Rights Reserved
#
#  Permission to use, copy, modify, and distribute this software and
#  its documentation for any purpose and without fee is hereby granted,
#  provided that the above copyright notice appear in all copies and
#  that both that copyright notice and this permission notice appear in
#  supporting documentation, and that the name of the author not be
#  used in advertising or publicity pertaining to distribution of the
#  software without specific, written prior permission.
#
#  This program is distributed in the hope that it will be "useful",
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
#  Taken from a C++ group project where I was a lead contributer
#  OOP Group4!
*/

/* Methods string infix calculator file for Abacus */

#include "AbacusP.h"
#ifndef WINVER
#include <math.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
#ifndef M_E
#define M_E 2.7182818284590452354
extern int signgam;
#endif
#endif

/* proposed, implemented only a small portion
Letter      Meaning
------      -------
<Interrupt (^C etx 03)> kill program, or turn off calculator [quit]
<Back space (^H bs 010)> delete last digit [numeric]
<Line feed (^J lf 012), Carriage return (^M cr 015), Space (040)> [ignore]
!     factorial
"
#     number of values for statistics
$     summation
%     mod e.g. 7%2=1 [medium]
&     bitwise and [medium]
'
(     (
)     ) [equate]
*     multipication [medium]
+     addition [low]
,     real imaginary delimitor [numeric]
-     subtraction (not sign change) [low]
.     decimal point (or octal pt if in octal, etc.) [numeric]
/     divide e.g. 1/2=0.5 [medium]
0     0 [numeric]
1     1 [numeric]
2     2 [numeric]
3     3 [numeric]
4     4 [numeric]
5     5 [numeric]
6     6 [numeric]
7     7 [numeric]
8     8 [numeric]
9     9 [numeric]
:
;
<     bitwise shift left [high]
=     = [equate]
>     bitwise shift right [high]
?     data input for statistics
@     average
A     hexadecimal 10 [numeric]
B     hexadecimal 11 [numeric]
C     hexadecimal 12 [numeric]
D     hexadecimal 13 [numeric]
E     hexadecimal 14 [numeric]
F     hexadecimal 15 [numeric]
G     variance (sigma^2)
H     hyperbolic
I     inverse
J
K
L     logarithm base 2
M     memory recall ('M', ('0'-'9' | 'A'-'F'))
N     natural logarithm
O       bitwise xor [high]
P     permutation [low]
Q     quit [quit]
R     "to the root of" e.g. 8R3=2 [high]
S     sample variance (s^2)
T       square summation
U       x^3
V     x^2
W       convert from MinSec
X     e^x (unfortunately 'e' & 'E' are used already)
Y
Z
[
\     Pascal's div i.e 28\8=3 [medium]
]
^     "power of" e.g. 2^3=8 [high]
_       reset statistics
`
a       clear almost all [clear]
b     base mode ('b', (['2'-'9'] | '1',['0'-'6']))
c     combination [low]
d       decimal hot key (also 'b', '1', '0')
e     used for exponents e.g. 6.02*10^22 = 6.02e22(input) = 6.02 22(output)
f
g     gradient mode
h       hexadecimal hot key (also 'b', '1', '6')
i     invert 1/x
j
k     cosine (kosine)
l     logarithm base 10
m     memory ('m', ('0'-'9' | 'A'-'F'))
n     bitwise negation
o     degree mode
p     pi
q     clear everything (quit all calulations) [clear]
r     radian mode
s     sine
t     tangent
u     cube root
v     unary operation square root (v-) UNIX's dc & bc use this also
w       convert to MinSec
x       complex mode (base 10 only)
y
z     clear (zero) [clear]
{
|     bitwise or [low]
}
~     negate +/- [numeric (and also unary)]
*/
enum OrderType {notused, low, medium, high, unary, mode, constant, equate};
static const short unsigned int orderASCII[] =
{
   notused,  notused,  notused,  notused,
   notused,  notused,  notused,  notused,
   notused,  notused,  notused,  notused,
   notused,  notused,  notused,  notused,
   notused,  notused,  notused,  notused,
   notused,  notused,  notused,  notused,
   notused,  notused,  notused,  notused,
   notused,  notused,  notused,  notused,

   notused,    unary,  notused, constant, /* Space ! " # */
  constant,   medium,   medium,  notused, /* $ % & ' */
    equate,   equate,   medium,      low, /* ( ) * + */
   notused,      low,  notused,   medium, /* , - . / */
   notused,  notused,  notused,  notused, /* 0 1 2 3 */
   notused,  notused,  notused,  notused, /* 4 5 6 7 */
   notused,  notused,  notused,  notused, /* 8 9 : ; */
      high,   equate,     high,    unary, /* < = > ? */


  constant,  notused,  notused,  notused, /* @ A B C */
   notused,  notused,  notused, constant, /* D E F G */
      mode,     mode,  notused,  notused, /* H I J K */
     unary, constant,    unary,     high, /* L M N O */
       low,  notused,     high, constant, /* P Q R S */
  constant,    unary,    unary,    unary, /* T U V W */
     unary,  notused,  notused,  notused, /* X Y Z [ */
    medium,  notused,     high,     mode, /* \ ] ^ _ */

   notused,  notused,     mode,      low, /* ` a b c */
      mode, constant,  notused,     mode, /* d e f g */
      mode,    unary,  notused,    unary, /* h i j k */
     unary,     mode,    unary,     mode, /* l m n o */
  constant,  notused,     mode,    unary, /* p q r s */
     unary,    unary,    unary,    unary, /* t u v w */
      mode,  notused,  notused,  notused, /* x y z { */
       low,  notused,    unary,  notused  /* | } ~ Delete */
};

enum OperationType {undefined, ignore, numeric, operation, clear, quit};
static const short unsigned int operationASCII[] =
{
  undefined, undefined, undefined,      quit, /* Null SOH STX Interrupt */
  undefined, undefined, undefined, undefined, /* EOT ENQ ACK Bell */
    numeric, undefined,    ignore, undefined, /* Backspace Tab Linefeed VT */
  undefined,    ignore, undefined, undefined, /* Formfeed Carriagereturn SO SI */
  undefined, undefined, undefined, undefined, /* DLE DC1 DC2 DC3 */
  undefined, undefined, undefined, undefined, /* DC4 NAK SYN ETB */
  undefined, undefined, undefined, undefined, /* CAN EM SUB Escape */
  undefined, undefined, undefined, undefined, /* FS GS RS US */

     ignore, operation, undefined, operation, /* Space ! " # */
  operation, operation, operation, undefined, /* $ % & ' */
  operation, operation, operation, operation, /* ( ) * + */
    numeric, operation,   numeric, operation, /* , - . / */
    numeric,   numeric,   numeric,   numeric, /* 0 1 2 3 */
    numeric,   numeric,   numeric,   numeric, /* 4 5 6 7 */
    numeric,   numeric, undefined, undefined, /* 8 9 : ; */
  operation, operation, operation, operation, /* < = > ? */

  operation,   numeric,   numeric,   numeric, /* @ A B C */
    numeric,   numeric,   numeric, operation, /* D E F G */
  operation, operation, undefined, undefined, /* H I J K */
  operation, operation, operation, operation, /* L M N O */
  operation,      quit, operation, operation, /* P Q R S */
  operation, operation, operation, operation, /* T U V W */
  operation, undefined, undefined, undefined, /* X Y Z [ */
  operation, undefined, operation, operation, /* \ ] ^ _ */

  undefined,     clear, operation, operation, /* ` a b c */
  operation, operation, undefined, operation, /* d e f g */
  operation, operation, undefined, operation, /* h i j k */
  operation, operation, operation, operation, /* l m n o */
  operation,     clear, operation, operation, /* p q r s */
  operation, operation, operation, operation, /* t u v w */
  operation, undefined,     clear, undefined, /* x y z { */
  operation, undefined,   numeric, undefined  /* | } ~ Delete */
};

#define CHAR_TO_DIGIT(c) ((c >= 'A') ? c - 'A' + 10 : c - '0')
#define DIGIT_TO_CHAR(d) ((d >= 10) ? (char) ('A' + d - 10) : (char) ('0' + d))
#define IS_DIGIT(c) ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F'))
/* True for period, +/-, or operator */
#define IS_VALID(v, b) ((IS_DIGIT(v)) ? (CHAR_TO_DIGIT(v) < b) : True)
#define MAXVALUELENGTH 64

enum StackUsage {paren, order};

typedef struct _Term
{
      double variable;
      char operation;
      Boolean orderUsage;
      struct _Term *previous;
} Term;

typedef struct _Expression
{
      /* char *variable; */
      char variable[MAXVALUELENGTH]; /* Hard code a limit for now */
      char operation;
      struct _Expression *previous;
} Expression;

/* struct Stack */
static Term *term;
static Expression *expression;

#define DEFAULTBASE 10
#define DEFAULTFRACTDIGITS 16

/* Inputter & Parser & Paren Manager */
static Boolean period = False;
static Boolean gotFirstDigit = False; /* handles special case of just a '0' */
static Boolean negateNext = False; /* handles unary '-' */
static double left, right; /* sides of a binary operation */
static char pendingOperation; /* operation to be performed on left (& right if not unary) */
static Boolean hub; /* intermediate result? usually a ')' or pi pressed */
static char memoryBuf[64];
static char displayBuf[64];
static int digits = 1;
static int currentBase = DEFAULTBASE, fractDigits = DEFAULTFRACTDIGITS;
static int nestingLevel = 0;
static Expression parseExpression;

#if 0
static double
cbrt(double x) /* -inf < x < inf */
{
      return ((x < 0.0) ? -pow(-x, 1.0 / 3.0) : pow(x, 1.0 / 3.0));
}
#endif

static double
powInt(int base, int y)
{
      int i;
      double z = 1.0;

      if (y > 0)
            for (i = 0; i < y; i++)
                  z *= base;
      else if (y < 0)
            for (i = 0; i > y; i--)
                  z /= base;
      else
            z = 1.0;
      return z;
}

/* More exact (int) (log(x) / log ((double) base)) */
static int
logInt(double x, int base)
{
      int i = 0;

      if (x >= (double) base)
            while (x >= (double) base) {
                  x /= (double) base;
                  i++;
            }
      else if (x > 0.0)
            while (x < 1.0) {
                  x *= (double) base;
                  i--;
            }
      return i;
}

static double
rootInt(double x, int y) /* y != 0 && (x >= 0 || (y odd)) */
{
      if (x < 0.0 && ((double) y / 2.0) != ((double) (y / 2)))
            return -pow (-x, 1.0 / (double) y);
      else if (x == 0.0)
            return 0.0;
      else
            return pow (x, 1.0 / (double) y);
}

static double
convertToDecimal(int b, char *inputstring)
{
      int k = 0;
      Boolean negative = False;
      double number = 0.0;
      int digit;
      int length = 0;
      double factor;

      /* Convert Integer Part */
      k = 0;
      if (inputstring[k] == '-')
      {
            negative = True;
            k++;
      }
      while (IS_DIGIT(inputstring[k + length]))
            length++;
      factor = powInt(b, length);
      for (; length > 0; length--, k++)
      {
            digit = CHAR_TO_DIGIT(inputstring[k]);
            factor /= ((double) b);
            number += ((double) digit) * factor;
      }

      /* Convert Fractional Part */
      if (inputstring[k] == '.')
      {
            k++;
            while (IS_DIGIT(inputstring[k]))
            {
                  digit = CHAR_TO_DIGIT(inputstring[k]);
                  factor /= ((double) b);
                  number += ((double) digit) * factor;
                  k++;
            }
      }

      if ((Boolean) negative)
            number = -number;
      negative = False;

      return number;
}

static void
convertFromDecimal(char *outputString, int b, double x)
{
      char string[MAXVALUELENGTH];
      Boolean localPeriod = False;
      double number = 0.0;
      int places_base;
      int l = 0, i = 0;
      short unsigned int digit;
      double factor;
      int fractdigits = fractDigits;

      (void) sprintf(string, "%g", x);
      if (string[i] == '-') {
            outputString[l++] = '-';
            x = -x;
      }
      while (string[i] != '\0') {
            if (string[i] == '.')
                  localPeriod = True;
            i++;
      }
      {
            /* Chicken and egg problem:
               rounding might increase places_base */
            places_base = logInt(x, b);
            fractdigits -= (places_base + 1);
            /* rounder */
            x += (pow((double) b, (double) -fractdigits) / 2.0);

            number = x;
            /* Convert Integer Part */
            if (number < 1.0) {
                  outputString[l++] = '0';
                  factor = 1.0 / ((double) b);
            } else {
                  places_base = logInt(number, b);
                  factor = pow((double) b, (double) places_base);
                  for (; places_base >= 0; places_base--) {
                        digit = (int) (number / factor);
                        outputString[l++] = DIGIT_TO_CHAR(digit);
                        number -= digit * factor;
                        factor /= ((double) b);
                  }
            }
            /* Convert Fractional Part */
            if (localPeriod) {
                  outputString[l++] = '.';
                  for (places_base = 1; places_base <= fractdigits;
                              places_base++) {
                        digit = (int) (number / factor);
                        outputString[l++] = DIGIT_TO_CHAR(digit);
                        number -= digit * factor;
                        factor /= ((double) b);
                  }
                  while (outputString[l - 1] == '0')
                        l--;
            }
      }

      outputString[l] = '\0';
}

static double
formatFromDisplay(int base, char *string)
{
      char floatString[MAXVALUELENGTH];
      Boolean got1Digit = False;
      short unsigned int periods = 0;
      int s = 0, k = 0;

      while (string[s] != '\0') { /* Look at each input character */
            if (IS_DIGIT(string[s])) {
                  got1Digit = True;
                  floatString[k++] = string[s];
            } else switch (string[s]) {
            case '-':
                  floatString[k++] = '-';
                  break;
            case '.':
                  if (periods == 1)
                        (void) printf("'%c' handler not implemented in Format_From_Display\n", string[s]);
                  periods++;
                  if (!got1Digit) {
                        got1Digit = True;
                        floatString[k++] ='0';
                  }
                  floatString[k++] = '.';
                  break;
            default:
                  (void) printf("'%c' handler not implemented in Format_From_Display\n", string[s]);
            }
            s++;
      }
      if (!got1Digit) {
            got1Digit = True;
            floatString[k++] = '0';
      }
      floatString[k] = '\0';
      return convertToDecimal(base, floatString);
}

static void
formatToDisplay (char *string, double z)
{
      int i = 0, j, length;
      short unsigned int periods = 0;

      convertFromDecimal(string, currentBase, z);
      length = strlen(string);
      while (i <= length) {
            if (string[i] == '\0' && periods == 0) {
                  j = length;
                  while (j >= i) {
                        string[j + 1] = string[j];
                        j--;
                  }
                  length++;
                  string[i++] = '.';
                  periods++;
            }
            if (string[i] == '.')
                  periods++;
            if (string[i] == '+') {
                  j = i;
                  while (j < length) {
                        string[j] = string[j + 1];
                        j++;
                  }
                  length--;
            }
            else
                  i++;
      }
      string[length] = '\0';
}


static void reset(void)
{
      period = False;
      gotFirstDigit = False;
      digits = 1;
      memoryBuf[0] = '0';
      memoryBuf[1] = '\0';
}

static void setBase(int base)
{
      currentBase = base;
      fractDigits = logInt(powInt(DEFAULTBASE, DEFAULTFRACTDIGITS), base);
}

static int getNestingLevel(void)
{
      return nestingLevel;
}

static void incNestingLevel(void)
{
      nestingLevel++;
}

static void decNestingLevel(void)
{
      nestingLevel--;
      if (nestingLevel < 0) /* Ignore extra right parentheses */
            nestingLevel = 0;
}

static void resetNestingLevel(void)
{
      nestingLevel = 0;
}

static double
evaluateSingle(double arg, char unaryOperation)
{
      switch(unaryOperation) {
      case 'i':
            if (arg == 0.0) {
                  return 0.0;
            }
            return 1.0 / arg;
      case '!':
#ifdef WINVER
            if ((double)((int) arg) == arg) {
                  long long i, j;

                  if (arg < 0.0 || arg > 20.0) {
                        return 0.0;
                  }
                  j = 1;
                  for (i = 2; i <= arg; i++) {
                        j = j * i;
                  }
                  return (double) j;
            } else {
                  return 0.0;
            }
#else
            if ((arg < 0.0 && ((double)((int) arg) == arg)) ||
                        arg > 20.0) {
                  /* this does not catch all the errors */
                  return 0.0;
            } else {
                  double lg;
#ifdef _REENT_ONLY
                  int signgam_r;

                  lg = lgamma_r(arg + 1.0);
                  return signgam_r * exp(lg);
#else
                  lg = lgamma(arg + 1.0);
                  return signgam * exp(lg);
#endif
            }
#endif
      case 'v':
            if (arg <= 0.0) {
                  return 0.0;
            }
            return sqrt(arg);
      case 'u':
            return cbrt(arg);
      default:
            return 0.0;
      }
}

static double
evaluateDouble(double arg1, char binaryOperation, double arg2)
{
      double comp = 0.0;

      switch(binaryOperation) {
      case '+':
            comp = arg1 + arg2;
            break;
      case '-':
            comp = arg1 - arg2;
            break;
      case '*':
            comp = arg1 * arg2;
            break;
      case '/':
            if (arg2 == 0.0)
                  return 0.0;
            comp = arg1 / arg2;
            break;
      case '^':
            comp = pow(arg1, arg2);
            break;
      default:
            return 0.0;
      }
      return comp;
}

static Boolean
initStack(void)
{
      Term *plate;

      if (!(plate = (Term *) malloc(sizeof(Term))))
            return False;
      plate->previous = NULL;
      term = plate->previous;
      return True;
}

static Boolean
emptyStack(void)
{
      return ((Boolean) (term == NULL));
}

static void
flushStack(void)
{
      while (!emptyStack()) {
            Term *plate = term;

            term = plate->previous;
            free(plate);
      }
}

static void
delStack(void)
{
      flushStack();
      /* free(term); */
}

static Boolean
pushStack(double z, char c, Boolean u)
{
      Term *plate;

      if (!(plate = (Term *) malloc(sizeof(Term))))
            return False;
      plate->variable = z;
      plate->operation = c;
      plate->orderUsage = u;
      plate->previous = term;
      term = plate;
      return True;
}

static void popStack(double *z, char *c, Boolean *u)
{
      Term *plate = term;

      *z = term->variable;
      *c = term->operation;
      *u = term->orderUsage;
      term = plate->previous;
      free(plate);
}

static char topOp(void)
{
      return term->operation;
}

static Boolean topUsage(void)
{
      return term->orderUsage;
}

static Boolean emptyExpression(void)
{
      return (emptyStack());
}

static Boolean previousOrder(void)
{
      return ((Boolean) (!emptyExpression() && topUsage() == order));
}

static Boolean canReduceExpression(char binaryOperation)
{
      return ((Boolean) (previousOrder() && orderASCII[(int) topOp()] >=
                  orderASCII[(int) binaryOperation]));
}

static void resetWholeExpression(void)
{
      flushStack();
}

static void getPreviousExpressionPart(double *myLeft, char *binaryOperation)
{
      Boolean dummy;

      popStack(myLeft, binaryOperation, &dummy);
}

static Boolean storeExpressionParen(double *myLeft, char *binaryOperation)
{
      if (pushStack(*myLeft, *binaryOperation, paren)) {
            *myLeft = 0.0;
            *binaryOperation = '\0';
            return True;
      }
      return False;
}

static void evaluateExpressionPart(double *myLeft, char binaryOperation,
            double myRight)
{
      if (binaryOperation != '\0')
            *myLeft = evaluateDouble(*myLeft, binaryOperation, myRight);
      else
            *myLeft = myRight;
}

static Boolean evaluateExpressionOrder(double *myLeft, char *binaryOperation,
      double *myRight, char newOperation)
{
      if (*binaryOperation != '\0') {
            if (orderASCII[(int) *binaryOperation] >=
                        orderASCII[(int) newOperation]) {
                  *myLeft = evaluateDouble(*myLeft, *binaryOperation,
                        *myRight);
                  while (canReduceExpression(newOperation)) {
                        *myRight = *myLeft;
                        getPreviousExpressionPart (myLeft,
                              binaryOperation);
                        evaluateExpressionPart(myLeft,
                              *binaryOperation, *myRight);
                  }
            } else {
                  if (pushStack(*myLeft, *binaryOperation, order)) {
                        *myLeft = *myRight;
                        return True;
                  } else {
                        return False;
                  }
            }
      } else
            *myLeft = *myRight;
      return True;
}

static void evaluateExpressionParen(double *myLeft, char *binaryOperation)
{
      double myRight;

      while (!emptyExpression() && topUsage() == order) {
            myRight = *myLeft;
            getPreviousExpressionPart(myLeft, binaryOperation);
            evaluateExpressionPart(myLeft, *binaryOperation, myRight);
      }
}

static void evaluateExpression(double *myLeft, char *binaryOperation)
{
      double myRight;

      while (!emptyExpression()) {
            myRight = *myLeft;
            getPreviousExpressionPart(myLeft, binaryOperation);
            if (binaryOperation != '\0')
                  *myLeft = evaluateDouble(*myLeft, *binaryOperation,
                        myRight);
            else
                  *myLeft = myRight;
      } /* ignore uneven "(()" */
      *binaryOperation = '\0';
}

static void
initParser(void)
{
      left = 0.0;
      right = 0.0;
      pendingOperation = '\0';
      hub = False;
      /* FIXME expression = Expression(); */
}

static void
resetRight(void)
{
      right = 0.0;
      hub = True;
}

static void
resetExpression(void)
{
      right = left = 0.0;
      pendingOperation = '\0';
      hub = False;
      resetWholeExpression();
}

static void
parse(double input, Boolean numeral, char newOperation)
{
      if (numeral) {
            if (negateNext) {
                  negateNext = False;
                  right = -input;
            } else {
                  right = input;
            }
      } else if (hub) {
            numeral = True;
            hub = False;
      }
      if (orderASCII[(int) newOperation] == equate) {
            switch (newOperation) {
            case '(':
                  incNestingLevel();
                  (void) storeExpressionParen(&left, &pendingOperation);
                  right = left; /* "#(" # is lost forever */
                  break;
            case ')': /* Evaluate last term and restore variable and operation. */
                  decNestingLevel();
                  if (pendingOperation != '\0' && numeral) /* this stops 4+) = 8 */
                        left = evaluateDouble(left, pendingOperation, right);
                  if (pendingOperation == '\0' && numeral)
                        left = right;
                  else {
                        evaluateExpressionParen(&left, &pendingOperation);
                        pendingOperation = '\0';
                        right = left;
                        if (!emptyExpression()) /* ignore uneven "())" */
                        {
                              getPreviousExpressionPart (&left, &pendingOperation);
                              hub = True;
                        }
                  }
                  break;
            case '=':
                  /* Evaluate term and restore variable and operation. */
                  resetNestingLevel();
                  if (pendingOperation != '\0' && numeral) {
                        /* this stops 4+= = 8 (2+2) */
                        left = evaluateDouble(left, pendingOperation,
                              right);
                  }
                  if (pendingOperation == '\0' && numeral) {
                        left = right;
                  } else {
                        evaluateExpression(&left, &pendingOperation);
                        right = left;
                  }
                  break;
            default:
                  resetExpression();
            }
      } else if (orderASCII[(int) newOperation] == constant) {
            switch (newOperation) {
            case 'e':   /* natural logarithm */
                  right = M_E;
                  break;
            case 'p':   /* pi */
                  right = M_PI;
                  break;
            default:
                  resetExpression();
            }
            hub = True;
      } else if (orderASCII[(int) newOperation] == unary) {
            right = evaluateSingle(right, newOperation);
            if (pendingOperation == '\0')
                  left = right;
            hub = True;
      } else if (orderASCII[(int) newOperation] != notused) {
            /* binary operation */
            if (!numeral) {
                  if (previousOrder()) /* this stops 2*+ = 6 (2*2+2) */ {
                        getPreviousExpressionPart(&left,
                              &pendingOperation);
                        (void) evaluateExpressionOrder(&left,
                              &pendingOperation, &right,
                              newOperation);
                        right = left;
                  } else if (pendingOperation != '\0') {
                        resetExpression();
                  } else if (newOperation == '-') {
                        negateNext = True;
                  }
            } else {
                  (void) evaluateExpressionOrder(&left,
                        &pendingOperation, &right, newOperation);
                  right = left;
            }
            pendingOperation = newOperation;
      } else { /* not used operation */
            resetExpression();
      }
      formatToDisplay(memoryBuf, right);
      (void) strcpy(displayBuf, memoryBuf); /* update display */
}

static void
inputOperator(char input)
{
      if (!gotFirstDigit) {
            parse(0.0, False, input);
      } else {
            parse(formatFromDisplay(currentBase, memoryBuf), True, input);
      }
      reset();
}

static Boolean
inputNumeric(char input)
{
      int i = digits - 1, j;

      if (!IS_VALID(input, currentBase)) {
            reset();
            return False;
      }
      if (IS_DIGIT(input)) {
            gotFirstDigit = True;
            if (memoryBuf[0] == '0' && memoryBuf[1] == '\0') {
                  memoryBuf[0] = input;
            } else {
                  memoryBuf[digits] = input;
                  digits++;
                  memoryBuf[digits] = '\0';
            }
      } else switch(input) {
      case '.':
            if (period) {
                  reset(); /* Handle multiple '.' */
            }
            period = True;
            memoryBuf[digits] = input;
            digits++;
            memoryBuf[digits] = '\0';
            break;
      case '~': /* Handle +/- */
            /* Note: if `memoryBuf == "0"' then "+/-" should act
               as a unary operation, that is, if no number is entered,
               it should act on the result. */
            if (!gotFirstDigit) {
                  inputOperator ('~');
                  return False;
            }
            if (memoryBuf[0] == '0' && memoryBuf[1] == '\0')
                  return False;
            while (memoryBuf[i] != ' ' && memoryBuf[i] != '-' &&
                  memoryBuf[i] != ',' && i != 0)
                  i--;
            if (memoryBuf[i] == '-') {
                  /* Take a '-' from front of a negative number */
                  while (memoryBuf[i] != '\0') {
                        memoryBuf[i] = memoryBuf[i + 1];
                        i++;
                  }
                  digits--;
            } else {
                  /* Put the '-' in the front of a positive number */
                  if (digits == MAXVALUELENGTH - 1)
                        return False;
                  j = digits;
                  while (j >= i) {
                        memoryBuf[j + 1] = memoryBuf[j];
                        j--;
                  }
                  memoryBuf[i] = '-';
                  digits++;
            }
            break;
      default:
            reset();
            return False;
      }
      return True;
}

static void
convertStringToAbacus(AbacusWidget w, char *string)
{
      int decimal = 0;
      int num, factor, i, sign = 0, len = strlen(string);

      ClearRails(w);
      while (string[decimal] != '\0' && string[decimal] != '.')
            decimal++;
      if (string[0] == '-' || string[0] == '+') {
            sign = 1;
      }
      for (i = 0; i < decimal - sign; i++) {
            /* w->abacus.displayBase == w->abacus.base and all that ... */
            num = char2Int(string[decimal - 1 - i]);
            factor = num / w->abacus.decks[TOP].factor;
            if (factor > 0) {
                  SetAbacusMove(w, ABACUS_MOVE, 0, 1, i, factor);
                  num = num - factor * w->abacus.decks[TOP].factor;
            }
            factor = num / w->abacus.decks[BOTTOM].factor;
            if (factor > 0) {
                  SetAbacusMove(w, ABACUS_MOVE, 0, 0, i, factor);
            }
      }
      if (w->abacus.sign && string[0] == '-') {
            SetAbacusMove(w, ABACUS_MOVE, 0, 0, w->abacus.rails -
                  w->abacus.decimalPosition - 1, 1);
      }
      for (i = 0; i < len - decimal - 1 &&
                  i < w->abacus.decimalPosition; i++) {
            num = char2Int(string[decimal + i + 1]);
            factor = num / w->abacus.decks[TOP].factor;
            if (factor > 0) {
                  SetAbacusMove(w, ABACUS_MOVE, 0, 1, -i - 1, factor);
                  num = num - factor * w->abacus.decks[TOP].factor;
            }
            factor = num / w->abacus.decks[BOTTOM].factor;
            if (factor > 0) {
                  SetAbacusMove(w, ABACUS_MOVE, 0, 0, -i - 1, factor);
            }
      }
}

void calculate(AbacusWidget w, char * buffer)
{
      unsigned int i;

      if (w->abacus.displayBase != w->abacus.base)
            return;
      currentBase = w->abacus.displayBase;
      fractDigits = logInt(powInt(DEFAULTBASE, DEFAULTFRACTDIGITS),
            currentBase);
      resetExpression();
      memoryBuf[0] = '0';
      memoryBuf[1] = '\0';
      displayBuf[0] = '0';
      displayBuf[1] = '\0';
      for (i = 0; i < strlen(buffer); i++) {
            switch (operationASCII[(int) buffer[i]]) {
            case undefined:
#ifdef DEBUG
                  (void) printf("undefined\n");
#endif
                  break;
            case ignore:
#ifdef DEBUG
                  (void) printf("ignore\n");
#endif
                  break;
            case numeric:
#ifdef DEBUG
                  (void) printf("number %c %s\n", buffer[i], memoryBuf);
#endif
                  (void) inputNumeric(buffer[i]);
                  break;
            case operation:
#ifdef DEBUG
                  (void) printf("operate %c %s\n", buffer[i], memoryBuf);
#endif
                  inputOperator(buffer[i]);
                  break;
            case clear:
#ifdef DEBUG
                  (void) printf("clear\n");
#endif
                  break;
            default:
#ifdef DEBUG
                  (void) printf("QUIT\n");
#endif
                  break;
            }
      }
      inputOperator('=');
#ifdef DEBUG
      (void) printf("displayBuf %s\n", displayBuf);
#endif
      convertStringToAbacus(w, displayBuf);
}

Generated by  Doxygen 1.6.0   Back to index