[comp.windows.x] xcalc - an X desk accessory

bradley@DSL.CIS.UPENN.EDU.UUCP (03/27/87)

This is a vaguely-nifty little program that brings a scientific calculator up
on your favorite X display.  The calculator bears more than a passing
resemblance to a TI-30SLR.  I've gotten it to run on both an IBM RT (under
BSD 4.2), and a MicroVAX II, (under Ultrix 1.2).  You shouldn't have any 
problems porting it to any other 4.2 systems, particularly if you are familiar
(or willing to get that way) with your machine's floating point routines.

Comments, Fan Mail, and Verbal Abuse cheerfully accepted.

John Bradley,  University of Pennsylvania
(bradley@cis.upenn.edu)


P.S.  Sorry if this is the wrong place to post this, but net.sources seemed
  like the wrong place to post something as 'specialized' as X sources.

P.P.S  Sorry if this is a repost, but the first shot didn't seem to properly
  escape from the local cluster.

-----------------------------------(cut here)---------------------------------
#!/bin/sh
# to extract, remove the header and type "sh filename"
if `test ! -s ./Makefile`
then
echo "writing ./Makefile"
cat > ./Makefile << '\Rogue\Monster\'
INCLUDES = -I../include

XLIB = -lX
CFLAGS = $(INCLUDES)       # add -DIEEE if you have the IEEE fp routines
CLIBS = -lm

.SUFFIXES: .o .h .c .a

OBJS = xcalc.o

all: xcalc

xcalc: $(OBJS)
	cc $(CFLAGS) -o xcalc $(OBJS) $(XLIB) $(CLIBS)

\Rogue\Monster\
else
  echo "will not over write ./Makefile"
fi
if `test ! -s ./README`
then
echo "writing ./README"
cat > ./README << '\Rogue\Monster\'
Notes on xcalc:

I've gotten the sucker to run on an IBM RT, under BSD 4.2, and on a MicroVAX 
GPX, under Ultrix 1.2.  The RT is lucky enough to have the IEEE math routines.
Under these routines, if you say "x = 1.0 / 0.0", it doesn't blow up.  
Instead, when you decide to printf() x, it shows up as "INF".  The routines
also have the nice feature of being terribly accurate.  Needless to say, this
all makes writing a calculator fun/E-Z.

On the MicroVAX, however, I had to use a wretched math package, one that only
goes between 1E-38 and 1E+38, one that isn't very accurate, and one that will
cause an FP Exception at the slightest prompting.  As a result, I had to put
in all sorts of evil nasty 'sigvec's and 'setjmp's and things.  I think it
takes away from the intrinsic beauty (hah!) of the code, but at least it 
doesn't say "floating exception:  core dumped" anymore, so it's a step in
the right direction.

The point is:  If you're lucky enough to have the IEEE routines, by all means 
add a -DIEEE to the CFLAGS line in the Makefile.

-jhb, 3/16/86
\Rogue\Monster\
else
  echo "will not over write ./README"
fi
if `test ! -s ./cursor`
then
echo "writing ./cursor"
cat > ./cursor << '\Rogue\Monster\'
#define cursor_width 16
#define cursor_height 16
#define cursor_x_hot 3
#define cursor_y_hot 1
static short cursor_bits[] = {
   0x0000, 0x0008, 0x0018, 0x0038,
   0x0078, 0x00f8, 0x01f8, 0x03f8,
   0x07f8, 0x00f8, 0x00d8, 0x0188,
   0x0180, 0x0300, 0x0300, 0x0000};
\Rogue\Monster\
else
  echo "will not over write ./cursor"
fi
if `test ! -s ./cursor.mask`
then
echo "writing ./cursor.mask"
cat > ./cursor.mask << '\Rogue\Monster\'
#define cursor_mask_width 16
#define cursor_mask_height 16
static short cursor_mask_bits[] = {
   0x000c, 0x001c, 0x003c, 0x007c,
   0x00fc, 0x01fc, 0x03fc, 0x07fc,
   0x0ffc, 0x0ffc, 0x01fc, 0x03dc,
   0x03cc, 0x0780, 0x0780, 0x0300};
\Rogue\Monster\
else
  echo "will not over write ./cursor.mask"
fi
if `test ! -s ./deg.bm`
then
echo "writing ./deg.bm"
cat > ./deg.bm << '\Rogue\Monster\'
#define deg_width 18
#define deg_height 5
static short deg_bits[] = {
   0xe7cf, 0x0001, 0x1051, 0x0000,
   0xd1d1, 0x0001, 0x1051, 0x0001,
   0xe7cf, 0x0001};
\Rogue\Monster\
else
  echo "will not over write ./deg.bm"
fi
if `test ! -s ./e.bm`
then
echo "writing ./e.bm"
cat > ./e.bm << '\Rogue\Monster\'
#define e_width 8
#define e_height 8
static short e_bits[] = {
   0x00ff, 0x00ff, 0x0003, 0x001f,
   0x001f, 0x0003, 0x00ff, 0x00ff};
\Rogue\Monster\
else
  echo "will not over write ./e.bm"
fi
if `test ! -s ./grad.bm`
then
echo "writing ./grad.bm"
cat > ./grad.bm << '\Rogue\Monster\'
#define grad_width 24
#define grad_height 5
static short grad_bits[] = {
   0xe3de, 0x003c, 0x1441, 0x0045,
   0xf3dd, 0x0045, 0x1251, 0x0045,
   0x145e, 0x003d};
\Rogue\Monster\
else
  echo "will not over write ./grad.bm"
