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