DIRECTORY Basics USING [bytesPerWord], BcdDefs USING [BCD, FTIndex, FTRecord, MTIndex, MTNull, MTRecord, SGRecord, VersionID, VersionStamp], CodeLister USING [ListCode, ListFGT], Commander USING [CommandProc, Register], CommandTool USING [Failed, ParseToList], ConvertUnsafe USING [SubString], FS, FSBackdoor, Literals USING [LitDescriptor, LTIndex, LTNull, LTRecord, MSTIndex, STIndex, STNull], ListerUtils USING [PrintIndex, PrintName, PrintSE, PrintSei, PrintTree, PrintVersion, ReadMtr, ReadSgr, ShortName], IO USING [Close, GetChar, PutChar, PutF, PutF1, PutFR1, PutRope, RIS, RopeFromROS, ROS, SetIndex, STREAM, UnsafeGetBlock], Rope USING [Compare, Concat, Equal, Fetch, Flatten, Length, Match, Replace, ROPE, SkipTo], SymbolPack, Symbols USING [BitAddress, BodyRecord, BTIndex, ContextLevel, CSEIndex, CTXIndex, CTXNull, CTXRecord, HTIndex, ISEIndex, ISENull, lG, lL, lZ, MDIndex, Name, nullName, RootBti, SEIndex, SENull, SERecord, TransferMode, TypeClass, typeTYPE], SymbolTable USING [Acquire, Base, Release], Tree USING [Index, Link, NodeName]; KLister: PROGRAM IMPORTS CodeLister, Commander, CommandTool, FS, FSBackdoor, IO, ListerUtils, Rope, SymbolPack, SymbolTable = BEGIN BCD: TYPE = BcdDefs.BCD; BitAddress: TYPE = Symbols.BitAddress; BTIndex: TYPE = Symbols.BTIndex; BTRecord: TYPE = Symbols.BodyRecord; bytesPerWord: NAT = Basics.bytesPerWord; CSEIndex: TYPE = Symbols.CSEIndex; typeTYPE: CSEIndex = Symbols.typeTYPE; ContextLevel: TYPE = Symbols.ContextLevel; lZ: ContextLevel = Symbols.lZ; lG: ContextLevel = Symbols.lG; lL: ContextLevel = Symbols.lL; CTXIndex: TYPE = Symbols.CTXIndex; CTXNull: CTXIndex = Symbols.CTXNull; CTXRecord: TYPE = Symbols.CTXRecord; FTIndex: TYPE = BcdDefs.FTIndex; FTRecord: TYPE = BcdDefs.FTRecord; HTIndex: TYPE = Symbols.HTIndex; ISEIndex: TYPE = Symbols.ISEIndex; ISENull: ISEIndex = Symbols.ISENull; ISERecord: TYPE = SERecord.id; LTIndex: TYPE = Literals.LTIndex; LTNull: LTIndex = Literals.LTNull; LTRecord: TYPE = Literals.LTRecord; LitDescriptor: TYPE = Literals.LitDescriptor; MDIndex: TYPE = Symbols.MDIndex; MSTIndex: TYPE = Literals.MSTIndex; MSTNull: MSTIndex = LOOPHOLE[STNull]; MTIndex: TYPE = BcdDefs.MTIndex; MTNull: MTIndex = BcdDefs.MTNull; MTRecord: TYPE = BcdDefs.MTRecord; Name: TYPE = Symbols.Name; nullName: Name = Symbols.nullName; NodeName: TYPE = Tree.NodeName; RefBCD: TYPE = REF BCD; RefMTRecord: TYPE = REF MTRecord; RefSGRecord: TYPE = REF SGRecord; RootBti: BTIndex = Symbols.RootBti; ROPE: TYPE = Rope.ROPE; SEIndex: TYPE = Symbols.SEIndex; SENull: SEIndex = Symbols.SENull; SERecord: TYPE = Symbols.SERecord; SGRecord: TYPE = BcdDefs.SGRecord; STIndex: TYPE = Literals.STIndex; STNull: STIndex = Literals.STNull; STREAM: TYPE = IO.STREAM; SubString: TYPE = ConvertUnsafe.SubString; SymbolTableBase: TYPE = SymbolTable.Base; TransferMode: TYPE = Symbols.TransferMode; TypeClass: TYPE = Symbols.TypeClass; VersionStamp: TYPE = BcdDefs.VersionStamp; UC: PROC [c: CHAR] RETURNS [CHAR] = { IF c IN ['a..'z] THEN RETURN ['A + (c - 'a)] ELSE RETURN [c]}; ListSymbols: Commander.CommandProc = TRUSTED { in: STREAM = IO.RIS[cmd.commandLine]; name: ROPE; tempName: ROPE; combinedSymbols, totalFiles: LIST OF REF ANY _ NIL; sortedSymbols: BOOL _ cmd.procData.clientData = $SortedSymbols OR cmd.procData.clientData = $SortedDefs; stream: STREAM _ NIL; inStream: STREAM _ NIL; stb: SymbolTableBase _ NIL; any: BOOL _ FALSE; switches: PACKED ARRAY CHAR['A..'Z] OF BOOL _ ALL[FALSE]; args: LIST OF ROPE _ CommandTool.ParseToList[cmd ! CommandTool.Failed => {msg _ errorMsg; GO TO failed} ].list; Cleanup: PROC = { IF stream # NIL AND stream # cmd.out THEN IO.Close[stream]; IF inStream # NIL THEN IO.Close[inStream]; IF stb # NIL THEN {SymbolTable.Release[stb]; stb _ NIL}; }; IsInCache: PROC [name: ROPE] RETURNS [present: BOOL _ FALSE] = { noteName: FSBackdoor.NameProc = TRUSTED { present _ TRUE; continue _ FALSE; }; FSBackdoor.EnumerateCacheForNames[proc: noteName, pattern: name]; }; EachName: FS.NameProc = TRUSTED { IF IsInCache[fullFName] THEN tempName _ fullFName ELSE tempName _ FS.Copy[from: fullFName, to: "///Temp/Lister.temp$", setKeep: TRUE, keep: 6, remoteCheck: FALSE ! FS.Error => {msg _ error.explanation; GO TO failed} ]; inStream _ FS.StreamOpen[fileName: tempName, remoteCheck: FALSE, streamOptions: [FALSE, TRUE, TRUE, TRUE, TRUE] ! FS.Error => {msg _ error.explanation; GO TO failed} ]; {ENABLE UNWIND => Cleanup[]; short: ROPE _ ListerUtils.ShortName[fullFName]; bcd: RefBCD _ NEW[BCD]; ext: ROPE _ NIL; outName: ROPE _ NIL; configOk: BOOL _ FALSE; defsOK: BOOL _ FALSE; file: FS.OpenFile _ FS.OpenFileFromStream[inStream]; [] _ IO.UnsafeGetBlock[ inStream, [base: LOOPHOLE[bcd], startIndex: 0, count: SIZE[BCD]*bytesPerWord]]; IF switches['M] AND (bcd.nConfigs # 0 OR bcd.definitions) THEN GO TO processNext; SELECT cmd.procData.clientData FROM $Bodies => ext _ ".bodyList"; $Code => ext _ ".codeList"; $FGT => ext _ ".fgtList"; $Files => {ext _ ".filesList"; configOk _ TRUE; defsOK _ TRUE}; $Symbols => {ext _ ".symbolList"; defsOK _ TRUE}; $Using => {ext _ ".usingList"; defsOK _ TRUE}; ENDCASE => ext _ ".list"; IF ext # NIL THEN { SELECT TRUE FROM switches['C] => ext _ NIL; Rope.Match["*.bcd", short, FALSE] => outName _ short.Replace[short.Length[]-4, 4, ext]; ENDCASE => outName _ short.Concat[ext]; }; SELECT TRUE FROM bcd.versionIdent # BcdDefs.VersionID => IO.PutF1[cmd.out, "Not a valid Cedar bcd file: %g\n", [rope[short]]]; bcd.nConfigs # 0 AND ~configOk => IO.PutF1[cmd.out, "Bound configurations not supported: %g\n", [rope[short]]]; bcd.definitions AND NOT defsOK => IO.PutF1[cmd.out, "Definitions files not supported: %g\n", [rope[short]]]; ENDCASE => { sourceName: ROPE _ NIL; IF bcd.nConfigs = 0 THEN { mtr: RefMTRecord = ListerUtils.ReadMtr[inStream, bcd, LOOPHOLE[0]]; sgr: RefSGRecord = ListerUtils.ReadSgr[inStream, bcd, mtr.sseg]; pages: CARDINAL = IF bcd.extended THEN sgr.pages+sgr.extraPages ELSE sgr.pages; IF pages = 0 THEN { IO.PutF1[cmd.out, "Error - no symbols from %g\n", [rope[fullFName]]]; result _ $Failure; GO TO bailOut; }; stb _ SymbolTable.Acquire[[file, [sgr.base-1, pages]]]; }; sourceName _ RopeForBcdName[inStream, bcd.ssOffset, bcd.source]; IF ext = NIL THEN { stream _ cmd.out; IO.PutF1[stream, "Listing for %g\n", [rope[fullFName]] ]; } ELSE { IO.PutF[ cmd.out, "%g output to %g\n", [rope[cmd.command]], [rope[outName]]]; stream _ FS.StreamOpen[outName, $create]; IO.PutRope[stream, outName]; }; IF sortedSymbols THEN { IF ~bcd.definitions AND cmd.procData.clientData = $SortedDefs THEN GO TO bailOut; totalFiles _ CONS[short, totalFiles]; } ELSE { IO.PutF1[stream, "\n object: %g {", [rope[short]]]; ListerUtils.PrintVersion[bcd.version, stream]; IO.PutRope[stream, "}\n source: "]; IO.PutRope[stream, sourceName]; IO.PutRope[stream, " {"]; ListerUtils.PrintVersion[bcd.sourceVersion, stream, TRUE]; IO.PutRope[stream, "}\n creator: {"]; ListerUtils.PrintVersion[bcd.creator, stream]; IO.PutRope[stream, "}\n\n"]; }; SELECT cmd.procData.clientData FROM $Bodies => PrintBodies[stream, stb]; $Code => CodeLister.ListCode[stream, inStream, stb, bcd, NIL]; $FGT => CodeLister.ListFGT[stream, inStream, stb, bcd]; $Files => PrintFiles[stream, bcd, fullFName]; $Symbols => PrintSymbols[bcd.definitions, stream, stb]; $Using => PrintUsing[stream, stb]; ENDCASE; EXITS bailOut => {}; }; Cleanup[]; continue _ TRUE; EXITS processNext => continue _ TRUE; }; EXITS failed => {result _ $Failed; Cleanup[]; continue _ FALSE}; }; WHILE args # NIL DO name _ args.first; args _ args.rest; SELECT TRUE FROM Rope.Match["-*", name] => { sense: BOOL _ TRUE; num: INT _ 0; FOR i: INT IN [1..Rope.Length[name]) DO c: CHAR _ Rope.Fetch[name, i]; SELECT c FROM IN ['A..'Z] => switches[c] _ sense; IN ['a..'z] => switches[c-('a-'A)] _ sense; IN ['0..'9] => num _ num * 10 + (c - '0); '~ => sense _ NOT sense; ENDCASE; ENDLOOP; LOOP; }; Rope.Match["*.bcd", name, FALSE], Rope.Match["*.bcd!*", name, FALSE] => {}; ENDCASE => name _ Rope.Concat[name, ".bcd"]; any _ TRUE; name _ FS.ExpandName[name ! FS.Error => {msg _ error.explanation; GO TO failed}; ].fullFName; IF NOT Rope.Match["*!*", name] THEN name _ Rope.Concat[name, "!h"]; FS.EnumerateForNames[name, EachName]; IF result # NIL THEN GO TO failed; ENDLOOP; IF NOT any THEN { result _ $Failure; msg _ IO.PutFR1["Usage: %g file ...", [rope[cmd.command]]]; }; EXITS failed => result _ $Failure; }; PrintBodies: PUBLIC PROC [stream: STREAM, stb: SymbolTableBase] = { PrintBody: PROC [bti: BTIndex] RETURNS [BOOL] = { body: LONG POINTER TO BTRecord = @stb.bb[bti]; IO.PutRope[stream, "Body: "]; WITH b: body SELECT FROM Callable => { ListerUtils.PrintSei[b.id, stream, stb]; IF b.inline THEN IO.PutRope[stream, " [inline]"] ELSE { IO.PutF1[stream, ", ep: %g", [cardinal[b.entryIndex]]]; WITH b SELECT FROM Inner => IO.PutF1[stream, ", frame addr: %g", [cardinal[frameOffset]]]; ENDCASE; }; IO.PutRope[stream, ", attrs: "]; IO.PutChar[stream, IF ~b.noXfers THEN 'x ELSE '-]; IO.PutChar[stream, IF b.hints.safe THEN 's ELSE '-]; IO.PutChar[stream, IF b.hints.nameSafe THEN 'n ELSE '-]; IF ~b.hints.noStrings THEN IO.PutRope[stream, "\n string literals"]; }; ENDCASE => IO.PutRope[stream, "(anon)"]; IO.PutRope[stream, "\n context: "]; ListerUtils.PrintIndex[body.localCtx, stream]; IO.PutF1[stream, ", level: %g", [cardinal[body.level]]]; WITH body.info SELECT FROM Internal => { IO.PutF1[stream, ", frame size: %g", [cardinal[frameSize]]]; IF body.kind = Callable THEN ListerUtils.PrintTree[[subtree[index: bodyTree]], 0, stream, stb] ELSE {IO.PutRope[stream, ", tree root: "]; ListerUtils.PrintIndex[bodyTree, stream]}; }; ENDCASE; IO.PutRope[stream, "\n\n"]; RETURN [FALSE]; }; [] _ stb.EnumerateBodies[RootBti, PrintBody]; IO.PutRope[stream, "\n"]; }; PrintGlobalFrames: PUBLIC PROC [stream: STREAM, stb: SymbolTableBase] = { PrintBody: PROC [bti: BTIndex] RETURNS [BOOL] = { body: LONG POINTER TO BTRecord = @stb.bb[bti]; IO.PutRope[stream, "Body: "]; WITH b: body SELECT FROM Callable => { ListerUtils.PrintSei[b.id, stream, stb]; IF b.inline THEN IO.PutRope[stream, " [inline]"] ELSE { IO.PutF1[stream, ", ep: %g", [cardinal[b.entryIndex]]]; WITH b SELECT FROM Inner => IO.PutF1[stream, ", frame addr: %g", [cardinal[frameOffset]]]; ENDCASE; }; IO.PutRope[stream, ", attrs: "]; IO.PutChar[stream, IF ~b.noXfers THEN 'x ELSE '-]; IO.PutChar[stream, IF b.hints.safe THEN 's ELSE '-]; IO.PutChar[stream, IF b.hints.nameSafe THEN 'n ELSE '-]; IF ~b.hints.noStrings THEN IO.PutRope[stream, "\n string literals"]; }; ENDCASE => RETURN [FALSE]; IO.PutRope[stream, "\n context: "]; ListerUtils.PrintIndex[body.localCtx, stream]; IO.PutF1[stream, ", level: %g", [cardinal[body.level]]]; WITH body.info SELECT FROM Internal => { IO.PutF1[stream, ", frame size: %g", [cardinal[frameSize]]]; IF body.kind = Callable THEN ListerUtils.PrintTree[[subtree[index: bodyTree]], 0, stream, stb] ELSE {IO.PutRope[stream, ", tree root: "]; ListerUtils.PrintIndex[bodyTree, stream]}; }; ENDCASE; IO.PutRope[stream, "\n\n"]; RETURN [FALSE]; }; [] _ stb.EnumerateBodies[RootBti, PrintBody]; IO.PutRope[stream, "\n"]; }; PrintSymbols: PUBLIC PROC [definitions: BOOL, stream: STREAM, stb: SymbolTableBase] = { ctx: CTXIndex; limit: CTXIndex; limit _ LOOPHOLE[stb.stHandle.ctxBlock.size]; ctx _ CTXIndex.FIRST + CTXRecord.nil.SIZE; UNTIL ctx = limit DO PrintContext[ctx, definitions, stream, stb]; IO.PutRope[stream, "\n\n"]; ctx _ ctx + (WITH stb.ctxb[ctx] SELECT FROM included => CTXRecord.included.SIZE, imported => CTXRecord.imported.SIZE, ENDCASE => CTXRecord.simple.SIZE); ENDLOOP; IO.PutRope[stream, "\n"]; }; PrintContext: PROC [ctx: CTXIndex, definitionsOnly: BOOL, stream: STREAM, stb: SymbolTableBase] = { sei, root: ISEIndex; cp: LONG POINTER TO CTXRecord = @stb.ctxb[ctx]; IO.PutRope[stream, "Context: "]; ListerUtils.PrintIndex[ctx, stream]; IF stb.ctxb[ctx].level # lZ THEN IO.PutF1[stream, ", level: %g", [cardinal[cp.level]]]; WITH c: cp SELECT FROM included => { IO.PutRope[stream, ", copied from: "]; ListerUtils.PrintName[stb.mdb[c.module].moduleId, stream, stb]; IO.PutRope[stream, " ["]; ListerUtils.PrintName[stb.mdb[c.module].fileId, stream, stb]; IO.PutRope[stream, ", "]; ListerUtils.PrintVersion[stb.mdb[c.module].stamp, stream]; IO.PutRope[stream, "], context: "]; ListerUtils.PrintIndex[c.map, stream]; }; imported => { IO.PutRope[stream, ", imported from: "]; ListerUtils.PrintName[stb.mdb[stb.ctxb[c.includeLink].module].moduleId, stream, stb]; }; ENDCASE; root _ sei _ stb.ctxb[ctx].seList; DO IF sei = SENull THEN EXIT; ListerUtils.PrintSE[sei, 2, definitionsOnly , stream, stb]; IF (sei _ stb.NextSe[sei]) = root THEN EXIT; ENDLOOP; }; PrintUsing: PROC [stream: STREAM, stb: SymbolTableBase] = { limit: CTXIndex = LOOPHOLE[stb.stHandle.ctxBlock.size]; ctx: CTXIndex _ CTXIndex.FIRST + CTXRecord.nil.SIZE; firstUsing: BOOL _ TRUE; pairs: LIST OF Pair _ NIL; ros: STREAM _ IO.ROS[]; firstCopiedHash: Symbols.HTIndex; InDirectory: PROC [ctx: CTXIndex] RETURNS [BOOL] = { FOR dirSei: ISEIndex _ stb.FirstCtxSe[stb.stHandle.directoryCtx], stb.NextSe[dirSei] UNTIL dirSei = ISENull DO WITH se: stb.seb[stb.UnderType[stb.seb[dirSei].idType]] SELECT FROM definition => IF ctx = se.defCtx THEN RETURN [TRUE]; ENDCASE; ENDLOOP; RETURN [FALSE]; }; DoContext: PROC [ctx: CTXIndex] = { IF ctx # CTXNull THEN { sei, root: ISEIndex; cp: LONG POINTER TO CTXRecord = @stb.ctxb[ctx]; which: LIST OF Pair _ NIL; key, modName: ROPE _ NIL; mdi: MDIndex; DoSei: PROC [sei: ISEIndex] = { sep: LONG POINTER TO ISERecord = @stb.seb[sei]; IF sep.hash < firstCopiedHash THEN { name: ROPE _ NIL; IF sep.idType = typeTYPE THEN { typeSei: SEIndex _ sep.idInfo; WITH tse: stb.seb[typeSei] SELECT FROM id => { IF tse.idCtx # ctx AND InDirectory[tse.idCtx] THEN RETURN; }; ENDCASE; }; ros _ IO.ROS[ros]; ListerUtils.PrintSei[sei, ros, stb]; name _ IO.RopeFromROS[ros, FALSE]; which.first.names _ InsertName[name, which.first.names]; }; }; WITH c: cp SELECT FROM included => { mdi _ c.module; }; imported => { mdi _ stb.ctxb[c.includeLink].module; }; ENDCASE => RETURN; ros _ IO.ROS[ros]; ListerUtils.PrintName[stb.mdb[mdi].moduleId, ros, stb]; modName _ IO.RopeFromROS[ros, FALSE]; [which, pairs] _ FindList[modName, pairs]; IF which.first.file = NIL THEN { modFileName: ROPE _ NIL; ros _ IO.ROS[ros]; ListerUtils.PrintName[stb.mdb[mdi].fileId, ros, stb]; modFileName _ IO.RopeFromROS[ros, FALSE]; modFileName _ Rope.Flatten[modFileName, 0, Rope.SkipTo[modFileName, 0, "."]]; which.first.file _ modFileName; }; root _ sei _ stb.ctxb[ctx].seList; DO IF sei = SENull THEN EXIT; DoSei[sei]; IF (sei _ stb.NextSe[sei]) = root THEN EXIT; ENDLOOP; }; }; FOR hti: HTIndex IN (0..LENGTH[stb.ht]) DO IF stb.ht[hti].ssIndex = stb.ht[hti - 1].ssIndex THEN { firstCopiedHash _ hti; EXIT}; REPEAT FINISHED => firstCopiedHash _ LENGTH[stb.ht]; ENDLOOP; FOR dirSei: ISEIndex _ stb.FirstCtxSe[stb.stHandle.directoryCtx], stb.NextSe[dirSei] UNTIL dirSei = ISENull DO WITH se: stb.seb[stb.UnderType[stb.seb[dirSei].idType]] SELECT FROM definition => DoContext[se.defCtx]; ENDCASE; ENDLOOP; FOR dirSei: ISEIndex _ stb.FirstCtxSe[stb.stHandle.importCtx], stb.NextSe[dirSei] UNTIL dirSei = ISENull DO WITH se: stb.seb[stb.UnderType[stb.seb[dirSei].idType]] SELECT FROM definition => DoContext[se.defCtx]; transfer => { bti: BTIndex = stb.seb[dirSei].idInfo; DoContext[stb.bb[bti].localCtx]; }; ENDCASE; ENDLOOP; IF pairs = NIL THEN IO.PutRope[stream, "No DIRECTORY.\n"] ELSE { IO.PutRope[stream, "DIRECTORY\n"]; WHILE pairs # NIL DO pair: Pair = pairs.first; names: LIST OF ROPE _ pair.names; IO.PutRope[stream, " "]; IO.PutRope[stream, pair.key]; IF NOT Rope.Equal[pair.key, pair.file, FALSE] THEN { IO.PutF1[stream, ": FROM \"%g\"", [rope[pair.file]]]; }; IO.PutRope[stream, " USING ["]; WHILE names # NIL DO IO.PutRope[stream, names.first]; IF names.rest # NIL THEN IO.PutRope[stream, ", "]; names _ names.rest; ENDLOOP; IF pairs.rest # NIL THEN IO.PutRope[stream, "],\n"] ELSE IO.PutRope[stream, "];\n"]; pairs _ pairs.rest; ENDLOOP; }; }; PrintFiles: PROC [stream: STREAM, bcd: RefBCD, fileName: ROPE] = { FTRSeq: TYPE = RECORD [SEQUENCE len: NAT OF FTRecord]; inStream: STREAM = FS.StreamOpen[fileName, $read]; fti: CARDINAL = LOOPHOLE[FIRST[FTIndex]]; nFiles: CARDINAL = (bcd.ftLimit-FIRST[FTIndex])/SIZE[FTRecord]; bytes: CARDINAL = nFiles*SIZE[FTRecord]*bytesPerWord; fileSeq: REF FTRSeq = NEW[FTRSeq[nFiles]]; ftp: LONG POINTER TO FTRecord _ @fileSeq[0]; IO.PutF1[stream, "# files: %g\n\n", [integer[nFiles]]]; IO.SetIndex[inStream, (fti+bcd.ftOffset)*bytesPerWord]; [] _ IO.UnsafeGetBlock[ inStream, [base: LOOPHOLE[@fileSeq[0]], startIndex: 0, count: bytes]]; FOR i: NAT IN [0..nFiles) DO IO.PutF[ stream, "%g - fti: %g", [rope[RopeForBcdName[inStream, bcd.ssOffset, ftp.name]]], [integer[i*SIZE[FTRecord]]]]; IO.PutRope[stream, ", version: "]; ListerUtils.PrintVersion[ftp.version, stream]; IO.PutRope[stream, "\n"]; ftp _ ftp + SIZE[FTRecord]; ENDLOOP; IO.Close[inStream]; }; RopeForBcdName: PROC [inStream: STREAM, base: CARDINAL, index: CARDINAL] RETURNS [ROPE] = { ros: STREAM = IO.ROS[]; IO.SetIndex[inStream, base*bytesPerWord+index+3]; THROUGH [0..IO.GetChar[inStream]-0C) DO IO.PutChar[ros, IO.GetChar[inStream]]; ENDLOOP; RETURN [IO.RopeFromROS[ros]]; }; Pair: TYPE = RECORD [key: ROPE, file: ROPE, names: LIST OF ROPE]; FindList: PROC [key: ROPE, base: LIST OF Pair] RETURNS [which,newBase: LIST OF Pair _ NIL] = { newBase _ base; WHILE which = NIL DO FOR each: LIST OF Pair _ newBase, each.rest WHILE each # NIL DO IF key.Equal[each.first.key] THEN {which _ each; RETURN}; ENDLOOP; newBase _ InsertPair[[key, NIL, NIL], newBase]; ENDLOOP; }; InsertName: PROC [rope: ROPE, list: LIST OF ROPE] RETURNS [LIST OF ROPE] = { lag: LIST OF ROPE _ NIL; FOR each: LIST OF ROPE _ list, each.rest WHILE each # NIL DO SELECT Rope.Compare[rope, each.first, FALSE] FROM less => EXIT; equal => SELECT Rope.Compare[rope, each.first, TRUE] FROM less => EXIT; equal => RETURN [list]; greater => {}; ENDCASE; greater => {}; ENDCASE => ERROR; lag _ each; ENDLOOP; IF lag = NIL THEN RETURN [CONS[rope, list]] ELSE {lag.rest _ CONS[rope, lag.rest]; RETURN [list]}; }; InsertPair: PROC [pair: Pair, list: LIST OF Pair] RETURNS [LIST OF Pair] = { lag: LIST OF Pair _ NIL; key: ROPE _ pair.key; FOR each: LIST OF Pair _ list, each.rest WHILE each # NIL DO SELECT Rope.Compare[key, each.first.key, FALSE] FROM less => EXIT; equal => SELECT Rope.Compare[key, each.first.key, TRUE] FROM less => EXIT; equal => RETURN [list]; greater => {}; ENDCASE; greater => {}; ENDCASE => ERROR; lag _ each; ENDLOOP; IF lag = NIL THEN RETURN [CONS[pair, list]] ELSE {lag.rest _ CONS[pair, lag.rest]; RETURN [list]}; }; Commander.Register[ "CodeLister", ListSymbols, "List the code for a bcd file.", $Code]; Commander.Register[ "ExportsLister", ListSymbols, "List the exports for a bcd file.", $Exports]; Commander.Register[ "FGTLister", ListSymbols, "List the fine grain table for a bcd file.", $FGT]; Commander.Register[ "FilesLister", ListSymbols, "List the items used by a bcd file.", $Files]; Commander.Register[ "GlobalFramesLister", ListSymbols, "List the global frames for a bcd file.", $Globals]; Commander.Register[ "SymbolLister", ListSymbols, "List the symbols for a bcd file.", $Symbols]; Commander.Register[ "UnboundLister", ListSymbols, "List the items used by a bcd file.", $Unbound]; Commander.Register[ "UsingLister", ListSymbols, "List the items used by a bcd file.", $Using]; END. ΪKLister.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Sweet December 17, 1985 3:41:40 pm PST Russ Atkinson (RRA) December 9, 1985 1:21:25 pm PST Satterthwaite November 5, 1985 11:42:03 am PST T Y P E S & C O N S T A N T S Major procedures [cmd: Handle] RETURNS [result: REF _ NIL, msg: ROPE _ NIL] [fullGName: ROPE] RETURNS [continue: BOOLEAN] [fullFName: ROPE] RETURNS [continue: BOOL] Now we have a single-module file. Get the module. Get the source fullFName for later Open the output stream (if any) Get the module name Get the module file name At this point all of the entries have been made. Utility procedures If no such named list is found, one is created and inserted into the base. I N I T Κ˜codešœ ™ Kšœ Οmœ1™Kšœ7˜7Kšœ-˜-Kšœ7˜7Kšœ"˜"Kšžœ˜—Kšžœ˜K˜——Kšœ ˜ Kšœ žœ˜Kšžœžœ˜%Kšœ˜—Kšžœ4žœ˜@K˜—šžœžœž˜Kšœ˜Kšœ˜šžœžœž˜šœ˜Kšœžœžœ˜Kšœžœ˜ šžœžœžœž˜'Kšœžœ˜šžœž˜ Kšžœ!˜#Kšžœ)˜+Kšžœ'˜)Kšœžœ˜Kšžœ˜—Kšžœ˜—Kšžœ˜K˜—Kšœžœžœ˜KKšžœ%˜,—Kšœžœ˜ šœžœ˜Kšœžœ$žœžœ ˜6Kšœ ˜ —Kšžœžœžœ ˜CKšžœ#˜%Kš žœ žœžœžœžœ˜"Kšžœ˜—šžœžœžœ˜Kšœ˜Kšœžœ3˜;Kšœ˜—Kšžœ˜"K˜K˜—šŸ œžœžœ žœ˜CšŸ œžœžœžœ˜1Kšœžœžœžœ˜.Kšžœ˜šžœ žœž˜˜ Kšœ(˜(šžœ ˜ Kšžœžœ˜$šžœ˜Kšžœ5˜7šžœžœž˜Kšœ žœ<˜GKšžœ˜—Kšœ˜——Kšžœ˜ Kšžœžœ žœžœ˜2Kšžœžœžœžœ˜4Kšžœžœžœžœ˜8Kšžœžœžœ(˜EKšœ˜—Kšžœžœ˜(—Kšžœ"˜$Kšœ.˜.Kšžœ6˜8šžœ žœž˜˜ Kšžœ:˜<šžœ˜KšžœB˜FKšžœžœM˜U—Kšœ˜—Kšžœ˜—Kšžœ˜Kšžœžœ˜Kšœ˜—Kšœ-˜-Kšžœ˜K˜K˜—šŸœžœžœ žœ˜IšŸ œžœžœžœ˜1Kšœžœžœžœ˜.Kšžœ˜šžœ žœž˜˜ Kšœ(˜(šžœ ˜ Kšžœžœ˜$šžœ˜Kšžœ5˜7šžœžœž˜Kšœ žœ<˜GKšžœ˜—Kšœ˜——Kšžœ˜ Kšžœžœ žœžœ˜2Kšžœžœžœžœ˜4Kšžœžœžœžœ˜8Kšžœžœžœ(˜EKšœ˜—Kšžœžœžœ˜—Kšžœ"˜$Kšœ.˜.Kšžœ6˜8šžœ žœž˜˜ Kšžœ:˜<šžœ˜KšžœB˜FKšžœžœM˜U—Kšœ˜—Kšžœ˜—Kšžœ˜Kšžœžœ˜Kšœ˜—Kšœ-˜-Kšžœ˜K˜K˜—š Ÿ œžœžœžœ žœ˜WK˜K˜Kšœžœ˜-Kšœžœžœ˜*šžœ ž˜K˜,Kšžœ˜šœ žœžœž˜+Kšœžœ˜$Kšœžœ˜$Kšžœžœ˜"—Kšžœ˜—Kšžœ˜K˜K˜—šŸ œžœ"žœ žœ˜cK˜Kšœžœžœžœ˜/Kšžœ˜ Kšœ$˜$šžœž˜ Kšžœ4˜6—šžœžœž˜˜ Kšžœ$˜&Kšœ?˜?Kšžœ˜Kšœ=˜=Kšžœ˜Kšœ:˜:Kšžœ!˜#Kšœ&˜&K˜—˜ Kšžœ&˜(KšœU˜UK˜—Kšžœ˜—K˜"šž˜Kšžœžœžœ˜Kšœ;˜;Kšžœ žœžœ˜,Kšžœ˜—Kšœ˜K˜—šŸ œžœ žœ˜;Kšœžœ˜7Kšœžœžœ˜4Kšœ žœžœ˜Kšœžœžœžœ˜Kšœžœžœžœ˜K˜!šŸ œžœžœžœ˜4šžœ˜Kšœ@žœž˜Yšžœ4žœž˜CKš œžœžœžœžœ˜4Kšžœ˜—Kšžœ˜—Kšžœžœ˜K˜—šŸ œžœ˜#šžœžœ˜Kšœ˜Kšœžœžœžœ˜/Kšœžœžœžœ˜Kšœžœžœ˜K˜ šŸœžœ˜Kšœžœžœžœ˜/šžœžœ˜$Kšœžœžœ˜šžœžœ˜K˜šžœžœž˜&˜Kšžœžœžœžœ˜:K˜—Kšžœ˜—Kšœ˜—Kšœžœžœ˜Kšœ$˜$Kšœžœžœ˜"Kšœ8˜8K˜—K˜—šžœžœž˜˜ Kšœ˜K˜—˜ Kšœ%˜%K˜—Kšžœžœ˜—K˜Kšœ™Kšœžœžœ˜Kšœ7˜7Kšœ žœžœ˜%K˜Kšœ*˜*šžœžœžœ˜ Kšœ™Kšœ žœžœ˜Kšœžœžœ˜Kšœ5˜5Kšœžœžœ˜)KšœM˜MKšœ˜K˜—K˜"šž˜Kšžœžœžœ˜Kšœ ˜ Kšžœ žœžœ˜,Kšžœ˜—K˜—K˜—šžœžœžœ ž˜*šžœ/žœ˜7Kšœžœ˜—Kšžœžœžœ ˜4Kšžœ˜—šžœ˜Kšœ@žœž˜Yšžœ4žœž˜CKšœ#˜#Kšžœ˜—Kšžœ˜—šžœ˜Kšœ=žœž˜Všžœ4žœž˜CKšœ#˜#šœ ˜ Kšœ&˜&Kšœ ˜ K˜—Kšžœ˜—Kšžœ˜—Kšœ0™0šžœ ž˜Kšžœžœ#˜*šžœ˜Kšžœ ˜"šžœ žœž˜Kšœ˜Kšœžœžœžœ˜!Kšžœ˜Kšžœ˜šžœžœ!žœžœ˜4Kšžœ3˜5K˜—Kšžœ˜šžœ žœž˜Kšžœ˜ Kšžœžœžœ˜2K˜Kšžœ˜—šžœž˜Kšžœžœ˜Kšžœžœ˜ —Kšœ˜Kšžœ˜—K˜——Kšœ˜K˜—šŸ œžœ žœžœ˜BKš œžœžœžœžœžœ ˜6Kšœ žœžœ˜2Kšœžœžœžœ ˜)Kšœžœžœ žœ ˜?Kšœžœ žœ˜5Kšœ žœ žœ˜*Kšœžœžœžœ˜,Kšžœ5˜7Kšžœ5˜7šœžœ˜Kšœ ˜ Kšœžœ-˜<—šžœžœžœ ž˜šžœ˜Kšœ˜Kšœ9˜9Kšœ žœ˜—Kšžœ ˜"Kšœ.˜.Kšžœ˜Kšœ žœ ˜Kšžœ˜—Kšžœ˜K˜K˜——šœ™K˜šŸœžœ žœžœ žœžœžœ˜[Kšœžœžœžœ˜Kšžœ/˜1Kš žœžœžœžœžœžœ˜XKšžœžœ˜K˜K˜—Kšœžœžœžœžœ žœžœžœ˜AšŸœžœžœžœžœžœžœžœžœ˜^KšœJ™JKšœ˜šžœ žœž˜š žœžœžœžœžœž˜?Kšžœžœžœ˜9Kšžœ˜—Kšœžœžœ ˜/Kšžœ˜—K˜K˜—šŸ œžœžœžœžœžœžœžœžœžœ˜LKš œžœžœžœžœ˜š žœžœžœžœžœžœž˜<šžœ žœž˜1Kšœžœ˜ šœ˜šžœ žœž˜0Kšœžœ˜ Kšœ žœ˜K˜Kšžœ˜——K˜Kšžœžœ˜—K˜ Kšžœ˜—šžœž˜ Kšžœžœžœ ˜Kšžœ žœžœ ˜6—K˜K˜—šŸ œžœžœžœžœžœžœ ˜LKšœžœžœžœ˜Kšœžœ ˜š žœžœžœžœžœž˜<šžœ#žœž˜4Kšœžœ˜ šœ˜šžœ#žœž˜3Kšœžœ˜ Kšœ žœ˜K˜Kšžœ˜——K˜Kšžœžœ˜—K˜ Kšžœ˜—šžœž˜ Kšžœžœžœ ˜Kšžœ žœžœ ˜6—K˜K˜——™K˜˜Kšœ˜Kšœ(˜(K˜—˜Kšœ˜Kšœ.˜.K˜—˜Kšœ˜Kšœ3˜3K˜—˜Kšœ˜Kšœ.˜.K˜—˜Kšœ"˜"Kšœ4˜4K˜—˜Kšœ˜Kšœ.˜.K˜—˜Kšœ˜Kšœ0˜0K˜—˜Kšœ˜Kšœ.˜.K˜——Kšžœ˜K˜K˜K˜K˜—…—Kώiτ