home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 December
/
simtel1292_SIMTEL_1292_Walnut_Creek.iso
/
msdos
/
c
/
tsrc.arc
/
TSRI.LTG
< prev
Wrap
Text File
|
1988-02-04
|
13KB
|
501 lines
Terminate and Stay Resident Programs by Al Stevens
/* -------- Listing 1 - tsr.h --------- */
void resinit(void);
void resident_psp(void);
void interrupted_psp(void);
unsigned resident(char *,void interrupt (*)());
void terminate(void);
void restart(void);
void suspend(void);
int get_char(void);
void popup(void);
void openfiles(void);
void closefiles(void);
/* ---------- Listing 2 - tsr.c ---------- */
#include <dos.h>
#include <stdio.h>
#include <string.h>
#include <dir.h>
#include "tsr.h"
static union REGS rg;
/* -------- modify for the specific TSR ------------ */
unsigned sizeprogram = 9000/16; /* TSR SIZE (PARAGRAPHS) */
unsigned scancode = 52; /* HOT KEY SCAN CODE */
unsigned keymask = 8; /* HOT KEY STATUS MASK */
char signature [] = "CLOCK"; /* TSR SIGNATURE */
static void interrupt ifunc();
/* --------- main function for the TSR program ------- */
main(argc, argv)
char *argv[];
{
int ivec;
if ((ivec = resident(signature, ifunc)) != 0) {
/* ----- TSR is resident ------- */
if (argc > 1) {
/* ---- there is a command line parameter --- */
rg.x.ax = 0;
if (strcmp(argv[1], "quit") == 0)
rg.x.ax = 1;
else if (strcmp(argv[1], "restart") == 0)
rg.x.ax = 2;
else if (strcmp(argv[1], "wait") == 0)
rg.x.ax = 3;
if (rg.x.ax) {
/* -- call the communications interrupt -- */
int86(ivec, &rg, &rg);
return;è }
}
printf("\nClock is already resident");
}
else {
/* ------ initial load of TSR program ------ */
printf("\nResident clock is loaded");
openfiles();
resinit();
}
}
/* -------- TSR communications ISR ---------- */
void interrupt ifunc(bp,di,si,ds,es,dx,cx,bx,ax)
{
if (ax == 1) /* "quit" */
terminate();
else if (ax == 2) /* "restart" */
restart();
else if (ax == 3) /* "wait" */
suspend();
}
/* -------- Listing 3 - resident.c --------- */
#include <dos.h>
#include <stdio.h>
#include "tsr.h"
/* --- vectors ---- */
#define KEYBD 9
#define TIMER 0x1c
#define DISK 0x13
#define VIDEO 0x10
#define ZERODIV 0
#define INT28 0x28
#define CRIT 0x24
/* ------ interrupt vector chains ------ */
static void interrupt (*oldtimer)();
static void interrupt (*old28)();
static void interrupt (*oldkb)();
static void interrupt (*olddisk)();
static void interrupt (*oldvideo)();
static void interrupt (*oldcrit)();
extern void interrupt (*ZeroDivVector)();
/* ------ ISRs for the TSR ------- */
static void interrupt newtimer();
static void interrupt new28();
static void interrupt newkb();
static void interrupt newdisk();
static void interrupt newvideo();
static void interrupt newcrit();
/* ------ registers for int86 & dos86 ------- */
static union REGS rg;èstatic struct SREGS seg;
static unsigned dosseg; /* DOS segment address */
static unsigned dosbusy; /* offset to InDOS flag */
static char far *mydta; /* TSR's DTA */
static unsigned myss; /* TSR's stack segment */
static unsigned stack; /* TSR's stack pointer */
static unsigned mypsp; /* TSR's PSP address */
static unsigned intpsp; /* Interrupted PSP address */
static unsigned psps[2]; /* Table of DOS PSP addresses */
static int pspctr; /* # of DOS PSP addresses */
static int resoff; /* suspend/resume flag */
static int running; /* TSR running indicator */
static int popflg; /* Hot key pressed flag */
static int diskflag; /* Disk BIOS busy flag */
static int videoflag; /* Video BIOS busy flag */
static int cflag; /* staging area for flags */
/* ------- local prototypes -------- */
static void resterm(void);
static void pspaddr(void);
static void dores(void);
/* -------- establish & declare residency --------- */
void resinit()
{
extern unsigned sizeprogram; /* defined in popup.c */
segread(&seg);
myss = seg.ss;
/* ------ get address of DOS busy flag ---- */
rg.h.ah = 0x34;
intdos(&rg, &rg);
dosseg = _ES;
dosbusy = rg.x.bx;
/* ----- get address of resident program's dta ----- */
mydta = getdta();
/* -------- get addresses of PID in DOS ------- */
pspaddr();
/* ----- get original interrupt vectors ----- */
oldtimer = getvect(TIMER);
old28 = getvect(INT28);
oldkb = getvect(KEYBD);
olddisk = getvect(DISK);
oldvideo = getvect(VIDEO);
/* ----- attach vectors to resident program ----- */
setvect(TIMER, newtimer);
setvect(KEYBD, newkb);
setvect(INT28, new28);
setvect(DISK, newdisk);
setvect(VIDEO, newvideo);
/* ------ compute stack pointer ------- */
stack = (sizeprogram - (seg.ds - seg.cs)) * 16 - 300;
/* ---- restore zero divide interrupt vector --- */
setvect(ZERODIV, ZeroDivVector);è /* ----- terminate and stay resident ------- */
keep(0, sizeprogram);
}
/* ------ BIOS disk functions ISR ------- */
void interrupt newvideo(bp,di,si,ds,es,dx,cx,bx,ax)
{
videoflag++;
(*oldvideo)();
ax = _AX; /* for the register returns */
bx = _BX;
cx = _CX;
dx = _DX;
es = _ES;
di = _DI;
--videoflag;
}
/* -------- critical error ISR ---------- */
void interrupt newcrit(bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flgs)
{
ax = 0; /* ignore critical errors */
cflag = flgs; /* for newdisk */
}
/* ------ BIOS disk functions ISR ------- */
void interrupt newdisk(bp,di,si,ds,es,dx,cx,bx,ax,ip,cs,flgs)
{
diskflag++;
(*olddisk)();
ax = _AX; /* for the ax return */
newcrit(); /* to get current flags register */
flgs = cflag; /* newdisk will return oldisk's flags */
--diskflag;
}
/* ----- keyboard ISR ------ */
void interrupt newkb()
{
extern unsigned scancode; /* defined in ... */
extern unsigned keymask; /* ... popup.c */
static int kbval;
if (inportb(0x60) == scancode) {
kbval = peekb(0, 0x417);
if (!resoff && ((kbval & keymask) ^ keymask) == 0) {
/* --- reset the keyboard ---- */
kbval = inportb(0x61);
outportb(0x61, kbval | 0x80);
outportb(0x61, kbval);
disable();
outportb(0x20, 0x20);
enable();
/* ---- set hotkey indicator ---- */
if (!running)è popflg = 1;
return;
}
}
(*oldkb)();
}
/* ----- timer ISR ------- */
void interrupt newtimer()
{
(*oldtimer)();
if (popflg && peekb(dosseg, dosbusy) == 0)
if (diskflag == 0 && videoflag == 0) {
outportb(0x20, 0x20);
popflg = 0;
dores();
}
}
/* ----- 0x28 ISR -------- */
void interrupt new28()
{
(*old28)();
if (popflg && peekb(dosseg, dosbusy) != 0) {
popflg = 0;
dores();
}
}
/* ------ switch psp context from interrupted to TSR ----- */
void resident_psp()
{
int pp;
/* ------ save interrupted program's psp ----- */
intpsp = peek(dosseg, *psps);
/* ----- set resident program's psp ----- */
for (pp = 0; pp < pspctr; pp++)
poke(dosseg, psps [pp], mypsp);
}
/* ---- switch psp context from TSR to interrupted ---- */
void interrupted_psp()
{
int pp;
/* ----- reset interrupted program's psp ----- */
for (pp = 0; pp < pspctr; pp++)
poke(dosseg, psps [pp], intpsp);
}
/* ------ execute the resident program ------- */
static void dores()
{
static char far *intdta; /* interrupted DTA */è static unsigned intsp; /* " stack pointer */
static unsigned intss; /* " stack segment */
static unsigned ctrl_break; /* Ctrl-Break setting */
running = 1;
disable();
intsp = _SP;
intss = _SS;
_SP = stack;
_SS = myss;
enable();
oldcrit = getvect(CRIT);/* redirect critical error */
setvect(CRIT, newcrit);
rg.x.ax = 0x3300; /* get ctrl break setting */
intdos(&rg, &rg);
ctrl_break = rg.h.dl;
rg.x.ax = 0x3301; /* turn off ctrl break logic */
rg.h.dl = 0;
intdos(&rg, &rg);
intdta = getdta(); /* get interrupted dta */
setdta(mydta); /* set resident dta */
resident_psp(); /* swap psps */
popup(); /* execute resident program */
interrupted_psp(); /* reset interrupted psp */
setdta(intdta); /* reset interrupted dta */
setvect(CRIT, oldcrit); /* reset critical error */
rg.x.ax = 0x3301; /* reset ctrl break */
rg.h.dl = ctrl_break;
intdos(&rg, &rg);
disable(); /* reset interrupted stack */
_SP = intsp;
_SS = intss;
enable();
running = 0;
}
static int avec = 0;
/* ------- test to see if the program is already resident
if not, attach to an available interrupt ---------- */
unsigned resident(signature, ifunc)
char *signature;
void interrupt (*ifunc)();
{
char *sg;
unsigned df;
int vec;
segread(&seg);
df = seg.ds-seg.cs;
for (vec = 0x60; vec < 0x68; vec++) {
if (getvect(vec) == NULL) {
if (!avec)
avec = vec;
continue;è }
for (sg = signature; *sg; sg++)
if (*sg!=peekb(peek(0,2+vec*4)+df,(unsigned)sg))
break;
if (!*sg)
return vec;
}
if (avec)
setvect(avec, ifunc);
return 0;
}
/* -------- find address of PID ---------- */
static void pspaddr()
{
unsigned adr = 0;
unsigned enddos; /* offset to the end of DOS */
/* ------- get the current psp --------- */
rg.h.ah = 0x51;
intdos(&rg, &rg);
mypsp = rg.x.bx;
/* ----- find the end of the DOS segment ------- */
rg.h.ah = 0x52;
intdos(&rg, &rg);
enddos = _ES;
enddos = peek(enddos, rg.x.bx-2);
/* ---- search for matches on the psp in dos ---- */
while (pspctr < 2 &&
(unsigned)((dosseg<<4) + adr) < (enddos<<4)) {
if (peek(dosseg, adr) == mypsp) {
rg.h.ah = 0x50;
rg.x.bx = mypsp + 1;
intdos(&rg, &rg);
if (peek(dosseg, adr) == mypsp+1)
psps[pspctr++] = adr;
/* ---- reset the original psp ------ */
rg.h.ah = 0x50;
rg.x.bx = mypsp;
intdos(&rg, &rg);
}
adr++;
}
}
/* ------- terminate function ----------- */
static void resterm()
{
static unsigned mcbseg;
closefiles(); /* close TSR files */
/* ----- restore the interrupt vectors ----- */
setvect(TIMER, oldtimer);
setvect(KEYBD, oldkb);
setvect(INT28, old28);è setvect(DISK, olddisk);
setvect(VIDEO, oldvideo);
setvect(avec, (void interrupt (*)()) 0);
/* ---- get the seg addr of 1st DOS MCB ---- */
rg.h.ah = 0x52;
intdos(&rg, &rg);
mcbseg = _ES;
mcbseg = peek(mcbseg, rg.x.bx-2);
/* ---- walk thru mcb chain & release memory ----- */
segread(&seg);
while (peekb(mcbseg, 0) == 0x4d) {
if (peek(mcbseg, 1) == mypsp) {
rg.h.ah = 0x49;
seg.es = mcbseg+1;
intdosx(&rg, &rg, &seg);
}
mcbseg += peek(mcbseg, 3) + 1;
}
}
/* --------- terminate the resident program --------- */
void terminate()
{
if (getvect(VIDEO) == (void interrupt (*)()) newvideo)
if (getvect(DISK) == (void interrupt (*)()) newdisk)
if (getvect(KEYBD) == newkb)
if (getvect(INT28) == new28)
if (getvect(TIMER) == newtimer) {
resterm();
return;
}
resoff = 1; /* another TSR is above us, merely suspend */
}
/* ------------- restart the resident program --------- */
void restart()
{
resoff = 0;
}
/* ------- put the program on hold -------- */
void suspend()
{
resoff = 1;
}
/* ------------- get a keyboard character ---------------- */
int get_char()
{
int c;
while (1) {
rg.h.ah = 1;
int86(0x16, &rg, &rg); /* char ready? */
if (rg.x.flags & 0x40) {è int86(0x28, &rg, &rg); /* 0x28 interrupt */
continue;
}
rg.h.ah = 0;
int86(0x16, &rg, &rg); /* read the char */
if (rg.h.al == 0) /* function key? */
c = rg.h.ah | 128; /* adjust scan code */
else
c = rg.h.al;
break;
}
return c;
}
/* ---------- Listing 4 - clock.c ------------ */
/*
* A sample TSR that is connected with the TSR Library
* functions. This program will display the current date
* and time on the screen when the hot key is pressed.
* The display remains and the TSR stays popped up until
* another key is pressed.
*/
#include <stdio.h>
#include <dos.h>
#include "tsr.h"
#define VSEG 0xb800 /* change to 0xb000 for MDA */
#define ROW 10 /* where the clock displays */
#define COL 30
void popup()
{
struct date dat;
struct time tim;
int sv[20];
char bf[20];
unsigned v;
static char tmsk [] = " %2d-%02d-%02d %02d:%02d:%02d ";
/* ---- get the current date and time ------ */
gettime(&tim);
getdate(&dat);
/* ----- save the video memory ----- */
for (v = 0; v < 19; v++)
sv[v] = peek(VSEG, ((ROW*80+COL) + v) * 2);
/* ----- build the date/time display ------- */
sprintf(bf,tmsk,dat.da_day,dat.da_mon,dat.da_year
% 100,tim.ti_hour, tim.ti_min, tim.ti_sec);
/* ----- display the date and time -------- */
for (v = 0; v < 19; v++)
poke(VSEG, ((ROW*80+COL) + v) * 2, 0x7000 + bf[v]);
get_char();
/* -------- restore the video memory ---- */è for (v = 0; v < 19; v++)
poke(VSEG, ((ROW*80+COL) + v) * 2, sv[v]);
}
/* ----- startup function, to be used in TSR application ---- */
void openfiles()
{
}
/* ----- shutdown function, to be used in TSR application ---- */
void closefiles()
{
}