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