ListImpl.Mesa
Edited by Bruce on 13-Jan-81 11:01:26
Edited by Sweet on 20-Mar-81 14:10:24
Edited by Lewis on 14-Jan-81 15:59:40
Edited by Satterthwaite on May 10, 1983 12:56 pm
DIRECTORY
Ascii: TYPE USING [CR],
BcdDefs: TYPE,
BcdOps: TYPE USING [BcdBase, NameString],
CommanderOps: TYPE USING [AddCommand, CommandBlockHandle],
FileStream: TYPE USING [Create, EndOf],
FileSegment: TYPE USING [Pages, nullPages],
GSort: TYPE USING [
CompareProcType, Port, PutProcType, SortItemPort, SortStarter, SortStopper, Sort],
ListerDefs: TYPE,
LongString: TYPE,
OSMiscOps: TYPE USING [FileError, FindFile],
OutputDefs: TYPE,
Space: TYPE USING [Handle, Delete, LongPointer],
Stream: TYPE USING [Delete, GetChar, Handle],
Symbols: TYPE,
SymbolTable: TYPE USING [Acquire, Base, Release];
ListImpl: PROGRAM
IMPORTS
CommanderOps, FileStream, GSort, ListerDefs, LongString, OSMiscOps,
OutputDefs, Space, Stream, SymbolTable =
BEGIN OPEN OutputDefs, BcdDefs;
bcd: BcdOps.BcdBase;
tb: Base;
ssb: BcdOps.NameString;
evb: Base;
spb: Base;
ctb: Base;
mtb: Base;
itb: Base;
etb: Base;
sgb: Base;
ftb: Base;
ntb: Base;
typb: Base;
InstallBcd: PROCEDURE [seg: FileSegment.Pages] RETURNS [space: Space.Handle] =
BEGIN
DO
size: CARDINAL;
space ← ListerDefs.MapPages[seg];
bcd ← space.LongPointer;
IF (size ← bcd.nPages) = seg.span.pages THEN EXIT;
seg.span.pages ← size;
Space.Delete[space];
ENDLOOP;
tb ← LOOPHOLE[bcd];
ssb ← LOOPHOLE[bcd + bcd.ssOffset];
ctb ← tb + bcd.ctOffset;
mtb ← tb + bcd.mtOffset;
itb ← tb + bcd.impOffset;
etb ← tb + bcd.expOffset;
sgb ← tb + bcd.sgOffset;
ftb ← tb + bcd.ftOffset;
ntb ← tb + bcd.ntOffset;
evb ← tb + bcd.evOffset;
spb ← tb + bcd.spOffset;
typb ← tb + bcd.typOffset;
RETURN
END;
UnstallBcd: PROCEDURE [space: Space.Handle] =
BEGIN
Space.Delete[space];
RETURN
END;
ScanExports: PROCEDURE [action: PROC[EXPIndex]] =
BEGIN
eti: EXPIndex ← FIRST[EXPIndex];
UNTIL eti = bcd.expLimit DO
action[eti !
ListerDefs.NoFile =>
BEGIN OPEN etb[eti];
ListerDefs.WriteString["Can't find "L];
WriteName[ftb[file].name];
ListerDefs.WriteChar[Ascii.CR];
CONTINUE
END;
ListerDefs.MultipleModules =>
BEGIN OPEN etb[eti];
ListerDefs.WriteString["Bad format for "L];
WriteName[ftb[file].name];
ListerDefs.WriteChar[Ascii.CR];
CONTINUE
END;
ListerDefs.NoSymbols =>
BEGIN OPEN etb[eti];
ListerDefs.WriteString["No symbols for "L];
WriteName[ftb[file].name];
ListerDefs.WriteChar[Ascii.CR];
CONTINUE
END;
ListerDefs.IncorrectVersion =>
BEGIN OPEN etb[eti];
ListerDefs.WriteString["Wrong version: "L];
WriteName[ftb[file].name];
ListerDefs.WriteChar[Ascii.CR];
CONTINUE
END];
UnloadSymbols[];
eti ← eti + etb[eti].size + SIZE[EXPRecord];
IF LOOPHOLE[eti, CARDINAL] > LOOPHOLE[bcd.expLimit, CARDINAL] THEN
GO TO Bogus;
REPEAT Bogus => PrintGarbage[];
ENDLOOP;
RETURN
END;
ExportsToSort: PROC [eti: EXPIndex] =
BEGIN OPEN etb[eti];
i: CARDINAL;
n: CARDINAL ← 0;
link: BcdDefs.Link;
sei: Symbols.ISEIndex;
interfaceName.length ← 0;
AppendName[interfaceName, name];
FOR i IN [0..size) DO
link ← links[i];
IF link # BcdDefs.NullLink THEN
BEGIN
IF ~loaded THEN LoadSymbols[file];
sei ← SeiForItem[i];
IF sei = Symbols.ISENull THEN LOOP;
RecordExport[sei, TRUE];
END;
ENDLOOP;
RETURN
END;
SeiForItem: PROCEDURE [item: CARDINAL] RETURNS [sei: Symbols.ISEIndex] =
BEGIN OPEN symbols;
FOR sei ← FirstCtxSe[stHandle.outerCtx], NextSe[sei] UNTIL sei =
Symbols.ISENull DO
IF seb[sei].idValue = item THEN
SELECT LinkMode[
sei] FROM
val => IF seb[sei].extended THEN RETURN[Symbols.ISENull] ELSE RETURN;
ref => RETURN[sei];
manifest => LOOP; -- constant
ENDCASE => RETURN[Symbols.ISENull];
ENDLOOP;
ERROR;
END;
AddInterface: PROC =
BEGIN OPEN Symbols, symbols;
interfaceName.length ← 0;
LongString.AppendString[interfaceName, moduleName];
LoadSymbolsName[moduleName !
ListerDefs.NoFile =>
BEGIN
ListerDefs.WriteString["Can't find "L];
ListerDefs.WriteString[moduleName];
ListerDefs.WriteChar[Ascii.CR];
GO TO cant;
END];
FOR sei: ISEIndex ← FirstCtxSe[stHandle.outerCtx],
NextSe[sei] UNTIL sei = ISENull DO
SELECT LinkMode[sei] FROM
val, ref => RecordExport[sei, FALSE];
ENDCASE;
ENDLOOP;
UnloadSymbols[];
EXITS
cant => NULL;
END;
symbols: SymbolTable.Base ← NIL;
sseg: FileSegment.Pages ← FileSegment.nullPages;
loaded: BOOLEANFALSE;
LoadSymbols: PROCEDURE [file: FTIndex] =
BEGIN OPEN ListerDefs;
s: STRING ← [60];
IF file = FTNull OR file = FTSelf
OR symbols # NIL OR sseg # FileSegment.nullPages THEN ERROR;
GetBcdName[s, ftb[file].name];
LoadSymbolsName[s];
IF ftb[file].version # symbols.stHandle.version THEN
SIGNAL ListerDefs.IncorrectVersion;
END;
LoadSymbolsName: PROCEDURE [s: STRING] =
BEGIN OPEN ListerDefs;
cseg: FileSegment.Pages;
bs: STRING ← [50];
LongString.AppendString[bs, s];
FOR i: CARDINAL IN [0..bs.length) DO
IF bs[i] = '. THEN EXIT;
REPEAT
FINISHED => LongString.AppendString[bs, ".bcd"L];
ENDLOOP;
[code: cseg, symbols: sseg] ← Load[bs ! NoCode, NoFGT => RESUME ];
symbols ← SymbolTable.Acquire[sseg];
SetRoutineSymbols[symbols];
loaded ← TRUE;
END;
UnloadSymbols: PROCEDURE =
BEGIN
IF symbols # NIL THEN SymbolTable.Release[symbols];
symbols ← NIL;
sseg ← FileSegment.nullPages;
loaded ← FALSE;
END;
Utility Prints
PrintGarbage: PROCEDURE =
BEGIN
PutString["? looks like garbage to me ..."L];
PutCR[];
RETURN
END;
GetBcdName: PUBLIC PROCEDURE [s: STRING, n: NameRecord] =
BEGIN
i: CARDINAL;
ssd: LongString.SubStringDescriptor ←
[base: @ssb.string, offset: n, length: MIN[ssb.size[n], 100]];
s.length ← 0;
LongString.AppendSubString[s, @ssd];
FOR i IN [0..s.length) DO IF s[i] = '. THEN RETURN ENDLOOP;
LongString.AppendString[s, ".bcd"L];
RETURN
END;
Utility Puts
PutName: PUBLIC PROCEDURE [n: NameRecord] =
BEGIN
ssd: LongString.SubStringDescriptor ←
[base: @ssb.string, offset: n, length: MIN[ssb.size[n], 100]];
PutLongSubString[@ssd];
RETURN
END;
AppendName: PUBLIC PROCEDURE [s: STRING, n: NameRecord] =
BEGIN
ssd: LongString.SubStringDescriptor ←
[base: @ssb.string, offset: n, length: MIN[ssb.size[n], 100]];
LongString.AppendSubString[s, @ssd];
RETURN
END;
WriteName: PUBLIC PROCEDURE [n: NameRecord] =
BEGIN
s: LONG STRING = @ssb.string;
last: CARDINAL = MIN[ssb.size[n], 100];
FOR i: CARDINAL ← n, i + 1 UNTIL i >= n + last DO
ListerDefs.WriteChar[s[i]];
ENDLOOP;
RETURN
END;
RecordExport: PROC [item: Symbols.ISEIndex, present: BOOLEAN] =
BEGIN OPEN LongString;
desc: SubStringDescriptor;
sortLength: CARDINAL;
buffer^ ← [
interface: NULL,
module: NULL,
item: [length: 0, maxlength: 100, text:]];
symbols.SubStringForName[LOOPHOLE[@desc], symbols.NameForSe[item]];
AppendSubString[@buffer.item, @desc];
buffer.interface ←
LOOPHOLE[sortLength ← WordsForString[buffer.item.length] + 2];
buffer[buffer.interface] ← [length: 0, maxlength: 100, text:];
AppendString[@buffer[buffer.interface], interfaceName];
sortLength ← sortLength + WordsForString[interfaceName.length];
IF ~present THEN buffer.module ← NullString
ELSE
BEGIN
buffer.module ← LOOPHOLE[sortLength];
buffer[buffer.module] ← [length: 0, maxlength: 100, text:];
AppendString[@buffer[buffer.module], moduleName];
sortLength ← sortLength + WordsForString[moduleName.length];
END;
buffer ← OutToSort[sortLength];
END;
Compare: PROCEDURE [p1, p2: LONG POINTER] RETURNS [i: INTEGER] =
BEGIN OPEN LongString;
k1: KeyBase = p1;
k2: KeyBase = p2;
i ← CompareStrings[@k1[k1.interface], @k2[k2.interface]];
IF i = 0 THEN i ← CompareStrings[@k1.item, @k2.item];
IF i = 0 THEN i ← CompareStrings[@k1[k1.module], @k2[k2.module]];
END;
lastInterface: STRING ← [60];
lastItem: STRING ← [60];
first: BOOLEANTRUE;
Put: PROC [p: LONG POINTER, len: CARDINAL] =
BEGIN
key: KeyBase = p;
NextItem[
interface: @key[key.interface],
item: @key.item,
module: IF key.module = NullString THEN NIL ELSE @key[key.module]];
END;
NextItem: PROCEDURE [interface, item, module: LONG STRING] =
BEGIN OPEN OutputDefs;
IF ~LongString.EqualString[interface, lastInterface] THEN
BEGIN
IF ~first THEN PutChar[')];
first ← TRUE;
PutCR[];
PutCR[];
PutLongString[interface];
lastInterface.length ← 0;
LongString.AppendString[lastInterface, interface];
lastItem.length ← 0;
END;
IF ~LongString.EqualString[item, lastItem] THEN
{IF ~first THEN PutChar[')];
PutCR[]; PutString[" "L]; PutLongString[item];
lastItem.length ← 0; LongString.AppendString[lastItem, item];
first ← TRUE};
IF module # NIL THEN
BEGIN
IF first THEN {PutString[" ("L]; first ← FALSE}
ELSE PutString[", "L];
PutLongString[module];
END;
END;
KeyBase: TYPE = LONG BASE POINTER TO SortKey;
SortKey: TYPE = RECORD [
interface, module: KeyBase RELATIVE POINTER TO StringBody,
item: StringBody];
NullString: KeyBase RELATIVE POINTER TO StringBody = LOOPHOLE[0];
buffer: KeyBase;
interfaceName: STRING ← [60];
moduleName: STRING ← [40];
OutToSort: GSort.SortItemPort;
onLine: CARDINAL;
firstFile: BOOLEANTRUE;
Implementors: PROCEDURE [fileList: STRING] =
BEGIN OPEN OutputDefs;
s: STRING ← [50];
ch: CHARACTER;
open list of names
cs: Stream.Handle ← FileStream.Create[
OSMiscOps.FindFile[fileList ! OSMiscOps.FileError => GO TO notFound]];
crank up the sort package
LOOPHOLE[OutToSort, GSort.Port].out ← GSort.Sort;
buffer ← LOOPHOLE[OutToSort, GSort.SortStarter][
nextItem: @OutToSort, put: Put,
compare: Compare, expectedItemSize: 40, maxItemSize: 70];
OutputDefs.OpenOutput[fileList, ".iml"L];
PutString["Interface items implemented by:"L];
PutCR[]; onLine ← 0;
go through list of names, calling OutToSort
UNTIL FileStream.EndOf[cs] DO
s.length ← 0;
WHILE ~FileStream.EndOf[cs] AND (ch ← cs.GetChar[]) # ' DO
LongString.AppendChar[s, ch] ENDLOOP;
IF s.length > 0 THEN
BEGIN OPEN ListerDefs;
WriteChar[Ascii.CR];
WriteString[" "L];
WriteString[s];
ProcessFile[s];
END;
ENDLOOP;
ListerDefs.WriteChar[Ascii.CR];
Stream.Delete[cs];
PutCR[];
get ready to write output
lastInterface.length ← 0;
lastItem.length ← 0;
shut down the sort package (and call Put many times)
LOOPHOLE[OutToSort, GSort.SortStopper][];
IF ~first THEN PutChar[')];
OutputDefs.PutCR[];
OutputDefs.CloseOutput[];
EXITS notFound => ListerDefs.WriteLine[" Command file not found"L];
END;
ProcessFile: PROCEDURE [root: STRING] =
BEGIN
i: CARDINAL;
bcdfile: STRING ← [40];
file: STRING ← [40];
seg: FileSegment.Pages;
BEGIN
FOR i IN [0..root.length) DO
IF root[i] = '. THEN EXIT;
LongString.AppendChar[bcdfile, root[i]];
ENDLOOP;
LongString.AppendString[file, bcdfile];
LongString.AppendString[bcdfile, ".bcd"];
END;
BEGIN
bcdSpace: Space.Handle;
seg ← [
file: OSMiscOps.FindFile[bcdfile, ! OSMiscOps.FileError => GO TO NoFile],
span: [1, 1]];
bcdSpace ← InstallBcd[seg];
BEGIN
name: BcdDefs.NameRecord = mtb[FIRST[BcdDefs.MTIndex]].name;
moduleName.length ← 0; AppendName[moduleName, name];
IF firstFile THEN firstFile ← FALSE ELSE PutChar[',];
IF onLine + file.length > 70 THEN {PutCR[]; onLine ← 0}
ELSE {PutChar[' ]; onLine ← onLine + 2}; -- 1 for the comma
PutString[file]; onLine ← onLine + file.length;
IF bcd.definitions THEN AddInterface[]
ELSE ScanExports[ExportsToSort];
END;
UnstallBcd[bcdSpace];
EXITS NoFile => ListerDefs.WriteString[" File not found"L];
END;
RETURN
END;
Init: PROCEDURE =
BEGIN
command: CommanderOps.CommandBlockHandle;
command ← CommanderOps.AddCommand[
"Implementors", LOOPHOLE[Implementors], 1];
command.params[0] ← [type: string, prompt: "fileList"];
END;
Init[];
END....