home *** CD-ROM | disk | FTP | other *** search
- /************************************************************************
- * *
- * 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 <dos.h>
- #include <stdio.h>
- #include <setjmp.h>
- #include <float.h>
- #include <signal.h>
-
- /* 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 */
- {
- }