-- file CLList.mesa -- last edited by Satterthwaite on May 10, 1983 12:15 pm DIRECTORY BcdDefs: TYPE USING [Base, MTIndex], BcdOps: TYPE USING [BcdBase, MTHandle], CharIO: TYPE USING [PutChar, PutNumber, PutString, PutSubString], Environment: TYPE USING [Byte, PageCount], FileSegment: TYPE USING [Pages, nullPages], FileStream: TYPE USING [Create, EndOf, SetIndex], Format: TYPE USING [NumberFormat], Heap: TYPE USING [systemZone], Inline: TYPE USING [BITOR], ListerOps: TYPE USING [CodeOptions], ListerUtil: TYPE USING [ CreateStream, LoadBcd, LoadModule, MapPages, Message, SetFileName, SetRoutineSymbols, PutFileID, UnknownModule], 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 [InstLength, InstName], OSMiscOps: TYPE USING [FileError, FindFile], PrincOps: TYPE USING [ CSegPrefix, EntryVectorItem, FrameHandle, FrameVec, InstWord], Space: TYPE USING [Handle, LongPointer, Delete], Stream: TYPE USING [Delete, GetChar, Handle], Strings: TYPE USING [String, SubStringDescriptor, EqualSubStrings], Symbols: TYPE USING [ Name, ISEIndex, BodyInfo, BodyRecord, BTIndex, CBTIndex, nullName, ISENull, BTNull], SymbolSegment: TYPE USING [FGTEntry], SymbolTable: TYPE USING [Base, Acquire, Release, SetCacheSize]; CLList: PROGRAM IMPORTS CharIO, FileStream, Heap, Inline, ListerUtil, OpTableDefs, OSMiscOps, Space, Stream, Strings, SymbolTable EXPORTS ListerOps = { CodeOptions: TYPE = ListerOps.CodeOptions; 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: BOOL, bti: Symbols.CBTIndex]; FGT: TYPE = RECORD [ length: NAT, info: SEQUENCE maxLength: NAT OF FineGrainInfo]; FGHandle: TYPE = LONG POINTER TO FGT; nullSource: CARDINAL = CARDINAL.LAST; -- 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: BOOL←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: TRASH]]}; BySource: PROC [r1, r2: LONG POINTER TO FineGrainInfo] RETURNS [BOOL] = { 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 [BOOL] = { 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 [BOOL]] = { 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*s.fgTable.LENGTH)/2; SetupMyFGT[]; bti ← Symbols.BTIndex.FIRST; 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]}; -- source file procedures source: Stream.Handle; sourceAvailable: BOOL; out: Stream.Handle ← NIL; OpenOutput: PROC [root: Strings.String] = { outName: STRING ← [40]; ListerUtil.SetFileName[outName, root, "cl"L]; out ← ListerUtil.CreateStream[outName]}; CloseOutput: PROC = { Stream.Delete[out]; out ← NIL}; OutCheck: PROC [xfirst: CARDINAL, xlast: CARDINAL] = { nextchar: CHAR; 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 CharIO.PutChar[out, ' ] 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; CharIO.PutChar[out, nextchar]; REPEAT eof => NULL; ENDLOOP; IF nextchar # '\n THEN CharIO.PutChar[out, '\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]}; FilterBody: PROC [bti: Symbols.CBTIndex, key: Strings.String] RETURNS [BOOL←TRUE] = { IF key # NIL THEN { sei: Symbols.ISEIndex = symbols.bb[bti].id; hti: Symbols.Name; d1: Strings.SubStringDescriptor; d2: Strings.SubStringDescriptor ← [base: key, offset: 0, length: key.length]; IF sei = Symbols.ISENull OR (hti ← symbols.seb[sei].hash) = Symbols.nullName THEN RETURN [FALSE]; symbols.SubStringForName[@d1, hti]; RETURN [Strings.EqualSubStrings[@d1, @d2]]}}; PrintBodyName: PROC [bti: Symbols.CBTIndex] = { IF ~sourceAvailable THEN { sei: Symbols.ISEIndex = symbols.bb[bti].id; hti: Symbols.Name; IF sei # Symbols.ISENull AND (hti ← symbols.seb[sei].hash) # Symbols.nullName THEN { ss: Strings.SubStringDescriptor; symbols.SubStringForName[@ss, hti]; CharIO.PutSubString[out, @ss]; CharIO.PutString[out, ":\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, options: CodeOptions] = { Pbytes ← Pbytes + tablength*2; FOR pc: CARDINAL IN [tabstart..tabstart + tablength) DO w: INTEGER = GetWord[pc]; CharIO.PutString[out, "\n\t\t"L]; IF options.stripped THEN {CharIO.PutNumber[out, w, hoctal5]; LOOP}; IF options.full THEN CharIO.PutString[out, "\t\t"L]; CharIO.PutString[out, " ("L]; CharIO.PutNumber[out, JumpAddress[Mopcodes.zJIW, w], hoctal5]; CharIO.PutChar[out, ')]; ENDLOOP}; OutBJTab: PROC [tabstart, tablength: CARDINAL, options: CodeOptions] = { Pbytes ← Pbytes + EvenUp[tablength]; FOR pc: CARDINAL IN [tabstart*2..tabstart*2 + tablength) DO b: BYTE = GetByte[pc]; CharIO.PutString[out, "\n\t\t"L]; IF options.stripped THEN {CharIO.PutNumber[out, b, hoctal5]; LOOP}; IF options.full THEN CharIO.PutString[out, "\t\t"L]; CharIO.PutString[out, " ("L]; CharIO.PutNumber[out, JumpAddress[Mopcodes.zJIB, b], hoctal5]; CharIO.PutChar[out, ')]; ENDLOOP}; PutPair: PROC [byte: CARDINAL] = { a: CARDINAL = byte/16; b: CARDINAL = byte MOD 16; IF a < 8 AND b < 8 THEN CharIO.PutChar[out, ' ]; CharIO.PutChar[out, '[]; CharIO.PutNumber[out, a, hoctal1]; CharIO.PutChar[out, ',]; CharIO.PutNumber[out, b, hoctal1]; CharIO.PutChar[out, ']]}; PrintCode: PROC [ startcode, endcode: CARDINAL, options: CodeOptions] = { -- 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; CharIO.PutChar[out, '\t]; IF ~options.stripped THEN { IF options.full THEN { CharIO.PutNumber[out, offset/2, hoctal5]; CharIO.PutString[out, (IF offset MOD 2 = 0 THEN ",E "L ELSE ",O "L)]}; CharIO.PutNumber[out, offset, hoctal5]; CharIO.PutChar[out, ':]}; IF options.full THEN { CharIO.PutString[out, "\t["L]; CharIO.PutNumber[out, inst, hoctal3z]; CharIO.PutChar[out, ']]}; CharIO.PutChar[out, '\t]; CharIO.PutString[out, 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 ~options.stripped THEN { CharIO.PutString[out, "\t ("L]; CharIO.PutNumber[out, JumpAddress[inst, 0], hoctal1]; CharIO.PutChar[out, ')]}}; 2 => { byte: BYTE = GetByte[(offset ← offset + 1)]; Pbytes ← Pbytes + 2; CharIO.PutChar[out, '\t]; SELECT inst FROM zRILP, zWILP, zRXLP, zWXLP, zRIGP, zRXLPL, zWXLPL, zRXGPL, zWXGPL, zRILPL, zWILPL, zRIGPL, zWIGPL => PutPair[byte]; ENDCASE => CharIO.PutNumber[out, byte, hoctal6]; IF inst = zLIB THEN lastconstant ← byte ELSE IF inst IN JumpOp AND ~options.stripped THEN { CharIO.PutString[out, " ("L]; CharIO.PutNumber[out, JumpAddress[inst, byte], hoctal1]; CharIO.PutChar[out, ')]}}; 3 => { ab: RECORD [first, second: BYTE]; Pbytes ← Pbytes + 3; ab.first ← GetByte[(offset ← offset + 1)]; ab.second ← GetByte[(offset ← offset + 1)]; CharIO.PutChar[out, '\t]; SELECT inst FROM zRF, zWF, zWSF, zRFC, zRFL, zWFL => { CharIO.PutNumber[out, ab.first, hoctal6]; CharIO.PutString[out, ", "L]; PutPair[ab.second]}; ENDCASE => { v: INTEGER = ab.first*256 + ab.second; CharIO.PutNumber[out, v, hoctal6]; SELECT inst FROM zJIB => OutBJTab[v, lastconstant, options]; zJIW => OutWJTab[v, lastconstant, options]; zLIW => lastconstant ← v; IN JumpOp => IF ~options.stripped THEN { CharIO.PutString[out, " ("L]; CharIO.PutNumber[out, JumpAddress[inst, v], hoctal1]; CharIO.PutChar[out, ')]}; ENDCASE}}; ENDCASE; CharIO.PutChar[out, '\n]; ENDLOOP}; ListModule: PROC [ file, module, proc: Strings.String, output: Strings.String, options: CodeOptions] = { bcdFile: Strings.String ← [100]; bcdSeg, cSeg, sSeg: FileSegment.Pages; mti: BcdDefs.MTIndex; ListerUtil.SetFileName[bcdFile, file, "bcd"L]; bcdSeg ← ListerUtil.LoadBcd[bcdFile]; IF bcdSeg = FileSegment.nullPages THEN GO TO NoFile; [mti, cSeg, sSeg] ← ListerUtil.LoadModule[bcdSeg, module ! ListerUtil.UnknownModule => {GO TO NoModule}]; DoCodeListing[cSeg, sSeg, bcdSeg, mti, proc, output, options] EXITS NoFile => ListerUtil.Message["File cannot be opened"L]; NoModule => { ListerUtil.Message["File does not contain module "L]; ListerUtil.Message[module]}}; ShowTotals: PROC = { CharIO.PutString[out, "Instructions: "L]; CharIO.PutNumber[out, Pinst, decimal]; CharIO.PutString[out, ", Bytes: "L]; CharIO.PutNumber[out, Pbytes ← EvenUp[Pbytes], decimal]; CharIO.PutString[out, "\n\n"L]; Tinst ← Tinst + Pinst; Pinst ← 0; Tbytes ← Tbytes + Pbytes; Pbytes ← 0}; DoCodeListing: PROC [ cseg, sseg, bcdseg: FileSegment.Pages, mti: MTIndex, proc: Strings.String, output: Strings.String, options: CodeOptions] = { OPEN BcdDefs, Symbols; codeSpace: Space.Handle; crossJumped: BOOL; codeOffset, framesize: CARDINAL; prevBti: BTIndex ← BTNull; BEGIN bcdSpace: Space.Handle ← ListerUtil.MapPages[bcdseg]; bcd: BcdOps.BcdBase ← bcdSpace.LongPointer; mth: BcdOps.MTHandle ← @LOOPHOLE[bcd + bcd.mtOffset, Base][mti]; codeOffset ← mth.code.offset; framesize ← mth.framesize; crossJumped ← mth.crossJumped; Space.Delete[bcdSpace]; END; IF cseg = FileSegment.nullPages THEN ListerUtil.Message["Code not available"L] ELSE IF sseg = FileSegment.nullPages THEN ListerUtil.Message["Symbols not available"L] ELSE { print: BOOL ← FALSE; cspp: LONG POINTER TO PrincOps.CSegPrefix; codeSpace ← ListerUtil.MapPages[cseg]; codebase ← codeSpace.LongPointer + codeOffset; codepages ← cseg.span.pages; cspp ← codebase; SymbolTable.SetCacheSize[0]; -- clear cache symbols ← SymbolTable.Acquire[sseg]; IF cspp.header.info.altoCode THEN { ListerUtil.Message["Cannot list Alto code"L]; GO TO Fail}; IF symbols.fgTable = NIL THEN { ListerUtil.Message["Bad bcd format"L]; GO TO Fail}; ListerUtil.SetRoutineSymbols[symbols]; SetUpSource[]; OpenOutput[output]; ListerUtil.PutFileID[out]; IF crossJumped THEN CharIO.PutString[out, "Cross jumped\n"L]; CharIO.PutString[out, "Global frame size: "L]; CharIO.PutNumber[out, framesize, decimal]; CharIO.PutString[out, "\n\n"L]; IF options.radix = $hex THEN Hexify[] ELSE Octify[]; Tbytes ← Tinst ← 0; DigestFGT[]; FOR i: CARDINAL IN [0..myFGT.length) DO ff: FineGrainInfo = myFGT[i]; IF ff.bti # prevBti THEN { IF prevBti # BTNull AND print THEN ShowTotals[]; print ← FilterBody[ff.bti, proc]}; IF ff.firstSource # nullSource AND print THEN IF ff.lastSource = ff.firstSource THEN CharIO.PutChar[out, '\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]; IF print THEN { PrintBodyName[ff.bti]; IF options.full THEN CharIO.PutChar[out, '\t]; CharIO.PutString[out, " Entry point: "L]; CharIO.PutNumber[out, ep, decimal]; CharIO.PutString[out, ", Frame size: "L]; CharIO.PutNumber[out, fsize, decimal]; CharIO.PutChar[out, '\n]}}; IF print THEN { IF ~ff.procEnd THEN PrintCode[ff.pc, myFGT[i + 1].pc, options]; CharIO.PutChar[out, '\n]}; prevBti ← ff.bti; ENDLOOP; IF prevBti # Symbols.BTNull AND print THEN ShowTotals[]; (Heap.systemZone).FREE[@myFGT]; SymbolTable.Release[symbols]; Space.Delete[codeSpace]; CloseSource[]; CharIO.PutChar[out, '\n]; IF proc = NIL THEN { IF options.full THEN CharIO.PutChar[out, '\t]; CharIO.PutString[out, "Total instructions: "L]; CharIO.PutNumber[out, Tinst, decimal]; CharIO.PutString[out, ", Bytes: "L]; CharIO.PutNumber[out, Tbytes, decimal]; CharIO.PutChar[out, '\n]}; CloseOutput[] EXITS Fail => {SymbolTable.Release[symbols]; Space.Delete[codeSpace]}}}; ListProc: PUBLIC PROC [ input, proc: Strings.String, output: Strings.String, options: CodeOptions] = { ListModule[input, input, proc, output, options]}; ListCode: PUBLIC PROC [root: Strings.String, options: CodeOptions] = { ListModule[root, root, NIL, root, options]}; ListCodeInConfig: PUBLIC PROC [config, name: Strings.String, options: CodeOptions] = { ListModule[config, name, NIL, name, options]}; -- initialization Octify[]; }.