-- file: ChollaStepList.mesa
-- edited by Barth, August 20, 1981 11:05 PM
-- edited by Brotz, March 3, 1983 5:11 PM
-- edited by Crowther, December 23, 1981 10:13 AM

DIRECTORY
Ascii,
ccD: FROM "ChollaCmdDefs",
csD: FROM "CoreStreamDefs",
dsD: FROM "DisplayDefs",
Editor,
exD: FROM "ExceptionDefs",
inD: FROM "InteractorDefs",
intCommon,
lmD: FROM "LaurelMenuDefs",
MessageParse,
opD: FROM "OperationsDefs",
Storage,
String,
tsD: FROM "TOCSelectionDefs",
vmD: FROM "VirtualMgrDefs";

ChollaStepList: PROGRAM
IMPORTS ccD, dsD, Editor, exD, inD, intC: intCommon, lmD, MessageParse, Storage,
String, tsD, vmD
EXPORTS ccD =

BEGIN


stepListTopHp, stepListMiddleHp, stepLowerHp, stepListBracketsHp, prototypesMiddleHp,
prototypesLowerHp: inD.HousePtr;


SLStepList: inD.CommandProcedure =
BEGIN
IF ~ccD.IsAuthorized[onlooker, hp] THEN RETURN;
SELECT TRUE FROM
~confirmed AND ~inD.ConfirmBrackets[hp: hp.nextHouse, fileExtension: "StepList.chml."L]
=> NULL;
hp.nextHouse.text.length = 0 =>
BEGIN
String.AppendString[hp.nextHouse.text, ccD.stepListRunName];
hp.nextHouse.houseRefresher[hp.nextHouse];
exD.DisplayExceptionString["Must name a run."L];
END;
hp.nextHouse.text.length > 20 => exD.DisplayExceptionString["Run name is too long!"L];
ENDCASE =>
BEGIN
ccD.PreserveChangeInDoneFile[];
IF InstallStepList[stepListBracketsHp.text] THEN DoLowerMenu[ccD.stepListLowerHp];
END;
END; -- of SLStepList --


InstallStepList: PUBLIC PROCEDURE [runName: STRING] RETURNS [worked: BOOLEAN] =
BEGIN
-- it should compute the current step as the first unstarted step
-- and set the selection for it
IF ~MakeStepListCurrent[runName] THEN RETURN[FALSE];
intC.bboardCommandHouse.command ← SLBBoardCommand;
intC.userBracketsHouse.nextHouse ← stepListTopHp;
inD.ChangeCommandMenu
[cnp: intC.mailCommandNbr, region: intC.mailCommandRegion, linesToKeep: 2];
intC.tocCommandNbr.houses ← stepListMiddleHp;
inD.ChangeCommandMenu
[cnp: intC.tocCommandNbr, region: intC.TOCCommandRegion, linesToKeep: 0];
DoLowerMenu[ccD.stepListLowerHp];
RETURN[TRUE];
END; -- of InstallStepList --


MakeStepListCurrent: PROCEDURE [runName: STRING] RETURNS [BOOLEAN] =
BEGIN
fileName: STRING ← [ccD.tocCacheFileStringLength];
tnp: inD.TOCTextNbrPtr = intC.tocTextNbr;
toc: vmD.TOCHandle;
key: CARDINAL;
IF runName[0] # ’[ AND runName.length >= 18 THEN
{exD.DisplayExceptionString["Run name is too long."L]; RETURN[FALSE]};
ccD.CleanupDisplayMessage[];
ccD.displayedStep ← 0;
IF tnp.toc # NIL THEN
{key ← vmD.WaitForLock[tnp.toc]; toc ← tnp.toc; tnp.toc ← NIL; vmD.UnlockTOC[toc, key]};
dsD.ClearRectangle[inD.leftMargin, inD.rightMargin, tnp.topY, tnp.bottomY];
String.AppendString[fileName, runName];
String.AppendString[fileName, "StepList.chml"L];
[toc, key] ← ccD.GetTOCForFile[fileName, stepList];
IF toc = NIL THEN
{exD.DisplayExceptionString["Cannot get Step list file."L]; RETURN[FALSE]};
SetSelectionToStepToDo[toc, key];
-- Order in the String appends is critical: runName may be = to stepListBracketsHp.text.
ccD.stepListRunName.length ← 0;
String.AppendString[ccD.stepListRunName, runName];
stepListBracketsHp.text.length ← 0;
String.AppendString[stepListBracketsHp.text, ccD.stepListRunName];
tnp.toc ← toc;
dsD.ClearRectangle[inD.leftMargin, inD.rightMargin, tnp.topY, tnp.bottomY];
inD.TOCTextPainter[tnp, key];
vmD.UnlockTOC[toc, key];
RETURN[TRUE];
END; -- of MakeStepListCurrent --


SLLaurelCommand: inD.CommandProcedure =
BEGIN
ccD.PreserveChangeInDoneFile[];
ccD.RestoreLaurel[];
END; -- of SLLaurelCommand --


