1 # 2 char id_tset[] = "@(#)tset.c 1.2"; 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 # define CTRL(x) (x ^ 0100) 293 # define BACKSPACE (CTRL('H')) 294 # define CHK(val, dft) (val<=0 ? dft : val) 295 # define isdigit(c) (c >= '0' && c <= '9') 296 # define isalnum(c) (c > ' ' && !(index("<@=>!:|\177", c)) ) 297 # define OLDERASE '#' 298 # define OLDKILL '@' 299 300 # define FILEDES 2 /* do gtty/stty on this descriptor */ 301 # define STDOUT 1 /* output of -s/-S to this descriptor */ 302 303 # ifdef V6 304 # define UIDMASK 0377 305 # else 306 # define UIDMASK -1 307 # endif 308 309 # ifdef UCB_NTTY 310 # define USAGE "usage: tset [-] [-nrsIQS] [-eC] [-kC] [-m [ident][test speed]:type] [type]\n" 311 # else 312 # define USAGE "usage: tset [-] [-rsIQS] [-eC] [-kC] [-m [ident][test speed]:type] [type]\n" 313 # endif 314 315 # define OLDFLAGS 316 # define DIALUP "dialup" 317 # define OLDDIALUP "sd" 318 # define PLUGBOARD "plugboard" 319 # define OLDPLUGBOARD "sp" 320 /*** 321 # define ARPANET "arpanet" 322 # define OLDARPANET "sa" 323 /***/ 324 325 # define DEFTYPE "unknown" 326 327 328 # ifdef GTTYN 329 # define NOTTY 0 330 # else 331 # define NOTTY 'x' 332 # endif 333 334 /* 335 * Baud Rate Conditionals 336 */ 337 # define ANY 0 338 # define GT 1 339 # define EQ 2 340 # define LT 4 341 # define GE (GT|EQ) 342 # define LE (LT|EQ) 343 # define NE (GT|LT) 344 # define ALL (GT|EQ|LT) 345 346 347 348 # define NMAP 10 349 350 struct map { 351 char *Ident; 352 char Test; 353 char Speed; 354 char *Type; 355 } map[NMAP]; 356 357 struct map *Map = map; 358 359 /* This should be available in an include file */ 360 struct 361 { 362 char *string; 363 int speed; 364 int baudrate; 365 } speeds[] = { 366 "0", B0, 0, 367 "50", B50, 50, 368 "75", B75, 75, 369 "110", B110, 110, 370 "134", B134, 134, 371 "134.5",B134, 134, 372 "150", B150, 150, 373 "200", B200, 200, 374 "300", B300, 300, 375 "600", B600, 600, 376 "1200", B1200, 1200, 377 "1800", B1800, 1800, 378 "2400", B2400, 2400, 379 "4800", B4800, 4800, 380 "9600", B9600, 9600, 381 "exta", EXTA, 19200, 382 "extb", EXTB, 38400, 383 0, 384 }; 385 386 #ifdef CBVIRTTERM 387 struct vterm { 388 char cap[2]; 389 char *value; 390 } vtab [] = { 391 "al", "\033\120", 392 "cd", "\033\114", 393 "ce", "\033\113", 394 "cm", "\033\107%r%.%.", 395 "cl", "\033\112", 396 "dc", "\033\115", 397 "dl", "\033\116", 398 "ic", "\033\117", 399 "kl", "\033\104", 400 "kr", "\033\103", 401 "ku", "\033\101", 402 "kd", "\033\102", 403 "kh", "\033\105", 404 "nd", "\033\103", 405 "se", "\033\142\004", 406 "so", "\033\141\004", 407 "ue", "\033\142\001", 408 "up", "\033\101", 409 "us", "\033\141\001", 410 "\0\0", NULL, 411 }; 412 413 int VirTermNo = -2; 414 # endif CBVIRTTERM 415 416 char Erase_char; /* new erase character */ 417 char Kill_char; /* new kill character */ 418 char Specialerase; /* set => Erase_char only on terminals with backspace */ 419 420 # ifdef GTTYN 421 char *Ttyid = NOTTY; /* terminal identifier */ 422 # else 423 char Ttyid = NOTTY; /* terminal identifier */ 424 # endif 425 char *TtyType; /* type of terminal */ 426 char *DefType; /* default type if none other computed */ 427 char *NewType; /* mapping identifier based on old flags */ 428 int Mapped; /* mapping has been specified */ 429 int Dash_u; /* don't update htmp */ 430 int Dash_h; /* don't read htmp */ 431 int DoSetenv; /* output setenv commands */ 432 int BeQuiet; /* be quiet */ 433 int NoInit; /* don't output initialization string */ 434 int IsReset; /* invoked as reset */ 435 int Report; /* report current type */ 436 int Ureport; /* report to user */ 437 int RepOnly; /* report only */ 438 int CmndLine; /* output full command lines (-s option) */ 439 int Ask; /* ask user for termtype */ 440 int DoVirtTerm = YES; /* Set up a virtual terminal */ 441 int New = NO; /* use new tty discipline */ 442 int HasAM; /* True if terminal has automatic margins */ 443 int PadBaud; /* Min rate of padding needed */ 444 445 # define CAPBUFSIZ 1024 446 char Capbuf[CAPBUFSIZ]; /* line from /etc/termcap for this TtyType */ 447 char *Ttycap; /* termcap line from termcap or environ */ 448 449 char Aliasbuf[128]; 450 char *Alias[16]; 451 452 struct delay 453 { 454 int d_delay; 455 int d_bits; 456 }; 457 458 # include "tset.delays.h" 459 460 # ifndef USG 461 struct sgttyb mode; 462 struct sgttyb oldmode; 463 # else 464 struct termio mode; 465 struct termio oldmode; 466 # endif 467 # ifdef CBVIRTTERM 468 struct termcb block = {0, 2, 0, 0, 0, 20}; 469 # endif CBVIRTTERM 470 471 472 main(argc, argv) 473 int argc; 474 char *argv[]; 475 { 476 char buf[256]; 477 char termbuf[32]; 478 auto char *bufp; 479 register char *p; 480 char *command; 481 register int i; 482 int j; 483 int Break; 484 int Not; 485 char *nextarg(); 486 char *mapped(); 487 extern char *rindex(); 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=nothing"); 848 /* get current idea of terminal type from environment */ 849 if (!Dash_h && !Mapped && 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 TtyType = mapped(TtyType); 897 898 /* TtyType now contains a pointer to the type of the terminal */ 899 /* If the first character is '?', ask the user */ 900 if (TtyType[0] == '?') 901 { 902 Ask = YES; 903 TtyType++; 904 if (TtyType[0] == '\0') 905 TtyType = DEFTYPE; 906 } 907 if (Ask) 908 { 909 prs("TERM = ("); 910 prs(TtyType); 911 prs(") "); 912 flush(); 913 914 /* read the terminal. If not empty, set type */ 915 i = read(2, termbuf, sizeof termbuf - 1); 916 if (i > 0) 917 { 918 if (termbuf[i - 1] == '\n') 919 i--; 920 termbuf[i] = '\0'; 921 if (termbuf[0] != '\0') 922 TtyType = termbuf; 923 } 924 } 925 926 /* get terminal capabilities */ 927 if (!(Alias[0] && isalias(TtyType))) { 928 switch (tgetent(Capbuf, TtyType)) 929 { 930 case -1: 931 prs("Cannot find termcap\n"); 932 flush(); 933 exit(-1); 934 935 case 0: 936 prs("Type "); 937 prs(TtyType); 938 prs(" unknown\n"); 939 flush(); 940 if (DoSetenv) 941 { 942 TtyType = DEFTYPE; 943 tgetent(Capbuf, TtyType); 944 } 945 else 946 exit(1); 947 } 948 } 949 Ttycap = Capbuf; 950 951 if (!RepOnly) 952 { 953 /* determine erase and kill characters */ 954 if (Specialerase && !tgetflag("bs")) 955 Erase_char = 0; 956 bufp = buf; 957 p = tgetstr("kb", &bufp); 958 if (p == NULL || p[1] != '\0') 959 p = tgetstr("bc", &bufp); 960 if (p != NULL && p[1] == '\0') 961 bs_char = p[0]; 962 else if (tgetflag("bs")) 963 bs_char = BACKSPACE; 964 else 965 bs_char = 0; 966 if (Erase_char == 0 && !tgetflag("os") && curerase == OLDERASE) 967 { 968 if (tgetflag("bs") || bs_char != 0) 969 Erase_char = -1; 970 } 971 if (Erase_char < 0) 972 Erase_char = (bs_char != 0) ? bs_char : BACKSPACE; 973 974 if (curerase == 0) 975 curerase = OLDERASE; 976 if (Erase_char != 0) 977 curerase = Erase_char; 978 979 if (curkill == 0) 980 curkill = OLDKILL; 981 if (Kill_char != 0) 982 curkill = Kill_char; 983 984 /* set modes */ 985 PadBaud = tgetnum("pb"); /* OK if fails */ 986 for (i=0; speeds[i].string; i++) 987 if (speeds[i].baudrate == PadBaud) { 988 PadBaud = speeds[i].speed; 989 break; 990 } 991 # ifndef USG 992 setdelay("dC", CRdelay, CRbits, &mode.sg_flags); 993 setdelay("dN", NLdelay, NLbits, &mode.sg_flags); 994 setdelay("dB", BSdelay, BSbits, &mode.sg_flags); 995 setdelay("dF", FFdelay, FFbits, &mode.sg_flags); 996 setdelay("dT", TBdelay, TBbits, &mode.sg_flags); 997 if (tgetflag("UC") || (command[0] & 0140) == 0100) 998 mode.sg_flags |= LCASE; 999 else if (tgetflag("LC")) 1000 mode.sg_flags &= ~LCASE; 1001 mode.sg_flags &= ~(EVENP | ODDP | RAW); 1002 # ifdef CBREAK 1003 mode.sg_flags &= ~CBREAK; 1004 # endif 1005 if (tgetflag("EP")) 1006 mode.sg_flags |= EVENP; 1007 if (tgetflag("OP")) 1008 mode.sg_flags |= ODDP; 1009 if ((mode.sg_flags & (EVENP | ODDP)) == 0) 1010 mode.sg_flags |= EVENP | ODDP; 1011 mode.sg_flags |= CRMOD | ECHO | XTABS; 1012 if (tgetflag("NL")) /* new line, not line feed */ 1013 mode.sg_flags &= ~CRMOD; 1014 if (tgetflag("HD")) /* half duplex */ 1015 mode.sg_flags &= ~ECHO; 1016 if (tgetflag("pt")) /* print tabs */ 1017 mode.sg_flags &= ~XTABS; 1018 # else 1019 setdelay("dC", CRdelay, CRbits, &mode.c_oflag); 1020 setdelay("dN", NLdelay, NLbits, &mode.c_oflag); 1021 setdelay("dB", BSdelay, BSbits, &mode.c_oflag); 1022 setdelay("dF", FFdelay, FFbits, &mode.c_oflag); 1023 setdelay("dT", TBdelay, TBbits, &mode.c_oflag); 1024 setdelay("dV", VTdelay, VTbits, &mode.c_oflag); 1025 1026 if (tgetflag("UC") || (command[0] & 0140) == 0100) { 1027 mode.c_iflag |= IUCLC; 1028 mode.c_oflag |= OLCUC; 1029 } 1030 else if (tgetflag("LC")) { 1031 mode.c_iflag &= ~IUCLC; 1032 mode.c_oflag &= ~OLCUC; 1033 } 1034 mode.c_iflag &= ~(PARMRK|INPCK); 1035 mode.c_lflag |= ICANON; 1036 if (tgetflag("EP")) { 1037 mode.c_cflag |= PARENB; 1038 mode.c_cflag &= ~PARODD; 1039 } 1040 if (tgetflag("OP")) { 1041 mode.c_cflag |= PARENB; 1042 mode.c_cflag |= PARODD; 1043 } 1044 1045 mode.c_oflag |= ONLCR; 1046 mode.c_iflag |= ICRNL; 1047 mode.c_lflag |= ECHO; 1048 mode.c_oflag |= TAB3; 1049 if (tgetflag("NL")) { /* new line, not line feed */ 1050 mode.c_oflag &= ~ONLCR; 1051 mode.c_iflag &= ~ICRNL; 1052 } 1053 if (tgetflag("HD")) /* half duplex */ 1054 mode.c_lflag &= ~ECHO; 1055 if (tgetflag("pt")) /* print tabs */ 1056 mode.c_oflag &= ~TAB3; 1057 1058 mode.c_lflag |= (ECHOE|ECHOK); 1059 # endif 1060 # ifdef CBVIRTTERM 1061 HasAM = tgetflag("am"); 1062 # endif CBVIRTTERM 1063 # ifdef UCB_NTTY 1064 if (ldisc == NTTYDISC) 1065 { 1066 lmode |= LCTLECH; /* display ctrl chars */ 1067 if (tgetflag("hc")) 1068 { /** set printer modes **/ 1069 lmode &= ~(LCRTBS|LCRTERA|LCRTKIL); 1070 lmode |= LPRTERA; 1071 } 1072 else 1073 { /** set crt modes **/ 1074 if (!tgetflag("os")) 1075 { 1076 lmode &= ~LPRTERA; 1077 lmode |= LCRTBS; 1078 if (mode.sg_ospeed >= B1200) 1079 lmode |= LCRTERA|LCRTKIL; 1080 } 1081 } 1082 } 1083 ioctl(FILEDES, TIOCLSET, &lmode); 1084 # endif 1085 1086 /* get pad character */ 1087 bufp = buf; 1088 if (tgetstr("pc", &bufp) != 0) 1089 PC = buf[0]; 1090 1091 /* output startup string */ 1092 if (!NoInit) 1093 { 1094 # ifndef USG 1095 if (oldmode.sg_flags&(XTABS|CRMOD)) 1096 { 1097 oldmode.sg_flags &= ~(XTABS|CRMOD); 1098 setmode(-1); 1099 } 1100 # else 1101 if (oldmode.c_oflag&(TAB3|ONLCR|OCRNL|ONLRET)) 1102 { 1103 oldmode.c_oflag &= (TAB3|ONLCR|OCRNL|ONLRET); 1104 setmode(-1); 1105 } 1106 # endif 1107 # ifdef CBVIRTTERM 1108 block.st_termt = 0; 1109 ioctl(FILEDES, LDSETT, &block); 1110 # endif CBVIRTTERM 1111 if (settabs()) { 1112 settle = YES; 1113 flush(); 1114 } 1115 bufp = buf; 1116 if (tgetstr(IsReset? "rs" : "is", &bufp) != 0) 1117 { 1118 tputs(buf, 0, prc); 1119 settle = YES; 1120 flush(); 1121 } 1122 bufp = buf; 1123 if (tgetstr(IsReset? "rf" : "if", &bufp) != 0) 1124 { 1125 cat(buf); 1126 settle = YES; 1127 } 1128 if (settle) 1129 { 1130 prc('\r'); 1131 flush(); 1132 sleep(1); /* let terminal settle down */ 1133 } 1134 } 1135 1136 # ifdef CBVIRTTERM 1137 if (DoVirtTerm) { 1138 j = tgetnum("vt"); 1139 VirTermNo = -1; 1140 for (i=0; vt_map[i].stdnum; i++) 1141 if (vt_map[i].stdnum == j) 1142 VirTermNo = vt_map[i].localnum; 1143 } else 1144 VirTermNo = -1; 1145 # endif CBVIRTTERM 1146 1147 setmode(0); /* set new modes, if they've changed */ 1148 1149 /* set up environment for the shell we are using */ 1150 /* (this code is rather heuristic, checking for $SHELL */ 1151 /* ending in the 3 characters "csh") */ 1152 csh = NO; 1153 if (DoSetenv) 1154 { 1155 # ifndef V6 1156 char *sh; 1157 1158 if ((sh = getenv("SHELL")) && (i = strlen(sh)) >= 3) 1159 { 1160 if ((csh = sequal(&sh[i-3], "csh")) && CmndLine) 1161 write(STDOUT, "set noglob;\n", 12); 1162 } 1163 if (!csh) 1164 # endif 1165 /* running Bourne shell */ 1166 write(STDOUT, "export TERMCAP TERM;\n", 21); 1167 } 1168 } 1169 1170 /* report type if appropriate */ 1171 if (DoSetenv || Report || Ureport) 1172 { 1173 /* if type is the short name, find first alias (if any) */ 1174 makealias(Ttycap); 1175 if (sequal(TtyType, Alias[0]) && Alias[1]) { 1176 TtyType = Alias[1]; 1177 } 1178 1179 if (DoSetenv) 1180 { 1181 if (csh) 1182 { 1183 if (CmndLine) 1184 write(STDOUT, "setenv TERM ", 12); 1185 write(STDOUT, TtyType, strlen(TtyType)); 1186 write(STDOUT, " ", 1); 1187 if (CmndLine) 1188 write(STDOUT, ";\n", 2); 1189 } 1190 else 1191 { 1192 write(STDOUT, "TERM=", 5); 1193 write(STDOUT, TtyType, strlen(TtyType)); 1194 write(STDOUT, ";\n", 2); 1195 } 1196 } 1197 else if (Report) 1198 { 1199 write(STDOUT, TtyType, strlen(TtyType)); 1200 write(STDOUT, "\n", 1); 1201 } 1202 if (Ureport) 1203 { 1204 prs("Terminal type is "); 1205 prs(TtyType); 1206 prs("\n"); 1207 flush(); 1208 } 1209 1210 if (DoSetenv) 1211 { 1212 if (csh) 1213 { 1214 if (CmndLine) 1215 write(STDOUT, "setenv TERMCAP '", 16); 1216 } 1217 else 1218 write(STDOUT, "TERMCAP='", 9); 1219 wrtermcap(Ttycap); 1220 if (csh) 1221 { 1222 if (CmndLine) 1223 { 1224 write(STDOUT, "';\n", 3); 1225 write(STDOUT, "unset noglob;\n", 14); 1226 } 1227 } 1228 else 1229 write(STDOUT, "';\n", 3); 1230 } 1231 } 1232 1233 if (RepOnly) 1234 exit(0); 1235 1236 /* tell about changing erase and kill characters */ 1237 reportek("Erase", curerase, olderase, OLDERASE); 1238 reportek("Kill", curkill, oldkill, OLDKILL); 1239 1240 # ifdef V6 1241 /* update htmp */ 1242 if (!Dash_u) 1243 { 1244 if (Ttyid == 0) 1245 Ttyid = ttyn(FILEDES); 1246 if (Ttyid == 'x') 1247 { 1248 prs("Cannot update htmp\n"); 1249 flush(); 1250 } 1251 else 1252 { 1253 /* update htmp file only if changed */ 1254 if (!bequal(Capbuf, hsgettype(), 2)) 1255 { 1256 hsettype(Capbuf[0] | (Capbuf[1] << 8)); 1257 hput(Ttyid); 1258 } 1259 } 1260 } 1261 # endif 1262 1263 exit(0); 1264 } 1265 1266 /* 1267 * Set the hardware tabs on the terminal, using the ct (clear all tabs), 1268 * st (set one tab) and ch (horizontal cursor addressing) capabilities. 1269 * This is done before if and is, so they can patch in case we blow this. 1270 */ 1271 settabs() 1272 { 1273 char caps[100]; 1274 char *capsp = caps; 1275 char *clear_tabs, *set_tab, *set_column, *set_pos; 1276 char *tg_out, *tgoto(); 1277 int columns, lines, c; 1278 1279 clear_tabs = tgetstr("ct", &capsp); 1280 set_tab = tgetstr("st", &capsp); 1281 set_column = tgetstr("ch", &capsp); 1282 if (set_column == 0) 1283 set_pos = tgetstr("cm", &capsp); 1284 columns = tgetnum("co"); 1285 lines = tgetnum("li"); 1286 1287 if (clear_tabs && set_tab) { 1288 prc('\r'); /* force to be at left margin */ 1289 tputs(clear_tabs, 0, prc); 1290 } 1291 if (set_tab) { 1292 for (c=8; c<columns; c += 8) { 1293 /* get to that column. */ 1294 tg_out = "OOPS"; /* also returned by tgoto */ 1295 if (set_column) 1296 tg_out = tgoto(set_column, 0, c); 1297 if (*tg_out == 'O' && set_pos) 1298 tg_out = tgoto(set_pos, c, lines-1); 1299 if (*tg_out != 'O') 1300 tputs(tg_out, 1, prc); 1301 else { 1302 prc(' '); prc(' '); prc(' '); prc(' '); 1303 prc(' '); prc(' '); prc(' '); prc(' '); 1304 } 1305 /* set the tab */ 1306 tputs(set_tab, 0, prc); 1307 } 1308 prc('\r'); 1309 return 1; 1310 } 1311 return 0; 1312 } 1313 1314 setmode(flag) 1315 int flag; 1316 /* flag serves several purposes: 1317 * if called as the result of a signal, flag will be > 0. 1318 * if called from terminal init, flag == -1 means reset "oldmode". 1319 * called with flag == 0 at end of normal mode processing. 1320 */ 1321 { 1322 # ifndef USG 1323 struct sgttyb *ttymode; 1324 # else 1325 struct termio *ttymode; 1326 # endif 1327 1328 if (flag < 0) /* unconditionally reset oldmode (called from init) */ 1329 ttymode = &oldmode; 1330 else if (!bequal(&mode, &oldmode, sizeof mode)) 1331 ttymode = &mode; 1332 else /* don't need it */ 1333 # ifndef USG 1334 ttymode = (struct sgttyb *)0; 1335 # else 1336 ttymode = (struct termio *)0; 1337 # endif 1338 1339 if (ttymode) 1340 { 1341 # ifdef USG 1342 ioctl(FILEDES, TCSETAW, ttymode); 1343 # else 1344 # ifndef V6 1345 ioctl(FILEDES, TIOCSETN, ttymode); /* don't flush */ 1346 # else 1347 stty(FILEDES, ttymode); 1348 # endif 1349 # endif 1350 } 1351 # ifdef CBVIRTTERM 1352 if (VirTermNo != -2) { 1353 int r1, r2; 1354 extern int errno; 1355 1356 r1 = ioctl(FILEDES, LDGETT, &block); 1357 block.st_flgs |= TM_SET; 1358 block.st_termt = VirTermNo; 1359 if (block.st_termt < 0) 1360 block.st_termt = 0; 1361 if (!HasAM) 1362 block.st_flgs |= TM_ANL; 1363 else 1364 block.st_flgs &= ~TM_ANL; 1365 r2 = ioctl(FILEDES, LDSETT, &block); 1366 } 1367 # endif 1368 1369 if (flag > 0) /* trapped signal */ 1370 exit(1); 1371 } 1372 1373 reportek(name, new, old, def) 1374 char *name; 1375 char old; 1376 char new; 1377 char def; 1378 { 1379 register char o; 1380 register char n; 1381 register char *p; 1382 char buf[32]; 1383 char *bufp; 1384 1385 if (BeQuiet) 1386 return; 1387 o = old; 1388 n = new; 1389 1390 if (o == n && n == def) 1391 return; 1392 prs(name); 1393 if (o == n) 1394 prs(" is "); 1395 else 1396 prs(" set to "); 1397 bufp = buf; 1398 if (tgetstr("kb", &bufp) > 0 && n == buf[0] && buf[1] == NULL) 1399 prs("Backspace\n"); 1400 else if (n == 0177) 1401 prs("Delete\n"); 1402 else 1403 { 1404 if (n < 040) 1405 { 1406 prs("Ctrl-"); 1407 n ^= 0100; 1408 } 1409 p = "x\n"; 1410 p[0] = n; 1411 prs(p); 1412 } 1413 flush(); 1414 } 1415 1416 1417 1418 1419 setdelay(cap, dtab, bits, flags) 1420 char *cap; 1421 struct delay dtab[]; 1422 int bits; 1423 int *flags; 1424 { 1425 register int i; 1426 register struct delay *p; 1427 # ifdef V6 1428 extern int ospeed; 1429 # else 1430 extern short ospeed; 1431 # endif 1432 1433 /* see if this capability exists at all */ 1434 i = tgetnum(cap); 1435 if (i < 0) 1436 i = 0; 1437 /* No padding at speeds below PadBaud */ 1438 if (PadBaud > ospeed) 1439 i = 0; 1440 1441 /* clear out the bits, replace with new ones */ 1442 *flags &= ~bits; 1443 1444 /* scan dtab for first entry with adequate delay */ 1445 for (p = dtab; p->d_delay >= 0; p++) 1446 { 1447 if (p->d_delay >= i) 1448 { 1449 p++; 1450 break; 1451 } 1452 } 1453 1454 /* use last entry if none will do */ 1455 *flags |= (--p)->d_bits; 1456 } 1457 1458 1459 prs(s) 1460 char *s; 1461 { 1462 while (*s != '\0') 1463 prc(*s++); 1464 } 1465 1466 1467 char OutBuf[256]; 1468 int OutPtr; 1469 1470 prc(c) 1471 char c; 1472 { 1473 OutBuf[OutPtr++] = c; 1474 if (OutPtr >= sizeof OutBuf) 1475 flush(); 1476 } 1477 1478 flush() 1479 { 1480 if (OutPtr > 0) 1481 write(2, OutBuf, OutPtr); 1482 OutPtr = 0; 1483 } 1484 1485 1486 cat(file) 1487 char *file; 1488 { 1489 register int fd; 1490 register int i; 1491 char buf[BUFSIZ]; 1492 1493 fd = open(file, 0); 1494 if (fd < 0) 1495 { 1496 prs("Cannot open "); 1497 prs(file); 1498 prs("\n"); 1499 flush(); 1500 return; 1501 } 1502 1503 while ((i = read(fd, buf, BUFSIZ)) > 0) 1504 write(FILEDES, buf, i); 1505 1506 close(fd); 1507 } 1508 1509 1510 1511 bmove(from, to, length) 1512 char *from; 1513 char *to; 1514 int length; 1515 { 1516 register char *p, *q; 1517 register int i; 1518 1519 i = length; 1520 p = from; 1521 q = to; 1522 1523 while (i-- > 0) 1524 *q++ = *p++; 1525 } 1526 1527 1528 1529 bequal(a, b, len) /* must be same thru len chars */ 1530 char *a; 1531 char *b; 1532 int len; 1533 { 1534 register char *p, *q; 1535 register int i; 1536 1537 i = len; 1538 p = a; 1539 q = b; 1540 1541 while (*p && *q && (*p == *q) && --i > 0) 1542 { 1543 p++; q++; 1544 } 1545 return ((*p == *q) && i >= 0); 1546 } 1547 1548 sequal(a, b) /* must be same thru NULL */ 1549 char *a; 1550 char *b; 1551 { 1552 register char *p = a, *q = b; 1553 1554 while (*p && *q && (*p == *q)) 1555 { 1556 p++; q++; 1557 } 1558 return (*p == *q); 1559 } 1560 1561 makealias(buf) 1562 char *buf; 1563 { 1564 register int i; 1565 register char *a; 1566 register char *b; 1567 1568 Alias[0] = a = Aliasbuf; 1569 b = buf; 1570 i = 1; 1571 while (*b && *b != ':') { 1572 if (*b == '|') { 1573 *a++ = NULL; 1574 Alias[i++] = a; 1575 b++; 1576 } 1577 else 1578 *a++ = *b++; 1579 } 1580 *a = NULL; 1581 Alias[i] = NULL; 1582 # ifdef DEB 1583 for(i = 0; Alias[i]; printf("A:%s\n", Alias[i++])); 1584 # endif 1585 } 1586 1587 isalias(ident) /* is ident same as one of the aliases? */ 1588 char *ident; 1589 { 1590 char **a = Alias; 1591 1592 if (*a) 1593 while (*a) 1594 if (sequal(ident, *a)) 1595 return(YES); 1596 else 1597 a++; 1598 return(NO); 1599 } 1600 1601 # ifdef GTTYN 1602 char * 1603 stypeof(ttyid) 1604 char *ttyid; 1605 { 1606 static char typebuf[50]; 1607 register char *PortType; 1608 register char *PortName; 1609 register char *TtyId; 1610 register char *p; 1611 register FILE *f; 1612 1613 if (ttyid == NOTTY) 1614 return (DEFTYPE); 1615 f = fopen(GTTYN, "r"); 1616 if (f == NULL) 1617 return (DEFTYPE); 1618 1619 /* split off end of name */ 1620 TtyId = ttyid; 1621 while (*ttyid) 1622 if (*ttyid++ == '/') 1623 TtyId = ttyid; 1624 1625 /* scan the file */ 1626 while (fgets(typebuf, sizeof typebuf, f) != NULL) 1627 { 1628 p = PortType = typebuf; 1629 while (*p && isalnum(*p)) 1630 p++; 1631 *p++ = NULL; 1632 1633 /* skip separator */ 1634 while (*p && !isalnum(*p)) 1635 p++; 1636 1637 PortName = p; 1638 /* put NULL at end of name */ 1639 while (*p && isalnum(*p)) 1640 p++; 1641 *p = NULL; 1642 1643 /* check match on port name */ 1644 if (sequal(PortName, TtyId)) /* found it */ 1645 { 1646 fclose (f); 1647 /* get aliases from termcap entry */ 1648 if (Mapped && tgetent(Capbuf, PortType) > 0) { 1649 makealias(Capbuf); 1650 if (sequal(Alias[0], PortType) && Alias[1]) 1651 PortType = Alias[1]; 1652 } 1653 return(PortType); 1654 } 1655 } 1656 fclose (f); 1657 return (DEFTYPE); 1658 } 1659 # endif 1660 1661 /* 1662 * routine to output the string for the environment TERMCAP variable 1663 */ 1664 #define WHITE(c) (c == ' ' || c == '\t') 1665 char delcap[128][2]; 1666 int ncap = 0; 1667 1668 wrtermcap(bp) 1669 char *bp; 1670 { 1671 char buf[CAPBUFSIZ]; 1672 register int i; 1673 char *p = buf; 1674 char *tp; 1675 char *putbuf(); 1676 int space, empty; 1677 1678 /* discard names with blanks */ 1679 /** May not be desireable ? **/ 1680 while (*bp && *bp != ':') { 1681 if (*bp == '|') { 1682 tp = bp+1; 1683 space = NO; 1684 while (*tp && *tp != '|' && *tp != ':') { 1685 space = (space || WHITE(*tp) ); 1686 tp++; 1687 } 1688 if (space) { 1689 bp = tp; 1690 continue; 1691 } 1692 } 1693 *p++ = *bp++; 1694 } 1695 /**/ 1696 1697 # ifdef CBVIRTTERM 1698 if (VirTermNo > 0) { 1699 p = putbuf(p, ":am"); /* All virt terms have auto margins */ 1700 cancelled("am"); 1701 } 1702 # endif 1703 while (*bp) { 1704 switch (*bp) { 1705 case ':': /* discard empty, cancelled or dupl fields */ 1706 tp = bp+1; 1707 empty = YES; 1708 while (*tp && *tp != ':') { 1709 empty = (empty && WHITE(*tp) ); 1710 tp++; 1711 } 1712 # ifdef CBVIRTTERM 1713 /* 1714 * Virtual terminals use ic, not im or ei. Turn 1715 * any of them into ic - duplicates will be cancelled 1716 * below. I assume that terminals needing im+ic+ei 1717 * are handled by the kernel. 1718 */ 1719 if (VirTermNo > 0 && !HasAM && 1720 (bp[1]=='i' && bp[2]=='m' || 1721 bp[1]=='e' && bp[2]=='i')) { 1722 bp[1] = 'i'; 1723 bp[2] = 'c'; 1724 } 1725 if (VirTermNo > 0 && !HasAM && 1726 (bp[1]=='c' && bp[2]=='s')) { 1727 bp[1] = 'd'; 1728 bp[2] = 'l'; 1729 /* Also need al, so kludge: */ 1730 if (!cancelled("al")) 1731 p = putbuf(p, ":al=\033\120"); 1732 } 1733 # endif CBVIRTTERM 1734 if (empty || cancelled(bp+1)) { 1735 bp = tp; 1736 continue; 1737 } 1738 # ifdef CBVIRTTERM 1739 if (VirTermNo > 0 && !HasAM) 1740 for (i = 0; vtab[i].value; i++) { 1741 if (vtab[i].cap[0] == bp[1] && 1742 vtab[i].cap[1] == bp[2]) { 1743 *p++ = *bp++; /* colon */ 1744 *p++ = *bp++; /* first char */ 1745 *p++ = *bp++; /* second " */ 1746 *p++ = *bp++; /* = sign */ 1747 p = putbuf(p, vtab[i].value); 1748 bp = tp; 1749 goto contin; 1750 } 1751 } 1752 # endif CBVIRTTERM 1753 break; 1754 1755 case ' ': /* no spaces in output */ 1756 p = putbuf(p, "\\040"); 1757 bp++; 1758 continue; 1759 1760 case '!': /* the shell thinks this is history */ 1761 p = putbuf(p, "\\041"); 1762 bp++; 1763 continue; 1764 1765 case ',': /* the shell thinks this is history */ 1766 p = putbuf(p, "\\054"); 1767 bp++; 1768 continue; 1769 1770 case '"': /* no quotes in output */ 1771 p = putbuf(p, "\\042"); 1772 bp++; 1773 continue; 1774 1775 case '\'': /* no quotes in output */ 1776 p = putbuf(p, "\\047"); 1777 bp++; 1778 continue; 1779 1780 case '`': /* no back quotes in output */ 1781 p = putbuf(p, "\\140"); 1782 bp++; 1783 continue; 1784 1785 case '\\': 1786 case '^': /* anything following is OK */ 1787 *p++ = *bp++; 1788 # ifdef CBVIRTTERM 1789 if (*bp == 'E' && VirTermNo > 0 && 1790 (bp[-3]!='\\'||bp[-2]!='E') && 1791 (bp[1]!='\\'||bp[2]!='E')) 1792 p = putbuf(p, "E\\"); 1793 # endif CBVIRTTERM 1794 } 1795 *p++ = *bp++; 1796 contin: ; 1797 } 1798 *p++ = ':'; /* we skipped the last : with the : lookahead hack */ 1799 write (STDOUT, buf, p-buf); 1800 } 1801 1802 cancelled(cap) 1803 char *cap; 1804 { 1805 register int i; 1806 1807 for (i = 0; i < ncap; i++) 1808 { 1809 if (cap[0] == delcap[i][0] && cap[1] == delcap[i][1]) 1810 return (YES); 1811 } 1812 /* delete a second occurrance of the same capability */ 1813 delcap[ncap][0] = cap[0]; 1814 delcap[ncap][1] = cap[1]; 1815 ncap++; 1816 return (cap[2] == '@'); 1817 } 1818 1819 char * 1820 putbuf(ptr, str) 1821 char *ptr; 1822 char *str; 1823 { 1824 char buf[20]; 1825 1826 while (*str) { 1827 switch (*str) { 1828 case '\033': 1829 ptr = putbuf(ptr, "\\E"); 1830 str++; 1831 break; 1832 default: 1833 if (*str <= ' ') { 1834 sprintf(buf, "\\%03o", *str); 1835 ptr = putbuf(ptr, buf); 1836 str++; 1837 } else 1838 *ptr++ = *str++; 1839 } 1840 } 1841 return (ptr); 1842 } 1843 1844 1845 baudrate(p) 1846 char *p; 1847 { 1848 char buf[8]; 1849 int i = 0; 1850 1851 while (i < 7 && (isalnum(*p) || *p == '.')) 1852 buf[i++] = *p++; 1853 buf[i] = NULL; 1854 for (i=0; speeds[i].string; i++) 1855 if (sequal(speeds[i].string, buf)) 1856 return (speeds[i].speed); 1857 return (-1); 1858 } 1859 1860 char * 1861 mapped(type) 1862 char *type; 1863 { 1864 # ifdef V6 1865 extern int ospeed; 1866 # else 1867 extern short ospeed; 1868 # endif 1869 int match; 1870 1871 # ifdef DEB 1872 printf ("spd:%d\n", ospeed); 1873 prmap(); 1874 # endif 1875 Map = map; 1876 while (Map->Ident) 1877 { 1878 if (*(Map->Ident) == NULL || sequal(Map->Ident, type) || isalias(Map->Ident)) 1879 { 1880 match = NO; 1881 switch (Map->Test) 1882 { 1883 case ANY: /* no test specified */ 1884 case ALL: 1885 match = YES; 1886 break; 1887 1888 case GT: 1889 match = (ospeed > Map->Speed); 1890 break; 1891 1892 case GE: 1893 match = (ospeed >= Map->Speed); 1894 break; 1895 1896 case EQ: 1897 match = (ospeed == Map->Speed); 1898 break; 1899 1900 case LE: 1901 match = (ospeed <= Map->Speed); 1902 break; 1903 1904 case LT: 1905 match = (ospeed < Map->Speed); 1906 break; 1907 1908 case NE: 1909 match = (ospeed != Map->Speed); 1910 break; 1911 } 1912 if (match) 1913 return (Map->Type); 1914 } 1915 Map++; 1916 } 1917 /* no match found; return given type */ 1918 return (type); 1919 } 1920 1921 # ifdef DEB 1922 prmap() 1923 { 1924 Map = map; 1925 while (Map->Ident) 1926 { 1927 printf ("%s t:%d s:%d %s\n", 1928 Map->Ident, Map->Test, Map->Speed, Map->Type); 1929 Map++; 1930 } 1931 } 1932 # endif 1933 1934 char * 1935 nextarg(argc, argv) 1936 int argc; 1937 char *argv[]; 1938 { 1939 if (argc <= 0) 1940 fatal ("Too few args: ", *argv); 1941 if (*(*++argv) == '-') 1942 fatal ("Unexpected arg: ", *argv); 1943 return (*argv); 1944 } 1945 1946 fatal (mesg, obj) 1947 char *mesg; 1948 char *obj; 1949 { 1950 prs (mesg); 1951 prs (obj); 1952 prc ('\n'); 1953 prs (USAGE); 1954 flush(); 1955 exit(1); 1956 } 1957