Category : C Source Code
Archive   : 3TCTGR.ZIP
Filename : TSRCALC.C

 
Output of file : TSRCALC.C contained in archive : 3TCTGR.ZIP

/* TSRCALC.C 12/10/87 Version 1.00
*
* Written By Mark E Johnson
* 2272-F Benson Avenue
* St. Paul, MN 55116
* (612)-698-3686
*
* COPYRIGHT 1987 MARK E JOHNSON. ALL RIGHTS RESERVED
*
* The windows library WINDOWS.INC was taken from the public domain, and
* modified for my use with TurboC from a Lattice C environment. Credit
* is due to the writer, whose identity is unknown.
*
* Compile this with TURBO C. Use the LARGE MODEL ONLY!
* Set MODEL to LARGE
* Set STACK CHECKING OFF
* Set STANDARD STACK FRAME OFF
* Set FLOATING POINT EMULATION (I'm not saving the 8087 context here)
*
* This program installs itself as a resident process. It monitors
* the status of the shift and Alt keys. When you hit Alt-lShift-rShift,
* the program checks the state of DOS's 'critical' flag. If the flag
* indicates no DOS calls are in progress, then the function 'service()'
* will be executed. If the flag indicates that DOS IO is not safe,
* then this program will check at each timer tick and wait to execute
* 'service()'.
*/

/* ----------- INCLUDES ----------- */

#include
#include
#include "window.h"

/* ----------- FUNCTION PROTOTYPES ----------- */

void interrupt tickhandler();
void sound(int , int );
int safe();
void prtint(int, char *, unsigned int);
unsigned int get_psp();
void set_psp(unsigned );
void service(void);

/* ----------- DEFINES ----------- */

#define RSHIFT 1
#define LSHIFT 2
#define ALT 8
#define TESTIT (RSHIFT | LSHIFT | ALT)
#define TICKINT 8
#define NEWTICK 0x50
#define INT28OLD 0x28
#define INT28NEW 0x51
#define FINI 0x5A
#define TRUE 1
#define FALSE 0
#define ESCAPE 0x1B

/* ----------- TYPEDEFS ----------- */

typedef struct { /* MSDOS allocation header format */
char flag; /* 0x5a=end, 0x4a=not end */
unsigned nextpsp, paragraphs;
} HEAD;

/* ----------- VARIABLES ----------- */

union REGS regs;
struct SREGS segregs;

HEAD *header;

extern unsigned _psp; /* Segment address of this programs PSP */
unsigned meminstall; /* Paragraphs of free memory */
char intable[0x400]; /* Buffer of Interrupt table */
char *shiftptr = (char *)0x417L; /* DOS's Shift key status byte */
char *safety_flag;
char **newtick, **oldtick; /* char is just a convenience. */
int hold_service = 0; /* if true, then service routine is running */
char **new28, **old28; /* Vectors for INT 28 */
int wait = 0; /* If > 0 then hot key was pressed, but the
'critical flag' indicates it's not safe
to do DOS I/O */

/* USED FOR DEBUGGING PURPOSES */

int i;
int call28 = 0;

char *bp_pointer;
char bp_value;

char hi_bp = 0;
char lo_bp = 126;

/* Holders for local PSP and current PSP */

unsigned int my_psp, callers_psp;

/* ----- Variables used by calculator program ----- */

char linebuffer[128];
char number[32]; /* holds current number in string form */
double fnumber1,hold; /* holds current number in double form */
double memory;
int mode; /* Flag, Scientific display or number pad */
int op,lastc;
char c;


/* ----------- MAIN PROGRAM ----------- */

void main(void)
{

page = 0;
mon_type = what_mon();
if (mon_type == 1)
attribute = set_color(BLACK, GREEN);
else
attribute = REVERSE;

/* MK_FP creates a far pointer, format: farptr = MK_FP(segment, offset) */

regs.h.ah = 0x34; /* Set up for get critical flag */
intdosx(®s, ®s, &segregs);
safety_flag = MK_FP(segregs.es, regs.x.bx);
printf("\nCritical error flag at %lx is set to %x",safety_flag, *safety_flag);


header = MK_FP(_psp - 1, 0); /* Point to TSR's allocation header */

newtick = MK_FP(0, 4 * NEWTICK); /* Swap interrupt vectors */
oldtick = MK_FP(0, 4 * TICKINT);

disable(); /* Disable hardware interrupts */
*newtick = *oldtick; /* Save old interrupt address */
*oldtick = (char *)tickhandler; /* Put new interrupt addr to table */

/* Set up Interrupt 28 trap */
/*
new28 = MK_FP(0,4 * INT28NEW);
old28 = MK_FP(0,4 * INT28OLD);
*new28 = *old28;
*old28 = (char *)doshandler;
*/

enable(); /* Re-Enable interrupts */

/* memcpy(intable,NULL,0x400); */ /* save old interrupt table */

geninterrupt(0x12); /* Ask BIOS how much memory avail. */
meminstall = _AX * 0x40; /* Store amount in paragraphs */

my_psp = get_psp();

printf("\nKeyboard TSR is now installed."
"\nPress Alt-Lshift-Rshift to activate"
"\nInt 8 handler at %lx",*oldtick);
printf("\nPSP at %04x, %04x",_psp, my_psp);

/* ----- Initialize Calculator globals ----- */
lastc='c'; /* indicates cleared calculator */
mode=TRUE; /* display number pad */
*number = NULL; /* Start with Zero in display */
fnumber1 = hold = 0;

/* Use the function keep(0,n) to set aside n paragraphs and terminate */

keep(0, _SS - _psp + 1);
}

