[comp.sys.ibm.pc] TC StayRes sources

david@squid.UUCP (04/15/88)

From squid!david Thu Apr 14 17:41 CST 1988 remote from occrsh
From: ihnp4!occrsh!squid!david (David M Drexler)
Date: Thu, 14 Apr 88 17:41:56 CST
Comments: Give up now, before it's too late;
	  it'll never work, don't waste your time.
Message-Id: <8810417103C@squid.UUCP>
X-mailer: TeddyRuxpin mail v -1.0
Subject: TC StayRes sources

/**
 **  Address in header may be incorrect. Please reply to:
 **  { ihnp4, moss, cbosgd, uokmax }!occrsh!squid!david
 **
 **/

There seems to have been enuf interest in this subject, judging from replies
to my earlier postings, to warrant putting this code here, and it isn't very
big anyway.

This is the code from the Feb issue of Computer Languages Magazine. Get the
magazine and read it; much will be explained.

I still have the windows/tsr code by the same author from his book, which
explores the subject in much more depth than this code does. The code is
usable without the book, but the book explains why he did what he did, and how
to avoid dos programming pitfalls, etc.

I'm interested in swapping C code that is known to compile clean (and run :-)
under TC 1.5. I've currently got: the windows/tsr by Al Stevens mentioned
above, lex, sed, and m4. Someone is supposedly sending me GNUPLOT modified for
TC. The sed arrived two days ago, and has a lot of problems. The others are
pretty solid, so far as I can tell.

Does anybody have the resources to handle a mailing list just for TC sources?
Please get in touch if you do.

David Drexler       ihnp4!occrsh!squid!david
_______________________________________________________________
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()
{
}

_______________________________________________________________
Posted (not written) by

David Drexler  ihnp4!occrsh!squid!david