add Berkeley specific header, minor cleanup
[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
cf63ef11 14static char sccsid[] = "@(#)tset.c 5.9 (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();
cf63ef11
KB
499extern char *tgetstr();
500extern int prc();
26a253fc 501
177ed6dd
BJ
502struct delay
503{
504 int d_delay;
505 int d_bits;
506};
507
508# include "tset.delays.h"
509
6a19f69a
BJ
510# ifndef USG
511struct sgttyb mode;
512struct sgttyb oldmode;
537a9a14
JB
513struct tchars tchar;
514struct tchars oldtchar;
6a19f69a
BJ
515# else
516struct termio mode;
517struct termio oldmode;
518# endif
519# ifdef CBVIRTTERM
520struct termcb block = {0, 2, 0, 0, 0, 20};
521# endif CBVIRTTERM
177ed6dd
BJ
522
523
524main(argc, argv)
525int argc;
526char *argv[];
527{
dad1b0b2 528 char buf[CAPBUFSIZ];
6a19f69a 529 char termbuf[32];
177ed6dd
BJ
530 auto char *bufp;
531 register char *p;
532 char *command;
533 register int i;
26a253fc 534# ifdef CBVIRTTERM
6a19f69a 535 int j;
26a253fc 536# endif CBVIRTTERM
177ed6dd
BJ
537 int Break;
538 int Not;
6a19f69a
BJ
539 char *nextarg();
540 char *mapped();
541 extern char *rindex();
48e4fbf9 542 struct winsize win;
177ed6dd
BJ
543# ifdef V6
544 extern char *hsgettype();
545# else
546 extern char *getenv();
547# endif
548# ifdef GTTYN
6a19f69a 549 char *stypeof();
177ed6dd 550 extern char *ttyname();
177ed6dd
BJ
551# endif
552 char bs_char;
553 int csh;
6a19f69a
BJ
554 int settle;
555 int setmode();
177ed6dd 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;
607
608 if (ldisc == NTTYDISC)
609 {
26a253fc 610 (void) ioctl(FILEDES, TIOCGLTC, (char *)&ltc);
0b1d4860
JB
611 ltc.t_suspc = CHK(ltc.t_suspc, CSUSP);
612 ltc.t_dsuspc = CHK(ltc.t_dsuspc, CDSUSP);
613 ltc.t_rprntc = CHK(ltc.t_rprntc, CRPRNT);
614 ltc.t_flushc = CHK(ltc.t_flushc, CFLUSH);
615 ltc.t_werasc = CHK(ltc.t_werasc, CWERASE);
616 ltc.t_lnextc = CHK(ltc.t_lnextc, CLNEXT);
26a253fc 617 (void) ioctl(FILEDES, TIOCSLTC, (char *)&ltc);
6a19f69a
BJ
618 }
619# endif UCB_NTTY
620# ifndef USG
621# ifdef TIOCGETC
0b1d4860
JB
622 tchar.t_intrc = CHK(tchar.t_intrc, CINTR);
623 tchar.t_quitc = CHK(tchar.t_quitc, CQUIT);
624 tchar.t_startc = CHK(tchar.t_startc, CSTART);
625 tchar.t_stopc = CHK(tchar.t_stopc, CSTOP);
626 tchar.t_eofc = CHK(tchar.t_eofc, CEOF);
6a19f69a 627 /* brkc is left alone */
26a253fc 628 (void) ioctl(FILEDES, TIOCSETC, (char *)&tchar);
6a19f69a
BJ
629# endif TIOCGETC
630 mode.sg_flags &= ~(RAW
631# ifdef CBREAK
632 |CBREAK
633# endif CBREAK
634 |VTDELAY|ALLDELAY);
635 mode.sg_flags |= XTABS|ECHO|CRMOD|ANYP;
0b1d4860
JB
636 curerase = CHK(curerase, CERASE);
637 curkill = CHK(curkill, CKILL);
638 curintr = CHK(curintr, CINTR);
6a19f69a 639# else USG
26a253fc 640 (void) ioctl(FILEDES, TCGETA, (char *)&mode);
6a19f69a
BJ
641 curerase = CHK(curerase, OLDERASE);
642 curkill = CHK(curkill, OLDKILL);
0b1d4860
JB
643 curintr = CHK(curintr, OLDINTR);
644 mode.c_cc[VQUIT] = CHK(mode.c_cc[VQUIT], CQUIT);
645 mode.c_cc[VEOF] = CHK(mode.c_cc[VEOF], CEOF);
6a19f69a
BJ
646
647 mode.c_iflag |= (BRKINT|ISTRIP|ICRNL|IXON);
648 mode.c_iflag &= ~(IGNBRK|PARMRK|INPCK|INLCR|IGNCR|IUCLC|IXOFF);
649 mode.c_oflag |= (OPOST|ONLCR);
650 mode.c_oflag &= ~(OLCUC|OCRNL|ONOCR|ONLRET|OFILL|OFDEL|
651 NLDLY|CRDLY|TABDLY|BSDLY|VTDLY|FFDLY);
652 mode.c_cflag |= (CS7|CREAD);
653 mode.c_cflag &= ~(CSIZE|PARODD|CLOCAL);
654 mode.c_lflag |= (ISIG|ICANON|ECHO|ECHOK);
655 mode.c_lflag &= ~(XCASE|ECHONL|NOFLSH);
26a253fc 656 (void) ioctl(FILEDES, TCSETAW, (char *)&mode);
6a19f69a
BJ
657# endif USG
658# endif V6
659 Dash_u = YES;
660 BeQuiet = YES;
661 IsReset = YES;
662 }
663 else if (argc == 2 && sequal(argv[1], "-"))
664 {
665 RepOnly = YES;
666 Dash_u = YES;
177ed6dd
BJ
667 }
668 argc--;
6a19f69a
BJ
669
670 /* scan argument list and collect flags */
177ed6dd
BJ
671 while (--argc >= 0)
672 {
673 p = *++argv;
674 if (*p == '-')
675 {
676 if (*++p == NULL)
6a19f69a 677 Report = YES; /* report current terminal type */
177ed6dd
BJ
678 else while (*p) switch (*p++)
679 {
680
6a19f69a
BJ
681# ifdef UCB_NTTY
682 case 'n':
683 ldisc = NTTYDISC;
26a253fc 684 if (ioctl(FILEDES, TIOCSETD, (char *)&ldisc)<0)
6a19f69a
BJ
685 fatal("ioctl ", "new");
686 continue;
687# endif
688
177ed6dd 689 case 'r': /* report to user */
6a19f69a 690 Ureport = YES;
177ed6dd
BJ
691 continue;
692
693 case 'E': /* special erase: operate on all but TTY33 */
6a19f69a 694 Specialerase = YES;
177ed6dd
BJ
695 /* explicit fall-through to -e case */
696
697 case 'e': /* erase character */
698 if (*p == NULL)
699 Erase_char = -1;
700 else
701 {
702 if (*p == '^' && p[1] != NULL)
0b1d4860
JB
703 if (*++p == '?')
704 Erase_char = '\177';
705 else
706 Erase_char = CNTL(*p);
177ed6dd
BJ
707 else
708 Erase_char = *p;
709 p++;
710 }
711 continue;
712
537a9a14 713# if defined(USG) || defined(TIOCGETC)
0b1d4860 714 case 'i': /* interrupt character */
537a9a14 715 if (*p == NULL)
0b1d4860 716 Intr_char = CNTL('C');
537a9a14
JB
717 else
718 {
719 if (*p == '^' && p[1] != NULL)
0b1d4860
JB
720 if (*++p == '?')
721 Intr_char = '\177';
722 else
723 Intr_char = CNTL(*p);
537a9a14
JB
724 else
725 Intr_char = *p;
726 p++;
727 }
728 continue;
729# endif
730
177ed6dd
BJ
731 case 'k': /* kill character */
732 if (*p == NULL)
0b1d4860 733 Kill_char = CNTL('X');
177ed6dd
BJ
734 else
735 {
736 if (*p == '^' && p[1] != NULL)
0b1d4860
JB
737 if (*++p == '?')
738 Kill_char = '\177';
739 else
740 Kill_char = CNTL(*p);
177ed6dd
BJ
741 else
742 Kill_char = *p;
743 p++;
744 }
745 continue;
746
747# ifdef OLDFLAGS
748# ifdef OLDDIALUP
749 case 'd': /* dialup type */
750 NewType = DIALUP;
751 goto mapold;
752# endif
753
754# ifdef OLDPLUGBOARD
755 case 'p': /* plugboard type */
756 NewType = PLUGBOARD;
757 goto mapold;
758# endif
759
760# ifdef OLDARPANET
761 case 'a': /* arpanet type */
762 Newtype = ARPANET;
763 goto mapold;
764# endif
765
766mapold: Map->Ident = NewType;
767 Map->Test = ALL;
768 if (*p == NULL)
769 {
770 p = nextarg(argc--, argv++);
771 }
772 Map->Type = p;
773 Map++;
6a19f69a 774 Mapped = YES;
177ed6dd
BJ
775 p = "";
776 continue;
777# endif
778
779 case 'm': /* map identifier to type */
780 /* This code is very loose. Almost no
781 ** syntax checking is done!! However,
782 ** illegal syntax will only produce
783 ** weird results.
784 */
785 if (*p == NULL)
786 {
787 p = nextarg(argc--, argv++);
788 }
789 if (isalnum(*p))
790 {
791 Map->Ident = p; /* identifier */
792 while (isalnum(*p)) p++;
793 }
794 else
795 Map->Ident = "";
6a19f69a
BJ
796 Break = NO;
797 Not = NO;
177ed6dd
BJ
798 while (!Break) switch (*p)
799 {
800 case NULL:
801 p = nextarg(argc--, argv++);
802 continue;
803
804 case ':': /* mapped type */
805 *p++ = NULL;
6a19f69a 806 Break = YES;
177ed6dd
BJ
807 continue;
808
809 case '>': /* conditional */
810 Map->Test |= GT;
811 *p++ = NULL;
812 continue;
813
814 case '<': /* conditional */
815 Map->Test |= LT;
816 *p++ = NULL;
817 continue;
818
819 case '=': /* conditional */
820 case '@':
821 Map->Test |= EQ;
822 *p++ = NULL;
823 continue;
824
825 case '!': /* invert conditions */
826 Not = ~Not;
827 *p++ = NULL;
828 continue;
829
830 case 'B': /* Baud rate */
831 p++;
832 /* intentional fallthru */
833 default:
834 if (isdigit(*p) || *p == 'e')
835 {
836 Map->Speed = baudrate(p);
837 while (isalnum(*p) || *p == '.')
838 p++;
839 }
840 else
6a19f69a 841 Break = YES;
177ed6dd
BJ
842 continue;
843 }
844 if (Not) /* invert sense of test */
845 {
846 Map->Test = (~(Map->Test))&ALL;
847 }
848 if (*p == NULL)
849 {
850 p = nextarg(argc--, argv++);
851 }
852 Map->Type = p;
853 p = "";
854 Map++;
6a19f69a 855 Mapped = YES;
177ed6dd
BJ
856 continue;
857
858 case 'h': /* don't get type from htmp or env */
6a19f69a 859 Dash_h = YES;
177ed6dd
BJ
860 continue;
861
862 case 'u': /* don't update htmp */
6a19f69a 863 Dash_u = YES;
177ed6dd
BJ
864 continue;
865
866 case 's': /* output setenv commands */
6a19f69a
BJ
867 DoSetenv = YES;
868 CmndLine = YES;
177ed6dd
BJ
869 continue;
870
871 case 'S': /* output setenv strings */
6a19f69a
BJ
872 DoSetenv = YES;
873 CmndLine = NO;
177ed6dd
BJ
874 continue;
875
876 case 'Q': /* be quiet */
6a19f69a 877 BeQuiet = YES;
177ed6dd
BJ
878 continue;
879
880 case 'I': /* no initialization */
6a19f69a 881 NoInit = YES;
177ed6dd
BJ
882 continue;
883
884 case 'A': /* Ask user */
6a19f69a
BJ
885 Ask = YES;
886 continue;
887
888 case 'v': /* no virtual terminal */
889 DoVirtTerm = NO;
177ed6dd
BJ
890 continue;
891
892 default:
893 *p-- = NULL;
894 fatal("Bad flag -", p);
895 }
896 }
897 else
898 {
899 /* terminal type */
900 DefType = p;
901 }
902 }
903
904 if (DefType)
905 {
906 if (Mapped)
907 {
908 Map->Ident = ""; /* means "map any type" */
909 Map->Test = ALL; /* at all baud rates */
910 Map->Type = DefType; /* to the default type */
911 }
912 else
913 TtyType = DefType;
914 }
915
916# ifndef V6
6a19f69a
BJ
917 /*
918 * Get rid of $TERMCAP, if it's there, so we get a real
919 * entry from /etc/termcap. This prevents us from being
920 * fooled by out of date stuff in the environment, and
921 * makes tabs work right on CB/Unix.
922 */
923 bufp = getenv("TERMCAP");
924 if (bufp && *bufp != '/')
26a253fc 925 (void) strcpy(bufp-8, "NOTHING"); /* overwrite only "TERMCAP" */
177ed6dd 926 /* get current idea of terminal type from environment */
8d1e1d87 927 if (!Dash_h && TtyType == 0)
177ed6dd
BJ
928 TtyType = getenv("TERM");
929# endif
930
931 /* determine terminal id if needed */
932# ifdef V6
933 if (Ttyid == NOTTY && (TtyType == 0 || !Dash_h || !Dash_u))
934 Ttyid = ttyn(FILEDES);
935# else
936 if (!RepOnly && Ttyid == NOTTY && (TtyType == 0 || !Dash_h))
937 Ttyid = ttyname(FILEDES);
938# endif
939
940# ifdef V6
941 /* get htmp if ever used */
942 if (!Dash_u || (TtyType == 0 && !Dash_h))
943 {
944 /* get htmp entry -- if error or wrong user use ttytype */
945 if (Ttyid == NOTTY || hget(Ttyid) < 0 ||
946 hgettype() == 0 || hgetuid() != (getuid() & UIDMASK))
947 Dash_h++;
948 }
949
950 /* find terminal type (if not already known) */
951 if (TtyType == 0 && !Dash_h)
952 {
953 /* get type from /etc/htmp */
954 TtyType = hsgettype();
955 }
956# endif
957
958# ifdef GTTYN
959 /* If still undefined, look at /etc/ttytype */
960 if (TtyType == 0)
961 {
962 TtyType = stypeof(Ttyid);
963 }
964# endif
965
966 /* If still undefined, use DEFTYPE */
967 if (TtyType == 0)
968 {
969 TtyType = DEFTYPE;
970 }
971
972 /* check for dialup or other mapping */
973 if (Mapped)
6d31b7ce
EW
974 {
975 if (!(Alias[0] && isalias(TtyType)))
976 if (tgetent(Capbuf, TtyType) > 0)
977 makealias(Capbuf);
6a19f69a 978 TtyType = mapped(TtyType);
6d31b7ce 979 }
177ed6dd
BJ
980
981 /* TtyType now contains a pointer to the type of the terminal */
982 /* If the first character is '?', ask the user */
983 if (TtyType[0] == '?')
984 {
6a19f69a 985 Ask = YES;
177ed6dd
BJ
986 TtyType++;
987 if (TtyType[0] == '\0')
988 TtyType = DEFTYPE;
989 }
990 if (Ask)
991 {
dad1b0b2 992ask:
177ed6dd
BJ
993 prs("TERM = (");
994 prs(TtyType);
995 prs(") ");
996 flush();
997
998 /* read the terminal. If not empty, set type */
6a19f69a
BJ
999 i = read(2, termbuf, sizeof termbuf - 1);
1000 if (i > 0)
177ed6dd 1001 {
6a19f69a 1002 if (termbuf[i - 1] == '\n')
177ed6dd 1003 i--;
6a19f69a
BJ
1004 termbuf[i] = '\0';
1005 if (termbuf[0] != '\0')
1006 TtyType = termbuf;
177ed6dd
BJ
1007 }
1008 }
1009
6a19f69a
BJ
1010 /* get terminal capabilities */
1011 if (!(Alias[0] && isalias(TtyType))) {
177ed6dd
BJ
1012 switch (tgetent(Capbuf, TtyType))
1013 {
1014 case -1:
6a19f69a 1015 prs("Cannot find termcap\n");
177ed6dd
BJ
1016 flush();
1017 exit(-1);
1018
1019 case 0:
1020 prs("Type ");
1021 prs(TtyType);
1022 prs(" unknown\n");
1023 flush();
6a19f69a
BJ
1024 if (DoSetenv)
1025 {
1026 TtyType = DEFTYPE;
dad1b0b2
S
1027 Alias[0] = '\0';
1028 goto ask;
6a19f69a
BJ
1029 }
1030 else
1031 exit(1);
177ed6dd 1032 }
177ed6dd 1033 }
6a19f69a 1034 Ttycap = Capbuf;
177ed6dd
BJ
1035
1036 if (!RepOnly)
1037 {
1038 /* determine erase and kill characters */
1039 if (Specialerase && !tgetflag("bs"))
1040 Erase_char = 0;
1041 bufp = buf;
1042 p = tgetstr("kb", &bufp);
1043 if (p == NULL || p[1] != '\0')
1044 p = tgetstr("bc", &bufp);
1045 if (p != NULL && p[1] == '\0')
1046 bs_char = p[0];
1047 else if (tgetflag("bs"))
1048 bs_char = BACKSPACE;
1049 else
1050 bs_char = 0;
6a19f69a 1051 if (Erase_char == 0 && !tgetflag("os") && curerase == OLDERASE)
177ed6dd
BJ
1052 {
1053 if (tgetflag("bs") || bs_char != 0)
1054 Erase_char = -1;
1055 }
1056 if (Erase_char < 0)
1057 Erase_char = (bs_char != 0) ? bs_char : BACKSPACE;
1058
6a19f69a 1059 if (curerase == 0)
0b1d4860 1060 curerase = CERASE;
177ed6dd 1061 if (Erase_char != 0)
6a19f69a 1062 curerase = Erase_char;
177ed6dd 1063
537a9a14 1064 if (curintr == 0)
0b1d4860 1065 curintr = CINTR;
537a9a14
JB
1066 if (Intr_char != 0)
1067 curintr = Intr_char;
1068
6a19f69a 1069 if (curkill == 0)
0b1d4860 1070 curkill = CKILL;
177ed6dd 1071 if (Kill_char != 0)
6a19f69a 1072 curkill = Kill_char;
177ed6dd
BJ
1073
1074 /* set modes */
6a19f69a
BJ
1075 PadBaud = tgetnum("pb"); /* OK if fails */
1076 for (i=0; speeds[i].string; i++)
1077 if (speeds[i].baudrate == PadBaud) {
1078 PadBaud = speeds[i].speed;
1079 break;
1080 }
1081# ifndef USG
177ed6dd
BJ
1082 setdelay("dC", CRdelay, CRbits, &mode.sg_flags);
1083 setdelay("dN", NLdelay, NLbits, &mode.sg_flags);
1084 setdelay("dB", BSdelay, BSbits, &mode.sg_flags);
1085 setdelay("dF", FFdelay, FFbits, &mode.sg_flags);
1086 setdelay("dT", TBdelay, TBbits, &mode.sg_flags);
6a19f69a 1087 if (tgetflag("UC") || (command[0] & 0140) == 0100)
177ed6dd
BJ
1088 mode.sg_flags |= LCASE;
1089 else if (tgetflag("LC"))
1090 mode.sg_flags &= ~LCASE;
1091 mode.sg_flags &= ~(EVENP | ODDP | RAW);
6a19f69a 1092# ifdef CBREAK
177ed6dd
BJ
1093 mode.sg_flags &= ~CBREAK;
1094# endif
1095 if (tgetflag("EP"))
1096 mode.sg_flags |= EVENP;
1097 if (tgetflag("OP"))
1098 mode.sg_flags |= ODDP;
1099 if ((mode.sg_flags & (EVENP | ODDP)) == 0)
1100 mode.sg_flags |= EVENP | ODDP;
1101 mode.sg_flags |= CRMOD | ECHO | XTABS;
1102 if (tgetflag("NL")) /* new line, not line feed */
1103 mode.sg_flags &= ~CRMOD;
1104 if (tgetflag("HD")) /* half duplex */
1105 mode.sg_flags &= ~ECHO;
1106 if (tgetflag("pt")) /* print tabs */
1107 mode.sg_flags &= ~XTABS;
177ed6dd 1108# else
6a19f69a
BJ
1109 setdelay("dC", CRdelay, CRbits, &mode.c_oflag);
1110 setdelay("dN", NLdelay, NLbits, &mode.c_oflag);
1111 setdelay("dB", BSdelay, BSbits, &mode.c_oflag);
1112 setdelay("dF", FFdelay, FFbits, &mode.c_oflag);
1113 setdelay("dT", TBdelay, TBbits, &mode.c_oflag);
1114 setdelay("dV", VTdelay, VTbits, &mode.c_oflag);
1115
1116 if (tgetflag("UC") || (command[0] & 0140) == 0100) {
1117 mode.c_iflag |= IUCLC;
1118 mode.c_oflag |= OLCUC;
1119 }
1120 else if (tgetflag("LC")) {
1121 mode.c_iflag &= ~IUCLC;
1122 mode.c_oflag &= ~OLCUC;
1123 }
1124 mode.c_iflag &= ~(PARMRK|INPCK);
1125 mode.c_lflag |= ICANON;
1126 if (tgetflag("EP")) {
1127 mode.c_cflag |= PARENB;
1128 mode.c_cflag &= ~PARODD;
1129 }
1130 if (tgetflag("OP")) {
1131 mode.c_cflag |= PARENB;
1132 mode.c_cflag |= PARODD;
1133 }
1134
1135 mode.c_oflag |= ONLCR;
1136 mode.c_iflag |= ICRNL;
1137 mode.c_lflag |= ECHO;
1138 mode.c_oflag |= TAB3;
1139 if (tgetflag("NL")) { /* new line, not line feed */
1140 mode.c_oflag &= ~ONLCR;
1141 mode.c_iflag &= ~ICRNL;
1142 }
1143 if (tgetflag("HD")) /* half duplex */
1144 mode.c_lflag &= ~ECHO;
1145 if (tgetflag("pt")) /* print tabs */
1146 mode.c_oflag &= ~TAB3;
1147
1148 mode.c_lflag |= (ECHOE|ECHOK);
1149# endif
1150# ifdef CBVIRTTERM
1151 HasAM = tgetflag("am");
1152# endif CBVIRTTERM
1153# ifdef UCB_NTTY
1154 if (ldisc == NTTYDISC)
1155 {
1156 lmode |= LCTLECH; /* display ctrl chars */
1157 if (tgetflag("hc"))
1158 { /** set printer modes **/
1159 lmode &= ~(LCRTBS|LCRTERA|LCRTKIL);
1160 lmode |= LPRTERA;
1161 }
1162 else
1163 { /** set crt modes **/
1164 if (!tgetflag("os"))
1165 {
1166 lmode &= ~LPRTERA;
1167 lmode |= LCRTBS;
1168 if (mode.sg_ospeed >= B1200)
1169 lmode |= LCRTERA|LCRTKIL;
1170 }
1171 }
1172 }
521cc310
JL
1173 if (IsReset)
1174 lmode &= ~(LMDMBUF|LLITOUT|LPASS8);
26a253fc 1175 (void) ioctl(FILEDES, TIOCLSET, (char *)&lmode);
177ed6dd
BJ
1176# endif
1177
1178 /* get pad character */
1179 bufp = buf;
1180 if (tgetstr("pc", &bufp) != 0)
1181 PC = buf[0];
1182
48e4fbf9
JB
1183 columns = tgetnum("co");
1184 lines = tgetnum("li");
1185
1186 /* Set window size */
26a253fc 1187 (void) ioctl(FILEDES, TIOCGWINSZ, (char *)&win);
0b1d4860
JB
1188 if (win.ws_row == 0 && win.ws_col == 0 &&
1189 lines > 0 && columns > 0) {
1190 win.ws_row = lines;
1191 win.ws_col = columns;
26a253fc 1192 (void) ioctl(FILEDES, TIOCSWINSZ, (char *)&win);
48e4fbf9 1193 }
177ed6dd
BJ
1194 /* output startup string */
1195 if (!NoInit)
1196 {
6a19f69a
BJ
1197# ifndef USG
1198 if (oldmode.sg_flags&(XTABS|CRMOD))
1199 {
1200 oldmode.sg_flags &= ~(XTABS|CRMOD);
1201 setmode(-1);
1202 }
1203# else
1204 if (oldmode.c_oflag&(TAB3|ONLCR|OCRNL|ONLRET))
1205 {
1206 oldmode.c_oflag &= (TAB3|ONLCR|OCRNL|ONLRET);
1207 setmode(-1);
1208 }
1209# endif
1210# ifdef CBVIRTTERM
1211 block.st_termt = 0;
26a253fc 1212 (void) ioctl(FILEDES, LDSETT, (char *)&block);
6a19f69a
BJ
1213# endif CBVIRTTERM
1214 if (settabs()) {
1215 settle = YES;
1216 flush();
1217 }
177ed6dd 1218 bufp = buf;
0b1d4860
JB
1219 if (IsReset && tgetstr("rs", &bufp) != 0 ||
1220 tgetstr("is", &bufp) != 0)
6a19f69a 1221 {
177ed6dd 1222 tputs(buf, 0, prc);
6a19f69a
BJ
1223 settle = YES;
1224 flush();
1225 }
177ed6dd 1226 bufp = buf;
0b1d4860
JB
1227 if (IsReset && tgetstr("rf", &bufp) != 0 ||
1228 tgetstr("if", &bufp) != 0)
6a19f69a 1229 {
177ed6dd 1230 cat(buf);
6a19f69a
BJ
1231 settle = YES;
1232 }
1233 if (settle)
1234 {
1235 prc('\r');
1236 flush();
1237 sleep(1); /* let terminal settle down */
1238 }
177ed6dd
BJ
1239 }
1240
6a19f69a
BJ
1241# ifdef CBVIRTTERM
1242 if (DoVirtTerm) {
1243 j = tgetnum("vt");
1244 VirTermNo = -1;
1245 for (i=0; vt_map[i].stdnum; i++)
1246 if (vt_map[i].stdnum == j)
1247 VirTermNo = vt_map[i].localnum;
1248 } else
1249 VirTermNo = -1;
1250# endif CBVIRTTERM
1251
1252 setmode(0); /* set new modes, if they've changed */
1253
177ed6dd 1254 /* set up environment for the shell we are using */
6a19f69a
BJ
1255 /* (this code is rather heuristic, checking for $SHELL */
1256 /* ending in the 3 characters "csh") */
1257 csh = NO;
177ed6dd
BJ
1258 if (DoSetenv)
1259 {
1260# ifndef V6
1261 char *sh;
1262
1263 if ((sh = getenv("SHELL")) && (i = strlen(sh)) >= 3)
1264 {
26a253fc
JB
1265 if ((csh = sequal(&sh[i-3], "csh")) && CmndLine)
1266 (void) write(STDOUT, "set noglob;\n", 12);
177ed6dd
BJ
1267 }
1268 if (!csh)
1269# endif
26a253fc
JB
1270 /* running Bourne shell */
1271 (void) write(STDOUT, "export TERMCAP TERM;\n", 21);
177ed6dd
BJ
1272 }
1273 }
1274
1275 /* report type if appropriate */
1276 if (DoSetenv || Report || Ureport)
1277 {
6a19f69a
BJ
1278 /* if type is the short name, find first alias (if any) */
1279 makealias(Ttycap);
1280 if (sequal(TtyType, Alias[0]) && Alias[1]) {
1281 TtyType = Alias[1];
1282 }
1283
177ed6dd
BJ
1284 if (DoSetenv)
1285 {
1286 if (csh)
1287 {
1288 if (CmndLine)
26a253fc
JB
1289 (void) write(STDOUT, "setenv TERM ", 12);
1290 (void) write(STDOUT, TtyType, strlen(TtyType));
1291 (void) write(STDOUT, " ", 1);
177ed6dd 1292 if (CmndLine)
26a253fc 1293 (void) write(STDOUT, ";\n", 2);
177ed6dd
BJ
1294 }
1295 else
1296 {
26a253fc
JB
1297 (void) write(STDOUT, "TERM=", 5);
1298 (void) write(STDOUT, TtyType, strlen(TtyType));
1299 (void) write(STDOUT, ";\n", 2);
177ed6dd
BJ
1300 }
1301 }
6a19f69a 1302 else if (Report)
177ed6dd 1303 {
26a253fc
JB
1304 (void) write(STDOUT, TtyType, strlen(TtyType));
1305 (void) write(STDOUT, "\n", 1);
177ed6dd
BJ
1306 }
1307 if (Ureport)
1308 {
177ed6dd 1309 prs("Terminal type is ");
6a19f69a 1310 prs(TtyType);
177ed6dd
BJ
1311 prs("\n");
1312 flush();
1313 }
6a19f69a 1314
177ed6dd
BJ
1315 if (DoSetenv)
1316 {
1317 if (csh)
1318 {
26a253fc
JB
1319 if (CmndLine)
1320 (void) write(STDOUT, "setenv TERMCAP '", 16);
177ed6dd
BJ
1321 }
1322 else
26a253fc 1323 (void) write(STDOUT, "TERMCAP='", 9);
177ed6dd
BJ
1324 wrtermcap(Ttycap);
1325 if (csh)
1326 {
1327 if (CmndLine)
1328 {
26a253fc
JB
1329 (void) write(STDOUT, "';\n", 3);
1330 (void) write(STDOUT, "unset noglob;\n", 14);
177ed6dd
BJ
1331 }
1332 }
1333 else
26a253fc 1334 (void) write(STDOUT, "';\n", 3);
177ed6dd
BJ
1335 }
1336 }
1337
1338 if (RepOnly)
1339 exit(0);
1340
77f8c4bb 1341 /* tell about changing erase, kill and interrupt characters */
6a19f69a
BJ
1342 reportek("Erase", curerase, olderase, OLDERASE);
1343 reportek("Kill", curkill, oldkill, OLDKILL);
77f8c4bb 1344 reportek("Interrupt", curintr, oldintr, OLDINTR);
177ed6dd
BJ
1345
1346# ifdef V6
1347 /* update htmp */
1348 if (!Dash_u)
1349 {
1350 if (Ttyid == 0)
1351 Ttyid = ttyn(FILEDES);
1352 if (Ttyid == 'x')
1353 {
1354 prs("Cannot update htmp\n");
1355 flush();
1356 }
1357 else
1358 {
1359 /* update htmp file only if changed */
1360 if (!bequal(Capbuf, hsgettype(), 2))
1361 {
1362 hsettype(Capbuf[0] | (Capbuf[1] << 8));
1363 hput(Ttyid);
1364 }
1365 }
1366 }
1367# endif
1368
1369 exit(0);
1370}
1371
6a19f69a
BJ
1372/*
1373 * Set the hardware tabs on the terminal, using the ct (clear all tabs),
1374 * st (set one tab) and ch (horizontal cursor addressing) capabilities.
1375 * This is done before if and is, so they can patch in case we blow this.
1376 */
1377settabs()
1378{
1379 char caps[100];
1380 char *capsp = caps;
1381 char *clear_tabs, *set_tab, *set_column, *set_pos;
1382 char *tg_out, *tgoto();
48e4fbf9 1383 int c;
6a19f69a
BJ
1384
1385 clear_tabs = tgetstr("ct", &capsp);
1386 set_tab = tgetstr("st", &capsp);
1387 set_column = tgetstr("ch", &capsp);
1388 if (set_column == 0)
1389 set_pos = tgetstr("cm", &capsp);
6a19f69a
BJ
1390
1391 if (clear_tabs && set_tab) {
1392 prc('\r'); /* force to be at left margin */
1393 tputs(clear_tabs, 0, prc);
1394 }
1395 if (set_tab) {
1396 for (c=8; c<columns; c += 8) {
1397 /* get to that column. */
1398 tg_out = "OOPS"; /* also returned by tgoto */
1399 if (set_column)
1400 tg_out = tgoto(set_column, 0, c);
1401 if (*tg_out == 'O' && set_pos)
1402 tg_out = tgoto(set_pos, c, lines-1);
1403 if (*tg_out != 'O')
1404 tputs(tg_out, 1, prc);
1405 else {
1406 prc(' '); prc(' '); prc(' '); prc(' ');
1407 prc(' '); prc(' '); prc(' '); prc(' ');
1408 }
1409 /* set the tab */
1410 tputs(set_tab, 0, prc);
1411 }
1412 prc('\r');
1413 return 1;
1414 }
1415 return 0;
1416}
1417
1418setmode(flag)
1419int flag;
1420/* flag serves several purposes:
1421 * if called as the result of a signal, flag will be > 0.
1422 * if called from terminal init, flag == -1 means reset "oldmode".
1423 * called with flag == 0 at end of normal mode processing.
1424 */
1425{
1426# ifndef USG
1427 struct sgttyb *ttymode;
1428# else
1429 struct termio *ttymode;
1430# endif
537a9a14
JB
1431# ifdef TIOCGETC
1432 struct tchars *ttytchars;
1433# endif
6a19f69a 1434
537a9a14 1435 if (flag < 0) { /* unconditionally reset oldmode (called from init) */
6a19f69a 1436 ttymode = &oldmode;
537a9a14
JB
1437# ifdef TIOCGETC
1438 ttytchars = &oldtchar;
1439# endif
26a253fc 1440 } else if (!bequal((char *)&mode, (char *)&oldmode, sizeof mode)) {
6a19f69a 1441 ttymode = &mode;
537a9a14
JB
1442# ifdef TIOCGETC
1443 ttytchars = &tchar;
1444# endif
1445 } else { /* don't need it */
6a19f69a
BJ
1446# ifndef USG
1447 ttymode = (struct sgttyb *)0;
1448# else
1449 ttymode = (struct termio *)0;
1450# endif
537a9a14
JB
1451# ifdef TIOCGETC
1452 ttytchars = (struct tchars *)0;
1453# endif
1454 }
6a19f69a
BJ
1455
1456 if (ttymode)
1457 {
1458# ifdef USG
26a253fc 1459 (void) ioctl(FILEDES, TCSETAW, (char *)ttymode);
6a19f69a
BJ
1460# else
1461# ifndef V6
26a253fc
JB
1462 /* don't flush */
1463 (void) ioctl(FILEDES, TIOCSETN, (char *)ttymode);
6a19f69a
BJ
1464# else
1465 stty(FILEDES, ttymode);
1466# endif
1467# endif
1468 }
537a9a14
JB
1469# ifdef TIOCGETC
1470 if (ttytchars) {
26a253fc 1471 (void) ioctl(FILEDES, TIOCSETC, (char *)ttytchars);
537a9a14
JB
1472 }
1473# endif
6a19f69a
BJ
1474# ifdef CBVIRTTERM
1475 if (VirTermNo != -2) {
1476 int r1, r2;
1477 extern int errno;
1478
26a253fc 1479 r1 = ioctl(FILEDES, LDGETT, (char *)&block);
6a19f69a
BJ
1480 block.st_flgs |= TM_SET;
1481 block.st_termt = VirTermNo;
1482 if (block.st_termt < 0)
1483 block.st_termt = 0;
1484 if (!HasAM)
1485 block.st_flgs |= TM_ANL;
1486 else
1487 block.st_flgs &= ~TM_ANL;
26a253fc 1488 r2 = ioctl(FILEDES, LDSETT, (char *)&block);
6a19f69a
BJ
1489 }
1490# endif
1491
1492 if (flag > 0) /* trapped signal */
1493 exit(1);
1494}
1495
177ed6dd
BJ
1496reportek(name, new, old, def)
1497char *name;
1498char old;
1499char new;
1500char def;
1501{
1502 register char o;
1503 register char n;
1504 register char *p;
6a19f69a
BJ
1505 char buf[32];
1506 char *bufp;
177ed6dd
BJ
1507
1508 if (BeQuiet)
1509 return;
1510 o = old;
1511 n = new;
1512
1513 if (o == n && n == def)
1514 return;
1515 prs(name);
1516 if (o == n)
1517 prs(" is ");
1518 else
1519 prs(" set to ");
6a19f69a
BJ
1520 bufp = buf;
1521 if (tgetstr("kb", &bufp) > 0 && n == buf[0] && buf[1] == NULL)
1522 prs("Backspace\n");
1523 else if (n == 0177)
1524 prs("Delete\n");
1525 else
177ed6dd 1526 {
6a19f69a
BJ
1527 if (n < 040)
1528 {
1529 prs("Ctrl-");
1530 n ^= 0100;
1531 }
1532 p = "x\n";
1533 p[0] = n;
1534 prs(p);
177ed6dd 1535 }
177ed6dd
BJ
1536 flush();
1537}
1538
1539
1540
1541
1542setdelay(cap, dtab, bits, flags)
1543char *cap;
1544struct delay dtab[];
1545int bits;
d3c31938 1546short *flags;
177ed6dd
BJ
1547{
1548 register int i;
1549 register struct delay *p;
6a19f69a
BJ
1550# ifdef V6
1551 extern int ospeed;
1552# else
1553 extern short ospeed;
1554# endif
177ed6dd
BJ
1555
1556 /* see if this capability exists at all */
1557 i = tgetnum(cap);
1558 if (i < 0)
1559 i = 0;
6a19f69a
BJ
1560 /* No padding at speeds below PadBaud */
1561 if (PadBaud > ospeed)
1562 i = 0;
177ed6dd
BJ
1563
1564 /* clear out the bits, replace with new ones */
1565 *flags &= ~bits;
1566
1567 /* scan dtab for first entry with adequate delay */
1568 for (p = dtab; p->d_delay >= 0; p++)
1569 {
1570 if (p->d_delay >= i)
1571 {
1572 p++;
1573 break;
1574 }
1575 }
1576
1577 /* use last entry if none will do */
1578 *flags |= (--p)->d_bits;
1579}
1580
1581
1582prs(s)
1583char *s;
1584{
1585 while (*s != '\0')
1586 prc(*s++);
1587}
1588
1589
1590char OutBuf[256];
1591int OutPtr;
1592
1593prc(c)
6a19f69a 1594char c;
177ed6dd
BJ
1595{
1596 OutBuf[OutPtr++] = c;
1597 if (OutPtr >= sizeof OutBuf)
1598 flush();
1599}
1600
1601flush()
1602{
1603 if (OutPtr > 0)
26a253fc 1604 (void) write(2, OutBuf, OutPtr);
177ed6dd
BJ
1605 OutPtr = 0;
1606}
1607
1608
1609cat(file)
1610char *file;
1611{
1612 register int fd;
1613 register int i;
1614 char buf[BUFSIZ];
1615
1616 fd = open(file, 0);
1617 if (fd < 0)
1618 {
1619 prs("Cannot open ");
1620 prs(file);
1621 prs("\n");
1622 flush();
6a19f69a 1623 return;
177ed6dd
BJ
1624 }
1625
177ed6dd 1626 while ((i = read(fd, buf, BUFSIZ)) > 0)
26a253fc 1627 (void) write(FILEDES, buf, i);
177ed6dd 1628
26a253fc 1629 (void) close(fd);
177ed6dd
BJ
1630}
1631
1632
1633
1634bmove(from, to, length)
1635char *from;
1636char *to;
1637int length;
1638{
1639 register char *p, *q;
1640 register int i;
1641
1642 i = length;
1643 p = from;
1644 q = to;
1645
1646 while (i-- > 0)
1647 *q++ = *p++;
1648}
1649
1650
1651
6a19f69a 1652bequal(a, b, len) /* must be same thru len chars */
177ed6dd
BJ
1653char *a;
1654char *b;
1655int len;
1656{
1657 register char *p, *q;
1658 register int i;
1659
1660 i = len;
1661 p = a;
1662 q = b;
1663
dad88ed7 1664 while ((*p == *q) && --i > 0)
177ed6dd
BJ
1665 {
1666 p++; q++;
1667 }
1668 return ((*p == *q) && i >= 0);
1669}
1670
6a19f69a 1671sequal(a, b) /* must be same thru NULL */
177ed6dd
BJ
1672char *a;
1673char *b;
1674{
1675 register char *p = a, *q = b;
1676
1677 while (*p && *q && (*p == *q))
1678 {
1679 p++; q++;
1680 }
1681 return (*p == *q);
1682}
1683
6a19f69a
BJ
1684makealias(buf)
1685char *buf;
1686{
1687 register int i;
1688 register char *a;
1689 register char *b;
1690
1691 Alias[0] = a = Aliasbuf;
1692 b = buf;
1693 i = 1;
1694 while (*b && *b != ':') {
1695 if (*b == '|') {
1696 *a++ = NULL;
1697 Alias[i++] = a;
1698 b++;
1699 }
1700 else
1701 *a++ = *b++;
1702 }
1703 *a = NULL;
1704 Alias[i] = NULL;
1705# ifdef DEB
1706 for(i = 0; Alias[i]; printf("A:%s\n", Alias[i++]));
1707# endif
1708}
1709
1710isalias(ident) /* is ident same as one of the aliases? */
1711char *ident;
1712{
1713 char **a = Alias;
1714
1715 if (*a)
1716 while (*a)
1717 if (sequal(ident, *a))
1718 return(YES);
1719 else
1720 a++;
1721 return(NO);
1722}
1723
177ed6dd
BJ
1724# ifdef GTTYN
1725char *
1726stypeof(ttyid)
1727char *ttyid;
1728{
177ed6dd 1729 register char *PortType;
177ed6dd 1730 register char *TtyId;
9479aa87 1731 struct ttyent *t;
177ed6dd
BJ
1732
1733 if (ttyid == NOTTY)
1734 return (DEFTYPE);
177ed6dd
BJ
1735
1736 /* split off end of name */
1737 TtyId = ttyid;
1738 while (*ttyid)
1739 if (*ttyid++ == '/')
1740 TtyId = ttyid;
1741
1742 /* scan the file */
9479aa87 1743 if ((t = getttynam(TtyId)) != NULL)
177ed6dd 1744 {
9479aa87
BJ
1745 PortType = t->ty_type;
1746 /* get aliases from termcap entry */
1747 if (Mapped && tgetent(Capbuf, PortType) > 0) {
1748 makealias(Capbuf);
1749 if (sequal(Alias[0], PortType) && Alias[1])
1750 PortType = Alias[1];
177ed6dd 1751 }
9479aa87 1752 return (PortType);
177ed6dd 1753 }
177ed6dd
BJ
1754 return (DEFTYPE);
1755}
1756# endif
1757
177ed6dd
BJ
1758/*
1759 * routine to output the string for the environment TERMCAP variable
1760 */
1761#define WHITE(c) (c == ' ' || c == '\t')
1762char delcap[128][2];
1763int ncap = 0;
1764
1765wrtermcap(bp)
1766char *bp;
1767{
1768 char buf[CAPBUFSIZ];
1769 char *p = buf;
1770 char *tp;
1771 char *putbuf();
1772 int space, empty;
26a253fc
JB
1773# ifdef CBVIRTTERM
1774 register int i;
1775# endif CBVIRTTERM
177ed6dd
BJ
1776
1777 /* discard names with blanks */
1778/** May not be desireable ? **/
1779 while (*bp && *bp != ':') {
1780 if (*bp == '|') {
1781 tp = bp+1;
1782 space = NO;
1783 while (*tp && *tp != '|' && *tp != ':') {
1784 space = (space || WHITE(*tp) );
1785 tp++;
1786 }
1787 if (space) {
1788 bp = tp;
1789 continue;
1790 }
1791 }
1792 *p++ = *bp++;
1793 }
1794/**/
1795
6a19f69a
BJ
1796# ifdef CBVIRTTERM
1797 if (VirTermNo > 0) {
1798 p = putbuf(p, ":am"); /* All virt terms have auto margins */
1799 cancelled("am");
1800 }
1801# endif
177ed6dd
BJ
1802 while (*bp) {
1803 switch (*bp) {
1804 case ':': /* discard empty, cancelled or dupl fields */
1805 tp = bp+1;
1806 empty = YES;
1807 while (*tp && *tp != ':') {
1808 empty = (empty && WHITE(*tp) );
1809 tp++;
1810 }
6a19f69a
BJ
1811# ifdef CBVIRTTERM
1812 /*
1813 * Virtual terminals use ic, not im or ei. Turn
1814 * any of them into ic - duplicates will be cancelled
1815 * below. I assume that terminals needing im+ic+ei
1816 * are handled by the kernel.
1817 */
1818 if (VirTermNo > 0 && !HasAM &&
1819 (bp[1]=='i' && bp[2]=='m' ||
1820 bp[1]=='e' && bp[2]=='i')) {
1821 bp[1] = 'i';
1822 bp[2] = 'c';
1823 }
1824 if (VirTermNo > 0 && !HasAM &&
1825 (bp[1]=='c' && bp[2]=='s')) {
1826 bp[1] = 'd';
1827 bp[2] = 'l';
1828 /* Also need al, so kludge: */
1829 if (!cancelled("al"))
1830 p = putbuf(p, ":al=\033\120");
1831 }
1832# endif CBVIRTTERM
177ed6dd
BJ
1833 if (empty || cancelled(bp+1)) {
1834 bp = tp;
1835 continue;
1836 }
6a19f69a
BJ
1837# ifdef CBVIRTTERM
1838 if (VirTermNo > 0 && !HasAM)
1839 for (i = 0; vtab[i].value; i++) {
1840 if (vtab[i].cap[0] == bp[1] &&
1841 vtab[i].cap[1] == bp[2]) {
1842 *p++ = *bp++; /* colon */
1843 *p++ = *bp++; /* first char */
1844 *p++ = *bp++; /* second " */
1845 *p++ = *bp++; /* = sign */
1846 p = putbuf(p, vtab[i].value);
1847 bp = tp;
1848 goto contin;
1849 }
1850 }
1851# endif CBVIRTTERM
177ed6dd
BJ
1852 break;
1853
1854 case ' ': /* no spaces in output */
1855 p = putbuf(p, "\\040");
1856 bp++;
1857 continue;
1858
6a19f69a
BJ
1859 case '!': /* the shell thinks this is history */
1860 p = putbuf(p, "\\041");
1861 bp++;
1862 continue;
1863
1864 case ',': /* the shell thinks this is history */
1865 p = putbuf(p, "\\054");
1866 bp++;
1867 continue;
1868
177ed6dd
BJ
1869 case '"': /* no quotes in output */
1870 p = putbuf(p, "\\042");
1871 bp++;
1872 continue;
1873
1874 case '\'': /* no quotes in output */
1875 p = putbuf(p, "\\047");
1876 bp++;
1877 continue;
1878
6a19f69a
BJ
1879 case '`': /* no back quotes in output */
1880 p = putbuf(p, "\\140");
1881 bp++;
1882 continue;
1883
177ed6dd
BJ
1884 case '\\':
1885 case '^': /* anything following is OK */
1886 *p++ = *bp++;
6a19f69a
BJ
1887# ifdef CBVIRTTERM
1888 if (*bp == 'E' && VirTermNo > 0 &&
1889 (bp[-3]!='\\'||bp[-2]!='E') &&
1890 (bp[1]!='\\'||bp[2]!='E'))
1891 p = putbuf(p, "E\\");
1892# endif CBVIRTTERM
177ed6dd
BJ
1893 }
1894 *p++ = *bp++;
26a253fc 1895# ifdef CBVIRTTERM
6a19f69a 1896contin: ;
26a253fc 1897# endif CBVIRTTERM
177ed6dd 1898 }
6a19f69a 1899 *p++ = ':'; /* we skipped the last : with the : lookahead hack */
26a253fc 1900 (void) write (STDOUT, buf, p-buf);
177ed6dd
BJ
1901}
1902
1903cancelled(cap)
1904char *cap;
1905{
1906 register int i;
1907
1908 for (i = 0; i < ncap; i++)
1909 {
1910 if (cap[0] == delcap[i][0] && cap[1] == delcap[i][1])
1911 return (YES);
1912 }
1913 /* delete a second occurrance of the same capability */
1914 delcap[ncap][0] = cap[0];
1915 delcap[ncap][1] = cap[1];
1916 ncap++;
1917 return (cap[2] == '@');
1918}
1919
1920char *
1921putbuf(ptr, str)
1922char *ptr;
1923char *str;
1924{
6a19f69a
BJ
1925 char buf[20];
1926
1927 while (*str) {
1928 switch (*str) {
1929 case '\033':
1930 ptr = putbuf(ptr, "\\E");
1931 str++;
1932 break;
1933 default:
1934 if (*str <= ' ') {
26a253fc 1935 (void) sprintf(buf, "\\%03o", *str);
6a19f69a
BJ
1936 ptr = putbuf(ptr, buf);
1937 str++;
1938 } else
1939 *ptr++ = *str++;
1940 }
1941 }
177ed6dd
BJ
1942 return (ptr);
1943}
1944
1945
1946baudrate(p)
1947char *p;
1948{
1949 char buf[8];
1950 int i = 0;
1951
1952 while (i < 7 && (isalnum(*p) || *p == '.'))
1953 buf[i++] = *p++;
1954 buf[i] = NULL;
1955 for (i=0; speeds[i].string; i++)
1956 if (sequal(speeds[i].string, buf))
1957 return (speeds[i].speed);
1958 return (-1);
1959}
1960
1961char *
6a19f69a 1962mapped(type)
177ed6dd 1963char *type;
177ed6dd 1964{
6a19f69a
BJ
1965# ifdef V6
1966 extern int ospeed;
1967# else
1968 extern short ospeed;
1969# endif
177ed6dd
BJ
1970 int match;
1971
1972# ifdef DEB
6a19f69a 1973 printf ("spd:%d\n", ospeed);
177ed6dd
BJ
1974 prmap();
1975# endif
1976 Map = map;
1977 while (Map->Ident)
1978 {
6a19f69a 1979 if (*(Map->Ident) == NULL || sequal(Map->Ident, type) || isalias(Map->Ident))
177ed6dd
BJ
1980 {
1981 match = NO;
1982 switch (Map->Test)
1983 {
1984 case ANY: /* no test specified */
1985 case ALL:
1986 match = YES;
1987 break;
1988
1989 case GT:
6a19f69a 1990 match = (ospeed > Map->Speed);
177ed6dd
BJ
1991 break;
1992
1993 case GE:
6a19f69a 1994 match = (ospeed >= Map->Speed);
177ed6dd
BJ
1995 break;
1996
1997 case EQ:
6a19f69a 1998 match = (ospeed == Map->Speed);
177ed6dd
BJ
1999 break;
2000
2001 case LE:
6a19f69a 2002 match = (ospeed <= Map->Speed);
177ed6dd
BJ
2003 break;
2004
2005 case LT:
6a19f69a 2006 match = (ospeed < Map->Speed);
177ed6dd
BJ
2007 break;
2008
2009 case NE:
6a19f69a 2010 match = (ospeed != Map->Speed);
177ed6dd
BJ
2011 break;
2012 }
2013 if (match)
2014 return (Map->Type);
2015 }
2016 Map++;
2017 }
2018 /* no match found; return given type */
2019 return (type);
2020}
2021
2022# ifdef DEB
2023prmap()
2024{
2025 Map = map;
2026 while (Map->Ident)
2027 {
2028 printf ("%s t:%d s:%d %s\n",
2029 Map->Ident, Map->Test, Map->Speed, Map->Type);
2030 Map++;
2031 }
2032}
2033# endif
2034
2035char *
2036nextarg(argc, argv)
2037int argc;
2038char *argv[];
2039{
2040 if (argc <= 0)
2041 fatal ("Too few args: ", *argv);
2042 if (*(*++argv) == '-')
2043 fatal ("Unexpected arg: ", *argv);
2044 return (*argv);
2045}
2046
2047fatal (mesg, obj)
2048char *mesg;
2049char *obj;
2050{
2051 prs (mesg);
2052 prs (obj);
2053 prc ('\n');
2054 prs (USAGE);
2055 flush();
2056 exit(1);
2057}