-- CLControl.mesa -- Last edited by Satterthwaite on September 15, 1982 5:47 pm DIRECTORY CharIO: TYPE USING [PutChar, PutLine, PutString], CommandUtil: TYPE USING [ CommandObject, CopyString, Echo, Failed, FreePairList, FreeString, GetNth, ListLength, PairList, Parse], Exec: TYPE USING [AddCommand, commandLine, w], ExecOps: TYPE USING [CheckForAbort, Command], ListerOps: TYPE USING [ListProc], OSMiscOps: TYPE USING [BcdCreateTime], Runtime: TYPE USING [CallDebugger], Stream: TYPE USING [ Handle, Object, PutByteProcedure, DeleteProcedure, Delete], Strings: TYPE USING [ AppendChar, AppendString, EquivalentSubString, String, SubStringDescriptor], Time: TYPE USING [Append, AppendCurrent, Current, Unpack], TTY: TYPE USING [PutChar]; CLControl: PROGRAM IMPORTS CharIO, CommandUtil, Exec, ExecOps, ListerOps, OSMiscOps, Runtime, Stream, Strings, Time, TTY = { EquivalentString: PROC [s1, s2: Strings.String] RETURNS [BOOL] = { ss1: Strings.SubStringDescriptor ← [base: s1, offset: 0, length: s1.length]; ss2: Strings.SubStringDescriptor ← [base: s2, offset: 0, length: s2.length]; RETURN [Strings.EquivalentSubString[@ss1, @ss2]]}; -- command gathering and logging log: Stream.Handle ← NIL; logStreamObject: Stream.Object; SetLogStream: PROC = { logStreamObject ← [ options: TRASH, getByte: TRASH, putByte: PutTTY, getWord: TRASH, putWord: TRASH, get: TRASH, put: TRASH, setSST: TRASH, sendAttention: TRASH, waitAttention: TRASH, delete: NullDelete]; log ← @logStreamObject}; PutTTY: Stream.PutByteProcedure = {(Exec.w).PutChar['\000 + byte]}; NullDelete: Stream.DeleteProcedure = {}; LogString: PROC [s: Strings.String] = {CharIO.PutString[log, s]}; LogChar: PROC [c: CHAR] = {CharIO.PutChar[log, c]}; renamedOutput: BOOL ← FALSE; RepeatCommand: PROC [s: Stream.Handle] = { OPEN CharIO; PutString[s, "\nListing "L]; PutString[s, inputName]; IF renamedOutput THEN { PutString[s, ", listing to "L]; PutString[s, outputName]}; PutChar[s, '\n]}; WriteHerald: PROC [s: Stream.Handle, id: Strings.String] = { OPEN CharIO; herald: STRING ← [60]; Strings.AppendString[herald, "Cedar 3.4 Code Lister of "L]; Time.Append[herald, Time.Unpack[[OSMiscOps.BcdCreateTime[]]]]; herald.length ← herald.length-3; PutLine[s, herald]; IF id # NIL THEN {PutString[s, id]; PutString[s, " -- "L]}; herald.length ← 0; Time.AppendCurrent[herald]; PutLine[s, herald]}; -- file name bookkeeping inputName, outputName: Strings.String ← NIL; commandArgs: CommandUtil.PairList; rootName, procName: Strings.String ← NIL; ExtractParts: PROC [s: Strings.String] RETURNS [root, rest: Strings.String] = { m: CARDINAL ← 0; WHILE m < s.length AND s[m] # '. DO m ← m+1 ENDLOOP; root ← CommandUtil.CopyString[NIL, m]; FOR i: CARDINAL IN [0..m) DO Strings.AppendChar[root, s[i]] ENDLOOP; IF m + 1 < s.length THEN { rest ← CommandUtil.CopyString[NIL, s.length-(m+1)]; FOR i: CARDINAL IN (m..s.length) DO Strings.AppendChar[rest, s[i]] ENDLOOP} ELSE rest ← NIL; RETURN}; -- switches StandardDefaults: PACKED ARRAY CHAR ['a..'z] OF BOOL = ALL[FALSE]; -- D Call debugger on error -- H Hexadecimal code -- O Octal code -- S Stripped code -- others are unused -- Exec interfaces DoCommand: PROC = { theCommand: CommandUtil.CommandObject ← [ pos: Exec.commandLine.i, len: Exec.commandLine.s.length, -- data: @Exec.commandLine.s.text]; data: LOOPHOLE[Exec.commandLine.s + StringBody[0].SIZE]]; results: CommandUtil.PairList; switches: Strings.String; defaultSwitches: PACKED ARRAY CHAR ['a..'z] OF BOOL ← StandardDefaults; localSwitches: PACKED ARRAY CHAR ['a..'z] OF BOOL; SetLogStream[]; WriteHerald[log, NIL]; -- main loop DO { Initialize: PROC = {RepeatCommand[log]}; Finalize: PROC = {}; startTime: LONG CARDINAL; localSwitches ← defaultSwitches; renamedOutput ← FALSE; [inputName, commandArgs, results, switches] ← CommandUtil.Parse[ s: @theCommand, opX: 2+("bcd"L).length, resultX: 2+("cl"L).length ! CommandUtil.Failed => {GO TO badSyntax}]; IF inputName = NIL AND switches = NIL THEN EXIT; -- done listing LogString["\nCommand: "L]; CommandUtil.Echo[ d: log, operator: inputName, argList: commandArgs, resultList: results, switches: switches]; IF inputName = NIL THEN GO TO globalSwitches; SELECT CommandUtil.ListLength[results] FROM 0 => NULL; 1 => { outputName ← CommandUtil.GetNth[list: results, n: 0]; renamedOutput ← TRUE} ENDCASE => GO TO badSemantics; [rootName, procName] ← ExtractParts[inputName]; IF outputName = NIL THEN { IF procName # NIL THEN { outputName ← CommandUtil.CopyString[procName]; renamedOutput ← TRUE} ELSE outputName ← CommandUtil.CopyString[rootName]}; IF switches # NIL THEN { i: CARDINAL ← 0; sense: BOOL ← TRUE; WHILE i < switches.length DO c: CHAR = switches[i]; SELECT c FROM '-, '~ => sense ← ~sense; IN ['a..'z] => {localSwitches[c] ← sense; sense ← TRUE}; IN ['A..'Z] => {localSwitches[c + ('a-'A)] ← sense; sense ← TRUE}; '! => {Runtime.CallDebugger[NIL]; sense ← TRUE}; ENDCASE; i ← i+1; ENDLOOP; switches ← CommandUtil.FreeString[switches]}; startTime ← Time.Current[]; Initialize[]; ListerOps.ListProc[ input: rootName, proc: procName, output: outputName, options: [ full: localSwitches['h] OR localSwitches['o], stripped: localSwitches['s], radix: IF localSwitches['h] THEN hex ELSE octal] ! UNWIND => {Finalize[]}]; Finalize[]; IF ExecOps.CheckForAbort[] THEN EXIT; EXITS globalSwitches => { sense: BOOL ← TRUE; results ← CommandUtil.FreePairList[results]; FOR i: CARDINAL IN [0..switches.length) DO c: CHAR = switches[i]; SELECT c FROM '-, '~ => sense ← ~sense; '! => Runtime.CallDebugger[NIL]; IN ['a..'z] => {defaultSwitches[c] ← sense; sense ← TRUE}; IN ['A..'Z] => {defaultSwitches[c + ('a-'A)] ← sense; sense ← TRUE}; ENDCASE => EXIT; ENDLOOP; switches ← CommandUtil.FreeString[switches]}; badSemantics => { results ← CommandUtil.FreePairList[results]; LogString["\n -- Illegal command"L]}}; inputName ← CommandUtil.FreeString[inputName]; outputName ← CommandUtil.FreeString[outputName]; commandArgs ← CommandUtil.FreePairList[commandArgs]; rootName ← CommandUtil.FreeString[rootName]; procName ← CommandUtil.FreeString[procName]; REPEAT badSyntax => {LogString["-- Illegal syntax"L]}; ENDLOOP; Stream.Delete[log]; log ← NIL}; -- global Binder initialization Init: PROC = { Exec.AddCommand["cl"L, DoCommand]; Exec.AddCommand["CodeLister"L, DoCommand]}; Init[]; }.