blob: 33f7b21dd0563a9d9e52d351cd412c3317759ccd [file] [log] [blame]
Eric Andersen98e599c2001-02-14 18:47:33 +00001/* vi: set sw=4 ts=4: */
2/* stty -- change and print terminal line settings
3 Copyright (C) 1990-1999 Free Software Foundation, Inc.
4
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00005 Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
6*/
Eric Andersen98e599c2001-02-14 18:47:33 +00007/* Usage: stty [-ag] [-F device] [setting...]
8
9 Options:
10 -a Write all current settings to stdout in human-readable form.
11 -g Write all current settings to stdout in stty-readable form.
12 -F Open and use the specified device instead of stdin
13
14 If no args are given, write to stdout the baud rate and settings that
15 have been changed from their defaults. Mode reading and changes
16 are done on the specified device, or stdin if none was specified.
17
18 David MacKenzie <djm@gnu.ai.mit.edu>
19
Eric Andersen7467c8d2001-07-12 20:26:32 +000020 Special for busybox ported by Vladimir Oleynik <dzo@simtreas.ru> 2001
Eric Andersen98e599c2001-02-14 18:47:33 +000021
22 */
23
Denis Vlasenkob6adbf12007-05-26 19:00:18 +000024#include "libbb.h"
Eric Andersen98e599c2001-02-14 18:47:33 +000025
Eric Andersen98e599c2001-02-14 18:47:33 +000026#ifndef _POSIX_VDISABLE
27# define _POSIX_VDISABLE ((unsigned char) 0)
28#endif
29
30#define Control(c) ((c) & 0x1f)
Denis Vlasenko9efb0702006-09-19 14:17:10 +000031/* Canonical values for control characters */
Eric Andersen98e599c2001-02-14 18:47:33 +000032#ifndef CINTR
Denis Vlasenko9efb0702006-09-19 14:17:10 +000033# define CINTR Control('c')
Eric Andersen98e599c2001-02-14 18:47:33 +000034#endif
35#ifndef CQUIT
36# define CQUIT 28
37#endif
38#ifndef CERASE
39# define CERASE 127
40#endif
41#ifndef CKILL
Denis Vlasenko9efb0702006-09-19 14:17:10 +000042# define CKILL Control('u')
Eric Andersen98e599c2001-02-14 18:47:33 +000043#endif
44#ifndef CEOF
Denis Vlasenko9efb0702006-09-19 14:17:10 +000045# define CEOF Control('d')
Eric Andersen98e599c2001-02-14 18:47:33 +000046#endif
47#ifndef CEOL
48# define CEOL _POSIX_VDISABLE
49#endif
50#ifndef CSTART
Denis Vlasenko9efb0702006-09-19 14:17:10 +000051# define CSTART Control('q')
Eric Andersen98e599c2001-02-14 18:47:33 +000052#endif
53#ifndef CSTOP
Denis Vlasenko9efb0702006-09-19 14:17:10 +000054# define CSTOP Control('s')
Eric Andersen98e599c2001-02-14 18:47:33 +000055#endif
56#ifndef CSUSP
Denis Vlasenko9efb0702006-09-19 14:17:10 +000057# define CSUSP Control('z')
Eric Andersen98e599c2001-02-14 18:47:33 +000058#endif
59#if defined(VEOL2) && !defined(CEOL2)
60# define CEOL2 _POSIX_VDISABLE
61#endif
Denis Vlasenko9efb0702006-09-19 14:17:10 +000062/* ISC renamed swtch to susp for termios, but we'll accept either name */
Eric Andersen98e599c2001-02-14 18:47:33 +000063#if defined(VSUSP) && !defined(VSWTCH)
64# define VSWTCH VSUSP
65# define CSWTCH CSUSP
66#endif
67#if defined(VSWTCH) && !defined(CSWTCH)
68# define CSWTCH _POSIX_VDISABLE
69#endif
70
Denis Vlasenko79deb662006-09-19 15:12:12 +000071/* SunOS 5.3 loses (^Z doesn't work) if 'swtch' is the same as 'susp'.
72 So the default is to disable 'swtch.' */
Denis Vlasenkoff131b92007-04-10 15:42:06 +000073#if defined(__sparc__) && defined(__svr4__)
Eric Andersen98e599c2001-02-14 18:47:33 +000074# undef CSWTCH
75# define CSWTCH _POSIX_VDISABLE
76#endif
77
Denis Vlasenkoff131b92007-04-10 15:42:06 +000078#if defined(VWERSE) && !defined(VWERASE) /* AIX-3.2.5 */
Eric Andersen98e599c2001-02-14 18:47:33 +000079# define VWERASE VWERSE
80#endif
Denis Vlasenkoff131b92007-04-10 15:42:06 +000081#if defined(VDSUSP) && !defined(CDSUSP)
Denis Vlasenko9efb0702006-09-19 14:17:10 +000082# define CDSUSP Control('y')
Eric Andersen98e599c2001-02-14 18:47:33 +000083#endif
Mark Whitley446dd272001-03-02 20:00:54 +000084#if !defined(VREPRINT) && defined(VRPRNT) /* Irix 4.0.5 */
Eric Andersen98e599c2001-02-14 18:47:33 +000085# define VREPRINT VRPRNT
86#endif
87#if defined(VREPRINT) && !defined(CRPRNT)
Denis Vlasenko9efb0702006-09-19 14:17:10 +000088# define CRPRNT Control('r')
Eric Andersen98e599c2001-02-14 18:47:33 +000089#endif
90#if defined(VWERASE) && !defined(CWERASE)
Denis Vlasenko9efb0702006-09-19 14:17:10 +000091# define CWERASE Control('w')
Eric Andersen98e599c2001-02-14 18:47:33 +000092#endif
93#if defined(VLNEXT) && !defined(CLNEXT)
Denis Vlasenko9efb0702006-09-19 14:17:10 +000094# define CLNEXT Control('v')
Eric Andersen98e599c2001-02-14 18:47:33 +000095#endif
96#if defined(VDISCARD) && !defined(VFLUSHO)
97# define VFLUSHO VDISCARD
98#endif
Mark Whitley446dd272001-03-02 20:00:54 +000099#if defined(VFLUSH) && !defined(VFLUSHO) /* Ultrix 4.2 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000100# define VFLUSHO VFLUSH
101#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000102#if defined(CTLECH) && !defined(ECHOCTL) /* Ultrix 4.3 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000103# define ECHOCTL CTLECH
104#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000105#if defined(TCTLECH) && !defined(ECHOCTL) /* Ultrix 4.2 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000106# define ECHOCTL TCTLECH
107#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000108#if defined(CRTKIL) && !defined(ECHOKE) /* Ultrix 4.2 and 4.3 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000109# define ECHOKE CRTKIL
110#endif
111#if defined(VFLUSHO) && !defined(CFLUSHO)
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000112# define CFLUSHO Control('o')
Eric Andersen98e599c2001-02-14 18:47:33 +0000113#endif
114#if defined(VSTATUS) && !defined(CSTATUS)
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000115# define CSTATUS Control('t')
Eric Andersen98e599c2001-02-14 18:47:33 +0000116#endif
117
Jeremie Koenig138ce542010-07-30 06:01:37 +0200118/* Save us from #ifdef forest plague */
119#ifndef BSDLY
120# define BSDLY 0
121#endif
122#ifndef CIBAUD
123# define CIBAUD 0
124#endif
125#ifndef CRDLY
126# define CRDLY 0
127#endif
128#ifndef CRTSCTS
129# define CRTSCTS 0
130#endif
131#ifndef ECHOCTL
132# define ECHOCTL 0
133#endif
134#ifndef ECHOKE
135# define ECHOKE 0
136#endif
137#ifndef ECHOPRT
138# define ECHOPRT 0
139#endif
140#ifndef FFDLY
141# define FFDLY 0
142#endif
143#ifndef IEXTEN
144# define IEXTEN 0
145#endif
146#ifndef IMAXBEL
147# define IMAXBEL 0
148#endif
149#ifndef IUCLC
150# define IUCLC 0
151#endif
152#ifndef IXANY
153# define IXANY 0
154#endif
155#ifndef NLDLY
156# define NLDLY 0
157#endif
158#ifndef OCRNL
159# define OCRNL 0
160#endif
161#ifndef OFDEL
162# define OFDEL 0
163#endif
164#ifndef OFILL
165# define OFILL 0
166#endif
167#ifndef OLCUC
168# define OLCUC 0
169#endif
170#ifndef ONLCR
171# define ONLCR 0
172#endif
173#ifndef ONLRET
174# define ONLRET 0
175#endif
176#ifndef ONOCR
177# define ONOCR 0
178#endif
179#ifndef OXTABS
180# define OXTABS 0
181#endif
182#ifndef TABDLY
183# define TABDLY 0
184#endif
185#ifndef TAB1
186# define TAB1 0
187#endif
188#ifndef TAB2
189# define TAB2 0
190#endif
191#ifndef TOSTOP
192# define TOSTOP 0
193#endif
194#ifndef VDSUSP
195# define VDSUSP 0
196#endif
197#ifndef VEOL2
198# define VEOL2 0
199#endif
200#ifndef VFLUSHO
201# define VFLUSHO 0
202#endif
203#ifndef VLNEXT
204# define VLNEXT 0
205#endif
206#ifndef VREPRINT
207# define VREPRINT 0
208#endif
209#ifndef VSTATUS
210# define VSTATUS 0
211#endif
212#ifndef VSWTCH
213# define VSWTCH 0
214#endif
215#ifndef VTDLY
216# define VTDLY 0
217#endif
218#ifndef VWERASE
219# define VWERASE 0
220#endif
221#ifndef XCASE
222# define XCASE 0
223#endif
224
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000225/* Which speeds to set */
Eric Andersen98e599c2001-02-14 18:47:33 +0000226enum speed_setting {
227 input_speed, output_speed, both_speeds
228};
229
Denis Vlasenko79deb662006-09-19 15:12:12 +0000230/* Which member(s) of 'struct termios' a mode uses */
Denis Vlasenko20b253d2006-09-19 14:24:23 +0000231enum {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000232 /* Do NOT change the order or values, as mode_type_flag()
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000233 * depends on them */
Eric Andersen98e599c2001-02-14 18:47:33 +0000234 control, input, output, local, combination
235};
236
Denis Vlasenko79deb662006-09-19 15:12:12 +0000237/* Flags for 'struct mode_info' */
238#define SANE_SET 1 /* Set in 'sane' mode */
239#define SANE_UNSET 2 /* Unset in 'sane' mode */
240#define REV 4 /* Can be turned off by prepending '-' */
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000241#define OMIT 8 /* Don't display value */
Eric Andersen98e599c2001-02-14 18:47:33 +0000242
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000243
244/* Each mode.
245 * This structure should be kept as small as humanly possible.
246 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000247struct mode_info {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000248 const uint8_t type; /* Which structure element to change */
249 const uint8_t flags; /* Setting and display options */
250 /* only these values are ever used, so... */
251#if (CSIZE | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY) < 0x100
252 const uint8_t mask;
253#elif (CSIZE | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY) < 0x10000
254 const uint16_t mask;
255#else
Bernhard Reutner-Fischer21fc7402007-01-17 19:44:24 +0000256 const tcflag_t mask; /* Other bits to turn off for this mode */
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000257#endif
258 /* was using short here, but ppc32 was unhappy */
Bernhard Reutner-Fischer21fc7402007-01-17 19:44:24 +0000259 const tcflag_t bits; /* Bits to set for this mode */
Eric Andersen98e599c2001-02-14 18:47:33 +0000260};
261
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000262enum {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000263 /* Must match mode_name[] and mode_info[] order! */
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000264 IDX_evenp = 0,
265 IDX_parity,
266 IDX_oddp,
267 IDX_nl,
268 IDX_ek,
269 IDX_sane,
270 IDX_cooked,
271 IDX_raw,
272 IDX_pass8,
273 IDX_litout,
274 IDX_cbreak,
275 IDX_crt,
276 IDX_dec,
Jeremie Koenig138ce542010-07-30 06:01:37 +0200277#if IXANY
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000278 IDX_decctlq,
279#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200280#if TABDLY || OXTABS
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000281 IDX_tabs,
282#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200283#if XCASE && IUCLC && OLCUC
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000284 IDX_lcase,
285 IDX_LCASE,
286#endif
287};
Denis Vlasenkob2abef32007-01-01 18:18:04 +0000288
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000289#define MI_ENTRY(N,T,F,B,M) N "\0"
Manuel Novoa III cad53642003-03-19 09:13:01 +0000290
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000291/* Mode names given on command line */
292static const char mode_name[] =
293 MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 )
294 MI_ENTRY("parity", combination, REV | OMIT, 0, 0 )
295 MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 )
296 MI_ENTRY("nl", combination, REV | OMIT, 0, 0 )
297 MI_ENTRY("ek", combination, OMIT, 0, 0 )
298 MI_ENTRY("sane", combination, OMIT, 0, 0 )
299 MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 )
300 MI_ENTRY("raw", combination, REV | OMIT, 0, 0 )
301 MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 )
302 MI_ENTRY("litout", combination, REV | OMIT, 0, 0 )
303 MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 )
304 MI_ENTRY("crt", combination, OMIT, 0, 0 )
305 MI_ENTRY("dec", combination, OMIT, 0, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200306#if IXANY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000307 MI_ENTRY("decctlq", combination, REV | OMIT, 0, 0 )
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000308#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200309#if TABDLY || OXTABS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000310 MI_ENTRY("tabs", combination, REV | OMIT, 0, 0 )
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000311#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200312#if XCASE && IUCLC && OLCUC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000313 MI_ENTRY("lcase", combination, REV | OMIT, 0, 0 )
314 MI_ENTRY("LCASE", combination, REV | OMIT, 0, 0 )
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000315#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000316 MI_ENTRY("parenb", control, REV, PARENB, 0 )
317 MI_ENTRY("parodd", control, REV, PARODD, 0 )
318 MI_ENTRY("cs5", control, 0, CS5, CSIZE)
319 MI_ENTRY("cs6", control, 0, CS6, CSIZE)
320 MI_ENTRY("cs7", control, 0, CS7, CSIZE)
321 MI_ENTRY("cs8", control, 0, CS8, CSIZE)
322 MI_ENTRY("hupcl", control, REV, HUPCL, 0 )
323 MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 )
324 MI_ENTRY("cstopb", control, REV, CSTOPB, 0 )
325 MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 )
326 MI_ENTRY("clocal", control, REV, CLOCAL, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200327#if CRTSCTS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000328 MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000329#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000330 MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 )
331 MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 )
332 MI_ENTRY("ignpar", input, REV, IGNPAR, 0 )
333 MI_ENTRY("parmrk", input, REV, PARMRK, 0 )
334 MI_ENTRY("inpck", input, REV, INPCK, 0 )
335 MI_ENTRY("istrip", input, REV, ISTRIP, 0 )
336 MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 )
337 MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 )
338 MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 )
339 MI_ENTRY("ixon", input, REV, IXON, 0 )
340 MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 )
341 MI_ENTRY("tandem", input, REV | OMIT, IXOFF, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200342#if IUCLC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000343 MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000344#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200345#if IXANY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000346 MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000347#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200348#if IMAXBEL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000349 MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000350#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000351 MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200352#if OLCUC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000353 MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000354#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200355#if OCRNL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000356 MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000357#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200358#if ONLCR
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000359 MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000360#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200361#if ONOCR
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000362 MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000363#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200364#if ONLRET
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000365 MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000366#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200367#if OFILL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000368 MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000369#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200370#if OFDEL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000371 MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000372#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200373#if NLDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000374 MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY)
375 MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000376#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200377#if CRDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000378 MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY)
379 MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY)
380 MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY)
381 MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000382#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000383
Jeremie Koenig138ce542010-07-30 06:01:37 +0200384#if TABDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000385 MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200386# if TAB2
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000387 MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200388# endif
389# if TAB1
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000390 MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200391# endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000392 MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000393#else
Jeremie Koenig138ce542010-07-30 06:01:37 +0200394# if OXTABS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000395 MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000396# endif
397#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000398
Jeremie Koenig138ce542010-07-30 06:01:37 +0200399#if BSDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000400 MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY)
401 MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000402#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200403#if VTDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000404 MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY)
405 MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000406#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200407#if FFDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000408 MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY)
409 MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000410#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000411 MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 )
412 MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200413#if IEXTEN
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000414 MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000415#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000416 MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 )
417 MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 )
418 MI_ENTRY("crterase", local, REV | OMIT, ECHOE, 0 )
419 MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 )
420 MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 )
421 MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200422#if XCASE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000423 MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000424#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200425#if TOSTOP
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000426 MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000427#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200428#if ECHOPRT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000429 MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 )
430 MI_ENTRY("prterase", local, REV | OMIT, ECHOPRT, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000431#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200432#if ECHOCTL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000433 MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 )
434 MI_ENTRY("ctlecho", local, REV | OMIT, ECHOCTL, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000435#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200436#if ECHOKE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000437 MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 )
438 MI_ENTRY("crtkill", local, REV | OMIT, ECHOKE, 0 )
439#endif
440 ;
441
442#undef MI_ENTRY
443#define MI_ENTRY(N,T,F,B,M) { T, F, M, B },
444
445static const struct mode_info mode_info[] = {
446 /* This should be verbatim cut-n-paste copy of the above MI_ENTRYs */
447 MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 )
448 MI_ENTRY("parity", combination, REV | OMIT, 0, 0 )
449 MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 )
450 MI_ENTRY("nl", combination, REV | OMIT, 0, 0 )
451 MI_ENTRY("ek", combination, OMIT, 0, 0 )
452 MI_ENTRY("sane", combination, OMIT, 0, 0 )
453 MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 )
454 MI_ENTRY("raw", combination, REV | OMIT, 0, 0 )
455 MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 )
456 MI_ENTRY("litout", combination, REV | OMIT, 0, 0 )
457 MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 )
458 MI_ENTRY("crt", combination, OMIT, 0, 0 )
459 MI_ENTRY("dec", combination, OMIT, 0, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200460#if IXANY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000461 MI_ENTRY("decctlq", combination, REV | OMIT, 0, 0 )
462#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200463#if TABDLY || OXTABS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000464 MI_ENTRY("tabs", combination, REV | OMIT, 0, 0 )
465#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200466#if XCASE && IUCLC && OLCUC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000467 MI_ENTRY("lcase", combination, REV | OMIT, 0, 0 )
468 MI_ENTRY("LCASE", combination, REV | OMIT, 0, 0 )
469#endif
470 MI_ENTRY("parenb", control, REV, PARENB, 0 )
471 MI_ENTRY("parodd", control, REV, PARODD, 0 )
472 MI_ENTRY("cs5", control, 0, CS5, CSIZE)
473 MI_ENTRY("cs6", control, 0, CS6, CSIZE)
474 MI_ENTRY("cs7", control, 0, CS7, CSIZE)
475 MI_ENTRY("cs8", control, 0, CS8, CSIZE)
476 MI_ENTRY("hupcl", control, REV, HUPCL, 0 )
477 MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 )
478 MI_ENTRY("cstopb", control, REV, CSTOPB, 0 )
479 MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 )
480 MI_ENTRY("clocal", control, REV, CLOCAL, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200481#if CRTSCTS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000482 MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 )
483#endif
484 MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 )
485 MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 )
486 MI_ENTRY("ignpar", input, REV, IGNPAR, 0 )
487 MI_ENTRY("parmrk", input, REV, PARMRK, 0 )
488 MI_ENTRY("inpck", input, REV, INPCK, 0 )
489 MI_ENTRY("istrip", input, REV, ISTRIP, 0 )
490 MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 )
491 MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 )
492 MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 )
493 MI_ENTRY("ixon", input, REV, IXON, 0 )
494 MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 )
495 MI_ENTRY("tandem", input, REV | OMIT, IXOFF, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200496#if IUCLC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000497 MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 )
498#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200499#if IXANY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000500 MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 )
501#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200502#if IMAXBEL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000503 MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 )
504#endif
505 MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200506#if OLCUC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000507 MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 )
508#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200509#if OCRNL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000510 MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 )
511#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200512#if ONLCR
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000513 MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 )
514#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200515#if ONOCR
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000516 MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 )
517#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200518#if ONLRET
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000519 MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 )
520#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200521#if OFILL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000522 MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 )
523#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200524#if OFDEL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000525 MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 )
526#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200527#if NLDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000528 MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY)
529 MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY)
530#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200531#if CRDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000532 MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY)
533 MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY)
534 MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY)
535 MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY)
536#endif
537
Jeremie Koenig138ce542010-07-30 06:01:37 +0200538#if TABDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000539 MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200540# if TAB2
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000541 MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200542# endif
543# if TAB1
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000544 MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200545# endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000546 MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY)
547#else
Jeremie Koenig138ce542010-07-30 06:01:37 +0200548# if OXTABS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000549 MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 )
550# endif
551#endif
552
Jeremie Koenig138ce542010-07-30 06:01:37 +0200553#if BSDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000554 MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY)
555 MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY)
556#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200557#if VTDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000558 MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY)
559 MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY)
560#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200561#if FFDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000562 MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY)
563 MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY)
564#endif
565 MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 )
566 MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200567#if IEXTEN
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000568 MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 )
569#endif
570 MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 )
571 MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 )
572 MI_ENTRY("crterase", local, REV | OMIT, ECHOE, 0 )
573 MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 )
574 MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 )
575 MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200576#if XCASE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000577 MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 )
578#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200579#if TOSTOP
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000580 MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 )
581#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200582#if ECHOPRT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000583 MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 )
584 MI_ENTRY("prterase", local, REV | OMIT, ECHOPRT, 0 )
585#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200586#if ECHOCTL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000587 MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 )
588 MI_ENTRY("ctlecho", local, REV | OMIT, ECHOCTL, 0 )
589#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200590#if ECHOKE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000591 MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 )
592 MI_ENTRY("crtkill", local, REV | OMIT, ECHOKE, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000593#endif
Eric Andersen98e599c2001-02-14 18:47:33 +0000594};
595
Rob Landleybc68cd12006-03-10 19:22:06 +0000596enum {
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000597 NUM_mode_info = ARRAY_SIZE(mode_info)
Rob Landleybc68cd12006-03-10 19:22:06 +0000598};
Eric Andersen98e599c2001-02-14 18:47:33 +0000599
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000600
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000601/* Control characters */
Eric Andersen98e599c2001-02-14 18:47:33 +0000602struct control_info {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000603 const uint8_t saneval; /* Value to set for 'stty sane' */
604 const uint8_t offset; /* Offset in c_cc */
Eric Andersen98e599c2001-02-14 18:47:33 +0000605};
606
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000607enum {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000608 /* Must match control_name[] and control_info[] order! */
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000609 CIDX_intr = 0,
610 CIDX_quit,
611 CIDX_erase,
612 CIDX_kill,
613 CIDX_eof,
614 CIDX_eol,
Jeremie Koenig138ce542010-07-30 06:01:37 +0200615#if VEOL2
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000616 CIDX_eol2,
617#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200618#if VSWTCH
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000619 CIDX_swtch,
620#endif
621 CIDX_start,
622 CIDX_stop,
623 CIDX_susp,
Jeremie Koenig138ce542010-07-30 06:01:37 +0200624#if VDSUSP
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000625 CIDX_dsusp,
626#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200627#if VREPRINT
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000628 CIDX_rprnt,
629#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200630#if VWERASE
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000631 CIDX_werase,
632#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200633#if VLNEXT
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000634 CIDX_lnext,
635#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200636#if VFLUSHO
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000637 CIDX_flush,
638#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200639#if VSTATUS
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000640 CIDX_status,
641#endif
642 CIDX_min,
643 CIDX_time,
644};
Eric Andersen98e599c2001-02-14 18:47:33 +0000645
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000646#define CI_ENTRY(n,s,o) n "\0"
647
648/* Name given on command line */
649static const char control_name[] =
650 CI_ENTRY("intr", CINTR, VINTR )
651 CI_ENTRY("quit", CQUIT, VQUIT )
652 CI_ENTRY("erase", CERASE, VERASE )
653 CI_ENTRY("kill", CKILL, VKILL )
654 CI_ENTRY("eof", CEOF, VEOF )
655 CI_ENTRY("eol", CEOL, VEOL )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200656#if VEOL2
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000657 CI_ENTRY("eol2", CEOL2, VEOL2 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000658#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200659#if VSWTCH
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000660 CI_ENTRY("swtch", CSWTCH, VSWTCH )
Eric Andersen98e599c2001-02-14 18:47:33 +0000661#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000662 CI_ENTRY("start", CSTART, VSTART )
663 CI_ENTRY("stop", CSTOP, VSTOP )
664 CI_ENTRY("susp", CSUSP, VSUSP )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200665#if VDSUSP
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000666 CI_ENTRY("dsusp", CDSUSP, VDSUSP )
Eric Andersen98e599c2001-02-14 18:47:33 +0000667#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200668#if VREPRINT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000669 CI_ENTRY("rprnt", CRPRNT, VREPRINT)
Eric Andersen98e599c2001-02-14 18:47:33 +0000670#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200671#if VWERASE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000672 CI_ENTRY("werase", CWERASE, VWERASE )
Eric Andersen98e599c2001-02-14 18:47:33 +0000673#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200674#if VLNEXT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000675 CI_ENTRY("lnext", CLNEXT, VLNEXT )
Eric Andersen98e599c2001-02-14 18:47:33 +0000676#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200677#if VFLUSHO
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000678 CI_ENTRY("flush", CFLUSHO, VFLUSHO )
Eric Andersen98e599c2001-02-14 18:47:33 +0000679#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200680#if VSTATUS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000681 CI_ENTRY("status", CSTATUS, VSTATUS )
Eric Andersen98e599c2001-02-14 18:47:33 +0000682#endif
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000683 /* These must be last because of the display routines */
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000684 CI_ENTRY("min", 1, VMIN )
685 CI_ENTRY("time", 0, VTIME )
686 ;
687
688#undef CI_ENTRY
689#define CI_ENTRY(n,s,o) { s, o },
690
691static const struct control_info control_info[] = {
692 /* This should be verbatim cut-n-paste copy of the above CI_ENTRYs */
693 CI_ENTRY("intr", CINTR, VINTR )
694 CI_ENTRY("quit", CQUIT, VQUIT )
695 CI_ENTRY("erase", CERASE, VERASE )
696 CI_ENTRY("kill", CKILL, VKILL )
697 CI_ENTRY("eof", CEOF, VEOF )
698 CI_ENTRY("eol", CEOL, VEOL )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200699#if VEOL2
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000700 CI_ENTRY("eol2", CEOL2, VEOL2 )
701#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200702#if VSWTCH
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000703 CI_ENTRY("swtch", CSWTCH, VSWTCH )
704#endif
705 CI_ENTRY("start", CSTART, VSTART )
706 CI_ENTRY("stop", CSTOP, VSTOP )
707 CI_ENTRY("susp", CSUSP, VSUSP )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200708#if VDSUSP
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000709 CI_ENTRY("dsusp", CDSUSP, VDSUSP )
710#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200711#if VREPRINT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000712 CI_ENTRY("rprnt", CRPRNT, VREPRINT)
713#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200714#if VWERASE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000715 CI_ENTRY("werase", CWERASE, VWERASE )
716#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200717#if VLNEXT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000718 CI_ENTRY("lnext", CLNEXT, VLNEXT )
719#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200720#if VFLUSHO
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000721 CI_ENTRY("flush", CFLUSHO, VFLUSHO )
722#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200723#if VSTATUS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000724 CI_ENTRY("status", CSTATUS, VSTATUS )
725#endif
726 /* These must be last because of the display routines */
727 CI_ENTRY("min", 1, VMIN )
728 CI_ENTRY("time", 0, VTIME )
Eric Andersen98e599c2001-02-14 18:47:33 +0000729};
730
Rob Landleybc68cd12006-03-10 19:22:06 +0000731enum {
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000732 NUM_control_info = ARRAY_SIZE(control_info)
Rob Landleybc68cd12006-03-10 19:22:06 +0000733};
Eric Andersen98e599c2001-02-14 18:47:33 +0000734
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000735
736struct globals {
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100737 const char *device_name;
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000738 /* The width of the screen, for output wrapping */
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100739 unsigned max_col;
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000740 /* Current position, to know when to wrap */
741 unsigned current_col;
742 char buf[10];
Denys Vlasenko98a4c7c2010-02-04 15:00:15 +0100743} FIX_ALIASING;
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000744#define G (*(struct globals*)&bb_common_bufsiz1)
Denis Vlasenko7049ff82008-06-25 09:53:17 +0000745#define INIT_G() do { \
746 G.device_name = bb_msg_standard_input; \
747 G.max_col = 80; \
748} while (0)
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000749
Eric Andersen8876fb22003-06-20 09:01:58 +0000750
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000751/* Return a string that is the printable representation of character CH */
Denis Vlasenko79deb662006-09-19 15:12:12 +0000752/* Adapted from 'cat' by Torbjorn Granlund */
Denis Vlasenko240a1cf2007-04-08 16:07:02 +0000753static const char *visible(unsigned ch)
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000754{
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000755 char *bpout = G.buf;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000756
757 if (ch == _POSIX_VDISABLE)
758 return "<undef>";
759
760 if (ch >= 128) {
761 ch -= 128;
762 *bpout++ = 'M';
763 *bpout++ = '-';
764 }
765
766 if (ch < 32) {
767 *bpout++ = '^';
768 *bpout++ = ch + 64;
769 } else if (ch < 127) {
770 *bpout++ = ch;
771 } else {
772 *bpout++ = '^';
773 *bpout++ = '?';
774 }
775
776 *bpout = '\0';
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000777 return G.buf;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000778}
779
780static tcflag_t *mode_type_flag(unsigned type, const struct termios *mode)
781{
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000782 static const uint8_t tcflag_offsets[] ALIGN1 = {
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000783 offsetof(struct termios, c_cflag), /* control */
784 offsetof(struct termios, c_iflag), /* input */
785 offsetof(struct termios, c_oflag), /* output */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000786 offsetof(struct termios, c_lflag) /* local */
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000787 };
788
789 if (type <= local) {
790 return (tcflag_t*) (((char*)mode) + tcflag_offsets[type]);
791 }
792 return NULL;
793}
794
Denis Vlasenkoc7cc5a92009-04-19 01:27:20 +0000795static void set_speed_or_die(enum speed_setting type, const char *arg,
796 struct termios *mode)
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000797{
798 speed_t baud;
799
Bernhard Reutner-Fischer4950f012007-01-17 19:44:59 +0000800 baud = tty_value_to_baud(xatou(arg));
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000801
802 if (type != output_speed) { /* either input or both */
803 cfsetispeed(mode, baud);
804 }
805 if (type != input_speed) { /* either output or both */
806 cfsetospeed(mode, baud);
807 }
808}
809
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000810static NORETURN void perror_on_device_and_die(const char *fmt)
Eric Andersen8876fb22003-06-20 09:01:58 +0000811{
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000812 bb_perror_msg_and_die(fmt, G.device_name);
Eric Andersen8876fb22003-06-20 09:01:58 +0000813}
814
Denis Vlasenko20b253d2006-09-19 14:24:23 +0000815static void perror_on_device(const char *fmt)
816{
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000817 bb_perror_msg(fmt, G.device_name);
Denis Vlasenko20b253d2006-09-19 14:24:23 +0000818}
819
Eric Andersen98e599c2001-02-14 18:47:33 +0000820/* Print format string MESSAGE and optional args.
821 Wrap to next line first if it won't fit.
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000822 Print a space first unless MESSAGE will start a new line */
Eric Andersen98e599c2001-02-14 18:47:33 +0000823static void wrapf(const char *message, ...)
824{
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +0000825 char buf[128];
Eric Andersen98e599c2001-02-14 18:47:33 +0000826 va_list args;
Denis Vlasenko77ad97f2008-05-13 02:27:31 +0000827 unsigned buflen;
Eric Andersen98e599c2001-02-14 18:47:33 +0000828
829 va_start(args, message);
Bernhard Reutner-Fischer8eb05492007-01-17 19:46:33 +0000830 buflen = vsnprintf(buf, sizeof(buf), message, args);
Eric Andersen98e599c2001-02-14 18:47:33 +0000831 va_end(args);
Bernhard Reutner-Fischer1a250d92007-01-18 08:41:22 +0000832 /* We seem to be called only with suitable lengths, but check if
833 somebody failed to adhere to this assumption just to be sure. */
834 if (!buflen || buflen >= sizeof(buf)) return;
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +0000835
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000836 if (G.current_col > 0) {
837 G.current_col++;
Denis Vlasenko79deb662006-09-19 15:12:12 +0000838 if (buf[0] != '\n') {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000839 if (G.current_col + buflen >= G.max_col) {
Denis Vlasenko4daad902007-09-27 10:20:47 +0000840 bb_putchar('\n');
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000841 G.current_col = 0;
Denis Vlasenko79deb662006-09-19 15:12:12 +0000842 } else
Denis Vlasenko4daad902007-09-27 10:20:47 +0000843 bb_putchar(' ');
Denis Vlasenko79deb662006-09-19 15:12:12 +0000844 }
Eric Andersen98e599c2001-02-14 18:47:33 +0000845 }
846 fputs(buf, stdout);
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000847 G.current_col += buflen;
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +0000848 if (buf[buflen-1] == '\n')
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000849 G.current_col = 0;
Eric Andersen98e599c2001-02-14 18:47:33 +0000850}
851
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100852static void newline(void)
853{
854 if (G.current_col != 0)
855 wrapf("\n");
856}
857
Jeremie Koenig138ce542010-07-30 06:01:37 +0200858#ifdef TIOCGWINSZ
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100859static void set_window_size(int rows, int cols)
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000860{
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000861 struct winsize win = { 0, 0, 0, 0 };
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000862
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000863 if (ioctl(STDIN_FILENO, TIOCGWINSZ, &win)) {
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000864 if (errno != EINVAL) {
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000865 goto bail;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000866 }
867 memset(&win, 0, sizeof(win));
868 }
869
870 if (rows >= 0)
871 win.ws_row = rows;
872 if (cols >= 0)
873 win.ws_col = cols;
874
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000875 if (ioctl(STDIN_FILENO, TIOCSWINSZ, (char *) &win))
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000876bail:
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000877 perror_on_device("%s");
878}
Jeremie Koenig138ce542010-07-30 06:01:37 +0200879#endif
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000880
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100881static void display_window_size(int fancy)
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000882{
883 const char *fmt_str = "%s\0%s: no size information for this device";
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000884 unsigned width, height;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000885
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000886 if (get_terminal_width_height(STDIN_FILENO, &width, &height)) {
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000887 if ((errno != EINVAL) || ((fmt_str += 2), !fancy)) {
888 perror_on_device(fmt_str);
889 }
890 } else {
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100891 wrapf(fancy ? "rows %u; columns %u;" : "%u %u\n",
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000892 height, width);
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000893 }
894}
895
Eric Andersen98e599c2001-02-14 18:47:33 +0000896static const struct suffix_mult stty_suffixes[] = {
Denis Vlasenkof8689632007-07-27 15:06:25 +0000897 { "b", 512 },
898 { "k", 1024 },
899 { "B", 1024 },
Denys Vlasenko043b1e52009-09-06 12:47:55 +0200900 { "", 0 }
Eric Andersen98e599c2001-02-14 18:47:33 +0000901};
902
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000903static const struct mode_info *find_mode(const char *name)
904{
Denis Vlasenkoda42bd52008-01-27 23:24:31 +0000905 int i = index_in_strings(mode_name, name);
906 return i >= 0 ? &mode_info[i] : NULL;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000907}
908
909static const struct control_info *find_control(const char *name)
910{
Denis Vlasenkoda42bd52008-01-27 23:24:31 +0000911 int i = index_in_strings(control_name, name);
912 return i >= 0 ? &control_info[i] : NULL;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000913}
914
915enum {
916 param_need_arg = 0x80,
Denis Vlasenko9ace6132007-04-19 19:55:54 +0000917 param_line = 1 | 0x80,
918 param_rows = 2 | 0x80,
919 param_cols = 3 | 0x80,
920 param_columns = 4 | 0x80,
921 param_size = 5,
922 param_speed = 6,
923 param_ispeed = 7 | 0x80,
924 param_ospeed = 8 | 0x80,
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000925};
926
Denis Vlasenkoc7cc5a92009-04-19 01:27:20 +0000927static int find_param(const char *name)
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000928{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000929 static const char params[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000930 "line\0" /* 1 */
931 "rows\0" /* 2 */
932 "cols\0" /* 3 */
933 "columns\0" /* 4 */
934 "size\0" /* 5 */
935 "speed\0" /* 6 */
936 "ispeed\0"
937 "ospeed\0";
938 int i = index_in_strings(params, name) + 1;
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000939 if (i == 0)
Bernhard Reutner-Fischercbd6e652007-02-04 11:13:57 +0000940 return 0;
Denis Vlasenko9ace6132007-04-19 19:55:54 +0000941 if (i != 5 && i != 6)
Bernhard Reutner-Fischercbd6e652007-02-04 11:13:57 +0000942 i |= 0x80;
Bernhard Reutner-Fischera6e31ad2007-01-17 19:45:14 +0000943 return i;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000944}
945
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000946static int recover_mode(const char *arg, struct termios *mode)
947{
948 int i, n;
Denis Vlasenko240a1cf2007-04-08 16:07:02 +0000949 unsigned chr;
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000950 unsigned long iflag, oflag, cflag, lflag;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000951
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000952 /* Scan into temporaries since it is too much trouble to figure out
953 the right format for 'tcflag_t' */
954 if (sscanf(arg, "%lx:%lx:%lx:%lx%n",
955 &iflag, &oflag, &cflag, &lflag, &n) != 4)
956 return 0;
957 mode->c_iflag = iflag;
958 mode->c_oflag = oflag;
959 mode->c_cflag = cflag;
960 mode->c_lflag = lflag;
961 arg += n;
962 for (i = 0; i < NCCS; ++i) {
963 if (sscanf(arg, ":%x%n", &chr, &n) != 1)
964 return 0;
965 mode->c_cc[i] = chr;
966 arg += n;
967 }
968
969 /* Fail if there are too many fields */
970 if (*arg != '\0')
971 return 0;
972
973 return 1;
974}
975
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +0000976static void display_recoverable(const struct termios *mode,
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000977 int UNUSED_PARAM dummy)
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000978{
979 int i;
980 printf("%lx:%lx:%lx:%lx",
981 (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
982 (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
983 for (i = 0; i < NCCS; ++i)
984 printf(":%x", (unsigned int) mode->c_cc[i]);
Denis Vlasenko4daad902007-09-27 10:20:47 +0000985 bb_putchar('\n');
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000986}
987
988static void display_speed(const struct termios *mode, int fancy)
989{
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100990 //____________________ 01234567 8 9
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000991 const char *fmt_str = "%lu %lu\n\0ispeed %lu baud; ospeed %lu baud;";
992 unsigned long ispeed, ospeed;
993
994 ospeed = ispeed = cfgetispeed(mode);
995 if (ispeed == 0 || ispeed == (ospeed = cfgetospeed(mode))) {
996 ispeed = ospeed; /* in case ispeed was 0 */
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100997 //________ 0123 4 5 6 7 8 9
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000998 fmt_str = "%lu\n\0\0\0\0\0speed %lu baud;";
999 }
1000 if (fancy) fmt_str += 9;
1001 wrapf(fmt_str, tty_baud_to_value(ispeed), tty_baud_to_value(ospeed));
1002}
1003
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001004static void do_display(const struct termios *mode, int all)
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001005{
1006 int i;
1007 tcflag_t *bitsp;
1008 unsigned long mask;
1009 int prev_type = control;
1010
1011 display_speed(mode, 1);
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001012 if (all)
1013 display_window_size(1);
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001014#ifdef HAVE_C_LINE
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001015 wrapf("line = %u;\n", mode->c_line);
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001016#else
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001017 newline();
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001018#endif
1019
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001020 for (i = 0; i != CIDX_min; ++i) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001021 /* If swtch is the same as susp, don't print both */
1022#if VSWTCH == VSUSP
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001023 if (i == CIDX_swtch)
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001024 continue;
1025#endif
1026 /* If eof uses the same slot as min, only print whichever applies */
1027#if VEOF == VMIN
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001028 if (!(mode->c_lflag & ICANON)
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001029 && (i == CIDX_eof || i == CIDX_eol)
1030 ) {
1031 continue;
1032 }
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001033#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001034 wrapf("%s = %s;", nth_string(control_name, i),
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001035 visible(mode->c_cc[control_info[i].offset]));
1036 }
1037#if VEOF == VMIN
1038 if ((mode->c_lflag & ICANON) == 0)
1039#endif
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001040 wrapf("min = %u; time = %u;", mode->c_cc[VMIN], mode->c_cc[VTIME]);
1041 newline();
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001042
1043 for (i = 0; i < NUM_mode_info; ++i) {
1044 if (mode_info[i].flags & OMIT)
1045 continue;
1046 if (mode_info[i].type != prev_type) {
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001047 newline();
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001048 prev_type = mode_info[i].type;
1049 }
1050
1051 bitsp = mode_type_flag(mode_info[i].type, mode);
1052 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001053 if ((*bitsp & mask) == mode_info[i].bits) {
1054 if (all || (mode_info[i].flags & SANE_UNSET))
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001055 wrapf("-%s"+1, nth_string(mode_name, i));
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001056 } else {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001057 if ((all && mode_info[i].flags & REV)
1058 || (!all && (mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV))
1059 ) {
1060 wrapf("-%s", nth_string(mode_name, i));
1061 }
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001062 }
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001063 }
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001064 newline();
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001065}
1066
1067static void sane_mode(struct termios *mode)
1068{
1069 int i;
1070 tcflag_t *bitsp;
1071
1072 for (i = 0; i < NUM_control_info; ++i) {
1073#if VMIN == VEOF
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001074 if (i == CIDX_min)
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001075 break;
1076#endif
1077 mode->c_cc[control_info[i].offset] = control_info[i].saneval;
1078 }
1079
1080 for (i = 0; i < NUM_mode_info; ++i) {
1081 if (mode_info[i].flags & SANE_SET) {
1082 bitsp = mode_type_flag(mode_info[i].type, mode);
1083 *bitsp = (*bitsp & ~((unsigned long)mode_info[i].mask))
1084 | mode_info[i].bits;
1085 } else if (mode_info[i].flags & SANE_UNSET) {
1086 bitsp = mode_type_flag(mode_info[i].type, mode);
1087 *bitsp = *bitsp & ~((unsigned long)mode_info[i].mask)
1088 & ~mode_info[i].bits;
1089 }
1090 }
1091}
1092
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001093static void set_mode(const struct mode_info *info, int reversed,
1094 struct termios *mode)
1095{
1096 tcflag_t *bitsp;
1097
1098 bitsp = mode_type_flag(info->type, mode);
1099
1100 if (bitsp) {
1101 if (reversed)
1102 *bitsp = *bitsp & ~info->mask & ~info->bits;
1103 else
1104 *bitsp = (*bitsp & ~info->mask) | info->bits;
1105 return;
1106 }
1107
1108 /* Combination mode */
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001109 if (info == &mode_info[IDX_evenp] || info == &mode_info[IDX_parity]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001110 if (reversed)
1111 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1112 else
1113 mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001114 } else if (info == &mode_info[IDX_oddp]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001115 if (reversed)
1116 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1117 else
1118 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001119 } else if (info == &mode_info[IDX_nl]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001120 if (reversed) {
1121 mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
1122 mode->c_oflag = (mode->c_oflag | ONLCR) & ~OCRNL & ~ONLRET;
1123 } else {
1124 mode->c_iflag = mode->c_iflag & ~ICRNL;
1125 if (ONLCR) mode->c_oflag = mode->c_oflag & ~ONLCR;
1126 }
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001127 } else if (info == &mode_info[IDX_ek]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001128 mode->c_cc[VERASE] = CERASE;
1129 mode->c_cc[VKILL] = CKILL;
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001130 } else if (info == &mode_info[IDX_sane]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001131 sane_mode(mode);
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001132 } else if (info == &mode_info[IDX_cbreak]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001133 if (reversed)
1134 mode->c_lflag |= ICANON;
1135 else
1136 mode->c_lflag &= ~ICANON;
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001137 } else if (info == &mode_info[IDX_pass8]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001138 if (reversed) {
1139 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1140 mode->c_iflag |= ISTRIP;
1141 } else {
1142 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1143 mode->c_iflag &= ~ISTRIP;
1144 }
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001145 } else if (info == &mode_info[IDX_litout]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001146 if (reversed) {
1147 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1148 mode->c_iflag |= ISTRIP;
1149 mode->c_oflag |= OPOST;
1150 } else {
1151 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1152 mode->c_iflag &= ~ISTRIP;
1153 mode->c_oflag &= ~OPOST;
1154 }
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001155 } else if (info == &mode_info[IDX_raw] || info == &mode_info[IDX_cooked]) {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001156 if ((info == &mode_info[IDX_raw] && reversed)
1157 || (info == &mode_info[IDX_cooked] && !reversed)
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001158 ) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001159 /* Cooked mode */
1160 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
1161 mode->c_oflag |= OPOST;
1162 mode->c_lflag |= ISIG | ICANON;
1163#if VMIN == VEOF
1164 mode->c_cc[VEOF] = CEOF;
1165#endif
1166#if VTIME == VEOL
1167 mode->c_cc[VEOL] = CEOL;
1168#endif
1169 } else {
1170 /* Raw mode */
1171 mode->c_iflag = 0;
1172 mode->c_oflag &= ~OPOST;
1173 mode->c_lflag &= ~(ISIG | ICANON | XCASE);
1174 mode->c_cc[VMIN] = 1;
1175 mode->c_cc[VTIME] = 0;
1176 }
1177 }
Jeremie Koenig138ce542010-07-30 06:01:37 +02001178#if IXANY
1179 else if (info == &mode_info[IDX_decctlq]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001180 if (reversed)
1181 mode->c_iflag |= IXANY;
1182 else
1183 mode->c_iflag &= ~IXANY;
1184 }
Jeremie Koenig138ce542010-07-30 06:01:37 +02001185#endif
1186#if TABDLY
1187 else if (info == &mode_info[IDX_tabs]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001188 if (reversed)
1189 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
1190 else
1191 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
1192 }
Jeremie Koenig138ce542010-07-30 06:01:37 +02001193#endif
1194#if OXTABS
1195 else if (info == &mode_info[IDX_tabs]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001196 if (reversed)
1197 mode->c_oflag |= OXTABS;
1198 else
1199 mode->c_oflag &= ~OXTABS;
Jeremie Koenig138ce542010-07-30 06:01:37 +02001200 }
1201#endif
1202#if XCASE && IUCLC && OLCUC
1203 else if (info==&mode_info[IDX_lcase] || info==&mode_info[IDX_LCASE]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001204 if (reversed) {
1205 mode->c_lflag &= ~XCASE;
1206 mode->c_iflag &= ~IUCLC;
1207 mode->c_oflag &= ~OLCUC;
1208 } else {
1209 mode->c_lflag |= XCASE;
1210 mode->c_iflag |= IUCLC;
1211 mode->c_oflag |= OLCUC;
1212 }
Jeremie Koenig138ce542010-07-30 06:01:37 +02001213 }
1214#endif
1215 else if (info == &mode_info[IDX_crt]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001216 mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001217 } else if (info == &mode_info[IDX_dec]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001218 mode->c_cc[VINTR] = 3; /* ^C */
1219 mode->c_cc[VERASE] = 127; /* DEL */
1220 mode->c_cc[VKILL] = 21; /* ^U */
1221 mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
1222 if (IXANY) mode->c_iflag &= ~IXANY;
1223 }
1224}
1225
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001226static void set_control_char_or_die(const struct control_info *info,
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001227 const char *arg, struct termios *mode)
1228{
1229 unsigned char value;
1230
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001231 if (info == &control_info[CIDX_min] || info == &control_info[CIDX_time])
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001232 value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
1233 else if (arg[0] == '\0' || arg[1] == '\0')
1234 value = arg[0];
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001235 else if (strcmp(arg, "^-") == 0 || strcmp(arg, "undef") == 0)
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001236 value = _POSIX_VDISABLE;
1237 else if (arg[0] == '^') { /* Ignore any trailing junk (^Cjunk) */
1238 value = arg[1] & 0x1f; /* Non-letters get weird results */
1239 if (arg[1] == '?')
1240 value = 127;
1241 } else
1242 value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
1243 mode->c_cc[info->offset] = value;
1244}
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001245
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001246#define STTY_require_set_attr (1 << 0)
1247#define STTY_speed_was_set (1 << 1)
1248#define STTY_verbose_output (1 << 2)
1249#define STTY_recoverable_output (1 << 3)
1250#define STTY_noargs (1 << 4)
1251
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00001252int stty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denys Vlasenkoe992bae2009-11-28 15:18:53 +01001253int stty_main(int argc UNUSED_PARAM, char **argv)
Eric Andersen98e599c2001-02-14 18:47:33 +00001254{
1255 struct termios mode;
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001256 void (*output_func)(const struct termios *, int);
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001257 const char *file_name = NULL;
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001258 int display_all = 0;
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001259 int stty_state;
1260 int k;
1261
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001262 INIT_G();
1263
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001264 stty_state = STTY_noargs;
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001265 output_func = do_display;
Eric Andersen98e599c2001-02-14 18:47:33 +00001266
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001267 /* First pass: only parse/verify command line params */
1268 k = 0;
1269 while (argv[++k]) {
1270 const struct mode_info *mp;
1271 const struct control_info *cp;
1272 const char *arg = argv[k];
1273 const char *argnext = argv[k+1];
1274 int param;
Eric Andersen98e599c2001-02-14 18:47:33 +00001275
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001276 if (arg[0] == '-') {
1277 int i;
1278 mp = find_mode(arg+1);
1279 if (mp) {
1280 if (!(mp->flags & REV))
Bernhard Reutner-Fischer4fa566d2007-01-17 19:42:30 +00001281 goto invalid_argument;
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001282 stty_state &= ~STTY_noargs;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001283 continue;
1284 }
1285 /* It is an option - parse it */
1286 i = 0;
1287 while (arg[++i]) {
1288 switch (arg[i]) {
1289 case 'a':
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001290 stty_state |= STTY_verbose_output;
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001291 output_func = do_display;
1292 display_all = 1;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001293 break;
1294 case 'g':
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001295 stty_state |= STTY_recoverable_output;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001296 output_func = display_recoverable;
1297 break;
1298 case 'F':
1299 if (file_name)
1300 bb_error_msg_and_die("only one device may be specified");
1301 file_name = &arg[i+1]; /* "-Fdevice" ? */
1302 if (!file_name[0]) { /* nope, "-F device" */
1303 int p = k+1; /* argv[p] is argnext */
1304 file_name = argnext;
1305 if (!file_name)
1306 bb_error_msg_and_die(bb_msg_requires_arg, "-F");
1307 /* remove -F param from arg[vc] */
Denys Vlasenkoe992bae2009-11-28 15:18:53 +01001308 while (argv[p]) {
1309 argv[p] = argv[p+1];
1310 ++p;
1311 }
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001312 }
1313 goto end_option;
1314 default:
Bernhard Reutner-Fischer4fa566d2007-01-17 19:42:30 +00001315 goto invalid_argument;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001316 }
1317 }
Denis Vlasenko240a1cf2007-04-08 16:07:02 +00001318 end_option:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001319 continue;
Eric Andersen98e599c2001-02-14 18:47:33 +00001320 }
1321
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001322 mp = find_mode(arg);
1323 if (mp) {
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001324 stty_state &= ~STTY_noargs;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001325 continue;
1326 }
1327
1328 cp = find_control(arg);
1329 if (cp) {
1330 if (!argnext)
1331 bb_error_msg_and_die(bb_msg_requires_arg, arg);
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001332 /* called for the side effect of xfunc death only */
1333 set_control_char_or_die(cp, argnext, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001334 stty_state &= ~STTY_noargs;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001335 ++k;
1336 continue;
1337 }
1338
1339 param = find_param(arg);
1340 if (param & param_need_arg) {
1341 if (!argnext)
1342 bb_error_msg_and_die(bb_msg_requires_arg, arg);
1343 ++k;
1344 }
1345
1346 switch (param) {
1347#ifdef HAVE_C_LINE
1348 case param_line:
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +00001349# ifndef TIOCGWINSZ
Denis Vlasenko13858992006-10-08 12:49:22 +00001350 xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
Eric Andersen98e599c2001-02-14 18:47:33 +00001351 break;
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +00001352# endif /* else fall-through */
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001353#endif
1354#ifdef TIOCGWINSZ
1355 case param_rows:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001356 case param_cols:
Denis Vlasenko9ace6132007-04-19 19:55:54 +00001357 case param_columns:
Denis Vlasenko13858992006-10-08 12:49:22 +00001358 xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001359 break;
1360 case param_size:
1361#endif
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001362 case param_speed:
1363 break;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001364 case param_ispeed:
1365 /* called for the side effect of xfunc death only */
1366 set_speed_or_die(input_speed, argnext, &mode);
1367 break;
1368 case param_ospeed:
1369 /* called for the side effect of xfunc death only */
1370 set_speed_or_die(output_speed, argnext, &mode);
1371 break;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001372 default:
1373 if (recover_mode(arg, &mode) == 1) break;
Bernhard Reutner-Fischer4950f012007-01-17 19:44:59 +00001374 if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) break;
Denis Vlasenko240a1cf2007-04-08 16:07:02 +00001375 invalid_argument:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001376 bb_error_msg_and_die("invalid argument '%s'", arg);
1377 }
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001378 stty_state &= ~STTY_noargs;
Eric Andersen98e599c2001-02-14 18:47:33 +00001379 }
1380
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001381 /* Specifying both -a and -g is an error */
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001382 if ((stty_state & (STTY_verbose_output | STTY_recoverable_output)) ==
Bernhard Reutner-Fischer4fa566d2007-01-17 19:42:30 +00001383 (STTY_verbose_output | STTY_recoverable_output))
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001384 bb_error_msg_and_die("verbose and stty-readable output styles are mutually exclusive");
1385 /* Specifying -a or -g with non-options is an error */
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001386 if (!(stty_state & STTY_noargs)
1387 && (stty_state & (STTY_verbose_output | STTY_recoverable_output))
1388 ) {
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001389 bb_error_msg_and_die("modes may not be set when specifying an output style");
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001390 }
Eric Andersen98e599c2001-02-14 18:47:33 +00001391
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001392 /* Now it is safe to start doing things */
Eric Andersen98e599c2001-02-14 18:47:33 +00001393 if (file_name) {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001394 G.device_name = file_name;
Denys Vlasenkoab19ede2009-11-11 21:05:42 +01001395 xmove_fd(xopen_nonblocking(G.device_name), STDIN_FILENO);
1396 ndelay_off(STDIN_FILENO);
Eric Andersen98e599c2001-02-14 18:47:33 +00001397 }
1398
1399 /* Initialize to all zeroes so there is no risk memcmp will report a
Denis Vlasenko9efb0702006-09-19 14:17:10 +00001400 spurious difference in an uninitialized portion of the structure */
Eric Andersen98e599c2001-02-14 18:47:33 +00001401 memset(&mode, 0, sizeof(mode));
"Vladimir N. Oleynik"9b9a9202006-01-30 12:23:46 +00001402 if (tcgetattr(STDIN_FILENO, &mode))
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001403 perror_on_device_and_die("%s");
Eric Andersen98e599c2001-02-14 18:47:33 +00001404
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001405 if (stty_state & (STTY_verbose_output | STTY_recoverable_output | STTY_noargs)) {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001406 get_terminal_width_height(STDOUT_FILENO, &G.max_col, NULL);
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001407 output_func(&mode, display_all);
Eric Andersen98e599c2001-02-14 18:47:33 +00001408 return EXIT_SUCCESS;
1409 }
1410
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001411 /* Second pass: perform actions */
Eric Andersenfc059092002-06-06 11:35:29 +00001412 k = 0;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001413 while (argv[++k]) {
1414 const struct mode_info *mp;
1415 const struct control_info *cp;
1416 const char *arg = argv[k];
1417 const char *argnext = argv[k+1];
1418 int param;
Eric Andersen98e599c2001-02-14 18:47:33 +00001419
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001420 if (arg[0] == '-') {
1421 mp = find_mode(arg+1);
1422 if (mp) {
1423 set_mode(mp, 1 /* reversed */, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001424 stty_state |= STTY_require_set_attr;
Eric Andersenfc059092002-06-06 11:35:29 +00001425 }
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001426 /* It is an option - already parsed. Skip it */
1427 continue;
Eric Andersen98e599c2001-02-14 18:47:33 +00001428 }
Mark Whitley446dd272001-03-02 20:00:54 +00001429
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001430 mp = find_mode(arg);
1431 if (mp) {
1432 set_mode(mp, 0 /* non-reversed */, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001433 stty_state |= STTY_require_set_attr;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001434 continue;
1435 }
Mark Whitley446dd272001-03-02 20:00:54 +00001436
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001437 cp = find_control(arg);
1438 if (cp) {
1439 ++k;
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001440 set_control_char_or_die(cp, argnext, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001441 stty_state |= STTY_require_set_attr;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001442 continue;
1443 }
Mark Whitley446dd272001-03-02 20:00:54 +00001444
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001445 param = find_param(arg);
1446 if (param & param_need_arg) {
1447 ++k;
1448 }
1449
1450 switch (param) {
Eric Andersen98e599c2001-02-14 18:47:33 +00001451#ifdef HAVE_C_LINE
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001452 case param_line:
Denis Vlasenko13858992006-10-08 12:49:22 +00001453 mode.c_line = xatoul_sfx(argnext, stty_suffixes);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001454 stty_state |= STTY_require_set_attr;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001455 break;
Eric Andersen98e599c2001-02-14 18:47:33 +00001456#endif
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001457#ifdef TIOCGWINSZ
1458 case param_cols:
Denys Vlasenko9f5a5772009-12-11 14:17:02 +01001459 case param_columns:
Denis Vlasenko13858992006-10-08 12:49:22 +00001460 set_window_size(-1, xatoul_sfx(argnext, stty_suffixes));
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001461 break;
1462 case param_size:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001463 display_window_size(0);
1464 break;
1465 case param_rows:
Denis Vlasenko13858992006-10-08 12:49:22 +00001466 set_window_size(xatoul_sfx(argnext, stty_suffixes), -1);
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001467 break;
1468#endif
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001469 case param_speed:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001470 display_speed(&mode, 0);
1471 break;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001472 case param_ispeed:
1473 set_speed_or_die(input_speed, argnext, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001474 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001475 break;
1476 case param_ospeed:
1477 set_speed_or_die(output_speed, argnext, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001478 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001479 break;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001480 default:
1481 if (recover_mode(arg, &mode) == 1)
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001482 stty_state |= STTY_require_set_attr;
Bernhard Reutner-Fischer4950f012007-01-17 19:44:59 +00001483 else /* true: if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) */{
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001484 set_speed_or_die(both_speeds, arg, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001485 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001486 } /* else - impossible (caught in the first pass):
1487 bb_error_msg_and_die("invalid argument '%s'", arg); */
Eric Andersen98e599c2001-02-14 18:47:33 +00001488 }
Eric Andersen98e599c2001-02-14 18:47:33 +00001489 }
1490
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001491 if (stty_state & STTY_require_set_attr) {
Eric Andersen98e599c2001-02-14 18:47:33 +00001492 struct termios new_mode;
1493
"Vladimir N. Oleynik"9b9a9202006-01-30 12:23:46 +00001494 if (tcsetattr(STDIN_FILENO, TCSADRAIN, &mode))
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001495 perror_on_device_and_die("%s");
Eric Andersen98e599c2001-02-14 18:47:33 +00001496
1497 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
1498 it performs *any* of the requested operations. This means it
Denis Vlasenko79deb662006-09-19 15:12:12 +00001499 can report 'success' when it has actually failed to perform
Eric Andersen98e599c2001-02-14 18:47:33 +00001500 some proper subset of the requested operations. To detect
1501 this partial failure, get the current terminal attributes and
Denis Vlasenko9efb0702006-09-19 14:17:10 +00001502 compare them to the requested ones */
Eric Andersen98e599c2001-02-14 18:47:33 +00001503
1504 /* Initialize to all zeroes so there is no risk memcmp will report a
Denis Vlasenko9efb0702006-09-19 14:17:10 +00001505 spurious difference in an uninitialized portion of the structure */
Eric Andersen98e599c2001-02-14 18:47:33 +00001506 memset(&new_mode, 0, sizeof(new_mode));
"Vladimir N. Oleynik"9b9a9202006-01-30 12:23:46 +00001507 if (tcgetattr(STDIN_FILENO, &new_mode))
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001508 perror_on_device_and_die("%s");
Eric Andersen98e599c2001-02-14 18:47:33 +00001509
Eric Andersen98e599c2001-02-14 18:47:33 +00001510 if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) {
Jeremie Koenig138ce542010-07-30 06:01:37 +02001511#if CIBAUD
Eric Andersen98e599c2001-02-14 18:47:33 +00001512 /* SunOS 4.1.3 (at least) has the problem that after this sequence,
1513 tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
1514 sometimes (m1 != m2). The only difference is in the four bits
1515 of the c_cflag field corresponding to the baud rate. To save
1516 Sun users a little confusion, don't report an error if this
1517 happens. But suppress the error only if we haven't tried to
1518 set the baud rate explicitly -- otherwise we'd never give an
Denis Vlasenko9efb0702006-09-19 14:17:10 +00001519 error for a true failure to set the baud rate */
Eric Andersen98e599c2001-02-14 18:47:33 +00001520
1521 new_mode.c_cflag &= (~CIBAUD);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001522 if ((stty_state & STTY_speed_was_set)
1523 || memcmp(&mode, &new_mode, sizeof(mode)) != 0)
Eric Andersen98e599c2001-02-14 18:47:33 +00001524#endif
Denis Vlasenko89f0b342006-11-18 22:04:09 +00001525 perror_on_device_and_die("%s: cannot perform all requested operations");
Eric Andersen98e599c2001-02-14 18:47:33 +00001526 }
1527 }
1528
1529 return EXIT_SUCCESS;
1530}