(* Execswap. works i guess *)

{$F-,A+,O+,G+,R-,S+,I+,Q-,V-,B-,X+,T-,P-,N-,E+}
unit Swapit;

interface


const
  UseEmsIfAvailable : Boolean = True;
  BytesSwapped : LongInt = 0;
  EmsAllocated : Boolean = False;
  FileAllocated : Boolean = False;

function ExecWithSwap(Path, CmdLine : String) : Word;
function InitExecSwap(LastToSave : Pointer; SwapFileName : String) : Boolean;
procedure ShutdownExecSwap;

implementation

var
  EmsHandle  : Word;
  FrameSeg   : Word;
  FileHandle : Word;
  SwapName   : String[80];
  SaveExit   : Pointer;

  {$L SWAP.OBJ}
  function ExecWithSwap(Path, CmdLine : String) : Word; external;
  procedure FirstToSave; external;
  function AllocateSwapFile : Boolean; external;
  procedure DeallocateSwapFile; external;

  {$F+}
  function EmsInstalled : Boolean; external;
  function EmsPageFrame : Word; external;
  function AllocateEmsPages(NumPages : Word) : Word; external;
  procedure DeallocateEmsHandle(Handle : Word); external;
  function DefaultDrive : Char; external;
  function DiskFree(Drive : Byte) : LongInt; external;

  procedure ExecSwapExit;
  begin
    ExitProc := SaveExit;
    ShutdownExecSwap;
  end;
  {$F-}

  procedure ShutdownExecSwap;
  begin
    if EmsAllocated then
        begin
        DeallocateEmsHandle(EmsHandle);
        EmsAllocated := False;
       end else if FileAllocated then
         begin
         DeallocateSwapFile;
         FileAllocated := False;
         end;
  end;

  function PtrDiff(H, L : Pointer) : LongInt;
  type
    OS = record O, S : Word; end;
  begin
    PtrDiff := (LongInt(OS(H).S) shl 4+OS(H).O)-
               (LongInt(OS(L).S) shl 4+OS(L).O);
  end;

  function InitExecSwap(LastToSave : Pointer;
                        SwapFileName : String) : Boolean;
  const
    EmsPageSize = 16384;
  var
    PagesInEms : Word;
    BytesFree : LongInt;
    DriveChar : Char;
  begin
    InitExecSwap := False;

    if EmsAllocated or FileAllocated then  Exit;
    BytesSwapped := PtrDiff(LastToSave, @FirstToSave);
    if BytesSwapped <= 0 then   Exit;

    if UseEmsIfAvailable and EmsInstalled then
      begin
      PagesInEms := (BytesSwapped+EmsPageSize-1) div EmsPageSize;
      EmsHandle := AllocateEmsPages(PagesInEms);
      if EmsHandle <> $FFFF then
              begin
              EmsAllocated := True;
              FrameSeg := EmsPageFrame;
              if FrameSeg <> 0 then
                 begin
                 InitExecSwap := True;
                 exit;
                 end;
              end;
      end;
    if Length(SwapFileName) <> 0 then
      begin
       SwapName := SwapFileName+#0;
       if Pos(':', SwapFileName) = 2 then DriveChar := Upcase(SwapFileName[1])
       else DriveChar := DefaultDrive;
       BytesFree := DiskFree(Byte(DriveChar)-$40);
       FileAllocated := (BytesFree > BytesSwapped) and AllocateSwapFile;
       if FileAllocated then  InitExecSwap := True;
      end;
  end;

begin
  SaveExit := ExitProc;
  ExitProc := @ExecSwapExit;
end.
