xref: /illumos-gate/usr/src/ucbcmd/stty/sttyparse.c (revision dd72704bd9e794056c558153663c739e2012d721)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 1997 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <sys/types.h>
33 #include <termio.h>
34 #include <sys/stermio.h>
35 #include <sys/termiox.h>
36 #include "stty.h"
37 
38 static char	*s_arg;			/* s_arg: ptr to mode to be set */
39 static int	match;
40 static int gct(), eq(), encode();
41 static int eqarg(char *, int);
42 
43 /* set terminal modes for supplied options */
44 char *
45 sttyparse(argc, argv, term, ocb, cb, termiox, winsize)
46 int	argc;
47 char	*argv[];
48 int	term; /* type of tty device, -1 means allow all options,
49 	       * no sanity check
50 	       */
51 struct	termio	*ocb;
52 struct	termios	*cb;
53 struct	termiox	*termiox;
54 struct	winsize	*winsize;
55 {
56 	int i;
57 	extern	const struct	speeds	speeds[];
58 	extern	const struct	mds	lmodes[];
59 	extern	const struct	mds	nlmodes[];
60 	extern	const struct	mds	cmodes[];
61 	extern	const struct	mds	ncmodes[];
62 	extern	const struct	mds	imodes[];
63 	extern	const struct	mds	nimodes[];
64 	extern	const struct	mds	omodes[];
65 	extern	const struct	mds	hmodes[];
66 	extern	const struct	mds	clkmodes[];
67 
68 	while(--argc > 0) {
69 
70 		s_arg = *++argv;
71 		match = 0;
72 		if ((term & ASYNC) || term == -1) {
73 			if (eqarg("erase", argc) && --argc)
74 				cb->c_cc[VERASE] = gct(*++argv, term);
75 			else if (eqarg("intr", argc) && --argc)
76 				cb->c_cc[VINTR] = gct(*++argv, term);
77 			else if (eqarg("quit", argc) && --argc)
78 				cb->c_cc[VQUIT] = gct(*++argv, term);
79 			else if (eqarg("eof", argc) && --argc)
80 				cb->c_cc[VEOF] = gct(*++argv, term);
81 			else if (eqarg("min", argc) && --argc)
82 				cb->c_cc[VMIN] = atoi(*++argv);
83 			else if (eqarg("eol", argc) && --argc)
84 				cb->c_cc[VEOL] = gct(*++argv, term);
85 			else if (eqarg("brk", argc) && --argc)
86 				cb->c_cc[VEOL] = gct(*++argv, term);
87 			else if (eqarg("eol2", argc) && --argc)
88 				cb->c_cc[VEOL2] = gct(*++argv, term);
89 			else if (eqarg("time", argc) && --argc)
90 				cb->c_cc[VTIME] = atoi(*++argv);
91 			else if (eqarg("kill", argc) && --argc)
92 				cb->c_cc[VKILL] = gct(*++argv, term);
93 			else if (eqarg("swtch", argc) && --argc)
94 				cb->c_cc[VSWTCH] = gct(*++argv, term);
95 			if(match)
96 				continue;
97 			if((term & TERMIOS) || term == -1) {
98 				if (eqarg("start", argc) && --argc)
99 					cb->c_cc[VSTART] = gct(*++argv, term);
100 				else if (eqarg("stop", argc) && --argc)
101 					cb->c_cc[VSTOP] = gct(*++argv, term);
102 				else if (eqarg("susp", argc) && --argc)
103 					cb->c_cc[VSUSP] = gct(*++argv, term);
104 				else if (eqarg("dsusp", argc) && --argc)
105 					cb->c_cc[VDSUSP] = gct(*++argv, term);
106 				else if (eqarg("rprnt", argc) && --argc)
107 					cb->c_cc[VREPRINT] = gct(*++argv, term);
108 				else if (eqarg("flush", argc) && --argc)
109 					cb->c_cc[VDISCARD] = gct(*++argv, term);
110 				else if (eqarg("werase", argc) && --argc)
111 					cb->c_cc[VWERASE] = gct(*++argv, term);
112 				else if (eqarg("lnext", argc) && --argc)
113 					cb->c_cc[VLNEXT] = gct(*++argv, term);
114 			}
115 			if(match)
116 				continue;
117 			if (eq("ek")) {
118 				cb->c_cc[VERASE] = CERASE;
119 				cb->c_cc[VKILL] = CKILL;
120 			}
121 			else if (eq("crt") || eq("newcrt")) {
122 				cb->c_lflag &= ~ECHOPRT;
123 				cb->c_lflag |= ECHOE|ECHOCTL;
124 				if (cfgetospeed(cb) >= B1200)
125 					cb->c_lflag |= ECHOKE;
126 			}
127 			else if (eq("dec")) {
128 				cb->c_cc[VERASE] = 0177;
129 				cb->c_cc[VKILL] = CTRL('u');
130 				cb->c_cc[VINTR] = CTRL('c');
131 				cb->c_lflag &= ~ECHOPRT;
132 				cb->c_lflag |= ECHOE|ECHOCTL|IEXTEN;
133 				if (cfgetospeed(cb) >= B1200)
134 					cb->c_lflag |= ECHOKE;
135 			}
136 			else if (eqarg("line", argc) && (!(term & TERMIOS) || term == -1) && --argc) {
137 				ocb->c_line = atoi(*++argv);
138 				continue;
139 			}
140 			else if (eq("raw") || eq("cbreak")) {
141 				cb->c_cc[VMIN] = 1;
142 				cb->c_cc[VTIME] = 0;
143 			}
144 			else if (eq("-raw") || eq("-cbreak") || eq("cooked")) {
145 				cb->c_cc[VEOF] = CEOF;
146 				cb->c_cc[VEOL] = CNUL;
147 			}
148 			else if(eq("sane")) {
149 				cb->c_cc[VERASE] = CERASE;
150 				cb->c_cc[VKILL] = CKILL;
151 				cb->c_cc[VQUIT] = CQUIT;
152 				cb->c_cc[VINTR] = CINTR;
153 				cb->c_cc[VEOF] = CEOF;
154 				cb->c_cc[VEOL] = CNUL;
155 							   /* SWTCH purposely not set */
156 			}
157 			else if((term & TERMIOS) && eqarg("ospeed", argc) && --argc) {
158 				s_arg = *++argv;
159 				match = 0;
160 				for(i=0; speeds[i].string; i++)
161 					if(eq(speeds[i].string))
162 					    cfsetospeed(cb, speeds[i].speed);
163 				if(!match)
164 					return s_arg;
165 				continue;
166 			}
167 			else if((term & TERMIOS) && eqarg("ispeed", argc) && --argc) {
168 				s_arg = *++argv;
169 				match = 0;
170 				for(i=0; speeds[i].string; i++)
171 					if(eq(speeds[i].string))
172 					    cfsetispeed(cb, speeds[i].speed);
173 				if(!match)
174 					return s_arg;
175 				continue;
176 			}
177 			else if (argc == 0) {
178 				(void) fprintf(stderr, "stty: No argument for \"%s\"\n", s_arg);
179 				exit(1);
180 			}
181 			for(i=0; speeds[i].string; i++)
182 				if(eq(speeds[i].string)) {
183 					cfsetospeed(cb, B0);
184 					cfsetispeed(cb, B0);
185 					cfsetospeed(cb, speeds[i].speed);
186 				}
187 		}
188 		if ((!(term & ASYNC) || term == -1) && eqarg("ctab", argc) && --argc) {
189 			cb->c_cc[7] = gct(*++argv, term);
190 			continue;
191 		}
192 		else if (argc == 0) {
193 			(void) fprintf(stderr, "stty: No argument for \"%s\"\n", s_arg);
194 			exit(1);
195 		}
196 
197 		for(i=0; imodes[i].string; i++)
198 			if(eq(imodes[i].string)) {
199 				cb->c_iflag &= ~imodes[i].reset;
200 				cb->c_iflag |= imodes[i].set;
201 			}
202 		if((term & TERMIOS) || term == -1) {
203 			for(i=0; nimodes[i].string; i++)
204 				if(eq(nimodes[i].string)) {
205 					cb->c_iflag &= ~nimodes[i].reset;
206 					cb->c_iflag |= nimodes[i].set;
207 				}
208 		}
209 
210 		for(i=0; omodes[i].string; i++)
211 			if(eq(omodes[i].string)) {
212 				cb->c_oflag &= ~omodes[i].reset;
213 				cb->c_oflag |= omodes[i].set;
214 			}
215 		if((!(term & ASYNC) || term == -1) && eq("sane")) {
216 			cb->c_oflag |= TAB3;
217 			continue;
218 		}
219 		for(i=0; cmodes[i].string; i++)
220 			if(eq(cmodes[i].string)) {
221 				cb->c_cflag &= ~cmodes[i].reset;
222 				cb->c_cflag |= cmodes[i].set;
223 			}
224 		if((term & TERMIOS) || term == -1)
225 			for(i=0; ncmodes[i].string; i++)
226 				if(eq(ncmodes[i].string)) {
227 					cb->c_cflag &= ~ncmodes[i].reset;
228 					cb->c_cflag |= ncmodes[i].set;
229 				}
230 		for(i=0; lmodes[i].string; i++)
231 			if(eq(lmodes[i].string)) {
232 				cb->c_lflag &= ~lmodes[i].reset;
233 				cb->c_lflag |= lmodes[i].set;
234 			}
235 		if((term & TERMIOS) || term == -1)
236 			for(i=0; nlmodes[i].string; i++)
237 				if(eq(nlmodes[i].string)) {
238 					cb->c_lflag &= ~nlmodes[i].reset;
239 					cb->c_lflag |= nlmodes[i].set;
240 				}
241 		if((term & FLOW) || term == -1) {
242 			for(i=0; hmodes[i].string; i++)
243 				if(eq(hmodes[i].string)) {
244 					termiox->x_hflag &= ~hmodes[i].reset;
245 					termiox->x_hflag |= hmodes[i].set;
246 				}
247 			for(i=0; clkmodes[i].string; i++)
248 				if(eq(clkmodes[i].string)) {
249 					termiox->x_cflag &= ~clkmodes[i].reset;
250 					termiox->x_cflag |= clkmodes[i].set;
251 				}
252 
253 		}
254 		if(eqarg("rows", argc) && --argc)
255 			winsize->ws_row = atoi(*++argv);
256 		else if((eqarg("columns", argc) || eqarg("cols", argc)) && --argc)
257 			winsize->ws_col = atoi(*++argv);
258 		else if(eqarg("xpixels", argc) && --argc)
259 			winsize->ws_xpixel = atoi(*++argv);
260 		else if(eqarg("ypixels", argc) && --argc)
261 			winsize->ws_ypixel = atoi(*++argv);
262 		else if (argc == 0) {
263 			(void) fprintf(stderr, "stty: No argument for \"%s\"\n", s_arg);
264 			exit(1);
265 		}
266 		if(!match)
267 			if(!encode(cb, term)) {
268 				return(s_arg); /* parsing failed */
269 			}
270 	}
271 	return((char *)0);
272 }
273 
274 static int eq(string)
275 char *string;
276 {
277 	int i;
278 
279 	if(!s_arg)
280 		return(0);
281 	i = 0;
282 loop:
283 	if(s_arg[i] != string[i])
284 		return(0);
285 	if(s_arg[i++] != '\0')
286 		goto loop;
287 	match++;
288 	return(1);
289 }
290 
291 /* Checks for options that require an argument */
292 static int
293 eqarg(char *string, int argc)
294 {
295 	int status;
296 
297 	if ((status = eq(string)) == 1) {
298 		if (argc <= 1) {
299 			(void) fprintf(stderr, "stty: No argument for \"%s\"\n",
300 					 	s_arg);
301 			exit(1);
302 		}
303 	}
304 	return(status);
305 }
306 
307 /* get pseudo control characters from terminal */
308 /* and convert to internal representation      */
309 static int gct(cp, term)
310 char *cp;
311 int term;
312 {
313 	int c;
314 
315 	c = *cp++;
316 	if (c == '^') {
317 		c = *cp;
318 		if (c == '?')
319 			c = 0177;		/* map '^?' to DEL */
320 		else if (c == '-')
321 			c = (term & TERMIOS) ? _POSIX_VDISABLE : 0200;		/* map '^-' to undefined */
322 		else
323 			c &= 037;
324 	}
325 	return(c);
326 }
327 
328 /* get modes of tty device and fill in applicable structures */
329 int
330 get_ttymode(fd, termio, termios, stermio, termiox, winsize)
331 int fd;
332 struct termio *termio;
333 struct termios *termios;
334 struct stio *stermio;
335 struct termiox *termiox;
336 struct winsize *winsize;
337 {
338 	int i;
339 	int term = 0;
340 	if(ioctl(fd, STGET, stermio) == -1) {
341 		term |= ASYNC;
342 		if(ioctl(fd, TCGETS, termios) == -1) {
343 			if(ioctl(fd, TCGETA, termio) == -1)
344 				return -1;
345 			termios->c_lflag = termio->c_lflag;
346 			termios->c_oflag = termio->c_oflag;
347 			termios->c_iflag = termio->c_iflag;
348 			termios->c_cflag = termio->c_cflag;
349 			for(i = 0; i < NCC; i++)
350 				termios->c_cc[i] = termio->c_cc[i];
351 		} else
352 			term |= TERMIOS;
353 	}
354 	else {
355 		termios->c_cc[7] = (unsigned)stermio->tab;
356 		termios->c_lflag = stermio->lmode;
357 		termios->c_oflag = stermio->omode;
358 		termios->c_iflag = stermio->imode;
359 	}
360 
361 	if(ioctl(fd, TCGETX, termiox) == 0)
362 		term |= FLOW;
363 
364 	if(ioctl(fd, TIOCGWINSZ, winsize) == 0)
365 		term |= WINDOW;
366 	return term;
367 }
368 
369 /* set tty modes */
370 int
371 set_ttymode(fd, term, termio, termios, stermio, termiox, winsize, owinsize)
372 int fd, term;
373 struct termio *termio;
374 struct termios *termios;
375 struct stio *stermio;
376 struct termiox *termiox;
377 struct winsize *winsize, *owinsize;
378 {
379 	int i;
380 	if (term & ASYNC) {
381 		if(term & TERMIOS) {
382 			if(ioctl(fd, TCSETSW, termios) == -1)
383 				return -1;
384 		} else {
385 			termio->c_lflag = termios->c_lflag;
386 			termio->c_oflag = termios->c_oflag;
387 			termio->c_iflag = termios->c_iflag;
388 			termio->c_cflag = termios->c_cflag;
389 			for(i = 0; i < NCC; i++)
390 				termio->c_cc[i] = termios->c_cc[i];
391 			if(ioctl(fd, TCSETAW, termio) == -1)
392 				return -1;
393 		}
394 
395 	} else {
396 		stermio->imode = termios->c_iflag;
397 		stermio->omode = termios->c_oflag;
398 		stermio->lmode = termios->c_lflag;
399 		stermio->tab = termios->c_cc[7];
400 		if (ioctl(fd, STSET, stermio) == -1)
401 			return -1;
402 	}
403 	if(term & FLOW) {
404 		if(ioctl(fd, TCSETXW, termiox) == -1)
405 			return -1;
406 	}
407 	if((owinsize->ws_col != winsize->ws_col
408 	   || owinsize->ws_row != winsize->ws_row)
409 	   && ioctl(0, TIOCSWINSZ, winsize) != 0)
410 		return -1;
411 	return 0;
412 }
413 
414 static int encode(cb, term)
415 struct	termios	*cb;
416 int term;
417 {
418 	unsigned long grab[20], i;
419 	int last;
420 	i = sscanf(s_arg,
421 	"%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx",
422 	&grab[0],&grab[1],&grab[2],&grab[3],&grab[4],&grab[5],&grab[6],
423 	&grab[7],&grab[8],&grab[9],&grab[10],&grab[11],
424 	&grab[12], &grab[13], &grab[14], &grab[15],
425 	&grab[16], &grab[17], &grab[18], &grab[19]);
426 
427 	if((term & TERMIOS) && i < 20 && term != -1 || i < 12)
428 		return(0);
429 	cb->c_iflag = grab[0];
430 	cb->c_oflag = grab[1];
431 	cb->c_cflag = grab[2];
432 	cb->c_lflag = grab[3];
433 
434 	if(term & TERMIOS)
435 		last = NCCS - 1;
436 	else
437 		last = NCC;
438 	for(i=0; i<last; i++)
439 		cb->c_cc[i] = (unsigned char) grab[i+4];
440 	return(1);
441 }
442 
443