Edit

IABSD.fr/xenocara/app/xcalc/math.c

Branch :

  • Show log

    Commit

  • Author : matthieu
    Date : 2026-03-08 15:38:16
    Hash : 3673818e
    Message : Update to xcalc 1.1.3

  • app/xcalc/math.c
  • /*
     *  math.c  -  mathematics functions for a hand calculator under X
     *
     *  Author:    John H. Bradley, University of Pennsylvania
     *                (bradley@cis.upenn.edu)
     *                     March, 1987
     *
     *  RPN mode added and port to X11 by Mark Rosenstein, MIT Project Athena
     *
     *  Modified to be a client of the Xt toolkit and the Athena widget set by
     *  Donna Converse, MIT X Consortium.  This is all that remains of the
     *  original calculator, and it still needs to be rewritten.  The HP
     *  functionality should be separated from the TI functionality.
     *  Beware the HP functions: there are still errors here.
     *
     *  Geoffrey Coram fixed most of the HP mode bugs.
     */
    
    #include "xcalc.h"
    
    #ifndef M_PI        /* sometimes defined in math.h */
    #define M_PI        3.14159265358979323846
    #endif
    
    #ifndef M_E         /* sometimes defined in math.h */
    #define M_E           2.7182818284590452354
    #endif
    
    #define MAXDISP     11
    #define DEG 0		/* DRG mode.  used for trig calculations */
    #define RAD 1
    #define GRAD 2
    
    #define True	1
    #define False   0
    
    #ifndef IEEE
    jmp_buf env;
    #endif
    
    
    /* This section is all of the state machine that implements the calculator
     * functions.  Much of it is shared between the infix and rpn modes.
     */
    
    static int flagINV, flagPAREN, flagM, drgmode, numbase;	/* display flags */
    
    static double drg2rad=M_PI/180.0;  /* Conversion factors for trig funcs */
    static double rad2drg=180.0/M_PI;
    static int entered=1;  /* true if display contains a valid number.
                              if==2, then use 'dnum', rather than the string
                              stored in the display.  (for accuracy)
                              if==3, then error occurred, only CLR & AC work */
    /* entered seems to be overloaded - dmc */
    static int lift_enabled = 0;	/* for rpn mode only */
    
    static int CLR    =0;  /* CLR clears display.  if 1, clears acc, also */
    static int Dpoint=0;  /* to prevent using decimal pt twice in a # */
    static int clrdisp=1;  /* if true clears display before entering # */
    static int lastop =kCLR;
    static int memop  =kCLR;
    static int exponent=0;
    static double acc =0.0;
    static double dnum=0.0;
    #define XCALC_MEMORY 10
    static double mem[XCALC_MEMORY] = { 0.0 };
    
    static void   DrawDisplay(void);
    static void   PushOp(int op);
    static int    PopOp(void);
    static int    isopempty(void);
    #ifdef DEBUG
    static void   showstack(char *string);
    #endif
    static void   PushNum(double num);
    static double PopNum(void);
    static void   RollNum(int dir);
    static void   ClearStacks(void);
    static int    priority(int op);
    
    #ifndef HAVE_STRLCPY
    /* Close enough for the short strings copied in xcalc */
    static inline size_t
    strlcpy(char *dst, const char *src, size_t size)
    {
        strncpy(dst, src, size);
        dst[size - 1] = '\0';
        return strlen(src);
    }
    #endif
    
    /*
     * The following is to deal with the unfortunate assumption that if errno
     * is non-zero then an error has occurred.  On some systems (e.g. Ultrix),
     * sscanf will call lower level routines that will set errno.
     */
    static void
    parse_double(double *dp)
    {
        unsigned long n = 0;
        int olderrno = errno;
    
        switch (numbase) {
        case 8:
            sscanf(dispstr, "%lo", &n);
            *dp = (double)n;
        break;
        case 16:
            sscanf(dispstr, "%lX", &n);
            *dp = (double)n;
        break;
        default:
            sscanf(dispstr, "%lf", dp);
        }
    
        errno = olderrno;
        return;
    }
    
    /**
     * Format the given double according to the
     * selected number base.
     */
    static void
    format_double(double n)
    {
        switch (numbase) {
        case 8:
            snprintf(dispstr, sizeof(dispstr), "%lo", (long)n);
        break;
        case 16:
            snprintf(dispstr, sizeof(dispstr), "%lX", (long)n);
        break;
        default:
            snprintf(dispstr, sizeof(dispstr), "%.8g", n);
        }
    }
    
    /*********************************/
    int pre_op(int keynum)
    {
        if (keynum==-1) return(0);
    
        errno = 0;			/* for non-IEEE machines */
    
        if ( (entered==3) && !(keynum==kCLR || keynum==kOFF)) {
          if (rpn) {
    	clrdisp++;
          } else {
            ringbell();
            return(1);	/* the intent was probably not to do the operation */
          }
        }
    
        if (keynum != kCLR) CLR=0;
        return(0);
    }
    
    #ifndef IEEE
    
    /* cannot assign result of setjmp under ANSI C, use global instead */
    static volatile int SignalKind;
    
    void fail_op(void)
    {
        if (SignalKind == SIGFPE)
    	strlcpy(dispstr, "math error", sizeof(dispstr));
        else if (SignalKind == SIGILL)
    	strlcpy(dispstr, "illegal operand", sizeof(dispstr));
    
        entered=3;
        DrawDisplay();
        return;
    }
    
    /*ARGSUSED*/
    void fperr(int sig)
    {
    #if defined(SYSV) || defined(SVR4) || defined(linux)
        signal(SIGFPE, fperr);
    #endif
        SignalKind = sig;
        longjmp(env,1);
    }
    
    /* for VAX BSD4.3 */
    /*ARGSUSED*/
    void illerr(int sig)
    {
        /* not reset when caught? */
        signal(SIGILL, illerr);
    
        SignalKind = sig;
        longjmp(env,1);
    }
    
    #endif	/* not IEEE */
    
    
    void post_op(void)
    {
    #ifdef DEBUG
        showstack("\0");
    #endif
    #ifndef IEEE
        if (errno) {
            strlcpy(dispstr, "error", sizeof(dispstr));
            DrawDisplay();
            entered=3;
            errno=0;
            }
    #endif
    }
    
    /*-------------------------------------------------------------------------*/
    static void
    DrawDisplay(void)
    {
        if (strlen(dispstr) >= MAXDISP) { /* strip out some decimal digits */
            char *estr = index(dispstr,'e');  /* search for exponent part */
            if (!estr) dispstr[12]='\0';      /* no exp, just trunc. */
            else {
                char tmp[32];
                if (strlen(estr) <= 4)        /* leftmost 8 chars plus exponent */
                    snprintf(tmp, sizeof(tmp), "%.8s%s", dispstr, estr);
                else                          /* leftmost 7 chars plus exponent */
                    snprintf(tmp, sizeof(tmp), "%.7s%s", dispstr, estr);
                strlcpy(dispstr, tmp, sizeof(dispstr));
            }
        }
        draw(dispstr);
        setflag(XCalc_MEMORY, (flagM));
        setflag(XCalc_INVERSE, (flagINV));
        setflag(XCalc_DEGREE, (drgmode==DEG));
        setflag(XCalc_RADIAN, (drgmode==RAD));
        setflag(XCalc_GRADAM, (drgmode==GRAD));
        setflag(XCalc_PAREN, (flagPAREN));
        setflag(XCalc_HEX, (numbase==16));
        setflag(XCalc_DEC, (numbase==10));
        setflag(XCalc_OCT, (numbase==8));
    }
    
    /*-------------------------------------------------------------------------*/
    void
    change_base(void)
    {
    	parse_double(&dnum);
    
        if (dnum >= 0) {
            switch (numbase) {
            case 8:  numbase = 10;  break;
            case 10: numbase = 16;  break;
            case 16: numbase = 8;   break;
            }
    
            format_double(dnum);
        } else strlcpy(dispstr, "error", sizeof(dispstr));
    
        DrawDisplay();
    }
    
    /*-------------------------------------------------------------------------*/
    void
    numeric(int keynum)
    {
      char st[2];
    
      flagINV=0;
    
      if (rpn && (memop == kSTO || memop == kRCL || memop == kSUM)) {
          int cell = 0;
    
          switch (keynum) {
    	case kONE:	cell = 1; break;
    	case kTWO:	cell = 2; break;
    	case kTHREE:	cell = 3; break;
    	case kFOUR:	cell = 4; break;
    	case kFIVE:	cell = 5; break;
    	case kSIX:	cell = 6; break;
    	case kSEVEN:	cell = 7; break;
    	case kEIGHT:	cell = 8; break;
    	case kNINE:	cell = 9; break;
    	case kZERO:	cell = 0; break;
          }
          switch (memop) {
          case kSTO:
    	mem[cell] = dnum;
    	lift_enabled = 1;
    	entered = 2;
    	clrdisp++;
    	break;
          case kRCL:
    	PushNum(dnum);
    	dnum = mem[cell];
    	format_double(dnum);
    	lift_enabled = 1;
            entered = 1;
    	clrdisp++;
    	break;
          case kSUM:
    	mem[cell] += dnum;
    	lift_enabled = 1;
    	entered = 2;
    	clrdisp++;
    	break;
          }
          memop = kCLR;
          DrawDisplay();
          return;
      }
    
      if (clrdisp) {
        dispstr[0]='\0';
        exponent=Dpoint=0;
    /*    if (rpn && entered==2)
          PushNum(dnum);
     */
        if (rpn & lift_enabled)
    	PushNum(dnum);
      }
      if ((int) strlen(dispstr) >= MAXDISP)
        return;
    
      st[0] = '\0';
      switch (keynum){
          case kZERO:	st[0] = '0'; break;
          case kONE:	st[0] = '1'; break;
          case kTWO:	st[0] = '2'; break;
          case kTHREE:	st[0] = '3'; break;
          case kFOUR:	st[0] = '4'; break;
          case kFIVE:	st[0] = '5'; break;
          case kSIX:	st[0] = '6'; break;
          case kSEVEN:	st[0] = '7'; break;
          case kEIGHT:	if (numbase > 8)  st[0] = '8'; break;
          case kNINE:	if (numbase > 8)  st[0] = '9'; break;
          case kxA: 	if (numbase > 10) st[0] = 'A'; break;
          case kxB: 	if (numbase > 10) st[0] = 'B'; break;
          case kxC: 	if (numbase > 10) st[0] = 'C'; break;
          case kxD: 	if (numbase > 10) st[0] = 'D'; break;
          case kxE: 	if (numbase > 10) st[0] = 'E'; break;
          case kxF: 	if (numbase > 10) st[0] = 'F'; break;
        }
    
        if (st[0] == '\0')
            return;
        st[1] = '\0';
        strcat(dispstr,st);
    
      DrawDisplay();
      if (clrdisp && keynum != kZERO)
        clrdisp=0; /*no leading 0s*/
      memop = keynum;
      entered=1;
      lift_enabled = 0;
    }
    
    void
    bkspf(void)
    {
    
      lift_enabled = 0;
    
      if (! flagINV)
      {
          if (entered!=1) {
    	  clearf();
    	  return;
          }
          if (clrdisp)
    	  return;
          if ((int) strlen(dispstr) > 0) {
    #ifndef X_LOCALE
              const char *dp = localeconv()->decimal_point;
              size_t dp_len = strlen(dp);
              size_t ds_len = strlen(dispstr);
              if (ds_len >= dp_len && strcmp(dispstr + ds_len - dp_len, dp) == 0)
                 Dpoint=0;
    #else
    	  if (dispstr[strlen(dispstr)-1] == '.')
                 Dpoint=0;
    #endif
    	  dispstr[strlen(dispstr)-1] = 0;
          }
          if (strlen(dispstr) == 0) {
    	  strcat(dispstr, "0");
    	  clrdisp++;
          }
      }
      else
      {
          strlcpy(dispstr, "0", sizeof(dispstr));
          dnum = 0.0;
          clrdisp++;
          flagINV = 0;
      }
      DrawDisplay();
    }
    
    void
    decf(void)
    {
      flagINV=0;
      if (clrdisp) {
          if (rpn && lift_enabled)
    	PushNum(dnum);
          strlcpy(dispstr, "0", sizeof(dispstr));
      }
      if (!Dpoint) {
    #ifndef X_LOCALE
        strcat(dispstr, localeconv()->decimal_point);
    #else
        strcat(dispstr, ".");
    #endif
        DrawDisplay();
        Dpoint++;
      }
      clrdisp=0;
      entered=1;
    }
    
    void
    eef(void)
    {
      flagINV=0;
      if (clrdisp) {
          if (rpn && lift_enabled)
    	PushNum(dnum);
          strlcpy(dispstr, rpn ? "1" : "0", sizeof(dispstr));
      }
      if (!exponent) {
        strcat(dispstr,"E+");
        DrawDisplay();
        exponent=(int) strlen(dispstr)-1;  /* where the '-' goes */
      }
      clrdisp=0;
      entered=1;
    }
    
    void
    clearf(void)
    {
      flagINV=0;
      if (CLR && !rpn) { /* clear all */
        ClearStacks();
        flagPAREN=0;
      }
      CLR++;
      exponent=Dpoint=0;
      clrdisp=1;
      entered=1;
      strlcpy(dispstr, "0", sizeof(dispstr));
      DrawDisplay();
    }
    
    void
    negf(void)
    {
      flagINV=0;
      if (exponent) {       /* neg the exponent */
        if (dispstr[exponent]=='-')
          dispstr[exponent]='+';
        else
          dispstr[exponent]='-';
        DrawDisplay();
        return;
      }
    
      if (strcmp("0",dispstr)==0)
        return;			/* don't neg a zero */
      if (dispstr[0]=='-')	 	/* already neg-ed */
        strcpy(dispstr,dispstr+1);  /* move str left once */
      else {			/* not neg-ed.  add a '-' */
        char tmp[LCD_STR_LEN + 1];
        snprintf(tmp, sizeof(tmp), "-%s", dispstr);
        strlcpy(dispstr, tmp, sizeof(dispstr));
      }
      if (entered==2)
        dnum = -1.0 * dnum;
      DrawDisplay();
    }
    
    /* Two operand functions for infix calc */
    void
    twoop(int keynum)
    {
      if (flagINV) {
        flagINV=0;
        DrawDisplay();
      }
    
      if (!entered) {		/* something like "5+*" */
        if (!isopempty())
          PopOp();			/* replace the prev op */
        PushOp(keynum);		/* with the new one */
        return;
      }
    
      if (entered==1)
        parse_double(&dnum);
    
      clrdisp=CLR=1;
      entered=Dpoint=exponent=0;
    
      if (!isopempty()) {  /* there was a previous op */
        lastop=PopOp();   /* get it */
    
        if (lastop==kLPAR) {  /* put it back */
          PushOp(kLPAR);
          PushOp(keynum);
          PushNum(dnum);
          return;
        }
    
        /* now, if the current op (keynum) is of
           higher priority than the lastop, the current
           op and number are just pushed on top
           Priorities:  (Y^X) > *,/ > +,- > >>,<< > & > ^ > ~ */
    
        if (priority(keynum) > priority(lastop)) {
          PushNum(dnum);
          PushOp(lastop);
          PushOp(keynum);
        } else {  /* execute lastop on lastnum and dnum, push
    	       result and current op on stack */
          acc=PopNum();
          switch (lastop) { /* perform the operation */
          case kADD: acc += dnum;  break;
          case kSUB: acc -= dnum;  break;
          case kMUL: acc *= dnum;  break;
          case kDIV: acc /= dnum;  break;
          case kPOW: acc =  pow(acc,dnum);  break;
          case kMOD: acc = (long)acc %  (long)dnum;  break;
          case kAND: acc = (long)acc &  (long)dnum;  break;
          case kOR:  acc = (long)acc |  (long)dnum;  break;
          case kXOR: acc = (long)acc ^  (long)dnum;  break;
          case kSHL: acc = (long)acc << (long)dnum;  break;
          case kSHR: acc = (long)acc >> (long)dnum;  break;
          }
    
          PushNum(acc);
          PushOp(keynum);
          format_double(acc);
          DrawDisplay();
          dnum=acc;
        }
      }
      else { /* op stack is empty, push op and num */
        PushOp(keynum);
        PushNum(dnum);
      }
    }
    
    /* Two operand functions for rpn calc */
    void
    twof(int keynum)
    {
      if (flagINV) {
        flagINV=0;
        DrawDisplay();
      }
      if (!entered)
        return;
      if (entered==1)
        parse_double(&dnum);
      acc = PopNum();
      switch(keynum) {
      case kADD: acc += dnum;  break;
      case kSUB: acc -= dnum;  break;
      case kMUL: acc *= dnum;  break;
      case kDIV: acc /= dnum;  break;
      case kPOW: acc =  pow(acc,dnum);  break;
      case kXXY: PushNum(dnum);  break;
      case kMOD: acc = (long)acc %  (long)dnum;  break;
      case kAND: acc = (long)acc &  (long)dnum;  break;
      case kOR:  acc = (long)acc |  (long)dnum;  break;
      case kXOR: acc = (long)acc ^  (long)dnum;  break;
      case kSHL: acc = (long)acc << (long)dnum;  break;
      case kSHR: acc = (long)acc >> (long)dnum;  break;
      }
    
      format_double(acc);
      DrawDisplay();
      clrdisp++;
      Dpoint = exponent = 0;
      entered = 2;
      lift_enabled = 1;
      dnum = acc;
    }
    
    void
    entrf(void)
    {
      flagINV=0;
      if (!entered)
        return;
    
      clrdisp=CLR=1;
      Dpoint=exponent=0;
    
      if (entered==1)
        parse_double(&dnum);
      entered=2;
      memop = kENTR;
      PushNum(dnum);
      lift_enabled = 0;
    }
    
    void
    equf(void)
    {
      flagINV=0;
      if (!entered)
        return;
    
      clrdisp=CLR=1;
      Dpoint=exponent=0;
    
      if (entered==1)
        parse_double(&dnum);
      entered=2;
    
      PushNum(dnum);
    
      while (!isopempty()) {  /* do all pending ops */
        dnum=PopNum();
        acc=PopNum();
        lastop=PopOp();
        switch (lastop) {
        case kADD:  acc += dnum;
    		break;
        case kSUB:  acc -= dnum;
    		break;
        case kMUL:  acc *= dnum;
    		break;
        case kDIV:  acc /= dnum;
    		break;
        case kPOW:  acc = pow(acc,dnum);
    		break;
        case kLPAR:	flagPAREN--;
    		PushNum(acc);
    		break;
        case kMOD:  acc = (long)acc % (long)dnum;
    		break;
        case kAND:  acc = (long)acc & (long)dnum;
    		break;
        case kOR:   acc = (long)acc | (long)dnum;
    		break;
        case kXOR:  acc = (long)acc ^ (long)dnum;
    		break;
        case kSHL:  acc = (long)acc << (long)dnum;
    		break;
        case kSHR:  acc = (long)acc >> (long)dnum;
    		break;
        }
        dnum=acc;
        PushNum(dnum);
      }
    
      format_double(dnum);
      DrawDisplay();
    }
    
    void
    lparf(void)
    {
      flagINV=0;
      PushOp(kLPAR);
      flagPAREN++;
      DrawDisplay();
    }
    
    void
    rollf(void)
    {
      if (!entered)
        return;
      if (entered==1)
        parse_double(&dnum);
      entered = 2;
      lift_enabled = 1;
      RollNum(flagINV);
      flagINV=0;
      clrdisp++;
      format_double(dnum);
      DrawDisplay();
    }
    
    void
    rparf(void)
    {
      flagINV=0;
      if (!entered)
        return;
    
      if (!flagPAREN)
        return;
    
      clrdisp++;
      Dpoint=exponent=0;
    
      if (entered==1)
        parse_double(&dnum);
      entered=2;
    
      PushNum(dnum);
      while (!isopempty() && (lastop=PopOp())!=kLPAR) {
        /* do all pending ops, back to left paren */
        dnum=PopNum();
        acc=PopNum();
        switch (lastop) {
        case kADD:  acc += dnum;
    		break;
        case kSUB:  acc -= dnum;
    		break;
        case kMUL:  acc *= dnum;
    		break;
        case kDIV:  acc /= dnum;
    		break;
        case kPOW:  acc = pow(acc,dnum);
    		break;
        case kMOD:  acc = (long)acc % (long)dnum;
    		break;
        case kAND:  acc = (long)acc & (long)dnum;
    		break;
        case kOR:   acc = (long)acc | (long)dnum;
    		break;
        case kXOR:  acc = (long)acc ^ (long)dnum;
    		break;
        case kSHL:  acc = (long)acc << (long)dnum;
    		break;
        case kSHR:  acc = (long)acc >> (long)dnum;
    		break;
        }
        dnum=acc;
        PushNum(dnum);
      }
      PopNum();
      flagPAREN--;
      entered=2;
      format_double(dnum);
      DrawDisplay();
    }
    
    void
    drgf(void)
    {
      if (flagINV) {
        if (entered==1)
          parse_double(&dnum);
        switch (drgmode) {
        case DEG:  dnum=dnum*M_PI/180.0;    break;
        case RAD:  dnum=dnum*200.0/M_PI;    break;
        case GRAD: dnum=dnum*90.0/100.0;  break;
        }
        entered=2;
        clrdisp=1;
        flagINV=0;
        format_double(dnum);
      }
    
      flagINV=0;
      drgmode = (drgmode + 1) % 3;
      switch (drgmode) {
      case DEG:  drg2rad=M_PI / 180.0;
    	     rad2drg=180.0 / M_PI;
    	     break;
      case RAD:  drg2rad=1.0;
    	     rad2drg=1.0;
    	     break;
      case GRAD: drg2rad=M_PI / 200.0;
    	     rad2drg=200.0 / M_PI;
    	     break;
      }
      DrawDisplay();
    }
    
    void
    invf(void)
    {
      flagINV = ~flagINV;
      DrawDisplay();
    }
    
    void
    memf(int keynum)
    {
        memop = keynum;
        if (entered==1)
          parse_double(&dnum);
        entered = 2;
        clrdisp++;
        lift_enabled = 0;
    }
    
    void
    oneop(int keynum)
    {
      int i,j;
      double dtmp;
    
      if (entered==1)
        parse_double(&dnum);
      entered = 2;
    
      switch (keynum) {  /* do the actual math fn. */
      case kE:     if (rpn && memop != kENTR) PushNum(dnum); dnum=M_E;  break;
      case kPI:    if (rpn && memop != kENTR) PushNum(dnum); dnum=M_PI;  break;
      case kRECIP: dnum=1.0/dnum;  break;
      case kSQR:   flagINV = !flagINV; /* fall through */
      case kSQRT:  if (flagINV) dnum=dnum*dnum;
    	       else dnum=sqrt(dnum);
    	       break;
      case k10X:   flagINV = !flagINV; /* fall through */
      case kLOG:   if (flagINV) dnum=pow(10.0,dnum);
      	       else dnum=log10(dnum);
    	       break;
      case kEXP:   flagINV = !flagINV; /* fall through */
      case kLN:    if (flagINV) dnum=exp(dnum);
    	       else dnum=log(dnum);
    	       break;
      case kSIN:   if (flagINV) dnum=asin(dnum)*rad2drg;
    	       else dnum=sin(dnum*drg2rad);
    	       break;
      case kCOS:   if (flagINV) dnum=acos(dnum)*rad2drg;
    	       else dnum=cos(dnum*drg2rad);
    	       break;
      case kTAN:   if (flagINV) dnum=atan(dnum)*rad2drg;
    	       else dnum=tan(dnum*drg2rad);
    	       break;
      case kSTO:   mem[0]=dnum;  flagM=!(mem[0]==0.0);  break;
      case kRCL:   if (rpn && lift_enabled) PushNum(dnum);
                   dnum=mem[0];  flagM=!(mem[0]==0.0);  break;
      case kSUM:   mem[0]+=dnum; flagM=!(mem[0]==0.0);  break;
      case kEXC:   dtmp=dnum; dnum=mem[0];  mem[0]=dtmp;
    	       flagM=!(mem[0]==0.0);  break;
      case kFACT:  if (floor(dnum)!=dnum || dnum<0.0 || dnum>500.0) {
                     strlcpy(dispstr, "error", sizeof(dispstr));
    		 entered=3;
    		 break;
    	       }
    	       dtmp = floor(dnum); i = dtmp;
    	       for (j=1,dnum=1.0; j<=i; j++)
    		 dnum*=(float) j;
    	       break;
      case kNOT:   dnum = ~(long)dnum;  break;
      case kTRUNC: dnum = trunc(dnum);  break;
      }
    
      if (entered==3) {  /* error */
        DrawDisplay();
        return;
      }
    
      memop = keynum;
      entered=2;
      clrdisp=1;
      flagINV=0;
      lift_enabled = 1;
      format_double(dnum);
      DrawDisplay();
    }
    
    void
    offf(void)
    {
      /* full reset */
      ResetCalc();
      entered=clrdisp=1;
      lift_enabled = 0;
      dnum=mem[0]=0.0;
      if (rpn)
          for (int i=1; i < XCALC_MEMORY; i++)
    	  mem[i]=0.0;
      exponent=Dpoint=0;
      DrawDisplay();
    }
    
    
    #define STACKMAX 32
    static int opstack[STACKMAX];
    static int opsp;
    static double numstack[STACKMAX];
    static int numsp;
    
    
    /*******/
    static void
    PushOp(int op)
    /*******/
    {
      if (opsp==STACKMAX) {
          strlcpy(dispstr, "stack error", sizeof(dispstr));
          entered=3;
      } else
          opstack[opsp++]=op;
    }
    
    /*******/
    static int
    PopOp(void)
    /*******/
    {
      if (opsp==0) {
          strlcpy(dispstr, "stack error", sizeof(dispstr));
          entered=3;
          return(kNOP);
      } else
        return(opstack[--opsp]);
    }
    
    /*******/
    static int
    isopempty(void)
    /*******/
    {
      return( opsp ? 0 : 1 );
    }
    
    #ifdef DEBUG
    static void
    showstack(char *string)
    {
        fprintf(stderr, "%s: %lf %lf %lf\n", string, numstack[0], numstack[1],
    	    numstack[2]);
    }
    #endif
    
    /*******/
    static void
    PushNum(double num)
    /*******/
    {
      if (rpn) {
          numstack[2] = numstack[1];
          numstack[1] = numstack[0];
          numstack[0] = num;
          return;
      }
      if (numsp==STACKMAX) {
          strlcpy(dispstr, "stack error", sizeof(dispstr));
          entered=3;
      } else
        numstack[numsp++]=num;
    }
    
    /*******/
    static double
    PopNum(void)
    /*******/
    {
        if (rpn) {
    	double tmp = numstack[0];
    	numstack[0] = numstack[1];
    	numstack[1] = numstack[2];
    	return(tmp);
        }
        if (numsp==0) {
    	strlcpy(dispstr, "stack error", sizeof(dispstr));
    	entered=3;
    	return 0.0;
        } else
          return(numstack[--numsp]);
    }
    
    /*******/
    static void
    RollNum(int dir)
    /*******/
    {
        double tmp;
    
        if (dir) {				/* roll up */
    	tmp         = dnum;
    	dnum        = numstack[2];
    	numstack[2] = numstack[1];
    	numstack[1] = numstack[0];
    	numstack[0] = tmp;
        } else {				/* roll down */
    	tmp         = dnum;
    	dnum        = numstack[0];
    	numstack[0] = numstack[1];
    	numstack[1] = numstack[2];
    	numstack[2] = tmp;
        }
    }
    
    
    /*******/
    static void
    ClearStacks(void)
    /*******/
    {
        if (rpn)
          numstack[0] = numstack[1] = numstack[2] = 0.;
        opsp=numsp=0;
    }
    
    
    /*******/
    static int
    priority(int op)
    /*******/
    {
        switch (op) {
            case kPOW: return(6);
            case kMUL:
            case kDIV:
            case kMOD: return(5);
            case kADD:
            case kSUB: return(4);
            case kSHL:
            case kSHR: return(3);
            case kAND: return(2);
            case kXOR: return(1);
            case kOR:  return(0);
        }
        return 0;
    }
    
    
    /********/
    void
    ResetCalc(void)
    /********/
    {
        flagM=flagINV=flagPAREN=0;  drgmode=DEG;
        numbase=(!numbase ? 10 : numbase);
        setflag(XCalc_MEMORY, False);
        setflag(XCalc_INVERSE, False);
        setflag(XCalc_PAREN, False);
        setflag(XCalc_RADIAN, False);
        setflag(XCalc_GRADAM, False);
        setflag(XCalc_DEGREE, True);
        setflag(XCalc_HEX, False);
        setflag(XCalc_DEC, True);
        setflag(XCalc_OCT, False);
        strlcpy(dispstr, "0", sizeof(dispstr));
        draw(dispstr);
        ClearStacks();
        drg2rad=M_PI/180.0;
        rad2drg=180.0/M_PI;
    }