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