home *** CD-ROM | disk | FTP | other *** search
- {$C-}
- {-----------------------------------------------------------------------------}
- { }
- { }
- { }
- { " S o r r y , D a v e, I C a n ' t D o T h a t . " }
- { }
- { }
- { Arthur C. Clark }
- { " 2 0 0 1 " }
- {-----------------------------------------------------------------------------}
-
- { A Turbo "stay-resident" program clobbers the Dos register stack. It
- jumps over the Turbo run-time initialization code that would set up the
- program registers and environment. Secondly, a stay-resident program
- could not ordinarily issue file I/O since that would clobber Dos interrupt
- registers. Therefore, the following code proposes an inline solution,
- providing a Turbo entry stack for "stay-resident" programs and allowing
- those programs to issue Dos I/O and other interrupts.
-
- This Turbo stay-resident demo has been put together to perform both Dos I/O
- and Bios interrupts. It has also been tested for re-entrancy and
- recursiveness on an IBM PC with PCDos .
-
- Separate the include files, compile to a COM file and execute with the
- Alt-F10 key. It will also free its memory and return to Dos with the
- Ctrl-Home key at the "Press a key" prompt. (Illustrated in the Stayxit
- file). Maximum free dynamic memory should be between A40-B00 since this
- demo uses a recursive stack.
-
- The Hunters Helper
-
- L.Ferris
- 4268 26th St
- San Francisco,Ca. 94131
- [ 70357,2716 ] }
- {-----------------------------------------------------------------------------}
- { This code has been tested/used on an IBM PC using PC-DOS 2.10 }
- {-----------------------------------------------------------------------------}
-
-
- { Authors: Lane H. Ferris (Stay Resident Code)
- Neil J. Rubenking (Directory code and ideas)
- Jim Everingham (The Window Manager/Editor)
- Other Public Gurus on whose shoulders we stand.
-
- { PURPOSE: This code will serve as a template to create other "Stay Resident"
- programs in Turbo Pascal(tm). This code intercepts Int 16,
- displacing original Interrupt 16 Vector to User Interrupt 68.
- During execution of other programs, it can be invoked by the
- special key combination specified by "Our_Char" (in this case
- <Alt>-F10.)
- }
-
- Program Stay_Resident;
-
- { * * * * * * * CONSTANTS * * * * * * * * * * * * * * * * * * * * * * }
- const
- Our_Char = 113; {this is the scan code for AltF10}
- Ctrl_Home = #119; {Control Home Scan Code }
- Quit_Key = #119;
- Ctrl_End = #117; {Control End Scan Code }
- User_Int = $68; {place to put new interrupt}
- Kybrd_Int = $16; {BIOS keyboard interrupt}
-
- { - - - - - - - T Y P E D E C L A R A T I O N S - - - - - - - - - - - - }
- Type
- Regtype = record Ax,Bx,Cx,Dx,Bp,Si,Di,Ds,Es,Flags:integer end;
- HalfRegtype = record Al,Ah,Bl,Bh,Cl,Ch,Dl,Dh:byte end;
- filename_type = string[64];
-
- { - - - - - - - T Y P E D C O N S T A N T S - - - - - - - - - - - - - - -}
- Const
- {regs is defined as a typed constant in order to get it in the code segment}
- Regs : regtype = (Ax:0;Bx:0;Cx:0;Dx:0;Bp:0;Si:0;Di:0;Ds:0;Es:0;Flags:0);
-
- OurDseg: integer = 0; {Our Data Segment Value }
- OurSseg: integer = 0; {Our Stack Segment Value }
- DosSseg: integer = 0; {Dos Stack Segment Value }
- Inuse : Boolean = false; {Recursion flag }
-
- { - - - - - - - V A R I A B L E S - - - - - - - - - - - - - - - - - - - - - -}
- Var
- SaveRegs : regtype;
- HalfRegs : halfregtype absolute regs;
- Terminate_flag : boolean ;
- Keychr : char ;
- Old_Xpos,Old_Ypos : integer ;
- { - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - }
-
- { - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - }
- { Check Terminate Keys
- { - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - }
- Procedure Chk_Term_Key;
- {$I StayXit.Inc} {Check for Exit to Dos }
- {-----------------------------------------------------------------------------}
- { G E T F I L E }
- {-----------------------------------------------------------------------------}
-
- procedure get_file;
- {$I staysubs.inc}
- var
- attribyte,
- OldAttribute : byte;
- Xcursor : integer ;
- Ycursor : integer ;
- {----------------------------------------------------------------------------}
- begin
-
- filename := '*.*' ;
- attribyte := 255 ;
- OldAttribute := attribyte;
-
- Xcursor := 2 ;
- Ycursor := 1 ;
- GotoXy(Xcursor,Ycursor) ;
-
- Find_First(attribyte,filename,Retcode);
- If Retcode = 0 then
- begin
- write(Filename);
- Ycursor := Ycursor +1 ;
- end;
- {Now we repeat Find_Next until an error occurs }
-
- repeat
- Find_Next(attribyte,filename,Retcode);
- if Retcode = 0 then
- begin
- GotoXY(Xcursor,Ycursor);
- Write(filename) ;
- Ycursor := Ycursor + 1 ;
-
- if WhereY >= 14 then
- begin
- Xcursor := Xcursor + 16 ;
- Ycursor := 1 ;
- end;
-
- if (Xcursor >= 50) and (Ycursor = 13 ) then
- begin
- Ycursor := Ycursor + 1;
- GotoXY(Xcursor,Ycursor);
- Write ('More...');
- read ;
- clrscr ;
- Xcursor := 2 ;
- Ycursor := 1 ;
- end;
- end;
- until Retcode <> 0;
-
- GotoXY(Xcursor,Ycursor); Write('Press a key . . .');
- repeat until keypressed ;
- Chk_Term_Key ; { See if Return to Dos }
- end;
-
- {-----------------------------------------------------------------------------}
- { D E M O }
- {-----------------------------------------------------------------------------}
- Procedure Demo ; { Give Demonstration of Code }
-
- {$I WINDMNGR.INC}
-
- begin
-
- Add_Window(5,5,75,20,11,0,2);
-
- Get_file;
-
- Remove(1);
-
- end; { Demo }
-
-
- {----------------------------------------------------------------------------}
- { P R O C E S S I N T E R R U P T }
- { - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - }
- Procedure Process_Intr;
-
- { PURPOSE: This procedure replaces the standard keyboard interrupt. If
- anything but <Alt>-F10 is pressed, the key is passed on to the
- standard keyboard interrupt. B*U*T when <Alt>- F10 is pressed,
- this program takes over. The variable InUse is set to TRUE to
- ensure that this code doesn't try to run "on top of itself " AND to
- indicate to the Inline code to save/restore the original interrupt
- regs.
- }
-
- Begin
- { K e y b o a r d Interrupt o c c u r s here }
- {----------------------------------------------------------------------}
- {$I Staysave.inc}
- {----------------------------------------------------------------------}
- { Check the Int 16 request function in Ah reg:
- 0 = read character from Keyboard
- 1 = check character available
- 2 = check shift key values
- }
- if HalfRegs.Ah <> 0 then {if this is not character request...}
- Begin
- Intr(User_Int,Regs) { just pass it on to standard interrupt }
- End
-
- Else { HalfRegs.Ah = 0 then { This is a Character Request }
- Begin {Get Keyboard Char }
-
- Intr (User_Int, Regs); { Use the standard interrupt}
-
- if (Halfregs.Ah = Our_Char) { Separate the test so code }
- { performs efficiently }
- then if (not InUse) then
-
- begin { Demo }
- InUse := true; { "dont clobber saved stack"}
- { .
- .
- . Your
- . Program
- . Goes
- . Here
- .
- } { Get current Cursor Position }
- Old_Xpos := WhereX; Old_Ypos := WhereY;
- Demo ;
- GotoXY(Old_Xpos,Old_Ypos); { Put Cursor Back }
- Regs.Ax := Ord(KeyChr) shl 8 ; {Give back Last entered char }
- InUse := false; { ok to restore interrupted stack }
- end { Demo }
-
- end; {Get Keyboard Char }
-
- {$I Stayrstr.inc} { Return to Caller }
- end ;
- {-----------------------------------------------------------------------}
-
- {The main program installs the new interrupt routine and makes it permanently
- resident as the keyboard interrupt. The old keyboard interrupt is addressed
- through #68H, so it can still be used.
-
- The following dos calls are used:
-
- Function 25 - Install interrupt address
- input al = int number,
- ds:dx = address to install
-
- Function 35 - get interrupt address
- input al = int number
- output es:bx = address in interrupt
-
- Function 31 - terminate and stay resident
- input dx = size of resident program obtained from the memory
- allocation block at [Cs:0 - $10 + 3]
-
- Function 49 - Free Allocated Memory
- input Es = Block Segment to free
-
- Interrupt 20 - Return to invoking process
- }
-
- {-----------M A I N B L O C K---------------------------------------------}
- Begin {**main**}
-
- InUse := false;
- OurDseg:= Dseg; { Save the Data Segment Address for Interrupts }
- OurSseg:= Sseg; { Save our Stack Segment for Interrupts }
-
- Terminate_Flag := false ;
-
- {now install the interrupt routine}
-
- SaveRegs.Ax := $35 shl 8 + User_Int;
- Intr($21,SaveRegs); {Check to make sure int not already used}
-
- if SaveRegs.Es <> $00 then
- WriteLn ('Interrupt in use -- can''t install Resident Turbo Code')
- else
- begin
-
- { Initialize Your Progam Here since you wont get control again
- until "Our_Char" is entered from the Keyboard. }
-
- SaveRegs.Ax := $35 shl 8 + Kybrd_Int;
- Intr($21,SaveRegs); {get the address of keyboard interrupt }
-
- SaveRegs.Ax := $25 shl 8 + User_Int;
- SaveRegs.Ds := SaveRegs.Es;
- SaveRegs.Dx := SaveRegs.Bx;
- Intr($21,SaveRegs); { set the user-interrupt address to point
- { to the keyboard interrupt address }
-
- SaveRegs.Ax := $25 shl 8 + Kybrd_Int;
- SaveRegs.Ds := Cseg;
- SaveRegs.Dx := Ofs(Process_Intr);
- Intr ($21,SaveRegs); { set the keyboard interrupt to point to
- "Process-Intr" above}
-
- Writeln(' Turbo Stay-Resident Demo: Press Alt-F10');
-
- {now terminate and stay resident}
- { Pass return code of zero }
- SaveRegs.Ax := $31 shl 8 + 0 ; { Terminate and Stay Resident }
- SaveRegs.Dx := MemW [Cseg-1:0003] ; { Prog_Size from Allocation Blk}
- Intr ($21,SaveRegs);
-
- end;
- { END OF RESIDENCY CODE }
- end.
- {****************************************************************************}
- { S T A Y S A V E . I N C }
- { }
- { This is the Staysave.Inc file included above }
- { }
- { Separate the code out into a file or replace the $I Staysave.Inc }
- { statement above with this code. }
- {****************************************************************************}
-
- {This Inline routine will save the regs and Stack for Stay resident programs.
- It restores Ds and Ss from the previously saved integer constants "OurDseg"
- and "OurSSeg". This is important since Dos is not re-entrant and any attempt
- to use Interrupt I/O services will clobber the very stack on which the
- Resident Turbo program just saved its regs. Thus, on the final return, you
- and Toto will end up somewhere other than Kansas and without your Ruby Reds.
- }
-
- { Arthor: L.H. Ferris
-
- Distributed to the Public Domain for use without profit.
- Original Version 5.15.85
- }
- { On entry the Stack will already contain: }
- { 1) Sp for Dos }
- { 2) Bp for Dos }
- { 3) Ip for Dos }
- { 4) Cs for Dos }
- Inline ( { 5) Flags for Dos }
-
-
-
- $FA / { Cli Stop all interrupts }
-
- { Bp and Sp aready saved at Begin Stmt }
- $55/ {Push Bp Save again for Regpak }
- $BD/Regs/ {Mov Bp,offset REGS}
- $2E/$89/$46/$00/ {CS:Mov [Bp+0],AX}
- $2E/$89/$5E/$02/ {Cs:Mov [Bp+2],Bx}
- $2E/$89/$4E/$04/ {CS:Mov [Bp+4],CX}
- $2E/$89/$56/$06/ {CS:Mov [Bp+6],DX}
- $2E/$8F/$46/$08/ {Pop Cs:[Bp+8] Fetch Bp from stack }
- $2E/$89/$76/$0A/ {CS:Mov [Bp+A],SI}
- $2E/$89/$7E/$0C/ {CS:Mov [Bp+C],DI}
- $2E/$8C/$5E/$0E/ {CS:Mov [Bp+E],DS}
- $2E/$8C/$46/$10/ {CS:Mov [Bp+10],ES}
- $9C/ {PUSHF put Flags on stack to retrieve }
- $2E/$8F/$46/$12/ {POP Cs:[Bp+12]}
-
- { If Current SS := [OurSseg] or Inuse = True, then dont save the stack. }
- { This program is being recursive. }
-
- $2E/$80/$3E/Inuse/$01/ {Cmp Cs:[Inuse],1 }
- $74/$4D/ {Je ReCurin ------J-U-M-P--------------- }
-
- { Now save 5 Words from the Dos Stack before performing any }
- { I/O or re-using the Dos stack }
-
- $2E/$8C/$16/DosSSeg/ {Mov Cs:DosSSeg,SS Save Dos Stack Segment }
- $8C/$D6/ {Mov Si,SS If this is our Stack Seg }
- $8E/$C6/ {Mov Es,Si Get Dos StackSeg }
- $2E/$8E/$16/OurSSeg/ {Mov SS,Cs:OurSSeg Get our Stack segment }
- $2E/$8E/$1E/OurDseg/ {Mov Ds,Cs:Our_Ds Setup our Data Segment }
-
-
- $2E/$3B/$36/OurSSeg/ {Cmp Si,Cs:OurSSeg ..use current Stack ptr }
- $89/$E6/ {Mov Si,Sp ..value..else reset stack }
- $74/$05/ {Je $+5 ..to original Turbo stack }
- $3E/$8B/$36/$74/$01/ {Mov Si,Ds:[174] ..(cf. code at B2B 3.0x) }
-
- $87/$F4/ {Xchg Sp,Si Set new Stack Pointer }
-
- $2E/$FF/$76/$00/ {Push [Bp+0] Save Dos/User regs for Exit }
- $2E/$FF/$76/$02/ {Push [Bp+2] Save Bx }
- $2E/$FF/$76/$04/ {Push [Bp+4] Save Cx }
- $2E/$FF/$76/$06/ {Push [Bp+6] Save Dx }
- {Push [Bp+8] Save Bp }
- $2E/$FF/$76/$0A/ {Push [Bp+A] Save Si }
- $2E/$FF/$76/$0C/ {Push [Bp+C] Save Di }
- $2E/$FF/$76/$0E/ {Push [Bp+E] Save Ds }
- $2E/$FF/$76/$10/ {Push [Bp+10] Save Es }
-
-
- $2E/$8E/$16/OurSSeg/ {Mov SS,Cs:OurSSeg Set up our Stack }
- $56/ {Push Si Save bottom of Dos Stack }
- $2E/$8C/$5E/$0E/ {Mov Cs:[Bp+E],Ds Set New Data Segmt in regs}
- {Recurin Jump here if Recursion }
- $FB {Sti Enable Interrupts }
-
- ) ;
- {****************************************************************************}
- { S T A Y R S T R . I N C }
- { }
- { This is the StayRstr.Inc file included above }
- { Separate the code out into a file or replace the $I StayRstr.Inc }
- { statement above with this code. }
- {****************************************************************************}
-
- { Inline Code to restore the stack and regs moved to the Turbo Resident
- Program Stack to allow re-entrancy into the Dos Code for I/O and
- recursion from built-in Turbo functions.
-
- ; Arthor: L.H. Ferris
-
- ; Distributed to the Public Domain for use without profit.
- ; Original Version 5.15.85
-
- ;----------------------------------------------------------------------;
- ; Restore the Dos Regs and Stack
- ;----------------------------------------------------------------------;
-
- ; On entry the Stack will already contain:
- ;
- ; 1) Bottom of Dos Stack Ptr
- ; 2) Dos Flags
- ; 3) Dos Code Segment
- ; 4) Dos Instruction Ptr
- ; 5) Dos Base Pointer
- ; 6) Dos Original Stack Ptr
- }
- inline(
-
- $BD/Regs/ {Mov Bp,offset REGS}
- $2E/$8B/$46/$00/ {CS:Mov Ax,[Bp+0]}
- $2E/$8B/$5E/$02/ {Cs:Mov Bx,[Bp+2]}
- $2E/$8B/$4E/$04/ {CS:Mov Cx,[Bp+4]}
- $2E/$8B/$56/$06/ {CS:Mov Dx,[Bp+6]}
-
- $2E/$8B/$76/$0A/ {CS:Mov Si,[Bp+A]}
- $2E/$8B/$7E/$0C/ {CS:Mov Di,[Bp+C]}
- $2E/$8E/$5E/$0E/ {CS:Mov DS,[Bp+E]}
- $2E/$8E/$46/$10/ {CS:Mov ES,[Bp+10]}
- $2E/$FF/$76/$12/ {Push Cs:[Bp+12]}
- $9D/ {Popf}
-
- { If [Cs:InUse]:= True, then dont restore the stack. This program is }
- { being recursive. Else restore Dos Stack and Program Entry registers }
-
- $2E/$80/$3E/Inuse/$01/ {Cmp byte ptr Cs:[Inuse],1 }
- $74/$12/ {Je ReCurOut }
-
- $FA / { Cli ; Stop all interrupts }
-
-
- $5D/ {Pop Bp Save Dos Sp across pops }
-
- $07/ {Pop Es }
- $1F/ {Pop Ds }
- $5F/ {Pop Di }
- $5E/ {Pop Si }
- $5A/ {Pop Dx }
- $59/ {Pop Cx }
- $5B/ {Pop Bx }
- $44/$44/ {Inc sp/Inc sp Thow old Ax value away }
-
- $89/$EC/ {Mov Sp,Bp Setup Dos Stack Ptr }
- $2E/$8E/$16/DosSSeg/ {Mov SS,Cs:DosSSeg Give back Dos Stack }
-
- {RecurOut Clean up the Stack }
-
- $5D/ {Pop Bp Throw away old dos Sp }
-
- $BD/Regs/ {Mov Bp,offset REGS}
- $2E/$FF/$76/$12/ {Push Cs:[Bp+12]}
- $9D/ {Popf}
- $5D/ {Pop Bp Retrieve old BP }
-
- $FB/ {Sti Enable interrupts }
- $CA/$02/$00 {Ret Far 002 }
- );
-
- {****************************************************************************}
- { S T A Y S U B S . I N C }
- { }
- { Separate this file into "Staysubs.Inc" to provide Directory routines }
- { for the Stay-Resident Demo. }
- { }
- {****************************************************************************}
-
-
- {----------------------------------------------------------------------------}
- { F I L E S U B R O U T I N E S }
- {----------------------------------------------------------------------------}
- type
- Dir_Entry = record
- Reserved : array[1..21] of byte;
- Attribute: byte;
- Time, Date, FileSizeLo, FileSizeHi : integer;
- Name : string[13];
- end;
- var
- RetCode : byte;
- Filename : filename_type;
- Buffer : Dir_Entry;
- Attribute : byte;
- {----------------------------------------------------------------------------}
- { S E T Disk Transfer Address }
- {----------------------------------------------------------------------------}
- Procedure Disk_Trns_Addr(var Disk_Buf);
- var
- Registers : regtype;
- Begin
- with Registers do
- begin
- Ax := $1A shl 8; { Set disk transfer address to }
- Ds := seg(Disk_Buf); { our disk buffer }
- Dx := ofs(Disk_Buf);
- msdos(Registers);
- end;
- end;
- {----------------------------------------------------------------------------}
- { F I N D N E X T F I L E E N T R Y }
- {----------------------------------------------------------------------------}
- Procedure Find_Next(var Att:byte; var Filename : Filename_type;
- var Next_RetCode : byte);
- var
- Registers : regtype;
- Carry_flag : integer;
- N : byte;
-
- Begin {Find_Next}
- Buffer.Name := ' '; { Clear result buffer }
- with Registers do
- begin
- Ax := $4F shl 8; { Dos Find next function }
- MsDos(Registers);
- Att := Buffer.Attribute; { Set file attribute }
- Carry_flag := 1 and Flags; { Isolate the Error flag }
- Filename := ' ';
- if Carry_flag = 1 then
- Next_RetCode := Ax and $00FF
- else
- begin { Move file name }
- Next_RetCode := 0;
- for N := 0 to 12 do FileName[N+1] := Buffer.Name[N];
- end;
- end; {with}
- end;
- {----------------------------------------------------------------------------}
- { F I N D F I R S T F I L E F U N C T I O N }
- {----------------------------------------------------------------------------}
- Procedure Find_First (var Att: byte;
- var Filename: Filename_type;
- var RetCode_code : byte);
-
- var
- Registers :regtype;
- Carry_flag :integer;
- Mask, N :byte;
-
- begin
- Disk_Trns_Addr(buffer);
- Filename[length(Filename) + 1] := chr(0);
- Buffer.Name := ' ';
- with Registers do
- begin
- Ax := $4E shl 8; { Dos Find First Function }
- Cx := Att; { Attribute of file to fine }
- Ds := seg(Filename); { Ds:Dx Asciiz string to find }
- Dx := ofs(Filename) + 1;
- MsDos(Registers);
- Att := Buffer.Attribute; { set the file attribute byte }
-
- { If error occured set, Return code. }
-
- Carry_flag := 1 and Flags; { If Carry flag, error occured }
- { and Ax will contain Return code }
- if Carry_flag = 1 then
- begin
- RetCode_code := Ax and $00FF;
- end
-
- else
- begin
- RetCode_code := 0;
- Filename := ' ';
- for N := 0 to 12 do FileName[N+1] := Buffer.Name[N];
- end;
-
- end; {with}
- end;
- {****************************************************************************}
- { S T A Y X I T . I N C }
- { }
- { Separate this file into "StayXIT.Inc" to provide a "Go-non-Resident" }
- { routine or the Stay-Resident Demo. }
- { }
- {****************************************************************************}
-
- {-----------------------------------------------------------------------------}
- { Stay_Xit Check Terminate Keys }
- { }
- { Check for Ctrl_Home key. Free the Environment , the program segment }
- { memory and return to Dos. Programs using this routine ,must be the }
- { last program in memory, else ,a hole will be left causing Dos }
- { to go GooGoo . }
- {-----------------------------------------------------------------------------}
-
- Begin { Block }
- if Keypressed then
- Begin { Keypressed }
- While Keypressed do read (Kbd,Keychr);
- If Keychr = Quit_Key then
- Begin { Terminate }
- Writeln ('Stay-Resident program Terminating') ;
- SaveRegs.Ax := $35 shl 8 + User_Int;
- MsDos(SaveRegs); {get the original Int 16 Addr }
-
- SaveRegs.Ax := $25 shl 8 + Kybrd_Int;
- SaveRegs.Ds := SaveRegs.Es;
- SaveRegs.Dx := SaveRegs.Bx; { set the user-interrupt address to }
- MsDos(SaveRegs); { the keyboard interrupt address }
-
- MemW[$00:User_Int * 4] := 0 ; { Clear User Interrupt vector }
- MemW[$00:User_Int * 4 + 2] :=0;
-
- Saveregs.Ax := $49 shl 8 + 0 ; { Free Allocated Block function}
- Saveregs.Es := MemW[Cseg:$2C] ; { Free environment block }
- MsDos( Saveregs ) ;
-
- Saveregs.Ax := $49 shl 8 + 0 ; { Free Allocated Block function}
- Saveregs.Es := Cseg ; { Free Program }
- MsDos( Saveregs ) ;
-
- Intr($20,Regs) ; { Return to Dos }
-
- End { Terminate } ;
- End { Keypressed };
- End { Block };
- {****************************************************************************}
- { W I N D M N G R . I N C }
- { }
- { Separate this file into "WindMngr.Inc" to provide a Window for }
- { the Stay-Resident Demo. }
- { }
- {****************************************************************************}
- { Window Manager/Editor System Include file .. }
- { Author:
-
- Jim Everingham (The Window Manager/Editor) }
-
-
- Const
- MaxScreens = 8; { Number of Windows Allowed, do not Change }
- Screen_seg = $B800; { Change to #B000 for MonoChrome, Change
- then # sign to a Dollar sign Though. }
- Data_Addr = $0000;
- Fc : Array[1..4, 1..7] of Integer
- = ((218, 196, 191, 179, 192, 196, 217),
- (201, 205, 187, 186, 200, 205, 188),
- (213, 205, 184, 179, 212, 205, 190),
- (219, 219, 219, 219, 219, 219, 219));
-
- type maxstr = string[80];
- window_rec = record
- x1,x2,y1,y2,c1,b1,w1,w2: Integer;
- Screen: Array[1..4000] of byte;
- end;
-
- var Stack_Top,Last_Window_Num,
- line_pos,F1 : Integer;
- screen : Array[1..4000] of byte;
- real_screen : Array[1..4000] of byte absolute Screen_Seg:Data_Addr;
- Page_1 : Array[1..4000] of byte absolute Screen_Seg:$1000;
- Imig : Array [1..MaxScreens] of Window_rec;
- Original : Array[1..4000] of byte;
- Coords : Array[1..8,1..MaxScreens] of Integer;
-
-
- {----------------------------------------------------------------------------}
- { S E T _ P A G E }
- {----------------------------------------------------------------------------}
- procedure set_page(page: byte);
-
- type
- Result =
- record
- AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags: byte;
- end;
- var rec:result;
-
- begin
- Rec.AX := page;
- Rec.BX := $05;
- Intr($10,Rec);
- end;
-
- {----------------------------------------------------------------------------}
- { S C R N _ O F F }
- {----------------------------------------------------------------------------}
- Procedure Scrn_off;
- begin
- inline($52/$50/$ba/$d8/$03/$b0/$21/$ee/$58/$5a)
- end;
- {----------------------------------------------------------------------------}
- { S C R N _ O N }
- {----------------------------------------------------------------------------}
- Procedure Scrn_on;
- begin
- inline($52/$50/$ba/$d8/$03/$b0/$29/$ee/$58/$5a)
- end;
- {----------------------------------------------------------------------------}
- { A C T I V E }
- {----------------------------------------------------------------------------}
- Function active: integer;
- begin
- active:=stack_top
- end;
- {----------------------------------------------------------------------------}
- { P U S H }
- {----------------------------------------------------------------------------}
- Procedure Push(Ulx, Uly, Lrx, Lry, Foreground, Background: integer);
-
- { This procedure Saves screens in memory. When a new window is put
- on the Screen, the preceding window is stored away for later reference.}
-
- begin
- { If last Window up, move the Original Screen into Screen Memory}
- if stack_top = 0 then
- begin
- Scrn_off;
- move(real_screen, Original, 4000);
- Scrn_on
- end;
- {Save all Data concerning the windows}
- if (Stack_top < MaxScreens) and (Stack_Top >= 0) then
- begin
- Stack_top:=Stack_top+1;
- Imig[Stack_top].x1:=Ulx;
- Imig[Stack_top].y1:=Uly;
- Imig[Stack_top].x2:=Lrx;
- Imig[Stack_top].y2:=Lry;
- Imig[stack_top].c1:=Foreground;
- Imig[Stack_top].b1:=Background
- end;
-
- { Push Screen on Stack ... Sort of... }
- Scrn_off;
- Move(real_screen,Imig[Stack_top].Screen,4000);
- Scrn_on
- end;
- {----------------------------------------------------------------------------}
- { P O P }
- {----------------------------------------------------------------------------}
- Procedure Pop;
-
- { This Procedure takes the screen that procedes the current window and
- Copies back to screen memory, restores all data concerning the previous
- window and activates it.. Neat huh? }
-
- begin
-
- { If no windows are active, save the current screen }
- if stack_top =0 then
- begin
- normvideo;
- window(1,1,80,25);
- Scrn_off;
- move(Original, real_screen, 4000);
- Scrn_on;
- end;
-
- { Get Preceding screen and copy it to screen memory }
- Scrn_off;
- Move(Imig[Stack_top].Screen,Real_Screen,4000);
- Scrn_on;
- Stack_top:=Stack_top-1
- end;
- {----------------------------------------------------------------------------}
- { W R I T E X Y }
- {----------------------------------------------------------------------------}
- Procedure Writexy(long_string:maxstr; xcoord,ycoord:integer; var color: integer);
-
- { This procedure Draws whatever you want, wherever you want, by changing the
- value of Screen in the variable declaration, it can draw a "Picture" any-
- were in memory. This allows for the Speed of the window making process..}
-
- var str_len, real_pos, scr_pos: integer;
-
- begin
- {$I-}
- str_len:=length(long_string); { So I know how much to write }
- Scr_pos:=0;
-
- { The next 8 lines write the string in every "even" location in memory
- and ever odd location gets the attribute with determines how the
- string is displayed on the screen}
- for real_pos:=1 to str_len do
- if scr_pos < 4001 then
- begin
- scr_pos:=((xcoord*2)-1)+(ycoord*160);
- screen[scr_pos]:=ord(copy(long_string,real_pos,1));
- screen[scr_pos+1]:=color;
- xcoord:=xcoord+1;
- end
- {$I+}
- end;
-
- {----------------------------------------------------------------------------}
- { F R A M E }
- {----------------------------------------------------------------------------}
- Procedure Frame(WindowType, UpperLeftX, UpperLeftY, LowerRightX, LowerRightY, color: Integer);
-
- { This procedure draws the window frame in another part of memory. }
- var i: integer;
- begin
- WriteXY(chr(Fc[WindowType,1]),UpperLeftX, UpperLeftY,color);
- for i:=UpperLeftX+1 to LowerRightX-1 do WriteXY(chr(Fc[WindowType,2]),i,UpperleftY,color);
- WriteXY(chr(Fc[WindowType,3]),i+1,UpperleftY,color);
- for i:=UpperLeftY+1 to LowerRightY-1 do
- begin
- WriteXY(chr(Fc[WindowType,4]),UpperLeftX , i,color);
- WriteXY(chr(Fc[WindowType,4]),LowerRightX, i,color);
- end;
- WriteXY(chr(Fc[WindowType,5]),UpperLeftX, LowerRightY, color);
- for i:=UpperLeftX+1 to LowerRightX-1 do WriteXY(chr(Fc[WindowType,6]),i,LowerrightY,color);
- WriteXY(chr(Fc[WindowType,7]),i+1,LowerRightY,color);
- end { Frame };
- {----------------------------------------------------------------------------}
- { I N I T I A L I Z E }
- {----------------------------------------------------------------------------}
- Procedure initialize;
-
- { Set up memory and the stack }
-
- var i:integer;
-
- begin
- Stack_top:=0;
- move(real_screen,screen,4000);
- with imig[1] do for i:=1 to 4000 do screen[i]:=$00;
- for i:=2 to 9 do move(Imig[i-1].screen,imig[i].screen,4000);
- move(imig[1].screen,screen,4000);
- move(imig[1].screen,original,4000)
- end;
- {----------------------------------------------------------------------------}
- { A D D _ W I N D O W }
- {----------------------------------------------------------------------------}
- Procedure Add_window(UpperLeftX,UpperLeftY,LowerRightX,LowerRightY,Foreground,
- BackGround, WindowType: Integer);
-
- { This procedure does all the laborous work for you.. The variables make it
- Fairly easy to understand. }
-
- Var i,j,k,Color: Integer;
-
- begin
- Imig[Stack_top].w1:=whereX;
- Imig[Stack_top].w2:=WhereY;
- UpperLeftX:=UpperLeftX+1;
- LowerRightX:=LowerRightX-1;
- LowerRightY:=LowerRightY-2;
- f1:=WindowType;color:=0;
- Scrn_off;
- move(real_screen,screen,4000);
- Scrn_on;
-
- { Set color attribute for direct writeng to memory }
- if background < 17 then Color:=foreground+(background*16);
-
- { Check for invalid window frame types }
- if (WindowType > 5) or (WindowType < 0) then
- begin
- Clrscr;
- Writeln('Invalid Frame Type!')
- end
- else
-
- { If the window is valid then Procede }
- begin
-
- { Fill color Attribute of window directly into memory }
- k:=1;
- for j:=UpperLeftY to LowerRightY do
- for i:=UpperLeftX to LowerRightX do
- begin
- k:=(j*160)+(i*2);
- Screen[k]:=Color;
- Screen[k-1]:=$20
- end;
-
- { Frame Window }
- Case Windowtype of
- 1:Frame(WindowType,UpperLeftX-1,UpperLeftY-1,
- LowerRightX+1,LowerRightY+1,
- color);
- 2:Frame(WindowType,UpperLeftX-1,UpperLeftY-1,
- LowerRightX+1,LowerRightY+1,
- color);
- 3:Frame(WindowType,UpperLeftX-1,UpperLeftY-1,
- LowerRightX+1,LowerRightY+1,
- color);
- 4:Frame(WindowType,UpperLeftX-1,UpperLeftY-1,
- LowerRightX+1,LowerRightY+1,
- color);
- end { Case }
- end;
-
- { Activate newly formed window }
- Window(1,1,80,25);
- Window(UpperLeftX,UpperLeftY+1,LowerRightX,LowerRightY+1);
- push(UpperLeftx,UpperLeftY+1,LowerRightX,LowerRightY+1,Foreground, Background);
- Scrn_off;
- Move(screen,real_screen,4000);gotoxy(1,1);
- Scrn_on;
- Textcolor(Foreground);TextBackground(backGround);ClrScr;
- end;
- {----------------------------------------------------------------------------}
- { C O L O R _ W I N D O W }
- {----------------------------------------------------------------------------}
- Procedure Color_window(Foreground, Background: integer);
-
- { This procedure allows you to change the foreground and background color
- of the active window. }
-
- var i,j,Color: Integer;
-
- begin
-
- { Set Attribute value }
- if background < 8 then Color:=foreground+(background*16);
-
- { Write new attribute direclty to screen memory }
- for j:=(Imig[Stack_top].y1-2) to Imig[Stack_top].y2 do
- for i:=(Imig[Stack_top].x1-1) to (Imig[Stack_top].x2+1) do
- begin
- Real_Screen[(j*160)+(i*2)]:=Color
- end
- end;
- {----------------------------------------------------------------------------}
- { R E M O V E }
- {----------------------------------------------------------------------------}
- Procedure Remove(Num_to_Remove: Integer);
-
- { This Procedure removes 1 or a specified number of windows from the
- screen and reactivates the underlying window }
-
- var i: integer;
- begin
- if (Num_to_Remove > 0) and (Num_to_Remove < MaxScreens) then
- for i:=1 to Num_to_remove do Pop
- else
- Pop;
- Window(1,1,80,25);
- Window(Imig[Stack_top].x1+1,Imig[Stack_top].y1,Imig[Stack_top].x2,Imig[Stack_top].y2);
- gotoxy(1,1);
- TextBackground(Imig[Stack_top].b1);TextColor(Imig[Stack_top].c1);
- GotoXY((Imig[Stack_top].w1-1),Imig[Stack_top].w2)
- end;
- {----------------------------------------------------------------------------}
- { W I N D O W _ T I T L E }
- {----------------------------------------------------------------------------}
- Procedure Window_Title(Name: Maxstr; color:integer);
-
- var i, k, l, m: integer;
-
- begin
- If Length(name)>0 then
- begin
- l:=1;
- color:=color+(Imig[Stack_top].b1*16);
- if f1 < 4 then Real_Screen[(((Imig[Stack_top].Y1-2)*160)+(Imig[Stack_top].X1*2))+l]:=$5b;
- for i:=1 to length(Name) do
- begin
- k:=(((Imig[Stack_top].Y1-2)*160)+(Imig[Stack_top].X1*2))+l+1;
- Real_Screen[k+1]:=ord(copy(Name,i,1));
- Real_Screen[k+2]:=color;
- l:=l+2
- end;
- if f1 < 4 then Real_Screen[k+3]:=$5d
- end
- end;
-
- { Thats all.. }
-