-- ListUsing.mesa -- modified by Bruce, August 28, 1979 8:51 AM -- modified by Sweet, May 16, 1980 9:37 AM DIRECTORY AltoDefs USING [PageSize], CommanderDefs USING [AddCommand, CommandBlockHandle], FSPDefs, IODefs USING [SP, CR, NUL, WriteLine, WriteString], ListerDefs USING [ IncorrectVersion, Load, MultipleModules, NoCode, NoFGT, NoSymbols, SetRoutineSymbols, WriteFileID], OutputDefs USING [ CloseOutput, OpenOutput, PutChar, PutCR, PutString, PutSubString, outStream], SegmentDefs USING [ DeleteFileSegment, FileHandle, FileNameError, FileSegmentHandle, SwapError, DestroyFile, SetFileAccess, Read, Write, Append, LockFile, UnlockFile], StreamDefs USING [ NewByteStream, Read, StreamHandle, CreateByteStream, StreamError], String USING [ AppendChar, AppendString, EquivalentSubStrings, SubString, SubStringDescriptor, UpperCase, WordsForString], Symbols USING [BTIndex, CTXIndex, HTIndex, ISEIndex, ISENull, MDIndex, SENull], SymbolTable USING [Acquire, Base, Release, TableForSegment], Storage USING [Pages, FreePages]; ListUsing: PROGRAM IMPORTS CommanderDefs, FSPDefs, IODefs, ListerDefs, OutputDefs, SegmentDefs, StreamDefs, String, SymbolTable, Storage EXPORTS ListerDefs = BEGIN OPEN ListerDefs, OutputDefs, Symbols; FileHandle: TYPE = SegmentDefs.FileHandle; symbols: SymbolTable.Base; myHeap: FSPDefs.ZonePointer ← NIL; Alloc: PROCEDURE [nwords: CARDINAL] RETURNS [p: POINTER] = BEGIN OPEN AltoDefs, Storage, FSPDefs; p ← FSPDefs.MakeNode[ myHeap, nwords ! NoRoomInZone => BEGIN AddToNewZone[myHeap, Pages[1], PageSize, FreePages]; RESUME END] END; Free: PROCEDURE [p: POINTER] = BEGIN FSPDefs.FreeNode[myHeap, p] END; AllocString: PROCEDURE [nchars: CARDINAL] RETURNS [s: STRING] = BEGIN s ← Alloc[String.WordsForString[nchars]]; s↑ ← [length: 0, maxlength: nchars, text:]; END; FreeString: PROCEDURE [s: STRING] = LOOPHOLE[Free]; InitHeap: PROCEDURE = BEGIN OPEN Storage; IF myHeap # NIL THEN RETURN; myHeap ← FSPDefs.MakeNewZone[Pages[5], 5*AltoDefs.PageSize, FreePages]; END; EraseHeap: PROCEDURE = BEGIN FSPDefs.DestroyZone[myHeap]; myHeap ← NIL; END; StringCompare: PROCEDURE [s1, s2: STRING] RETURNS [INTEGER] = BEGIN i: CARDINAL; c1, c2: CHARACTER; FOR i IN [0..MIN[s1.length, s2.length]) DO c1 ← String.UpperCase[s1[i]]; c2 ← String.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] END; CompareNames: PROCEDURE [n1, n2: String.SubString] RETURNS [INTEGER] = BEGIN i: CARDINAL; c1, c2: CHARACTER; FOR i IN [0..MIN[n1.length, n2.length]) DO c1 ← String.UpperCase[n1.base[n1.offset + i]]; c2 ← String.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]; END; SortNames: PROCEDURE [na: DESCRIPTOR FOR ARRAY OF String.SubStringDescriptor] = BEGIN i: CARDINAL; j: INTEGER; key: String.SubStringDescriptor; FOR i IN [1..LENGTH[na]) DO key ← na[i]; j ← i - 1; WHILE j >= 0 AND CompareNames[@na[j], @key] > 0 DO na[j + 1] ← na[j]; j ← j - 1; ENDLOOP; na[j + 1] ← key; ENDLOOP; END; GenCtx: PROCEDURE [ctx: Symbols.CTXIndex, p: PROCEDURE [Symbols.ISEIndex]] = BEGIN OPEN symbols; sei: Symbols.ISEIndex; FOR sei ← FirstCtxSe[ctx], NextSe[sei] UNTIL sei = SENull DO p[sei]; ENDLOOP; END; PrintUsing: PROCEDURE = BEGIN OPEN Symbols, symbols; bti: BTIndex; ctx: CTXIndex; sei: ISEIndex; hti: HTIndex; mdi: MDIndex; i, n, idir, ndir: CARDINAL; first: BOOLEAN ← TRUE; desc: String.SubStringDescriptor; modname: String.SubString = @desc; desc2: String.SubStringDescriptor; filename: String.SubString = @desc2; mname: String.SubString; DirRec: TYPE = RECORD [dirname: String.SubStringDescriptor, dirsei: ISEIndex]; da: DESCRIPTOR FOR ARRAY OF DirRec; na: DESCRIPTOR FOR ARRAY OF String.SubStringDescriptor; firstCopiedHash: Symbols.HTIndex; countids: PROCEDURE [sei: ISEIndex] = BEGIN IF seb[sei].hash < firstCopiedHash THEN n ← n + 1; END; insertid: PROCEDURE [sei: ISEIndex] = BEGIN OPEN symbols; IF seb[sei].hash < firstCopiedHash THEN BEGIN SubStringForHash[@na[i], seb[sei].hash]; i ← i + 1; END; END; PutCR[]; FOR hti IN (0..LENGTH[ht]) DO IF ht[hti].ssIndex = ht[hti - 1].ssIndex THEN BEGIN firstCopiedHash ← hti; EXIT END; 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 BEGIN i: INTEGER ← ndir - 1; SubStringForHash[modname, seb[sei].hash]; WHILE i >= 0 AND CompareNames[@da[i].dirname, modname] > 0 DO da[i + 1] ← da[i]; i ← i - 1; ENDLOOP; da[i + 1] ← [modname↑, sei]; ndir ← ndir + 1; END; ENDLOOP; FOR idir IN [0..ndir) DO mname ← @da[idir].dirname; sei ← da[idir].dirsei; WITH seb[UnderType[seb[sei].idType]] SELECT FROM definition => BEGIN 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 BEGIN ctx ← defCtx; EXIT END; ENDCASE; ENDCASE; ENDLOOP; END; transfer => BEGIN bti ← seb[sei].idInfo; ctx ← bb[bti].localCtx; END; ENDCASE => ERROR; n ← 0; GenCtx[ctx, countids]; WITH ctxb[ctx] SELECT FROM included => mdi ← module; imported => BEGIN mdi ← ctxb[includeLink].module; GenCtx[includeLink, countids]; END; ENDCASE => LOOP; -- main body IF n > 0 THEN na ← DESCRIPTOR[Alloc[SIZE[String.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 PutString["DIRECTORY"] ELSE PutChar[',]; PutCR[]; first ← FALSE; PutString[" "]; PutSubString[mname]; SubStringForHash[filename, mdb[mdi].fileId]; FOR j: CARDINAL IN [0..filename.length) DO IF filename.base[filename.offset + j] = '. THEN BEGIN filename.length ← j; EXIT END; ENDLOOP; IF ~String.EquivalentSubStrings[mname, filename] THEN BEGIN PutString[": FROM """]; PutSubString[filename]; PutChar['"]; END; PutString[" USING ["]; IF n > 0 THEN BEGIN SortNames[na]; PutSubString[@na[0]]; FOR i IN (0..LENGTH[na]) DO PutString[", "]; PutSubString[@na[i]]; ENDLOOP; Free[BASE[na]]; END; PutChar[']]; ENDLOOP; Free[BASE[da]]; PutChar[';]; PutCR[]; PutCR[]; PutCR[]; RETURN END; Item: TYPE = RECORD [ link: POINTER TO Item, value: STRING, sublink: POINTER TO Item]; Head: POINTER TO Item ← NIL; CopyString: PROCEDURE [old: STRING] RETURNS [copy: STRING] = BEGIN IF old = NIL THEN RETURN[NIL]; copy ← AllocString[old.length]; String.AppendString[copy, old]; END; MakeItem: PROCEDURE [value: STRING, link: POINTER TO Item] RETURNS [item: POINTER TO Item] = BEGIN item ← Alloc[SIZE[Item]]; item↑ ← [link: link, value: value, sublink: NIL]; END; AddItem: PROCEDURE [ value: STRING, list: POINTER TO POINTER TO Item, copyString: BOOLEAN ← TRUE] RETURNS [item: POINTER TO Item] = BEGIN prev: POINTER TO Item ← NIL; FOR item ← list↑, item.link UNTIL item = NIL DO SELECT StringCompare[ item.value, value] FROM 0 => EXIT; 1 => BEGIN item ← MakeItem[IF copyString THEN CopyString[value] ELSE value, item]; IF prev = NIL THEN list↑ ← item ELSE prev.link ← item; EXIT END; ENDCASE; prev ← item; REPEAT FINISHED => BEGIN item ← MakeItem[IF copyString THEN CopyString[value] ELSE value, NIL]; IF prev = NIL THEN list↑ ← item ELSE prev.link ← item; END; ENDLOOP; END; GetToken: PROCEDURE [in: StreamDefs.StreamHandle, s: STRING] RETURNS [term: CHARACTER] = BEGIN ENABLE StreamDefs.StreamError => GOTO eof; s.length ← 0; WHILE (term ← in.get[in]) <= IODefs.SP DO NULL ENDLOOP; WHILE term IN ['a..'z] OR term IN ['A..'Z] OR term IN ['0..'9] DO String.AppendChar[s, term]; term ← in.get[in] ENDLOOP; EXITS eof => term ← IODefs.NUL; END; compressing: BOOLEAN ← FALSE; list: BOOLEAN ← FALSE; Compress: PROCEDURE [file: STRING] = BEGIN OPEN SegmentDefs; fh: FileHandle; dh: StreamDefs.StreamHandle; compressing ← TRUE; InitHeap[]; OpenOutput[file, ".ul$"L]; WITH d: outStream SELECT FROM Disk => fh ← d.file; ENDCASE => ERROR; IODefs.WriteLine["UsingList:"L]; UsingList[file]; LockFile[fh]; CloseOutput[]; SetFileAccess[fh, Read + Write + Append]; dh ← StreamDefs.CreateByteStream[fh, Read]; OpenOutput[file, ".ul"L]; IODefs.WriteLine["Compressing:"L]; CompressIt[dh]; CloseOutput[]; dh.destroy[dh]; UnlockFile[fh]; DestroyFile[fh]; EraseHeap[]; Head ← NIL; compressing ← FALSE; END; UsingList: PROCEDURE [cmd: STRING] = BEGIN OPEN String, StreamDefs; s: STRING ← [50]; ch: CHARACTER; cs: StreamHandle ← NewByteStream[cmd, Read]; list ← TRUE; IF ~compressing THEN InitHeap[]; UNTIL cs.endof[cs] DO s.length ← 0; WHILE ~cs.endof[cs] AND (ch ← cs.get[cs]) # ' DO AppendChar[s, ch]; ENDLOOP; IF s.length > 0 THEN BEGIN IF compressing THEN IODefs.WriteString[" "L]; IODefs.WriteLine[s]; Using[s]; END; ENDLOOP; cs.destroy[cs]; IF ~compressing THEN EraseHeap[]; list ← FALSE; END; Using: PROCEDURE [root: STRING] = BEGIN OPEN String, SegmentDefs; i: CARDINAL; defs: BOOLEAN ← FALSE; bcdFile: STRING ← [40]; sseg, cseg: FileSegmentHandle; 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"]; ENDLOOP; BEGIN [code: cseg, symbols: sseg] ← Load[ bcdFile ! NoFGT => RESUME ; NoCode => BEGIN defs ← TRUE; RESUME END; NoSymbols, IncorrectVersion, MultipleModules => GOTO badformat; SegmentDefs.FileNameError => GOTO badname]; symbols ← SymbolTable.Acquire[SymbolTable.TableForSegment[sseg]]; IF ~defs THEN SegmentDefs.DeleteFileSegment[cseg ! SegmentDefs.SwapError => CONTINUE]; ListerDefs.SetRoutineSymbols[symbols]; IF ~compressing THEN OpenOutput[root, ".ul"]; WriteFileID[]; IF symbols.sourceFile # NIL THEN BEGIN PutString[" Source: "]; PutString[symbols.sourceFile]; PutCR[]; END; PrintUsing[]; SymbolTable.Release[symbols]; SegmentDefs.DeleteFileSegment[sseg ! SegmentDefs.SwapError => CONTINUE]; IF ~compressing THEN CloseOutput[]; IF ~list AND ~compressing THEN EraseHeap[]; EXITS badformat => IODefs.WriteString["Bad Format!"]; badname => IODefs.WriteString["File Not Found!"]; END; END; CompressIt: PROCEDURE [input: StreamDefs.StreamHandle] = BEGIN OPEN IODefs; term: CHARACTER; user: STRING ← [40]; userCopy: STRING; interface: STRING ← [40]; used: STRING ← [40]; int: POINTER TO Item; DO userCopy ← NIL; IF (term ← GetToken[input, user]) = NUL THEN EXIT; IODefs.WriteString[" "L]; IODefs.WriteLine[user]; UNTIL term = '; OR term = CR AND StringCompare[interface, "DIRECTORY"] = 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 BEGIN intitem: POINTER TO Item ← AddItem[interface, @Head]; item: 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]; END; ENDLOOP; ENDLOOP; FOR int ← Head, int.link UNTIL int = NIL DO BEGIN item, user: POINTER TO Item; c: CHARACTER; IF int.sublink = NIL THEN LOOP; PutString[int.value]; PutCR[]; FOR item ← int.sublink, item.link UNTIL item = NIL DO PutString[" "L]; PutString[item.value]; PutChar[SP]; c ← '(; FOR user ← item.sublink, user.link UNTIL user = NIL DO PutChar[c]; c ← SP; PutString[user.value]; ENDLOOP; PutChar[')]; PutCR[]; ENDLOOP; PutCR[]; END ENDLOOP; END; command: CommanderDefs.CommandBlockHandle; command ← CommanderDefs.AddCommand["Using", LOOPHOLE[Using], 1]; command.params[0] ← [type: string, prompt: "Filename"]; command ← CommanderDefs.AddCommand["UsingList", LOOPHOLE[UsingList], 1]; command.params[0] ← [type: string, prompt: "Filename"]; command ← CommanderDefs.AddCommand["CompressUsing", LOOPHOLE[Compress], 1]; command.params[0] ← [type: string, prompt: "Filename"]; END...