fi
if `test ! -s ./icon`
then
echo "writing ./icon"
cat > ./icon << '\Rogue\Monster\'
#define icon_width 48
#define icon_height 48
static short icon_bits[] = {
   0xffff, 0x0fff, 0x0000, 0xffff,
   0x0fff, 0x0000, 0x0003, 0x0c00,
   0x0000, 0x5dd3, 0x0c5d, 0x0000,
   0x5113, 0x0c45, 0x0000, 0xddd3,
   0x0ddd, 0x0000, 0x1053, 0x0d51,
   0x0000, 0x1dd3, 0x0ddd, 0x0000,
   0x0003, 0x0c00, 0x0000, 0xffff,
   0x0fff, 0x0000, 0xffff, 0x0fff,
   0x0000, 0x0001, 0x0800, 0x0000,
   0xf7bd, 0x0bde, 0x0000, 0xf7bd,
   0x0bde, 0x0000, 0x0001, 0x0800,
   0x0000, 0xf7bd, 0x0bde, 0x0000,
   0x94a5, 0x0a52, 0x0000, 0xf7bd,
   0x0bde, 0x0000, 0x0001, 0x0800,
   0x0000, 0xf7bd, 0x0bde, 0x0000,
   0xf7bd, 0x0bde, 0x0000, 0xf7bd,
   0x0bde, 0x0000, 0x0001, 0x0800,
   0x0000, 0xf7bd, 0x0bde, 0x0000,
   0xf7bd, 0x0bde, 0x0000, 0xf7bd,
   0x0bde, 0x0000, 0x0001, 0x0800,
   0x0000, 0xf7bd, 0x0bde, 0x0000,
   0x94a5, 0x0bde, 0x0000, 0x94a5,
   0x0bde, 0x0000, 0xf7bd, 0x0bde,
   0x0000, 0x0001, 0x0800, 0x0000,
   0xf7bd, 0x0bde, 0x0000, 0x94a5,
   0x0bde, 0x0000, 0x94a5, 0x0bde,
   0x0000, 0xf7bd, 0x0bde, 0x0000,
   0x0001, 0x0800, 0x0000, 0xf7bd,
   0x0bde, 0x0000, 0x94a5, 0x0bde,
   0x0000, 0x94a5, 0x0bde, 0x0000,
   0xf7bd, 0x0bde, 0x0000, 0x0001,
   0x0800, 0x0000, 0xf7fd, 0x0bde,
   0x0000, 0x9405, 0x0bde, 0x0000,
   0x9405, 0x0bde, 0x0000, 0xf7fd,
   0x0bde, 0x0000, 0x0001, 0x0800,
   0x0000, 0xffff, 0x0fff, 0x0000};
\Rogue\Monster\
else
  echo "will not over write ./icon"
fi
if `test ! -s ./inv.bm`
then
echo "writing ./inv.bm"
cat > ./inv.bm << '\Rogue\Monster\'
#define inv_width 18
#define inv_height 5
static short inv_bits[] = {
   0x4517, 0x0000, 0x4532, 0x0000,
   0x4552, 0x0000, 0x2992, 0x0000,
   0x1117, 0x0000};
\Rogue\Monster\
else
  echo "will not over write ./inv.bm"
fi
if `test ! -s ./k.bm`
then
echo "writing ./k.bm"
cat > ./k.bm << '\Rogue\Monster\'
#define k_width 6
#define k_height 5
static short k_bits[] = {
   0x0011, 0x0009, 0x0007, 0x0009,
   0x0011};
\Rogue\Monster\
else
  echo "will not over write ./k.bm"
fi
if `test ! -s ./m.bm`
then
echo "writing ./m.bm"
cat > ./m.bm << '\Rogue\Monster\'
#define m_width 8
#define m_height 8
static short m_bits[] = {
   0x00c3, 0x00e7, 0x00ff, 0x00ff,
   0x00db, 0x00c3, 0x00c3, 0x00c3};
\Rogue\Monster\
else
  echo "will not over write ./m.bm"
fi
if `test ! -s ./paren.bm`
then
echo "writing ./paren.bm"
cat > ./paren.bm << '\Rogue\Monster\'
#define paren_width 12
#define paren_height 5
static short paren_bits[] = {
   0x0104, 0x0202, 0x0202, 0x0202,
   0x0104};
\Rogue\Monster\
else
  echo "will not over write ./paren.bm"
fi
if `test ! -s ./rad.bm`
then
echo "writing ./rad.bm"
cat > ./rad.bm << '\Rogue\Monster\'
#define rad_width 18
#define rad_height 5
static short rad_bits[] = {
   0xf38f, 0x0000, 0x1451, 0x0001,
   0x17cf, 0x0001, 0x1449, 0x0001,
   0xf451, 0x0000};
\Rogue\Monster\
else
  echo "will not over write ./rad.bm"
