-- file TableSymbols.mesa
-- last edited by Satterthwaite, November 2, 1982 10:37 am

DIRECTORY
BcdDefs: TYPE,
BcdOps: TYPE USING [BcdBase, MTHandle],
File: TYPE USING [Capability],
FileSegment: TYPE USING [Pages, nullPages],
OSMiscOps: TYPE USING [FindFile],
Space: TYPE USING [
Handle, nullHandle, virtualMemory, Create, LongPointer, Map, Delete],
Strings: TYPE USING [String, SubStringDescriptor, AppendString],
Symbols: TYPE,
SymbolTable: TYPE USING [Base, Handle, Acquire, Release],
Table: TYPE USING [Base],
TableCommand: TYPE;

TableSymbols: PROGRAM
IMPORTS OSMiscOps, Space, Strings, SymbolTable
EXPORTS TableCommand = {

-- public interface

BadInterface: PUBLIC ERROR [Strings.String] = CODE;

FindInterface: PUBLIC PROC [id, file: Strings.String] RETURNS [
 version: BcdDefs.VersionStamp ← BcdDefs.NullVersion,
 pages: FileSegment.Pages ← FileSegment.nullPages] = {
headerSpace: Space.Handle ← Space.nullHandle;

DeleteHeader: PROC = {
IF headerSpace # Space.nullHandle THEN {
 Space.Delete[headerSpace];
 headerSpace ← Space.nullHandle}};

bcd: BcdOps.BcdBase;
mtb: BcdOps.MTHandle;
sgb: Table.Base;
sSeg: BcdDefs.SGIndex;
s: STRING ← [40];
Strings.AppendString[s, IF file = NIL THEN id ELSE file];
FOR i: CARDINAL IN [0 .. s.length) DO
IF s[i] = '. THEN EXIT;
REPEAT
 FINISHED => Strings.AppendString[s, ".bcd"L];
ENDLOOP;

BEGIN
ENABLE {
 UNWIND => {NULL};
 ANY => {GO TO badFile}};
BcdBase: PROC [p: LONG POINTER] RETURNS [BcdDefs.Base] = INLINE {
 RETURN [LOOPHOLE[p, BcdDefs.Base]]};
file: File.Capability;
bcdPages: CARDINAL ← 8;
file ← OSMiscOps.FindFile[s, read];
DO
headerSpace ← Space.Create[size: bcdPages, parent: Space.virtualMemory];
 headerSpace.Map[window: [file: file, base: 1]];
 bcd ← headerSpace.LongPointer[];
 IF bcd.versionIdent # BcdDefs.VersionID THEN GO TO badFile;
 IF bcdPages >= bcd.nPages THEN EXIT;
 bcdPages ← bcd.nPages;
 Space.Delete[headerSpace]; headerSpace ← Space.nullHandle
 ENDLOOP;
IF bcd.nConfigs # 0 OR bcd.nModules # 1 THEN GO TO badFile;
mtb ← BcdBase[bcd + bcd.mtOffset];
sgb ← BcdBase[bcd + bcd.sgOffset]; sSeg ← mtb.sseg;
IF sSeg = BcdDefs.SGNull OR sgb[sSeg].pages = 0 OR sgb[sSeg].file # BcdDefs.FTSelf
 THEN GO TO badFile;
version ← bcd.version;
pages ← [file: file, span: [base: sgb[sSeg].base, pages: sgb[sSeg].pages]];
DeleteHeader[];
EXITS
 badFile => {DeleteHeader[]; ERROR BadInterface[s]};
END;

IF ~CheckId[pages, id] THEN ERROR BadInterface[id];
RETURN};

CheckId: PROC [symbols: SymbolTable.Handle, id: Strings.String]
RETURNS [found: BOOL] = {
base: SymbolTable.Base ← SymbolTable.Acquire[symbols];
BEGIN
OPEN Symbols, base;
ss: Strings.SubStringDescriptor ← [base:id, offset:0, length:id.length];
sei: ISEIndex = SearchContext[FindString[@ss], stHandle.directoryCtx];
found ← sei # ISENull AND seb[sei].public;
END;
SymbolTable.Release[base];
RETURN};


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

}.