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