/* * 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 #include #include #include #include #include #ifdef TC #include #include #endif #include #include #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; 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(); } }