RTGetSymbolsImpl.mesa
Copyright © 1984, 1985, 1986 by Xerox Corporation. All rights reserved.
Bob Hagmann On May 7, 1984 3:33:31 pm PDT
Russ Atkinson (RRA) April 7, 1986 7:11:11 pm PST
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;
Variables protected by the monitor
onePageSpace: VM.Interval = VM.Allocate[1];
PUBLIC PROCS
OuterFromSTH:
PUBLIC
PROC [sth: SymbolTableHandle, inner:
PROC [stb: SymbolTableBase] ] = {
Provided as a convenience for clients who want to know that they have been adequately protected against failure to release a symbol table.
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] = {
this may return nullHandle but will not raise any signals
[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 {
search the BCD's file table
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 {
look for the specified file
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;
};
version must match bcd.version
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];
here if file is found and version matches
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] = {
stamp on the MODULE, maybe different than bcd.version
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 {
Try the quick kill for an already acquired symbol handle associated with the stamp.
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
Try the file name hint locally
newFile ← AMFiles.OpenIt[fileName].openFile;
DO
IF newFile =
FS.nullOpenFile
THEN {
no local file with that name
IF EQStamps[stamp, BcdDefs.NullVersion]
THEN GOTO noFile
ELSE {
look for the module's original file
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;
};
};
here with a valid FC
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] ] = {
Provided as a convenience for clients who want to know that they have been adequately protected against failure to release a symbol table.
stb: SymbolTableBase ← AcquireSTBFromGFH[gfh];
inner[stb ! UNWIND => ReleaseSTB[stb] ];
ReleaseSTB[stb];
AcquireSTBFromGFH:
PUBLIC
PROC [gfh: GlobalFrameHandle]
RETURNS [stb: SymbolTableBase ← nullBase] = {
raises Error if there are no symbols for the specified module
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);
{
First look in the umid -> sth map
found: BOOL;
stx: RTTypesBasicPrivate.SymbolTableIndex;
[stx, found] ← FindSTX[umid];
IF found THEN sth ← AcquireSTHFromSTX[stx].sth};
IF NullSth[sth]
THEN
then try for the one referenced in the bcd
sth ← AcquireSTHFromSGI[bcd, mth.sseg];
IF NullSth[sth]
THEN {
then try for the named module's file (locally)
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
then try for the original one
[sth: sth, moduleName: moduleName]
← AcquireSTHFromSTX[RTTypesBasicPrivate.FindSTI[[symbolsStamp: umid, bcd: bcd]]];
IF NullSth[sth]
THEN {
then give up.
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]] = {
Provided as a convenience for clients who want to know that they have been adequately protected against failure to release a symbol table.
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] = {
sgi identifies the symbol segment
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]];
};
PRIVATE PROCS
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] = {
returns nullHandle if there are no symbols
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] = {
may return 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] = {
may return 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] =
{
Note: this has to change if there is ever another bcd format
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 {
We are about to lose it. But we can try the short name against the version map to get a long name, then remove the version and try the resulting long name to try for the most recent remote version. This may help with incremental searches.
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]];
};
MODULE INITIALIZATION
YRCMapOps.EstablishOuter[RCMapOuterY]; -- NOTE this line should precede the next one
XRCMapOps.EstablishOuter[RCMapOuterX];
YSymbolTable.SetCacheSize[pages: 512];
XSymbolTable.SetCacheSize[pages: 512];
}.