-- ListCode.mesa; -- edited by Bruce; 13-Jan-81 11:00:33 -- edited by Sandman; September 29, 1980 9:21 AM -- edited by Sweet; 26-Mar-81 12:26:01 -- edited by Satterthwaite; September 20, 1982 1:37 pm DIRECTORY BcdDefs: TYPE USING [Base, MTIndex], BcdOps: TYPE USING [BcdBase, MTHandle], CommanderOps: TYPE USING [AddCommand, CommandBlockHandle], Environment: TYPE USING [Byte, PageCount], FileSegment: TYPE USING [Pages], FileStream: TYPE USING [Create, EndOf, SetIndex], Format: TYPE USING [NumberFormat], Heap: TYPE USING [systemZone], Inline: TYPE USING [BITOR], ListerDefs: TYPE USING [ IncorrectVersion, Load, LoadFromConfig, MapPages, NoCode, NoFGT, NoFile, NoSymbols, SetRoutineSymbols, WriteFileID, WriteString], Mopcodes: TYPE USING [ zJ2, zJ9, zJEQ2, zJEQ9, zJIB, zJIW, zJNE2, zJNE9, zLI0, zLI6, zLIB, zLIW, zRF, zRFC, zRFL, zRIGP, zRIGPL, zRILP, zRILPL, zRXGPL, zRXLP, zRXLPL, zWF, zWFL, zWIGPL, zWILP, zWILPL, zWSF, zWXGPL, zWXLP, zWXLPL], OpTableDefs: TYPE USING [InstAligned, InstLength, InstName, PopStack, PushStack], OSMiscOps: TYPE USING [FileError, FindFile], OutputDefs: TYPE USING [ CloseOutput, OpenOutput, PutChar, PutNumber, PutString, PutLongSubString], PrincOps: TYPE USING [ CSegPrefix, EntryVectorItem, FrameHandle, FrameVec, InstWord], Space: TYPE USING [Handle, LongPointer, Delete], Stream: TYPE USING [Delete, GetChar, Handle], Strings: TYPE USING [AppendString, SubStringDescriptor], Symbols: TYPE USING [ BodyInfo, BodyRecord, BTIndex, BTNull, CBTIndex, HTIndex, HTNull, ISEIndex, SENull], SymbolSegment: TYPE USING [FGTEntry], SymbolTable: TYPE USING [Base, Acquire, Release, SetCacheSize]; ListCode: PROGRAM IMPORTS CommanderOps, FileStream, Heap, Inline, ListerDefs, OpTableDefs, OSMiscOps, OutputDefs, Space, Stream, Strings, SymbolTable = { OPEN OutputDefs; MTIndex: TYPE = BcdDefs.MTIndex; FrameHandle: TYPE = PrincOps.FrameHandle; NumberFormat: TYPE = Format.NumberFormat; PageCount: TYPE = Environment.PageCount; BYTE: TYPE = Environment.Byte; opcode: TYPE = BYTE; JumpOp: TYPE = [Mopcodes.zJ2..Mopcodes.zJIW]; FineGrainInfo: TYPE = RECORD [ firstSource, lastSource: CARDINAL ← nullSource, pc: CARDINAL, procEnd: BOOLEAN, bti: Symbols.CBTIndex]; FGT: TYPE = RECORD [ length: NAT, info: SEQUENCE maxLength: NAT OF FineGrainInfo]; FGHandle: TYPE = LONG POINTER TO FGT; nullSource: CARDINAL = LAST[CARDINAL]; -- if lastSource, causes to EOF myFGT: FGHandle; DigestFGT: PROC = { OPEN s: symbols; bti, prev: Symbols.BTIndex; cspp: LONG POINTER TO PrincOps.CSegPrefix = codebase; AddMyEntry: PROC [ source: CARDINAL←nullSource, object: CARDINAL, procEnd: BOOLEAN←FALSE] = { IF n = myFGTSize THEN { oldFGT: FGHandle ← myFGT; myFGTSize ← myFGTSize + 10; SetupMyFGT[]; FOR i: NAT IN [0..oldFGT.maxLength) DO myFGT[i] ← oldFGT[i] ENDLOOP; (Heap.systemZone).FREE[@oldFGT]}; myFGT[n] ← [firstSource: source, pc: object, procEnd: procEnd, bti: LOOPHOLE[bti]]; myFGT.length ← n ← n + 1}; AddBodyFGT: PROC [bti: Symbols.CBTIndex] = { OPEN s: symbols; procstart: CARDINAL = cspp.entry[s.bb[bti].entryIndex].initialpc*2; info: Symbols.BodyInfo[External] = NARROW[s.bb[bti].info, Symbols.BodyInfo[External]]; fgLast: CARDINAL = info.startIndex + info.indexLength - 1; lastSource: CARDINAL ← s.bb[bti].sourceIndex; lastObject: CARDINAL ← procstart; FOR i: CARDINAL IN [info.startIndex..fgLast] DO f: SymbolSegment.FGTEntry = s.fgTable[i]; WITH f SELECT FROM normal => { lastSource ← lastSource + deltaSource; lastObject ← lastObject + deltaObject; AddMyEntry[source: lastSource, object: lastObject]}; step => IF which = source THEN lastSource ← lastSource + delta ELSE lastObject ← lastObject + delta; ENDCASE; ENDLOOP; AddMyEntry[object: procstart + info.bytes, procEnd: TRUE]}; SetupMyFGT: PROC = INLINE { myFGT ← (Heap.systemZone).NEW[FGT[myFGTSize] ← [length: 0, info: NULL]]}; BySource: PROC [r1, r2: LONG POINTER TO FineGrainInfo] RETURNS [BOOLEAN] = { IF r1.firstSource > r2.firstSource THEN RETURN [TRUE]; IF r1.firstSource = r2.firstSource THEN RETURN [r1.pc > r2.pc]; RETURN [FALSE]}; ByPC: PROC [r1, r2: LONG POINTER TO FineGrainInfo] RETURNS [BOOLEAN] = { IF r1.pc > r2.pc THEN RETURN [TRUE]; IF r1.pc < r2.pc THEN RETURN [FALSE]; IF r1.procEnd THEN RETURN [FALSE]; IF r2.procEnd THEN RETURN [TRUE]; RETURN [r1.firstSource > r2.firstSource]}; Sort: PROC [ n: CARDINAL, greater: PROC [r1, r2: LONG POINTER TO FineGrainInfo] RETURNS [BOOLEAN]] = { i: CARDINAL; temp: FineGrainInfo; SiftUp: PROC [l, u: CARDINAL] = { s: CARDINAL; key: FineGrainInfo ← myFGT[l-1]; DO s ← l*2; IF s > u THEN EXIT; IF s < u AND greater[@myFGT[s+1-1], @myFGT[s-1]] THEN s ← s+1; IF greater[@key, @myFGT[s-1]] THEN EXIT; myFGT[l-1] ← myFGT[s-1]; l ← s; ENDLOOP; myFGT[l-1] ← key}; FOR i DECREASING IN [2..n/2] DO SiftUp[i, n]; ENDLOOP; FOR i DECREASING IN [2..n] DO SiftUp[1, i]; temp ← myFGT[1-1]; myFGT[1-1] ← myFGT[i-1]; myFGT[i-1] ← temp; ENDLOOP}; n: CARDINAL ← 0; myFGTSize: CARDINAL ← (3*LENGTH[s.fgTable])/2; SetupMyFGT[]; bti ← FIRST[Symbols.BTIndex]; IF s.bb[bti].sourceIndex # 0 THEN AddMyEntry[source: 0, object: cspp.entry[0].initialpc*2]; DO WITH s.bb[bti] SELECT FROM Callable => IF ~inline THEN AddBodyFGT[LOOPHOLE[bti]]; ENDCASE; IF s.bb[bti].firstSon # Symbols.BTNull THEN bti ← s.bb[bti].firstSon ELSE DO prev ← bti; bti ← s.bb[bti].link.index; IF bti = Symbols.BTNull THEN GO TO Done; IF s.bb[prev].link.which # parent THEN EXIT; ENDLOOP; REPEAT Done => NULL; ENDLOOP; Sort[n, BySource]; FOR i: CARDINAL DECREASING IN [0..n - 1) DO IF myFGT[i].firstSource = nullSource THEN LOOP; IF myFGT[i].firstSource = myFGT[i+1].firstSource THEN { myFGT[i].lastSource ← myFGT[i+1].lastSource; myFGT[i+1].firstSource ← myFGT[i+1].lastSource} ELSE myFGT[i].lastSource ← myFGT[i + 1].firstSource; ENDLOOP; Sort[n, ByPC]}; offset: CARDINAL; codebase: LONG POINTER; codepages: PageCount; symbols: SymbolTable.Base; Tinst, Tbytes, Pinst, Pbytes: CARDINAL ← 0; -- number formats (initialized by Octify) decimal: NumberFormat = NumberFormat[ base: 10, columns: 1, zerofill: FALSE, unsigned: TRUE]; decimal3: NumberFormat = NumberFormat[ base: 10, columns: 3, zerofill: FALSE, unsigned: TRUE]; hoctal3: NumberFormat; hoctal3z: NumberFormat; hoctal5: NumberFormat; hoctal6: NumberFormat; hoctal1: NumberFormat; -- set base for listings Hexify: PROC = { hoctal3 ← NumberFormat[base: 16, columns: 3, zerofill: FALSE, unsigned: TRUE]; hoctal3z ← NumberFormat[ base: 16, columns: 3, zerofill: FALSE, unsigned: TRUE]; hoctal5 ← NumberFormat[base: 16, columns: 5, zerofill: FALSE, unsigned: TRUE]; hoctal6 ← NumberFormat[base: 16, columns: 6, zerofill: FALSE, unsigned: TRUE]; hoctal1 ← NumberFormat[base: 16, columns: 1, zerofill: FALSE, unsigned: TRUE]}; Octify: PROC = { hoctal3 ← NumberFormat[base: 8, columns: 3, zerofill: FALSE, unsigned: TRUE]; hoctal3z ← NumberFormat[base: 8, columns: 3, zerofill: TRUE, unsigned: TRUE]; hoctal5 ← NumberFormat[base: 8, columns: 5, zerofill: FALSE, unsigned: TRUE]; hoctal6 ← NumberFormat[base: 8, columns: 6, zerofill: FALSE, unsigned: TRUE]; hoctal1 ← NumberFormat[base: 8, columns: 1, zerofill: FALSE, unsigned: TRUE]}; -- generate list of opcode lengths OpcodeLengths: PROC [root: STRING] = { OPEN OpTableDefs; digit: STRING = "0123456789"L; OpenOutput[root, ".list"L]; PutString[" OpcodeLengths: PACKED ARRAY [0..255] OF [0..3] = ["L]; FOR i: opcode IN opcode DO IF i MOD 32 = 0 THEN PutString["\n "L]; PutChar[digit[InstLength[i]]]; IF i # LAST[opcode] THEN PutChar[',]; ENDLOOP; PutString["];\n"L]; CloseOutput[]}; -- generate list of opcodes OpcodeList: PROC [root: STRING] = { OPEN OpTableDefs; digit: STRING = "0123456789"L; OpenOutput[root, ".list"L]; PutString["-- Mesa Opcodes\n"L]; PutString["-- Format: name hoctal(decimal)push,pop,length,aligned\n\n"L]; FOR i: opcode IN opcode DO op: STRING ← InstName[i]; length: [0..3] = InstLength[i]; IF length = 0 THEN op.length ← 0; PutString[op]; THROUGH (op.length..8] DO PutChar[' ] ENDLOOP; PutNumber[i, hoctal3]; PutChar['(]; PutNumber[i, decimal3]; PutChar[')]; PutChar[digit[PushStack[i]]]; PutChar[',]; PutChar[digit[PopStack[i]]]; PutChar[',]; PutChar[digit[length]]; PutChar[',]; PutChar[IF InstAligned[i] THEN 'T ELSE 'F]; PutString[IF i MOD 4 = 3 THEN ";\n"L ELSE "; "L]; ENDLOOP; CloseOutput[]}; -- source file procedures source: Stream.Handle; sourceAvailable: BOOLEAN; outcheck: PROC [xfirst: CARDINAL, xlast: CARDINAL] = { nextchar: CHARACTER; lastcr: CARDINAL; IF ~sourceAvailable THEN RETURN; FOR lastcr ← xfirst, lastcr - 1 UNTIL lastcr = 0 DO FileStream.SetIndex[source, lastcr]; IF source.GetChar[] = '\n THEN EXIT; ENDLOOP; THROUGH (lastcr..xfirst) DO PutChar[' ] ENDLOOP; FileStream.SetIndex[source, xfirst]; WHILE xfirst # xlast DO IF FileStream.EndOf[source] THEN GOTO eof; nextchar ← source.GetChar[]; xfirst ← xfirst + 1; IF nextchar = '\032 THEN -- Bravo trailer WHILE nextchar # '\n DO IF FileStream.EndOf[source] THEN GOTO eof; nextchar ← source.GetChar[]; xfirst ← xfirst + 1; ENDLOOP; PutChar[nextchar]; REPEAT eof => NULL; ENDLOOP; IF nextchar # '\n THEN PutChar['\n]}; setupsource: PROC = { sourceAvailable ← TRUE; source ← FileStream.Create[ OSMiscOps.FindFile[symbols.sourceFile ! OSMiscOps.FileError => {sourceAvailable ← FALSE; CONTINUE}]]}; closesource: PROC = {IF sourceAvailable THEN Stream.Delete[source]}; PrintBodyName: PROC [bti: Symbols.BTIndex] = { OPEN symbols; sei: Symbols.ISEIndex; hti: Symbols.HTIndex; ss: Strings.SubStringDescriptor; IF sourceAvailable THEN RETURN; WITH bb[bti] SELECT FROM Callable => IF (sei ← id) = Symbols.SENull OR (hti ← seb[sei].hash) = Symbols.HTNull THEN RETURN; ENDCASE => RETURN; SubStringForHash[@ss, hti]; PutLongSubString[@ss]; PutString[":\n"L]}; EvenUp: PROC [n: CARDINAL] RETURNS [CARDINAL] = INLINE { -- Round up to an even number RETURN [n + n MOD 2]}; getbyte: PROC [pc: CARDINAL] RETURNS [BYTE] = { -- pc is a byte address w: LONG POINTER TO PrincOps.InstWord = codebase + pc/2; RETURN [IF pc MOD 2 = 0 THEN w.evenbyte ELSE w.oddbyte]}; getword: PROC [pc: CARDINAL] RETURNS [WORD] = INLINE { -- pc is a word address RETURN [(codebase + pc)↑]}; jumpaddress: PROC [jop: opcode, arg: INTEGER] RETURNS [CARDINAL] = { -- given a jump operator and its argument, return its target address OPEN Mopcodes; SELECT OpTableDefs.InstLength[ jop] FROM 1 => SELECT jop FROM IN [zJ2..zJ9] => arg ← jop - zJ2 + 2; IN [zJEQ2..zJEQ9] => arg ← jop - zJEQ2 + 2; IN [zJNE2..zJNE9] => arg ← jop - zJNE2 + 2; ENDCASE => ERROR; 2 => { IF arg > 177B THEN arg ← Inline.BITOR[arg, 177400B]; arg ← arg - 1}; ENDCASE => arg ← arg - 2; RETURN [INTEGER[offset] + arg]}; outwjtab: PROC [ tabstart, tablength: CARDINAL, octal: BOOLEAN, stripped: BOOLEAN] = { Pbytes ← Pbytes + tablength*2; FOR pc: CARDINAL IN [tabstart..tabstart + tablength) DO w: INTEGER = getword[pc]; PutString["\n\t\t"L]; IF stripped THEN {PutNumber[w, hoctal5]; LOOP}; IF octal THEN PutString["\t\t"L]; PutString[" ("L]; PutNumber[jumpaddress[Mopcodes.zJIW, w], hoctal5]; PutChar[')]; ENDLOOP}; outbjtab: PROC [ tabstart, tablength: CARDINAL, octal: BOOLEAN, stripped: BOOLEAN] = { Pbytes ← Pbytes + EvenUp[tablength]; FOR pc: CARDINAL IN [tabstart*2..tabstart*2 + tablength) DO b: BYTE = getbyte[pc]; PutString["\n\t\t"L]; IF stripped THEN {PutNumber[b, hoctal5]; LOOP}; IF octal THEN PutString["\t\t"L]; PutString[" ("L]; PutNumber[jumpaddress[Mopcodes.zJIB, b], hoctal5]; PutChar[')]; ENDLOOP}; PutPair: PROC [byte: CARDINAL] = { a: CARDINAL = byte/16; b: CARDINAL = byte MOD 16; IF a < 8 AND b < 8 THEN PutChar[' ]; PutChar['[]; PutNumber[a, hoctal1]; PutChar[',]; PutNumber[b, hoctal1]; PutChar[']]}; printcode: PROC [ startcode, endcode: CARDINAL, octal: BOOLEAN, stripped: BOOLEAN] = { -- list opcodes for indicated segment of code OPEN Mopcodes; lastconstant: INTEGER; FOR offset IN [startcode..endcode) DO inst: BYTE = getbyte[offset]; il: [0..3] = OpTableDefs.InstLength[inst]; -- loginst[inst]; Pinst ← Pinst + 1; PutChar['\t]; IF ~stripped THEN { IF octal THEN { PutNumber[offset/2, hoctal5]; PutString[(IF offset MOD 2 = 0 THEN ",E "L ELSE ",O "L)]}; PutNumber[offset, hoctal5]; PutChar[':]}; IF octal THEN { PutString["\t["L]; PutNumber[inst, hoctal3z]; PutChar[']]}; PutChar['\t]; PutString[OpTableDefs.InstName[inst]]; SELECT il FROM 0, 1 => { Pbytes ← Pbytes + 1; IF inst IN [zLI0..zLI6] THEN lastconstant ← inst - zLI0 ELSE IF inst IN JumpOp AND ~stripped THEN { PutString["\t ("L]; PutNumber[jumpaddress[inst, 0], hoctal1]; PutChar[')]}}; 2 => { byte: BYTE = getbyte[(offset ← offset + 1)]; Pbytes ← Pbytes + 2; PutChar['\t]; SELECT inst FROM zRILP, zWILP, zRXLP, zWXLP, zRIGP, zRXLPL, zWXLPL, zRXGPL, zWXGPL, zRILPL, zWILPL, zRIGPL, zWIGPL => PutPair[byte]; ENDCASE => PutNumber[byte, hoctal6]; IF inst = zLIB THEN lastconstant ← byte ELSE IF inst IN JumpOp AND ~stripped THEN { PutString[" ("L]; PutNumber[jumpaddress[inst, byte], hoctal1]; PutChar[')]}}; 3 => { ab: RECORD [first, second: BYTE]; Pbytes ← Pbytes + 3; ab.first ← getbyte[(offset ← offset + 1)]; ab.second ← getbyte[(offset ← offset + 1)]; PutChar['\t]; SELECT inst FROM zRF, zWF, zWSF, zRFC, zRFL, zWFL => { PutNumber[ab.first, hoctal6]; PutString[", "L]; PutPair[ab.second]}; ENDCASE => { v: INTEGER = ab.first*256 + ab.second; PutNumber[v, hoctal6]; SELECT inst FROM zJIB => outbjtab[v, lastconstant, octal, stripped]; zJIW => outwjtab[v, lastconstant, octal, stripped]; zLIW => lastconstant ← v; IN JumpOp => IF ~stripped THEN { PutString[" ("L]; PutNumber[jumpaddress[inst, v], hoctal1]; PutChar[')]}; ENDCASE}}; ENDCASE; PutChar['\n]; ENDLOOP}; ListFile: PROC [root: STRING, octal, stripped: BOOLEAN] = { OPEN symbols; cseg, sseg, bcdseg: FileSegment.Pages; bcdFile: STRING ← [40]; Strings.AppendString[bcdFile, root]; FOR i: CARDINAL IN [0..root.length) DO IF root[i] = '. THEN EXIT; REPEAT FINISHED => Strings.AppendString[bcdFile, ".bcd"L]; ENDLOOP; [cseg, sseg, bcdseg] ← ListerDefs.Load[bcdFile]; DoCodeListing[root, cseg, sseg, bcdseg, FIRST[MTIndex], octal, stripped]}; ListModInConfig: PROC [config, module: STRING, octal, stripped: BOOLEAN] = { OPEN symbols; cseg, sseg, bcdseg: FileSegment.Pages; bcdFile: STRING ← [40]; mti: BcdDefs.MTIndex; Strings.AppendString[bcdFile, config]; FOR i: CARDINAL IN [0..config.length) DO IF config[i] = '. THEN EXIT; REPEAT FINISHED => Strings.AppendString[bcdFile, ".bcd"L]; ENDLOOP; [cseg, sseg, bcdseg, mti] ← ListerDefs.LoadFromConfig[bcdFile, module]; DoCodeListing[module, cseg, sseg, bcdseg, mti, octal, stripped]}; ShowTotals: PROC = { PutString["Instructions: "L]; PutNumber[Pinst, decimal]; PutString[", Bytes: "L]; PutNumber[Pbytes ← EvenUp[Pbytes], decimal]; PutString["\n\n"L]; Tinst ← Tinst + Pinst; Pinst ← 0; Tbytes ← Tbytes + Pbytes; Pbytes ← 0}; DoCodeListing: PROC [ root: STRING, cseg, sseg, bcdseg: FileSegment.Pages, mti: MTIndex, octal, stripped: BOOLEAN] = { OPEN BcdDefs, Symbols; cspp: LONG POINTER TO PrincOps.CSegPrefix; ff: FineGrainInfo; bcdSpace, codeSpace: Space.Handle; bcd: BcdOps.BcdBase; mth: BcdOps.MTHandle; prevBti: BTIndex ← BTNull; bcdSpace ← ListerDefs.MapPages[bcdseg]; bcd ← bcdSpace.LongPointer; mth ← @LOOPHOLE[bcd + bcd.mtOffset, Base][mti]; codeSpace ← ListerDefs.MapPages[cseg]; codebase ← codeSpace.LongPointer + mth.code.offset; codepages ← cseg.span.pages; cspp ← codebase; IF cspp.header.info.altoCode THEN { ListerDefs.WriteString["Cannot list Alto code"L]; RETURN}; SymbolTable.SetCacheSize[0]; -- clear cache symbols ← SymbolTable.Acquire[sseg]; ListerDefs.SetRoutineSymbols[symbols]; setupsource[]; OpenOutput[root, ".cl"L]; ListerDefs.WriteFileID[]; IF mth.crossJumped THEN PutString["Cross jumped\n"L]; PutString["Global frame size: "L]; PutNumber[mth.framesize, decimal]; PutString["\n\n"L]; Space.Delete[bcdSpace]; Tbytes ← Tinst ← 0; DigestFGT[]; FOR i: CARDINAL IN [0..myFGT.length) DO ff ← myFGT[i]; IF ff.bti # prevBti AND prevBti # BTNull THEN ShowTotals[]; IF ff.firstSource # nullSource THEN IF ff.lastSource = ff.firstSource THEN PutChar['\n] ELSE outcheck[ff.firstSource, ff.lastSource]; IF ff.bti # prevBti THEN { ep: CARDINAL = symbols.bb[ff.bti].entryIndex; evi: LONG POINTER TO PrincOps.EntryVectorItem = @cspp.entry[ep]; fsize: CARDINAL = PrincOps.FrameVec[evi.info.framesize]; PrintBodyName[ff.bti]; IF octal THEN PutChar['\t]; PutString[" Entry point: "L]; PutNumber[ep, decimal]; PutString[", Frame size: "L]; PutNumber[fsize, decimal]; PutChar['\n]}; IF ~ff.procEnd THEN printcode[ff.pc, myFGT[i + 1].pc, octal, stripped]; PutChar['\n]; prevBti ← ff.bti; ENDLOOP; IF prevBti # Symbols.BTNull THEN ShowTotals[]; (Heap.systemZone).FREE[@myFGT]; SymbolTable.Release[symbols]; Space.Delete[codeSpace]; closesource[]; PutChar['\n]; IF octal THEN PutChar['\t]; PutString["Total instructions: "L]; PutNumber[Tinst, decimal]; PutString[", Bytes: "L]; PutNumber[Tbytes, decimal]; PutChar['\n]; CloseOutput[]}; LCode: PROC [name: STRING, octal, stripped: BOOLEAN] = { OPEN ListerDefs; ListFile[name, octal, stripped ! NoCode => {ListerDefs.WriteString["Code not available"L]; CONTINUE}; NoSymbols => {ListerDefs.WriteString["Symbols not available"L]; CONTINUE}; NoFGT, IncorrectVersion => {ListerDefs.WriteString["Bad format"L]; CONTINUE}; NoFile => {ListerDefs.WriteString["File not found"L]; CONTINUE}]}; Code: PROC [name: STRING] = {LCode[name, FALSE, FALSE]}; OctalCode: PROC [name: STRING] = {LCode[name, TRUE, FALSE]}; StrippedCode: PROC [name: STRING] = {LCode[name, FALSE, TRUE]}; LCodeInConfig: PROC [config, name: STRING, octal, stripped: BOOLEAN] = { OPEN ListerDefs; ListModInConfig[config, name, octal, stripped ! NoCode => {ListerDefs.WriteString["Code not available"L]; CONTINUE}; NoSymbols => {ListerDefs.WriteString["Symbols not available"L]; CONTINUE}; NoFGT, IncorrectVersion => {ListerDefs.WriteString["Bad format"L]; CONTINUE}; NoFile => {ListerDefs.WriteString["File not found"L]; CONTINUE}]}; CodeInConfig: PROC [config, name: STRING] = { LCodeInConfig[config, name, FALSE, FALSE]}; OctalCodeInConfig: PROC [config, name: STRING] = { LCodeInConfig[config, name, TRUE, FALSE]}; StrippedCodeInConfig: PROC [config, name: STRING] = { LCodeInConfig[config, name, FALSE, TRUE]}; Init: PROC = { command: CommanderOps.CommandBlockHandle; Octify[]; command ← CommanderOps.AddCommand["Hexify", LOOPHOLE[Hexify], 0]; command ← CommanderOps.AddCommand["Octify", LOOPHOLE[Octify], 0]; command ← CommanderOps.AddCommand["OpcodeLengths", LOOPHOLE[OpcodeLengths], 1]; command.params[0] ← [type: string, prompt: "Filename"]; command ← CommanderOps.AddCommand["OpcodeList", LOOPHOLE[OpcodeList], 1]; command.params[0] ← [type: string, prompt: "Filename"]; command ← CommanderOps.AddCommand["OctalCode", LOOPHOLE[OctalCode], 1]; command.params[0] ← [type: string, prompt: "Filename"]; command ← CommanderOps.AddCommand["Code", LOOPHOLE[Code], 1]; command.params[0] ← [type: string, prompt: "Filename"]; command ← CommanderOps.AddCommand["StrippedCode", LOOPHOLE[StrippedCode], 1]; command.params[0] ← [type: string, prompt: "Filename"]; command ← CommanderOps.AddCommand[ "OctalCodeInConfig", LOOPHOLE[OctalCodeInConfig], 2]; command.params[0] ← [type: string, prompt: "ConfigName"]; command.params[1] ← [type: string, prompt: "ModName"]; command ← CommanderOps.AddCommand["CodeInConfig", LOOPHOLE[CodeInConfig], 2]; command.params[0] ← [type: string, prompt: "ConfigName"]; command.params[1] ← [type: string, prompt: "ModName"]; command ← CommanderOps.AddCommand[ "StrippedCodeInConfig", LOOPHOLE[StrippedCodeInConfig], 2]; command.params[0] ← [type: string, prompt: "ConfigName"]; command.params[1] ← [type: string, prompt: "ModName"]}; Init[]; }.