-- FileTableImpl.Mesa  
--  Last edited by Lewis on  3-Jan-81 16:04:40
--  Last edited by Sweet on  6-Feb-81 14:56:24

DIRECTORY
  BcdDefs USING [FTIndex, FTRecord, FTSelf, NameRecord],
  FileTable,
  PackagerDefs USING [globalData, NullSourceIndex],
  PackEnviron USING [SetBlock],
  PackHeap USING [GetSpace, FreeSpace],
  Segments USING [
    FHandle, LockFile, NewFile, Read,
    ReleasableFile, ReleaseFile, UnlockFile],
  SourceBcd USING [bcdBases, bcdLimits, SubStringForName],
  Strings USING [AppendString, AppendSubString, SubString, SubStringDescriptor],
  SymTabDefs USING [HTIndex],
  SymTabOps USING [EnterString];

FileTableImpl: PROGRAM
    IMPORTS PackagerDefs, PackEnviron, PackHeap, Segments, SourceBcd, Strings,
      SymTabOps
    EXPORTS FileTable =
  BEGIN

  FTIndex: TYPE = BcdDefs.FTIndex;
  SubStringDescriptor: TYPE = Strings.SubStringDescriptor;
  SubString: TYPE = Strings.SubString;

  UnknownFile: PUBLIC ERROR [fti: FTIndex] = CODE;

  fileArray: LONG DESCRIPTOR FOR ARRAY OF Segments.FHandle;
  numFiles: CARDINAL; 


  Build: PUBLIC PROC =
    BEGIN OPEN BcdDefs;
    fileNameString: STRING ← [50];
    fti: FTIndex;
    ftiNameDesc: SubStringDescriptor;
    ftiName: SubString ← @ftiNameDesc;
    saveIndex: CARDINAL = PackagerDefs.globalData.textIndex;
    i: CARDINAL;
    PackagerDefs.globalData.textIndex ← PackagerDefs.NullSourceIndex;
    -- allocate file handle array
    numFiles ← IndexForFti[SourceBcd.bcdLimits.ft];
    fileArray ← DESCRIPTOR[PackHeap.GetSpace[numFiles], numFiles];
    PackEnviron.SetBlock[BASE[fileArray], NIL, numFiles];
    -- enter file names into symtab (if not already there) to speed file lookup
    i ← 0;
    FOR fti ← FIRST[FTIndex], fti+SIZE[FTRecord] 
      UNTIL fti = SourceBcd.bcdLimits.ft DO
      SourceBcd.SubStringForName[ftiName, SourceBcd.bcdBases.ftb[fti].name];
      [] ← SymTabOps.EnterString[ftiName];
      fileNameString.length ← 0;
      Strings.AppendSubString[fileNameString, ftiName];
      FOR j: CARDINAL IN [0..fileNameString.length) DO
        IF fileNameString[j] = '. THEN EXIT;
	REPEAT
	  FINISHED => Strings.AppendString[fileNameString, ".bcd"L];
	ENDLOOP;
      fileArray[i] ← Segments.NewFile[fileNameString, Segments.Read ! ANY => CONTINUE];
      IF fileArray[i] # NIL THEN Segments.LockFile[fileArray[i]];
      i ← i + 1;
      ENDLOOP;
    PackagerDefs.globalData.textIndex ← saveIndex;
    END;

  IndexForFti: PROC [fti: FTIndex] RETURNS [CARDINAL] = INLINE
    {RETURN[ LOOPHOLE[fti, CARDINAL] / SIZE[BcdDefs.FTRecord] ]};

  Destroy: PUBLIC PROC =
    BEGIN
    f: Segments.FHandle;
    FOR i: CARDINAL IN [0..numFiles) DO
      IF (f ← fileArray[i]) # NIL THEN
        BEGIN
        Segments.UnlockFile[f];  
        IF Segments.ReleasableFile[f] THEN Segments.ReleaseFile[f];
        END;
      ENDLOOP;
    PackHeap.FreeSpace[BASE[fileArray]];
    numFiles ← 0;
    END;


  HandleForFile: PUBLIC PROC [fti: FTIndex] RETURNS [file: Segments.FHandle] =
    BEGIN
    index: CARDINAL;
    IF fti = BcdDefs.FTSelf THEN
      RETURN [PackagerDefs.globalData.sourceBcdFile];
    index ← IndexForFti[fti];
    IF index >= numFiles OR fileArray[index] = NIL THEN
      ERROR UnknownFile[fti];
    RETURN[fileArray[index]];
    END;

  END.