Category : Alternate Operating Systems - Quarterdeck DesqView, CP/M, etc
Archive   : CALCDV.ZIP
Filename : CALCDV.C
* *
* A Simple Calculator for Desqview *
* *
* Written By: Phillip A. Kaufman November, 1987 *
* *
* Copyright 1987, 1988 Phillip A. Kaufman. All rights, except those *
* specifically granted herein are reserved by the author. The right *
* to copy and distribute this material is granted without fee for *
* any and all non-commercial use. This material specifically may *
* not be distributed or sold for a fee nor incorporated in whole or *
* in part into any other product that is distributed or sold for a *
* fee without specific permission of the author. To obtain special *
* permission or to report any difficulties with this material *
* contact: *
* Phillip A. Kaufman *
* 19987 Moran Lane *
* Saratoga, CA 95070 *
* *
* THIS MATERIAL IS DISTRIBUTES "as is" WITHOUT ANY EXPRESSED OR *
* IMPLIED WARRANTY OR LIABILITY FOR DIRECT, INDIRECT OR *
* CONSEQUENTIAL DAMAGES. *
************************************************************************
* Inputs: *
* Decimal Digits; 0 to 9 *
* Floating representation (+/-xxx.xxx) in decimal *
* mode only. *
* Hex digits; A to F REPRESENTED BY Function keys *
* Ops; + - * / There is full chaining of ops *
* HEX and Binary Ops: And, Or, Xor *
* No chaining of logical ops *
* Change Sign # *
* Memory; MClear, MRecall, M+, M- *
* Modes; Hex, Decimal, Binary *
* (hex and binary are integer only) *
* Clear Entry or Accum; C *
* EXIT; ESC *
************************************************************************
* CALCULATOR SCREEN IMAGE *
* *
* +------------------------------+ *
* 0 | | *
* 1 | MEMORY +-----------+ | *
* 2 | 1234567890123 1234567890123 | *
* 3 | +-----------+ | *
* 4 | | *
* 5 | MCLEAR M- DEC HEX BIN | *
* 6 | | *
* 7 | MRECALL M+ AND OR XOR | *
* 8 | | *
* 9 | A(F5) B(F6) 7 8 9 / | *
* 10 | | *
* 11 | C(F7) D(F8) 4 5 6 * | *
* 12 | | *
* 13 | E(F9) F(F10) 1 2 3 - | *
* 14 | | *
* 15 | CLEAR +/-(#) 0 . = + | *
* 16 | | *
* +------------------------------+ *
* 11111111112222222222 *
* 012345678901234567890123456789 *
* *
* *
************************************************************************/
#include
#include
#include
#include
#include
/* colors may be changed to suit user */
#define FG 0x07 /* forground color, unselected info */
#define BG 0x01 /* background color, main image */
#define HC 0x0a /* highlight color, selectable keys */
#define WF 0x00 /* answer window FG color */
#define WB 0x07 /* answer window BG color */
#define SC 0x0f /* selected info color */
#define EC 0x06 /* error color */
#define CASE case
#define DEFAULT default
#define OK 1
#define BAD 0
#define TRUE 1
#define FALSE 0
#define YES 1
#define NO 0
#define ROWS 17 /* for convenience - do not change */
#define COLS 30
#define ROW2 ROWS*2
#define COL2 COLS*2
#define attr(f,b) (char)( (((b)&0x0F) << 4) | ((f)&0x0F) ) /*make attr byte*/
#define apos(r,c) ((r)*COL2 + (c)*2) /* memory offset of r,c */
#define MEMR 2 /* memory disp row */
#define MEMC 1 /* memory disp col */
#define ACCR 2 /* accum row */
#define ACCC 16 /* accum col */
#define MEMPOS apos(MEMR,MEMC) /* memory display position */
#define ACPOS apos(ACCR,ACCC) /* accumulator display position */
#define ANSLEN 13 /* answers string length */
#define ERRR 1 /* error display row */
#define ERRC 16 /* error display col */
#define DEC 0 /* modes */
#define HEX 1
#define BIN 2
int mode = DEC; /* startup mode */
unsigned char modeloc[3][2] = {5,16, 5,21, 5,26};
unsigned char aoxloc[3][2] = {7,16, 7,21, 7,26};
/* All characters that appear statically highlighted */
unsigned char hichar[][3] = {
5,1,'M', 5,2,'C', 5,11,'M', 5,12,'-',
5,16,'D', 5,21,'H', 5,26,'B',
7,1,'M', 7,2,'R', 7,11,'M', 7,12,'+',
7,16,'A', 7,21,'O', 7,26,'X',
9,3,'F', 9,4,'5', 9,11,'F', 9,12,'6',
9,18,'7', 9,21,'8', 9,24,'9', 9,28,'/',
11,3,'F', 11,4,'7', 11,11,'F', 11,12,'8',
11,18,'4', 11,21,'5', 11,24,'6', 11,28,'*',
13,3,'F', 13,4,'9', 13,11,'F', 13,12,'1', 13,13,'0',
13,18,'1', 13,21,'2', 13,24,'3', 13,28,'-',
15,1,'C', 15,13,'#',
15,18,'0', 15,21,'.', 15,24,'=', 15,28,'+',
0,0,0}; /* end marker */
/* All characters that appear statically not highlighted */
unsigned char lochar[][3] = {
1,4,'M', 1,5,'E', 1,6,'M', 1,7,'O', 1,8,'R', 1,9,'Y',
5,3,'L', 5,4,'E', 5,5,'A',5,6,'R',
5,17,'E', 5,18,'C', 5,22,'E', 5,23,'X', 5,27,'I', 5,28,'N',
7,3,'E', 7,4,'C', 7,5,'A', 7,6,'L', 7,7,'L',
7,17,'N', 7,18,'D', 7,22,'R', 7,27,'O', 7,28,'R',
9,1,'A', 9,2,'(', 9,5,')', 9,9,'B', 9,10,'(', 9,13,')',
11,1,'C', 11,2,'(', 11,5,')', 11,9,'D', 11,10,'(', 11,13,')',
13,1,'E', 13,2,'(', 13,5,')', 13,9,'F', 13,10,'(', 13,14,')',
15,2,'L', 15,3,'E', 15,4,'A', 15,5,'R',
15,9,'+', 15,10,'/', 15,11,'-', 15,12,'(', 15,14,')',
0,0,0};
#define ERRLEN 11 /* number of chars in error msgs */
char OVERFLOW[] = "OVERFLOW "; /* error messages */
char ZERODIV[] = "DIVIDE BY 0";
char BADKEY[] = "ILLEGAL KEY";
char FORMATERR[]= "FORMAT ERR ";
char ENTLENGTH[]= "# TOO LONG ";
char DISPOV[] = "# TOO BIG ";
char NOERR[] = " ";
char *errptr; /* ptr to current error msg */
union REGS rg; /* cpu regs */
struct SREGS segregs;
union{
long l;
unsigned char far *p;
} addr;
char entry[ANSLEN+2]; /* entry string */
double faccum = 0.0; /* accumulator */
double fsave = 0.0; /* save for chaining */
double ftemp; /* temp for calculations */
double fmemacc = 0.0; /* memory accumulator */
char c; /* input key */
int oper; /* last operator entered */
int memop; /* last memory operator */
int equ; /* an equal sign seen */
int collect; /* collecting digits */
int recall; /* just did memory recall */
#define MEMOP 0
#define ACCOP 1
int optype; /* acc or mem for fp recovery */
int fphandler(); /* take care of floating errors */
jmp_buf mark;
main()
{
register int i;
dvinit(); /* check dv, get display addr */
setrattr(attr(FG,BG),0,0,ROWS-1,COLS-1); /* full window attributes */
setrattr(attr(WF,WB),ACCR,ACCC,ACCR+1,ACCC+ANSLEN-1);
/* answer window attr */
setrattr(attr(EC,WB),ERRR,ERRC,ERRR,ERRC+ANSLEN-1);
/* answer window attr,err */
setrattr(attr(WF,WB),MEMR,MEMC,MEMR,MEMC+ANSLEN-1);
/* mem answer window attr */
dispca(attr(HC,BG),hichar); /* static highlight chars */
dispca(attr(FG,BG),lochar); /* static normal chars */
errptr = NOERR; /* start error free */
signal(SIGFPE,fphandler);
if (setjmp(mark) == -1 ){ /* here on fp error return */
if (optype == ACCOP) faccum = 0.0;
if (optype == MEMOP) fmemacc = 0.0;
doerr();
}
oper = '\0';
memop = '\0';
equ = NO;
collect = NO;
recall = NO;
optype = ACCOP;
/* input scanner and computations */
while(1) {
display(); /* show accum and mem value */
setmode(); /* show current mode */
memop = '\0';
c = getch(); /* wait, get char */
c = toupper(c);
errptr = BADKEY; /* assume bad key */
if ( c == 'M'){ /* memory ops */
errptr = NOERR;
c = getch();
c = toupper(c);
switch (c) {
CASE '+': /* M+ or M- get pushed as = */
CASE '-':
memop = c;
c = '=';
break;
CASE 'C': /* MCLEAR */
fmemacc = 0.0;
c = 0xFF; /* don't want to see C again */
break;
CASE 'R': /* MRECALL */
if (equ == NO) fsave = faccum;
faccum = fmemacc;
recall = YES; /* fake any entry */
collect = YES;
break;
DEFAULT:
errptr = BADKEY; /* bad key */
c = 0xFF; /* bad key sequence */
}
}
switch (c) {
CASE 0x1B: /* ESC ==> exit */
exit(0);
CASE '#': /* Change Sign */
errptr = NOERR;
faccum = - faccum;
break;
CASE 'B': /* binary mode */
errptr = NOERR;
mode = BIN;
collect = NO;
recall = NO;
break;
CASE 'C': /* clear entry or accumulator */
errptr = NOERR;
if (collect){
faccum = 0.0;
}
else {
faccum = 0.0;
fsave = 0.0;
oper = '\0';
equ = NO;
}
collect = NO;
recall = NO;
break;
CASE 'D': /* set decimal mode */
errptr = NOERR;
if (oper == 'A' || oper == 'O' || oper == 'X')
oper = '\0';
mode = DEC;
collect = NO;
recall = NO;
break;
CASE 'H': /* set hex mode */
errptr = NOERR;
mode = HEX;
collect = NO;
recall = NO;
break;
CASE 'A': /* logicals stack for = */
CASE 'O':
CASE 'X':
if (mode != DEC){ /* no decimal logicals */
collect = NO;
recall = NO;
errptr = NOERR;
oper = c;
equ = NO;
}
break;
CASE '+':
CASE '-':
CASE '*': /* standard ops */
CASE '/':
errptr = NOERR;
if (equ == NO && collect){ /* a pending op to do */
ftemp = faccum;
switch (oper) {
CASE '*':
faccum *= fsave;
break;
CASE '/':
if (faccum == 0.0)
errptr = ZERODIV;
else faccum = fsave / faccum;
break;
CASE '+':
faccum += fsave;
break;
CASE '-':
faccum = fsave - faccum;
}
fsave = ftemp;
}
collect = NO;
recall = NO;
oper = c;
equ = NO;
break;
CASE '=': /* execute and chain operations */
errptr = NOERR;
if (equ == NO || (collect && equ)){ /* pending op or
pending entry */
ftemp = faccum;
switch (oper){
CASE 'A':
faccum = (double)
((long)fsave & (long)faccum);
break;
CASE 'O':
faccum = (double)
((long)fsave | (long)faccum);
break;
CASE 'X':
faccum = (double)
((long)fsave ^ (long)faccum);
break;
CASE '*':
ftemp = fsave;
if ((collect == NO) && (equ == NO))
faccum *= faccum;
else
faccum *= fsave;
break;
CASE '/':
if ((collect == NO) && (equ == NO))
faccum = 1 / faccum;
else if (equ){
if (fsave == 0.0){
errptr = ZERODIV;
faccum = 0.0;
}
else faccum = faccum / fsave;
}
else {
if (faccum == 0.0){
errptr = ZERODIV;
faccum = 0.0;
}
else faccum = fsave / faccum;
}
break;
CASE '+':
faccum += fsave;
break;
CASE '-':
if (equ)
faccum = faccum - fsave;
else
faccum = fsave - faccum;
}
}
if (equ == NO)
fsave = ftemp;
equ = YES;
collect = NO;
recall = NO;
switch (memop){
CASE '\0':
break;
CASE '+':
optype = MEMOP;
fmemacc = faccum + fmemacc;
optype = ACCOP;
break;
CASE '-':
optype = MEMOP;
fmemacc = fmemacc - faccum;
optype = ACCOP;
}
memop = '\0';
break;
CASE '0':
CASE '1':
addchar();
break;
CASE '2':
CASE '3':
CASE '4':
CASE '5':
CASE '6':
CASE '7':
CASE '8':
CASE '9':
if ( mode != BIN) {
addchar();
break;
}
CASE '\0': /* special keys */
c = getch(); /* get 2nd part */
if (mode != HEX) break;
if ( c == 0x3F) c = 'A'; /* function key 5 */
else if (c == 0x40) c = 'B'; /* f6 */
else if (c == 0x41) c = 'C'; /* f7 */
else if (c == 0x42) c = 'D'; /* f8 */
else if (c == 0x43) c = 'E'; /* f9 */
else if (c == 0x44) c = 'F'; /* f10 */
else break;
addchar();
break;
CASE '.':
if (mode != DEC) break;
addchar();
break;
CASE 0x53: /* DEL (since follows 0 - not S) */
CASE 0x08: /* Back Space */
errptr = NOERR;
if (collect == YES) {
c = '\0'; /* delete flag */
addchar();
}
}
}
}
/* set attributes for rectangle */
setrattr(attrib, ulr, ulc, lrr, lrc)
unsigned char attrib,ulr,ulc,lrr,lrc;
{
unsigned char far *ptr;
register int i, j;
for ( i = ulr; i < lrr+1; i++){ /* rows counter */
ptr = addr.p + 1 + apos(i,ulc);
for ( j = ulc; j < lrc+1; j++){ /* column position */
*ptr = attrib;
ptr = ptr + 2;
}
}
return;
}
/* display an array of characters with attributes */
dispca(attrib,array)
unsigned char attrib;
unsigned char *array;
{
unsigned char far *ptr;
while (*(array) != 0 && *(array+1) != 0){
ptr = addr.p + apos( *array,*(array+1) );
*ptr = *(array+2);
ptr++;
*ptr = attrib;
array = array +3;
}
return;
}
setmode()
{
int i, mattr;
for ( i = 0; i < 3; i++){
setrattr(attr(HC,BG),modeloc[i][0],modeloc[i][1],modeloc[i][0],
modeloc[i][1]); /* highlight 1st mode letr*/
setrattr(attr(FG,BG),modeloc[i][0],modeloc[i][1]+1,
modeloc[i][0], modeloc[i][1]+2); /* lowlight rest */
}
setrattr(attr(SC,BG),modeloc[mode][0],modeloc[mode][1],
modeloc[mode][0], modeloc[mode][1]+2);
/* highlight select mode word */
if (mode == DEC) mattr = attr(FG,BG);
else mattr = attr(HC,BG);
for ( i = 0; i < 3; i++){ /* set allowed and/or/xor command */
setrattr(mattr,aoxloc[i][0],aoxloc[i][1],
aoxloc[i][0],aoxloc[i][1]);
}
return;
}
addchar() /* check and put an input character on entry string */
{
register int i;
int elen;
double base; /* base for conversion */
double atof(); /* return types */
static int dpoint; /* saw a dp on this sequence */
if (recall == YES) return; /* can't modify mem recall */
errptr = NOERR;
if (collect == NO){ /* first char of entry so clear it out */
if (equ == NO) fsave = faccum;
faccum = 0.0;
entry[0] = '\0';
dpoint = 0;
}
collect = YES;
elen = strlen(entry);
if (dpoint == 0 && entry[elen-1] == '.') entry[--elen] = '\0';
if ( c != '\0'){ /* check length on additions */
if ( (mode == HEX && elen == 8) ||
(mode == DEC && dpoint == 0 && elen == ANSLEN -2) ||
(elen == ANSLEN -1) ){
errptr = ENTLENGTH;
return;
}
}
if (c == '.'){
if (dpoint == 0) dpoint++;
else {
errptr = FORMATERR;
return;
}
}
if (c == '\0'){ /* delete a char */
if (elen != 0){
if (entry[--elen] == '.') dpoint--;
entry[elen] = '\0';
if (elen == 0) { /* if last char del, set "0" */
entry[0] = '0';
elen = 1;
}
}
}
else { /* add a char */
if (elen == 1 && entry[0] == '0'){
if (c == '0') return; /* no extra leading zeros */
else elen--; /* take off leading zero */
}
entry[elen++] = c;
entry[elen] = '\0';
}
if (mode == DEC) {
faccum = atof(entry);
}
else {
if (mode == HEX) base = 16.0;
if (mode == BIN) base = 2.0;
faccum = 0.0;
for ( i = 0; i < elen; i++){
faccum = faccum * base + ( (entry[i]<0x40)?
entry[i] - 0x30 : entry[i] - 0x41 + 10 );
}
}
return;
}
/* update memory and accum display */
display()
{
char abuf[30];
char mbuf[30];
char tbuf[30];
unsigned char far *ptr;
register int i,j;
long int lint;
if (mode == DEC){
if (collect == NO || recall == YES){
sprintf(abuf,"% #12.11lf",faccum);
ffixup(abuf);
}
optype = MEMOP;
sprintf(mbuf,"% #12.11lf",fmemacc);
ffixup(mbuf);
optype = ACCOP;
}
else if (mode == HEX) {
if (collect == NO || recall ==YES){
lint = faccum;
faccum = (double)lint;
sprintf(abuf,"%13lX",lint);
}
optype = MEMOP;
lint = (long)fmemacc;
fmemacc = (double)lint;
sprintf(mbuf,"%13lX",lint);
optype = ACCOP;
}
else {
if (collect == NO || recall == YES){
i = (int)faccum;
faccum = (double)i;
itoa(i, tbuf, 2);
sfixup (tbuf, abuf);
}
optype = MEMOP;
i = (int)(fmemacc);
fmemacc = (double)i;
itoa(i, tbuf, 2);
sfixup (tbuf, mbuf);
optype = ACCOP;
}
if (collect == YES && recall == NO)
sfixup (entry, abuf); /* display entry string */
ptr = addr.p + MEMPOS;
for (i = 0; i < 13; i++){
*ptr = mbuf[i];
ptr = ptr + 2;
}
ptr = addr.p + ACPOS;
for (i = 0; i < 13; i++){
*ptr = abuf[i];
ptr = ptr + 2;
}
doerr();
return;
}
ffixup(buf) /* display fixup for floating point */
char *buf;
{
register int i, dotpos, zeros;
char temp[14];
for (i = 0; i <13 && buf[i] != '.'; i++);
dotpos = i;
if (dotpos >12){
errptr = DISPOV;
buf[12] = '>';
buf[13] = '\0';
doerr();
return;
}
for (i = 12; i >1 && buf[i] == '0'; i--);
if (i < 12){
zeros = 12 - i; /* number of trailing zeros */
temp[0] = buf[0];
for (i = 1; i <= zeros; i++)
temp[i] = ' ';
for (; i <13; i++)
temp[i] = buf[i-zeros];
strcpy (buf,temp);
}
return;
}
sfixup(tbuf,obuf) /* display fixup for strings */
char *tbuf, *obuf;
{
int x;
register int i,j;
x = strlen(tbuf);
if (x > ANSLEN) { /* too long, display with ">" */
errptr = DISPOV;
strncpy (obuf, tbuf, ANSLEN-1);
obuf[ANSLEN-1] = '>';
}
else { /* right justify if short */
for (i = 0; i < ANSLEN-x; i++) obuf[i] = ' ';
for (j = 0; i < ANSLEN; i++,j++) obuf[i] = tbuf[j];
}
return;
}
doerr() /* update display of error string */
{
unsigned char far *ptr;
register int i;
ptr = addr.p + apos(ERRR,ERRC+1);
for (i = 0; i < ERRLEN ; i++){
*ptr = *(errptr+i);
ptr = ptr + 2;
}
return(OK);
}
dvinit() /* Check for Desqview and use its buffer */
{
rg.x.ax = 0x2B01; /* do date set as DV check */
rg.x.cx = 0x4445; /* "DESQ"an illegal date */
rg.x.dx = 0x5351;
int86(0x21,&rg,&rg);
if (rg.h.al != 0xFF){ /* we are in desqview */
rg.h.ah = 0xFE; /* dv get buff addr */
int86(0x10,&rg,&rg);
segread(&segregs);
addr.l=((unsigned long)segregs.es<<16)+(unsigned long)rg.x.di;
}
else {
cputs ("\x07Program requires DESQview!\n");
exit(1);
}
/* put the cursor outside the window */
rg.h.ah = 0x2;
rg.h.bh = 0;
rg.x.dx = 0x151f; /* row 24 col 79*/
int86(0x10,&rg,&rg);
return;
}
int fphandler(sig,num)
int sig,num;
{
if (num == FPE_ZERODIVIDE) errptr = ZERODIV;
else errptr = OVERFLOW;
doerr();
_fpreset();
longjmp(mark,-1);
}
_setargv() /* dummy since we use no command line args */
{
}
_setenvp() /* dummy since we don't use environment variables */
{
}
Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!
This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.
But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/