/* ----------- SUPPORT ROUTINES ----------- */

#include "window.inc"

unsigned int get_psp()
{
_AH = 0x51;
geninterrupt(0x21);
return(_BX);
}

void set_psp(unsigned segment)
{
_BX = segment;
_AH = 0x50;
geninterrupt(0x21);
}


/* This is the real guts of the whole program */

void interrupt tickhandler()
{
geninterrupt(NEWTICK); /* Chain the interrupt first, if
you don't then the hardware will
be left disabled, causing a
crash when any I/O is attempted
*/

/* check to see if the HOT KEY as already been pressed */

if (hold_service == 0) /* Don't re-execute service if */
{ /* it's already running! */
if (wait > 0) /* Waiting for critical error flag */

if(*safety_flag == 0) /* It must be 0 to be safe */
{
service(); /* Execute application */
wait = 0; /* Re-set HOT KEY flag */
}
else
wait++;

else

/* On every tick, check for the HOT key sequence: Alt-Lshft-Rshft */

if( (*shiftptr & TESTIT) == TESTIT) /* We got a match */
{
sound(100,100);
if(*safety_flag == 0)
service();
else
wait++;
}
/* implied end of 'if (wait > 0) else' */
} /* if (hold_service == 1) */

}

/* Interrupt trap for INT 28, Must be patched with debug before use */
/* Right now as it stands, this function doesn't do anything usefull */

void interrupt doshandler(unsigned bp, unsigned di, unsigned si, unsigned ds,
unsigned es)
{

/*
asm mov ax,[bp+18] ;if we could get the next line of C code to
asm mov bp_value,ax ;compile to this, Things would be alot easier
*/

bp_value = bp; /* This compiles to: mov ax,[bp+0] change to [bp+18] */
if (hi_bp < bp_value)
hi_bp = bp_value;

if (lo_bp > bp_value)
lo_bp = bp_value;

call28++;
geninterrupt(INT28NEW);
}


/* Sound a tone, from the Turbo C manual */

void sound(int tone, int x)
{
int i,j;
char originalbits, bits;
unsigned char bcount;

bits = originalbits = inportb(0x61);

bcount = x;

for (i=0; i <= bcount; i++)
{
outportb(0x61, bits & 0xfc);
for (j=0; j <= tone; j++)
;
outportb(0x61,bits | 2);
for (j=0; j <= tone; j++)
;
}
outportb(0x61, originalbits); /* restore port setting */
}



/* -------------------------------------- */
/* From Here on down is the Resident Calculator Program.
* To make you own C program resident, Place it here instead, It
* is much easier to debug if you first write your 'service' program
* as a standard C program, and debug it as you normally would. Then
* rename the 'main()' procedure to 'service()'. If you have initialization
* code, place it in the 'main()' procedure of this file, so that it
* only gets executed once. Make sure that your program never executes
* an 'exit()', but simply drops through the last brace. At the beginning
* of your program, add the line 'hold_service = 1;' to keep it from being
* re-entered on the next clock interrupt. Before termination, add the
* line 'hold_service = 0;' to re-enable it.
*/

/* This is the Application Service Routine that is called after tickhandler
determines it is safe to perform DOS functions. I believe that at this
point, it is safe to do many types of DOS IO */