fi
if `test ! -s ./xcalc.1`
then
echo "writing ./xcalc.1"
cat > ./xcalc.1 << '\Rogue\Monster\'
.TH XCALC 1 "16 March 1987" "X Version 10"
.SH NAME
xcalc \- X based scientific calculator
.SH SYNOPSIS
.B xcalc
[host:display]  [-bw <pixels>] [-stip] [-rv] [=geometry]
.SH DESCRIPTION
.I Xcalc
is a program that brings up a scientific calculator desk accessory.  The 
calculator should remind you more than a little bit of the TI-30.
.SH OPTIONS
.PP
.TP 14
.B \-bw
The border width in pixels
.PP
.TP 14
.B \-stip
Sets the 'stipple' option.  See 'defaults'.
.PP
.TP 14
.B \-rv
Reverse video (on monochrom displays).
.PP
.TP 14
.B \=geometry
The width and height shouldn't be set by the user, as the default size is also
the minimum size, and anything larger than that won't be 'right'.  You can, 
however feel free to set the position.
.PP
.TP 14
.B \fIhost\fP:\fIdisplay\fP
Normally,
.I xcalc
gets  the host and display number to use from the environment variable
``DISPLAY''.  One can, however specify them explicitly.
The
.I host
specifies which machine to create the
.I xcalc
window on, and
the
.I display
argument specifies the display number.
.SH OPERATION
.PP
.I Mouse Operation:
The left button is the only one (really) used to operate the calculator.
Pressing the AC key with the right button terminates the calculator.
.PP
.I Key Usage:
The number keys, the +/- key, and the +, -, *, /, and = keys all do exactly 
what you would expect them to.  It should be noted that the operators obey
the standard rules of precedence.  Thus, entering "3+4*5=" results in "23",
not "35".  The parentheses can be used to override this.  For example, 
"(1+2+3)*(4+5+6)=" results in "6*15=90".  The non-obvious keys are detailed
below.
.PP
.B 1/x
replaces the number in the display with its reciprocal.
.PP
.B x^2
squares the number in the display.
.PP
.B SQRT
takes the square root of the number in the display.
.PP
.B CE/C
when pressed once, clears the number in the display without clearing the state
of the machine.  Allows you to re-enter a number if you screw it up.  
Pressing it twice clears the state, also.
.PP
.B AC
clears everything, the display, the state, the memory, everything.  Pressing
it with the right button 'turns off' the calculator, in that it exits the
program.  Somewhat more equivalent to throwing the calculator in the trash,
if we were to pursue the analogy.
.PP
.B INV
inverts the meaning of the function keys.  See the individual function keys
for details.
.PP
.B sin
computes the sine of the number in the display, as interpreted by the current
DRG mode (see DRG, below).  If inverted, computes the arcsine.
.PP
.B cos
computes the cosine, or arccosine when inverted.
.PP
.B tan
computes the tangent, or arctangent when inverted.
.PP
.B DRG
changes the DRG mode, as indicated by 'DEG', 'RAD', or 'GRAD' at the bottom of
the display.  When in 'DEG' mode, numbers in the display are taken as being
degrees.  In 'RAD' mode, numbers are in radians, and in 'GRAD' mode, numbers
are in gradians.  When inverted, the DRG key has the nifty feature of 
converting degrees to radians to gradians and vice-versa.  Example:  put the 
calculator into 'DEG' mode, and type "45 INV DRG".  The display should now
show something along the lines of ".785398", which is 45 degrees converted to
radians.
.PP
.B e
the constant 'e'.  (2.7182818...)
.PP
.B EE
used for entering exponential numbers.  For example, to enter "-2.3E-4" you'd
type "2 . 3 +/- EE 4 +/-"
.PP
.B log
calculates the log (base 10) of the number in the display.  When inverted,
raises "10.0" to the number in the display.  For example, typing "3 INV log"
should result in "1000".
.PP
.B ln
calcuates the log (base e) of the number in the display.  When inverted, 
raises "e" to the number in the display.  For example, typing "e ln" should
result in "1"
.PP
.B y^x
raises the number on the left to the power of the number on the right.  For 
example "2 y^x 3 =" results in "8", which is 2^3.  For a further example,
"(1+2+3) y^x (1+2) =" equals "6 y^x 3" which equals "216".
.PP
.B PI
the constant 'pi'.  (3.1415927....)
.PP
.B x!
computes the factorial of the number in the display.  The number in the display
must be an integer in the range 0-500, though, depending on your math library,
it might overflow long before that.
.PP
.B STO
copies the number in the display to the memory location.
.PP
.B RCL
copies the number from the memory location to the display.
.PP
.B SUM
adds the number in the display to the number in the memory location.
.PP
.B EXC
swaps the number in the display with the number in the memory location.
.SH KEYBOARD EQUIVALENTS
If you have the mouse in the xcalc window, you can use the keyboard to speed
entry, as almost all of the calculator keys have a keyboard equivalent.  The
number keys, the operator keys, and the parentheses all have the obvious
equivalent.  The less-obvious equivalents are as follows:
.PP
.EX
n:  +/-            !:  x!
p:  PI             e:  EE
l:  ln             ^:  y^x
i:  INV            s:  sin
c:  cos            t:  tan
d:  DRG      BS, DEL:  CE/C
.SH COLOR USAGE
.I Xcalc
uses a lot of colors, given the opportunity.  In the default case, it will 
just use two colors (Foreground and Background) for everything.  This works out
nicely.  However, if you're a color fanatic you can specify the colors used 
for the number keys, the operator (+-*/=) keys, the function keys, the display,
and the icon.
.SH X DEFAULTS
.PP
.TP 8
.B BorderWidth
width of border.  Default is '2'.
.PP
.TP 8
.B ReverseVideo
reverses colors on monochrome displays
.PP
.TP 8
.B Stipple
makes the calculator background a 50% stipple.  Default is 'on' on 
monochrome displays, 'off' on color displays.  
.PP
.TP 8
.B Foreground
the default color used for borders and text.
.PP
.TP 8
.B Background
the default color used for the background.
.B NKeyFore, NKeyBack
the colors used for the number keys.
.PP
.TP 8
.B OKeyFore, OKeyBack
the colors used for the operator keys.
.PP
.TP 8
.B FKeyFore, FKeyBack
the colors used for the function keys.
.B DispFore, DispBack
the colors used for the display.
.B IconFore, IconBack
the colors used for the icon.
.SH SAMPLE .XDEFAULTS ENTRY
If you're running on a monochrome display, you shouldn't need any .Xdefaults
entries for xcalc.  On a color display, you might want to try the following:

.EX
xcalc.Foreground:               Black
xcalc.Background:               LightSteelBlue
xcalc.NKeyFore:                 Black
xcalc.NKeyBack:                 White
xcalc.OKeyFore:                 Aquamarine
xcalc.OKeyBack:                 DarkSlateGray
xcalc.FKeyFore:                 White
xcalc.FKeyBack:                 #900
xcalc.DispFore:                 Yellow
xcalc.DispBack:                 #777
xcalc.IconFore:                 Red
xcalc.IconBack:                 White

<well, *I* like them.>
.SH BUGS
Well, it would be really nice if you could (usefully) rescale the calculator,
and the redraw of the keys is sort of slow.  Nothing fatal though, I think.
.SH AUTHOR
John Bradley, University of Pennsylvania

(bradley@cis.upenn.edu)

\Rogue\Monster\
else
  echo "will not over write ./xcalc.1"
fi
if `test ! -s ./xcalc.c`
then
echo "writing ./xcalc.c"
cat > ./xcalc.c << '\Rogue\Monster\'
/*
 * xcalc.c  -  a hand calculator for the X Window system
 *
 *  Author:    John H. Bradley, University of Pennsylvania
 *                (bradley@cis.upenn.edu)
 *                     March, 1987
 */

/*
 * color usage:  ForeColor is used for all frames, BackColor is the color of 
 *                  the calculator body.
 *               NKeyFore, NKeyBack are the colors used for the number keys.
 *               OKeyFore, OKeyBack are used for the operator keys (+-*=/).
 *               FKeyFore, FKeyBack are used for all the other keys.
 *               DispFore, DispBack are used for the display.
 *               IconFore, IconBack are used for the display.
 *
 *               if running on monochrome monitor, or if 'stipple' option
 *                  set, the calculator body is a 50% stipple of ForeColor
 *                  and BackColor.  This looks nice in mono, but can prevent
 *                  you from getting the 'right' colors in color mode, so
 *                  it's an option.
 */

#include <stdio.h>
#include <math.h>
#include <strings.h>
#include <signal.h>
#include <X/Xlib.h>
#include <sys/time.h>
#include <setjmp.h>

/* nnw arrow cursor */
#include "cursor"
#include "cursor.mask"

/* program icon */
#include "icon"
#define iconRwidth 28       /* actual width of icon */

/* bitmaps for display flags */
#include "deg.bm"      
#include "rad.bm"
#include "grad.bm"
#include "inv.bm"
#include "k.bm"
#include "paren.bm"
#include "m.bm"
#include "e.bm"


/* constants used for setting up the calculator.  changing them would 
   probably be bad.  If you do, don't forget to change the values in the
   syntax routine */

#define FONT  "6x10"
#define DFONT "9x15"
#define PADDINGW    4
#define PADDINGH    8
#define DEF_BDRWIDE 2
#define MAXDISP     11
#define KEYPADH     2
#define KEYPADW     2
#define EXTRAH      2
#define DISPPADH    4
#define DISPPADW    8
#define FLAGH       9
#define PI          3.14159265358979
#define E           2.71828182845904

/* DRG mode.  used for trig calculations */
#define DEG 0
#define RAD 1
#define GRAD 2


/* handy-dandy functions */
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
#define abs(a) ((a) < 0 ? -(a) : (a))


/* colors */
int ForeColor, BackColor, NKeyFore, NKeyBack, OKeyFore, OKeyBack;
int FKeyFore, FKeyBack, DispFore, DispBack, IconFore, IconBack;

