ListUsing.mesa
modified by Bruce, 13-Jan-81 11:05:04
modified by Sweet, May 16, 1980 9:37 AM
modified by Satterthwaite, May 10, 1983 12:58 pm
DIRECTORY
Ascii: TYPE USING [SP, CR, NUL],
CommanderOps: TYPE USING [AddCommand, CommandBlockHandle],
File: TYPE USING [Capability],
FileSegment: TYPE USING [Pages],
FileStream: TYPE USING [Create, EndOf, GetCapability],
Heap: TYPE USING [
Create, Delete, Error, Expand, FreeNode, FreeString, Handle, MakeNode, MakeString],
ListerDefs: TYPE USING [
IncorrectVersion, Load, MultipleModules, NoCode, NoFGT, NoFile,
NoSymbols, SetRoutineSymbols, WriteFileID, WriteLine, WriteString],
LongString: TYPE USING [
AppendChar, AppendString, EquivalentSubStrings, SubString, SubStringDescriptor, UpperCase],
OSMiscOps: TYPE USING [FindFile],
OutputDefs: TYPE USING [
CloseOutput, OpenOutput, PutChar, PutCR, PutLongString, PutLongSubString, outStream],
Stream: TYPE USING [Delete, GetChar, Handle],
Symbols: TYPE USING [BTIndex, CTXIndex, HTIndex, ISEIndex, ISENull, MDIndex, SENull],
SymbolTable: TYPE USING [Acquire, Base, Release];
ListUsing: PROGRAM
IMPORTS
CommanderOps, FileStream, Heap, ListerDefs, LongString, OutputDefs,
OSMiscOps, Stream, SymbolTable = {
OPEN ListerDefs, OutputDefs, Symbols;
symbols: SymbolTable.Base;
myHeap: Heap.Handle ← NIL;
LongSubString: TYPE = LONG POINTER TO LongString.SubStringDescriptor;
Alloc: PROC [nwords: CARDINAL] RETURNS [p: LONG POINTER] = {
OPEN Heap;
p ← MakeNode[
myHeap, nwords
! Error => IF type = insufficientSpace THEN {Expand[myHeap, 1]; RETRY}]};
Free: PROC [p: LONG POINTER] = {Heap.FreeNode[myHeap, p]};
AllocString: PROC [nchars: CARDINAL] RETURNS [s: LONG STRING] = {
OPEN Heap;
s ← MakeString[
myHeap, nchars
! Error => IF type = insufficientSpace THEN {Expand[myHeap, 1]; RETRY}]};
FreeString: PROC [s: LONG STRING] = {Heap.FreeString[myHeap, s]};
InitHeap: PROC = {IF myHeap = NIL THEN myHeap ← Heap.Create[5]};
EraseHeap: PROC = {Heap.Delete[myHeap]; myHeap ← NIL};
PutVeryLongSubString: PROC [s: LongSubString] = {
ss: LongString.SubStringDescriptor ← s^;
PutLongSubString[@ss]};
StringCompare: PROC [s1, s2: LONG STRING] RETURNS [INTEGER] = {
c1, c2: CHAR;
FOR i: CARDINAL IN [0..MIN[s1.length, s2.length]) DO
c1 ← LongString.UpperCase[s1[i]];
c2 ← LongString.UpperCase[s2[i]];
IF c1 < c2 THEN RETURN[-1];
IF c1 > c2 THEN RETURN[1];
ENDLOOP;
RETURN[
SELECT TRUE FROM
s1.length < s2.length => -1,
s1.length > s2.length => 1,
ENDCASE => 0]};
CompareNames: PROC [n1, n2: LongSubString] RETURNS [INTEGER] = {
c1, c2: CHAR;
FOR i: CARDINAL IN [0..MIN[n1.length, n2.length]) DO
c1 ← LongString.UpperCase[n1.base[n1.offset + i]];
c2 ← LongString.UpperCase[n2.base[n2.offset + i]];
SELECT c1 - c2 FROM < 0 => RETURN[-1]; > 0 => RETURN[1]; ENDCASE;
ENDLOOP;
SELECT INTEGER[
n1.length - n2.length] FROM
< 0 => RETURN[-1];
> 0 => RETURN[1];
ENDCASE => RETURN[0]};
SortNames: PROC [na: LONG DESCRIPTOR FOR ARRAY OF LongString.SubStringDescriptor] = {
j: INTEGER;
key: LongString.SubStringDescriptor;
FOR i: CARDINAL IN [1..LENGTH[na]) DO
key ← na[i];
j ← i - 1;
WHILE j >= 0 AND CompareNames[@na[j], @key] > 0 DO
temp: CARDINAL = j + 1;
na[temp] ← na[j];
j ← j - 1;
ENDLOOP;
j ← j + 1;
na[j] ← key;
ENDLOOP};
GenCtx: PROC [ctx: Symbols.CTXIndex, p: PROC [Symbols.ISEIndex]] = {
OPEN symbols;
sei: Symbols.ISEIndex;
FOR sei ← FirstCtxSe[ctx], NextSe[sei] UNTIL sei = SENull DO p[sei]; ENDLOOP};
PrintUsing: PROC = {
OPEN Symbols, symbols;
bti: BTIndex;
ctx: CTXIndex;
sei: ISEIndex;
hti: HTIndex;
mdi: MDIndex;
i, n, idir, ndir: CARDINAL;
first: BOOLTRUE;
desc: LongString.SubStringDescriptor;
modname: LongString.SubString = @desc;
desc2: LongString.SubStringDescriptor;
filename: LongString.SubString = @desc2;
mname: LongSubString;
DirRec: TYPE = RECORD [dirname: LongString.SubStringDescriptor, dirsei: ISEIndex];
da: LONG DESCRIPTOR FOR ARRAY OF DirRec;
na: LONG DESCRIPTOR FOR ARRAY OF LongString.SubStringDescriptor;
firstCopiedHash: Symbols.HTIndex;
countids: PROC [sei: ISEIndex] = {
IF seb[sei].hash < firstCopiedHash THEN n ← n + 1};
insertid: PROC [sei: ISEIndex] = {
OPEN symbols;
IF seb[sei].hash < firstCopiedHash THEN {
ss: LongString.SubStringDescriptor;
SubStringForName[LOOPHOLE[@ss], seb[sei].hash];
na[i] ← ss;
i ← i + 1}};
PutCR[];
FOR hti IN (0..LENGTH[ht]) DO
IF ht[hti].ssIndex = ht[hti - 1].ssIndex THEN {
firstCopiedHash ← hti; EXIT};
REPEAT FINISHED => firstCopiedHash ← LENGTH[ht];
ENDLOOP;
ndir ← 0;
FOR sei ← FirstCtxSe[stHandle.directoryCtx], NextSe[sei] UNTIL sei = ISENull
DO ndir ← ndir + 1; ENDLOOP;
IF ndir = 0 THEN RETURN;
da ← DESCRIPTOR[Alloc[SIZE[DirRec]*ndir], ndir];
ndir ← 0;
FOR sei ← FirstCtxSe[stHandle.directoryCtx], NextSe[sei] UNTIL sei = ISENull
DO
i: INTEGER ← ndir - 1;
SubStringForName[LOOPHOLE[modname], seb[sei].hash];
WHILE i >= 0 AND CompareNames[@da[i].dirname, modname] > 0 DO
da[i + 1] ← da[i]; i ← i - 1; ENDLOOP;
i ← i + 1;         -- for compiler
da[i] ← [modname^, sei];
ndir ← ndir + 1;
ENDLOOP;
FOR idir IN [0..ndir) DO
mname ← @da[idir].dirname;
sei ← da[idir].dirsei;
WITH seb[UnderType[seb[sei].idType]] SELECT FROM
definition => {
isei: ISEIndex;
ctx ← defCtx;
FOR isei ← FirstCtxSe[stHandle.importCtx], NextSe[isei] UNTIL isei =
ISENull DO
WITH seb[UnderType[seb[isei].idType]] SELECT FROM
definition =>
WITH ctxb[defCtx] SELECT FROM
imported =>
IF includeLink = ctx THEN {ctx ← defCtx; EXIT};
ENDCASE;
ENDCASE;
ENDLOOP};
transfer => {bti ← seb[sei].idInfo; ctx ← bb[bti].localCtx};
ENDCASE => ERROR;
n ← 0;
GenCtx[ctx, countids];
WITH ctxb[ctx] SELECT FROM
included => mdi ← module;
imported => {
mdi ← ctxb[includeLink].module;
GenCtx[includeLink, countids]};
ENDCASE => LOOP; -- main body
IF n > 0 THEN na ← DESCRIPTOR[Alloc[SIZE[LongString.SubStringDescriptor]*n], n];
IF n = 0 AND ~mdb[mdi].exported THEN LOOP;
i ← 0;
GenCtx[ctx, insertid];
WITH ctxb[ctx] SELECT FROM
imported => GenCtx[includeLink, insertid];
ENDCASE;
IF first THEN PutLongString["DIRECTORY"L] ELSE PutChar[',];
PutCR[];
first ← FALSE;
PutLongString[" "L];
PutVeryLongSubString[mname];
SubStringForName[LOOPHOLE[filename], mdb[mdi].fileId];
FOR j: CARDINAL IN [0..filename.length) DO
IF filename.base[filename.offset + j] = '. THEN {
filename.length ← j; EXIT};
ENDLOOP;
IF ~Equivalent[mname, filename] THEN {
PutLongString[": FROM """L]; PutLongSubString[filename]; PutChar['"]}
ELSE PutLongString[": TYPE"L];
PutLongString[" USING ["L];
IF n > 0 THEN {
SortNames[na];
PutVeryLongSubString[@na[0]];
FOR i IN (0..LENGTH[na]) DO
PutLongString[", "L]; PutVeryLongSubString[@na[i]]; ENDLOOP;
Free[BASE[na]]};
PutChar[']];
ENDLOOP;
Free[BASE[da]];
PutChar[';];
PutCR[];
PutCR[];
PutCR[];
RETURN};
Equivalent: PROC [s1, s2: LongSubString] RETURNS [BOOL] = {
ss1: LongString.SubStringDescriptor ← s1^;
ss2: LongString.SubStringDescriptor ← s2^;
RETURN [LongString.EquivalentSubStrings[@ss1, @ss2]]};
Item: TYPE = RECORD [
link: LONG POINTER TO Item, value: LONG STRING, sublink: LONG POINTER TO Item];
Head: LONG POINTER TO Item ← NIL;
CopyString: PROC [old: LONG STRING] RETURNS [copy: LONG STRING] = {
IF old = NIL THEN RETURN[NIL];
copy ← AllocString[old.length];
LongString.AppendString[copy, old]};
MakeItem: PROC [value: LONG STRING, link: LONG POINTER TO Item]
RETURNS [item: LONG POINTER TO Item] = {
item ← Alloc[SIZE[Item]];
item^ ← [link: link, value: value, sublink: NIL]};
AddItem: PROC [
value: LONG STRING, list: LONG POINTER TO LONG POINTER TO Item, copyString: BOOLTRUE]
RETURNS [item: LONG POINTER TO Item] = {
prev: LONG POINTER TO Item ← NIL;
FOR item ← list^, item.link UNTIL item = NIL DO
SELECT StringCompare[
item.value, value] FROM
0 => EXIT;
1 => {
item ← MakeItem[IF copyString THEN CopyString[value] ELSE value, item];
IF prev = NIL THEN list^ ← item ELSE prev.link ← item;
EXIT};
ENDCASE;
prev ← item;
REPEAT
FINISHED => {
item ← MakeItem[IF copyString THEN CopyString[value] ELSE value, NIL];
IF prev = NIL THEN list^ ← item ELSE prev.link ← item};
ENDLOOP};
GetToken: PROC [in: Stream.Handle, s: LONG STRING]
RETURNS [term: CHAR] = {
s.length ← 0;
DO
IF FileStream.EndOf[in] THEN GOTO eof;
IF (term ← in.GetChar[]) > Ascii.SP THEN EXIT;
ENDLOOP;
WHILE term IN ['a..'z] OR term IN ['A..'Z] OR term IN ['0..'9] DO
LongString.AppendChar[s, term];
IF FileStream.EndOf[in] THEN GOTO eof;
term ← in.GetChar[];
ENDLOOP;
EXITS eof => term ← Ascii.NUL};
compressing: BOOLFALSE;
list: BOOLFALSE;
Compress: PROC [file: STRING] = {
fh: File.Capability;
dh: Stream.Handle;
compressing ← TRUE;
InitHeap[];
OpenOutput[file, ".ul$"L];
fh ← FileStream.GetCapability[outStream];
ListerDefs.WriteLine["UsingList:"L];
UsingList[file];
CloseOutput[];
SetFileAccess[fh, Read + Write + Append];
dh ← FileStream.Create[fh];
OpenOutput[file, ".ul"L];
ListerDefs.WriteLine["Compressing:"L];
CompressIt[dh];
CloseOutput[];
Stream.Delete[dh];
EraseHeap[];
Head ← NIL;
compressing ← FALSE};
UsingList: PROC [cmd: STRING] = {
s: STRING ← [100];
ch: CHAR;
cs: Stream.Handle ← FileStream.Create[OSMiscOps.FindFile[cmd]];
list ← TRUE;
IF ~compressing THEN InitHeap[];
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 {
IF compressing THEN ListerDefs.WriteString[" "L];
ListerDefs.WriteLine[s];
Using[s]};
ENDLOOP;
Stream.Delete[cs];
IF ~compressing THEN EraseHeap[];
list ← FALSE};
Using: PROC [root: STRING] = {
OPEN LongString;
i: CARDINAL;
defs: BOOLFALSE;
bcdFile: STRING ← [100];
sseg: FileSegment.Pages;
IF ~list AND ~compressing THEN InitHeap[];
AppendString[bcdFile, root];
FOR i IN [0..bcdFile.length) DO
IF bcdFile[i] = '. THEN EXIT;
REPEAT FINISHED => AppendString[bcdFile, ".bcd"L];
ENDLOOP;
BEGIN
[symbols: sseg] ← Load[
bcdFile ! NoFGT => RESUME; NoCode => {defs ← TRUE; RESUME};
NoSymbols, IncorrectVersion, MultipleModules => GOTO badformat;
NoFile => GOTO badname];
symbols ← SymbolTable.Acquire[sseg];
ListerDefs.SetRoutineSymbols[symbols];
IF ~compressing THEN OpenOutput[root, ".ul"L];
WriteFileID[];
IF symbols.sourceFile # NIL THEN {
PutLongString[" Source: "L]; PutLongString[symbols.sourceFile]; PutCR[]};
PrintUsing[];
SymbolTable.Release[symbols];
IF ~compressing THEN CloseOutput[];
IF ~list AND ~compressing THEN EraseHeap[];
EXITS
badformat => ListerDefs.WriteString["Bad Format!"L];
badname => ListerDefs.WriteString["File Not Found!"L];
END};
CompressIt: PROC [input: Stream.Handle] = {
OPEN Ascii;
term: CHAR;
user: STRING ← [40];
userCopy: LONG STRING;
interface: STRING ← [40];
used: STRING ← [40];
int: LONG POINTER TO Item;
DO
userCopy ← NIL;
IF (term ← GetToken[input, user]) = NUL THEN EXIT;
ListerDefs.WriteString[" "L];
ListerDefs.WriteLine[user];
UNTIL term = '; OR term = CR AND StringCompare[interface, "DIRECTORY"L] = 0
DO term ← GetToken[input, interface] ENDLOOP;
IF term = '; THEN LOOP;
UNTIL term = '; DO
term ← GetToken[input, interface];
UNTIL term = ', OR term = '[ OR term = '; DO
term ← GetToken[input, used] ENDLOOP;
IF term = '; THEN EXIT;
IF term = '[ THEN {
intitem: LONG POINTER TO Item ← AddItem[interface, @Head];
item: LONG POINTER TO Item;
IF userCopy = NIL THEN userCopy ← CopyString[user];
DO
term ← GetToken[input, used];
item ← AddItem[used, @intitem.sublink];
[] ← AddItem[userCopy, @item.sublink, FALSE];
IF term = '] THEN EXIT;
ENDLOOP;
term ← GetToken[input, used]};
ENDLOOP;
ENDLOOP;
FOR int ← Head, int.link UNTIL int = NIL DO
item, user: LONG POINTER TO Item;
c: CHAR;
IF int.sublink = NIL THEN LOOP;
PutLongString[int.value];
PutCR[];
FOR item ← int.sublink, item.link UNTIL item = NIL DO
PutLongString[" "L];
PutLongString[item.value];
PutChar[SP];
c ← '(;
FOR user ← item.sublink, user.link UNTIL user = NIL DO
PutChar[c]; c ← SP; PutLongString[user.value]; ENDLOOP;
PutChar[')];
PutCR[];
ENDLOOP;
PutCR[];
ENDLOOP};
command: CommanderOps.CommandBlockHandle;
command ← CommanderOps.AddCommand["Using", LOOPHOLE[Using], 1];
command.params[0] ← [type: string, prompt: "Filename"];
command ← CommanderOps.AddCommand["UsingList", LOOPHOLE[UsingList], 1];
command.params[0] ← [type: string, prompt: "Filename"];
command ← CommanderOps.AddCommand["CompressUsing", LOOPHOLE[Compress], 1];
command.params[0] ← [type: string, prompt: "Filename"];
}.