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 <stdlib.h>
272 #include <termio.h>
273 #include <signal.h>
274
275
276 #define YES 1
277 #define NO 0
278 #undef CNTL
279 #define CNTL(c) ((c)&037)
280 #define BACKSPACE (CNTL('H'))
281 #define isdigit(c) (c >= '0' && c <= '9')
282 #define isalnum(c) (c > ' ' && (index("<@=>!:|\177", c) == NULL))
283 #define OLDERASE '#'
284
285 /* default special characters */
286 #ifndef CERASE
287 #define CERASE '\177'
288 #endif
289 #ifndef CKILL
290 #define CKILL CNTL('U')
291 #endif
292 #ifndef CINTR
293 #define CINTR CNTL('C')
294 #endif
295 #ifndef CDSUSP
296 #define CQUIT 034 /* FS, ^\ */
297 #define CSTART CNTL('Q')
298 #define CSTOP CNTL('S')
299 #define CEOF CNTL('D')
300 #define CEOT CEOF
301 #define CBRK 0377
302 #define CSUSP CNTL('Z')
303 #define CDSUSP CNTL('Y')
304 #define CRPRNT CNTL('R')
305 #define CFLUSH CNTL('O')
306 #define CWERASE CNTL('W')
307 #define CLNEXT CNTL('V')
308 #endif
309
310 #define FILEDES 2 /* do gtty/stty on this descriptor */
311 #define STDOUT 1 /* output of -s/-S to this descriptor */
312
313 #define UIDMASK -1
314
315 #define USAGE "usage: tset [-] [-rsIQS] [-eC] [-kC] " \
316 "[-iC] [-m [ident][test speed]:type] [type]\n"
317
318 #define OLDFLAGS
319 #define DIALUP "dialup"
320 #define OLDDIALUP "sd"
321 #define PLUGBOARD "plugboard"
322 #define OLDPLUGBOARD "sp"
323
324 #define DEFTYPE "unknown"
325
326 /*
327 * Baud Rate Conditionals
328 */
329 #define ANY 0
330 #define GT 1
331 #define EQ 2
332 #define LT 4
333 #define GE (GT|EQ)
334 #define LE (LT|EQ)
335 #define NE (GT|LT)
336 #define ALL (GT|EQ|LT)
337
338
339
340 #define NMAP 10
341
342 struct map {
343 char *Ident;
344 char Test;
345 char Speed;
346 char *Type;
347 } map[NMAP];
348
349 struct map *Map = map;
350
351 struct {
352 char *string;
353 int speed;
354 int baudrate;
355 } speeds[] = {
356 "0", B0, 0,
357 "50", B50, 50,
358 "75", B75, 75,
359 "110", B110, 110,
360 "134", B134, 134,
361 "134.5", B134, 134,
362 "150", B150, 150,
363 "200", B200, 200,
364 "300", B300, 300,
365 "600", B600, 600,
366 "1200", B1200, 1200,
367 "1800", B1800, 1800,
368 "2400", B2400, 2400,
369 "4800", B4800, 4800,
370 "9600", B9600, 9600,
371 "19200", EXTA, 19200,
372 "exta", EXTA, 19200,
373 "extb", EXTB, 38400,
374 "57600", B57600, 57600,
375 "76800", B76800, 76800,
376 "115200", B115200, 115200,
377 "153600", B153600, 153600,
378 "230400", B230400, 230400,
379 "307200", B307200, 307200,
380 "460800", B460800, 460800,
381 "921600", B921600, 921600,
382 "1000000", B1000000, 1000000,
383 "1152000", B1152000, 1152000,
384 "1500000", B1500000, 1500000,
385 "2000000", B2000000, 2000000,
386 "2500000", B2500000, 2500000,
387 "3000000", B3000000, 3000000,
388 "3500000", B3500000, 3500000,
389 "4000000", B4000000, 4000000,
390 0,
391 };
392
393 signed char Erase_char; /* new erase character */
394 char Kill_char; /* new kill character */
395 char Intr_char; /* new interrupt character */
396 char Specialerase; /* set => Erase_char only on terminals with backspace */
397
398 char *TtyType; /* type of terminal */
399 char *DefType; /* default type if none other computed */
400 char *NewType; /* mapping identifier based on old flags */
401 int Mapped; /* mapping has been specified */
402 int Dash_u; /* don't update htmp */
403 int Dash_h; /* don't read htmp */
404 int DoSetenv; /* output setenv commands */
405 int BeQuiet; /* be quiet */
406 int NoInit; /* don't output initialization string */
407 int IsReset; /* invoked as reset */
408 int Report; /* report current type */
409 int Ureport; /* report to user */
410 int RepOnly; /* report only */
411 int CmndLine; /* output full command lines (-s option) */
412 int Ask; /* ask user for termtype */
413 int DoVirtTerm = YES; /* Set up a virtual terminal */
414 int PadBaud; /* Min rate of padding needed */
415
416 #define CAPBUFSIZ 1024
417 char Capbuf[CAPBUFSIZ]; /* line from /etc/termcap for this TtyType */
418 char *Ttycap; /* termcap line from termcap or environ */
419
420 char Aliasbuf[128];
421 char *Alias[16];
422
423 extern char *strcpy();
424 extern char *index();
425
426 struct delay
427 {
428 int d_delay;
429 int d_bits;
430 };
431
432 #include "tset.delays.h"
433
434 struct termio mode;
435 struct termio oldmode;
436 struct termios modes;
437 struct termios oldmodes;
438 int istermios;
439
440 void reportek(char *, char, char, char);
441 void setdelay(char *, struct delay [], tcflag_t, tcflag_t *);
442 void prs(char *);
443 void prc(char);
444 void flush(void);
445 void cat(char *);
446 void bmove(char *, char *, int);
447 void makealias(char *);
448 void wrtermcap(char *);
449 void fatal(char *, char *);
450 char reset(); /* Routine for checking&resetting chars */
451
452 int
main(int argc,char * argv[])453 main(int argc, char *argv[])
454 {
455 char buf[CAPBUFSIZ];
456 char termbuf[32];
457 auto char *bufp;
458 char *p;
459 char *command;
460 int i;
461 int Break;
462 int Not;
463 char *nextarg();
464 char *mapped();
465 extern char *rindex();
466 struct winsize win;
467 extern char *getenv();
468 extern char *tgetstr();
469 char bs_char;
470 int csh;
471 int settle = NO;
472 void setmode();
473 extern char PC;
474 extern short ospeed;
475
476 if ((istermios = ioctl(FILEDES, TCGETS, (char *)&modes)) < 0) {
477 if (ioctl(FILEDES, TCGETA, (char *)&mode) < 0) {
478 prs("Not a terminal\n");
479 exit(1);
480 }
481 bmove((char *)&mode, (char *)&oldmode, sizeof (mode));
482 modes.c_lflag = oldmodes.c_lflag = mode.c_lflag;
483 modes.c_oflag = oldmodes.c_oflag = mode.c_oflag;
484 modes.c_iflag = oldmodes.c_iflag = mode.c_iflag;
485 modes.c_cflag = oldmodes.c_cflag = mode.c_cflag;
486 for (i = 0; i < NCC; i++)
487 modes.c_cc[i] = oldmodes.c_cc[i] = mode.c_cc[i];
488 } else
489 bmove((char *)&modes, (char *)&oldmodes, sizeof (modes));
490 ospeed = cfgetospeed(&modes);
491 (void) signal(SIGINT, setmode);
492 (void) signal(SIGQUIT, setmode);
493 (void) signal(SIGTERM, setmode);
494
495 if (command = rindex(argv[0], '/'))
496 command++;
497 else
498 command = argv[0];
499 if (sequal(command, "reset")) {
500 /*
501 * Reset the teletype mode bits to a sensible state.
502 * Copied from the program by Kurt Shoens & Mark Horton.
503 * Very useful after crapping out in raw.
504 */
505 if ((istermios = ioctl(FILEDES, TCGETS, (char *)&modes)) < 0) {
506 (void) ioctl(FILEDES, TCGETA, (char *)&mode);
507 modes.c_lflag = mode.c_lflag;
508 modes.c_oflag = mode.c_oflag;
509 modes.c_iflag = mode.c_iflag;
510 modes.c_cflag = mode.c_cflag;
511 for (i = 0; i < NCC; i++)
512 modes.c_cc[i] = mode.c_cc[i];
513 }
514 curerase = reset(curerase, CERASE);
515 curkill = reset(curkill, CKILL);
516 curintr = reset(curintr, CINTR);
517 modes.c_cc[VQUIT] = reset(modes.c_cc[VQUIT], CQUIT);
518 modes.c_cc[VEOF] = reset(modes.c_cc[VEOF], CEOF);
519
520 modes.c_iflag |= (BRKINT|ISTRIP|ICRNL|IXON);
521 modes.c_iflag &= ~(IGNBRK|PARMRK|INPCK|INLCR|IGNCR|IUCLC|IXOFF);
522 modes.c_oflag |= (OPOST|ONLCR);
523 modes.c_oflag &= ~(OLCUC|OCRNL|ONOCR|ONLRET|OFILL|OFDEL|
524 NLDLY|CRDLY|TABDLY|BSDLY|VTDLY|FFDLY);
525 modes.c_cflag |= (CS7|CREAD);
526 modes.c_cflag &= ~(PARODD|CLOCAL);
527 modes.c_lflag |= (ISIG|ICANON|ECHO|ECHOK);
528 modes.c_lflag &= ~(XCASE|ECHONL|NOFLSH);
529 if (istermios < 0) {
530 mode.c_lflag = modes.c_lflag;
531 mode.c_oflag = modes.c_oflag;
532 mode.c_iflag = modes.c_iflag;
533 mode.c_cflag = modes.c_cflag;
534 for (i = 0; i < NCC; i++)
535 mode.c_cc[i] = modes.c_cc[i];
536 (void) ioctl(FILEDES, TCSETAW, (char *)&mode);
537 } else
538 (void) ioctl(FILEDES, TCSETSW, (char *)&modes);
539 Dash_u = YES;
540 BeQuiet = YES;
541 IsReset = YES;
542 } else if (argc == 2 && sequal(argv[1], "-")) {
543 RepOnly = YES;
544 Dash_u = YES;
545 }
546 argc--;
547
548 /* scan argument list and collect flags */
549 while (--argc >= 0) {
550 p = *++argv;
551 if (*p == '-') {
552 if (*++p == '\0')
553 Report = YES; /* report current terminal type */
554 else
555 while (*p)
556 switch (*p++) {
557
558 case 'r': /* report to user */
559 Ureport = YES;
560 continue;
561
562 case 'E':
563 /* special erase: operate on all but TTY33 */
564 Specialerase = YES;
565 /* explicit fall-through to -e case */
566 /* FALLTHROUGH */
567
568 case 'e': /* erase character */
569 if (*p == '\0')
570 Erase_char = -1;
571 else {
572 if (*p == '^' && p[1] != '\0')
573 if (*++p == '?')
574 Erase_char = '\177';
575 else
576 Erase_char = CNTL(*p);
577 else
578 Erase_char = *p;
579 p++;
580 }
581 continue;
582
583 case 'i': /* interrupt character */
584 if (*p == '\0')
585 Intr_char = CNTL('C');
586 else {
587 if (*p == '^' && p[1] != '\0')
588 if (*++p == '?')
589 Intr_char = '\177';
590 else
591 Intr_char = CNTL(*p);
592 else
593 Intr_char = *p;
594 p++;
595 }
596 continue;
597
598 case 'k': /* kill character */
599 if (*p == '\0')
600 Kill_char = CNTL('U');
601 else {
602 if (*p == '^' && p[1] != '\0')
603 if (*++p == '?')
604 Kill_char = '\177';
605 else
606 Kill_char = CNTL(*p);
607 else
608 Kill_char = *p;
609 p++;
610 }
611 continue;
612
613 #ifdef OLDFLAGS
614 #ifdef OLDDIALUP
615 case 'd': /* dialup type */
616 NewType = DIALUP;
617 goto mapold;
618 #endif
619
620 #ifdef OLDPLUGBOARD
621 case 'p': /* plugboard type */
622 NewType = PLUGBOARD;
623 goto mapold;
624 #endif
625
626 #ifdef OLDARPANET
627 case 'a': /* arpanet type */
628 Newtype = ARPANET;
629 goto mapold;
630 #endif
631
632 mapold: Map->Ident = NewType;
633 Map->Test = ALL;
634 if (*p == '\0') {
635 p = nextarg(argc--, argv++);
636 }
637 Map->Type = p;
638 Map++;
639 Mapped = YES;
640 p = "";
641 continue;
642 #endif
643
644 case 'm': /* map identifier to type */
645 /*
646 * This code is very loose. Almost no
647 * syntax checking is done!! However,
648 * illegal syntax will only produce
649 * weird results.
650 */
651 if (*p == '\0') {
652 p = nextarg(argc--, argv++);
653 }
654 if (isalnum(*p)) {
655 Map->Ident = p; /* identifier */
656 while (isalnum(*p)) p++;
657 }
658 else
659 Map->Ident = "";
660 Break = NO;
661 Not = NO;
662 while (!Break)
663 switch (*p) {
664 case '\0':
665 p = nextarg(argc--, argv++);
666 continue;
667
668 case ':': /* mapped type */
669 *p++ = '\0';
670 Break = YES;
671 continue;
672
673 case '>': /* conditional */
674 Map->Test |= GT;
675 *p++ = '\0';
676 continue;
677
678 case '<': /* conditional */
679 Map->Test |= LT;
680 *p++ = '\0';
681 continue;
682
683 case '=': /* conditional */
684 case '@':
685 Map->Test |= EQ;
686 *p++ = '\0';
687 continue;
688
689 case '!': /* invert conditions */
690 Not = ~Not;
691 *p++ = '\0';
692 continue;
693
694 case 'B': /* Baud rate */
695 p++;
696 /* intentional fallthru */
697 default:
698 if (isdigit(*p) || *p == 'e') {
699 Map->Speed =
700 baudrate(p);
701 while (isalnum(*p) ||
702 *p == '.')
703 p++;
704 } else
705 Break = YES;
706 continue;
707 }
708 if (Not) { /* invert sense of test */
709 Map->Test = (~(Map->Test))&ALL;
710 }
711 if (*p == '\0') {
712 p = nextarg(argc--, argv++);
713 }
714 Map->Type = p;
715 p = "";
716 Map++;
717 Mapped = YES;
718 continue;
719
720 case 'h': /* don't get type from htmp or env */
721 Dash_h = YES;
722 continue;
723
724 case 'u': /* don't update htmp */
725 Dash_u = YES;
726 continue;
727
728 case 's': /* output setenv commands */
729 DoSetenv = YES;
730 CmndLine = YES;
731 continue;
732
733 case 'S': /* output setenv strings */
734 DoSetenv = YES;
735 CmndLine = NO;
736 continue;
737
738 case 'Q': /* be quiet */
739 BeQuiet = YES;
740 continue;
741
742 case 'I': /* no initialization */
743 NoInit = YES;
744 continue;
745
746 case 'A': /* Ask user */
747 Ask = YES;
748 continue;
749
750 case 'v': /* no virtual terminal */
751 DoVirtTerm = NO;
752 continue;
753
754 default:
755 *p-- = '\0';
756 fatal("Bad flag -", p);
757 }
758 } else {
759 /* terminal type */
760 DefType = p;
761 }
762 }
763
764 if (DefType) {
765 if (Mapped) {
766 Map->Ident = ""; /* means "map any type" */
767 Map->Test = ALL; /* at all baud rates */
768 Map->Type = DefType; /* to the default type */
769 } else
770 TtyType = DefType;
771 }
772
773 /*
774 * Get rid of $TERMCAP, if it's there, so we get a real
775 * entry from /etc/termcap. This prevents us from being
776 * fooled by out of date stuff in the environment, and
777 * makes tabs work right on CB/Unix.
778 */
779 bufp = getenv("TERMCAP");
780 if (bufp && *bufp != '/')
781 (void) strcpy(bufp-8, "NOTHING"); /* overwrite only "TERMCAP" */
782 /* get current idea of terminal type from environment */
783 if (!Dash_h && TtyType == NULL)
784 TtyType = getenv("TERM");
785
786 /* If still undefined, use DEFTYPE */
787 if (TtyType == NULL) {
788 TtyType = DEFTYPE;
789 }
790
791 /* check for dialup or other mapping */
792 if (Mapped) {
793 if (!(Alias[0] && isalias(TtyType)))
794 if (tgetent(Capbuf, TtyType) > 0)
795 makealias(Capbuf);
796 TtyType = mapped(TtyType);
797 }
798
799 /* TtyType now contains a pointer to the type of the terminal */
800 /* If the first character is '?', ask the user */
801 if (TtyType[0] == '?') {
802 Ask = YES;
803 TtyType++;
804 if (TtyType[0] == '\0')
805 TtyType = DEFTYPE;
806 }
807 if (Ask) {
808 ask:
809 prs("TERM = (");
810 prs(TtyType);
811 prs(") ");
812 flush();
813
814 /* read the terminal. If not empty, set type */
815 i = read(2, termbuf, sizeof (termbuf) - 1);
816 if (i > 0) {
817 if (termbuf[i - 1] == '\n')
818 i--;
819 termbuf[i] = '\0';
820 if (termbuf[0] != '\0')
821 TtyType = termbuf;
822 }
823 }
824
825 /* get terminal capabilities */
826 if (!(Alias[0] && isalias(TtyType))) {
827 switch (tgetent(Capbuf, TtyType)) {
828 case -1:
829 prs("Cannot find termcap\n");
830 flush();
831 exit(-1);
832
833 case 0:
834 prs("Type ");
835 prs(TtyType);
836 prs(" unknown\n");
837 flush();
838 if (DoSetenv) {
839 TtyType = DEFTYPE;
840 Alias[0] = '\0';
841 goto ask;
842 } else
843 exit(1);
844 }
845 }
846 Ttycap = Capbuf;
847
848 if (!RepOnly) {
849 /* determine erase and kill characters */
850 if (Specialerase && !tgetflag("bs"))
851 Erase_char = 0;
852 bufp = buf;
853 p = tgetstr("kb", &bufp);
854 if (p == NULL || p[1] != '\0')
855 p = tgetstr("bc", &bufp);
856 if (p != NULL && p[1] == '\0')
857 bs_char = p[0];
858 else if (tgetflag("bs"))
859 bs_char = BACKSPACE;
860 else
861 bs_char = 0;
862 /*
863 * The next statement can't be fixed, because now users
864 * depend on keeping their erase character as DEL if the
865 * system set it there. People who want backspace have
866 * to say tset -e.
867 */
868 if (Erase_char == 0 && !tgetflag("os") &&
869 curerase == OLDERASE) {
870 if (tgetflag("bs") || bs_char != 0)
871 Erase_char = -1;
872 }
873 if (Erase_char < 0)
874 Erase_char = (bs_char != 0) ? bs_char : BACKSPACE;
875
876 if (curerase == 0)
877 curerase = CERASE;
878 if (Erase_char != 0)
879 curerase = Erase_char;
880
881 if (curintr == 0)
882 curintr = CINTR;
883 if (Intr_char != 0)
884 curintr = Intr_char;
885
886 if (curkill == 0)
887 curkill = CKILL;
888 if (Kill_char != 0)
889 curkill = Kill_char;
890
891 /* set modes */
892 PadBaud = tgetnum("pb"); /* OK if fails */
893 for (i = 0; speeds[i].string; i++)
894 if (speeds[i].baudrate == PadBaud) {
895 PadBaud = speeds[i].speed;
896 break;
897 }
898 setdelay("dC", CRdelay, CRbits, &modes.c_oflag);
899 setdelay("dN", NLdelay, NLbits, &modes.c_oflag);
900 setdelay("dB", BSdelay, BSbits, &modes.c_oflag);
901 setdelay("dF", FFdelay, FFbits, &modes.c_oflag);
902 setdelay("dT", TBdelay, TBbits, &modes.c_oflag);
903 setdelay("dV", VTdelay, VTbits, &modes.c_oflag);
904
905 if (tgetflag("UC") || (command[0] & 0140) == 0100) {
906 modes.c_iflag |= IUCLC;
907 modes.c_oflag |= OLCUC;
908 modes.c_cflag |= XCASE;
909 } else if (tgetflag("LC")) {
910 modes.c_iflag &= ~IUCLC;
911 modes.c_oflag &= ~OLCUC;
912 modes.c_cflag &= ~XCASE;
913 }
914 modes.c_iflag &= ~(PARMRK|INPCK);
915 modes.c_lflag |= ICANON;
916 if (tgetflag("EP")) {
917 modes.c_iflag |= INPCK;
918 modes.c_cflag |= PARENB;
919 modes.c_cflag &= ~PARODD;
920 }
921 if (tgetflag("OP")) {
922 modes.c_iflag |= INPCK;
923 modes.c_cflag |= PARENB;
924 modes.c_cflag |= PARODD;
925 }
926
927 modes.c_oflag |= ONLCR;
928 modes.c_iflag |= ICRNL;
929 modes.c_lflag |= ECHO;
930 modes.c_oflag |= TAB3;
931 if (tgetflag("NL")) { /* new line, not line feed */
932 modes.c_oflag &= ~ONLCR;
933 modes.c_iflag &= ~ICRNL;
934 }
935 if (tgetflag("HD")) /* half duplex */
936 modes.c_lflag &= ~ECHO;
937 if (tgetflag("pt")) /* print tabs */
938 modes.c_oflag &= ~TAB3;
939
940 modes.c_lflag |= (ECHOE|ECHOK);
941 if (tgetflag("hc")) { /* set printer modes */
942 modes.c_lflag &= ~ECHOE;
943 }
944
945 /* get pad character */
946 bufp = buf;
947 if (tgetstr("pc", &bufp) != 0)
948 PC = buf[0];
949
950 /* output startup string */
951 if (!NoInit) {
952 if (oldmodes.c_oflag&(TAB3|ONLCR|OCRNL|ONLRET)) {
953 oldmodes.c_oflag &= (TAB3|ONLCR|OCRNL|ONLRET);
954 setmode(-1);
955 }
956 if (settabs()) {
957 settle = YES;
958 flush();
959 }
960 bufp = buf;
961 if (IsReset && tgetstr("rs", &bufp) != 0 ||
962 tgetstr("is", &bufp) != 0) {
963 tputs(buf, 0, prc);
964 settle = YES;
965 flush();
966 }
967 bufp = buf;
968 if (IsReset && tgetstr("rf", &bufp) != 0 ||
969 tgetstr("if", &bufp) != 0) {
970 cat(buf);
971 settle = YES;
972 }
973 if (settle) {
974 prc('\r');
975 if (IsReset)
976 prc('\n'); /* newline too */
977 flush();
978 sleep(1); /* let terminal settle down */
979 }
980 }
981
982 setmode(0); /* set new modes, if they've changed */
983
984 /* set up environment for the shell we are using */
985 /* (this code is rather heuristic, checking for $SHELL */
986 /* ending in the 3 characters "csh") */
987 csh = NO;
988 if (DoSetenv) {
989 char *sh;
990
991 if ((sh = getenv("SHELL")) && (i = strlen(sh)) >= 3) {
992 if ((csh = sequal(&sh[i-3], "csh")) && CmndLine)
993 (void) write(STDOUT,
994 "set noglob;\n", 12);
995 }
996 if (!csh) { /* running Bourne shell */
997 (void) write(STDOUT,
998 "export TERMCAP TERM;\n", 21);
999 }
1000 }
1001 }
1002
1003 /* report type if appropriate */
1004 if (DoSetenv || Report || Ureport) {
1005 /* if type is the short name, find first alias (if any) */
1006 makealias(Ttycap);
1007 if (sequal(TtyType, Alias[0]) && Alias[1]) {
1008 TtyType = Alias[1];
1009 }
1010
1011 if (DoSetenv) {
1012 if (csh) {
1013 if (CmndLine)
1014 (void) write(STDOUT,
1015 "setenv TERM ", 12);
1016 (void) write(STDOUT, TtyType, strlen(TtyType));
1017 (void) write(STDOUT, " ", 1);
1018 if (CmndLine)
1019 (void) write(STDOUT, ";\n", 2);
1020 } else {
1021 (void) write(STDOUT, "TERM=", 5);
1022 (void) write(STDOUT, TtyType, strlen(TtyType));
1023 (void) write(STDOUT, ";\n", 2);
1024 }
1025 } else if (Report) {
1026 (void) write(STDOUT, TtyType, strlen(TtyType));
1027 (void) write(STDOUT, "\n", 1);
1028 }
1029 if (Ureport) {
1030 prs("Terminal type is ");
1031 prs(TtyType);
1032 prs("\n");
1033 flush();
1034 }
1035
1036 if (DoSetenv) {
1037 if (csh) {
1038 if (CmndLine)
1039 (void) write(STDOUT,
1040 "setenv TERMCAP '", 16);
1041 } else
1042 (void) write(STDOUT, "TERMCAP='", 9);
1043 wrtermcap(Ttycap);
1044 if (csh) {
1045 if (CmndLine) {
1046 (void) write(STDOUT, "';\n", 3);
1047 (void) write(STDOUT,
1048 "unset noglob;\n", 14);
1049 }
1050 } else
1051 (void) write(STDOUT, "';\n", 3);
1052 }
1053 }
1054
1055 if (RepOnly)
1056 exit(0);
1057
1058 /* tell about changing erase, kill and interrupt characters */
1059 reportek("Erase", curerase, olderase, CERASE);
1060 reportek("Kill", curkill, oldkill, CKILL);
1061 reportek("Interrupt", curintr, oldintr, CINTR);
1062
1063 return (0);
1064 }
1065
1066 /*
1067 * Set the hardware tabs on the terminal, using the ct (clear all tabs),
1068 * st (set one tab) and ch (horizontal cursor addressing) capabilities.
1069 * This is done before if and is, so they can patch in case we blow this.
1070 */
1071 int
settabs(void)1072 settabs(void)
1073 {
1074 char caps[100];
1075 char *capsp = caps;
1076 char *clear_tabs, *set_tab, *set_column, *set_pos;
1077 char *tg_out, *tgoto();
1078 int c;
1079 extern char *tgetstr();
1080 int lines, columns;
1081
1082 clear_tabs = tgetstr("ct", &capsp);
1083 set_tab = tgetstr("st", &capsp);
1084 set_column = tgetstr("ch", &capsp);
1085 if (set_column == 0)
1086 set_pos = tgetstr("cm", &capsp);
1087
1088 if (clear_tabs && set_tab) {
1089 prc('\r'); /* force to be at left margin */
1090 tputs(clear_tabs, 0, prc);
1091 }
1092 if (set_tab) {
1093 columns = tgetnum("co");
1094 lines = tgetnum("li");
1095 for (c = 0; c < columns; c += 8) {
1096 /* get to that column. */
1097 tg_out = "OOPS"; /* also returned by tgoto */
1098 if (set_column)
1099 tg_out = tgoto(set_column, 0, c);
1100 if (*tg_out == 'O' && set_pos)
1101 tg_out = tgoto(set_pos, c, lines-1);
1102 if (*tg_out != 'O')
1103 tputs(tg_out, 1, prc);
1104 else if (c != 0) {
1105 prc(' '); prc(' '); prc(' '); prc(' ');
1106 prc(' '); prc(' '); prc(' '); prc(' ');
1107 }
1108 /* set the tab */
1109 tputs(set_tab, 0, prc);
1110 }
1111 prc('\r');
1112 return (1);
1113 }
1114 return (0);
1115 }
1116
1117 /*
1118 * flag serves several purposes:
1119 * if called as the result of a signal, flag will be > 0.
1120 * if called from terminal init, flag == -1 means reset "oldmode".
1121 * called with flag == 0 at end of normal mode processing.
1122 */
1123 void
setmode(int flag)1124 setmode(int flag)
1125 {
1126 struct termio *ttymode;
1127 struct termios *ttymodes;
1128 int i;
1129
1130 ttymode = (struct termio *)0;
1131 ttymodes = (struct termios *)0;
1132
1133 if (flag < 0) { /* unconditionally reset oldmode (called from init) */
1134 if (istermios < 0) {
1135 oldmode.c_lflag = oldmodes.c_lflag;
1136 oldmode.c_oflag = oldmodes.c_oflag;
1137 oldmode.c_iflag = oldmodes.c_iflag;
1138 oldmode.c_cflag = oldmodes.c_cflag;
1139 for (i = 0; i < NCC; i++)
1140 oldmode.c_cc[i] = oldmodes.c_cc[i];
1141 ttymode = &oldmode;
1142 } else
1143 ttymodes = &oldmodes;
1144 } else {
1145 if (istermios < 0) {
1146 oldmode.c_lflag = oldmodes.c_lflag;
1147 oldmode.c_oflag = oldmodes.c_oflag;
1148 oldmode.c_iflag = oldmodes.c_iflag;
1149 oldmode.c_cflag = oldmodes.c_cflag;
1150 for (i = 0; i < NCC; i++)
1151 oldmode.c_cc[i] = oldmodes.c_cc[i];
1152 mode.c_lflag = modes.c_lflag;
1153 mode.c_oflag = modes.c_oflag;
1154 mode.c_iflag = modes.c_iflag;
1155 mode.c_cflag = modes.c_cflag;
1156 for (i = 0; i < NCC; i++)
1157 mode.c_cc[i] = modes.c_cc[i];
1158 if (!bequal((char *)&mode, (char *)&oldmode,
1159 sizeof (mode)))
1160 ttymode = &mode;
1161 } else if (!bequal((char *)&modes, (char *)&oldmodes,
1162 sizeof (modes)))
1163 ttymodes = &modes;
1164 }
1165
1166 if (ttymode) {
1167 (void) ioctl(FILEDES, TCSETAW, (char *)ttymode);
1168 } else if (ttymodes) {
1169 (void) ioctl(FILEDES, TCSETSW, (char *)ttymodes);
1170 }
1171 if (flag > 0) /* trapped signal */
1172 exit(1);
1173 }
1174
1175 void
reportek(char * name,char new,char old,char def)1176 reportek(char *name, char new, char old, char def)
1177 {
1178 char o;
1179 char n;
1180 char *p;
1181 char buf[32];
1182 char *bufp;
1183 extern char *tgetstr();
1184
1185 if (BeQuiet)
1186 return;
1187 o = old;
1188 n = new;
1189
1190 if (o == n && n == def)
1191 return;
1192 prs(name);
1193 if (o == n)
1194 prs(" is ");
1195 else
1196 prs(" set to ");
1197 bufp = buf;
1198 if (tgetstr("kb", &bufp) > (char *)0 && n == buf[0] && buf[1] == '\0')
1199 prs("Backspace\n");
1200 else if (n == 0177)
1201 prs("Delete\n");
1202 else {
1203 if (n < 040) {
1204 prs("Ctrl-");
1205 n ^= 0100;
1206 }
1207 p = "x\n";
1208 p[0] = n;
1209 prs(p);
1210 }
1211 flush();
1212 }
1213
1214
1215
1216 void
setdelay(char * cap,struct delay dtab[],tcflag_t bits,tcflag_t * flags)1217 setdelay(char *cap, struct delay dtab[], tcflag_t bits, tcflag_t *flags)
1218 {
1219 int i;
1220 struct delay *p;
1221 extern short ospeed;
1222
1223 /* see if this capability exists at all */
1224 i = tgetnum(cap);
1225 if (i < 0)
1226 i = 0;
1227 /* No padding at speeds below PadBaud */
1228 if (PadBaud > ospeed)
1229 i = 0;
1230
1231 /* clear out the bits, replace with new ones */
1232 *flags &= ~bits;
1233
1234 /* scan dtab for first entry with adequate delay */
1235 for (p = dtab; p->d_delay >= 0; p++) {
1236 if (p->d_delay >= i) {
1237 p++;
1238 break;
1239 }
1240 }
1241
1242 /* use last entry if none will do */
1243 *flags |= (tcflag_t)((--p)->d_bits);
1244 }
1245
1246 void
prs(char * s)1247 prs(char *s)
1248 {
1249 while (*s != '\0')
1250 prc(*s++);
1251 }
1252
1253
1254 char OutBuf[256];
1255 int OutPtr;
1256
1257 void
prc(char c)1258 prc(char c)
1259 {
1260 OutBuf[OutPtr++] = c;
1261 if (OutPtr >= sizeof (OutBuf))
1262 flush();
1263 }
1264
1265 void
flush(void)1266 flush(void)
1267 {
1268 if (OutPtr > 0)
1269 (void) write(2, OutBuf, OutPtr);
1270 OutPtr = 0;
1271 }
1272
1273 void
cat(char * file)1274 cat(char *file)
1275 {
1276 int fd;
1277 int i;
1278 char buf[BUFSIZ];
1279
1280 fd = open(file, 0);
1281 if (fd < 0) {
1282 prs("Cannot open ");
1283 prs(file);
1284 prs("\n");
1285 flush();
1286 return;
1287 }
1288
1289 while ((i = read(fd, buf, BUFSIZ)) > 0)
1290 (void) write(FILEDES, buf, i);
1291
1292 (void) close(fd);
1293 }
1294
1295
1296 void
bmove(char * from,char * to,int length)1297 bmove(char *from, char *to, int length)
1298 {
1299 char *p, *q;
1300 int i;
1301
1302 i = length;
1303 p = from;
1304 q = to;
1305
1306 while (i-- > 0)
1307 *q++ = *p++;
1308 }
1309
1310
1311 int
bequal(char * a,char * b,int len)1312 bequal(char *a, char *b, int len) /* must be same thru len chars */
1313 {
1314 char *p, *q;
1315 int i;
1316
1317 i = len;
1318 p = a;
1319 q = b;
1320
1321 while ((*p == *q) && --i > 0) {
1322 p++; q++;
1323 }
1324 return ((*p == *q) && i >= 0);
1325 }
1326
1327 int
sequal(char * a,char * b)1328 sequal(char *a, char *b) /* must be same thru NULL */
1329 {
1330 char *p = a, *q = b;
1331
1332 while (*p && *q && (*p == *q)) {
1333 p++; q++;
1334 }
1335 return (*p == *q);
1336 }
1337
1338 void
makealias(char * buf)1339 makealias(char *buf)
1340 {
1341 int i;
1342 char *a;
1343 char *b;
1344
1345 Alias[0] = a = Aliasbuf;
1346 b = buf;
1347 i = 1;
1348 while (*b && *b != ':') {
1349 if (*b == '|') {
1350 *a++ = '\0';
1351 Alias[i++] = a;
1352 b++;
1353 } else
1354 *a++ = *b++;
1355 }
1356 *a = '\0';
1357 Alias[i] = NULL;
1358 #ifdef DEB
1359 for (i = 0; Alias[i]; printf("A:%s\n", Alias[i++]))
1360 ;
1361 #endif
1362 }
1363
1364 int
isalias(char * ident)1365 isalias(char *ident) /* is ident same as one of the aliases? */
1366 {
1367 char **a = Alias;
1368
1369 if (*a)
1370 while (*a)
1371 if (sequal(ident, *a))
1372 return (YES);
1373 else
1374 a++;
1375 return (NO);
1376 }
1377
1378
1379 /*
1380 * routine to output the string for the environment TERMCAP variable
1381 */
1382 #define WHITE(c) (c == ' ' || c == '\t')
1383 char delcap[128][2];
1384 int ncap = 0;
1385
1386 void
wrtermcap(char * bp)1387 wrtermcap(char *bp)
1388 {
1389 char buf[CAPBUFSIZ];
1390 char *p = buf;
1391 char *tp;
1392 char *putbuf();
1393 int space, empty;
1394
1395 /* discard names with blanks */
1396 /* May not be desireable ? */
1397 while (*bp && *bp != ':') {
1398 if (*bp == '|') {
1399 tp = bp+1;
1400 space = NO;
1401 while (*tp && *tp != '|' && *tp != ':') {
1402 space = (space || WHITE(*tp));
1403 tp++;
1404 }
1405 if (space) {
1406 bp = tp;
1407 continue;
1408 }
1409 }
1410 *p++ = *bp++;
1411 }
1412
1413 while (*bp) {
1414 switch (*bp) {
1415 case ':': /* discard empty, cancelled or dupl fields */
1416 tp = bp + 1;
1417 empty = YES;
1418 while (*tp && *tp != ':') {
1419 empty = (empty && WHITE(*tp));
1420 tp++;
1421 }
1422 if (empty || cancelled(bp+1)) {
1423 bp = tp;
1424 continue;
1425 }
1426 break;
1427
1428 case ' ': /* no spaces in output */
1429 p = putbuf(p, "\\040");
1430 bp++;
1431 continue;
1432
1433 case '!': /* the shell thinks this is history */
1434 p = putbuf(p, "\\041");
1435 bp++;
1436 continue;
1437
1438 case ',': /* the shell thinks this is history */
1439 p = putbuf(p, "\\054");
1440 bp++;
1441 continue;
1442
1443 case '"': /* no quotes in output */
1444 p = putbuf(p, "\\042");
1445 bp++;
1446 continue;
1447
1448 case '\'': /* no quotes in output */
1449 p = putbuf(p, "\\047");
1450 bp++;
1451 continue;
1452
1453 case '`': /* no back quotes in output */
1454 p = putbuf(p, "\\140");
1455 bp++;
1456 continue;
1457
1458 case '\\':
1459 case '^': /* anything following is OK */
1460 *p++ = *bp++;
1461 }
1462 *p++ = *bp++;
1463 }
1464 *p++ = ':'; /* we skipped the last : with the : lookahead hack */
1465 (void) write(STDOUT, buf, p-buf);
1466 }
1467
1468 int
cancelled(char * cap)1469 cancelled(char *cap)
1470 {
1471 int i;
1472
1473 for (i = 0; i < ncap; i++) {
1474 if (cap[0] == delcap[i][0] && cap[1] == delcap[i][1])
1475 return (YES);
1476 }
1477 /* delete a second occurrance of the same capability */
1478 delcap[ncap][0] = cap[0];
1479 delcap[ncap][1] = cap[1];
1480 ncap++;
1481 return (cap[2] == '@');
1482 }
1483
1484 char *
putbuf(ptr,str)1485 putbuf(ptr, str)
1486 char *ptr;
1487 char *str;
1488 {
1489 char buf[20];
1490
1491 while (*str) {
1492 switch (*str) {
1493 case '\033':
1494 ptr = putbuf(ptr, "\\E");
1495 str++;
1496 break;
1497 default:
1498 if (*str <= ' ') {
1499 (void) sprintf(buf, "\\%03o", *str);
1500 ptr = putbuf(ptr, buf);
1501 str++;
1502 } else
1503 *ptr++ = *str++;
1504 }
1505 }
1506 return (ptr);
1507 }
1508
1509 int
baudrate(char * p)1510 baudrate(char *p)
1511 {
1512 char buf[8];
1513 int i = 0;
1514
1515 while (i < 7 && (isalnum(*p) || *p == '.'))
1516 buf[i++] = *p++;
1517 buf[i] = '\0';
1518 for (i = 0; speeds[i].string; i++)
1519 if (sequal(speeds[i].string, buf))
1520 return (speeds[i].speed);
1521 return (-1);
1522 }
1523
1524 char *
mapped(type)1525 mapped(type)
1526 char *type;
1527 {
1528 extern short ospeed;
1529 int match;
1530
1531 #ifdef DEB
1532 printf("spd:%d\n", ospeed);
1533 prmap();
1534 #endif
1535 Map = map;
1536 while (Map->Ident) {
1537 if (*(Map->Ident) == '\0' ||
1538 sequal(Map->Ident, type) || isalias(Map->Ident)) {
1539 match = NO;
1540 switch (Map->Test) {
1541 case ANY: /* no test specified */
1542 case ALL:
1543 match = YES;
1544 break;
1545
1546 case GT:
1547 match = (ospeed > Map->Speed);
1548 break;
1549
1550 case GE:
1551 match = (ospeed >= Map->Speed);
1552 break;
1553
1554 case EQ:
1555 match = (ospeed == Map->Speed);
1556 break;
1557
1558 case LE:
1559 match = (ospeed <= Map->Speed);
1560 break;
1561
1562 case LT:
1563 match = (ospeed < Map->Speed);
1564 break;
1565
1566 case NE:
1567 match = (ospeed != Map->Speed);
1568 break;
1569 }
1570 if (match)
1571 return (Map->Type);
1572 }
1573 Map++;
1574 }
1575 /* no match found; return given type */
1576 return (type);
1577 }
1578
1579 #ifdef DEB
prmap()1580 prmap()
1581 {
1582 Map = map;
1583 while (Map->Ident) {
1584 printf("%s t:%d s:%d %s\n",
1585 Map->Ident, Map->Test, Map->Speed, Map->Type);
1586 Map++;
1587 }
1588 }
1589 #endif
1590
1591 char *
nextarg(argc,argv)1592 nextarg(argc, argv)
1593 int argc;
1594 char *argv[];
1595 {
1596 if (argc <= 0)
1597 fatal("Too few args: ", *argv);
1598 if (*(*++argv) == '-')
1599 fatal("Unexpected arg: ", *argv);
1600 return (*argv);
1601 }
1602
1603 void
fatal(char * mesg,char * obj)1604 fatal(char *mesg, char *obj)
1605 {
1606 prs(mesg);
1607 prs(obj);
1608 prc('\n');
1609 prs(USAGE);
1610 flush();
1611 exit(1);
1612 }
1613
1614
1615 /*
1616 * Stolen from /usr/src/ucb/reset.c, which this mod obsoletes.
1617 */
1618 char
reset(ch,def)1619 reset(ch, def)
1620 char ch;
1621 int def;
1622 {
1623 if (ch == 0 || (ch&0377) == 0377)
1624 return (def);
1625 return (ch);
1626 }
1627