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