[comp.sources.misc] v08i021: Rpn v1.1

allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (08/27/89)

Posting-number: Volume 8, Issue 21
Submitted-by: egray@fthood.UUCP
Archive-name: rpn_eg

[I see a few "questional" preprocessor constructs in this code.  ++bsa]

Rpn is a public domain "pop up" reverse polish notation calculator that
is designed to have the same (dare I say?) "look and feel" of the
Hewlett-Packard HP-16c.  It can compile on virtually any flavor of Unix
and MSDOS.  The MSDOS version will require the public domain PC Curses
package.

I've included both the nroff version of the Unix manual page and the
"ASCII'ized" version for folks (like MSDOS) without the Document Writers
Workbench.  A makefile isn't required... it's only one file.

Have fun...

Emmet P. Gray				US Army, HQ III Corps & Fort Hood
...!uunet!uiucuxc!fthood!egray		Attn: AFZF-DE-ENV
fthood!egray@uxc.cso.uiuc.edu		Directorate of Engineering & Housing
					Environmental Management Office
					Fort Hood, TX 76544-5057

------------------------------------------------------------------------------
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	rpn.c
#	rpn.1
#	rpn.man
# This archive created: Fri Aug 25 14:51:23 1989
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'rpn.c'" '(19008 characters)'
if test -f 'rpn.c'
then
	echo shar: "will not over-write existing file 'rpn.c'"
