aboutsummaryrefslogtreecommitdiff
path: root/sys/gio/stdgraph/stgrcur.x
diff options
context:
space:
mode:
Diffstat (limited to 'sys/gio/stdgraph/stgrcur.x')
-rw-r--r--sys/gio/stdgraph/stgrcur.x425
1 files changed, 425 insertions, 0 deletions
diff --git a/sys/gio/stdgraph/stgrcur.x b/sys/gio/stdgraph/stgrcur.x
new file mode 100644
index 00000000..e0ab890a
--- /dev/null
+++ b/sys/gio/stdgraph/stgrcur.x
@@ -0,0 +1,425 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <syserr.h>
+include <config.h>
+include <error.h>
+include <chars.h>
+include <ttset.h>
+include <gset.h>
+include <fset.h>
+include <gki.h>
+include "stdgraph.h"
+
+define MAX_LENCUR 17
+define MAX_KEYLINES 30
+define KEYSIZE 1
+define QUIT 'q'
+define GO 'g'
+
+# STG_READCURSOR -- Physically read the cursor, returning the cursor position
+# in GKI coordinates and the keystroke value as output arguments. The cursor
+# value string is read in raw mode with interrupts disabled. Receipt of the
+# EOF character or CR causes EOF to be returned as the key value.
+#
+# The cursor is described by two parameters, a pattern string (CD) and a string
+# length parameter (CN).
+#
+# CD A pattern specifying either the delimiter sequence if
+# len_curval > 0, or the entire cursor value string if
+# len_curval <= 0.
+#
+# CN If no pattern is given, CN is the number of characters to be
+# read and automatic error detection is not possible. If a
+# pattern is given, a negative CN specifies the minimum number
+# of characters in the cursor value string, with the pattern
+# being used to match the characters in the actual cursor value
+# string. A positive CN specifies a fixed length cursor value
+# string, which which case the pattern is used only to determine
+# when a valid cursor value string has been received.
+#
+# The cursor read algorithm tries to ignore unsolicited input and recover from
+# bad cursor reads, or loss of hardware cursor mode during a cursor read, e.g.,
+# if the screen is accidentally cleared or the terminal otherwise initialized.
+#
+# The physical cursor read sequence is implemented by the stg_rdcursor routine.
+# The purpose of the higher level routine is to support STTY playback mode.
+# In playback mode, terminal input is taken from a logfile rather than from
+# the physical terminal; this is used to prepare automatic scripts to test
+# software and for demos. If playback mode is enabled and `verify' is enabled,
+# the logged cursor position will be read, a WC will be issued to move the
+# cursor to that position, and then the physical cursor will be read and the
+# return value discard, returning the logged position to the calling program.
+# In playback mode with `verify' disabled, we need only disable the RC
+# instruction and read the logged cursor position; the physical cursor is
+# never turned on.
+
+procedure stg_readcursor (cursor, cn, key, sx, sy, raster, rx, ry)
+
+int cursor #I cursor to be read
+int cn #O cursor which was read
+int key #O keystroke which terminated cursor read
+int sx, sy #O screen coordinates of cursor in GKI units
+int raster #O raster number
+int rx, ry #O raster coordinates of cursor in GKI units
+
+short texts[4]
+char textc[4], ch
+pointer sp, pbdevice, tx, o_tx
+int delay, nchars, mx, my, i, j, k
+bool playback_mode, pbverify_mode
+
+bool strne()
+pointer ttygdes()
+int ttstati(), ttstats(), ctocc()
+errchk ttygdes, syserr
+include "stdgraph.com"
+define samedev_ 91
+
+begin
+ playback_mode = (ttstati (STDIN, TT_PLAYBACK) == YES)
+
+ if (!playback_mode) {
+ call stg_rdcursor (g_tty, cursor, YES,
+ cn, key, sx, sy, raster, rx, ry)
+ return
+ }
+
+ call smark (sp)
+ call salloc (pbdevice, SZ_GDEVICE, TY_CHAR)
+ call salloc (o_tx, LEN_TX, TY_STRUCT)
+
+ # The playback script may have been generated on a different graphics
+ # terminal than the one we are playing it back on. Open the graphcap
+ # descriptor for the device used when the script was recorded. This
+ # must be used when decoding cursor input from the logfile. If device
+ # name not recorded in logfile, try to make do with the descriptor for
+ # the current stdgraph device.
+
+ if (ttstats (STDIN, TT_GDEVICE, Memc[pbdevice], SZ_GDEVICE) <= 0) {
+ # Device name not recorded in logfile.
+ call syserr (SYS_STTYNOGDEV)
+
+ } else if (g_pbtty == NULL || strne (g_pbdevice, Memc[pbdevice])) {
+ # Device name was recorded; try to load graphcap for it if not
+ # already loaded.
+
+ if (g_pbtty != NULL)
+ call ttycdes (g_pbtty)
+ iferr (g_pbtty = ttygdes (Memc[pbdevice])) {
+ g_pbtty = NULL
+ call erract (EA_ERROR)
+ }
+
+ call strcpy (Memc[pbdevice], g_pbdevice, SZ_GDEVICE)
+ }
+
+ # Set the playback delay to 0 msec while reading the cursor, else
+ # the multicharacter cursor read will take forever. We issue the
+ # delay below, ourselves, one per cursor read.
+
+ delay = ttstati (STDIN, TT_PBDELAY)
+ call ttseti (STDIN, TT_PBDELAY, 0)
+
+ # Read the logged cursor position with RC disabled.
+ call stg_rdcursor (g_pbtty, cursor, NO,
+ cn, key, sx, sy, raster, rx, ry)
+
+ # Determine if verify mode is set for this cursor read. This must
+ # be done after the call to stg_rdcursor to permit processing of
+ # any \{ .. \} in the logfile.
+
+ pbverify_mode = (ttstati (STDIN, TT_PBVERIFY) == YES)
+
+ # Set passthru mode to read/write the device directly.
+ call ttseti (STDIN, TT_PASSTHRU, YES)
+
+ # Encode the logged keystroke as a character string.
+ if (key == EOF) {
+ call strcpy ("EOF", textc, 4)
+ nchars = 3
+ } else if (key <= ' ') {
+ ch = key
+ nchars = ctocc (ch, textc, 4)
+ } else {
+ nchars = 1
+ textc[1] = key
+ }
+
+ # Pack the string in a short array for the GKI operator.
+ call achtcs (textc, texts, nchars)
+
+ # Set the text drawing attributes.
+ tx = SG_TXAP(g_sg)
+ call amovi (Memi[tx], Memi[o_tx], LEN_TX)
+ TX_SIZE(tx) = KEYSIZE
+ TX_HJUSTIFY(tx) = GT_LEFT
+ TX_VJUSTIFY(tx) = GT_BOTTOM
+
+ # Echo the key character in graphics mode on the top line of the screen,
+ # duplicating the text drawn at the cursor position.
+
+ mx = nint ((g_keycol + 0.5) * SG_CHARWIDTH(g_sg,1))
+ my = GKI_MAXNDC - nint ((g_keyline + 0.2) * SG_CHARHEIGHT(g_sg,KEYSIZE))
+
+ call stg_text (mx, my, texts, nchars)
+ g_keyline = g_keyline + 1
+ if (g_keyline > MAX_KEYLINES) {
+ g_keycol = g_keycol + 1
+ g_keyline = 1
+ }
+
+ # Echo the logged keystroke at the position of the cursor. This may
+ # not always be readable, but at least it marks the cursor position.
+
+ call stg_text (sx, sy, texts, nchars)
+
+ if (pbverify_mode) {
+ # Issue a WC to set the cursor position, and perform a normal
+ # cursor read in passthru mode, discarding the return value.
+
+ call stg_setcursor (sx, sy, cursor)
+ call stg_rdcursor (g_tty, cursor, YES, i, i, j, k, i, j, k)
+
+ # User wants to terminate playback mode?
+ if (k == QUIT || k == INTCHAR) {
+ call ttseti (STDIN, TT_PLAYBACK, NO)
+ call stg_ctrl ("GD")
+ call putline (STDOUT, "[playback mode terminated]")
+ call stg_ctrl ("GE")
+ call flush (STDOUT)
+ call zwmsec (500)
+ if (k == INTCHAR)
+ key = EOF
+ } else if (k == GO)
+ call ttseti (STDIN, TT_PBVERIFY, NO)
+ } else
+ call zwmsec (delay)
+
+ # Restore everything modified earlier.
+ call ttseti (STDIN, TT_PASSTHRU, NO)
+ call ttseti (STDIN, TT_PBDELAY, delay)
+ call amovi (Memi[o_tx], Memi[tx], LEN_TX)
+
+ call sfree (sp)
+end
+
+
+# STG_RDCURSOR -- Physically read the cursor; an internal routine called only
+# by the stg_readcursor procedure. A lower level routine is needed since
+# two cursor reads may be required in STTY playback mode, one to read the
+# logged cursor position and another to read the physical cursor to synch
+# with the user. This is the real cursor read routine; the only concession
+# to playback mode is the `output_rc' switch, to disable output of the RC
+# instruction to the terminal, so that the routine does only input from the
+# logical device.
+
+procedure stg_rdcursor (tty, cursor, output_rc, cn, key, sx,sy, raster, rx,ry)
+
+pointer tty #I graphcap descriptor
+int cursor #I cursor to be read
+int output_rc #I flag to output the RC instruction
+int cn #O cursor which was read
+int key #O keystroke which terminated cursor read
+int sx, sy #O cursor screen position in GKI coords
+int raster #O raster number
+int rx, ry #O cursor raster position in GKI coords
+
+pointer decodecur, delimcur, pattern, patbuf, sp, otop
+int len_pattern, len_curval, sv_iomode, nchars, ip, op, i1, i2, ch
+
+bool ttygetb()
+int getci(), stg_encode()
+int ttygets(), ttygeti(), gstrcpy(), gpatmatch(), patmake(), fstati()
+include "stdgraph.com"
+define quit_ 91
+
+begin
+ call smark (sp)
+ call salloc (pattern, SZ_LINE, TY_CHAR)
+ call salloc (patbuf, SZ_LINE, TY_CHAR)
+ call salloc (decodecur, SZ_LINE, TY_CHAR)
+ call salloc (delimcur, SZ_FNAME, TY_CHAR)
+
+ key = EOF
+
+ # Make sure there is a cursor before going any further.
+ if (!ttygetb (g_tty, "RC"))
+ goto quit_
+
+ len_curval = ttygeti (tty, "CN")
+ if (ttygets (tty, "SC", Memc[decodecur], SZ_LINE) <= 0)
+ goto quit_
+
+ len_pattern = 0
+ if (ttygets (tty, "CD", Memc[delimcur], SZ_FNAME) > 0)
+ len_pattern = gstrcpy (Memc[delimcur], Memc[pattern], SZ_LINE)
+
+ # Either len_curval or pattern must be given, preferably both.
+ if (len_curval == 0 && len_pattern == 0)
+ goto quit_
+
+ # Encode the cursor value pattern, which may be either a pattern
+ # matching the entire cursor value, or just the delimiter. The value
+ # of len_curval may be negative if a pattern is given, but must be
+ # positive otherwise. If the pattern is a delimiter string, append
+ # the $ metacharacter to match only at the end of the string.
+
+ if (len_pattern > 0) {
+ if (len_curval > 0) {
+ Memc[pattern+len_pattern] = '$'
+ len_pattern = len_pattern + 1
+ Memc[pattern+len_pattern] = EOS
+ }
+ if (patmake (Memc[pattern], Memc[patbuf], SZ_LINE) == ERR)
+ goto quit_
+ } else if (len_curval < 0)
+ len_curval = -len_curval
+
+ # Set raw mode on the input file (the graphics terminal).
+ call flush (STDOUT); call flush (STDERR)
+ sv_iomode = fstati (g_in, F_IOMODE)
+ if (sv_iomode != IO_RAW)
+ call fseti (g_in, F_IOMODE, IO_RAW)
+
+ repeat {
+ # Initiate a cursor read.
+ if (output_rc == YES) {
+ call stg_ctrl1 ("RC", cursor)
+ call flush (g_out)
+ }
+
+ # Read the cursor value string. If a pattern is given accumulate
+ # at least abs(len_curval) characters and stop when the pattern
+ # is matched, returning the last len_curval characters if
+ # len_curval > 0, else the matched substring. If no pattern is
+ # given simply accumulate len_curval characters. The number of
+ # characters we will accumulate in one iteration is limited to
+ # MAX_LENCUR to permit retransmission of the RC control sequence
+ # in the event that hardware cursor mode is accidentally cleared.
+
+ for (op=1; op <= MAX_LENCUR; op=op+1) {
+ g_mem[op] = getci (g_in, key)
+ g_mem[op+1] = EOS
+
+ if (key == EOF) {
+ # Turn off raw input mode and return EOF.
+ key = EOF
+ if (sv_iomode != IO_RAW)
+ call fseti (g_in, F_IOMODE, sv_iomode)
+ goto quit_
+
+ } else if (len_pattern > 0) {
+ # A pattern string was given. Once the minimum number of
+ # chars have been accumulated, try to match the pattern,
+ # which may match either the cursor string delimiter (in
+ # the case of a fixed length cursor value), or the entire
+ # cursor string (which may then be variable length).
+
+ if (op < abs(len_curval))
+ next
+ else if (gpatmatch (g_mem[1], Memc[patbuf], i1,i2) > 0) {
+ if (len_curval > 0)
+ ip = op - len_curval + 1 # fixed length cur
+ else
+ ip = i1 # variable length cur
+ break
+ }
+
+ } else if (op >= len_curval) {
+ # No pattern was given. Terminate the cursor read once
+ # the len_curval characters have been accumulated.
+
+ ip = 1
+ break
+ }
+ }
+
+ # We have received too many characters, indicating that cursor
+ # mode was lost and the user has been pounding on the keyboard
+ # trying to get the cursor back. Discard the chars, restart
+ # the cursor and try again.
+
+ if (op > MAX_LENCUR)
+ op = -1
+
+ } until (op >= abs(len_curval) || len_curval == 0)
+
+ # Decode the cursor value string and return the position and key
+ # as output values. Return the cursor position in GKI coordinates.
+ # If extra characters were typed, e.g., before the cursor was turned
+ # on, and the cursor has a delimiter string, the extra characters will
+ # have been read into low memory and we should be able to ignore them
+ # and still get a valid read.
+
+ g_reg[E_IOP] = ip
+ call aclri (g_reg, 7)
+ if (stg_encode (Memc[decodecur], g_mem, g_reg) != OK)
+ call syserr (SYS_GGCUR)
+
+ # Multiple cursors are not implemented yet so just echo input.
+ cn = cursor
+
+ # Standard cursor value.
+ sx = nint ((g_reg[1] - g_x1) / g_dx)
+ sy = nint ((g_reg[2] - g_y1) / g_dy)
+ key = g_reg[3]
+
+ # Only some devices return the following fields. Note that FX,FY
+ # are returned by stg_encode in GKI coordinates.
+
+ nchars = g_reg[4]
+ raster = g_reg[5]
+ if (raster == 0) {
+ rx = sx
+ ry = sy
+ } else {
+ rx = g_reg[6]
+ ry = g_reg[7]
+ }
+
+ # If the NCHARS field is nonzero then a data block of length nchars
+ # follows the cursor value struct returned by the terminal. Read this
+ # into the g_msgbuf message buffer. The client makes a subsequent
+ # call to stg_readtty to access this data, otherwise it is discarded
+ # in the next cursor read.
+
+ if (nchars > 0) {
+ if (nchars > g_msgbuflen) {
+ g_msgbuflen = (nchars + SZ_MSGBUF - 1) / SZ_MSGBUF * SZ_MSGBUF
+ call realloc (g_msgbuf, g_msgbuflen, TY_CHAR)
+ }
+
+ # We should encode this data transfer in a way that permits
+ # detection and recovery from lost data. For the moment, the
+ # following assumes that nchars of data will actually be received.
+
+ op = g_msgbuf
+ otop = g_msgbuf + nchars
+ while (op < otop && getci (g_in, ch) != EOF) {
+ Memc[op] = ch
+ op = op + 1
+ }
+ g_msglen = op - g_msgbuf
+ Memc[op] = EOS
+
+ } else
+ g_msglen = 0
+
+ # Turn off raw input mode.
+ if (sv_iomode != IO_RAW)
+ call fseti (g_in, F_IOMODE, sv_iomode)
+
+ # Return EOF if any EOF character (e.g., <ctrl/z> or <ctrl/d>) or the
+ # interrupt character is typed.
+
+ if (key == EOFCHAR || key == INTCHAR || key == '\004' || key == '\032')
+ key = EOF
+quit_
+ # Terminate the cursor read.
+ if (output_rc == YES) {
+ call stg_ctrl1 ("RE", cursor)
+ call flush (g_out)
+ }
+
+ call sfree (sp)
+end