-- File: FindDiskAddresses.mesa,  Last Edit: HGM  October 18, 1980  8:57 PM

DIRECTORY
  AltoFileDefs USING [vDA, eofDA, fillinDA],
  BFSDefs USING [ActOnPages, GetNextDA],
  ControlDefs USING [GlobalFrameHandle],
  DiskDefs USING [DiskRequest],
  FrameOps USING [CodeHandle, MyGlobalFrame],
  MiscDefs USING [SetBlock],
  SegmentDefs USING [
    DataSegmentHandle, FileSegmentHandle, FileHandle, EasyDown, SetFileSegmentDA,
    EnumerateFileSegments, MakeDataSegment, DefaultMDSBase, DeleteDataSegment,
    DataSegmentAddress],
  Storage USING [PagesForWords],
  TajoOps USING [];

-- For getting things started

FindDiskAddresses: PROGRAM
  IMPORTS BFSDefs, FrameOps, MiscDefs, SegmentDefs, Storage EXPORTS TajoOps =
  BEGIN

  -- This is just a hook to let Tajo call us.  The actual work is done by START traps.
  StartClient: PUBLIC PROCEDURE = BEGIN END;

  FindDiskAddresses: PROCEDURE =
    BEGIN
    myFrame: ControlDefs.GlobalFrameHandle ← FrameOps.MyGlobalFrame[];
    myCode: SegmentDefs.FileSegmentHandle ← FrameOps.CodeHandle[myFrame];
    CollectDiskAddresses[myCode.file];
    END;


  -- Copied from MakeImage

  CollectDiskAddresses: PROCEDURE [imageFile: SegmentDefs.FileHandle] =
    BEGIN OPEN Storage, SegmentDefs, AltoFileDefs;
    DAs: DESCRIPTOR FOR ARRAY OF vDA;
    maxunknown, maxknown: CARDINAL ← FIRST[CARDINAL];
    minunknown: CARDINAL ← LAST[CARDINAL];
    maxknownDA: vDA;
    diskrequest: DiskDefs.DiskRequest;
    bufseg, DAseg: DataSegmentHandle;
    FindEnds: PROCEDURE [seg: FileSegmentHandle] RETURNS [BOOLEAN] =
      BEGIN
      WITH s: seg SELECT FROM
	disk =>
	  IF s.file = imageFile AND s.hint.da = eofDA THEN
	    BEGIN
	    maxunknown ← MAX[maxunknown, s.base];
	    minunknown ← MIN[minunknown, s.base];
	    END;
	ENDCASE;
      RETURN[FALSE];
      END;
    FindKnown: PROCEDURE [seg: FileSegmentHandle] RETURNS [BOOLEAN] =
      BEGIN
      WITH s: seg SELECT FROM
	disk =>
	  IF s.file = imageFile AND s.hint.da # eofDA AND s.base < minunknown AND
	    s.base > maxknown THEN
	    BEGIN maxknown ← s.base; maxknownDA ← s.hint.da END;
	ENDCASE;
      RETURN[FALSE];
      END;
    PlugDA: PROCEDURE [seg: FileSegmentHandle] RETURNS [BOOLEAN] =
      BEGIN
      WITH s: seg SELECT FROM
	disk =>
	  IF s.file = imageFile AND s.hint.da = eofDA AND s.base IN
	    (maxknown..maxunknown] THEN
	    SegmentDefs.SetFileSegmentDA[@s, DAs[s.base]];
	ENDCASE;
      RETURN[FALSE];
      END;
    [] ← EnumerateFileSegments[FindEnds];
    [] ← EnumerateFileSegments[FindKnown];
    bufseg ← MakeDataSegment[DefaultMDSBase, 1, EasyDown];
    DAseg ← MakeDataSegment[
      DefaultMDSBase, PagesForWords[maxunknown - maxknown + 3], EasyDown];
    DAs ← DESCRIPTOR[DataSegmentAddress[DAseg] - (maxknown - 1), maxunknown + 2];
    diskrequest ← DiskDefs.DiskRequest[
      ca: DataSegmentAddress[bufseg], fixedCA: TRUE, da: @DAs[0],
      fp: @imageFile.fp, firstPage: maxknown, lastPage: maxunknown, action: ReadD,
      lastAction: ReadD, signalCheckError: FALSE,
      option: update[cleanup: BFSDefs.GetNextDA]];
    MiscDefs.SetBlock[@DAs[maxknown - 1], fillinDA, maxunknown - maxknown + 3];
    DAs[maxknown] ← maxknownDA;
    [] ← BFSDefs.ActOnPages[LOOPHOLE[@diskrequest]];
    -- we know it is an Update diskrequest
    [] ← EnumerateFileSegments[PlugDA];
    DeleteDataSegment[DAseg];
    DeleteDataSegment[bufseg];
    END;

  FindDiskAddresses[];
  END.