else
sed 's/^X//' << \SHAR_EOF > 'rpn.c'
X/*
X * Simple RPN (Reverse Polish Notation) calculator.  Layout and functions
X * loosely modeled after the HP-16c.  MSDOS versions will require the
X * PC Curses package.
X *
X * on Unix compile with:
X * 	cc -O [-f] -s rpn.c -o rpn -lm -lcurses [-ltermcap] [-lc_s]
X *
X * Emmet P. Gray			US Army, HQ III Corps & Fort Hood
X * ...!uunet!uiucuxc!fthood!egray	Attn: AFZF-DE-ENV
X * fthood!egray@uxc.cso.uiuc.edu	Directorate of Engineering & Housing
X * 					Environmental Management Office
X * 					Fort Hood, TX 76544-5057
X */
X
X#undef OLD_CURSES			/* for old Xenix and Berkeley */
X#undef MSDOS				/* for MSDOS (requires PC Curses) */
X#undef XENIX_3				/* for old Xenix 3.0/3.5 */
X#undef BIG_END_FIRST			/* for Intel style CPU's */
X#undef ANSI_C				/* for ANSI C */
X
X#include <stdio.h>
X#include <math.h>
X#include <curses.h>
X
X#ifdef ANSI_C
X#include <limits.h>
X#include <float.h>
X#else /* ANSI_C */
X#define LONG_MAX	0x7fffffff
X#define ULONG_MAX	0xffffffff
X#define DBL_DIG		15
X#define DBL_MAX		1.7976931348623167e+308
X#endif /* ANSI_C */
X
X#define DBL_ULONG_MAX	4294967295.0		/* ULONG_MAX as a double */
X
X#ifdef OLD_CURSES
X#define wattron(win,A_REVERSE) wstandout(win)
X#define wattroff(win,A_REVERSE) wstandend(win)
X#define wattrset(win,A_NORMAL) wstandend(win)
X#define cbreak crmode
Xchar tb[1024];
X#endif /* OLD_CURSES */
X
X#ifdef MSDOS
X#define what_is_at(w,a,b) (w->_line[a][b])
X#define getenv strdup
X#else /* MSDOS */
X#define what_is_at(w,a,b) (w->_y[a][b])
X#endif /* MSDOS */
X					/* some fundamental contstants */
X#define MAX_LOGICAL		0xffffffff
X#define SCREEN_SIZE		36
X#define STACK_SIZE		5
X#define MAX_FLOAT_DIGITS	SCREEN_SIZE-1
X#define MAX_HEX_DIGITS		8
X#define MAX_OCTAL_DIGITS	11
X#define MAX_DECIMAL_DIGITS	10
X#define MAX_BINARY_DIGITS	32
X#define DECIMAL_PLACES		8
X					/* operating modes */
X#define FLOAT	0
X#define HEX	1
X#define DECIMAL	2
X#define OCTAL	3
X#define BINARY	4
X					/* location of calculator on screen */
X#define BASE_Y	5
X#define BASE_X	0
X
Xstruct layout {
X	char key;
X	int y;
X	int x;
X};
X
Xdouble stack[STACK_SIZE] = {0.0};
Xdouble sto[10] = {0.0};
Xchar blank[SCREEN_SIZE + 1];
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	int i, mode, store_it, position, over_flow, x, y, help_is_showing;
X	int got_decimal, got_exponent, want_out, decimal_places;
X	unsigned long int_part, dtoul();
X	double op2, current, pop(), convert();
X	char c, c1, input[SCREEN_SIZE], *strchr(), *memset(), *term, *getenv();
X	char output[SCREEN_SIZE + 1], *bitpattern(), last_operator, *strcpy();
X	void push(), exit(), paint_calc(), flash_key(), clear_display();
X	WINDOW *win, *hwin, *help(), *newwin();
X
X					/* initialize the terminal */
X	term = getenv("TERM");
X	if (term == NULL || *term == '\0') {
X		printf("%s: TERM not defined...\n", argv[0]);
X		exit(1);
X	}
X					/* i=1 required for PC curses */
X	i = 1;
X#ifdef OLD_CURSES
X	i = tgetent(tb, term);
X#else /* OLD_CURSES */
X	setupterm(term, 1, &i);
X#endif /* OLD_CURSES */
X	if (i != 1) {
X		printf("%s: No terminfo data for '%s'...\n", argv[0], term);
X		exit(1);
X	}
X	initscr();
X	cbreak();
X	noecho();
X#ifdef XENIX_3
X	raw();
X#endif /* XENIX_3 */
X					/* percision in the display */
X	if (argc > 1 && *argv[1] == '-') {
X		decimal_places = atoi(&argv[1][1]);
X		if (decimal_places < 0)
X			decimal_places = 0;
X		if (decimal_places > DBL_DIG)
X			decimal_places = DBL_DIG;
X	}
X	else
X		decimal_places = DECIMAL_PLACES;
X
X	win = newwin(15, 47, BASE_Y, BASE_X);
X	paint_calc(win);
X
X	memset(blank, ' ', SCREEN_SIZE);
X	blank[SCREEN_SIZE] = '\0';
X	current = 0.0;
X	position = 0;
X	mode = FLOAT;
X	help_is_showing = 0;
X	last_operator = 0;
X	got_decimal = 0;
X	got_exponent = 0;
X	want_out = 0;
X
X	while (1) {
X		c = wgetch(win);
X					/* erase the help window */
X		if (help_is_showing) {
X			help_is_showing = 0;
X			werase(hwin);
X			wrefresh(hwin);
X			delwin(hwin);
X
X			touchwin(win);
X			wrefresh(win);
X		}
X
X		store_it = 0;
X		over_flow = 0;
X					/* get incoming digits */
X		switch (mode) {
X			case FLOAT:
X				if (strchr("0123456789.eE+-", c) != NULL)
X					store_it++;
X				switch (c) {
X					case '.':
X						if (got_decimal || got_exponent)
X							store_it = 0;
X						got_decimal++;
X						break;
X					case 'e':
X					case 'E':
X						if (!position || got_exponent)
X							store_it = 0;
X						got_exponent++;
X						break;
X
X						/*
X						 * Is it an operator or is it
X						 * the sign of the exponent?
X						 */
X					case '+':
X					case '-':
X						if (!position || (input[position - 1] != 'e' && input[position - 1] != 'E'))
X							store_it = 0;
X						break;
X				}
X				if (position >= MAX_FLOAT_DIGITS)
X					over_flow++;
X				break;
X			case HEX:
X				if (strchr("0123456789abcdef", c) != NULL)
X					store_it++;
X				if (position >= MAX_HEX_DIGITS)
X					over_flow++;
X				break;
X			case OCTAL:
X				if (strchr("01234567", c) != NULL)
X					store_it++;
X				if (position >= MAX_OCTAL_DIGITS)
X					over_flow++;
X				break;
X			case DECIMAL:
X				if (strchr("0123456789", c) != NULL)
X					store_it++;
X				if (position >= MAX_DECIMAL_DIGITS)
X					over_flow++;
X				break;
X			case BINARY:
X				if (strchr("01", c) != NULL)
X					store_it++;
X				if (position >= MAX_BINARY_DIGITS)
X					over_flow++;
X				break;
X		}
X					/* store digits */
X		if (store_it) {
X			if (over_flow) {
X				fputc(7, stderr);
X				continue;
X			}
X			flash_key(win, c);
X			if (!position)
X				clear_display(win);
X			waddch(win, c);
X			wrefresh(win);
X
X			input[position++] = c;
X			input[position] = '\0';
X			continue;
X		}
X					/* process pseudo operators */
X		switch (c) {
X			case 'q':	/* time to quit? */
X			case 'Q':
X				want_out++;
X				break;
X			case '\b':	/* do a backspace */
X				if (position) {
X					input[--position] = '\0';
X					flash_key(win, c);
X					getyx(win, y, x);
X					x--;
X					wmove(win, y, x);
X					waddch(win, ' ');
X					wmove(win, y, x);
X					wrefresh(win);
X				}
X				else
X					fputc(7, stderr);
X				continue;
X			case '?':	/* help! */
X				flash_key(win, c);
X				hwin = help();
X				help_is_showing = 1;
X				continue;
X			default:
X				break;
X		}
X		if (want_out)
X			break;
X					/* test for valid operator */
X		if (strchr("/FhHDoOB*&|lLxX\r\n-^~sSrRC+", c) == NULL) {
X			fputc(7, stderr);
X			continue;
X		}
X					/* if you've got input, convert it */
X		if (position) {
X			current = convert(input, mode);
X
X			/*
X			 * This is a little weird... if the last operator was
X			 * the <enter>, then replace (rather than push) the
X			 * value on stack.
X			 */
X			if (last_operator == '\r' || last_operator == '\n')
X				stack[0] = current;
X			else
X				push(current);
X
X			position = 0;
X			input[0] = '\0';
X			got_decimal = 0;
X			got_exponent = 0;
X		}
X					/* process "real" operators */
X		switch (c) {
X			case '\r':
X			case '\n':
X				push(current);
X				break;
X			case '+':
X				current = pop() + pop();
X				push(current);
X				break;
X			case '-':
X				op2 = pop();
X				current = pop() - op2;
X				push(current);
X				break;
X			case '*':
X				current = pop() * pop();
X				push(current);
X				break;
X			case '/':
X				op2 = pop();
X				if (op2 == 0.0) {
X					clear_display(win);
X					mvwaddstr(win, 3, 5, "divide by zero");
X					wrefresh(win);
X					continue;
X				}
X				current = pop() / op2;
X				push(current);
X				break;
X			case 'C':	/* change sign */
X				current = pop() * -1.0;
X				push(current);
X				break;
X			case 'F':	/* float */
X				mode = FLOAT;
X				mvwaddch(win, 3, SCREEN_SIZE + 5, ' ');
X				wmove(win, 3, 5);
X				break;
X			case 'h':
X			case 'H':	/* hex */
X				mode = HEX;
X				mvwaddch(win, 3, SCREEN_SIZE + 5, 'h');
X				wmove(win, 3, 5);
X				break;
X			case 'D':	/* decimal */
X				mode = DECIMAL;
X				mvwaddch(win, 3, SCREEN_SIZE + 5, 'd');
X				wmove(win, 3, 5);
X				break;
X			case 'o':
X			case 'O':	/* octal */
X				mode = OCTAL;
X				mvwaddch(win, 3, SCREEN_SIZE + 5, 'o');
X				wmove(win, 3, 5);
X				break;
X			case 'B':	/* binary */
X				mode = BINARY;
X				mvwaddch(win, 3, SCREEN_SIZE + 5, 'b');
X				wmove(win, 3, 5);
X				break;
X			case '&':	/* and */
X				int_part = dtoul(pop()) & dtoul(pop());
X				current = int_part;
X				push(current);
X				break;
X			case '|':	/* or */
X				int_part = dtoul(pop()) | dtoul(pop());
X				current = int_part;
X				push(current);
X				break;
X			case '^':	/* exclusive or */
X				int_part = dtoul(pop()) ^ dtoul(pop());
X				current = int_part;
X				push(current);
X				break;
X			case '~':	/* 1's complement */
X				int_part = (~dtoul(pop()) & MAX_LOGICAL);
X				current = int_part;
X				push(current);
X				break;
X			case 'x':
X			case 'X':	/* xchg x and y */
X				op2 = pop();
X				current = pop();
X				push(op2);
X				push(current);
X				break;
X			case 's':
X			case 'S':	/* store */
X				flash_key(win, c);
X				c1 = wgetch(win);
X				if (strchr("0123456789", c1) == NULL) {
X					fputc(7, stderr);
X					continue;
X				}
X					/* doesn't disturb the stack */
X				sto[c1 - '0'] = current;
X				break;
X			case 'r':
X			case 'R':	/* recall */
X				flash_key(win, c);
X				c1 = wgetch(win);
X				if (strchr("0123456789", c1) == NULL) {
X					fputc(7, stderr);
X					continue;
X				}
X				current = sto[c1 - '0'];
X				push(current);
X				break;
X			case 'l':
X			case 'L':	/* roll the stack */
X				op2 = stack[0];
X				for (i = 0; i < STACK_SIZE - 1; i++)
X					stack[i] = stack[i + 1];
X				stack[STACK_SIZE - 1] = op2;
X				current = stack[0];
X				break;
X			default:
X				fputc(7, stderr);
X				continue;
X		}
X		last_operator = c;
X					/* display operator key */
X		flash_key(win, c);
X					/* convert double to unsigned long */
X		if (mode != FLOAT)
X			int_part = dtoul(current);
X
X		/*
X		 * Dectect overflows in float mode only.  It's OK to overflow
X		 * in the hex/dec/oct/bin modes.
X		 */
X		if (mode == FLOAT && fabs(current) >= DBL_MAX) {
X			clear_display(win);
X			mvwaddstr(win, 3, 5, "overflow");
X			wrefresh(win);
X			continue;
X		}
X					/* print the answer */
X		switch (mode) {
X			case FLOAT:
X				sprintf(output, "%.*g", decimal_places, current);
X				break;
X			case HEX:
X				sprintf(output, "%lx", int_part);
X				break;
X			case OCTAL:
X				sprintf(output, "%lo", int_part);
X				break;
X			case DECIMAL:
X				sprintf(output, "%lu", int_part);
X				break;
X			case BINARY:
X				strcpy(output, bitpattern(int_part));
X				break;
X		}
X		clear_display(win);
X		waddstr(win, output);
X		wmove(win, 3, 5);
X		wrefresh(win);
X	}
X
X#ifdef OLD_CURSES
X	move(LINES - 1, 0);
X	refresh();
X#endif /* OLD_CURSES */
X	endwin();
X	exit(0);
X}
X
X/*
X * Push a number on the stack.  If the stack is full, the "top" value
X * is lost.
X */
X
Xvoid
Xpush(f)
Xdouble f;
X{
X	int i;
X
X	for (i = STACK_SIZE - 1; i > 0; i--)
X		stack[i] = stack[i - 1];
X	stack[0] = f;
X	return;
X}
X
X/*
X * Pop a value off the stack.  The "top" value is always preserved.
X */
X
Xdouble
Xpop()
X{
X	int i;
X	double f;
X
X	f = stack[0];
X	for (i = 0; i < STACK_SIZE - 1; i++)
X		stack[i] = stack[i + 1];
X	return (f);
X}
X
X/*
X * Convert a double to an unsigned long.  Some (most?) systems will generate
X * a FPE (Floating Point Exception) if you attempt to assign a double that
X * is greater than LONG_MAX.
X */
X
Xunsigned long
Xdtoul(d)
Xdouble d;
X{
X	double temp;
X	unsigned long ans;
X					/* is it too big for assignment? */
X	if (fabs(d) > LONG_MAX) {
X					/* chop it to a resonable size */
X		temp = fmod(d, DBL_ULONG_MAX);
X		/*
X		 * if the fmod() returns a zero, then the number is just too
X		 * big to fit any useful information in 32 bits.
X		 */
X		if (temp == 0.0)
X			ans = ULONG_MAX;
X		else {
X			if (temp > LONG_MAX) {
X				ans = (temp - LONG_MAX);
X				ans += LONG_MAX;
X			}
X			else
X				ans = temp;
X		}
X					/* boundary condition at zero */
X		if (temp != 0.0 && d > DBL_ULONG_MAX)
X			ans -= 1L;
X	}
X	else				/* gee, isn't this soooo much easier? */
X		ans = d;
X
X	return (ans & MAX_LOGICAL);
X}
X
X/*
X * Convert an ascii "number" into a double.  Handles hex/oct/bin digits.
X */
X
Xdouble
Xconvert(buf, mode)
Xchar *buf;
Xint mode;
X{
X	double f, atof();
X	unsigned long strtoul();
X
X	switch (mode) {
X		case DECIMAL:
X		case FLOAT:
X			f = atof(buf);
X			break;
X		case HEX:
X			f = (double) strtoul(buf, (char **) NULL, 16);
X			break;
X		case OCTAL:
X			f = (double) strtoul(buf, (char **) NULL, 8);
X			break;
X		case BINARY:
X			f = (double) strtoul(buf, (char **) NULL, 2);
X			break;
X	}
X	return (f);
X}
X
X/*
X * Convert a number into its binary bit pattern.  Returns a pointer to
X * a static buffer.  The BIG_END_FIRST pre-processor macro determines if
X * the number is stored "big end first" on your processor.
X */
X
Xchar *
Xbitpattern(val)
Xunsigned long val;
X{
X	unsigned char c, *p;
X	int i, j, size, printed, bp;
X	static char bitbuf[SCREEN_SIZE];
X
X					/* max of 32 bits  */
X	size = sizeof(val);
X	if (size > 4)
X		size = 4;
X
X	p = (unsigned char *) &val;
X#ifdef BIG_END_FIRST
X	p += size - 1;
X#endif /* BIG_END_FIRST */
X
X	bp = 0;
X	printed = 0;
X	for (i = 1; i <= size; i++) {
X		c = *p;
X#ifdef BIG_END_FIRST
X		p--;
X#else /* BIG_END_FIRST */
X		p++;
X#endif /* BIG_END_FIRST */
X		if (c == 0 && !printed && i != size)
X			continue;
X		for (j = 7; j >= 0; j--)
X			bitbuf[bp++] = ((c >> j) & 1) ? '1' : '0';
X		if (i != size)
X			bitbuf[bp++] = ' ';
X		printed++;
X	}
X	bitbuf[bp++] = '\0';
X	return (bitbuf);
X}
X
X/*
X * Put a key in inverse video.  This routine leaves the key in inverse video
X * until the next key is pressed.
X */
Xstruct layout button[] = {
X	'a', 6, 3,    'b', 6, 7,    'c', 6, 11,   'd', 6, 15,   'e', 6, 19,
X	'f', 6, 23,   '7', 6, 28,   '8', 6, 32,   '9', 6, 36,   '/', 6, 40,
X	'?', 8, 3,    'F', 8, 7,    'h', 8, 11,   'H', 8, 11,   'D', 8, 15,
X	'o', 8, 19,   'O', 8, 19,   'B', 8, 23,   '4', 8, 28,   '5', 8, 32,
X	'6', 8, 36,   '*', 8, 40,   '&', 10, 3,   '|', 10, 7,   'l', 10, 11,
X	'L', 10, 11,  'x', 10, 15,  'X', 10, 15,  '\b', 10, 19, '\n', 10, 23,
X	'\r', 10, 23, '1', 10, 28,  '2', 10, 32,  '3', 10, 36,  '-', 10, 40,
X	'q', 12, 3,   'Q', 12, 3,   '^', 12, 7,   '~', 12, 11,  's', 12, 15,
X	'S', 12, 15,  'r', 12, 19,  'R', 12, 19,  '0', 12, 28,  '.', 12, 32,
X	'C', 12, 36,  '+', 12, 40,  '\0', 0, 0};
X
Xvoid
Xflash_key(win, c)
XWINDOW *win;
Xchar c;
X{
X	int i, n, temp_x, old_x, old_y;
X	static int last_y = 0, last_x = 0;
X	static char keybuf[3];
X					/* get x, y coordinates */
X	n = 0;
X	while (button[n].key != '\0') {
X		if (button[n].key == c)
X			break;
X		n++;
X	}
X	if (button[n].key == '\0')
X		return;
X
X	getyx(win, old_y, old_x);
X					/* undo last button */
X	if (last_y) {
X		if (last_y == 10 && last_x == 23) {
X			for (i = 0; i < 3; i++) {
X				wmove(win, i + 10, 23);
X				wattrset(win, A_NORMAL);
X				waddstr(win, "<cr>");
X			}
X		}
X		else {
X			wmove(win, last_y, last_x);
X			wattrset(win, A_NORMAL);
X			waddstr(win, keybuf);
X		}
X	}
X					/* the enter key is 3x4 chars */
X	if (button[n].y == 10 && button[n].x == 23) {
X		for (i = 0; i < 3; i++) {
X			wmove(win, i + 10, 23);
X			wattron(win, A_REVERSE);
X			waddstr(win, "<cr>");
X			wattroff(win, A_REVERSE);
X		}
X	}
X	else {				/* flash a button */
X		wmove(win, button[n].y, button[n].x);
X		wattron(win, A_REVERSE);
X		temp_x = button[n].x;
X		for (i = 0; i < 3; i++) {
X			keybuf[i] = what_is_at(win, button[n].y, temp_x++);
X			waddch(win, keybuf[i]);
X		}
X		wattroff(win, A_REVERSE);
X	}
X	wrefresh(win);
X
X	wmove(win, old_y, old_x);
X	last_y = button[n].y;
X	last_x = button[n].x;
X	return;
X}
X
X/*
X * The image of the calculator.
X */
X
Xvoid
Xpaint_calc(win)
XWINDOW *win;
X{
X	void mybox();
X	int i;
X
X	waddstr(win, "                                              \n");
X	waddstr(win, "    Reverse Polish Notation calculator v1.1   \n");
X	waddstr(win, "   +---------------------------------------+  \n");
X	waddstr(win, "   |                                       |  \n");
X	waddstr(win, "   +---------------------------------------+  \n");
X	waddstr(win, "                                              \n");
X	waddstr(win, "    a   b   c   d   e   f    7   8   9   /    \n");
X	waddstr(win, "                                              \n");
X	waddstr(win, "    ?  Flt Hex Dec Oct Bin   4   5   6   *    \n");
X	waddstr(win, "                                              \n");
X	waddstr(win, "    &   |  roL  Xy  ^H <cr>  1   2   3   -    \n");
X	waddstr(win, "                       <cr>                   \n");
X	waddstr(win, "   Quit ^   ~  Sto Rcl <cr>  0   .  Chs  +    \n");
X	waddstr(win, "                                              \n");
X
X	/*
X	 * If you've got line drawing characters, build a box around the
X	 * calculator display, replacing the crude one above.
X	 */
X#ifdef ACS_VLINE
X	for (i = 3; i < SCREEN_SIZE + 7; i++) {
X		mvwaddch(win, 2, i, ACS_HLINE);
X		mvwaddch(win, 4, i, ACS_HLINE);
X	}
X	mvwaddch(win, 3, 3, ACS_VLINE);
X	mvwaddch(win, 3, SCREEN_SIZE + 7, ACS_VLINE);
X					/* fix up corners */
X	mvwaddch(win, 2, 3, ACS_ULCORNER);
X	mvwaddch(win, 2, SCREEN_SIZE + 7, ACS_URCORNER);
X	mvwaddch(win, 4, 3, ACS_LLCORNER);
X	mvwaddch(win, 4, SCREEN_SIZE + 7, ACS_LRCORNER);
X#endif /* ACS_VLINE */
X
X	mybox(win);
X	wmove(win, 3, 5);
X	wrefresh(win);
X	return;
X}
X
X/*
X * A box() routine that will fix up the corners if your version of
X * curses is too stupid to do that itself.
X */
X
Xvoid
Xmybox(win)
XWINDOW *win;
X{
X#ifdef ACS_VLINE
X	box(win, 0, 0);
X#else /* ACS_VLINE */
X	box(win, '|', '-');
X	mvwaddch(win, 0, 0, '+');
X	mvwaddch(win, 0, win->_maxx - 1, '+');
X	mvwaddch(win, win->_maxy - 1, 0, '+');
X	mvwaddch(win, win->_maxy - 1, win->_maxx - 1, '+');
X#endif /* ACS_VLINE */
X	return;
X}
X
X/*
X * Clear the calculator "display" by writing blanks to it.  Does not
X * clear the hex/oct/dec/bin flag at the end.
X */
X
Xvoid
Xclear_display(win)
XWINDOW *win;
X{
X	mvwaddstr(win, 3, 5, blank);
X	wmove(win, 3, 5);
X	wrefresh(win);
X	return;
X}
X
X/*
X * The help screen... it really only gives a list of the abbreviations.
X */
X
XWINDOW *
Xhelp()
X{
X	WINDOW *hwin, *newwin();
X	void mybox();
X
X	hwin = newwin(14, 46, 2, 34);
X	waddstr(hwin, "\n             RPN v1.1 - 18 Aug 89\n\n");
X	waddstr(hwin, "     +  add              &  logical and\n");
X	waddstr(hwin, "     -  subtract         |  logical or\n");
X	waddstr(hwin, "     *  multiply         ^  exclusive or\n");
X	waddstr(hwin, "     /  divide           ~  1's complement\n");
X	waddstr(hwin, "    <cr> enter key      Chs change sign\n");
X	waddstr(hwin, "    Flt float mode      Sto store [0-9]\n");
X	waddstr(hwin, "    Hex hex mode        Rcl recall [0-9]\n");
X	waddstr(hwin, "    Oct octal mode      roL roll stack\n");
X	waddstr(hwin, "    Bin binary mode      Xy exchange x y\n");
X	mybox(hwin);
X	wrefresh(hwin);
X	return (hwin);
X}
X
X#ifndef ANSI_C
X#include <errno.h>
X#include <ctype.h>
Xextern int errno;
X
Xunsigned long
Xstrtoul(buf, trailing, base)
Xchar *buf;
Xchar **trailing;
Xint base;
X{
X	int c;
X	unsigned long ans;
X
X	ans = 0L;
X
X	while (isspace(*buf))
X		buf++;
X					/* try to guess the base */
X	if (base == 0) {
X		if (*buf == '0') {
X			base = 8;
X			if (buf[1] == 'x' || buf[1] == 'X')
X				base = 16;
X		}
X		else
X			base = 10;
X	}
X					/* skip over '0x' and '0X' */
X	if (base == 16) {
X		if (*buf == '0' && (buf[1] == 'x' || buf[1] == 'X'))
X			buf += 2;
X	}
X
X	while (1) {
X		c = *buf;
X		if (isdigit(c))
X			c -= '0';
X		else if (islower(c))
X			c -= 'a' - 10;
X		else if (isupper(c))
X			c -= 'A' - 10;
X		else			/* unrecognized character, so stop */
X			break;
X					/* is this digit allowed? */
X		if (c >= base)
X			break;
X
X		if ((ULONG_MAX - (unsigned int) c) / (unsigned int) base < ans) {
X			ans = ULONG_MAX;
X			errno = ERANGE;
X			break;
X		}
X		ans = ans * base + c;
X		buf++;
X	}
X
X	if (trailing)
X		*trailing = buf;
X
X	return (ans);
X}
X#endif /* ANSI_C */
SHAR_EOF
if test 19008 -ne "`wc -c < 'rpn.c'`"
then
	echo shar: "error transmitting 'rpn.c'" '(should have been 19008 characters)'
