aboutsummaryrefslogtreecommitdiff
path: root/sys/tty
diff options
context:
space:
mode:
authorJoseph Hunkeler <jhunkeler@gmail.com>2015-07-08 20:46:52 -0400
committerJoseph Hunkeler <jhunkeler@gmail.com>2015-07-08 20:46:52 -0400
commitfa080de7afc95aa1c19a6e6fc0e0708ced2eadc4 (patch)
treebdda434976bc09c864f2e4fa6f16ba1952b1e555 /sys/tty
downloadiraf-linux-fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4.tar.gz
Initial commit
Diffstat (limited to 'sys/tty')
-rw-r--r--sys/tty/README29
-rw-r--r--sys/tty/doc/tty.hlp485
-rw-r--r--sys/tty/gttyload.x38
-rw-r--r--sys/tty/mkpkg52
-rw-r--r--sys/tty/tty.h51
-rw-r--r--sys/tty/ttycaps.x13
-rw-r--r--sys/tty/ttycdes.x11
-rw-r--r--sys/tty/ttyclear.x31
-rw-r--r--sys/tty/ttyclln.x32
-rw-r--r--sys/tty/ttyclose.x11
-rw-r--r--sys/tty/ttyctrl.x31
-rw-r--r--sys/tty/ttydelay.x31
-rw-r--r--sys/tty/ttydevnm.x41
-rw-r--r--sys/tty/ttygdes.x148
-rw-r--r--sys/tty/ttygetb.x15
-rw-r--r--sys/tty/ttygeti.x27
-rw-r--r--sys/tty/ttygetr.x41
-rw-r--r--sys/tty/ttygets.x73
-rw-r--r--sys/tty/ttygoto.x78
-rw-r--r--sys/tty/ttygsize.x115
-rw-r--r--sys/tty/ttyindex.x167
-rw-r--r--sys/tty/ttyinit.x46
-rw-r--r--sys/tty/ttyload.x44
-rw-r--r--sys/tty/ttyodes.x183
-rw-r--r--sys/tty/ttyopen.x299
-rw-r--r--sys/tty/ttyputl.x322
-rw-r--r--sys/tty/ttyputs.x15
-rw-r--r--sys/tty/ttyread.x102
-rw-r--r--sys/tty/ttyseti.x36
-rw-r--r--sys/tty/ttyso.x32
-rw-r--r--sys/tty/ttystati.x37
-rw-r--r--sys/tty/ttysubi.x194
-rw-r--r--sys/tty/ttywrite.x60
-rw-r--r--sys/tty/x_mkttydata.x367
-rw-r--r--sys/tty/zzdebug.x184
35 files changed, 3441 insertions, 0 deletions
diff --git a/sys/tty/README b/sys/tty/README
new file mode 100644
index 00000000..2ab27b7e
--- /dev/null
+++ b/sys/tty/README
@@ -0,0 +1,29 @@
+This directory contains the source for the TTY interface, a device independent
+interface used to control terminals. We interface to the widely used
+TERMCAP terminal database, thereby gaining the data required to control many
+diverse terminals. (Written Jan84 dct).
+
+Mar84 Added TTYGDES and the "graphcap" file, used to describe graphics
+ devices.
+
+Jly84 Added capability to compile selected termcap entries to speedup
+ TTYODES. Added TTYCOMPILE, TTYLOAD, TTYOPEN, TTYCLOSE. Modified
+ the existing routines TTYODES and TTYGDES. The new open and close
+ routines are useful for any type of database maintained in termcap
+ format.
+
+Jly84 Entry point TTYCLINE changed to TTYCLEARLN to avoid name conflict
+ with TTYCLOSE.
+
+Jly84 Task MKTTYDATA is used to compile selected entries from TERMCAP
+ files. The include files "cache_?.dat" are the output of this
+ program. To tailor the cache of pre-compiled termcap device
+ entries for a site, compile MKTTYDATA and run it to generate
+ the files "cache_t.dat" for "dev$termcap" (default MKTTYDATA params)
+ and "cache_g.dat" for "dev$graphcap", then do a Sysgen to recompile
+ the libraries. All programs which use the TTY interface, e.g.,
+ the SYSTEM package, must then be relinked to make use of the new
+ cache.
+
+Jun85 Changed filenames to make them more machine independent.
+ Installed MKTTYDATA as a task in the SOFTOOLS package.
diff --git a/sys/tty/doc/tty.hlp b/sys/tty/doc/tty.hlp
new file mode 100644
index 00000000..62924590
--- /dev/null
+++ b/sys/tty/doc/tty.hlp
@@ -0,0 +1,485 @@
+.help tty Dec83 "Terminal Control Interface"
+.nh
+Introduction
+
+ The TTY interface is a table driven, device independent interface for
+controlling terminal and printer devices. Devices are described either by
+environment definitions, or by an entry in the TTY database file. The TTY
+database file is the standard Berkeley UNIX termcap terminal capability
+database file (a text file), to which we have added entries for our printer
+devices. Accessing the UNIX termcap file directly without modification
+is sometimes awkward, but the benefits of accessing a widely used, standard
+database more than compensate for any clumsiness.
+
+When the CL starts up, the following environment variables are defined to
+describe the default terminal and printer devices. The user may subsequently
+change the values of these variables with the SET statement or with the STTY
+program.
+
+
+.ks
+.nf
+ printer default printer (i.e., "versatec")
+ terminal default terminal (i.e., "vt100", "tek4012")
+ termcap terminal/printer database filename
+ ttybaud baud rate, default 9600
+ ttyncols number of characters per line
+ ttynlines number of lines per screen
+.fi
+.ke
+
+
+The variables defining the names of the default terminal and printer
+devices will normally correspond to the names of device entries in the
+termcap file. The name of a file containing a single termcap entry
+for the device may optionally be given; the file name must contain a
+VFN or OSFN directory prefix to be recognized as a filename. The default
+termcap file is dev$termcap. Terminal initialization files (used to
+set tabstops) are files of the form dev$tty.tbi, where "tty" is the last
+field of the UNIX pathname in the "if" termcap entry. If the first
+character of the "if" filename string is not a /, an IRAF VFN should
+be given.
+
+The value strings for the environment variables TTYNCOLS and TTYNLINES,
+defining the screen dimensions, are extracted from the termcap file by the
+STTY program during startup. The screen dimensions are defined in the
+environment for two reasons: (1) efficiency (the TTY package is not needed
+to learn the screen dimensions), and (2) if a window is used, the logical
+screen dimensions may be less than the physical screen dimensions.
+Most applications programs should therefore use ENVGETI rather than TTYGETI
+to get the screen dimensions. TTYGETI returns the physical screen dimensions
+as given in the termcap file.
+
+.nh
+Library Procedures
+
+ Before any TTY control sequences can be output, the TTY device descriptor
+must be read from the termcap file into a buffer for efficient access.
+TYODES is used to "open" the TTY descriptor; TTYCDES should be called when
+done to close the descriptor, returning all buffer space used. If "ttyname"
+is "terminal" or "printer", the descriptor for the default terminal or printer
+is accessed.
+
+
+.ks
+.nf
+Open/Close descriptor:
+
+ tty = ttyodes (ttyname) # pointer ttyodes()
+ ttycdes (tty)
+.fi
+.ke
+
+
+.ks
+.nf
+Low level database access, tty control:
+
+ int = ttygeti (tty, cap)
+ real = ttygetr (tty, cap)
+ bool = ttygetb (tty, cap)
+ nchars = ttygets (tty, cap, outstr, maxch)
+ ttyputs (fd, tty, ctrlstr, afflncnt)
+ ttysubi (ctrlstr, outstr, maxch, arg1, arg2)
+.fi
+.ke
+
+
+.ks
+.nf
+High level control
+
+ OK|ERR = ttyctrl (fd, tty, cap, afflncnt)
+
+ ttyso (fd, tty, YES|NO) # turn standout mode on|off
+ ttygoto (fd, tty, col, line) # move cursor absolute
+NI ttyhorz (fd, tty, from, to) # move cursor on line
+NI ttyvert (fd, tty, from, to) # move cursor on column
+ ttyinit (fd, tty) # send :is & :if, if defined
+ ttyclear (fd, tty) # clear screen
+ ttyclearln (fd, tty) # clear the current line
+ ttyputline (fd, tty, textline, map_cc) # put text line
+.fi
+.ke
+
+
+The TTYGET procedures are used to get capabilities from the database entry.
+If the named capability is not found, TTYGETI returns zero, TTYGETB returns
+false, and TTYGETS returns the null string. TTYSUBI performs argument
+substitution on a control sequence containing at most two integer arguments
+(such as a cursor motion control sequence), generating an output sequence
+suitable for input to TTYPUTS. TTYPUTS puts the control sequence to the
+output file, padding as required given the number of affected lines.
+The baud rate and pad character, used to generate padding, are evaluated at
+TTYODES time and are conveyed to TTYPUTS in the tty descriptor.
+
+TTYSO turns standout mode on or off.
+TTYCNTRL calls TTYGETS and TTYPUTS to process and output a control sequence
+(slightly less efficiently than if the control string is buffered by
+the user code). TTYGOTO moves the cursor to the
+desired column and line. TTYHORZ and TTYVERT move the cursor on a line
+or column, using knowledge of the terminal's capabilities to generate the
+most efficient sequence.
+
+TTYPUTLINE is like the FIO PUTLINE, except that it processes any form feeds,
+standout mode directives, and other control characters (including tabs)
+embedded in the text. Lines longer than TTYNCOLS are broken into several
+output lines. TTYPUTLINE is used by the help, page, type, and lprint utilities
+to map tabs and standout mode directives for a particular output device.
+Standout mode is mapped as reverse video on most VDT's, and as underscore
+on most printers and on overstrike terminals such as the tek4012.
+
+.nh
+Implementation Notes
+
+ Of the low level routines, only TTYODES and TTYSUBI are at all complex.
+The high level routines can be fairly complex due to the logic required to
+perform a function on devices which may vary greatly in capabilities.
+
+.nh 2
+Structure
+
+.ks
+.nf
+open descriptor:
+
+ ttyodes
+ envget[si]
+ calloc [alloc tty descriptor]
+ open,close,seek [read termcap file]
+ tty_fetch_entry [fetch entry from file]
+ getline,getc
+ realloc
+ realloc
+ tty_index_caplist [encode, sort caplist]
+ ttygeti [set padchar]
+.fi
+.ke
+
+
+.ks
+.nf
+close descriptor:
+
+ ttycdes
+ ttyctrl [sometimes needed]
+ mfree [free tty descriptor]
+.fi
+.ke
+
+
+.ks
+.nf
+get integer capability:
+
+ ttygeti
+ tty_find_capability [binary search of caplist]
+ ctoi
+.fi
+.ke
+
+
+.ks
+.nf
+get string capability:
+
+ ttygets
+ tty_find_capability [binary search caplist]
+ tty_map_escapes [get control string]
+.fi
+.ke
+
+
+.ks
+.nf
+perform argument substitution on control string:
+
+ ttysubi
+ gltoc
+.fi
+.ke
+
+
+.ks
+.nf
+output control string:
+ ttyputs
+ putc
+.fi
+.ke
+
+.nh 2
+Data Structures
+
+ The tty descriptor contains several parameters describing the most basic
+features of the device, the raw termcap entry, an encoded index into the
+termcap entry used to speed up searches, and any status variables for the
+device. Since a fixed length array is used to index capabilities, there is
+an upper limit on the number of capabilities, but there is no limit on the
+length of a termcap entry.
+
+
+.ks
+.nf
+ struct tty_descriptor {
+ int t_len # length of descriptor
+ int t_op # offset into caplist
+ int t_padchar # pad character
+ int t_baud # baud rate, bits/sec
+ int t_nlines # lines per screen
+ int t_ncols # chars per line
+ int t_ncaps # number of capabilities
+ int t_capcode # sorted, encoded caplist
+ int t_capindex # indices of cap strings
+ char caplist[ARB] # termcap entry
+ }
+.fi
+.ke
+
+
+TTYODES "opens" the tty descriptor, i.e., allocates a descriptor,
+scans the termcap file and reads the terminal entry into the descriptor,
+expanding any tc references, and then sets the baud and padchar fields.
+There is no limit on the size of a termcap entry, unlike the UNIX
+implementation which uses a fixed size, 1024 character caplist buffer.
+
+
+.tp 10
+.nf
+procedure ttyodes (ttyname)
+
+begin
+ # Get device name or file name.
+ if (ttyname equals "terminal")
+ ttysource = fetch environment variable "terminal"
+ else if (ttyname equals "printer")
+ ttysource = fetch environment variable "printer"
+ else
+ ttysource = ttyname
+
+ # Get device name AND file name.
+ if (ttysource is a filename) {
+ file = ttysource
+ entry = "" (first entry)
+ } else {
+ file = fetch termcap filename from environment
+ entry = ttysource
+ }
+
+ allocate tty descriptor structure "tty"
+ tty.len = default length of descriptor
+ tty.op = pointer to first char of caplist string
+
+ # Fetch termcap entry into tty descriptor, expanding any "tc"
+ # references to other records by rescanning the file.
+
+ fd = open (termcap file)
+ repeat {
+ tty_fetch_entry (fd, entry, tty)
+ if (last field of entry is a "tc") {
+ entry = value of "tc" field
+ set tty.op to overwrite tc field
+ rewind (fd)
+ } else
+ break
+ }
+ close (fd)
+
+ # Get pad character and baud rate and store explicitly in the
+ # descriptor, since these values are used in every TTYPUTS call.
+
+ call realloc to return unused space in tty descriptor
+ call tty_index_caplist to index the caplist for efficient
+ searches
+ tty.baud = fetch "baud" from environment
+ tty.padchar = ttygeti (tty, "pc")
+
+ return (tty)
+end
+.fi
+
+
+Scan the termcap file until the desired entry is found. Copy the entry
+into the caplist field of the tty descriptor. If the caplist buffer
+overflows, reallocate a larger buffer.
+
+.nf
+procedure tty_fetch_entry (fd, entry, tty)
+
+begin
+ # Locate entry.
+ repeat {
+ advance to next record
+ if (at eof)
+ error: termcap entry not found
+ } until (positioned to the entry we are looking for)
+
+ # Fetch entry.
+ while (getc (fd, ch) != EOF) {
+ if (ch equals \ and next ch is newline) {
+ throw both out
+ } else if (ch equals newline) {
+ deposit EOS
+ return
+ } else
+ deposit ch
+
+ bump output pointer
+ if (buffer is full)
+ allocate more space
+ }
+
+ error: EOF encountered while reading termcap entry
+end
+.fi
+
+
+Prepare the caplist index. Each two-character capability name maps into
+an unique integer code. We prepare an list of capcodes and an associated
+list of indices into the caplist, then sort the capcode list. At runtime
+we will perform a binary search of the capcode list to find the desired
+capcode.
+
+.nf
+procedure tty_index_caplist (caplist, capcode_list, capindex_list)
+
+begin
+ for (each entry in caplist) {
+ compute capcode
+ if (capcode is not already in capcode_list) {
+ bump list pointer
+ if (list overflows)
+ error: too many capabilities in termcap entry
+
+ # Termcap flags capabilities that are not available
+ # with the char '@'.
+ if (first char of entry is '@')
+ index = 0
+ save capcode, index in lists
+ }
+ }
+
+ if (two or more elements in list)
+ sort list
+end
+.fi
+
+
+Process a capability string containing arguments. Examples of such capability
+strings are cursor motion to [x,y], and set scrolling region to [l1,l2].
+Note that arguments in the termcap database are zero-indexed by default,
+while the TTYSUBI arguments are one-indexed. The control string given as
+input has already been processed to reduce all escape sequences to single
+characters.
+
+.nf
+procedure ttysubi (ctrlstr, outstr, maxch, arg1, arg2)
+
+ctrlstr: device control string
+outstr: receives processed string
+arg1,arg2: on input, the arguments to be expanded in the control
+ string. on output, the difference between the
+ input arg values and the values actually used
+ to produce outstr; these may differ if necessary
+ to avoid special control chars in outstr.
+
+begin
+ # Make a local copy of the arguments to make reversal easy. Also
+ # switch to zero-indexing internally, since the termcap entry is
+ # zero-indexed.
+
+ arg[1] = arg1 - 1
+ arg1 = 0
+ arg[2] = arg2 - 1
+ arg2 = 0
+ argnum = 1
+
+ op = 1
+ for (ip=1; ctrlstr[ip] != EOS; ip=ip+1) {
+ ch = ctrlstr[ip]
+ if (ch != '%') {
+ put char in outstr, bump op
+ next
+ }
+
+ switch (ch)
+ case 'd', '2', '3', '+':
+ format coord and concat to outstr
+ increment argnum
+
+ case '.':
+ # Binary output format. Coordinate output in binary is a
+ # problem because the OS driver may see a tab, newline, or
+ # whatever and map it into something else. If the value of
+ # arg[argnum] corresponds to a special control character,
+ # we increment it until we have an acceptable value, leaving
+ # it up to our caller to do the rest.
+
+ while (arg[argnum] is a special control character) {
+ increment arg[argnum]
+ increment arg1 or arg2
+ }
+ put binary value of arg[argnum] to outstr
+ increment argnum
+
+ case '>':
+ conditionally modify arg[argnum]
+ case 'r':
+ swap arg[1] and arg[2]
+ case 'i':
+ increment arg[1] and arg[2]
+ case '%':
+ put % to outstr, bump op
+ case 'B':
+ BCD encode next arg
+ case 'D':
+ backwards BCD encode next arg (ugh)
+ }
+ }
+
+ deposit EOS
+end
+.fi
+
+
+The technique used for cursor addressing depends on the characteristics
+of the terminal. If the terminal has no cursor motion capability, we
+try to position the cursor using primitive motion commands. Otherwise
+we use TTYSUBI to generate the cursor motion sequence. If TTYSUBI returns
+a residual, we use primitive motion commands (up line and backspace) to go
+the rest of the way in.
+
+
+.nf
+procedure ttygoto (fd, tty, col, line)
+
+begin
+ if (tty has no cursor addressing capability) {
+ # If possible, the calling program should keep track of the
+ # cursor position and use primitive motion commands for
+ # positioning when possible. We do the best we can without
+ # knowledge of the current position.
+
+ # First get to a known position.
+ goto home or lower-left, depending on which is closest to
+ desired position and on capabilities of terminal.
+
+ # Now move to the desired position.
+ step to desired line using ttyvert
+ advance to desired column using ttyhorz
+
+ } else {
+ get cursor motion control string
+ call ttysubi to substitute in desired coordinates
+ call ttyputs to put control string to file
+
+ # In certain cases, ttysubi cannot get us all the way there,
+ # and we have to step in the rest of the way.
+
+ if (line residual)
+ call ttyhorz to adjust position within line
+ if (col residual)
+ call ttyvert to adjust vertical position
+ }
+end
+.fi
diff --git a/sys/tty/gttyload.x b/sys/tty/gttyload.x
new file mode 100644
index 00000000..066c1582
--- /dev/null
+++ b/sys/tty/gttyload.x
@@ -0,0 +1,38 @@
+# G_TTYLOAD -- Version of the TTYLOAD procedure for accessing compiled entries
+# from the GRAPHCAP database file. Search the database of compiled GRAPHCAP
+# entries for the named device, and if found, return the CAPLIST string (list
+# of device capabilities) in the output string. The number of characters output
+# is returned as the function value. The compiled database is defined by the
+# include file "cacheg.dat", which serves as a cache for the GRAPHCAP
+# entries of heavily used devices (see TTYLOAD, TTYCOMPILE).
+
+int procedure g_ttyload (fname, device, outstr, maxch)
+
+char fname[ARB] # name of termcap file being referenced
+char device[ARB] # device name as in TERMCAP entry
+char outstr[maxch] # output string to receive caplist
+int maxch
+
+int dev
+bool streq(), strne()
+int gstrcpy()
+
+include "dev$cacheg.dat"
+
+begin
+ # If the name of the file being referenced is not the same as the
+ # name of the file used to build the cache, then the cache is
+ # invalidated.
+
+ if (strne (fname, sbuf[termcap_filename]))
+ return (0)
+
+ # NDEVICES, DEVNAME, DEVCAPS, and SBUF are defined and initialized
+ # in the include file.
+
+ do dev = 1, ndevices
+ if (streq (sbuf[devname[dev]], device))
+ return (gstrcpy (sbuf[devcaps[dev]], outstr, maxch))
+
+ return (0)
+end
diff --git a/sys/tty/mkpkg b/sys/tty/mkpkg
new file mode 100644
index 00000000..35e97a8a
--- /dev/null
+++ b/sys/tty/mkpkg
@@ -0,0 +1,52 @@
+# Make the TTY interface portion of the LIBSYS library.
+
+$checkout libsys.a lib$
+$update libsys.a
+$checkin libsys.a lib$
+$exit
+
+update:
+ $call relink
+ $call install
+ ;
+
+relink:
+ $omake x_mkttydata.x <error.h> tty.h
+ $link x_mkttydata.o
+ ;
+
+install:
+ $move x_mkttydata.e bin$
+ ;
+
+libsys.a:
+ gttyload.x
+ ttycaps.x tty.h
+ ttycdes.x
+ ttyclear.x tty.h <chars.h>
+ ttyclln.x tty.h <chars.h>
+ ttyclose.x
+ ttyctrl.x tty.h <chars.h>
+ ttydelay.x tty.h
+ ttydevnm.x <ctype.h>
+ ttygdes.x dev$cacheg.dat tty.h <chars.h> <ctype.h> <error.h>
+ ttygetb.x
+ ttygeti.x
+ ttygetr.x <mach.h>
+ ttygets.x <chars.h>
+ ttygoto.x tty.h <chars.h>
+ ttygsize.x <fset.h> <ttset.h> <ttyset.h>
+ ttyindex.x tty.h <chars.h>
+ ttyinit.x tty.h <chars.h> <error.h> <fset.h>
+ ttyload.x dev$cachet.dat
+ ttyodes.x tty.h <chars.h> <ctype.h> <error.h>
+ ttyopen.x tty.h <chars.h> <ctype.h> <error.h>
+ ttyputl.x tty.h <chars.h> <ctype.h>
+ ttyputs.x
+ ttyread.x <chars.h> <fset.h>
+ ttyseti.x tty.h <chars.h> <ttyset.h>
+ ttyso.x
+ ttystati.x tty.h <chars.h> <ttyset.h>
+ ttysubi.x tty.h <chars.h> <ctype.h>
+ ttywrite.x tty.h <chars.h> <ctype.h>
+ ;
diff --git a/sys/tty/tty.h b/sys/tty/tty.h
new file mode 100644
index 00000000..6e0e58e0
--- /dev/null
+++ b/sys/tty/tty.h
@@ -0,0 +1,51 @@
+# TTY package definitions. Requires <chars.h>.
+
+define TABSIZE 8
+define MAX_TC_NESTING 5 # max nesting of tc=term references
+
+# Include here all special control characters (mapped by driver) which should
+# not be used as binary cursor coordinates. The list must be terminated by
+# an EOS; do not count the EOS in NDCHARS. Note that NUL cannot be included
+# in the list because it is the same as EOS.
+
+define NDCHARS 3
+define DRIVER_CHARS EOT,HT,LF,EOS
+
+# Mapping function used to map capcodes ("cm", etc.) into unique integers.
+define ENCODE ($1[1]*128+$1[2])
+
+# Types of standout modes defined for terminals.
+
+define SOSE 1 # use so,se or us,ue capabilities
+define BSOS 2 # backspace and overstrike with _
+define CROS 3 # CR and overstrike with full line
+define TOUP 4 # map standout chars to upper case
+
+# TTY descriptor structure. Full termcap entry is the 'caplist' string.
+# The caplist is indexed at open time to permit a binary search for
+# capabilities at run time.
+
+define T_MEMINCR 512 # increment if overflow occurs
+define T_OFFCAP 215 # struct offset to caplist field
+define MAX_CAPS 100 # maximum capabilities
+define MAX_COORDS 7 # maximum coords for ttysubi
+define SZ_CTRLSTR 50 # buffer size for control strings
+define LEN_DEFTTY (256+1024) # initial length of tty structure
+
+define T_LEN Memi[$1] # length of tty structure
+define T_OP Memi[$1+1] # offset into caplist
+define T_PADCHAR Memi[$1+2] # pad character for delays
+define T_TABCHAR Memi[$1+3] # tab character, if HW tabs ok
+define T_BSOK Memi[$1+4] # terminal backspaces with BS
+define T_HTOK Memi[$1+5] # term has HT (horiz tab) in hardware
+define T_AM Memi[$1+6] # term has automargin advance
+define T_SOTYPE Memi[$1+7] # type of standout mode (ttyputline)
+define T_BAUD Memi[$1+8] # baud rate for delays
+define T_NLINES Memi[$1+9] # nlines on terminal at open
+define T_NCOLS Memi[$1+10] # ncols on terminal at open
+define T_NCAPS Memi[$1+11] # number of capabilities
+define T_CAPLEN Memi[$1+12] # length of caplist, chars
+ # (extra space)
+define T_CAPCODE Memi[$1+15] # cap code array: c1*128+c2
+define T_CAPINDEX Memi[$1+115] # cap index array
+define T_CAPLIST Memc[($1+215-1)*SZ_STRUCT+1] # termcap entry
diff --git a/sys/tty/ttycaps.x b/sys/tty/ttycaps.x
new file mode 100644
index 00000000..e6fcbcf0
--- /dev/null
+++ b/sys/tty/ttycaps.x
@@ -0,0 +1,13 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include "tty.h"
+
+# TTYCAPS -- Return a pointer to the caplist field of an open TTY descriptor.
+
+pointer procedure ttycaps (tty)
+
+pointer tty # tty descriptor
+
+begin
+ return (P2C (tty + T_OFFCAP))
+end
diff --git a/sys/tty/ttycdes.x b/sys/tty/ttycdes.x
new file mode 100644
index 00000000..0b778a51
--- /dev/null
+++ b/sys/tty/ttycdes.x
@@ -0,0 +1,11 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+# TTYCDES -- Close a terminal opened with TTYODES or TTYGDES.
+
+procedure ttycdes (tty)
+
+pointer tty
+
+begin
+ call ttyclose (tty)
+end
diff --git a/sys/tty/ttyclear.x b/sys/tty/ttyclear.x
new file mode 100644
index 00000000..86dac6ff
--- /dev/null
+++ b/sys/tty/ttyclear.x
@@ -0,0 +1,31 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <chars.h>
+include "tty.h"
+
+# TTYCLEAR -- Clear the terminal screen.
+
+procedure ttyclear (fd, tty)
+
+int fd
+pointer tty
+
+int status
+bool ttygetb()
+int ttyctrl()
+errchk ttygetb, ttyctrl
+
+begin
+ # If hardcopy terminal, output formfeed instead of clear.
+ if (ttygetb (tty, "ht"))
+ status = ttyctrl (fd, tty, "ff", T_NLINES(tty))
+ else
+ status = ERR
+ if (status == ERR)
+ status = ttyctrl (fd, tty, "cl", T_NLINES(tty))
+
+ # If ff or cl capability not found, the best we can do is output
+ # a newline.
+ if (status == ERR)
+ call putline (fd, "\n")
+end
diff --git a/sys/tty/ttyclln.x b/sys/tty/ttyclln.x
new file mode 100644
index 00000000..34e57328
--- /dev/null
+++ b/sys/tty/ttyclln.x
@@ -0,0 +1,32 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <chars.h>
+include "tty.h"
+
+# TTYCLEARLN -- Clear the current line. The cursor is left positioned at the
+# left margin. If the clear has to be performed by overwriting the line with
+# blanks, the final column is not cleared.
+
+procedure ttyclearln (fd, tty)
+
+int fd
+pointer tty
+pointer sp, buf
+int nchars, ttygets()
+errchk salloc, ttygets, putc, ttywrite, fprintf, pargi
+
+begin
+ call smark (sp)
+ call salloc (buf, SZ_CTRLSTR, TY_CHAR)
+
+ nchars = ttygets (tty, "ce", Memc[buf], SZ_CTRLSTR)
+ if (nchars > 0) {
+ call putci (fd, '\r')
+ call ttywrite (fd, tty, Memc[buf], nchars, 1)
+ } else {
+ call fprintf (fd, "\r%*w\r")
+ call pargi (T_NCOLS(tty) - 1)
+ }
+
+ call sfree (sp)
+end
diff --git a/sys/tty/ttyclose.x b/sys/tty/ttyclose.x
new file mode 100644
index 00000000..f30644dd
--- /dev/null
+++ b/sys/tty/ttyclose.x
@@ -0,0 +1,11 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+# TTYCLOSE -- Close the tty terminal descriptor opened with TTYOPEN.
+
+procedure ttyclose (tty)
+
+pointer tty
+
+begin
+ call mfree (tty, TY_STRUCT)
+end
diff --git a/sys/tty/ttyctrl.x b/sys/tty/ttyctrl.x
new file mode 100644
index 00000000..3a66e961
--- /dev/null
+++ b/sys/tty/ttyctrl.x
@@ -0,0 +1,31 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <chars.h>
+include "tty.h"
+
+# TTYCTRL -- Output a control sequence to the terminal.
+
+int procedure ttyctrl (fd, tty, cap, afflncnt)
+
+int fd, afflncnt
+char cap[ARB]
+pointer tty
+
+pointer sp, buf
+int status, nchars, ttygets()
+errchk ttygets, ttywrite
+
+begin
+ call smark (sp)
+ call salloc (buf, SZ_CTRLSTR, TY_CHAR)
+
+ nchars = ttygets (tty, cap, Memc[buf], SZ_CTRLSTR)
+ if (nchars > 0) {
+ call ttywrite (fd, tty, Memc[buf], nchars, afflncnt)
+ status = OK
+ } else
+ status = ERR
+
+ call sfree (sp)
+ return (status)
+end
diff --git a/sys/tty/ttydelay.x b/sys/tty/ttydelay.x
new file mode 100644
index 00000000..7fc6b3d4
--- /dev/null
+++ b/sys/tty/ttydelay.x
@@ -0,0 +1,31 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include "tty.h"
+
+# TTYDELAY -- Output a sequence of pad characters to create a delay, giving
+# the terminal time to complete some operation before being passed the next
+# request.
+
+procedure ttydelay (fd, tty, delay)
+
+int fd # output file
+pointer tty # tty descriptor
+int delay # desired milliseconds of delay
+
+int padchar, npadchars
+real msec_per_char
+int and()
+
+begin
+ # Add padding if needed to generate delay. (8 = nbits per char,
+ # baud is in units of bits per second).
+
+ if (delay > 0 && T_BAUD(tty) > 0) {
+ padchar = and (T_PADCHAR(tty), 177B)
+ msec_per_char = real(8 * 1000) / real(T_BAUD(tty))
+ npadchars = int (delay / msec_per_char + 0.5)
+
+ for (; npadchars > 0; npadchars = npadchars - 1)
+ call putci (fd, padchar)
+ }
+end
diff --git a/sys/tty/ttydevnm.x b/sys/tty/ttydevnm.x
new file mode 100644
index 00000000..76996d69
--- /dev/null
+++ b/sys/tty/ttydevnm.x
@@ -0,0 +1,41 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ctype.h>
+
+# TTYDEVNAME -- Extract the logical device name from a full device specification
+# of the form "node ! logical_device ? physical_device". The node prefix, if
+# given, specifies the node from which the device is to be accessed (via the
+# network), and the physical device field contains particulars about the
+# physical device to be accessed. Only the logical device field, used to index
+# the termcap file, is of any interest to TTY. The logical device name
+# consists of chars chosen from the set [a-zA-Z0-9_+-].
+
+procedure ttydevname (device, ldevice, maxch)
+
+char device[ARB] # full device specification
+char ldevice[maxch] # logical device name
+int maxch
+
+pointer sp, nodename
+int ip, op, ch
+int ki_extnode()
+
+begin
+ call smark (sp)
+ call salloc (nodename, SZ_FNAME, TY_CHAR)
+
+ ip = ki_extnode (device, Memc[nodename], maxch, op) + 1
+
+ for (op=1; device[ip] != EOS; ip=ip+1) {
+ ch = device[ip]
+ if (!(IS_ALNUM(ch) || ch == '_' || ch == '+' || ch == '-')) {
+ ldevice[op] = EOS
+ break
+ } else {
+ ldevice[op] = ch
+ op = op + 1
+ }
+ }
+
+ call sfree (sp)
+end
diff --git a/sys/tty/ttygdes.x b/sys/tty/ttygdes.x
new file mode 100644
index 00000000..8eff579a
--- /dev/null
+++ b/sys/tty/ttygdes.x
@@ -0,0 +1,148 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <error.h>
+include <syserr.h>
+include <ctype.h>
+include <chars.h>
+include "tty.h"
+
+define DEF_BAUDRATE 9600
+
+# TTYGDES -- Open a TTY graphics stdgraph descriptor. If ttyname is
+# "stdgraph" or "stdplot", get the name of the physical graphics device
+# from the environment. The name of the graphcap file is fetched from the
+# environment and the graphcap file is searched for an entry corresponding
+# to the named device.
+#
+# The descriptor is then allocated, and the graphcap entry read in. Graphcap
+# permits an entry to be defined in terms of another entry with the "tc"
+# field; we must expand such references by rescanning the file once for each
+# such reference. Finally, the graphcap entry is indexed for efficient access.
+# The form of a graphcap entry is identical to that for a termcap entry.
+
+pointer procedure ttygdes (ttyname)
+
+char ttyname[ARB]
+
+int nchars
+pointer sp, ttysource, device, devname, fname, tty
+pointer ttyopen()
+extern g_ttyload()
+bool streq(), ttygetb()
+int fnldir(), ttygeti(), ttygets()
+int envgets(), envgeti()
+errchk envgets, envgeti, ttyopen, ttygets, syserrs
+errchk tty_index_caps, ttygeti, envindir
+
+string stdgraph "stdgraph"
+string stdimage "stdimage"
+string stdplot "stdplot"
+string graphcap "graphcap"
+
+begin
+ call smark (sp)
+ call salloc (ttysource, SZ_FNAME, TY_CHAR)
+ call salloc (devname, SZ_FNAME, TY_CHAR)
+ call salloc (device, SZ_FNAME, TY_CHAR)
+ call salloc (fname, SZ_FNAME, TY_CHAR)
+
+ # Resolve any indirection in the device name.
+ call envindir (ttyname, Memc[devname], SZ_FNAME)
+
+ # Get device name or graphcap file name.
+ if (streq (Memc[devname], stdgraph)) {
+ if (envgets (stdgraph, Memc[ttysource], SZ_FNAME) <= 0)
+ call syserrs (SYS_ENVNF, stdgraph)
+ } else if (streq (Memc[devname], stdimage)) {
+ if (envgets (stdimage, Memc[ttysource], SZ_FNAME) <= 0)
+ call syserrs (SYS_ENVNF, stdimage)
+ } else if (streq (Memc[devname], stdplot)) {
+ if (envgets (stdplot, Memc[ttysource], SZ_FNAME) <= 0)
+ call syserrs (SYS_ENVNF, stdplot)
+ } else
+ call strcpy (Memc[devname], Memc[ttysource], SZ_FNAME)
+
+ # If ttysource is a filename, we assume that it is the name of
+ # a graphcap format file, the first entry of which (matched by the
+ # null device name) is the entry for the device. Otherwise,
+ # ttysource is the name of the desired graphcap entry in the regular
+ # graphcap file.
+
+ if (fnldir (Memc[ttysource], Memc[fname], SZ_FNAME) > 0) {
+ call strcpy (Memc[ttysource], Memc[fname], SZ_FNAME)
+ Memc[device] = EOS
+ } else {
+ if (envgets (graphcap, Memc[fname], SZ_FNAME) <= 0)
+ call syserrs (SYS_ENVNF, graphcap)
+ call strcpy (Memc[ttysource], Memc[device], SZ_FNAME)
+ }
+
+ # Truncate the device name if device fields are appended.
+ call ttydevname (Memc[device], Memc[device], SZ_FNAME)
+
+ # Allocate and initialize the tty descriptor structure. Fetch graphcap
+ # entry from graphcap file into descriptor. The G_TTYLOAD procedure,
+ # passed as an argument to TTYOPEN, is searched for cached termcap
+ # entries before accessing the actual file.
+
+ tty = ttyopen (Memc[fname], Memc[device], g_ttyload)
+
+ # Prepare index of fields in the descriptor, so that we can more
+ # efficiently search for fields later.
+
+ call tty_index_caps (tty, T_CAPCODE(tty), T_CAPINDEX(tty), T_NCAPS(tty))
+
+ # Determine whether or not the stdgraph device can backspace with BS.
+ if (ttygetb (tty, "bs"))
+ T_BSOK(tty) = YES
+ else
+ T_BSOK(tty) = NO
+
+ # Determine whether or not the stdgraph device can expand tabs.
+ # If it can but it requires some long string, don't bother.
+
+ T_HTOK(tty) = NO
+ T_TABCHAR(tty) = 0
+ if (ttygetb (tty, "pt")) {
+ nchars = ttygets (tty, "ta", Memc[fname], SZ_FNAME)
+ if (nchars <= 0) {
+ T_HTOK(tty) = YES
+ T_TABCHAR(tty) = '\t'
+ } else if (nchars == 1) {
+ T_HTOK(tty) = YES
+ T_TABCHAR(tty) = Memc[fname]
+ }
+ }
+
+ # Determine the optimimum mode for handling standout mode control,
+ # and save in the descriptor.
+
+ if (ttygetb (tty, "so")) {
+ T_SOTYPE(tty) = SOSE # use so, se
+ } else if (ttygetb (tty, "os")) {
+ if (T_BSOK(tty) == YES || ttygetb (tty, "bc"))
+ T_SOTYPE(tty) = BSOS # backspace, ostrike
+ else
+ T_SOTYPE(tty) = CROS # ostrike whole line
+ } else
+ T_SOTYPE(tty) = TOUP # to upper case
+
+ # Get pad char and baud rate (used by ttyputs to generate delays)
+ # and put in descriptor for efficient access. Also get tty screen
+ # dimensions since they are fundamental and will probably prove
+ # useful later.
+
+ T_PADCHAR(tty) = ttygeti (tty, "pc") # returns 0 if field not found
+ T_NLINES(tty) = ttygeti (tty, "li")
+ T_NCOLS(tty) = ttygeti (tty, "co")
+
+ # Baud rate may not be right if device is attached to the host, and
+ # and user is working remotely. Nonetheless it is safer to pick up
+ # the value from the environment than to assume a default.
+
+ iferr (T_BAUD(tty) = envgeti ("ttybaud"))
+ T_BAUD(tty) = DEF_BAUDRATE
+
+ call sfree (sp)
+ return (tty)
+end
diff --git a/sys/tty/ttygetb.x b/sys/tty/ttygetb.x
new file mode 100644
index 00000000..8c6fdbd4
--- /dev/null
+++ b/sys/tty/ttygetb.x
@@ -0,0 +1,15 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+# TTYGETB -- Determine whether or not a capability exists for a device.
+# If there is any entry at all, the capability exists.
+
+bool procedure ttygetb (tty, cap)
+
+pointer tty # tty descriptor
+char cap[ARB] # two character capability name
+pointer ip
+int tty_find_capability()
+
+begin
+ return (tty_find_capability (tty, cap, ip) == YES)
+end
diff --git a/sys/tty/ttygeti.x b/sys/tty/ttygeti.x
new file mode 100644
index 00000000..95384df3
--- /dev/null
+++ b/sys/tty/ttygeti.x
@@ -0,0 +1,27 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+# TTYGETI -- Get an integer valued capability. If the capability is not
+# found for the device, or cannot be interpreted as an integer, zero is
+# returned. Integer capabilities have the format ":xx#dd:".
+
+int procedure ttygeti (tty, cap)
+
+pointer tty # tty descriptor
+char cap[ARB] # two character capability name
+int ival
+pointer ip
+int tty_find_capability(), ctoi()
+
+begin
+ if (tty_find_capability (tty, cap, ip) == NO)
+ return (0)
+ else if (Memc[ip] != '#')
+ return (0)
+ else {
+ ip = ip + 1 # skip the '#'
+ if (ctoi (Memc, ip, ival) == 0)
+ return (0)
+ else
+ return (ival)
+ }
+end
diff --git a/sys/tty/ttygetr.x b/sys/tty/ttygetr.x
new file mode 100644
index 00000000..f4e2a8a8
--- /dev/null
+++ b/sys/tty/ttygetr.x
@@ -0,0 +1,41 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+
+# TTYGETR -- Get a real valued capability. If the capability is not
+# found for the device, or cannot be interpreted as a number, zero is
+# returned. Real valued capabilities have the format ":xx#num:".
+
+real procedure ttygetr (tty, cap)
+
+pointer tty # tty descriptor
+char cap[ARB] # two character capability name
+
+char numstr[MAX_DIGITS]
+int np, op
+pointer ip
+double dval
+int tty_find_capability(), ctod()
+
+begin
+ if (tty_find_capability (tty, cap, ip) == NO)
+ return (0.0)
+ else if (Memc[ip] != '#')
+ return (0.0)
+ else {
+ # Extract the number into numstr. Cannot convert in place in
+ # the table because the ":" delimiter will by interpreted by
+ # ctod as for a sexagesimal number.
+ op = 1
+ for (ip=ip+1; op <= MAX_DIGITS && Memc[ip] != ':'; ip=ip+1) {
+ numstr[op] = Memc[ip]
+ op = op + 1
+ }
+ numstr[op] = EOS
+ np = 1
+ if (ctod (numstr, np, dval) == 0)
+ return (0.0)
+ else
+ return (dval)
+ }
+end
diff --git a/sys/tty/ttygets.x b/sys/tty/ttygets.x
new file mode 100644
index 00000000..23da69e1
--- /dev/null
+++ b/sys/tty/ttygets.x
@@ -0,0 +1,73 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <chars.h>
+
+.help ttygets
+.nf ___________________________________________________________________________
+TTYGETS -- Get the string value of a capability. Process all termcap escapes.
+These are:
+
+ \E ascii esc (escape)
+ ^X control-X (i.e., ^C=03B, ^Z=032B, etc.)
+ \[nrtbf] newline, return, tab, backspace, formfeed
+ \ddd octal value of character
+ \^ the character ^
+ \\ the character \
+
+The character ':' may not be placed directly in a capability string; it
+should be given as \072 instead. The null character is represented as \200;
+all characters are masked to 7 bits upon output by TTYPUTS, hence \200
+is sent to the terminal as NUL.
+.endhelp ______________________________________________________________________
+
+int procedure ttygets (tty, cap, outstr, maxch)
+
+pointer tty # tty descriptor
+char cap[ARB] # two character capability name
+char outstr[ARB] # receives cap string
+int maxch # size of outstr
+
+char ch
+pointer ip
+int op, junk, temp
+int tty_find_capability(), cctoc()
+
+begin
+ op = 1
+
+ if (tty_find_capability (tty, cap, ip) == YES) {
+ # Skip the '=' which follows the two character capability name.
+ if (Memc[ip] == '=')
+ ip = ip + 1
+
+ # Extract the string, processing all escapes.
+ for (ch=Memc[ip]; ch != ':'; ch=Memc[ip]) {
+ if (ch == '^') {
+ ip = ip + 1
+ temp = Memc[ip]
+ ch = mod (temp, 40B)
+ } else if (ch == '\\') {
+ switch (Memc[ip+1]) {
+ case 'E':
+ ip = ip + 1
+ ch = ESC
+ case '^', ':', '\\':
+ ip = ip + 1
+ ch = Memc[ip]
+ default:
+ junk = cctoc (Memc, ip, ch)
+ ip = ip - 1
+ }
+ }
+
+ outstr[op] = ch
+ op = op + 1
+ ip = ip + 1
+ if (op >= maxch)
+ break
+ }
+ }
+
+ outstr[op] = EOS
+ return (op-1)
+end
diff --git a/sys/tty/ttygoto.x b/sys/tty/ttygoto.x
new file mode 100644
index 00000000..d8896125
--- /dev/null
+++ b/sys/tty/ttygoto.x
@@ -0,0 +1,78 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <chars.h>
+include "tty.h"
+
+# TTYGOTO -- Position the cursor to the given absolute screen coordinates.
+# We do not require any knowledge of the current screen position; many programs
+# will wish to do cursor positioning at a lower level to take advantage of
+# knowledge of the current position.
+
+procedure ttygoto (fd, tty, col, line)
+
+int fd # output stream
+pointer tty # termcap descriptor
+int col # destination column
+int line # destination line
+
+pointer sp, cm_in, cm_out
+int coords[2], nchars, i
+int ttygets(), ttysubi()
+errchk salloc, ttygets, ttyputs, ttywrite
+
+begin
+ call smark (sp)
+ call salloc (cm_in, SZ_CTRLSTR, TY_CHAR)
+ call salloc (cm_out, SZ_LINE, TY_CHAR)
+
+ # Use the cursor motion control string to position cursor, if the
+ # terminal has such a capability. Otherwise try to use primitive
+ # motion commands.
+
+ if (ttygets (tty, "cm", Memc[cm_in], SZ_CTRLSTR) > 0) {
+ # Coordinates are ordered line,col in the termcap entry,
+ # whereas our args are ordered col,line (e.g., x,y). Store
+ # in "coords" in the termcap order.
+
+ coords[1] = line
+ coords[2] = col
+ nchars = ttysubi (Memc[cm_in], Memc[cm_out], SZ_LINE, coords, 2)
+
+ # Output cursor motion control string to file.
+ call ttywrite (fd, tty, Memc[cm_out], nchars, 1)
+
+ # If unable to position to the exact coordinates, use primitive
+ # motion commands to step the rest of the way in. Do not abort
+ # if unable to do so.
+
+ if (coords[2] > 0) {
+ # Presumably we do not have to step in very often, so we do
+ # nothing special to buffer the backspace control sequence.
+ # Most terminals recognize BS in any case.
+
+ if (T_BSOK(tty) == YES) {
+ Memc[cm_out] = BS
+ Memc[cm_out+1] = EOS
+ } else if (ttygets (tty, "bc", Memc[cm_out], SZ_CTRLSTR) == 0)
+ Memc[cm_out] = EOS
+
+ for (i=coords[2]; i > 0; i=i-1)
+ call ttyputs (fd, tty, Memc[cm_out], 1)
+ }
+
+ # Now adjust vertical position if necessary.
+ if (coords[1] > 0) {
+ if (ttygets (tty, "up", Memc[cm_out], SZ_CTRLSTR) > 0)
+ for (i=coords[1]; i > 0; i=i-1)
+ call ttyputs (fd, tty, Memc[cm_out], 1)
+ }
+
+ } else {
+ # Terminal has no nifty cursor addressing capability; add code here
+ # to position cursor by generating a sequence of more primitive
+ # codes. Not going to bother with this for now.
+ ;
+ }
+
+ call sfree (sp)
+end
diff --git a/sys/tty/ttygsize.x b/sys/tty/ttygsize.x
new file mode 100644
index 00000000..e4ccfa1a
--- /dev/null
+++ b/sys/tty/ttygsize.x
@@ -0,0 +1,115 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ttyset.h>
+include <ttset.h>
+include <fset.h>
+
+define TIMEOUT 2000 # timeout interval, msec, for size query
+
+
+# TTYGSIZE -- Get the width and height of the terminal screen in characters.
+# For a conventional terminal these values are given as constants in the
+# termcap entry for the device. If the terminal has a screen which can vary
+# in size at runtime (e.g., a window on a workstation), then the screen size
+# is queried at runtime.
+
+procedure ttygsize (in, out, tty, width, height)
+
+int in, out # input and output streams
+pointer tty # terminal descriptor
+int width # ncols on screen (out)
+int height # nlines on screen (out)
+
+pointer sp, patbuf, buf, qs, wh, ip, op
+int index, len_qs, len_wh, w_index, h_index, sv_iomode, nchars, junk
+
+int patmake(), patindex(), gstrcpy(), ctoi()
+int ttygets(), ttyread(), ttystati(), ttstati(), fstati()
+define noquery_ 91
+errchk ttyread
+
+begin
+ call smark (sp)
+ call salloc (patbuf, SZ_LINE, TY_CHAR)
+ call salloc (buf, SZ_LINE, TY_CHAR)
+ call salloc (qs, SZ_FNAME, TY_CHAR)
+ call salloc (wh, SZ_FNAME, TY_CHAR)
+
+ width = 0
+ height = 0
+ index = 0
+
+ # Just use the termcap values if in stty playback or record mode.
+ if (ttstati(in,TT_LOGIN) == YES || ttstati(in,TT_PLAYBACK) == YES)
+ goto noquery_
+
+ len_qs = ttygets (tty, "qs", Memc[qs], SZ_FNAME)
+ len_wh = ttygets (tty, "wh", Memc[wh], SZ_FNAME)
+
+ # Process the string DS (decode size string) to map the %W %H fields
+ # into the pattern strings "%[0-9]*", noting the index positions of
+ # the W and H fields.
+
+ if (len_wh > 0) {
+ op = buf
+ for (ip=wh; Memc[ip] != EOS; ip=ip+1) {
+ if ((Memc[ip] == '%') && ip > wh && Memc[ip-1] != '\\' &&
+ (Memc[ip+1] == 'W' || Memc[ip+1] == 'H')) {
+
+ index = index + 1
+ op = op + gstrcpy ("%[0-9]*", Memc[op], ARB)
+ ip = ip + 1
+
+ if (Memc[ip] == 'W')
+ w_index = index
+ else
+ h_index = index
+ } else {
+ Memc[op] = Memc[ip]
+ op = op + 1
+ }
+ }
+ Memc[op] = EOS
+ junk = patmake (Memc[buf], Memc[patbuf], SZ_LINE)
+ }
+
+ # Query the terminal for the screen size, read back and decode the
+ # encoded screen size string.
+
+ if (len_qs > 0 && len_wh > 0) {
+ sv_iomode = fstati (in, F_IOMODE)
+ if (sv_iomode != IO_RAW)
+ call fseti (in, F_IOMODE, IO_RAW)
+
+ call ttywrite (out, tty, Memc[qs], len_qs, 0)
+ call flush (out)
+
+ nchars = ttyread (in, tty, Memc[buf],SZ_LINE,Memc[patbuf], TIMEOUT)
+ if (nchars > 0) {
+ if (ctoi (Memc[buf],patindex(Memc[patbuf],w_index),width) <= 0)
+ width = 0
+ if (ctoi (Memc[buf],patindex(Memc[patbuf],h_index),height) <= 0)
+ height = 0
+ }
+
+ if (sv_iomode != IO_RAW)
+ call fseti (in, F_IOMODE, sv_iomode)
+
+ if (width == 0 && nchars == 0) {
+ call eprintf ("timeout - terminal type set wrong? ")
+ call eprintf ("(`stty termtype' to reset)\n")
+ }
+ }
+
+noquery_
+ # If we still do not know the screen width or height, use the values
+ # given in the user environment, else in the termcap entry for the
+ # device.
+
+ if (width <= 0)
+ width = ttystati (tty, TTY_NCOLS)
+ if (height <= 0)
+ height = ttystati (tty, TTY_NLINES)
+
+ call sfree (sp)
+end
diff --git a/sys/tty/ttyindex.x b/sys/tty/ttyindex.x
new file mode 100644
index 00000000..6d9ae222
--- /dev/null
+++ b/sys/tty/ttyindex.x
@@ -0,0 +1,167 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <syserr.h>
+include <chars.h>
+include "tty.h"
+
+.help index caplist
+.nf _________________________________________________________________________
+TTY_INDEX_CAPS -- Prepare an index into the caplist string, stored in
+the tty descriptor. Each two character capability name maps into a unique
+integer code, called the capcode. We prepare a list of capcodes, keeping
+only the first such code encountered in the case of multiple entries.
+The offset of the capability in the caplist string is associated with each
+capcode. When these lists have been prepared, they are sorted to permit
+a binary search for capabilities at runtime.
+.endhelp ____________________________________________________________________
+
+procedure tty_index_caps (tty, t_capcode, t_capindex, ncaps)
+
+pointer tty
+int t_capcode[ARB], t_capindex[ARB]
+int ncaps
+
+pointer ip, caplist
+int i, swap, capcode, temp
+int tty_encode_capability()
+pointer coerce()
+errchk syserr
+
+begin
+ caplist = coerce (tty + T_OFFCAP, TY_STRUCT, TY_CHAR)
+ ip = caplist
+
+ # Scan the caplist and prepare the capcode and capindex lists.
+ for (ncaps=0; ncaps <= MAX_CAPS; ) {
+ # Advance to the next capability field. Normal exit occurs
+ # when ':' is followed immediately by EOS.
+
+ while (Memc[ip] != ':' && Memc[ip] != EOS)
+ ip = ip + 1
+ if (Memc[ip+1] == EOS || Memc[ip] == EOS)
+ break
+
+ ip = ip + 1 # skip the ':'
+ capcode = tty_encode_capability (Memc[ip])
+
+ # Is the capcode already in the list? If not found, add it to
+ # the list.
+ for (i=1; i <= ncaps && t_capcode[i] != capcode; i=i+1)
+ ;
+ if (i > ncaps) { # not found
+ ncaps = ncaps + 1
+ t_capcode[ncaps] = capcode
+ t_capindex[ncaps] = ip - caplist + 1
+ }
+ }
+
+ if (ncaps > MAX_CAPS)
+ call syserr (SYS_TTYOVFL)
+
+ # A simple interchange sort is sufficient here, even though it would
+ # not be hard to interface to qsort. The longest termcap entries are
+ # about 50 caps, and the time req'd to sort such a short list is
+ # negligible compared to the time spent searching the termcap file.
+
+ if (ncaps > 1)
+ repeat {
+ swap = 0
+ do i = 1, ncaps-1
+ if (t_capcode[i] > t_capcode[i+1]) {
+ temp = t_capcode[i]
+ t_capcode[i] = t_capcode[i+1]
+ t_capcode[i+1] = temp
+ temp = t_capindex[i]
+ t_capindex[i] = t_capindex[i+1]
+ t_capindex[i+1] = temp
+ swap = 1
+ }
+ } until (swap == 0)
+end
+
+
+# TTY_FIND_CAPABILITY -- Search the caplist for the named capability.
+# If found, return the char pointer IP to the first char of the value field,
+# and YES as the function value. If the first char in the capability string
+# is '@', the capability "is not present".
+
+int procedure tty_find_capability (tty, cap, ip)
+
+pointer tty # tty descriptor
+char cap[ARB] # two character name of capability
+pointer ip # pointer to capability string
+
+int capcode, capnum
+int tty_binsearch(), tty_encode_capability()
+pointer coerce()
+errchk syserr
+
+begin
+ if (tty == NULL)
+ call syserr (SYS_TTYINVDES)
+
+ capcode = tty_encode_capability (cap)
+ capnum = tty_binsearch (capcode, T_CAPCODE(tty), T_NCAPS(tty))
+
+ if (capnum > 0) {
+ # Add 2 to skip the two capname chars.
+ ip = coerce (tty + T_OFFCAP, TY_STRUCT, TY_CHAR) +
+ T_CAPINDEX(tty+capnum-1) - 1 + 2
+ if (Memc[ip] != '@')
+ return (YES)
+ }
+
+ return (NO)
+end
+
+
+# TTY_BINSEARCH -- Perform a binary search of the capcode array for the
+# indicated capability. Return the array index of the capability if found,
+# else zero.
+
+int procedure tty_binsearch (capcode, t_capcode, ncaps)
+
+int capcode
+int t_capcode[ARB], ncaps
+int low, high, pos, ntrips
+
+begin
+ low = 1
+ high = ncaps
+ pos = 0
+
+ # Cut range of search in half until code is found, or until range
+ # vanishes (high - low <= 1). If neither high or low is the one,
+ # code is not found in the list.
+
+ do ntrips = 1, ncaps {
+ pos = (high - low) / 2 + low
+ if (t_capcode[low] == capcode)
+ return (low)
+ else if (t_capcode[high] == capcode)
+ return (high)
+ else if (pos == low) # (high-low)/2 == 0
+ return (0) # not found
+ else if (t_capcode[pos] < capcode)
+ low = pos
+ else
+ high = pos
+ }
+
+ # Search cannot fail to converge unless there is a bug in the software
+ # somewhere.
+
+ call syserr (SYS_TTYBINSRCH)
+end
+
+
+# TTY_ENCODE_CAPABILITY -- Encode the two character capability string
+# as a unique integer value.
+
+int procedure tty_encode_capability (cap)
+
+char cap[ARB]
+
+begin
+ return (ENCODE(cap))
+end
diff --git a/sys/tty/ttyinit.x b/sys/tty/ttyinit.x
new file mode 100644
index 00000000..9aeff341
--- /dev/null
+++ b/sys/tty/ttyinit.x
@@ -0,0 +1,46 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <error.h>
+include <chars.h>
+include <fset.h>
+include "tty.h"
+
+# TTYINIT -- Initialize the terminal. The termcap entry potentially contains
+# two initialization entries. The first, "is" is an initialization string
+# which is sent to the terminal. The second, "if", is the name of a file
+# containing the initialization string. If both are given, "if" is sent
+# followed by "is", however, there seems no reason to have an "is" string
+# if there is already an initialization file. The names of initialization
+# files may be either IRAF virtual filenames or host system pathnames.
+
+procedure ttyinit (fd, tty)
+
+int fd # file descriptor of terminal
+pointer tty # tty descriptor
+
+pointer sp, fname
+int in, junk, rawmode
+int ttyctrl(), ttygets(), open(), fstati()
+errchk ttygets, fcopyo
+
+begin
+ call smark (sp)
+ call salloc (fname, SZ_PATHNAME, TY_CHAR)
+
+ # Output contents of initialization file, if any.
+ if (ttygets (tty, "if", Memc[fname], SZ_PATHNAME) > 0)
+ iferr (in = open (Memc[fname], READ_ONLY, TEXT_FILE))
+ call erract (EA_WARN)
+ else {
+ rawmode = fstati (fd, F_RAW)
+ call fseti (fd, F_RAW, YES)
+ call fcopyo (in, fd)
+ call fseti (fd, F_RAW, rawmode)
+ call close (in)
+ }
+
+ # Output initialization string.
+ junk = ttyctrl (fd, tty, "is", 1)
+
+ call sfree (sp)
+end
diff --git a/sys/tty/ttyload.x b/sys/tty/ttyload.x
new file mode 100644
index 00000000..117575b8
--- /dev/null
+++ b/sys/tty/ttyload.x
@@ -0,0 +1,44 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+# TTYLOAD -- Search the database of compiled TERMCAP entries for the named
+# device, and if found, return the CAPLIST string (list of device capabilities)
+# in the output string. The number of characters output is returned as the
+# function value. The compiled database is defined by the include file
+# "cachet.dat", which serves as a cache for the TERMCAP entries of heavily
+# used devices (see TTYCOMPILE).
+#
+# N.B.: This file can serve as a template for generating TTYLOAD procedures
+# for devices other than the terminal. Change the name TTYLOAD to something
+# else, change the name of the include file, generate a different include file
+# with TTYCOMPILE, and you are in business.
+
+int procedure ttyload (fname, device, outstr, maxch)
+
+char fname[ARB] # name of termcap file being referenced
+char device[ARB] # device name as in TERMCAP entry
+char outstr[maxch] # output string to receive caplist
+int maxch
+
+int dev
+bool streq(), strne()
+int gstrcpy()
+
+include "dev$cachet.dat"
+
+begin
+ # If the name of the file being referenced is not the same as the
+ # name of the file used to build the cache, then the cache is
+ # invalidated.
+
+ if (strne (fname, sbuf[termcap_filename]))
+ return (0)
+
+ # NDEVICES, DEVNAME, DEVCAPS, and SBUF are defined and initialized
+ # in the include file.
+
+ do dev = 1, ndevices
+ if (streq (sbuf[devname[dev]], device))
+ return (gstrcpy (sbuf[devcaps[dev]], outstr, maxch))
+
+ return (0)
+end
diff --git a/sys/tty/ttyodes.x b/sys/tty/ttyodes.x
new file mode 100644
index 00000000..a01ffdca
--- /dev/null
+++ b/sys/tty/ttyodes.x
@@ -0,0 +1,183 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <error.h>
+include <syserr.h>
+include <ctype.h>
+include <chars.h>
+include "tty.h"
+
+define DEF_BAUDRATE 9600
+define DEF_TTYNLINES 24
+define DEF_TTYNCOLS 80
+
+# TTYODES -- Open a TTY terminal descriptor. If ttyname is "terminal" or
+# "printer", get the name of the default terminal or printer from the
+# environment. If the "name" of the terminal is a filename, the first termcap
+# entry in the name file is read. Otherwise, the termcap file is searched for
+# an entry corresponding to the named device.
+#
+# The descriptor is then allocated, and the termcap entry read in. Termcap
+# permits an entry to be defined in terms of another entry with the "tc"
+# field; we must expand such references by rescanning the file once for each
+# such reference. Finally, the termcap entry is indexed for efficient access.
+#
+# The form of a termcap entry is one logical line (usually extending over
+# several physical lines using newline escapes), consisting of several alternate
+# names for the device, followed by a list of ':' delimited capabilities:
+#
+# name1 '|' name2 [ '|' namen... ] ':' cap ':' [ cap ':' ... ]
+#
+# If the final cap in an entry is of the form ":tc=name:", the capability
+# is replaced by the capability list of the named entry.
+
+pointer procedure ttyodes (ttyname)
+
+char ttyname[ARB]
+
+bool istty
+int nchars
+pointer sp, ttysource, device, devname, fname, tty
+
+pointer ttyopen()
+extern ttyload()
+bool streq(), ttygetb()
+int envgets(), envgeti(), btoi()
+int fnldir(), ttygeti(), ttygets()
+errchk syserrs, tty_index_caps, ttygeti, ttyopen, ttygets
+errchk envgets, envgeti, envindir
+
+string terminal "terminal" # terminal named in environment
+string printer "printer" # printer named in environment
+string termcap "termcap" # name of termcap file stored in env. too
+
+begin
+ call smark (sp)
+ call salloc (ttysource, SZ_FNAME, TY_CHAR)
+ call salloc (devname, SZ_FNAME, TY_CHAR)
+ call salloc (device, SZ_FNAME, TY_CHAR)
+ call salloc (fname, SZ_FNAME, TY_CHAR)
+
+ # Resolve any indirection in the device name.
+ call envindir (ttyname, Memc[devname], SZ_FNAME)
+
+ # Get device name or termcap file name.
+ if (streq (Memc[devname], terminal)) {
+ if (envgets (terminal, Memc[ttysource], SZ_FNAME) <= 0)
+ call syserrs (SYS_ENVNF, terminal)
+ } else if (streq (Memc[devname], printer)) {
+ if (envgets (printer, Memc[ttysource], SZ_FNAME) <= 0)
+ call syserrs (SYS_ENVNF, printer)
+ } else
+ call strcpy (Memc[devname], Memc[ttysource], SZ_FNAME)
+
+ # If ttysource is a filename, we assume that it is the name of
+ # a termcap format file, the first entry of which (matched by the
+ # null device name) is the entry for the device. Otherwise,
+ # ttysource is the name of the desired termcap entry in the regular
+ # termcap file.
+
+ if (fnldir (Memc[ttysource], Memc[fname], SZ_FNAME) > 0) {
+ call strcpy (Memc[ttysource], Memc[fname], SZ_FNAME)
+ Memc[device] = EOS
+ } else {
+ if (envgets (termcap, Memc[fname], SZ_FNAME) <= 0)
+ call syserrs (SYS_ENVNF, termcap)
+ call strcpy (Memc[ttysource], Memc[device], SZ_FNAME)
+ }
+
+ # Truncate the device name if device fields are appended.
+ call ttydevname (Memc[device], Memc[device], SZ_FNAME)
+
+ # Allocate and initialize the tty descriptor structure and fetch
+ # termcap entry from termcap file. The TTYLOAD procedure, passed
+ # as an argument to TTYOPEN, is searched for cached termcap entries
+ # before accessing the actual file.
+
+ tty = ttyopen (Memc[fname], Memc[device], ttyload)
+
+ # Prepare index of fields in the descriptor, so that we can more
+ # efficiently search for fields later.
+
+ call tty_index_caps (tty, T_CAPCODE(tty), T_CAPINDEX(tty),
+ T_NCAPS(tty))
+
+ # Determine whether or not the terminal can backspace with BS.
+ if (ttygetb (tty, "bs"))
+ T_BSOK(tty) = YES
+ else
+ T_BSOK(tty) = NO
+
+ # Determine whether or not the stdgraph device can expand tabs.
+ # If it can but it requires some long string, don't bother.
+
+ T_HTOK(tty) = NO
+ T_TABCHAR(tty) = 0
+ if (ttygetb (tty, "pt")) {
+ nchars = ttygets (tty, "ta", Memc[fname], SZ_FNAME)
+ if (nchars <= 0) {
+ T_HTOK(tty) = YES
+ T_TABCHAR(tty) = '\t'
+ } else if (nchars == 1) {
+ T_HTOK(tty) = YES
+ T_TABCHAR(tty) = Memc[fname]
+ }
+ }
+
+ # Does the terminal autoadvance at the right margin?
+ T_AM(tty) = btoi (ttygetb (tty, "am"))
+
+ # Determine the optimimum mode for handling standout mode control,
+ # and save in the descriptor.
+
+ if (ttygetb (tty, "so")) {
+ T_SOTYPE(tty) = SOSE # use so, se
+ } else if (ttygetb (tty, "os")) {
+ if (T_BSOK(tty) == YES || ttygetb (tty, "bc"))
+ T_SOTYPE(tty) = BSOS # backspace, ostrike
+ else
+ T_SOTYPE(tty) = CROS # ostrike whole line
+ } else
+ T_SOTYPE(tty) = TOUP # to upper case
+
+ # Get pad char and baud rate (used by ttyputs to generate delays)
+ # and put in descriptor for efficient access. Also get tty screen
+ # dimensions since they are fundamental and will probably prove
+ # useful later.
+
+ T_PADCHAR(tty) = ttygeti (tty, "pc") # returns 0 if field not found
+
+ # Allow environment variables to override physical screen dimensions
+ # if device is the standard terminal.
+
+ istty = (streq (Memc[devname], terminal))
+
+ # Get nlines.
+ if (istty)
+ iferr (T_NLINES(tty) = envgeti ("ttynlines"))
+ T_NLINES(tty) = 0
+ if (T_NLINES(tty) <= 0)
+ iferr (T_NLINES(tty) = ttygeti (tty, "li"))
+ T_NLINES(tty) = 0
+ if (T_NLINES(tty) <= 0)
+ T_NLINES(tty) = DEF_TTYNLINES
+
+ # Get ncols.
+ if (istty)
+ iferr (T_NCOLS(tty) = envgeti ("ttyncols"))
+ T_NCOLS(tty) = 0
+ if (T_NCOLS(tty) <= 0)
+ iferr (T_NCOLS(tty) = ttygeti (tty, "co"))
+ T_NCOLS(tty) = 0
+ if (T_NCOLS(tty) <= 0)
+ T_NCOLS(tty) = DEF_TTYNCOLS
+
+ # Baud rate may not be right if device is a printer attached to the
+ # host, and user is working remotely. Nonetheless it is safer to pick
+ # up the value from the environment than to assume a default.
+
+ iferr (T_BAUD(tty) = envgeti ("ttybaud"))
+ T_BAUD(tty) = DEF_BAUDRATE
+
+ call sfree (sp)
+ return (tty)
+end
diff --git a/sys/tty/ttyopen.x b/sys/tty/ttyopen.x
new file mode 100644
index 00000000..07577821
--- /dev/null
+++ b/sys/tty/ttyopen.x
@@ -0,0 +1,299 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <error.h>
+include <syserr.h>
+include <ctype.h>
+include <chars.h>
+include "tty.h"
+
+# TTYOPEN -- Scan the named TERMCAP style file for the entry for the named
+# device, and if found allocate a TTY descriptor structure, leaving the
+# termcap entry for the device in the descriptor.
+
+pointer procedure ttyopen (termcap_file, device, ttyload)
+
+char termcap_file[ARB] # termcap file to be scanned
+char device[ARB] # name of device to be scanned for
+extern ttyload() # fetches pre-compiled entries from a cache
+int ttyload()
+
+int maxch, nchars
+pointer tty, sp, devname
+errchk ttyload, calloc, realloc
+
+begin
+ call smark (sp)
+ call salloc (devname, SZ_FNAME, TY_CHAR)
+
+ # Truncate the device name if device fields are appended.
+ call strcpy (device, Memc[devname], SZ_FNAME)
+ call ttydevname (Memc[devname], Memc[devname], SZ_FNAME)
+
+ # Allocate and initialize the tty descriptor structure.
+ call calloc (tty, LEN_DEFTTY, TY_STRUCT)
+
+ T_LEN(tty) = LEN_DEFTTY
+ T_OP(tty) = 1
+
+ # Call the TTYLOAD procedure to see if the TERMCAP entry for the device
+ # is in the cache of pre-compiled device entries. If not in cache,
+ # we must scan the actual termcap file.
+
+ maxch = (T_LEN(tty) - T_OFFCAP) * SZ_STRUCT
+ nchars = ttyload (termcap_file, Memc[devname], T_CAPLIST(tty), maxch)
+
+ if (nchars > 0) {
+ # Found device in cache.
+ T_OP(tty) = nchars + 1
+ T_CAPLEN(tty) = T_OP(tty)
+ } else {
+ # Must scan the source file.
+ iferr (call tty_scan_termcap_file (tty, termcap_file,
+ Memc[devname])) {
+ call mfree (tty, TY_STRUCT)
+ call erract (EA_ERROR)
+ }
+ }
+
+ # Call realloc to return any unused space in the descriptor.
+ T_LEN(tty) = T_OFFCAP + (T_OP(tty) + SZ_STRUCT-1) / SZ_STRUCT
+ call realloc (tty, T_LEN(tty), TY_STRUCT)
+
+ call sfree (sp)
+ return (tty)
+end
+
+
+# TTY_SCAN_TERMCAP_FILE -- Open and scan the named TERMCAP format database
+# file for the named device. Fetch termcap entry, expanding any and all
+# "tc" references by repeatedly rescanning file.
+
+procedure tty_scan_termcap_file (tty, termcap_file, devname)
+
+pointer tty # tty descriptor structure
+char termcap_file[ARB] # termcap format file to be scanned
+char devname[ARB] # termcap entry to be scanned for
+
+int fd, ntc
+pointer sp, device, ip, op, caplist
+int open(), strlen(), strncmp()
+pointer coerce()
+errchk open, syserrs
+
+begin
+ call smark (sp)
+ call salloc (device, SZ_FNAME, TY_CHAR)
+
+ fd = open (termcap_file, READ_ONLY, TEXT_FILE)
+ call strcpy (devname, Memc[device], SZ_FNAME)
+
+ ntc = 0
+ repeat {
+ iferr (call tty_fetch_entry (fd, Memc[device], tty)) {
+ call close (fd)
+ call erract (EA_ERROR)
+ }
+
+ # Back up to start of last field in entry.
+ caplist = coerce (tty + T_OFFCAP, TY_STRUCT, TY_CHAR)
+ ip = caplist + T_OP(tty)-1 - 2
+ while (ip > caplist && Memc[ip] != ':')
+ ip = ip - 1
+
+ # If last field is "tc", backup op so that the tc field gets
+ # overwritten with the referenced entry.
+
+ if (strncmp (Memc[ip+1], "tc", 2) == 0) {
+ # Check for recursive tc reference.
+ ntc = ntc + 1
+ if (ntc > MAX_TC_NESTING) {
+ call close (fd)
+ call syserrs (SYS_TTYTC, Memc[device])
+ }
+
+ # Set op to point to the ":" in ":tc=file".
+ T_OP(tty) = ip - caplist + 1
+
+ # Get device name from tc field, and loop again to fetch new
+ # entry.
+ ip = ip + strlen (":tc=")
+ for (op=device; Memc[ip] != EOS && Memc[ip] != ':'; ip=ip+1) {
+ Memc[op] = Memc[ip]
+ op = op + 1
+ }
+ Memc[op] = EOS
+ call seek (fd, BOFL)
+ } else
+ break
+ }
+
+ call close (fd)
+ call sfree (sp)
+end
+
+
+# TTY_FETCH_ENTRY -- Search the termcap file for the named entry, then read
+# the colon delimited capabilities list into the caplist field of the tty
+# descriptor. If the caplist field fills up, allocate more space.
+
+procedure tty_fetch_entry (fd, device, tty)
+
+int fd
+char device[ARB]
+pointer tty
+
+char ch, lastch
+pointer sp, ip, op, otop, lbuf, alias, caplist
+bool device_found, streq()
+char getc()
+int getline(), tty_extract_alias()
+pointer coerce()
+errchk getline, getc, realloc, salloc
+define errtn_ 91
+
+begin
+ call smark (sp)
+ call salloc (lbuf, SZ_LINE, TY_CHAR)
+ call salloc (alias, SZ_FNAME, TY_CHAR)
+
+ # Locate entry. First line of each termcap entry contains a list
+ # of aliases for the device. Only first lines and comment lines
+ # are left justified.
+
+ repeat {
+ # Skip comment and continuation lines and blank lines.
+ device_found = false
+
+ if (getc (fd, ch) == EOF)
+ goto errtn_
+
+ if (ch == '\n') {
+ # Skip a blank line.
+ next
+ } else if (ch == '#' || IS_WHITE (ch)) {
+ # Discard the rest of the line and continue.
+ if (getline (fd, Memc[lbuf]) == EOF)
+ goto errtn_
+ next
+ }
+
+ # Extract list of aliases. The first occurrence of ':' marks
+ # the end of the alias list and the beginning of the caplist.
+
+ Memc[lbuf] = ch
+ op = lbuf + 1
+
+ for (; getc(fd,ch) != ':'; op=op+1) {
+ Memc[op] = ch
+ if (ch == EOF || ch == '\n' || op-lbuf >= SZ_LINE) {
+ goto errtn_
+ }
+ }
+ Memc[op] = EOS
+
+ ip = lbuf
+ while (tty_extract_alias (Memc, ip, Memc[alias], SZ_FNAME) > 0) {
+ if (device[1] == EOS || streq (Memc[alias], device)) {
+ device_found = true
+ break
+ } else if (Memc[ip] == '|')
+ ip = ip + 1 # skip delimiter
+ }
+
+ # Skip rest of line if no match.
+ if (!device_found) {
+ if (getline (fd, Memc[lbuf]) == EOF) {
+ goto errtn_
+ }
+ }
+ } until (device_found)
+
+ # Caplist begins at first ':'. Each line has some whitespace at the
+ # beginning which should be skipped. Escaped newline implies
+ # continuation.
+
+ caplist = coerce (tty + T_OFFCAP, TY_STRUCT, TY_CHAR)
+ op = caplist + T_OP(tty) - 1
+ otop = coerce (tty + T_LEN(tty), TY_STRUCT, TY_CHAR) - 1
+
+ # We are already positioned to the start of the caplist.
+ Memc[op] = ':'
+ op = op + 1
+ lastch = ':'
+
+ # Extract newline terminated caplist string.
+ while (getc (fd, ch) != EOF) {
+ if (ch == '\\') { # escaped newline?
+ if (getc (fd, ch) == '\n') {
+ while (getc (fd, ch) != EOF)
+ if (!IS_WHITE(ch))
+ break
+ if (ch == EOF || ch == '\n')
+ goto errtn_
+ # Avoid null entries ("::").
+ if (ch == ':' && lastch == ':')
+ next
+ else
+ Memc[op] = ch
+ } else { # no, keep both chars
+ Memc[op] = '\\'
+ op = op + 1
+ Memc[op] = ch
+ }
+ } else if (ch == '\n') { # normal exit
+ Memc[op] = EOS
+ T_OP(tty) = op - caplist + 1
+ T_CAPLEN(tty) = T_OP(tty)
+ call sfree (sp)
+ return
+ } else
+ Memc[op] = ch
+
+ # Increase size of buffer if necessary. Note that realloc may
+ # move the buffer, so we must recalculate op and otop.
+
+ lastch = ch
+ op = op + 1
+ if (op >= otop) {
+ T_OP(tty) = op - caplist + 1
+ T_LEN(tty) = T_LEN(tty) + T_MEMINCR
+ call realloc (tty, T_LEN(tty), TY_STRUCT)
+ op = caplist + T_OP(tty) - 1
+ otop = coerce (tty + T_LEN(tty), TY_STRUCT, TY_CHAR) - 1
+ }
+ }
+
+errtn_
+ call sfree (sp)
+ call syserrs (SYS_TTYDEVNF, device)
+end
+
+
+# TTY_EXTRACT_ALIAS -- Extract a device alias string from the header of
+# a termcap entry. The alias string is terminated by '|' or ':'. Leave
+# ip pointing at the delimiter. Return number of chars in alias string.
+
+int procedure tty_extract_alias (str, ip, outstr, maxch)
+
+char str[ARB] # first line of termcap entry
+int ip # on input, first char of alias
+char outstr[ARB]
+int maxch
+
+char ch
+int op
+
+begin
+ op = 1
+ for (ch=str[ip]; ch != '|' && ch != ':' && ch != EOS; ch=str[ip]) {
+ outstr[op] = ch
+ op = min (maxch, op) + 1
+ ip = ip + 1
+ }
+ outstr[op] = EOS
+
+ if (ch == EOS)
+ return (0)
+ else
+ return (op-1)
+end
diff --git a/sys/tty/ttyputl.x b/sys/tty/ttyputl.x
new file mode 100644
index 00000000..1510168c
--- /dev/null
+++ b/sys/tty/ttyputl.x
@@ -0,0 +1,322 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ctype.h>
+include <chars.h>
+include "tty.h"
+
+.help ttyputline
+.nf ___________________________________________________________________________
+TTYPUTLINE -- Put a line to a tty device, processing any special control codes
+therein. We are concerned with formfeeds, tabs, and standout mode. Formfeeds
+are dealt with by sending the ff capability, if defined for the device (FF is
+sent if there is no ff entry). Tabs are expanded if the device does not have
+hardware tabs; if tabs are not expanded, the ta capability is sent to the device
+for each tab (HT is sent if there is no ta string).
+
+Standout mode is more complex. We distinguish between four types of devices
+for standout mode control (presented in order of desirability):
+
+ (1) [SOSE] Device has so/se. Map SO, SE chars in input stream into so/se
+ sequences.
+
+ (2) [BSOS] Device can backspace and overstrike. Backspace each printable
+ char in standout mode and overstrike with the underscore character.
+
+ (3) [CROS] Device cannot backspace, but can overstrike. Follow the output
+ line with a CR and then a line consisting only of spaces and
+ underscores.
+
+ (4) [TOUP] No conventional way to generate standout mode for device.
+ Map alpha chars to upper case to make them standout.
+
+Long lines are automatically broken at the right margin.
+.endhelp ______________________________________________________________________
+
+
+procedure ttyputline (fd, tty, text, map_cc)
+
+int fd # output file
+pointer tty # TTY descriptor
+char text[ARB] # line of text to be output
+int map_cc # enable mapping of SO, SE control chars
+
+char obuf[SZ_LINE]
+int ip, op, pos, col, maxcols, tabstop, tabchar, ch
+errchk write
+define hardcase_ 91
+
+begin
+ maxcols = min (SZ_LINE, T_NCOLS(tty))
+ tabchar = T_TABCHAR(tty)
+ pos = 1
+ col = 1
+ op = 1
+
+ # Optimize the special case of a line less than the maximum length
+ # which contains no special control characters. As long as this is
+ # handled efficiently, the rest doesn't matter.
+
+ for (pos=1; text[pos] != EOS; pos=pos+1) {
+ do ip = pos, ARB {
+ ch = text[ip]
+
+ if (ch >= ' ') {
+ # Ordinary printable character; the most common case.
+ obuf[op] = ch
+ op = op + 1
+ col = col + 1
+
+ # If col > maxcols then we have completely filled the
+ # output line. If there is more text to come we must
+ # break the line. If the next character is newline we
+ # may also break the line and discard the newline.
+
+ if (col > maxcols && text[ip+1] != EOS) {
+ if (T_AM(tty) == NO) {
+ obuf[op] = '\n'
+ op = op + 1
+ }
+ pos = ip
+ if (text[ip+1] == '\n')
+ pos = pos + 1
+ break
+ }
+
+ } else if (ch == '\n') {
+ # End of line.
+ obuf[op] = ch
+ op = op + 1
+ pos = ip
+ break
+
+ } else if (ch == '\t') {
+ # Tab.
+ tabstop = min (maxcols, ((col-1) / 8 + 1) * 8 + 1)
+ if (tabchar != 0) {
+ obuf[op] = tabchar
+ op = op + 1
+ col = tabstop
+ } else {
+ while (col < tabstop) {
+ obuf[op] = ' '
+ op = op + 1
+ col = col + 1
+ }
+ }
+
+ } else if (ch == EOS) {
+ pos = ip - 1
+ break
+
+ } else
+ goto hardcase_
+ }
+
+ if (op > 1)
+ call write (fd, obuf, op - 1)
+
+ op = 1
+ col = 1
+ }
+
+ return
+
+hardcase_
+ # Special processsing is needed.
+ call ttygputline (fd, tty, text, map_cc)
+end
+
+
+# TTYGPUTLINE -- This is the original ttypuline. The code is not very
+# efficient, but it handles formfeeds, standout mode, etc. in a generalized
+# fashion.
+
+procedure ttygputline (fd, tty, text, map_cc)
+
+int fd # output file
+pointer tty # TTY descriptor
+char text[ARB] # line of text to be output
+int map_cc # enable mapping of SO, SE control chars
+
+pointer sp, ostrike, op
+bool so_seen, so_mode_in_effect
+int ip, so_type, ocol, junk, ch, tabchar
+int ttyctrl()
+errchk tty_break_line, putci, ttyctrl, ttyso
+
+begin
+ call smark (sp)
+ call salloc (ostrike, SZ_LINE, TY_CHAR)
+
+ so_mode_in_effect = false
+ so_type = T_SOTYPE(tty)
+ tabchar = T_TABCHAR(tty)
+ so_seen = false
+ ocol = 1
+ op = ostrike
+
+ # Process the input line, mapping all known sequences. Other control
+ # chars are passed on without modification. The input line should be
+ # an entire line, or CROS mode will not work correctly. Lines longer
+ # than T_NCOLS are broken at the right margin.
+
+ for (ip=1; text[ip] != EOS; ip=ip+1) {
+ ch = text[ip]
+
+ # Break line if newline seen or at right margin.
+ if (ch == '\n' || ocol > T_NCOLS(tty)) {
+ call tty_break_line (fd, tty, ostrike, op, so_type, so_seen)
+ so_mode_in_effect = false
+ ocol = 1
+
+ # Output a newline if short line or the terminal does not
+ # have automargins.
+
+ if (ocol < T_NCOLS(tty) || T_AM(tty) == NO)
+ call putci (fd, '\n')
+
+ # Fall through and output ch if ch was not newline.
+ if (ch == '\n')
+ next
+ }
+
+ # Deal with common printable characters. If standout mode is
+ # in effect, we must take special actions to make the char
+ # stand out if the terminal does not have the so/se capability.
+ # Note that blanks may be made to standout; if this is not
+ # desired, the high level code must turn standout mode on and off.
+
+ if (ch >= BLANK) {
+ if (so_type != SOSE)
+ switch (so_type) {
+ case BSOS:
+ if (so_mode_in_effect) {
+ call putci (fd, '_')
+ if (T_BSOK(tty) == YES)
+ call putci (fd, BS)
+ else
+ junk = ttyctrl (fd, tty, "bc", 1)
+ }
+ case CROS:
+ if (so_mode_in_effect)
+ Memc[op] = '_'
+ else
+ Memc[op] = BLANK
+ op = op + 1
+ case TOUP:
+ if (so_mode_in_effect && IS_LOWER(ch))
+ ch = TO_UPPER (ch)
+ }
+
+ call putci (fd, ch)
+ ocol = ocol + 1
+ next
+ }
+
+ # We get here only if the character is a control character.
+
+ if (ch == '\t') {
+ # If hardware tab expansion is enabled, use that, otherwise
+ # wait and put out blanks in next block of code.
+
+ if (T_HTOK(tty) == YES) {
+ call putci (fd, tabchar)
+ if (so_type == CROS) {
+ Memc[op] = '\t'
+ op = op + 1
+ }
+ }
+
+ # Keep track of virtual output column, also output blanks to
+ # expand tab if hardware expansion is disabled.
+
+ repeat {
+ if (T_HTOK(tty) != YES) {
+ call putci (fd, BLANK)
+ if (so_type == CROS) {
+ Memc[op] = BLANK
+ op = op + 1
+ }
+ }
+ ocol = ocol + 1
+ } until (mod (ocol+TABSIZE-1, TABSIZE) == 0)
+
+ } else if (ch == FF) {
+ # Formfeed breaks the output line if not at beginning of a
+ # line.
+
+ if (ocol > 1) {
+ call tty_break_line (fd, tty, ostrike, op, so_type, so_seen)
+ if (ocol < T_NCOLS(tty) || T_AM(tty) == NO)
+ call putci (fd, '\n')
+ }
+ if (ttyctrl (fd, tty, "ff", T_NLINES(tty)) == ERR)
+ call putci (fd, FF)
+ ocol = 1
+ so_mode_in_effect = false
+
+ } else if (ch == SO_ON) {
+ # Begin standout mode.
+ if (so_type == SOSE)
+ call ttyso (fd, tty, YES)
+ so_mode_in_effect = true
+ so_seen = true
+
+ } else if (ch == SO_OFF) {
+ # End standout mode.
+ if (so_type == SOSE)
+ call ttyso (fd, tty, NO)
+ so_mode_in_effect = false
+
+ } else {
+ # Unknown control character. Do not increment ocol.
+ if (map_cc == YES) {
+ call putci (fd, '^')
+ call putci (fd, ch + 'A' - 1)
+ } else
+ call putci (fd, ch)
+ }
+ }
+
+ # If EOS is seen, but not newline, do not issue a newline, but do
+ # ignore contents of overstrike buffer. Thus, we can be used to output
+ # portions of a line on non-CROS terminals.
+
+ call sfree (sp)
+end
+
+
+# TTY_BREAK_LINE -- Break the output line. If overstrike is selected,
+# overstrike output line with the ostrike line. We assume that OP is
+# valid only if so_type is CROS. Note that OP and SO_SEEN are reset.
+
+procedure tty_break_line (fd, tty, ostrike, op, so_type, so_seen)
+
+int fd
+pointer tty, ostrike, op
+int so_type
+bool so_seen
+
+int ch
+pointer ip
+
+begin
+ # If carriage return, overstrike is enabled and the line had a standout
+ # mode directive, output the overstrike line.
+
+ if (so_type == CROS && so_seen) {
+ call putci (fd, '\r')
+ Memc[op] = EOS
+
+ # Output overstrike line.
+ for (ip=ostrike; Memc[ip] != EOS; ip=ip+1) {
+ ch = Memc[ip]
+ if (ch == '\t')
+ ch = T_TABCHAR(tty)
+ call putci (fd, ch)
+ }
+ }
+
+ op = ostrike
+ so_seen = false
+end
diff --git a/sys/tty/ttyputs.x b/sys/tty/ttyputs.x
new file mode 100644
index 00000000..aeec99ef
--- /dev/null
+++ b/sys/tty/ttyputs.x
@@ -0,0 +1,15 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+# TTYPUTS -- Put an EOS delimited control string to the output file.
+
+procedure ttyputs (fd, tty, ctrlstr, afflncnt)
+
+int fd # output file
+pointer tty # terminal descriptor
+char ctrlstr[ARB] # control sequence to be output
+int afflncnt # number of lines affected
+int strlen()
+
+begin
+ call ttywrite (fd, tty, ctrlstr, strlen(ctrlstr), afflncnt)
+end
diff --git a/sys/tty/ttyread.x b/sys/tty/ttyread.x
new file mode 100644
index 00000000..7ead64a3
--- /dev/null
+++ b/sys/tty/ttyread.x
@@ -0,0 +1,102 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <chars.h>
+include <fset.h>
+
+define PAUSE 20 # pause if no data, msec
+
+
+# TTYREAD -- Read from the terminal in raw mode until sufficient data is
+# accumulated to match the given encoded pattern. Any additional data read
+# prior to the matched pattern (normally due to type-ahead) is pushed back
+# into the input stream. If timeout > 0 nonblocking reads are used, and
+# the operation will time out if the pattern is not matched within the given
+# interval in milliseconds. A valid read returns nchars > 0 indicating the
+# length of the matched pattern; 0 is returned for a timeout and ERR for a
+# garbled read.
+
+int procedure ttyread (fd, tty, outbuf, maxch, patbuf, timeout)
+
+int fd # output file
+pointer tty # terminal descriptor
+char outbuf[maxch] # output data buffer
+int maxch # max chars out
+char patbuf[ARB] # encoded pattern
+int timeout # timeout interval, msec (0 for no timeout)
+
+bool match
+pointer sp, ip, op, buf
+int sv_iomode, iomode, delay, first, last, nchars, ch
+int fstati(), patmatch(), gpatmatch(), getci(), gstrcpy()
+errchk getci, unread
+define abort_ 91
+
+begin
+ call smark (sp)
+ call salloc (buf, SZ_LINE, TY_CHAR)
+
+ # Save raw mode state and set up for nonblocking raw mode reads
+ # if a timeout interval was specified.
+
+ iomode = IO_RAW
+ if (timeout > 0)
+ iomode = iomode + IO_NDELAY
+
+ sv_iomode = fstati (fd, F_IOMODE)
+ if (sv_iomode != iomode)
+ call fseti (fd, F_IOMODE, iomode)
+
+ outbuf[1] = EOS
+ match = false
+ nchars = 0
+ delay = 0
+ op = buf
+
+ # Accumulate input characters in nonblocking raw mode until either
+ # the given pattern is matched, or we timeout.
+
+ repeat {
+ # Read characters until the full sequence has been input or no
+ # more data is available.
+
+ while (!match && (op-buf < SZ_LINE) && getci(fd, ch) != EOF) {
+ if (ch==INTCHAR || ch==EOFCHAR || ch == '\r' || ch == '\n') {
+ nchars = ERR
+ goto abort_
+ }
+
+ Memc[op] = ch; op = op + 1
+ Memc[op] = EOS
+ match = (gpatmatch (Memc[buf], patbuf, first, last) > 0)
+
+ if (match) {
+ ip = buf + first - 1
+ if (first > 1) {
+ # Put back any input typed before our data block.
+ call unread (fd, Memc[buf], first-1)
+
+ # Redo the match to correct index marks for string
+ # offset.
+ match = (patmatch (Memc[ip], patbuf) > 0)
+ }
+ nchars = gstrcpy (Memc[ip], outbuf, maxch)
+ }
+ }
+
+ # If the nonblocking read returns EOF, indicating no input was
+ # queued, wait a bit and try again.
+
+ if (!match && ch == EOF) {
+ call zwmsec (PAUSE)
+ delay = delay + PAUSE
+ }
+ } until (match || delay > timeout)
+
+abort_
+ # Restore previous raw mode state.
+ if (sv_iomode != iomode)
+ call fseti (fd, F_IOMODE, sv_iomode)
+
+ call sfree (sp)
+ return (nchars)
+end
diff --git a/sys/tty/ttyseti.x b/sys/tty/ttyseti.x
new file mode 100644
index 00000000..18493766
--- /dev/null
+++ b/sys/tty/ttyseti.x
@@ -0,0 +1,36 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <syserr.h>
+include <chars.h>
+include <ttyset.h>
+include "tty.h"
+
+# TTYSETI -- Set a TTY parameter. Can be used after a ttyodes to override
+# termcap and environment parameters affecting terminal control.
+
+procedure ttyseti (tty, parameter, value)
+
+pointer tty
+int parameter, value
+char parnum[3]
+int junk, itoc()
+
+begin
+ switch (parameter) {
+ case TTY_PADCHAR:
+ T_PADCHAR(tty) = value
+ case TTY_TABS:
+ T_HTOK(tty) = value
+ case TTY_SOTYPE:
+ T_SOTYPE(tty) = value
+ case TTY_BAUD:
+ T_BAUD(tty) = value
+ case TTY_NLINES:
+ T_NLINES(tty) = value
+ case TTY_NCOLS:
+ T_NCOLS(tty) = value
+ default:
+ junk = itoc (parameter, parnum, 3)
+ call syserrs (SYS_TTYSET, parnum)
+ }
+end
diff --git a/sys/tty/ttyso.x b/sys/tty/ttyso.x
new file mode 100644
index 00000000..e03de838
--- /dev/null
+++ b/sys/tty/ttyso.x
@@ -0,0 +1,32 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+# TTYSO -- Turn "standout" mode on or off.
+
+procedure ttyso (fd, tty, onflag)
+
+int fd, onflag
+pointer tty
+
+char cap[2]
+bool ttygetb()
+int junk, ttyctrl()
+errchk ttygetb
+
+begin
+ # Select name of capability (so, se, us, ue). Use so/se if it is
+ # available for the terminal, otherwise try us/ue.
+ if (ttygetb (tty, "so")) {
+ cap[1] = 's'
+ cap[2] = 'o'
+ } else {
+ cap[1] = 'u'
+ cap[2] = 's'
+ }
+ if (onflag == NO)
+ cap[2] = 'e'
+ cap[3] = EOS
+
+ # Output the control sequence. If cap is not available for the
+ # terminal, nothing will be output.
+ junk = ttyctrl (fd, tty, cap, 1)
+end
diff --git a/sys/tty/ttystati.x b/sys/tty/ttystati.x
new file mode 100644
index 00000000..52578fba
--- /dev/null
+++ b/sys/tty/ttystati.x
@@ -0,0 +1,37 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <syserr.h>
+include <chars.h>
+include <ttyset.h>
+include "tty.h"
+
+# TTYSTATI -- Fetch a TTY parameter.
+
+int procedure ttystati (tty, parameter)
+
+pointer tty
+int parameter
+char parnum[3]
+int value, junk, itoc()
+
+begin
+ switch (parameter) {
+ case TTY_PADCHAR:
+ value = T_PADCHAR(tty)
+ case TTY_TABS:
+ value = T_HTOK(tty)
+ case TTY_SOTYPE:
+ value = T_SOTYPE(tty)
+ case TTY_BAUD:
+ value = T_BAUD(tty)
+ case TTY_NLINES:
+ value = T_NLINES(tty)
+ case TTY_NCOLS:
+ value = T_NCOLS(tty)
+ default:
+ junk = itoc (parameter, parnum, 3)
+ call syserrs (SYS_TTYSTAT, parnum)
+ }
+
+ return (value)
+end
diff --git a/sys/tty/ttysubi.x b/sys/tty/ttysubi.x
new file mode 100644
index 00000000..870dce59
--- /dev/null
+++ b/sys/tty/ttysubi.x
@@ -0,0 +1,194 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <chars.h>
+include <ctype.h>
+include "tty.h"
+
+.help ttysubi
+.nf ___________________________________________________________________________
+TTYSUBI -- Argument substitution on a control string.
+
+ Process a capability string containing arguments. Examples of such
+capability strings are cursor motion to [x,y], and set scrolling region to
+[line1,line2]. Note that arguments in the termcap database are zero-indexed
+by default, while the TTYSUBI arguments are one-indexed. The control string
+given as input has already been processed to reduce all escape sequences to
+single characters.
+
+Various output formats are supported (some of these are completely off the
+wall, very special case, but that's how termcap does it):
+
+ %d print decimal integer, zero origin.
+ %2 like %2d.
+ %3 like %3d.
+ %. put binary value of x,y arg as a character
+ %+x like %., but add value of char X first
+ %% print a single %.
+
+The following format codes affect the arguments, but do not directly cause
+any output:
+
+ %>xy if next arg value > char x add char y.
+ %r reverses order of arguments.
+ %i increments arg values by one, for 1 origin.
+ %n exlusive-or args with 0140B. (DM2500)
+ %B BCD next arg, (16*(x/10))+(mod(x,10).
+ %D Reverse coding (x-2*(mod(x,16))). (Delta Data)
+
+We have generalized the termcap formats somewhat to permit a greater range
+of %n formats (%1-%4), as well as %o and %x formats, in case a terminal
+comes along which likes octal or hex numbers.
+
+The %. format causes special problems. If the terminal requires coordinates
+in binary in the range zero or one to 40B, we can expect problems trying to
+push such chars through the OS driver and any other software (networks, etc.),
+since system software likes to map control characters on output. To get around
+this we have defined a set of reserved codes which are not to be generated.
+This set is defined in tty.h, and includes newline, tab, etc. When asked to
+output one of these chars, we output a char with a somewhat larger value
+and return the delta to our caller, which does whatever is appropriate to
+complete the function.
+.endhelp ______________________________________________________________________
+
+int procedure ttysubi (ctrlstr, outstr, maxch, coords, ncoords)
+
+char ctrlstr[ARB] # control string containing % formats
+char outstr[ARB] # receives processed string
+int maxch
+int coords[ncoords] # on input, coords; on output, deltas
+int ncoords
+
+bool reverse # reverse deltas on output
+int revstart # first arg/coord reversed
+int args[MAX_COORDS] # processed values of arguments
+int argnum # arg being processed
+int nargs # number of args (min(MAX_COORDS,ncoords))
+char driver_chars[NDCHARS]
+char ch, format_char
+int i, ip, op, field_width, left, right, temp
+int stridx(), strlen(), xor()
+data driver_chars /DRIVER_CHARS/
+errchk sprintf, pargi
+
+begin
+ # Make a local copy of the arguments to make reversal etc. easy.
+ # Also switch to zero-indexing internally, since the termcap entry
+ # is zero-indexed.
+
+ nargs = min (MAX_COORDS, ncoords)
+ do i = 1, nargs {
+ args[i] = coords[i] - 1 # make zero-indexed
+ coords[i] = 0 # init delta
+ }
+ argnum = 1 # output x first by default
+ reverse = false
+
+ op = 1
+ for (ip=1; ctrlstr[ip] != EOS && op <= maxch; ip=ip+1) {
+ ch = ctrlstr[ip]
+
+ # If normal char, we do not get past this if statement.
+ if (ch != '%') {
+ outstr[op] = ch
+ op = op + 1
+ next
+ } else {
+ ip = ip + 1 # fetch format-type char
+ ch = ctrlstr[ip]
+ }
+
+ # Get here only if processing a %x format specification.
+ switch (ch) {
+ case '%': # %% --> %
+ outstr[op] = ch
+ op = op + 1
+
+ case 'd', 'o', 'x', '1', '2', '3', '4':
+ # Output next argument according to the format given.
+ if (IS_DIGIT(ch)) {
+ field_width = TO_INTEG(ch)
+ format_char = 'd'
+ } else {
+ field_width = 0
+ format_char = ch
+ }
+
+ call sprintf (outstr[op], maxch-op+1, "%0*.0*")
+ call pargi (field_width)
+ call pargc (format_char)
+ call pargi (args[argnum])
+
+ argnum = min (nargs, argnum + 1)
+ op = op + strlen (outstr[op])
+
+ case '.', '+':
+ # Binary output format. Coordinate output in binary is a
+ # problem because the OS driver may see a tab, newline, or
+ # whatever and map it into something else. If the value of
+ # args[argnum] corresponds to a special control character,
+ # we increment it until we have an acceptable value, leaving
+ # it up to our caller to do the rest.
+
+ if (ch == '+') {
+ ip = ip + 1
+ args[argnum] = args[argnum] + ctrlstr[ip]
+ }
+
+ repeat {
+ ch = char (args[argnum])
+ if (stridx (ch, driver_chars) > 0) {
+ args[argnum] = args[argnum] + 1
+ coords[argnum] = coords[argnum] + 1
+ } else
+ break
+ }
+
+ outstr[op] = args[argnum]
+ op = op + 1
+ argnum = min (nargs, argnum + 1)
+
+ # The remaining cases are used to change the values of the
+ # remaining arguments, and do not cause any output.
+
+ case '>': # %>xy
+ if (args[argnum] > ctrlstr[ip+1])
+ args[argnum] = args[argnum] + ctrlstr[ip+2]
+ ip = ip + 2
+ case 'r': # swap remaining args
+ do left = argnum, (nargs - argnum + 1) / 2 {
+ right = nargs - (left - argnum)
+ temp = args[left]
+ args[left] = args[right]
+ args[right] = temp
+ }
+ reverse = !reverse
+ revstart = argnum
+ case 'i': # increment by one
+ do i = argnum, nargs
+ args[i] = args[i] + 1
+ case 'n': # exclusive or with 140B
+ do i = argnum, nargs
+ args[i] = xor (args[i], 140B)
+ case 'B': # BCD encode next arg
+ temp = args[argnum]
+ args[argnum] = 16 * (temp / 10) + mod (temp, 10)
+ case 'D': # Reverse code next arg
+ temp = args[argnum]
+ args[argnum] = temp - 2 * mod (temp, 16)
+ }
+ }
+
+ # If the input coordinates were reversed, we must reverse the
+ # correction deltas, too.
+
+ if (reverse)
+ do left = revstart, (nargs - revstart + 1) / 2 {
+ right = nargs - (left - revstart)
+ temp = coords[left]
+ coords[left] = coords[right]
+ coords[right] = temp
+ }
+
+ outstr[op] = EOS
+ return (op - 1)
+end
diff --git a/sys/tty/ttywrite.x b/sys/tty/ttywrite.x
new file mode 100644
index 00000000..3a581523
--- /dev/null
+++ b/sys/tty/ttywrite.x
@@ -0,0 +1,60 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ctype.h>
+include <chars.h>
+include "tty.h"
+
+# TTYWRITE -- Put a counted control string to the output file. The control
+# string consists of an optional prefix specifying the delay required, followed
+# by the chars to be sent to the terminal. If the delay is given as a simple
+# integer number (i.e., ":cl=50\E"), it specifies the delay in milliseconds.
+# If the delay number is followed by an asterisk (i.e., ":cd=3.5*\E^C:") it
+# specifies the delay in milliseconds per line affected by the operation.
+# In the latter case, the AFFLNCNT argument is used to compute the total
+# delay. Delays are generated by writing a sequence of pad characters
+# (usually NUL); the number of pad chars sent to achieve a particular delay
+# depends on the baud rate.
+
+procedure ttywrite (fd, tty, ctrlstr, nchars, afflncnt)
+
+int fd # output file
+pointer tty # terminal descriptor
+char ctrlstr[ARB] # control sequence to be output
+int nchars # nchars in control string
+int afflncnt # number of lines affected
+
+double dval
+int ip, delay, junk, ch
+int ctod(), and()
+errchk putci
+
+begin
+ # Determine number of milliseconds of delay req'd, and position ip
+ # to start of control string. Do not use CTOD to test whether or not
+ # the string begins with a number, because it is not permissable to
+ # skip whitespace (blank and tab are legal output chars).
+
+ ip = 1
+ if (IS_DIGIT (ctrlstr[ip])) {
+ junk = ctod (ctrlstr, ip, dval)
+ if (ctrlstr[ip] == '*') {
+ delay = dval * afflncnt + 0.5
+ ip = ip + 1
+ } else
+ delay = dval
+ } else
+ delay = 0
+
+ # Output the control sequence, passing only the first seven bits of
+ # each character. This is where the \200 escapes get turned into NULs.
+ # Do not use MOD to do the masking because 200B is a negative integer
+ # if CHAR is implemented as 8 bits.
+
+ for (; ip <= nchars; ip=ip+1) {
+ ch = ctrlstr[ip]
+ call putci (fd, and (ch, 177B))
+ }
+
+ # Add padding if needed to generate delay.
+ call ttydelay (fd, tty, delay)
+end
diff --git a/sys/tty/x_mkttydata.x b/sys/tty/x_mkttydata.x
new file mode 100644
index 00000000..a48cbca8
--- /dev/null
+++ b/sys/tty/x_mkttydata.x
@@ -0,0 +1,367 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <error.h>
+include <syserr.h>
+include "tty.h"
+
+task mkttydata = t_mkttydata
+
+.help mkttydata
+.nf -------------------------------------------------------------------------
+MKTTYDATA -- System Manager's program to compile the TERMCAP entries for a
+list of terminals. Output is an SPP format include file to be used in TTYLOAD
+to statically declare and initialize the TERMCAP entries for the named
+devices, eliminating the need to scan the TERMCAP file for those devices.
+
+Compilation of selected termcap entries to speed up accesses to the
+termcap database for frequently referenced terminals. We read and preprocess
+the entries for the named terminals from the termcap file, producing the source
+code for the TTYLOAD procedure as output. The termcap entry for each device
+is included in the source for TTYLOAD as a static data structure. TTYLOAD is
+subsequently compiled and placed in the library with the other TTY routines.
+At run time, TTYODES first tries to load the termcap database entry using
+TTYLOAD, and if that fails it goes and reads the termcap file.
+
+N.B.: The TTY interface may be used for any termcap format file, regardless
+of whether or not the database describes terminals.
+.endhelp ---------------------------------------------------------------------
+
+# Tunable parameters.
+
+define MAX_DEVICES 25 # initial max termcap entries
+define INC_DEVICES 25 # increment if overflow occurs
+define SZ_SBUF 4096 # initial size of string buffer
+define INC_SZSBUF 2048 # increment if overflow occurs
+define NI_PERLINE 5 # number of datastmt ints per line
+define NC_PERLINE 8 # number of datastmt chars per line
+
+# Device descriptor structure (contains the extracted termcap entries).
+# There are no upper limits on the number of devices or upon the sizes of
+# any of the substructures.
+
+define LEN_TCSTRUCT 8
+
+define TC_NDEVICES Memi[$1] # number of termcap entries
+define TC_MAXDEVICES Memi[$1+1] # initial max termcap entries
+define TC_DEVNAME_P Memi[$1+2] # pointer to devname index array
+define TC_CAPLIST_P Memi[$1+3] # pointer to caplist index array
+define TC_SBUF Memi[$1+4] # pointer to string buffer
+define TC_SZSBUF Memi[$1+5] # current size of string buffer
+define TC_NEXTCH Memi[$1+6] # offset of next avail char in sbuf
+define TC_TCFNAME Memi[$1+7] # name of termcap file
+
+define TC_DEVNAME Memi[TC_DEVNAME_P($1)+$2-1]
+define TC_CAPLIST Memi[TC_CAPLIST_P($1)+$2-1]
+
+# MKTTYDATA -- Given the name of a termcap format file and a list of device
+# names, call TTYOPEN to fetch the termcap entry of the device.
+# Move the entry for the device into the dev structure and continue until
+# the entries for all devices have been read. Write out the source code for
+# the data structures of these devices. This output file is "included"
+# when TTYLOAD is later compiled, cacheing the termcap entries for the
+# named devices in memory.
+
+procedure t_mkttydata()
+
+bool verbose
+int devlist, fd, ndev, buflen
+pointer sp, termcap_file, output_file, devname, tc, tty
+bool clgetb()
+int clpopnu(), clgfil(), tc_putstr(), open(), tc_dummy_ttyload()
+pointer ttyopen()
+extern tc_dummy_ttyload()
+errchk open, tc_write_data_declarations, clgfil, tc_putstr, malloc, realloc
+
+begin
+ call smark (sp)
+ call salloc (termcap_file, SZ_FNAME, TY_CHAR)
+ call salloc (output_file, SZ_FNAME, TY_CHAR)
+ call salloc (devname, SZ_FNAME, TY_CHAR)
+ call salloc (tc, LEN_TCSTRUCT, TY_STRUCT)
+
+ # Open the list of devices to be compiled into the cache. CLGFIL is
+ # useful for reading the list even though the list elements are not
+ # filenames, because it can expand comma a delimited list passed as
+ # a string as well as read from a list file. The list is not sorted
+ # so that the caller can order the devices in the order in which they
+ # will most frequently be referenced (though really it matters little).
+ # Get the names of the input and output files.
+
+ devlist = clpopnu ("devlist")
+ call clgstr ("termcap_file", Memc[termcap_file], SZ_FNAME)
+ call clgstr ("output_file", Memc[output_file], SZ_FNAME)
+ verbose = clgetb ("verbose")
+
+ # Initialize the TC descriptor structure. Allocate the variable sized
+ # buffers.
+
+ ndev = 0
+ buflen = MAX_DEVICES
+
+ TC_NDEVICES(tc) = 0
+ TC_MAXDEVICES(tc) = MAX_DEVICES
+ TC_SZSBUF(tc) = SZ_SBUF
+ TC_NEXTCH(tc) = 0
+
+ iferr {
+ call malloc (TC_DEVNAME_P(tc), buflen, TY_INT)
+ call malloc (TC_CAPLIST_P(tc), buflen, TY_INT)
+ call malloc (TC_SBUF(tc), SZ_SBUF, TY_CHAR)
+ } then
+ call erract (EA_FATAL)
+
+ # Store the name of the termcap file in the descriptor. The descriptor
+ # is only valid if TTYLOAD is called with the exact same filename.
+
+ TC_TCFNAME(tc) = tc_putstr (tc, Memc[termcap_file])
+
+ # Fetch the termcap entry for each device in the list. This is not
+ # done very efficiently, but it does not matter since this program
+ # is infrequently run. Accumulate the entries in the TC structure.
+
+ while (clgfil (devlist, Memc[devname], SZ_FNAME) != EOF) {
+ # Fetch entry from termcap file.
+
+ iferr (tty = ttyopen (Memc[termcap_file], Memc[devname],
+ tc_dummy_ttyload)) {
+
+ call erract (EA_WARN)
+ next
+
+ } else if (verbose) {
+ call eprintf ("%4d %s: %d chars\n")
+ call pargi (ndev + 1)
+ call pargstr (Memc[devname])
+ call pargi (T_CAPLEN(tty))
+ }
+
+ ndev = ndev + 1
+ TC_NDEVICES(tc) = ndev
+
+ # Make room for more devices if necessary.
+ if (ndev > TC_MAXDEVICES(tc)) {
+ TC_MAXDEVICES(tc) = TC_MAXDEVICES(tc) + INC_DEVICES
+ buflen = TC_MAXDEVICES(tc)
+ iferr {
+ call realloc (TC_DEVNAME_P(tc), buflen, TY_INT)
+ call realloc (TC_CAPLIST_P(tc), buflen, TY_INT)
+ } then
+ call erract (EA_FATAL)
+ }
+
+ # Add entry to descriptor.
+ TC_DEVNAME(tc,ndev) = tc_putstr (tc, Memc[devname])
+ TC_CAPLIST(tc,ndev) = tc_putstr (tc, T_CAPLIST(tty))
+
+ call ttyclose (tty)
+ }
+
+ call clpcls (devlist)
+
+ # Write the output file (an SPP "include" file) containing data
+ # declarations for the data structures in the TC structure.
+
+ iferr (call delete (Memc[output_file]))
+ ;
+ fd = open (Memc[output_file], NEW_FILE, TEXT_FILE)
+ call tc_write_data_declarations (fd, tc, Memc[termcap_file])
+ call close (fd)
+
+ call mfree (TC_DEVNAME_P(tc), TY_INT)
+ call mfree (TC_CAPLIST_P(tc), TY_INT)
+ call mfree (TC_SBUF(tc), TY_CHAR)
+ call sfree (sp)
+end
+
+
+# TC_PUTSTR -- Put a string (incl EOS) in the string buffer at nextch.
+# If there is not enough space in the buffer, reallocate a larger buffer.
+# Return the index of the string in the string buffer.
+
+int procedure tc_putstr (tc, str)
+
+pointer tc
+char str[ARB]
+int nextch, nchars, strlen()
+errchk realloc
+
+begin
+ # Null strings are not stored and cause a null index to be returned.
+ nchars = strlen (str)
+ if (nchars == 0)
+ return (0)
+
+ nextch = TC_NEXTCH(tc)
+ if (nextch + nchars + 1 > TC_SZSBUF(tc)) {
+ TC_SZSBUF(tc) = TC_SZSBUF(tc) + INC_SZSBUF
+ call realloc (TC_SBUF(tc), TC_SZSBUF(tc), TY_CHAR)
+ }
+
+ call strcpy (str, Memc[TC_SBUF(tc) + nextch], ARB)
+ TC_NEXTCH(tc) = nextch + nchars + 1
+
+ return (nextch)
+end
+
+
+# TC_WRITE_DATA_DECLARATIONS -- Write the SPP data declarations required to
+# declare and initialize the following data structures:
+#
+# int ndevices # number of devices in cache
+# int devname[] # 0-indexed offset into sbuf of device name
+# int devcaps[] # 0-indexed offset into sbuf of termcap entry
+# char sbuf[] # string buffer
+
+procedure tc_write_data_declarations (fd, tc, termcap_file)
+
+int fd # output file
+pointer tc # TC descriptor
+char termcap_file[ARB] # name of source file
+
+int ndevices, dev
+pointer sbuf
+int strlen()
+
+begin
+ ndevices = TC_NDEVICES(tc)
+ sbuf = TC_SBUF(tc)
+
+ # Write a comments section naming the devices represented by the
+ # data declarations which follow.
+
+ call fprintf (fd,
+ "# TERMCAP data declarations for %d devices from '%s'\n")
+ call pargi (TC_NDEVICES(tc))
+ call pargstr (termcap_file)
+
+ do dev = 1, ndevices {
+ call fprintf (fd, "#%15s (size %d+1 chars)\n")
+ call pargstr (Memc[sbuf+TC_DEVNAME(tc,dev)])
+ call pargi (strlen (Memc[sbuf+TC_CAPLIST(tc,dev)]))
+ }
+
+ # Output the object declarations.
+
+ call fprintf (fd, "\n")
+ call fprintf (fd, "int\ttermcap_filename, ndevices, i\n")
+ call fprintf (fd, "int\tdevname[%d], devcaps[%d]\n")
+ call pargi (ndevices)
+ call pargi (ndevices)
+
+ # Do not add 1 char for the EOS; SPP compiler automatically does so.
+ call fprintf (fd, "char\tsbuf[%d]\n")
+ call pargi (TC_NEXTCH(tc))
+
+ # Output the data initialization declarations.
+
+ call fprintf (fd, "\n")
+ call fprintf (fd, "data\tndevices /%d/\n")
+ call pargi (ndevices)
+ call fprintf (fd, "data\ttermcap_filename /%d/\n")
+ call pargi (TC_TCFNAME(tc) + 1)
+
+ call tc_init_datai (fd, "devname", Memi[TC_DEVNAME_P(tc)], ndevices)
+ call tc_init_datai (fd, "devcaps", Memi[TC_CAPLIST_P(tc)], ndevices)
+ call fprintf (fd, "\n")
+ call tc_init_datac (fd, "sbuf", Memc[TC_SBUF(tc)], TC_NEXTCH(tc)+1)
+end
+
+
+# TC_INIT_DATAI -- Write a series of data statements to initialize an
+# integer array. A single large statement is not used due to variation
+# in the permissible number of continuation statements permitted by
+# different compilers.
+
+procedure tc_init_datai (fd, varname, array, npix)
+
+int fd # output file
+char varname[ARB] # name of variable to be initialized
+int array[npix] # array values
+int npix
+
+int i, j, i1, i2
+
+begin
+ for (j=1; j <= npix; j = j + NI_PERLINE) {
+ i1 = j
+ i2 = min (j + NI_PERLINE - 1, npix)
+
+ # Begin new data statement.
+ call fprintf (fd, "data\t(%s(i),i=%2d,%2d)\t/")
+ call pargstr (varname)
+ call pargi (i1)
+ call pargi (i2)
+
+ # Output data values. NOTE: the TC_SBUF offsets are zero-indexed
+ # offsets into Mem, but the SBUF array in the include file is a
+ # static Fortran array which requires 1-indexed offsets, so we
+ # add one before writing out the offsets.
+
+ for (i=i1; i <= i2; i=i+1) {
+ if (i > i1)
+ call fprintf (fd, ", ")
+ call fprintf (fd, "%d")
+ call pargi (array[i] + 1)
+ }
+
+ # Terminate statement.
+ call fprintf (fd, "/\n")
+ }
+end
+
+
+# TC_INIT_DATAC -- Write a series of data statements to initialize a
+# char array. A single large statement is not used due to variation
+# in the permissible number of continuation statements permitted by
+# different compilers.
+
+procedure tc_init_datac (fd, varname, str, nchars)
+
+int fd # output file
+char varname[ARB] # name of variable to be initialized
+char str[nchars] # array values
+int nchars
+
+int i, j, i1, i2
+
+begin
+ for (j=1; j <= nchars; j = j + NC_PERLINE) {
+ i1 = j
+ i2 = min (j + NC_PERLINE - 1, nchars)
+
+ # Begin new data statement.
+ call fprintf (fd, "data\t(%s(i),i=%2d,%2d)\t/")
+ call pargstr (varname)
+ call pargi (i1)
+ call pargi (i2)
+
+ # Output data values.
+ for (i=i1; i <= i2; i=i+1) {
+ if (i > i1)
+ call fprintf (fd, ", ")
+ call fprintf (fd, "%3d")
+ call pargc (str[i])
+ }
+
+ # Terminate statement.
+ call fprintf (fd, "/\n")
+ }
+end
+
+
+# TC_DUMMY_TTYLOAD -- Since we are rebuilding a TTYLOAD, we cannot pass
+# a real one to TTYOPEN. This dummy procedure returns 0 to TTYOPEN for
+# all devices, forcing TTYOPEN to open and scan the termcap file to fetch
+# the termcap entry for a device.
+
+int procedure tc_dummy_ttyload (termcap_file, devname, outstr, maxch)
+
+char termcap_file[ARB]
+char devname[ARB]
+char outstr[maxch]
+int maxch
+
+begin
+ outstr[1] = EOS
+ return (0)
+end
diff --git a/sys/tty/zzdebug.x b/sys/tty/zzdebug.x
new file mode 100644
index 00000000..f28b1714
--- /dev/null
+++ b/sys/tty/zzdebug.x
@@ -0,0 +1,184 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <ctype.h>
+include <ttyset.h>
+include "tty.h"
+
+# Debug TTY package.
+
+task find=t_find, cap=t_cap, init=t_init
+
+define SZ_CAPSTR 30
+define FAKE_PADCHAR 177B
+
+
+# FIND -- Find an entry in the termcap database, and print out the caplist
+# string.
+
+procedure t_find()
+
+char ttyname[SZ_FNAME]
+pointer tty, ttygdes()
+
+begin
+ call clgstr ("ttyname", ttyname, SZ_FNAME)
+ tty = ttygdes (ttyname)
+
+ call printf ("Termcap entry for '%s', %d capabilities\n")
+ call pargstr (ttyname)
+ call pargi (T_NCAPS(tty))
+ call printf (" pc=%oB, bsok=%b, htok=%b, %d by %d, %d baud\n")
+ call pargi (T_PADCHAR(tty))
+ call pargi (T_BSOK(tty))
+ call pargi (T_HTOK(tty))
+ call pargi (T_NCOLS(tty))
+ call pargi (T_NLINES(tty))
+ call pargi (T_BAUD(tty))
+
+ call putline (STDOUT, T_CAPLIST(tty))
+ call putci (STDOUT, '\n')
+ call ttycdes (tty)
+end
+
+
+# CAP -- Open descriptor, then sit in a get/put capability loop. Capabilities
+# are put to the stdout in a readable form.
+
+procedure t_cap()
+
+char ttyname[SZ_FNAME], capstr[SZ_CAPSTR]
+char ctrlstr[SZ_CTRLSTR], tempstr[SZ_CTRLSTR], obuf[SZ_LINE]
+int fd, args[MAX_COORDS], nargs, nchars
+
+int stropen(), ttygets(), ttysubi(), clglstr(), strlen(), nscan()
+pointer tty, ttygdes()
+
+begin
+ call clgstr ("ttyname", ttyname, SZ_FNAME)
+ tty = ttygdes (ttyname)
+ call ttyseti (tty, TTY_PADCHAR, FAKE_PADCHAR)
+
+ call printf ("Termcap entry for '%s', %d capabilities\n")
+ call pargstr (ttyname)
+ call pargi (T_NCAPS(tty))
+ call printf (" pc=%oB, bsok=%b, htok=%b, %d by %d, %d baud\n")
+ call pargi (T_PADCHAR(tty))
+ call pargi (T_BSOK(tty))
+ call pargi (T_HTOK(tty))
+ call pargi (T_NCOLS(tty))
+ call pargi (T_NLINES(tty))
+ call pargi (T_BAUD(tty))
+
+ while (clglstr ("cap", capstr, SZ_CAPSTR) != EOF)
+ if (ttygets (tty, capstr, ctrlstr, SZ_CTRLSTR) == 0) {
+ call printf ("capability '%s' not found\n")
+ call pargstr (capstr)
+ } else {
+ fd = stropen (obuf, SZ_LINE, NEW_FILE)
+
+ # Expand args? (as in "cap: cm 11 4")
+ if (strlen (capstr) > 2) {
+ call sscan (capstr[3])
+ for (nargs=0; nscan() == nargs; nargs=nargs+1)
+ call gargi (args[nargs+1])
+ nargs = nargs - 1
+ call strcpy (ctrlstr, tempstr, SZ_CTRLSTR)
+ nchars = ttysubi (tempstr, ctrlstr,SZ_CTRLSTR, args,nargs)
+ } else
+ nargs = 0
+
+ call ttyputs (fd, tty, ctrlstr, 1)
+ if (nargs > 0 && args[1] != 0 || args[2] != 0) {
+ call fprintf (fd, " residual x=%d, y=%d")
+ call pargi (args[1])
+ call pargi (args[2])
+ }
+ call close (fd)
+ call dump_chars (STDOUT, obuf)
+ }
+ call putci (STDOUT, '\n')
+
+ call ttycdes (tty)
+end
+
+
+# INIT -- Output initialization string in human readable form on the standard
+# output.
+
+define SZ_OBUF 1024
+
+
+procedure t_init()
+
+char ttyname[SZ_FNAME]
+char obuf[SZ_OBUF]
+int fd
+int stropen()
+pointer tty, ttygdes()
+
+begin
+ call clgstr ("ttyname", ttyname, SZ_FNAME)
+ tty = ttygdes (ttyname)
+ call ttyseti (tty, TTY_PADCHAR, FAKE_PADCHAR)
+
+ # Print header identifying basic terminal capabilities.
+ call printf ("Termcap entry for '%s', %d capabilities\n")
+ call pargstr (ttyname)
+ call pargi (T_NCAPS(tty))
+ call printf (" pc=%oB, bsok=%b, htok=%b, %d by %d, %d baud\n")
+ call pargi (T_PADCHAR(tty))
+ call pargi (T_BSOK(tty))
+ call pargi (T_HTOK(tty))
+ call pargi (T_NCOLS(tty))
+ call pargi (T_NLINES(tty))
+ call pargi (T_BAUD(tty))
+
+ # Dump initialization string into buffer, print buffer in readable
+ # form on STDOUT.
+
+ fd = stropen (obuf, SZ_OBUF, NEW_FILE)
+ call ttyinit (fd, tty)
+ call close (fd)
+ call dump_chars (STDOUT, obuf)
+ call putci (STDOUT, '\n')
+
+ call ttycdes (tty)
+end
+
+
+# DUMP_CHARS -- Print out a sequence of normal and control chars in a nice
+# readable form.
+
+procedure dump_chars (fd, str)
+
+int fd
+char str[ARB]
+char ch
+int ip, iptop
+int stridx()
+errchk putci, putline
+
+begin
+ for (ip=1; str[ip] != EOS; ) {
+ if (ip > 1)
+ call putci (fd, '\n')
+ call putline (fd, " ")
+ for (iptop=ip+50; ip < iptop && str[ip] != EOS; ip=ip+1) {
+ ch = str[ip]
+ if (IS_CNTRL(ch)) {
+ if (stridx (ch, "\b\f\t\r\n") > 0)
+ call putcc (fd, ch)
+ else {
+ call putci (fd, '^')
+ call putci (fd, ch + 'A' - 1)
+ }
+ } else if (ch == FAKE_PADCHAR) {
+ call putci (fd, '.')
+ } else
+ call putc (fd, ch)
+ }
+ }
+
+ if (ip < iptop)
+ call putci (fd, '\n')
+end