DIRECTORY
BcdDefs: TYPE,
CommandUtil: TYPE USING [SetExtension],
ConvertUnsafe: TYPE USING [SubString],
FileSegment: TYPE USING [Pages, nullPages],
FS: TYPE USING [OpenFile, Read],
OSMiscOps: TYPE USING [FindFile],
Rope: TYPE USING [Flatten, Length, ROPE],
Symbols: TYPE,
SymbolTable: TYPE USING [Base, Handle, Acquire, Release],
Table: TYPE USING [Base],
TableCommand: TYPE,
VM: TYPE USING [Allocate, Free, Interval, nullInterval, PageNumberToAddress];
TableSymbols:
PROGRAM
IMPORTS CommandUtil, FS, OSMiscOps, Rope, SymbolTable, VM
EXPORTS TableCommand = {
public interface
BadInterface: PUBLIC ERROR [Rope.ROPE] = CODE;
FindInterface:
PUBLIC
PROC [id, file: Rope.
ROPE]
RETURNS [
version: BcdDefs.VersionStamp ← BcdDefs.NullVersion,
pages: FileSegment.Pages ← FileSegment.nullPages] = {
headerInterval: VM.Interval ← VM.nullInterval;
DeleteHeader:
PROC = {
IF headerInterval #
VM.nullInterval
THEN {
VM.Free[headerInterval];
headerInterval ← VM.nullInterval}};
bcd: BcdDefs.BcdBase;
mtb: BcdDefs.MTHandle;
sgb: Table.Base;
sSeg: BcdDefs.SGIndex;
s: Rope.
ROPE ← CommandUtil.SetExtension[
IF file =
NIL
THEN id
ELSE file, "bcd"];
BEGIN
ENABLE {
UNWIND => {NULL};
ANY => {GO TO badFile}};
BcdBase:
PROC [p:
LONG
POINTER]
RETURNS [BcdDefs.Base] =
INLINE {
RETURN [LOOPHOLE[p, BcdDefs.Base]]};
file: FS.OpenFile;
bcdPages: CARDINAL ← 8;
file ← OSMiscOps.FindFile[s, read];
DO
headerInterval ← VM.Allocate[bcdPages];
bcd ← VM.PageNumberToAddress[headerInterval.page];
FS.Read[file: file, fromPage: 0, pageCount: bcdPages, to: bcd];
IF bcd.versionIdent # BcdDefs.VersionID THEN GO TO badFile;
IF bcdPages >= bcd.nPages THEN EXIT;
bcdPages ← bcd.nPages;
VM.Free[headerInterval]; headerInterval ← VM.nullInterval
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: Rope.
ROPE]
RETURNS [found: BOOL] = {
base: SymbolTable.Base ← SymbolTable.Acquire[symbols];
BEGIN
OPEN Symbols, base;
ss: ConvertUnsafe.SubString;
sei: ISEIndex = SearchContext[FindString[ss], stHandle.directoryCtx];
ss.offset ← 0;
ss.length ← id.Length[];
ss.base ← LOOPHOLE[Rope.Flatten[id]];
found ← sei # ISENull AND seb[sei].public;
END;
SymbolTable.Release[base];
RETURN};
FindItem:
PUBLIC
PROC [symbols: SymbolTable.Handle, item: Rope.
ROPE]
RETURNS [size, entry: CARDINAL] = {
base: SymbolTable.Base ← SymbolTable.Acquire[symbols];
BEGIN
OPEN Symbols, base;
itemSei: ISEIndex ← ISENull;
ss: ConvertUnsafe.SubString;
hti: HTIndex = FindString[ss];
ss.offset ← 0;
ss.length ← item.Length[];
ss.base ← LOOPHOLE[Rope.Flatten[item]];
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};
}.