MODULE TALK; (*$VER 1.0*) (*$HDR -1*) (* Modula-2 Talk by David Tingler, January 2, 1987. This program demonstrates the use of the AMOS ITC system with Modula-2. It is a simple multi-user chat facility modeled after a program written by David Pallmann. *) FROM SYSTEM IMPORT ADDRESS, VAL; FROM SYSCOM IMPORT SCBPTR; FROM SYSJOB IMPORT jmon, JCBPTR, JOBIDX; FROM ITCUTL IMPORT MsgSuccess, OpenMessage, CloseMessage, SendMessage, RecvMessage, CheckMessage; FROM ASCII IMPORT ETX, ESC, BS, CR, DEL, EOL, EOS; FROM Terminal IMPORT WriteString, Write, WriteLn, Read, KeyPressed; FROM TermLib IMPORT CursorReturn, ClearEndLine, ScreenCode; FROM Strings IMPORT Concat; FROM Rad50Lib IMPORT LongRad50ToString; FROM BreakLib IMPORT Break; CONST MaxChars = 78; (* maximum input line chars *) VAR MyPrg: LONGCARD; (* my running program in rad50 *) MyJob: LONGCARD; (* my job name in rad50 *) MyName: ARRAY [0..5] OF CHAR; (* my job name in ascii *) Line: ARRAY [0..127] OF CHAR; (* input line buffer *) Chars: CARDINAL; (* total chars in input buffer *) Done: BOOLEAN; (* exit flag *) Result: LONGCARD; (* ITC result code *) ch: CHAR; (* input char *) PROCEDURE Redraw; (* Redraw the input prompt and chars *) VAR i: CARDINAL; BEGIN i := 0; Write(">"); WHILE i < Chars DO Write(Line[i]); INC(i); END; END Redraw; PROCEDURE PutMsg(msg: ARRAY OF CHAR); (* Send msg to any job running same program, doesn't care if *) (* msg gets through to other users or not. *) VAR jcb: JCBPTR; jtp: POINTER TO ADDRESS; cnt: CARDINAL; res: LONGCARD; BEGIN cnt := 1; (* set job table counter *) jtp := SCBPTR^.jobtbl; (* get pointer to job table *) jcb := jtp^; (* get first jcb ptr from table *) REPEAT IF jcb # NIL THEN (* skip unallocated table entries *) IF (jcb^.jobprg = MyPrg) & NOT (jmon IN jcb^.jobsts) THEN SendMessage(cnt, 0, msg, res); (* send if same prg & not at amos *) END; END; INC(cnt); (* increment counter *) INC(jtp,4); (* increment our job table ptr *) jcb := jtp^; (* assign jcb address ptr *) UNTIL jcb = VAL(ADDRESS,-1D); (* until end of job table *) END PutMsg; PROCEDURE GetMsg; (* Get incoming message and display it *) VAR sck, cod: CARDINAL; msg: ARRAY [0..127] OF CHAR; res: LONGCARD; BEGIN RecvMessage(sck, cod, msg, res); (* receive ITC message *) IF res = MsgSuccess THEN (* if msg received then display it*) Write(CR); (* move cursor to start of line *) WriteString(msg); (* write msg *) ScreenCode(ClearEndLine); (* clear any left over chars *) WriteLn; (* new line *) Redraw; (* redraw input prompt and line *) END; END GetMsg; PROCEDURE Start(): BOOLEAN; (* Open ITC system and send announcement. *) VAR i: CARDINAL; jcb: JCBPTR; res: LONGCARD; msg: ARRAY [0..127] OF CHAR; done: BOOLEAN; BEGIN OpenMessage(128,5,res); IF res = MsgSuccess THEN (* open message socket *) JOBIDX(jcb); (* index my job *) MyJob := jcb^.jobnam; (* get my job name *) MyPrg := jcb^.jobprg; (* get my running program name *) LongRad50ToString(MyJob,MyName,done); (* convert job name to ascii *) FOR i := 0 TO HIGH(MyName) DO IF MyName[i] = ' ' THEN MyName[i] := EOS; (* null any trailing spaces *) END; END; Concat('[',MyName,msg); (* make announcement *) Concat(msg,' has entered Talk]',msg); PutMsg(msg); (* send announcement *) RETURN TRUE; (* return success *) ELSE RETURN FALSE; (* ITC didn't open *) END; END Start; PROCEDURE Finish; (* Close ITC System and send exit announcement. *) VAR msg: ARRAY [0..127] OF CHAR; res: LONGCARD; BEGIN Concat('[',MyName,msg); (* make announcement *) Concat(msg,' has left Talk]',msg); PutMsg(msg); (* send announcement *) CloseMessage(res); (* close message system *) Write(CR); (* go to start of input line *) WriteString("[EXIT]"); (* write message to user *) ScreenCode(ClearEndLine); (* clear any left over chars *) WriteLn; END Finish; BEGIN (*main*) WriteString("Modula-2 Talk Version 1.0"); WriteLn; WriteLn; IF Start() THEN Chars := 0; Done := FALSE; Redraw; REPEAT IF CheckMessage(Result) THEN (* print any waiting messages *) GetMsg; ELSIF KeyPressed() THEN Read(ch); IF (ch = ETX) OR (ch = ESC) THEN (* user press control-c or escape*) Done := TRUE; ELSIF (ch = EOL) THEN (* user pressed return so send msg*) Line[Chars] := EOS; Concat(' - ', Line, Line); Concat(MyName, Line, Line); PutMsg(Line); Chars := 0; ELSIF (ch = BS) OR (ch = DEL) THEN (* handle input line delete *) IF Chars > 0 THEN DEC(Chars); Write(BS); Write(' '); Write(BS); END; ELSIF (ch >= ' ') & (ch <= '~') THEN (* add input char to line *) IF Chars < MaxChars THEN Write(ch); Line[Chars] := ch; INC(Chars); END; END; END; UNTIL (Break()) OR (Done); (* quit if user presses control-c *) Finish; (* close the ITC system *) ELSE WriteString("%Cannot open message system."); END; WriteLn; END TALK. .