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