SLBBoardCommand: inD.CommandProcedure =
BEGIN
IF ~ccD.IsAuthorized[onlooker, hp] THEN RETURN;
ccD.PreserveChangeInDoneFile[];
ccD.CleanupDisplayMessage[];
ccD.InstallBB[];
END; -- of SLBBoardCommand --


PrototypesCommand: inD.CommandProcedure =
BEGIN
tnp: inD.TOCTextNbrPtr = intC.tocTextNbr;
toc: vmD.TOCHandle;
key: CARDINAL;
IF intC.cmCommandNbr.houses = prototypesLowerHp THEN RETURN;
IF ~ccD.IsAuthorized[maven, hp] THEN RETURN;
ccD.PreserveChangeInDoneFile[];
ccD.CleanupDisplayMessage[];
ccD.displayedStep ← 0;
IF tnp.toc # NIL THEN
{key ← vmD.WaitForLock[tnp.toc]; toc ← tnp.toc; tnp.toc ← NIL; vmD.UnlockTOC[toc, key]};
[toc, key] ← ccD.GetTOCForFile["StepListPrototypes"L, prototypes];
tnp.toc ← toc;
intC.tocCommandNbr.houses ← prototypesMiddleHp;
inD.ChangeCommandMenu
[cnp: intC.tocCommandNbr, region: intC.TOCCommandRegion, linesToKeep: 0];
DoLowerMenu[prototypesLowerHp];
tsD.ResetTOCSelection[toc, key];
dsD.ClearRectangle[inD.leftMargin, inD.rightMargin, tnp.topY, tnp.bottomY];
inD.TOCTextPainter[tnp, key];
vmD.UnlockTOC[toc, key];
END; -- of PrototypesCommand --


CurrentStep: PUBLIC PROCEDURE RETURNS [entry: vmD.TOCIndex] =
BEGIN
toc: vmD.TOCHandle = ccD.cacheTable[stepList].a.toc;
key: CARDINAL = vmD.WaitForLock[toc];
last: vmD.TOCIndex = tsD.LastSelectedEntry[toc, key];
entry ← tsD.FirstSelectedEntry[toc, key];
IF entry # last OR entry # ccD.displayedStep THEN entry ← 0;
IF entry = 0 THEN exD.DisplayExceptionString["Selection missmatch"L];
vmD.UnlockTOC[toc, key];
END; -- of CurrentStep --


StepCommand: inD.CommandProcedure =
BEGIN
tocString: STRING ← [opD.maxTOCStringLength];
tnp: inD.TOCTextNbrPtr = intC.tocTextNbr;
toc: vmD.TOCHandle = tnp.toc;
key: CARDINAL = vmD.WaitForLock[toc];
entry: vmD.TOCIndex ← tsD.FirstSelectedEntry[toc, key];
last: vmD.TOCIndex = tsD.LastSelectedEntry[toc, key];
IF ~ccD.IsAuthorized[onlooker, hp] THEN {vmD.UnlockTOC[toc, key]; RETURN};
IF entry # last OR entry = 0 THEN
{exD.DisplayExceptionString["Need one selection"L]; vmD.UnlockTOC[toc, key]; RETURN};
IF entry = ccD.displayedStep AND entry = ccD.currentStepNumber THEN
BEGIN
entry ← MIN[entry + 1, toc.indexFF - 1];
inD.MakeTOCIndexVisible[entry, key];
tsD.DeconsiderAll[tnp, key];
tsD.SetTOCSelection[toc, key, entry];
inD.Consider[entry, entry, tnp, key];
END;
vmD.GetTOCString[toc, key, entry, tocString];
vmD.UnlockTOC[toc, key];
ccD.displayedStep ← entry;
ccD.CleanupDisplayMessage[];
DoLowerMenu[stepLowerHp];
ccD.StepOperation[tocString];
END; -- of StepCommand --


StepListAndPrototypesDisplayCommand: inD.CommandProcedure =
BEGIN
IF ~ccD.IsAuthorized[onlooker, hp] THEN RETURN;
inD.DisplayMessageCommand[hp, TRUE];
END; -- of StepListAndPrototypesDisplayCommand --


