-- CheckIncludes.Mesa
-- Last modified by Sandman on July 8, 1980 9:19 AM
-- Last modified by Lewis on October 14, 1980 11:09 AM
-- Copyright Xerox Corporation 1979, 1980
DIRECTORY
AltoDefs USING [PageCount, PageNumber],
AltoFileDefs USING [CFA, FilenameChars, FP],
BcdDefs USING [
BCD, FTNull, FTSelf, MTIndex, SGIndex, VersionID, VersionStamp, Base],
BcdOps USING [FTHandle, NameString, SGHandle],
DirectoryDefs USING [EnumerateDirectory],
FileLists USING [
feb, ifb, ifdb, EnlargingTables, DoneEnlargingTables, fileList, FE, FEnil,
IncFile, InclusionDepth, IFnil, NullStamp, NullTime, IncFileDesc, IFDnil,
Initialize, Finalize, InsertInUserList, IsInUserList, InsertInFileList,
InsertIncludeFileItem],
ImageDefs USING [BcdTime, StopMesa],
IncludesSymTables USING [
mdb, mdLimit, ssb, ht, LoadSymTables, ReleaseSymTables,
ObsoleteSymbolTable, UnlockSymFileSegments, ReloadSymFileSegments],
IODefs USING [
CR, SP, FF, NumberFormat, ReadID, Rubout, WriteChar, WriteLine,
WriteString],
MiscDefs USING [CommandLineCFA],
OutputDefs USING [
CloseOutput, OpenOutput, PutChar, PutCR, PutNumber, PutString, PutTime],
SegmentDefs USING [
DefaultAccess, DefaultVersion, DeleteFileSegment, FileHandle,
FileSegmentAddress, FileSegmentHandle, InsertFile, LockFile,
MoveFileSegment, NewFile, NewFileSegment, Read, SwapIn, Unlock,
UnlockFile],
SourceTime USING [FindSourceVersion],
StreamDefs USING [
CreateByteStream, GetIndex, JumpToFA, ModifyIndex, Read, SetIndex,
StreamError, StreamHandle],
String USING [
AppendChar, AppendString, AppendSubString, EquivalentString, SubString,
SubStringDescriptor],
Symbols USING [HTIndex, HTNull, MDIndex, MDRecord, NullFileIndex],
TimeDefs USING [AppendDayTime, DefaultTime, PackedTime, UnpackDT];
CheckIncludes: PROGRAM
IMPORTS
DirectoryDefs, FileLists, IODefs, ImageDefs, IncludesSymTables, MiscDefs,
OutputDefs, SegmentDefs, SourceTime, String, TimeDefs, StreamDefs =
BEGIN OPEN SegmentDefs, FileLists;
-- USER-SPECIFIED SWITCHES
SwitchTypes: TYPE = -- default is /io~c~m~n~p~t~d
{consistent, includes, multiple, order, pause, dateFromText,
noCompIfNotOnDisk, debug};
Switches: PACKED ARRAY SwitchTypes OF BOOLEAN ←
[FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE];
-- INITIALIZATION AND FINALIZATION
commandStream: StreamDefs.StreamHandle;
outputFileName: STRING ← [AltoFileDefs.FilenameChars + 1];
Initialize: PROC =
BEGIN
PutHeading[];
GetOutputFileAndSwitches[];
FileLists.Initialize[Switches[debug]];
GetInputFileNames[];
END;
Finalize: PROC =
{FileLists.Finalize[Switches[debug]]};
PutHeading: PROC =
BEGIN OPEN TimeDefs, IODefs;
herald: STRING ← [60];
WriteChar[CR];
String.AppendString[herald, "Alto/Mesa IncludeChecker 6.0 of "L];
AppendDayTime[herald, UnpackDT[ImageDefs.BcdTime[]]];
herald.length ← herald.length - 3;
WriteLine[herald];
herald.length ← 0;
String.AppendString[herald, " "L];
AppendDayTime[herald, UnpackDT[DefaultTime]];
herald.length ← herald.length - 3;
WriteLine[herald];
END;
GetOutputFileAndSwitches: PROC =
BEGIN OPEN IODefs, StreamDefs;
cfa: POINTER TO AltoFileDefs.CFA ← MiscDefs.CommandLineCFA[];
commandStream ← CreateByteStream[
SegmentDefs.InsertFile[@cfa.fp, Read], Read];
JumpToFA[commandStream, @cfa.fa];
BEGIN
WHILE commandStream.get[commandStream ! StreamError => GOTO noFileNames] <=
IODefs.SP DO NULL ENDLOOP;
SetIndex[commandStream, ModifyIndex[GetIndex[commandStream], -1]];
EXITS
noFileNames =>
{commandStream.destroy[commandStream]; commandStream ← NIL};
END;
WriteChar[CR];
GetToken["Output file name/switches? "L, outputFileName];
SetSwitches[outputFileName];
IF outputFileName.length = 0 THEN
String.AppendString[outputFileName, "Includes"L];
END;
GetInputFileNames: PROC =
BEGIN OPEN IODefs;
fileName: STRING ← [AltoFileDefs.FilenameChars + 1];
IF commandStream = NIL THEN WriteLine["Input file names?"L];
GetToken[" File: "L, fileName];
UNTIL fileName.length = 0 DO
FileLists.InsertInUserList[fileName];
GetToken[" File: "L, fileName];
ENDLOOP;
IF commandStream = NIL THEN WriteChar[CR];
END;
GetToken: PROC [prompt, name: STRING] =
BEGIN OPEN IODefs;
c: CHARACTER;
IF commandStream = NIL THEN
BEGIN
WriteString[prompt];
ReadID[name
! Rubout => {WriteLine[" XXX"]; WriteString[prompt]; RETRY}];
WriteChar[CR];
WHILE String.EquivalentString[name, "?"L] DO
DisplayUsageInfo[];
WriteString[prompt];
ReadID[name
! Rubout => {WriteLine[" XXX"]; WriteString[prompt]; RETRY}];
WriteChar[CR];
ENDLOOP;
END
ELSE
BEGIN
name.length ← 0;
UNTIL commandStream.endof[commandStream] DO
c ← commandStream.get[commandStream];
SELECT c FROM
SP, CR => IF name.length > 0 THEN RETURN;
ENDCASE => String.AppendChar[name, c];
ENDLOOP;
END;
END;
DisplayUsageInfo: PROC =
BEGIN OPEN IODefs;
WriteLine[
" If an empty output file name is given, the file ""Includes.list"" is assumed."L];
WriteLine[
" If no extension is given for the output file, "".list"" is assumed."L];
WriteLine[
" Switches may follow the output file name after a ""/"". A ""~"" turns them off."L];
WriteLine[" The switches are:"L];
WriteLine[
" C (consistent compilation command), I (includes/included by relations),"L];
WriteLine[" M (multiple output files), N (compile only files with Bcds on disk),"L];
WriteLine[" O (compilation order),"L];
WriteLine[
" P (put ""/p"" after last definitions file in compilation command,"L];
WriteLine[" S (same as C-I-O), T (source file creation date from text)."L];
WriteLine[" The default switches are IO~C~M~N~T~P."L];
WriteLine[" An empty file name terminates the list of input files."L];
WriteLine[
" If no names are given, all source and bcd files on the disk are processed."L];
WriteChar[CR];
END;
SetSwitches: PROC [s: STRING] =
BEGIN
i, start: CARDINAL;
notMinus: BOOLEAN ← TRUE;
FOR i IN [0..s.length) DO
IF s[i] = '/ THEN {start ← i; EXIT};
REPEAT
FINISHED => RETURN;
ENDLOOP;
FOR i IN (start..s.length) DO
SELECT s[
i] FROM
'/ => LOOP;
'-, '~ => {notMinus ← FALSE; LOOP};
'c, 'C => Switches[consistent] ← notMinus;
'i, 'I => Switches[includes] ← notMinus;
'm, 'M => Switches[multiple] ← notMinus;
'n, 'N => Switches[noCompIfNotOnDisk] ← notMinus;
'o, 'O => Switches[order] ← notMinus;
's, 'S =>
IF notMinus THEN -- star hack (=C~I~O)
BEGIN
Switches[consistent] ← TRUE;
Switches[includes] ← Switches[order] ← FALSE;
END;
'p, 'P => Switches[pause] ← notMinus;
't, 'T => Switches[dateFromText] ← notMinus;
'd, 'D => Switches[debug] ← notMinus;
ENDCASE => LOOP;
notMinus ← TRUE;
ENDLOOP;
s.length ← start;
END;
-- ADD USER-SPECIFIED FILES TO FILELIST, AND ANY FILES THEY DIRECTLY INCLUDE
AddUserSpecifiedFiles: PROC =
BEGIN OPEN IODefs;
CheckOneFile: PROC [
fp: POINTER TO AltoFileDefs.FP, dirName: STRING]
RETURNS [stop: BOOLEAN] =
BEGIN
fileName: STRING ← [AltoFileDefs.FilenameChars + 1];
ext: STRING ← [AltoFileDefs.FilenameChars + 1];
mesa, bcd: BOOLEAN ← FALSE;
file: SegmentDefs.FileHandle;
SplitFileName[wholename: dirName, name: fileName, ext: ext];
IF String.EquivalentString[ext, "mesa"] THEN mesa ← TRUE
ELSE
IF String.EquivalentString[ext, "bcd"] THEN bcd ← TRUE
ELSE RETURN[FALSE];
IF FileLists.IsInUserList[fileName] THEN
BEGIN
file ← InsertFile[fp, Read];
LockFile[file];
IF mesa THEN AddSourceFile[file, fileName]
ELSE AddObjectFile[file, fileName];
UnlockFile[file];
END;
RETURN[FALSE]
END;
WriteLine["Processing file:"L];
DirectoryDefs.EnumerateDirectory[CheckOneFile];
END;
SplitFileName: PROC [wholename, name, ext: STRING] =
BEGIN
i: CARDINAL;
active: STRING ← name;
name.length ← ext.length ← 0;
FOR i IN [0..wholename.length) DO
IF wholename[i] = '. THEN active ← ext
ELSE String.AppendChar[active, wholename[i]];
ENDLOOP;
END;
AddSourceFile: PROC [sourceFile: FileHandle, fileName: STRING] =
BEGIN OPEN IODefs;
fe: FileLists.FE;
WriteString[" "L]; WriteString[fileName]; WriteLine[".mesa"L];
fe ← FileLists.InsertInFileList[fileName];
feb[fe].source ← TRUE;
feb[fe].sourceTime ← SourceTime.FindSourceVersion[
sourceFile, Switches[dateFromText]];
END;
NotCompilerBcd: ERROR = CODE; -- Binder created or no symbol segment
ObsoleteBcd: ERROR = CODE; -- Bcd or symbol table version not current
CompilerSmashedBcd: ERROR = CODE; -- File had compilation errors
ErroneousBcd: ERROR = CODE;
AddObjectFile: PROC [bcdFile: FileHandle, fileName: STRING] =
BEGIN OPEN String, IODefs;
symFile: FileHandle;
symSegBase, symSegSize: AltoDefs.PageNumber;
bcdVersion: BcdDefs.VersionStamp;
bcdSourceTime: LONG CARDINAL;
defModule, notAlto, crossJumped, longAlto, tableCompiled: BOOLEAN;
fe: FileLists.FE;
BEGIN
[bcdVersion, bcdSourceTime, symFile, symSegBase, symSegSize, defModule,
notAlto, crossJumped, longAlto, tableCompiled] ← ExamineBcd[bcdFile
! NotCompilerBcd => GOTO ignoreBcd;
ObsoleteBcd => GOTO obsoleteBcd;
CompilerSmashedBcd => GOTO compilerSmashedBcd;
ANY => GOTO processingError];
IF symFile # NIL THEN
IncludesSymTables.LoadSymTables[
symFile, symSegBase, symSegSize
! IncludesSymTables.ObsoleteSymbolTable => GOTO obsoleteBcd]
ELSE --no symbols--
IF ~tableCompiled THEN GOTO ignoreBcd;
WriteString[" "L]; WriteString[fileName]; WriteLine[".bcd"L];
fe ← FileLists.InsertInFileList[fileName];
feb[fe].stamp ← bcdVersion;
feb[fe].bcdSourceTime ← bcdSourceTime;
feb[fe].notAlto ← notAlto;
feb[fe].crossJumped ← crossJumped;
feb[fe].longAlto ← longAlto;
feb[fe].tableCompiled ← tableCompiled;
IF defModule THEN feb[fe].depth ← 50 + (feb[fe].depth MOD 50);
-- if defs file was included by another defs file
IF symFile # NIL THEN
BEGIN
ProcessIncludedFiles[fe, fileName ! ErroneousBcd => GOTO erroneousBcd];
IncludesSymTables.ReleaseSymTables[];
IF symFile # bcdFile THEN UnlockFile[symFile];
END;
EXITS
ignoreBcd => NULL;
obsoleteBcd =>
BEGIN
WriteString[" "L];
WriteString[fileName];
WriteLine[".bcd -- compiled by an obsolete compiler"L];
fe ← FileLists.InsertInFileList[fileName];
feb[fe].obsolete ← TRUE;
END;
compilerSmashedBcd =>
BEGIN
WriteString[" "L];
WriteString[fileName];
WriteLine[" -- Bcd was marked invalid due to compilation errors"L];
fe ← FileLists.InsertInFileList[fileName];
feb[fe].erroneous ← TRUE;
END;
processingError =>
BEGIN
WriteString[" "L];
WriteString[fileName];
WriteLine[" -- Processing error"L];
END;
erroneousBcd =>
BEGIN
WriteLine[" -- invalid Bcd"L];
IncludesSymTables.ReleaseSymTables[];
IF symFile # bcdFile THEN UnlockFile[symFile];
END;
END;
END;
ExamineBcd: PROC [bcdFile: FileHandle]
RETURNS [
bcdVersion: BcdDefs.VersionStamp, bcdSourceTime: LONG CARDINAL,
symFile: FileHandle, symSegBase, symSegSize: AltoDefs.PageNumber,
defModule, notAlto, crossJumped, longAlto, tableCompiled: BOOLEAN] =
BEGIN
bcd: POINTER TO BcdDefs.BCD;
bcdPages: AltoDefs.PageCount;
mtb: BcdDefs.Base;
mti: BcdDefs.MTIndex = FIRST[BcdDefs.MTIndex];
bcdseg: FileSegmentHandle ← NewFileSegment[bcdFile, 1, 1, Read];
CleanUp: PROC =
{Unlock[bcdseg]; DeleteFileSegment[bcdseg]};
SwapIn[bcdseg];
bcd ← FileSegmentAddress[bcdseg];
IF (bcdPages ← bcd.nPages) # 1 THEN
BEGIN
Unlock[bcdseg];
MoveFileSegment[bcdseg, 1, bcdPages];
SwapIn[bcdseg];
bcd ← FileSegmentAddress[bcdseg];
END;
IF bcd.versionIdent # BcdDefs.VersionID THEN
IF bcd.versionIdent = FileLists.NullStamp.time THEN
ERROR CompilerSmashedBcd[ ! UNWIND => CleanUp[]]
ELSE ERROR ObsoleteBcd[ ! UNWIND => CleanUp[]];
IF bcd.nConfigs # 0 THEN ERROR NotCompilerBcd[ ! UNWIND => CleanUp[]];
mtb ← LOOPHOLE[bcd + bcd.mtOffset];
bcdVersion ← bcd.version;
bcdSourceTime ← bcd.sourceVersion.time;
defModule ← bcd.definitions;
tableCompiled ← bcd.tableCompiled;
notAlto ← ~mtb[mti].altoCode;
crossJumped ← mtb[mti].crossJumped;
longAlto ← mtb[mti].long AND mtb[mti].altoCode;
[symFile, symSegBase, symSegSize] ← FindSeg[
bcdseg, mtb[mti].sseg ! UNWIND => CleanUp[]];
CleanUp[];
END;
FindSeg: PROC [
bcdSeg: FileSegmentHandle, sgi: BcdDefs.SGIndex]
RETURNS [segFile: FileHandle, segBase, segSize: AltoDefs.PageNumber] =
BEGIN OPEN String;
bcd: POINTER TO BcdDefs.BCD ← FileSegmentAddress[bcdSeg];
segHandle: BcdOps.SGHandle ←
@LOOPHOLE[bcd + bcd.sgOffset, BcdDefs.Base][sgi];
IF segHandle.file = BcdDefs.FTNull THEN {segFile ← NIL; segBase ← 0}
ELSE
BEGIN
IF segHandle.file = BcdDefs.FTSelf THEN segFile ← bcdSeg.file
ELSE
BEGIN
f: BcdOps.FTHandle = @LOOPHOLE[bcd + bcd.ftOffset, BcdDefs.Base][
segHandle.file];
ssb: BcdOps.NameString ← LOOPHOLE[bcd + bcd.ssOffset];
ss: SubStringDescriptor ← [@ssb.string, f.name, ssb.size[f.name]];
segFileName: STRING ← [AltoFileDefs.FilenameChars + 1];
AppendSubString[segFileName, @ss];
AddExtension[segFileName, ".bcd"];
segFile ← NewFile[segFileName, DefaultAccess, DefaultVersion];
LockFile[segFile];
END;
segBase ← segHandle.base;
segSize ← segHandle.pages;
END;
END;
AddExtension: PROC [name, ext: STRING] =
BEGIN
i: CARDINAL;
FOR i IN [0..name.length) DO
IF name[i] = '. THEN RETURN;
ENDLOOP;
String.AppendString[name, ext];
END;
ProcessIncludedFiles: PROC [includer: FileLists.FE, includerName: STRING] =
BEGIN
mdi: Symbols.MDIndex;
includee: FileLists.FE;
includeeName: STRING ← [AltoFileDefs.FilenameChars + 1];
ss: String.SubStringDescriptor;
i: CARDINAL;
FOR mdi ← (FIRST[Symbols.MDIndex] + SIZE[Symbols.MDRecord]),
(mdi + SIZE[Symbols.MDRecord]) UNTIL mdi >= IncludesSymTables.mdLimit DO
SubStringForHash[@ss, IncludesSymTables.mdb[mdi].fileId];
IF ss.length > (AltoFileDefs.FilenameChars + 1) THEN ERROR ErroneousBcd;
includeeName.length ← 0;
FOR i IN [0..ss.length) DO
IF ss.base[ss.offset + i] = '. THEN EXIT;
String.AppendChar[includeeName, ss.base[ss.offset + i]];
ENDLOOP;
includee ← FileLists.InsertInFileList[includeeName];
feb[includer].includes ← FileLists.InsertIncludeFileItem[
incList: feb[includer].includes, fe: includee, feName: includeeName,
stamp: IncludesSymTables.mdb[mdi].stamp,
fileOpenedByCompiler:
(IncludesSymTables.mdb[mdi].file # Symbols.NullFileIndex)];
IncreaseDepth[includee, (feb[includer].depth + 1)];
feb[includee].includedBy ← FileLists.InsertIncludeFileItem[
incList: feb[includee].includedBy,
fe: includer, feName: includerName, stamp: FileLists.NullStamp,
fileOpenedByCompiler: FALSE];
ENDLOOP;
END;
SubStringForHash: PROC [ss: String.SubString, hti: Symbols.HTIndex] =
BEGIN
ss.base ← IncludesSymTables.ssb;
IF hti = Symbols.HTNull THEN ss.offset ← ss.length ← 0
ELSE
BEGIN
ss.offset ← IncludesSymTables.ht[hti - 1].ssIndex;
ss.length ← (IncludesSymTables.ht[hti].ssIndex - ss.offset);
END;
END;
largestDepthCount: FileLists.InclusionDepth ← 0;
IncreaseDepth: PROC [
root: FileLists.FE, minDepth: FileLists.InclusionDepth] =
BEGIN OPEN IODefs;
i: FileLists.IncFile;
includedFileDesc: FileLists.IncFileDesc;
includedFile: FileLists.FE;
IF feb[root].busy THEN
BEGIN
WriteString[" "L];
WriteString[@feb[root].name];
WriteLine[" is dependent upon a module that, in turn, depends upon it"L];
RETURN;
END;
IF feb[root].depth >= minDepth THEN RETURN;
feb[root].busy ← TRUE;
largestDepthCount ← MAX[minDepth, largestDepthCount];
feb[root].depth ← minDepth;
FOR i ← feb[root].includes, ifb[i].link UNTIL i = FileLists.IFnil DO
includedFileDesc ← ifb[i].includeFileDesc;
includedFile ← ifdb[includedFileDesc].file;
IncreaseDepth[includedFile, (minDepth + 1)];
ENDLOOP;
feb[root].busy ← FALSE;
END;
-- DISPLAY FILES WITH SOURCE BUT NO BCD ON DISK
CheckForSourceButNoBcd: PROC =
BEGIN OPEN IODefs;
fe: FileLists.FE;
firstTime: BOOLEAN ← TRUE;
anyWritten: BOOLEAN ← FALSE;
numOnLine: CARDINAL ← 0;
FOR fe ← FileLists.fileList, feb[fe].link UNTIL fe = FileLists.FEnil DO
IF feb[fe].source AND feb[fe].stamp = FileLists.NullStamp
AND ~(feb[fe].obsolete OR feb[fe].erroneous)
AND ~feb[fe].tableCompiled THEN
BEGIN
IF firstTime THEN
BEGIN
WriteChar[CR];
WriteString["The following source files have no Bcds on the disk:"L];
WriteChar[CR];
END;
IF (numOnLine ← numOnLine + 1) > 4 THEN
{WriteChar[CR]; numOnLine ← 1};
WriteString[" "L]; WriteString[@feb[fe].name];
WriteString[".mesa"L];
firstTime ← FALSE;
anyWritten ← TRUE;
END;
ENDLOOP;
IF anyWritten THEN WriteChar[CR];
END;
-- MARK FILES THAT DIRECTLY (THEMSELVES) NEED RECOMPILATION
badFilesExist: BOOLEAN ← FALSE;
MarkDirectBads: PROC =
BEGIN OPEN IODefs;
fe: FileLists.FE;
i: FileLists.IncFile;
incFileDesc: FileLists.IncFileDesc;
incStamp, diskStamp: BcdDefs.VersionStamp;
ClearAllTags[]; -- prepare to tag files referenced in different versions
FOR fe ← FileLists.fileList, feb[fe].link UNTIL fe = FileLists.FEnil DO
SELECT TRUE FROM
feb[fe].obsolete, feb[fe].erroneous => MarkFileBad[fe];
feb[fe].stamp # FileLists.NullStamp => -- bcd is on disk
BEGIN
IF feb[fe].source AND feb[fe].sourceTime # FileLists.NullTime
AND feb[fe].bcdSourceTime # FileLists.NullTime
AND feb[fe].sourceTime > feb[fe].bcdSourceTime THEN MarkFileBad[fe]
ELSE
FOR i ← feb[fe].includes, ifb[i].link UNTIL i = FileLists.IFnil DO
incFileDesc ← ifb[i].includeFileDesc;
incStamp ← ifdb[incFileDesc].stamp;
diskStamp ← feb[ifdb[incFileDesc].file].stamp;
IF incStamp # diskStamp AND incStamp # FileLists.NullStamp AND diskStamp #
FileLists.NullStamp THEN
BEGIN
MarkFileBad[fe];
feb[ifdb[incFileDesc].file].tag ← TRUE; -- tag included file
EXIT;
END;
ENDLOOP;
END;
feb[fe].source => -- source but no bcd on disk
IF ~Switches[noCompIfNotOnDisk] AND ~feb[fe].tableCompiled THEN
MarkFileBad[fe];
ENDCASE;
ENDLOOP;
ClearAllTags[];
END;
MarkFileBad: PROC [fe: FileLists.FE] =
{feb[fe].bad ← badFilesExist ← TRUE};
ClearAllTags: PROC =
BEGIN
fe: FileLists.FE;
FOR fe ← FileLists.fileList, feb[fe].link UNTIL fe = FileLists.FEnil DO
feb[fe].tag ← FALSE ENDLOOP;
END;
PrintFilesInDifferentVersions: PROC =
BEGIN OPEN IODefs;
fe: FileLists.FE;
firstTime: BOOLEAN ← TRUE;
anyWritten: BOOLEAN ← FALSE;
numOnLine: CARDINAL ← 0;
PrintFile: PROC [fe: FileLists.FE] =
BEGIN
IF firstTime THEN
BEGIN
WriteChar[CR];
WriteString[
"The following Bcds are included in a version different than that on disk:"L];
WriteChar[CR];
END;
IF (numOnLine ← numOnLine + 1) >= 4 THEN {WriteChar[CR]; numOnLine ← 1};
WriteString[" "L];
WriteString[@feb[fe].name];
WriteString[".bcd"L];
firstTime ← FALSE;
anyWritten ← TRUE;
END;
FOR fe ← FileLists.fileList, feb[fe].link UNTIL fe = FileLists.FEnil DO
IF feb[fe].tag THEN PrintFile[fe];
ENDLOOP;
IF anyWritten THEN WriteChar[CR];
END;
-- OUTPUT COMPILATION ORDER, INCLUDE/INCLUDED BY RELATIONS, COMPILATION COMMAND
DoOutput: PROC =
BEGIN
IF Switches[order] THEN -- print compilation order
BEGIN
IF Switches[multiple] THEN
BEGIN OPEN String;
s: STRING ← [AltoFileDefs.FilenameChars + 1];
AppendChar[s, '.];
AppendString[s, outputFileName];
IF s[s.length] = '. THEN s.length ← s.length - 1;
OutputDefs.OpenOutput["Source"L, s]
END
ELSE OutputDefs.OpenOutput[outputFileName, ".list"L];
OutputCompileOrder[];
END;
IF Switches[includes] THEN -- print includes/included by relations
BEGIN
IF Switches[multiple] THEN
BEGIN
IF Switches[order] THEN OutputDefs.CloseOutput[];
OutputDefs.OpenOutput[outputFileName, ".includes"L];
END
ELSE IF ~Switches[order] THEN
OutputDefs.OpenOutput[outputFileName, ".list"L];
OutputIncludesRelation[];
IF Switches[multiple] THEN
BEGIN
OutputDefs.CloseOutput[];
OutputDefs.OpenOutput[outputFileName, ".includedBy"L];
END
ELSE OutputDefs.PutChar[IODefs.FF];
OutputIncludedByRelation[];
OutputDefs.CloseOutput[];
END
ELSE IF Switches[order] THEN OutputDefs.CloseOutput[];
IF Switches[consistent] THEN -- put compilation command in Line.Cm
BEGIN
OutputDefs.OpenOutput["Line"L, ".cm"L];
OutputCompilationCommand[];
OutputDefs.CloseOutput[];
END;
END;
OutputCompileOrder: PROC =
BEGIN OPEN OutputDefs;
currentDepth, nextLargestDepth: FileLists.InclusionDepth;
OutputFilesOfDepth: PROC [depth: FileLists.InclusionDepth] =
BEGIN
fe: FileLists.FE;
numOnLine: CARDINAL;
PutString[" "L];
nextLargestDepth ← numOnLine ← 0;
FOR fe ← FileLists.fileList, feb[fe].link UNTIL fe = FileLists.FEnil DO
IF ~feb[fe].tag THEN
IF feb[fe].depth = depth THEN
BEGIN
IF (numOnLine ← numOnLine + 1) > 6 THEN
{PutCR[]; PutString[" "L]; numOnLine ← 1};
PutString[@feb[fe].name];
PutChar[IODefs.SP];
feb[fe].tag ← TRUE;
END
ELSE nextLargestDepth ← MAX[feb[fe].depth, nextLargestDepth];
ENDLOOP;
PutCR[];
END;
PutString["Compilation Order (by inclusion depth):"L];
PutCR[];
ClearAllTags[];
currentDepth ← largestDepthCount;
WHILE currentDepth > 0 DO
OutputFilesOfDepth[currentDepth]; currentDepth ← nextLargestDepth;
ENDLOOP;
ClearAllTags[];
PutCR[];
END;
OutputIncludesRelation: PROC =
BEGIN OPEN OutputDefs;
fe: FileLists.FE;
compilationSourceTimeOutput: BOOLEAN;
FOR fe ← FileLists.fileList, feb[fe].link UNTIL fe = FileLists.FEnil DO
compilationSourceTimeOutput ← FALSE;
SELECT TRUE FROM
feb[fe].obsolete => PrintObsoleteFile[fe];
feb[fe].erroneous => PrintErroneousFile[fe];
feb[fe].stamp # FileLists.NullStamp => -- bcd is on disk
BEGIN
PutFileName[fe, printStamp, 0];
IF feb[fe].bcdSourceTime # FileLists.NullStamp.time THEN
BEGIN
PutString[" (compilation source: "L];
PutTime[feb[fe].bcdSourceTime];
PutChar[')];
compilationSourceTimeOutput ← TRUE;
END;
IF feb[fe].source AND feb[fe].sourceTime # FileLists.NullStamp.time THEN
BEGIN
IF compilationSourceTimeOutput THEN {PutCR[]; PutString[" "L]}
ELSE PutChar[IODefs.SP];
IF feb[fe].bcdSourceTime # FileLists.NullStamp.time
AND feb[fe].sourceTime > feb[fe].bcdSourceTime THEN PutChar['*];
PutString["(source on disk: "L];
IF feb[fe].bcdSourceTime # FileLists.NullStamp.time
AND feb[fe].bcdSourceTime = feb[fe].sourceTime THEN
PutString["[same]"L]
ELSE PutTime[feb[fe].sourceTime];
PutChar[')];
END;
PutString[" includes"L];
IF feb[fe].includes = FileLists.IFnil THEN PutString[" nothing"L]
ELSE PrintIncludedFiles[fe];
PutCR[]; PutCR[];
END;
ENDCASE;
ENDLOOP;
END;
PrintObsoleteFile: PROC [fe: FileLists.FE] =
BEGIN OPEN OutputDefs;
PutChar['*];
PutFileName[fe, noStamp, 0];
PutString[" was compiled by an obsolete version of the compiler"L];
PutCR[]; PutCR[];
END;
PrintErroneousFile: PROC [fe: FileLists.FE] =
BEGIN OPEN OutputDefs;
PutChar['*];
PutFileName[fe, noStamp, 0];
PutString[" was marked invalid because of compilation errors"L];
PutCR[]; PutCR[];
END;
PrintIncludedFiles: PROC [fe: FileLists.FE] =
BEGIN OPEN OutputDefs;
i: FileLists.IncFile;
FOR i ← feb[fe].includes, ifb[i].link UNTIL i = FileLists.IFnil DO
BEGIN
incFileDesc: FileLists.IncFileDesc = ifb[i].includeFileDesc;
incStamp: BcdDefs.VersionStamp = ifdb[incFileDesc].stamp;
incFile: FileLists.FE = ifdb[incFileDesc].file;
incBad: BOOLEAN =
incStamp # feb[incFile].stamp
AND feb[incFile].stamp # FileLists.NullStamp;
PutCR[];
PutChar[IODefs.SP];
PutChar[IF incBad THEN '* ELSE IODefs.SP];
PutFileName[incFile, printStamp, 0];
IF incBad THEN
BEGIN
PutString[", but version included was ("L];
PutStamp[incStamp];
PutChar[')];
END
ELSE IF incStamp = FileLists.NullStamp THEN
PutString[" ** never referenced"L];
END;
ENDLOOP;
END;
PutStamp: PROC [s: BcdDefs.VersionStamp] =
BEGIN OPEN OutputDefs;
PutTime[s.time];
PutChar[IODefs.SP];
PutNumber[s.net, [8, FALSE, FALSE, 1]];
PutChar['#];
PutNumber[s.host, [8, FALSE, FALSE, 1]];
PutChar['#];
END;
PutFileName: PROC [
fe: FileLists.FE, stampFlag: {printStamp, noStamp}, padLen: CARDINAL] =
BEGIN OPEN OutputDefs;
PutString[@feb[fe].name];
IF padLen # 0 THEN
BEGIN
IF feb[fe].name.length < padLen THEN
THROUGH [0..(padLen - feb[fe].name.length)) DO
PutChar[IODefs.SP];
ENDLOOP
ELSE PutChar[IODefs.SP];
END;
IF stampFlag = printStamp THEN
IF feb[fe].stamp.time # FileLists.NullStamp.time THEN
{PutString[" ("L]; PutStamp[feb[fe].stamp]; PutChar[')]};
END;
OutputIncludedByRelation: PROC =
BEGIN OPEN OutputDefs;
fe, incByFile: FileLists.FE;
i: FileLists.IncFile;
incFileDesc: FileLists.IncFileDesc;
lhs: BOOLEAN;
FOR fe ← FileLists.fileList, feb[fe].link UNTIL fe = FileLists.FEnil DO
IF feb[fe].stamp # FileLists.NullStamp
OR (feb[fe].obsolete OR feb[fe].erroneous) THEN
BEGIN
PutFileName[fe, noStamp, 0];
PutString[" is included by"L];
IF feb[fe].includedBy = FileLists.IFnil THEN PutString[" nothing"L]
ELSE
BEGIN
lhs ← TRUE;
FOR i ← feb[fe].includedBy, ifb[i].link UNTIL i = FileLists.IFnil DO
incFileDesc ← ifb[i].includeFileDesc;
incByFile ← ifdb[incFileDesc].file;
IF lhs THEN
{PutCR[]; PutString[" "L]; PutFileName[incByFile, noStamp, 22]}
ELSE PutFileName[incByFile, noStamp, 0];
lhs ← ~lhs;
ENDLOOP;
END;
PutCR[]; PutCR[];
END;
ENDLOOP;
END;
nextLargestBadDepth: FileLists.InclusionDepth ← 0;
lastFileCompiledHadSwitch: BOOLEAN ← FALSE;
numOnLine: CARDINAL;
OutputCompilationCommand: PROC =
BEGIN
badDepth: FileLists.InclusionDepth;
fe: FileLists.FE;
IF badFilesExist THEN
BEGIN
ExtendBadMarks[]; -- mark bad all files depending on directly bad files
IODefs.WriteChar[IODefs.CR];
IODefs.WriteLine["The following compilation command was written to Line.cm:"L];
IODefs.WriteChar[IODefs.CR];
OutputDefs.PutString["Compile"L];
IODefs.WriteString[" Compile"L];
numOnLine ← 0;
ClearAllTags[];
badDepth ← 0;
FOR fe ← FileLists.fileList, feb[fe].link UNTIL fe = FileLists.FEnil DO
IF feb[fe].bad THEN badDepth ← MAX[feb[fe].depth, badDepth];
ENDLOOP;
WHILE badDepth > 0 DO
CompileBadFilesOfDepth[badDepth];
IF Switches[pause] AND nextLargestBadDepth > 0 THEN
BEGIN
OutputDefs.PutString[IF lastFileCompiledHadSwitch THEN "p"L ELSE "/p"L];
IODefs.WriteString[IF lastFileCompiledHadSwitch THEN "p"L ELSE "/p"L];
END;
badDepth ← nextLargestBadDepth;
ENDLOOP;
ClearAllTags[];
OutputDefs.PutCR[]; OutputDefs.PutCR[];
IODefs.WriteChar[IODefs.CR]; IODefs.WriteChar[IODefs.CR];
ListNeededFiles[];
END
ELSE
BEGIN
OutputDefs.PutString["// The files are consistent"L];
OutputDefs.PutCR[];
IODefs.WriteChar[IODefs.CR];
IODefs.WriteLine["The files are consistent"L];
END;
END;
ExtendBadMarks: PROC =
BEGIN
fe: FileLists.FE;
MarkBad: PROC [fe: FileLists.FE] =
BEGIN
i: FileLists.IncFile;
incFileDesc: FileLists.IncFileDesc;
IF feb[fe].tag THEN RETURN; -- fe & includers already marked bad
IF CheckCycle[fe] THEN RETURN;
feb[fe].busy ← TRUE;
FOR i ← feb[fe].includedBy, ifb[i].link UNTIL i = FileLists.IFnil DO
incFileDesc ← ifb[i].includeFileDesc;
MarkBad[ifdb[incFileDesc].file];
ENDLOOP;
feb[fe].bad ← TRUE;
feb[fe].tag ← TRUE;
feb[fe].busy ← FALSE;
END;
ClearAllTags[];
FOR fe ← FileLists.fileList, feb[fe].link UNTIL fe = FileLists.FEnil DO
IF feb[fe].bad THEN MarkBad[fe];
ENDLOOP;
ClearAllTags[];
END;
CheckCycle: PROC [fe: FileLists.FE] RETURNS [BOOLEAN] =
BEGIN OPEN OutputDefs;
IF feb[fe].busy THEN
BEGIN
PutCR[];
PutString["-- "L];
PutString[@feb[fe].name];
PutString[" is dependent upon a module that, in turn, depends upon it"L];
PutCR[];
END;
RETURN[feb[fe].busy];
END;
CompileBadFilesOfDepth: PROC [depth: FileLists.InclusionDepth] =
BEGIN
fe: FileLists.FE;
nextLargestBadDepth ← 0;
FOR fe ← FileLists.fileList, feb[fe].link UNTIL fe = FileLists.FEnil DO
IF feb[fe].bad AND ~feb[fe].tag THEN
IF feb[fe].depth = depth THEN
BEGIN
lastFileCompiledHadSwitch ← FALSE;
OutputDefs.PutChar[IODefs.SP];
OutputDefs.PutString[@feb[fe].name];
IF (numOnLine ← numOnLine + 1) > 5 THEN
BEGIN
IODefs.WriteChar[IODefs.CR]; IODefs.WriteString[" "L];
numOnLine ← 1;
END
ELSE IODefs.WriteChar[IODefs.SP];
IODefs.WriteString[@feb[fe].name];
IF feb[fe].notAlto OR feb[fe].crossJumped OR feb[fe].longAlto THEN
BEGIN
OutputDefs.PutChar['/]; IODefs.WriteChar['/];
IF feb[fe].notAlto THEN
{OutputDefs.PutString["-a"L]; IODefs.WriteString["-a"L]};
IF feb[fe].crossJumped THEN
{OutputDefs.PutChar['j]; IODefs.WriteChar['j]};
IF feb[fe].longAlto THEN
{OutputDefs.PutChar['l]; IODefs.WriteChar['l]};
lastFileCompiledHadSwitch ← TRUE;
END;
feb[fe].tag ← TRUE;
END
ELSE nextLargestBadDepth ← MAX[feb[fe].depth, nextLargestBadDepth];
ENDLOOP;
END;
ListNeededFiles: PROC =
BEGIN
TagNeededFilesNotOnDisk[];
ListNeededSourceFiles[];
ListNeededBcdFiles[];
END;
TagNeededFilesNotOnDisk: PROC =
BEGIN
fe, incFile: FileLists.FE;
i: FileLists.IncFile;
incFileDesc: FileLists.IncFileDesc;
CheckIfFileRequired: PROC [
fp: POINTER TO AltoFileDefs.FP, dirName: STRING]
RETURNS [stop: BOOLEAN] =
BEGIN OPEN String;
fe: FileLists.FE;
name: STRING ← [AltoFileDefs.FilenameChars + 1];
ext: STRING ← [AltoFileDefs.FilenameChars + 1];
mesa, bcd: BOOLEAN ← FALSE;
SplitFileName[wholename: dirName, name: name, ext: ext];
IF EquivalentString[ext, "mesa"] THEN mesa ← TRUE
ELSE IF EquivalentString[ext, "bcd"] THEN bcd ← TRUE ELSE RETURN[FALSE];
FOR fe ← FileLists.fileList, feb[fe].link UNTIL fe = FileLists.FEnil DO
IF feb[fe].tag AND EquivalentString[@feb[fe].name, name] THEN
BEGIN
IF (bcd AND ~feb[fe].bad) OR (mesa AND feb[fe].bad) THEN
{feb[fe].tag ← FALSE; EXIT};
END;
ENDLOOP;
RETURN[FALSE]
END;
ClearAllTags[];
FOR fe ← FileLists.fileList, feb[fe].link UNTIL fe = FileLists.FEnil DO
IF feb[fe].bad THEN
BEGIN -- tag all files needed to compile "bad" file fe
FOR i ← feb[fe].includes, ifb[i].link UNTIL i = IFnil DO
IF ifb[i].fileOpenedByCompiler THEN
BEGIN
incFileDesc ← ifb[i].includeFileDesc;
incFile ← ifdb[incFileDesc].file;
feb[incFile].tag ← TRUE;
END;
ENDLOOP;
feb[fe].tag ← TRUE;
END;
ENDLOOP;
-- Remove tags if (not bad) bcd or mesa source exists.
DirectoryDefs.EnumerateDirectory[CheckIfFileRequired];
END;
ListNeededSourceFiles: PROC =
BEGIN
fe: FileLists.FE;
firstTime: BOOLEAN ← TRUE;
anyWritten: BOOLEAN ← FALSE;
numOnLine: CARDINAL ← 0;
FOR fe ← FileLists.fileList, feb[fe].link UNTIL fe = FileLists.FEnil DO
IF ~feb[fe].source AND (feb[fe].tag AND feb[fe].bad) THEN
BEGIN -- by def. of tag, source not on disk
IF firstTime THEN
BEGIN
OutputDefs.PutString["// Source files needed for the compilation which are not on the disk:"L];
OutputDefs.PutCR[];
OutputDefs.PutString["// "L];
IODefs.WriteLine["The following source files needed for the compilation are not on the disk:"L];
IODefs.WriteString[" "L];
firstTime ← FALSE;
END;
IF (numOnLine ← numOnLine + 1) > 4 THEN
BEGIN
OutputDefs.PutCR[]; OutputDefs.PutString["// "L];
IODefs.WriteChar[IODefs.CR]; IODefs.WriteString[" "L];
numOnLine ← 1;
END;
OutputDefs.PutString[@feb[fe].name]; OutputDefs.PutString[".mesa"L];
OutputDefs.PutString[" "L];
IODefs.WriteString[@feb[fe].name]; IODefs.WriteString[".mesa"L];
IODefs.WriteString[" "L];
anyWritten ← TRUE;
feb[fe].tag ← FALSE;
END;
ENDLOOP;
IF anyWritten THEN {OutputDefs.PutCR[]; IODefs.WriteChar[IODefs.CR]};
END;
ListNeededBcdFiles: PROC =
BEGIN
fe: FileLists.FE;
firstTime: BOOLEAN ← TRUE;
anyWritten: BOOLEAN ← FALSE;
numOnLine: CARDINAL ← 0;
FOR fe ← FileLists.fileList, feb[fe].link UNTIL fe = FileLists.FEnil DO
IF feb[fe].tag --AND NOT feb[fe].bad-- THEN
BEGIN -- by def. of tag, bcd not on disk
IF firstTime THEN
BEGIN
OutputDefs.PutCR[];
OutputDefs.PutString["// Bcd files needed for the compilation which are not on the disk:"L];
OutputDefs.PutCR[];
OutputDefs.PutString["// "L];
IODefs.WriteChar[IODefs.CR];
IODefs.WriteLine["The following Bcds needed for the compilation are not on the disk:"L];
IODefs.WriteString[" "L];
firstTime ← FALSE;
END;
IF (numOnLine ← numOnLine + 1) > 4 THEN
BEGIN
OutputDefs.PutCR[]; OutputDefs.PutString["// "L];
IODefs.WriteChar[IODefs.CR]; IODefs.WriteString[" "L];
numOnLine ← 1;
END;
OutputDefs.PutString[@feb[fe].name]; OutputDefs.PutString[".bcd"L];
OutputDefs.PutString[" "L];
IODefs.WriteString[@feb[fe].name]; IODefs.WriteString[".bcd"L];
IODefs.WriteString[" "L];
anyWritten ← TRUE;
feb[fe].tag ← FALSE;
END;
ENDLOOP;
IF anyWritten THEN {OutputDefs.PutCR[]; IODefs.WriteChar[IODefs.CR]};
END;
-- MAIN BODY CODE
BEGIN OPEN IODefs;
ENABLE
BEGIN
FileLists.EnlargingTables =>
{IncludesSymTables.UnlockSymFileSegments[]; RESUME};
FileLists.DoneEnlargingTables =>
{IncludesSymTables.ReloadSymFileSegments[]; RESUME};
END;
Initialize[];
AddUserSpecifiedFiles[];
CheckForSourceButNoBcd[];
MarkDirectBads[];
DoOutput[];
Finalize[];
ImageDefs.StopMesa[];
END;
END.