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