void service(void)
{
extern unsigned int page;
extern unsigned int attribute;
extern unsigned int mon_type;
int line;

/* Set hold_service to true, to keep the clock interrupt from re-
activating the service routine from within itself
*/

hold_service = 1;
win_save('s'); /* Save user screen */
make_window(1,1,24,13,1); /* Make a window */

disp_calc();
display();
while(TRUE)
{
getnum(number);
if (iindex(c,"1234567890.`") != -1)
{
sscanf(number,"%lf",&fnumber1); /* convert to float */
display();
}
else
{
if (c == 0x0D) /* is same as equals */
c = '=';
if (c == 0x7F) /* is same as C */
c = 'C';
if (c == ',') /* comma is same as + */
c = '+';

switch(toupper(c))
{

case 'C' : /* Clear calculator */
*number = NULL;
fnumber1=0;
{ disp_calc(); }
display();
hold=0;
op=' ';
break;

case '-' : /* Unary or Dyadic minus */
if (number == NULL && (lastc == 'c' | lastc == 'C') )
{
*number=c;
fnumber1=0;
display();
}
else
{
operation();
hold=fnumber1;
sprintf(number,"%lf",fnumber1);
display();
*number=NULL;
op=c;
}
break;

case '+' : /* Plus key */
operation();
hold=fnumber1;
sprintf(number,"%lf",fnumber1);
display();
*number=NULL;
op=c;
break;

case '*' : /* Times key */
operation();
hold=fnumber1;
sprintf(number,"%lf",fnumber1);
display();
*number=NULL;
op=c;
break;

case '/' : /* Divide key */
operation();
hold=fnumber1;
sprintf(number,"%lf",fnumber1);
display();
*number=NULL;
op=c;
break;

case 'Q' : /* Square root */

if (fnumber1 > 0)
fnumber1=sqrt(fnumber1);
sprintf(number,"%lf",fnumber1);
display();
break;

case '=' : /* Equals key */
operation();
sprintf(number,"%lf",fnumber1);
display();
op=' ';
*number=NULL;
hold=fnumber1;
break;

case '>' : /* Store display to memory */
memory=memory+fnumber1;
sprintf(number,"%lf",fnumber1);
display();
*number=NULL;
break;

case '<' : /* Recall memory */
fnumber1=memory;
sprintf(number,"%lf",fnumber1);
display();
break;

case 'L' : /* Clear memory */
memory=0;
display();
break;

case 0x1B : /* Control-C exits program */
goto exit;

} /* case */
} /* iindex else */
} /* while(true) */
exit:
win_save('r'); /* Restore original screen */

/* Reset hold_service so that the use may HOT KEY it again */
hold_service = 0;
}

getnum(num)
char *num;

/* Append a digit from console to the array pointed to by NUM. */
/* the GLOBAL variable 'c' (defined in the main program) will */
/* contain the last character typed. */

{
static char *p1;
static int point;

if (strlen(num) == NULL)
{
p1=num;
point=FALSE;
}

c = getch();

if (c == 0x08) /* process backspace */
c='`';

if (iindex(c,"1234567890.`") != -1)
{
if(c == '`' && strlen(number) > 0)
{
if( *--p1 == '.' )
point=FALSE;
*p1 = '\0';
}
else
{
if(c != '.' || (c == '.' && point == FALSE))
{
*p1++ = c;
*p1='\0';
if( c == '.' )
point=TRUE;
}
}
}
return(c);
}

operation()
{

if (op == '+' )
fnumber1 = fnumber1+hold;
if (op == '-' )
fnumber1 = hold-fnumber1;
if (op == '*' )
fnumber1 = hold*fnumber1;
if (op =='/' )
fnumber1 = hold/fnumber1;
if (op == '^' )
fnumber1 = fnumber1; /* power does nothing now */

}

disp_calc()
{

print(2,2,"+=====================+");
print(2,3,"| |");
print(2,4,"+---------------------+");
print(2,5,"| Micro-Tool Calc |");
if (mode == TRUE )
{
print(2,6,"| |");
print(2,7,"|m+ 7 8 9 +, |");
print(2,8,"|> - |");
print(2,9,"|mr Help 4 5 6 * |");
print(2,10,"|< / |");
print(2,11,"|mcL Win 1 2 3 |");
print(2,12,"| |");
print(2,13,"|Del Bksp 0 . = |");
print(2,14,"+=====================+");
print(2,15," Press to quit ");
}
else
{
print(2,6,"| Q G \" |");
print(2,7,"|sqr log in-cm |");
print(2,8,"| X T ' |");
print(2,9,"|exp tan cm-in |");
print(2,10,"| S N F |");
print(2,11,"|sin asn fahr-cent |");
print(2,12,"| O A E |");
print(2,13,"|cos acs cent-fahr |");
print(2,14,"+=====================+");
}
}

display() /* display number on calculator */
{
sprintf(linebuffer,"%18lf",fnumber1);
print(4,3,linebuffer);
if (op == '-' && number != NULL ) /* do nothing */ ;
else
{
print(4,3,"-");
}
if (memory != 0.0 )
print(3,3,"m");
else
print(3,3," ");
}


append(s,c)
char *s, c;

/* append the character 'c' to the CHAR array pointed to by 's' */

{
while(*s != '\0')
s++;
*s++ = c;
*s = '\0';
}


int iindex(c,s) /* return position that C occurs in S, or -1 */
char c, *s;
{
int i, retval;

retval = -1;
i=0;
while(*s != '\0')
{
if(*s++ == c)
{
retval=i;
break;
}
i++;
}
return(retval);
}