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: #if !defined(lint) && defined(DOSCCS) 8: char copyright[] = 9: "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 10: All rights reserved.\n"; 11: 12: static char sccsid[] = "@(#)tset.c 5.8.2 (2.11BSD GTE) 1997/3/28"; 13: #endif 14: 15: /* 16: ** TSET -- set terminal modes 17: ** 18: ** This program does sophisticated terminal initialization. 19: ** I recommend that you include it in your .profile or .login 20: ** file to initialize whatever terminal you are on. 21: ** 22: ** There are several features: 23: ** 24: ** A special file or sequence (as controlled by the termcap file) 25: ** is sent to the terminal. 26: ** 27: ** Mode bits are set on a per-terminal_type basis (much better 28: ** than UNIX itself). This allows special delays, automatic 29: ** tabs, etc. 30: ** 31: ** Erase and Kill characters can be set to whatever you want. 32: ** Default is to change erase to control-H on a terminal which 33: ** can overstrike, and leave it alone on anything else. Kill 34: ** is always left alone unless specifically requested. These 35: ** characters can be represented as "^X" meaning control-X; 36: ** X is any character. 37: ** 38: ** Terminals which are dialups or plugboard types can be aliased 39: ** to whatever type you may have in your home or office. Thus, 40: ** if you know that when you dial up you will always be on a 41: ** TI 733, you can specify that fact to tset. You can represent 42: ** a type as "?type". This will ask you what type you want it 43: ** to be -- if you reply with just a newline, it will default 44: ** to the type given. 45: ** 46: ** The current terminal type can be queried. 47: ** 48: ** Usage: 49: ** tset [-] [-eC] [-kC] [-iC] [-s] [-r] 50: ** [-m [ident] [test baudrate] :type] 51: ** [-Q] [-I] [-S] [type] 52: ** 53: ** In systems with environments, use: 54: ** eval `tset -s ...` 55: ** Actually, this doesn't work in old csh's. 56: ** Instead, use: 57: ** tset -s ... > tset.tmp 58: ** source tset.tmp 59: ** rm tset.tmp 60: ** or: 61: ** set noglob 62: ** set term=(`tset -S ....`) 63: ** setenv TERM $term[1] 64: ** setenv TERMCAP "$term[2]" 65: ** unset term 66: ** unset noglob 67: ** 68: ** Positional Parameters: 69: ** type -- the terminal type to force. If this is 70: ** specified, initialization is for this 71: ** terminal type. 72: ** 73: ** Flags: 74: ** - -- report terminal type. Whatever type is 75: ** decided on is reported. If no other flags 76: ** are stated, the only affect is to write 77: ** the terminal type on the standard output. 78: ** -r -- report to user in addition to other flags. 79: ** -eC -- set the erase character to C on all terminals. 80: ** C defaults to control-H. If not specified, 81: ** the erase character is untouched; however, if 82: ** not specified and the erase character is NULL 83: ** (zero byte), the erase character is set to delete. 84: ** -kC -- set the kill character to C on all terminals. 85: ** Default for C is control-X. If not specified, 86: ** the kill character is untouched; however, if 87: ** not specified and the kill character is NULL 88: ** (zero byte), the kill character is set to control-U. 89: ** -iC -- set the interrupt character to C on all terminals. 90: ** Default for C is control-C. If not specified, the 91: ** interrupt character is untouched; however, if 92: ** not specified and the interrupt character is NULL 93: ** (zero byte), the interrupt character is set to 94: ** control-C. 95: ** -qC -- reserved for setable quit character. 96: ** -m -- map the system identified type to some user 97: ** specified type. The mapping can be baud rate 98: ** dependent. 99: ** Syntax: -m identifier [test baudrate] :type 100: ** where: ``identifier'' is terminal type found in 101: ** /etc/ttys for this port, (abscence of an identifier 102: ** matches any identifier); ``test'' may be any combination 103: ** of > = < ! @; ``baudrate'' is as with stty(1); 104: ** ``type'' is the actual terminal type to use if the 105: ** mapping condition is met. Multiple maps are scanned 106: ** in order and the first match prevails. 107: ** -n -- If the new tty driver from UCB is available, this flag 108: ** will activate the new options for erase and kill 109: ** processing. This will be different for printers 110: ** and crt's. For crts, if the baud rate is < 1200 then 111: ** erase and kill don't remove characters from the screen. 112: ** -s -- output setenv commands for TERM. This can be 113: ** used with 114: ** `tset -s ...` 115: ** and is to be prefered to: 116: ** setenv TERM `tset - ...` 117: ** because -s sets the TERMCAP variable also. 118: ** -S -- Similar to -s but outputs 2 strings suitable for 119: ** use in csh .login files as follows: 120: ** set noglob 121: ** set term=(`tset -S .....`) 122: ** setenv TERM $term[1] 123: ** setenv TERMCAP "$term[2]" 124: ** unset term 125: ** unset noglob 126: ** -Q -- be quiet. don't output 'Erase set to' etc. 127: ** -I -- don't do terminal initialization (is & if 128: ** strings). 129: ** 130: ** Files: 131: ** /etc/ttys 132: ** contains a terminal id -> terminal type 133: ** mapping; used when any user mapping is specified, 134: ** or the environment doesn't have TERM set. 135: ** /etc/termcap 136: ** a terminal_type -> terminal_capabilities 137: ** mapping. 138: ** 139: ** Return Codes: 140: ** -1 -- couldn't open ttycap. 141: ** 1 -- bad terminal type, or standard output not tty. 142: ** 0 -- ok. 143: ** 144: ** Defined Constants: 145: ** BACKSPACE -- control-H, the default for -e. 146: ** CNTL('X') -- control-X, the default for -k. 147: ** OLDERASE -- the system default erase character. 148: ** OLDKILL -- the system default kill character. 149: ** FILEDES -- the file descriptor to do the operation 150: ** on, nominally 1 or 2. 151: ** 152: ** Requires: 153: ** Routines to handle htmp, ttys, and ttycap. 154: ** 155: ** Trace Flags: 156: ** none 157: ** 158: ** Diagnostics: 159: ** Bad flag 160: ** An incorrect option was specified. 161: ** Too few args 162: ** more command line arguments are required. 163: ** Unexpected arg 164: ** wrong type of argument was encountered. 165: ** Cannot open ... 166: ** The specified file could not be openned. 167: ** Type ... unknown 168: ** An unknown terminal type was specified. 169: ** Cannot update htmp 170: ** Cannot update htmp file when the standard 171: ** output is not a terminal. 172: ** Erase set to ... 173: ** Telling that the erase character has been 174: ** set to the specified character. 175: ** Kill set to ... 176: ** Ditto for kill 177: ** Erase is ... Kill is ... 178: ** Tells that the erase/kill characters were 179: ** wierd before, but they are being left as-is. 180: ** Not a terminal 181: ** Set if FILEDES is not a terminal. 182: ** 183: ** Author: 184: ** Eric Allman 185: ** Electronics Research Labs 186: ** U.C. Berkeley 187: ** 188: ** History: 189: ** 1997/3/28 -- major cleanup. 190: ** 1/81 -- Added alias checking for mapping identifiers. 191: ** 9/80 -- Added UCB_NTTY mods to setup the new tty driver. 192: ** Added the 'reset ...' invocation. 193: ** 7/80 -- '-S' added. '-m' mapping added. TERMCAP string 194: ** cleaned up. 195: ** 3/80 -- Changed to use tputs. Prc & flush added. 196: ** 10/79 -- '-s' option extended to handle TERMCAP 197: ** variable, set noglob, quote the entry, 198: ** and know about the Bourne shell. Terminal 199: ** initialization moved to before any information 200: ** output so screen clears would not screw you. 201: ** '-Q' option added. 202: ** 8/79 -- '-' option alone changed to only output 203: ** type. '-s' option added. 'VERSION7' 204: ** changed to 'V6' for compatibility. 205: ** 12/78 -- modified for eventual migration to VAX/UNIX, 206: ** so the '-' option is changed to output only 207: ** the terminal type to STDOUT instead of 208: ** FILEDES. 209: ** 9/78 -- '-' and '-p' options added (now fully 210: ** compatible with ttytype!), and spaces are 211: ** permitted between the -d and the type. 212: ** 8/78 -- The sense of -h and -u were reversed, and the 213: ** -f flag is dropped -- same effect is available 214: ** by just stating the terminal type. 215: ** 10/77 -- Written. 216: */ 217: 218: #define curerase mode.sg_erase 219: #define curkill mode.sg_kill 220: #define curintr tchar.t_intrc 221: #define olderase oldmode.sg_erase 222: #define oldkill oldmode.sg_kill 223: #define oldintr oldtchar.t_intrc 224: 225: #include <ttyent.h> 226: #include <sgtty.h> 227: #include <stdio.h> 228: #undef putchar 229: #include <errno.h> 230: #include <signal.h> 231: #include <ctype.h> 232: #include <strings.h> 233: #include <stdlib.h> 234: #include <unistd.h> 235: 236: #define YES 1 237: #define NO 0 238: #undef CNTL 239: #define CNTL(c) ((c)&037) 240: #define BACKSPACE (CNTL('H')) 241: #define CHK(val, dft) (val<=0 ? dft : val) 242: #define OLDERASE '#' 243: #define OLDKILL '@' 244: #define OLDINTR '\177' /* del */ 245: 246: /* default special characters */ 247: #ifndef CERASE 248: #define CERASE '\177' 249: #endif 250: #ifndef CKILL 251: #define CKILL CNTL('U') 252: #endif 253: #ifndef CINTR 254: #define CINTR CNTL('C') 255: #endif 256: #ifndef CDSUSP 257: #define CQUIT 034 /* FS, ^\ */ 258: #define CSTART CNTL('Q') 259: #define CSTOP CNTL('S') 260: #define CEOF CNTL('D') 261: #define CEOT CEOF 262: #define CBRK 0377 263: #define CSUSP CNTL('Z') 264: #define CDSUSP CNTL('Y') 265: #define CRPRNT CNTL('R') 266: #define CFLUSH CNTL('O') 267: #define CWERASE CNTL('W') 268: #define CLNEXT CNTL('V') 269: #endif 270: 271: #define FILEDES 2 /* do gtty/stty on this descriptor */ 272: 273: #define USAGE "usage: tset [-] [-nrsIQS] [-eC] [-kC] [-iC] [-m [ident][test speed]:type] [type]\n" 274: 275: #define DIALUP "dialup" 276: #define PLUGBOARD "plugboard" 277: #define ARPANET "arpanet" 278: 279: /* 280: * Baud Rate Conditionals 281: */ 282: #define ANY 0 283: #define GT 1 284: #define EQ 2 285: #define LT 4 286: #define GE (GT|EQ) 287: #define LE (LT|EQ) 288: #define NE (GT|LT) 289: #define ALL (GT|EQ|LT) 290: 291: # define NMAP 10 292: 293: struct map { 294: char *Ident; 295: char Test; 296: char Speed; 297: char *Type; 298: } map[NMAP]; 299: 300: struct map *Map = map; 301: 302: /* This should be available in an include file */ 303: struct 304: { 305: char *string; 306: int speed; 307: int baudrate; 308: } speeds[] = { 309: "0", B0, 0, 310: "50", B50, 50, 311: "75", B75, 75, 312: "110", B110, 110, 313: "134", B134, 134, 314: "134.5",B134, 134, 315: "150", B150, 150, 316: "200", B200, 200, 317: "300", B300, 300, 318: "600", B600, 600, 319: "1200", B1200, 1200, 320: "1800", B1800, 1800, 321: "2400", B2400, 2400, 322: "4800", B4800, 4800, 323: "9600", B9600, 9600, 324: "19200",EXTA, 19200, 325: "exta", EXTA, 19200, 326: "extb", EXTB, 38400, 327: 0, 328: }; 329: 330: char Erase_char; /* new erase character */ 331: char Kill_char; /* new kill character */ 332: char Intr_char; /* new interrupt character */ 333: 334: char *TtyType; /* type of terminal */ 335: char *DefType; /* default type if none other computed */ 336: char *NewType; /* mapping identifier based on old flags */ 337: int DoSetenv; /* output setenv commands */ 338: int BeQuiet; /* be quiet */ 339: int NoInit; /* don't output initialization string */ 340: int IsReset; /* invoked as reset */ 341: int Report; /* report current type */ 342: int Ureport; /* report to user */ 343: int RepOnly; /* report only */ 344: int CmndLine; /* output full command lines (-s option) */ 345: int Ask; /* ask user for termtype */ 346: int PadBaud; /* Min rate of padding needed */ 347: int lines, columns; 348: short ospeed; 349: 350: #define CAPBUFSIZ 1024 351: char Capbuf[CAPBUFSIZ]; /* line from /etc/termcap for this TtyType */ 352: char *Ttycap; /* termcap line from termcap or environ */ 353: char *askuser(); 354: 355: struct sgttyb mode; 356: struct sgttyb oldmode; 357: struct tchars tchar; 358: struct tchars oldtchar; 359: int prc(); 360: void wrtermcap(); 361: 362: extern char *tgetstr(); 363: 364: main(argc, argv) 365: int argc; 366: char *argv[]; 367: { 368: char buf[CAPBUFSIZ]; 369: char termbuf[32]; 370: char *bufp, *ttypath; 371: register char *p; 372: char *command; 373: register int i; 374: int Break; 375: int Not; 376: char *nextarg(); 377: char *mapped(); 378: struct winsize win; 379: char bs_char; 380: int csh; 381: int settle; 382: int setmode(); 383: extern char PC; 384: int lmode; 385: int ldisc; 386: struct ttyent *t; 387: 388: (void) ioctl(FILEDES, TIOCLGET, (char *)&lmode); 389: (void) ioctl(FILEDES, TIOCGETD, (char *)&ldisc); 390: 391: if (gtty(FILEDES, &mode) < 0) 392: { 393: prs("Not a terminal\n"); 394: exit(1); 395: } 396: bcopy((char *)&mode, (char *)&oldmode, sizeof mode); 397: (void) ioctl(FILEDES, TIOCGETC, (char *)&tchar); 398: bcopy((char *)&tchar, (char *)&oldtchar, sizeof tchar); 399: ospeed = mode.sg_ospeed & 017; 400: (void) signal(SIGINT, setmode); 401: (void) signal(SIGQUIT, setmode); 402: (void) signal(SIGTERM, setmode); 403: 404: if (command = rindex(argv[0], '/')) 405: command++; 406: else 407: command = argv[0]; 408: if (!strcmp(command, "reset") ) 409: { 410: /* 411: * reset the teletype mode bits to a sensible state. 412: * Copied from the program by Kurt Shoens & Mark Horton. 413: * Very useful after crapping out in raw. 414: */ 415: struct ltchars ltc; 416: 417: if (ldisc == NTTYDISC) 418: { 419: (void) ioctl(FILEDES, TIOCGLTC, (char *)<c); 420: ltc.t_suspc = CHK(ltc.t_suspc, CSUSP); 421: ltc.t_dsuspc = CHK(ltc.t_dsuspc, CDSUSP); 422: ltc.t_rprntc = CHK(ltc.t_rprntc, CRPRNT); 423: ltc.t_flushc = CHK(ltc.t_flushc, CFLUSH); 424: ltc.t_werasc = CHK(ltc.t_werasc, CWERASE); 425: ltc.t_lnextc = CHK(ltc.t_lnextc, CLNEXT); 426: (void) ioctl(FILEDES, TIOCSLTC, (char *)<c); 427: } 428: tchar.t_intrc = CHK(tchar.t_intrc, CINTR); 429: tchar.t_quitc = CHK(tchar.t_quitc, CQUIT); 430: tchar.t_startc = CHK(tchar.t_startc, CSTART); 431: tchar.t_stopc = CHK(tchar.t_stopc, CSTOP); 432: tchar.t_eofc = CHK(tchar.t_eofc, CEOF); 433: /* brkc is left alone */ 434: (void) ioctl(FILEDES, TIOCSETC, (char *)&tchar); 435: mode.sg_flags &= ~(RAW | CBREAK); 436: mode.sg_flags |= XTABS|ECHO|CRMOD|ANYP; 437: curerase = CHK(curerase, CERASE); 438: curkill = CHK(curkill, CKILL); 439: curintr = CHK(curintr, CINTR); 440: BeQuiet = YES; 441: IsReset = YES; 442: } 443: else if (argc == 2 && !strcmp(argv[1], "-")) 444: RepOnly = YES; 445: 446: argc--; 447: 448: /* scan argument list and collect flags */ 449: while (--argc >= 0) 450: { 451: p = *++argv; 452: if (*p == '-') 453: { 454: if (*++p == NULL) 455: Report = YES; /* report current terminal type */ 456: else while (*p) switch (*p++) 457: { 458: case 'n': 459: ldisc = NTTYDISC; 460: if (ioctl(FILEDES, TIOCSETD, (char *)&ldisc)<0) 461: fatal("ioctl ", "new"); 462: continue; 463: case 'r': /* report to user */ 464: Ureport = YES; 465: continue; 466: case 'e': /* erase character */ 467: if (*p == NULL) 468: Erase_char = -1; 469: else 470: { 471: if (*p == '^' && p[1] != NULL) 472: if (*++p == '?') 473: Erase_char = '\177'; 474: else 475: Erase_char = CNTL(*p); 476: else 477: Erase_char = *p; 478: p++; 479: } 480: continue; 481: case 'i': /* interrupt character */ 482: if (*p == NULL) 483: Intr_char = CNTL('C'); 484: else 485: { 486: if (*p == '^' && p[1] != NULL) 487: if (*++p == '?') 488: Intr_char = '\177'; 489: else 490: Intr_char = CNTL(*p); 491: else 492: Intr_char = *p; 493: p++; 494: } 495: continue; 496: case 'k': /* kill character */ 497: if (*p == NULL) 498: Kill_char = CNTL('X'); 499: else 500: { 501: if (*p == '^' && p[1] != NULL) 502: if (*++p == '?') 503: Kill_char = '\177'; 504: else 505: Kill_char = CNTL(*p); 506: else 507: Kill_char = *p; 508: p++; 509: } 510: continue; 511: case 'd': /* dialup type */ 512: NewType = DIALUP; 513: goto mapold; 514: case 'p': /* plugboard type */ 515: NewType = PLUGBOARD; 516: goto mapold; 517: case 'a': /* arpanet type */ 518: NewType = ARPANET; 519: mapold: Map->Ident = NewType; 520: Map->Test = ALL; 521: if (*p == NULL) 522: p = nextarg(argc--, argv++); 523: Map->Type = p; 524: Map++; 525: p = ""; 526: continue; 527: case 'm': /* map identifier to type */ 528: /* This code is very loose. Almost no 529: ** syntax checking is done!! However, 530: ** illegal syntax will only produce 531: ** weird results. 532: */ 533: if (*p == NULL) 534: { 535: p = nextarg(argc--, argv++); 536: } 537: if (isalnum(*p)) 538: { 539: Map->Ident = p; /* identifier */ 540: while (isalnum(*p)) p++; 541: } 542: else 543: Map->Ident = ""; 544: Break = NO; 545: Not = NO; 546: while (!Break) switch (*p) 547: { 548: case NULL: 549: p = nextarg(argc--, argv++); 550: continue; 551: 552: case ':': /* mapped type */ 553: *p++ = NULL; 554: Break = YES; 555: continue; 556: 557: case '>': /* conditional */ 558: Map->Test |= GT; 559: *p++ = NULL; 560: continue; 561: 562: case '<': /* conditional */ 563: Map->Test |= LT; 564: *p++ = NULL; 565: continue; 566: 567: case '=': /* conditional */ 568: case '@': 569: Map->Test |= EQ; 570: *p++ = NULL; 571: continue; 572: 573: case '!': /* invert conditions */ 574: Not = ~Not; 575: *p++ = NULL; 576: continue; 577: 578: case 'B': /* Baud rate */ 579: p++; 580: /* intentional fallthru */ 581: default: 582: if (isdigit(*p) || *p == 'e') 583: { 584: Map->Speed = baudrate(p); 585: while (isalnum(*p) || *p == '.') 586: p++; 587: } 588: else 589: Break = YES; 590: continue; 591: } 592: if (Not) /* invert sense of test */ 593: { 594: Map->Test = (~(Map->Test))&ALL; 595: } 596: if (*p == NULL) 597: { 598: p = nextarg(argc--, argv++); 599: } 600: Map->Type = p; 601: p = ""; 602: Map++; 603: continue; 604: case 's': /* output setenv commands */ 605: DoSetenv = YES; 606: CmndLine = YES; 607: continue; 608: case 'S': /* output setenv strings */ 609: DoSetenv = YES; 610: CmndLine = NO; 611: continue; 612: case 'Q': /* be quiet */ 613: BeQuiet = YES; 614: continue; 615: case 'I': /* no initialization */ 616: NoInit = YES; 617: continue; 618: default: 619: *p-- = NULL; 620: fatal("Bad flag -", p); 621: } 622: } 623: else 624: DefType = p; /* terminal type */ 625: } 626: 627: if (DefType) 628: { 629: Map->Ident = ""; /* means "map any type" */ 630: Map->Test = ALL; /* at all baud rates */ 631: Map->Type = DefType; /* to the default type */ 632: } 633: 634: /* 635: * Get rid of $TERMCAP, if it's there, so we get a real 636: * entry from /etc/termcap. This prevents us from being 637: * fooled by out of date stuff in the environment. 638: */ 639: unsetenv("TERMCAP"); 640: /* get current idea of terminal type from environment */ 641: if (TtyType) 642: goto found; 643: if (TtyType = getenv("TERM")) 644: goto map; 645: 646: /* Try ttyname(3) if type is current unknown */ 647: if (TtyType == 0) 648: { 649: if (ttypath = ttyname(FILEDES)) 650: { 651: if (p = rindex(ttypath, '/')) 652: ++p; 653: else 654: p = ttypath; 655: if ((t = getttynam(p))) 656: TtyType = t->ty_type; 657: } 658: } 659: /* If still undefined, use "unknown" */ 660: if (TtyType == 0) 661: TtyType = "unknown"; 662: 663: /* check for dialup or other mapping */ 664: map: 665: TtyType = mapped(TtyType); 666: 667: /* TtyType now contains a pointer to the type of the terminal */ 668: /* If the first character is '?', ask the user */ 669: found: 670: if (TtyType[0] == '?') 671: { 672: if (TtyType[1] != '\0') 673: TtyType = askuser(TtyType + 1); 674: else 675: TtyType = askuser(NULL); 676: } 677: 678: /* Find the termcap entry. If it doesn't exist, ask the user. */ 679: while ((i = tgetent(Capbuf, TtyType)) == 0) 680: { 681: (void)fprintf(stderr, "tset: terminal type %s is unknown\n", 682: TtyType); 683: TtyType = askuser(NULL); 684: } 685: if (i == -1) 686: fatal("termcap", strerror(errno ? errno : ENOENT)); 687: 688: Ttycap = Capbuf; 689: 690: if (!RepOnly) 691: { 692: /* determine erase and kill characters */ 693: bufp = buf; 694: p = tgetstr("kb", &bufp); 695: if (p == NULL || p[1] != '\0') 696: p = tgetstr("bc", &bufp); 697: if (p != NULL && p[1] == '\0') 698: bs_char = p[0]; 699: else if (tgetflag("bs")) 700: bs_char = BACKSPACE; 701: else 702: bs_char = 0; 703: if (Erase_char == 0 && !tgetflag("os") && curerase == OLDERASE) 704: { 705: if (tgetflag("bs") || bs_char != 0) 706: Erase_char = -1; 707: } 708: if (Erase_char < 0) 709: Erase_char = (bs_char != 0) ? bs_char : BACKSPACE; 710: 711: if (curerase == 0) 712: curerase = CERASE; 713: if (Erase_char != 0) 714: curerase = Erase_char; 715: 716: if (curintr == 0) 717: curintr = CINTR; 718: if (Intr_char != 0) 719: curintr = Intr_char; 720: 721: if (curkill == 0) 722: curkill = CKILL; 723: if (Kill_char != 0) 724: curkill = Kill_char; 725: 726: /* set modes */ 727: PadBaud = tgetnum("pb"); /* OK if fails */ 728: for (i=0; speeds[i].string; i++) 729: if (speeds[i].baudrate == PadBaud) { 730: PadBaud = speeds[i].speed; 731: break; 732: } 733: mode.sg_flags &= ~(EVENP | ODDP | RAW | CBREAK); 734: if (tgetflag("EP")) 735: mode.sg_flags |= EVENP; 736: if (tgetflag("OP")) 737: mode.sg_flags |= ODDP; 738: if ((mode.sg_flags & (EVENP | ODDP)) == 0) 739: mode.sg_flags |= EVENP | ODDP; 740: mode.sg_flags |= CRMOD | ECHO | XTABS; 741: if (tgetflag("NL")) /* new line, not line feed */ 742: mode.sg_flags &= ~CRMOD; 743: if (tgetflag("HD")) /* half duplex */ 744: mode.sg_flags &= ~ECHO; 745: if (tgetflag("pt")) /* print tabs */ 746: mode.sg_flags &= ~XTABS; 747: if (ldisc == NTTYDISC) 748: { 749: lmode |= LCTLECH; /* display ctrl chars */ 750: if (tgetflag("hc")) 751: { /** set printer modes **/ 752: lmode &= ~(LCRTBS|LCRTERA|LCRTKIL); 753: lmode |= LPRTERA; 754: } 755: else 756: { /** set crt modes **/ 757: if (!tgetflag("os")) 758: { 759: lmode &= ~LPRTERA; 760: lmode |= LCRTBS; 761: if (mode.sg_ospeed >= B1200) 762: lmode |= LCRTERA|LCRTKIL; 763: } 764: } 765: } 766: if (IsReset) 767: lmode &= ~(LMDMBUF|LLITOUT|LPASS8); 768: (void) ioctl(FILEDES, TIOCLSET, (char *)&lmode); 769: 770: /* get pad character */ 771: bufp = buf; 772: if (tgetstr("pc", &bufp) != 0) 773: PC = buf[0]; 774: 775: columns = tgetnum("co"); 776: lines = tgetnum("li"); 777: 778: /* Set window size */ 779: (void) ioctl(FILEDES, TIOCGWINSZ, (char *)&win); 780: if (win.ws_row == 0 && win.ws_col == 0 && 781: lines > 0 && columns > 0) { 782: win.ws_row = lines; 783: win.ws_col = columns; 784: (void) ioctl(FILEDES, TIOCSWINSZ, (char *)&win); 785: } 786: /* output startup string */ 787: if (!NoInit) 788: { 789: if (oldmode.sg_flags&(XTABS|CRMOD)) 790: { 791: oldmode.sg_flags &= ~(XTABS|CRMOD); 792: setmode(-1); 793: } 794: if (settabs()) { 795: settle = YES; 796: flush(); 797: } 798: bufp = buf; 799: if (IsReset && tgetstr("rs", &bufp) != 0 || 800: tgetstr("is", &bufp) != 0) 801: { 802: tputs(buf, 0, prc); 803: settle = YES; 804: flush(); 805: } 806: bufp = buf; 807: if (IsReset && tgetstr("rf", &bufp) != 0 || 808: tgetstr("if", &bufp) != 0) 809: { 810: cat(buf); 811: settle = YES; 812: } 813: if (settle) 814: { 815: prc('\r'); 816: flush(); 817: sleep(1); /* let terminal settle down */ 818: } 819: } 820: 821: setmode(0); /* set new modes, if they've changed */ 822: 823: /* set up environment for the shell we are using */ 824: /* (this code is rather heuristic, checking for $SHELL */ 825: /* ending in the 3 characters "csh") */ 826: csh = NO; 827: if (DoSetenv) 828: { 829: char *sh; 830: 831: if ((sh = getenv("SHELL")) && (i = strlen(sh)) >= 3) 832: { 833: if ((csh = !strcmp(&sh[i-3], "csh")) && CmndLine) 834: (void) puts("set noglob;"); 835: } 836: if (!csh) 837: /* running Bourne shell */ 838: (void) puts("export TERMCAP TERM;"); 839: } 840: } 841: 842: /* report type if appropriate */ 843: if (DoSetenv || Report || Ureport) 844: { 845: /* 846: * GET THE TERMINAL TYPE (second name in termcap entry) 847: * See line 182 of 4.4's tset/tset.c 848: */ 849: if (DoSetenv) 850: { 851: if (csh) 852: { 853: if (CmndLine) 854: (void) printf("%s", "setenv TERM "); 855: (void) printf("%s ", TtyType); 856: if (CmndLine) 857: (void) puts(";"); 858: } 859: else 860: (void) printf("TERM=%s;\n", TtyType); 861: } 862: else if (Report) 863: (void) puts(TtyType); 864: if (Ureport) 865: { 866: prs("Terminal type is "); 867: prs(TtyType); 868: prs("\n"); 869: flush(); 870: } 871: 872: if (DoSetenv) 873: { 874: if (csh) 875: { 876: if (CmndLine) 877: (void) printf("setenv TERMCAP '"); 878: } 879: else 880: (void) printf("TERMCAP='"); 881: wrtermcap(Ttycap); 882: if (csh) 883: { 884: if (CmndLine) 885: { 886: (void) puts("';"); 887: (void) puts("unset noglob;"); 888: } 889: } 890: else 891: (void) puts("';"); 892: } 893: } 894: 895: if (RepOnly) 896: exit(0); 897: 898: /* tell about changing erase, kill and interrupt characters */ 899: reportek("Erase", curerase, olderase, OLDERASE); 900: reportek("Kill", curkill, oldkill, OLDKILL); 901: reportek("Interrupt", curintr, oldintr, OLDINTR); 902: exit(0); 903: } 904: 905: /* 906: * Set the hardware tabs on the terminal, using the ct (clear all tabs), 907: * st (set one tab) and ch (horizontal cursor addressing) capabilities. 908: * This is done before if and is, so they can patch in case we blow this. 909: */ 910: settabs() 911: { 912: char caps[100]; 913: char *capsp = caps; 914: char *clear_tabs, *set_tab, *set_column, *set_pos; 915: char *tg_out, *tgoto(); 916: int c; 917: 918: clear_tabs = tgetstr("ct", &capsp); 919: set_tab = tgetstr("st", &capsp); 920: set_column = tgetstr("ch", &capsp); 921: if (set_column == 0) 922: set_pos = tgetstr("cm", &capsp); 923: 924: if (clear_tabs && set_tab) { 925: prc('\r'); /* force to be at left margin */ 926: tputs(clear_tabs, 0, prc); 927: } 928: if (set_tab) { 929: for (c=8; c<columns; c += 8) { 930: /* get to that column. */ 931: tg_out = "OOPS"; /* also returned by tgoto */ 932: if (set_column) 933: tg_out = tgoto(set_column, 0, c); 934: if (*tg_out == 'O' && set_pos) 935: tg_out = tgoto(set_pos, c, lines-1); 936: if (*tg_out != 'O') 937: tputs(tg_out, 1, prc); 938: else 939: prs(" "); 940: /* set the tab */ 941: tputs(set_tab, 0, prc); 942: } 943: prc('\r'); 944: return 1; 945: } 946: return 0; 947: } 948: 949: setmode(flag) 950: int flag; 951: /* flag serves several purposes: 952: * if called as the result of a signal, flag will be > 0. 953: * if called from terminal init, flag == -1 means reset "oldmode". 954: * called with flag == 0 at end of normal mode processing. 955: */ 956: { 957: struct sgttyb *ttymode; 958: struct tchars *ttytchars; 959: 960: if (flag < 0) { /* unconditionally reset oldmode (called from init) */ 961: ttymode = &oldmode; 962: ttytchars = &oldtchar; 963: } else if (bcmp((char *)&mode, (char *)&oldmode, sizeof mode)) { 964: ttymode = &mode; 965: ttytchars = &tchar; 966: } else { /* don't need it */ 967: ttymode = (struct sgttyb *)0; 968: ttytchars = (struct tchars *)0; 969: } 970: 971: if (ttymode) 972: (void) ioctl(FILEDES, TIOCSETN, (char *)ttymode); 973: if (ttytchars) 974: (void) ioctl(FILEDES, TIOCSETC, (char *)ttytchars); 975: if (flag > 0) /* trapped signal */ 976: exit(1); 977: } 978: 979: reportek(name, new, old, def) 980: char *name; 981: char old; 982: char new; 983: char def; 984: { 985: register char o; 986: register char n; 987: register char *p; 988: char buf[32]; 989: char *bufp; 990: 991: if (BeQuiet) 992: return; 993: o = old; 994: n = new; 995: 996: if (o == n && n == def) 997: return; 998: prs(name); 999: if (o == n) 1000: prs(" is "); 1001: else 1002: prs(" set to "); 1003: bufp = buf; 1004: if (tgetstr("kb", &bufp) > 0 && n == buf[0] && buf[1] == NULL) 1005: prs("Backspace\n"); 1006: else if (n == 0177) 1007: prs("Delete\n"); 1008: else 1009: { 1010: if (n < 040) 1011: { 1012: prs("Ctrl-"); 1013: n ^= 0100; 1014: } 1015: p = "x\n"; 1016: p[0] = n; 1017: prs(p); 1018: } 1019: flush(); 1020: } 1021: 1022: prs(s) 1023: register char *s; 1024: { 1025: while (*s != '\0') 1026: prc(*s++); 1027: } 1028: 1029: 1030: prc(c) 1031: char c; 1032: { 1033: putc(c, stderr); 1034: } 1035: 1036: flush() 1037: { 1038: fflush(stderr); 1039: } 1040: 1041: 1042: cat(file) 1043: char *file; 1044: { 1045: register int fd; 1046: register int i; 1047: char buf[BUFSIZ]; 1048: 1049: fd = open(file, 0); 1050: if (fd < 0) 1051: { 1052: prs("Cannot open "); 1053: prs(file); 1054: prs("\n"); 1055: flush(); 1056: return; 1057: } 1058: 1059: while ((i = read(fd, buf, BUFSIZ)) > 0) 1060: (void) write(FILEDES, buf, i); 1061: 1062: (void) close(fd); 1063: } 1064: 1065: /* 1066: * routine to output the string for the environment TERMCAP variable 1067: */ 1068: 1069: void 1070: wrtermcap(bp) 1071: char *bp; 1072: { 1073: register int ch; 1074: register char *p; 1075: char *t, *sep; 1076: 1077: /* Find the end of the terminal names. */ 1078: if ((t = index(bp, ':')) == NULL) 1079: fatal("termcap names not colon terminated", ""); 1080: *t++ = '\0'; 1081: 1082: /* Output terminal names that don't have whitespace. */ 1083: sep = ""; 1084: while ((p = strsep(&bp, "|")) != NULL) 1085: if (*p != '\0' && strpbrk(p, " \t") == NULL) { 1086: (void)printf("%s%s", sep, p); 1087: sep = "|"; 1088: } 1089: (void)putchar(':'); 1090: 1091: /* 1092: * Output fields, transforming any dangerous characters. Skip 1093: * empty fields or fields containing only whitespace. 1094: */ 1095: while ((p = strsep(&t, ":")) != NULL) { 1096: while ((ch = *p) != '\0' && isspace(ch)) 1097: ++p; 1098: if (ch == '\0') 1099: continue; 1100: while ((ch = *p++) != '\0') 1101: switch(ch) { 1102: case '\033': 1103: (void)printf("\\E"); 1104: case ' ': /* No spaces. */ 1105: (void)printf("\\040"); 1106: break; 1107: case '!': /* No csh history chars. */ 1108: (void)printf("\\041"); 1109: break; 1110: case ',': /* No csh history chars. */ 1111: (void)printf("\\054"); 1112: break; 1113: case '"': /* No quotes. */ 1114: (void)printf("\\042"); 1115: break; 1116: case '\'': /* No quotes. */ 1117: (void)printf("\\047"); 1118: break; 1119: case '`': /* No quotes. */ 1120: (void)printf("\\140"); 1121: break; 1122: case '\\': /* Anything following is OK. */ 1123: case '^': 1124: (void)putchar(ch); 1125: if ((ch = *p++) == '\0') 1126: break; 1127: /* FALLTHROUGH */ 1128: default: 1129: (void)putchar(ch); 1130: } 1131: (void)putchar(':'); 1132: } 1133: } 1134: 1135: baudrate(p) 1136: char *p; 1137: { 1138: char buf[8]; 1139: int i = 0; 1140: 1141: while (i < 7 && (isalnum(*p) || *p == '.')) 1142: buf[i++] = *p++; 1143: buf[i] = NULL; 1144: for (i=0; speeds[i].string; i++) 1145: if (!strcmp(speeds[i].string, buf)) 1146: return (speeds[i].speed); 1147: return (-1); 1148: } 1149: 1150: char * 1151: mapped(type) 1152: char *type; 1153: { 1154: int match; 1155: 1156: # ifdef DEB 1157: printf ("spd:%d\n", ospeed); 1158: prmap(); 1159: # endif 1160: Map = map; 1161: while (Map->Ident) 1162: { 1163: if (*(Map->Ident) == NULL || !strcmp(Map->Ident, type)) 1164: { 1165: match = NO; 1166: switch (Map->Test) 1167: { 1168: case ANY: /* no test specified */ 1169: case ALL: 1170: match = YES; 1171: break; 1172: 1173: case GT: 1174: match = (ospeed > Map->Speed); 1175: break; 1176: 1177: case GE: 1178: match = (ospeed >= Map->Speed); 1179: break; 1180: 1181: case EQ: 1182: match = (ospeed == Map->Speed); 1183: break; 1184: 1185: case LE: 1186: match = (ospeed <= Map->Speed); 1187: break; 1188: 1189: case LT: 1190: match = (ospeed < Map->Speed); 1191: break; 1192: 1193: case NE: 1194: match = (ospeed != Map->Speed); 1195: break; 1196: } 1197: if (match) 1198: return (Map->Type); 1199: } 1200: Map++; 1201: } 1202: /* no match found; return given type */ 1203: return (type); 1204: } 1205: 1206: # ifdef DEB 1207: prmap() 1208: { 1209: Map = map; 1210: while (Map->Ident) 1211: { 1212: printf ("%s t:%d s:%d %s\n", 1213: Map->Ident, Map->Test, Map->Speed, Map->Type); 1214: Map++; 1215: } 1216: } 1217: # endif 1218: 1219: char * 1220: nextarg(argc, argv) 1221: int argc; 1222: char *argv[]; 1223: { 1224: if (argc <= 0) 1225: fatal ("Too few args: ", *argv); 1226: if (*(*++argv) == '-') 1227: fatal ("Unexpected arg: ", *argv); 1228: return (*argv); 1229: } 1230: 1231: fatal (mesg, obj) 1232: char *mesg, *obj; 1233: { 1234: 1235: fprintf(stderr, "%s%s\n%s", mesg, obj, USAGE); 1236: exit(1); 1237: } 1238: 1239: /* Prompt the user for a terminal type. */ 1240: char * 1241: askuser(dflt) 1242: char *dflt; 1243: { 1244: static char answer[64]; 1245: char *p; 1246: 1247: /* We can get recalled; if so, don't continue uselessly. */ 1248: if (feof(stdin) || ferror(stdin)) { 1249: (void)fprintf(stderr, "\n"); 1250: exit(1); 1251: } 1252: for (;;) { 1253: if (dflt) 1254: (void)fprintf(stderr, "Terminal type? [%s] ", dflt); 1255: else 1256: (void)fprintf(stderr, "Terminal type? "); 1257: (void)fflush(stderr); 1258: 1259: if (fgets(answer, sizeof(answer), stdin) == NULL) { 1260: if (dflt == NULL) { 1261: (void)fprintf(stderr, "\n"); 1262: exit(1); 1263: } 1264: return (dflt); 1265: } 1266: 1267: if (p = index(answer, '\n')) 1268: *p = '\0'; 1269: if (answer[0]) 1270: return (answer); 1271: if (dflt != NULL) 1272: return (dflt); 1273: } 1274: }