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 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 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 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 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 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 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 1258 prc(char c) 1259 { 1260 OutBuf[OutPtr++] = c; 1261 if (OutPtr >= sizeof (OutBuf)) 1262 flush(); 1263 } 1264 1265 void 1266 flush(void) 1267 { 1268 if (OutPtr > 0) 1269 (void) write(2, OutBuf, OutPtr); 1270 OutPtr = 0; 1271 } 1272 1273 void 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 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 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 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 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 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 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 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 * 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 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 * 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 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 * 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 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 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