<> <> <> 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 = { <> 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}; }.