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 *)&ltc);
 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 *)&ltc);
 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: }

Defined functions

askuser defined in line 1240; used 4 times
baudrate defined in line 1135; used 3 times
cat defined in line 1042; used 1 times
fatal defined in line 1231; used 6 times
flush defined in line 1036; used 6 times
main defined in line 364; never used
mapped defined in line 1150; used 2 times
nextarg defined in line 1219; used 5 times
prc defined in line 1030; used 9 times
prmap defined in line 1207; used 1 times
prs defined in line 1022; used 15 times
reportek defined in line 979; used 3 times
setmode defined in line 949; used 6 times
settabs defined in line 910; used 1 times
wrtermcap defined in line 1069; used 2 times

Defined variables

Ask defined in line 345; never used
BeQuiet defined in line 338; used 3 times
Capbuf defined in line 351; used 2 times
CmndLine defined in line 344; used 7 times
DefType defined in line 335; used 3 times
DoSetenv defined in line 337; used 6 times
Erase_char defined in line 330; used 10 times
Intr_char defined in line 332; used 6 times
IsReset defined in line 340; used 4 times
Kill_char defined in line 331; used 6 times
Map defined in line 300; used 37 times
NewType defined in line 336; used 4 times
NoInit defined in line 339; used 2 times
PadBaud defined in line 346; used 3 times
RepOnly defined in line 343; used 3 times
Report defined in line 341; used 3 times
TtyType defined in line 334; used 20 times
Ttycap defined in line 352; used 2 times
Ureport defined in line 342; used 3 times
columns defined in line 347; used 4 times
copyright defined in line 8; never used
lines defined in line 347; used 4 times
map defined in line 298; used 3 times
mode defined in line 355; used 21 times
oldmode defined in line 356; used 7 times
oldtchar defined in line 358; used 3 times
ospeed defined in line 348; used 8 times
sccsid defined in line 12; never used
tchar defined in line 357; used 16 times

Defined struct's

map defined in line 293; used 2 times
  • in line 300(2)

Defined macros

ALL defined in line 289; used 3 times
ANY defined in line 282; never used
ARPANET defined in line 277; used 1 times
BACKSPACE defined in line 240; used 2 times
CAPBUFSIZ defined in line 350; used 2 times
CBRK defined in line 262; never used
CDSUSP defined in line 264; used 2 times
CEOF defined in line 260; used 2 times
CEOT defined in line 261; never used
CERASE defined in line 248; used 3 times
CFLUSH defined in line 266; used 1 times
CHK defined in line 241; used 14 times
CINTR defined in line 254; used 4 times
CKILL defined in line 251; used 3 times
CLNEXT defined in line 268; used 1 times
CNTL defined in line 239; used 18 times
CQUIT defined in line 257; used 1 times
CRPRNT defined in line 265; used 1 times
CSTART defined in line 258; used 1 times
CSTOP defined in line 259; used 1 times
CSUSP defined in line 263; used 1 times
CWERASE defined in line 267; used 1 times
DIALUP defined in line 275; used 1 times
EQ defined in line 284; used 4 times
FILEDES defined in line 271; used 15 times
GE defined in line 286; never used
GT defined in line 283; used 4 times
LE defined in line 287; never used
LT defined in line 285; used 4 times
NE defined in line 288; never used
NMAP defined in line 291; used 1 times
NO defined in line 237; used 5 times
OLDERASE defined in line 242; used 2 times
OLDINTR defined in line 244; used 1 times
OLDKILL defined in line 243; used 1 times
PLUGBOARD defined in line 276; used 1 times
USAGE defined in line 273; used 1 times
YES defined in line 236; used 16 times
curerase defined in line 218; used 7 times
curintr defined in line 220; used 6 times
curkill defined in line 219; used 6 times
olderase defined in line 221; used 1 times
oldintr defined in line 223; used 1 times
oldkill defined in line 222; used 1 times
Last modified: 1997-03-28
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3635
Valid CSS Valid XHTML 1.0 Strict