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