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