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

Defined functions

baudrate defined in line 1843; used 3 times
bequal defined in line 1527; used 2 times
bmove defined in line 1509; used 1 times
cancelled defined in line 1800; used 3 times
cat defined in line 1484; used 1 times
fatal defined in line 1944; used 4 times
flush defined in line 1476; used 12 times
isalias defined in line 1585; used 2 times
main defined in line 470; never used
makealias defined in line 1559; used 2 times
mapped defined in line 1858; used 2 times
nextarg defined in line 1932; used 5 times
prc defined in line 1468; used 18 times
prmap defined in line 1920; used 1 times
prs defined in line 1457; used 25 times
putbuf defined in line 1817; used 13 times
reportek defined in line 1371; used 2 times
sequal defined in line 1546; used 9 times
setdelay defined in line 1417; used 11 times
setmode defined in line 1312; used 7 times
settabs defined in line 1269; used 1 times
stypeof defined in line 1600; used 2 times
wrtermcap defined in line 1666; used 1 times

Defined variables

Alias defined in line 448; used 13 times
Aliasbuf defined in line 447; used 1 times
Ask defined in line 437; used 3 times
BeQuiet defined in line 430; used 3 times
Capbuf defined in line 444; used 8 times
CmndLine defined in line 436; used 7 times
Dash_h defined in line 428; used 7 times
Dash_u defined in line 427; used 6 times
DefType defined in line 424; used 4 times
DoSetenv defined in line 429; used 7 times
DoVirtTerm defined in line 438; used 2 times
Erase_char defined in line 414; used 10 times
HasAM defined in line 440; used 5 times
IsReset defined in line 432; used 3 times
Kill_char defined in line 415; used 5 times
Map defined in line 355; used 38 times
Mapped defined in line 426; used 6 times
New defined in line 439; never used
NewType defined in line 425; used 3 times
NoInit defined in line 431; used 2 times
OutBuf defined in line 1465; used 3 times
OutPtr defined in line 1466; used 5 times
PadBaud defined in line 441; used 4 times
RepOnly defined in line 435; used 4 times
Report defined in line 433; used 3 times
Specialerase defined in line 416; used 2 times
TtyType defined in line 423; used 34 times
Ttycap defined in line 445; used 3 times
Ttyid defined in line 421; used 11 times
Ureport defined in line 434; used 3 times
VirTermNo defined in line 411; used 10 times
block defined in line 466; used 10 times
delcap defined in line 1663; used 4 times
id_tset defined in line 2; never used
map defined in line 353; used 3 times
mode defined in line 462; used 74 times
ncap defined in line 1664; used 4 times
oldmode defined in line 463; used 11 times
vtab defined in line 388; used 4 times

Defined struct's

delay defined in line 450; used 4 times
map defined in line 348; used 2 times
  • in line 355(2)
vterm defined in line 385; never used

Defined macros

ALL defined in line 342; used 3 times
ANY defined in line 335; never used
BACKSPACE defined in line 291; used 2 times
CAPBUFSIZ defined in line 443; used 2 times
CHK defined in line 292; used 18 times
CTRL defined in line 290; used 19 times
DEFTYPE defined in line 323; used 6 times
DIALUP defined in line 314; used 1 times
EQ defined in line 337; used 4 times
FILEDES defined in line 298; used 22 times
GE defined in line 339; never used
GT defined in line 336; used 4 times
GTTYN defined in line 272; used 6 times
LE defined in line 340; never used
LT defined in line 338; used 4 times
NE defined in line 341; never used
NMAP defined in line 346; used 1 times
NO defined in line 288; used 9 times
NOTTY defined in line 329; used 6 times
OLDDIALUP defined in line 315; used 1 times
OLDERASE defined in line 295; used 5 times
OLDFLAGS defined in line 313; used 1 times
OLDKILL defined in line 296; used 4 times
OLDPLUGBOARD defined in line 317; used 1 times
PLUGBOARD defined in line 316; used 1 times
STDOUT defined in line 299; used 17 times
UIDMASK defined in line 304; used 1 times
USAGE defined in line 310; used 1 times
WHITE defined in line 1662; used 2 times
YES defined in line 287; used 29 times
curerase defined in line 265; used 9 times
curkill defined in line 266; used 8 times
index defined in line 258; used 1 times
isalnum defined in line 294; used 7 times
isdigit defined in line 293; used 1 times
olderase defined in line 267; used 1 times
oldkill defined in line 268; used 1 times
rindex defined in line 259; used 2 times
Last modified: 1983-08-05
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4237
Valid CSS Valid XHTML 1.0 Strict