fi
fi
echo shar: "extracting 'rpn.1'" '(4028 characters)'
if test -f 'rpn.1'
then
	echo shar: "will not over-write existing file 'rpn.1'"
else
sed 's/^X//' << \SHAR_EOF > 'rpn.1'
X.TH RPN 1 local
X.SH NAME
Xrpn \- an HP-16c reverse polish notation (rpn) calculator
X.SH SYNOPSIS
X.B rpn
X[
X.B \-d
X]
X.SH DESCRIPTION
X.I Rpn
Xis a ``pop up'' calculator for Unix and MSDOS that is designed to
Xoperate similar to the Hewlett-Packard HP-16c (Computer Scientist)
Xcalculator.  It can operate in a floating point, hexidecimal, decimal,
Xoctal, or binary mode.
X.PP
XThe
X.I \-d
Xoption is used to specify the number of decimal point precision that
Xwill appear in the display.  The internal precision of the calculator is
Xnot affected.
X.PP
XThe calculator appears on the screen as:
X.PP
X.RS 5
X.nf
X+---------------------------------------------+
X|   Reverse Polish Notation calculator v1.1   |
X|  +---------------------------------------+  |
X|  |                                       |  |
X|  +---------------------------------------+  |
X|                                             |
X|   a   b   c   d   e   f    7   8   9   /    |
X|                                             |
X|   ?  Flt Hex Dec Oct Bin   4   5   6   *    |
X|                                             |
X|   &   |  roL  Xy  ^H <cr>  1   2   3   -    |
X|                      <cr>                   |
X|  Quit ^   ~  Sto Rcl <cr>  0   .  Chs  +    |
X|                                             |
X+---------------------------------------------+
X.fi
X.RE
X.PP
XThe ``buttons'' that appear on the screen turn to inverse video when the
Xappropriate key on the keyboard is pressed.
X.PP
XReverse polish notation is an operating logic that envolves the use of
Xthe ``enter'' key in lieu of an equal sign.  To perform arithmetic,
Xkey in the first number, press the ``enter'' key, key in the second
Xnumber, and then press the operator.  For example, to add 2 plus 3,
Xyou type:
X.PP
X.RS 5
X2 ``enter'' 3 +.
X.RE
X.PP
XThe current mode of the calculator is displayed in the last
Xposition on the ``screen'' as a blank, 'h', 'd', 'o', or 'b' for the
Xfloating point, hexidecimal, decimal, octal, and binary modes
Xrespectively.
X.PP
XThe use of the hex, decimal, octal, or binary modes implies that
Xfractional parts of numbers are discarded and that negative numbers are
Xdisplayed as a 2's complement.
X.SH COMMANDS
XThe
X.I rpn
Xprogram can perform the following mathematical and logical functions:
X.PP
X.RS 5
X.nf
X.if n .ta 2.5i
X.if t .ta 2i
X\fB+\fP addition	\fB&\fP logical and
X\fB-\fP subtraction	\fB|\fP logical or
X\fB*\fP multiplication	\fB^\fP logical exculsive or
X\fB/\fP division	\fB~\fP 1's complement
X.fi
X.RE
X.PP
XThe following operators are also available:
X.TP
X.B ?
XHelp screen.  A pop-up help screen to explain the abreviations.
X.TP
X.B F
XFloating point mode.  Numbers with decimal points and/or exponents may
Xbe used.  Exponents are entered with the 'e' and may be followed by an
Xoptional sign, as in 1.23e-12.
X.TP
X.B H
XHexidecimal mode.  Numbers use hexidecimal notation (digits in the range
Xof 0-9 and a-f).  The maximum hexidecimal number is 0xffffffff.  To
Xenter a hexidecimal digit in the range of a-f, you \fImust\fP use lower
Xcase letters.
X.TP
X.B D
XDecimal mode.  Numbers use decimal notation (digits in the range of
X0-9).  The maximum decimal number is 4294967295.
X.TP
X.B O
XOctal mode.  Numbers use octal notation (digits in the range of 0-7).
XThe maximum octal number is 0377777777777.
X.TP
X.B B
Xbinary mode.  Numbers use binary notation (the digits 0 and 1).  The
Xmaximum is 32 bits.
X.TP
X.B L
XRoll the stack.  The contents of the stack are ``rolled'' down by one
Xposition.
X.TP
X.B X
XExchange X and Y values.  The last two values on the stack (X and Y)
Xswap positions.
X.TP
X.B ^H
XThe backspace key, to correct input.
X.TP
X.B ^M
XThe ``enter'' key, shown as <cr> on the calculator.
X.TP
X.B Q
XQuit.  Exit the program.
X.TP
X.B S
XStore a value in a register.  Registers are numbered 0-9.  To store a value
Xin register 2, you enter S2.
X.TP
X.B R
XRecall a value from a register.  Registers are numbered 0-9.
X.TP
X.B C
XChange sign.  To enter a negative number, you first enter the number and 
Xthen change the sign.
X.SH BUGS
XMost operators are case sensitive.
X.SH "SEE ALSO"
Xdc(1), bc(1)
SHAR_EOF
if test 4028 -ne "`wc -c < 'rpn.1'`"
then
	echo shar: "error transmitting 'rpn.1'" '(should have been 4028 characters)'
