home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / MADTRB15.ZIP / STAYRES.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1985-07-28  |  41.7 KB  |  979 lines

  1.    {$C-}
  2. {-----------------------------------------------------------------------------}
  3. {                                                                             }
  4. {                                                                             }
  5. {                                                                             }
  6. {         "  S o r r y ,  D a v e,   I   C a n ' t   D o   T h a t .  "       }
  7. {                                                                             }
  8. {                                                                             }
  9. {                                                          Arthur C. Clark    }
  10. {                                                           " 2 0 0 1 "       }
  11. {-----------------------------------------------------------------------------}
  12.  
  13. {  A  Turbo  "stay-resident" program clobbers the Dos register stack.  It
  14.   jumps over the Turbo run-time initialization code that would set up the
  15.   program registers  and environment.   Secondly,  a  stay-resident  program
  16.   could not ordinarily issue file I/O since that would clobber Dos interrupt
  17.   registers.  Therefore,  the following code proposes an inline solution,
  18.   providing a Turbo entry  stack  for  "stay-resident"  programs  and allowing
  19.   those programs to issue Dos I/O and other interrupts.
  20.  
  21.    This Turbo stay-resident demo has been put together to perform both Dos I/O
  22.    and Bios interrupts. It has also been tested for re-entrancy and
  23.    recursiveness on an IBM PC with PCDos .
  24.  
  25.     Separate the include files, compile to a COM file and execute with the
  26.     Alt-F10 key. It will also free its memory and return to Dos with the
  27.     Ctrl-Home key at the "Press a key" prompt. (Illustrated in the Stayxit
  28.     file). Maximum free dynamic memory should be between A40-B00 since this
  29.     demo uses a recursive stack.
  30.  
  31.                                                  The Hunters Helper
  32.  
  33.                                                   L.Ferris
  34.                                                   4268 26th St
  35.                                                   San Francisco,Ca. 94131
  36.                                                   [ 70357,2716 ]      }
  37. {-----------------------------------------------------------------------------}
  38. {     This code has been tested/used on an IBM PC using PC-DOS 2.10           }
  39. {-----------------------------------------------------------------------------}
  40.  
  41.  
  42. { Authors: Lane H. Ferris (Stay Resident Code)
  43.            Neil J. Rubenking (Directory code and ideas)
  44.            Jim Everingham (The Window Manager/Editor)
  45.            Other Public Gurus on whose shoulders we stand.
  46.  
  47. { PURPOSE:  This code will serve as a template to create other "Stay  Resident"
  48.             programs  in  Turbo  Pascal(tm).   This  code  intercepts  Int  16,
  49.             displacing original Interrupt  16  Vector  to  User  Interrupt  68.
  50.             During  execution  of  other  programs,  it  can  be invoked by the
  51.             special key combination  specified  by  "Our_Char"  (in  this  case
  52.             <Alt>-F10.)
  53. }
  54.  
  55. Program Stay_Resident;
  56.  
  57.   { * * * * * * * CONSTANTS * * * * * * * * * * * * * * * * * * * * * * }
  58.   const
  59.     Our_Char        =  113; {this is the scan code for AltF10}
  60.     Ctrl_Home       = #119; {Control Home Scan Code          }
  61.     Quit_Key        = #119;
  62.     Ctrl_End        = #117; {Control End Scan Code           }
  63.     User_Int        = $68; {place to put new interrupt}
  64.     Kybrd_Int       = $16; {BIOS keyboard interrupt}
  65.  
  66.   { - - - - - - - T Y P E    D E C L A R A T I O N S - - - - - - - - - - - -  }
  67.   Type
  68.     Regtype     = record Ax,Bx,Cx,Dx,Bp,Si,Di,Ds,Es,Flags:integer  end;
  69.     HalfRegtype = record Al,Ah,Bl,Bh,Cl,Ch,Dl,Dh:byte              end;
  70.     filename_type = string[64];
  71.  
  72.   { - - - - - - - T Y P E D   C O N S T A N T S - - - - - - - - - - - - - - -}
  73.   Const
  74.     {regs is defined as a typed constant in order to get it in the code segment}
  75.     Regs   : regtype = (Ax:0;Bx:0;Cx:0;Dx:0;Bp:0;Si:0;Di:0;Ds:0;Es:0;Flags:0);
  76.  
  77.       OurDseg: integer = 0;            {Our Data Segment Value             }
  78.       OurSseg: integer = 0;            {Our Stack Segment Value            }
  79.       DosSseg: integer = 0;            {Dos Stack Segment Value            }
  80.       Inuse  : Boolean = false;        {Recursion flag                     }
  81.  
  82.  { - - - - - - - V A R I A B L E S - - - - - - - - - - - - - - - - - - - - - -}
  83.     Var
  84.       SaveRegs                      : regtype;
  85.       HalfRegs                      : halfregtype absolute regs;
  86.       Terminate_flag                : boolean ;
  87.       Keychr                        : char ;
  88.       Old_Xpos,Old_Ypos             : integer ;
  89. { - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - }
  90.  
  91. { - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - }
  92. {  Check Terminate Keys
  93. { - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - }
  94. Procedure Chk_Term_Key;
  95. {****************************************************************************}
  96. {                       S T A Y X I T   .   I N C                            }
  97. {                                                                            }
  98. {     Separate this file into "StayXIT.Inc" to provide a "Go-non-Resident"   }
  99. {                   routine or the Stay-Resident Demo.                       }
  100. {                                                                            }
  101. {****************************************************************************}
  102.  
  103. {-----------------------------------------------------------------------------}
  104. {  Stay_Xit Check Terminate Keys                                              }
  105. {                                                                             }
  106. {  Check for Ctrl_Home key. Free the Environment , the program segment        }
  107. {  memory and return to Dos. Programs using this routine ,must be the         }
  108. {  last program in memory, else ,a hole will be left causing Dos              }
  109. {  to go GooGoo .                                                             }
  110. {-----------------------------------------------------------------------------}
  111.  
  112.    Begin { Block }
  113.       if Keypressed then
  114.          Begin { Keypressed }
  115.          While Keypressed do read (Kbd,Keychr);
  116.          If Keychr = Quit_Key then
  117.             Begin { Terminate }
  118.             Writeln ('Stay-Resident program Terminating') ;
  119.             SaveRegs.Ax := $35 shl 8 + User_Int;
  120.             MsDos(SaveRegs);           {get the original Int 16 Addr   }
  121.  
  122.             SaveRegs.Ax := $25 shl 8 + Kybrd_Int;
  123.             SaveRegs.Ds := SaveRegs.Es;
  124.             SaveRegs.Dx := SaveRegs.Bx; { set the user-interrupt address to }
  125.             MsDos(SaveRegs);            { the keyboard interrupt address    }
  126.  
  127.             MemW[$00:User_Int * 4] := 0 ; { Clear User Interrupt vector     }
  128.             MemW[$00:User_Int * 4 + 2] :=0;
  129.  
  130.             Saveregs.Ax := $49 shl 8 + 0 ;    { Free Allocated Block function}
  131.             Saveregs.Es := MemW[Cseg:$2C] ; { Free environment block       }
  132.             MsDos( Saveregs ) ;
  133.  
  134.             Saveregs.Ax := $49 shl 8 + 0 ;    { Free Allocated Block function}
  135.             Saveregs.Es := Cseg ;             { Free Program                 }
  136.             MsDos( Saveregs ) ;
  137.  
  138.             Intr($20,Regs) ;           { Return to Dos }
  139.  
  140.             End   { Terminate } ;
  141.          End  { Keypressed };
  142.    End  { Block };
  143. (*  {$I StayXit.Inc}                   {Check for Exit to Dos                     } *)
  144. {-----------------------------------------------------------------------------}
  145. {            G  E  T  F  I  L  E                                              }
  146. {-----------------------------------------------------------------------------}
  147.  
  148. procedure get_file;
  149. {****************************************************************************}
  150. {                         S T A Y S U B S  .  I N C                          }
  151. {                                                                            }
  152. {   Separate this file into "Staysubs.Inc" to provide Directory routines     }
  153. {       for the Stay-Resident Demo.                                          }
  154. {                                                                            }
  155. {****************************************************************************}
  156.  
  157.  
  158. {----------------------------------------------------------------------------}
  159. {                  F I L E         S U B R O U T I N E S                     }
  160. {----------------------------------------------------------------------------}
  161.   type
  162.     Dir_Entry   = record
  163.                       Reserved : array[1..21] of byte;
  164.                       Attribute: byte;
  165.                       Time, Date, FileSizeLo, FileSizeHi : integer;
  166.                       Name : string[13];
  167.                     end;
  168.   var
  169.     RetCode     : byte;
  170.     Filename  : filename_type;
  171.     Buffer    : Dir_Entry;
  172.     Attribute : byte;
  173. {----------------------------------------------------------------------------}
  174. {                S  E  T       Disk  Transfer  Address                       }
  175. {----------------------------------------------------------------------------}
  176. Procedure Disk_Trns_Addr(var Disk_Buf);
  177. var
  178.   Registers : regtype;
  179. Begin
  180.   with Registers do
  181.     begin
  182.       Ax := $1A shl 8;                 { Set disk transfer address to  }
  183.       Ds := seg(Disk_Buf);             { our disk buffer               }
  184.       Dx := ofs(Disk_Buf);
  185.       msdos(Registers);
  186.     end;
  187. end;
  188. {----------------------------------------------------------------------------}
  189. {                  F I N D   N E X T   F I L E   E N T R Y                   }
  190. {----------------------------------------------------------------------------}
  191. Procedure Find_Next(var Att:byte; var Filename : Filename_type;
  192.                                       var Next_RetCode : byte);
  193. var
  194.   Registers  : regtype;
  195.   Carry_flag : integer;
  196.   N          : byte;
  197.  
  198. Begin  {Find_Next}
  199.   Buffer.Name := '             ';     { Clear result buffer }
  200.   with Registers do
  201.       begin
  202.       Ax := $4F shl 8;                 { Dos Find next function }
  203.       MsDos(Registers);
  204.       Att := Buffer.Attribute;         { Set file attribute     }
  205.       Carry_flag := 1 and Flags;       { Isolate the Error flag }
  206.       Filename := '             ';
  207.       if Carry_flag = 1 then
  208.         Next_RetCode := Ax and $00FF
  209.       else
  210.         begin                          { Move file name         }
  211.         Next_RetCode := 0;
  212.         for N := 0 to 12 do FileName[N+1] := Buffer.Name[N];
  213.         end;
  214.     end;  {with}
  215. end;
  216. {----------------------------------------------------------------------------}
  217. {              F I N D   F I R S T   F I L E   F U N C T I O N               }
  218. {----------------------------------------------------------------------------}
  219. Procedure Find_First (var Att: byte;
  220.                       var Filename: Filename_type;
  221.                       var RetCode_code : byte);
  222.  
  223.   var
  224.       Registers        :regtype;
  225.       Carry_flag       :integer;
  226.       Mask, N          :byte;
  227.  
  228.   begin
  229.     Disk_Trns_Addr(buffer);
  230.     Filename[length(Filename) + 1] := chr(0);
  231.     Buffer.Name := '             ';
  232.     with Registers do
  233.       begin
  234.       Ax := $4E shl 8;                  { Dos Find First Function }
  235.       Cx := Att;                        { Attribute of file to fine }
  236.       Ds := seg(Filename);              { Ds:Dx Asciiz string to find }
  237.       Dx := ofs(Filename) + 1;
  238.       MsDos(Registers);
  239.       Att := Buffer.Attribute;          { set the file attribute byte  }
  240.  
  241.         { If error occured set, Return code. }
  242.  
  243.         Carry_flag := 1 and Flags;      { If Carry flag, error occured }
  244.                                         { and Ax will contain Return code }
  245.         if Carry_flag = 1 then
  246.           begin
  247.           RetCode_code := Ax and $00FF;
  248.           end
  249.  
  250.         else
  251.           begin
  252.           RetCode_code := 0;
  253.           Filename := '             ';
  254.           for N := 0 to 12 do FileName[N+1] := Buffer.Name[N];
  255.           end;
  256.  
  257.       end;  {with}
  258. end;
  259. (* {$I staysubs.inc} *)
  260. var
  261.   attribyte,
  262.   OldAttribute : byte;
  263.   Xcursor      : integer ;
  264.   Ycursor      : integer ;
  265. {----------------------------------------------------------------------------}
  266. begin
  267.  
  268.       filename := '*.*' ;
  269.       attribyte := 255 ;
  270.       OldAttribute := attribyte;
  271.  
  272.               Xcursor := 2 ;
  273.               Ycursor := 1 ;
  274.               GotoXy(Xcursor,Ycursor) ;
  275.  
  276.           Find_First(attribyte,filename,Retcode);
  277.               If Retcode = 0 then
  278.                  begin
  279.                  write(Filename);
  280.                  Ycursor := Ycursor +1 ;
  281.                  end;
  282.           {Now we repeat Find_Next until an error occurs }
  283.  
  284.               repeat
  285.                 Find_Next(attribyte,filename,Retcode);
  286.                 if Retcode = 0 then
  287.                  begin
  288.                         GotoXY(Xcursor,Ycursor);
  289.                         Write(filename) ;
  290.                         Ycursor := Ycursor + 1 ;
  291.  
  292.                         if WhereY >= 14 then
  293.                         begin
  294.                         Xcursor := Xcursor + 16 ;
  295.                         Ycursor := 1 ;
  296.                         end;
  297.  
  298.                         if (Xcursor >= 50) and (Ycursor = 13 ) then
  299.                         begin
  300.                         Ycursor := Ycursor + 1;
  301.                         GotoXY(Xcursor,Ycursor);
  302.                         Write ('More...');
  303.                         read ;
  304.                         clrscr ;
  305.                         Xcursor := 2 ;
  306.                         Ycursor := 1 ;
  307.                         end;
  308.                  end;
  309.                until Retcode <> 0;
  310.  
  311.                GotoXY(Xcursor,Ycursor); Write('Press a key . . .');
  312.                repeat until keypressed ;
  313.                Chk_Term_Key ;          { See if Return to Dos }
  314. end;
  315.  
  316. {-----------------------------------------------------------------------------}
  317. {        D   E  M  O                                                          }
  318. {-----------------------------------------------------------------------------}
  319. Procedure Demo ;                   { Give Demonstration of Code               }
  320. {****************************************************************************}
  321. {                       W I N D M N G R    .   I N C                         }
  322. {                                                                            }
  323. {     Separate this file into "WindMngr.Inc" to provide a Window for         }
  324. {                    the Stay-Resident Demo.                                 }
  325. {                                                                            }
  326. {****************************************************************************}
  327.             { Window Manager/Editor System Include file .. }
  328. { Author:
  329.           
  330.            Jim Everingham (The Window Manager/Editor)                        }
  331.           
  332.  
  333. Const
  334.       MaxScreens = 8;     { Number of Windows Allowed, do not Change }
  335.       Screen_seg = $B800; { Change to #B000 for MonoChrome, Change
  336.                             then # sign to a Dollar sign Though. }
  337.       Data_Addr = $0000;
  338.       Fc        : Array[1..4, 1..7] of Integer
  339.                 = ((218, 196, 191, 179, 192, 196, 217),
  340.                    (201, 205, 187, 186, 200, 205, 188),
  341.                    (213, 205, 184, 179, 212, 205, 190),
  342.                    (219, 219, 219, 219, 219, 219, 219));
  343.  
  344. type maxstr     = string[80];
  345.      window_rec = record
  346.                         x1,x2,y1,y2,c1,b1,w1,w2: Integer;
  347.                         Screen: Array[1..4000] of byte;
  348.                   end;
  349.  
  350. var  Stack_Top,Last_Window_Num,
  351.      line_pos,F1         : Integer;
  352.      screen              : Array[1..4000] of byte;
  353.      real_screen         : Array[1..4000] of byte absolute Screen_Seg:Data_Addr;
  354.      Page_1              : Array[1..4000] of byte absolute Screen_Seg:$1000;
  355.      Imig                : Array [1..MaxScreens] of Window_rec;
  356.      Original            : Array[1..4000] of byte;
  357.      Coords              : Array[1..8,1..MaxScreens] of Integer;
  358.  
  359.  
  360. {----------------------------------------------------------------------------}
  361. {                              S E T _ P A G E                               }
  362. {----------------------------------------------------------------------------}
  363. procedure set_page(page: byte);
  364.  
  365. type
  366.   Result =
  367.     record
  368.       AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags: byte;
  369.     end;
  370. var rec:result;
  371.  
  372. begin
  373.   Rec.AX := page;
  374.   Rec.BX := $05;
  375.   Intr($10,Rec);
  376. end;
  377.  
  378. {----------------------------------------------------------------------------}
  379. {                        S  C  R  N  _  O  F  F                              }
  380. {----------------------------------------------------------------------------}
  381. Procedure Scrn_off;
  382. begin
  383.      inline($52/$50/$ba/$d8/$03/$b0/$21/$ee/$58/$5a)
  384. end;
  385. {----------------------------------------------------------------------------}
  386. {                        S  C  R  N  _  O  N                                 }
  387. {----------------------------------------------------------------------------}
  388. Procedure Scrn_on;
  389. begin
  390.      inline($52/$50/$ba/$d8/$03/$b0/$29/$ee/$58/$5a)
  391. end;
  392. {----------------------------------------------------------------------------}
  393. {                        A  C  T  I  V  E                                    }
  394. {----------------------------------------------------------------------------}
  395. Function active: integer;
  396. begin
  397.      active:=stack_top
  398. end;
  399. {----------------------------------------------------------------------------}
  400. {                              P  U  S  H                                    }
  401. {----------------------------------------------------------------------------}
  402. Procedure Push(Ulx, Uly, Lrx, Lry, Foreground, Background: integer);
  403.  
  404. { This procedure Saves screens in memory. When a new window is put
  405.   on the Screen, the preceding window is stored away for later reference.}
  406.  
  407. begin
  408.      { If last Window up, move the Original Screen into Screen Memory}
  409.      if stack_top = 0 then
  410.            begin
  411.               Scrn_off;
  412.               move(real_screen, Original, 4000);
  413.               Scrn_on
  414.            end;
  415.      {Save all Data concerning the windows}
  416.      if (Stack_top < MaxScreens) and (Stack_Top >= 0) then
  417.             begin
  418.                  Stack_top:=Stack_top+1;
  419.                  Imig[Stack_top].x1:=Ulx;
  420.                  Imig[Stack_top].y1:=Uly;
  421.                  Imig[Stack_top].x2:=Lrx;
  422.                  Imig[Stack_top].y2:=Lry;
  423.                  Imig[stack_top].c1:=Foreground;
  424.                  Imig[Stack_top].b1:=Background
  425.             end;
  426.  
  427.      { Push Screen on Stack ... Sort of... }
  428.      Scrn_off;
  429.      Move(real_screen,Imig[Stack_top].Screen,4000);
  430.      Scrn_on
  431. end;
  432. {----------------------------------------------------------------------------}
  433. {                              P  O  P                                       }
  434. {----------------------------------------------------------------------------}
  435. Procedure Pop;
  436.  
  437. { This Procedure takes the screen that procedes the current window and
  438.   Copies back to screen memory, restores all data concerning the previous
  439.   window and activates it.. Neat huh? }
  440.  
  441. begin
  442.  
  443.      { If no windows are active, save the current screen }
  444.      if stack_top =0 then
  445.            begin
  446.                 normvideo;
  447.                 window(1,1,80,25);
  448.                 Scrn_off;
  449.                 move(Original, real_screen, 4000);
  450.                 Scrn_on;
  451.            end;
  452.  
  453.      { Get Preceding screen and copy it to screen memory }
  454.      Scrn_off;
  455.      Move(Imig[Stack_top].Screen,Real_Screen,4000);
  456.      Scrn_on;
  457.      Stack_top:=Stack_top-1
  458. end;
  459. {----------------------------------------------------------------------------}
  460. {                           W  R  I  T  E  X  Y                              }
  461. {----------------------------------------------------------------------------}
  462. Procedure Writexy(long_string:maxstr; xcoord,ycoord:integer; var color: integer);
  463.  
  464. { This procedure Draws whatever you want, wherever you want, by changing the
  465.   value of Screen in the variable declaration, it can draw a "Picture" any-
  466.   were in memory. This allows for the Speed of the window making process..}
  467.  
  468. var str_len, real_pos, scr_pos: integer;
  469.  
  470. begin
  471. {$I-}
  472.      str_len:=length(long_string); { So I know how much to write }
  473.      Scr_pos:=0;
  474.  
  475.      { The next 8 lines write the string in every "even" location in memory
  476.        and ever odd location gets the attribute with determines how the
  477.        string is displayed on the screen}
  478.      for real_pos:=1 to str_len do
  479.                  if scr_pos < 4001 then
  480.                        begin
  481.                             scr_pos:=((xcoord*2)-1)+(ycoord*160);
  482.                             screen[scr_pos]:=ord(copy(long_string,real_pos,1));
  483.                             screen[scr_pos+1]:=color;
  484.                             xcoord:=xcoord+1;
  485.                        end
  486. {$I+}
  487. end;
  488.  
  489. {----------------------------------------------------------------------------}
  490. {                              F  R  A  M  E                                 }
  491. {----------------------------------------------------------------------------}
  492. Procedure Frame(WindowType, UpperLeftX, UpperLeftY, LowerRightX, LowerRightY, color: Integer);
  493.  
  494. { This procedure draws the window frame in another part of memory. }
  495. var i: integer;
  496. begin
  497.      WriteXY(chr(Fc[WindowType,1]),UpperLeftX, UpperLeftY,color);
  498.      for i:=UpperLeftX+1 to LowerRightX-1 do WriteXY(chr(Fc[WindowType,2]),i,UpperleftY,color);
  499.      WriteXY(chr(Fc[WindowType,3]),i+1,UpperleftY,color);
  500.      for i:=UpperLeftY+1 to LowerRightY-1 do
  501.          begin
  502.               WriteXY(chr(Fc[WindowType,4]),UpperLeftX , i,color);
  503.               WriteXY(chr(Fc[WindowType,4]),LowerRightX, i,color);
  504.          end;
  505.      WriteXY(chr(Fc[WindowType,5]),UpperLeftX, LowerRightY, color);
  506.      for i:=UpperLeftX+1 to LowerRightX-1 do WriteXY(chr(Fc[WindowType,6]),i,LowerrightY,color);
  507.      WriteXY(chr(Fc[WindowType,7]),i+1,LowerRightY,color);
  508. end  { Frame };
  509. {----------------------------------------------------------------------------}
  510. {                         I  N  I  T  I  A  L  I  Z  E                       }
  511. {----------------------------------------------------------------------------}
  512. Procedure initialize;
  513.  
  514. { Set up memory and the stack }
  515.  
  516. var i:integer;
  517.  
  518. begin
  519.      Stack_top:=0;
  520.      move(real_screen,screen,4000);
  521.      with imig[1] do for i:=1 to 4000 do screen[i]:=$00;
  522.      for i:=2 to 9 do move(Imig[i-1].screen,imig[i].screen,4000);
  523.      move(imig[1].screen,screen,4000);
  524.      move(imig[1].screen,original,4000)
  525. end;
  526. {----------------------------------------------------------------------------}
  527. {                    A  D  D  _  W  I  N  D  O  W                            }
  528. {----------------------------------------------------------------------------}
  529. Procedure Add_window(UpperLeftX,UpperLeftY,LowerRightX,LowerRightY,Foreground,
  530.                  BackGround, WindowType: Integer);
  531.  
  532. { This procedure does all the laborous work for you.. The variables make it
  533.   Fairly easy to understand. }
  534.  
  535. Var i,j,k,Color: Integer;
  536.  
  537. begin
  538.      Imig[Stack_top].w1:=whereX;
  539.      Imig[Stack_top].w2:=WhereY;
  540.      UpperLeftX:=UpperLeftX+1;
  541.      LowerRightX:=LowerRightX-1;
  542.      LowerRightY:=LowerRightY-2;
  543.      f1:=WindowType;color:=0;
  544.      Scrn_off;
  545.      move(real_screen,screen,4000);
  546.      Scrn_on;
  547.  
  548.      { Set color attribute for direct writeng to memory }
  549.      if background < 17 then Color:=foreground+(background*16);
  550.  
  551.      { Check for invalid window frame types }
  552.      if (WindowType > 5) or (WindowType < 0) then
  553.               begin
  554.                    Clrscr;
  555.                    Writeln('Invalid Frame Type!')
  556.               end
  557.     else
  558.  
  559.      { If the window is valid then Procede }
  560.               begin
  561.  
  562.      { Fill color Attribute of window directly into memory }
  563.                    k:=1;
  564.                    for j:=UpperLeftY to LowerRightY do
  565.                            for i:=UpperLeftX to LowerRightX do
  566.                                     begin
  567.                                          k:=(j*160)+(i*2);
  568.                                          Screen[k]:=Color;
  569.                                          Screen[k-1]:=$20
  570.                                     end;
  571.  
  572.     { Frame Window }
  573.                    Case Windowtype of
  574.                              1:Frame(WindowType,UpperLeftX-1,UpperLeftY-1,
  575.                                       LowerRightX+1,LowerRightY+1,
  576.                                       color);
  577.                              2:Frame(WindowType,UpperLeftX-1,UpperLeftY-1,
  578.                                       LowerRightX+1,LowerRightY+1,
  579.                                       color);
  580.                              3:Frame(WindowType,UpperLeftX-1,UpperLeftY-1,
  581.                                            LowerRightX+1,LowerRightY+1,
  582.                                            color);
  583.                              4:Frame(WindowType,UpperLeftX-1,UpperLeftY-1,
  584.                                       LowerRightX+1,LowerRightY+1,
  585.                                       color);
  586.                              end { Case }
  587.               end;
  588.  
  589.     { Activate newly formed window }
  590.     Window(1,1,80,25);
  591.     Window(UpperLeftX,UpperLeftY+1,LowerRightX,LowerRightY+1);
  592.     push(UpperLeftx,UpperLeftY+1,LowerRightX,LowerRightY+1,Foreground, Background);
  593.     Scrn_off;
  594.     Move(screen,real_screen,4000);gotoxy(1,1);
  595.     Scrn_on;
  596.     Textcolor(Foreground);TextBackground(backGround);ClrScr;
  597. end;
  598. {----------------------------------------------------------------------------}
  599. {                    C  O  L  O  R  _  W  I  N  D  O  W                      }
  600. {----------------------------------------------------------------------------}
  601. Procedure Color_window(Foreground, Background: integer);
  602.  
  603. { This procedure allows you to change the foreground and background color
  604.   of the active window. }
  605.  
  606. var i,j,Color: Integer;
  607.  
  608. begin
  609.  
  610.      { Set Attribute value }
  611.      if background < 8 then Color:=foreground+(background*16);
  612.  
  613.      { Write new attribute direclty to screen memory }
  614.      for j:=(Imig[Stack_top].y1-2) to Imig[Stack_top].y2 do
  615.             for i:=(Imig[Stack_top].x1-1) to (Imig[Stack_top].x2+1) do
  616.                     begin
  617.                          Real_Screen[(j*160)+(i*2)]:=Color
  618.                     end
  619. end;
  620. {----------------------------------------------------------------------------}
  621. {                        R  E  M  O  V  E                                    }
  622. {----------------------------------------------------------------------------}
  623. Procedure Remove(Num_to_Remove: Integer);
  624.  
  625. { This Procedure removes 1 or a specified number of windows from the
  626.   screen and reactivates the underlying window }
  627.  
  628. var i: integer;
  629. begin
  630.      if (Num_to_Remove > 0) and (Num_to_Remove < MaxScreens) then
  631.           for i:=1 to Num_to_remove do Pop
  632.      else
  633.          Pop;
  634.      Window(1,1,80,25);
  635.      Window(Imig[Stack_top].x1+1,Imig[Stack_top].y1,Imig[Stack_top].x2,Imig[Stack_top].y2);
  636.      gotoxy(1,1);
  637.      TextBackground(Imig[Stack_top].b1);TextColor(Imig[Stack_top].c1);
  638.      GotoXY((Imig[Stack_top].w1-1),Imig[Stack_top].w2)
  639. end;
  640. {----------------------------------------------------------------------------}
  641. {                   W  I  N  D  O  W  _  T  I  T  L  E                       }
  642. {----------------------------------------------------------------------------}
  643. Procedure Window_Title(Name: Maxstr; color:integer);
  644.  
  645. var i, k, l, m: integer;
  646.  
  647. begin
  648.      If Length(name)>0 then
  649.      begin
  650.      l:=1;
  651.      color:=color+(Imig[Stack_top].b1*16);
  652.      if f1 < 4 then Real_Screen[(((Imig[Stack_top].Y1-2)*160)+(Imig[Stack_top].X1*2))+l]:=$5b;
  653.      for i:=1 to length(Name) do
  654.              begin
  655.                   k:=(((Imig[Stack_top].Y1-2)*160)+(Imig[Stack_top].X1*2))+l+1;
  656.                   Real_Screen[k+1]:=ord(copy(Name,i,1));
  657.                   Real_Screen[k+2]:=color;
  658.                   l:=l+2
  659.              end;
  660.      if f1 < 4 then Real_Screen[k+3]:=$5d
  661.      end
  662. end;
  663. (* {$I WINDMNGR.INC} *)
  664.  
  665. begin
  666.  
  667.      Add_Window(5,5,75,20,11,0,2);
  668.  
  669.      Get_file;
  670.  
  671.      Remove(1);
  672.  
  673. end; { Demo }
  674.  
  675.  
  676. {----------------------------------------------------------------------------}
  677. {              P R O C E S S   I N T E R R U P T                             }
  678. { - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - }
  679. Procedure Process_Intr;
  680.  
  681. {  PURPOSE:  This  procedure  replaces  the  standard  keyboard  interrupt.  If
  682.             anything but <Alt>-F10 is pressed,  the key is  passed  on  to  the
  683.             standard  keyboard  interrupt.  B*U*T  when  <Alt>- F10 is pressed,
  684.             this program takes over.  The variable InUse  is  set  to  TRUE  to
  685.             ensure that this code doesn't try to run "on top of itself " AND to
  686.             indicate  to the Inline code to save/restore the original interrupt
  687.             regs.
  688. }
  689.  
  690. Begin
  691.           { K e y b o a r d    Interrupt   o c c u r s   here }
  692. {----------------------------------------------------------------------}
  693. {****************************************************************************}
  694. {                 S  T  A  Y  S  A  V  E  .  I  N  C                         }
  695. {                                                                            }
  696. {           This is the Staysave.Inc file included above                     }
  697. {                                                                            }
  698. {      Separate the code out into a file or replace the $I Staysave.Inc      }
  699. {                statement above with this code.                             }
  700. {****************************************************************************}
  701.  
  702. {This Inline routine will save the regs and Stack for Stay resident programs.
  703.  It restores Ds and Ss from the previously saved integer constants "OurDseg"
  704.   and "OurSSeg". This is important since Dos is not re-entrant and any attempt
  705.   to use Interrupt I/O services will clobber the very stack on which the
  706.   Resident Turbo program just saved its regs. Thus, on the final return, you
  707.   and Toto will end up somewhere other than Kansas and without your Ruby Reds.
  708.    }
  709.  
  710. { Arthor:      L.H. Ferris
  711.  
  712.        Distributed to the Public Domain for use without profit.
  713.                     Original Version 5.15.85
  714. }
  715.                                    { On entry the Stack will already contain: }
  716.                                    {  1) Sp for Dos                           }
  717.                                    {  2) Bp for Dos                           }
  718.                                    {  3) Ip for Dos                           }
  719.                                    {  4) Cs for Dos                           }
  720.   Inline (                         {  5) Flags for Dos                        }
  721.  
  722.  
  723.  
  724.     $FA /                              {  Cli       Stop all interrupts       }
  725.  
  726.                                        { Bp and Sp aready saved at Begin Stmt }
  727.     $55/                               {Push   Bp  Save again for Regpak      }
  728.     $BD/Regs/                          {Mov    Bp,offset REGS}
  729.     $2E/$89/$46/$00/                   {CS:Mov [Bp+0],AX}
  730.     $2E/$89/$5E/$02/                   {Cs:Mov [Bp+2],Bx}
  731.     $2E/$89/$4E/$04/                   {CS:Mov [Bp+4],CX}
  732.     $2E/$89/$56/$06/                   {CS:Mov [Bp+6],DX}
  733.     $2E/$8F/$46/$08/                   {Pop    Cs:[Bp+8] Fetch Bp from stack  }
  734.     $2E/$89/$76/$0A/                   {CS:Mov [Bp+A],SI}
  735.     $2E/$89/$7E/$0C/                   {CS:Mov [Bp+C],DI}
  736.     $2E/$8C/$5E/$0E/                   {CS:Mov [Bp+E],DS}
  737.     $2E/$8C/$46/$10/                   {CS:Mov [Bp+10],ES}
  738.     $9C/                               {PUSHF  put Flags on stack to retrieve }
  739.     $2E/$8F/$46/$12/                   {POP Cs:[Bp+12]}
  740.  
  741.     { If Current SS := [OurSseg] or Inuse = True, then dont save the stack. }
  742.     { This program is being recursive.                                      }
  743.  
  744.      $2E/$80/$3E/Inuse/$01/   {Cmp  Cs:[Inuse],1                          }
  745.      $74/$4D/                 {Je   ReCurin ------J-U-M-P---------------  }
  746.  
  747.     { Now save 5 Words from the Dos Stack before performing any         }
  748.     { I/O or re-using the Dos stack                                     }
  749.  
  750.      $2E/$8C/$16/DosSSeg/     {Mov  Cs:DosSSeg,SS Save Dos Stack Segment    }
  751.      $8C/$D6/                 {Mov  Si,SS         If this is our Stack Seg  }
  752.      $8E/$C6/                 {Mov  Es,Si         Get Dos StackSeg          }
  753.      $2E/$8E/$16/OurSSeg/     {Mov  SS,Cs:OurSSeg Get our Stack segment     }
  754.      $2E/$8E/$1E/OurDseg/     {Mov  Ds,Cs:Our_Ds  Setup our Data Segment    }
  755.  
  756.  
  757.      $2E/$3B/$36/OurSSeg/     {Cmp  Si,Cs:OurSSeg ..use current Stack ptr   }
  758.      $89/$E6/                 {Mov  Si,Sp         ..value..else reset stack }
  759.      $74/$05/                 {Je   $+5           ..to original Turbo stack }
  760.      $3E/$8B/$36/$74/$01/     {Mov  Si,Ds:[174]   ..(cf. code at B2B 3.0x)  }
  761.  
  762.      $87/$F4/                 {Xchg Sp,Si         Set new  Stack Pointer    }
  763.  
  764.      $2E/$FF/$76/$00/         {Push [Bp+0]  Save Dos/User regs for Exit     }
  765.      $2E/$FF/$76/$02/         {Push [Bp+2]  Save Bx                         }
  766.      $2E/$FF/$76/$04/         {Push [Bp+4]  Save Cx                         }
  767.      $2E/$FF/$76/$06/         {Push [Bp+6]  Save Dx                         }
  768.                               {Push [Bp+8]  Save Bp                         }
  769.      $2E/$FF/$76/$0A/         {Push [Bp+A]  Save Si                         }
  770.      $2E/$FF/$76/$0C/         {Push [Bp+C]  Save Di                         }
  771.      $2E/$FF/$76/$0E/         {Push [Bp+E]  Save Ds                         }
  772.      $2E/$FF/$76/$10/         {Push [Bp+10] Save Es                         }
  773.  
  774.  
  775.      $2E/$8E/$16/OurSSeg/     {Mov  SS,Cs:OurSSeg Set up our Stack          }
  776.      $56/                     {Push Si            Save bottom of Dos Stack  }
  777.      $2E/$8C/$5E/$0E/         {Mov  Cs:[Bp+E],Ds  Set New Data Segmt in regs}
  778. {Recurin                                            Jump here if Recursion  }
  779.      $FB                      {Sti Enable Interrupts                        }
  780.  
  781.        ) ;
  782. (* {$I Staysave.inc} *)
  783. {----------------------------------------------------------------------}
  784. { Check the Int 16 request function in Ah reg:
  785.                    0 = read character from Keyboard
  786.                    1 = check character available
  787.                    2 = check shift key values
  788. }
  789. if HalfRegs.Ah <> 0 then  {if this is not character request...}
  790.    Begin
  791.    Intr(User_Int,Regs)    { just pass it on to standard interrupt }
  792.    End
  793.  
  794. Else      { HalfRegs.Ah = 0 then    { This is a Character Request }
  795.   Begin   {Get Keyboard Char }
  796.  
  797.   Intr (User_Int, Regs);             { Use the standard interrupt}
  798.  
  799.   if (Halfregs.Ah = Our_Char)        { Separate the test so code }
  800.                                      { performs efficiently      }
  801.      then if  (not InUse) then
  802.  
  803.      begin { Demo }
  804.      InUse := true;                  { "dont clobber saved stack"}
  805. {            .
  806.              .
  807.              .  Your
  808.              .      Program
  809.              .             Goes
  810.              .                 Here
  811.              .
  812. }                                    { Get current Cursor Position    }
  813.      Old_Xpos := WhereX; Old_Ypos := WhereY;
  814.      Demo ;
  815.      GotoXY(Old_Xpos,Old_Ypos);       { Put Cursor Back                }
  816.      Regs.Ax := Ord(KeyChr) shl 8 ;        {Give back Last entered char     }
  817.      InUse := false;                  { ok to restore interrupted stack }
  818.      end  { Demo }
  819.  
  820.   end; {Get Keyboard Char }
  821.  
  822. {****************************************************************************}
  823. {                  S  T  A  Y  R  S  T  R  .  I  N  C                        }
  824. {                                                                            }
  825. {           This is the StayRstr.Inc file included above                     }
  826. {       Separate the code out into a file or replace the $I StayRstr.Inc     }
  827. {                  statement above with this code.                           }
  828. {****************************************************************************}
  829.  
  830. { Inline Code to restore the stack and regs moved to the Turbo Resident
  831.   Program Stack to allow re-entrancy into the Dos Code for I/O and
  832.   recursion from built-in Turbo functions.
  833.  
  834. ; Arthor:      L.H. Ferris
  835.  
  836. ; Distributed to the Public Domain for use without profit.
  837. ; Original Version 5.15.85
  838.  
  839. ;----------------------------------------------------------------------;
  840. ;        Restore the Dos Regs and Stack
  841. ;----------------------------------------------------------------------;
  842.  
  843. ; On entry the Stack will already contain:
  844. ;
  845. ;        1) Bottom of Dos Stack Ptr
  846. ;        2) Dos Flags
  847. ;        3) Dos Code Segment
  848. ;        4) Dos Instruction Ptr
  849. ;        5) Dos Base Pointer
  850. ;        6) Dos Original Stack Ptr
  851. }
  852.     inline(
  853.  
  854.     $BD/Regs/                          {Mov    Bp,offset REGS}
  855.     $2E/$8B/$46/$00/                   {CS:Mov Ax,[Bp+0]}
  856.     $2E/$8B/$5E/$02/                   {Cs:Mov Bx,[Bp+2]}
  857.     $2E/$8B/$4E/$04/                   {CS:Mov Cx,[Bp+4]}
  858.     $2E/$8B/$56/$06/                   {CS:Mov Dx,[Bp+6]}
  859.  
  860.     $2E/$8B/$76/$0A/                   {CS:Mov Si,[Bp+A]}
  861.     $2E/$8B/$7E/$0C/                   {CS:Mov Di,[Bp+C]}
  862.     $2E/$8E/$5E/$0E/                   {CS:Mov DS,[Bp+E]}
  863.     $2E/$8E/$46/$10/                   {CS:Mov ES,[Bp+10]}
  864.     $2E/$FF/$76/$12/                   {Push Cs:[Bp+12]}
  865.     $9D/                               {Popf}
  866.  
  867.     { If [Cs:InUse]:= True,  then dont restore the stack. This program is   }
  868.     { being recursive. Else restore  Dos Stack and Program Entry registers  }
  869.  
  870.      $2E/$80/$3E/Inuse/$01/   {Cmp  byte ptr Cs:[Inuse],1                   }
  871.      $74/$12/                 {Je   ReCurOut                                }
  872.  
  873.       $FA /                   { Cli      ; Stop all interrupts    }
  874.  
  875.  
  876.     $5D/                     {Pop Bp           Save Dos Sp across pops   }
  877.  
  878.     $07/                     {Pop  Es                                     }
  879.     $1F/                     {Pop  Ds                                     }
  880.     $5F/                     {Pop  Di                                     }
  881.     $5E/                     {Pop  Si                                     }
  882.     $5A/                     {Pop  Dx                                     }
  883.     $59/                     {Pop  Cx                                     }
  884.     $5B/                     {Pop  Bx                                     }
  885.     $44/$44/                 {Inc sp/Inc sp Thow old Ax value away        }
  886.  
  887.     $89/$EC/                  {Mov  Sp,Bp         Setup Dos Stack Ptr      }
  888.     $2E/$8E/$16/DosSSeg/      {Mov  SS,Cs:DosSSeg Give back Dos Stack      }
  889.  
  890. {RecurOut                              Clean up the Stack              }
  891.  
  892.     $5D/                               {Pop Bp  Throw away old dos Sp  }
  893.  
  894.     $BD/Regs/                          {Mov    Bp,offset REGS}
  895.     $2E/$FF/$76/$12/                   {Push Cs:[Bp+12]}
  896.     $9D/                               {Popf}
  897.     $5D/                               {Pop Bp  Retrieve old BP        }
  898.  
  899.     $FB/                               {Sti     Enable interrupts      }
  900.     $CA/$02/$00                        {Ret Far 002                    }
  901.         );
  902. (* {$I Stayrstr.inc}                      { Return to Caller } *)
  903. end ;
  904. {-----------------------------------------------------------------------}
  905.  
  906. {The main program installs the new interrupt routine and makes it permanently
  907.  resident as the keyboard interrupt.  The old keyboard interrupt is addressed
  908.  through #68H, so it can still be used.
  909.  
  910. The following dos calls are used:
  911.  
  912.  Function 25 - Install interrupt address
  913.                input al = int number,
  914.                ds:dx = address to install
  915.  
  916.  Function 35 - get interrupt address
  917.                input al = int number
  918.                output es:bx = address in interrupt
  919.  
  920.  Function 31 - terminate and stay resident
  921.                input dx = size of resident program obtained from the memory
  922.                allocation block at [Cs:0 - $10 + 3]
  923.  
  924.  Function 49 - Free Allocated Memory
  925.                input Es = Block Segment to free
  926.  
  927.  Interrupt 20 - Return to invoking process
  928. }
  929.  
  930. {-----------M A I N    B L O C K---------------------------------------------}
  931. Begin                                  {**main**}
  932.  
  933.   InUse  := false;
  934.   OurDseg:= Dseg;       { Save the Data Segment Address for Interrupts }
  935.   OurSseg:= Sseg;       { Save our Stack Segment for Interrupts        }
  936.  
  937.   Terminate_Flag := false ;
  938.  
  939.   {now install the interrupt routine}
  940.  
  941.   SaveRegs.Ax := $35 shl 8 + User_Int;
  942.   Intr($21,SaveRegs);                 {Check to make sure int not already used}
  943.  
  944.   if SaveRegs.Es <> $00 then
  945.     WriteLn ('Interrupt in use -- can''t install Resident Turbo Code')
  946.   else
  947.     begin
  948.  
  949.       { Initialize Your Progam Here since you wont get control again
  950.         until "Our_Char" is entered from the Keyboard.               }
  951.  
  952.       SaveRegs.Ax := $35 shl 8 + Kybrd_Int;
  953.       Intr($21,SaveRegs);        {get the address of keyboard interrupt }
  954.  
  955.       SaveRegs.Ax := $25 shl 8 + User_Int;
  956.       SaveRegs.Ds := SaveRegs.Es;
  957.       SaveRegs.Dx := SaveRegs.Bx;
  958.       Intr($21,SaveRegs);         { set the user-interrupt address to point
  959.                                 { to the keyboard interrupt address }
  960.  
  961.       SaveRegs.Ax := $25 shl 8 + Kybrd_Int;
  962.       SaveRegs.Ds := Cseg;
  963.       SaveRegs.Dx := Ofs(Process_Intr);
  964.       Intr ($21,SaveRegs);        { set the keyboard interrupt to point to
  965.                                   "Process-Intr" above}
  966.  
  967.       Writeln('  Turbo Stay-Resident Demo: Press Alt-F10');
  968.  
  969.       {now terminate and stay resident}
  970.                                               { Pass return code of zero    }
  971.       SaveRegs.Ax := $31 shl 8 + 0 ;          { Terminate and Stay Resident }
  972.       SaveRegs.Dx := MemW [Cseg-1:0003] ;     { Prog_Size from Allocation Blk}
  973.       Intr ($21,SaveRegs);
  974.  
  975.     end;
  976.        { END OF RESIDENCY CODE }
  977. end.
  978. { Thats all.. }
  979.