xref: /original-bsd/bin/stty/stty.c (revision 61b6c03f)
1 /*
2  * Copyright (c) 1980 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 char copyright[] =
9 "@(#) Copyright (c) 1980 Regents of the University of California.\n\
10  All rights reserved.\n";
11 #endif not lint
12 
13 #ifndef lint
14 static char sccsid[] = "@(#)stty.c	5.4 (Berkeley) 04/04/86";
15 #endif not lint
16 
17 /*
18  * set teletype modes
19  */
20 
21 #include <stdio.h>
22 #include <sys/ioctl.h>
23 
24 struct
25 {
26 	char	*string;
27 	int	speed;
28 } speeds[] = {
29 	"0",	B0,
30 	"50",	B50,
31 	"75",	B75,
32 	"110",	B110,
33 	"134",	B134,
34 	"134.5",B134,
35 	"150",	B150,
36 	"200",	B200,
37 	"300",	B300,
38 	"600",	B600,
39 	"1200",	B1200,
40 	"1800",	B1800,
41 	"2400",	B2400,
42 	"4800",	B4800,
43 	"9600",	B9600,
44 	"exta",	EXTA,
45 	"19200", EXTA,
46 	"extb",	EXTB,
47 	"38400", EXTB,
48 	0,
49 };
50 struct
51 {
52 	char	*string;
53 	int	set;
54 	int	reset;
55 	int	lset;
56 	int	lreset;
57 } modes[] = {
58 	"even",		EVENP, 0, 0, 0,
59 	"-even",	0, EVENP, 0, 0,
60 	"odd",		ODDP, 0, 0, 0,
61 	"-odd",		0, ODDP, 0, 0,
62 	"raw",		RAW, 0, 0, 0,
63 	"-raw",		0, RAW, 0, 0,
64 	"cooked",	0, RAW, 0, 0,
65 	"-nl",		CRMOD, 0, 0, 0,
66 	"nl",		0, CRMOD, 0, 0,
67 	"echo",		ECHO, 0, 0, 0,
68 	"-echo",	0, ECHO, 0, 0,
69 	"LCASE",	LCASE, 0, 0, 0,
70 	"lcase",	LCASE, 0, 0, 0,
71 	"-LCASE",	0, LCASE, 0, 0,
72 	"-lcase",	0, LCASE, 0, 0,
73 	"-tabs",	XTABS, 0, 0, 0,
74 	"tabs",		0, XTABS, 0, 0,
75 	"tandem",	TANDEM, 0, 0, 0,
76 	"-tandem",	0, TANDEM, 0, 0,
77 	"cbreak",	CBREAK, 0, 0, 0,
78 	"-cbreak",	0, CBREAK, 0, 0,
79 	"cr0",		CR0, CR3, 0, 0,
80 	"cr1",		CR1, CR3, 0, 0,
81 	"cr2",		CR2, CR3, 0, 0,
82 	"cr3",		CR3, CR3, 0, 0,
83 	"tab0",		TAB0, XTABS, 0, 0,
84 	"tab1",		TAB1, XTABS, 0, 0,
85 	"tab2",		TAB2, XTABS, 0, 0,
86 	"nl0",		NL0, NL3, 0, 0,
87 	"nl1",		NL1, NL3, 0, 0,
88 	"nl2",		NL2, NL3, 0, 0,
89 	"nl3",		NL3, NL3, 0, 0,
90 	"ff0",		FF0, FF1, 0, 0,
91 	"ff1",		FF1, FF1, 0, 0,
92 	"bs0",		BS0, BS1, 0, 0,
93 	"bs1",		BS1, BS1, 0, 0,
94 	"33",		CR1, ALLDELAY, 0, 0,
95 	"tty33",	CR1, ALLDELAY, 0, 0,
96 	"37",		FF1+CR2+TAB1+NL1, ALLDELAY, 0, 0,
97 	"tty37",	FF1+CR2+TAB1+NL1, ALLDELAY, 0, 0,
98 	"05",		NL2, ALLDELAY, 0, 0,
99 	"vt05",		NL2, ALLDELAY, 0, 0,
100 	"tn",		CR1, ALLDELAY, 0, 0,
101 	"tn300",	CR1, ALLDELAY, 0, 0,
102 	"ti",		CR2, ALLDELAY, 0, 0,
103 	"ti700",	CR2, ALLDELAY, 0, 0,
104 	"tek",		FF1, ALLDELAY, 0, 0,
105 	"crtbs",	0, 0, LCRTBS, LPRTERA,
106 	"-crtbs",	0, 0, 0, LCRTBS,
107 	"prterase",	0, 0, LPRTERA, LCRTBS+LCRTKIL+LCRTERA,
108 	"-prterase",	0, 0, 0, LPRTERA,
109 	"crterase",	0, 0, LCRTERA, LPRTERA,
110 	"-crterase",	0, 0, 0, LCRTERA,
111 	"crtkill",	0, 0, LCRTKIL, LPRTERA,
112 	"-crtkill",	0, 0, 0, LCRTKIL,
113 	"tilde",	0, 0, LTILDE, 0,
114 	"-tilde",	0, 0, 0, LTILDE,
115 	"mdmbuf",	0, 0, LMDMBUF, 0,
116 	"-mdmbuf",	0, 0, 0, LMDMBUF,
117 	"litout",	0, 0, LLITOUT, 0,
118 	"-litout",	0, 0, 0, LLITOUT,
119 	"pass8",	0, 0, LPASS8, 0,
120 	"-pass8",	0, 0, 0, LPASS8,
121 	"tostop",	0, 0, LTOSTOP, 0,
122 	"-tostop",	0, 0, 0, LTOSTOP,
123 	"flusho",	0, 0, LFLUSHO, 0,
124 	"-flusho",	0, 0, 0, LFLUSHO,
125 	"nohang",	0, 0, LNOHANG, 0,
126 	"-nohang",	0, 0, 0, LNOHANG,
127 #ifdef notdef
128 	"etxack",	0, 0, LETXACK, 0,
129 	"-etxack",	0, 0, 0, LETXACK,
130 #endif
131 	"ctlecho",	0, 0, LCTLECH, 0,
132 	"-ctlecho",	0, 0, 0, LCTLECH,
133 	"pendin",	0, 0, LPENDIN, 0,
134 	"-pendin",	0, 0, 0, LPENDIN,
135 	"decctlq",	0, 0, LDECCTQ, 0,
136 	"-decctlq",	0, 0, 0, LDECCTQ,
137 	"noflsh",	0, 0, LNOFLSH, 0,
138 	"-noflsh",	0, 0, 0, LNOFLSH,
139 	0,
140 };
141 
142 struct tchars tc;
143 struct ltchars ltc;
144 struct sgttyb mode;
145 struct winsize win;
146 int	lmode;
147 int	oldisc, ldisc;
148 
149 struct	special {
150 	char	*name;
151 	char	*cp;
152 	char	def;
153 } special[] = {
154 	"erase",	&mode.sg_erase,		CERASE,
155 	"kill",		&mode.sg_kill,		CKILL,
156 	"intr",		&tc.t_intrc,		CINTR,
157 	"quit",		&tc.t_quitc,		CQUIT,
158 	"start",	&tc.t_startc,		CSTART,
159 	"stop",		&tc.t_stopc,		CSTOP,
160 	"eof",		&tc.t_eofc,		CEOF,
161 	"brk",		&tc.t_brkc,		CBRK,
162 	"susp",		&ltc.t_suspc,		CSUSP,
163 	"dsusp",	&ltc.t_dsuspc,		CDSUSP,
164 	"rprnt",	&ltc.t_rprntc,		CRPRNT,
165 	"flush",	&ltc.t_flushc,		CFLUSH,
166 	"werase",	&ltc.t_werasc,		CWERASE,
167 	"lnext",	&ltc.t_lnextc,		CLNEXT,
168 	0
169 };
170 char	*arg;
171 
172 int	argc;
173 char	**argv;
174 main(iargc, iargv)
175 char	**iargv;
176 {
177 	int i;
178 	register struct special *sp;
179 	char obuf[BUFSIZ];
180 
181 	setbuf(stderr, obuf);
182 	argc = iargc;
183 	argv = iargv;
184 	ioctl(1, TIOCGETP, &mode);
185 	ioctl(1, TIOCGETD, &ldisc);
186 	oldisc = ldisc;
187 	ioctl(1, TIOCGETC, &tc);
188 	ioctl(1, TIOCLGET, &lmode);
189 	ioctl(1, TIOCGLTC, &ltc);
190 	ioctl(1, TIOCGWINSZ, &win);
191 	if(argc == 1) {
192 		prmodes(0);
193 		exit(0);
194 	}
195 	if (argc == 2 && !strcmp(argv[1], "all")) {
196 		prmodes(1);
197 		exit(0);
198 	}
199 	if (argc == 2 && !strcmp(argv[1], "everything")) {
200 		prmodes(2);
201 		exit(0);
202 	}
203 /*
204 	if (argc == 2 && !strcmp(argv[1], "all")) {
205 		prmodes(2);
206 		exit(0);
207 	}
208 */
209 	while(--argc > 0) {
210 		arg = *++argv;
211 		if (eq("ek")){
212 			mode.sg_erase = '#';
213 			mode.sg_kill = '@';
214 			continue;
215 		}
216 		if (eq("new")){
217 			ldisc = NTTYDISC;
218 			if (ioctl(1, TIOCSETD, &ldisc)<0)
219 				perror("ioctl");
220 			continue;
221 		}
222 		if (eq("newcrt")){
223 			ldisc = NTTYDISC;
224 			lmode &= ~LPRTERA;
225 			lmode |= LCRTBS|LCTLECH;
226 			if (mode.sg_ospeed >= B1200)
227 				lmode |= LCRTERA|LCRTKIL;
228 			if (ioctl(1, TIOCSETD, &ldisc)<0)
229 				perror("ioctl");
230 			continue;
231 		}
232 		if (eq("crt")){
233 			lmode &= ~LPRTERA;
234 			lmode |= LCRTBS|LCTLECH;
235 			if (mode.sg_ospeed >= B1200)
236 				lmode |= LCRTERA|LCRTKIL;
237 			continue;
238 		}
239 		if (eq("old")){
240 			ldisc = 0;
241 			if (ioctl(1, TIOCSETD, &ldisc)<0)
242 				perror("ioctl");
243 			continue;
244 		}
245 		if (eq("dec")){
246 			mode.sg_erase = 0177;
247 			mode.sg_kill = CTRL(u);
248 			tc.t_intrc = CTRL(c);
249 			ldisc = NTTYDISC;
250 			lmode &= ~LPRTERA;
251 			lmode |= LCRTBS|LCTLECH|LDECCTQ;
252 			if (mode.sg_ospeed >= B1200)
253 				lmode |= LCRTERA|LCRTKIL;
254 			if (ioctl(1, TIOCSETD, &ldisc)<0)
255 				perror("ioctl");
256 			continue;
257 		}
258 		for (sp = special; sp->name; sp++)
259 			if (eq(sp->name)) {
260 				if (--argc == 0)
261 					goto done;
262 				if (**++argv == 'u')
263 					*sp->cp = 0377;
264 				else if (**argv == '^')
265 					*sp->cp = ((*argv)[1] == '?') ?
266 					    0177 : (*argv)[1] & 037;
267 				else
268 					*sp->cp = **argv;
269 				goto cont;
270 			}
271 		if (eq("gspeed")) {
272 			mode.sg_ispeed = B300;
273 			mode.sg_ospeed = B9600;
274 			continue;
275 		}
276 		if (eq("hup")) {
277 			ioctl(1, TIOCHPCL, NULL);
278 			continue;
279 		}
280 		if (eq("rows")) {
281 			if (--argc == 0)
282 				goto done;
283 			win.ws_row = atoi(*++argv);
284 		}
285 		if (eq("cols") || eq("columns")) {
286 			if (--argc == 0)
287 				goto done;
288 			win.ws_col = atoi(*++argv);
289 		}
290 		if (eq("size")) {
291 			ioctl(open("/dev/tty", 0), TIOCGWINSZ, &win);
292 			printf("%d %d\n", win.ws_row, win.ws_col);
293 			exit(0);
294 		}
295 		for(i=0; speeds[i].string; i++)
296 			if(eq(speeds[i].string)) {
297 				mode.sg_ispeed = mode.sg_ospeed = speeds[i].speed;
298 				goto cont;
299 			}
300 		if (eq("speed")) {
301 			ioctl(open("/dev/tty", 0), TIOCGETP, &mode);
302 			for(i=0; speeds[i].string; i++)
303 				if (mode.sg_ospeed == speeds[i].speed) {
304 					printf("%s\n", speeds[i].string);
305 					exit(0);
306 				}
307 			printf("unknown\n");
308 			exit(1);
309 		}
310 		for(i=0; modes[i].string; i++)
311 			if(eq(modes[i].string)) {
312 				mode.sg_flags &= ~modes[i].reset;
313 				mode.sg_flags |= modes[i].set;
314 				lmode &= ~modes[i].lreset;
315 				lmode |= modes[i].lset;
316 			}
317 		if(arg)
318 			fprintf(stderr,"unknown mode: %s\n", arg);
319 cont:
320 		;
321 	}
322 done:
323 	ioctl(1, TIOCSETN, &mode);
324 	ioctl(1, TIOCSETC, &tc);
325 	ioctl(1, TIOCSLTC, &ltc);
326 	ioctl(1, TIOCLSET, &lmode);
327 	ioctl(1, TIOCSWINSZ, &win);
328 }
329 
330 eq(string)
331 char *string;
332 {
333 	int i;
334 
335 	if(!arg)
336 		return(0);
337 	i = 0;
338 loop:
339 	if(arg[i] != string[i])
340 		return(0);
341 	if(arg[i++] != '\0')
342 		goto loop;
343 	arg = 0;
344 	return(1);
345 }
346 
347 prmodes(all)
348 {
349 	register m;
350 	int any;
351 
352 	if(ldisc==NETLDISC)
353 		fprintf(stderr, "net discipline, ");
354 	else if(ldisc==NTTYDISC)
355 		fprintf(stderr, "new tty, ");
356 	else if(all==2)
357 		fprintf(stderr, "old tty, ");
358 	if(mode.sg_ispeed != mode.sg_ospeed) {
359 		prspeed("input speed ", mode.sg_ispeed);
360 		prspeed("output speed ", mode.sg_ospeed);
361 	} else
362 		prspeed("speed ", mode.sg_ispeed);
363 	if (all)
364 		fprintf(stderr, ", %d rows, %d columns", win.ws_row, win.ws_col);
365 	fprintf(stderr, all==2 ? "\n" : "; ");
366 	m = mode.sg_flags;
367 	if(all==2 || (m&(EVENP|ODDP))!=(EVENP|ODDP)) {
368 		if(m & EVENP)	fprintf(stderr,"even ");
369 		if(m & ODDP)	fprintf(stderr,"odd ");
370 	}
371 	if(all==2 || m&RAW)
372 		fprintf(stderr,"-raw "+((m&RAW)!=0));
373 	if(all==2 || (m&CRMOD)==0)
374 		fprintf(stderr,"-nl "+((m&CRMOD)==0));
375 	if(all==2 || (m&ECHO)==0)
376 		fprintf(stderr,"-echo "+((m&ECHO)!=0));
377 	if(all==2 || (m&LCASE))
378 		fprintf(stderr,"-lcase "+((m&LCASE)!=0));
379 	if(all==2 || (m&TANDEM))
380 		fprintf(stderr,"-tandem "+((m&TANDEM)!=0));
381 	fprintf(stderr,"-tabs "+((m&XTABS)!=XTABS));
382 	if(all==2 || (m&CBREAK))
383 		fprintf(stderr,"-cbreak "+((m&CBREAK)!=0));
384 	if(all==2 || (m&NLDELAY))
385 		delay((m&NLDELAY)/NL1,	"nl");
386 	if ((m&TBDELAY)!=XTABS)
387 		delay((m&TBDELAY)/TAB1,	"tab");
388 	if(all==2 || (m&CRDELAY))
389 		delay((m&CRDELAY)/CR1,	"cr");
390 	if(all==2 || (m&VTDELAY))
391 		delay((m&VTDELAY)/FF1,	"ff");
392 	if(all==2 || (m&BSDELAY))
393 		delay((m&BSDELAY)/BS1,	"bs");
394 	if (all)
395 		fprintf(stderr,"\n");
396 #define	lpit(what,str) \
397 	if (all==2||(lmode&what)) { \
398 		fprintf(stderr,str+((lmode&what)!=0)); any++; \
399 	}
400 	if (ldisc == NTTYDISC) {
401 		int newcrt = (lmode&(LCTLECH|LCRTBS)) == (LCTLECH|LCRTBS) &&
402 		    (lmode&(LCRTERA|LCRTKIL)) ==
403 		      ((mode.sg_ospeed > B300) ? LCRTERA|LCRTKIL : 0);
404 		int nothing = 1;
405 		if (newcrt) {
406 			if (all==2)
407 				fprintf(stderr, "crt: (crtbs crterase crtkill ctlecho) ");
408 			else
409 				fprintf(stderr, "crt ");
410 			any++;
411 		} else {
412 			lpit(LCRTBS, "-crtbs ");
413 			lpit(LCRTERA, "-crterase ");
414 			lpit(LCRTKIL, "-crtkill ");
415 			lpit(LCTLECH, "-ctlecho ");
416 			lpit(LPRTERA, "-prterase ");
417 		}
418 		lpit(LTOSTOP, "-tostop ");
419 		if (all==2) {
420 			fprintf(stderr, "\n");
421 			any = 0;
422 			nothing = 0;
423 		}
424 		lpit(LTILDE, "-tilde ");
425 		lpit(LFLUSHO, "-flusho ");
426 		lpit(LMDMBUF, "-mdmbuf ");
427 		lpit(LLITOUT, "-litout ");
428 		lpit(LPASS8, "-pass8 ");
429 		lpit(LNOHANG, "-nohang ");
430 		if (any) {
431 			fprintf(stderr,"\n");
432 			any = 0;
433 			nothing = 0;
434 		}
435 #ifdef notdef
436 		lpit(LETXACK, "-etxack ");
437 #endif
438 		lpit(LPENDIN, "-pendin ");
439 		lpit(LDECCTQ, "-decctlq ");
440 		lpit(LNOFLSH, "-noflsh ");
441 		if (any || nothing)
442 			fprintf(stderr,"\n");
443 	} else if (!all)
444 		fprintf(stderr,"\n");
445 	if (all) {
446 		switch (ldisc) {
447 
448 		case 0:
449 			fprintf(stderr,"\
450 erase  kill   intr   quit   stop   eof\
451 \n");
452 			pcol(mode.sg_erase, -1);
453 			pcol(mode.sg_kill, -1);
454 			pcol(tc.t_intrc, -1);
455 			pcol(tc.t_quitc, -1);
456 			pcol(tc.t_stopc, tc.t_startc);
457 			pcol(tc.t_eofc, tc.t_brkc);
458 			fprintf(stderr,"\n");
459 			break;
460 
461 		case NTTYDISC:
462 			fprintf(stderr,"\
463 erase  kill   werase rprnt  flush  lnext  susp   intr   quit   stop   eof\
464 \n");
465 			pcol(mode.sg_erase, -1);
466 			pcol(mode.sg_kill, -1);
467 			pcol(ltc.t_werasc, -1);
468 			pcol(ltc.t_rprntc, -1);
469 			pcol(ltc.t_flushc, -1);
470 			pcol(ltc.t_lnextc, -1);
471 			pcol(ltc.t_suspc, ltc.t_dsuspc);
472 			pcol(tc.t_intrc, -1);
473 			pcol(tc.t_quitc, -1);
474 			pcol(tc.t_stopc, tc.t_startc);
475 			pcol(tc.t_eofc, tc.t_brkc);
476 			fprintf(stderr,"\n");
477 			break;
478 		}
479 	} else if (ldisc != NETLDISC) {
480 		register struct special *sp;
481 		int first = 1;
482 
483 		for (sp = special; sp->name; sp++) {
484 			if ((*sp->cp&0377) != (sp->def&0377)) {
485 				pit(*sp->cp, sp->name, first ? "" : ", ");
486 				first = 0;
487 			};
488 			if (sp->cp == &tc.t_brkc && ldisc == 0)
489 				break;
490 		}
491 		if (!first)
492 			fprintf(stderr, "\n");
493 	}
494 }
495 
496 pcol(ch1, ch2)
497 	int ch1, ch2;
498 {
499 	int nout = 0;
500 
501 	ch1 &= 0377;
502 	ch2 &= 0377;
503 	if (ch1 == ch2)
504 		ch2 = 0377;
505 	for (; ch1 != 0377 || ch2 != 0377; ch1 = ch2, ch2 = 0377) {
506 		if (ch1 == 0377)
507 			continue;
508 		if (ch1 & 0200) {
509 			fprintf(stderr, "M-");
510 			nout += 2;
511 			ch1 &= ~ 0200;
512 		}
513 		if (ch1 == 0177) {
514 			fprintf(stderr, "^");
515 			nout++;
516 			ch1 = '?';
517 		} else if (ch1 < ' ') {
518 			fprintf(stderr, "^");
519 			nout++;
520 			ch1 += '@';
521 		}
522 		fprintf(stderr, "%c", ch1);
523 		nout++;
524 		if (ch2 != 0377) {
525 			fprintf(stderr, "/");
526 			nout++;
527 		}
528 	}
529 	while (nout < 7) {
530 		fprintf(stderr, " ");
531 		nout++;
532 	}
533 }
534 
535 pit(what, itsname, sep)
536 	unsigned what;
537 	char *itsname, *sep;
538 {
539 
540 	what &= 0377;
541 	fprintf(stderr, "%s%s", sep, itsname);
542 	if (what == 0377) {
543 		fprintf(stderr, " <undef>");
544 		return;
545 	}
546 	fprintf(stderr, " = ");
547 	if (what & 0200) {
548 		fprintf(stderr, "M-");
549 		what &= ~ 0200;
550 	}
551 	if (what == 0177) {
552 		fprintf(stderr, "^");
553 		what = '?';
554 	} else if (what < ' ') {
555 		fprintf(stderr, "^");
556 		what += '@';
557 	}
558 	fprintf(stderr, "%c", what);
559 }
560 
561 delay(m, s)
562 char *s;
563 {
564 
565 	if(m)
566 		fprintf(stderr,"%s%d ", s, m);
567 }
568 
569 int	speed[] = {
570 	0,50,75,110,134,150,200,300,600,1200,1800,2400,4800,9600,19200,38400
571 };
572 
573 prspeed(c, s)
574 char *c;
575 {
576 
577 	fprintf(stderr,"%s%d baud",  c, speed[s]);
578 }
579