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