int border = DEF_BDRWIDE;


/* objects */
Window   theWindow, iconWindow, dispwid;
Cursor   arrow;
Font     keyfont, dispfont;
FontInfo *kfontinfo, *dfontinfo; 
Bitmap   stippleBit;
Pixmap   stipplePix;
Pixmap   regBorder, dimBorder;


/* variables used in setup */
int dispwide, disphigh, keywide, keyhigh;


/* display flags */
int flagK, flagINV, flagPAREN, flagM, flagE, drgmode;
char dispstr[32];


/* stuff defining the keyboard layout.  The keypad is a 5x8 matrix of keys */
#define NUMKEYS 40
struct _key {
           Window wid;
           char   *st;
           short  x,y,width,height;
           int    fore,back;
            } key[NUMKEYS];

char *keystrings[NUMKEYS]= {"1/x", "x^2", "SQRT","CE/C", "AC",
                            "INV", "sin", "cos", "tan",  "DRG",
                            "e",   "EE",  "log", "ln",   "y^x",
                            "PI",  "x!",  "(",   ")",    "/",
                            "STO", "7",   "8",   "9",    "*",
                            "RCL", "4",   "5",   "6",    "-",
                            "SUM", "1",   "2",   "3",    "+",
                            "EXC", "0",   ".",   "+/-",  "=" };
#define kRECIP 0
#define kSQR   1
#define kSQRT  2
#define kCLR   3
#define kOFF   4
#define kINV   5
#define kSIN   6
#define kCOS   7
#define kTAN   8
#define kDRG   9
#define kE     10
#define kEE    11
#define kLOG   12
#define kLN    13
#define kPOW   14
#define kPI    15
#define kFACT  16
#define kLPAR  17
#define kRPAR  18
#define kDIV   19
#define kSTO   20
#define kSEVEN 21
#define kEIGHT 22
#define kNINE  23
#define kMUL   24
#define kRCL   25
#define kFOUR  26
#define kFIVE  27
#define kSIX   28
#define kSUB   29
#define kSUM   30
#define kONE   31
#define kTWO   32
#define kTHREE 33
#define kADD   34
#define kEXC   35
#define kZERO  36
#define kDEC   37
#define kNEG   38
#define kEQU   39


/* checkerboard used in mono mode */
static short check_bits[] = {
   0x5555, 0xaaaa, 0x5555, 0xaaaa,
   0x5555, 0xaaaa, 0x5555, 0xaaaa,
   0x5555, 0xaaaa, 0x5555, 0xaaaa,
   0x5555, 0xaaaa, 0x5555, 0xaaaa};


#ifndef IEEE
    jmp_buf env;
#endif


/**************/
main(argc, argv)
    int   argc;
    char *argv[];
