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