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