MarkCommand: inD.CommandProcedure =
BEGIN
tnp: inD.TOCTextNbrPtr = intC.tocTextNbr;
toc: vmD.TOCHandle = tnp.toc;
key: CARDINAL;
cm: vmD.ComposedMessagePtr;
index: vmD.TOCIndex;
i: vmD.CharIndex;
IF ~ccD.IsAuthorized[technician, hp] THEN RETURN;
key ← vmD.WaitForLock[toc];
cm ← vmD.AllocateComposedMessageObject[];
FOR index ← tsD.FirstSelectedEntry[toc, key], tsD.NextSelectedEntry[toc, key, index]
UNTIL index = 0 DO
fieldList, subjectFL: MessageParse.FieldList;
count: CARDINAL;
ccD.LoadComposedMessage[toc, key, index, cm];
fieldList ← MessageParse.MakeFieldList[cm];
[subjectFL, count] ← MessageParse.LocateField[fieldList, "Subject"L];
IF count = 0 THEN exD.SysBug[];
FOR i IN [subjectFL.valueStart .. subjectFL.valueEnd) DO
IF vmD.GetMessageChar[cm, i] = ’/ THEN
BEGIN
i ← i + 1;
IF i >= subjectFL.valueEnd THEN EXIT;
IF vmD.GetMessageChar[cm, i] = ccD.stepListMarkChar THEN
BEGIN
vmD.DeleteRangeInMessage[[i, i + 1, cm]];
subjectFL.valueEnd ← subjectFL.valueEnd - 1;
MessageParse.UpdateFieldList[subjectFL.next, -1];
END
ELSE BEGIN
vmD.StartMessageInsertion[cm, i];
vmD.InsertMessageChar[cm, ccD.stepListMarkChar];
vmD.StopMessageInsertion[cm];
subjectFL.valueEnd ← subjectFL.valueEnd + 1;
MessageParse.UpdateFieldList[subjectFL.next, 1];
END;
[] ← ccD.SendChollaMail[replace, step, toc, key, index, cm, @fieldList];
EXIT;
END;
ENDLOOP;
MessageParse.FreeFieldList[fieldList];
ENDLOOP;
inD.UpdateTOCThumbLine[tnp, key];
vmD.UnlockTOC[toc, key];
vmD.FreeVirtualMessageObject[cm];
END; -- of MarkCommand --


