home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
pascal
/
library
/
dos
/
teseract
/
tessdemo.c
< prev
next >
Wrap
C/C++ Source or Header
|
1988-10-02
|
34KB
|
1,052 lines
/*
* TESSDEMO.C -- TesSeRact Demonstration Program
*/
/******************************< TESSDEMO.C >********************************
* *
* TesSeRact Demonstration Program *
* -------------------------------- *
* *
* Copyright (c) 1986, 1987, 1988, TesSeRact Development Team *
* *
*************************************************************************CR*/
/*
* Compiled with Turbo-C 1.5 for demonstration purposes
* Used with small model
*
* To compile with MSC, use /DMSC5 command-line switch
* Note that if this is compiled with MSC 5.0, a lot of warning
* messages are generated -- this is because of the bug in MSC5.0
* having to do with functions prototyped with a 'void' parameter.
* It's not worth it to fix bugs in the compiler.
*
*/
#ifndef MSC5 /* if MSC5 not defined */
#define TC /* assume Turbo C */
#endif
#include <stdio.h>
#include <dos.h>
#include <bios.h>
#include <stdlib.h>
#include <string.h>
#include <io.h>
#ifdef TC
#include <conio.h>
#include <dir.h>
#endif
#include <ctype.h>
#include <errno.h>
#include "tess.h" /* Include file for TesSeRact */
/* structures and prototypes */
/*
* #define NOTSR to test routines
*/
/* #define NOTSR 1 */
/*
* Function prototypes for this file
*/
void c_str(int row, char *str);
void SaveCursor(void);
void RestoreCursor(void);
void NoCursor(void);
void BigCursor(void);
void DisplayTime(void);
void AdjustTime(void);
void fixrows(void);
unsigned SizeOfCode(unsigned type);
void InitTsrDemo(void);
void do_cpyrt(void);
/*
* Defines to be used for 'type' parameter
* of SizeOfCode
*/
#define NOHEAP 1
#define ALLHEAP 2
#define ALLSTACK 3
#ifdef TC
/*
* Variables specific to Turbo-C
*/
extern unsigned _heaplen = 128; /* Use 128-byte heap */
extern char _video[]; /* undocumented video structure */
extern void _VideoInt(void); /* undocumented INT 10h call that */
/* also saves BP register to */
/* compensate for buggy BIOSes */
#endif
/*
* Variables for Turbo-C Video Services
*/
#define MAXVIDROWS 60 /* VGA allows 50 lines */
/* But I have 60 on my screen */
#define MAXVIDCOLS 80 /* Only dealing with 80-cols */
#define MAXVIDSIZE (MAXVIDROWS * MAXVIDCOLS * 2)
#ifdef MSC5
#define COLORNORM 0x1e
#define COLORREV 0x4f
#else
#define COLORNORM (YELLOW + (BLUE << 4))
#define COLORREV (WHITE + (RED << 4))
#endif
#define MONONORM 0x07
#define MONOREV 0x70
#ifdef TC
#define cputc putch /* easier to understand */
#else
#define cprintf printf /* CONSOLE I/O doesn't work with */
#define cputs puts /* MSC 5.x! Some kind of problem*/
#define cputc putchar /* with reentrancy, I assume */
#endif
char savescreen[MAXVIDSIZE + 10]; /* buffer to save screen image */
/* includes 10-byte fudge factor */
unsigned NormAtt, /* Default Normal Attribute */
RevAtt, /* Default Reverse Attribute */
curmode, /* Current video mode */
pagenum, /* Current video page */
curtype, /* Default cursor type */
oldcur, /* Old Cursor shape */
oldpos; /* Old Cursor position */
unsigned maxrows = 25; /* Maximum rows on screen */
unsigned char far *biosvid; /* Pointer to video buffer */
/*
* Other global variables
*/
char buffer[10]; /* work buffer for date/time format*/
unsigned idnum, /* TSR Identification Number */
hours, /* Current hour of day */
mins, /* Current minute of hour */
secs, /* Current seconds of minute */
ticks; /* Timer-tick counter */
unsigned BackFlag = 0; /* Background flag to signal */
/* additional processing */
FILE *fp = NULL; /* file structure for file to keep */
/* open between popups */
#define FLUSHIT(fp) fclose(fp); \
fp = fopen("Tessdemo.dat","a+b")
#ifdef MSC5
/************************************************************
* MSC 5.x compatibility routines *
*********************************************************CR*/
void gotoxy(unsigned x, unsigned y) /* position cursor using BIOS */
{
union REGS regs;
regs.h.dh = y - 1;
regs.h.dl = x - 1;
regs.h.bh = 0;
regs.h.ah = 2;
int86(0x10, ®s, ®s);
}
void textmode(unsigned mode) /* set video mode using BIOS */
{
union REGS regs;
regs.h.ah = 0;
regs.h.al = mode;
int86(0x10, ®s, ®s);
}
unsigned currentattr = 0x07, /* only needed for MSC5 */
ulc = 0,
lrc = 0x184f;
/* set local variables */
void window(int left, int top, int right, int bottom)
{
ulc = ((top - 1) << 8) + (left - 1);
lrc = ((bottom - 1) << 8) + (right - 1);
}
void textattr(unsigned attr)
{
currentattr = attr; /* we don't change atts with MSC */
}
void clrscr(void) /* clear active window area */
{
union REGS regs;
regs.x.ax = 0x0600;
regs.h.bh = currentattr;
regs.x.cx = ulc;
regs.x.dx = lrc;
int86(0x10, ®s, ®s);
}
/* get text from video to buffer */
int gettext(int left, int top, int right, int bottom, char *buffer)
{
int i,j;
char far *video;
for(i = top - 1; i < bottom; i++)
{
FP_SEG(video) = FP_SEG(biosvid);
FP_OFF(video) = ((i * 80) + (left - 1) ) * 2;
for(j = left - 1; j < right; j++)
{
*buffer++ = *video++;
*buffer++ = *video++;
}
}
return(0);
}
/* put text from buffer into video */
int puttext(int left, int top, int right, int bottom, char *buffer)
{
int i,j;
char far *video;
for(i = top - 1; i < bottom; i++)
{
FP_SEG(video) = FP_SEG(biosvid);
FP_OFF(video) = ((i * 80) + (left - 1) ) * 2;
for(j = left - 1; j < right; j++)
{
*video++ = *buffer++;
*video++ = *buffer++;
}
}
return(0);
}
int wherex(void) /* get current x coordinate */
{
union REGS regs;
regs.h.ah = 0x03;
regs.h.bh = 0;
int86(0x10, ®s, ®s);
return(regs.h.dl + 1);
}
int wherey(void) /* get current y coordinate */
{
union REGS regs;
regs.h.ah = 0x03;
regs.h.bh = 0;
int86(0x10, ®s, ®s);
return(regs.h.dh + 1);
}
#define bioskey(c) _bios_keybrd((c))
#endif
/************************************************************
* Video Support Routines *
*********************************************************CR*/
void c_str(int row, char *str) /* Print a string, centered */
{
unsigned wid; /* temporary width variable */
wid = (80 - strlen(str))/2; /* calculate cursor position */
gotoxy(wid,row); /* go there */
cputs(str); /* display the string */
}
void SaveCursor(void) /* save current cursor size and */
{ /* position */
#ifdef MSC5
#define MONO 7
union REGS regs;
regs.h.ah = 3;
regs.h.bh = 0;
int86(0x10, ®s, ®s);
oldpos = regs.x.dx;
oldcur = regs.x.cx;
#else
_AH = 3; /* Get Cursor Position */
_BH = 0;
_VideoInt();
oldpos = _DX; /* Save return values */
oldcur = _CX;
#endif
/* known bug on some monochrome */
/* adapters reports the wrong */
/* cursor shape when both color */
/* and monochrome systems are */
/* installed. */
if( (curmode == MONO) && (oldcur == 0x0607) )
oldcur = 0x0c0d;
NoCursor(); /* Make cursor hidden */
}
void RestoreCursor(void) /* restore saved cursor position */
{ /* and size */
#ifdef MSC5
union REGS regs;
regs.h.ah = 2;
regs.h.bh = 0;
regs.x.dx = oldpos;
int86(0x10, ®s, ®s);
regs.h.ah = 1;
regs.h.bh = 0;
regs.x.cx = oldcur;
int86(0x10, ®s, ®s);
#else
_AH = 2; /* restore saved position */
_BH = 0;
_DX = oldpos;
_VideoInt();
_AH = 1; /* restore saved cursor type */
_BH = 0;
_CX = oldcur;
_VideoInt();
#endif
}
void NoCursor(void) /* turn off cursor */
{
#ifdef MSC5
union REGS regs;
regs.h.ah = 1;
regs.x.cx = 0xf0f0;
int86(0x10, ®s, ®s);
#else
_AH = 1;
_CX = 0xf0f0;
_VideoInt();
#endif
}
void BigCursor(void) /* use block cursor */
{
#ifdef MSC5
union REGS regs;
regs.h.ah = 1;
regs.x.cx = curtype;
int86(0x10, ®s, ®s);
#else
_AH = 1;
_CX = curtype;
_VideoInt();
#endif
}
void GetVideoMode(void)
{
#ifdef MSC5
union REGS regs;
regs.h.ah = 0x0f;
int86(0x10, ®s, ®s);
curmode = regs.h.al;
pagenum = regs.h.bh;
#else
_AH = 0x0f;
_VideoInt();
curmode = _AL;
pagenum = _BH;
#endif
}
void fixrows(void) /* Re-initialize current video */
{ /* information for new instance */
/* of video usage */
#ifdef TC
extern char _video[]; /* Undocumented Video Data region */
extern void _crtinit(int newmode); /* Internal Initialization Routine */
#endif
#ifdef MSC5
#define BW40 0
#define C40 1
#define BW80 2
#define C80 3
GetVideoMode();
maxrows = (*((unsigned char far *)0x484) + 1);
if(maxrows < 25)
maxrows = 25;
#else
_crtinit(curmode); /* re-initialize video subsystem */
maxrows = _video[7];
#endif
switch(curmode) /* deal with text mode */
{
case BW40:
textmode(BW80); /* we need 80 columns */
case BW80:
case MONO:
NormAtt = MONONORM; /* use Monochrome Attributes */
RevAtt = MONOREV;
break;
case C40:
textmode(C80); /* we need 80 columns */
case C80:
NormAtt = COLORNORM; /* use Color attributes */
RevAtt = COLORREV;
break;
}
if(curmode == MONO) /* If monochrome .... */
{
#ifdef MSC5
FP_SEG(biosvid) = 0xb000;
FP_OFF(biosvid) = 0;
#else
biosvid = MK_FP(0xb000,0); /* ... set pointer and cursor */
#endif
curtype = 0x000d;
}
else /* That means color .... */
{
#ifdef MSC5
FP_SEG(biosvid) = 0xb800;
FP_OFF(biosvid) = 0;
#else
biosvid = MK_FP(0xb800,0); /* ... so set pointer and cursor */
curtype = 0x0007;
#endif
}
}
/*****************************< main >******************************
* *
* main routine of C program *
* ------------------------- *
* *
* Simple-minded main. Calculates top of background stack region, *
* sets the stack points for the TSR; tests to see if we are already *
* resident; if so, displays ID number and exits. If it is OK *
* to install it goes resident with DoTsrInit(). Note that InitTsrDemo *
* is called by TsrCleanUp(). *
* *
* Parameters: *
* none *
* *
* Returns: *
* none *
* *
*************************************************************************CR*/
struct ExtraHot MyKeys[2] = {
{ TSRHOT_X, TSRPOPALT, 1 },
{ TSRHOT_Y, TSRPOPCTRL, 2 }
};
void main(void)
{
char far *stackptr1, /* Pointer to top of Popup Stack */
far *stackptr2; /* Pointer to top of Background */
/* stack area */
#ifdef MSC5
extern unsigned _atopsp; /* undocumented offset of top of */
/* MSC5 stack area */
extern unsigned pascal STKHQQ; /* undocumented offset of base of */
/* MSC5 stack area (plus fudge) */
struct SREGS sregs;
#else
extern unsigned __heapbase, /* undocumented offset of base of */
/* TC 1.5 heap area */
_heaplen, /* size of heap */
_stklen; /* size of stack */
#endif
#ifdef MSC5
segread(&sregs);
FP_SEG(stackptr2) = sregs.ds;
FP_OFF(stackptr2) = _atopsp - ((_atopsp - STKHQQ) / 2);
FP_SEG(stackptr1) = sregs.ds;
FP_OFF(stackptr1) = _atopsp;
#else
stackptr1 = MK_FP(_DS, __heapbase + _heaplen + (_stklen / 2) - 16);
stackptr2 = MK_FP(_DS, __heapbase + _heaplen + _stklen - 16);
#endif
TsSetStack(stackptr1, stackptr2); /* Set Popup Stack to stackptr1 */
/* background stack to stackptr2 */
/* Are we already here? */
#ifdef MSC5
if(TsCheckResident("TESSMSC ",&idnum) == 0xffff)
#else
if(TsCheckResident("TESSDEMO",&idnum) == 0xffff)
#endif
{
/* Yep! */
puts("The TesSeRact Demonstration TSR has already been loaded");
if(idnum & 0xff00) /* if released */
{
puts(" But it is currently waiting to be released from memory");
puts(" Restarting the TesSeRact Demonstration Program Now");
TsRestart(idnum & 0x00ff);
}
else
{
puts(" Use ALT-LeftShift-R to PopUp the TsrMain() routine");
printf(" Use ID Number %d to communicate through TesSeRact " \
"Multiplex functions\n",idnum);
}
exit(1);
}
if(TsCheckHotkey(TSRHOT_R) == 0xffff) /* is hotkey safe? */
{ /* ... nope! */
puts("The TesSeRact Demonstration TSR cannot be loaded because");
puts(" another TSR currently resident on this system is using");
puts(" the same hotkey!");
exit(1);
}
#ifdef NOTSR
TsrMain(); /* Test to call TsrMain */
bioskey(0);
#else
if( TsDoInit(
TSRHOT_R,
TSRPOPALT + TSRPOPLSHIFT,
TSRUSEPOPUP + TSRUSEBACK + TSRUSETIMER + TSRUSEUSER + NOPOPGRAPH,
SizeOfCode(ALLSTACK)) )
puts("Bad DoInit\n");
#endif
}
/*****************************< SizeOfCode >******************************
* *
* Determine size of program to keep resident *
* ------------------------------------------ *
* *
* This function is an example of a function that can be used to determine *
* the size of the TSR that is to remain resident. There are three *
* options to this function -- NOHEAP, ALLHEAP, and ALLSTACK. ALLHEAP *
* and ALLSTACK are identical with MSC 5.0 -- the stack is below *
* the heap, and the stack will be part of the NOHEAP version as well. *
* In Turbo C 1.5, with the stack ABOVE the heap in tiny and small *
* models, we can keep part of the heap, but drop off the stack. *
* Example code is shown for both MSC 5 and TC; other compilers and *
* langauges can determine the appropriate info as well. *
* *
* Parameters: *
* type NOHEAP, ALLHEAP or ALLSTACK parameters define above*
* *
* Returns: *
* Number of 16-byte paragraphs of memory to keep when going resident. *
* *
*************************************************************************CR*/
unsigned SizeOfCode(unsigned type)
{
#ifdef MSC5
unsigned int far *PSP; /* far pointer to PSP */
extern unsigned _psp, /* segment of PSP */
_atopsp; /* undocumented offset of top of */
/* MSC 5.0 stack */
#endif /* End of MSC5 */
#ifdef TC
extern unsigned _psp, /* segment address of PSP */
__heapbase, /* undocumented offset of base of */
/* TC 1.5 heap area */
_heaplen, /* size of heap */
_stklen; /* size of stack */
#endif /* End of TC */
unsigned used; /* variable to save paragraphs */
struct SREGS sregs; /* segment register structure */
segread(&sregs); /* read the segment regs */
switch(type)
{
case ALLSTACK:
#ifdef TC
used = (((__heapbase + 16 + _heaplen + _stklen) >> 4) + sregs.ds) - _psp;
break;
#endif
case ALLHEAP:
#ifdef MSC5
FP_SEG(PSP) = _psp; /* segment address of psp */
FP_OFF(PSP) = 0; /* offset of the psp is zero */
used = *(PSP+1) - _psp; /* number of paras used by program */
#endif
#ifdef TC
used = (((__heapbase + 16 + _heaplen) >> 4) + sregs.ds) - _psp;
#endif
break;
case NOHEAP:
#ifdef MSC5
used = (((_atopsp + 16) >> 4) + sregs.ds) - _psp;
#endif /* End of MSC5 */
#ifdef TC
used = (((__heapbase + 16) >> 4) + sregs.ds) - _psp;
#endif /* End of TC */
break;
}
return(used); /* return number of paragraphs */
}
/*****************************< do_cpyrt >******************************
* *
* Display Copyright Information *
* ----------------------------- *
* *
* Function to display formatted copyright information on the screen. *
* *
* Parameters: *
* none *
* *
* Returns: *
* none *
* *
*************************************************************************CR*/
void do_cpyrt(void)
{
textattr(RevAtt);
c_str(2,"The TesSeRact Demonstration Program");
textattr(NormAtt);
gotoxy(12,4);
cputs("Copyright 1986, 1987, 1988, TesSeRact Development Team");
gotoxy(12,5);
cputs("All Rights Reserved");
}
/*****************************< DisplayTime >******************************
* *
* 'Poke' current time into video RAM *
* ---------------------------------- *
* *
* Adjusts minutes and seconds, and then pokes the holding buffer into *
* the first 8 character bytes of the Video RAM segment. Note that *
* the 'hours' will be adjusted by the AdjustTime function. *
* *
* Parameters: *
* none *
* *
* Returns: *
* none *
* *
*************************************************************************CR***/
void DisplayTime(void)
{
int i;
buffer[0] = (hours / 10) + 0x30;
buffer[1] = (hours % 10) + 0x30;
buffer[3] = (mins / 10) + 0x30;
buffer[4] = (mins % 10) + 0x30;
buffer[6] = (secs / 10) + 0x30;
buffer[7] = (secs % 10) + 0x30;
for(i=0;i<8;i++)
biosvid[i*2] = buffer[i];
}
/*****************************< AdjustTime >******************************
* *
* Call DOS to get the current time *
* -------------------------------- *
* *
* Calls DOS to get the current time, save it to clobal values, and then *
* calls the C runtime sprintf() function to format it into the buffer *
* *
* Parameters: *
* none *
* *
* Returns: *
* none *
* *
*************************************************************************CR***/
void AdjustTime(void)
{
#ifdef MSC5
struct dostime_t timep;
_dos_gettime(&timep);
hours = timep.hour;
mins = timep.minute;
secs = timep.second;
#else
struct time timep;
gettime(&timep);
hours = timep.ti_hour;
mins = timep.ti_min;
secs = timep.ti_sec;
#endif
sprintf(buffer,"%02d:%02d:%02d",hours,mins,secs);
}
/*****************************< InitTsrDemo >******************************
* *
* Initialize variables and video *
* ------------------------------ *
* *
* This function just initializes everything, displays a sign-on message, *
* and gets the clock info for the first time. *
* *
* Parameters: *
* none *
* *
* Returns: *
* none *
* *
*************************************************************************CR***/
void InitTsrDemo(void)
{
GetVideoMode(); /* save current mode for later */
fixrows();
clrscr();
window(1,1,80,8);
textattr(NormAtt);
clrscr();
do_cpyrt();
c_str(7,"Press Alt-LeftShift-R to activate the TesSeRact " \
"Demonstration Program\n ");
AdjustTime();
DisplayTime();
if(fp == NULL)
{
fp = fopen("Tessdemo.dat","a+b");
fprintf(fp,"TesSeRact Demonstration Program loaded at %s\n\r",buffer);
FLUSHIT(fp);
}
}
/************************************************************
* TSR Procedures *
*********************************************************CR*/
char *StuffBuf = "\x72\x13\x69\x17\x6e\x31\x67\x22";
unsigned StuffLen = 4;
void far pascal TsrMain(void)
{
unsigned oldstat,curdisk,ret;
long bypercl, frees, total;
unsigned char SaveVideoPageNum = 0;
struct TsrParms far *ParmsPtr;
#ifdef MSC5
struct diskfree_t diskfree;
union REGS regs;
#else
struct dfree diskfree;
#endif
GetVideoMode(); /* save current mode for later */
SaveCursor();
if(pagenum)
{
SaveVideoPageNum = pagenum;
#ifdef MSC5
regs.x.ax = 0x0500;
int86(0x10, ®s, ®s);
#else
_AX = 0x0500;
_VideoInt();
#endif
}
fixrows();
window(1,1,80,maxrows);
gettext(1,1,80,maxrows,savescreen);
textattr(NormAtt);
clrscr();
do_cpyrt();
ParmsPtr = TsGetParms(idnum);
oldstat = TsGetStat(idnum);
gotoxy(5,7);
cprintf("This TSR popped up with HotKey #%d, and is using the "
"following procedures:", ParmsPtr->HotKeyFlag);
if(oldstat & TSRUSEPOPUP)
{
gotoxy(10,wherey()+1);
cputs("User-Defined PopUp Procedure");
}
if(oldstat & TSRUSEBACK)
{
gotoxy(10,wherey()+1);
cputs("User-Defined Background Procedure");
}
if(oldstat & TSRUSETIMER)
{
gotoxy(10,wherey()+1);
cputs("User-Defined Timer Procedure");
}
if(oldstat & TSRUSEUSER)
{
gotoxy(10,wherey()+1);
cputs("User-Defined User Communication Procedure");
}
#ifdef MSC5
_dos_getdrive(&curdisk);
_dos_getdiskfree(curdisk, &diskfree);
bypercl = (long)(diskfree.bytes_per_sector * diskfree.sectors_per_cluster);
frees = bypercl * diskfree.avail_clusters;
total = bypercl * diskfree.total_clusters;
#else
curdisk = getdisk() + 1;
getdfree(curdisk, &diskfree);
bypercl = (long)(diskfree.df_bsec * diskfree.df_sclus);
frees = bypercl * diskfree.df_avail;
total = bypercl * diskfree.df_total;
#endif
gotoxy(5,19);
cprintf("Current disk is %c:, with %ld bytes available, %ld total bytes",
curdisk + 0x40, frees, total);
fprintf(fp,"TesSeRact Demonstration Program popped up at %s\n\r",buffer);
FLUSHIT(fp);
gotoxy(5,21);
cprintf("This TSR is called %-8.8Fs, and has a PSP at segment %04x",
ParmsPtr->IdCode, ParmsPtr->TsrPSP);
gotoxy(25,22);
cprintf("Supported functions are %lx", ParmsPtr->FuncFlags);
c_str(24,"Press 'R' to remove TSR from RAM; 'K' to stuff keyboard; any other key to exit");
ret = bioskey(0) & 0xff;
/* ret = getch(); */
/* if(ret == 0) */
/* getch(); */
if(toupper(ret) == 'R')
TsRelease(idnum);
else
if(toupper(ret) == 'K')
TsStuffKeyboard(idnum, StuffBuf, StuffLen, STUFF_FAST);
puttext(1,1,80,maxrows,savescreen);
if(SaveVideoPageNum)
{
#ifdef MSC5
regs.h.ah = 0x05;
regs.h.al = SaveVideoPageNum;
int86(0x10, ®s, ®s);
#else
_AH = 0x05; /* Routine to restore correct */
_AL = SaveVideoPageNum; /* video page; courtesy of Bruce */
_VideoInt(); /* Kitchin */
#endif
}
RestoreCursor();
}
unsigned far pascal TsrBackCheck(void)
{
return(BackFlag);
}
void far pascal TsrBackProc(void)
{
AdjustTime();
fprintf(fp,"TesSeRact Demonstration Program adjusted time at %s\n\r",buffer);
FLUSHIT(fp);
BackFlag = 0;
}
void far pascal TsrTimerProc(void)
{
if(++ticks > 18)
{
ticks = 0; /* always clear ticks if > 18 */
secs++;
switch(secs)
{
case 60:
secs = 0; /* reset ticks for display & count */
if(++mins > 59) /* inc mins */
{
mins = 0; /* flip the minutes */
if(++hours > 23) /* update the hours */
hours = 0;
}
BackFlag = 1;
break;
case 20:
case 40:
secs++; /* fudge for approx ticks */
break;
}
DisplayTime(); /* always display time! */
}
}
void far pascal TsrUserProc(void far *UserPtr)
{
printf("This is the user procedure: Passed ptr = %Fs\n",UserPtr);
}
void far pascal TsrCleanUp(unsigned InitOrShutdown)
{
#ifdef TC
extern void _restorezero(void);
#else
extern void _ctermsub(void);
#endif /* End of */
if(InitOrShutdown) /* if we're shutting down */
{
if(fp != NULL)
{
fprintf(fp,"TesSeRact Demonstration Program "
"released at %s\n\r",buffer);
fclose(fp);
}
/*
* Please note that it is *absolutely* vital to call _restorezero()
* or _ctermsub() at this point -- otherwise, the INT 0 vector
* is not restored, and a divide-by-zero exception will cause
* a crash, rather than a clean exit. Note that this routine
* is compiler-dependent .... CR
*/
#ifdef TC
_restorezero();
#else
_ctermsub();
#endif
}
else
{
TsSetExtraHot(idnum, 2, MyKeys);
InitTsrDemo();
}
}