xref: /original-bsd/bin/stty/stty.c (revision ba762ddc)
1 /*-
2  * Copyright (c) 1989, 1991 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.proprietary.c%
6  */
7 
8 #ifndef lint
9 char copyright[] =
10 "@(#) Copyright (c) 1989, 1991 The Regents of the University of California.\n\
11  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)stty.c	5.21 (Berkeley) 05/02/91";
16 #endif /* not lint */
17 
18 #include <sys/types.h>
19 #include <sys/ioctl.h>
20 #include <termios.h>
21 #include <fcntl.h>
22 #include <errno.h>
23 #include <unistd.h>
24 #include <stdio.h>
25 #include <ctype.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include "stty.h"
29 #include "extern.h"
30 
31 static void usage __P((void));
32 
33 main(argc, argv)
34 	int argc;
35 	char **argv;
36 {
37 	extern char *optarg;
38 	extern int optind;
39 	extern struct cchar cchars1[], cchars2[];
40 	extern struct modes cmodes[], imodes[], lmodes[], omodes[];
41 	register struct modes *mp;
42 	register struct cchar *cp;
43 	struct winsize win;
44 	struct termios t;
45 	enum FMT fmt;
46 	int ch, ctl, ldisc, tmp;
47 
48 	ctl = STDIN_FILENO;
49 	fmt = NOTSET;
50 	while ((ch = getopt(argc, argv, "aef:g")) != EOF)
51 		switch(ch) {
52 		case 'a':		/* undocumented: POSIX compatibility */
53 			fmt = POSIX;
54 			break;
55 		case 'e':
56 			fmt = BSD;
57 			break;
58 		case 'f':
59 			if ((ctl = open(optarg, O_RDONLY | O_NONBLOCK)) < 0)
60 				err(optarg);
61 			break;
62 		case 'g':
63 			fmt = GFLAG;
64 			break;
65 		case '?':
66 			usage();
67 		default:
68 			--optind;
69 			goto args;
70 		}
71 
72 args:	argc -= optind;
73 	argv += optind;
74 
75 	if (ioctl(ctl, TIOCGETD, &ldisc) < 0)
76 		err("TIOCGETD: %s", strerror(errno));
77 	if (tcgetattr(ctl, &t) < 0)
78 		err("tcgetattr: %s", strerror(errno));
79 	if (ioctl(ctl, TIOCGWINSZ, &win) < 0)
80 		warn("TIOCGWINSZ: %s\n", strerror(errno));
81 
82 	checkredirect();			/* conversion aid */
83 
84 	switch(fmt) {
85 	case NOTSET:
86 		if (*argv)
87 			break;
88 		/* FALLTHROUGH */
89 	case BSD:
90 	case POSIX:
91 		print(&t, &win, ldisc, fmt);
92 		break;
93 	case GFLAG:
94 		gprint(&t, &win, ldisc);
95 		break;
96 	}
97 
98 #define	CHK(s)	(**argv == s[0] && !strcmp(*argv, s))
99 
100 	for (; *argv; ++argv) {
101 		if (CHK("-nl")) {
102 			t.c_iflag |= ICRNL;
103 			t.c_oflag |= ONLCR;
104 			continue;
105 		}
106 		if (CHK("all")) {
107 			print(&t, &win, ldisc, BSD);
108 			continue;
109 		}
110 		if (CHK("-cbreak"))
111 			goto reset;
112 		if (CHK("cbreak")) {
113 			t.c_iflag | BRKINT|IXON|IMAXBEL;
114 			t.c_oflag |= OPOST;
115 			t.c_lflag |= ISIG|IEXTEN;
116 			t.c_lflag &= ~ICANON;
117 			continue;
118 		}
119 		if (CHK("cols")) {
120 			if (!*++argv)
121 				err("option requires an argument -- cols");
122 			goto columns;
123 		}
124 		if (CHK("columns")) {
125 			if (!*++argv)
126 				err("option requires an argument -- columns");
127 columns:		win.ws_col = atoi(*argv);
128 			continue;
129 		}
130 		if (CHK("cooked"))
131 			goto reset;
132 		if (CHK("dec")) {
133 			t.c_cc[VERASE] = (u_char)0177;
134 			t.c_cc[VKILL] = CTRL('u');
135 			t.c_cc[VINTR] = CTRL('c');
136 			t.c_lflag &= ~ECHOPRT;
137 			t.c_lflag |= ECHOE|ECHOKE|ECHOCTL;
138 			t.c_iflag &= ~IXANY;
139 			continue;
140 		}
141 		if (CHK("everything")) {
142 			print(&t, &win, ldisc, BSD);
143 			continue;
144 		}
145 		if (CHK("-extproc")) {
146 			tmp = 0;
147 			ioctl(ctl, TIOCEXT, &tmp);
148 			continue;
149 		}
150 		if (CHK("extrpc")) {
151 			tmp = 1;
152 			ioctl(ctl, TIOCEXT, &tmp);
153 			continue;
154 		}
155 		if (CHK("ispeed")) {
156 			if (!*++argv)
157 				err("option requires an argument -- ispeed");
158 			cfsetispeed(&t, atoi(*argv));
159 			continue;
160 		}
161 		if (CHK("new"))
162 			goto tty;
163 		if (CHK("nl")) {
164 			t.c_iflag &= ~ICRNL;
165 			t.c_oflag &= ~ONLCR;
166 			continue;
167 		}
168 		if (CHK("old"))
169 			goto tty;
170 		if (CHK("ospeed")) {
171 			if (!*++argv)
172 				err("option requires an argument -- ospeed");
173 			cfsetospeed(&t, atoi(*argv));
174 			continue;
175 		}
176 		if (CHK("-raw"))
177 			goto reset;
178 		if (CHK("raw")) {
179 			cfmakeraw(&t);
180 			t.c_cflag &= ~(CSIZE|PARENB);
181 			t.c_cflag |= CS8;
182 			continue;
183 		}
184 		if (CHK("rows")) {
185 			if (!*++argv)
186 				err("option requires an argument -- rows");
187 			win.ws_row = atoi(*argv);
188 			continue;
189 		}
190 		if (CHK("sane")) {
191 reset:			t.c_cflag = TTYDEF_CFLAG | (t.c_cflag & CLOCAL);
192 			t.c_iflag = TTYDEF_IFLAG;
193 			t.c_iflag |= ICRNL;
194 			/* preserve user-preference flags in lflag */
195 #define	LKEEP	(ECHOKE|ECHOE|ECHOK|ECHOPRT|ECHOCTL|ALTWERASE|TOSTOP|NOFLSH)
196 			t.c_lflag = TTYDEF_LFLAG | (t.c_lflag & LKEEP);
197 			t.c_oflag = TTYDEF_OFLAG;
198 			continue;
199 		}
200 		if (CHK("size")) {
201 			(void)printf("%d %d\n", win.ws_row, win.ws_col);
202 			continue;
203 		}
204 		if (CHK("speed")) {
205 			(void)printf("%d\n", cfgetospeed(&t));
206 			continue;
207 		}
208 		if (CHK("tty")) {
209 tty:			tmp = TTYDISC;
210 			if (ioctl(0, TIOCSETD, &tmp) < 0)
211 				err("TIOCSETD: %s", strerror(errno));
212 			continue;
213 		}
214 
215 		for (mp = cmodes; mp->name; ++mp)
216 			if (CHK(mp->name)) {
217 				t.c_cflag &= ~mp->unset;
218 				t.c_cflag |= mp->set;
219 				goto next;
220 			}
221 		for (mp = imodes; mp->name; ++mp)
222 			if (CHK(mp->name)) {
223 				t.c_iflag &= ~mp->unset;
224 				t.c_iflag |= mp->set;
225 				goto next;
226 			}
227 		for (mp = lmodes; mp->name; ++mp)
228 			if (CHK(mp->name)) {
229 				t.c_lflag &= ~mp->unset;
230 				t.c_lflag |= mp->set;
231 				goto next;
232 			}
233 		for (mp = omodes; mp->name; ++mp)
234 			if (CHK(mp->name)) {
235 				t.c_oflag &= ~mp->unset;
236 				t.c_oflag |= mp->set;
237 				goto next;
238 			}
239 		for (cp = cchars1; cp->name; ++cp) {
240 			if (!CHK(cp->name))
241 				continue;
242 			goto ccfound;
243 		}
244 		for (cp = cchars2; cp->name; ++cp) {
245 			if (!CHK(cp->name))
246 				continue;
247 ccfound:		if (!*++argv)
248 				err("option requires an argument -- %s",
249 				    cp->name);
250 			if (CHK("undef") || CHK("disable"))
251 				t.c_cc[cp->sub] = _POSIX_VDISABLE;
252 			else if (**argv == '^')
253 				t.c_cc[cp->sub] =
254 				    ((*argv)[1] == '?') ? 0177 :
255 				    ((*argv)[1] == '-') ? _POSIX_VDISABLE :
256 				    (*argv)[1] & 037;
257 			else
258 				t.c_cc[cp->sub] = **argv;
259 			goto next;
260 		}
261 
262 		if (isdigit(**argv)) {
263 			cfsetospeed(&t, atoi(*argv));
264 			cfsetispeed(&t, atoi(*argv));
265 			goto next;
266 		}
267 		if (!strncmp(*argv, "gfmt1", sizeof("gfmt1") - 1)) {
268 			gread(&t, *argv + sizeof("gfmt1") - 1);
269 			goto next;
270 		}
271 
272 		err("illegal option -- %s", *argv);
273 next:		continue;
274 	}
275 
276 	if (tcsetattr(ctl, 0, &t) < 0)
277 		err("tcsetattr: %s", strerror(errno));
278 	if (ioctl(ctl, TIOCSWINSZ, &win) < 0)
279 		warn("TIOCSWINSZ: %s", strerror(errno));
280 	exit(0);
281 }
282 
283 static void
284 usage()
285 {
286 	(void)fprintf(stderr, "usage: stty: [-eg] [-f file] [options]\n");
287 	exit(1);
288 }
289