112e1d9cbSmrg/*
24d9b34d9Smrg *  math.c  -  mathematics functions for a hand calculator under X
34d9b34d9Smrg *
44d9b34d9Smrg *  Author:    John H. Bradley, University of Pennsylvania
54d9b34d9Smrg *                (bradley@cis.upenn.edu)
64d9b34d9Smrg *                     March, 1987
74d9b34d9Smrg *
84d9b34d9Smrg *  RPN mode added and port to X11 by Mark Rosenstein, MIT Project Athena
94d9b34d9Smrg *
104d9b34d9Smrg *  Modified to be a client of the Xt toolkit and the Athena widget set by
11498372abSmrg *  Donna Converse, MIT X Consortium.  This is all that remains of the
124d9b34d9Smrg *  original calculator, and it still needs to be rewritten.  The HP
13498372abSmrg *  functionality should be separated from the TI functionality.
144d9b34d9Smrg *  Beware the HP functions: there are still errors here.
154d9b34d9Smrg *
164d9b34d9Smrg *  Geoffrey Coram fixed most of the HP mode bugs.
174d9b34d9Smrg */
184d9b34d9Smrg
194d9b34d9Smrg#include "xcalc.h"
204d9b34d9Smrg
2119d64aeeSmrg#ifndef M_PI        /* sometimes defined in math.h */
2219d64aeeSmrg#define M_PI        3.14159265358979323846
234d9b34d9Smrg#endif
2419d64aeeSmrg
2519d64aeeSmrg#ifndef M_E         /* sometimes defined in math.h */
2619d64aeeSmrg#define M_E           2.7182818284590452354
2719d64aeeSmrg#endif
2819d64aeeSmrg
294d9b34d9Smrg#define MAXDISP     11
304d9b34d9Smrg#define DEG 0		/* DRG mode.  used for trig calculations */
314d9b34d9Smrg#define RAD 1
324d9b34d9Smrg#define GRAD 2
3319d64aeeSmrg
344d9b34d9Smrg#define True	1
354d9b34d9Smrg#define False   0
364d9b34d9Smrg
374d9b34d9Smrg#ifndef IEEE
388512f934Smrgjmp_buf env;
394d9b34d9Smrg#endif
404d9b34d9Smrg
41498372abSmrg
424d9b34d9Smrg/* This section is all of the state machine that implements the calculator
434d9b34d9Smrg * functions.  Much of it is shared between the infix and rpn modes.
444d9b34d9Smrg */
454d9b34d9Smrg
462256ab8cSmrgstatic int flagINV, flagPAREN, flagM, drgmode, numbase;	/* display flags */
474d9b34d9Smrg
4819d64aeeSmrgstatic double drg2rad=M_PI/180.0;  /* Conversion factors for trig funcs */
4919d64aeeSmrgstatic double rad2drg=180.0/M_PI;
504d9b34d9Smrgstatic int entered=1;  /* true if display contains a valid number.
514d9b34d9Smrg                          if==2, then use 'dnum', rather than the string
52498372abSmrg                          stored in the display.  (for accuracy)
534d9b34d9Smrg                          if==3, then error occurred, only CLR & AC work */
544d9b34d9Smrg/* entered seems to be overloaded - dmc */
554d9b34d9Smrgstatic int lift_enabled = 0;	/* for rpn mode only */
564d9b34d9Smrg
574d9b34d9Smrgstatic int CLR    =0;  /* CLR clears display.  if 1, clears acc, also */
584d9b34d9Smrgstatic int Dpoint=0;  /* to prevent using decimal pt twice in a # */
594d9b34d9Smrgstatic int clrdisp=1;  /* if true clears display before entering # */
604d9b34d9Smrgstatic int lastop =kCLR;
614d9b34d9Smrgstatic int memop  =kCLR;
624d9b34d9Smrgstatic int exponent=0;
634d9b34d9Smrgstatic double acc =0.0;
644d9b34d9Smrgstatic double dnum=0.0;
654d9b34d9Smrg#define XCALC_MEMORY 10
664d9b34d9Smrgstatic double mem[XCALC_MEMORY] = { 0.0 };
674d9b34d9Smrg
684d9b34d9Smrgstatic void   DrawDisplay(void);
694d9b34d9Smrgstatic void   PushOp(int op);
704d9b34d9Smrgstatic int    PopOp(void);
714d9b34d9Smrgstatic int    isopempty(void);
724d9b34d9Smrg#ifdef DEBUG
734d9b34d9Smrgstatic void   showstack(char *string);
744d9b34d9Smrg#endif
754d9b34d9Smrgstatic void   PushNum(double num);
764d9b34d9Smrgstatic double PopNum(void);
774d9b34d9Smrgstatic void   RollNum(int dir);
784d9b34d9Smrgstatic void   ClearStacks(void);
794d9b34d9Smrgstatic int    priority(int op);
804d9b34d9Smrg
8119d64aeeSmrg#ifndef HAVE_STRLCPY
8219d64aeeSmrg/* Close enough for the short strings copied in xcalc */
8319d64aeeSmrgstatic inline size_t
8419d64aeeSmrgstrlcpy(char *dst, const char *src, size_t size)
8519d64aeeSmrg{
8619d64aeeSmrg    strncpy(dst, src, size);
8719d64aeeSmrg    dst[size - 1] = '\0';
8819d64aeeSmrg    return strlen(src);
8919d64aeeSmrg}
9019d64aeeSmrg#endif
9119d64aeeSmrg
924d9b34d9Smrg/*
934d9b34d9Smrg * The following is to deal with the unfortunate assumption that if errno
94498372abSmrg * is non-zero then an error has occurred.  On some systems (e.g. Ultrix),
954d9b34d9Smrg * sscanf will call lower level routines that will set errno.
964d9b34d9Smrg */
974d9b34d9Smrgstatic void
982256ab8cSmrgparse_double(double *dp)
994d9b34d9Smrg{
1002256ab8cSmrg    unsigned long n = 0;
1014d9b34d9Smrg    int olderrno = errno;
1024d9b34d9Smrg
1032256ab8cSmrg    switch (numbase) {
1042256ab8cSmrg    case 8:
105fc5a3af9Smrg        sscanf(dispstr, "%lo", &n);
1062256ab8cSmrg        *dp = (double)n;
1072256ab8cSmrg    break;
1082256ab8cSmrg    case 16:
109fc5a3af9Smrg        sscanf(dispstr, "%lX", &n);
1102256ab8cSmrg        *dp = (double)n;
1112256ab8cSmrg    break;
1122256ab8cSmrg    default:
113fc5a3af9Smrg        sscanf(dispstr, "%lf", dp);
1142256ab8cSmrg    }
1152256ab8cSmrg
1164d9b34d9Smrg    errno = olderrno;
1174d9b34d9Smrg    return;
1184d9b34d9Smrg}
1194d9b34d9Smrg
1202256ab8cSmrg/**
1212256ab8cSmrg * Format the given double according to the
1222256ab8cSmrg * selected number base.
1232256ab8cSmrg */
1242256ab8cSmrgstatic void
1252256ab8cSmrgformat_double(double n)
1262256ab8cSmrg{
1272256ab8cSmrg    switch (numbase) {
1282256ab8cSmrg    case 8:
1292256ab8cSmrg        snprintf(dispstr, sizeof(dispstr), "%lo", (long)n);
1302256ab8cSmrg    break;
1312256ab8cSmrg    case 16:
1322256ab8cSmrg        snprintf(dispstr, sizeof(dispstr), "%lX", (long)n);
1332256ab8cSmrg    break;
1342256ab8cSmrg    default:
1352256ab8cSmrg        snprintf(dispstr, sizeof(dispstr), "%.8g", n);
1362256ab8cSmrg    }
1372256ab8cSmrg}
1384d9b34d9Smrg
1394d9b34d9Smrg/*********************************/
1408512f934Smrgint pre_op(int keynum)
1414d9b34d9Smrg{
1424d9b34d9Smrg    if (keynum==-1) return(0);
143498372abSmrg
1444d9b34d9Smrg    errno = 0;			/* for non-IEEE machines */
1454d9b34d9Smrg
1464d9b34d9Smrg    if ( (entered==3) && !(keynum==kCLR || keynum==kOFF)) {
1474d9b34d9Smrg      if (rpn) {
1484d9b34d9Smrg	clrdisp++;
1494d9b34d9Smrg      } else {
1504d9b34d9Smrg        ringbell();
1514d9b34d9Smrg        return(1);	/* the intent was probably not to do the operation */
1524d9b34d9Smrg      }
1534d9b34d9Smrg    }
1544d9b34d9Smrg
1554d9b34d9Smrg    if (keynum != kCLR) CLR=0;
1564d9b34d9Smrg    return(0);
1574d9b34d9Smrg}
1584d9b34d9Smrg
1594d9b34d9Smrg#ifndef IEEE
1604d9b34d9Smrg
1614d9b34d9Smrg/* cannot assign result of setjmp under ANSI C, use global instead */
1624d9b34d9Smrgstatic volatile int SignalKind;
1634d9b34d9Smrg
1648512f934Smrgvoid fail_op(void)
1654d9b34d9Smrg{
1664d9b34d9Smrg    if (SignalKind == SIGFPE)
16719d64aeeSmrg	strlcpy(dispstr, "math error", sizeof(dispstr));
1688512f934Smrg    else if (SignalKind == SIGILL)
16919d64aeeSmrg	strlcpy(dispstr, "illegal operand", sizeof(dispstr));
1704d9b34d9Smrg
1714d9b34d9Smrg    entered=3;
1724d9b34d9Smrg    DrawDisplay();
1734d9b34d9Smrg    return;
1744d9b34d9Smrg}
1754d9b34d9Smrg
1764d9b34d9Smrg/*ARGSUSED*/
17719d64aeeSmrgvoid fperr(int sig)
1784d9b34d9Smrg{
1794d9b34d9Smrg#if defined(SYSV) || defined(SVR4) || defined(linux)
1808512f934Smrg    signal(SIGFPE, fperr);
1814d9b34d9Smrg#endif
1824d9b34d9Smrg    SignalKind = sig;
1834d9b34d9Smrg    longjmp(env,1);
1844d9b34d9Smrg}
1854d9b34d9Smrg
1864d9b34d9Smrg/* for VAX BSD4.3 */
1874d9b34d9Smrg/*ARGSUSED*/
18819d64aeeSmrgvoid illerr(int sig)
1894d9b34d9Smrg{
1904d9b34d9Smrg    /* not reset when caught? */
1918512f934Smrg    signal(SIGILL, illerr);
1924d9b34d9Smrg
1934d9b34d9Smrg    SignalKind = sig;
1944d9b34d9Smrg    longjmp(env,1);
1954d9b34d9Smrg}
1964d9b34d9Smrg
1974d9b34d9Smrg#endif	/* not IEEE */
1984d9b34d9Smrg
1994d9b34d9Smrg
2008512f934Smrgvoid post_op(void)
2014d9b34d9Smrg{
2024d9b34d9Smrg#ifdef DEBUG
2034d9b34d9Smrg    showstack("\0");
2044d9b34d9Smrg#endif
2054d9b34d9Smrg#ifndef IEEE
2064d9b34d9Smrg    if (errno) {
20719d64aeeSmrg        strlcpy(dispstr, "error", sizeof(dispstr));
2084d9b34d9Smrg        DrawDisplay();
2094d9b34d9Smrg        entered=3;
2104d9b34d9Smrg        errno=0;
2114d9b34d9Smrg        }
2124d9b34d9Smrg#endif
2134d9b34d9Smrg}
2142256ab8cSmrg
2154d9b34d9Smrg/*-------------------------------------------------------------------------*/
2164d9b34d9Smrgstatic void
2174d9b34d9SmrgDrawDisplay(void)
2184d9b34d9Smrg{
2192256ab8cSmrg    if (strlen(dispstr) >= MAXDISP) { /* strip out some decimal digits */
2202256ab8cSmrg        char *estr = index(dispstr,'e');  /* search for exponent part */
2214d9b34d9Smrg        if (!estr) dispstr[12]='\0';      /* no exp, just trunc. */
2224d9b34d9Smrg        else {
22319d64aeeSmrg            char tmp[32];
22419d64aeeSmrg            if (strlen(estr) <= 4)        /* leftmost 8 chars plus exponent */
22519d64aeeSmrg                snprintf(tmp, sizeof(tmp), "%.8s%s", dispstr, estr);
22619d64aeeSmrg            else                          /* leftmost 7 chars plus exponent */
22719d64aeeSmrg                snprintf(tmp, sizeof(tmp), "%.7s%s", dispstr, estr);
22819d64aeeSmrg            strlcpy(dispstr, tmp, sizeof(dispstr));
2294d9b34d9Smrg        }
23019d64aeeSmrg    }
2314d9b34d9Smrg    draw(dispstr);
2324d9b34d9Smrg    setflag(XCalc_MEMORY, (flagM));
2334d9b34d9Smrg    setflag(XCalc_INVERSE, (flagINV));
2344d9b34d9Smrg    setflag(XCalc_DEGREE, (drgmode==DEG));
2354d9b34d9Smrg    setflag(XCalc_RADIAN, (drgmode==RAD));
2364d9b34d9Smrg    setflag(XCalc_GRADAM, (drgmode==GRAD));
2374d9b34d9Smrg    setflag(XCalc_PAREN, (flagPAREN));
2382256ab8cSmrg    setflag(XCalc_HEX, (numbase==16));
2392256ab8cSmrg    setflag(XCalc_DEC, (numbase==10));
2402256ab8cSmrg    setflag(XCalc_OCT, (numbase==8));
2412256ab8cSmrg}
2422256ab8cSmrg
2432256ab8cSmrg/*-------------------------------------------------------------------------*/
2442256ab8cSmrgvoid
2452256ab8cSmrgchange_base(void)
2462256ab8cSmrg{
2472256ab8cSmrg	parse_double(&dnum);
2482256ab8cSmrg
2492256ab8cSmrg    if (dnum >= 0) {
2502256ab8cSmrg        switch (numbase) {
2512256ab8cSmrg        case 8:  numbase = 10;  break;
2522256ab8cSmrg        case 10: numbase = 16;  break;
2532256ab8cSmrg        case 16: numbase = 8;   break;
2542256ab8cSmrg        }
2552256ab8cSmrg
2562256ab8cSmrg        format_double(dnum);
2572256ab8cSmrg    } else strlcpy(dispstr, "error", sizeof(dispstr));
2582256ab8cSmrg
2592256ab8cSmrg    DrawDisplay();
2604d9b34d9Smrg}
2614d9b34d9Smrg
2624d9b34d9Smrg/*-------------------------------------------------------------------------*/
2634d9b34d9Smrgvoid
2648512f934Smrgnumeric(int keynum)
2654d9b34d9Smrg{
2660df20633Smrg  char st[2];
2674d9b34d9Smrg
2684d9b34d9Smrg  flagINV=0;
2694d9b34d9Smrg
2704d9b34d9Smrg  if (rpn && (memop == kSTO || memop == kRCL || memop == kSUM)) {
2710df20633Smrg      int cell = 0;
2720df20633Smrg
2734d9b34d9Smrg      switch (keynum) {
2744d9b34d9Smrg	case kONE:	cell = 1; break;
2754d9b34d9Smrg	case kTWO:	cell = 2; break;
2764d9b34d9Smrg	case kTHREE:	cell = 3; break;
2774d9b34d9Smrg	case kFOUR:	cell = 4; break;
2784d9b34d9Smrg	case kFIVE:	cell = 5; break;
2794d9b34d9Smrg	case kSIX:	cell = 6; break;
2804d9b34d9Smrg	case kSEVEN:	cell = 7; break;
2814d9b34d9Smrg	case kEIGHT:	cell = 8; break;
2824d9b34d9Smrg	case kNINE:	cell = 9; break;
2834d9b34d9Smrg	case kZERO:	cell = 0; break;
2844d9b34d9Smrg      }
2854d9b34d9Smrg      switch (memop) {
2864d9b34d9Smrg      case kSTO:
2874d9b34d9Smrg	mem[cell] = dnum;
2884d9b34d9Smrg	lift_enabled = 1;
2894d9b34d9Smrg	entered = 2;
2904d9b34d9Smrg	clrdisp++;
2914d9b34d9Smrg	break;
2924d9b34d9Smrg      case kRCL:
2934d9b34d9Smrg	PushNum(dnum);
2944d9b34d9Smrg	dnum = mem[cell];
2952256ab8cSmrg	format_double(dnum);
2964d9b34d9Smrg	lift_enabled = 1;
2974d9b34d9Smrg        entered = 1;
2984d9b34d9Smrg	clrdisp++;
2994d9b34d9Smrg	break;
3004d9b34d9Smrg      case kSUM:
3014d9b34d9Smrg	mem[cell] += dnum;
3024d9b34d9Smrg	lift_enabled = 1;
3034d9b34d9Smrg	entered = 2;
3044d9b34d9Smrg	clrdisp++;
3054d9b34d9Smrg	break;
3064d9b34d9Smrg      }
3074d9b34d9Smrg      memop = kCLR;
3084d9b34d9Smrg      DrawDisplay();
3094d9b34d9Smrg      return;
3104d9b34d9Smrg  }
3114d9b34d9Smrg
3124d9b34d9Smrg  if (clrdisp) {
3134d9b34d9Smrg    dispstr[0]='\0';
3144d9b34d9Smrg    exponent=Dpoint=0;
3154d9b34d9Smrg/*    if (rpn && entered==2)
3164d9b34d9Smrg      PushNum(dnum);
3174d9b34d9Smrg */
3184d9b34d9Smrg    if (rpn & lift_enabled)
3194d9b34d9Smrg	PushNum(dnum);
3204d9b34d9Smrg  }
3214d9b34d9Smrg  if ((int) strlen(dispstr) >= MAXDISP)
3224d9b34d9Smrg    return;
323498372abSmrg
3242256ab8cSmrg  st[0] = '\0';
3250df20633Smrg  switch (keynum){
3262256ab8cSmrg      case kZERO:	st[0] = '0'; break;
3274d9b34d9Smrg      case kONE:	st[0] = '1'; break;
3284d9b34d9Smrg      case kTWO:	st[0] = '2'; break;
3294d9b34d9Smrg      case kTHREE:	st[0] = '3'; break;
3304d9b34d9Smrg      case kFOUR:	st[0] = '4'; break;
3314d9b34d9Smrg      case kFIVE:	st[0] = '5'; break;
3324d9b34d9Smrg      case kSIX:	st[0] = '6'; break;
3334d9b34d9Smrg      case kSEVEN:	st[0] = '7'; break;
3342256ab8cSmrg      case kEIGHT:	if (numbase > 8)  st[0] = '8'; break;
3352256ab8cSmrg      case kNINE:	if (numbase > 8)  st[0] = '9'; break;
3362256ab8cSmrg      case kxA: 	if (numbase > 10) st[0] = 'A'; break;
3372256ab8cSmrg      case kxB: 	if (numbase > 10) st[0] = 'B'; break;
3382256ab8cSmrg      case kxC: 	if (numbase > 10) st[0] = 'C'; break;
3392256ab8cSmrg      case kxD: 	if (numbase > 10) st[0] = 'D'; break;
3402256ab8cSmrg      case kxE: 	if (numbase > 10) st[0] = 'E'; break;
3412256ab8cSmrg      case kxF: 	if (numbase > 10) st[0] = 'F'; break;
3422256ab8cSmrg    }
3432256ab8cSmrg
3442256ab8cSmrg    if (st[0] == '\0')
3452256ab8cSmrg        return;
3462256ab8cSmrg    st[1] = '\0';
3472256ab8cSmrg    strcat(dispstr,st);
3484d9b34d9Smrg
3494d9b34d9Smrg  DrawDisplay();
3504d9b34d9Smrg  if (clrdisp && keynum != kZERO)
3514d9b34d9Smrg    clrdisp=0; /*no leading 0s*/
3524d9b34d9Smrg  memop = keynum;
3534d9b34d9Smrg  entered=1;
3544d9b34d9Smrg  lift_enabled = 0;
3554d9b34d9Smrg}
3564d9b34d9Smrg
3574d9b34d9Smrgvoid
3584d9b34d9Smrgbkspf(void)
3594d9b34d9Smrg{
3604d9b34d9Smrg
3614d9b34d9Smrg  lift_enabled = 0;
3624d9b34d9Smrg
3634d9b34d9Smrg  if (! flagINV)
3644d9b34d9Smrg  {
3654d9b34d9Smrg      if (entered!=1) {
3664d9b34d9Smrg	  clearf();
3674d9b34d9Smrg	  return;
3684d9b34d9Smrg      }
3694d9b34d9Smrg      if (clrdisp)
3704d9b34d9Smrg	  return;
3714d9b34d9Smrg      if ((int) strlen(dispstr) > 0) {
3724d9b34d9Smrg#ifndef X_LOCALE
3734d9b34d9Smrg          const char *dp = localeconv()->decimal_point;
3744d9b34d9Smrg          size_t dp_len = strlen(dp);
3754d9b34d9Smrg          size_t ds_len = strlen(dispstr);
3764d9b34d9Smrg          if (ds_len >= dp_len && strcmp(dispstr + ds_len - dp_len, dp) == 0)
3774d9b34d9Smrg             Dpoint=0;
3784d9b34d9Smrg#else
3794d9b34d9Smrg	  if (dispstr[strlen(dispstr)-1] == '.')
3804d9b34d9Smrg             Dpoint=0;
381498372abSmrg#endif
3824d9b34d9Smrg	  dispstr[strlen(dispstr)-1] = 0;
3834d9b34d9Smrg      }
3844d9b34d9Smrg      if (strlen(dispstr) == 0) {
3854d9b34d9Smrg	  strcat(dispstr, "0");
3864d9b34d9Smrg	  clrdisp++;
3874d9b34d9Smrg      }
3884d9b34d9Smrg  }
3894d9b34d9Smrg  else
3904d9b34d9Smrg  {
39119d64aeeSmrg      strlcpy(dispstr, "0", sizeof(dispstr));
3924d9b34d9Smrg      dnum = 0.0;
3934d9b34d9Smrg      clrdisp++;
3944d9b34d9Smrg      flagINV = 0;
3954d9b34d9Smrg  }
3964d9b34d9Smrg  DrawDisplay();
3974d9b34d9Smrg}
3984d9b34d9Smrg
3994d9b34d9Smrgvoid
4004d9b34d9Smrgdecf(void)
4014d9b34d9Smrg{
4024d9b34d9Smrg  flagINV=0;
4034d9b34d9Smrg  if (clrdisp) {
4044d9b34d9Smrg      if (rpn && lift_enabled)
4054d9b34d9Smrg	PushNum(dnum);
40619d64aeeSmrg      strlcpy(dispstr, "0", sizeof(dispstr));
4074d9b34d9Smrg  }
4084d9b34d9Smrg  if (!Dpoint) {
4094d9b34d9Smrg#ifndef X_LOCALE
4104d9b34d9Smrg    strcat(dispstr, localeconv()->decimal_point);
4114d9b34d9Smrg#else
4124d9b34d9Smrg    strcat(dispstr, ".");
4134d9b34d9Smrg#endif
4144d9b34d9Smrg    DrawDisplay();
4154d9b34d9Smrg    Dpoint++;
4164d9b34d9Smrg  }
4174d9b34d9Smrg  clrdisp=0;
4184d9b34d9Smrg  entered=1;
4194d9b34d9Smrg}
4204d9b34d9Smrg
4214d9b34d9Smrgvoid
4224d9b34d9Smrgeef(void)
4234d9b34d9Smrg{
4244d9b34d9Smrg  flagINV=0;
4254d9b34d9Smrg  if (clrdisp) {
4264d9b34d9Smrg      if (rpn && lift_enabled)
4274d9b34d9Smrg	PushNum(dnum);
42819d64aeeSmrg      strlcpy(dispstr, rpn ? "1" : "0", sizeof(dispstr));
4294d9b34d9Smrg  }
4304d9b34d9Smrg  if (!exponent) {
4314d9b34d9Smrg    strcat(dispstr,"E+");
4324d9b34d9Smrg    DrawDisplay();
4334d9b34d9Smrg    exponent=strlen(dispstr)-1;  /* where the '-' goes */
4344d9b34d9Smrg  }
4354d9b34d9Smrg  clrdisp=0;
4364d9b34d9Smrg  entered=1;
4374d9b34d9Smrg}
4384d9b34d9Smrg
4394d9b34d9Smrgvoid
4404d9b34d9Smrgclearf(void)
4414d9b34d9Smrg{
4424d9b34d9Smrg  flagINV=0;
4434d9b34d9Smrg  if (CLR && !rpn) { /* clear all */
4444d9b34d9Smrg    ClearStacks();
4454d9b34d9Smrg    flagPAREN=0;
4464d9b34d9Smrg  }
4474d9b34d9Smrg  CLR++;
4484d9b34d9Smrg  exponent=Dpoint=0;
4494d9b34d9Smrg  clrdisp=1;
4504d9b34d9Smrg  entered=1;
45119d64aeeSmrg  strlcpy(dispstr, "0", sizeof(dispstr));
4524d9b34d9Smrg  DrawDisplay();
4534d9b34d9Smrg}
4544d9b34d9Smrg
4554d9b34d9Smrgvoid
4564d9b34d9Smrgnegf(void)
4574d9b34d9Smrg{
4584d9b34d9Smrg  flagINV=0;
4594d9b34d9Smrg  if (exponent) {       /* neg the exponent */
4604d9b34d9Smrg    if (dispstr[exponent]=='-')
4614d9b34d9Smrg      dispstr[exponent]='+';
4624d9b34d9Smrg    else
4634d9b34d9Smrg      dispstr[exponent]='-';
4644d9b34d9Smrg    DrawDisplay();
4654d9b34d9Smrg    return;
4664d9b34d9Smrg  }
4674d9b34d9Smrg
4684d9b34d9Smrg  if (strcmp("0",dispstr)==0)
4694d9b34d9Smrg    return;			/* don't neg a zero */
4704d9b34d9Smrg  if (dispstr[0]=='-')	 	/* already neg-ed */
4714d9b34d9Smrg    strcpy(dispstr,dispstr+1);  /* move str left once */
4724d9b34d9Smrg  else {			/* not neg-ed.  add a '-' */
4734d9b34d9Smrg    char tmp[32];
47419d64aeeSmrg    snprintf(tmp, sizeof(tmp), "-%s", dispstr);
47519d64aeeSmrg    strlcpy(dispstr, tmp, sizeof(dispstr));
4764d9b34d9Smrg  }
4774d9b34d9Smrg  if (entered==2)
4784d9b34d9Smrg    dnum = -1.0 * dnum;
4794d9b34d9Smrg  DrawDisplay();
4804d9b34d9Smrg}
4814d9b34d9Smrg
4824d9b34d9Smrg/* Two operand functions for infix calc */
4834d9b34d9Smrgvoid
4844d9b34d9Smrgtwoop(int keynum)
4854d9b34d9Smrg{
4864d9b34d9Smrg  if (flagINV) {
4874d9b34d9Smrg    flagINV=0;
4884d9b34d9Smrg    DrawDisplay();
4894d9b34d9Smrg  }
4904d9b34d9Smrg
4914d9b34d9Smrg  if (!entered) {		/* something like "5+*" */
4924d9b34d9Smrg    if (!isopempty())
493fc5a3af9Smrg      PopOp();			/* replace the prev op */
4944d9b34d9Smrg    PushOp(keynum);		/* with the new one */
4954d9b34d9Smrg    return;
4964d9b34d9Smrg  }
497498372abSmrg
4984d9b34d9Smrg  if (entered==1)
4992256ab8cSmrg    parse_double(&dnum);
5004d9b34d9Smrg
5014d9b34d9Smrg  clrdisp=CLR=1;
5024d9b34d9Smrg  entered=Dpoint=exponent=0;
5034d9b34d9Smrg
5044d9b34d9Smrg  if (!isopempty()) {  /* there was a previous op */
5054d9b34d9Smrg    lastop=PopOp();   /* get it */
5064d9b34d9Smrg
5074d9b34d9Smrg    if (lastop==kLPAR) {  /* put it back */
5084d9b34d9Smrg      PushOp(kLPAR);
5094d9b34d9Smrg      PushOp(keynum);
5104d9b34d9Smrg      PushNum(dnum);
5114d9b34d9Smrg      return;
5124d9b34d9Smrg    }
5134d9b34d9Smrg
5144d9b34d9Smrg    /* now, if the current op (keynum) is of
5154d9b34d9Smrg       higher priority than the lastop, the current
516498372abSmrg       op and number are just pushed on top
5172256ab8cSmrg       Priorities:  (Y^X) > *,/ > +,- > >>,<< > & > ^ > ~ */
518498372abSmrg
5194d9b34d9Smrg    if (priority(keynum) > priority(lastop)) {
5204d9b34d9Smrg      PushNum(dnum);
5214d9b34d9Smrg      PushOp(lastop);
5224d9b34d9Smrg      PushOp(keynum);
5234d9b34d9Smrg    } else {  /* execute lastop on lastnum and dnum, push
5244d9b34d9Smrg	       result and current op on stack */
5254d9b34d9Smrg      acc=PopNum();
5264d9b34d9Smrg      switch (lastop) { /* perform the operation */
5274d9b34d9Smrg      case kADD: acc += dnum;  break;
5284d9b34d9Smrg      case kSUB: acc -= dnum;  break;
5294d9b34d9Smrg      case kMUL: acc *= dnum;  break;
5304d9b34d9Smrg      case kDIV: acc /= dnum;  break;
5314d9b34d9Smrg      case kPOW: acc =  pow(acc,dnum);  break;
5322256ab8cSmrg      case kMOD: acc = (long)acc %  (long)dnum;  break;
5332256ab8cSmrg      case kAND: acc = (long)acc &  (long)dnum;  break;
5342256ab8cSmrg      case kOR:  acc = (long)acc |  (long)dnum;  break;
5352256ab8cSmrg      case kXOR: acc = (long)acc ^  (long)dnum;  break;
5362256ab8cSmrg      case kSHL: acc = (long)acc << (long)dnum;  break;
5372256ab8cSmrg      case kSHR: acc = (long)acc >> (long)dnum;  break;
5382256ab8cSmrg      }
5392256ab8cSmrg
5404d9b34d9Smrg      PushNum(acc);
5414d9b34d9Smrg      PushOp(keynum);
5422256ab8cSmrg      format_double(acc);
5434d9b34d9Smrg      DrawDisplay();
5444d9b34d9Smrg      dnum=acc;
5454d9b34d9Smrg    }
5464d9b34d9Smrg  }
5474d9b34d9Smrg  else { /* op stack is empty, push op and num */
5484d9b34d9Smrg    PushOp(keynum);
5494d9b34d9Smrg    PushNum(dnum);
550498372abSmrg  }
551498372abSmrg}
5524d9b34d9Smrg
5534d9b34d9Smrg/* Two operand functions for rpn calc */
5544d9b34d9Smrgvoid
5554d9b34d9Smrgtwof(int keynum)
5564d9b34d9Smrg{
5574d9b34d9Smrg  if (flagINV) {
5584d9b34d9Smrg    flagINV=0;
5594d9b34d9Smrg    DrawDisplay();
5604d9b34d9Smrg  }
5614d9b34d9Smrg  if (!entered)
5624d9b34d9Smrg    return;
5634d9b34d9Smrg  if (entered==1)
5642256ab8cSmrg    parse_double(&dnum);
5654d9b34d9Smrg  acc = PopNum();
5664d9b34d9Smrg  switch(keynum) {
5674d9b34d9Smrg  case kADD: acc += dnum;  break;
5684d9b34d9Smrg  case kSUB: acc -= dnum;  break;
5694d9b34d9Smrg  case kMUL: acc *= dnum;  break;
5704d9b34d9Smrg  case kDIV: acc /= dnum;  break;
5714d9b34d9Smrg  case kPOW: acc =  pow(acc,dnum);  break;
5722256ab8cSmrg  case kXXY: PushNum(dnum);  break;
5732256ab8cSmrg  case kMOD: acc = (long)acc %  (long)dnum;  break;
5742256ab8cSmrg  case kAND: acc = (long)acc &  (long)dnum;  break;
5752256ab8cSmrg  case kOR:  acc = (long)acc |  (long)dnum;  break;
5762256ab8cSmrg  case kXOR: acc = (long)acc ^  (long)dnum;  break;
5772256ab8cSmrg  case kSHL: acc = (long)acc << (long)dnum;  break;
5782256ab8cSmrg  case kSHR: acc = (long)acc >> (long)dnum;  break;
5794d9b34d9Smrg  }
5802256ab8cSmrg
5812256ab8cSmrg  format_double(acc);
5824d9b34d9Smrg  DrawDisplay();
5834d9b34d9Smrg  clrdisp++;
5844d9b34d9Smrg  Dpoint = exponent = 0;
5854d9b34d9Smrg  entered = 2;
5864d9b34d9Smrg  lift_enabled = 1;
5874d9b34d9Smrg  dnum = acc;
5884d9b34d9Smrg}
5894d9b34d9Smrg
5904d9b34d9Smrgvoid
5914d9b34d9Smrgentrf(void)
5924d9b34d9Smrg{
5934d9b34d9Smrg  flagINV=0;
5944d9b34d9Smrg  if (!entered)
5954d9b34d9Smrg    return;
5964d9b34d9Smrg
5974d9b34d9Smrg  clrdisp=CLR=1;
5984d9b34d9Smrg  Dpoint=exponent=0;
5994d9b34d9Smrg
6004d9b34d9Smrg  if (entered==1)
6012256ab8cSmrg    parse_double(&dnum);
6024d9b34d9Smrg  entered=2;
6034d9b34d9Smrg  memop = kENTR;
6044d9b34d9Smrg  PushNum(dnum);
6054d9b34d9Smrg  lift_enabled = 0;
6064d9b34d9Smrg}
6074d9b34d9Smrg
6084d9b34d9Smrgvoid
6094d9b34d9Smrgequf(void)
6104d9b34d9Smrg{
6114d9b34d9Smrg  flagINV=0;
6124d9b34d9Smrg  if (!entered)
6134d9b34d9Smrg    return;
6144d9b34d9Smrg
6154d9b34d9Smrg  clrdisp=CLR=1;
6164d9b34d9Smrg  Dpoint=exponent=0;
6174d9b34d9Smrg
6184d9b34d9Smrg  if (entered==1)
6192256ab8cSmrg    parse_double(&dnum);
6204d9b34d9Smrg  entered=2;
6214d9b34d9Smrg
6224d9b34d9Smrg  PushNum(dnum);
6234d9b34d9Smrg
6244d9b34d9Smrg  while (!isopempty()) {  /* do all pending ops */
6254d9b34d9Smrg    dnum=PopNum();
6264d9b34d9Smrg    acc=PopNum();
6274d9b34d9Smrg    lastop=PopOp();
6284d9b34d9Smrg    switch (lastop) {
6294d9b34d9Smrg    case kADD:  acc += dnum;
6304d9b34d9Smrg		break;
6314d9b34d9Smrg    case kSUB:  acc -= dnum;
6324d9b34d9Smrg		break;
6334d9b34d9Smrg    case kMUL:  acc *= dnum;
6344d9b34d9Smrg		break;
6354d9b34d9Smrg    case kDIV:  acc /= dnum;
6364d9b34d9Smrg		break;
6374d9b34d9Smrg    case kPOW:  acc = pow(acc,dnum);
6384d9b34d9Smrg		break;
6394d9b34d9Smrg    case kLPAR:	flagPAREN--;
6404d9b34d9Smrg		PushNum(acc);
6414d9b34d9Smrg		break;
6422256ab8cSmrg    case kMOD:  acc = (long)acc % (long)dnum;
6432256ab8cSmrg		break;
6442256ab8cSmrg    case kAND:  acc = (long)acc & (long)dnum;
6452256ab8cSmrg		break;
6462256ab8cSmrg    case kOR:   acc = (long)acc | (long)dnum;
6472256ab8cSmrg		break;
6482256ab8cSmrg    case kXOR:  acc = (long)acc ^ (long)dnum;
6492256ab8cSmrg		break;
6502256ab8cSmrg    case kSHL:  acc = (long)acc << (long)dnum;
6512256ab8cSmrg		break;
6522256ab8cSmrg    case kSHR:  acc = (long)acc >> (long)dnum;
6532256ab8cSmrg		break;
6544d9b34d9Smrg    }
6554d9b34d9Smrg    dnum=acc;
6564d9b34d9Smrg    PushNum(dnum);
6574d9b34d9Smrg  }
6584d9b34d9Smrg
6592256ab8cSmrg  format_double(dnum);
6604d9b34d9Smrg  DrawDisplay();
6614d9b34d9Smrg}
662498372abSmrg
6634d9b34d9Smrgvoid
6644d9b34d9Smrglparf(void)
6654d9b34d9Smrg{
6664d9b34d9Smrg  flagINV=0;
6674d9b34d9Smrg  PushOp(kLPAR);
6684d9b34d9Smrg  flagPAREN++;
6694d9b34d9Smrg  DrawDisplay();
6704d9b34d9Smrg}
6714d9b34d9Smrg
6724d9b34d9Smrgvoid
6734d9b34d9Smrgrollf(void)
6744d9b34d9Smrg{
6754d9b34d9Smrg  if (!entered)
6764d9b34d9Smrg    return;
6774d9b34d9Smrg  if (entered==1)
6782256ab8cSmrg    parse_double(&dnum);
6794d9b34d9Smrg  entered = 2;
6804d9b34d9Smrg  lift_enabled = 1;
6814d9b34d9Smrg  RollNum(flagINV);
6824d9b34d9Smrg  flagINV=0;
6834d9b34d9Smrg  clrdisp++;
6842256ab8cSmrg  format_double(dnum);
6854d9b34d9Smrg  DrawDisplay();
6864d9b34d9Smrg}
6874d9b34d9Smrg
6884d9b34d9Smrgvoid
6894d9b34d9Smrgrparf(void)
6904d9b34d9Smrg{
6914d9b34d9Smrg  flagINV=0;
6924d9b34d9Smrg  if (!entered)
6934d9b34d9Smrg    return;
6944d9b34d9Smrg
6954d9b34d9Smrg  if (!flagPAREN)
6964d9b34d9Smrg    return;
697498372abSmrg
6984d9b34d9Smrg  clrdisp++;
6994d9b34d9Smrg  Dpoint=exponent=0;
7004d9b34d9Smrg
7014d9b34d9Smrg  if (entered==1)
7022256ab8cSmrg    parse_double(&dnum);
7034d9b34d9Smrg  entered=2;
7044d9b34d9Smrg
7054d9b34d9Smrg  PushNum(dnum);
7064d9b34d9Smrg  while (!isopempty() && (lastop=PopOp())!=kLPAR) {
7074d9b34d9Smrg    /* do all pending ops, back to left paren */
7084d9b34d9Smrg    dnum=PopNum();
7094d9b34d9Smrg    acc=PopNum();
7104d9b34d9Smrg    switch (lastop) {
7114d9b34d9Smrg    case kADD:  acc += dnum;
7124d9b34d9Smrg		break;
7134d9b34d9Smrg    case kSUB:  acc -= dnum;
7144d9b34d9Smrg		break;
7154d9b34d9Smrg    case kMUL:  acc *= dnum;
7164d9b34d9Smrg		break;
7174d9b34d9Smrg    case kDIV:  acc /= dnum;
7184d9b34d9Smrg		break;
7194d9b34d9Smrg    case kPOW:  acc = pow(acc,dnum);
7204d9b34d9Smrg		break;
7212256ab8cSmrg    case kMOD:  acc = (long)acc % (long)dnum;
7222256ab8cSmrg		break;
7232256ab8cSmrg    case kAND:  acc = (long)acc & (long)dnum;
7242256ab8cSmrg		break;
7252256ab8cSmrg    case kOR:   acc = (long)acc | (long)dnum;
7262256ab8cSmrg		break;
7272256ab8cSmrg    case kXOR:  acc = (long)acc ^ (long)dnum;
7282256ab8cSmrg		break;
7292256ab8cSmrg    case kSHL:  acc = (long)acc << (long)dnum;
7302256ab8cSmrg		break;
7312256ab8cSmrg    case kSHR:  acc = (long)acc >> (long)dnum;
7322256ab8cSmrg		break;
7334d9b34d9Smrg    }
7344d9b34d9Smrg    dnum=acc;
7354d9b34d9Smrg    PushNum(dnum);
7364d9b34d9Smrg  }
737fc5a3af9Smrg  PopNum();
7384d9b34d9Smrg  flagPAREN--;
7394d9b34d9Smrg  entered=2;
7402256ab8cSmrg  format_double(dnum);
7414d9b34d9Smrg  DrawDisplay();
7424d9b34d9Smrg}
7434d9b34d9Smrg
7444d9b34d9Smrgvoid
7454d9b34d9Smrgdrgf(void)
7464d9b34d9Smrg{
7474d9b34d9Smrg  if (flagINV) {
7484d9b34d9Smrg    if (entered==1)
7492256ab8cSmrg      parse_double(&dnum);
7504d9b34d9Smrg    switch (drgmode) {
75119d64aeeSmrg    case DEG:  dnum=dnum*M_PI/180.0;    break;
75219d64aeeSmrg    case RAD:  dnum=dnum*200.0/M_PI;    break;
7534d9b34d9Smrg    case GRAD: dnum=dnum*90.0/100.0;  break;
7544d9b34d9Smrg    }
7554d9b34d9Smrg    entered=2;
7564d9b34d9Smrg    clrdisp=1;
7574d9b34d9Smrg    flagINV=0;
7582256ab8cSmrg    format_double(dnum);
7594d9b34d9Smrg  }
760498372abSmrg
7614d9b34d9Smrg  flagINV=0;
7624d9b34d9Smrg  drgmode = (drgmode + 1) % 3;
7634d9b34d9Smrg  switch (drgmode) {
76419d64aeeSmrg  case DEG:  drg2rad=M_PI / 180.0;
76519d64aeeSmrg	     rad2drg=180.0 / M_PI;
7664d9b34d9Smrg	     break;
7674d9b34d9Smrg  case RAD:  drg2rad=1.0;
7684d9b34d9Smrg	     rad2drg=1.0;
7694d9b34d9Smrg	     break;
77019d64aeeSmrg  case GRAD: drg2rad=M_PI / 200.0;
77119d64aeeSmrg	     rad2drg=200.0 / M_PI;
7724d9b34d9Smrg	     break;
7734d9b34d9Smrg  }
7744d9b34d9Smrg  DrawDisplay();
7754d9b34d9Smrg}
7764d9b34d9Smrg
7774d9b34d9Smrgvoid
7784d9b34d9Smrginvf(void)
7794d9b34d9Smrg{
7804d9b34d9Smrg  flagINV = ~flagINV;
7814d9b34d9Smrg  DrawDisplay();
7824d9b34d9Smrg}
7834d9b34d9Smrg
7844d9b34d9Smrgvoid
7854d9b34d9Smrgmemf(int keynum)
7864d9b34d9Smrg{
7874d9b34d9Smrg    memop = keynum;
7884d9b34d9Smrg    if (entered==1)
7892256ab8cSmrg      parse_double(&dnum);
7904d9b34d9Smrg    entered = 2;
7914d9b34d9Smrg    clrdisp++;
7924d9b34d9Smrg    lift_enabled = 0;
7934d9b34d9Smrg}
7944d9b34d9Smrg
7954d9b34d9Smrgvoid
7964d9b34d9Smrgoneop(int keynum)
7974d9b34d9Smrg{
7984d9b34d9Smrg  int i,j;
7994d9b34d9Smrg  double dtmp;
8004d9b34d9Smrg
8014d9b34d9Smrg  if (entered==1)
8022256ab8cSmrg    parse_double(&dnum);
8034d9b34d9Smrg  entered = 2;
8044d9b34d9Smrg
8054d9b34d9Smrg  switch (keynum) {  /* do the actual math fn. */
80619d64aeeSmrg  case kE:     if (rpn && memop != kENTR) PushNum(dnum); dnum=M_E;  break;
80719d64aeeSmrg  case kPI:    if (rpn && memop != kENTR) PushNum(dnum); dnum=M_PI;  break;
8084d9b34d9Smrg  case kRECIP: dnum=1.0/dnum;  break;
8090df20633Smrg  case kSQR:   flagINV = !flagINV; /* fall through */
8104d9b34d9Smrg  case kSQRT:  if (flagINV) dnum=dnum*dnum;
8114d9b34d9Smrg	       else dnum=sqrt(dnum);
8124d9b34d9Smrg	       break;
8130df20633Smrg  case k10X:   flagINV = !flagINV; /* fall through */
8144d9b34d9Smrg  case kLOG:   if (flagINV) dnum=pow(10.0,dnum);
8154d9b34d9Smrg  	       else dnum=log10(dnum);
8164d9b34d9Smrg	       break;
8170df20633Smrg  case kEXP:   flagINV = !flagINV; /* fall through */
8184d9b34d9Smrg  case kLN:    if (flagINV) dnum=exp(dnum);
8194d9b34d9Smrg	       else dnum=log(dnum);
8204d9b34d9Smrg	       break;
8214d9b34d9Smrg  case kSIN:   if (flagINV) dnum=asin(dnum)*rad2drg;
8224d9b34d9Smrg	       else dnum=sin(dnum*drg2rad);
8234d9b34d9Smrg	       break;
8244d9b34d9Smrg  case kCOS:   if (flagINV) dnum=acos(dnum)*rad2drg;
8254d9b34d9Smrg	       else dnum=cos(dnum*drg2rad);
8264d9b34d9Smrg	       break;
8274d9b34d9Smrg  case kTAN:   if (flagINV) dnum=atan(dnum)*rad2drg;
8284d9b34d9Smrg	       else dnum=tan(dnum*drg2rad);
8294d9b34d9Smrg	       break;
8304d9b34d9Smrg  case kSTO:   mem[0]=dnum;  flagM=!(mem[0]==0.0);  break;
8314d9b34d9Smrg  case kRCL:   if (rpn && lift_enabled) PushNum(dnum);
8324d9b34d9Smrg               dnum=mem[0];  flagM=!(mem[0]==0.0);  break;
8334d9b34d9Smrg  case kSUM:   mem[0]+=dnum; flagM=!(mem[0]==0.0);  break;
8344d9b34d9Smrg  case kEXC:   dtmp=dnum; dnum=mem[0];  mem[0]=dtmp;
8354d9b34d9Smrg	       flagM=!(mem[0]==0.0);  break;
8364d9b34d9Smrg  case kFACT:  if (floor(dnum)!=dnum || dnum<0.0 || dnum>500.0) {
83719d64aeeSmrg                 strlcpy(dispstr, "error", sizeof(dispstr));
8384d9b34d9Smrg		 entered=3;
8394d9b34d9Smrg		 break;
8404d9b34d9Smrg	       }
8418512f934Smrg	       dtmp = floor(dnum); i = dtmp;
842498372abSmrg	       for (j=1,dnum=1.0; j<=i; j++)
8434d9b34d9Smrg		 dnum*=(float) j;
8444d9b34d9Smrg	       break;
8452256ab8cSmrg  case kNOT:   dnum = ~(long)dnum;  break;
8462256ab8cSmrg  case kTRUNC: dnum = trunc(dnum);  break;
8474d9b34d9Smrg  }
848498372abSmrg
8494d9b34d9Smrg  if (entered==3) {  /* error */
8504d9b34d9Smrg    DrawDisplay();
8514d9b34d9Smrg    return;
8524d9b34d9Smrg  }
8534d9b34d9Smrg
8544d9b34d9Smrg  memop = keynum;
8554d9b34d9Smrg  entered=2;
8564d9b34d9Smrg  clrdisp=1;
8574d9b34d9Smrg  flagINV=0;
8584d9b34d9Smrg  lift_enabled = 1;
8592256ab8cSmrg  format_double(dnum);
8604d9b34d9Smrg  DrawDisplay();
8614d9b34d9Smrg}
8624d9b34d9Smrg
8634d9b34d9Smrgvoid
8644d9b34d9Smrgofff(void)
8654d9b34d9Smrg{
8664d9b34d9Smrg  /* full reset */
8674d9b34d9Smrg  ResetCalc();
8684d9b34d9Smrg  entered=clrdisp=1;
8694d9b34d9Smrg  lift_enabled = 0;
8704d9b34d9Smrg  dnum=mem[0]=0.0;
8714d9b34d9Smrg  if (rpn)
8720df20633Smrg      for (int i=1; i < XCALC_MEMORY; i++)
8734d9b34d9Smrg	  mem[i]=0.0;
8744d9b34d9Smrg  exponent=Dpoint=0;
8754d9b34d9Smrg  DrawDisplay();
8764d9b34d9Smrg}
8774d9b34d9Smrg
8784d9b34d9Smrg
8794d9b34d9Smrg#define STACKMAX 32
8804d9b34d9Smrgstatic int opstack[STACKMAX];
8814d9b34d9Smrgstatic int opsp;
8824d9b34d9Smrgstatic double numstack[STACKMAX];
8834d9b34d9Smrgstatic int numsp;
8844d9b34d9Smrg
8854d9b34d9Smrg
8864d9b34d9Smrg/*******/
8874d9b34d9Smrgstatic void
8888512f934SmrgPushOp(int op)
8894d9b34d9Smrg/*******/
8904d9b34d9Smrg{
89119d64aeeSmrg  if (opsp==STACKMAX) {
89219d64aeeSmrg      strlcpy(dispstr, "stack error", sizeof(dispstr));
89319d64aeeSmrg      entered=3;
89419d64aeeSmrg  } else
89519d64aeeSmrg      opstack[opsp++]=op;
8964d9b34d9Smrg}
8974d9b34d9Smrg
8984d9b34d9Smrg/*******/
8994d9b34d9Smrgstatic int
9004d9b34d9SmrgPopOp(void)
9014d9b34d9Smrg/*******/
9024d9b34d9Smrg{
9034d9b34d9Smrg  if (opsp==0) {
90419d64aeeSmrg      strlcpy(dispstr, "stack error", sizeof(dispstr));
9054d9b34d9Smrg      entered=3;
9064d9b34d9Smrg      return(kNOP);
9074d9b34d9Smrg  } else
9084d9b34d9Smrg    return(opstack[--opsp]);
9094d9b34d9Smrg}
9104d9b34d9Smrg
9114d9b34d9Smrg/*******/
9124d9b34d9Smrgstatic int
9134d9b34d9Smrgisopempty(void)
9144d9b34d9Smrg/*******/
9154d9b34d9Smrg{
9164d9b34d9Smrg  return( opsp ? 0 : 1 );
9174d9b34d9Smrg}
9184d9b34d9Smrg
9194d9b34d9Smrg#ifdef DEBUG
9204d9b34d9Smrgstatic void
9218512f934Smrgshowstack(char *string)
9224d9b34d9Smrg{
9234d9b34d9Smrg    fprintf(stderr, "%s: %lf %lf %lf\n", string, numstack[0], numstack[1],
9244d9b34d9Smrg	    numstack[2]);
9254d9b34d9Smrg}
9264d9b34d9Smrg#endif
9274d9b34d9Smrg
9284d9b34d9Smrg/*******/
9294d9b34d9Smrgstatic void
9308512f934SmrgPushNum(double num)
9314d9b34d9Smrg/*******/
9324d9b34d9Smrg{
9334d9b34d9Smrg  if (rpn) {
9344d9b34d9Smrg      numstack[2] = numstack[1];
9354d9b34d9Smrg      numstack[1] = numstack[0];
9364d9b34d9Smrg      numstack[0] = num;
9374d9b34d9Smrg      return;
9384d9b34d9Smrg  }
9394d9b34d9Smrg  if (numsp==STACKMAX) {
94019d64aeeSmrg      strlcpy(dispstr, "stack error", sizeof(dispstr));
9414d9b34d9Smrg      entered=3;
9424d9b34d9Smrg  } else
9434d9b34d9Smrg    numstack[numsp++]=num;
9444d9b34d9Smrg}
9454d9b34d9Smrg
9464d9b34d9Smrg/*******/
9474d9b34d9Smrgstatic double
9484d9b34d9SmrgPopNum(void)
9494d9b34d9Smrg/*******/
9504d9b34d9Smrg{
9514d9b34d9Smrg    if (rpn) {
9524d9b34d9Smrg	double tmp = numstack[0];
9534d9b34d9Smrg	numstack[0] = numstack[1];
9544d9b34d9Smrg	numstack[1] = numstack[2];
9554d9b34d9Smrg	return(tmp);
9564d9b34d9Smrg    }
9574d9b34d9Smrg    if (numsp==0) {
95819d64aeeSmrg	strlcpy(dispstr, "stack error", sizeof(dispstr));
9594d9b34d9Smrg	entered=3;
9604d9b34d9Smrg	return 0.0;
9614d9b34d9Smrg    } else
9624d9b34d9Smrg      return(numstack[--numsp]);
9634d9b34d9Smrg}
9644d9b34d9Smrg
9654d9b34d9Smrg/*******/
9664d9b34d9Smrgstatic void
9674d9b34d9SmrgRollNum(int dir)
9684d9b34d9Smrg/*******/
9694d9b34d9Smrg{
9704d9b34d9Smrg    double tmp;
9714d9b34d9Smrg
9724d9b34d9Smrg    if (dir) {				/* roll up */
9734d9b34d9Smrg	tmp         = dnum;
9744d9b34d9Smrg	dnum        = numstack[2];
9754d9b34d9Smrg	numstack[2] = numstack[1];
9764d9b34d9Smrg	numstack[1] = numstack[0];
9774d9b34d9Smrg	numstack[0] = tmp;
9784d9b34d9Smrg    } else {				/* roll down */
9794d9b34d9Smrg	tmp         = dnum;
9804d9b34d9Smrg	dnum        = numstack[0];
9814d9b34d9Smrg	numstack[0] = numstack[1];
9824d9b34d9Smrg	numstack[1] = numstack[2];
9834d9b34d9Smrg	numstack[2] = tmp;
9844d9b34d9Smrg    }
9854d9b34d9Smrg}
9864d9b34d9Smrg
9874d9b34d9Smrg
9884d9b34d9Smrg/*******/
9894d9b34d9Smrgstatic void
9904d9b34d9SmrgClearStacks(void)
9914d9b34d9Smrg/*******/
9924d9b34d9Smrg{
9934d9b34d9Smrg    if (rpn)
9944d9b34d9Smrg      numstack[0] = numstack[1] = numstack[2] = 0.;
9954d9b34d9Smrg    opsp=numsp=0;
9964d9b34d9Smrg}
9974d9b34d9Smrg
9984d9b34d9Smrg
9994d9b34d9Smrg/*******/
10004d9b34d9Smrgstatic int
10018512f934Smrgpriority(int op)
10024d9b34d9Smrg/*******/
10034d9b34d9Smrg{
10044d9b34d9Smrg    switch (op) {
10052256ab8cSmrg        case kPOW: return(6);
10064d9b34d9Smrg        case kMUL:
10072256ab8cSmrg        case kDIV:
10082256ab8cSmrg        case kMOD: return(5);
10094d9b34d9Smrg        case kADD:
10102256ab8cSmrg        case kSUB: return(4);
10112256ab8cSmrg        case kSHL:
10122256ab8cSmrg        case kSHR: return(3);
10132256ab8cSmrg        case kAND: return(2);
10142256ab8cSmrg        case kXOR: return(1);
10152256ab8cSmrg        case kOR:  return(0);
10162256ab8cSmrg    }
10174d9b34d9Smrg    return 0;
10184d9b34d9Smrg}
10194d9b34d9Smrg
10204d9b34d9Smrg
10214d9b34d9Smrg/********/
10224d9b34d9Smrgvoid
10234d9b34d9SmrgResetCalc(void)
10244d9b34d9Smrg/********/
10254d9b34d9Smrg{
10264d9b34d9Smrg    flagM=flagINV=flagPAREN=0;  drgmode=DEG;
10272256ab8cSmrg    numbase=(!numbase ? 10 : numbase);
10284d9b34d9Smrg    setflag(XCalc_MEMORY, False);
10294d9b34d9Smrg    setflag(XCalc_INVERSE, False);
10304d9b34d9Smrg    setflag(XCalc_PAREN, False);
10314d9b34d9Smrg    setflag(XCalc_RADIAN, False);
10324d9b34d9Smrg    setflag(XCalc_GRADAM, False);
10334d9b34d9Smrg    setflag(XCalc_DEGREE, True);
10342256ab8cSmrg    setflag(XCalc_HEX, False);
10352256ab8cSmrg    setflag(XCalc_DEC, True);
10362256ab8cSmrg    setflag(XCalc_OCT, False);
103719d64aeeSmrg    strlcpy(dispstr, "0", sizeof(dispstr));
10384d9b34d9Smrg    draw(dispstr);
10394d9b34d9Smrg    ClearStacks();
104019d64aeeSmrg    drg2rad=M_PI/180.0;
104119d64aeeSmrg    rad2drg=180.0/M_PI;
10424d9b34d9Smrg}
1043