-- BcdInfo.mesa; edited by Sandman, July 8, 1980 8:52 AM -- Copyright Xerox Corporation 1979, 1980 DIRECTORY AltoDefs USING [PageSize], AltoFileDefs USING [FP], BcdDefs USING [FTIndex, FTNull, FTSelf, MTIndex, SGIndex, Base, VersionID], BcdInfoDefs USING [], BcdOps USING [ BcdBase, FTHandle, MTHandle, NameString, ProcessModules, ProcessSegs, SGHandle], DirectoryDefs USING [EnumerateDirectory], SegmentDefs USING [ DeleteFileSegment, FileHandle, FileSegmentAddress, FileSegmentHandle, InsertFile, MoveFileSegment, NewFile, NewFileSegment, OldFileOnly, Read, SwapIn, Unlock, VMtoFileSegment], String USING [EquivalentSubStrings, SubString, SubStringDescriptor], Storage USING [Pages, FreePages]; BcdInfo: PROGRAM IMPORTS DirectoryDefs, BcdOps, SegmentDefs, String, Storage EXPORTS BcdInfoDefs = BEGIN OPEN SegmentDefs; bcd: BcdOps.BcdBase ← NIL; bcdseg: FileSegmentHandle ← NIL; SetBcd: PUBLIC PROCEDURE [name: STRING] RETURNS [BcdOps.BcdBase] = BEGIN pages: CARDINAL; ClearFileObjectTable[]; ClearFrameObjectTable[]; IF bcdseg # NIL THEN BEGIN Unlock[bcdseg]; DeleteFileSegment[bcdseg] END; bcdseg ← NewFileSegment[NewFile[name, Read, OldFileOnly], 1, 1, Read]; SwapIn[bcdseg]; bcd ← FileSegmentAddress[bcdseg]; IF (pages ← bcd.nPages) # 1 THEN BEGIN Unlock[bcdseg]; MoveFileSegment[bcdseg, 1, pages]; SwapIn[bcdseg]; bcd ← FileSegmentAddress[bcdseg]; END; IF bcd.versionIdent # BcdDefs.VersionID THEN BEGIN Unlock[bcdseg]; DeleteFileSegment[bcdseg]; RETURN[NIL]; END; RETURN[bcd] END; -- SymbolTable Lookup FTIndex: TYPE = BcdDefs.FTIndex; FTHandle: TYPE = BcdOps.FTHandle; MTIndex: TYPE = BcdDefs.MTIndex; MTHandle: TYPE = BcdOps.MTHandle; SGIndex: TYPE = BcdDefs.SGIndex; SGHandle: TYPE = BcdOps.SGHandle; CodeForModule: PUBLIC PROCEDURE [mti: MTIndex] RETURNS [FileSegmentHandle] = BEGIN f: FrameItem; sgb, mtb: BcdDefs.Base; CodeFile: PROCEDURE [f: FrameItem] RETURNS [BOOLEAN] = BEGIN RETURN[f.mti = mti]; END; IF (f ← EnumFrameObjects[CodeFile]) # NIL THEN RETURN[f.code]; sgb ← LOOPHOLE[bcd + bcd.sgOffset]; mtb ← LOOPHOLE[bcd + bcd.mtOffset]; AddFileName[bcd, mtb[mti].code.sgi, @sgb[mtb[mti].code.sgi]]; LookupFiles[]; AddModuleCode[bcd, mti, @mtb[mti]]; ClearFileObjectTable[]; RETURN[EnumFrameObjects[CodeFile].code] END; SymbolsForModule: PUBLIC PROCEDURE [mti: MTIndex] RETURNS [FileSegmentHandle] = BEGIN f: FrameItem; sgb, mtb: BcdDefs.Base; SymbolFile: PROCEDURE [f: FrameItem] RETURNS [BOOLEAN] = BEGIN RETURN[f.mti = mti]; END; IF (f ← EnumFrameObjects[SymbolFile]) # NIL THEN RETURN[f.symbols]; sgb ← LOOPHOLE[bcd + bcd.sgOffset]; mtb ← LOOPHOLE[bcd + bcd.mtOffset]; AddFileName[bcd, mtb[mti].sseg, @sgb[mtb[mti].sseg]]; LookupFiles[]; AddModuleSymbols[bcd, mti, @mtb[mti]]; ClearFileObjectTable[]; RETURN[EnumFrameObjects[SymbolFile].symbols] END; AddFileName: PUBLIC PROCEDURE [ bcd: BcdOps.BcdBase, sgi: SGIndex, sgh: SGHandle] = BEGIN ExistingFile: PROCEDURE [f: FileItem] RETURNS [BOOLEAN] = BEGIN RETURN[f.fti = sgh.file]; END; f: FileItem; IF EnumFileObjects[ExistingFile] # NIL THEN RETURN; f ← GetFileObject[]; f↑ ← [fileHandle: NIL, fti: sgh.file]; IF sgh.file = BcdDefs.FTSelf THEN f.fileHandle ← SegmentDefs.VMtoFileSegment[bcd].file; RETURN; END; AddModuleSymbols: PROCEDURE [bcd: BcdOps.BcdBase, mti: MTIndex, mth: MTHandle] = BEGIN sgh: SGHandle = @LOOPHOLE[bcd + bcd.sgOffset, BcdDefs.Base][mth.sseg]; SymbolFile: PROCEDURE [f: FileItem] RETURNS [BOOLEAN] = BEGIN RETURN[f.fti = sgh.file]; END; fi: FileItem; fr: FrameItem; symfile: SegmentDefs.FileHandle; symfile ← IF (fi ← EnumFileObjects[SymbolFile]) = NIL THEN NIL ELSE fi.fileHandle; fr ← GetFrameItem[mti]; fr.symbols ← IF symfile = NIL OR sgh.pages = 0 THEN NIL ELSE SegmentDefs.NewFileSegment[ symfile, sgh.base, sgh.pages + sgh.extraPages, SegmentDefs.Read]; RETURN; END; AddModuleCode: PROCEDURE [bcd: BcdOps.BcdBase, mti: MTIndex, mth: MTHandle] = BEGIN OPEN SegmentDefs; sgh: SGHandle = @LOOPHOLE[bcd + bcd.sgOffset, BcdDefs.Base][mth.code.sgi]; CodeFile: PROCEDURE [f: FileItem] RETURNS [BOOLEAN] = BEGIN RETURN[f.fti = sgh.file]; END; fi: FileItem; fr: FrameItem; codeFile: FileHandle; codeFile ← IF (fi ← EnumFileObjects[CodeFile]) = NIL THEN NIL ELSE fi.fileHandle; fr ← GetFrameItem[mti]; fr.code ← IF codeFile = NIL OR sgh.pages = 0 THEN NIL ELSE NewFileSegment[codeFile, sgh.base, sgh.pages, Read]; RETURN; END; FindAllFiles: PUBLIC PROCEDURE = BEGIN EnterFile: PROCEDURE [sgh: SGHandle, sgi: SGIndex] RETURNS [BOOLEAN] = BEGIN AddFileName[bcd, sgi, sgh]; RETURN[FALSE]; END; DoModule: PROCEDURE [mth: MTHandle, mti: MTIndex] RETURNS [BOOLEAN] = BEGIN AddModuleSymbols[bcd, mti, mth]; AddModuleCode[bcd, mti, mth]; RETURN[FALSE]; END; [] ← BcdOps.ProcessSegs[bcd, EnterFile]; LookupFiles[]; [] ← BcdOps.ProcessModules[bcd, DoModule]; ClearFileObjectTable[]; RETURN END; -- File Lookup Object Management FileObject: TYPE = RECORD [ fileHandle: SegmentDefs.FileHandle, fti: BcdDefs.FTIndex]; FileItem: TYPE = POINTER TO FileObject; FileObjectTable: TYPE = RECORD [ link: POINTER TO FileObjectTable, subTable: ARRAY [0..0) OF FileObject]; fileTable: POINTER TO FileObjectTable ← NIL; nFiles: CARDINAL ← MaxNFileObjects; MaxNFileObjects: CARDINAL = (AltoDefs.PageSize - 1)/SIZE[FileObject]; GetFileObject: PROCEDURE RETURNS [f: FileItem] = BEGIN newTable: POINTER TO FileObjectTable; IF nFiles < MaxNFileObjects THEN BEGIN f ← @fileTable.subTable[nFiles]; nFiles ← nFiles + 1; END ELSE BEGIN newTable ← Storage.Pages[1]; newTable.link ← fileTable; fileTable ← newTable; nFiles ← 1; RETURN[@fileTable.subTable[0]]; END; END; EnumFileObjects: PROCEDURE [proc: PROCEDURE [f: FileItem] RETURNS [BOOLEAN]] RETURNS [f: FileItem] = BEGIN i: CARDINAL; table: POINTER TO FileObjectTable; IF fileTable = NIL THEN RETURN[NIL]; IF nFiles < MaxNFileObjects THEN FOR i IN [0..nFiles) DO IF proc[f ← @fileTable.subTable[i]] THEN RETURN; ENDLOOP; FOR table ← fileTable.link, table.link UNTIL table = NIL DO FOR i IN [0..MaxNFileObjects) DO IF proc[f ← @table.subTable[i]] THEN RETURN; ENDLOOP; ENDLOOP; RETURN[NIL]; END; ClearFileObjectTable: PROCEDURE = BEGIN table: POINTER TO FileObjectTable; UNTIL fileTable = NIL DO table ← fileTable; fileTable ← fileTable.link; Storage.FreePages[table]; ENDLOOP; nFiles ← MaxNFileObjects; RETURN END; -- Symbol Table Management FrameObject: TYPE = RECORD [mti: MTIndex, symbols, code: FileSegmentHandle]; FrameItem: TYPE = POINTER TO FrameObject; FrameObjectTable: TYPE = RECORD [ link: POINTER TO FrameObjectTable, subTable: ARRAY [0..0) OF FrameObject]; frameTable: POINTER TO FrameObjectTable ← NIL; nFrames: CARDINAL ← MaxNFrameObjects; MaxNFrameObjects: CARDINAL = (AltoDefs.PageSize - 1)/SIZE[FrameObject]; GetFrameItem: PROCEDURE [mti: MTIndex] RETURNS [f: FrameItem] = BEGIN FindMatch: PROCEDURE [f: FrameItem] RETURNS [BOOLEAN] = BEGIN RETURN[f.mti = mti]; END; IF (f ← EnumFrameObjects[FindMatch]) = NIL THEN f ← NewFrameItem[mti]; END; NewFrameItem: PROCEDURE [mti: MTIndex] RETURNS [f: FrameItem] = BEGIN newTable: POINTER TO FrameObjectTable; IF nFrames < MaxNFrameObjects THEN BEGIN f ← @frameTable.subTable[nFrames]; nFrames ← nFrames + 1; END ELSE BEGIN newTable ← Storage.Pages[1]; newTable.link ← frameTable; frameTable ← newTable; nFrames ← 1; f ← @frameTable.subTable[0]; END; f↑ ← [mti: mti, code: NIL, symbols: NIL]; END; EnumFrameObjects: PROCEDURE [proc: PROCEDURE [f: FrameItem] RETURNS [BOOLEAN]] RETURNS [f: FrameItem] = BEGIN i: CARDINAL; table: POINTER TO FrameObjectTable; IF frameTable = NIL THEN RETURN[NIL]; IF nFrames < MaxNFrameObjects THEN FOR i IN [0..nFrames) DO IF proc[f ← @frameTable.subTable[i]] THEN RETURN; ENDLOOP; FOR table ← frameTable.link, table.link UNTIL table = NIL DO FOR i IN [0..MaxNFrameObjects) DO IF proc[f ← @table.subTable[i]] THEN RETURN; ENDLOOP; ENDLOOP; RETURN[NIL]; END; ClearFrameObjectTable: PROCEDURE = BEGIN table: POINTER TO FrameObjectTable; UNTIL frameTable = NIL DO table ← frameTable; frameTable ← frameTable.link; Storage.FreePages[table]; ENDLOOP; nFrames ← MaxNFrameObjects; RETURN END; -- Directory Lookup of File Table nFilesToFind: CARDINAL; LookupFiles: PUBLIC PROCEDURE = BEGIN name: STRING ← [40]; CountFilesToLookup: PROCEDURE [f: FileItem] RETURNS [BOOLEAN] = BEGIN nFilesToFind ← nFilesToFind + 1; RETURN[FALSE]; END; nFilesToFind ← 0; [] ← EnumFileObjects[CountFilesToLookup]; DirectoryDefs.EnumerateDirectory[CheckOne]; RETURN END; CheckOne: PROCEDURE [fp: POINTER TO AltoFileDefs.FP, name: STRING] RETURNS [found: BOOLEAN] = BEGIN OPEN String; i: CARDINAL; dirName: SubStringDescriptor; bcd: SubStringDescriptor ← [base: "bcd"L, offset: 0, length: 3]; file: FileItem; FOR i IN [0..name.length) DO IF name[i] = '. THEN BEGIN IF name.length - i # 5 THEN GOTO UseWholeName; dirName ← [base: name, offset: i + 1, length: 3]; IF ~EquivalentSubStrings[@dirName, @bcd] THEN GOTO UseWholeName; dirName.offset ← 0; dirName.length ← i; GOTO HasBCDExtension; END; REPEAT UseWholeName => NULL; HasBCDExtension => BEGIN [found, file] ← FindFileName[@dirName]; IF found THEN RETURN[ThisIsTheOne[fp, file]]; END; ENDLOOP; dirName ← [base: name, offset: 0, length: name.length - 1]; [found, file] ← FindFileName[@dirName]; RETURN[IF found THEN ThisIsTheOne[fp, file] ELSE FALSE]; END; ThisIsTheOne: PROCEDURE [fp: POINTER TO AltoFileDefs.FP, file: FileItem] RETURNS [BOOLEAN] = BEGIN file.fileHandle ← SegmentDefs.InsertFile[fp, SegmentDefs.Read]; RETURN[(nFilesToFind ← nFilesToFind - 1) = 0]; END; FindFileName: PUBLIC PROCEDURE [name: String.SubString] RETURNS [found: BOOLEAN, file: FileItem] = BEGIN OPEN String; ns: BcdOps.NameString ← LOOPHOLE[bcd + bcd.ssOffset]; ftb: BcdDefs.Base ← LOOPHOLE[bcd + bcd.ftOffset]; filename: SubStringDescriptor ← [base: @ns.string, offset:, length:]; MatchName: PROCEDURE [f: FileItem] RETURNS [BOOLEAN] = BEGIN IF f.fti = BcdDefs.FTNull THEN RETURN[FALSE]; IF f.fti = BcdDefs.FTSelf THEN RETURN[FALSE]; filename.offset ← ftb[f.fti].name; filename.length ← ns.size[ftb[f.fti].name]; IF LastCharIsDot[@filename] THEN name.length ← name.length + 1; RETURN[EquivalentSubStrings[@filename, name]]; END; f: FileItem; f ← EnumFileObjects[MatchName]; RETURN[f # NIL, f]; END; LastCharIsDot: PUBLIC PROCEDURE [name: String.SubString] RETURNS [BOOLEAN] = BEGIN RETURN[name.base[name.offset + name.length - 1] = '.]; END; END...