/**************/
{
    int i, status,dpcs;
    char *strind;
#ifndef IEEE
    extern fperr();
#endif

    char *fc, *bc, *nfc, *nbc, *ofc, *obc, *ffc, *fbc, *dfc, *dbc, *ifc, *ibc;
    char *geom    = NULL;
    char *display = NULL;
    int rvflag    = 0;      /* don't use reverse video as a default */
    int stip      = 0;      /* don't stipple background by default */
    int invkey    = -1;

    Color cdef;

    XEvent event;

    char *def;



    /*********************Defaults*********************/
    
    if ((def=XGetDefault(argv[0],"BorderWidth"))!=NULL)
         border=atoi(def);

    if ((def=XGetDefault(argv[0],"ReverseVideo"))!=NULL)
         if (strcmp(def,"on")==0) rvflag=1;

    if ((def=XGetDefault(argv[0],"Stipple"))!=NULL)
         if (strcmp(def,"on")==0) stip=1;

    fc  = XGetDefault(argv[0], "Foreground");
    bc  = XGetDefault(argv[0], "Background");
    nfc = XGetDefault(argv[0], "NKeyFore");
    nbc = XGetDefault(argv[0], "NKeyBack");
    ofc = XGetDefault(argv[0], "OKeyFore");
    obc = XGetDefault(argv[0], "OKeyBack");
    ffc = XGetDefault(argv[0], "FKeyFore");
    fbc = XGetDefault(argv[0], "FKeyBack");
    dfc = XGetDefault(argv[0], "DispFore");
    dbc = XGetDefault(argv[0], "DispBack");
    ifc = XGetDefault(argv[0], "IconFore");
    ibc = XGetDefault(argv[0], "IconBack");


    /*********************Options*********************/

    for (i = 1; i < argc; i++) {

        if (argv[i][0] == '=') {
            geom = argv[i];
            continue;
            }

        strind = index(argv[i], ':');

        if(strind != NULL) {
            display = argv[i];
            continue;
            }

        if (strcmp(argv [i], "-bw") == 0) {
            if (++i >= argc) Syntax(argv[0]);
            border = atoi(argv [i]);
            continue;
            }

        if (strcmp(argv [i], "-stip") == 0) {
            stip=1;
            continue;
            }

        if (strcmp(argv [i], "-help") == 0) {
            Syntax(argv[0]);
            }

        if (strcmp(argv [i], "-rv") == 0) {
            rvflag++;
            continue;
            }

        Syntax(argv[0]);
    }


    /*****************************************************/

    /* Open up the display. */

    if (XOpenDisplay(display) == NULL) {
        fprintf(stderr, "%s: Can't open display '%s'\n",
                          argv[0], DisplayName());
        exit(1);
        }

    /* Set up colors and pixmaps. */

    /* Set normal default colors */
    if (!rvflag) { ForeColor=BlackPixel;  BackColor=WhitePixel; }
            else { ForeColor=WhitePixel;  BackColor=BlackPixel; }


    dpcs=DisplayCells();
    if (dpcs<=2) stip=1;  /* monochrome display */

    if (dpcs>2&&(fc !=NULL)&&XParseColor(fc ,&cdef)&&XGetHardwareColor(&cdef))
        ForeColor=cdef.pixel;

    if (dpcs>2&&(bc !=NULL)&&XParseColor(bc ,&cdef)&&XGetHardwareColor(&cdef))
        BackColor=cdef.pixel;


    NKeyFore = OKeyFore = FKeyFore = DispFore = IconFore = ForeColor;
    NKeyBack = OKeyBack = FKeyBack = DispBack = IconBack = BackColor;


    if (dpcs>2&&(nfc!=NULL)&&XParseColor(nfc,&cdef)&&XGetHardwareColor(&cdef))
        NKeyFore=cdef.pixel;

    if (dpcs>2&&(nbc!=NULL)&&XParseColor(nbc,&cdef)&&XGetHardwareColor(&cdef))
        NKeyBack=cdef.pixel;

    if (dpcs>2&&(ofc!=NULL)&&XParseColor(ofc,&cdef)&&XGetHardwareColor(&cdef))
        OKeyFore=cdef.pixel;

    if (dpcs>2&&(obc!=NULL)&&XParseColor(obc,&cdef)&&XGetHardwareColor(&cdef))
        OKeyBack=cdef.pixel;

    if (dpcs>2&&(ffc!=NULL)&&XParseColor(ffc,&cdef)&&XGetHardwareColor(&cdef))
        FKeyFore=cdef.pixel;

    if (dpcs>2&&(fbc!=NULL)&&XParseColor(fbc,&cdef)&&XGetHardwareColor(&cdef))
        FKeyBack=cdef.pixel;

    if (dpcs>2&&(dfc!=NULL)&&XParseColor(dfc,&cdef)&&XGetHardwareColor(&cdef))
        DispFore=cdef.pixel;

    if (dpcs>2&&(dbc!=NULL)&&XParseColor(dbc,&cdef)&&XGetHardwareColor(&cdef))
        DispBack=cdef.pixel;

    if (dpcs>2&&(ifc!=NULL)&&XParseColor(ifc,&cdef)&&XGetHardwareColor(&cdef))
        IconFore=cdef.pixel;

    if (dpcs>2&&(ibc!=NULL)&&XParseColor(ibc,&cdef)&&XGetHardwareColor(&cdef))
        IconBack=cdef.pixel;


    /* load fonts, figure out sizes of keypad and display */

    kfontinfo = XOpenFont(FONT);
    if (!kfontinfo) XCalcError("Can't open '%s' font\n",FONT);
    keyfont = kfontinfo->id;

    dfontinfo = XOpenFont(DFONT);
    if (!dfontinfo) XCalcError("Can't open '%s' font\n",DFONT);
    dispfont = dfontinfo->id;

    keywide = XQueryWidth("MMMM", keyfont) + KEYPADW;
    keyhigh = kfontinfo->height + KEYPADH;

    dispwide  = 5*keywide+4*PADDINGW;
    disphigh = dfontinfo->height + DISPPADH + FLAGH;

    /* Open the main window. */
    {
    int min_width, min_height;
    char def_geom[32];
    OpaqueFrame frame;
    
    min_width  = dispwide + 2*PADDINGW + 2;
    min_height = disphigh + 2 + 8*keyhigh + 10*PADDINGH + 10*EXTRAH;
    sprintf (def_geom, "=%dx%d-16-16", min_width, min_height);

    frame.bdrwidth   = border;
    stippleBit       = XStoreBitmap(16,16,check_bits);
    stipplePix       = XMakePixmap(stippleBit,ForeColor,BackColor);
    regBorder        = XMakeTile(ForeColor);
    dimBorder        = stipplePix;
    frame.border     = dimBorder;

    if (stip) frame.background=stipplePix;
         else frame.background=XMakeTile(BackColor);

    theWindow = XCreate("Calculator", argv[0], geom, def_geom,
                          &frame, min_width, min_height);

    if (!theWindow) XCalcError("Can't open calculator window");

    iconWindow = XCreateWindow(RootWindow,0,0,iconRwidth,icon_height,
                               0,frame.border,XMakeTile(BackColor));

    XSetIconWindow(theWindow,iconWindow);
    SetupCalc();
    }


    arrow=XCreateCursor(cursor_width,cursor_height,cursor_bits,
                        cursor_mask_bits, cursor_x_hot, cursor_y_hot,
                        ForeColor, BackColor, GXcopy);

    XSelectInput(theWindow, ExposeWindow|ExposeRegion|KeyPressed|EnterWindow|LeaveWindow);
    XSelectInput(iconWindow,ExposeWindow|ExposeRegion);
    XSelectInput(dispwid,   ExposeWindow|ExposeRegion|EnterWindow|LeaveWindow);

    for (i=0; i<NUMKEYS; i++)
        XSelectInput(key[i].wid,ExposeWindow|ExposeRegion|
                                ButtonPressed|ButtonReleased|
                                EnterWindow|LeaveWindow);

    XMapWindow    (theWindow);
    XMapSubwindows(theWindow);
    XDefineCursor(theWindow,arrow);


    /*********** Set up SIGFPE hander ***********/
#ifndef IEEE
    signal(SIGFPE,fperr);
#endif

    /**************** Main loop *****************/

    while (1) {
        Window wind;

        XNextEvent(&event);

        switch (event.type) {

        case ExposeRegion:            
        case ExposeWindow: {
            XExposeWindowEvent *exp_event = (XExposeWindowEvent *) &event;
            wind = exp_event->window;

            if (wind==dispwid) DrawDisplay();
            else if (wind==iconWindow)
                 XBitmapBitsPut(iconWindow,0,0,icon_width,icon_height,
                                icon_bits, IconFore, IconBack, 0,
                                GXcopy, AllPlanes);
            else {
                for (i=0; i<NUMKEYS; i++) {
                   if (key[i].wid==wind) DrawKey(i);
                   }
                }
            }
            break;

        case ButtonPressed: {
            XButtonEvent *but_event = (XButtonEvent *) &event;
            wind = but_event->window;
            if ((but_event->detail & 0xff) == LeftButton) {
                for (i=0; i<NUMKEYS; i++) {
                   if (key[i].wid==wind) { PressedKey(i); invkey=i; }
                   }
                }

            else if ((but_event->detail & 0xff) == RightButton) {
                if (key[kOFF].wid==wind) Quit();
                                    else XFeep(0);
                }
            }
            break;
                       
        case ButtonReleased: {
            XButtonEvent *but_event = (XButtonEvent *) &event;
            wind = but_event->window;
            if ((but_event->detail & 0xff) == LeftButton) {
                for (i=0; i<NUMKEYS; i++) {
                   if (key[i].wid==wind) LetgoKey(invkey);
                   }
                invkey = -1;
                }
            }
            break;

        case KeyPressed: {
            XKeyEvent *key_event = (XKeyEvent *) &event;
            wind = key_event->window;
            if (wind==theWindow) {
               char *st;
               st = XLookupMapping(key_event,&i);
               for ( ; i>0; i--) TypeChar(*st++);
               }
            else {
               printf("KeyPressed in window %ld\n",wind);
               }
            }
            break;
                    
        case EnterWindow:
        case LeaveWindow: {
            XMouseOrCrossingEvent *cross_event = 
              (XMouseOrCrossingEvent *) &event;

            if ( ((cross_event->detail & 0xff)==2) ||

                ( ((cross_event->detail & 0xff)==0) &&
                   (cross_event->window==theWindow) ) ) {

                if (cross_event->type==EnterWindow)
                     XChangeBorder(theWindow,regBorder);
                else XChangeBorder(theWindow,dimBorder);
                }
            }
            break;
                    
        default:
           printf("event type=%ld\n",event.type); 
           XCalcError("Unexpected X_Event");

        }  /* end of switch */
    }  /* end main loop */
}


