change macro for control characters, use system predefined values as much as
[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
0b1d4860 14static char sccsid[] = "@(#)tset.c 5.6 (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')
313# define isalnum(c) (c > ' ' && !(index("<@=>!:|\177", c)) )
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;
458# endif CBVIRTTERM
459
177ed6dd
BJ
460char Erase_char; /* new erase character */
461char Kill_char; /* new kill character */
77f8c4bb 462char Intr_char; /* new interrupt character */
177ed6dd
BJ
463char Specialerase; /* set => Erase_char only on terminals with backspace */
464
6a19f69a
BJ
465# ifdef GTTYN
466char *Ttyid = NOTTY; /* terminal identifier */
467# else
468char Ttyid = NOTTY; /* terminal identifier */
469# endif
177ed6dd
BJ
470char *TtyType; /* type of terminal */
471char *DefType; /* default type if none other computed */
472char *NewType; /* mapping identifier based on old flags */
6a19f69a 473int Mapped; /* mapping has been specified */
177ed6dd
BJ
474int Dash_u; /* don't update htmp */
475int Dash_h; /* don't read htmp */
476int DoSetenv; /* output setenv commands */
477int BeQuiet; /* be quiet */
478int NoInit; /* don't output initialization string */
6a19f69a 479int IsReset; /* invoked as reset */
177ed6dd
BJ
480int Report; /* report current type */
481int Ureport; /* report to user */
482int RepOnly; /* report only */
483int CmndLine; /* output full command lines (-s option) */
484int Ask; /* ask user for termtype */
6a19f69a
BJ
485int DoVirtTerm = YES; /* Set up a virtual terminal */
486int New = NO; /* use new tty discipline */
487int HasAM; /* True if terminal has automatic margins */
488int PadBaud; /* Min rate of padding needed */
48e4fbf9 489int lines, columns;
177ed6dd
BJ
490
491# define CAPBUFSIZ 1024
492char Capbuf[CAPBUFSIZ]; /* line from /etc/termcap for this TtyType */
493char *Ttycap; /* termcap line from termcap or environ */
494
6a19f69a
BJ
495char Aliasbuf[128];
496char *Alias[16];
497
177ed6dd
BJ
498struct delay
499{
500 int d_delay;
501 int d_bits;
502};
503
504# include "tset.delays.h"
505
6a19f69a
BJ
506# ifndef USG
507struct sgttyb mode;
508struct sgttyb oldmode;
537a9a14
JB
509struct tchars tchar;
510struct tchars oldtchar;
6a19f69a
BJ
511# else
512struct termio mode;
513struct termio oldmode;
514# endif
515# ifdef CBVIRTTERM
516struct termcb block = {0, 2, 0, 0, 0, 20};
517# endif CBVIRTTERM
177ed6dd
BJ
518
519
520main(argc, argv)
521int argc;
522char *argv[];
523{
dad1b0b2 524 char buf[CAPBUFSIZ];
6a19f69a 525 char termbuf[32];
177ed6dd
BJ
526 auto char *bufp;
527 register char *p;
528 char *command;
529 register int i;
6a19f69a 530 int j;
177ed6dd
BJ
531 int Break;
532 int Not;
6a19f69a
BJ
533 char *nextarg();
534 char *mapped();
535 extern char *rindex();
48e4fbf9 536 struct winsize win;
177ed6dd
BJ
537# ifdef V6
538 extern char *hsgettype();
539# else
540 extern char *getenv();
541# endif
542# ifdef GTTYN
6a19f69a 543 char *stypeof();
177ed6dd
BJ
544 extern char *ttyname();
545 extern char *tgetstr();
546# endif
547 char bs_char;
548 int csh;
6a19f69a
BJ
549 int settle;
550 int setmode();
177ed6dd
BJ
551 extern prc();
552 extern char PC;
6a19f69a
BJ
553# ifdef V6
554 extern int ospeed;
555# else
177ed6dd 556 extern short ospeed;
6a19f69a
BJ
557# endif
558# ifdef UCB_NTTY
559 int lmode;
560 int ldisc;
177ed6dd 561
6a19f69a
BJ
562 ioctl(FILEDES, TIOCLGET, &lmode);
563 ioctl(FILEDES, TIOCGETD, &ldisc);
564# endif
565
566# ifndef USG
177ed6dd 567 if (gtty(FILEDES, &mode) < 0)
6a19f69a
BJ
568# else
569 if (ioctl(FILEDES, TCGETA, &mode) < 0)
570# endif
177ed6dd
BJ
571 {
572 prs("Not a terminal\n");
573 exit(1);
574 }
575 bmove(&mode, &oldmode, sizeof mode);
537a9a14
JB
576# ifdef TIOCGETC
577 (void)ioctl(FILEDES, TIOCGETC, &tchar);
578 bmove(&tchar, &oldtchar, sizeof tchar);
579# endif
6a19f69a
BJ
580# ifndef USG
581 ospeed = mode.sg_ospeed & 017;
582# else
583 ospeed = mode.c_cflag & CBAUD;
584# endif
585 signal(SIGINT, setmode);
586 signal(SIGQUIT, setmode);
587 signal(SIGTERM, setmode);
177ed6dd 588
6a19f69a
BJ
589 if (command = rindex(argv[0], '/'))
590 command++;
591 else
592 command = argv[0];
593 if (sequal(command, "reset") )
177ed6dd 594 {
6a19f69a
BJ
595 /*
596 * reset the teletype mode bits to a sensible state.
597 * Copied from the program by Kurt Shoens & Mark Horton.
598 * Very useful after crapping out in raw.
599 */
600# ifndef V6
6a19f69a
BJ
601# ifdef UCB_NTTY
602 struct ltchars ltc;
0b1d4860
JB
603#ifdef TIOCLBIC
604 static int lclear = LMDMBUF|LLITOUT|LPASS8;
605#endif TIOCLBIC
6a19f69a
BJ
606
607 if (ldisc == NTTYDISC)
608 {
609 ioctl(FILEDES, TIOCGLTC, &ltc);
0b1d4860
JB
610 ltc.t_suspc = CHK(ltc.t_suspc, CSUSP);
611 ltc.t_dsuspc = CHK(ltc.t_dsuspc, CDSUSP);
612 ltc.t_rprntc = CHK(ltc.t_rprntc, CRPRNT);
613 ltc.t_flushc = CHK(ltc.t_flushc, CFLUSH);
614 ltc.t_werasc = CHK(ltc.t_werasc, CWERASE);
615 ltc.t_lnextc = CHK(ltc.t_lnextc, CLNEXT);
6a19f69a
BJ
616 ioctl(FILEDES, TIOCSLTC, &ltc);
617 }
618# endif UCB_NTTY
619# ifndef USG
620# ifdef TIOCGETC
0b1d4860
JB
621 tchar.t_intrc = CHK(tchar.t_intrc, CINTR);
622 tchar.t_quitc = CHK(tchar.t_quitc, CQUIT);
623 tchar.t_startc = CHK(tchar.t_startc, CSTART);
624 tchar.t_stopc = CHK(tchar.t_stopc, CSTOP);
625 tchar.t_eofc = CHK(tchar.t_eofc, CEOF);
6a19f69a 626 /* brkc is left alone */
0b1d4860
JB
627 ioctl(FILEDES, TIOCSETC, &tchar);
628#ifdef TIOCLBIC
629 ioctl(FILEDES, TIOCLBIC, &lclear);
630#endif TIOCLBIC
6a19f69a
BJ
631# endif TIOCGETC
632 mode.sg_flags &= ~(RAW
633# ifdef CBREAK
634 |CBREAK
635# endif CBREAK
636 |VTDELAY|ALLDELAY);
637 mode.sg_flags |= XTABS|ECHO|CRMOD|ANYP;
0b1d4860
JB
638 curerase = CHK(curerase, CERASE);
639 curkill = CHK(curkill, CKILL);
640 curintr = CHK(curintr, CINTR);
6a19f69a
BJ
641# else USG
642 ioctl(FILEDES, TCGETA, &mode);
643 curerase = CHK(curerase, OLDERASE);
644 curkill = CHK(curkill, OLDKILL);
0b1d4860
JB
645 curintr = CHK(curintr, OLDINTR);
646 mode.c_cc[VQUIT] = CHK(mode.c_cc[VQUIT], CQUIT);
647 mode.c_cc[VEOF] = CHK(mode.c_cc[VEOF], CEOF);
6a19f69a
BJ
648
649 mode.c_iflag |= (BRKINT|ISTRIP|ICRNL|IXON);
650 mode.c_iflag &= ~(IGNBRK|PARMRK|INPCK|INLCR|IGNCR|IUCLC|IXOFF);
651 mode.c_oflag |= (OPOST|ONLCR);
652 mode.c_oflag &= ~(OLCUC|OCRNL|ONOCR|ONLRET|OFILL|OFDEL|
653 NLDLY|CRDLY|TABDLY|BSDLY|VTDLY|FFDLY);
654 mode.c_cflag |= (CS7|CREAD);
655 mode.c_cflag &= ~(CSIZE|PARODD|CLOCAL);
656 mode.c_lflag |= (ISIG|ICANON|ECHO|ECHOK);
657 mode.c_lflag &= ~(XCASE|ECHONL|NOFLSH);
658 ioctl(FILEDES, TCSETAW, &mode);
659# endif USG
660# endif V6
661 Dash_u = YES;
662 BeQuiet = YES;
663 IsReset = YES;
664 }
665 else if (argc == 2 && sequal(argv[1], "-"))
666 {
667 RepOnly = YES;
668 Dash_u = YES;
177ed6dd
BJ
669 }
670 argc--;
6a19f69a
BJ
671
672 /* scan argument list and collect flags */
177ed6dd
BJ
673 while (--argc >= 0)
674 {
675 p = *++argv;
676 if (*p == '-')
677 {
678 if (*++p == NULL)
6a19f69a 679 Report = YES; /* report current terminal type */
177ed6dd
BJ
680 else while (*p) switch (*p++)
681 {
682
6a19f69a
BJ
683# ifdef UCB_NTTY
684 case 'n':
685 ldisc = NTTYDISC;
686 if (ioctl(FILEDES, TIOCSETD, &ldisc)<0)
687 fatal("ioctl ", "new");
688 continue;
689# endif
690
177ed6dd 691 case 'r': /* report to user */
6a19f69a 692 Ureport = YES;
177ed6dd
BJ
693 continue;
694
695 case 'E': /* special erase: operate on all but TTY33 */
6a19f69a 696 Specialerase = YES;
177ed6dd
BJ
697 /* explicit fall-through to -e case */
698
699 case 'e': /* erase character */
700 if (*p == NULL)
701 Erase_char = -1;
702 else
703 {
704 if (*p == '^' && p[1] != NULL)
0b1d4860
JB
705 if (*++p == '?')
706 Erase_char = '\177';
707 else
708 Erase_char = CNTL(*p);
177ed6dd
BJ
709 else
710 Erase_char = *p;
711 p++;
712 }
713 continue;
714
537a9a14 715# if defined(USG) || defined(TIOCGETC)
0b1d4860 716 case 'i': /* interrupt character */
537a9a14 717 if (*p == NULL)
0b1d4860 718 Intr_char = CNTL('C');
537a9a14
JB
719 else
720 {
721 if (*p == '^' && p[1] != NULL)
0b1d4860
JB
722 if (*++p == '?')
723 Intr_char = '\177';
724 else
725 Intr_char = CNTL(*p);
537a9a14
JB
726 else
727 Intr_char = *p;
728 p++;
729 }
730 continue;
731# endif
732
177ed6dd
BJ
733 case 'k': /* kill character */
734 if (*p == NULL)
0b1d4860 735 Kill_char = CNTL('X');
177ed6dd
BJ
736 else
737 {
738 if (*p == '^' && p[1] != NULL)
0b1d4860
JB
739 if (*++p == '?')
740 Kill_char = '\177';
741 else
742 Kill_char = CNTL(*p);
177ed6dd
BJ
743 else
744 Kill_char = *p;
745 p++;
746 }
747 continue;
748
749# ifdef OLDFLAGS
750# ifdef OLDDIALUP
751 case 'd': /* dialup type */
752 NewType = DIALUP;
753 goto mapold;
754# endif
755
756# ifdef OLDPLUGBOARD
757 case 'p': /* plugboard type */
758 NewType = PLUGBOARD;
759 goto mapold;
760# endif
761
762# ifdef OLDARPANET
763 case 'a': /* arpanet type */
764 Newtype = ARPANET;
765 goto mapold;
766# endif
767
768mapold: Map->Ident = NewType;
769 Map->Test = ALL;
770 if (*p == NULL)
771 {
772 p = nextarg(argc--, argv++);
773 }
774 Map->Type = p;
775 Map++;
6a19f69a 776 Mapped = YES;
177ed6dd
BJ
777 p = "";
778 continue;
779# endif
780
781 case 'm': /* map identifier to type */
782 /* This code is very loose. Almost no
783 ** syntax checking is done!! However,
784 ** illegal syntax will only produce
785 ** weird results.
786 */
787 if (*p == NULL)
788 {
789 p = nextarg(argc--, argv++);
790 }
791 if (isalnum(*p))
792 {
793 Map->Ident = p; /* identifier */
794 while (isalnum(*p)) p++;
795 }
796 else
797 Map->Ident = "";
6a19f69a
BJ
798 Break = NO;
799 Not = NO;
177ed6dd
BJ
800 while (!Break) switch (*p)
801 {
802 case NULL:
803 p = nextarg(argc--, argv++);
804 continue;
805
806 case ':': /* mapped type */
807 *p++ = NULL;
6a19f69a 808 Break = YES;
177ed6dd
BJ
809 continue;
810
811 case '>': /* conditional */
812 Map->Test |= GT;
813 *p++ = NULL;
814 continue;
815
816 case '<': /* conditional */
817 Map->Test |= LT;
818 *p++ = NULL;
819 continue;
820
821 case '=': /* conditional */
822 case '@':
823 Map->Test |= EQ;
824 *p++ = NULL;
825 continue;
826
827 case '!': /* invert conditions */
828 Not = ~Not;
829 *p++ = NULL;
830 continue;
831
832 case 'B': /* Baud rate */
833 p++;
834 /* intentional fallthru */
835 default:
836 if (isdigit(*p) || *p == 'e')
837 {
838 Map->Speed = baudrate(p);
839 while (isalnum(*p) || *p == '.')
840 p++;
841 }
842 else
6a19f69a 843 Break = YES;
177ed6dd
BJ
844 continue;
845 }
846 if (Not) /* invert sense of test */
847 {
848 Map->Test = (~(Map->Test))&ALL;
849 }
850 if (*p == NULL)
851 {
852 p = nextarg(argc--, argv++);
853 }
854 Map->Type = p;
855 p = "";
856 Map++;
6a19f69a 857 Mapped = YES;
177ed6dd
BJ
858 continue;
859
860 case 'h': /* don't get type from htmp or env */
6a19f69a 861 Dash_h = YES;
177ed6dd
BJ
862 continue;
863
864 case 'u': /* don't update htmp */
6a19f69a 865 Dash_u = YES;
177ed6dd
BJ
866 continue;
867
868 case 's': /* output setenv commands */
6a19f69a
BJ
869 DoSetenv = YES;
870 CmndLine = YES;
177ed6dd
BJ
871 continue;
872
873 case 'S': /* output setenv strings */
6a19f69a
BJ
874 DoSetenv = YES;
875 CmndLine = NO;
177ed6dd
BJ
876 continue;
877
878 case 'Q': /* be quiet */
6a19f69a 879 BeQuiet = YES;
177ed6dd
BJ
880 continue;
881
882 case 'I': /* no initialization */
6a19f69a 883 NoInit = YES;
177ed6dd
BJ
884 continue;
885
886 case 'A': /* Ask user */
6a19f69a
BJ
887 Ask = YES;
888 continue;
889
890 case 'v': /* no virtual terminal */
891 DoVirtTerm = NO;
177ed6dd
BJ
892 continue;
893
894 default:
895 *p-- = NULL;
896 fatal("Bad flag -", p);
897 }
898 }
899 else
900 {
901 /* terminal type */
902 DefType = p;
903 }
904 }
905
906 if (DefType)
907 {
908 if (Mapped)
909 {
910 Map->Ident = ""; /* means "map any type" */
911 Map->Test = ALL; /* at all baud rates */
912 Map->Type = DefType; /* to the default type */
913 }
914 else
915 TtyType = DefType;
916 }
917
918# ifndef V6
6a19f69a
BJ
919 /*
920 * Get rid of $TERMCAP, if it's there, so we get a real
921 * entry from /etc/termcap. This prevents us from being
922 * fooled by out of date stuff in the environment, and
923 * makes tabs work right on CB/Unix.
924 */
925 bufp = getenv("TERMCAP");
926 if (bufp && *bufp != '/')
dad88ed7 927 strcpy(bufp-8, "NOTHING"); /* overwrite only "TERMCAP" */
177ed6dd 928 /* get current idea of terminal type from environment */
8d1e1d87 929 if (!Dash_h && TtyType == 0)
177ed6dd
BJ
930 TtyType = getenv("TERM");
931# endif
932
933 /* determine terminal id if needed */
934# ifdef V6
935 if (Ttyid == NOTTY && (TtyType == 0 || !Dash_h || !Dash_u))
936 Ttyid = ttyn(FILEDES);
937# else
938 if (!RepOnly && Ttyid == NOTTY && (TtyType == 0 || !Dash_h))
939 Ttyid = ttyname(FILEDES);
940# endif
941
942# ifdef V6
943 /* get htmp if ever used */
944 if (!Dash_u || (TtyType == 0 && !Dash_h))
945 {
946 /* get htmp entry -- if error or wrong user use ttytype */
947 if (Ttyid == NOTTY || hget(Ttyid) < 0 ||
948 hgettype() == 0 || hgetuid() != (getuid() & UIDMASK))
949 Dash_h++;
950 }
951
952 /* find terminal type (if not already known) */
953 if (TtyType == 0 && !Dash_h)
954 {
955 /* get type from /etc/htmp */
956 TtyType = hsgettype();
957 }
958# endif
959
960# ifdef GTTYN
961 /* If still undefined, look at /etc/ttytype */
962 if (TtyType == 0)
963 {
964 TtyType = stypeof(Ttyid);
965 }
966# endif
967
968 /* If still undefined, use DEFTYPE */
969 if (TtyType == 0)
970 {
971 TtyType = DEFTYPE;
972 }
973
974 /* check for dialup or other mapping */
975 if (Mapped)
6d31b7ce
EW
976 {
977 if (!(Alias[0] && isalias(TtyType)))
978 if (tgetent(Capbuf, TtyType) > 0)
979 makealias(Capbuf);
6a19f69a 980 TtyType = mapped(TtyType);
6d31b7ce 981 }
177ed6dd
BJ
982
983 /* TtyType now contains a pointer to the type of the terminal */
984 /* If the first character is '?', ask the user */
985 if (TtyType[0] == '?')
986 {
6a19f69a 987 Ask = YES;
177ed6dd
BJ
988 TtyType++;
989 if (TtyType[0] == '\0')
990 TtyType = DEFTYPE;
991 }
992 if (Ask)
993 {
dad1b0b2 994ask:
177ed6dd
BJ
995 prs("TERM = (");
996 prs(TtyType);
997 prs(") ");
998 flush();
999
1000 /* read the terminal. If not empty, set type */
6a19f69a
BJ
1001 i = read(2, termbuf, sizeof termbuf - 1);
1002 if (i > 0)
177ed6dd 1003 {
6a19f69a 1004 if (termbuf[i - 1] == '\n')
177ed6dd 1005 i--;
6a19f69a
BJ
1006 termbuf[i] = '\0';
1007 if (termbuf[0] != '\0')
1008 TtyType = termbuf;
177ed6dd
BJ
1009 }
1010 }
1011
6a19f69a
BJ
1012 /* get terminal capabilities */
1013 if (!(Alias[0] && isalias(TtyType))) {
177ed6dd
BJ
1014 switch (tgetent(Capbuf, TtyType))
1015 {
1016 case -1:
6a19f69a 1017 prs("Cannot find termcap\n");
177ed6dd
BJ
1018 flush();
1019 exit(-1);
1020
1021 case 0:
1022 prs("Type ");
1023 prs(TtyType);
1024 prs(" unknown\n");
1025 flush();
6a19f69a
BJ
1026 if (DoSetenv)
1027 {
1028 TtyType = DEFTYPE;
dad1b0b2
S
1029 Alias[0] = '\0';
1030 goto ask;
6a19f69a
BJ
1031 }
1032 else
1033 exit(1);
177ed6dd 1034 }
177ed6dd 1035 }
6a19f69a 1036 Ttycap = Capbuf;
177ed6dd
BJ
1037
1038 if (!RepOnly)
1039 {
1040 /* determine erase and kill characters */
1041 if (Specialerase && !tgetflag("bs"))
1042 Erase_char = 0;
1043 bufp = buf;
1044 p = tgetstr("kb", &bufp);
1045 if (p == NULL || p[1] != '\0')
1046 p = tgetstr("bc", &bufp);
1047 if (p != NULL && p[1] == '\0')
1048 bs_char = p[0];
1049 else if (tgetflag("bs"))
1050 bs_char = BACKSPACE;
1051 else
1052 bs_char = 0;
6a19f69a 1053 if (Erase_char == 0 && !tgetflag("os") && curerase == OLDERASE)
177ed6dd
BJ
1054 {
1055 if (tgetflag("bs") || bs_char != 0)
1056 Erase_char = -1;
1057 }
1058 if (Erase_char < 0)
1059 Erase_char = (bs_char != 0) ? bs_char : BACKSPACE;
1060
6a19f69a 1061 if (curerase == 0)
0b1d4860 1062 curerase = CERASE;
177ed6dd 1063 if (Erase_char != 0)
6a19f69a 1064 curerase = Erase_char;
177ed6dd 1065
537a9a14 1066 if (curintr == 0)
0b1d4860 1067 curintr = CINTR;
537a9a14
JB
1068 if (Intr_char != 0)
1069 curintr = Intr_char;
1070
6a19f69a 1071 if (curkill == 0)
0b1d4860 1072 curkill = CKILL;
177ed6dd 1073 if (Kill_char != 0)
6a19f69a 1074 curkill = Kill_char;
177ed6dd
BJ
1075
1076 /* set modes */
6a19f69a
BJ
1077 PadBaud = tgetnum("pb"); /* OK if fails */
1078 for (i=0; speeds[i].string; i++)
1079 if (speeds[i].baudrate == PadBaud) {
1080 PadBaud = speeds[i].speed;
1081 break;
1082 }
1083# ifndef USG
177ed6dd
BJ
1084 setdelay("dC", CRdelay, CRbits, &mode.sg_flags);
1085 setdelay("dN", NLdelay, NLbits, &mode.sg_flags);
1086 setdelay("dB", BSdelay, BSbits, &mode.sg_flags);
1087 setdelay("dF", FFdelay, FFbits, &mode.sg_flags);
1088 setdelay("dT", TBdelay, TBbits, &mode.sg_flags);
6a19f69a 1089 if (tgetflag("UC") || (command[0] & 0140) == 0100)
177ed6dd
BJ
1090 mode.sg_flags |= LCASE;
1091 else if (tgetflag("LC"))
1092 mode.sg_flags &= ~LCASE;
1093 mode.sg_flags &= ~(EVENP | ODDP | RAW);
6a19f69a 1094# ifdef CBREAK
177ed6dd
BJ
1095 mode.sg_flags &= ~CBREAK;
1096# endif
1097 if (tgetflag("EP"))
1098 mode.sg_flags |= EVENP;
1099 if (tgetflag("OP"))
1100 mode.sg_flags |= ODDP;
1101 if ((mode.sg_flags & (EVENP | ODDP)) == 0)
1102 mode.sg_flags |= EVENP | ODDP;
1103 mode.sg_flags |= CRMOD | ECHO | XTABS;
1104 if (tgetflag("NL")) /* new line, not line feed */
1105 mode.sg_flags &= ~CRMOD;
1106 if (tgetflag("HD")) /* half duplex */
1107 mode.sg_flags &= ~ECHO;
1108 if (tgetflag("pt")) /* print tabs */
1109 mode.sg_flags &= ~XTABS;
177ed6dd 1110# else
6a19f69a
BJ
1111 setdelay("dC", CRdelay, CRbits, &mode.c_oflag);
1112 setdelay("dN", NLdelay, NLbits, &mode.c_oflag);
1113 setdelay("dB", BSdelay, BSbits, &mode.c_oflag);
1114 setdelay("dF", FFdelay, FFbits, &mode.c_oflag);
1115 setdelay("dT", TBdelay, TBbits, &mode.c_oflag);
1116 setdelay("dV", VTdelay, VTbits, &mode.c_oflag);
1117
1118 if (tgetflag("UC") || (command[0] & 0140) == 0100) {
1119 mode.c_iflag |= IUCLC;
1120 mode.c_oflag |= OLCUC;
1121 }
1122 else if (tgetflag("LC")) {
1123 mode.c_iflag &= ~IUCLC;
1124 mode.c_oflag &= ~OLCUC;
1125 }
1126 mode.c_iflag &= ~(PARMRK|INPCK);
1127 mode.c_lflag |= ICANON;
1128 if (tgetflag("EP")) {
1129 mode.c_cflag |= PARENB;
1130 mode.c_cflag &= ~PARODD;
1131 }
1132 if (tgetflag("OP")) {
1133 mode.c_cflag |= PARENB;
1134 mode.c_cflag |= PARODD;
1135 }
1136
1137 mode.c_oflag |= ONLCR;
1138 mode.c_iflag |= ICRNL;
1139 mode.c_lflag |= ECHO;
1140 mode.c_oflag |= TAB3;
1141 if (tgetflag("NL")) { /* new line, not line feed */
1142 mode.c_oflag &= ~ONLCR;
1143 mode.c_iflag &= ~ICRNL;
1144 }
1145 if (tgetflag("HD")) /* half duplex */
1146 mode.c_lflag &= ~ECHO;
1147 if (tgetflag("pt")) /* print tabs */
1148 mode.c_oflag &= ~TAB3;
1149
1150 mode.c_lflag |= (ECHOE|ECHOK);
1151# endif
1152# ifdef CBVIRTTERM
1153 HasAM = tgetflag("am");
1154# endif CBVIRTTERM
1155# ifdef UCB_NTTY
1156 if (ldisc == NTTYDISC)
1157 {
1158 lmode |= LCTLECH; /* display ctrl chars */
1159 if (tgetflag("hc"))
1160 { /** set printer modes **/
1161 lmode &= ~(LCRTBS|LCRTERA|LCRTKIL);
1162 lmode |= LPRTERA;
1163 }
1164 else
1165 { /** set crt modes **/
1166 if (!tgetflag("os"))
1167 {
1168 lmode &= ~LPRTERA;
1169 lmode |= LCRTBS;
1170 if (mode.sg_ospeed >= B1200)
1171 lmode |= LCRTERA|LCRTKIL;
1172 }
1173 }
1174 }
1175 ioctl(FILEDES, TIOCLSET, &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 */
0b1d4860
JB
1187 ioctl(FILEDES, TIOCGWINSZ, &win);
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;
1192 ioctl(FILEDES, TIOCSWINSZ, &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;
1212 ioctl(FILEDES, LDSETT, &block);
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 {
6a19f69a 1265 if ((csh = sequal(&sh[i-3], "csh")) && CmndLine)
177ed6dd
BJ
1266 write(STDOUT, "set noglob;\n", 12);
1267 }
1268 if (!csh)
1269# endif
6a19f69a 1270 /* running Bourne shell */
177ed6dd
BJ
1271 write(STDOUT, "export TERMCAP TERM;\n", 21);
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)
1289 write(STDOUT, "setenv TERM ", 12);
6a19f69a 1290 write(STDOUT, TtyType, strlen(TtyType));
177ed6dd
BJ
1291 write(STDOUT, " ", 1);
1292 if (CmndLine)
1293 write(STDOUT, ";\n", 2);
1294 }
1295 else
1296 {
1297 write(STDOUT, "TERM=", 5);
6a19f69a 1298 write(STDOUT, TtyType, strlen(TtyType));
177ed6dd
BJ
1299 write(STDOUT, ";\n", 2);
1300 }
1301 }
6a19f69a 1302 else if (Report)
177ed6dd 1303 {
6a19f69a 1304 write(STDOUT, TtyType, strlen(TtyType));
177ed6dd
BJ
1305 write(STDOUT, "\n", 1);
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 {
1319 if (CmndLine)
1320 write(STDOUT, "setenv TERMCAP '", 16);
1321 }
1322 else
1323 write(STDOUT, "TERMCAP='", 9);
1324 wrtermcap(Ttycap);
1325 if (csh)
1326 {
1327 if (CmndLine)
1328 {
1329 write(STDOUT, "';\n", 3);
1330 write(STDOUT, "unset noglob;\n", 14);
1331 }
1332 }
1333 else
1334 write(STDOUT, "';\n", 3);
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
1440 } else if (!bequal(&mode, &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
1459 ioctl(FILEDES, TCSETAW, ttymode);
1460# else
1461# ifndef V6
1462 ioctl(FILEDES, TIOCSETN, ttymode); /* don't flush */
1463# else
1464 stty(FILEDES, ttymode);
1465# endif
1466# endif
1467 }
537a9a14
JB
1468# ifdef TIOCGETC
1469 if (ttytchars) {
1470 ioctl(FILEDES, TIOCSETC, ttytchars);
1471 }
1472# endif
6a19f69a
BJ
1473# ifdef CBVIRTTERM
1474 if (VirTermNo != -2) {
1475 int r1, r2;
1476 extern int errno;
1477
1478 r1 = ioctl(FILEDES, LDGETT, &block);
1479 block.st_flgs |= TM_SET;
1480 block.st_termt = VirTermNo;
1481 if (block.st_termt < 0)
1482 block.st_termt = 0;
1483 if (!HasAM)
1484 block.st_flgs |= TM_ANL;
1485 else
1486 block.st_flgs &= ~TM_ANL;
1487 r2 = ioctl(FILEDES, LDSETT, &block);
1488 }
1489# endif
1490
1491 if (flag > 0) /* trapped signal */
1492 exit(1);
1493}
1494
177ed6dd
BJ
1495reportek(name, new, old, def)
1496char *name;
1497char old;
1498char new;
1499char def;
1500{
1501 register char o;
1502 register char n;
1503 register char *p;
6a19f69a
BJ
1504 char buf[32];
1505 char *bufp;
177ed6dd
BJ
1506
1507 if (BeQuiet)
1508 return;
1509 o = old;
1510 n = new;
1511
1512 if (o == n && n == def)
1513 return;
1514 prs(name);
1515 if (o == n)
1516 prs(" is ");
1517 else
1518 prs(" set to ");
6a19f69a
BJ
1519 bufp = buf;
1520 if (tgetstr("kb", &bufp) > 0 && n == buf[0] && buf[1] == NULL)
1521 prs("Backspace\n");
1522 else if (n == 0177)
1523 prs("Delete\n");
1524 else
177ed6dd 1525 {
6a19f69a
BJ
1526 if (n < 040)
1527 {
1528 prs("Ctrl-");
1529 n ^= 0100;
1530 }
1531 p = "x\n";
1532 p[0] = n;
1533 prs(p);
177ed6dd 1534 }
177ed6dd
BJ
1535 flush();
1536}
1537
1538
1539
1540
1541setdelay(cap, dtab, bits, flags)
1542char *cap;
1543struct delay dtab[];
1544int bits;
d3c31938 1545short *flags;
177ed6dd
BJ
1546{
1547 register int i;
1548 register struct delay *p;
6a19f69a
BJ
1549# ifdef V6
1550 extern int ospeed;
1551# else
1552 extern short ospeed;
1553# endif
177ed6dd
BJ
1554
1555 /* see if this capability exists at all */
1556 i = tgetnum(cap);
1557 if (i < 0)
1558 i = 0;
6a19f69a
BJ
1559 /* No padding at speeds below PadBaud */
1560 if (PadBaud > ospeed)
1561 i = 0;
177ed6dd
BJ
1562
1563 /* clear out the bits, replace with new ones */
1564 *flags &= ~bits;
1565
1566 /* scan dtab for first entry with adequate delay */
1567 for (p = dtab; p->d_delay >= 0; p++)
1568 {
1569 if (p->d_delay >= i)
1570 {
1571 p++;
1572 break;
1573 }
1574 }
1575
1576 /* use last entry if none will do */
1577 *flags |= (--p)->d_bits;
1578}
1579
1580
1581prs(s)
1582char *s;
1583{
1584 while (*s != '\0')
1585 prc(*s++);
1586}
1587
1588
1589char OutBuf[256];
1590int OutPtr;
1591
1592prc(c)
6a19f69a 1593char c;
177ed6dd
BJ
1594{
1595 OutBuf[OutPtr++] = c;
1596 if (OutPtr >= sizeof OutBuf)
1597 flush();
1598}
1599
1600flush()
1601{
1602 if (OutPtr > 0)
1603 write(2, OutBuf, OutPtr);
1604 OutPtr = 0;
1605}
1606
1607
1608cat(file)
1609char *file;
1610{
1611 register int fd;
1612 register int i;
1613 char buf[BUFSIZ];
1614
1615 fd = open(file, 0);
1616 if (fd < 0)
1617 {
1618 prs("Cannot open ");
1619 prs(file);
1620 prs("\n");
1621 flush();
6a19f69a 1622 return;
177ed6dd
BJ
1623 }
1624
177ed6dd
BJ
1625 while ((i = read(fd, buf, BUFSIZ)) > 0)
1626 write(FILEDES, buf, i);
1627
1628 close(fd);
1629}
1630
1631
1632
1633bmove(from, to, length)
1634char *from;
1635char *to;
1636int length;
1637{
1638 register char *p, *q;
1639 register int i;
1640
1641 i = length;
1642 p = from;
1643 q = to;
1644
1645 while (i-- > 0)
1646 *q++ = *p++;
1647}
1648
1649
1650
6a19f69a 1651bequal(a, b, len) /* must be same thru len chars */
177ed6dd
BJ
1652char *a;
1653char *b;
1654int len;
1655{
1656 register char *p, *q;
1657 register int i;
1658
1659 i = len;
1660 p = a;
1661 q = b;
1662
dad88ed7 1663 while ((*p == *q) && --i > 0)
177ed6dd
BJ
1664 {
1665 p++; q++;
1666 }
1667 return ((*p == *q) && i >= 0);
1668}
1669
6a19f69a 1670sequal(a, b) /* must be same thru NULL */
177ed6dd
BJ
1671char *a;
1672char *b;
1673{
1674 register char *p = a, *q = b;
1675
1676 while (*p && *q && (*p == *q))
1677 {
1678 p++; q++;
1679 }
1680 return (*p == *q);
1681}
1682
6a19f69a
BJ
1683makealias(buf)
1684char *buf;
1685{
1686 register int i;
1687 register char *a;
1688 register char *b;
1689
1690 Alias[0] = a = Aliasbuf;
1691 b = buf;
1692 i = 1;
1693 while (*b && *b != ':') {
1694 if (*b == '|') {
1695 *a++ = NULL;
1696 Alias[i++] = a;
1697 b++;
1698 }
1699 else
1700 *a++ = *b++;
1701 }
1702 *a = NULL;
1703 Alias[i] = NULL;
1704# ifdef DEB
1705 for(i = 0; Alias[i]; printf("A:%s\n", Alias[i++]));
1706# endif
1707}
1708
1709isalias(ident) /* is ident same as one of the aliases? */
1710char *ident;
1711{
1712 char **a = Alias;
1713
1714 if (*a)
1715 while (*a)
1716 if (sequal(ident, *a))
1717 return(YES);
1718 else
1719 a++;
1720 return(NO);
1721}
1722
177ed6dd
BJ
1723# ifdef GTTYN
1724char *
1725stypeof(ttyid)
1726char *ttyid;
1727{
177ed6dd
BJ
1728 register char *PortType;
1729 register char *PortName;
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];
6a19f69a 1769 register int i;
177ed6dd
BJ
1770 char *p = buf;
1771 char *tp;
1772 char *putbuf();
1773 int space, empty;
1774
1775 /* discard names with blanks */
1776/** May not be desireable ? **/
1777 while (*bp && *bp != ':') {
1778 if (*bp == '|') {
1779 tp = bp+1;
1780 space = NO;
1781 while (*tp && *tp != '|' && *tp != ':') {
1782 space = (space || WHITE(*tp) );
1783 tp++;
1784 }
1785 if (space) {
1786 bp = tp;
1787 continue;
1788 }
1789 }
1790 *p++ = *bp++;
1791 }
1792/**/
1793
6a19f69a
BJ
1794# ifdef CBVIRTTERM
1795 if (VirTermNo > 0) {
1796 p = putbuf(p, ":am"); /* All virt terms have auto margins */
1797 cancelled("am");
1798 }
1799# endif
177ed6dd
BJ
1800 while (*bp) {
1801 switch (*bp) {
1802 case ':': /* discard empty, cancelled or dupl fields */
1803 tp = bp+1;
1804 empty = YES;
1805 while (*tp && *tp != ':') {
1806 empty = (empty && WHITE(*tp) );
1807 tp++;
1808 }
6a19f69a
BJ
1809# ifdef CBVIRTTERM
1810 /*
1811 * Virtual terminals use ic, not im or ei. Turn
1812 * any of them into ic - duplicates will be cancelled
1813 * below. I assume that terminals needing im+ic+ei
1814 * are handled by the kernel.
1815 */
1816 if (VirTermNo > 0 && !HasAM &&
1817 (bp[1]=='i' && bp[2]=='m' ||
1818 bp[1]=='e' && bp[2]=='i')) {
1819 bp[1] = 'i';
1820 bp[2] = 'c';
1821 }
1822 if (VirTermNo > 0 && !HasAM &&
1823 (bp[1]=='c' && bp[2]=='s')) {
1824 bp[1] = 'd';
1825 bp[2] = 'l';
1826 /* Also need al, so kludge: */
1827 if (!cancelled("al"))
1828 p = putbuf(p, ":al=\033\120");
1829 }
1830# endif CBVIRTTERM
177ed6dd
BJ
1831 if (empty || cancelled(bp+1)) {
1832 bp = tp;
1833 continue;
1834 }
6a19f69a
BJ
1835# ifdef CBVIRTTERM
1836 if (VirTermNo > 0 && !HasAM)
1837 for (i = 0; vtab[i].value; i++) {
1838 if (vtab[i].cap[0] == bp[1] &&
1839 vtab[i].cap[1] == bp[2]) {
1840 *p++ = *bp++; /* colon */
1841 *p++ = *bp++; /* first char */
1842 *p++ = *bp++; /* second " */
1843 *p++ = *bp++; /* = sign */
1844 p = putbuf(p, vtab[i].value);
1845 bp = tp;
1846 goto contin;
1847 }
1848 }
1849# endif CBVIRTTERM
177ed6dd
BJ
1850 break;
1851
1852 case ' ': /* no spaces in output */
1853 p = putbuf(p, "\\040");
1854 bp++;
1855 continue;
1856
6a19f69a
BJ
1857 case '!': /* the shell thinks this is history */
1858 p = putbuf(p, "\\041");
1859 bp++;
1860 continue;
1861
1862 case ',': /* the shell thinks this is history */
1863 p = putbuf(p, "\\054");
1864 bp++;
1865 continue;
1866
177ed6dd
BJ
1867 case '"': /* no quotes in output */
1868 p = putbuf(p, "\\042");
1869 bp++;
1870 continue;
1871
1872 case '\'': /* no quotes in output */
1873 p = putbuf(p, "\\047");
1874 bp++;
1875 continue;
1876
6a19f69a
BJ
1877 case '`': /* no back quotes in output */
1878 p = putbuf(p, "\\140");
1879 bp++;
1880 continue;
1881
177ed6dd
BJ
1882 case '\\':
1883 case '^': /* anything following is OK */
1884 *p++ = *bp++;
6a19f69a
BJ
1885# ifdef CBVIRTTERM
1886 if (*bp == 'E' && VirTermNo > 0 &&
1887 (bp[-3]!='\\'||bp[-2]!='E') &&
1888 (bp[1]!='\\'||bp[2]!='E'))
1889 p = putbuf(p, "E\\");
1890# endif CBVIRTTERM
177ed6dd
BJ
1891 }
1892 *p++ = *bp++;
6a19f69a 1893contin: ;
177ed6dd 1894 }
6a19f69a 1895 *p++ = ':'; /* we skipped the last : with the : lookahead hack */
177ed6dd
BJ
1896 write (STDOUT, buf, p-buf);
1897}
1898
1899cancelled(cap)
1900char *cap;
1901{
1902 register int i;
1903
1904 for (i = 0; i < ncap; i++)
1905 {
1906 if (cap[0] == delcap[i][0] && cap[1] == delcap[i][1])
1907 return (YES);
1908 }
1909 /* delete a second occurrance of the same capability */
1910 delcap[ncap][0] = cap[0];
1911 delcap[ncap][1] = cap[1];
1912 ncap++;
1913 return (cap[2] == '@');
1914}
1915
1916char *
1917putbuf(ptr, str)
1918char *ptr;
1919char *str;
1920{
6a19f69a
BJ
1921 char buf[20];
1922
1923 while (*str) {
1924 switch (*str) {
1925 case '\033':
1926 ptr = putbuf(ptr, "\\E");
1927 str++;
1928 break;
1929 default:
1930 if (*str <= ' ') {
1931 sprintf(buf, "\\%03o", *str);
1932 ptr = putbuf(ptr, buf);
1933 str++;
1934 } else
1935 *ptr++ = *str++;
1936 }
1937 }
177ed6dd
BJ
1938 return (ptr);
1939}
1940
1941
1942baudrate(p)
1943char *p;
1944{
1945 char buf[8];
1946 int i = 0;
1947
1948 while (i < 7 && (isalnum(*p) || *p == '.'))
1949 buf[i++] = *p++;
1950 buf[i] = NULL;
1951 for (i=0; speeds[i].string; i++)
1952 if (sequal(speeds[i].string, buf))
1953 return (speeds[i].speed);
1954 return (-1);
1955}
1956
1957char *
6a19f69a 1958mapped(type)
177ed6dd 1959char *type;
177ed6dd 1960{
6a19f69a
BJ
1961# ifdef V6
1962 extern int ospeed;
1963# else
1964 extern short ospeed;
1965# endif
177ed6dd
BJ
1966 int match;
1967
1968# ifdef DEB
6a19f69a 1969 printf ("spd:%d\n", ospeed);
177ed6dd
BJ
1970 prmap();
1971# endif
1972 Map = map;
1973 while (Map->Ident)
1974 {
6a19f69a 1975 if (*(Map->Ident) == NULL || sequal(Map->Ident, type) || isalias(Map->Ident))
177ed6dd
BJ
1976 {
1977 match = NO;
1978 switch (Map->Test)
1979 {
1980 case ANY: /* no test specified */
1981 case ALL:
1982 match = YES;
1983 break;
1984
1985 case GT:
6a19f69a 1986 match = (ospeed > Map->Speed);
177ed6dd
BJ
1987 break;
1988
1989 case GE:
6a19f69a 1990 match = (ospeed >= Map->Speed);
177ed6dd
BJ
1991 break;
1992
1993 case EQ:
6a19f69a 1994 match = (ospeed == Map->Speed);
177ed6dd
BJ
1995 break;
1996
1997 case LE:
6a19f69a 1998 match = (ospeed <= Map->Speed);
177ed6dd
BJ
1999 break;
2000
2001 case LT:
6a19f69a 2002 match = (ospeed < Map->Speed);
177ed6dd
BJ
2003 break;
2004
2005 case NE:
6a19f69a 2006 match = (ospeed != Map->Speed);
177ed6dd
BJ
2007 break;
2008 }
2009 if (match)
2010 return (Map->Type);
2011 }
2012 Map++;
2013 }
2014 /* no match found; return given type */
2015 return (type);
2016}
2017
2018# ifdef DEB
2019prmap()
2020{
2021 Map = map;
2022 while (Map->Ident)
2023 {
2024 printf ("%s t:%d s:%d %s\n",
2025 Map->Ident, Map->Test, Map->Speed, Map->Type);
2026 Map++;
2027 }
2028}
2029# endif
2030
2031char *
2032nextarg(argc, argv)
2033int argc;
2034char *argv[];
2035{
2036 if (argc <= 0)
2037 fatal ("Too few args: ", *argv);
2038 if (*(*++argv) == '-')
2039 fatal ("Unexpected arg: ", *argv);
2040 return (*argv);
2041}
2042
2043fatal (mesg, obj)
2044char *mesg;
2045char *obj;
2046{
2047 prs (mesg);
2048 prs (obj);
2049 prc ('\n');
2050 prs (USAGE);
2051 flush();
2052 exit(1);
2053}