<> <> <> <> DIRECTORY AMFiles USING [FullFileNameList, OpenIt], AMTypes USING [Error], BasicTime USING [GMT], BcdDefs USING [BcdBase, FTHandle, FTIndex, FTNull, FTSelf, MTHandle, MTIndex, NameRecord, NameString, NullVersion, SGHandle, SGIndex, SGNull, VersionID, VersionStamp], BcdOps USING [ProcessModules, ProcessFiles], BrandXSymbolDefs USING [nullSymbolIndex, rootBodyIndex, SymbolModuleIndex, SymbolTableBase], BrandYSymbolDefs USING [rootBodyIndex, nullSymbolIndex, SymbolTableBase, SymbolModuleIndex], ConvertUnsafe USING [SubString, SubStringToRope], FileSegment USING [Pages], FS USING [Close, Error, nullOpenFile, Open, OpenFile, Read], LoadState USING [Acquire, ConfigID, ConfigInfo, GlobalFrameToModule, local, ModuleIndex, Release], PrincOps USING [GlobalFrameHandle], RCMapOps USING [EstablishOuter], Rope USING [Concat, Equal, Find, Index, ROPE, SkipTo, Substr], RTSymbolDefs USING [nullBase, nullHandle, SymbolModuleIndex, SymbolTableBase, SymbolTableHandle], RTSymbolOps USING [NullModuleIndex, NullSth, STBToModuleName, STBVersion, SubStringForName], RTSymbols USING [], RTSymbolsPrivate USING [], RTTypesBasicPrivate USING [FindSTI, MapStiStd, STDesc, SymbolTableIndex], RuntimeError USING [UNCAUGHT], SymbolTable USING [Acquire, BaseToHandle, Release, SetCacheSize], Table USING [Base], VersionMap USING [MapList, MapAndNameList, ShortNameToNames], VersionMapDefaults USING [FileNameFromVersion, GetMapList], VM USING [AddressForPageNumber, Allocate, Free, Interval, PageNumberForAddress]; RTGetSymbolsImpl: MONITOR IMPORTS AMFiles, AMTypes, BcdOps, FS, ConvertUnsafe, LoadState, RCMapOps, Rope, RTSymbolOps, RTTypesBasicPrivate, RuntimeError, SymbolTable, VersionMap, VersionMapDefaults, VM EXPORTS RTSymbols, RTSymbolsPrivate SHARES Rope = { OPEN bx: BrandXSymbolDefs, by: BrandYSymbolDefs, XSymbolTable: SymbolTable, YSymbolTable: SymbolTable, XRCMapOps: RCMapOps, YRCMapOps: RCMapOps, PrincOps, RTSymbolDefs, RTSymbolOps, RuntimeError; <> onePageSpace: VM.Interval = VM.Allocate[1]; ROPE: TYPE = Rope.ROPE; <> OuterFromSTH: PUBLIC PROC [sth: SymbolTableHandle, inner: PROC [stb: SymbolTableBase] ] = { <> stb: SymbolTableBase _ AcquireSTB[sth]; inner[stb ! UNWIND => ReleaseSTB[stb] ]; ReleaseSTB[stb]; }; AcquireSTB: PUBLIC PROC [sth: SymbolTableHandle] RETURNS [stb: SymbolTableBase] = { stb _ WITH sth SELECT FROM t: SymbolTableHandle.x => [x[XSymbolTable.Acquire[t.e]]], t: SymbolTableHandle.y => [y[YSymbolTable.Acquire[t.e]]] ENDCASE => ERROR; WITH stb SELECT FROM t: SymbolTableBase.x => { IF NOT t.e.stHandle.extended THEN GO TO foo; IF t.e.bb[bx.rootBodyIndex].type = bx.nullSymbolIndex THEN GO TO foo; }; t: SymbolTableBase.y => { IF NOT t.e.stHandle.extended THEN GO TO foo; IF t.e.bb[by.rootBodyIndex].type = by.nullSymbolIndex THEN GO TO foo; }; ENDCASE => GO TO foo; RETURN[stb]; EXITS foo => { modName: ROPE = STBToModuleName[stb ! UNWIND => ReleaseSTB[stb]]; ReleaseSTB[stb]; ERROR AMTypes.Error[reason: noSymbols, msg: modName]; }; }; ReleaseSTB: PUBLIC PROC [stb: SymbolTableBase] = { WITH stb SELECT FROM t: SymbolTableBase.x => XSymbolTable.Release[t.e]; t: SymbolTableBase.y => YSymbolTable.Release[t.e] ENDCASE => ERROR; }; BaseToHandle: PUBLIC PROC [stb: SymbolTableBase] RETURNS [SymbolTableHandle] = { RETURN[WITH stb SELECT FROM t: SymbolTableBase.x => [x[XSymbolTable.BaseToHandle[t.e]]], t: SymbolTableBase.y => [y[YSymbolTable.BaseToHandle[t.e]]], ENDCASE => ERROR]; }; STPages: PUBLIC PROC [sth: SymbolTableHandle] RETURNS [CARDINAL] = { RETURN[WITH sth SELECT FROM t: SymbolTableHandle.x => t.e.span.pages, t: SymbolTableHandle.y => t.e.span.pages, ENDCASE => ERROR]; }; AcquireSTHFromSTX: PUBLIC PROC [stx: RTTypesBasicPrivate.SymbolTableIndex] RETURNS [sth: SymbolTableHandle _ nullHandle, moduleName: ROPE _ NIL] = { <> [sth, moduleName] _ DoAcquireSTHFromSTX[stx, TRUE]; }; DoAcquireSTHFromSTX: PROC [stx: RTTypesBasicPrivate.SymbolTableIndex, invokeGetSTHForModule: BOOL _ FALSE] RETURNS [sth: SymbolTableHandle _ nullHandle, moduleName: ROPE _ NIL] = { symbolsStamp: BcdDefs.VersionStamp; bcd: BcdDefs.BcdBase; IF NOT NullSth[RTTypesBasicPrivate.MapStiStd[stx].sth] THEN RETURN[sth: RTTypesBasicPrivate.MapStiStd[stx].sth]; symbolsStamp _ RTTypesBasicPrivate.MapStiStd[stx].symbolsStamp; bcd _ RTTypesBasicPrivate.MapStiStd[stx].bcd; IF bcd = NIL THEN { IF NOT invokeGetSTHForModule THEN RETURN; sth _ GetSTHForModule[stamp: symbolsStamp, fileName: NIL, moduleName: NIL ! UNCAUGHT => CONTINUE]; } ELSE { sgb: Table.Base = LOOPHOLE[bcd + bcd.sgOffset]; ftb: Table.Base = LOOPHOLE[bcd + bcd.ftOffset]; ssb: BcdDefs.NameString = LOOPHOLE[bcd + bcd.ssOffset]; fti: BcdDefs.FTIndex; sgi: BcdDefs.SGIndex = RTTypesBasicPrivate.MapStiStd[stx].sgi; IF sgi = BcdDefs.SGNull -- search the BCD's file table (find a DEFs) THEN { <> findSymbolFTI: PROC [ffth: BcdDefs.FTHandle, ffti: BcdDefs.FTIndex] RETURNS [stop: BOOL] = { IF NOT EQStamps[ffth.version, symbolsStamp] THEN GO TO nope; moduleName _ GetModuleName[ssb, ffth.name]; sth _ GetSTHForModule[stamp: symbolsStamp, fileName: Rope.Concat[moduleName, ".bcd"], moduleName: moduleName ! AMTypes.Error => GO TO nope]; RETURN[TRUE]; EXITS nope => RETURN [FALSE]; }; IF NOT invokeGetSTHForModule THEN RETURN; [] _ BcdOps.ProcessFiles[bcd, findSymbolFTI]; IF NullSth[sth] THEN sth _ GetSTHForModule[stamp: symbolsStamp, fileName: NIL, moduleName: moduleName ! UNCAUGHT => CONTINUE]; RTTypesBasicPrivate.MapStiStd[stx].sth _ sth; RETURN; } ELSE fti _ sgb[sgi].file; IF fti = BcdDefs.FTSelf THEN { file: FS.OpenFile = FileFromBcdBase[bcd]; moduleName _ GetModuleName[ssb, bcd.source]; IF file # FS.nullOpenFile THEN { p: FileSegment.Pages = [file: file, span: [base: sgb[sgi].base - 1, pages: sgb[sgi].pages + sgb[sgi].extraPages]]; sth _ IF IsXBCD[bcd] THEN [x[p]] ELSE [y[p]]; }; } ELSE { <> fileName: ROPE = GetFileName[ssb, ftb[fti].name]; moduleName _ GetModuleName[ssb, ftb[fti].name]; sth _ NewSymbolHandle[fileName: fileName, version: ftb[fti].version, base: sgb[sgi].base - 1, pages: sgb[sgi].pages + sgb[sgi].extraPages ! AMTypes.Error => CONTINUE] }; }; RTTypesBasicPrivate.MapStiStd[stx].sth _ sth; }; <> NewSymbolHandle: PUBLIC PROC [fileName: ROPE, base: CARDINAL, pages: CARDINAL, version: BcdDefs.VersionStamp _ BcdDefs.NullVersion] RETURNS [sth: SymbolTableHandle _ nullHandle] = { file: FS.OpenFile _ FS.nullOpenFile; stb: SymbolTableBase; symbolsStamp: BcdDefs.VersionStamp; isXBCD: BOOL = TRUE; -- NOTE XXX IF EQStamps[version, BcdDefs.NullVersion] THEN file _ AMFiles.OpenIt[fileName].openFile ELSE file _ AcquireFCFromVersion[version, fileName]; IF file = FS.nullOpenFile THEN ERROR AMTypes.Error[reason: noSymbols, msg: fileName]; <> sth _ IF isXBCD THEN [x[[file: file, span: [base: base, pages: pages]]]] ELSE [y[[file: file, span: [base: base, pages: pages]]]]; stb _ AcquireSTB[sth]; symbolsStamp _ STBVersion[stb]; ReleaseSTB[stb]; [] _ RTTypesBasicPrivate.FindSTI[[symbolsStamp: symbolsStamp, sth: sth]]; }; RCMapOuterX: PROC [stb: bx.SymbolTableBase, mdi: bx.SymbolModuleIndex, inner: PROC [base: bx.SymbolTableBase]] = { stb1: SymbolTableBase = AcquireSTBFromMDI[[x[stb]], [x[mdi]]]; inner[NARROW[stb1, SymbolTableBase.x].e ! UNWIND => ReleaseSTB[stb1]]; ReleaseSTB[stb1]; }; RCMapOuterY: PROC [stb: by.SymbolTableBase, mdi: by.SymbolModuleIndex, inner: PROC [base: by.SymbolTableBase]] = { stb1: SymbolTableBase = AcquireSTBFromMDI[[y[stb]], [y[mdi]]]; inner[NARROW[stb1, SymbolTableBase.y].e ! UNWIND => ReleaseSTB[stb1]]; ReleaseSTB[stb1]; }; OuterFromMDI: PUBLIC PROC [stb: SymbolTableBase, mdi: SymbolModuleIndex, inner: PROC [base: SymbolTableBase]] = { stb1: SymbolTableBase = AcquireSTBFromMDI[stb, mdi]; inner[stb1 ! UNWIND => ReleaseSTB[stb1]]; ReleaseSTB[stb1]; }; AcquireSTBFromMDI: PUBLIC PROC [stb: SymbolTableBase, mdi: SymbolModuleIndex] RETURNS [SymbolTableBase] = { fileNameDesc, modNameDesc: ConvertUnsafe.SubString; fileName: ROPE; modName: ROPE; IF NullModuleIndex[mdi] THEN ERROR; modNameDesc _ SubStringForName[ stb, WITH stb SELECT FROM t: SymbolTableBase.x => [x[t.e.mdb[NARROW[mdi, SymbolModuleIndex.x].e].moduleId]], t: SymbolTableBase.y => [y[t.e.mdb[NARROW[mdi, SymbolModuleIndex.y].e].moduleId]], ENDCASE => ERROR]; modName _ ConvertUnsafe.SubStringToRope[modNameDesc]; fileNameDesc _ SubStringForName[stb, WITH stb SELECT FROM t: SymbolTableBase.x => [x[t.e.mdb[NARROW[mdi, SymbolModuleIndex.x].e].fileId]], t: SymbolTableBase.y => [y[t.e.mdb[NARROW[mdi, SymbolModuleIndex.y].e].fileId]], ENDCASE => ERROR]; fileName _ ConvertUnsafe.SubStringToRope[fileNameDesc]; RETURN[ AcquireSTB[ GetSTHForModule[ (WITH stb SELECT FROM t: SymbolTableBase.x => t.e.mdb[NARROW[mdi, SymbolModuleIndex.x].e].stamp, t: SymbolTableBase.y => t.e.mdb[NARROW[mdi, SymbolModuleIndex.y].e].stamp, ENDCASE => ERROR), fileName, modName ] ] ]; }; GetSTHForModule: PUBLIC PROC [stamp: BcdDefs.VersionStamp, fileName: ROPE, moduleName: ROPE] RETURNS [sth: SymbolTableHandle _ nullHandle] = { <> bcd: BcdDefs.BcdBase; newFile: FS.OpenFile _ FS.nullOpenFile; sgb: Table.Base; ftb: Table.Base; ntb: BcdDefs.NameString; versionMapTried: BOOL _ FALSE; mth: BcdDefs.MTHandle; sSeg: BcdDefs.SGIndex; someNameMatched: BOOL _ FALSE; FindVersionStampedModule: PROC [mth: BcdDefs.MTHandle, mti: BcdDefs.MTIndex] RETURNS [stop: BOOL] = { umid: BcdDefs.VersionStamp = (IF mth.file = BcdDefs.FTSelf THEN bcd.version ELSE ftb[mth.file].version); namesMatch: BOOL _ TRUE; IF moduleName # NIL THEN { thisMN: ROPE = GetModuleName[ntb, mth.name]; namesMatch _ Rope.Equal[moduleName, thisMN]; someNameMatched _ someNameMatched OR namesMatch; }; RETURN[namesMatch AND (EQStamps[stamp, BcdDefs.NullVersion] OR EQStamps[stamp, umid])]; }; IF NOT EQStamps[stamp, BcdDefs.NullVersion] THEN { <> found: BOOL; stx: RTTypesBasicPrivate.SymbolTableIndex; [stx, found] _ FindSTX[stamp]; IF found THEN sth _ DoAcquireSTHFromSTX[stx].sth; IF NOT NullSth[sth] THEN RETURN[sth]; }; IF fileName = NIL AND moduleName # NIL THEN fileName _ Rope.Concat[moduleName, ".bcd"]; IF fileName # NIL THEN <> newFile _ AMFiles.OpenIt[fileName].openFile; DO IF newFile = FS.nullOpenFile THEN { <> IF EQStamps[stamp, BcdDefs.NullVersion] THEN GOTO noFile ELSE { <> fn: ROPE = IF moduleName = NIL THEN NIL ELSE Rope.Concat[moduleName, ".bcd"]; newFile _ VersionToReadableFile[versionStamp: stamp, shortNameHint: fn]; versionMapTried _ TRUE; IF newFile = FS.nullOpenFile THEN GOTO noFile; }; }; <> bcd _ AcquireBCDFromCap[newFile]; sgb _ LOOPHOLE[bcd + bcd.sgOffset]; ftb _ LOOPHOLE[bcd + bcd.ftOffset]; ntb _ LOOPHOLE[bcd + bcd.ssOffset]; IF bcd.versionIdent # BcdDefs.VersionID THEN { IF versionMapTried THEN GOTO oldSymbols ELSE {newFile _ FS.nullOpenFile; LOOP}; }; someNameMatched _ FALSE; mth _ BcdOps.ProcessModules[bcd, FindVersionStampedModule].mth; IF mth = NIL THEN { IF NOT versionMapTried THEN {newFile _ FS.nullOpenFile; LOOP}; IF someNameMatched THEN GOTO wrongVersion ELSE GOTO noSymbols; }; sSeg _ mth.sseg; IF sSeg = BcdDefs.SGNull OR sgb[sSeg].pages = 0 OR ((NOT bcd.definitions) AND (sgb[sSeg].extraPages = 0)) -- compressed symbols OR sgb[sSeg].file # BcdDefs.FTSelf THEN { IF versionMapTried THEN GOTO noSymbols ELSE {newFile _ FS.nullOpenFile; LOOP}; }; { p: FileSegment.Pages = [file: newFile, span: [base: sgb[sSeg].base - 1, pages: sgb[sSeg].pages + sgb[sSeg].extraPages] ]; sth _ IF IsXBCD[bcd] THEN [x[p]] ELSE [y[p]]; }; IF EQStamps[stamp, BcdDefs.NullVersion] THEN { stb: SymbolTableBase = AcquireSTB[sth]; stamp _ STBVersion[stb]; ReleaseSTB[stb]; }; [] _ RTTypesBasicPrivate.FindSTI[[symbolsStamp: stamp, sth: sth]]; ReleaseBCD[bcd]; RETURN[sth]; ENDLOOP; EXITS noFile => ERROR AMTypes.Error[reason: noSymbols, msg: fileName]; oldSymbols => ERROR AMTypes.Error[reason: noSymbols, msg: moduleName]; noSymbols => ERROR AMTypes.Error[reason: noSymbols, msg: IF moduleName = NIL THEN fileName ELSE moduleName]; wrongVersion => ERROR AMTypes.Error[reason: noSymbols, msg: moduleName]; }; OuterFromGFH: PUBLIC PROC [gfh: GlobalFrameHandle, inner: PROC [stb: SymbolTableBase] ] = { <> stb: SymbolTableBase _ AcquireSTBFromGFH[gfh]; inner[stb ! UNWIND => ReleaseSTB[stb] ]; ReleaseSTB[stb]; }; AcquireSTBFromGFH: PUBLIC PROC [gfh: GlobalFrameHandle] RETURNS [stb: SymbolTableBase _ nullBase] = { <> bcd: BcdDefs.BcdBase; bcdns: BcdDefs.NameString; moduleName: ROPE; mth: BcdDefs.MTHandle; config: LoadState.ConfigID; moduleIndex: LoadState.ModuleIndex; umid: BcdDefs.VersionStamp; -- functional version stamp of the module ftb: Table.Base; sth: SymbolTableHandle _ nullHandle; FindModule: PROC [mth: BcdDefs.MTHandle, mti: BcdDefs.MTIndex] RETURNS [BOOL] = { RETURN[(mth.gfi <= moduleIndex) AND (moduleIndex < (mth.gfi + mth.ngfi))]; }; LoadState.local.Acquire[]; [config, moduleIndex] _ LoadState.local.GlobalFrameToModule[gfh]; bcd _ LoadState.local.ConfigInfo[config].bcd; LoadState.local.Release[]; bcdns _ LOOPHOLE[bcd + bcd.ssOffset]; ftb _ LOOPHOLE[bcd + bcd.ftOffset]; [mth,] _ BcdOps.ProcessModules[bcd, FindModule]; IF mth = NIL THEN ERROR; umid _ (IF mth.file = BcdDefs.FTSelf THEN bcd.version ELSE ftb[mth.file].version); { < sth map>> found: BOOL; stx: RTTypesBasicPrivate.SymbolTableIndex; [stx, found] _ FindSTX[umid]; IF found THEN sth _ AcquireSTHFromSTX[stx].sth}; IF NullSth[sth] THEN <> sth _ AcquireSTHFromSGI[bcd, mth.sseg]; IF NullSth[sth] THEN { <> n: BcdDefs.NameRecord = IF mth.file = BcdDefs.FTSelf THEN mth.name ELSE ftb[mth.file].name; sth _ GetSTHForModule[ stamp: umid, fileName: GetFileName[ssb: bcdns, n: n], moduleName: GetModuleName[ssb: bcdns, n: mth.name] ! UNCAUGHT => CONTINUE ]; }; IF NullSth[sth] THEN <> [sth: sth, moduleName: moduleName] _ AcquireSTHFromSTX[RTTypesBasicPrivate.FindSTI[[symbolsStamp: umid, bcd: bcd]]]; IF NullSth[sth] THEN { <> sgb: Table.Base = LOOPHOLE[bcd + bcd.sgOffset]; IF moduleName = NIL THEN { n: BcdDefs.NameRecord = IF sgb[mth.sseg].file = BcdDefs.FTSelf THEN mth.name ELSE ftb[sgb[mth.sseg].file].name; moduleName _ GetFileName[ssb: bcdns, n: n]; }; ERROR AMTypes.Error[reason: noSymbols, msg: moduleName]; }; stb _ AcquireSTB[sth]; RETURN[stb]; }; OuterFromSGI: PUBLIC PROC [bcd: BcdDefs.BcdBase, sgi: BcdDefs.SGIndex, inner: PROC [base: SymbolTableBase]] = { <> stb: SymbolTableBase _ AcquireSTBFromSGI[bcd, sgi]; inner[stb ! UNWIND => ReleaseSTB[stb] ]; ReleaseSTB[stb]; }; <<>> AcquireSTBFromSGI: PUBLIC PROC [bcd: BcdDefs.BcdBase, sgi: BcdDefs.SGIndex] RETURNS [stb: SymbolTableBase _ nullBase] = { <> ftb: Table.Base = LOOPHOLE[bcd + bcd.ftOffset]; sgh: BcdDefs.SGHandle = @LOOPHOLE[bcd + bcd.sgOffset, Table.Base][sgi]; sth: SymbolTableHandle _ AcquireSTHFromSGI[bcd, sgi]; -- try for the referenced one IF NullSth[sth] THEN { ssb: BcdDefs.NameString = LOOPHOLE[bcd + bcd.ssOffset]; msg: ROPE = IF sgh.file = BcdDefs.FTSelf THEN GetFileName[ssb: ssb, n: bcd.source] ELSE GetFileName[ssb: ssb, n: ftb[sgh.file].name]; ERROR AMTypes.Error[reason: noSymbols, msg: msg]; }; RETURN[AcquireSTB[sth]]; }; <> EQStamps: PROC [s1, s2: BcdDefs.VersionStamp] RETURNS [BOOL] = INLINE { RETURN[s1.net = s2.net AND s1.host = s2.host AND s1.time = s2.time]; }; FindSTX: PROC [stamp: BcdDefs.VersionStamp] RETURNS [stx: RTTypesBasicPrivate.SymbolTableIndex, found: BOOL] = { FOR stx IN [1..RTTypesBasicPrivate.MapStiStd.length) DO IF RTTypesBasicPrivate.MapStiStd[stx] = NIL THEN EXIT; IF EQStamps[stamp, RTTypesBasicPrivate.MapStiStd[stx].symbolsStamp] THEN RETURN[stx, TRUE]; ENDLOOP; RETURN[0, FALSE]; }; AcquireSTHFromSGI: PROC [bcd: BcdDefs.BcdBase, sgi: BcdDefs.SGIndex] RETURNS [sth: SymbolTableHandle _ nullHandle] = { <> sgb: Table.Base = LOOPHOLE[bcd + bcd.sgOffset]; ftb: Table.Base = LOOPHOLE[bcd + bcd.ftOffset]; ssb: BcdDefs.NameString = LOOPHOLE[bcd + bcd.ssOffset]; sgh: BcdDefs.SGHandle _ @sgb[sgi]; IF sgh.class # symbols THEN ERROR; IF (sgh.pages = 0) -- empty symbol segment OR ((NOT bcd.definitions) AND (sgh.extraPages = 0)) -- compressed symbols OR sgh.file = BcdDefs.FTNull THEN RETURN; IF sgh.file = BcdDefs.FTSelf THEN { stb: SymbolTableBase; symbolsStamp: BcdDefs.VersionStamp; file: FS.OpenFile = FileFromBcdBase[bcd]; IF file = FS.nullOpenFile THEN RETURN; { p: FileSegment.Pages = [file: file, span: [base: sgh.base-1, pages: sgh.pages+sgh.extraPages]]; sth _ IF IsXBCD[bcd] THEN [x[p]] ELSE [y[p]]; }; stb _ AcquireSTB[sth]; symbolsStamp _ STBVersion[stb]; ReleaseSTB[stb]; [] _ RTTypesBasicPrivate.FindSTI[[symbolsStamp: symbolsStamp, sth: sth]]; } ELSE { fileName: ROPE _ GetFileName[ssb, ftb[sgh.file].name]; sth _ NewSymbolHandle[fileName: fileName, base: sgh.base - 1, pages: sgh.pages+sgh.extraPages, version: ftb[sgh.file].version ! UNCAUGHT => CONTINUE]; }; }; GetModuleName: PROC [ssb: BcdDefs.NameString, n: BcdDefs.NameRecord] RETURNS [name: ROPE _ NIL] = { ssd: ConvertUnsafe.SubString = [base: @ssb.string, offset: n, length: ssb.size[n]]; name _ ConvertUnsafe.SubStringToRope[ssd]; name _ name.Substr[start: 0, len: name.Index[pos1: 0, s2: "."]] }; GetFileName: PROC [ssb: BcdDefs.NameString, n: BcdDefs.NameRecord] RETURNS [name: ROPE _ NIL] = { ssd: ConvertUnsafe.SubString = [base: @ssb.string, offset: n, length: ssb.size[n]]; name _ ConvertUnsafe.SubStringToRope[ssd]; IF Rope.Find[name, "."] = -1 THEN name _ Rope.Concat[name, ".bcd"]; }; FileFromBcdBase: PROC [bcd: BcdDefs.BcdBase] RETURNS [fc: FS.OpenFile _ FS.nullOpenFile] = { ssb: BcdDefs.NameString = LOOPHOLE[bcd + bcd.ssOffset]; fc _ AcquireFCFromVersion[ versionStamp: bcd.version, shortFileNameHint: Rope.Concat[GetModuleName[ssb, bcd.source], ".bcd"] ]; }; AcquireFCFromVersion: PROC [ versionStamp: BcdDefs.VersionStamp, shortFileNameHint: ROPE _ NIL] RETURNS [file: FS.OpenFile _ FS.nullOpenFile] = { <> fileNameList: LIST OF ROPE; IF shortFileNameHint # NIL THEN fileNameList _ AMFiles.FullFileNameList[shortFileNameHint]; IF fileNameList # NIL THEN { FOR fileNames: LIST OF ROPE _ fileNameList, fileNames.rest UNTIL fileNames = NIL DO file _ FS.Open[fileNames.first ! FS.Error => {file _ FS.nullOpenFile; CONTINUE}]; IF file # FS.nullOpenFile THEN { IF EQStamps[GetBCDVersionInfo[file].fileVersionStamp, versionStamp] THEN RETURN[file]; FS.Close[file]; file _ FS.nullOpenFile; }; ENDLOOP; }; file _ VersionToReadableFile[versionStamp, shortFileNameHint]; }; AcquireBCDFromVersion: PUBLIC PROC [versionStamp: BcdDefs.VersionStamp, shortFileNameHint: ROPE _ NIL] RETURNS [bcd: BcdDefs.BcdBase _ NIL] = { <> file: FS.OpenFile _ AcquireFCFromVersion[versionStamp, shortFileNameHint]; IF file # FS.nullOpenFile THEN bcd _ AcquireBCDFromCap[file]; }; AcquireBCDFromCap: ENTRY PROC [file: FS.OpenFile] RETURNS [bcd: BcdDefs.BcdBase] = { ENABLE UNWIND => NULL; size: NAT; -- pages bcd _ LOOPHOLE[VM.AddressForPageNumber[onePageSpace.page]]; FS.Read[file: file, from: 0, nPages: 1, to: bcd]; IF bcd.extended THEN size _ MAX[1, bcd.nPages - bcd.rtPages.pages] ELSE size _ bcd.nPages; bcd _ LOOPHOLE[VM.AddressForPageNumber[VM.Allocate[size].page]]; FS.Read[file: file, from: 0, nPages: size, to: bcd]; }; IsXBCD: PROC [bcd: BcdDefs.BcdBase--only the first page!!--] RETURNS [BOOL] = { <> RETURN[TRUE]; }; ReleaseBCD: PUBLIC ENTRY PROC [bcd: BcdDefs.BcdBase] = { ENABLE UNWIND => NULL; count: INT _ MAX[1, IF bcd.extended THEN bcd.nPages - bcd.rtPages.pages ELSE bcd.nPages]; VM.Free[[page: VM.PageNumberForAddress[bcd], count: count]]; }; GetBCDVersionInfo: ENTRY PROC [file: FS.OpenFile] RETURNS [fileVersionIdent: CARDINAL, fileVersionStamp: BcdDefs.VersionStamp, isXBCD: BOOL] = { ENABLE UNWIND => NULL; bcd: BcdDefs.BcdBase = LOOPHOLE[VM.AddressForPageNumber[onePageSpace.page]]; FS.Read[file: file, from: 0, nPages: 1, to: bcd]; fileVersionIdent _ bcd.versionIdent; fileVersionStamp _ bcd.version; isXBCD _ IsXBCD[bcd]; }; VersionToReadableFile: PUBLIC PROC [versionStamp: BcdDefs.VersionStamp, shortNameHint: ROPE _ NIL] RETURNS [file: FS.OpenFile _ FS.nullOpenFile] = { mn: ROPE _ NIL; created: BasicTime.GMT; IF shortNameHint # NIL THEN { fileNameList: LIST OF ROPE; IF shortNameHint # NIL THEN fileNameList _ AMFiles.FullFileNameList[shortNameHint]; IF fileNameList # NIL THEN { FOR names: LIST OF ROPE _ fileNameList, names.rest UNTIL names = NIL DO file _ FS.Open[names.first ! FS.Error => {file _ FS.nullOpenFile; CONTINUE}]; IF file # FS.nullOpenFile THEN { IF EQStamps[GetBCDVersionInfo[file].fileVersionStamp, versionStamp] THEN RETURN[file]; FS.Close[file]; file _ FS.nullOpenFile; }; ENDLOOP; }; }; [mn, created] _ VersionMapDefaults.FileNameFromVersion[ which: $Symbols, version: versionStamp ! UNCAUGHT => CONTINUE]; IF mn # NIL THEN file _ AMFiles.OpenIt[mn, created].openFile; IF shortNameHint # NIL AND file = NIL THEN { <> names: VersionMap.MapAndNameList _ VersionMap.ShortNameToNames[GetMapList[], shortNameHint]; FOR each: VersionMap.MapAndNameList _ names, each.rest WHILE each # NIL DO name: ROPE _ each.first.name; name _ Rope.Substr[name, 0, Rope.SkipTo[name, 0, "!"]]; file _ FS.Open[name ! FS.Error => LOOP]; IF EQStamps[GetBCDVersionInfo[file].fileVersionStamp, versionStamp] THEN RETURN[file]; ENDLOOP; file _ FS.nullOpenFile; }; }; GetMapList: PUBLIC PROC RETURNS [VersionMap.MapList] = { RETURN[VersionMapDefaults.GetMapList[$Symbols]]; }; <<>> <> YRCMapOps.EstablishOuter[RCMapOuterY]; -- NOTE this line should precede the next one XRCMapOps.EstablishOuter[RCMapOuterX]; YSymbolTable.SetCacheSize[pages: 512]; XSymbolTable.SetCacheSize[pages: 512]; }.