EditListCommand: inD.CommandProcedure =
BEGIN
mnp: inD.MessageTextNbrPtr = intC.cmTextNbr;
cm: vmD.ComposedMessagePtr;
toc: vmD.TOCHandle = intC.tocTextNbr.toc;
key: CARDINAL;
tocString: STRING ← [opD.maxTOCStringLength];
start: CARDINAL;
IF ~ccD.IsAuthorized[maven, hp] THEN RETURN;
IF ~confirmed AND ~inD.Confirm[1] THEN RETURN;
ccD.PreserveChangeInDoneFile[];
DoLowerMenu[ccD.stepListLowerHp];
Editor.SwapMessageWithDeletionBuffer[mnp];
cm ← vmD.ComposedMessage[mnp.message];
vmD.InitComposedMessage[cm, "
"L];
vmD.StartMessageInsertion[cm, 0];
key ← vmD.WaitForLock[toc];
FOR i: vmD.TOCIndex ← tsD.FirstSelectedEntry[toc, key], tsD.NextSelectedEntry[toc, key, i]
UNTIL i = 0 DO
vmD.GetTOCString[toc, key, i, tocString];
start ← 0;
THROUGH [1 .. 2] DO
UNTIL tocString[start] = opD.substringSeparator DO
start ← start + 1;
ENDLOOP;
start ← start + 1;
ENDLOOP;
[] ← vmD.InsertSubstringInMessage[cm, tocString, start, tocString.length - start];
[] ← vmD.InsertMessageChar[cm, Ascii.CR];
ENDLOOP;
vmD.StopMessageInsertion[cm];
vmD.UnlockTOC[toc, key];
ccD.ResetTheEditor[TRUE];
END; -- of EditListCommand --


EditEntryCommand: inD.CommandProcedure =
BEGIN
mnp: inD.MessageTextNbrPtr = intC.cmTextNbr;
cm: vmD.ComposedMessagePtr;
toc: vmD.TOCHandle = intC.tocTextNbr.toc;
key: CARDINAL;
tocIndex: vmD.TOCIndex;
fieldList: MessageParse.FieldList;
IF ~ccD.IsAuthorized[maven, hp] THEN RETURN;
key ← vmD.WaitForLock[toc];
tocIndex ← tsD.FirstSelectedEntry[toc, key];
vmD.UnlockTOC[toc, key];
IF tocIndex = 0 THEN {exD.DisplayExceptionString["An entry must be selected."L]; RETURN};
IF ~confirmed AND ~inD.Confirm[1] THEN RETURN;
ccD.PreserveChangeInDoneFile[];
DoLowerMenu[ccD.stepListLowerHp];
Editor.SwapMessageWithDeletionBuffer[mnp];
cm ← vmD.ComposedMessage[mnp.message];
key ← vmD.WaitForLock[toc];
ccD.LoadComposedMessage[toc, key, tocIndex, cm];
vmD.UnlockTOC[toc, key];
fieldList ← MessageParse.MakeFieldList[cm];
MessageParse.DeleteField[cm, @fieldList, "UniqueID"L];
MessageParse.DeleteField[cm, @fieldList, "ThisID"L];
MessageParse.FreeFieldList[fieldList];
ccD.ResetTheEditor[TRUE];
END; -- of EditEntryCommand --


InsertInStepListCommand: inD.CommandProcedure =
BEGIN
cm: vmD.ComposedMessagePtr = vmD.ComposedMessage[intC.cmTextNbr.message];
tnp: inD.TOCTextNbrPtr = intC.tocTextNbr;
toc: vmD.TOCHandle = tnp.toc;
fieldList, subjectFL: MessageParse.FieldList ← NIL;
nIDs: CARDINAL;
valid: BOOLEAN;
count, key: CARDINAL;
first, preInsertFF: vmD.TOCIndex;
IF ~ccD.IsAuthorized[maven, hp] THEN RETURN;
ccD.StartMultiTOCOperation[];
BEGIN -- for EXITS --
key ← vmD.WaitForLock[toc];
first ← tsD.FirstSelectedEntry[toc, key] + 1;
preInsertFF ← toc.indexFF;
IF first < FirstEditableStep[toc, key] THEN
BEGIN
exD.DisplayExceptionString["Editing the step list before a started step is not allowed."L];
GO TO Return;
END;
fieldList ← MessageParse.MakeFieldList[cm];
[subjectFL, count] ← MessageParse.LocateField[fieldList, "Subject"L];
SELECT count FROM
0 => {[valid, nIDs] ← ValidateInsertList[cm, fieldList]; IF ~valid THEN GO TO Return};
1 =>
BEGIN
string: STRING ← [opD.maxTOCStringLength];
IF subjectFL.valueEnd - subjectFL.valueStart > opD.maxTOCStringLength THEN
{exD.DisplayExceptionString["Entry too long!"L]; GO TO Return};
MessageParse.GetWholeField[cm, subjectFL, "Subject"L, string];
IF ~ValidateOneStepListLine[string] THEN GO TO Return;
nIDs ← 1;
END;
ENDCASE => {exD.DisplayExceptionString["Too many Subject: fields!"L]; GO TO Return};
tsD.DeconsiderAll[tnp, key];
tsD.ResetTOCSelection[toc, key];
MessageParse.ReplaceOrAppendField[cm, @fieldList, "
Run"L, ccD.stepListRunName];
IF ~ccD.SendChollaMail[action: insert, type: step, toc: toc, key: key, index: first, cm: cm,
fieldListPtr: @fieldList, nIDs: nIDs]
THEN exD.DisplayExceptionString["Could not insert in step list!"L];
IF toc.indexFF = preInsertFF THEN first ← first - 1;
IF first > 0 THEN tsD.SetTOCSelection[toc, key, first];
tsD.ConsiderAll[tnp, key];
inD.UpdateTOCThumbLine[tnp, key];
EXITS
Return => NULL;
END; -- of EXITS block --
MessageParse.FreeFieldList[fieldList];
vmD.UnlockTOC[toc, key];
ccD.FinishMultiTOCOperation[];
END; -- of InsertInStepListCommand --


ValidateInsertList: PROCEDURE
[cm: vmD.ComposedMessagePtr, fieldList: MessageParse.FieldList]
RETURNS [valid: BOOLEAN, nIDs: CARDINAL] =
BEGIN
char: CHARACTER;
string: STRING ← [opD.maxTOCStringLength];
nIDs ← 0;
valid ← FALSE;
FOR i: vmD.CharIndex IN [0 .. vmD.GetMessageSize[cm]) DO
IF (char ← vmD.GetMessageChar[cm, i]) = Ascii.CR THEN
BEGIN
IF string.length > 0 THEN
BEGIN
IF ValidateOneStepListLine[string] THEN {nIDs ← nIDs + 1; string.length ← 0}
ELSE GO TO Malformed;
END;
END
ELSE BEGIN
IF string.length >= string.maxlength THEN
{exD.DisplayExceptionString["Entry too long!"L]; GO TO Malformed};
string[string.length] ← char;
string.length ← string.length + 1;
END;
REPEAT
Malformed =>
BEGIN
target: inD.TextSelectionPtr = @intC.target;
exD.DisplayExceptionStringOnLine
["Malformed step list entry near underlined selection."L, 2];
Editor.DeUnderlineSelection[selection: target, underline: target];
target↑ ← inD.TextSelection[intC.cmTextNbr, i, i + 1, i, 0, char, FALSE];
intC.newTargetSelection ← TRUE;
Editor.UnderlineSelection[selection: target, underline: target];
inD.IdleLoop[];
RETURN;
END;
ENDLOOP;
IF nIDs = 0 THEN
{exD.DisplayExceptionString["Cannot insert: no steps are specified."L]; RETURN};
IF vmD.GetMessageChar[cm, 0] # Ascii.CR THEN
BEGIN
vmD.StartMessageInsertion[cm, 0];
vmD.InsertMessageChar[cm, Ascii.CR];
vmD.StopMessageInsertion[cm];
MessageParse.UpdateFieldList[fieldList, 1];
END;
valid ← TRUE;
END; -- of ValidateInsertList --


ValidateOneStepListLine: PROCEDURE [string: STRING] RETURNS [valid: BOOLEAN] =
BEGIN
slashCount: CARDINAL ← 0;
stepName: STRING ← [2];
specName: STRING ← [2];
dataName: STRING ← [0];
p: ccD.ParsedStep ← [specName, 0, dataName, 0, stepName, none, 0, 0];
FOR i: CARDINAL IN [0 .. string.length) DO
IF string[i] = ’/ THEN slashCount ← slashCount + 1;
ENDLOOP;
ccD.ParseStep[string, @p];
valid ← FALSE;
SELECT TRUE FROM
p.stepName.length = 0 => exD.DisplayExceptionString["No /StepName/"L];
slashCount MOD 2 = 1 => exD.DisplayExceptionString["Unmatched slash ( / )."L];
p.status = none => exD.DisplayExceptionString["Invalid status word."L];
p.specName.length = 0 => exD.DisplayExceptionString["No specification listed."L];
ENDCASE => valid ← TRUE;
END; -- of ValidateOneStepListLine --


ReplaceEntryCommand: inD.CommandProcedure =
BEGIN
tnp: inD.TOCTextNbrPtr = intC.tocTextNbr;
toc: vmD.TOCHandle = tnp.toc;
fieldList, subjectFL, deleteFL: MessageParse.FieldList ← NIL;
cm: vmD.ComposedMessagePtr = vmD.ComposedMessage[intC.cmTextNbr.message];
deleteCM: vmD.ComposedMessagePtr;
index, firstIndex, lastIndex: vmD.TOCIndex;
count, key, nIDs: CARDINAL;
valid: BOOLEAN;
IF ~ccD.IsAuthorized[maven, hp] THEN RETURN;
ccD.StartMultiTOCOperation[];
BEGIN -- for EXITS --
key ← vmD.WaitForLock[toc];
firstIndex ← lastIndex ← tsD.FirstSelectedEntry[toc, key];
IF firstIndex < FirstEditableStep[toc, key] THEN
BEGIN
exD.DisplayExceptionString["Editing the step list before a started step is not allowed."L];
GO TO Return;
END;
IF firstIndex = 0 THEN
{exD.DisplayExceptionString["An entry must be selected"L]; GO TO Return};
UNTIL (index ← tsD.NextSelectedEntry[toc, key, lastIndex]) = 0 DO
IF index # lastIndex + 1 THEN
{exD.DisplayExceptionString["Cannot replace discontiguous steps!"L]; GO TO Return};
lastIndex ← index;
ENDLOOP;
fieldList ← MessageParse.MakeFieldList[cm];
[subjectFL, count] ← MessageParse.LocateField[fieldList, "Subject"L];
SELECT count FROM
0 => {[valid, nIDs] ← ValidateInsertList[cm, fieldList]; IF ~valid THEN GO TO Return};
1 =>
BEGIN
string: STRING ← [opD.maxTOCStringLength];
IF subjectFL.valueEnd - subjectFL.valueStart > opD.maxTOCStringLength THEN
{exD.DisplayExceptionString["Entry too long!"L]; GO TO Return};
MessageParse.GetWholeField[cm, subjectFL, "Subject"L, string];
IF ~ValidateOneStepListLine[string] THEN GO TO Return;
nIDs ← 1;
END;
ENDCASE => {exD.DisplayExceptionString["Too many Subject: fields!"L]; GO TO Return};
MessageParse.ReplaceOrAppendField[cm, @fieldList, "
Run"L, ccD.stepListRunName];
deleteCM ← vmD.AllocateComposedMessageObject[];
tsD.DeconsiderAll[tnp, key];
tsD.ResetTOCSelection[toc, key];
FOR index DECREASING IN [firstIndex .. lastIndex] DO
ccD.LoadComposedMessage[toc, key, index, deleteCM];
deleteFL ← MessageParse.MakeFieldList[deleteCM];
IF ~ccD.SendChollaMail[delete, step, toc, key, index, deleteCM, @deleteFL] THEN
exD.DisplayExceptionString["Could not delete entry!"L];
MessageParse.FreeFieldList[deleteFL];
ENDLOOP;
vmD.FreeVirtualMessageObject[deleteCM];
IF ~ccD.SendChollaMail[action: insert, type: step, toc: toc, key: key, index: firstIndex,
cm: cm, fieldListPtr: @fieldList, nIDs: nIDs]
THEN exD.DisplayExceptionString["Could not insert entry!"L];
inD.UpdateTOCThumbLine[tnp, key];
EXITS
Return => NULL;
END; -- of EXITS block --
vmD.UnlockTOC[toc, key];
ccD.FinishMultiTOCOperation[];
MessageParse.FreeFieldList[fieldList];
END; -- of ReplaceEntryCommand --


DeleteEntryCommand: inD.CommandProcedure =
BEGIN
tnp: inD.TOCTextNbrPtr = intC.tocTextNbr;
toc: vmD.TOCHandle = tnp.toc;
key: CARDINAL;
cm: vmD.ComposedMessagePtr ← vmD.AllocateComposedMessageObject[];
prev: vmD.TOCIndex;
ccD.StartMultiTOCOperation[];
key ← vmD.WaitForLock[toc];
SELECT TRUE FROM
~ccD.IsAuthorized[maven, hp] => NULL;
tsD.TOCSelectionEmpty[toc, key] =>
exD.DisplayExceptionString["An entry must be selected"L];
tsD.FirstSelectedEntry[toc, key] < FirstEditableStep[toc, key] =>
exD.DisplayExceptionString["Editing the step list before a started step is not allowed."L];
(confirmed OR inD.Confirm[1]) =>
FOR tocIndex: vmD.TOCIndex ← tsD.LastSelectedEntry[toc, key], prev
UNTIL tocIndex = 0 DO
fieldList: MessageParse.FieldList;
prev ← tsD.PrevSelectedEntry[toc, key, tocIndex];
tsD.RemoveRange[toc, key, tocIndex, tocIndex];
ccD.LoadComposedMessage[toc, key, tocIndex, cm];
fieldList ← MessageParse.MakeFieldList[cm];
IF ~ccD.SendChollaMail[delete, step, toc, key, tocIndex, cm, @fieldList] THEN
exD.DisplayExceptionString["Could not delete entry!"L];
MessageParse.FreeFieldList[fieldList];
ENDLOOP;
ENDCASE;
inD.UpdateTOCThumbLine[tnp, key];
vmD.UnlockTOC[toc, key];
ccD.FinishMultiTOCOperation[];
vmD.FreeVirtualMessageObject[cm];
END; -- of DeleteEntryCommand --


PrototypesInsertCommand: inD.CommandProcedure =
BEGIN
cm: vmD.ComposedMessagePtr = vmD.ComposedMessage[intC.cmTextNbr.message];
tnp: inD.TOCTextNbrPtr = intC.tocTextNbr;
toc: vmD.TOCHandle = tnp.toc;
key: CARDINAL ← vmD.WaitForLock[toc];
tocIndex: vmD.TOCIndex ← tsD.FirstSelectedEntry[toc, key] + 1;
IF ccD.IsAuthorized[maven, hp] THEN
BEGIN
fieldList: MessageParse.FieldList;
tsD.DeconsiderAll[tnp, key];
tsD.ResetTOCSelection[toc, key];
fieldList ← MessageParse.MakeFieldList[cm];
BEGIN -- for EXITS --
IF MessageParse.LocateField[fieldList, "Subject"L].count = 0 THEN
BEGIN
exD.DisplayExceptionString
["No Subject: field! Are you sure you want to modify the Prototypes file?"L];
IF ~inD.Confirm[2] THEN GO TO DontWantTo;
END;
IF ccD.SendChollaMail[insert, prototypes, toc, key, tocIndex, cm, @fieldList] THEN
tsD.SetTOCSelection[toc, key, tocIndex]
ELSE exD.DisplayExceptionString["Malformed prototypes message!"L];
EXITS
DontWantTo => NULL;
END; -- of block for EXITS --
MessageParse.FreeFieldList[fieldList];
tsD.ConsiderAll[tnp, key];
inD.UpdateTOCThumbLine[tnp, key];
END;
vmD.UnlockTOC[toc, key];
END; -- of PrototypesInsertCommand --


PrototypesReplaceCommand: inD.CommandProcedure =
BEGIN
cm: vmD.ComposedMessagePtr = vmD.ComposedMessage[intC.cmTextNbr.message];
tnp: inD.TOCTextNbrPtr = intC.tocTextNbr;
toc: vmD.TOCHandle = tnp.toc;
key: CARDINAL ← vmD.WaitForLock[toc];
tocIndex: vmD.TOCIndex ← tsD.FirstSelectedEntry[toc, key];
SELECT TRUE FROM
~ccD.IsAuthorized[maven, hp] => NULL;
tocIndex = 0 => exD.DisplayExceptionString["An entry must be selected"L];
ENDCASE =>
BEGIN
fieldList: MessageParse.FieldList ← MessageParse.MakeFieldList[cm];
CopyUniqueIDsIntoMessage[toc, key, tocIndex, cm, @fieldList];
IF ~ccD.SendChollaMail[replace, prototypes, toc, key, tocIndex, cm, @fieldList] THEN
exD.DisplayExceptionString["Could not replace prototype message!"L];
MessageParse.FreeFieldList[fieldList];
END;
inD.UpdateTOCThumbLine[tnp, key];
vmD.UnlockTOC[toc, key];
END; -- of PrototypesReplaceCommand --


PrototypesDeleteCommand: inD.CommandProcedure =
BEGIN
tnp: inD.TOCTextNbrPtr = intC.tocTextNbr;
toc: vmD.TOCHandle = tnp.toc;
key: CARDINAL ← vmD.WaitForLock[toc];
cm: vmD.ComposedMessagePtr ← vmD.AllocateComposedMessageObject[];
prev: vmD.TOCIndex;
SELECT TRUE FROM
~ccD.IsAuthorized[maven, hp] => NULL;
tsD.TOCSelectionEmpty[toc, key] =>
exD.DisplayExceptionString["An entry must be selected"L];
(confirmed OR inD.Confirm[1]) =>
FOR tocIndex: vmD.TOCIndex ← tsD.LastSelectedEntry[toc, key], prev
UNTIL tocIndex = 0 DO
fieldList: MessageParse.FieldList;
prev ← tsD.PrevSelectedEntry[toc, key, tocIndex];
tsD.RemoveRange[toc, key, tocIndex, tocIndex];
ccD.LoadComposedMessage[toc, key, tocIndex, cm];
fieldList ← MessageParse.MakeFieldList[cm];
IF ~ccD.SendChollaMail[delete, prototypes, toc, key, tocIndex, cm, @fieldList] THEN
exD.DisplayExceptionString["Could not delete prototype message!"L];
MessageParse.FreeFieldList[fieldList];
ENDLOOP;
ENDCASE;
inD.UpdateTOCThumbLine[tnp, key];
vmD.UnlockTOC[toc, key];
vmD.FreeVirtualMessageObject[cm];
END; -- of PrototypesDeleteCommand --


GetStepStatus: PUBLIC PROCEDURE
[toc: vmD.TOCHandle, key: CARDINAL, index: vmD.TOCIndex]
RETURNS [s: ccD.StepStatus] =
BEGIN
dummy: STRING ← [0];
p: ccD.ParsedStep ← [dummy, 0, dummy, 0, dummy, none, 0, 0];
tocString: STRING ← [opD.maxTOCStringLength];
vmD.GetTOCString[toc, key, index, tocString];
ccD.ParseStep[tocString, @p];
RETURN[p.status];
END; -- of GetStepStatus --


SetStepStatus: PUBLIC PROCEDURE
[toc: vmD.TOCHandle, key: CARDINAL, index: vmD.TOCIndex, s: ccD.StepStatus] =
BEGIN
dummy: STRING ← [0];
p: ccD.ParsedStep ← [dummy, 0, dummy, 0, dummy, none, 0, 0];
tocString: STRING ← [opD.maxTOCStringLength];
statusString: STRING ← [20];
lookup: ARRAY [0 .. 1) OF MessageParse.FieldRec
← [[name: "Subject"L, bodyStart: 0, bodyEnd: 0, found: 0]];
dm: vmD.DisplayMessagePtr ← vmD.AllocateDisplayMessageObject[];
vmD.LoadDisplayMessage[toc, key, index, dm];
MessageParse.ParseMessage[vm: dm, fields: DESCRIPTOR[lookup]];
IF lookup[0].found # 1 THEN exD.SysBug[]; --someday do better
StatusToString[s, statusString];
FOR i: CARDINAL IN [0 .. 11) DO
vmD.PutMessageChar[dm, lookup[0].bodyStart + 1 + i, statusString[i]];
ENDLOOP;
vmD.FlushDisplayMessage[dm, key];
vmD.FreeVirtualMessageObject[dm];
vmD.GetTOCString[toc, key, index, tocString];
ccD.ParseStep[tocString, @p];
IF p.status = none THEN exD.SysBug[];
FOR i: CARDINAL IN [0 .. 11) DO
tocString[p.statusIndex + i] ← statusString[i];
ENDLOOP;
vmD.PutTOCString[toc, key, index, tocString];
IF intC.tocTextNbr.toc = toc THEN inD.RefreshTOCChange[toc, key, index, replace];
END; -- of SetStepStatus --


StatusToString: PUBLIC PROCEDURE [s: ccD.StepStatus, t: STRING] =
BEGIN
a: STRING ← SELECT s FROM
finished => "Finished
"L,
notStarted => "Not Started"L,
started => "Started
"L,
inProcess => "InProcess
"L,
processDone => "Processed
"L,
rejected => "Rejected
"L,
ENDCASE => "None
"L;
t.length ← 0;
String.AppendString[t , a];
END; -- of StatusToString --


SetSelectionToStepToDo: PROCEDURE [toc: vmD.TOCHandle, key: CARDINAL] =
BEGIN
index: vmD.TOCIndex = StepToDo[toc, key];
IF index = 0 THEN tsD.ResetTOCSelection[toc, key] ELSE tsD.SetTOCSelection[toc, key, index];
END; -- of SetSelectionToStepToDo --


StepToDo: PROCEDURE [toc: vmD.TOCHandle, key: CARDINAL]
RETURNS [index: vmD.TOCIndex] =
BEGIN
statusWord: STRING ← [15];
indexFF: vmD.TOCIndex = vmD.FirstFreeTOCIndex[toc, key];
index ← 0;
FOR i: vmD.TOCIndex DECREASING IN [1 .. indexFF) DO
ccD.StatusOfTOCEntry[toc, key, i, statusWord];
SELECT TRUE FROM
String.EquivalentString[statusWord, "NotStarted"L] => LOOP;
String.EquivalentString[statusWord, "Finished"L] => index ← i + 1;
String.EquivalentString[statusWord, "Rejected"L] => index ← i + 1;
ENDCASE => index ← i;
IF index = indexFF THEN index ← index - 1;
EXIT;
ENDLOOP;
END; -- of StepToDo --


FirstEditableStep: PROCEDURE [toc: vmD.TOCHandle, key: CARDINAL]
RETURNS [vmD.TOCIndex] =
BEGIN
statusWord: STRING ← [15];
indexFF: vmD.TOCIndex = vmD.FirstFreeTOCIndex[toc, key];
FOR index: vmD.TOCIndex DECREASING IN [1 .. indexFF) DO
ccD.StatusOfTOCEntry[toc, key, index, statusWord];
IF ~String.EquivalentString[statusWord, "NotStarted"L] THEN RETURN[index + 1];
ENDLOOP;
RETURN[1];
END; -- of FirstEditableStep --


DoLowerMenu: PUBLIC PROCEDURE [hp: inD.HousePtr] =
-- Sets the editor window menu to the list headed by hp.
BEGIN
IF intC.cmCommandNbr.houses = hp THEN RETURN;
lmD.ChangeEditorMenu[singleLine];
intC.cmCommandNbr.houses ← hp;
inD.ChangeCommandMenu
[cnp: intC.cmCommandNbr, region: intC.CMCommandRegion, linesToKeep: 0];
END; -- of DoLowerMenu --


CopyUniqueIDsIntoMessage: PUBLIC PROCEDURE
[toc: vmD.TOCHandle, key: CARDINAL, index: vmD.TOCIndex,
cm: vmD.ComposedMessagePtr, fieldListPtr: MessageParse.FieldListPtr] =
BEGIN
thisID, uniqueID: ccD.UniqueID;
ccD.GetBothIDsUsingIndex[toc, key, index, @thisID, @uniqueID];
ccD.FillIDField[cm, fieldListPtr, "UniqueID"L, @uniqueID];
ccD.FillIDField[cm, fieldListPtr, "ThisID"L, @thisID];
END; -- of CopyUniqueIDsIntoMessage --


-- Startup code for StepList --

Init: PROCEDURE =
BEGIN
stepListTopMenu: ARRAY [0 .. 3) OF lmD.HouseDescriptor ←
[[text: "Step list"L, type: brackets, bracketsText: ""L, command: SLStepList],
[text: "Prototypes"L, command: PrototypesCommand],
[text: "Laurel"L, command: SLLaurelCommand, indicDone: FALSE, endOfLine: TRUE,
rightFlush: TRUE]];
stepListMiddleMenu: ARRAY [0 .. 6) OF lmD.HouseDescriptor ←
[[text: "Step"L, command: StepCommand],
[text: "Display"L, command: StepListAndPrototypesDisplayCommand],
[text: "Mark"L, command: MarkCommand],
[text: "Edit list"L, command: EditListCommand],
[text: "Edit entry"L, command: EditEntryCommand],
[text: "Spec"L, type: brackets, bracketsText: ""L, command: ccD.SpecCommand]];
stepListLowerMenu: ARRAY [0 .. 4) OF lmD.HouseDescriptor ←
[[text: "Step list: "L, type: text],
[text: "Insert"L, command: InsertInStepListCommand],
[text: "Replace"L, command: ReplaceEntryCommand],
[text: "Delete"L, command: DeleteEntryCommand]];
stepLowerMenu: ARRAY [0 .. 6) OF lmD.HouseDescriptor ←
[[text: "Start"L, command: ccD.StartStepCommand],
[text: "Process"L, command: ccD.ProcessStepCommand],
[text: "Cancel"L, command: ccD.CancelStepCommand],
[text: "Process done"L, command: ccD.ProcessDoneStepCommand],
[text: "Reject"L, command: ccD.RejectStepCommand],
[text: "Finish"L, endOfLine: TRUE, command: ccD.FinishStepCommand]];
prototypesMiddleMenu: ARRAY [0 .. 1) OF lmD.HouseDescriptor ←
[[text: "Display"L, command: StepListAndPrototypesDisplayCommand]];
prototypesLowerMenu: ARRAY [0 .. 4) OF lmD.HouseDescriptor ←
[[text: "Prototypes: "L, type: text],
[text: "Insert"L, command: PrototypesInsertCommand],
[text: "Replace"L, command: PrototypesReplaceCommand],
[text: "Delete"L, command: PrototypesDeleteCommand]];
prototypesHp, laurelHp: inD.HousePtr;

stepListTopHp ← lmD.CreateCommandHouses
[DESCRIPTOR[stepListTopMenu], Storage.Node, Storage.String, 2,
intC.newMailCommandHouse.leftX];
stepListBracketsHp ← stepListTopHp.nextHouse;
prototypesHp ← lmD.MapHouseTextToHousePtr[stepListTopHp, "Prototypes"L];
laurelHp ← lmD.MapHouseTextToHousePtr[prototypesHp, "Laurel"L];
prototypesHp.leftX ← prototypesHp.leftX + (laurelHp.leftX - prototypesHp.rightX - 25);
prototypesHp.rightX ← prototypesHp.rightX + (laurelHp.leftX - prototypesHp.rightX - 25);
stepListMiddleHp ← lmD.CreateCommandHouses
[DESCRIPTOR[stepListMiddleMenu], Storage.Node, Storage.String, 0];
ccD.stepListLowerHp ← lmD.CreateCommandHouses
[DESCRIPTOR[stepListLowerMenu], Storage.Node, Storage.String, 0];
ccD.stepListLowerHp.typeface ← italicFace;
stepLowerHp ← lmD.CreateCommandHouses
[DESCRIPTOR[stepLowerMenu], Storage.Node, Storage.String, 0];
prototypesMiddleHp ← lmD.CreateCommandHouses
[DESCRIPTOR[prototypesMiddleMenu], Storage.Node, Storage.String, 0];
prototypesLowerHp ← lmD.CreateCommandHouses
[DESCRIPTOR[prototypesLowerMenu], Storage.Node, Storage.String, 0];
prototypesLowerHp.typeface ← italicFace;
END; -- of Init --


Init[];


END. -- of ChollaStepList --