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