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