home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / TURBOPAS / LASTCOM2.ZIP / LASTCOM2.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1985-12-28  |  10.8 KB  |  296 lines

  1. {LAST COMMAND
  2.              written by Stephen R. Davis 2/28/85}
  3. {$c-}
  4. {$k-}
  5.  
  6. {this program is a "stay resident" program which allows
  7.  the operator to perform any of the last 10 commands
  8.  which he had entered by entering an AltF10 to get a
  9.  list of them, followed by a function key F1-F10
  10.  to select which command to reenter.  Command lines which
  11.  begin with nonprintable keystrokes are not saved.  This
  12.  program was written as an example of a TurboPascal
  13.  stay-resident "interrupt borrower" program}
  14.  
  15. {declare our constants}
  16.  
  17. const
  18.     our_char = 113;          {this is the scan code for AltF10}
  19.     scan_offset = 58;        {scan code of F1 - 1}
  20.     first_row = 5;           {window size and position}
  21.     first_col = 5;
  22.     numb_saved = 10;         {number of command lines saved}
  23.     windowwidth = 40;
  24.     windowlength = 12;       {='numb_saved' + 2}
  25.  
  26.     CR = $D;                 {ascii carriage return}
  27.     ESCAPE = $1B;            {  "   escape}
  28.     DEL = $8;                {  "   delete character}
  29.     CntrlC = $3;             {  "   control C}
  30.     Unprintable = $0;        {nonascii keys generate 0 char}
  31.  
  32.     user_int = $68;          {place to put borrowed interrupt--
  33.                               may be changed to any available
  34.                               interrupt the user desires}
  35.  
  36.     kybrd_int = $16;         {BIOS keyboard interrupt}
  37.     prog_size = 16000;       {approximate size of program --
  38.                              this much space is reserved
  39.                              upon exit}
  40.  
  41. {here the global (static type) variables}
  42.  
  43. type
  44.     regtype = record
  45.                    ax,bx,cx,dx,bp,si,di,ds,es,flags:integer
  46.               end;
  47.     halfregtype = record
  48.                    al,ah,bl,bh,cl,ch,dl,dh:byte
  49.               end;
  50.  
  51. const                        {put 'regs' in the code segment
  52.                               by giving variables initial values}
  53.     regs : regtype = (ax:0;bx:0;cx:0;dx:0;bp:0;si:0;di:0;
  54.                       ds:0;es:0;flags:0);
  55.     feeding_char   :boolean = FALSE;
  56.     no_cr          :boolean = FALSE;
  57.     j              :integer = 1;
  58.     saveds         :integer = 0;
  59.  
  60. var
  61.     savreg         :regtype; {define a variable for the
  62.                               register structures}
  63.     halfregs       :halfregtype absolute regs; {and for the
  64.                                                 half registers}
  65.  
  66.     i              :integer;
  67.     trash_line     :boolean;
  68.     last_lines     :array [0..numb_saved] of
  69.                     array[1..60] of integer;
  70.     cursorpos      :integer;
  71. {.pa}
  72. {include the window manipulation software}
  73. {$i window.pas}
  74. {.pa}
  75. {the following code prints out the previous n commands in
  76.  the window previously opened up}
  77.  
  78. procedure printchoices;
  79. var
  80.    i,j : integer;
  81.    outchar : byte;
  82.  
  83. begin
  84.    for i := 2 to numb_saved+1 do         {loop thru the
  85.                                           saved commands}
  86.    begin
  87.       GoToXY(2,i);
  88.                              {put up the function key}
  89.       Write('F');Write(((i-1) mod 10):1);Write(')');
  90.       j := 1;
  91.                              {now the saved command}
  92.       while ((last_lines[i-1][j] and $FF) <> CR)
  93.               and (j <> (windowwidth-5)) do
  94.       begin
  95.          Write(Chr(last_lines[i-1][j] and $FF));
  96.          j := j + 1
  97.       end
  98.    end
  99. end;
  100. {.pa}
  101. {the following routine saves a keystroke in the
  102.  command push down stack.  If the key has some special
  103.  meaning, this routine attempts to interpret it; e.g.
  104.  'del' deletes previous character, etc.  It can only
  105.  interpret so much, and even then it only knows
  106.  COMMAND.COM's rules}
  107.  
  108. procedure save_key;
  109. begin
  110.     last_lines[0][j] := regs.ax;
  111.     if (j < 60) and not trash_line then
  112.          j := j + 1;
  113.     case halfregs.al of   {if that was a...}
  114.     DEL:                  {...delete then...}
  115.          if j > 2 then    {...delete char}
  116.               j := j - 2
  117.          else
  118.               j := 1;
  119.  
  120.     ESCAPE:               {...escape then...}
  121.          j := 1;          {...delete the line}
  122.  
  123.     CntrlC:               {...Cntrl C then...}
  124.          j := 1;          {...delete the line}
  125.  
  126.     Unprintable:          {...non ascii characters...}
  127.          if (regs.ax = 0) or {...if its BREAK...}
  128.             (regs.ax = $3F00) then  {...or F5 then...}
  129.               j := 1      {...just clear the line; else...}
  130.          else
  131.               trash_line := TRUE; {...trash the remainder}
  132.                                   {of the line to next CR}
  133.  
  134.     CR:                   {...if carriage return then...}
  135.          begin
  136.               if trash_line then  {if trash line flag set...}
  137.                    j := 1;        {...dont save the line...}
  138.               if j > 2 then    {..and dont save empty lines...}
  139.                           {...else push command on 'stack',...}
  140.                    for i := numb_saved downto 1 do
  141.                         last_lines[i] := last_lines[i-1];
  142.               for i := 1 to 60 do  {...clear last entry,...}
  143.                    last_lines[0][i] := $07 shl 8 + CR;
  144.               j := 1      {...and reset pointer}
  145.          end
  146.     end;
  147.  
  148.     if j = 1 then            {if the line becomes empty...}
  149.          trash_line := FALSE {...then stop trashing the line}
  150. end;
  151. {.pa}
  152. {this code processes interrupts to the keyboard BIOS interrupt (16 hex)}
  153.  
  154. procedure process_intr;
  155. begin;
  156. {$i savereg.pas}             {save the input registers}
  157.     if halfregs.ah = 0 then  {if this is character request...}
  158.     begin
  159.                              {if we were in the middle of
  160.                               spooling chars...}
  161.          if feeding_char then
  162.          begin               {...fetch the next character from
  163.                               the command stack and return that}
  164.               regs.ax := last_lines[i][j];
  165.               j := j + 1;
  166.                              {if this was the last char...}
  167.               if (halfregs.al = CR) or (j > 60) then
  168.               begin
  169.                    feeding_char := false; {...turn spooling off}
  170.                    j := 1;
  171.                    if no_cr then
  172.                         regs.ax := $0;
  173.                    no_cr := false
  174.               end
  175.          end
  176.          else
  177.          begin     {(we are not in the middle of spooling)}
  178.               Intr (user_int, regs);   {perform the BIOS call
  179.                                         the caller asked for}
  180.                              {if this wasn't "our" char...}
  181.               if halfregs.ah <> our_char then
  182.                    save_key  {...save the keystroke...}
  183.               else
  184.               begin
  185.                    savreg.ax := $0300;   {fetch the current...}
  186.                    savreg.bx := $0;      {...cursor position}
  187.                    Intr($10,savreg);
  188.                    cursorpos := savreg.dx;
  189.  
  190.                    openwindow;   {open up the display window}
  191.                    printchoices; {now print the command stack}
  192.                    regs.ax := $0;      {read a character...}
  193.                    Intr(user_int,regs);{...from the keyboard}
  194.  
  195.                                  {make F0 maps to 1, F1 to 2, etc.}
  196.                    i := halfregs.ah - scan_offset;
  197.                    if (i > 25) and (i < 37) then
  198.                    begin         {shift function keys act like normal
  199.                                   function keys except no return on end}
  200.                         i := i - 25;
  201.                         no_cr := true
  202.                    end;
  203.                    if (i > 0) and (i <= 10) then
  204.                    begin     {if input was a function key
  205.                               give him the 1st char of his choice...}
  206.                         regs.ax := last_lines[i][1];
  207.                         if halfregs.al <> CR then
  208.                         begin {...and set the flag to begin feeding
  209.                                him the remainder of the command every
  210.                                time he asks for a char from the keyboard}
  211.                              feeding_char := true;
  212.                              j := 2
  213.                         end;
  214.  
  215.                    end
  216.                    else      {not function key -- just save it}
  217.                         save_key;
  218.                    closewindow;        {put what was there back}
  219.  
  220.                    savreg.ax := $0200; {replace cursor}
  221.                    savreg.bx := $0;
  222.                    savreg.dx := cursorpos;
  223.                    Intr($10,savreg)
  224.               end
  225.          end
  226.     end
  227.     else                     {he's not trying to read a char}
  228.          if feeding_char then {if he's spooling chars...}
  229.                              {...clear the z-flag}
  230.               regs.flags := regs.flags and $FFBF
  231.          else
  232.               Intr(user_int,regs);
  233.  
  234. {$i restreg.pas}             {restore the registers from 'reg'}
  235.     inline($CA/$02/$00)      {RETF 02 - return to caller}
  236. end;
  237. {.pa}
  238. {this section of code installs the interrupt
  239.  routine and makes it a permanently
  240.  resident interrupt borrower}
  241.  
  242. {the following dos calls are used:
  243.  sys 25- install interrupt address
  244.    input al = int number, ds:dx = address to install
  245.  
  246.  sys 35- get interrupt address
  247.    input al = int number
  248.    output es:bx = address in interrupt
  249.  
  250.  int 27- terminate and stay resident
  251.    input dx = size of resident program
  252. }
  253. begin                                  {**main**}
  254.     {initialize the variables which the interrupt
  255.      service routine will use}
  256.  
  257.     for i := 0 to numb_saved do
  258.          for j := 1 to 60 do
  259.               last_lines[i][j] := $07 shl 8 + CR;
  260.     j := 1; trash_line := FALSE;
  261.     saveds := Dseg;          {save the data segment locally}
  262.  
  263.     {now install the interrupt routine}
  264.  
  265.     savreg.ax := $35 shl 8 + user_int; {check to make sure
  266.                                         int not already used}
  267.     Intr($21,savreg);
  268.     if savreg.es <> $00 then
  269.     begin
  270.          WriteLn ('Interrupt in use -- cant install LASTCOM');
  271.          Intr($20,savreg)
  272.     end
  273.     else
  274.     begin
  275.          WriteLn ('Installing LASTCOMMAND --');
  276.          WriteLn ('     press AltF10 to select last command');
  277.                              {get the address that was there}
  278.          savreg.ax := $35 shl 8 + kybrd_int;
  279.          Intr($21,savreg);
  280.                              {put the address in the
  281.                               user interrupt}
  282.          savreg.ax := $25 shl 8 + user_int;
  283.          savreg.ds := savreg.es;
  284.          savreg.dx := savreg.bx;
  285.          Intr($21,savreg);
  286.                              {install interrupt system call}
  287.          savreg.ax := $25 shl 8 + kybrd_int;
  288.          savreg.ds := cseg;
  289.                              {put our routine address}
  290.          savreg.dx := Ofs(process_intr);
  291.          Intr ($21,savreg);
  292.  
  293.          {now terminate and stay resident}
  294.  
  295.          savreg.dx := prog_size;
  296.          Intr ($27,sa