-- ProcBcdsImpl.Mesa, last edit April 5, 1982 10:59 am -- Pilot 6.0/ Mesa 7.0 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, WF3], Directory: TYPE USING [Error, Handle, ignore, 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, SubString, SubStringDescriptor], ProcBcds: TYPE USING [Innards, ProcDep, ProcMod], RTBcd: TYPE USING[RTBase], Space: TYPE USING [Create, CreateUniformSwapUnits, Delete, Handle, LongPointer, Map, nullHandle, virtualMemory], String: TYPE USING [AppendString, EquivalentString], Subr: TYPE USING [Any, ControlChars, GetCreateDate, 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, String, Subr, Time EXPORTS ProcBcds = { useonespace: BOOL = TRUE; -- FALSE has never worked -- uses NO MDS!!! 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] = BEGIN uns: UNSPECIFIED; sourcefile: STRING _ [100]; interfacename: STRING _ [100]; switches: STRING _ [100]; 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; 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]; 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]; RETURN; }; success _ GetModuleName[innards, interfacename]; IF NOT success THEN 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; RETURN; END; PrintDirectory: PROC[innards: ProcBcds.Innards, procDep: ProcBcds.ProcDep, uns: UNSPECIFIED, print: BOOL, bcdfilename: LONG STRING] RETURNS[ntype: CARDINAL] = { modulename: STRING _ [100]; filename: STRING _ [100]; fti: BcdDefs.FTIndex _ FIRST[BcdDefs.FTIndex]; ntype _ 0; UNTIL fti = innards.bcd.ftLimit DO PutName[innards, innards.ftb[fti].name, filename]; IF NOT Subr.Any[filename, '.] THEN String.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]; RETURN; }; ENDLOOP; IF print THEN CWF.WF1[" %d types.\n"L, @ntype]; }; -- returns NIL if can't find modulename GuessModulename: PROC[innards: ProcBcds.Innards, fti: BcdDefs.FTIndex, modulename: STRING] RETURNS[STRING] = { 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]; }; 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 STRING _ NIL, -- 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 ]; -- headerseg initted from ReadIn PrintSymbolsFile: PUBLIC PROC[innards: ProcBcds.Innards, procDep: ProcBcds.ProcDep, uns: UNSPECIFIED, print, allsyms, less: BOOL, bcdfilename: LONG STRING] RETURNS[success: BOOL, ntype: CARDINAL] = { mti, mtLimit: BcdDefs.MTIndex; symseg: BcdDefs.SGIndex; symrecord: SymRecord _ []; shortstr: STRING _ [100]; nullstr: STRING _ ""L; 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; RETURN[success, ntype]; }; -- init from bcd InitSym: PROC[innards: ProcBcds.Innards, sym: Sym, symseg: BcdDefs.SGIndex, less: BOOL, bcdfilename: LONG STRING] RETURNS[success: BOOL] = { npages: CARDINAL; sfnsym: STRING _ [100]; cap: File.Capability; local: BOOL; base: CARDINAL; p: LONG POINTER; success _ FALSE; IF innards.sgb[symseg].class ~= symbols THEN { CWF.WF0["Error - badly formed symbols.\n"L]; RETURN; }; IF innards.sgb[symseg].pages = 0 THEN { CWF.WF1["Warning - No symbols in %s.\n"L, bcdfilename]; 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]; 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]; 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]; }; RETURN[TRUE]; }; -- offset is # words off # base page number, size is # words in range GetSpace: PROC[innards: ProcBcds.Innards, sym: Sym, pbase, offset, size: CARDINAL] RETURNS[buffer: LONG POINTER, space: Space.Handle] = { 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: STRING _ [100]; smodulename: STRING _ [100]; substr: LongString.SubStringDescriptor; 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]; RETURN; }; ENDLOOP; IF print THEN CWF.WF1["%u types, "L, @ntype]; success _ TRUE; }; FindSourceFileName: PROC[sym: Sym, tostr: 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]; }; -- free the segment FreeSym: PROC[sym: Sym] = { 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: 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] = BEGIN OPEN innards.etb[eti]; stemp: STRING _ [100]; stemp1: STRING _ [100]; vers: BcdDefs.VersionStamp; 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]; RETURN; }; -- CWF.WF1["%s"L, stemp]; -- CWF.WF0[", file: "]; -- CWF.WF1["%s"L, stemp1]; vers _ innards.ftb[file].version; procDep[exports, stemp, stemp1, vers, uns]; END; 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: STRING _ [100]; stemp1: STRING _ [100]; vers: BcdDefs.VersionStamp; 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]; RETURN; }; vers _ innards.ftb[file].version; procDep[imports, stemp, stemp1, vers, uns]; }; -- if any one of the bcds ins not codebound, then the config -- is not codebound NotCodeBound: PROC[innards: ProcBcds.Innards, parent: BcdDefs.CTIndex] RETURNS [notcodebound: BOOL] = { 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; }; -- 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 PrintConfigDepends: PROC[innards: ProcBcds.Innards, procDep: ProcBcds.ProcDep,uns: UNSPECIFIED, notcodebound, stopnesting: BOOL] = { cti: BcdDefs.CTIndex _ FIRST[BcdDefs.CTIndex]; modname: STRING _ [100]; filename: STRING _ [100]; topcti: BcdDefs.CTIndex; ok: BOOL; 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]; RETURN; }; ENDLOOP; ProcessModuleTable[innards, procDep, uns, notcodebound]; }; ProcessModuleTable: PROC[innards: ProcBcds.Innards, procDep: ProcBcds.ProcDep, uns: UNSPECIFIED, notcodebound: BOOL] ={ symseg, codeseg: BcdDefs.SGIndex; mti: BcdDefs.MTIndex _ FIRST[BcdDefs.MTIndex]; modname: STRING _ [100]; filename: STRING _ [100]; cti: BcdDefs.CTIndex; 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]; 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 String.EquivalentString[filename, modname] THEN { symfilevers: TimeStamp.Stamp; -- symfilevers _ GetCorrectCreateDate[filename, -- innards.ftb[ -- innards.sgb[symseg].file].version]; 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]; 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]; RETURN; }; ENDLOOP; }; -- skip, since there were too many errors with version stamps -- that were not create dates -- the dates on .Symbols files are off by up to 30 seconds GetCorrectCreateDate: PROC[filename: STRING, verstamp: TimeStamp.Stamp] RETURNS[stamp: TimeStamp.Stamp] = { cap: File.Capability; filetime: LONG CARDINAL; i,j: INT; stamp _ verstamp; -- fix in correct create date cap _ Directory.Lookup[fileName: filename, permissions: Directory.ignore ! Directory.Error => GOTO err]; [create: filetime] _ Subr.GetCreateDate[cap]; -- create date here is actually the time stamp -- if differ by more than 30 seconds, file is no good i _ filetime; j _ verstamp.time; IF IsRealTime[verstamp.time] AND ABS[i - j] > 30 THEN CWF.WF3["Error in symbols file- %s is dated %lt but bound configuration wanted %lt.\n"L, filename, @filetime, @verstamp.time] ELSE stamp.time _ filetime; EXITS err => NULL; -- if its not on the disk, we must assume verstamp }; -- uses heuristics -- note: 1yr = 31,536,000 seconds IsRealTime: PUBLIC PROC[stamp: LONG CARDINAL] RETURNS[isrealtime: BOOL] = { time: LONG CARDINAL _ Time.Current[]; RETURN[time >= stamp AND stamp >= time - 30000000]; }; PutName: PROC [innards: ProcBcds.Innards, n: BcdDefs.NameRecord, stemp: STRING] = BEGIN i: INTEGER; str: STRING _ [100]; ssd: LongString.SubStringDescriptor _ [base: @innards.ssb.string, offset: n, length: MIN[innards.ssb.size[n], 100]]; LongString.AppendSubString[str, @ssd]; -- omit a leading directory name 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]; RETURN END; -- if no '.' is present, explicitely append ".bcd" at the end of stemp PrintFileName: PROC [innards: ProcBcds.Innards, fti: BcdDefs.FTIndex, stemp: STRING] = { 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 String.AppendString[stemp, ".bcd"L]; }; RETURN }; }. OldInitSym: PROC[innards: ProcBcds.Innards, sym: Sym, symseg: BcdDefs.SGIndex, less: BOOL, bcdfilename: LONG STRING] RETURNS[success: BOOL] = { b: LONG POINTER; tB: Table.Base; success _ FALSE; IF innards.sgb[symseg].class ~= symbols THEN { CWF.WF0["Error - badly formed symbols.\n"L]; RETURN; }; IF innards.sgb[symseg].pages = 0 THEN { CWF.WF1["Error - No symbols in %s.\n"L, bcdfilename]; RETURN; }; IF innards.bcdheaderspace ~= Space.nullHandle THEN { npages: CARDINAL; sfnsym: STRING _ [100]; cap: File.Capability; 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]; RETURN; }; } ELSE cap _ innards.cap; npages _ innards.sgb[symseg].pages; IF NOT less THEN npages _ npages + innards.sgb[symseg].extraPages; sym.symbolspace _ Space.Create[parent: Space.virtualMemory, size: npages]; Space.Map[space: sym.symbolspace, window: [file: cap, base: innards.sgb[symseg].base]]; sym.stHandle _ Space.LongPointer[sym.symbolspace]; } ELSE { IF ((innards.sgb[symseg].base * Environment.wordsPerPage) + SIZE[SymbolSegment.STHeader]) > innards.upperLimit THEN { CWF.WF0["Error - symbol segment not in memory.\n"L]; RETURN; }; sym.stHandle _ LOOPHOLE[innards.bcd + ((innards.sgb[symseg].base-1) * Environment.wordsPerPage)]; }; -- init symbols header b _ LOOPHOLE[sym.stHandle]; tB _ LOOPHOLE[sym.stHandle]; IF sym.stHandle.versionIdent ~= SymbolSegment.VersionID THEN { CWF.WF0["Error - Symbols versions do not agree.\n"L]; RETURN; }; sym.ht _ DESCRIPTOR[b+sym.stHandle.htBlock.offset, sym.stHandle.htBlock.size/SIZE[Symbols.HTRecord]]; sym.ssb _ b + sym.stHandle.ssBlock.offset; sym.seb _ tB + sym.stHandle.seBlock.offset; sym.ctxb _ tB + sym.stHandle.ctxBlock.offset; sym.mdb _ tB + sym.stHandle.mdBlock.offset; sym.bb _ tB + sym.stHandle.bodyBlock.offset; sym.tb _ tB + sym.stHandle.treeBlock.offset; sym.ltb _ tB + sym.stHandle.litBlock.offset; sym.extb _ tB + sym.stHandle.extBlock.offset; sym.mdLimit _ FIRST[Symbols.MDIndex] + sym.stHandle.mdBlock.size; sym.extLimit _ FIRST[SymbolSegment.ExtIndex] + sym.stHandle.extBlock.size; sym.mainCtx _ sym.stHandle.outerCtx; RETURN[TRUE]; }; -- if the file is code-bound, then we don't want to call -- the modules it depends on PrintConfigDepends: PROC[innards: ProcBcds.Innards, parent: BcdDefs.CTIndex, procDep: ProcBcds.ProcDep,uns: UNSPECIFIED, notcodebound, stopnesting: BOOL] = { cti: BcdDefs.CTIndex _ FIRST[BcdDefs.CTIndex]; modname: STRING _ [100]; filename: STRING _ [100]; UNTIL cti = innards.bcd.ctLimit DO IF innards.ctb[cti].config = parent THEN { IF 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]; }; -- will only print confignames below this level if stopnesting is true -- stopnesting will only be true if the config entry -- is not FTSelf, indicating a config bound in a config -- and not syntactically nested PrintConfigDepends[innards, cti, procDep, uns, notcodebound, NOT notcodebound]; IF notcodebound OR innards.ctb[cti].file = BcdDefs.FTSelf THEN ProcessModuleTable[innards, cti, procDep, uns, notcodebound]; }; 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; }; ProcessModuleTable: PROC[innards: ProcBcds.Innards, cti: BcdDefs.CTIndex, procDep: ProcBcds.ProcDep, uns: UNSPECIFIED, notcodebound: BOOL] ={ symseg, codeseg: BcdDefs.SGIndex; mti: BcdDefs.MTIndex _ FIRST[BcdDefs.MTIndex]; modname: STRING _ [100]; filename: STRING _ [100]; UNTIL mti = innards.bcd.mtLimit DO IF innards.mtb[mti].config = cti THEN { symseg _ innards.mtb[mti].sseg; IF innards.sgb[symseg].class ~= symbols THEN { CWF.WF0["Error - not symseg\n"L]; 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 String.EquivalentString[filename, modname] THEN { symfilevers: TimeStamp.Stamp; -- symfilevers _ GetCorrectCreateDate[filename, -- innards.ftb[ -- innards.sgb[symseg].file].version]; 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]; 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]; RETURN; }; ENDLOOP; };