/***********************************/
Syntax(call)
 char *call;
{
    printf ("Usage: %s [-bw <pixels>] [-stip] [-help] [-rv] [[<host>]:[<vs>]]\n");
    printf ("       [=geometry]\n\n");
    printf ("Default: %s -bw %d =156x226-16-16\n\n",call, DEF_BDRWIDE);
    exit(0);
}


/***********************************/
XCalcError (identifier)
       char *identifier;
{
    fprintf(stderr, "xcalc: %s\n", identifier);
    exit(1);
}



/***********************************/
SetupCalc()
{
    Pixmap      bd,nb,ob,fb,db;
    OpaqueFrame keyfrm[NUMKEYS], display;
    int i;

    bd=XMakeTile(ForeColor);
    nb=XMakeTile(NKeyBack);
    ob=XMakeTile(OKeyBack);
    fb=XMakeTile(FKeyBack);
    db=XMakeTile(DispBack);

    for (i=0; i<NUMKEYS; i++) {
        keyfrm[i].x = PADDINGW+(i%5)*(keywide+PADDINGW);
        keyfrm[i].y = disphigh+2+2*PADDINGH+(i/5)*(keyhigh+PADDINGH);
        keyfrm[i].width = keywide;
        keyfrm[i].height = keyhigh;

        if (i>=15) {
            keyfrm[i].height+=(2*EXTRAH);
            keyfrm[i].y     += ((i-15)/5)*EXTRAH*2;
            }

        keyfrm[i].bdrwidth=1;
        keyfrm[i].border=bd;

        switch (i) {
            case kZERO:  case kONE:  case kTWO:  case kTHREE:
            case kFOUR:  case kFIVE: case kSIX:  case kSEVEN:
            case kEIGHT: case kNINE: case kDEC:  case kNEG:
                keyfrm[i].background=nb;
                key[i].fore=NKeyFore;
                key[i].back=NKeyBack;
                break;
            case kADD:   case kSUB:  case kMUL:  case kDIV:  case kEQU:
                keyfrm[i].background=ob;
                key[i].fore=OKeyFore;
                key[i].back=OKeyBack;
                break;
            default:
                keyfrm[i].background=fb;
                key[i].fore=FKeyFore;
                key[i].back=FKeyBack;
            }
        
        }

    dispwid = XCreateWindow(theWindow,PADDINGW,PADDINGH,dispwide-2,disphigh,
                            2,bd,db);

    XCreateWindows(theWindow,keyfrm,NUMKEYS);

    for (i=0; i<NUMKEYS; i++) {
        key[i].wid    = keyfrm[i].self;
        key[i].st     = keystrings[i];
        key[i].x      = keyfrm[i].x;
        key[i].y      = keyfrm[i].y;
        key[i].width  = keyfrm[i].width;
        key[i].height = keyfrm[i].height;
        }

    ResetCalc();
}


/**************/
DrawDisplay()
{

    WindowInfo info;
    int strwide;

    if (strlen(dispstr)>12) {       /* strip out some decimal digits */
        char tmp[32];
        char *exp = index(dispstr,'e');  /* search for exponent part */
        if (!exp) dispstr[12]='\0';      /* no exp, just trunc. */
        else {
            if (strlen(exp)<=4) 
                sprintf(tmp,"%.8s",dispstr); /* leftmost 8 chars */
            else
                sprintf(tmp,"%.7s",dispstr); /* leftmost 7 chars */
            strcat (tmp,exp);            /* plus exponent */
            strcpy (dispstr,tmp);
            }
        }

    strwide=XStringWidth(dispstr,dfontinfo,0,0);

    XPixSet(dispwid,10,0,dispwide-20,disphigh,DispBack);
    XPixSet(dispwid,0,0,10,disphigh,ForeColor);
    XPixSet(dispwid,dispwide-10,0,10,disphigh,ForeColor);

    XText(dispwid,dispwide-10-DISPPADW/2-strwide,DISPPADH/2,
          dispstr,strlen(dispstr),dispfont,DispFore,DispBack);

    if (flagM) XBitmapBitsPut(dispwid,12,2,
                              m_width,m_height,m_bits, 
                              DispFore,DispBack,0,GXcopy,AllPlanes);

    if (flagE) XBitmapBitsPut(dispwid,12,12,
                              e_width,e_height,e_bits, 
                              DispFore,DispBack,0,GXcopy,AllPlanes);

    if (flagK) XBitmapBitsPut(dispwid,20,disphigh-FLAGH+2,
                              k_width,k_height,k_bits, 
                              DispFore,DispBack,0,GXcopy,AllPlanes);

    if (flagINV) XBitmapBitsPut(dispwid,30,disphigh-FLAGH+2,
                              inv_width,inv_height,inv_bits, 
                              DispFore,DispBack,0,GXcopy,AllPlanes);

    if (flagPAREN) XBitmapBitsPut(dispwid,dispwide-22,disphigh-FLAGH+2,
                              paren_width,paren_height,paren_bits, 
                              DispFore,DispBack,0,GXcopy,AllPlanes);

    if (drgmode==DEG) XBitmapBitsPut(dispwid,60,disphigh-FLAGH+2,
                              deg_width,deg_height,deg_bits, 
                              DispFore,DispBack,0,GXcopy,AllPlanes);

    if (drgmode==RAD) XBitmapBitsPut(dispwid,80,disphigh-FLAGH+2,
                              rad_width,rad_height,rad_bits, 
                              DispFore,DispBack,0,GXcopy,AllPlanes);

    if (drgmode==GRAD) XBitmapBitsPut(dispwid,100,disphigh-FLAGH+2,
                              grad_width,grad_height,grad_bits, 
                              DispFore,DispBack,0,GXcopy,AllPlanes);

}


/***************/
DrawKey(keynum)
    int keynum;
{
    WindowInfo info;
    char *str;
    int strwide,extrapad;
    struct _key *kp;

    kp = &key[keynum];
    str = kp->st;
    strwide = XStringWidth(str,kfontinfo,0,0);

    extrapad = (keynum>=15) ? EXTRAH : 0;

    XText(kp->wid,(kp->width-strwide)/2,KEYPADH/2+extrapad,
        str,strlen(str),keyfont,kp->fore,kp->back);
}


/*********************************/
InvertKey(keynum)
    int keynum;
{
    WindowInfo info;
    struct _key *kp;

    kp = &key[keynum];
    XPixFill(kp->wid,0,0,kp->width,kp->height,1,NULL,GXinvert,1);
}


/*********************************/
PressedKey(keynum)
       int keynum;
{
    /* currently, pressing a key merely inverts it.  Nothing happens until
       it is released. */

    InvertKey(keynum);
}

