** TSET -- set terminal modes
** This program does sophisticated terminal initialization.
** I recommend that you include it in your .start_up or .login
** file to initialize whatever terminal you are on.
** There are several features:
** A special file or sequence (as controlled by the ttycap file)
** is sent to the terminal.
** Mode bits are set on a per-terminal_type basis (much better
** than UNIX itself). This allows special delays, automatic
** Erase and Kill characters can be set to whatever you want.
** Default is to change erase to control-H on a terminal which
** can overstrike, and leave it alone on anything else. Kill
** is always left alone unless specifically requested.
** Terminals which are dialups or plugboard types can be aliased
** to whatever type you may have in your home or office. Thus,
** if you know that when you dial up you will always be on a
** TI 733, you can specify that fact to tset.
** The htmp file, used by ex, etc., can be updated.
** The current terminal type can be queried.
** tset [-] [-r] [-EC] [-eC] [-d type] [-p type]
** [-b type] [-h] [-u] [type]
** In systems with environments, use:
** setenv TERM `tset - ...`
** Positional Parameters:
** type -- the terminal type to force. If this is
** specified, initialization is for this
** - -- report terminal type. Whatever type is
** decided on is reported.
** -r -- report to user, on diagnostic output instead
** -EC -- set the erase character to C on all terminals
** except those which cannot backspace (e.g.,
** a TTY 33). C defaults to control-H.
** -eC -- set the erase character to C on all terminals.
** C defaults to control-H. If neither -E or -e
** are specified, the erase character is set to
** control-H if the terminal can both backspace
** and not overstrike (e.g., a CRT). If the erase
** character is NULL (zero byte), it will be reset
** to '#' if nothing else is specified.
** -kC -- set the kill character to C on all terminals.
** Default for C is control-X. If not specified,
** the kill character is untouched; however, if
** not specified and the kill character is NULL
** (zero byte), the kill character is set to '@'.
** -d type -- set the dialup type to be type. If the
** terminal type seems to be dialup, make it
** 'type' instead. There need not be a space
** between 'd' and 'type'.
** -p type -- ditto for a plugboard.
** -b type -- ditto for a bussiplexer.
** -h -- don't read htmp file. Normally the terminal type
** is determined by reading the htmp file (unless
** -d or -p are specified). This forces a read
** of the ttytype file -- useful when htmp is
** somehow wrong. On a version seven system, this
** flag means don't look at the TERM entry in
** -u -- don't update htmp. It seemed like this should
** be put in. Note that htmp is never actually
** written if there are no changes, so don't bother
** bother using this for efficiency reasons alone.
** On version seven systems this flag is ignored.
** contains a terminal id -> terminal type
** mapping; used when -h, -d, or -p is used.
** a terminal_type -> terminal_capabilities
** -1 -- couldn't open ttycap.
** 1 -- bad terminal type, or standard output not tty.
** DIALUP -- the type code for a dialup port
** PLUGBOARD -- the code for a plugboard port.
** BUSSIPLEXER -- the code for a bussiplexer port.
** BACKSPACE -- control-H, the default for -e.
** CONTROLX -- control-X, the default for -k.
** OLDERASE -- the system default erase character.
** OLDKILL -- the system default kill character.
** FILEDES -- the file descriptor to do the operation
** STDOUT -- the standard output file descriptor.
** UIDMASK -- the bit pattern to mask with the getuid()
** call to get just the user id.
** Routines to handle htmp, ttytype, and ttycap.
** PLUGBOARD -- if defined, accept the -p flag.
** BUSSIPLEXER -- if defined, accept the -b flag.
** FULLLOGIN -- if defined, login sets the ttytype from
** VERSION7 -- if set, use environments, not htmp.
** Also, use 'ioctl' not 'stty' -- to get type-
** GTTYN -- if set, uses generalized tty names.
** Compilation Instructions:
** where 'bin' should be whoever owns the 'htmp' file.
** If 'htmp' is 666, then tset need not be setuid.
** Electronics Research Labs
** 3/79 -- Use ioctl in version7.
** 12/78 -- modified for eventual migration to VAX/UNIX,
** so the '-' option is changed to output only
** the terminal type to STDOUT instead of
** FILEDES. FULLLOGIN flag added. BUSSIPLEXER
** 9/78 -- '-' and '-p' options added (now fully
** compatible with ttytype!), and spaces are
** permitted between the -d and the type.
** 8/78 -- The sense of -h and -u were reversed, and the
** -f flag is dropped -- same effect is available
** by just stating the terminal type.
** 10/77 -- This version, in much it's previous state,
** written by Eric Allman.
# define BACKSPACE ('H' & 037)
# define CONTROLX ('X' & 037)
# define BUSSIPLEXER "bx"
/* # define FULLLOGIN FULLLOGIN login does everything */
/* # define VERSION7 VERSION7 version seven flag */
/* # define GTTYN GTTYN general tty names */
char Erase_char
; /* new erase character */
char Kill_char
; /* new kill character */
char Specialerase
; /* set => Erase_char only on terminals with backspace */
ttyid_t Ttyid
= NOTTY
; /* terminal identifier */
char *Ttytype
; /* type of terminal */
char *Dialtype
; /* override type if dialup terminal */
char *Plugtype
; /* override type if plugboard port */
char *Bxtype
; /* override type if bussiplexer port */
int Dash_u
; /* don't-update-htmp flag */
int Dash_h
; /* don't-read-htmp flag */
int Report
; /* report current type */
int Ureport
; /* report to user */
char Usage
[] = "usage: tset [-] [-r] [-eC] [-kC] [-d T] [-p T] [-b T] [-h] [-u] [type]\n";
char Capbuf
[256]; /* line from /etc/ttycap for this Ttytype */
extern char *hsgettype();
/* scan argument list and collect flags */
case 0: /* report current terminal type */
case 'r': /* report to user */
case 'E': /* special erase: operate on all but TTY33 */
/* exlicit fall-through to -e case */
case 'e': /* erase character */
case 'k': /* kill character */
case 'd': /* dialup type */
else if (--argc
< 0 || argv
[1][0] == '-')
case 'p': /* plugboard type */
else if (--argc
< 0 || argv
[1][0] == '-')
case 'b': /* bussiplexer type */
else if (--argc
< 0 || argv
[1][0] == '-')
case 'h': /* don't get type from htmp */
case 'u': /* don't update htmp */
/* if dialup is specified, check ttytype not htmp */
if (Dialtype
!= 0 || Plugtype
!= 0 || Bxtype
!= 0)
/* determine terminal id if needed */
if (Ttyid
== NOTTY
&& (Ttytype
== 0 || !Dash_h
|| !Dash_u
))
Ttyid
= ttyname(FILEDES
);
/* get htmp if ever used */
if (!Dash_u
|| (Ttytype
== 0 && !Dash_h
))
/* if not for this user, look at ttytype file */
if (hgettype() == 0 || hgetuid() != (getuid() & UIDMASK
))
/* find terminal type (if not already known) */
/* get type from /etc/ttytype or /etc/htmp */
Ttytype
= getenv("TERM");
Ttytype
= stypeof(Ttyid
);
/* check for dialup or plugboard override */
if (Dialtype
!= 0 && bequal(Ttytype
, DIALUP
, 2))
else if (Plugtype
!= 0 && bequal(Ttytype
, PLUGBOARD
, 2))
else if (Bxtype
!= 0 && bequal(Ttytype
, BUSSIPLEXER
, 2))
/* Ttytype now contains a pointer to the type of the terminal */
if (gtty(FILEDES
, &mode
) < 0)
bmove(&mode
, &oldmode
, sizeof mode
);
/* get terminal capabilities */
switch (tgetent(Capbuf
, Ttytype
))
prs("Cannot open ttycap file\n");
/* report type if appropriate */
/* find first alias (if any) */
for (p
= Capbuf
; *p
!= 0 && *p
!= '|' && *p
!= ':'; p
++)
if (*p
== 0 || *p
== ':')
while (*p
!= '|' && *p
!= ':' && *p
!= 0)
write(STDOUT
, bufp
, p
+ 1 - bufp
);
prs("Terminal type is ");
/* determine erase and kill characters */
if (Specialerase
&& !tgetflag("bs"))
mode
.sg_erase
= OLDERASE
;
if (tgetflag("bs") && !tgetflag("os"))
mode
.sg_erase
= BACKSPACE
;
mode
.sg_erase
= Erase_char
;
mode
.sg_kill
= Kill_char
;
setdelay("dC", CRdelay
, CRbits
, &mode
.sg_flags
);
setdelay("dN", NLdelay
, NLbits
, &mode
.sg_flags
);
setdelay("dB", BSdelay
, BSbits
, &mode
.sg_flags
);
setdelay("dF", FFdelay
, FFbits
, &mode
.sg_flags
);
setdelay("dT", TBdelay
, TBbits
, &mode
.sg_flags
);
if (tgetflag("UC") || command
[0] == 'T')
mode
.sg_flags
&= ~(EVENP
| ODDP
| RAW
);
if ((mode
.sg_flags
& (EVENP
| ODDP
)) == 0)
mode
.sg_flags
|= EVENP
| ODDP
;
mode
.sg_flags
|= CRMOD
| ECHO
| XTABS
;
if (tgetflag("NL")) /* new line, not line feed */
if (tgetflag("HD")) /* half duplex */
if (tgetflag("pt")) /* print tabs */
if (!bequal(&mode
, &oldmode
, sizeof mode
))
ioctl(FILEDES
, TIOCSETN
, &mode
);
if (!bequal(&mode
, &oldmode
, sizeof mode
))
/* output startup string */
if (tgetstr("is", &bufp
) != 0)
if (tgetstr("if", &bufp
) != 0)
/* tell about changing erase and kill characters */
reportek("Erase", mode
.sg_erase
, oldmode
.sg_erase
, OLDERASE
);
reportek("Kill", mode
.sg_kill
, oldmode
.sg_kill
, OLDKILL
);
prs("Cannot update htmp\n");
/* update htmp file only if changed */
if (!bequal(Capbuf
, hsgettype(), 2))
hsettype(Capbuf
[0] | (Capbuf
[1] << 8));
reportek(name
, new, old
, def
)
setdelay(cap
, dtab
, bits
, flags
)
register struct delay
*p
;
/* see if this capability exists at all */
/* clear out the bits, replace with new ones */
/* scan dtab for first entry with adequate delay */
for (p
= dtab
; p
->d_delay
>= 0; p
++)
/* use last entry if none will do */
while ((i
= read(fd
, buf
, 512)) > 0)