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