xref: /plan9/sys/src/ape/9src/stty.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
1 #include <u.h>
2 #include <libc.h>
3 #include <tty.h>
4 
5 typedef struct Mode Mode;
6 struct Mode
7 {
8 	char*	name;
9 	int	bit;
10 };
11 
12 Mode ou[] =
13 {
14 	"opost",	OPOST,
15 	"olcuc",	OLCUC,
16 	"onlcr",	ONLCR,
17 	"ocrnl",	OCRNL,
18 	"onocr",	ONOCR,
19 	"onlret",	ONLRET,
20 	"ofill",	OFILL,
21 	"ofdel",	OFDEL,
22 	0
23 };
24 
25 Mode in[] =
26 {
27 	"brkint",	BRKINT,
28 	"icrnl",	ICRNL,
29 	"ignbrk",	IGNBRK,
30 	"igncr",	IGNCR,
31 	"ignpar",	IGNPAR,
32 	"inlcr",	INLCR,
33 	"inpck",	INPCK,
34 	"istrip",	ISTRIP,
35 	"ixoff",	IXOFF,
36 	"ixon",		IXON,
37 	"parmrk",	PARMRK,
38 	0
39 };
40 
41 Mode lo[] =
42 {
43 	"echo",		ECHO,
44 	"echoe",	ECHOE,
45 	"echok", 	ECHOK,
46 	"echonl",	ECHONL,
47 	"icanon",	ICANON,
48 	"iexten",	IEXTEN,
49 	"isig",		ISIG,
50 	"noflsh",	NOFLSH,
51 	"tostop",	TOSTOP,
52 	0
53 };
54 
55 Mode cc[] =
56 {
57 	"eof",		VEOF,
58 	"eol",		VEOL,
59 	"erase",	VERASE,
60 	"intr",		VINTR,
61 	"kill",		VKILL,
62 	"min",		VMIN,
63 	"quit",		VQUIT,
64 	"susp",		VSUSP,
65 	"time",		VTIME,
66 	"start",	VSTART,
67 	"stop",		VSTOP,
68 	0,
69 };
70 
71 int	getmode(int, Termios*);
72 int	setmode(int, Termios*);
73 
74 char*
ctlchar(char c)75 ctlchar(char c)
76 {
77 	static char buf[10];
78 
79 	if(c == 0x7f)
80 		return "DEL";
81 	if(c == 0)
82 		return "NUL";
83 	if(c < 32) {
84 		buf[0] = '^';
85 		buf[1] = '@'+c;
86 		buf[2] = '\0';
87 		return buf;
88 	}
89 	buf[0] = c;
90 	buf[1] = '\0';
91 	return buf;
92 }
93 
94 void
showmode(Termios * t)95 showmode(Termios *t)
96 {
97 	int i;
98 
99 	for(i = 0; cc[i].name; i++) {
100 		switch(cc[i].bit) {
101 		case VMIN:
102 		case VTIME:
103 			if(t->cc[i] != 0)
104 				print("%s %d ", cc[i].name, t->cc[i]);
105 			break;
106 		default:
107 			print("%s %s ", cc[i].name, ctlchar(t->cc[i]));
108 			break;
109 		}
110 	}
111 	print("\n");
112 
113 	for(i = 0; ou[i].name; i++)
114 		if(ou[i].bit & t->oflag)
115 			print("%s ", ou[i].name);
116 
117 	for(i = 0; in[i].name; i++)
118 		if(in[i].bit & t->iflag)
119 			print("%s ", in[i].name);
120 
121 	print("\n");
122 	for(i = 0; lo[i].name; i++)
123 		if(lo[i].bit & t->lflag)
124 			print("%s ", lo[i].name);
125 	print("\n");
126 }
127 
128 int
setreset(char * mode,int * bits,Mode * t)129 setreset(char *mode, int *bits, Mode *t)
130 {
131 	int i, clr;
132 
133 	clr = 0;
134 	if(mode[0] == '-') {
135 		mode++;
136 		clr = 1;
137 	}
138 	for(i = 0; t[i].name; i++) {
139 		if(strcmp(mode, t[i].name) == 0) {
140 			if(clr)
141 				*bits &= ~t[i].bit;
142 			else
143 				*bits |= t[i].bit;
144 
145 			return 1;
146 		}
147 	}
148 	return 0;
149 }
150 
151 int
ccname(char * name)152 ccname(char *name)
153 {
154 	int i;
155 
156 	for(i = 0; cc[i].name; i++)
157 		if(strcmp(cc[i].name, name) == 0)
158 			return i;
159 
160 	return -1;
161 }
162 
163 void
main(int argc,char ** argv)164 main(int argc, char **argv)
165 {
166 	Termios t;
167 	int i, stdin, wmo, cc;
168 
169 	/* Try and get a seek pointer */
170 	stdin = open("/fd/0", ORDWR);
171 	if(stdin < 0)
172 		stdin = 0;
173 
174 	if(getmode(stdin, &t) < 0) {
175 		fprint(2, "stty: tiocget %r\n");
176 		exits("1");
177 	}
178 
179 	if(argc < 2) {
180 		fprint(2, "usage: stty [-a|-g] modes...\n");
181 		exits("1");
182 	}
183 	wmo = 0;
184 	for(i = 1; i < argc; i++) {
185 		if(strcmp(argv[i], "-a") == 0) {
186 			showmode(&t);
187 			continue;
188 		}
189 		if(setreset(argv[i], &t.iflag, in)) {
190 			wmo++;
191 			continue;
192 		}
193 		if(setreset(argv[i], &t.lflag, lo)) {
194 			wmo++;
195 			continue;
196 		}
197 		if(setreset(argv[i], &t.oflag, ou)) {
198 			wmo++;
199 			continue;
200 		}
201 		cc = ccname(argv[i]);
202 		if(cc != -1 && i+1 < argc) {
203 			wmo++;
204 			t.cc[cc] = argv[++i][0];
205 			continue;
206 		}
207 		fprint(2, "stty: bad option/mode %s\n", argv[i]);
208 		exits("1");
209 	}
210 
211 	if(wmo) {
212 		if(setmode(stdin, &t) < 0) {
213 			fprint(2, "stty: cant set mode %r\n");
214 			exits("1");
215 		}
216 	}
217 
218 	exits(0);
219 }
220 
221 int
setmode(int fd,Termios * t)222 setmode(int fd, Termios *t)
223 {
224 	int n, i;
225 	char buf[256];
226 
227 	n = sprint(buf, "IOW %4.4ux %4.4ux %4.4ux %4.4ux ",
228 		t->iflag, t->oflag, t->cflag, t->lflag);
229 	for(i = 0; i < NCCS; i++)
230 		n += sprint(buf+n, "%2.2ux ", t->cc[i]);
231 
232 	if(seek(fd, -2, 0) != -2)
233 		return -1;
234 
235 	n = write(fd, buf, n);
236 	if(n < 0)
237 		return -1;
238 	return 0;
239 }
240 
241 /*
242  * Format is: IOR iiii oooo cccc llll xx xx xx xx ...
243  */
244 int
getmode(int fd,Termios * t)245 getmode(int fd, Termios *t)
246 {
247 	int n;
248 	char buf[256];
249 
250 	if(seek(fd, -2, 0) != -2)
251 		return -1;
252 
253 	n = read(fd, buf, 57);
254 	if(n < 0)
255 		return -1;
256 
257 	t->iflag = strtoul(buf+4, 0, 16);
258 	t->oflag = strtoul(buf+9, 0, 16);
259 	t->cflag = strtoul(buf+14, 0, 16);
260 	t->lflag = strtoul(buf+19, 0, 16);
261 
262 	for(n = 0; n < NCCS; n++)
263 		t->cc[n] = strtoul(buf+24+(n*3), 0, 16);
264 
265 	return 0;
266 }
267