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