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