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