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