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