clean better
[unix-history] / usr / src / usr.bin / tset / tset.c
CommitLineData
d0aeaf5a
DF
1/*
2 * Copyright (c) 1980 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 */
6
7#ifndef lint
8char copyright[] =
9"@(#) Copyright (c) 1980 Regents of the University of California.\n\
10 All rights reserved.\n";
11#endif not lint
12
524aa063 13#ifndef lint
26a253fc 14static char sccsid[] = "@(#)tset.c 5.7 (Berkeley) %G%";
d0aeaf5a 15#endif not lint
6a19f69a 16
177ed6dd
BJ
17/*
18** TSET -- set terminal modes
19**
20** This program does sophisticated terminal initialization.
0b1d4860 21** I recommend that you include it in your .profile or .login
177ed6dd
BJ
22** file to initialize whatever terminal you are on.
23**
24** There are several features:
25**
0b1d4860 26** A special file or sequence (as controlled by the termcap file)
177ed6dd
BJ
27** is sent to the terminal.
28**
29** Mode bits are set on a per-terminal_type basis (much better
30** than UNIX itself). This allows special delays, automatic
31** tabs, etc.
32**
33** Erase and Kill characters can be set to whatever you want.
34** Default is to change erase to control-H on a terminal which
35** can overstrike, and leave it alone on anything else. Kill
36** is always left alone unless specifically requested. These
37** characters can be represented as "^X" meaning control-X;
38** X is any character.
39**
40** Terminals which are dialups or plugboard types can be aliased
41** to whatever type you may have in your home or office. Thus,
42** if you know that when you dial up you will always be on a
43** TI 733, you can specify that fact to tset. You can represent
44** a type as "?type". This will ask you what type you want it
45** to be -- if you reply with just a newline, it will default
46** to the type given.
47**
177ed6dd
BJ
48** The current terminal type can be queried.
49**
50** Usage:
0b1d4860 51** tset [-] [-EC] [-eC] [-kC] [-iC] [-s] [-h] [-u] [-r]
177ed6dd
BJ
52** [-m [ident] [test baudrate] :type]
53** [-Q] [-I] [-S] [type]
54**
55** In systems with environments, use:
6a19f69a
BJ
56** eval `tset -s ...`
57** Actually, this doesn't work in old csh's.
177ed6dd
BJ
58** Instead, use:
59** tset -s ... > tset.tmp
60** source tset.tmp
61** rm tset.tmp
62** or:
63** set noglob
64** set term=(`tset -S ....`)
65** setenv TERM $term[1]
66** setenv TERMCAP "$term[2]"
67** unset term
68** unset noglob
69**
70** Positional Parameters:
71** type -- the terminal type to force. If this is
72** specified, initialization is for this
73** terminal type.
74**
75** Flags:
76** - -- report terminal type. Whatever type is
77** decided on is reported. If no other flags
78** are stated, the only affect is to write
79** the terminal type on the standard output.
80** -r -- report to user in addition to other flags.
81** -EC -- set the erase character to C on all terminals
82** except those which cannot backspace (e.g.,
83** a TTY 33). C defaults to control-H.
84** -eC -- set the erase character to C on all terminals.
0b1d4860
JB
85** C defaults to control-H. If not specified,
86** the erase character is untouched; however, if
87** not specified and the erase character is NULL
88** (zero byte), the erase character is set to delete.
177ed6dd
BJ
89** -kC -- set the kill character to C on all terminals.
90** Default for C is control-X. If not specified,
91** the kill character is untouched; however, if
92** not specified and the kill character is NULL
0b1d4860 93** (zero byte), the kill character is set to control-U.
77f8c4bb 94** -iC -- set the interrupt character to C on all terminals.
0b1d4860
JB
95** Default for C is control-C. If not specified, the
96** interrupt character is untouched; however, if
97** not specified and the interrupt character is NULL
98** (zero byte), the interrupt character is set to
99** control-C.
177ed6dd
BJ
100** -qC -- reserved for setable quit character.
101** -m -- map the system identified type to some user
102** specified type. The mapping can be baud rate
103** dependent. This replaces the old -d, -p flags.
104** (-d type -> -m dialup:type)
105** (-p type -> -m plug:type)
106** Syntax: -m identifier [test baudrate] :type
9479aa87
BJ
107** where: ``identifier'' is terminal type found in
108** /etc/ttys for this port, (abscence of an identifier
177ed6dd
BJ
109** matches any identifier); ``test'' may be any combination
110** of > = < ! @; ``baudrate'' is as with stty(1);
111** ``type'' is the actual terminal type to use if the
112** mapping condition is met. Multiple maps are scanned
113** in order and the first match prevails.
6a19f69a
BJ
114** -n -- If the new tty driver from UCB is available, this flag
115** will activate the new options for erase and kill
116** processing. This will be different for printers
117** and crt's. For crts, if the baud rate is < 1200 then
118** erase and kill don't remove characters from the screen.
177ed6dd
BJ
119** -h -- don't read htmp file. Normally the terminal type
120** is determined by reading the htmp file or the
121** environment (unless some mapping is specified).
122** This forces a read of the ttytype file -- useful
6a19f69a 123** when htmp is somehow wrong. (V6 only)
177ed6dd
BJ
124** -u -- don't update htmp. It seemed like this should
125** be put in. Note that htmp is never actually
126** written if there are no changes, so don't bother
127** bother using this for efficiency reasons alone.
128** -s -- output setenv commands for TERM. This can be
129** used with
130** `tset -s ...`
131** and is to be prefered to:
132** setenv TERM `tset - ...`
133** because -s sets the TERMCAP variable also.
134** -S -- Similar to -s but outputs 2 strings suitable for
135** use in csh .login files as follows:
136** set noglob
137** set term=(`tset -S .....`)
138** setenv TERM $term[1]
139** setenv TERMCAP "$term[2]"
140** unset term
141** unset noglob
142** -Q -- be quiet. don't output 'Erase set to' etc.
143** -I -- don't do terminal initialization (is & if
144** strings).
6a19f69a
BJ
145** -v -- On virtual terminal systems, don't set up a
146** virtual terminal. Otherwise tset will tell
147** the operating system what kind of terminal you
148** are on (if it is a known terminal) and fix up
149** the output of -s to use virtual terminal sequences.
177ed6dd
BJ
150**
151** Files:
9479aa87 152** /etc/ttys
177ed6dd
BJ
153** contains a terminal id -> terminal type
154** mapping; used when any user mapping is specified,
155** or the environment doesn't have TERM set.
156** /etc/termcap
157** a terminal_type -> terminal_capabilities
158** mapping.
159**
160** Return Codes:
161** -1 -- couldn't open ttycap.
162** 1 -- bad terminal type, or standard output not tty.
163** 0 -- ok.
164**
165** Defined Constants:
6a19f69a
BJ
166** DIALUP -- the type code for a dialup port.
167** PLUGBOARD -- the type code for a plugboard port.
168** ARPANET -- the type code for an arpanet port.
177ed6dd 169** BACKSPACE -- control-H, the default for -e.
0b1d4860 170** CNTL('X') -- control-X, the default for -k.
177ed6dd
BJ
171** OLDERASE -- the system default erase character.
172** OLDKILL -- the system default kill character.
173** FILEDES -- the file descriptor to do the operation
174** on, nominally 1 or 2.
175** STDOUT -- the standard output file descriptor.
176** UIDMASK -- the bit pattern to mask with the getuid()
177** call to get just the user id.
178** GTTYN -- defines file containing generalized ttynames
179** and compiles code to look there.
180**
181** Requires:
9479aa87 182** Routines to handle htmp, ttys, and ttycap.
177ed6dd
BJ
183**
184** Compilation Flags:
177ed6dd
BJ
185** OLDFLAGS -- must be defined to compile code for any of
186** the -d, -p, or -a flags.
6a19f69a
BJ
187** OLDDIALUP -- accept the -d flag.
188** OLDPLUGBOARD -- accept the -p flag.
189** OLDARPANET -- accept the -a flag.
177ed6dd
BJ
190** V6 -- if clear, use environments, not htmp.
191** also use TIOCSETN rather than stty to avoid flushing
9479aa87 192** GTTYN -- if set, compiles code to look at /etc/ttys.
6a19f69a 193** UCB_NTTY -- set to handle new tty driver modes.
177ed6dd
BJ
194**
195** Trace Flags:
196** none
197**
198** Diagnostics:
199** Bad flag
200** An incorrect option was specified.
201** Too few args
202** more command line arguments are required.
203** Unexpected arg
204** wrong type of argument was encountered.
205** Cannot open ...
206** The specified file could not be openned.
207** Type ... unknown
208** An unknown terminal type was specified.
209** Cannot update htmp
210** Cannot update htmp file when the standard
211** output is not a terminal.
212** Erase set to ...
213** Telling that the erase character has been
214** set to the specified character.
215** Kill set to ...
216** Ditto for kill
217** Erase is ... Kill is ...
218** Tells that the erase/kill characters were
219** wierd before, but they are being left as-is.
220** Not a terminal
221** Set if FILEDES is not a terminal.
222**
223** Compilation Instructions:
224** cc -n -O tset.c -ltermlib
225** mv a.out tset
226** chown bin tset
227** chmod 4755 tset
228**
229** where 'bin' should be whoever owns the 'htmp' file.
230** If 'htmp' is 666, then tset need not be setuid.
231**
6a19f69a
BJ
232** For version 6 the compile command should be:
233** cc -n -O -I/usr/include/retrofit tset.c -ltermlib -lretro -lS
234**
177ed6dd
BJ
235** Author:
236** Eric Allman
237** Electronics Research Labs
238** U.C. Berkeley
239**
240** History:
6a19f69a
BJ
241** 1/81 -- Added alias checking for mapping identifiers.
242** 9/80 -- Added UCB_NTTY mods to setup the new tty driver.
243** Added the 'reset ...' invocation.
244** 7/80 -- '-S' added. '-m' mapping added. TERMCAP string
177ed6dd
BJ
245** cleaned up.
246** 3/80 -- Changed to use tputs. Prc & flush added.
247** 10/79 -- '-s' option extended to handle TERMCAP
248** variable, set noglob, quote the entry,
249** and know about the Bourne shell. Terminal
250** initialization moved to before any information
251** output so screen clears would not screw you.
252** '-Q' option added.
253** 8/79 -- '-' option alone changed to only output
254** type. '-s' option added. 'VERSION7'
255** changed to 'V6' for compatibility.
256** 12/78 -- modified for eventual migration to VAX/UNIX,
257** so the '-' option is changed to output only
258** the terminal type to STDOUT instead of
9479aa87 259** FILEDES.
177ed6dd
BJ
260** 9/78 -- '-' and '-p' options added (now fully
261** compatible with ttytype!), and spaces are
262** permitted between the -d and the type.
263** 8/78 -- The sense of -h and -u were reversed, and the
264** -f flag is dropped -- same effect is available
265** by just stating the terminal type.
266** 10/77 -- Written.
267*/
268
1d5679ec
JB
269#define UCB_NTTY
270
6a19f69a
BJ
271# ifdef USG
272# define index strchr
273# define rindex strrchr
274# define curerase mode.c_cc[VERASE]
275# define curkill mode.c_cc[VKILL]
537a9a14 276# define curintr mode.c_cc[VINTR]
6a19f69a
BJ
277# define olderase oldmode.c_cc[VERASE]
278# define oldkill oldmode.c_cc[VKILL]
537a9a14 279# define oldintr oldmode.c_cc[VINTR]
6a19f69a
BJ
280# else
281# define curerase mode.sg_erase
282# define curkill mode.sg_kill
537a9a14 283# define curintr tchar.t_intrc
6a19f69a
BJ
284# define olderase oldmode.sg_erase
285# define oldkill oldmode.sg_kill
537a9a14 286# define oldintr oldtchar.t_intrc
6a19f69a
BJ
287# endif
288
177ed6dd 289# ifndef V6
9479aa87
BJ
290# define GTTYN
291# include <ttyent.h>
177ed6dd
BJ
292# endif
293
6a19f69a
BJ
294# ifndef USG
295# include <sgtty.h>
296# else
297# include <termio.h>
298# endif
299
177ed6dd 300# include <stdio.h>
6a19f69a
BJ
301# include <signal.h>
302# ifdef V6
303# include <retrofit.h>
304# endif
177ed6dd 305
6a19f69a
BJ
306# define YES 1
307# define NO 0
0b1d4860
JB
308#undef CNTL
309# define CNTL(c) ((c)&037)
310# define BACKSPACE (CNTL('H'))
6a19f69a
BJ
311# define CHK(val, dft) (val<=0 ? dft : val)
312# define isdigit(c) (c >= '0' && c <= '9')
26a253fc 313# define isalnum(c) (c > ' ' && (index("<@=>!:|\177", c) == NULL))
177ed6dd
BJ
314# define OLDERASE '#'
315# define OLDKILL '@'
537a9a14 316# define OLDINTR '\177' /* del */
177ed6dd 317
0b1d4860
JB
318/* default special characters */
319#ifndef CERASE
320#define CERASE '\177'
321#endif
322#ifndef CKILL
323#define CKILL CNTL('U')
324#endif
325#ifndef CINTR
326#define CINTR CNTL('C')
327#endif
328#ifndef CDSUSP
329#define CQUIT 034 /* FS, ^\ */
330#define CSTART CNTL('Q')
331#define CSTOP CNTL('S')
332#define CEOF CNTL('D')
333#define CEOT CEOF
334#define CBRK 0377
335#define CSUSP CNTL('Z')
336#define CDSUSP CNTL('Y')
337#define CRPRNT CNTL('R')
338#define CFLUSH CNTL('O')
339#define CWERASE CNTL('W')
340#define CLNEXT CNTL('V')
341#endif
342
6a19f69a
BJ
343# define FILEDES 2 /* do gtty/stty on this descriptor */
344# define STDOUT 1 /* output of -s/-S to this descriptor */
177ed6dd 345
6a19f69a 346# ifdef V6
177ed6dd
BJ
347# define UIDMASK 0377
348# else
349# define UIDMASK -1
350# endif
351
6a19f69a 352# ifdef UCB_NTTY
0b1d4860 353# define USAGE "usage: tset [-] [-nrsIQS] [-eC] [-kC] [-iC] [-m [ident][test speed]:type] [type]\n"
6a19f69a 354# else
0b1d4860 355# define USAGE "usage: tset [-] [-rsIQS] [-eC] [-kC] [-iC] [-m [ident][test speed]:type] [type]\n"
6a19f69a 356# endif
177ed6dd 357
6a19f69a 358# define OLDFLAGS
177ed6dd
BJ
359# define DIALUP "dialup"
360# define OLDDIALUP "sd"
361# define PLUGBOARD "plugboard"
362# define OLDPLUGBOARD "sp"
363/***
364# define ARPANET "arpanet"
365# define OLDARPANET "sa"
6a19f69a 366/***/
177ed6dd 367
6a19f69a 368# define DEFTYPE "unknown"
177ed6dd
BJ
369
370
371# ifdef GTTYN
177ed6dd
BJ
372# define NOTTY 0
373# else
177ed6dd
BJ
374# define NOTTY 'x'
375# endif
376
377/*
378 * Baud Rate Conditionals
379 */
380# define ANY 0
381# define GT 1
382# define EQ 2
383# define LT 4
384# define GE (GT|EQ)
385# define LE (LT|EQ)
386# define NE (GT|LT)
387# define ALL (GT|EQ|LT)
388
389
390
391# define NMAP 10
392
393struct map {
394 char *Ident;
395 char Test;
396 char Speed;
397 char *Type;
398} map[NMAP];
399
400struct map *Map = map;
401
6a19f69a 402/* This should be available in an include file */
177ed6dd
BJ
403struct
404{
405 char *string;
406 int speed;
6a19f69a 407 int baudrate;
177ed6dd 408} speeds[] = {
6a19f69a
BJ
409 "0", B0, 0,
410 "50", B50, 50,
411 "75", B75, 75,
412 "110", B110, 110,
413 "134", B134, 134,
414 "134.5",B134, 134,
415 "150", B150, 150,
416 "200", B200, 200,
417 "300", B300, 300,
418 "600", B600, 600,
419 "1200", B1200, 1200,
420 "1800", B1800, 1800,
421 "2400", B2400, 2400,
422 "4800", B4800, 4800,
423 "9600", B9600, 9600,
0b1d4860 424 "19200",EXTA, 19200,
6a19f69a
BJ
425 "exta", EXTA, 19200,
426 "extb", EXTB, 38400,
177ed6dd
BJ
427 0,
428};
429
6a19f69a
BJ
430#ifdef CBVIRTTERM
431struct vterm {
432 char cap[2];
433 char *value;
434} vtab [] = {
435 "al", "\033\120",
436 "cd", "\033\114",
437 "ce", "\033\113",
438 "cm", "\033\107%r%.%.",
439 "cl", "\033\112",
440 "dc", "\033\115",
441 "dl", "\033\116",
442 "ic", "\033\117",
443 "kl", "\033\104",
444 "kr", "\033\103",
445 "ku", "\033\101",
446 "kd", "\033\102",
447 "kh", "\033\105",
448 "nd", "\033\103",
449 "se", "\033\142\004",
450 "so", "\033\141\004",
451 "ue", "\033\142\001",
452 "up", "\033\101",
453 "us", "\033\141\001",
454 "\0\0", NULL,
455};
456
457int VirTermNo = -2;
26a253fc 458int HasAM; /* True if terminal has automatic margins */
6a19f69a
BJ
459# endif CBVIRTTERM
460
177ed6dd
BJ
461char Erase_char; /* new erase character */
462char Kill_char; /* new kill character */
77f8c4bb 463char Intr_char; /* new interrupt character */
177ed6dd
BJ
464char Specialerase; /* set => Erase_char only on terminals with backspace */
465
6a19f69a
BJ
466# ifdef GTTYN
467char *Ttyid = NOTTY; /* terminal identifier */
468# else
469char Ttyid = NOTTY; /* terminal identifier */
470# endif
177ed6dd
BJ
471char *TtyType; /* type of terminal */
472char *DefType; /* default type if none other computed */
473char *NewType; /* mapping identifier based on old flags */
6a19f69a 474int Mapped; /* mapping has been specified */
177ed6dd
BJ
475int Dash_u; /* don't update htmp */
476int Dash_h; /* don't read htmp */
477int DoSetenv; /* output setenv commands */
478int BeQuiet; /* be quiet */
479int NoInit; /* don't output initialization string */
6a19f69a 480int IsReset; /* invoked as reset */
177ed6dd
BJ
481int Report; /* report current type */
482int Ureport; /* report to user */
483int RepOnly; /* report only */
484int CmndLine; /* output full command lines (-s option) */
485int Ask; /* ask user for termtype */
6a19f69a 486int DoVirtTerm = YES; /* Set up a virtual terminal */
6a19f69a 487int PadBaud; /* Min rate of padding needed */
48e4fbf9 488int lines, columns;
177ed6dd
BJ
489
490# define CAPBUFSIZ 1024
491char Capbuf[CAPBUFSIZ]; /* line from /etc/termcap for this TtyType */
492char *Ttycap; /* termcap line from termcap or environ */
493
6a19f69a
BJ
494char Aliasbuf[128];
495char *Alias[16];
496
26a253fc
JB
497extern char *strcpy();
498extern char *index();
499
177ed6dd
BJ
500struct delay
501{
502 int d_delay;
503 int d_bits;
504};
505
506# include "tset.delays.h"
507
6a19f69a
BJ
508# ifndef USG
509struct sgttyb mode;
510struct sgttyb oldmode;
537a9a14
JB
511struct tchars tchar;
512struct tchars oldtchar;
6a19f69a
BJ
513# else
514struct termio mode;
515struct termio oldmode;
516# endif
517# ifdef CBVIRTTERM
518struct termcb block = {0, 2, 0, 0, 0, 20};
519# endif CBVIRTTERM
177ed6dd
BJ
520
521
522main(argc, argv)
523int argc;
524char *argv[];
525{
dad1b0b2 526 char buf[CAPBUFSIZ];
6a19f69a 527 char termbuf[32];
177ed6dd
BJ
528 auto char *bufp;
529 register char *p;
530 char *command;
531 register int i;
26a253fc 532# ifdef CBVIRTTERM
6a19f69a 533 int j;
26a253fc 534# endif CBVIRTTERM
177ed6dd
BJ
535 int Break;
536 int Not;
6a19f69a
BJ
537 char *nextarg();
538 char *mapped();
539 extern char *rindex();
48e4fbf9 540 struct winsize win;
177ed6dd
BJ
541# ifdef V6
542 extern char *hsgettype();
543# else
544 extern char *getenv();
545# endif
546# ifdef GTTYN
6a19f69a 547 char *stypeof();
177ed6dd
BJ
548 extern char *ttyname();
549 extern char *tgetstr();
550# endif
551 char bs_char;
552 int csh;
6a19f69a
BJ
553 int settle;
554 int setmode();
177ed6dd
BJ
555 extern prc();
556 extern char PC;
6a19f69a
BJ
557# ifdef V6
558 extern int ospeed;
559# else
177ed6dd 560 extern short ospeed;
6a19f69a
BJ
561# endif
562# ifdef UCB_NTTY
563 int lmode;
564 int ldisc;
177ed6dd 565
26a253fc
JB
566 (void) ioctl(FILEDES, TIOCLGET, (char *)&lmode);
567 (void) ioctl(FILEDES, TIOCGETD, (char *)&ldisc);
6a19f69a
BJ
568# endif
569
570# ifndef USG
177ed6dd 571 if (gtty(FILEDES, &mode) < 0)
6a19f69a 572# else
26a253fc 573 if (ioctl(FILEDES, TCGETA, (char *)&mode) < 0)
6a19f69a 574# endif
177ed6dd
BJ
575 {
576 prs("Not a terminal\n");
577 exit(1);
578 }
26a253fc 579 bmove((char *)&mode, (char *)&oldmode, sizeof mode);
537a9a14 580# ifdef TIOCGETC
26a253fc
JB
581 (void) ioctl(FILEDES, TIOCGETC, (char *)&tchar);
582 bmove((char *)&tchar, (char *)&oldtchar, sizeof tchar);
537a9a14 583# endif
6a19f69a
BJ
584# ifndef USG
585 ospeed = mode.sg_ospeed & 017;
586# else
587 ospeed = mode.c_cflag & CBAUD;
588# endif
26a253fc
JB
589 (void) signal(SIGINT, setmode);
590 (void) signal(SIGQUIT, setmode);
591 (void) signal(SIGTERM, setmode);
177ed6dd 592
6a19f69a
BJ
593 if (command = rindex(argv[0], '/'))
594 command++;
595 else
596 command = argv[0];
597 if (sequal(command, "reset") )
177ed6dd 598 {
6a19f69a
BJ
599 /*
600 * reset the teletype mode bits to a sensible state.
601 * Copied from the program by Kurt Shoens & Mark Horton.
602 * Very useful after crapping out in raw.
603 */
604# ifndef V6
6a19f69a
BJ
605# ifdef UCB_NTTY
606 struct ltchars ltc;
0b1d4860
JB
607#ifdef TIOCLBIC
608 static int lclear = LMDMBUF|LLITOUT|LPASS8;
609#endif TIOCLBIC
6a19f69a
BJ
610
611 if (ldisc == NTTYDISC)
612 {
26a253fc 613 (void) ioctl(FILEDES, TIOCGLTC, (char *)&ltc);
0b1d4860
JB
614 ltc.t_suspc = CHK(ltc.t_suspc, CSUSP);
615 ltc.t_dsuspc = CHK(ltc.t_dsuspc, CDSUSP);
616 ltc.t_rprntc = CHK(ltc.t_rprntc, CRPRNT);
617 ltc.t_flushc = CHK(ltc.t_flushc, CFLUSH);
618 ltc.t_werasc = CHK(ltc.t_werasc, CWERASE);
619 ltc.t_lnextc = CHK(ltc.t_lnextc, CLNEXT);
26a253fc 620 (void) ioctl(FILEDES, TIOCSLTC, (char *)&ltc);
6a19f69a
BJ
621 }
622# endif UCB_NTTY
623# ifndef USG
624# ifdef TIOCGETC
0b1d4860
JB
625 tchar.t_intrc = CHK(tchar.t_intrc, CINTR);
626 tchar.t_quitc = CHK(tchar.t_quitc, CQUIT);
627 tchar.t_startc = CHK(tchar.t_startc, CSTART);
628 tchar.t_stopc = CHK(tchar.t_stopc, CSTOP);
629 tchar.t_eofc = CHK(tchar.t_eofc, CEOF);
6a19f69a 630 /* brkc is left alone */
26a253fc 631 (void) ioctl(FILEDES, TIOCSETC, (char *)&tchar);
0b1d4860 632#ifdef TIOCLBIC
26a253fc 633 (void) ioctl(FILEDES, TIOCLBIC, (char *)&lclear);
0b1d4860 634#endif TIOCLBIC
6a19f69a
BJ
635# endif TIOCGETC
636 mode.sg_flags &= ~(RAW
637# ifdef CBREAK
638 |CBREAK
639# endif CBREAK
640 |VTDELAY|ALLDELAY);
641 mode.sg_flags |= XTABS|ECHO|CRMOD|ANYP;
0b1d4860
JB
642 curerase = CHK(curerase, CERASE);
643 curkill = CHK(curkill, CKILL);
644 curintr = CHK(curintr, CINTR);
6a19f69a 645# else USG
26a253fc 646 (void) ioctl(FILEDES, TCGETA, (char *)&mode);
6a19f69a
BJ
647 curerase = CHK(curerase, OLDERASE);
648 curkill = CHK(curkill, OLDKILL);
0b1d4860
JB
649 curintr = CHK(curintr, OLDINTR);
650 mode.c_cc[VQUIT] = CHK(mode.c_cc[VQUIT], CQUIT);
651 mode.c_cc[VEOF] = CHK(mode.c_cc[VEOF], CEOF);
6a19f69a
BJ
652
653 mode.c_iflag |= (BRKINT|ISTRIP|ICRNL|IXON);
654 mode.c_iflag &= ~(IGNBRK|PARMRK|INPCK|INLCR|IGNCR|IUCLC|IXOFF);
655 mode.c_oflag |= (OPOST|ONLCR);
656 mode.c_oflag &= ~(OLCUC|OCRNL|ONOCR|ONLRET|OFILL|OFDEL|
657 NLDLY|CRDLY|TABDLY|BSDLY|VTDLY|FFDLY);
658 mode.c_cflag |= (CS7|CREAD);
659 mode.c_cflag &= ~(CSIZE|PARODD|CLOCAL);
660 mode.c_lflag |= (ISIG|ICANON|ECHO|ECHOK);
661 mode.c_lflag &= ~(XCASE|ECHONL|NOFLSH);
26a253fc 662 (void) ioctl(FILEDES, TCSETAW, (char *)&mode);
6a19f69a
BJ
663# endif USG
664# endif V6
665 Dash_u = YES;
666 BeQuiet = YES;
667 IsReset = YES;
668 }
669 else if (argc == 2 && sequal(argv[1], "-"))
670 {
671 RepOnly = YES;
672 Dash_u = YES;
177ed6dd
BJ
673 }
674 argc--;
6a19f69a
BJ
675
676 /* scan argument list and collect flags */
177ed6dd
BJ
677 while (--argc >= 0)
678 {
679 p = *++argv;
680 if (*p == '-')
681 {
682 if (*++p == NULL)
6a19f69a 683 Report = YES; /* report current terminal type */
177ed6dd
BJ
684 else while (*p) switch (*p++)
685 {
686
6a19f69a
BJ
687# ifdef UCB_NTTY
688 case 'n':
689 ldisc = NTTYDISC;
26a253fc 690 if (ioctl(FILEDES, TIOCSETD, (char *)&ldisc)<0)
6a19f69a
BJ
691 fatal("ioctl ", "new");
692 continue;
693# endif
694
177ed6dd 695 case 'r': /* report to user */
6a19f69a 696 Ureport = YES;
177ed6dd
BJ
697 continue;
698
699 case 'E': /* special erase: operate on all but TTY33 */
6a19f69a 700 Specialerase = YES;
177ed6dd
BJ
701 /* explicit fall-through to -e case */
702
703 case 'e': /* erase character */
704 if (*p == NULL)
705 Erase_char = -1;
706 else
707 {
708 if (*p == '^' && p[1] != NULL)
0b1d4860
JB
709 if (*++p == '?')
710 Erase_char = '\177';
711 else
712 Erase_char = CNTL(*p);
177ed6dd
BJ
713 else
714 Erase_char = *p;
715 p++;
716 }
717 continue;
718
537a9a14 719# if defined(USG) || defined(TIOCGETC)
0b1d4860 720 case 'i': /* interrupt character */
537a9a14 721 if (*p == NULL)
0b1d4860 722 Intr_char = CNTL('C');
537a9a14
JB
723 else
724 {
725 if (*p == '^' && p[1] != NULL)
0b1d4860
JB
726 if (*++p == '?')
727 Intr_char = '\177';
728 else
729 Intr_char = CNTL(*p);
537a9a14
JB
730 else
731 Intr_char = *p;
732 p++;
733 }
734 continue;
735# endif
736
177ed6dd
BJ
737 case 'k': /* kill character */
738 if (*p == NULL)
0b1d4860 739 Kill_char = CNTL('X');
177ed6dd
BJ
740 else
741 {
742 if (*p == '^' && p[1] != NULL)
0b1d4860
JB
743 if (*++p == '?')
744 Kill_char = '\177';
745 else
746 Kill_char = CNTL(*p);
177ed6dd
BJ
747 else
748 Kill_char = *p;
749 p++;
750 }
751 continue;
752
753# ifdef OLDFLAGS
754# ifdef OLDDIALUP
755 case 'd': /* dialup type */
756 NewType = DIALUP;
757 goto mapold;
758# endif
759
760# ifdef OLDPLUGBOARD
761 case 'p': /* plugboard type */
762 NewType = PLUGBOARD;
763 goto mapold;
764# endif
765
766# ifdef OLDARPANET
767 case 'a': /* arpanet type */
768 Newtype = ARPANET;
769 goto mapold;
770# endif
771
772mapold: Map->Ident = NewType;
773 Map->Test = ALL;
774 if (*p == NULL)
775 {
776 p = nextarg(argc--, argv++);
777 }
778 Map->Type = p;
779 Map++;
6a19f69a 780 Mapped = YES;
177ed6dd
BJ
781 p = "";
782 continue;
783# endif
784
785 case 'm': /* map identifier to type */
786 /* This code is very loose. Almost no
787 ** syntax checking is done!! However,
788 ** illegal syntax will only produce
789 ** weird results.
790 */
791 if (*p == NULL)
792 {
793 p = nextarg(argc--, argv++);
794 }
795 if (isalnum(*p))
796 {
797 Map->Ident = p; /* identifier */
798 while (isalnum(*p)) p++;
799 }
800 else
801 Map->Ident = "";
6a19f69a
BJ
802 Break = NO;
803 Not = NO;
177ed6dd
BJ
804 while (!Break) switch (*p)
805 {
806 case NULL:
807 p = nextarg(argc--, argv++);
808 continue;
809
810 case ':': /* mapped type */
811 *p++ = NULL;
6a19f69a 812 Break = YES;
177ed6dd
BJ
813 continue;
814
815 case '>': /* conditional */
816 Map->Test |= GT;
817 *p++ = NULL;
818 continue;
819
820 case '<': /* conditional */
821 Map->Test |= LT;
822 *p++ = NULL;
823 continue;
824
825 case '=': /* conditional */
826 case '@':
827 Map->Test |= EQ;
828 *p++ = NULL;
829 continue;
830
831 case '!': /* invert conditions */
832 Not = ~Not;
833 *p++ = NULL;
834 continue;
835
836 case 'B': /* Baud rate */
837 p++;
838 /* intentional fallthru */
839 default:
840 if (isdigit(*p) || *p == 'e')
841 {
842 Map->Speed = baudrate(p);
843 while (isalnum(*p) || *p == '.')
844 p++;
845 }
846 else
6a19f69a 847 Break = YES;
177ed6dd
BJ
848 continue;
849 }
850 if (Not) /* invert sense of test */
851 {
852 Map->Test = (~(Map->Test))&ALL;
853 }
854 if (*p == NULL)
855 {
856 p = nextarg(argc--, argv++);
857 }
858 Map->Type = p;
859 p = "";
860 Map++;
6a19f69a 861 Mapped = YES;
177ed6dd
BJ
862 continue;
863
864 case 'h': /* don't get type from htmp or env */
6a19f69a 865 Dash_h = YES;
177ed6dd
BJ
866 continue;
867
868 case 'u': /* don't update htmp */
6a19f69a 869 Dash_u = YES;
177ed6dd
BJ
870 continue;
871
872 case 's': /* output setenv commands */
6a19f69a
BJ
873 DoSetenv = YES;
874 CmndLine = YES;
177ed6dd
BJ
875 continue;
876
877 case 'S': /* output setenv strings */
6a19f69a
BJ
878 DoSetenv = YES;
879 CmndLine = NO;
177ed6dd
BJ
880 continue;
881
882 case 'Q': /* be quiet */
6a19f69a 883 BeQuiet = YES;
177ed6dd
BJ
884 continue;
885
886 case 'I': /* no initialization */
6a19f69a 887 NoInit = YES;
177ed6dd
BJ
888 continue;
889
890 case 'A': /* Ask user */
6a19f69a
BJ
891 Ask = YES;
892 continue;
893
894 case 'v': /* no virtual terminal */
895 DoVirtTerm = NO;
177ed6dd
BJ
896 continue;
897
898 default:
899 *p-- = NULL;
900 fatal("Bad flag -", p);
901 }
902 }
903 else
904 {
905 /* terminal type */
906 DefType = p;
907 }
908 }
909
910 if (DefType)
911 {
912 if (Mapped)
913 {
914 Map->Ident = ""; /* means "map any type" */
915 Map->Test = ALL; /* at all baud rates */
916 Map->Type = DefType; /* to the default type */
917 }
918 else
919 TtyType = DefType;
920 }
921
922# ifndef V6
6a19f69a
BJ
923 /*
924 * Get rid of $TERMCAP, if it's there, so we get a real
925 * entry from /etc/termcap. This prevents us from being
926 * fooled by out of date stuff in the environment, and
927 * makes tabs work right on CB/Unix.
928 */
929 bufp = getenv("TERMCAP");
930 if (bufp && *bufp != '/')
26a253fc 931 (void) strcpy(bufp-8, "NOTHING"); /* overwrite only "TERMCAP" */
177ed6dd 932 /* get current idea of terminal type from environment */
8d1e1d87 933 if (!Dash_h && TtyType == 0)
177ed6dd
BJ
934 TtyType = getenv("TERM");
935# endif
936
937 /* determine terminal id if needed */
938# ifdef V6
939 if (Ttyid == NOTTY && (TtyType == 0 || !Dash_h || !Dash_u))
940 Ttyid = ttyn(FILEDES);
941# else
942 if (!RepOnly && Ttyid == NOTTY && (TtyType == 0 || !Dash_h))
943 Ttyid = ttyname(FILEDES);
944# endif
945
946# ifdef V6
947 /* get htmp if ever used */
948 if (!Dash_u || (TtyType == 0 && !Dash_h))
949 {
950 /* get htmp entry -- if error or wrong user use ttytype */
951 if (Ttyid == NOTTY || hget(Ttyid) < 0 ||
952 hgettype() == 0 || hgetuid() != (getuid() & UIDMASK))
953 Dash_h++;
954 }
955
956 /* find terminal type (if not already known) */
957 if (TtyType == 0 && !Dash_h)
958 {
959 /* get type from /etc/htmp */
960 TtyType = hsgettype();
961 }
962# endif
963
964# ifdef GTTYN
965 /* If still undefined, look at /etc/ttytype */
966 if (TtyType == 0)
967 {
968 TtyType = stypeof(Ttyid);
969 }
970# endif
971
972 /* If still undefined, use DEFTYPE */
973 if (TtyType == 0)
974 {
975 TtyType = DEFTYPE;
976 }
977
978 /* check for dialup or other mapping */
979 if (Mapped)
6d31b7ce
EW
980 {
981 if (!(Alias[0] && isalias(TtyType)))
982 if (tgetent(Capbuf, TtyType) > 0)
983 makealias(Capbuf);
6a19f69a 984 TtyType = mapped(TtyType);
6d31b7ce 985 }
177ed6dd
BJ
986
987 /* TtyType now contains a pointer to the type of the terminal */
988 /* If the first character is '?', ask the user */
989 if (TtyType[0] == '?')
990 {
6a19f69a 991 Ask = YES;
177ed6dd
BJ
992 TtyType++;
993 if (TtyType[0] == '\0')
994 TtyType = DEFTYPE;
995 }
996 if (Ask)
997 {
dad1b0b2 998ask:
177ed6dd
BJ
999 prs("TERM = (");
1000 prs(TtyType);
1001 prs(") ");
1002 flush();
1003
1004 /* read the terminal. If not empty, set type */
6a19f69a
BJ
1005 i = read(2, termbuf, sizeof termbuf - 1);
1006 if (i > 0)
177ed6dd 1007 {
6a19f69a 1008 if (termbuf[i - 1] == '\n')
177ed6dd 1009 i--;
6a19f69a
BJ
1010 termbuf[i] = '\0';
1011 if (termbuf[0] != '\0')
1012 TtyType = termbuf;
177ed6dd
BJ
1013 }
1014 }
1015
6a19f69a
BJ
1016 /* get terminal capabilities */
1017 if (!(Alias[0] && isalias(TtyType))) {
177ed6dd
BJ
1018 switch (tgetent(Capbuf, TtyType))
1019 {
1020 case -1:
6a19f69a 1021 prs("Cannot find termcap\n");
177ed6dd
BJ
1022 flush();
1023 exit(-1);
1024
1025 case 0:
1026 prs("Type ");
1027 prs(TtyType);
1028 prs(" unknown\n");
1029 flush();
6a19f69a
BJ
1030 if (DoSetenv)
1031 {
1032 TtyType = DEFTYPE;
dad1b0b2
S
1033 Alias[0] = '\0';
1034 goto ask;
6a19f69a
BJ
1035 }
1036 else
1037 exit(1);
177ed6dd 1038 }
177ed6dd 1039 }
6a19f69a 1040 Ttycap = Capbuf;
177ed6dd
BJ
1041
1042 if (!RepOnly)
1043 {
1044 /* determine erase and kill characters */
1045 if (Specialerase && !tgetflag("bs"))
1046 Erase_char = 0;
1047 bufp = buf;
1048 p = tgetstr("kb", &bufp);
1049 if (p == NULL || p[1] != '\0')
1050 p = tgetstr("bc", &bufp);
1051 if (p != NULL && p[1] == '\0')
1052 bs_char = p[0];
1053 else if (tgetflag("bs"))
1054 bs_char = BACKSPACE;
1055 else
1056 bs_char = 0;
6a19f69a 1057 if (Erase_char == 0 && !tgetflag("os") && curerase == OLDERASE)
177ed6dd
BJ
1058 {
1059 if (tgetflag("bs") || bs_char != 0)
1060 Erase_char = -1;
1061 }
1062 if (Erase_char < 0)
1063 Erase_char = (bs_char != 0) ? bs_char : BACKSPACE;
1064
6a19f69a 1065 if (curerase == 0)
0b1d4860 1066 curerase = CERASE;
177ed6dd 1067 if (Erase_char != 0)
6a19f69a 1068 curerase = Erase_char;
177ed6dd 1069
537a9a14 1070 if (curintr == 0)
0b1d4860 1071 curintr = CINTR;
537a9a14
JB
1072 if (Intr_char != 0)
1073 curintr = Intr_char;
1074
6a19f69a 1075 if (curkill == 0)
0b1d4860 1076 curkill = CKILL;
177ed6dd 1077 if (Kill_char != 0)
6a19f69a 1078 curkill = Kill_char;
177ed6dd
BJ
1079
1080 /* set modes */
6a19f69a
BJ
1081 PadBaud = tgetnum("pb"); /* OK if fails */
1082 for (i=0; speeds[i].string; i++)
1083 if (speeds[i].baudrate == PadBaud) {
1084 PadBaud = speeds[i].speed;
1085 break;
1086 }
1087# ifndef USG
177ed6dd
BJ
1088 setdelay("dC", CRdelay, CRbits, &mode.sg_flags);
1089 setdelay("dN", NLdelay, NLbits, &mode.sg_flags);
1090 setdelay("dB", BSdelay, BSbits, &mode.sg_flags);
1091 setdelay("dF", FFdelay, FFbits, &mode.sg_flags);
1092 setdelay("dT", TBdelay, TBbits, &mode.sg_flags);
6a19f69a 1093 if (tgetflag("UC") || (command[0] & 0140) == 0100)
177ed6dd
BJ
1094 mode.sg_flags |= LCASE;
1095 else if (tgetflag("LC"))
1096 mode.sg_flags &= ~LCASE;
1097 mode.sg_flags &= ~(EVENP | ODDP | RAW);
6a19f69a 1098# ifdef CBREAK
177ed6dd
BJ
1099 mode.sg_flags &= ~CBREAK;
1100# endif
1101 if (tgetflag("EP"))
1102 mode.sg_flags |= EVENP;
1103 if (tgetflag("OP"))
1104 mode.sg_flags |= ODDP;
1105 if ((mode.sg_flags & (EVENP | ODDP)) == 0)
1106 mode.sg_flags |= EVENP | ODDP;
1107 mode.sg_flags |= CRMOD | ECHO | XTABS;
1108 if (tgetflag("NL")) /* new line, not line feed */
1109 mode.sg_flags &= ~CRMOD;
1110 if (tgetflag("HD")) /* half duplex */
1111 mode.sg_flags &= ~ECHO;
1112 if (tgetflag("pt")) /* print tabs */
1113 mode.sg_flags &= ~XTABS;
177ed6dd 1114# else
6a19f69a
BJ
1115 setdelay("dC", CRdelay, CRbits, &mode.c_oflag);
1116 setdelay("dN", NLdelay, NLbits, &mode.c_oflag);
1117 setdelay("dB", BSdelay, BSbits, &mode.c_oflag);
1118 setdelay("dF", FFdelay, FFbits, &mode.c_oflag);
1119 setdelay("dT", TBdelay, TBbits, &mode.c_oflag);
1120 setdelay("dV", VTdelay, VTbits, &mode.c_oflag);
1121
1122 if (tgetflag("UC") || (command[0] & 0140) == 0100) {
1123 mode.c_iflag |= IUCLC;
1124 mode.c_oflag |= OLCUC;
1125 }
1126 else if (tgetflag("LC")) {
1127 mode.c_iflag &= ~IUCLC;
1128 mode.c_oflag &= ~OLCUC;
1129 }
1130 mode.c_iflag &= ~(PARMRK|INPCK);
1131 mode.c_lflag |= ICANON;
1132 if (tgetflag("EP")) {
1133 mode.c_cflag |= PARENB;
1134 mode.c_cflag &= ~PARODD;
1135 }
1136 if (tgetflag("OP")) {
1137 mode.c_cflag |= PARENB;
1138 mode.c_cflag |= PARODD;
1139 }
1140
1141 mode.c_oflag |= ONLCR;
1142 mode.c_iflag |= ICRNL;
1143 mode.c_lflag |= ECHO;
1144 mode.c_oflag |= TAB3;
1145 if (tgetflag("NL")) { /* new line, not line feed */
1146 mode.c_oflag &= ~ONLCR;
1147 mode.c_iflag &= ~ICRNL;
1148 }
1149 if (tgetflag("HD")) /* half duplex */
1150 mode.c_lflag &= ~ECHO;
1151 if (tgetflag("pt")) /* print tabs */
1152 mode.c_oflag &= ~TAB3;
1153
1154 mode.c_lflag |= (ECHOE|ECHOK);
1155# endif
1156# ifdef CBVIRTTERM
1157 HasAM = tgetflag("am");
1158# endif CBVIRTTERM
1159# ifdef UCB_NTTY
1160 if (ldisc == NTTYDISC)
1161 {
1162 lmode |= LCTLECH; /* display ctrl chars */
1163 if (tgetflag("hc"))
1164 { /** set printer modes **/
1165 lmode &= ~(LCRTBS|LCRTERA|LCRTKIL);
1166 lmode |= LPRTERA;
1167 }
1168 else
1169 { /** set crt modes **/
1170 if (!tgetflag("os"))
1171 {
1172 lmode &= ~LPRTERA;
1173 lmode |= LCRTBS;
1174 if (mode.sg_ospeed >= B1200)
1175 lmode |= LCRTERA|LCRTKIL;
1176 }
1177 }
1178 }
26a253fc 1179 (void) ioctl(FILEDES, TIOCLSET, (char *)&lmode);
177ed6dd
BJ
1180# endif
1181
1182 /* get pad character */
1183 bufp = buf;
1184 if (tgetstr("pc", &bufp) != 0)
1185 PC = buf[0];
1186
48e4fbf9
JB
1187 columns = tgetnum("co");
1188 lines = tgetnum("li");
1189
1190 /* Set window size */
26a253fc 1191 (void) ioctl(FILEDES, TIOCGWINSZ, (char *)&win);
0b1d4860
JB
1192 if (win.ws_row == 0 && win.ws_col == 0 &&
1193 lines > 0 && columns > 0) {
1194 win.ws_row = lines;
1195 win.ws_col = columns;
26a253fc 1196 (void) ioctl(FILEDES, TIOCSWINSZ, (char *)&win);
48e4fbf9 1197 }
177ed6dd
BJ
1198 /* output startup string */
1199 if (!NoInit)
1200 {
6a19f69a
BJ
1201# ifndef USG
1202 if (oldmode.sg_flags&(XTABS|CRMOD))
1203 {
1204 oldmode.sg_flags &= ~(XTABS|CRMOD);
1205 setmode(-1);
1206 }
1207# else
1208 if (oldmode.c_oflag&(TAB3|ONLCR|OCRNL|ONLRET))
1209 {
1210 oldmode.c_oflag &= (TAB3|ONLCR|OCRNL|ONLRET);
1211 setmode(-1);
1212 }
1213# endif
1214# ifdef CBVIRTTERM
1215 block.st_termt = 0;
26a253fc 1216 (void) ioctl(FILEDES, LDSETT, (char *)&block);
6a19f69a
BJ
1217# endif CBVIRTTERM
1218 if (settabs()) {
1219 settle = YES;
1220 flush();
1221 }
177ed6dd 1222 bufp = buf;
0b1d4860
JB
1223 if (IsReset && tgetstr("rs", &bufp) != 0 ||
1224 tgetstr("is", &bufp) != 0)
6a19f69a 1225 {
177ed6dd 1226 tputs(buf, 0, prc);
6a19f69a
BJ
1227 settle = YES;
1228 flush();
1229 }
177ed6dd 1230 bufp = buf;
0b1d4860
JB
1231 if (IsReset && tgetstr("rf", &bufp) != 0 ||
1232 tgetstr("if", &bufp) != 0)
6a19f69a 1233 {
177ed6dd 1234 cat(buf);
6a19f69a
BJ
1235 settle = YES;
1236 }
1237 if (settle)
1238 {
1239 prc('\r');
1240 flush();
1241 sleep(1); /* let terminal settle down */
1242 }
177ed6dd
BJ
1243 }
1244
6a19f69a
BJ
1245# ifdef CBVIRTTERM
1246 if (DoVirtTerm) {
1247 j = tgetnum("vt");
1248 VirTermNo = -1;
1249 for (i=0; vt_map[i].stdnum; i++)
1250 if (vt_map[i].stdnum == j)
1251 VirTermNo = vt_map[i].localnum;
1252 } else
1253 VirTermNo = -1;
1254# endif CBVIRTTERM
1255
1256 setmode(0); /* set new modes, if they've changed */
1257
177ed6dd 1258 /* set up environment for the shell we are using */
6a19f69a
BJ
1259 /* (this code is rather heuristic, checking for $SHELL */
1260 /* ending in the 3 characters "csh") */
1261 csh = NO;
177ed6dd
BJ
1262 if (DoSetenv)
1263 {
1264# ifndef V6
1265 char *sh;
1266
1267 if ((sh = getenv("SHELL")) && (i = strlen(sh)) >= 3)
1268 {
26a253fc
JB
1269 if ((csh = sequal(&sh[i-3], "csh")) && CmndLine)
1270 (void) write(STDOUT, "set noglob;\n", 12);
177ed6dd
BJ
1271 }
1272 if (!csh)
1273# endif
26a253fc
JB
1274 /* running Bourne shell */
1275 (void) write(STDOUT, "export TERMCAP TERM;\n", 21);
177ed6dd
BJ
1276 }
1277 }
1278
1279 /* report type if appropriate */
1280 if (DoSetenv || Report || Ureport)
1281 {
6a19f69a
BJ
1282 /* if type is the short name, find first alias (if any) */
1283 makealias(Ttycap);
1284 if (sequal(TtyType, Alias[0]) && Alias[1]) {
1285 TtyType = Alias[1];
1286 }
1287
177ed6dd
BJ
1288 if (DoSetenv)
1289 {
1290 if (csh)
1291 {
1292 if (CmndLine)
26a253fc
JB
1293 (void) write(STDOUT, "setenv TERM ", 12);
1294 (void) write(STDOUT, TtyType, strlen(TtyType));
1295 (void) write(STDOUT, " ", 1);
177ed6dd 1296 if (CmndLine)
26a253fc 1297 (void) write(STDOUT, ";\n", 2);
177ed6dd
BJ
1298 }
1299 else
1300 {
26a253fc
JB
1301 (void) write(STDOUT, "TERM=", 5);
1302 (void) write(STDOUT, TtyType, strlen(TtyType));
1303 (void) write(STDOUT, ";\n", 2);
177ed6dd
BJ
1304 }
1305 }
6a19f69a 1306 else if (Report)
177ed6dd 1307 {
26a253fc
JB
1308 (void) write(STDOUT, TtyType, strlen(TtyType));
1309 (void) write(STDOUT, "\n", 1);
177ed6dd
BJ
1310 }
1311 if (Ureport)
1312 {
177ed6dd 1313 prs("Terminal type is ");
6a19f69a 1314 prs(TtyType);
177ed6dd
BJ
1315 prs("\n");
1316 flush();
1317 }
6a19f69a 1318
177ed6dd
BJ
1319 if (DoSetenv)
1320 {
1321 if (csh)
1322 {
26a253fc
JB
1323 if (CmndLine)
1324 (void) write(STDOUT, "setenv TERMCAP '", 16);
177ed6dd
BJ
1325 }
1326 else
26a253fc 1327 (void) write(STDOUT, "TERMCAP='", 9);
177ed6dd
BJ
1328 wrtermcap(Ttycap);
1329 if (csh)
1330 {
1331 if (CmndLine)
1332 {
26a253fc
JB
1333 (void) write(STDOUT, "';\n", 3);
1334 (void) write(STDOUT, "unset noglob;\n", 14);
177ed6dd
BJ
1335 }
1336 }
1337 else
26a253fc 1338 (void) write(STDOUT, "';\n", 3);
177ed6dd
BJ
1339 }
1340 }
1341
1342 if (RepOnly)
1343 exit(0);
1344
77f8c4bb 1345 /* tell about changing erase, kill and interrupt characters */
6a19f69a
BJ
1346 reportek("Erase", curerase, olderase, OLDERASE);
1347 reportek("Kill", curkill, oldkill, OLDKILL);
77f8c4bb 1348 reportek("Interrupt", curintr, oldintr, OLDINTR);
177ed6dd
BJ
1349
1350# ifdef V6
1351 /* update htmp */
1352 if (!Dash_u)
1353 {
1354 if (Ttyid == 0)
1355 Ttyid = ttyn(FILEDES);
1356 if (Ttyid == 'x')
1357 {
1358 prs("Cannot update htmp\n");
1359 flush();
1360 }
1361 else
1362 {
1363 /* update htmp file only if changed */
1364 if (!bequal(Capbuf, hsgettype(), 2))
1365 {
1366 hsettype(Capbuf[0] | (Capbuf[1] << 8));
1367 hput(Ttyid);
1368 }
1369 }
1370 }
1371# endif
1372
1373 exit(0);
1374}
1375
6a19f69a
BJ
1376/*
1377 * Set the hardware tabs on the terminal, using the ct (clear all tabs),
1378 * st (set one tab) and ch (horizontal cursor addressing) capabilities.
1379 * This is done before if and is, so they can patch in case we blow this.
1380 */
1381settabs()
1382{
1383 char caps[100];
1384 char *capsp = caps;
1385 char *clear_tabs, *set_tab, *set_column, *set_pos;
1386 char *tg_out, *tgoto();
48e4fbf9 1387 int c;
6a19f69a
BJ
1388
1389 clear_tabs = tgetstr("ct", &capsp);
1390 set_tab = tgetstr("st", &capsp);
1391 set_column = tgetstr("ch", &capsp);
1392 if (set_column == 0)
1393 set_pos = tgetstr("cm", &capsp);
6a19f69a
BJ
1394
1395 if (clear_tabs && set_tab) {
1396 prc('\r'); /* force to be at left margin */
1397 tputs(clear_tabs, 0, prc);
1398 }
1399 if (set_tab) {
1400 for (c=8; c<columns; c += 8) {
1401 /* get to that column. */
1402 tg_out = "OOPS"; /* also returned by tgoto */
1403 if (set_column)
1404 tg_out = tgoto(set_column, 0, c);
1405 if (*tg_out == 'O' && set_pos)
1406 tg_out = tgoto(set_pos, c, lines-1);
1407 if (*tg_out != 'O')
1408 tputs(tg_out, 1, prc);
1409 else {
1410 prc(' '); prc(' '); prc(' '); prc(' ');
1411 prc(' '); prc(' '); prc(' '); prc(' ');
1412 }
1413 /* set the tab */
1414 tputs(set_tab, 0, prc);
1415 }
1416 prc('\r');
1417 return 1;
1418 }
1419 return 0;
1420}
1421
1422setmode(flag)
1423int flag;
1424/* flag serves several purposes:
1425 * if called as the result of a signal, flag will be > 0.
1426 * if called from terminal init, flag == -1 means reset "oldmode".
1427 * called with flag == 0 at end of normal mode processing.
1428 */
1429{
1430# ifndef USG
1431 struct sgttyb *ttymode;
1432# else
1433 struct termio *ttymode;
1434# endif
537a9a14
JB
1435# ifdef TIOCGETC
1436 struct tchars *ttytchars;
1437# endif
6a19f69a 1438
537a9a14 1439 if (flag < 0) { /* unconditionally reset oldmode (called from init) */
6a19f69a 1440 ttymode = &oldmode;
537a9a14
JB
1441# ifdef TIOCGETC
1442 ttytchars = &oldtchar;
1443# endif
26a253fc 1444 } else if (!bequal((char *)&mode, (char *)&oldmode, sizeof mode)) {
6a19f69a 1445 ttymode = &mode;
537a9a14
JB
1446# ifdef TIOCGETC
1447 ttytchars = &tchar;
1448# endif
1449 } else { /* don't need it */
6a19f69a
BJ
1450# ifndef USG
1451 ttymode = (struct sgttyb *)0;
1452# else
1453 ttymode = (struct termio *)0;
1454# endif
537a9a14
JB
1455# ifdef TIOCGETC
1456 ttytchars = (struct tchars *)0;
1457# endif
1458 }
6a19f69a
BJ
1459
1460 if (ttymode)
1461 {
1462# ifdef USG
26a253fc 1463 (void) ioctl(FILEDES, TCSETAW, (char *)ttymode);
6a19f69a
BJ
1464# else
1465# ifndef V6
26a253fc
JB
1466 /* don't flush */
1467 (void) ioctl(FILEDES, TIOCSETN, (char *)ttymode);
6a19f69a
BJ
1468# else
1469 stty(FILEDES, ttymode);
1470# endif
1471# endif
1472 }
537a9a14
JB
1473# ifdef TIOCGETC
1474 if (ttytchars) {
26a253fc 1475 (void) ioctl(FILEDES, TIOCSETC, (char *)ttytchars);
537a9a14
JB
1476 }
1477# endif
6a19f69a
BJ
1478# ifdef CBVIRTTERM
1479 if (VirTermNo != -2) {
1480 int r1, r2;
1481 extern int errno;
1482
26a253fc 1483 r1 = ioctl(FILEDES, LDGETT, (char *)&block);
6a19f69a
BJ
1484 block.st_flgs |= TM_SET;
1485 block.st_termt = VirTermNo;
1486 if (block.st_termt < 0)
1487 block.st_termt = 0;
1488 if (!HasAM)
1489 block.st_flgs |= TM_ANL;
1490 else
1491 block.st_flgs &= ~TM_ANL;
26a253fc 1492 r2 = ioctl(FILEDES, LDSETT, (char *)&block);
6a19f69a
BJ
1493 }
1494# endif
1495
1496 if (flag > 0) /* trapped signal */
1497 exit(1);
1498}
1499
177ed6dd
BJ
1500reportek(name, new, old, def)
1501char *name;
1502char old;
1503char new;
1504char def;
1505{
1506 register char o;
1507 register char n;
1508 register char *p;
6a19f69a
BJ
1509 char buf[32];
1510 char *bufp;
177ed6dd
BJ
1511
1512 if (BeQuiet)
1513 return;
1514 o = old;
1515 n = new;
1516
1517 if (o == n && n == def)
1518 return;
1519 prs(name);
1520 if (o == n)
1521 prs(" is ");
1522 else
1523 prs(" set to ");
6a19f69a
BJ
1524 bufp = buf;
1525 if (tgetstr("kb", &bufp) > 0 && n == buf[0] && buf[1] == NULL)
1526 prs("Backspace\n");
1527 else if (n == 0177)
1528 prs("Delete\n");
1529 else
177ed6dd 1530 {
6a19f69a
BJ
1531 if (n < 040)
1532 {
1533 prs("Ctrl-");
1534 n ^= 0100;
1535 }
1536 p = "x\n";
1537 p[0] = n;
1538 prs(p);
177ed6dd 1539 }
177ed6dd
BJ
1540 flush();
1541}
1542
1543
1544
1545
1546setdelay(cap, dtab, bits, flags)
1547char *cap;
1548struct delay dtab[];
1549int bits;
d3c31938 1550short *flags;
177ed6dd
BJ
1551{
1552 register int i;
1553 register struct delay *p;
6a19f69a
BJ
1554# ifdef V6
1555 extern int ospeed;
1556# else
1557 extern short ospeed;
1558# endif
177ed6dd
BJ
1559
1560 /* see if this capability exists at all */
1561 i = tgetnum(cap);
1562 if (i < 0)
1563 i = 0;
6a19f69a
BJ
1564 /* No padding at speeds below PadBaud */
1565 if (PadBaud > ospeed)
1566 i = 0;
177ed6dd
BJ
1567
1568 /* clear out the bits, replace with new ones */
1569 *flags &= ~bits;
1570
1571 /* scan dtab for first entry with adequate delay */
1572 for (p = dtab; p->d_delay >= 0; p++)
1573 {
1574 if (p->d_delay >= i)
1575 {
1576 p++;
1577 break;
1578 }
1579 }
1580
1581 /* use last entry if none will do */
1582 *flags |= (--p)->d_bits;
1583}
1584
1585
1586prs(s)
1587char *s;
1588{
1589 while (*s != '\0')
1590 prc(*s++);
1591}
1592
1593
1594char OutBuf[256];
1595int OutPtr;
1596
1597prc(c)
6a19f69a 1598char c;
177ed6dd
BJ
1599{
1600 OutBuf[OutPtr++] = c;
1601 if (OutPtr >= sizeof OutBuf)
1602 flush();
1603}
1604
1605flush()
1606{
1607 if (OutPtr > 0)
26a253fc 1608 (void) write(2, OutBuf, OutPtr);
177ed6dd
BJ
1609 OutPtr = 0;
1610}
1611
1612
1613cat(file)
1614char *file;
1615{
1616 register int fd;
1617 register int i;
1618 char buf[BUFSIZ];
1619
1620 fd = open(file, 0);
1621 if (fd < 0)
1622 {
1623 prs("Cannot open ");
1624 prs(file);
1625 prs("\n");
1626 flush();
6a19f69a 1627 return;
177ed6dd
BJ
1628 }
1629
177ed6dd 1630 while ((i = read(fd, buf, BUFSIZ)) > 0)
26a253fc 1631 (void) write(FILEDES, buf, i);
177ed6dd 1632
26a253fc 1633 (void) close(fd);
177ed6dd
BJ
1634}
1635
1636
1637
1638bmove(from, to, length)
1639char *from;
1640char *to;
1641int length;
1642{
1643 register char *p, *q;
1644 register int i;
1645
1646 i = length;
1647 p = from;
1648 q = to;
1649
1650 while (i-- > 0)
1651 *q++ = *p++;
1652}
1653
1654
1655
6a19f69a 1656bequal(a, b, len) /* must be same thru len chars */
177ed6dd
BJ
1657char *a;
1658char *b;
1659int len;
1660{
1661 register char *p, *q;
1662 register int i;
1663
1664 i = len;
1665 p = a;
1666 q = b;
1667
dad88ed7 1668 while ((*p == *q) && --i > 0)
177ed6dd
BJ
1669 {
1670 p++; q++;
1671 }
1672 return ((*p == *q) && i >= 0);
1673}
1674
6a19f69a 1675sequal(a, b) /* must be same thru NULL */
177ed6dd
BJ
1676char *a;
1677char *b;
1678{
1679 register char *p = a, *q = b;
1680
1681 while (*p && *q && (*p == *q))
1682 {
1683 p++; q++;
1684 }
1685 return (*p == *q);
1686}
1687
6a19f69a
BJ
1688makealias(buf)
1689char *buf;
1690{
1691 register int i;
1692 register char *a;
1693 register char *b;
1694
1695 Alias[0] = a = Aliasbuf;
1696 b = buf;
1697 i = 1;
1698 while (*b && *b != ':') {
1699 if (*b == '|') {
1700 *a++ = NULL;
1701 Alias[i++] = a;
1702 b++;
1703 }
1704 else
1705 *a++ = *b++;
1706 }
1707 *a = NULL;
1708 Alias[i] = NULL;
1709# ifdef DEB
1710 for(i = 0; Alias[i]; printf("A:%s\n", Alias[i++]));
1711# endif
1712}
1713
1714isalias(ident) /* is ident same as one of the aliases? */
1715char *ident;
1716{
1717 char **a = Alias;
1718
1719 if (*a)
1720 while (*a)
1721 if (sequal(ident, *a))
1722 return(YES);
1723 else
1724 a++;
1725 return(NO);
1726}
1727
177ed6dd
BJ
1728# ifdef GTTYN
1729char *
1730stypeof(ttyid)
1731char *ttyid;
1732{
177ed6dd 1733 register char *PortType;
177ed6dd 1734 register char *TtyId;
9479aa87 1735 struct ttyent *t;
177ed6dd
BJ
1736
1737 if (ttyid == NOTTY)
1738 return (DEFTYPE);
177ed6dd
BJ
1739
1740 /* split off end of name */
1741 TtyId = ttyid;
1742 while (*ttyid)
1743 if (*ttyid++ == '/')
1744 TtyId = ttyid;
1745
1746 /* scan the file */
9479aa87 1747 if ((t = getttynam(TtyId)) != NULL)
177ed6dd 1748 {
9479aa87
BJ
1749 PortType = t->ty_type;
1750 /* get aliases from termcap entry */
1751 if (Mapped && tgetent(Capbuf, PortType) > 0) {
1752 makealias(Capbuf);
1753 if (sequal(Alias[0], PortType) && Alias[1])
1754 PortType = Alias[1];
177ed6dd 1755 }
9479aa87 1756 return (PortType);
177ed6dd 1757 }
177ed6dd
BJ
1758 return (DEFTYPE);
1759}
1760# endif
1761
177ed6dd
BJ
1762/*
1763 * routine to output the string for the environment TERMCAP variable
1764 */
1765#define WHITE(c) (c == ' ' || c == '\t')
1766char delcap[128][2];
1767int ncap = 0;
1768
1769wrtermcap(bp)
1770char *bp;
1771{
1772 char buf[CAPBUFSIZ];
1773 char *p = buf;
1774 char *tp;
1775 char *putbuf();
1776 int space, empty;
26a253fc
JB
1777# ifdef CBVIRTTERM
1778 register int i;
1779# endif CBVIRTTERM
177ed6dd
BJ
1780
1781 /* discard names with blanks */
1782/** May not be desireable ? **/
1783 while (*bp && *bp != ':') {
1784 if (*bp == '|') {
1785 tp = bp+1;
1786 space = NO;
1787 while (*tp && *tp != '|' && *tp != ':') {
1788 space = (space || WHITE(*tp) );
1789 tp++;
1790 }
1791 if (space) {
1792 bp = tp;
1793 continue;
1794 }
1795 }
1796 *p++ = *bp++;
1797 }
1798/**/
1799
6a19f69a
BJ
1800# ifdef CBVIRTTERM
1801 if (VirTermNo > 0) {
1802 p = putbuf(p, ":am"); /* All virt terms have auto margins */
1803 cancelled("am");
1804 }
1805# endif
177ed6dd
BJ
1806 while (*bp) {
1807 switch (*bp) {
1808 case ':': /* discard empty, cancelled or dupl fields */
1809 tp = bp+1;
1810 empty = YES;
1811 while (*tp && *tp != ':') {
1812 empty = (empty && WHITE(*tp) );
1813 tp++;
1814 }
6a19f69a
BJ
1815# ifdef CBVIRTTERM
1816 /*
1817 * Virtual terminals use ic, not im or ei. Turn
1818 * any of them into ic - duplicates will be cancelled
1819 * below. I assume that terminals needing im+ic+ei
1820 * are handled by the kernel.
1821 */
1822 if (VirTermNo > 0 && !HasAM &&
1823 (bp[1]=='i' && bp[2]=='m' ||
1824 bp[1]=='e' && bp[2]=='i')) {
1825 bp[1] = 'i';
1826 bp[2] = 'c';
1827 }
1828 if (VirTermNo > 0 && !HasAM &&
1829 (bp[1]=='c' && bp[2]=='s')) {
1830 bp[1] = 'd';
1831 bp[2] = 'l';
1832 /* Also need al, so kludge: */
1833 if (!cancelled("al"))
1834 p = putbuf(p, ":al=\033\120");
1835 }
1836# endif CBVIRTTERM
177ed6dd
BJ
1837 if (empty || cancelled(bp+1)) {
1838 bp = tp;
1839 continue;
1840 }
6a19f69a
BJ
1841# ifdef CBVIRTTERM
1842 if (VirTermNo > 0 && !HasAM)
1843 for (i = 0; vtab[i].value; i++) {
1844 if (vtab[i].cap[0] == bp[1] &&
1845 vtab[i].cap[1] == bp[2]) {
1846 *p++ = *bp++; /* colon */
1847 *p++ = *bp++; /* first char */
1848 *p++ = *bp++; /* second " */
1849 *p++ = *bp++; /* = sign */
1850 p = putbuf(p, vtab[i].value);
1851 bp = tp;
1852 goto contin;
1853 }
1854 }
1855# endif CBVIRTTERM
177ed6dd
BJ
1856 break;
1857
1858 case ' ': /* no spaces in output */
1859 p = putbuf(p, "\\040");
1860 bp++;
1861 continue;
1862
6a19f69a
BJ
1863 case '!': /* the shell thinks this is history */
1864 p = putbuf(p, "\\041");
1865 bp++;
1866 continue;
1867
1868 case ',': /* the shell thinks this is history */
1869 p = putbuf(p, "\\054");
1870 bp++;
1871 continue;
1872
177ed6dd
BJ
1873 case '"': /* no quotes in output */
1874 p = putbuf(p, "\\042");
1875 bp++;
1876 continue;
1877
1878 case '\'': /* no quotes in output */
1879 p = putbuf(p, "\\047");
1880 bp++;
1881 continue;
1882
6a19f69a
BJ
1883 case '`': /* no back quotes in output */
1884 p = putbuf(p, "\\140");
1885 bp++;
1886 continue;
1887
177ed6dd
BJ
1888 case '\\':
1889 case '^': /* anything following is OK */
1890 *p++ = *bp++;
6a19f69a
BJ
1891# ifdef CBVIRTTERM
1892 if (*bp == 'E' && VirTermNo > 0 &&
1893 (bp[-3]!='\\'||bp[-2]!='E') &&
1894 (bp[1]!='\\'||bp[2]!='E'))
1895 p = putbuf(p, "E\\");
1896# endif CBVIRTTERM
177ed6dd
BJ
1897 }
1898 *p++ = *bp++;
26a253fc 1899# ifdef CBVIRTTERM
6a19f69a 1900contin: ;
26a253fc 1901# endif CBVIRTTERM
177ed6dd 1902 }
6a19f69a 1903 *p++ = ':'; /* we skipped the last : with the : lookahead hack */
26a253fc 1904 (void) write (STDOUT, buf, p-buf);
177ed6dd
BJ
1905}
1906
1907cancelled(cap)
1908char *cap;
1909{
1910 register int i;
1911
1912 for (i = 0; i < ncap; i++)
1913 {
1914 if (cap[0] == delcap[i][0] && cap[1] == delcap[i][1])
1915 return (YES);
1916 }
1917 /* delete a second occurrance of the same capability */
1918 delcap[ncap][0] = cap[0];
1919 delcap[ncap][1] = cap[1];
1920 ncap++;
1921 return (cap[2] == '@');
1922}
1923
1924char *
1925putbuf(ptr, str)
1926char *ptr;
1927char *str;
1928{
6a19f69a
BJ
1929 char buf[20];
1930
1931 while (*str) {
1932 switch (*str) {
1933 case '\033':
1934 ptr = putbuf(ptr, "\\E");
1935 str++;
1936 break;
1937 default:
1938 if (*str <= ' ') {
26a253fc 1939 (void) sprintf(buf, "\\%03o", *str);
6a19f69a
BJ
1940 ptr = putbuf(ptr, buf);
1941 str++;
1942 } else
1943 *ptr++ = *str++;
1944 }
1945 }
177ed6dd
BJ
1946 return (ptr);
1947}
1948
1949
1950baudrate(p)
1951char *p;
1952{
1953 char buf[8];
1954 int i = 0;
1955
1956 while (i < 7 && (isalnum(*p) || *p == '.'))
1957 buf[i++] = *p++;
1958 buf[i] = NULL;
1959 for (i=0; speeds[i].string; i++)
1960 if (sequal(speeds[i].string, buf))
1961 return (speeds[i].speed);
1962 return (-1);
1963}
1964
1965char *
6a19f69a 1966mapped(type)
177ed6dd 1967char *type;
177ed6dd 1968{
6a19f69a
BJ
1969# ifdef V6
1970 extern int ospeed;
1971# else
1972 extern short ospeed;
1973# endif
177ed6dd
BJ
1974 int match;
1975
1976# ifdef DEB
6a19f69a 1977 printf ("spd:%d\n", ospeed);
177ed6dd
BJ
1978 prmap();
1979# endif
1980 Map = map;
1981 while (Map->Ident)
1982 {
6a19f69a 1983 if (*(Map->Ident) == NULL || sequal(Map->Ident, type) || isalias(Map->Ident))
177ed6dd
BJ
1984 {
1985 match = NO;
1986 switch (Map->Test)
1987 {
1988 case ANY: /* no test specified */
1989 case ALL:
1990 match = YES;
1991 break;
1992
1993 case GT:
6a19f69a 1994 match = (ospeed > Map->Speed);
177ed6dd
BJ
1995 break;
1996
1997 case GE:
6a19f69a 1998 match = (ospeed >= Map->Speed);
177ed6dd
BJ
1999 break;
2000
2001 case EQ:
6a19f69a 2002 match = (ospeed == Map->Speed);
177ed6dd
BJ
2003 break;
2004
2005 case LE:
6a19f69a 2006 match = (ospeed <= Map->Speed);
177ed6dd
BJ
2007 break;
2008
2009 case LT:
6a19f69a 2010 match = (ospeed < Map->Speed);
177ed6dd
BJ
2011 break;
2012
2013 case NE:
6a19f69a 2014 match = (ospeed != Map->Speed);
177ed6dd
BJ
2015 break;
2016 }
2017 if (match)
2018 return (Map->Type);
2019 }
2020 Map++;
2021 }
2022 /* no match found; return given type */
2023 return (type);
2024}
2025
2026# ifdef DEB
2027prmap()
2028{
2029 Map = map;
2030 while (Map->Ident)
2031 {
2032 printf ("%s t:%d s:%d %s\n",
2033 Map->Ident, Map->Test, Map->Speed, Map->Type);
2034 Map++;
2035 }
2036}
2037# endif
2038
2039char *
2040nextarg(argc, argv)
2041int argc;
2042char *argv[];
2043{
2044 if (argc <= 0)
2045 fatal ("Too few args: ", *argv);
2046 if (*(*++argv) == '-')
2047 fatal ("Unexpected arg: ", *argv);
2048 return (*argv);
2049}
2050
2051fatal (mesg, obj)
2052char *mesg;
2053char *obj;
2054{
2055 prs (mesg);
2056 prs (obj);
2057 prc ('\n');
2058 prs (USAGE);
2059 flush();
2060 exit(1);
2061}