1 /* 2 * Copyright (c) 1980 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 */ 6 7 #ifndef lint 8 char copyright[] = 9 "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 10 All rights reserved.\n"; 11 #endif not lint 12 13 #ifndef lint 14 static char sccsid[] = "@(#)tset.c 5.8 (Berkeley) 04/28/86"; 15 #endif not lint 16 17 /* 18 ** TSET -- set terminal modes 19 ** 20 ** This program does sophisticated terminal initialization. 21 ** I recommend that you include it in your .profile or .login 22 ** file to initialize whatever terminal you are on. 23 ** 24 ** There are several features: 25 ** 26 ** A special file or sequence (as controlled by the termcap file) 27 ** is sent to the terminal. 28 ** 29 ** Mode bits are set on a per-terminal_type basis (much better 30 ** than UNIX itself). This allows special delays, automatic 31 ** tabs, etc. 32 ** 33 ** Erase and Kill characters can be set to whatever you want. 34 ** Default is to change erase to control-H on a terminal which 35 ** can overstrike, and leave it alone on anything else. Kill 36 ** is always left alone unless specifically requested. These 37 ** characters can be represented as "^X" meaning control-X; 38 ** X is any character. 39 ** 40 ** Terminals which are dialups or plugboard types can be aliased 41 ** to whatever type you may have in your home or office. Thus, 42 ** if you know that when you dial up you will always be on a 43 ** TI 733, you can specify that fact to tset. You can represent 44 ** a type as "?type". This will ask you what type you want it 45 ** to be -- if you reply with just a newline, it will default 46 ** to the type given. 47 ** 48 ** The current terminal type can be queried. 49 ** 50 ** Usage: 51 ** tset [-] [-EC] [-eC] [-kC] [-iC] [-s] [-h] [-u] [-r] 52 ** [-m [ident] [test baudrate] :type] 53 ** [-Q] [-I] [-S] [type] 54 ** 55 ** In systems with environments, use: 56 ** eval `tset -s ...` 57 ** Actually, this doesn't work in old csh's. 58 ** Instead, use: 59 ** tset -s ... > tset.tmp 60 ** source tset.tmp 61 ** rm tset.tmp 62 ** or: 63 ** set noglob 64 ** set term=(`tset -S ....`) 65 ** setenv TERM $term[1] 66 ** setenv TERMCAP "$term[2]" 67 ** unset term 68 ** unset noglob 69 ** 70 ** Positional Parameters: 71 ** type -- the terminal type to force. If this is 72 ** specified, initialization is for this 73 ** terminal type. 74 ** 75 ** Flags: 76 ** - -- report terminal type. Whatever type is 77 ** decided on is reported. If no other flags 78 ** are stated, the only affect is to write 79 ** the terminal type on the standard output. 80 ** -r -- report to user in addition to other flags. 81 ** -EC -- set the erase character to C on all terminals 82 ** except those which cannot backspace (e.g., 83 ** a TTY 33). C defaults to control-H. 84 ** -eC -- set the erase character to C on all terminals. 85 ** C defaults to control-H. If not specified, 86 ** the erase character is untouched; however, if 87 ** not specified and the erase character is NULL 88 ** (zero byte), the erase character is set to delete. 89 ** -kC -- set the kill character to C on all terminals. 90 ** Default for C is control-X. If not specified, 91 ** the kill character is untouched; however, if 92 ** not specified and the kill character is NULL 93 ** (zero byte), the kill character is set to control-U. 94 ** -iC -- set the interrupt character to C on all terminals. 95 ** Default for C is control-C. If not specified, the 96 ** interrupt character is untouched; however, if 97 ** not specified and the interrupt character is NULL 98 ** (zero byte), the interrupt character is set to 99 ** control-C. 100 ** -qC -- reserved for setable quit character. 101 ** -m -- map the system identified type to some user 102 ** specified type. The mapping can be baud rate 103 ** dependent. This replaces the old -d, -p flags. 104 ** (-d type -> -m dialup:type) 105 ** (-p type -> -m plug:type) 106 ** Syntax: -m identifier [test baudrate] :type 107 ** where: ``identifier'' is terminal type found in 108 ** /etc/ttys for this port, (abscence of an identifier 109 ** matches any identifier); ``test'' may be any combination 110 ** of > = < ! @; ``baudrate'' is as with stty(1); 111 ** ``type'' is the actual terminal type to use if the 112 ** mapping condition is met. Multiple maps are scanned 113 ** in order and the first match prevails. 114 ** -n -- If the new tty driver from UCB is available, this flag 115 ** will activate the new options for erase and kill 116 ** processing. This will be different for printers 117 ** and crt's. For crts, if the baud rate is < 1200 then 118 ** erase and kill don't remove characters from the screen. 119 ** -h -- don't read htmp file. Normally the terminal type 120 ** is determined by reading the htmp file or the 121 ** environment (unless some mapping is specified). 122 ** This forces a read of the ttytype file -- useful 123 ** when htmp is somehow wrong. (V6 only) 124 ** -u -- don't update htmp. It seemed like this should 125 ** be put in. Note that htmp is never actually 126 ** written if there are no changes, so don't bother 127 ** bother using this for efficiency reasons alone. 128 ** -s -- output setenv commands for TERM. This can be 129 ** used with 130 ** `tset -s ...` 131 ** and is to be prefered to: 132 ** setenv TERM `tset - ...` 133 ** because -s sets the TERMCAP variable also. 134 ** -S -- Similar to -s but outputs 2 strings suitable for 135 ** use in csh .login files as follows: 136 ** set noglob 137 ** set term=(`tset -S .....`) 138 ** setenv TERM $term[1] 139 ** setenv TERMCAP "$term[2]" 140 ** unset term 141 ** unset noglob 142 ** -Q -- be quiet. don't output 'Erase set to' etc. 143 ** -I -- don't do terminal initialization (is & if 144 ** strings). 145 ** -v -- On virtual terminal systems, don't set up a 146 ** virtual terminal. Otherwise tset will tell 147 ** the operating system what kind of terminal you 148 ** are on (if it is a known terminal) and fix up 149 ** the output of -s to use virtual terminal sequences. 150 ** 151 ** Files: 152 ** /etc/ttys 153 ** contains a terminal id -> terminal type 154 ** mapping; used when any user mapping is specified, 155 ** or the environment doesn't have TERM set. 156 ** /etc/termcap 157 ** a terminal_type -> terminal_capabilities 158 ** mapping. 159 ** 160 ** Return Codes: 161 ** -1 -- couldn't open ttycap. 162 ** 1 -- bad terminal type, or standard output not tty. 163 ** 0 -- ok. 164 ** 165 ** Defined Constants: 166 ** DIALUP -- the type code for a dialup port. 167 ** PLUGBOARD -- the type code for a plugboard port. 168 ** ARPANET -- the type code for an arpanet port. 169 ** BACKSPACE -- control-H, the default for -e. 170 ** CNTL('X') -- control-X, the default for -k. 171 ** OLDERASE -- the system default erase character. 172 ** OLDKILL -- the system default kill 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 ttycap. 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 ** UCB_NTTY -- set to handle new tty driver modes. 194 ** 195 ** Trace Flags: 196 ** none 197 ** 198 ** Diagnostics: 199 ** Bad flag 200 ** An incorrect option was specified. 201 ** Too few args 202 ** more command line arguments are required. 203 ** Unexpected arg 204 ** wrong type of argument was encountered. 205 ** Cannot open ... 206 ** The specified file could not be openned. 207 ** Type ... unknown 208 ** An unknown terminal type was specified. 209 ** Cannot update htmp 210 ** Cannot update htmp file when the standard 211 ** output is not a terminal. 212 ** Erase set to ... 213 ** Telling that the erase character has been 214 ** set to the specified character. 215 ** Kill set to ... 216 ** Ditto for kill 217 ** Erase is ... Kill is ... 218 ** Tells that the erase/kill characters were 219 ** wierd before, but they are being left as-is. 220 ** Not a terminal 221 ** Set if FILEDES is not a terminal. 222 ** 223 ** Compilation Instructions: 224 ** cc -n -O tset.c -ltermlib 225 ** mv a.out tset 226 ** chown bin tset 227 ** chmod 4755 tset 228 ** 229 ** where 'bin' should be whoever owns the 'htmp' file. 230 ** If 'htmp' is 666, then tset need not be setuid. 231 ** 232 ** For version 6 the compile command should be: 233 ** cc -n -O -I/usr/include/retrofit tset.c -ltermlib -lretro -lS 234 ** 235 ** Author: 236 ** Eric Allman 237 ** Electronics Research Labs 238 ** U.C. Berkeley 239 ** 240 ** History: 241 ** 1/81 -- Added alias checking for mapping identifiers. 242 ** 9/80 -- Added UCB_NTTY mods to setup the new tty driver. 243 ** Added the 'reset ...' invocation. 244 ** 7/80 -- '-S' added. '-m' mapping added. TERMCAP string 245 ** cleaned up. 246 ** 3/80 -- Changed to use tputs. Prc & flush added. 247 ** 10/79 -- '-s' option extended to handle TERMCAP 248 ** variable, set noglob, quote the entry, 249 ** and know about the Bourne shell. Terminal 250 ** initialization moved to before any information 251 ** output so screen clears would not screw you. 252 ** '-Q' option added. 253 ** 8/79 -- '-' option alone changed to only output 254 ** type. '-s' option added. 'VERSION7' 255 ** changed to 'V6' for compatibility. 256 ** 12/78 -- modified for eventual migration to VAX/UNIX, 257 ** so the '-' option is changed to output only 258 ** the terminal type to STDOUT instead of 259 ** FILEDES. 260 ** 9/78 -- '-' and '-p' options added (now fully 261 ** compatible with ttytype!), and spaces are 262 ** permitted between the -d and the type. 263 ** 8/78 -- The sense of -h and -u were reversed, and the 264 ** -f flag is dropped -- same effect is available 265 ** by just stating the terminal type. 266 ** 10/77 -- Written. 267 */ 268 269 #define UCB_NTTY 270 271 # ifdef USG 272 # define index strchr 273 # define rindex strrchr 274 # define curerase mode.c_cc[VERASE] 275 # define curkill mode.c_cc[VKILL] 276 # define curintr mode.c_cc[VINTR] 277 # define olderase oldmode.c_cc[VERASE] 278 # define oldkill oldmode.c_cc[VKILL] 279 # define oldintr oldmode.c_cc[VINTR] 280 # else 281 # define curerase mode.sg_erase 282 # define curkill mode.sg_kill 283 # define curintr tchar.t_intrc 284 # define olderase oldmode.sg_erase 285 # define oldkill oldmode.sg_kill 286 # define oldintr oldtchar.t_intrc 287 # endif 288 289 # ifndef V6 290 # define GTTYN 291 # include <ttyent.h> 292 # endif 293 294 # ifndef USG 295 # include <sgtty.h> 296 # else 297 # include <termio.h> 298 # endif 299 300 # include <stdio.h> 301 # include <signal.h> 302 # ifdef V6 303 # include <retrofit.h> 304 # endif 305 306 # define YES 1 307 # define NO 0 308 #undef CNTL 309 # define CNTL(c) ((c)&037) 310 # define BACKSPACE (CNTL('H')) 311 # define CHK(val, dft) (val<=0 ? dft : val) 312 # define isdigit(c) (c >= '0' && c <= '9') 313 # define isalnum(c) (c > ' ' && (index("<@=>!:|\177", c) == NULL)) 314 # define OLDERASE '#' 315 # define OLDKILL '@' 316 # define OLDINTR '\177' /* del */ 317 318 /* default special characters */ 319 #ifndef CERASE 320 #define CERASE '\177' 321 #endif 322 #ifndef CKILL 323 #define CKILL CNTL('U') 324 #endif 325 #ifndef CINTR 326 #define CINTR CNTL('C') 327 #endif 328 #ifndef CDSUSP 329 #define CQUIT 034 /* FS, ^\ */ 330 #define CSTART CNTL('Q') 331 #define CSTOP CNTL('S') 332 #define CEOF CNTL('D') 333 #define CEOT CEOF 334 #define CBRK 0377 335 #define CSUSP CNTL('Z') 336 #define CDSUSP CNTL('Y') 337 #define CRPRNT CNTL('R') 338 #define CFLUSH CNTL('O') 339 #define CWERASE CNTL('W') 340 #define CLNEXT CNTL('V') 341 #endif 342 343 # define FILEDES 2 /* do gtty/stty on this descriptor */ 344 # define STDOUT 1 /* output of -s/-S to this descriptor */ 345 346 # ifdef V6 347 # define UIDMASK 0377 348 # else 349 # define UIDMASK -1 350 # endif 351 352 # ifdef UCB_NTTY 353 # define USAGE "usage: tset [-] [-nrsIQS] [-eC] [-kC] [-iC] [-m [ident][test speed]:type] [type]\n" 354 # else 355 # define USAGE "usage: tset [-] [-rsIQS] [-eC] [-kC] [-iC] [-m [ident][test speed]:type] [type]\n" 356 # endif 357 358 # define OLDFLAGS 359 # define DIALUP "dialup" 360 # define OLDDIALUP "sd" 361 # define PLUGBOARD "plugboard" 362 # define OLDPLUGBOARD "sp" 363 /*** 364 # define ARPANET "arpanet" 365 # define OLDARPANET "sa" 366 /***/ 367 368 # define DEFTYPE "unknown" 369 370 371 # ifdef GTTYN 372 # define NOTTY 0 373 # else 374 # define NOTTY 'x' 375 # endif 376 377 /* 378 * Baud Rate Conditionals 379 */ 380 # define ANY 0 381 # define GT 1 382 # define EQ 2 383 # define LT 4 384 # define GE (GT|EQ) 385 # define LE (LT|EQ) 386 # define NE (GT|LT) 387 # define ALL (GT|EQ|LT) 388 389 390 391 # define NMAP 10 392 393 struct map { 394 char *Ident; 395 char Test; 396 char Speed; 397 char *Type; 398 } map[NMAP]; 399 400 struct map *Map = map; 401 402 /* This should be available in an include file */ 403 struct 404 { 405 char *string; 406 int speed; 407 int baudrate; 408 } speeds[] = { 409 "0", B0, 0, 410 "50", B50, 50, 411 "75", B75, 75, 412 "110", B110, 110, 413 "134", B134, 134, 414 "134.5",B134, 134, 415 "150", B150, 150, 416 "200", B200, 200, 417 "300", B300, 300, 418 "600", B600, 600, 419 "1200", B1200, 1200, 420 "1800", B1800, 1800, 421 "2400", B2400, 2400, 422 "4800", B4800, 4800, 423 "9600", B9600, 9600, 424 "19200",EXTA, 19200, 425 "exta", EXTA, 19200, 426 "extb", EXTB, 38400, 427 0, 428 }; 429 430 #ifdef CBVIRTTERM 431 struct vterm { 432 char cap[2]; 433 char *value; 434 } vtab [] = { 435 "al", "\033\120", 436 "cd", "\033\114", 437 "ce", "\033\113", 438 "cm", "\033\107%r%.%.", 439 "cl", "\033\112", 440 "dc", "\033\115", 441 "dl", "\033\116", 442 "ic", "\033\117", 443 "kl", "\033\104", 444 "kr", "\033\103", 445 "ku", "\033\101", 446 "kd", "\033\102", 447 "kh", "\033\105", 448 "nd", "\033\103", 449 "se", "\033\142\004", 450 "so", "\033\141\004", 451 "ue", "\033\142\001", 452 "up", "\033\101", 453 "us", "\033\141\001", 454 "\0\0", NULL, 455 }; 456 457 int VirTermNo = -2; 458 int HasAM; /* True if terminal has automatic margins */ 459 # endif CBVIRTTERM 460 461 char Erase_char; /* new erase character */ 462 char Kill_char; /* new kill character */ 463 char Intr_char; /* new interrupt character */ 464 char Specialerase; /* set => Erase_char only on terminals with backspace */ 465 466 # ifdef GTTYN 467 char *Ttyid = NOTTY; /* terminal identifier */ 468 # else 469 char Ttyid = NOTTY; /* terminal identifier */ 470 # endif 471 char *TtyType; /* type of terminal */ 472 char *DefType; /* default type if none other computed */ 473 char *NewType; /* mapping identifier based on old flags */ 474 int Mapped; /* mapping has been specified */ 475 int Dash_u; /* don't update htmp */ 476 int Dash_h; /* don't read htmp */ 477 int DoSetenv; /* output setenv commands */ 478 int BeQuiet; /* be quiet */ 479 int NoInit; /* don't output initialization string */ 480 int IsReset; /* invoked as reset */ 481 int Report; /* report current type */ 482 int Ureport; /* report to user */ 483 int RepOnly; /* report only */ 484 int CmndLine; /* output full command lines (-s option) */ 485 int Ask; /* ask user for termtype */ 486 int DoVirtTerm = YES; /* Set up a virtual terminal */ 487 int PadBaud; /* Min rate of padding needed */ 488 int lines, columns; 489 490 # define CAPBUFSIZ 1024 491 char Capbuf[CAPBUFSIZ]; /* line from /etc/termcap for this TtyType */ 492 char *Ttycap; /* termcap line from termcap or environ */ 493 494 char Aliasbuf[128]; 495 char *Alias[16]; 496 497 extern char *strcpy(); 498 extern char *index(); 499 500 struct delay 501 { 502 int d_delay; 503 int d_bits; 504 }; 505 506 # include "tset.delays.h" 507 508 # ifndef USG 509 struct sgttyb mode; 510 struct sgttyb oldmode; 511 struct tchars tchar; 512 struct tchars oldtchar; 513 # else 514 struct termio mode; 515 struct termio oldmode; 516 # endif 517 # ifdef CBVIRTTERM 518 struct termcb block = {0, 2, 0, 0, 0, 20}; 519 # endif CBVIRTTERM 520 521 522 main(argc, argv) 523 int argc; 524 char *argv[]; 525 { 526 char buf[CAPBUFSIZ]; 527 char termbuf[32]; 528 auto char *bufp; 529 register char *p; 530 char *command; 531 register int i; 532 # ifdef CBVIRTTERM 533 int j; 534 # endif CBVIRTTERM 535 int Break; 536 int Not; 537 char *nextarg(); 538 char *mapped(); 539 extern char *rindex(); 540 struct winsize win; 541 # ifdef V6 542 extern char *hsgettype(); 543 # else 544 extern char *getenv(); 545 # endif 546 # ifdef GTTYN 547 char *stypeof(); 548 extern char *ttyname(); 549 extern char *tgetstr(); 550 # endif 551 char bs_char; 552 int csh; 553 int settle; 554 int setmode(); 555 extern prc(); 556 extern char PC; 557 # ifdef V6 558 extern int ospeed; 559 # else 560 extern short ospeed; 561 # endif 562 # ifdef UCB_NTTY 563 int lmode; 564 int ldisc; 565 566 (void) ioctl(FILEDES, TIOCLGET, (char *)&lmode); 567 (void) ioctl(FILEDES, TIOCGETD, (char *)&ldisc); 568 # endif 569 570 # ifndef USG 571 if (gtty(FILEDES, &mode) < 0) 572 # else 573 if (ioctl(FILEDES, TCGETA, (char *)&mode) < 0) 574 # endif 575 { 576 prs("Not a terminal\n"); 577 exit(1); 578 } 579 bmove((char *)&mode, (char *)&oldmode, sizeof mode); 580 # ifdef TIOCGETC 581 (void) ioctl(FILEDES, TIOCGETC, (char *)&tchar); 582 bmove((char *)&tchar, (char *)&oldtchar, sizeof tchar); 583 # endif 584 # ifndef USG 585 ospeed = mode.sg_ospeed & 017; 586 # else 587 ospeed = mode.c_cflag & CBAUD; 588 # endif 589 (void) signal(SIGINT, setmode); 590 (void) signal(SIGQUIT, setmode); 591 (void) signal(SIGTERM, setmode); 592 593 if (command = rindex(argv[0], '/')) 594 command++; 595 else 596 command = argv[0]; 597 if (sequal(command, "reset") ) 598 { 599 /* 600 * reset the teletype mode bits to a sensible state. 601 * Copied from the program by Kurt Shoens & Mark Horton. 602 * Very useful after crapping out in raw. 603 */ 604 # ifndef V6 605 # ifdef UCB_NTTY 606 struct ltchars ltc; 607 608 if (ldisc == NTTYDISC) 609 { 610 (void) ioctl(FILEDES, TIOCGLTC, (char *)<c); 611 ltc.t_suspc = CHK(ltc.t_suspc, CSUSP); 612 ltc.t_dsuspc = CHK(ltc.t_dsuspc, CDSUSP); 613 ltc.t_rprntc = CHK(ltc.t_rprntc, CRPRNT); 614 ltc.t_flushc = CHK(ltc.t_flushc, CFLUSH); 615 ltc.t_werasc = CHK(ltc.t_werasc, CWERASE); 616 ltc.t_lnextc = CHK(ltc.t_lnextc, CLNEXT); 617 (void) ioctl(FILEDES, TIOCSLTC, (char *)<c); 618 } 619 # endif UCB_NTTY 620 # ifndef USG 621 # ifdef TIOCGETC 622 tchar.t_intrc = CHK(tchar.t_intrc, CINTR); 623 tchar.t_quitc = CHK(tchar.t_quitc, CQUIT); 624 tchar.t_startc = CHK(tchar.t_startc, CSTART); 625 tchar.t_stopc = CHK(tchar.t_stopc, CSTOP); 626 tchar.t_eofc = CHK(tchar.t_eofc, CEOF); 627 /* brkc is left alone */ 628 (void) ioctl(FILEDES, TIOCSETC, (char *)&tchar); 629 # endif TIOCGETC 630 mode.sg_flags &= ~(RAW 631 # ifdef CBREAK 632 |CBREAK 633 # endif CBREAK 634 |VTDELAY|ALLDELAY); 635 mode.sg_flags |= XTABS|ECHO|CRMOD|ANYP; 636 curerase = CHK(curerase, CERASE); 637 curkill = CHK(curkill, CKILL); 638 curintr = CHK(curintr, CINTR); 639 # else USG 640 (void) ioctl(FILEDES, TCGETA, (char *)&mode); 641 curerase = CHK(curerase, OLDERASE); 642 curkill = CHK(curkill, OLDKILL); 643 curintr = CHK(curintr, OLDINTR); 644 mode.c_cc[VQUIT] = CHK(mode.c_cc[VQUIT], CQUIT); 645 mode.c_cc[VEOF] = CHK(mode.c_cc[VEOF], CEOF); 646 647 mode.c_iflag |= (BRKINT|ISTRIP|ICRNL|IXON); 648 mode.c_iflag &= ~(IGNBRK|PARMRK|INPCK|INLCR|IGNCR|IUCLC|IXOFF); 649 mode.c_oflag |= (OPOST|ONLCR); 650 mode.c_oflag &= ~(OLCUC|OCRNL|ONOCR|ONLRET|OFILL|OFDEL| 651 NLDLY|CRDLY|TABDLY|BSDLY|VTDLY|FFDLY); 652 mode.c_cflag |= (CS7|CREAD); 653 mode.c_cflag &= ~(CSIZE|PARODD|CLOCAL); 654 mode.c_lflag |= (ISIG|ICANON|ECHO|ECHOK); 655 mode.c_lflag &= ~(XCASE|ECHONL|NOFLSH); 656 (void) ioctl(FILEDES, TCSETAW, (char *)&mode); 657 # endif USG 658 # endif V6 659 Dash_u = YES; 660 BeQuiet = YES; 661 IsReset = YES; 662 } 663 else if (argc == 2 && sequal(argv[1], "-")) 664 { 665 RepOnly = YES; 666 Dash_u = YES; 667 } 668 argc--; 669 670 /* scan argument list and collect flags */ 671 while (--argc >= 0) 672 { 673 p = *++argv; 674 if (*p == '-') 675 { 676 if (*++p == NULL) 677 Report = YES; /* report current terminal type */ 678 else while (*p) switch (*p++) 679 { 680 681 # ifdef UCB_NTTY 682 case 'n': 683 ldisc = NTTYDISC; 684 if (ioctl(FILEDES, TIOCSETD, (char *)&ldisc)<0) 685 fatal("ioctl ", "new"); 686 continue; 687 # endif 688 689 case 'r': /* report to user */ 690 Ureport = YES; 691 continue; 692 693 case 'E': /* special erase: operate on all but TTY33 */ 694 Specialerase = YES; 695 /* explicit fall-through to -e case */ 696 697 case 'e': /* erase character */ 698 if (*p == NULL) 699 Erase_char = -1; 700 else 701 { 702 if (*p == '^' && p[1] != NULL) 703 if (*++p == '?') 704 Erase_char = '\177'; 705 else 706 Erase_char = CNTL(*p); 707 else 708 Erase_char = *p; 709 p++; 710 } 711 continue; 712 713 # if defined(USG) || defined(TIOCGETC) 714 case 'i': /* interrupt character */ 715 if (*p == NULL) 716 Intr_char = CNTL('C'); 717 else 718 { 719 if (*p == '^' && p[1] != NULL) 720 if (*++p == '?') 721 Intr_char = '\177'; 722 else 723 Intr_char = CNTL(*p); 724 else 725 Intr_char = *p; 726 p++; 727 } 728 continue; 729 # endif 730 731 case 'k': /* kill character */ 732 if (*p == NULL) 733 Kill_char = CNTL('X'); 734 else 735 { 736 if (*p == '^' && p[1] != NULL) 737 if (*++p == '?') 738 Kill_char = '\177'; 739 else 740 Kill_char = CNTL(*p); 741 else 742 Kill_char = *p; 743 p++; 744 } 745 continue; 746 747 # ifdef OLDFLAGS 748 # ifdef OLDDIALUP 749 case 'd': /* dialup type */ 750 NewType = DIALUP; 751 goto mapold; 752 # endif 753 754 # ifdef OLDPLUGBOARD 755 case 'p': /* plugboard type */ 756 NewType = PLUGBOARD; 757 goto mapold; 758 # endif 759 760 # ifdef OLDARPANET 761 case 'a': /* arpanet type */ 762 Newtype = ARPANET; 763 goto mapold; 764 # endif 765 766 mapold: Map->Ident = NewType; 767 Map->Test = ALL; 768 if (*p == NULL) 769 { 770 p = nextarg(argc--, argv++); 771 } 772 Map->Type = p; 773 Map++; 774 Mapped = YES; 775 p = ""; 776 continue; 777 # endif 778 779 case 'm': /* map identifier to type */ 780 /* This code is very loose. Almost no 781 ** syntax checking is done!! However, 782 ** illegal syntax will only produce 783 ** weird results. 784 */ 785 if (*p == NULL) 786 { 787 p = nextarg(argc--, argv++); 788 } 789 if (isalnum(*p)) 790 { 791 Map->Ident = p; /* identifier */ 792 while (isalnum(*p)) p++; 793 } 794 else 795 Map->Ident = ""; 796 Break = NO; 797 Not = NO; 798 while (!Break) switch (*p) 799 { 800 case NULL: 801 p = nextarg(argc--, argv++); 802 continue; 803 804 case ':': /* mapped type */ 805 *p++ = NULL; 806 Break = YES; 807 continue; 808 809 case '>': /* conditional */ 810 Map->Test |= GT; 811 *p++ = NULL; 812 continue; 813 814 case '<': /* conditional */ 815 Map->Test |= LT; 816 *p++ = NULL; 817 continue; 818 819 case '=': /* conditional */ 820 case '@': 821 Map->Test |= EQ; 822 *p++ = NULL; 823 continue; 824 825 case '!': /* invert conditions */ 826 Not = ~Not; 827 *p++ = NULL; 828 continue; 829 830 case 'B': /* Baud rate */ 831 p++; 832 /* intentional fallthru */ 833 default: 834 if (isdigit(*p) || *p == 'e') 835 { 836 Map->Speed = baudrate(p); 837 while (isalnum(*p) || *p == '.') 838 p++; 839 } 840 else 841 Break = YES; 842 continue; 843 } 844 if (Not) /* invert sense of test */ 845 { 846 Map->Test = (~(Map->Test))&ALL; 847 } 848 if (*p == NULL) 849 { 850 p = nextarg(argc--, argv++); 851 } 852 Map->Type = p; 853 p = ""; 854 Map++; 855 Mapped = YES; 856 continue; 857 858 case 'h': /* don't get type from htmp or env */ 859 Dash_h = YES; 860 continue; 861 862 case 'u': /* don't update htmp */ 863 Dash_u = YES; 864 continue; 865 866 case 's': /* output setenv commands */ 867 DoSetenv = YES; 868 CmndLine = YES; 869 continue; 870 871 case 'S': /* output setenv strings */ 872 DoSetenv = YES; 873 CmndLine = NO; 874 continue; 875 876 case 'Q': /* be quiet */ 877 BeQuiet = YES; 878 continue; 879 880 case 'I': /* no initialization */ 881 NoInit = YES; 882 continue; 883 884 case 'A': /* Ask user */ 885 Ask = YES; 886 continue; 887 888 case 'v': /* no virtual terminal */ 889 DoVirtTerm = NO; 890 continue; 891 892 default: 893 *p-- = NULL; 894 fatal("Bad flag -", p); 895 } 896 } 897 else 898 { 899 /* terminal type */ 900 DefType = p; 901 } 902 } 903 904 if (DefType) 905 { 906 if (Mapped) 907 { 908 Map->Ident = ""; /* means "map any type" */ 909 Map->Test = ALL; /* at all baud rates */ 910 Map->Type = DefType; /* to the default type */ 911 } 912 else 913 TtyType = DefType; 914 } 915 916 # ifndef V6 917 /* 918 * Get rid of $TERMCAP, if it's there, so we get a real 919 * entry from /etc/termcap. This prevents us from being 920 * fooled by out of date stuff in the environment, and 921 * makes tabs work right on CB/Unix. 922 */ 923 bufp = getenv("TERMCAP"); 924 if (bufp && *bufp != '/') 925 (void) strcpy(bufp-8, "NOTHING"); /* overwrite only "TERMCAP" */ 926 /* get current idea of terminal type from environment */ 927 if (!Dash_h && TtyType == 0) 928 TtyType = getenv("TERM"); 929 # endif 930 931 /* determine terminal id if needed */ 932 # ifdef V6 933 if (Ttyid == NOTTY && (TtyType == 0 || !Dash_h || !Dash_u)) 934 Ttyid = ttyn(FILEDES); 935 # else 936 if (!RepOnly && Ttyid == NOTTY && (TtyType == 0 || !Dash_h)) 937 Ttyid = ttyname(FILEDES); 938 # endif 939 940 # ifdef V6 941 /* get htmp if ever used */ 942 if (!Dash_u || (TtyType == 0 && !Dash_h)) 943 { 944 /* get htmp entry -- if error or wrong user use ttytype */ 945 if (Ttyid == NOTTY || hget(Ttyid) < 0 || 946 hgettype() == 0 || hgetuid() != (getuid() & UIDMASK)) 947 Dash_h++; 948 } 949 950 /* find terminal type (if not already known) */ 951 if (TtyType == 0 && !Dash_h) 952 { 953 /* get type from /etc/htmp */ 954 TtyType = hsgettype(); 955 } 956 # endif 957 958 # ifdef GTTYN 959 /* If still undefined, look at /etc/ttytype */ 960 if (TtyType == 0) 961 { 962 TtyType = stypeof(Ttyid); 963 } 964 # endif 965 966 /* If still undefined, use DEFTYPE */ 967 if (TtyType == 0) 968 { 969 TtyType = DEFTYPE; 970 } 971 972 /* check for dialup or other mapping */ 973 if (Mapped) 974 { 975 if (!(Alias[0] && isalias(TtyType))) 976 if (tgetent(Capbuf, TtyType) > 0) 977 makealias(Capbuf); 978 TtyType = mapped(TtyType); 979 } 980 981 /* TtyType now contains a pointer to the type of the terminal */ 982 /* If the first character is '?', ask the user */ 983 if (TtyType[0] == '?') 984 { 985 Ask = YES; 986 TtyType++; 987 if (TtyType[0] == '\0') 988 TtyType = DEFTYPE; 989 } 990 if (Ask) 991 { 992 ask: 993 prs("TERM = ("); 994 prs(TtyType); 995 prs(") "); 996 flush(); 997 998 /* read the terminal. If not empty, set type */ 999 i = read(2, termbuf, sizeof termbuf - 1); 1000 if (i > 0) 1001 { 1002 if (termbuf[i - 1] == '\n') 1003 i--; 1004 termbuf[i] = '\0'; 1005 if (termbuf[0] != '\0') 1006 TtyType = termbuf; 1007 } 1008 } 1009 1010 /* get terminal capabilities */ 1011 if (!(Alias[0] && isalias(TtyType))) { 1012 switch (tgetent(Capbuf, TtyType)) 1013 { 1014 case -1: 1015 prs("Cannot find termcap\n"); 1016 flush(); 1017 exit(-1); 1018 1019 case 0: 1020 prs("Type "); 1021 prs(TtyType); 1022 prs(" unknown\n"); 1023 flush(); 1024 if (DoSetenv) 1025 { 1026 TtyType = DEFTYPE; 1027 Alias[0] = '\0'; 1028 goto ask; 1029 } 1030 else 1031 exit(1); 1032 } 1033 } 1034 Ttycap = Capbuf; 1035 1036 if (!RepOnly) 1037 { 1038 /* determine erase and kill characters */ 1039 if (Specialerase && !tgetflag("bs")) 1040 Erase_char = 0; 1041 bufp = buf; 1042 p = tgetstr("kb", &bufp); 1043 if (p == NULL || p[1] != '\0') 1044 p = tgetstr("bc", &bufp); 1045 if (p != NULL && p[1] == '\0') 1046 bs_char = p[0]; 1047 else if (tgetflag("bs")) 1048 bs_char = BACKSPACE; 1049 else 1050 bs_char = 0; 1051 if (Erase_char == 0 && !tgetflag("os") && curerase == OLDERASE) 1052 { 1053 if (tgetflag("bs") || bs_char != 0) 1054 Erase_char = -1; 1055 } 1056 if (Erase_char < 0) 1057 Erase_char = (bs_char != 0) ? bs_char : BACKSPACE; 1058 1059 if (curerase == 0) 1060 curerase = CERASE; 1061 if (Erase_char != 0) 1062 curerase = Erase_char; 1063 1064 if (curintr == 0) 1065 curintr = CINTR; 1066 if (Intr_char != 0) 1067 curintr = Intr_char; 1068 1069 if (curkill == 0) 1070 curkill = CKILL; 1071 if (Kill_char != 0) 1072 curkill = Kill_char; 1073 1074 /* set modes */ 1075 PadBaud = tgetnum("pb"); /* OK if fails */ 1076 for (i=0; speeds[i].string; i++) 1077 if (speeds[i].baudrate == PadBaud) { 1078 PadBaud = speeds[i].speed; 1079 break; 1080 } 1081 # ifndef USG 1082 setdelay("dC", CRdelay, CRbits, &mode.sg_flags); 1083 setdelay("dN", NLdelay, NLbits, &mode.sg_flags); 1084 setdelay("dB", BSdelay, BSbits, &mode.sg_flags); 1085 setdelay("dF", FFdelay, FFbits, &mode.sg_flags); 1086 setdelay("dT", TBdelay, TBbits, &mode.sg_flags); 1087 if (tgetflag("UC") || (command[0] & 0140) == 0100) 1088 mode.sg_flags |= LCASE; 1089 else if (tgetflag("LC")) 1090 mode.sg_flags &= ~LCASE; 1091 mode.sg_flags &= ~(EVENP | ODDP | RAW); 1092 # ifdef CBREAK 1093 mode.sg_flags &= ~CBREAK; 1094 # endif 1095 if (tgetflag("EP")) 1096 mode.sg_flags |= EVENP; 1097 if (tgetflag("OP")) 1098 mode.sg_flags |= ODDP; 1099 if ((mode.sg_flags & (EVENP | ODDP)) == 0) 1100 mode.sg_flags |= EVENP | ODDP; 1101 mode.sg_flags |= CRMOD | ECHO | XTABS; 1102 if (tgetflag("NL")) /* new line, not line feed */ 1103 mode.sg_flags &= ~CRMOD; 1104 if (tgetflag("HD")) /* half duplex */ 1105 mode.sg_flags &= ~ECHO; 1106 if (tgetflag("pt")) /* print tabs */ 1107 mode.sg_flags &= ~XTABS; 1108 # else 1109 setdelay("dC", CRdelay, CRbits, &mode.c_oflag); 1110 setdelay("dN", NLdelay, NLbits, &mode.c_oflag); 1111 setdelay("dB", BSdelay, BSbits, &mode.c_oflag); 1112 setdelay("dF", FFdelay, FFbits, &mode.c_oflag); 1113 setdelay("dT", TBdelay, TBbits, &mode.c_oflag); 1114 setdelay("dV", VTdelay, VTbits, &mode.c_oflag); 1115 1116 if (tgetflag("UC") || (command[0] & 0140) == 0100) { 1117 mode.c_iflag |= IUCLC; 1118 mode.c_oflag |= OLCUC; 1119 } 1120 else if (tgetflag("LC")) { 1121 mode.c_iflag &= ~IUCLC; 1122 mode.c_oflag &= ~OLCUC; 1123 } 1124 mode.c_iflag &= ~(PARMRK|INPCK); 1125 mode.c_lflag |= ICANON; 1126 if (tgetflag("EP")) { 1127 mode.c_cflag |= PARENB; 1128 mode.c_cflag &= ~PARODD; 1129 } 1130 if (tgetflag("OP")) { 1131 mode.c_cflag |= PARENB; 1132 mode.c_cflag |= PARODD; 1133 } 1134 1135 mode.c_oflag |= ONLCR; 1136 mode.c_iflag |= ICRNL; 1137 mode.c_lflag |= ECHO; 1138 mode.c_oflag |= TAB3; 1139 if (tgetflag("NL")) { /* new line, not line feed */ 1140 mode.c_oflag &= ~ONLCR; 1141 mode.c_iflag &= ~ICRNL; 1142 } 1143 if (tgetflag("HD")) /* half duplex */ 1144 mode.c_lflag &= ~ECHO; 1145 if (tgetflag("pt")) /* print tabs */ 1146 mode.c_oflag &= ~TAB3; 1147 1148 mode.c_lflag |= (ECHOE|ECHOK); 1149 # endif 1150 # ifdef CBVIRTTERM 1151 HasAM = tgetflag("am"); 1152 # endif CBVIRTTERM 1153 # ifdef UCB_NTTY 1154 if (ldisc == NTTYDISC) 1155 { 1156 lmode |= LCTLECH; /* display ctrl chars */ 1157 if (tgetflag("hc")) 1158 { /** set printer modes **/ 1159 lmode &= ~(LCRTBS|LCRTERA|LCRTKIL); 1160 lmode |= LPRTERA; 1161 } 1162 else 1163 { /** set crt modes **/ 1164 if (!tgetflag("os")) 1165 { 1166 lmode &= ~LPRTERA; 1167 lmode |= LCRTBS; 1168 if (mode.sg_ospeed >= B1200) 1169 lmode |= LCRTERA|LCRTKIL; 1170 } 1171 } 1172 } 1173 if (IsReset) 1174 lmode &= ~(LMDMBUF|LLITOUT|LPASS8); 1175 (void) ioctl(FILEDES, TIOCLSET, (char *)&lmode); 1176 # endif 1177 1178 /* get pad character */ 1179 bufp = buf; 1180 if (tgetstr("pc", &bufp) != 0) 1181 PC = buf[0]; 1182 1183 columns = tgetnum("co"); 1184 lines = tgetnum("li"); 1185 1186 /* Set window size */ 1187 (void) ioctl(FILEDES, TIOCGWINSZ, (char *)&win); 1188 if (win.ws_row == 0 && win.ws_col == 0 && 1189 lines > 0 && columns > 0) { 1190 win.ws_row = lines; 1191 win.ws_col = columns; 1192 (void) ioctl(FILEDES, TIOCSWINSZ, (char *)&win); 1193 } 1194 /* output startup string */ 1195 if (!NoInit) 1196 { 1197 # ifndef USG 1198 if (oldmode.sg_flags&(XTABS|CRMOD)) 1199 { 1200 oldmode.sg_flags &= ~(XTABS|CRMOD); 1201 setmode(-1); 1202 } 1203 # else 1204 if (oldmode.c_oflag&(TAB3|ONLCR|OCRNL|ONLRET)) 1205 { 1206 oldmode.c_oflag &= (TAB3|ONLCR|OCRNL|ONLRET); 1207 setmode(-1); 1208 } 1209 # endif 1210 # ifdef CBVIRTTERM 1211 block.st_termt = 0; 1212 (void) ioctl(FILEDES, LDSETT, (char *)&block); 1213 # endif CBVIRTTERM 1214 if (settabs()) { 1215 settle = YES; 1216 flush(); 1217 } 1218 bufp = buf; 1219 if (IsReset && tgetstr("rs", &bufp) != 0 || 1220 tgetstr("is", &bufp) != 0) 1221 { 1222 tputs(buf, 0, prc); 1223 settle = YES; 1224 flush(); 1225 } 1226 bufp = buf; 1227 if (IsReset && tgetstr("rf", &bufp) != 0 || 1228 tgetstr("if", &bufp) != 0) 1229 { 1230 cat(buf); 1231 settle = YES; 1232 } 1233 if (settle) 1234 { 1235 prc('\r'); 1236 flush(); 1237 sleep(1); /* let terminal settle down */ 1238 } 1239 } 1240 1241 # ifdef CBVIRTTERM 1242 if (DoVirtTerm) { 1243 j = tgetnum("vt"); 1244 VirTermNo = -1; 1245 for (i=0; vt_map[i].stdnum; i++) 1246 if (vt_map[i].stdnum == j) 1247 VirTermNo = vt_map[i].localnum; 1248 } else 1249 VirTermNo = -1; 1250 # endif CBVIRTTERM 1251 1252 setmode(0); /* set new modes, if they've changed */ 1253 1254 /* set up environment for the shell we are using */ 1255 /* (this code is rather heuristic, checking for $SHELL */ 1256 /* ending in the 3 characters "csh") */ 1257 csh = NO; 1258 if (DoSetenv) 1259 { 1260 # ifndef V6 1261 char *sh; 1262 1263 if ((sh = getenv("SHELL")) && (i = strlen(sh)) >= 3) 1264 { 1265 if ((csh = sequal(&sh[i-3], "csh")) && CmndLine) 1266 (void) write(STDOUT, "set noglob;\n", 12); 1267 } 1268 if (!csh) 1269 # endif 1270 /* running Bourne shell */ 1271 (void) write(STDOUT, "export TERMCAP TERM;\n", 21); 1272 } 1273 } 1274 1275 /* report type if appropriate */ 1276 if (DoSetenv || Report || Ureport) 1277 { 1278 /* if type is the short name, find first alias (if any) */ 1279 makealias(Ttycap); 1280 if (sequal(TtyType, Alias[0]) && Alias[1]) { 1281 TtyType = Alias[1]; 1282 } 1283 1284 if (DoSetenv) 1285 { 1286 if (csh) 1287 { 1288 if (CmndLine) 1289 (void) write(STDOUT, "setenv TERM ", 12); 1290 (void) write(STDOUT, TtyType, strlen(TtyType)); 1291 (void) write(STDOUT, " ", 1); 1292 if (CmndLine) 1293 (void) write(STDOUT, ";\n", 2); 1294 } 1295 else 1296 { 1297 (void) write(STDOUT, "TERM=", 5); 1298 (void) write(STDOUT, TtyType, strlen(TtyType)); 1299 (void) write(STDOUT, ";\n", 2); 1300 } 1301 } 1302 else if (Report) 1303 { 1304 (void) write(STDOUT, TtyType, strlen(TtyType)); 1305 (void) write(STDOUT, "\n", 1); 1306 } 1307 if (Ureport) 1308 { 1309 prs("Terminal type is "); 1310 prs(TtyType); 1311 prs("\n"); 1312 flush(); 1313 } 1314 1315 if (DoSetenv) 1316 { 1317 if (csh) 1318 { 1319 if (CmndLine) 1320 (void) write(STDOUT, "setenv TERMCAP '", 16); 1321 } 1322 else 1323 (void) write(STDOUT, "TERMCAP='", 9); 1324 wrtermcap(Ttycap); 1325 if (csh) 1326 { 1327 if (CmndLine) 1328 { 1329 (void) write(STDOUT, "';\n", 3); 1330 (void) write(STDOUT, "unset noglob;\n", 14); 1331 } 1332 } 1333 else 1334 (void) write(STDOUT, "';\n", 3); 1335 } 1336 } 1337 1338 if (RepOnly) 1339 exit(0); 1340 1341 /* tell about changing erase, kill and interrupt characters */ 1342 reportek("Erase", curerase, olderase, OLDERASE); 1343 reportek("Kill", curkill, oldkill, OLDKILL); 1344 reportek("Interrupt", curintr, oldintr, OLDINTR); 1345 1346 # ifdef V6 1347 /* update htmp */ 1348 if (!Dash_u) 1349 { 1350 if (Ttyid == 0) 1351 Ttyid = ttyn(FILEDES); 1352 if (Ttyid == 'x') 1353 { 1354 prs("Cannot update htmp\n"); 1355 flush(); 1356 } 1357 else 1358 { 1359 /* update htmp file only if changed */ 1360 if (!bequal(Capbuf, hsgettype(), 2)) 1361 { 1362 hsettype(Capbuf[0] | (Capbuf[1] << 8)); 1363 hput(Ttyid); 1364 } 1365 } 1366 } 1367 # endif 1368 1369 exit(0); 1370 } 1371 1372 /* 1373 * Set the hardware tabs on the terminal, using the ct (clear all tabs), 1374 * st (set one tab) and ch (horizontal cursor addressing) capabilities. 1375 * This is done before if and is, so they can patch in case we blow this. 1376 */ 1377 settabs() 1378 { 1379 char caps[100]; 1380 char *capsp = caps; 1381 char *clear_tabs, *set_tab, *set_column, *set_pos; 1382 char *tg_out, *tgoto(); 1383 int c; 1384 1385 clear_tabs = tgetstr("ct", &capsp); 1386 set_tab = tgetstr("st", &capsp); 1387 set_column = tgetstr("ch", &capsp); 1388 if (set_column == 0) 1389 set_pos = tgetstr("cm", &capsp); 1390 1391 if (clear_tabs && set_tab) { 1392 prc('\r'); /* force to be at left margin */ 1393 tputs(clear_tabs, 0, prc); 1394 } 1395 if (set_tab) { 1396 for (c=8; c<columns; c += 8) { 1397 /* get to that column. */ 1398 tg_out = "OOPS"; /* also returned by tgoto */ 1399 if (set_column) 1400 tg_out = tgoto(set_column, 0, c); 1401 if (*tg_out == 'O' && set_pos) 1402 tg_out = tgoto(set_pos, c, lines-1); 1403 if (*tg_out != 'O') 1404 tputs(tg_out, 1, prc); 1405 else { 1406 prc(' '); prc(' '); prc(' '); prc(' '); 1407 prc(' '); prc(' '); prc(' '); prc(' '); 1408 } 1409 /* set the tab */ 1410 tputs(set_tab, 0, prc); 1411 } 1412 prc('\r'); 1413 return 1; 1414 } 1415 return 0; 1416 } 1417 1418 setmode(flag) 1419 int flag; 1420 /* flag serves several purposes: 1421 * if called as the result of a signal, flag will be > 0. 1422 * if called from terminal init, flag == -1 means reset "oldmode". 1423 * called with flag == 0 at end of normal mode processing. 1424 */ 1425 { 1426 # ifndef USG 1427 struct sgttyb *ttymode; 1428 # else 1429 struct termio *ttymode; 1430 # endif 1431 # ifdef TIOCGETC 1432 struct tchars *ttytchars; 1433 # endif 1434 1435 if (flag < 0) { /* unconditionally reset oldmode (called from init) */ 1436 ttymode = &oldmode; 1437 # ifdef TIOCGETC 1438 ttytchars = &oldtchar; 1439 # endif 1440 } else if (!bequal((char *)&mode, (char *)&oldmode, sizeof mode)) { 1441 ttymode = &mode; 1442 # ifdef TIOCGETC 1443 ttytchars = &tchar; 1444 # endif 1445 } else { /* don't need it */ 1446 # ifndef USG 1447 ttymode = (struct sgttyb *)0; 1448 # else 1449 ttymode = (struct termio *)0; 1450 # endif 1451 # ifdef TIOCGETC 1452 ttytchars = (struct tchars *)0; 1453 # endif 1454 } 1455 1456 if (ttymode) 1457 { 1458 # ifdef USG 1459 (void) ioctl(FILEDES, TCSETAW, (char *)ttymode); 1460 # else 1461 # ifndef V6 1462 /* don't flush */ 1463 (void) ioctl(FILEDES, TIOCSETN, (char *)ttymode); 1464 # else 1465 stty(FILEDES, ttymode); 1466 # endif 1467 # endif 1468 } 1469 # ifdef TIOCGETC 1470 if (ttytchars) { 1471 (void) ioctl(FILEDES, TIOCSETC, (char *)ttytchars); 1472 } 1473 # endif 1474 # ifdef CBVIRTTERM 1475 if (VirTermNo != -2) { 1476 int r1, r2; 1477 extern int errno; 1478 1479 r1 = ioctl(FILEDES, LDGETT, (char *)&block); 1480 block.st_flgs |= TM_SET; 1481 block.st_termt = VirTermNo; 1482 if (block.st_termt < 0) 1483 block.st_termt = 0; 1484 if (!HasAM) 1485 block.st_flgs |= TM_ANL; 1486 else 1487 block.st_flgs &= ~TM_ANL; 1488 r2 = ioctl(FILEDES, LDSETT, (char *)&block); 1489 } 1490 # endif 1491 1492 if (flag > 0) /* trapped signal */ 1493 exit(1); 1494 } 1495 1496 reportek(name, new, old, def) 1497 char *name; 1498 char old; 1499 char new; 1500 char def; 1501 { 1502 register char o; 1503 register char n; 1504 register char *p; 1505 char buf[32]; 1506 char *bufp; 1507 1508 if (BeQuiet) 1509 return; 1510 o = old; 1511 n = new; 1512 1513 if (o == n && n == def) 1514 return; 1515 prs(name); 1516 if (o == n) 1517 prs(" is "); 1518 else 1519 prs(" set to "); 1520 bufp = buf; 1521 if (tgetstr("kb", &bufp) > 0 && n == buf[0] && buf[1] == NULL) 1522 prs("Backspace\n"); 1523 else if (n == 0177) 1524 prs("Delete\n"); 1525 else 1526 { 1527 if (n < 040) 1528 { 1529 prs("Ctrl-"); 1530 n ^= 0100; 1531 } 1532 p = "x\n"; 1533 p[0] = n; 1534 prs(p); 1535 } 1536 flush(); 1537 } 1538 1539 1540 1541 1542 setdelay(cap, dtab, bits, flags) 1543 char *cap; 1544 struct delay dtab[]; 1545 int bits; 1546 short *flags; 1547 { 1548 register int i; 1549 register struct delay *p; 1550 # ifdef V6 1551 extern int ospeed; 1552 # else 1553 extern short ospeed; 1554 # endif 1555 1556 /* see if this capability exists at all */ 1557 i = tgetnum(cap); 1558 if (i < 0) 1559 i = 0; 1560 /* No padding at speeds below PadBaud */ 1561 if (PadBaud > ospeed) 1562 i = 0; 1563 1564 /* clear out the bits, replace with new ones */ 1565 *flags &= ~bits; 1566 1567 /* scan dtab for first entry with adequate delay */ 1568 for (p = dtab; p->d_delay >= 0; p++) 1569 { 1570 if (p->d_delay >= i) 1571 { 1572 p++; 1573 break; 1574 } 1575 } 1576 1577 /* use last entry if none will do */ 1578 *flags |= (--p)->d_bits; 1579 } 1580 1581 1582 prs(s) 1583 char *s; 1584 { 1585 while (*s != '\0') 1586 prc(*s++); 1587 } 1588 1589 1590 char OutBuf[256]; 1591 int OutPtr; 1592 1593 prc(c) 1594 char c; 1595 { 1596 OutBuf[OutPtr++] = c; 1597 if (OutPtr >= sizeof OutBuf) 1598 flush(); 1599 } 1600 1601 flush() 1602 { 1603 if (OutPtr > 0) 1604 (void) write(2, OutBuf, OutPtr); 1605 OutPtr = 0; 1606 } 1607 1608 1609 cat(file) 1610 char *file; 1611 { 1612 register int fd; 1613 register int i; 1614 char buf[BUFSIZ]; 1615 1616 fd = open(file, 0); 1617 if (fd < 0) 1618 { 1619 prs("Cannot open "); 1620 prs(file); 1621 prs("\n"); 1622 flush(); 1623 return; 1624 } 1625 1626 while ((i = read(fd, buf, BUFSIZ)) > 0) 1627 (void) write(FILEDES, buf, i); 1628 1629 (void) close(fd); 1630 } 1631 1632 1633 1634 bmove(from, to, length) 1635 char *from; 1636 char *to; 1637 int length; 1638 { 1639 register char *p, *q; 1640 register int i; 1641 1642 i = length; 1643 p = from; 1644 q = to; 1645 1646 while (i-- > 0) 1647 *q++ = *p++; 1648 } 1649 1650 1651 1652 bequal(a, b, len) /* must be same thru len chars */ 1653 char *a; 1654 char *b; 1655 int len; 1656 { 1657 register char *p, *q; 1658 register int i; 1659 1660 i = len; 1661 p = a; 1662 q = b; 1663 1664 while ((*p == *q) && --i > 0) 1665 { 1666 p++; q++; 1667 } 1668 return ((*p == *q) && i >= 0); 1669 } 1670 1671 sequal(a, b) /* must be same thru NULL */ 1672 char *a; 1673 char *b; 1674 { 1675 register char *p = a, *q = b; 1676 1677 while (*p && *q && (*p == *q)) 1678 { 1679 p++; q++; 1680 } 1681 return (*p == *q); 1682 } 1683 1684 makealias(buf) 1685 char *buf; 1686 { 1687 register int i; 1688 register char *a; 1689 register char *b; 1690 1691 Alias[0] = a = Aliasbuf; 1692 b = buf; 1693 i = 1; 1694 while (*b && *b != ':') { 1695 if (*b == '|') { 1696 *a++ = NULL; 1697 Alias[i++] = a; 1698 b++; 1699 } 1700 else 1701 *a++ = *b++; 1702 } 1703 *a = NULL; 1704 Alias[i] = NULL; 1705 # ifdef DEB 1706 for(i = 0; Alias[i]; printf("A:%s\n", Alias[i++])); 1707 # endif 1708 } 1709 1710 isalias(ident) /* is ident same as one of the aliases? */ 1711 char *ident; 1712 { 1713 char **a = Alias; 1714 1715 if (*a) 1716 while (*a) 1717 if (sequal(ident, *a)) 1718 return(YES); 1719 else 1720 a++; 1721 return(NO); 1722 } 1723 1724 # ifdef GTTYN 1725 char * 1726 stypeof(ttyid) 1727 char *ttyid; 1728 { 1729 register char *PortType; 1730 register char *TtyId; 1731 struct ttyent *t; 1732 1733 if (ttyid == NOTTY) 1734 return (DEFTYPE); 1735 1736 /* split off end of name */ 1737 TtyId = ttyid; 1738 while (*ttyid) 1739 if (*ttyid++ == '/') 1740 TtyId = ttyid; 1741 1742 /* scan the file */ 1743 if ((t = getttynam(TtyId)) != NULL) 1744 { 1745 PortType = t->ty_type; 1746 /* get aliases from termcap entry */ 1747 if (Mapped && tgetent(Capbuf, PortType) > 0) { 1748 makealias(Capbuf); 1749 if (sequal(Alias[0], PortType) && Alias[1]) 1750 PortType = Alias[1]; 1751 } 1752 return (PortType); 1753 } 1754 return (DEFTYPE); 1755 } 1756 # endif 1757 1758 /* 1759 * routine to output the string for the environment TERMCAP variable 1760 */ 1761 #define WHITE(c) (c == ' ' || c == '\t') 1762 char delcap[128][2]; 1763 int ncap = 0; 1764 1765 wrtermcap(bp) 1766 char *bp; 1767 { 1768 char buf[CAPBUFSIZ]; 1769 char *p = buf; 1770 char *tp; 1771 char *putbuf(); 1772 int space, empty; 1773 # ifdef CBVIRTTERM 1774 register int i; 1775 # endif CBVIRTTERM 1776 1777 /* discard names with blanks */ 1778 /** May not be desireable ? **/ 1779 while (*bp && *bp != ':') { 1780 if (*bp == '|') { 1781 tp = bp+1; 1782 space = NO; 1783 while (*tp && *tp != '|' && *tp != ':') { 1784 space = (space || WHITE(*tp) ); 1785 tp++; 1786 } 1787 if (space) { 1788 bp = tp; 1789 continue; 1790 } 1791 } 1792 *p++ = *bp++; 1793 } 1794 /**/ 1795 1796 # ifdef CBVIRTTERM 1797 if (VirTermNo > 0) { 1798 p = putbuf(p, ":am"); /* All virt terms have auto margins */ 1799 cancelled("am"); 1800 } 1801 # endif 1802 while (*bp) { 1803 switch (*bp) { 1804 case ':': /* discard empty, cancelled or dupl fields */ 1805 tp = bp+1; 1806 empty = YES; 1807 while (*tp && *tp != ':') { 1808 empty = (empty && WHITE(*tp) ); 1809 tp++; 1810 } 1811 # ifdef CBVIRTTERM 1812 /* 1813 * Virtual terminals use ic, not im or ei. Turn 1814 * any of them into ic - duplicates will be cancelled 1815 * below. I assume that terminals needing im+ic+ei 1816 * are handled by the kernel. 1817 */ 1818 if (VirTermNo > 0 && !HasAM && 1819 (bp[1]=='i' && bp[2]=='m' || 1820 bp[1]=='e' && bp[2]=='i')) { 1821 bp[1] = 'i'; 1822 bp[2] = 'c'; 1823 } 1824 if (VirTermNo > 0 && !HasAM && 1825 (bp[1]=='c' && bp[2]=='s')) { 1826 bp[1] = 'd'; 1827 bp[2] = 'l'; 1828 /* Also need al, so kludge: */ 1829 if (!cancelled("al")) 1830 p = putbuf(p, ":al=\033\120"); 1831 } 1832 # endif CBVIRTTERM 1833 if (empty || cancelled(bp+1)) { 1834 bp = tp; 1835 continue; 1836 } 1837 # ifdef CBVIRTTERM 1838 if (VirTermNo > 0 && !HasAM) 1839 for (i = 0; vtab[i].value; i++) { 1840 if (vtab[i].cap[0] == bp[1] && 1841 vtab[i].cap[1] == bp[2]) { 1842 *p++ = *bp++; /* colon */ 1843 *p++ = *bp++; /* first char */ 1844 *p++ = *bp++; /* second " */ 1845 *p++ = *bp++; /* = sign */ 1846 p = putbuf(p, vtab[i].value); 1847 bp = tp; 1848 goto contin; 1849 } 1850 } 1851 # endif CBVIRTTERM 1852 break; 1853 1854 case ' ': /* no spaces in output */ 1855 p = putbuf(p, "\\040"); 1856 bp++; 1857 continue; 1858 1859 case '!': /* the shell thinks this is history */ 1860 p = putbuf(p, "\\041"); 1861 bp++; 1862 continue; 1863 1864 case ',': /* the shell thinks this is history */ 1865 p = putbuf(p, "\\054"); 1866 bp++; 1867 continue; 1868 1869 case '"': /* no quotes in output */ 1870 p = putbuf(p, "\\042"); 1871 bp++; 1872 continue; 1873 1874 case '\'': /* no quotes in output */ 1875 p = putbuf(p, "\\047"); 1876 bp++; 1877 continue; 1878 1879 case '`': /* no back quotes in output */ 1880 p = putbuf(p, "\\140"); 1881 bp++; 1882 continue; 1883 1884 case '\\': 1885 case '^': /* anything following is OK */ 1886 *p++ = *bp++; 1887 # ifdef CBVIRTTERM 1888 if (*bp == 'E' && VirTermNo > 0 && 1889 (bp[-3]!='\\'||bp[-2]!='E') && 1890 (bp[1]!='\\'||bp[2]!='E')) 1891 p = putbuf(p, "E\\"); 1892 # endif CBVIRTTERM 1893 } 1894 *p++ = *bp++; 1895 # ifdef CBVIRTTERM 1896 contin: ; 1897 # endif CBVIRTTERM 1898 } 1899 *p++ = ':'; /* we skipped the last : with the : lookahead hack */ 1900 (void) write (STDOUT, buf, p-buf); 1901 } 1902 1903 cancelled(cap) 1904 char *cap; 1905 { 1906 register int i; 1907 1908 for (i = 0; i < ncap; i++) 1909 { 1910 if (cap[0] == delcap[i][0] && cap[1] == delcap[i][1]) 1911 return (YES); 1912 } 1913 /* delete a second occurrance of the same capability */ 1914 delcap[ncap][0] = cap[0]; 1915 delcap[ncap][1] = cap[1]; 1916 ncap++; 1917 return (cap[2] == '@'); 1918 } 1919 1920 char * 1921 putbuf(ptr, str) 1922 char *ptr; 1923 char *str; 1924 { 1925 char buf[20]; 1926 1927 while (*str) { 1928 switch (*str) { 1929 case '\033': 1930 ptr = putbuf(ptr, "\\E"); 1931 str++; 1932 break; 1933 default: 1934 if (*str <= ' ') { 1935 (void) sprintf(buf, "\\%03o", *str); 1936 ptr = putbuf(ptr, buf); 1937 str++; 1938 } else 1939 *ptr++ = *str++; 1940 } 1941 } 1942 return (ptr); 1943 } 1944 1945 1946 baudrate(p) 1947 char *p; 1948 { 1949 char buf[8]; 1950 int i = 0; 1951 1952 while (i < 7 && (isalnum(*p) || *p == '.')) 1953 buf[i++] = *p++; 1954 buf[i] = NULL; 1955 for (i=0; speeds[i].string; i++) 1956 if (sequal(speeds[i].string, buf)) 1957 return (speeds[i].speed); 1958 return (-1); 1959 } 1960 1961 char * 1962 mapped(type) 1963 char *type; 1964 { 1965 # ifdef V6 1966 extern int ospeed; 1967 # else 1968 extern short ospeed; 1969 # endif 1970 int match; 1971 1972 # ifdef DEB 1973 printf ("spd:%d\n", ospeed); 1974 prmap(); 1975 # endif 1976 Map = map; 1977 while (Map->Ident) 1978 { 1979 if (*(Map->Ident) == NULL || sequal(Map->Ident, type) || isalias(Map->Ident)) 1980 { 1981 match = NO; 1982 switch (Map->Test) 1983 { 1984 case ANY: /* no test specified */ 1985 case ALL: 1986 match = YES; 1987 break; 1988 1989 case GT: 1990 match = (ospeed > Map->Speed); 1991 break; 1992 1993 case GE: 1994 match = (ospeed >= Map->Speed); 1995 break; 1996 1997 case EQ: 1998 match = (ospeed == Map->Speed); 1999 break; 2000 2001 case LE: 2002 match = (ospeed <= Map->Speed); 2003 break; 2004 2005 case LT: 2006 match = (ospeed < Map->Speed); 2007 break; 2008 2009 case NE: 2010 match = (ospeed != Map->Speed); 2011 break; 2012 } 2013 if (match) 2014 return (Map->Type); 2015 } 2016 Map++; 2017 } 2018 /* no match found; return given type */ 2019 return (type); 2020 } 2021 2022 # ifdef DEB 2023 prmap() 2024 { 2025 Map = map; 2026 while (Map->Ident) 2027 { 2028 printf ("%s t:%d s:%d %s\n", 2029 Map->Ident, Map->Test, Map->Speed, Map->Type); 2030 Map++; 2031 } 2032 } 2033 # endif 2034 2035 char * 2036 nextarg(argc, argv) 2037 int argc; 2038 char *argv[]; 2039 { 2040 if (argc <= 0) 2041 fatal ("Too few args: ", *argv); 2042 if (*(*++argv) == '-') 2043 fatal ("Unexpected arg: ", *argv); 2044 return (*argv); 2045 } 2046 2047 fatal (mesg, obj) 2048 char *mesg; 2049 char *obj; 2050 { 2051 prs (mesg); 2052 prs (obj); 2053 prc ('\n'); 2054 prs (USAGE); 2055 flush(); 2056 exit(1); 2057 } 2058