ProcBcdsImpl.Mesa
last edit April 5, 1982 10:59 am
last edit May 23, 1983 4:36 pm, Russ Atkinson (short STRING to LONG STRING)
DIRECTORY
BcdDefs: TYPE USING
[Base, CTIndex, CTNull, CTRecord, EXPIndex, EXPRecord, FTIndex, FTNull, FTRecord, FTSelf, IMPIndex, IMPRecord, Link, MTIndex, MTRecord, NameRecord, SGIndex, VersionID, VersionStamp],
CWF: TYPE USING [SWF0, WF0, WF1],
Directory: TYPE USING [Error, Handle, Lookup],
Environment: TYPE USING [wordsPerPage],
File: TYPE USING [Capability, nullCapability, read],
FileParms: TYPE USING [nullSymbolSpace, SymbolSpace],
LeafSubr: TYPE USING [RemoteMap],
LongString: TYPE USING
[AppendString, AppendSubString, EquivalentString, SubString, SubStringDescriptor],
ProcBcds: TYPE USING [Innards, ProcDep, ProcMod],
RTBcd: TYPE USING[RTBase],
Space: TYPE USING
[Create, CreateUniformSwapUnits, Delete, Handle, LongPointer, Map, nullHandle, virtualMemory],
Subr: TYPE USING
[AllocateString, Any, ControlChars, FreeString, SubStrCopy, strcpy],
Symbols: TYPE USING [HTIndex, HTNull, HTRecord, MDIndex, MDRecord, OwnMdi],
SymbolSegment: TYPE USING [FGHeader, STHeader, VersionID],
Table: TYPE USING [Base],
Time: TYPE USING [Current],
TimeStamp: TYPE USING [Stamp];
ProcBcdsImpl: PROGRAM
IMPORTS CWF, Directory, LeafSubr, LongString, Space, Subr, Time
EXPORTS ProcBcds = {
useonespace: BOOL = TRUE; -- FALSE has never worked
Sym: TYPE = POINTER TO SymRecord;
SymRecord: TYPE = RECORD[
stHandle: LONG POINTER TO SymbolSegment.STHeader ← NIL,
stHandleSpace: Space.Handle ← Space.nullHandle,
hash table
ht: LONG DESCRIPTOR FOR ARRAY Symbols.HTIndex OF Symbols.HTRecord ← NULL,
htSpace: Space.Handle ← Space.nullHandle,
ssb:  LONG STRINGNIL,  -- id string
ssbSpace: Space.Handle ← Space.nullHandle,
mdb:  Table.Base ← NIL,  -- module directory base
mdbSpace: Space.Handle ← Space.nullHandle,
mdLimit: Symbols.MDIndex ← NULL,  -- module directory size
fgptr: LONG POINTER TO SymbolSegment.FGHeader ← NIL, -- ptr to beginning of fine grain table
fgptrSpace: Space.Handle ← Space.nullHandle
];
InvalidBcd: PUBLIC SIGNAL = CODE;
ReadInSegmentsBcd: PUBLIC PROC [innards: ProcBcds.Innards] = {
local: BOOL;
npages: CARDINAL;
IF innards.cap = File.nullCapability AND innards.fh = NIL THEN ERROR;
local ← innards.fh = NIL;
map in at least one page to get total # of pages
innards.bcdheaderspace ← Space.Create[size: 10, parent: Space.virtualMemory];
IF local THEN
Space.Map[space: innards.bcdheaderspace,
window: [file: innards.cap, base: 1]]
ELSE LeafSubr.RemoteMap[space: innards.bcdheaderspace, fh: innards.fh, base: 0];
innards.bcd ← Space.LongPointer[innards.bcdheaderspace];
IF innards.bcd.versionIdent ~= BcdDefs.VersionID THEN {
not a bcd or invalid version ID in header
Space.Delete[innards.bcdheaderspace];
innards.bcdheaderspace ← Space.nullHandle;
innards.bcd ← NIL;
SIGNAL InvalidBcd;
RETURN;
};
npages ← innards.bcd.nPages;
IF npages > 10 THEN {
Space.Delete[innards.bcdheaderspace];
now map in the right number of pages
innards.bcdheaderspace ← Space.Create[size: npages, parent: Space.virtualMemory];
IF local THEN
Space.Map[space: innards.bcdheaderspace,
window: [file: innards.cap, base: 1]]
ELSE LeafSubr.RemoteMap[space: innards.bcdheaderspace, fh: innards.fh, base: 0];
innards.bcd ← Space.LongPointer[innards.bcdheaderspace];
};
Space.CreateUniformSwapUnits[parent: innards.bcdheaderspace, size: 8];
innards.upperLimit ← npages * Environment.wordsPerPage;
};
InstallAddressesBcd: PUBLIC PROC[innards: ProcBcds.Innards] = {
innards.tb ← LOOPHOLE[innards.bcd];
innards.ssb ← LOOPHOLE[innards.bcd + innards.bcd.ssOffset];
innards.ctb ← innards.tb + innards.bcd.ctOffset;
innards.mtb ← innards.tb + innards.bcd.mtOffset;
innards.itb ← innards.tb + innards.bcd.impOffset;
innards.etb ← innards.tb + innards.bcd.expOffset;
innards.sgb ← innards.tb + innards.bcd.sgOffset;
innards.ftb ← innards.tb + innards.bcd.ftOffset;
innards.ntb ← innards.tb + innards.bcd.ntOffset;
innards.evb ← innards.tb + innards.bcd.evOffset;
innards.spb ← innards.tb + innards.bcd.spOffset;
innards.fpb ← innards.tb + innards.bcd.fpOffset;
};
UnstallBcd: PUBLIC PROC [innards: ProcBcds.Innards] = {
IF innards.bcdheaderspace = Space.nullHandle THEN ERROR;
Space.Delete[innards.bcdheaderspace];
innards^ ← [bcdheaderspace: Space.nullHandle]; -- others are defaulted
};
PrintDepends: PUBLIC PROC
[innards: ProcBcds.Innards, procMod: ProcBcds.ProcMod,procDep: ProcBcds.ProcDep, print, calltwice, less: BOOL, bcdfilename: LONG STRING]
RETURNS [success, isconfig, isdefns: BOOL, nimp, nexp, ntype: CARDINAL] = {
uns: UNSPECIFIED;
cti: BcdDefs.CTIndex ← FIRST[BcdDefs.CTIndex];
nullstring: STRING ← ""L;
altoCode, boundsChecks, cedarSwitch, crossJump, linksInCode, nilChecks, sortByUsage: BOOL
FALSE;
notcodebound: BOOL;
symbolSpace: FileParms.SymbolSpace ← FileParms.nullSymbolSpace;
rtVersionID: CARDINAL ← 0;
sourcefile: LONG STRING ← Subr.AllocateString[100];
interfacename: LONG STRING ← Subr.AllocateString[100];
switches: LONG STRING ← Subr.AllocateString[100];
{ENABLE
UNWIND => {
Subr.FreeString[sourcefile]; Subr.FreeString[interfacename]; Subr.FreeString[switches]};
success ← isconfig ← isdefns ← FALSE;
nexp ← nimp ← ntype ← 0;
IF nullstring.length ~= 0 THEN ERROR;
IF innards.bcd.versionIdent ~= BcdDefs.VersionID THEN {
CWF.WF0[" Error - wrong bcd version.\n"L];
GO TO return;
};
if it is a defs file, we simply record the interface name
PutName[innards, innards.bcd.source, sourcefile];
IF sourcefile.length >0 AND sourcefile[sourcefile.length -1] = '. THEN
sourcefile.length ← sourcefile.length - 1;
CWF.WF1["sourcefiles %s\n"L, sourcefile];
IF Subr.ControlChars[sourcefile] THEN {
CWF.WF0[" Error - bad sourcefile.\n"L];
GO TO return;
};
success ← GetModuleName[innards, interfacename];
IF NOT success THEN GO TO return;
at this point, success must always be TRUE since
this code now calls the procDep and procMod procs
isconfig ← innards.bcd.nConfigs > 0;
IF NOT isconfig THEN {
sSeg: BcdDefs.SGIndex ← innards.mtb[FIRST[BcdDefs.MTIndex]].sseg;
altoCode ← innards.mtb[FIRST[BcdDefs.MTIndex]].altoCode;
boundsChecks ← innards.mtb[FIRST[BcdDefs.MTIndex]].boundsChecks;
crossJump ← innards.mtb[FIRST[BcdDefs.MTIndex]].crossJumped;
cedarSwitch ← IF NOT altoCode THEN innards.mtb[FIRST[BcdDefs.MTIndex]].long ELSE FALSE;
nilChecks ← innards.mtb[FIRST[BcdDefs.MTIndex]].nilChecks;
linksInCode ← innards.mtb[FIRST[BcdDefs.MTIndex]].linkLoc = code;
sortByUsage ← NOT innards.mtb[FIRST[BcdDefs.MTIndex]].initial; -- /s switch, initial = FALSE is /s
symbolSpace ← [file: innards.cap, span: [base: innards.sgb[sSeg].base,
pages: innards.sgb[sSeg].pages]];
};
notcodebound ← IF isconfig THEN NotCodeBound[innards, BcdDefs.CTNull] ELSE TRUE;
isdefns ← innards.bcd.definitions;
IF isdefns
THEN
uns ← procMod[sourcefile, interfacename,
innards.bcd.version, innards.bcd.sourceVersion,
innards.bcd.creator,
TRUE, FALSE, FALSE, FALSE,
FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, symbolSpace, 0]
ELSE {
IF innards.bcd.extended AND innards.bcd.rtPages.pages > 0 THEN
rtVersionID ← LOOPHOLE[innards.bcd + innards.bcd.rtPages.relPageBase*Environment.wordsPerPage, RTBcd.RTBase].versionIdent;
uns ← procMod[sourcefile, interfacename,
innards.bcd.version, innards.bcd.sourceVersion, innards.bcd.creator,
FALSE, isconfig, NOT notcodebound, innards.bcd.tableCompiled,
altoCode, boundsChecks, cedarSwitch, crossJump, linksInCode, nilChecks, sortByUsage,
symbolSpace, rtVersionID];
};
IF NOT isconfig THEN {
IF innards.bcd.extended
THEN
ntype ← PrintDirectory[innards, procDep, uns, print, bcdfilename]
ELSE
[,ntype] ← PrintSymbolsFile[innards, procDep, uns, print, FALSE, less, bcdfilename];
};
IF NOT isdefns THEN
nexp ← PrintExports[innards, procDep, uns, print];
IF calltwice AND NOT isdefns AND (ntype > 50 OR nexp > 30) THEN {
call again to avoid overflow in the database
uns ← procMod[
sourcefile, interfacename,
innards.bcd.version, innards.bcd.sourceVersion,
innards.bcd.creator, FALSE, isconfig, NOT notcodebound,
innards.bcd.tableCompiled, altoCode, boundsChecks, cedarSwitch,
crossJump, linksInCode, nilChecks, sortByUsage, symbolSpace, rtVersionID];
};
nimp ← PrintImports[innards, procDep, uns, print];
IF isconfig THEN {
PrintConfigDepends[innards, procDep, uns, notcodebound, FALSE];
IF NOT notcodebound AND print THEN CWF.WF0["(code bound)\n"L];
};
success ← TRUE;
EXITS return => {};
}; -- of ENABLE UNWIND
Subr.FreeString[sourcefile]; Subr.FreeString[interfacename]; Subr.FreeString[switches];
};
PrintDirectory: PROC
[innards: ProcBcds.Innards, procDep: ProcBcds.ProcDep, uns: UNSPECIFIED, print: BOOL, bcdfilename: LONG STRING]
RETURNS [ntype: CARDINAL] = {
modulename: LONG STRING ← Subr.AllocateString[100];
filename: LONG STRING ← Subr.AllocateString[100];
fti: BcdDefs.FTIndex ← FIRST[BcdDefs.FTIndex];
{ENABLE UNWIND => {Subr.FreeString[modulename]; Subr.FreeString[filename]};
ntype ← 0;
UNTIL fti = innards.bcd.ftLimit DO
PutName[innards, innards.ftb[fti].name, filename];
IF NOT Subr.Any[filename, '.] THEN
LongString.AppendString[filename, ".bcd"L];
procDep[defstype, GuessModulename[innards, fti, modulename],
filename, innards.ftb[fti].version, uns];
ntype ← ntype + 1;
fti ← fti + SIZE[BcdDefs.FTRecord];
IF LOOPHOLE[fti, CARDINAL] > LOOPHOLE[innards.bcd.ftLimit, CARDINAL] THEN
GO TO Bogus;
REPEAT Bogus => {
CWF.WF1["Error - Garbage FileTable in %s.\n"L, bcdfilename];
GO TO return;
};
ENDLOOP;
IF print THEN CWF.WF1[" %d types.\n"L, @ntype];
EXITS return => {};
}; -- of ENABLE UNWIND
Subr.FreeString[modulename]; Subr.FreeString[filename];
};
GuessModulename: PROC
[innards: ProcBcds.Innards, fti: BcdDefs.FTIndex, modulename: LONG STRING]
RETURNS[LONG STRING] = {
returns NIL if can't find modulename
iti: BcdDefs.IMPIndex ← FIRST[BcdDefs.IMPIndex];
eti: BcdDefs.EXPIndex ← FIRST[BcdDefs.EXPIndex];
WHILE LOOPHOLE[iti, CARDINAL] < LOOPHOLE[innards.bcd.impLimit, CARDINAL] DO
IF innards.itb[iti].file = fti THEN {
PutName[innards, innards.itb[iti].name, modulename];
RETURN[modulename];
};
iti ← iti + SIZE[BcdDefs.IMPRecord];
ENDLOOP;
WHILE LOOPHOLE[eti, CARDINAL] < LOOPHOLE[innards.bcd.expLimit, CARDINAL] DO
IF innards.etb[eti].file = fti THEN {
PutName[innards, innards.etb[eti].name, modulename];
RETURN[modulename];
};
eti ← eti + SIZE[BcdDefs.IMPRecord] + innards.etb[eti].size;
ENDLOOP;
RETURN[NIL];
};
PrintSymbolsFile: PUBLIC PROC
[innards: ProcBcds.Innards, procDep: ProcBcds.ProcDep, uns: UNSPECIFIED, print, allsyms, less: BOOL, bcdfilename: LONG STRING]
RETURNS[success: BOOL, ntype: CARDINAL] = {
headerseg initted from ReadIn
mti, mtLimit: BcdDefs.MTIndex;
symseg: BcdDefs.SGIndex;
symrecord: SymRecord ← [];
shortstr: LONG STRING ← Subr.AllocateString[100];
nullstr: STRING ← ""L;
{ENABLE UNWIND => {Subr.FreeString[shortstr]};
ntype ← 0;
success ← FALSE;
mti ← FIRST[BcdDefs.MTIndex];
mtLimit ← IF allsyms THEN innards.bcd.mtLimit ELSE mti + 1;
UNTIL LOOPHOLE[mti, CARDINAL] >= LOOPHOLE[mtLimit, CARDINAL] DO
symseg ← innards.mtb[mti].sseg;
success ← InitSym[innards, @symrecord, symseg, less, bcdfilename];
IF NOT success THEN EXIT;
[success, ntype] ← PrintModuleEntries[innards, @symrecord,
procDep, uns, print, bcdfilename];
IF NOT success THEN EXIT;
IF NOT less THEN {
FindSourceFileName[@symrecord, shortstr];
IF shortstr.length > 0 THEN
procDep[sourcefile, nullstr, shortstr, symrecord.stHandle.sourceVersion, uns];
};
FreeSym[@symrecord];
mti ← mti + (WITH m: innards.mtb[mti] SELECT FROM
direct => SIZE[BcdDefs.MTRecord[direct]] + m.length*SIZE[BcdDefs.Link],
indirect => SIZE[BcdDefs.MTRecord[indirect]],
multiple => SIZE[BcdDefs.MTRecord[multiple]],
ENDCASE => ERROR)
ENDLOOP;
}; -- of ENABLE UNWIND
Subr.FreeString[shortstr];
RETURN[success, ntype];
};
InitSym: PROC[innards: ProcBcds.Innards, sym: Sym, symseg: BcdDefs.SGIndex, less: BOOL,
bcdfilename: LONG STRING] RETURNS[success: BOOLFALSE] = {
init from bcd
npages: CARDINAL;
cap: File.Capability;
local: BOOL;
base: CARDINAL;
p: LONG POINTER;
sfnsym: LONG STRING ← Subr.AllocateString[100];
{ENABLE UNWIND => {Subr.FreeString[sfnsym]};
IF innards.sgb[symseg].class ~= symbols THEN {
CWF.WF0["Error - badly formed symbols.\n"L];
GO TO return;
};
IF innards.sgb[symseg].pages = 0 THEN {
CWF.WF1["Warning - No symbols in %s.\n"L, bcdfilename];
GO TO return;
};
IF innards.sgb[symseg].file ~= BcdDefs.FTSelf
THEN {
PrintFileName[innards, innards.sgb[symseg].file, sfnsym];
cap ← Directory.Lookup[
fileName: sfnsym, permissions: File.read
! Directory.Error => GOTO err];
EXITS
err => {
CWF.WF1["Error - can't find '%s'\n"L, sfnsym];
GO TO return;
};
}
ELSE cap ← innards.cap;
npages ← innards.sgb[symseg].pages;
IF NOT less THEN npages ← npages + innards.sgb[symseg].extraPages;
IF useonespace
THEN
sym.stHandleSpace ← Space.Create[parent: Space.virtualMemory, size: npages]
ELSE
sym.stHandleSpace ←
Space.Create[
parent: Space.virtualMemory,
size: (SIZE[SymbolSegment.STHeader]/Environment.wordsPerPage) + 1];
local ← innards.fh = NIL;
IF local
THEN {
base ← innards.sgb[symseg].base;
Space.Map[space: sym.stHandleSpace, window: [file: cap, base: base]]
}
ELSE {
base ← innards.sgb[symseg].base - 1;
LeafSubr.RemoteMap[sym.stHandleSpace, innards.fh, base];
};
sym.stHandle ← Space.LongPointer[sym.stHandleSpace];
IF sym.stHandle.versionIdent ~= SymbolSegment.VersionID THEN {
CWF.WF0["Error - Symbols versions do not agree.\n"L];
GO TO return;
};
init symbols header
IF useonespace
THEN {
b: LONG POINTER;
tB: Table.Base;
b ← LOOPHOLE[sym.stHandle];
tB ← LOOPHOLE[sym.stHandle];
sym.ht ← DESCRIPTOR[b+sym.stHandle.htBlock.offset,
sym.stHandle.htBlock.size/SIZE[Symbols.HTRecord]];
sym.ssb ← b + sym.stHandle.ssBlock.offset;
sym.mdb ← tB + sym.stHandle.mdBlock.offset;
sym.mdLimit ← FIRST[Symbols.MDIndex] + sym.stHandle.mdBlock.size;
IF NOT less THEN
sym.fgptr ← LOOPHOLE[
sym.stHandle + sym.stHandle.fgRelPgBase * Environment.wordsPerPage];
}
ELSE {
[p, sym.htSpace] ← GetSpace[innards, sym, base, sym.stHandle.htBlock.offset,
sym.stHandle.htBlock.size];
sym.ht ← DESCRIPTOR[p, sym.stHandle.htBlock.size/SIZE[Symbols.HTRecord]];
[sym.ssb, sym.ssbSpace] ← GetSpace[innards, sym, base,
sym.stHandle.ssBlock.offset, sym.stHandle.ssBlock.size];
[LOOPHOLE[sym.mdb, LONG POINTER], sym.mdbSpace] ← GetSpace[innards, sym, base,
sym.stHandle.mdBlock.offset, sym.stHandle.mdBlock.size];
sym.mdLimit ← FIRST[Symbols.MDIndex] + sym.stHandle.mdBlock.size;
IF NOT less THEN
[LOOPHOLE[sym.fgptr, LONG POINTER], sym.fgptrSpace] ←
GetSpace[
innards, sym, base,
sym.stHandle.fgRelPgBase * Environment.wordsPerPage,
Environment.wordsPerPage];
};
success ← TRUE;
EXITS return => {};
}; -- of ENABLE UNWIND
Subr.FreeString[sfnsym];
};
GetSpace: PROC[innards: ProcBcds.Innards, sym: Sym, pbase, offset, size: CARDINAL]
RETURNS[buffer: LONG POINTER, space: Space.Handle] = {
offset is # words off # base page number, size is # words in range
pstart, pnum: CARDINAL;
pageoffset: CARDINAL ← offset/Environment.wordsPerPage;
pstart ← pbase + pageoffset;
pnum ← ((size+offset)/Environment.wordsPerPage) - pageoffset + 1;
space ← Space.Create[parent: Space.virtualMemory, size: pnum];
IF innards.cap ~= File.nullCapability
THEN Space.Map[space, [innards.cap, pstart]]
ELSE LeafSubr.RemoteMap[space, innards.fh, pstart];
buffer ← Space.LongPointer[space];
buffer ← buffer + (offset - (pageoffset*Environment.wordsPerPage));
};
PrintModuleEntries: PROC[innards: ProcBcds.Innards, sym: Sym,
procDep: ProcBcds.ProcDep, uns: UNSPECIFIED, print: BOOL,
bcdfilename: LONG STRING]
RETURNS[success: BOOL, ntype: CARDINAL] = {
foreach module entry
since each filename ends in ".bcd.", we strip the trailing "." off
mdi: Symbols.MDIndex ← FIRST[Symbols.MDIndex];
sfn: LONG STRING ← Subr.AllocateString[100];
smodulename: LONG STRING ← Subr.AllocateString[100];
substr: LongString.SubStringDescriptor;
{ENABLE UNWIND => {Subr.FreeString[sfn]; Subr.FreeString[smodulename]};
ntype ← 0;
success ← FALSE;
DO
skip the module itself
IF mdi = Symbols.OwnMdi THEN mdi ← mdi + SIZE[Symbols.MDRecord];
IF mdi = sym.mdLimit THEN EXIT;
SubStringForHash[sym, @substr, sym.mdb[mdi].moduleId];
smodulename.length ← 0;
LongString.AppendSubString[smodulename, @substr];
SubStringForHash[sym, @substr, sym.mdb[mdi].fileId];
sfn.length ← 0;
LongString.AppendSubString[sfn, @substr];
IF sfn.length > 0 AND sfn[sfn.length-1] = '. THEN
sfn.length ← sfn.length - 1;  -- strip "."
CWF.WF2["module %s file %s\n"L, smodulename, sfn];
ntype ← ntype + 1;
procDep[defstype, smodulename, sfn, sym.mdb[mdi].stamp, uns];
mdi ← mdi + SIZE[Symbols.MDRecord];
IF LOOPHOLE[mdi, CARDINAL] > LOOPHOLE[sym.mdLimit, CARDINAL]
THEN {
CWF.WF1["Warning - symbols MDRecord is garbage in %s.\n"L, bcdfilename];
GO TO return;
};
ENDLOOP;
IF print THEN CWF.WF1["%u types, "L, @ntype];
success ← TRUE;
EXITS return => {};
}; -- of ENABLE UNWIND
Subr.FreeString[sfn]; Subr.FreeString[smodulename];
};
FindSourceFileName: PROC[sym: Sym, tostr: LONG STRING] = {
fine grain table is in sgb[].extrapages
IF sym.stHandle.fgRelPgBase > 0 AND sym.stHandle.fgPgCount > 0 THEN {
tostr.length ← 0;
LongString.AppendString[tostr, @sym.fgptr.sourceFile];
remove trailing "."
IF tostr.length > 0 AND tostr[tostr.length-1] = '. THEN
tostr.length ← tostr.length - 1;  -- strip "."
}
ELSE  tostr.length ← 0;
CWF.WF1["sourcefile <%s>\n"L, tostr];
};
FreeSym: PROC[sym: Sym] = {
free the segment
IF sym.stHandleSpace ~= Space.nullHandle THEN {
Space.Delete[sym.stHandleSpace];
sym.stHandleSpace ← Space.nullHandle;
};
IF sym.htSpace ~= Space.nullHandle THEN {
Space.Delete[sym.htSpace];
sym.htSpace ← Space.nullHandle;
};
IF sym.ssbSpace ~= Space.nullHandle THEN {
Space.Delete[sym.ssbSpace];
sym.ssbSpace ← Space.nullHandle;
};
IF sym.mdbSpace ~= Space.nullHandle THEN {
Space.Delete[sym.mdbSpace];
sym.mdbSpace ← Space.nullHandle;
};
IF sym.fgptrSpace ~= Space.nullHandle THEN {
Space.Delete[sym.fgptrSpace];
sym.fgptrSpace ← Space.nullHandle;
};
};
SubStringForHash: PROC [sym: Sym, s: LongString.SubString, hti: Symbols.HTIndex] = {
s.base ← sym.ssb;
IF hti = Symbols.HTNull
THEN s.offset ← s.length ← 0
ELSE s.length ← sym.ht[hti].ssIndex - (s.offset ← sym.ht[hti-1].ssIndex)
};
GetModuleName: PUBLIC PROC[innards: ProcBcds.Innards, interfacename: LONG STRING]
RETURNS[success: BOOL] = {
unofficially, a defs file or impl modules name is the first
index in the module table. Not so for configs.
they are in the config table
cti: BcdDefs.CTIndex ← FIRST[BcdDefs.CTIndex];
IF innards.bcd.nConfigs = 0 THEN
PutName[innards, innards.mtb[FIRST[BcdDefs.MTIndex]].name,
interfacename]
ELSE
UNTIL cti = innards.bcd.ctLimit DO
IF innards.ctb[cti].config = BcdDefs.CTNull THEN {
PutName[innards, innards.ctb[cti].name,
interfacename];
CWF.WF1["Name: %s\n"L, interfacename];
EXIT;
};
cti ← cti+innards.ctb[cti].nControls + SIZE[BcdDefs.CTRecord];
IF LOOPHOLE[cti, CARDINAL] > LOOPHOLE[innards.bcd.ctLimit,
CARDINAL] THEN {
CWF.WF0["Garbage Garbage Garbage.\n"L];
RETURN[FALSE];
};
ENDLOOP;
RETURN[TRUE];
};
PrintExports: PROC[innards: ProcBcds.Innards, procDep: ProcBcds.ProcDep,
uns: UNSPECIFIED, print: BOOL] RETURNS[nexp: CARDINAL] = {
eti: BcdDefs.EXPIndex ← FIRST[BcdDefs.EXPIndex];
nexp ← 0;
UNTIL eti = innards.bcd.expLimit DO
PrintExport[innards, eti, procDep, uns];
nexp ← nexp + 1;
eti ← eti + innards.etb[eti].size + SIZE[BcdDefs.EXPRecord];
IF LOOPHOLE[eti, CARDINAL] > LOOPHOLE[innards.bcd.expLimit, CARDINAL]
THEN GO TO Bogus;
REPEAT Bogus => {
CWF.WF0["Garbage Garbage Garbage.\n"L];
RETURN;
};
ENDLOOP;
IF print THEN CWF.WF1[" %d exp, "L, @nexp];
};
PrintExport: PROC [innards: ProcBcds.Innards, eti: BcdDefs.EXPIndex,
procDep: ProcBcds.ProcDep, uns: UNSPECIFIED] = {
OPEN innards.etb[eti];
stemp: LONG STRING ← Subr.AllocateString[100];
stemp1: LONG STRING ← Subr.AllocateString[100];
vers: BcdDefs.VersionStamp;
{ENABLE UNWIND => {Subr.FreeString[stemp]; Subr.FreeString[stemp1]};
PutName[innards, name, stemp];
PrintFileName[innards, file, stemp1];
IF stemp.length = 0 OR Subr.ControlChars[stemp]
OR stemp1.length = 0 OR Subr.ControlChars[stemp1] THEN {
CWF.WF0["name garbaged up\n"L];
GO TO return;
};
vers ← innards.ftb[file].version;
procDep[exports, stemp, stemp1, vers, uns];
EXITS return => {};
}; -- of ENABLE UNWIND
Subr.FreeString[stemp]; Subr.FreeString[stemp1];
};
PrintImports: PROC[innards: ProcBcds.Innards, procDep: ProcBcds.ProcDep,
uns: UNSPECIFIED, print: BOOL] RETURNS[nimp: CARDINAL] = {
iti: BcdDefs.IMPIndex ← FIRST[BcdDefs.IMPIndex];
nullstring: STRING ← ""L;
nimp ← 0;
UNTIL iti = innards.bcd.impLimit DO
PrintImport[innards, iti, procDep, uns];
nimp ← nimp + 1;
iti ← iti + SIZE[BcdDefs.IMPRecord];
IF LOOPHOLE[iti, CARDINAL] > LOOPHOLE[innards.bcd.impLimit, CARDINAL] THEN
GO TO Bogus;
REPEAT Bogus => {
CWF.WF0["Garbage Garbage Garbage.\n"L];
RETURN;
};
ENDLOOP;
IF print THEN CWF.WF1[" %d imp.\n"L, @nimp];
};
PrintImport: PROC [innards: ProcBcds.Innards, iti: BcdDefs.IMPIndex,
procDep: ProcBcds.ProcDep, uns: UNSPECIFIED] = {
OPEN innards.itb[iti];
stemp: LONG STRING ← Subr.AllocateString[100];
stemp1: LONG STRING ← Subr.AllocateString[100];
vers: BcdDefs.VersionStamp;
{ENABLE UNWIND => {Subr.FreeString[stemp]; Subr.FreeString[stemp1]};
PutName[innards, name, stemp];
PrintFileName[innards, file, stemp1];
IF stemp.length = 0 OR Subr.ControlChars[stemp]
OR stemp1.length = 0 OR Subr.ControlChars[stemp1] THEN {
CWF.WF0["name garbaged up\n"L];
GO TO return;
};
vers ← innards.ftb[file].version;
procDep[imports, stemp, stemp1, vers, uns];
EXITS return => {};
}; -- of ENABLE UNWIND
Subr.FreeString[stemp]; Subr.FreeString[stemp1];
};
NotCodeBound: PROC[innards: ProcBcds.Innards, parent: BcdDefs.CTIndex]
RETURNS [notcodebound: BOOL] = {
if any one of the bcds ins not codebound, then the config
is not codebound
cti: BcdDefs.CTIndex ← FIRST[BcdDefs.CTIndex];
notcodebound ← FALSE;
UNTIL cti = innards.bcd.ctLimit DO
IF innards.ctb[cti].config = parent THEN {
notcodebound ← notcodebound OR NotCodeBound[innards, cti];
notcodebound ← notcodebound OR NotCodeBoundModule[innards, cti];
};
cti ← cti + innards.ctb[cti].nControls + SIZE[BcdDefs.CTRecord];
IF LOOPHOLE[cti, CARDINAL] > LOOPHOLE[innards.bcd.ctLimit, CARDINAL]
THEN {
CWF.WF0["Garbage Config.\n"L];
RETURN;
};
ENDLOOP;
};
NotCodeBoundModule: PROC[innards: ProcBcds.Innards, cti: BcdDefs.CTIndex]
RETURNS[notcodebound: BOOL] = {
codeseg: BcdDefs.SGIndex;
mti: BcdDefs.MTIndex ← FIRST[BcdDefs.MTIndex];
notcodebound ← FALSE;
UNTIL mti = innards.bcd.mtLimit DO
IF innards.mtb[mti].config = cti THEN {
IF innards.mtb[mti].file ~= BcdDefs.FTSelf THEN {
codeseg ← innards.mtb[mti].code.sgi;
IF innards.sgb[codeseg].class ~= code THEN {
CWF.WF0["Error - not code seg\n"L];
RETURN;
};
notcodebound ← notcodebound
OR innards.sgb[codeseg].file ~= BcdDefs.FTSelf;
};
};
mti ← mti + (WITH m: innards.mtb[mti] SELECT FROM
direct => SIZE[BcdDefs.MTRecord[direct]] + m.length*SIZE[BcdDefs.Link],
indirect => SIZE[BcdDefs.MTRecord[indirect]],
multiple => SIZE[BcdDefs.MTRecord[multiple]],
ENDCASE => ERROR);
IF LOOPHOLE[mti, CARDINAL] > LOOPHOLE[innards.bcd.mtLimit, CARDINAL]
THEN {
CWF.WF0["Garbage Module.\n"L];
RETURN;
};
ENDLOOP;
};
PrintConfigDepends: PROC[innards: ProcBcds.Innards,
procDep: ProcBcds.ProcDep,uns: UNSPECIFIED, notcodebound, stopnesting: BOOL] = {
a config .bcd depends on itself + all module entries for itself + all config entries (not FTSelf) one level away + module entries for config's that are FTSelf's away from the top
for each config entry:
if parent = CTNull, print config and modules
if parent[parent] = CTNull print config
if (file = FTSelf)* and parent = CTNull, print modules
cti: BcdDefs.CTIndex ← FIRST[BcdDefs.CTIndex];
modname: LONG STRING ← Subr.AllocateString[100];
filename: LONG STRING ← Subr.AllocateString[100];
topcti: BcdDefs.CTIndex;
ok: BOOL;
{ENABLE UNWIND => {Subr.FreeString[modname]; Subr.FreeString[filename]};
UNTIL cti = innards.bcd.ctLimit DO
ok ← FALSE;
topcti ← innards.ctb[cti].config;  -- first level parent
WHILE topcti ~= BcdDefs.CTNull AND innards.ctb[topcti].file = BcdDefs.FTSelf DO
topcti ← innards.ctb[topcti].config;
ENDLOOP;
IF topcti = BcdDefs.CTNull
OR innards.ctb[topcti].config = BcdDefs.CTNull THEN ok ← TRUE;
IF ok AND innards.ctb[cti].file ~= BcdDefs.FTSelf THEN {
PutName[innards, innards.ctb[cti].name, modname];
PrintFileName[innards, innards.ctb[cti].file, filename];
procDep[
IF notcodebound THEN otherdepends ELSE canignore,
modname, filename,
innards.ftb[innards.ctb[cti].file].version,
uns];
};
cti ← cti + innards.ctb[cti].nControls + SIZE[BcdDefs.CTRecord];
IF LOOPHOLE[cti, CARDINAL] > LOOPHOLE[innards.bcd.ctLimit, CARDINAL]
THEN {
CWF.WF0["Garbage Config.\n"L];
GO TO return;
};
ENDLOOP;
ProcessModuleTable[innards, procDep, uns, notcodebound];
EXITS return => {};
}; -- of ENABLE UNWIND
Subr.FreeString[modname]; Subr.FreeString[filename];
};
ProcessModuleTable: PROC
[innards: ProcBcds.Innards, procDep: ProcBcds.ProcDep, uns: UNSPECIFIED, notcodebound: BOOL]
= {
symseg, codeseg: BcdDefs.SGIndex;
mti: BcdDefs.MTIndex ← FIRST[BcdDefs.MTIndex];
modname: LONG STRING ← Subr.AllocateString[100];
filename: LONG STRING ← Subr.AllocateString[100];
cti: BcdDefs.CTIndex;
{ENABLE UNWIND => {Subr.FreeString[modname]; Subr.FreeString[filename]};
UNTIL mti = innards.bcd.mtLimit DO
cti ← innards.mtb[mti].config;
WHILE innards.ctb[cti].file = BcdDefs.FTSelf DO
IF innards.ctb[cti].config = BcdDefs.CTNull THEN EXIT;
cti ← innards.ctb[cti].config;
ENDLOOP;
IF innards.ctb[cti].config = BcdDefs.CTNull THEN {
symseg ← innards.mtb[mti].sseg;
IF innards.sgb[symseg].class ~= symbols THEN {
CWF.WF0["Error - not symseg\n"L];
GO TO return;
};
IF innards.sgb[symseg].file ~= BcdDefs.FTSelf
AND innards.sgb[symseg].file ~= BcdDefs.FTNull THEN {
PrintFileName[innards, innards.sgb[symseg].file,
filename];
PutName[innards, innards.mtb[mti].name,modname];
IF NOT LongString.EquivalentString[filename, modname]
THEN {
symfilevers: TimeStamp.Stamp;
symfilevers ← innards.ftb[innards.sgb[symseg].file].version;
procDep[symbolsfile, modname, filename,
symfilevers, uns];
};
};
IF innards.mtb[mti].file ~= BcdDefs.FTSelf
AND innards.mtb[mti].file ~= BcdDefs.FTNull THEN {
codeseg ← innards.mtb[mti].code.sgi;
IF innards.sgb[codeseg].class ~= code THEN {
CWF.WF0["Error - not code seg\n"L];
GO TO return;
};
PutName[innards, innards.mtb[mti].name, modname];
PrintFileName[innards, innards.mtb[mti].file, filename];
procDep[IF notcodebound THEN otherdepends
ELSE canignore, modname,filename,
innards.ftb[innards.mtb[mti].file].version,
uns];
};
};
mti ← mti + (WITH m: innards.mtb[mti] SELECT FROM
direct => SIZE[BcdDefs.MTRecord[direct]] + m.length*SIZE[BcdDefs.Link],
indirect => SIZE[BcdDefs.MTRecord[indirect]],
multiple => SIZE[BcdDefs.MTRecord[multiple]],
ENDCASE => ERROR);
IF LOOPHOLE[mti, CARDINAL] > LOOPHOLE[innards.bcd.mtLimit, CARDINAL]
THEN {
CWF.WF0["Garbage Module.\n"L];
GO TO return;
};
ENDLOOP;
EXITS return => {};
}; -- of ENABLE UNWIND
Subr.FreeString[modname]; Subr.FreeString[filename];
};
IsRealTime: PUBLIC PROC[stamp: LONG CARDINAL] RETURNS[isrealtime: BOOL] = {
uses heuristics
note: 1yr = 31,536,000 seconds
time: LONG CARDINAL ← Time.Current[];
RETURN[time >= stamp AND stamp >= time - 30000000];
};
PutName: PROC [innards: ProcBcds.Innards, n: BcdDefs.NameRecord, stemp: LONG STRING] = {
i: INTEGER;
str: LONG STRING ← Subr.AllocateString[100];
ssd: LongString.SubStringDescriptor ←
[base: @innards.ssb.string, offset: n, length: MIN[innards.ssb.size[n], 100]];
{ENABLE UNWIND => {Subr.FreeString[str]};
omit a leading directory name
LongString.AppendSubString[str, @ssd];
i ← IF str.length > 0 THEN str.length - 1 ELSE 0;
WHILE i >= 0 DO
IF str[i] = '> OR str[i] = '/ THEN EXIT;
i ← i - 1;
ENDLOOP;
IF i >= 0
THEN Subr.SubStrCopy[stemp, str, i+1]
ELSE Subr.strcpy[stemp, str];
}; -- of ENABLE UNWIND
Subr.FreeString[str];
};
PrintFileName: PROC [innards: ProcBcds.Innards, fti: BcdDefs.FTIndex, stemp: LONG STRING] = {
if no '.' is present, explicitely append ".bcd" at the end of stemp
SELECT fti FROM
BcdDefs.FTNull => {
CWF.SWF0[stemp, "(null)"L];
ERROR;
};
BcdDefs.FTSelf => {
CWF.SWF0[stemp, "(self)"L];
ERROR;
};
ENDCASE => {
PutName[innards, innards.ftb[fti].name, stemp];
IF NOT Subr.Any[stemp, '.] THEN LongString.AppendString[stemp, ".bcd"L];
};
RETURN
};
}.