program IAC;

(*
This program fiddles with the Inter-Application Communications Area (IAC).

The IAC is 16 bytes beginning at addr 0040:00F0h. Any program can
write information to the IAC for another program to read. Please
note: unless the first program directly invokes the second program,
it cannot protect the IAC from being altered by an intervening program.
The IAC can be used, for instance, to pass an address from one program
to the next.

People have asked me about rules/guidelines for using the IAC.
There appear to be none!  First come, first served!  DOS doesn't seem
to use it at all (nor any of the common DOS utility programs, so far
as I can tell).  No telling WHAT other programs might depend on the IAC
being undisturbed.

How can it be used?  Following are some examples .. take your choice.
Remember, the main reason for its existence is for inter-program
communications .. so don't waste it as a 16-byte buffer!  That's what
you have your data segment for!

This code is written in, and works with, Turbo Pascal v3.1.
Donno about v4.0 and up!

David Kirschbaum
Toad Hall
kirsch@braggvax.ARPA

*)

TYPE                                     {Define the IAC in different ways}
  IAC_Array    = ARRAY[0..15] OF BYTE;
  IAC_Str      = STRING[15];             {Length byte + 15 chars}
  Real2_Array  = ARRAY[1..2] OF REAL;    {Reals are 6 bytes, so there's
                                          room for two of them}

VAR                                        {Some IAC typed variables}
  iacArrayPtr : ^IAC_Array;                {A pointer to an array of bytes}
  IACStrPtr   : ^IAC_Str;                  {.. and to a string}
  iacRealPtr  : ^Real2_Array;              {.. and to an array of reals}

  IAC         : IAC_Array Absolute $0040:$00F0;  {Here is the actual IAC}
  IACMsg      : IAC_Str Absolute IAC;      {Type a string to the same place}
  IACReal2    : Real2_Array Absolute IAC;  {And some reals}

  {some program variables to play with}

  i       : INTEGER;                     {handy counter}
  S       : STRING[255];                 {a string}
  saveIAC : IAC_Array;                   {an array of bytes}
  r2      : Real2_Array;                 {some reals}

BEGIN
  saveIAC := IAC;                        {Preserve the true IAC as an array}

  {Play with the IAC with our pointer variable}

  iacArrayPtr := Ptr($0040,$00F0);            {Point our pointer to the IAC}
  IACStrPtr   := Ptr($0040,$00F0);            {same place}
  iacRealPtr  := Ptr($0040,$00F0);            {same place}

  Writeln('Original IAC bytes: ':20);
  FOR i := 0 TO 15 DO
    Write(IAC[i]:4);                          {write actual IAC bytes}
  Writeln;

  Writeln('Using pointer:');
  FOR i := 0 TO 15 DO
    Write(iacArrayPtr^[i]:4);                 {same bytes, using our pointer}
  Writeln;

  FOR i := 0 TO 15 DO
    iacArrayPtr^[i] := i;                     {Change it}

  Writeln('Changed IAC bytes: ':20);
  FOR i := 0 TO 15 DO
    Write(iacArrayPtr^[i]:4);                 {Read it again}
  Writeln;


  {Now play with some real numbers}

  FOR i := 1 TO 2 DO
    IACReal2[i] := i /3.0;               {Produce some reals in the IAC}

  Write('New IAC reals: ':20);
  FOR i := 1 TO 2 DO
    Write(IACReal2[i]:6:3);              {Display the IAC reals}
  Writeln;

  Write('Using pointer: ':20);
  FOR i := 1 TO 2 DO
    Write(iacRealPtr^[i]:6:3);           {Display the IAC reals}
  Writeln;

  FOR i := 1 TO 2 DO
    r2[i] := i /6.0;                     {Build a local array of reals}

  Write('New local reals: ':20);
  FOR i := 1 TO 2 DO
    Write(r2[i]:6:3);                    {Display the local reals}
  Writeln;

  IACReal2 := r2;                        {Move the array into the IAC}

  Write('Changed IAC reals: ':20);
  FOR i := 1 TO 2 DO
    Write(IACReal2[i]:6:3);              {Display the IAC reals}
  Writeln;


  IAC := saveIAC;                        {Restore the old IAC}

  {Play with the IAC as a Pascal string}

  Write('Old IAC as strng: ':20);
  Writeln('[', IACMsg, ']');             {Normally the IAC is empty (0's),
                                          so the first time we run this
                                          program, the string should be
                                          empty (that 0 length byte).
                                         }
  IACMsg := '123456789ABCDEF';           {Change the IAC to our message.
                                          15 chars, right?}
  Write('Changed IAC msg: ':20);
  Writeln('[', IACMsg, ']');             {Now let's display the IAC itself}

  Write('Using pointer: ':20);
  Writeln('[', IACStrPtr^,']');

  S := IACMsg;                           {Bring the IAC into a local string}
  Write('IAC to local strng: ':20);
  Writeln('[', S, ']');                  {Write the local string}

  S := 'HowNowBrownCow?......';          {New msg.  Sure, this string is longer
                                          than the IAC, but since we've typed
                                          the IAC as a 15-char string, Turbo
                                          will only copy 15 characters of THIS
                                          string to it!  No problem over-
                                          running the IAC boundaries and
                                          trashing DOS's data.
                                          }
  IACMsg := S;                           {Leave msg in IAC}
  Write('Local strng to IAC: ':20);
  Writeln('[', IACMsg, ']');             {Let's display the IAC again}

  {Now run this program again!  You'll see the message from last time!
   (Which is the whole idea, after all!
  }

END.
