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