home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1998 #6 / amigamamagazinepolishissue1998.iso / coders / jËzyki_programowania / oberon / system / sessions.mod (.txt) < prev    next >
Oberon Text  |  1977-12-31  |  18KB  |  434 lines

  1. Syntax10.Scn.Fnt
  2. Syntax10i.Scn.Fnt
  3. StampElems
  4. Alloc
  5. 3 Mar 96
  6. FoldElems
  7. Syntax10.Scn.Fnt
  8. TCP, 
  9. Syntax10.Scn.Fnt
  10. (*V24*)
  11. Syntax10.Scn.Fnt
  12. NetSystem, 
  13. Syntax10b.Scn.Fnt
  14. Syntax10.Scn.Fnt
  15.         TCPConnection = POINTER TO RECORD(TCP.ConnectionDesc) channel: Channel END;
  16.         TCPChannel = POINTER TO RECORD(ChannelDesc) connection: TCPConnection END;
  17.         TCPTask = POINTER TO RECORD(TaskDesc) id: LONGINT END;
  18.         TCPListener = POINTER TO RECORD(ListenerDesc) l: TCP.Listener END;
  19. Syntax10.Scn.Fnt
  20.         NSConnection = POINTER TO RECORD(NetSystem.StreamDesc) channel: Channel END;
  21.         NSChannel = POINTER TO RECORD(ChannelDesc) connection: NSConnection END;
  22.         NSTask = POINTER TO RECORD(TaskDesc) c: NSConnection END;
  23.         NSListener = POINTER TO RECORD(ListenerDesc) l: NetSystem.Connection END;
  24. Syntax10.Scn.Fnt
  25. (*V24*)
  26. Syntax10.Scn.Fnt
  27.     PROCEDURE TCPGetState(c: Channel; VAR available: LONGINT; VAR terminated: BOOLEAN);
  28.         VAR connection: TCP.Connection;
  29.     BEGIN connection := c(TCPChannel).connection;
  30.         available := TCP.Available(connection); terminated := (available = 0) & ~TCP.Connected(connection)
  31.     END TCPGetState;
  32.     PROCEDURE TCPReadBytes(c: Channel; VAR bytes: ARRAY OF CHAR; n: LONGINT);
  33.     BEGIN TCP.ReadBytes(c(TCPChannel).connection, bytes, 0, n)
  34.     END TCPReadBytes;
  35.     PROCEDURE TCPSendBytes(c: Channel; VAR bytes: ARRAY OF CHAR; n: LONGINT);
  36.         VAR connection: TCP.Connection;
  37.     BEGIN connection := c(TCPChannel).connection;
  38.         IF TCP.Connected(connection) THEN TCP.WriteBytes(connection, bytes, 0, n) END
  39.     END TCPSendBytes;
  40.     PROCEDURE TCPSendBreak(c: Channel);
  41.     END TCPSendBreak;
  42.     PROCEDURE TCPClose(c: Channel);
  43.         VAR connection: TCP.Connection;
  44.     BEGIN connection := c(TCPChannel).connection;
  45.         IF TCP.Connected(connection) THEN TCP.Disconnect(connection) END
  46.     END TCPClose;
  47.     PROCEDURE TCPSelfChannel(t: Task): Channel;
  48.         VAR channel: Channel; c: TCP.Connection;
  49.     BEGIN c := TCP.ThisConnection(t(TCPTask).id);
  50.         IF c # NIL THEN channel := c(TCPConnection).channel ELSE channel := NIL END;
  51.         RETURN channel
  52.     END TCPSelfChannel;
  53.     PROCEDURE TCPSetupChannel(connection: TCPConnection; VAR channel: Channel; VAR task: Task);
  54.         VAR c: TCPChannel; t: TCPTask;
  55.     BEGIN NEW(c); c.connection := connection; connection.channel := c;
  56.         c.getState := TCPGetState; c.readBytes := TCPReadBytes;
  57.         c.sendBytes := TCPSendBytes; c.sendBreak := TCPSendBreak; c.close := TCPClose;
  58.         NEW(t); t.id := connection.id; t.channel := TCPSelfChannel;
  59.         channel := c; task := t
  60.     END TCPSetupChannel;
  61.     PROCEDURE TCPNewSession(hostname: ARRAY OF CHAR; port: LONGINT): Session;
  62.         VAR res: INTEGER; c: TCPConnection; channel: Channel; t: Task; s: Session; adr: TCP.IpAdr;
  63.     BEGIN s := NIL; TCP.HostByName(hostname, adr, res);
  64.         IF res = TCP.Done THEN NEW(c); TCP.Connect(c, TCP.AnyPort, adr, SHORT(port), 0, res);
  65.             IF res = TCP.Done THEN TCPSetupChannel(c, channel, t); s := NewSession(channel, t, hostname) END
  66.         END;
  67.         RETURN s
  68.     END TCPNewSession;
  69.     PROCEDURE TCPRequested(l: Listener): BOOLEAN;
  70.     BEGIN RETURN TCP.Requested(l(TCPListener).l)
  71.     END TCPRequested;
  72.     PROCEDURE TCPAcceptedSession(l: Listener; VAR serverName: ARRAY OF CHAR): Session;
  73.         VAR res: INTEGER; c: TCPConnection; channel: Channel; t: Task; s: Session;
  74.     BEGIN s := NIL;
  75.         NEW(c); TCP.Accept(l(TCPListener).l, c, res);
  76.         IF res = TCP.Done THEN TCPSetupChannel(c, channel, t); s := NewSession(channel, t, serverName) END;
  77.         RETURN s
  78.     END TCPAcceptedSession;
  79.     PROCEDURE TCPRemove(l: Listener);
  80.     BEGIN TCP.Close(l(TCPListener).l)
  81.     END TCPRemove;
  82.     PROCEDURE TCPNewListener(port: LONGINT): TCPListener;
  83.         VAR res: INTEGER; listener: TCPListener; l: TCP.Listener;
  84.     BEGIN listener := NIL;
  85.         NEW(l); TCP.Listen(l, SHORT(port), TCP.AnyAdr, TCP.AnyPort, res);
  86.         IF res = TCP.Done THEN NEW(listener); listener.l := l;
  87.             listener.requested := TCPRequested; listener.acceptedSession := TCPAcceptedSession;
  88.             listener.remove := TCPRemove
  89.         END;
  90.         RETURN listener
  91.     END TCPNewListener;
  92. Syntax10.Scn.Fnt
  93. (*V24*)
  94. Syntax10.Scn.Fnt
  95.     PROCEDURE NSGetState(c: Channel; VAR available: LONGINT; VAR terminated: BOOLEAN);
  96.         VAR connection: NetSystem.Stream;
  97.     BEGIN connection := c(NSChannel).connection;
  98.         available := NetSystem.Available(connection);
  99.         terminated := (available = 0) & (connection.C.state = NetSystem.closed)
  100.     END NSGetState;
  101.     PROCEDURE NSReadBytes(c: Channel; VAR bytes: ARRAY OF CHAR; n: LONGINT);
  102.     BEGIN NetSystem.ReadBytes(c(NSChannel).connection, bytes, 0, n)
  103.     END NSReadBytes;
  104.     PROCEDURE NSSendBytes(c: Channel; VAR bytes: ARRAY OF CHAR; n: LONGINT);
  105.         VAR connection: NetSystem.Stream;
  106.     BEGIN connection := c(NSChannel).connection;
  107.         IF connection.C.state # NetSystem.closed THEN NetSystem.WriteBytes(connection, bytes, 0, n) END
  108.     END NSSendBytes;
  109.     PROCEDURE NSSendBreak(c: Channel);
  110.     END NSSendBreak;
  111.     PROCEDURE NSClose(c: Channel);
  112.         VAR connection: NetSystem.Stream;
  113.     BEGIN connection := c(NSChannel).connection;
  114.         IF connection.C.state # NetSystem.closed THEN NetSystem.CloseConnection(connection.C) END
  115.     END NSClose;
  116.     PROCEDURE NSSelfChannel(t: Task): Channel;
  117.     BEGIN RETURN t(NSTask).c.channel
  118.     END NSSelfChannel;
  119.     PROCEDURE NSSetupChannel(connection: NSConnection; VAR channel: Channel; VAR task: Task);
  120.         VAR c: NSChannel; t: NSTask;
  121.     BEGIN NEW(c); c.connection := connection; connection.channel := c;
  122.         c.getState := NSGetState; c.readBytes := NSReadBytes;
  123.         c.sendBytes := NSSendBytes; c.sendBreak := NSSendBreak; c.close := NSClose;
  124.         NEW(t); t.c := connection; t.channel := NSSelfChannel;
  125.         channel := c; task := t
  126.     END NSSetupChannel;
  127.     PROCEDURE NSNewSession(hostname: ARRAY OF CHAR; port: LONGINT): Session;
  128.         VAR res: INTEGER; connection: NSConnection; channel: Channel; t: Task; s: Session; c: NetSystem.Connection;
  129.     BEGIN s := NIL;
  130.         NEW(c); NetSystem.OpenConnection(NetSystem.anyport, SHORT(port), hostname, NetSystem.tcp, c, res);
  131.         IF res = NetSystem.done THEN
  132.             NEW(connection); NetSystem.OpenStream(connection, c);
  133.             NSSetupChannel(connection, channel, t); s := NewSession(channel, t, hostname)
  134.         END;
  135.         RETURN s
  136.     END NSNewSession;
  137.     PROCEDURE NSRequested(l: Listener): BOOLEAN;
  138.     BEGIN RETURN NetSystem.Requested(l(NSListener).l)
  139.     END NSRequested;
  140.     PROCEDURE NSAcceptedSession(l: Listener; VAR serverName: ARRAY OF CHAR): Session;
  141.         VAR res: INTEGER; c: NSConnection; channel: Channel; t: Task; s: Session; connection: NetSystem.Connection;
  142.     BEGIN s := NIL;
  143.         NEW(c); NetSystem.Accept(l(NSListener).l, connection, res);
  144.         IF res = NetSystem.done THEN
  145.             NetSystem.OpenStream(c, connection);
  146.             NSSetupChannel(c, channel, t); s := NewSession(channel, t, serverName) END;
  147.         RETURN s
  148.     END NSAcceptedSession;
  149.     PROCEDURE NSRemove(l: Listener);
  150.     BEGIN NetSystem.CloseConnection(l(NSListener).l)
  151.     END NSRemove;
  152.     PROCEDURE NSNewListener(port: LONGINT): NSListener;
  153.         VAR res: INTEGER; listener: NSListener; l: NetSystem.Connection;
  154.     BEGIN listener := NIL;
  155.         NEW(l);
  156.         NetSystem.OpenConnection(SHORT(port), NetSystem.anyport, NetSystem.anyIP, NetSystem.tcp, l, res);
  157.         IF res = NetSystem.done THEN NEW(listener); listener.l := l;
  158.             listener.requested := NSRequested; listener.acceptedSession := NSAcceptedSession;
  159.             listener.remove := NSRemove
  160.         END;
  161.         RETURN listener
  162.     END NSNewListener;
  163. Syntax10.Scn.Fnt
  164. (*V24*)
  165. Syntax10.Scn.Fnt
  166. s := TCPNewSession(hostname, port)
  167. Syntax10.Scn.Fnt
  168. s := NSNewSession(hostname, port)
  169. Syntax10.Scn.Fnt
  170. l := TCPNewListener(port);
  171.                 IF l # NIL THEN ok := TRUE; s.listener := l; s.notify := c END
  172. Syntax10.Scn.Fnt
  173. l := NSNewListener(port);
  174.                 IF l # NIL THEN ok := TRUE; s.listener := l; s.notify := c END
  175. Syntax10.Scn.Fnt
  176. (*V24*)
  177. MODULE Sessions; (* ww 
  178.     IMPORT
  179. (*TCP*)
  180. V24, 
  181. (*NetSystem*)
  182. Oberon, Texts, Viewers, Display;
  183.     CONST
  184.         Sec* = 300;
  185.     TYPE
  186.         Channel = POINTER TO ChannelDesc;
  187.         Terminal* = POINTER TO TerminalDesc;
  188.         Session* = POINTER TO SessionDesc;
  189.         SessionDesc = RECORD
  190.             name: ARRAY 64 OF CHAR;
  191.             terminals, p: Terminal;
  192.             nomoreneeded: BOOLEAN;
  193.             channel: Channel
  194.         END;
  195.         ChannelDesc = RECORD
  196.             getState: PROCEDURE (c: Channel; VAR available: LONGINT; VAR terminated: BOOLEAN);
  197.             readBytes: PROCEDURE (c: Channel; VAR bytes: ARRAY OF CHAR; n: LONGINT);
  198.             sendBytes: PROCEDURE (c: Channel; VAR bytes: ARRAY OF CHAR; n: LONGINT);
  199.             sendBreak: PROCEDURE (c: Channel);
  200.             close: PROCEDURE (c: Channel);
  201.             session: Session
  202.         END;
  203.         Task = POINTER TO TaskDesc;
  204.         TaskDesc = RECORD(Oberon.TaskDesc)
  205.             channel: PROCEDURE (self: Task): Channel
  206.         END;
  207.         Receiver* = PROCEDURE (t: Terminal; ch: CHAR);
  208.         Flusher* = PROCEDURE (t: Terminal; changed, terminated: BOOLEAN);
  209.         TerminalDesc* = RECORD
  210.             next: Terminal;
  211.             session: Session;
  212.             nextTime, timeout*: LONGINT;
  213.             receive*: Receiver;
  214.             flush*: Flusher;
  215.             safe*: BOOLEAN
  216.         END;
  217.         Sentinel = POINTER TO RECORD(TerminalDesc) END;
  218.         Tester* = PROCEDURE (t: Terminal): BOOLEAN;
  219.         IdentifyMsg* = RECORD(Display.FrameMsg) session*: Session END;
  220.         Listener = POINTER TO ListenerDesc;
  221.         Service* = POINTER TO ServiceDesc;
  222.         ServiceCall* = PROCEDURE (this: Service; s: Session);
  223.         ServiceDesc* = RECORD
  224.             name: ARRAY 64 OF CHAR;
  225.             notify: ServiceCall;
  226.             listener: Listener
  227.         END;
  228.         ListenerDesc = RECORD
  229.             requested: PROCEDURE (l: Listener): BOOLEAN;
  230.             acceptedSession: PROCEDURE (l: Listener; VAR serverName: ARRAY OF CHAR): Session;
  231.             remove: PROCEDURE (l: Listener)
  232.         END;
  233.         ServiceTask = POINTER TO RECORD(Oberon.TaskDesc) service: Service END;
  234. (*TCP*)
  235. (*NetSystem*)
  236.         v24Session: Session;
  237.     PROCEDURE Distribute(s: Session; ch: CHAR);
  238.         VAR t: Terminal;
  239.     BEGIN s.p := s.terminals; t := s.p.next;
  240.         WHILE ~(t IS Sentinel) DO
  241.             IF ~t.safe THEN s.p.next := t.next; t.next := NIL END;
  242.             t.receive(t, ch);
  243.             IF (t.session = s) & (t.next = NIL) THEN t.next := s.p.next; s.p.next := t; s.p := t
  244.             ELSIF s.p.next = t THEN s.p := t
  245.             END;
  246.             t := s.p.next
  247.         END
  248.     END Distribute;
  249.     PROCEDURE Flush(s: Session; changed, terminated: BOOLEAN);
  250.         VAR t: Terminal; now: LONGINT;
  251.     BEGIN now := Oberon.Time(); s.p := s.terminals; t := s.p.next;
  252.         WHILE ~(t IS Sentinel) DO
  253.             IF changed OR terminated OR (t.nextTime <= now) & (t.timeout >= 0) THEN
  254.                 IF ~t.safe THEN s.p.next := t.next; t.next := NIL END;
  255.                 t.flush(t, changed, terminated); t.nextTime := now + t.timeout;
  256.                 IF (t.session = s) & (t.next = NIL) THEN t.next := s.p.next; s.p.next := t; s.p := t
  257.                 ELSIF s.p.next = t THEN s.p := t
  258.                 END
  259.             ELSE s.p := t
  260.             END;
  261.             t := s.p.next
  262.         END
  263.     END Flush;
  264.     PROCEDURE Close*(s: Session);
  265.         VAR c: Channel;
  266.     BEGIN c := s.channel;
  267.         IF c.close # NIL THEN c.close(c) END
  268.     END Close;
  269.     PROCEDURE TaskHandler;
  270.         CONST BufSize = 4096;
  271.         VAR n, i: LONGINT; terminated: BOOLEAN; s: Session; c: Channel; self: Task; buf: ARRAY BufSize OF CHAR;
  272.     BEGIN self := Oberon.CurTask(Task); c := self.channel(self);
  273.         IF c # NIL THEN s := c.session; c.getState(c, n, terminated);
  274.             IF n # 0 THEN
  275.                 IF n > BufSize THEN n := BufSize END;
  276.                 c.readBytes(c, buf, n);
  277.                 i := 0;
  278.                 REPEAT Distribute(s, buf[i]); INC(i) UNTIL i = n
  279.             END;
  280.             Flush(s, n # 0, terminated);
  281.             IF terminated THEN Close(s); Oberon.Remove(Oberon.CurTask) END
  282.         ELSE Oberon.Remove(Oberon.CurTask)
  283.         END
  284.     END TaskHandler;
  285.     PROCEDURE NewSession(c: Channel; task: Task; VAR name: ARRAY OF CHAR): Session;
  286.         VAR s: Session; sentinel: Sentinel;
  287.     BEGIN NEW(s); COPY(name, s.name);
  288.         s.channel := c; c.session := s;
  289.         NEW(sentinel); s.terminals := sentinel; sentinel.session := s; sentinel.next := sentinel;
  290.         task.handle := TaskHandler; task.safe := TRUE; task.time := -1;
  291.         Oberon.Install(task);
  292.         RETURN s
  293.     END NewSession;
  294.     PROCEDURE Install*(t: Terminal; s: Session; r: Receiver; f: Flusher; timeout: LONGINT);
  295.         VAR sentinel: Terminal;
  296.     BEGIN ASSERT(t.session = NIL);
  297.         t.session := s; sentinel := s.terminals; t.next := sentinel.next; sentinel.next := t;
  298.         IF s.p = s.terminals THEN s.p := t END;
  299.         t.receive := r; t.flush := f; t.timeout := timeout; t.nextTime := Oberon.Time() + timeout
  300.     END Install;
  301.     PROCEDURE Remove*(t: Terminal);
  302.         VAR p, q: Terminal; s: Session;
  303.     BEGIN s := t.session;
  304.         IF s # NIL THEN p := s.terminals; q := p.next;
  305.             WHILE (q # t) & ~(q IS Sentinel) DO p := q; q := q.next END;
  306.             IF q = t THEN p.next := t.next;
  307.                 IF q = s.p THEN s.p := p END
  308.             END;
  309.             t.session := NIL; t.next := NIL;
  310.             p := s.terminals;
  311.             IF p.next = p THEN Close(s) END
  312.         END
  313.     END Remove;
  314.     PROCEDURE ThisSession*(t: Terminal): Session;
  315.     BEGIN RETURN t.session
  316.     END ThisSession;
  317.     PROCEDURE ThisTerminal*(s: Session; test: Tester): Terminal;
  318.         VAR t: Terminal;
  319.     BEGIN t := s.terminals.next;
  320.         WHILE ~(t IS Sentinel) & ~test(t) DO t := t.next END;
  321.         IF t IS Sentinel THEN RETURN NIL ELSE RETURN t END
  322.     END ThisTerminal;
  323.     PROCEDURE GetName*(s: Session; VAR name: ARRAY OF CHAR);
  324.     BEGIN COPY(s.name, name)
  325.     END GetName;
  326.     PROCEDURE SendChar*(s: Session; ch: CHAR);
  327.         VAR c: Channel; buf: ARRAY 1 OF CHAR;
  328.     BEGIN c := s.channel; buf[0] := ch; c.sendBytes(c, buf, 1)
  329.     END SendChar;
  330.     PROCEDURE SendBytes*(s: Session; VAR bytes: ARRAY OF CHAR; n: LONGINT);
  331.         VAR c: Channel;
  332.     BEGIN c := s.channel; c.sendBytes(c, bytes, n)
  333.     END SendBytes;
  334.     PROCEDURE SendString*(s: Session; str: ARRAY OF CHAR);
  335.         VAR i: LONGINT; c: Channel;
  336.     BEGIN i := 0;
  337.         WHILE str[i] # 0X DO INC(i) END;
  338.         c := s.channel; c.sendBytes(c, str, i)
  339.     END SendString;
  340.     PROCEDURE SendBreak*(s: Session);
  341.         VAR c: Channel;
  342.     BEGIN c := s.channel; c.sendBreak(c)
  343.     END SendBreak;
  344. (*TCP*)
  345.     PROCEDURE V24GetState(c: Channel; VAR available: LONGINT; VAR terminated: BOOLEAN);
  346.     BEGIN available := V24.Available(); terminated := FALSE
  347.     END V24GetState;
  348.     PROCEDURE V24ReadBytes(c: Channel; VAR bytes: ARRAY OF CHAR; n: LONGINT);
  349.         VAR i: LONGINT;
  350.     BEGIN i := 0;
  351.         WHILE i # n DO V24.Receive(bytes[i]); INC(i) END
  352.     END V24ReadBytes;
  353.     PROCEDURE V24SendBytes(c: Channel; VAR bytes: ARRAY OF CHAR; n: LONGINT);
  354.         VAR i: LONGINT;
  355.     BEGIN i := 0;
  356.         WHILE i # n DO V24.Send(bytes[i]); INC(i) END
  357.     END V24SendBytes;
  358.     PROCEDURE V24SendBreak(c: Channel);
  359.     BEGIN V24.Break
  360.     END V24SendBreak;
  361.     PROCEDURE V24SelfChannel(self: Task): Channel;
  362.     BEGIN RETURN v24Session.channel
  363.     END V24SelfChannel;
  364.     PROCEDURE V24NewSession(): Session;
  365.         VAR c: Channel; task: Task; name: ARRAY 4 OF CHAR;
  366.     BEGIN NEW(c); c.getState := V24GetState; c.readBytes := V24ReadBytes;
  367.         c.sendBytes := V24SendBytes; c.sendBreak := V24SendBreak;
  368.         NEW(task); task.channel := V24SelfChannel;
  369.         name := "V24"; RETURN NewSession(c, task, name)
  370.     END V24NewSession;
  371. (*NetSystem*)
  372.     PROCEDURE New*(hostname: ARRAY OF CHAR; port: LONGINT): Session;
  373.         VAR s: Session;
  374.     BEGIN s := NIL;
  375.         IF hostname = "V24" THEN 
  376. s := v24Session
  377.         ELSE 
  378. (*TCP*)
  379. (*NetSystem*)
  380.         END;
  381.         RETURN s
  382.     END New;
  383.     PROCEDURE ServiceTaskHandler;
  384.         VAR serv: Service; l: Listener; s: Session;
  385.     BEGIN serv := Oberon.CurTask(ServiceTask).service; l := serv.listener;
  386.         IF l # NIL THEN
  387.             IF l.requested(l) THEN s := l.acceptedSession(l, serv.name);
  388.                 IF s # NIL THEN serv.notify(serv, s) END
  389.             END
  390.         ELSE Oberon.Remove(Oberon.CurTask)
  391.         END
  392.     END ServiceTaskHandler;
  393.     PROCEDURE InstallService*(s: Service; port: LONGINT; c: ServiceCall; name: ARRAY OF CHAR; VAR ok: BOOLEAN);
  394.         VAR l: Listener; task: ServiceTask;
  395.     BEGIN ok := FALSE;
  396.         IF s.listener = NIL THEN
  397.             IF name = "V24" THEN
  398.             ELSE 
  399. (*TCP*)
  400. (*NetSystem*)
  401.             END
  402.         END;
  403.         IF ok THEN NEW(task); task.handle := ServiceTaskHandler; task.time := -1; task.service := s;
  404.             Oberon.Install(task); COPY(name, s.name)
  405.         END
  406.     END InstallService;
  407.     PROCEDURE RemoveService*(s: Service);
  408.         VAR l: Listener;
  409.     BEGIN l := s.listener; l.remove(l); s.listener := NIL
  410.     END RemoveService;
  411.     PROCEDURE Send*;
  412.         VAR text: Texts.Text; beg, end, time: LONGINT; v: Viewers.Viewer; s: Texts.Scanner; identify: IdentifyMsg;
  413.     BEGIN
  414.         IF Oberon.Par.vwr.dsc = Oberon.Par.frame THEN v := Oberon.Par.vwr ELSE v := Oberon.FocusViewer END;
  415.         identify.session := NIL; v.handle(v, identify);
  416.         IF identify.session # NIL THEN
  417.             Texts.OpenScanner(s, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(s);
  418.             IF (s.class = Texts.Char) & (s.line = 0) & (s.c = "^") THEN Oberon.GetSelection(text, beg, end, time);
  419.                 IF time > 0 THEN Texts.OpenScanner(s, text, beg); Texts.Scan(s) END
  420.             END;
  421.             LOOP
  422.                 IF (s.class = Texts.Name) & (s.s = "BRK") THEN SendBreak(identify.session)
  423.                 ELSIF (s.class = Texts.Name) OR (s.class = Texts.String) THEN SendString(identify.session, s.s)
  424.                 ELSIF s.class = Texts.Int THEN SendChar(identify.session, CHR(s.i MOD 256))
  425.                 ELSE EXIT
  426.                 END;
  427.                 Texts.Scan(s)
  428.             END
  429.         END
  430.     END Send;
  431. BEGIN 
  432. v24Session := V24NewSession()
  433. END Sessions.
  434.