-- CLControl.mesa
-- Last edited by Satterthwaite on October 20, 1982 12:37 pm
DIRECTORY
CharIO: TYPE USING [PutChar, PutLine, PutString],
CommandUtil: TYPE USING [
CommandObject, CopyString, Echo, Failed, FreePairList, FreeString,
GetNth, ListLength, PairList, Parse, SetExtension],
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[VAL[byte]]};
NullDelete: Stream.DeleteProcedure = {};
LogString: PROC [s: Strings.String] = {CharIO.PutString[log, s]};
LogChar: PROC [c: CHAR] = {CharIO.PutChar[log, c]};
RepeatCommand: PROC [s: Stream.Handle] = {
OPEN CharIO;
PutString[s, "\nListing "L]; PutString[s, inputName];
PutString[s, ", output 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;
[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];
ENDCASE => GO TO badSemantics;
[rootName, procName] ← ExtractParts[inputName];
IF outputName = NIL THEN
outputName ← CommandUtil.CopyString[
IF procName # NIL THEN procName ELSE rootName, 2+("cl"L).length];
outputName ← CommandUtil.SetExtension[outputName, "cl"L];
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[VAL[(c.ORD-'A.ORD) + 'a.ORD]] ← 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[VAL[(c.ORD-'A.ORD) + 'a.ORD]] ← 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[];
}.