[comp.lang.pascal] How to "chain" in Turbo Pascal

mead@uxh.cso.uiuc.edu (09/02/90)

A while back, I asked if there was any way to "chain" from a Turbo
Pascal (V5.5) program to another.  I suggested stuffing the keyboard
buffer, but didn't know how to do this.  I have since learned, and for
the people who tried to help me, as well as for the curious, here it is:

  The keyboard buffer is 16 words of memory from $0040:$001e to $003c.
  The buffer is a circular queue - the head pointer points to the head
  of the queue from $0040:$001a and the tail from $001b.  (So all
  totaled, the buffer uses 17 words.  As a warning, I've seen utilities
  that are supposed to increase the buffer area, I'm not sure whether
  this will work in these cases.)

  As a consequence of this, you may clear the buffer by setting the
  head and tail to $0040:$001e (the first position of the queue)
  instead of: WHILE KeyPressed DO ch := ReadKey; .  Hopefully, this
  will be intuitive from the listing.  I'm not sure which is more
  efficient, but I imagine that the direct method would be superior if
  you had to use it often.

======


program Demo_Chaining_Process;

{ Drives CHAIN }

  procedure Chain( s          : string;     { The string to be outputted }
                   CRSwitch   : boolean );  { Add a CR at the end?       }

  {
    Places S into the keyboard buffer (thereby destroying any keystrokes
     that happen to be lying around) resulting in S being operated
     upon by DOS (provided that the program terminates without reading
     the keyboard buffer).

    Lifted from similar code in _Using Turbo Pascal_ by Michael Yester (p241)
  
  }

  const
      ASCIIEnter = 13;                     { ENTER's ASCII value }
      ExtEnter = 28;                       { ENTER's extended scan code }

  type
     KeyBufferType = array[ $1e..$3d ] of byte;   { 16 words ... }

  var

     i, Len : byte;
     HeadPointer : byte absolute $0040:$001a;
     TailPointer : byte absolute $0040:$001c;
     KeyBuffer : ^KeyBufferType;

  begin

    KeyBuffer := Ptr( $0040,$001e );    { The buffer is contiguous with the }
                                        {  head & tail pointers at $001a &  }
                                        {  $001c.                           }
    TailPointer := $1e;                 { The choice of subscripts makes    }
    HeadPointer := $1e;                 {  makes life easier.               }

    Len := Length( s );

    if CRSwitch then
      if Len > 14 then   { ... then it's too long - we need room for the CR }
        Len := 14
    else
      if Len > 15 then
        Len := 15;

    for i := 1 to Len do
      begin
        KeyBuffer^[ TailPointer ] := ord( s[i] );
        inc(TailPointer,2);
      end;

    if CRSwitch then
      begin
        KeyBuffer^[ TailPointer ] := ASCIIEnter;
        KeyBuffer^[ TailPointer+1 ]  := ExtEnter;
        inc( TailPointer,2 );
      end;

  end;

begin { Main }

   Chain( 'dir demochn.*',TRUE );
   {Chain( 'demochn',TRUE );}         { Try this :) }

end.

============

I'm not sure how the queue works, but as you can see from the last
assignments to the buffer (ASCIIEnter & ExtEnter), both the ASCII and
the Extended Scan Codes need to be stuffed.

Also, the buffer has 16 words of space, but strings greater than 15
bytes cause amusing results (well, not so amusing in the IDE).  I guess
that (as implied by my comments above) whenever the pointers point to
the same word, that word isn't used.

Hope this helps,

-alan mead