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