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