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