static double drg2rad=PI/180.0;  /* Conversion factors for trig funcs */
static double rad2drg=180.0/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 */

/*********************************/
LetgoKey(keynum)
     int keynum;
{
    int i,j;

    static int clear  =0;  /* CLR clears display.  if 1, clears acc, also */
    static int off    =0;  /* once clears mem, twice quits */
    static int decimal=0;  /* to prevent using decimal pt twice in a # */
    static int clrdisp=1;  /* if true clears display before entering # */
    static int accset =0;
    static int lastop =kCLR;
    static int exponent=0;
    static double acc =0.0;
    static double dnum=0.0;
    static double mem =0.0;

    double dtmp, PopNum();



    if (keynum==-1) return;
 
    InvertKey(keynum);

    if ( (entered==3) && !(keynum==kCLR || keynum==kOFF)) {
        XFeep(0);
        return;
        }

    if (keynum != kCLR) clear=0;
    if (keynum != kOFF) off=0;


#ifndef IEEE
    i=setjmp(env);
    if (i) {
        switch (i) {
           case FPE_FLTDIV_TRAP:  strcpy(dispstr,"div by zero"); break;
           case FPE_FLTDIV_FAULT: strcpy(dispstr,"div by zero"); break;
           case FPE_FLTOVF_TRAP:  strcpy(dispstr,"overflow"); break;
           case FPE_FLTOVF_FAULT: strcpy(dispstr,"overflow"); break;
           case FPE_FLTUND_TRAP:  strcpy(dispstr,"underflow"); break;
           case FPE_FLTUND_FAULT: strcpy(dispstr,"underflow"); break;
           default:               strcpy(dispstr,"error");
           }
        entered=3;
        DrawDisplay();
        return;
        }
#endif

    switch (keynum) {
        case kZERO:
        case kONE:
        case kTWO:
        case kTHREE:
        case kFOUR:
        case kFIVE:
        case kSIX:
        case kSEVEN:
        case kEIGHT:
        case kNINE:  flagINV=0;
                     if (clrdisp) {
                         dispstr[0]='\0';
                         exponent=decimal=0;
                         }
                     if (strlen(dispstr)>=MAXDISP) break;
                     strcat(dispstr,key[keynum].st);
                     DrawDisplay();
                     if (clrdisp && keynum!=kZERO) clrdisp=0; /*no leading 0s*/
                     entered=1;
                     break;

        case kDEC:   flagINV=0;
                     if (clrdisp) strcpy(dispstr,"0");
                     if (!decimal) {
                         strcat(dispstr,".");
                         DrawDisplay();
                         decimal++;
                         }
                     clrdisp=0;  entered=1;
                     break;

        case kEE:    flagINV=0;
                     if (clrdisp) strcpy(dispstr,"0");
                     if (!exponent) {
                         strcat(dispstr,"E+");
                         DrawDisplay();
                         exponent=strlen(dispstr)-1;  /* where the '-' goes */
                         }
                     clrdisp=0;  entered=1;
                     break;

        case kCLR:   flagINV=0;
                     if (clear) { /* clear all */
                         ClearStacks();  flagPAREN=0;
                         }
                     clear++;  exponent=decimal=0;
                     clrdisp=1; entered=1;
                     strcpy(dispstr,"0");
                     DrawDisplay();
                     break;

        case kNEG:   flagINV=0;
                     if (exponent) {       /* neg the exponent */
                         if (dispstr[exponent]=='-') dispstr[exponent]='+';
                                                else dispstr[exponent]='-';
                         DrawDisplay();
                         break;
                         }

                     if (strcmp("0",dispstr)==0) break;  /* 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[32];
                         sprintf(tmp,"-%s",dispstr);
                         strcpy(dispstr,tmp);
                         }
                     if (entered==2) dnum = -1.0 * dnum;
                     DrawDisplay();
                     break;

        case kADD:
        case kSUB:
        case kMUL:
        case kDIV:
        case kPOW:   if (flagINV) { flagINV=0;  DrawDisplay(); }

                     if (!entered) {                /* something like "5+*" */
                        if (!isopempty()) PopOp();  /* replace the prev op */
                        PushOp(keynum);             /* with the new one */
                        break;
                        }
                            
                     if (entered==1) sscanf(dispstr,"%lf",&dnum);

                     clrdisp++;  entered=decimal=exponent=0; clear=1;

                     if (!isopempty()) {  /* there was a previous op */
                        lastop=PopOp();   /* get it */

                        if (lastop==kLPAR) {  /* put it back */
                           PushOp(kLPAR);
                           PushOp(keynum);  PushNum(dnum);
                           break;
                           }

                        /* 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;
                              }
                           PushNum(acc);  PushOp(keynum);
                           sprintf(dispstr,"%.8g",acc);
                           DrawDisplay();
                           dnum=acc;
                           }
                        }
                     else { /* op stack is empty, push op and num */
                        PushOp(keynum);  PushNum(dnum);
                        }

                     break;
                      
        case kEQU:   flagINV=0;
                     if (!entered) break;

                     clrdisp++;  decimal=0;  exponent=0; clear=1;

                     if (entered==1) sscanf(dispstr,"%lf",&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;
                           }
                        dnum=acc;  PushNum(dnum);
                        }

                     sprintf(dispstr,"%.8g",dnum);
                     DrawDisplay();
                     break;
        
        case kLPAR:  flagINV=0;
                     PushOp(kLPAR);
                     flagPAREN++;
                     DrawDisplay();
                     break;

        case kRPAR:  flagINV=0;
                     if (!entered) break;
                     if (!flagPAREN) break;

                     clrdisp++;  decimal=0;  exponent=0;

                     if (entered==1) sscanf(dispstr,"%lf",&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;
                           }
                        dnum=acc;  PushNum(dnum);
                        }
                     PopNum();
                     flagPAREN--;  entered=2;
                     sprintf(dispstr,"%.8g",dnum);
                     DrawDisplay();
                     break;
        
        case kDRG:   if (flagINV) {
                         if (entered==1) sscanf(dispstr,"%lf",&dnum);
                         switch (drgmode) {
                             case DEG:  dnum=dnum*PI/180.0;    break;
                             case RAD:  dnum=dnum*200.0/PI;    break;
                             case GRAD: dnum=dnum*90.0/100.0;  break;
                             }
                         entered=2;  clrdisp=1;  flagINV=0;
                         sprintf(dispstr,"%.8g",dnum);
                         }
                         
                     flagINV=0;
                     drgmode = ++drgmode % 3;
                     switch (drgmode) {
                        case DEG:  drg2rad=PI / 180.0;
                                   rad2drg=180.0 / PI;
                                   break;
                        case RAD:  drg2rad=1.0;
                                   rad2drg=1.0;
                                   break;
                        case GRAD: drg2rad=PI / 200.0;
                                   rad2drg=200.0 / PI;
                                   break;
                        }
                     DrawDisplay();
                     break;

        case kINV:   flagINV = ~flagINV;
                     DrawDisplay();
                     break;
        case kE:
        case kPI:
        case kRECIP:
        case kSQR:
        case kSQRT:
        case kLOG:
        case kLN:
        case kSIN:
        case kCOS:
        case kTAN:
        case kSTO:
        case kRCL:
        case kSUM:
        case kEXC:
        case kFACT:
                     if (entered==1) sscanf(dispstr,"%lf",&dnum);

                     switch (keynum) {  /* do the actual math fn. */
                       case kE:     dnum=E;  break;
                       case kPI:    dnum=PI;  break;
                       case kRECIP: dnum=1.0/dnum;  break;
                       case kSQR:   dnum=dnum*dnum;  break;
                       case kSQRT:  dnum=sqrt(dnum);  break;
                       case kLOG:   if (flagINV) dnum=pow(10.0,dnum);
                                            else dnum=log10(dnum);
                                    break;
                       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=dnum;  flagM=!(mem==0.0);  break;
                       case kRCL:   dnum=mem;  flagM=!(mem==0.0);  break;
                       case kSUM:   mem+=dnum; flagM=!(mem==0.0);  break;
                       case kEXC:   dtmp=dnum; dnum=mem;  mem=dtmp;
                                    flagM=!(mem==0.0);  break;
                       case kFACT:  if (floor(dnum)!=dnum || dnum<0.0 || dnum>500.0) {
                                        strcpy(dispstr,"error");
                                        entered=3;
                                        break;
                                        }
                                    i=(int) (floor(dnum));
                                    for (j=1,dnum=1.0; j<=i; j++) 
                                        dnum*=(float) j;
                                    break;
                       }

                     if (entered==3) {  /* error */
                         DrawDisplay();
                         break;
                         }

                     entered=2;  clrdisp=1;  flagINV=0;
                     sprintf(dispstr,"%.8g",dnum);
                     DrawDisplay();
                     break;

        case kOFF:   /* full reset */
                     ResetCalc();
                     entered=1;  dnum=0.0;  mem=0.0;  accset=0;  clrdisp=1;
                     exponent=0;  decimal=0;
                     DrawDisplay();
                     break;

        default:     XFeep(0);
        }

