-- file TableSymbols.mesa
-- last edited by Satterthwaite, February 4, 1980  1:11 PM

DIRECTORY
  BcdDefs: FROM "bcddefs",
  SegmentDefs: FROM "segmentdefs",
  StringDefs: FROM "stringdefs" USING [SubStringDescriptor, AppendString],
  Symbols: FROM "symbols",
  SymbolTable: FROM "symboltable"
    USING [Base, Acquire, Release, TableForSegment],
  Table: FROM "table" USING [Base],
  TableCommand: FROM "tablecommand";

TableSymbols: PROGRAM
    IMPORTS SegmentDefs, StringDefs, SymbolTable
    EXPORTS TableCommand =
  BEGIN

 -- public interface

  BadInterface: PUBLIC ERROR [STRING] = CODE;

  FindInterface: PUBLIC PROCEDURE [id: STRING] RETURNS [
	version: BcdDefs.VersionStamp,
	symbolSeg: SegmentDefs.FileSegmentHandle] =
    BEGIN
    bcdPages: CARDINAL;
    headerSeg: SegmentDefs.FileSegmentHandle;

    DeleteHeader: PROCEDURE =
      BEGIN OPEN SegmentDefs;
      IF headerSeg # NIL
	THEN
	  BEGIN  Unlock[headerSeg];  DeleteFileSegment[headerSeg];
	  headerSeg ← NIL;
	  END;
      END;

    bcd: POINTER TO BcdDefs.BCD;
    mtRoot: POINTER TO BcdDefs.MTRecord;
    sgBase: Table.Base;
    sSeg: BcdDefs.SGIndex;
    s: STRING ← [40];
    StringDefs.AppendString[s, id];  StringDefs.AppendString[s, ".bcd."];
    symbolSeg ← headerSeg ← NIL;

      BEGIN  OPEN SegmentDefs;
      ENABLE
	BEGIN
	UNWIND => NULL;
	ANY => GO TO badFile
	END;
      bcdPages ← 1;
      headerSeg ← NewFileSegment[NewFile[s, Read, OldFileOnly], 1, bcdPages, Read];
	DO
	SwapIn[headerSeg];  bcd ← FileSegmentAddress[headerSeg];
	IF bcdPages = bcd.nPages THEN EXIT;
	bcdPages ← bcd.nPages;
	Unlock[headerSeg];  SwapOut[headerSeg];
	MoveFileSegment[headerSeg, 1, bcdPages];
	ENDLOOP;
      IF bcd.versionIdent # BcdDefs.VersionID
	OR bcd.nConfigs # 0 OR bcd.nModules # 1 THEN GO TO badFile;
      mtRoot ← LOOPHOLE[bcd + bcd.mtOffset];
      sgBase ← LOOPHOLE[bcd + bcd.sgOffset];  sSeg ← mtRoot.sseg;
      IF sSeg = BcdDefs.SGNull
       OR sgBase[sSeg].pages = 0 OR sgBase[sSeg].file # BcdDefs.FTSelf
	THEN GO TO badFile;
      version ← bcd.version;
      symbolSeg ← NewFileSegment[
			  headerSeg.file,
			  sgBase[sSeg].base, sgBase[sSeg].pages,
			  Read];
      symbolSeg.class ← other;
      DeleteHeader[];
      EXITS
	badFile =>
	  BEGIN  
	  IF headerSeg # NIL THEN  DeleteHeader[];
	  ERROR BadInterface[id];
	  END;
      END;

    RETURN
    END;

  FindItem: PUBLIC PROCEDURE [
	symbolSeg: SegmentDefs.FileSegmentHandle,
	item: STRING]
      RETURNS [size, entry: CARDINAL] =
    BEGIN
    base: SymbolTable.Base;
    base ← SymbolTable.Acquire[SymbolTable.TableForSegment[symbolSeg]];
      BEGIN
      OPEN Symbols, base;
      ss: StringDefs.SubStringDescriptor;
      hti: HTIndex;
      sei, itemSei: ISEIndex;
      ss ← [base:item, offset:0, length:item.length];
      hti ← FindString[@ss];
      IF hti = HTNull THEN GO TO fail;
      size ← 0;  itemSei ← ISENull;
      FOR sei ← FirstCtxSe[stHandle.outerCtx], NextSe[sei] UNTIL sei = SENull
	DO
	IF LinkMode[sei] # manifest THEN
	  BEGIN
	  size ← size + 1;
	  IF seb[sei].hash = hti THEN itemSei ← sei;
	  END;
	ENDLOOP;
      IF itemSei = ISENull THEN GO TO fail;
      entry ← seb[itemSei].idValue;
      EXITS
	fail => ERROR BadInterface[item];
      END;
    SymbolTable.Release[base];
    RETURN
    END;

  END.