fi
fi
echo shar: "extracting 'rpn.man'" '(5173 characters)'
if test -f 'rpn.man'
then
	echo shar: "will not over-write existing file 'rpn.man'"
else
sed 's/^X//' << \SHAR_EOF > 'rpn.man'
X
X
X
X     RPN(1)                       (local)                       RPN(1)
X
X
X
X     NAME
X          rpn - an HP-16c reverse polish notation (rpn) calculator
X
X     SYNOPSIS
X          rpn [ -d ]
X
X     DESCRIPTION
X          Rpn is a ``pop up'' calculator for Unix and MSDOS that is
X          designed to operate similar to the Hewlett-Packard HP-16c
X          (Computer Scientist) calculator.  It can operate in a
X          floating point, hexidecimal, decimal, octal, or binary mode.
X
X          The -d option is used to specify the number of decimal point
X          precision that will appear in the display.  The internal
X          precision of the calculator is not affected.
X
X          The calculator appears on the screen as:
X
X               +---------------------------------------------+
X               |   Reverse Polish Notation calculator v1.1   |
X               |  +---------------------------------------+  |
X               |  |                                       |  |
X               |  +---------------------------------------+  |
X               |                                             |
X               |   a   b   c   d   e   f    7   8   9   /    |
X               |                                             |
X               |   ?  Flt Hex Dec Oct Bin   4   5   6   *    |
X               |                                             |
X               |   &   |  roL  Xy  ^H <cr>  1   2   3   -    |
X               |                      <cr>                   |
X               |  Quit ^   ~  Sto Rcl <cr>  0   .  Chs  +    |
X               |                                             |
X               +---------------------------------------------+
X
X          The ``buttons'' that appear on the screen turn to inverse
X          video when the appropriate key on the keyboard is pressed.
X
X          Reverse polish notation is an operating logic that envolves
X          the use of the ``enter'' key in lieu of an equal sign.  To
X          perform arithmetic, key in the first number, press the
X          ``enter'' key, key in the second number, and then press the
X          operator.  For example, to add 2 plus 3, you type:
X
X               2 ``enter'' 3 +.
X
X          The current mode of the calculator is displayed in the last
X          position on the ``screen'' as a blank, 'h', 'd', 'o', or 'b'
X          for the floating point, hexidecimal, decimal, octal, and
X          binary modes respectively.
X
X          The use of the hex, decimal, octal, or binary modes implies
X          that fractional parts of numbers are discarded and that
X
X
X
X     Page 1
X
X
X
X
X
X
X     RPN(1)                       (local)                       RPN(1)
X
X
X
X          negative numbers are displayed as a 2's complement.
X
X     COMMANDS
X          The rpn program can perform the following mathematical and
X          logical functions:
X
X               + addition               & logical and
X               - subtraction            | logical or
X               * multiplication         ^ logical exculsive or
X               / division               ~ 1's complement
X
X          The following operators are also available:
X
X          ?    Help screen.  A pop-up help screen to explain the
X               abreviations.
X
X          F    Floating point mode.  Numbers with decimal points
X               and/or exponents may be used.  Exponents are entered
X               with the 'e' and may be followed by an optional sign,
X               as in 1.23e-12.
X
X          H    Hexidecimal mode.  Numbers use hexidecimal notation
X               (digits in the range of 0-9 and a-f).  The maximum
X               hexidecimal number is 0xffffffff.  To enter a
X               hexidecimal digit in the range of a-f, you must use
X               lower case letters.
X
X          D    Decimal mode.  Numbers use decimal notation (digits in
X               the range of 0-9).  The maximum decimal number is
X               4294967295.
X
X          O    Octal mode.  Numbers use octal notation (digits in the
X               range of 0-7).  The maximum octal number is
X               0377777777777.
X
X          B    binary mode.  Numbers use binary notation (the digits 0
X               and 1).  The maximum is 32 bits.
X
X          L    Roll the stack.  The contents of the stack are
X               ``rolled'' down by one position.
X
X          X    Exchange X and Y values.  The last two values on the
X               stack (X and Y) swap positions.
X
X          ^H   The backspace key, to correct input.
X
X          ^M   The ``enter'' key, shown as <cr> on the calculator.
X
X          Q    Quit.  Exit the program.
X
X          S    Store a value in a register.  Registers are numbered
X               0-9.  To store a value in register 2, you enter S2.
X
X
X
X     Page 2
X
X
X
X
X
X
X     RPN(1)                       (local)                       RPN(1)
X
X
X
X          R    Recall a value from a register.  Registers are numbered
X               0-9.
X
X          C    Change sign.  To enter a negative number, you first
X               enter the number and then change the sign.
X
X     BUGS
X          Most operators are case sensitive.
X
X     SEE ALSO
X          dc(1), bc(1)
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X     Page 3
X
X
X
SHAR_EOF
if test 5173 -ne "`wc -c < 'rpn.man'`"
then
	echo shar: "error transmitting 'rpn.man'" '(should have been 5173 characters)'
fi
fi
exit 0
#	End of shell archive