#ifndef IEEE
    if (errno) {
        strcpy(dispstr,"error");
        DrawDisplay();
        entered=3;
        errno=0;
        }
#endif
}


/*******/
Quit()
/*******/
{
    exit(0);
}


#define STACKMAX 32
static int opstack[STACKMAX];
static int opsp;
static double numstack[STACKMAX];
static int numsp;


/*******/
PushOp(op)
   int op;
/*******/
{
  if (opsp==STACKMAX) {strcpy(dispstr,"stack error");  entered=3;}
  else opstack[opsp++]=op;
}

/*******/
int PopOp()
/*******/
{
  if (opsp==0) {strcpy(dispstr,"stack error");  entered=3;}
  else return(opstack[--opsp]);
}

/*******/
int isopempty()
/*******/
{
  return( opsp ? 0 : 1 );
}

/*******/
PushNum(num)
 double num;
/*******/
{
  if (numsp==STACKMAX) {strcpy(dispstr,"stack error");  entered=3;}
  else numstack[numsp++]=num;
}

/*******/
double PopNum()
/*******/
{
  if (numsp==0) {strcpy(dispstr,"stack error");  entered=3;}
  else return(numstack[--numsp]);
}

/*******/
int isnumempty()
/*******/
{
  return( numsp ? 0 : 1 );
}


/*******/
ClearStacks()
/*******/
{
  opsp=numsp=0;
}


/*******/
int priority(op)
         int op;
/*******/
{
    switch (op) {
        case kPOW: return(2); break;
        case kMUL:
        case kDIV: return(1); break;
        case kADD:
        case kSUB: return(0); break;
        }
}


/********/
ResetCalc()
/********/
{
    flagM=flagK=flagINV=flagE=flagPAREN=0;  drgmode=DEG;
    strcpy(dispstr,"0");
    ClearStacks();
    drg2rad=PI/180.0;
    rad2drg=180.0/PI;
}


/*********/
TypeChar(c)
    char c;
/*********/
{
    /* figure out if person typed a valid calculator key.
         If so, press the key, wait a bit, and release the key
         else Feep() */

    int i,key;

    switch (c) {
        case '0':  key=kZERO;   break;
        case '1':  key=kONE;    break;
        case '2':  key=kTWO;    break;
        case '3':  key=kTHREE;  break;
        case '4':  key=kFOUR;   break;
        case '5':  key=kFIVE;   break;
        case '6':  key=kSIX;    break;
        case '7':  key=kSEVEN;  break;
        case '8':  key=kEIGHT;  break;
        case '9':  key=kNINE;   break;
        case '.':  key=kDEC;    break;
        case '+':  key=kADD;    break;
        case '-':  key=kSUB;    break;
        case '*':  key=kMUL;    break;
        case '/':  key=kDIV;    break;
        case '(':  key=kLPAR;   break;
        case ')':  key=kRPAR;   break;
        case '!':  key=kFACT;   break;
        case 'e':  key=kEE;     break;
        case '^':  key=kPOW;    break;
        case 'p':  key=kPI;     break;
        case 'i':  key=kINV;    break;
        case 's':  key=kSIN;    break;
        case 'c':  key=kCOS;    break;
        case 't':  key=kTAN;    break;
        case 'd':  key=kDRG;    break;
        case 'l':  key=kLN;     break;
        case '=':  key=kEQU;    break;
        case 'n':  key=kNEG;    break;
        case '\177':
        case '\010': key=kCLR;  break;
        case '\003': Quit();    break;
        default: key = -1;
        }

    if (key != -1) {
        PressedKey(key);
        XFlush();
        Timer(100000L);
        LetgoKey(key);
        XFlush();
        }
    else XFeep(0);
}



static int timerdone;

/*******/
onalarm()
/*******/
{
  timerdone=1;
}

/*******/
Timer(val)
 long val;
/*******/
{
        struct itimerval it;

        bzero(&it, sizeof(it));
        it.it_value.tv_usec = val;
        timerdone=0;
        signal(SIGALRM,onalarm);
        setitimer(ITIMER_REAL, &it, (struct itimerval *)0);
        while (!timerdone);
        signal(SIGALRM,SIG_DFL);
}



#ifndef IEEE
/******************/
fperr(sig,code,scp)
  int sig,code;
  struct sigcontext *scp;
/******************/
{
    longjmp(env,code);
}

#endif
\Rogue\Monster\
else
  echo "will not over write ./xcalc.c"
fi
echo "Finished archive 1 of 1"
exit