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