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