RTGetSymbolsImpl.mesa
Copyright © 1984 by Xerox Corporation. All rights reserved.
Russ Atkinson On June 14, 1984 2:08:15 pm PDT
Paul Rovner On December 12, 1983 5:06 pm
Bob Hagmann On May 7, 1984 3:33:31 pm PDT
DIRECTORY
AMFiles USING[OpenIt],
AMFilesExtras USING[FullFileNameList],
AMTypes USING[Error],
BcdDefs USING[
VersionStamp, NameRecord, MTIndex, SGIndex, SGNull, FTNull, FTSelf, VersionID, FTIndex, NullVersion, BcdBase, NameString, MTHandle, SGHandle, FTHandle],
BcdOps USING[ProcessModules, ProcessFiles],
BrandXSymbolDefs USING[
rootBodyIndex, nullSymbolIndex, SymbolTableBase, SymbolModuleIndex],
BrandYSymbolDefs USING[
rootBodyIndex, nullSymbolIndex, SymbolTableBase, SymbolModuleIndex],
ConvertUnsafe USING[SubString, SubStringToRope],
FileSegment USING[Pages],
FS USING[Error, Open, OpenFile, nullOpenFile, Read, Close],
LoadState USING[Acquire, Release, ConfigInfo, GlobalFrameToModule, local, ConfigID, ModuleIndex],
PrincOps USING[GlobalFrameHandle],
RCMapOps USING[EstablishOuter],
Rope USING[ROPE, Concat, Equal, Find, Substr, Index],
RTSymbolDefs USING[
SymbolTableBase, SymbolTableHandle, nullHandle, nullBase, SymbolModuleIndex],
RTSymbolOps USING[
STBToModuleName, STBVersion, SubStringForName, NullModuleIndex, NullSth],
RTSymbols USING[], -- EXPORTS only
RTSymbolsPrivate USING[], -- EXPORTS only
RTTypesBasicPrivate USING[SymbolTableIndex, FindSTI, MapStiStd, STDesc],
SymbolTable USING[SetCacheSize, Release, Acquire, BaseToHandle],
Table USING[Base],
VersionMap USING[MapList],
VersionMapDefaults USING[FileNameFromVersion, GetMapList],
VM USING[Interval, Allocate, AddressForPageNumber, Free, PageNumberForAddress];
RTGetSymbolsImpl: MONITOR
IMPORTS AMFiles, AMFilesExtras, AMTypes, BcdOps, FS, ConvertUnsafe, LoadState, RCMapOps, Rope, RTSymbolOps, RTTypesBasicPrivate, SymbolTable, VersionMapDefaults, VM
EXPORTS RTSymbols, RTSymbolsPrivate
SHARES Rope
= BEGIN
OPEN bx: BrandXSymbolDefs, by: BrandYSymbolDefs, XSymbolTable: SymbolTable, YSymbolTable: SymbolTable, XRCMapOps: RCMapOps, YRCMapOps: RCMapOps, RTSymbolDefs, RTSymbolOps;
Variables protected by the monitor
onePageSpace: VM.Interval = VM.Allocate[1];
ROPE: TYPE = Rope.ROPE;
-- PUBLIC PROCS --
Outer: PUBLIC PROC[
stb: SymbolTableBase, mdi: SymbolModuleIndex, inner: PROC[base: SymbolTableBase]] = {
stb1: SymbolTableBase = AcquireSTBFromMDI[stb, mdi];
inner[stb1 ! UNWIND => ReleaseSTB[stb1]];
ReleaseSTB[stb1];
};
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;
IF NOT (WITH stb SELECT FROM
t: SymbolTableBase.x => t.e.stHandle.extended,
t: SymbolTableBase.y => t.e.stHandle.extended,
ENDCASE => ERROR) -- symbol table made by an old version of the compiler
OR (WITH stb SELECT FROM
t: SymbolTableBase.x => t.e.bb[bx.rootBodyIndex].type = bx.nullSymbolIndex,
t: SymbolTableBase.y => t.e.bb[by.rootBodyIndex].type = by.nullSymbolIndex,
ENDCASE => ERROR)
THEN {modName: ROPE = STBToModuleName[stb ! UNWIND => ReleaseSTB[stb]];
ReleaseSTB[stb];
ERROR AMTypes.Error[reason: noSymbols, msg: modName]}
ELSE RETURN[stb]};
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]};
this may return nullHandle but will not raise any signals
AcquireSTHFromSTX: PUBLIC PROC[stx: RTTypesBasicPrivate.SymbolTableIndex]
RETURNS[sth: SymbolTableHandle ← nullHandle, moduleName: ROPENIL] = {
[sth, moduleName] ← DoAcquireSTHFromSTX[stx, TRUE];
};
DoAcquireSTHFromSTX:
PROC[stx: RTTypesBasicPrivate.SymbolTableIndex, invokeGetSTHForModule: BOOLFALSE]
RETURNS[sth: SymbolTableHandle ← nullHandle, moduleName: ROPENIL] = {
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 invokeGetSTHForModule
THEN sth ← GetSTHForModule[
    stamp: symbolsStamp,
    fileName: NIL,
    moduleName: NIL
    ! ANY => CONTINUE]
ELSE RETURN;
}
ELSE { --bcd # NIL
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 RETURN[FALSE];
moduleName ← GetModuleName[ssb, ffth.name];
sth ← GetSTHForModule[
  stamp: symbolsStamp,
  fileName: Rope.Concat[moduleName, ".bcd"],
  moduleName: moduleName
  ! AMTypes.Error => CONTINUE];
RETURN[TRUE];
};
IF NOT invokeGetSTHForModule THEN RETURN;
[] ← BcdOps.ProcessFiles[bcd, findSymbolFTI];
IF NullSth[sth]
THEN sth ← GetSTHForModule[
    stamp: symbolsStamp,
    fileName: NIL,
    moduleName: NIL
    ! ANY => 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,
  of indicated bcd. Should match bcd.version
  base: sgb[sgi].base - 1,
  pages: sgb[sgi].pages + sgb[sgi].extraPages
  ! AMTypes.Error => CONTINUE]
};
}; -- end ELSE (i.e. bcd # NIL)
RTTypesBasicPrivate.MapStiStd[stx].sth ← sth;
}; -- end DoAcquireSTHFromSTX
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]];
}; -- end NewSymbolHandle
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]};
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
]
]
];
};
stamp on the MODULE, maybe different than bcd.version
GetSTHForModule: PUBLIC PROC[
stamp: BcdDefs.VersionStamp,
fileName: ROPE, -- maybe NIL
moduleName: ROPE -- maybe NIL
]
RETURNS[sth: SymbolTableHandle ← nullHandle] = {
bcd: BcdDefs.BcdBase;
newFile: FS.OpenFile ← FS.nullOpenFile;
sgb: Table.Base;
ftb: Table.Base;
ntb: BcdDefs.NameString;
versionMapTried: BOOLFALSE;
mth: BcdDefs.MTHandle;
sSeg: BcdDefs.SGIndex;
someNameMatched: BOOLFALSE;
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: BOOLTRUE;
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])
];
}; -- end FindVersionStampedModule
START GetSTHForModule body here
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 THEN newFile ← AMFiles.OpenIt[fileName].openFile;
DO
IF newFile = FS.nullOpenFile -- no local file with that name
THEN {
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];
}; -- end GetSTHForModule
raises Error if there are no symbols for the specified module
AcquireSTBFromGFH: PUBLIC PROC[gfh: PrincOps.GlobalFrameHandle]
RETURNS[stb: SymbolTableBase ← nullBase] =
BEGIN
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 try for the one referenced in the bcd
THEN sth ← AcquireSTHFromSGI[bcd, mth.sseg];
IF NullSth[sth] -- then try for the named module's file (locally)
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]
! ANY => CONTINUE
];
};
IF NullSth[sth] -- then try for the original one
THEN [sth: sth, moduleName: moduleName]
← AcquireSTHFromSTX[RTTypesBasicPrivate.FindSTI[[symbolsStamp: umid,
bcd: bcd]]];
IF NullSth[sth] -- then give up.
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];
END; -- AcquireSTBFromGFH
AcquireSTBFromSGI: PUBLIC PROC[bcd: BcdDefs.BcdBase, sgi: BcdDefs.SGIndex]
sgi identifies the symbol segment
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];
ERROR AMTypes.Error[
  reason: noSymbols,
  msg: IF sgh.file = BcdDefs.FTSelf
   THEN GetFileName[ssb: ssb, n: bcd.source]
   ELSE GetFileName[ssb: ssb, n: ftb[sgh.file].name]];
};
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];
};
returns nullHandle if there are no symbols
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
  version of the specified file, not necessarily of the module
  ! ANY => CONTINUE];
};
}; -- end AcquireSTHFromSGI
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"]
];
};
may return FS.nullOpenFile
AcquireFCFromVersion: PROC[
versionStamp: BcdDefs.VersionStamp,
shortFileNameHint: ROPENIL]
RETURNS[file: FS.OpenFile ← FS.nullOpenFile] = {
fileNameList: LIST OF ROPE;
IF shortFileNameHint # NIL THEN fileNameList ← AMFilesExtras.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: versionStamp];
};
may return NIL
AcquireBCDFromVersion: PUBLIC PROC[versionStamp: BcdDefs.VersionStamp,
shortFileNameHint: ROPENIL]
RETURNS[bcd: BcdDefs.BcdBase] =
{ file: FS.OpenFile ← AcquireFCFromVersion[versionStamp, shortFileNameHint];
IF file = FS.nullOpenFile
THEN RETURN[NIL]
ELSE RETURN[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]}; -- NOTE XXX
ReleaseBCD: PUBLIC ENTRY PROC[bcd: BcdDefs.BcdBase] = {ENABLE UNWIND => NULL;
count: INTMAX[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: ROPENIL]
RETURNS[file: FS.OpenFile ← FS.nullOpenFile] = {
mn: ROPENIL;
IF shortNameHint # NIL
THEN {
fileNameList: LIST OF ROPE;
IF shortNameHint # NIL THEN fileNameList ← AMFilesExtras.FullFileNameList[shortNameHint];
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;
};
};
mn ← VersionMapDefaults.FileNameFromVersion
   [which: $Symbols, version: versionStamp ! ANY => CONTINUE];
IF mn # NIL THEN file ← AMFiles.OpenIt[mn].openFile;
};
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];
END.