diff options
author | Joe Hunkeler <jhunkeler@gmail.com> | 2015-08-11 16:51:37 -0400 |
---|---|---|
committer | Joe Hunkeler <jhunkeler@gmail.com> | 2015-08-11 16:51:37 -0400 |
commit | 40e5a5811c6ffce9b0974e93cdd927cbcf60c157 (patch) | |
tree | 4464880c571602d54f6ae114729bf62a89518057 /sys/tty | |
download | iraf-osx-40e5a5811c6ffce9b0974e93cdd927cbcf60c157.tar.gz |
Repatch (from linux) of OSX IRAF
Diffstat (limited to 'sys/tty')
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 |