date and time created 81/11/22 16:53:26 by root
[unix-history] / usr / src / usr.bin / tset / tset.c
CommitLineData
177ed6dd
BJ
1/*
2# define DEB
3/*
4** TSET -- set terminal modes
5**
6** This program does sophisticated terminal initialization.
7** I recommend that you include it in your .start_up or .login
8** file to initialize whatever terminal you are on.
9**
10** There are several features:
11**
12** A special file or sequence (as controlled by the ttycap file)
13** is sent to the terminal.
14**
15** Mode bits are set on a per-terminal_type basis (much better
16** than UNIX itself). This allows special delays, automatic
17** tabs, etc.
18**
19** Erase and Kill characters can be set to whatever you want.
20** Default is to change erase to control-H on a terminal which
21** can overstrike, and leave it alone on anything else. Kill
22** is always left alone unless specifically requested. These
23** characters can be represented as "^X" meaning control-X;
24** X is any character.
25**
26** Terminals which are dialups or plugboard types can be aliased
27** to whatever type you may have in your home or office. Thus,
28** if you know that when you dial up you will always be on a
29** TI 733, you can specify that fact to tset. You can represent
30** a type as "?type". This will ask you what type you want it
31** to be -- if you reply with just a newline, it will default
32** to the type given.
33**
34** The htmp file, used by ex, etc., can be updated.
35**
36** The current terminal type can be queried.
37**
38** Usage:
39** tset [-] [-EC] [-eC] [-kC] [-s] [-h] [-u] [-r]
40** [-m [ident] [test baudrate] :type]
41** [-Q] [-I] [-S] [type]
42**
43** In systems with environments, use:
44** `tset -s ...`
45** Actually, this doesn't work because of a shell bug.
46** Instead, use:
47** tset -s ... > tset.tmp
48** source tset.tmp
49** rm tset.tmp
50** or:
51** set noglob
52** set term=(`tset -S ....`)
53** setenv TERM $term[1]
54** setenv TERMCAP "$term[2]"
55** unset term
56** unset noglob
57**
58** Positional Parameters:
59** type -- the terminal type to force. If this is
60** specified, initialization is for this
61** terminal type.
62**
63** Flags:
64** - -- report terminal type. Whatever type is
65** decided on is reported. If no other flags
66** are stated, the only affect is to write
67** the terminal type on the standard output.
68** -r -- report to user in addition to other flags.
69** -EC -- set the erase character to C on all terminals
70** except those which cannot backspace (e.g.,
71** a TTY 33). C defaults to control-H.
72** -eC -- set the erase character to C on all terminals.
73** C defaults to control-H. If neither -E or -e
74** are specified, the erase character is set to
75** control-H if the terminal can both backspace
76** and not overstrike (e.g., a CRT). If the erase
77** character is NULL (zero byte), it will be reset
78** to '#' if nothing else is specified.
79** -kC -- set the kill character to C on all terminals.
80** Default for C is control-X. If not specified,
81** the kill character is untouched; however, if
82** not specified and the kill character is NULL
83** (zero byte), the kill character is set to '@'.
84** -iC -- reserved for setable interrupt character.
85** -qC -- reserved for setable quit character.
86** -m -- map the system identified type to some user
87** specified type. The mapping can be baud rate
88** dependent. This replaces the old -d, -p flags.
89** (-d type -> -m dialup:type)
90** (-p type -> -m plug:type)
91** Syntax: -m identifier [test baudrate] :type
92** where: ``identifier'' is whatever is found in
93** /etc/ttytype for this port, (abscence of an identifier
94** matches any identifier); ``test'' may be any combination
95** of > = < ! @; ``baudrate'' is as with stty(1);
96** ``type'' is the actual terminal type to use if the
97** mapping condition is met. Multiple maps are scanned
98** in order and the first match prevails.
99** -h -- don't read htmp file. Normally the terminal type
100** is determined by reading the htmp file or the
101** environment (unless some mapping is specified).
102** This forces a read of the ttytype file -- useful
103** when htmp is somehow wrong.
104** -u -- don't update htmp. It seemed like this should
105** be put in. Note that htmp is never actually
106** written if there are no changes, so don't bother
107** bother using this for efficiency reasons alone.
108** -s -- output setenv commands for TERM. This can be
109** used with
110** `tset -s ...`
111** and is to be prefered to:
112** setenv TERM `tset - ...`
113** because -s sets the TERMCAP variable also.
114** -S -- Similar to -s but outputs 2 strings suitable for
115** use in csh .login files as follows:
116** set noglob
117** set term=(`tset -S .....`)
118** setenv TERM $term[1]
119** setenv TERMCAP "$term[2]"
120** unset term
121** unset noglob
122** -Q -- be quiet. don't output 'Erase set to' etc.
123** -I -- don't do terminal initialization (is & if
124** strings).
125**
126** Files:
127** /etc/ttytype
128** contains a terminal id -> terminal type
129** mapping; used when any user mapping is specified,
130** or the environment doesn't have TERM set.
131** /etc/termcap
132** a terminal_type -> terminal_capabilities
133** mapping.
134**
135** Return Codes:
136** -1 -- couldn't open ttycap.
137** 1 -- bad terminal type, or standard output not tty.
138** 0 -- ok.
139**
140** Defined Constants:
141** DIALUP -- the type code for a dialup port
142** PLUGBOARD -- the code for a plugboard port.
143** ARPANET -- the code for an arpanet port.
144** BACKSPACE -- control-H, the default for -e.
145** CONTROLX -- control-X, the default for -k.
146** OLDERASE -- the system default erase character.
147** OLDKILL -- the system default kill character.
148** FILEDES -- the file descriptor to do the operation
149** on, nominally 1 or 2.
150** STDOUT -- the standard output file descriptor.
151** UIDMASK -- the bit pattern to mask with the getuid()
152** call to get just the user id.
153** GTTYN -- defines file containing generalized ttynames
154** and compiles code to look there.
155**
156** Requires:
157** Routines to handle htmp, ttytype, and ttycap.
158**
159** Compilation Flags:
160** OLDDIALUP -- accept the -d flag. Map "sd" to "dialup".
161** OLDPLUGBOARD -- accept the -p flag. Map "sp" to "plugboard".
162** OLDARPANET -- accept the -a flag. Map "sa" to "arpanet".
163** OLDFLAGS -- must be defined to compile code for any of
164** the -d, -p, or -a flags.
165** FULLLOGIN -- if defined, login sets the ttytype from
166** /etc/ttytype file.
167** V6 -- if clear, use environments, not htmp.
168** also use TIOCSETN rather than stty to avoid flushing
169** GTTYN -- if set, compiles code to look at /etc/ttytype.
170**
171** Trace Flags:
172** none
173**
174** Diagnostics:
175** Bad flag
176** An incorrect option was specified.
177** Too few args
178** more command line arguments are required.
179** Unexpected arg
180** wrong type of argument was encountered.
181** Cannot open ...
182** The specified file could not be openned.
183** Type ... unknown
184** An unknown terminal type was specified.
185** Cannot update htmp
186** Cannot update htmp file when the standard
187** output is not a terminal.
188** Erase set to ...
189** Telling that the erase character has been
190** set to the specified character.
191** Kill set to ...
192** Ditto for kill
193** Erase is ... Kill is ...
194** Tells that the erase/kill characters were
195** wierd before, but they are being left as-is.
196** Not a terminal
197** Set if FILEDES is not a terminal.
198**
199** Compilation Instructions:
200** cc -n -O tset.c -ltermlib
201** mv a.out tset
202** chown bin tset
203** chmod 4755 tset
204**
205** where 'bin' should be whoever owns the 'htmp' file.
206** If 'htmp' is 666, then tset need not be setuid.
207**
208** Author:
209** Eric Allman
210** Electronics Research Labs
211** U.C. Berkeley
212**
213** History:
214** 7/80 -- '-S' added. -m mapping added. TERMCAP string
215** cleaned up.
216** 3/80 -- Changed to use tputs. Prc & flush added.
217** 10/79 -- '-s' option extended to handle TERMCAP
218** variable, set noglob, quote the entry,
219** and know about the Bourne shell. Terminal
220** initialization moved to before any information
221** output so screen clears would not screw you.
222** '-Q' option added.
223** 8/79 -- '-' option alone changed to only output
224** type. '-s' option added. 'VERSION7'
225** changed to 'V6' for compatibility.
226** 12/78 -- modified for eventual migration to VAX/UNIX,
227** so the '-' option is changed to output only
228** the terminal type to STDOUT instead of
229** FILEDES. FULLLOGIN flag added.
230** 9/78 -- '-' and '-p' options added (now fully
231** compatible with ttytype!), and spaces are
232** permitted between the -d and the type.
233** 8/78 -- The sense of -h and -u were reversed, and the
234** -f flag is dropped -- same effect is available
235** by just stating the terminal type.
236** 10/77 -- Written.
237*/
238
239/*
240# define FULLLOGIN 1
241*/
242# ifndef V6
243# define GTTYN "/etc/ttytype"
244# endif
245
246# include <ctype.h>
247# include <sgtty.h>
248# include <stdio.h>
249
250# define BACKSPACE ('H' & 037)
251# define CONTROLX ('X' & 037)
252# define OLDERASE '#'
253# define OLDKILL '@'
254
255# define FILEDES 2
256# define STDOUT 1
257
258# ifdef V6
259# define UIDMASK 0377
260# else
261# define UIDMASK -1
262# endif
263
264# define DEFTYPE "unknown"
265# define USAGE\
266"usage: tset [-] [-hrsuIQS] [-eC] [-kC] [-m [ident][test speed]:type] [type]\n"
267
268# define DIALUP "dialup"
269# define OLDDIALUP "sd"
270# define PLUGBOARD "plugboard"
271# define OLDPLUGBOARD "sp"
272/***
273# define ARPANET "arpanet"
274# define OLDARPANET "sa"
275***/
276# define OLDFLAGS
277
278
279
280# ifdef GTTYN
281typedef char *ttyid_t;
282# define NOTTY 0
283# else
284typedef char ttyid_t;
285# define NOTTY 'x'
286# endif
287
288/*
289 * Baud Rate Conditionals
290 */
291# define ANY 0
292# define GT 1
293# define EQ 2
294# define LT 4
295# define GE (GT|EQ)
296# define LE (LT|EQ)
297# define NE (GT|LT)
298# define ALL (GT|EQ|LT)
299
300
301
302# define NMAP 10
303
304struct map {
305 char *Ident;
306 char Test;
307 char Speed;
308 char *Type;
309} map[NMAP];
310
311struct map *Map = map;
312
313struct
314{
315 char *string;
316 int speed;
317} speeds[] = {
318 "0", B0,
319 "50", B50,
320 "75", B75,
321 "110", B110,
322 "134", B134,
323 "134.5",B134,
324 "150", B150,
325 "200", B200,
326 "300", B300,
327 "600", B600,
328 "1200", B1200,
329 "1800", B1800,
330 "2400", B2400,
331 "4800", B4800,
332 "9600", B9600,
333 "exta", EXTA,
334 "extb", EXTB,
335 0,
336};
337
338char Erase_char; /* new erase character */
339char Kill_char; /* new kill character */
340char Specialerase; /* set => Erase_char only on terminals with backspace */
341
342ttyid_t Ttyid = NOTTY; /* terminal identifier */
343char *TtyType; /* type of terminal */
344char *DefType; /* default type if none other computed */
345char *NewType; /* mapping identifier based on old flags */
346int Dash_u; /* don't update htmp */
347int Dash_h; /* don't read htmp */
348int DoSetenv; /* output setenv commands */
349int BeQuiet; /* be quiet */
350int NoInit; /* don't output initialization string */
351int Report; /* report current type */
352int Ureport; /* report to user */
353int RepOnly; /* report only */
354int CmndLine; /* output full command lines (-s option) */
355int Ask; /* ask user for termtype */
356
357# define CAPBUFSIZ 1024
358char Capbuf[CAPBUFSIZ]; /* line from /etc/termcap for this TtyType */
359char *Ttycap; /* termcap line from termcap or environ */
360
361struct delay
362{
363 int d_delay;
364 int d_bits;
365};
366
367# include "tset.delays.h"
368
369
370
371main(argc, argv)
372int argc;
373char *argv[];
374{
375 struct sgttyb mode;
376 struct sgttyb oldmode;
377 char buf[256];
378 auto char *bufp;
379 register char *p;
380 char *command;
381 register int i;
382 int Break;
383 int Not;
384 int Mapped;
385 extern char *nextarg();
386 extern char *mapped();
387# ifdef V6
388 extern char *hsgettype();
389# else
390 extern char *getenv();
391# endif
392# ifdef GTTYN
393 extern char *stypeof();
394 extern char *ttyname();
395 extern char *tgetstr();
396# endif
397 char bs_char;
398 int csh;
399 extern prc();
400 extern char PC;
401 extern short ospeed;
402
403 if (gtty(FILEDES, &mode) < 0)
404 {
405 prs("Not a terminal\n");
406 exit(1);
407 }
408 bmove(&mode, &oldmode, sizeof mode);
409 ospeed = mode.sg_ospeed;
410
411 /* scan argument list and collect flags */
412 command = argv[0];
413 if (argc == 2 && argv[1][0] == '-' && argv[1][1] == '\0')
414 {
415 RepOnly++;
416 Dash_u++;
417 }
418 argc--;
419 while (--argc >= 0)
420 {
421 p = *++argv;
422 if (*p == '-')
423 {
424 if (*++p == NULL)
425 Report++; /* report current terminal type */
426 else while (*p) switch (*p++)
427 {
428
429 case 'r': /* report to user */
430 Ureport++;
431 continue;
432
433 case 'E': /* special erase: operate on all but TTY33 */
434 Specialerase++;
435 /* explicit fall-through to -e case */
436
437 case 'e': /* erase character */
438 if (*p == NULL)
439 Erase_char = -1;
440 else
441 {
442 if (*p == '^' && p[1] != NULL)
443 Erase_char = *++p & 037;
444 else
445 Erase_char = *p;
446 p++;
447 }
448 continue;
449
450 case 'k': /* kill character */
451 if (*p == NULL)
452 Kill_char = CONTROLX;
453 else
454 {
455 if (*p == '^' && p[1] != NULL)
456 Kill_char = *++p & 037;
457 else
458 Kill_char = *p;
459 p++;
460 }
461 continue;
462
463# ifdef OLDFLAGS
464# ifdef OLDDIALUP
465 case 'd': /* dialup type */
466 NewType = DIALUP;
467 goto mapold;
468# endif
469
470# ifdef OLDPLUGBOARD
471 case 'p': /* plugboard type */
472 NewType = PLUGBOARD;
473 goto mapold;
474# endif
475
476# ifdef OLDARPANET
477 case 'a': /* arpanet type */
478 Newtype = ARPANET;
479 goto mapold;
480# endif
481
482mapold: Map->Ident = NewType;
483 Map->Test = ALL;
484 if (*p == NULL)
485 {
486 p = nextarg(argc--, argv++);
487 }
488 Map->Type = p;
489 Map++;
490 Mapped++;
491 p = "";
492 continue;
493# endif
494
495 case 'm': /* map identifier to type */
496 /* This code is very loose. Almost no
497 ** syntax checking is done!! However,
498 ** illegal syntax will only produce
499 ** weird results.
500 */
501 if (*p == NULL)
502 {
503 p = nextarg(argc--, argv++);
504 }
505 if (isalnum(*p))
506 {
507 Map->Ident = p; /* identifier */
508 while (isalnum(*p)) p++;
509 }
510 else
511 Map->Ident = "";
512 Break = 0;
513 Not = 0;
514 while (!Break) switch (*p)
515 {
516 case NULL:
517 p = nextarg(argc--, argv++);
518 continue;
519
520 case ':': /* mapped type */
521 *p++ = NULL;
522 Break++;
523 continue;
524
525 case '>': /* conditional */
526 Map->Test |= GT;
527 *p++ = NULL;
528 continue;
529
530 case '<': /* conditional */
531 Map->Test |= LT;
532 *p++ = NULL;
533 continue;
534
535 case '=': /* conditional */
536 case '@':
537 Map->Test |= EQ;
538 *p++ = NULL;
539 continue;
540
541 case '!': /* invert conditions */
542 Not = ~Not;
543 *p++ = NULL;
544 continue;
545
546 case 'B': /* Baud rate */
547 p++;
548 /* intentional fallthru */
549 default:
550 if (isdigit(*p) || *p == 'e')
551 {
552 Map->Speed = baudrate(p);
553 while (isalnum(*p) || *p == '.')
554 p++;
555 }
556 else
557 Break++;
558 continue;
559 }
560 if (Not) /* invert sense of test */
561 {
562 Map->Test = (~(Map->Test))&ALL;
563 }
564 if (*p == NULL)
565 {
566 p = nextarg(argc--, argv++);
567 }
568 Map->Type = p;
569 p = "";
570 Map++;
571 Mapped++;
572 continue;
573
574 case 'h': /* don't get type from htmp or env */
575 Dash_h++;
576 continue;
577
578 case 'u': /* don't update htmp */
579 Dash_u++;
580 continue;
581
582 case 's': /* output setenv commands */
583 DoSetenv++;
584 CmndLine++;
585 continue;
586
587 case 'S': /* output setenv strings */
588 DoSetenv++;
589 CmndLine=0;
590 continue;
591
592 case 'Q': /* be quiet */
593 BeQuiet++;
594 continue;
595
596 case 'I': /* no initialization */
597 NoInit++;
598 continue;
599
600 case 'A': /* Ask user */
601 Ask++;
602 continue;
603
604 default:
605 *p-- = NULL;
606 fatal("Bad flag -", p);
607 }
608 }
609 else
610 {
611 /* terminal type */
612 DefType = p;
613 }
614 }
615
616 if (DefType)
617 {
618 if (Mapped)
619 {
620 Map->Ident = ""; /* means "map any type" */
621 Map->Test = ALL; /* at all baud rates */
622 Map->Type = DefType; /* to the default type */
623 }
624 else
625 TtyType = DefType;
626 }
627
628# ifndef V6
629 /* get current idea of terminal type from environment */
630 if (!Dash_h && !Mapped && TtyType == 0)
631 TtyType = getenv("TERM");
632# endif
633
634 /* determine terminal id if needed */
635# ifdef V6
636 if (Ttyid == NOTTY && (TtyType == 0 || !Dash_h || !Dash_u))
637 Ttyid = ttyn(FILEDES);
638# else
639 if (!RepOnly && Ttyid == NOTTY && (TtyType == 0 || !Dash_h))
640 Ttyid = ttyname(FILEDES);
641# endif
642
643# ifdef V6
644 /* get htmp if ever used */
645 if (!Dash_u || (TtyType == 0 && !Dash_h))
646 {
647 /* get htmp entry -- if error or wrong user use ttytype */
648 if (Ttyid == NOTTY || hget(Ttyid) < 0 ||
649 hgettype() == 0 || hgetuid() != (getuid() & UIDMASK))
650 Dash_h++;
651 }
652
653 /* find terminal type (if not already known) */
654 if (TtyType == 0 && !Dash_h)
655 {
656 /* get type from /etc/htmp */
657 TtyType = hsgettype();
658 }
659# endif
660
661# ifdef GTTYN
662 /* If still undefined, look at /etc/ttytype */
663 if (TtyType == 0)
664 {
665 TtyType = stypeof(Ttyid);
666 }
667# endif
668
669 /* If still undefined, use DEFTYPE */
670 if (TtyType == 0)
671 {
672 TtyType = DEFTYPE;
673 }
674
675 /* check for dialup or other mapping */
676 if (Mapped)
677 TtyType = mapped(TtyType, ospeed);
678
679 /* TtyType now contains a pointer to the type of the terminal */
680 /* If the first character is '?', ask the user */
681 if (TtyType[0] == '?')
682 {
683 Ask++;
684 TtyType++;
685 if (TtyType[0] == '\0')
686 TtyType = DEFTYPE;
687 }
688 if (Ask)
689 {
690 prs("TERM = (");
691 prs(TtyType);
692 prs(") ");
693 flush();
694
695 /* read the terminal. If not empty, set type */
696 i = read(2, buf, sizeof buf - 1);
697 if (i >= 0)
698 {
699 if (buf[i - 1] == '\n')
700 i--;
701 buf[i] = '\0';
702 if (buf[0] != '\0')
703 TtyType = buf;
704 }
705 }
706
707 if (Ttycap == 0)
708 {
709 /* get terminal capabilities */
710 switch (tgetent(Capbuf, TtyType))
711 {
712 case -1:
713 prs("Cannot open termcap file\n");
714 flush();
715 exit(-1);
716
717 case 0:
718 prs("Type ");
719 prs(TtyType);
720 prs(" unknown\n");
721 flush();
722 exit(1);
723 }
724 Ttycap = Capbuf;
725 }
726
727 if (!RepOnly)
728 {
729 /* determine erase and kill characters */
730 if (Specialerase && !tgetflag("bs"))
731 Erase_char = 0;
732 bufp = buf;
733 p = tgetstr("kb", &bufp);
734 if (p == NULL || p[1] != '\0')
735 p = tgetstr("bc", &bufp);
736 if (p != NULL && p[1] == '\0')
737 bs_char = p[0];
738 else if (tgetflag("bs"))
739 bs_char = BACKSPACE;
740 else
741 bs_char = 0;
742 if (Erase_char == 0 && !tgetflag("os") && mode.sg_erase == OLDERASE)
743 {
744 if (tgetflag("bs") || bs_char != 0)
745 Erase_char = -1;
746 }
747 if (Erase_char < 0)
748 Erase_char = (bs_char != 0) ? bs_char : BACKSPACE;
749
750 if (mode.sg_erase == 0)
751 mode.sg_erase = OLDERASE;
752 if (Erase_char != 0)
753 mode.sg_erase = Erase_char;
754
755 if (mode.sg_kill == 0)
756 mode.sg_kill = OLDKILL;
757 if (Kill_char != 0)
758 mode.sg_kill = Kill_char;
759
760 /* set modes */
761 setdelay("dC", CRdelay, CRbits, &mode.sg_flags);
762 setdelay("dN", NLdelay, NLbits, &mode.sg_flags);
763 setdelay("dB", BSdelay, BSbits, &mode.sg_flags);
764 setdelay("dF", FFdelay, FFbits, &mode.sg_flags);
765 setdelay("dT", TBdelay, TBbits, &mode.sg_flags);
766 if (tgetflag("UC") || command[0] == 'T')
767 mode.sg_flags |= LCASE;
768 else if (tgetflag("LC"))
769 mode.sg_flags &= ~LCASE;
770 mode.sg_flags &= ~(EVENP | ODDP | RAW);
771# ifndef V6
772 mode.sg_flags &= ~CBREAK;
773# endif
774 if (tgetflag("EP"))
775 mode.sg_flags |= EVENP;
776 if (tgetflag("OP"))
777 mode.sg_flags |= ODDP;
778 if ((mode.sg_flags & (EVENP | ODDP)) == 0)
779 mode.sg_flags |= EVENP | ODDP;
780 mode.sg_flags |= CRMOD | ECHO | XTABS;
781 if (tgetflag("NL")) /* new line, not line feed */
782 mode.sg_flags &= ~CRMOD;
783 if (tgetflag("HD")) /* half duplex */
784 mode.sg_flags &= ~ECHO;
785 if (tgetflag("pt")) /* print tabs */
786 mode.sg_flags &= ~XTABS;
787 if (!bequal(&mode, &oldmode, sizeof mode))
788# ifndef V6
789 ioctl(FILEDES, TIOCSETN, &mode);
790# else
791 stty(FILEDES, &mode);
792# endif
793
794 /* get pad character */
795 bufp = buf;
796 if (tgetstr("pc", &bufp) != 0)
797 PC = buf[0];
798
799 /* output startup string */
800 if (!NoInit)
801 {
802 bufp = buf;
803 if (tgetstr("is", &bufp) != 0)
804 tputs(buf, 0, prc);
805 flush();
806 bufp = buf;
807 if (tgetstr("if", &bufp) != 0)
808 cat(buf);
809 sleep(1); /* let terminal settle down */
810 }
811
812 /* set up environment for the shell we are using */
813 /* (this code is rather heuristic) */
814 csh = 0;
815 if (DoSetenv)
816 {
817# ifndef V6
818 char *sh;
819
820 if ((sh = getenv("SHELL")) && (i = strlen(sh)) >= 3)
821 {
822 p = &sh[i-3];
823 if ((csh = sequal(p, "csh")) && CmndLine)
824 write(STDOUT, "set noglob;\n", 12);
825 }
826 if (!csh)
827# endif
828 /* running system shell */
829 write(STDOUT, "export TERMCAP TERM;\n", 21);
830 }
831 }
832
833 /* report type if appropriate */
834 if (DoSetenv || Report || Ureport)
835 {
836 /* find first alias (if any) */
837 for (p = Ttycap; *p != 0 && *p != '|' && *p != ':'; p++)
838 continue;
839 if (*p == 0 || *p == ':')
840 p = Ttycap;
841 else
842 p++;
843 bufp = p;
844 while (*p != '|' && *p != ':' && *p != 0)
845 p++;
846 i = *p;
847 if (DoSetenv)
848 {
849 if (csh)
850 {
851 if (CmndLine)
852 write(STDOUT, "setenv TERM ", 12);
853 write(STDOUT, bufp, p - bufp);
854 write(STDOUT, " ", 1);
855 if (CmndLine)
856 write(STDOUT, ";\n", 2);
857 }
858 else
859 {
860 write(STDOUT, "TERM=", 5);
861 write(STDOUT, bufp, p - bufp);
862 write(STDOUT, ";\n", 2);
863 }
864 }
865 if (Report && !DoSetenv)
866 {
867 write(STDOUT, bufp, p - bufp);
868 write(STDOUT, "\n", 1);
869 }
870 if (Ureport)
871 {
872 *p = '\0';
873 prs("Terminal type is ");
874 prs(bufp);
875 prs("\n");
876 flush();
877 }
878 *p = i;
879 if (DoSetenv)
880 {
881 if (csh)
882 {
883 if (CmndLine)
884 write(STDOUT, "setenv TERMCAP '", 16);
885 }
886 else
887 write(STDOUT, "TERMCAP='", 9);
888 wrtermcap(Ttycap);
889 if (csh)
890 {
891 if (CmndLine)
892 {
893 write(STDOUT, "';\n", 3);
894 write(STDOUT, "unset noglob;\n", 14);
895 }
896 }
897 else
898 write(STDOUT, "';\n", 3);
899 }
900 }
901
902 if (RepOnly)
903 exit(0);
904
905 /* tell about changing erase and kill characters */
906 reportek("Erase", mode.sg_erase, oldmode.sg_erase, OLDERASE);
907 reportek("Kill", mode.sg_kill, oldmode.sg_kill, OLDKILL);
908
909# ifdef V6
910 /* update htmp */
911 if (!Dash_u)
912 {
913 if (Ttyid == 0)
914 Ttyid = ttyn(FILEDES);
915 if (Ttyid == 'x')
916 {
917 prs("Cannot update htmp\n");
918 flush();
919 }
920 else
921 {
922 /* update htmp file only if changed */
923 if (!bequal(Capbuf, hsgettype(), 2))
924 {
925 hsettype(Capbuf[0] | (Capbuf[1] << 8));
926 hput(Ttyid);
927 }
928 }
929 }
930# endif
931
932 exit(0);
933}
934
935reportek(name, new, old, def)
936char *name;
937char old;
938char new;
939char def;
940{
941 register char o;
942 register char n;
943 register char *p;
944
945 if (BeQuiet)
946 return;
947 o = old;
948 n = new;
949
950 if (o == n && n == def)
951 return;
952 prs(name);
953 if (o == n)
954 prs(" is ");
955 else
956 prs(" set to ");
957 if (n < 040)
958 {
959 prs("control-");
960 n = (n & 037) | 0100;
961 } else if (n == 0177) {
962 prs("delete\n");
963 flush();
964 return;
965 }
966 p = "x\n";
967 p[0] = n;
968 prs(p);
969 flush();
970}
971
972
973
974
975setdelay(cap, dtab, bits, flags)
976char *cap;
977struct delay dtab[];
978int bits;
979int *flags;
980{
981 register int i;
982 register struct delay *p;
983
984 /* see if this capability exists at all */
985 i = tgetnum(cap);
986 if (i < 0)
987 i = 0;
988
989 /* clear out the bits, replace with new ones */
990 *flags &= ~bits;
991
992 /* scan dtab for first entry with adequate delay */
993 for (p = dtab; p->d_delay >= 0; p++)
994 {
995 if (p->d_delay >= i)
996 {
997 p++;
998 break;
999 }
1000 }
1001
1002 /* use last entry if none will do */
1003 *flags |= (--p)->d_bits;
1004}
1005
1006
1007prs(s)
1008char *s;
1009{
1010 while (*s != '\0')
1011 prc(*s++);
1012}
1013
1014
1015char OutBuf[256];
1016int OutPtr;
1017
1018prc(c)
1019 char c;
1020{
1021 OutBuf[OutPtr++] = c;
1022 if (OutPtr >= sizeof OutBuf)
1023 flush();
1024}
1025
1026flush()
1027{
1028 if (OutPtr > 0)
1029 write(2, OutBuf, OutPtr);
1030 OutPtr = 0;
1031}
1032
1033
1034cat(file)
1035char *file;
1036{
1037 register int fd;
1038 register int i;
1039 char buf[BUFSIZ];
1040
1041 fd = open(file, 0);
1042 if (fd < 0)
1043 {
1044 prs("Cannot open ");
1045 prs(file);
1046 prs("\n");
1047 flush();
1048 exit(-1);
1049 }
1050
1051 flush();
1052 while ((i = read(fd, buf, BUFSIZ)) > 0)
1053 write(FILEDES, buf, i);
1054
1055 close(fd);
1056}
1057
1058
1059
1060bmove(from, to, length)
1061char *from;
1062char *to;
1063int length;
1064{
1065 register char *p, *q;
1066 register int i;
1067
1068 i = length;
1069 p = from;
1070 q = to;
1071
1072 while (i-- > 0)
1073 *q++ = *p++;
1074}
1075
1076
1077
1078bequal(a, b, len)
1079char *a;
1080char *b;
1081int len;
1082{
1083 register char *p, *q;
1084 register int i;
1085
1086 i = len;
1087 p = a;
1088 q = b;
1089
1090 while (*p && *q && (*p == *q) && --i > 0)
1091 {
1092 p++; q++;
1093 }
1094 return ((*p == *q) && i >= 0);
1095}
1096
1097sequal(a, b)
1098char *a;
1099char *b;
1100{
1101 register char *p = a, *q = b;
1102
1103 while (*p && *q && (*p == *q))
1104 {
1105 p++; q++;
1106 }
1107 return (*p == *q);
1108}
1109
1110# ifdef GTTYN
1111char *
1112stypeof(ttyid)
1113char *ttyid;
1114{
1115 static char typebuf[50];
1116 register char *PortType;
1117 register char *PortName;
1118 register char *TtyId;
1119 register char *p;
1120 register FILE *f;
1121
1122 if (ttyid == NOTTY)
1123 return (DEFTYPE);
1124 f = fopen(GTTYN, "r");
1125 if (f == NULL)
1126 return (DEFTYPE);
1127
1128 /* split off end of name */
1129 TtyId = ttyid;
1130 while (*ttyid)
1131 if (*ttyid++ == '/')
1132 TtyId = ttyid;
1133
1134 /* scan the file */
1135 while (fgets(typebuf, sizeof typebuf, f) != NULL)
1136 {
1137 p = PortType = typebuf;
1138 while (*p && isalnum(*p))
1139 p++;
1140 *p++ = NULL;
1141
1142 /* skip separator */
1143 while (*p && !isalnum(*p))
1144 p++;
1145
1146 PortName = p;
1147 /* put NULL at end of name */
1148 while (*p && isalnum(*p))
1149 p++;
1150 *p = NULL;
1151
1152 /* check match on port name */
1153 if (sequal(PortName, TtyId)) /* found it */
1154 {
1155# ifdef OLDDIALUP
1156 if (sequal(PortType, OLDDIALUP))
1157 PortType = DIALUP;
1158# endif
1159
1160# ifdef OLDPLUGBOARD
1161 if (sequal(PortType, OLDPLUGBOARD))
1162 PortType = PLUGBOARD;
1163# endif
1164
1165# ifdef OLDARPANET
1166 if (sequal(PortType, OLDARPANET))
1167 PortType = ARPANET;
1168# endif
1169 fclose (f);
1170 return(PortType);
1171 }
1172 }
1173 fclose (f);
1174 return (DEFTYPE);
1175}
1176# endif
1177
1178#define YES 1
1179#define NO 0
1180/*
1181 * routine to output the string for the environment TERMCAP variable
1182 */
1183#define WHITE(c) (c == ' ' || c == '\t')
1184char delcap[128][2];
1185int ncap = 0;
1186
1187wrtermcap(bp)
1188char *bp;
1189{
1190 char buf[CAPBUFSIZ];
1191 char *p = buf;
1192 char *tp;
1193 char *putbuf();
1194 int space, empty;
1195
1196 /* discard names with blanks */
1197/** May not be desireable ? **/
1198 while (*bp && *bp != ':') {
1199 if (*bp == '|') {
1200 tp = bp+1;
1201 space = NO;
1202 while (*tp && *tp != '|' && *tp != ':') {
1203 space = (space || WHITE(*tp) );
1204 tp++;
1205 }
1206 if (space) {
1207 bp = tp;
1208 continue;
1209 }
1210 }
1211 *p++ = *bp++;
1212 }
1213/**/
1214
1215 while (*bp) {
1216 switch (*bp) {
1217 case ':': /* discard empty, cancelled or dupl fields */
1218 tp = bp+1;
1219 empty = YES;
1220 while (*tp && *tp != ':') {
1221 empty = (empty && WHITE(*tp) );
1222 tp++;
1223 }
1224 if (empty || cancelled(bp+1)) {
1225 bp = tp;
1226 continue;
1227 }
1228 break;
1229
1230 case ' ': /* no spaces in output */
1231 p = putbuf(p, "\\040");
1232 bp++;
1233 continue;
1234
1235 case '"': /* no quotes in output */
1236 p = putbuf(p, "\\042");
1237 bp++;
1238 continue;
1239
1240 case '\'': /* no quotes in output */
1241 p = putbuf(p, "\\047");
1242 bp++;
1243 continue;
1244
1245 case '\\':
1246 case '^': /* anything following is OK */
1247 *p++ = *bp++;
1248 }
1249 *p++ = *bp++;
1250 }
1251 write (STDOUT, buf, p-buf);
1252}
1253
1254cancelled(cap)
1255char *cap;
1256{
1257 register int i;
1258
1259 for (i = 0; i < ncap; i++)
1260 {
1261 if (cap[0] == delcap[i][0] && cap[1] == delcap[i][1])
1262 return (YES);
1263 }
1264 /* delete a second occurrance of the same capability */
1265 delcap[ncap][0] = cap[0];
1266 delcap[ncap][1] = cap[1];
1267 ncap++;
1268 return (cap[2] == '@');
1269}
1270
1271char *
1272putbuf(ptr, str)
1273char *ptr;
1274char *str;
1275{
1276 while (*str)
1277 *ptr++ = *str++;
1278 return (ptr);
1279}
1280
1281
1282baudrate(p)
1283char *p;
1284{
1285 char buf[8];
1286 int i = 0;
1287
1288 while (i < 7 && (isalnum(*p) || *p == '.'))
1289 buf[i++] = *p++;
1290 buf[i] = NULL;
1291 for (i=0; speeds[i].string; i++)
1292 if (sequal(speeds[i].string, buf))
1293 return (speeds[i].speed);
1294 return (-1);
1295}
1296
1297char *
1298mapped(type, speed)
1299char *type;
1300short speed;
1301{
1302 int match;
1303
1304# ifdef DEB
1305 printf ("spd:%d\n", speed);
1306 prmap();
1307# endif
1308 Map = map;
1309 while (Map->Ident)
1310 {
1311 if (*(Map->Ident) == NULL || bequal(Map->Ident, type, 4))
1312 {
1313 match = NO;
1314 switch (Map->Test)
1315 {
1316 case ANY: /* no test specified */
1317 case ALL:
1318 match = YES;
1319 break;
1320
1321 case GT:
1322 match = (speed > Map->Speed);
1323 break;
1324
1325 case GE:
1326 match = (speed >= Map->Speed);
1327 break;
1328
1329 case EQ:
1330 match = (speed == Map->Speed);
1331 break;
1332
1333 case LE:
1334 match = (speed <= Map->Speed);
1335 break;
1336
1337 case LT:
1338 match = (speed < Map->Speed);
1339 break;
1340
1341 case NE:
1342 match = (speed != Map->Speed);
1343 break;
1344 }
1345 if (match)
1346 return (Map->Type);
1347 }
1348 Map++;
1349 }
1350 /* no match found; return given type */
1351 return (type);
1352}
1353
1354# ifdef DEB
1355prmap()
1356{
1357 Map = map;
1358 while (Map->Ident)
1359 {
1360 printf ("%s t:%d s:%d %s\n",
1361 Map->Ident, Map->Test, Map->Speed, Map->Type);
1362 Map++;
1363 }
1364}
1365# endif
1366
1367char *
1368nextarg(argc, argv)
1369int argc;
1370char *argv[];
1371{
1372 if (argc <= 0)
1373 fatal ("Too few args: ", *argv);
1374 if (*(*++argv) == '-')
1375 fatal ("Unexpected arg: ", *argv);
1376 return (*argv);
1377}
1378
1379fatal (mesg, obj)
1380char *mesg;
1381char *obj;
1382{
1383 prs (mesg);
1384 prs (obj);
1385 prc ('\n');
1386 prs (USAGE);
1387 flush();
1388 exit(1);
1389}