-- File: EchoServer.mesa, Last Edit: January 30, 1981 3:16 PM
-- Please don't forget to update the herald too.....
DIRECTORY
Ascii USING [CR],
InlineDefs USING [MesaToBcplLongNumber],
Process USING [Yield],
Event USING [Item, Reason, AddNotifier],
FormSW USING [
AllocateItemDescriptor, newLine, ClientItemsProcType, ProcType, FindItem,
Display, CommandItem, BooleanItem],
MsgSW USING [AppendString],
Tool USING [Create, MakeSWsProc, MakeMsgSW, MakeFormSW, AddThisSW],
ToolWindow USING [TransitionProcType, DisplayProcType, CreateSubwindow],
Window USING [Handle, Box, DisplayData, DisplayInvert, DisplayWhite],
EchoServerDefs USING [
echoStatsRequest, echoStatsReply, EchoStatsEntry, echoVersion],
StatsDefs USING [StatIncr, StatBump, StatGetCounter],
PupDefs USING [
PupBuffer, ReturnFreePupBuffer, PupPackageMake, PupPackageDestroy,
PupRouterSendThis, ReturnPup, SwapPupSourceAndDest, GetPupContentsBytes,
PupSocket, PupSocketMake, PupSocketDestroy, PupSocketKick, veryLongWait],
PupTypes USING [echoSoc, fillInPupAddress];
EchoServer: PROGRAM
IMPORTS
InlineDefs, Process, Event, FormSW, MsgSW, Tool, ToolWindow, Window,
StatsDefs, PupDefs
EXPORTS EchoServerDefs =
BEGIN OPEN PupDefs;
useCount, hits: CARDINAL ← 0;
pleaseStop, running, verbose: BOOLEAN ← FALSE;
echoFork: PROCESS;
echoSocket: PupSocket;
showSomething: PROCEDURE [CHARACTER] ← DummyEchoHook;
tool, msg, form, boxes: Window.Handle ← NIL;
eventItem: Event.Item ← [eventMask: 177777B, eventProc: Broom];
EchoServerOn: PUBLIC PROCEDURE =
BEGIN
IF (useCount ← useCount + 1) = 1 THEN BEGIN running ← TRUE; Starter[]; END;
UpdatePicture[];
END;
Starter: PROCEDURE =
BEGIN
pleaseStop ← FALSE;
PupDefs.PupPackageMake[];
echoSocket ← PupSocketMake[
PupTypes.echoSoc, PupTypes.fillInPupAddress, veryLongWait];
echoFork ← FORK Echoer[];
END;
EchoServerOff: PUBLIC PROCEDURE =
BEGIN
IF useCount # 0 AND (useCount ← useCount - 1) = 0 THEN
BEGIN running ← FALSE; Stopper[]; END;
UpdatePicture[];
END;
Stopper: PROCEDURE =
BEGIN
pleaseStop ← TRUE;
PupSocketKick[echoSocket];
JOIN echoFork[];
PupSocketDestroy[echoSocket];
PupDefs.PupPackageDestroy[];
END;
UpdatePicture: PROCEDURE =
BEGIN
IF running THEN SetupBoxes[] ELSE SetDownBoxes[];
IF form = NIL THEN RETURN;
FormSW.FindItem[form, startIX].flags.invisible ← running;
FormSW.FindItem[form, stopIX].flags.invisible ← ~running;
FormSW.Display[form];
END;
Echoer: PROCEDURE =
BEGIN
b: PupBuffer;
UNTIL pleaseStop DO
IF (b ← echoSocket.get[]) # NIL THEN
BEGIN
SELECT b.pupType FROM
echoMe =>
BEGIN
b.pupType ← iAmEcho;
SwapPupSourceAndDest[b];
PupRouterSendThis[b];
StatsDefs.StatIncr[pupsEchoed];
StatsDefs.StatBump[pupBytesEchoed, GetPupContentsBytes[b]];
showSomething['!];
END;
EchoServerDefs.echoStatsRequest =>
BEGIN OPEN EchoServerDefs;
ese: LONG POINTER TO EchoStatsEntry ← LOOPHOLE[@b.pupWords];
ese↑ ←
[version: echoVersion,
pupsEchoed: InlineDefs.MesaToBcplLongNumber[
StatsDefs.StatGetCounter[pupsEchoed]]];
ReturnPup[b, EchoServerDefs.echoStatsReply, 2*SIZE[EchoStatsEntry]];
END;
ENDCASE => ReturnFreePupBuffer[b];
END;
Process.Yield[]; -- avoid hogging machine
ENDLOOP;
END;
DummyEchoHook: PUBLIC PROCEDURE [c: CHARACTER] = {};
RealEchoHook: PUBLIC PROCEDURE [c: CHARACTER] =
BEGIN
s: STRING = [2];
IF boxes # NIL THEN FlipBoxes[];
IF msg = NIL OR ~verbose THEN RETURN;
s[0] ← c;
s.length ← 1;
IF ((hits ← hits + 1) MOD 50) = 0 THEN {s[1] ← Ascii.CR; s.length ← 2; };
MsgSW.AppendString[msg, s];
END;
indicator: {off, left, right} ← off;
indicatorBox: Window.Box = [[25, 10], [16, 16]];
DisplayBoxes: ToolWindow.DisplayProcType =
BEGIN
pattern: ARRAY [0..1] OF ARRAY [0..8) OF WORD;
left: WORD = 177400B;
right: WORD = 000377B;
SELECT indicator FROM
left => pattern ← [ALL[left], ALL[right]];
right => pattern ← [ALL[right], ALL[left]];
off => pattern ← [ALL[0], ALL[0]];
ENDCASE;
Window.DisplayData[window, indicatorBox, @pattern, 1]
END;
SetupBoxes: PROCEDURE =
BEGIN indicator ← left; IF boxes # NIL THEN DisplayBoxes[boxes]; END;
FlipBoxes: PROCEDURE =
BEGIN
SELECT indicator FROM
left => indicator ← right;
off, right => indicator ← left;
ENDCASE;
IF boxes # NIL THEN Window.DisplayInvert[boxes, indicatorBox];
END;
SetDownBoxes: PROCEDURE =
BEGIN
indicator ← off;
IF boxes # NIL THEN Window.DisplayWhite[boxes, indicatorBox];
END;
MakeBoxesSW: PROCEDURE [window: Window.Handle] =
BEGIN
boxes ← ToolWindow.CreateSubwindow[parent: window, display: DisplayBoxes];
boxes.box.dims.h ← 36;
Tool.AddThisSW[window: window, sw: boxes, swType: vanilla];
END;
Start: FormSW.ProcType = BEGIN EchoServerOn[]; END;
Stop: FormSW.ProcType = BEGIN EchoServerOff[]; END;
MakeSWs: Tool.MakeSWsProc =
BEGIN
msg ← Tool.MakeMsgSW[window: window, lines: 3];
form ← Tool.MakeFormSW[window: window, formProc: MakeForm];
MakeBoxesSW[window];
END;
startIX: CARDINAL = 0;
stopIX: CARDINAL = 1;
MakeForm: FormSW.ClientItemsProcType =
BEGIN
nParams: CARDINAL = 3;
items ← FormSW.AllocateItemDescriptor[nParams];
items[0] ← FormSW.CommandItem[
tag: "Start"L, proc: Start, place: FormSW.newLine, invisible: running];
items[1] ← FormSW.CommandItem[
tag: "Stop"L, proc: Stop, place: FormSW.newLine, invisible: ~running];
items[2] ← FormSW.BooleanItem[tag: "Verbose"L, switch: @verbose];
RETURN[items, TRUE];
END;
ClientTransition: ToolWindow.TransitionProcType =
BEGIN
IF new = inactive THEN msg ← form ← boxes ← NIL;
showSomething ← IF new = active THEN RealEchoHook ELSE DummyEchoHook;
END;
Broom: PROCEDURE [why: Event.Reason] =
BEGIN
SELECT why FROM
makeImage, makeCheck => IF running THEN Stopper[];
startImage, restartCheck, continueCheck => IF running THEN Starter[];
ENDCASE => NULL;
END;
-- initialization
tool ← Tool.Create[
name: "Echo Server of January 30, 1981"L, makeSWsProc: MakeSWs,
clientTransition: ClientTransition, initialState: inactive];
Event.AddNotifier[@eventItem];
EchoServerOn[]; -- This may be undesirable
END.