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