blob: 96754dd84029fbe3d0a4dbf865f4f4f96bf8d0ca [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
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +02005 Licensed under GPLv2 or later, see file LICENSE in this source tree.
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00006*/
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
Pere Orga34425382011-03-31 14:43:25 +020024//usage:#define stty_trivial_usage
25//usage: "[-a|g] [-F DEVICE] [SETTING]..."
26//usage:#define stty_full_usage "\n\n"
27//usage: "Without arguments, prints baud rate, line discipline,\n"
28//usage: "and deviations from stty sane\n"
Pere Orga34425382011-03-31 14:43:25 +020029//usage: "\n -F DEVICE Open device instead of stdin"
30//usage: "\n -a Print all current settings in human-readable form"
31//usage: "\n -g Print in stty-readable form"
32//usage: "\n [SETTING] See manpage"
33
Denis Vlasenkob6adbf12007-05-26 19:00:18 +000034#include "libbb.h"
Eric Andersen98e599c2001-02-14 18:47:33 +000035
Eric Andersen98e599c2001-02-14 18:47:33 +000036#ifndef _POSIX_VDISABLE
37# define _POSIX_VDISABLE ((unsigned char) 0)
38#endif
39
40#define Control(c) ((c) & 0x1f)
Denis Vlasenko9efb0702006-09-19 14:17:10 +000041/* Canonical values for control characters */
Eric Andersen98e599c2001-02-14 18:47:33 +000042#ifndef CINTR
Denis Vlasenko9efb0702006-09-19 14:17:10 +000043# define CINTR Control('c')
Eric Andersen98e599c2001-02-14 18:47:33 +000044#endif
45#ifndef CQUIT
46# define CQUIT 28
47#endif
48#ifndef CERASE
49# define CERASE 127
50#endif
51#ifndef CKILL
Denis Vlasenko9efb0702006-09-19 14:17:10 +000052# define CKILL Control('u')
Eric Andersen98e599c2001-02-14 18:47:33 +000053#endif
54#ifndef CEOF
Denis Vlasenko9efb0702006-09-19 14:17:10 +000055# define CEOF Control('d')
Eric Andersen98e599c2001-02-14 18:47:33 +000056#endif
57#ifndef CEOL
58# define CEOL _POSIX_VDISABLE
59#endif
60#ifndef CSTART
Denis Vlasenko9efb0702006-09-19 14:17:10 +000061# define CSTART Control('q')
Eric Andersen98e599c2001-02-14 18:47:33 +000062#endif
63#ifndef CSTOP
Denis Vlasenko9efb0702006-09-19 14:17:10 +000064# define CSTOP Control('s')
Eric Andersen98e599c2001-02-14 18:47:33 +000065#endif
66#ifndef CSUSP
Denis Vlasenko9efb0702006-09-19 14:17:10 +000067# define CSUSP Control('z')
Eric Andersen98e599c2001-02-14 18:47:33 +000068#endif
69#if defined(VEOL2) && !defined(CEOL2)
70# define CEOL2 _POSIX_VDISABLE
71#endif
Denys Vlasenko271c0ce2011-01-24 16:36:15 +010072/* glibc-2.12.1 uses only VSWTC name */
73#if defined(VSWTC) && !defined(VSWTCH)
74# define VSWTCH VSWTC
75#endif
Denis Vlasenko9efb0702006-09-19 14:17:10 +000076/* ISC renamed swtch to susp for termios, but we'll accept either name */
Eric Andersen98e599c2001-02-14 18:47:33 +000077#if defined(VSUSP) && !defined(VSWTCH)
78# define VSWTCH VSUSP
79# define CSWTCH CSUSP
80#endif
81#if defined(VSWTCH) && !defined(CSWTCH)
82# define CSWTCH _POSIX_VDISABLE
83#endif
84
Denis Vlasenko79deb662006-09-19 15:12:12 +000085/* SunOS 5.3 loses (^Z doesn't work) if 'swtch' is the same as 'susp'.
86 So the default is to disable 'swtch.' */
Denis Vlasenkoff131b92007-04-10 15:42:06 +000087#if defined(__sparc__) && defined(__svr4__)
Eric Andersen98e599c2001-02-14 18:47:33 +000088# undef CSWTCH
89# define CSWTCH _POSIX_VDISABLE
90#endif
91
Denis Vlasenkoff131b92007-04-10 15:42:06 +000092#if defined(VWERSE) && !defined(VWERASE) /* AIX-3.2.5 */
Eric Andersen98e599c2001-02-14 18:47:33 +000093# define VWERASE VWERSE
94#endif
Denis Vlasenkoff131b92007-04-10 15:42:06 +000095#if defined(VDSUSP) && !defined(CDSUSP)
Denis Vlasenko9efb0702006-09-19 14:17:10 +000096# define CDSUSP Control('y')
Eric Andersen98e599c2001-02-14 18:47:33 +000097#endif
Mark Whitley446dd272001-03-02 20:00:54 +000098#if !defined(VREPRINT) && defined(VRPRNT) /* Irix 4.0.5 */
Eric Andersen98e599c2001-02-14 18:47:33 +000099# define VREPRINT VRPRNT
100#endif
101#if defined(VREPRINT) && !defined(CRPRNT)
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000102# define CRPRNT Control('r')
Eric Andersen98e599c2001-02-14 18:47:33 +0000103#endif
104#if defined(VWERASE) && !defined(CWERASE)
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000105# define CWERASE Control('w')
Eric Andersen98e599c2001-02-14 18:47:33 +0000106#endif
107#if defined(VLNEXT) && !defined(CLNEXT)
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000108# define CLNEXT Control('v')
Eric Andersen98e599c2001-02-14 18:47:33 +0000109#endif
110#if defined(VDISCARD) && !defined(VFLUSHO)
111# define VFLUSHO VDISCARD
112#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000113#if defined(VFLUSH) && !defined(VFLUSHO) /* Ultrix 4.2 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000114# define VFLUSHO VFLUSH
115#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000116#if defined(CTLECH) && !defined(ECHOCTL) /* Ultrix 4.3 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000117# define ECHOCTL CTLECH
118#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000119#if defined(TCTLECH) && !defined(ECHOCTL) /* Ultrix 4.2 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000120# define ECHOCTL TCTLECH
121#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000122#if defined(CRTKIL) && !defined(ECHOKE) /* Ultrix 4.2 and 4.3 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000123# define ECHOKE CRTKIL
124#endif
125#if defined(VFLUSHO) && !defined(CFLUSHO)
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000126# define CFLUSHO Control('o')
Eric Andersen98e599c2001-02-14 18:47:33 +0000127#endif
128#if defined(VSTATUS) && !defined(CSTATUS)
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000129# define CSTATUS Control('t')
Eric Andersen98e599c2001-02-14 18:47:33 +0000130#endif
131
Jeremie Koenig138ce542010-07-30 06:01:37 +0200132/* Save us from #ifdef forest plague */
133#ifndef BSDLY
134# define BSDLY 0
135#endif
136#ifndef CIBAUD
137# define CIBAUD 0
138#endif
139#ifndef CRDLY
140# define CRDLY 0
141#endif
142#ifndef CRTSCTS
143# define CRTSCTS 0
144#endif
145#ifndef ECHOCTL
146# define ECHOCTL 0
147#endif
148#ifndef ECHOKE
149# define ECHOKE 0
150#endif
151#ifndef ECHOPRT
152# define ECHOPRT 0
153#endif
154#ifndef FFDLY
155# define FFDLY 0
156#endif
157#ifndef IEXTEN
158# define IEXTEN 0
159#endif
160#ifndef IMAXBEL
161# define IMAXBEL 0
162#endif
163#ifndef IUCLC
164# define IUCLC 0
165#endif
166#ifndef IXANY
167# define IXANY 0
168#endif
169#ifndef NLDLY
170# define NLDLY 0
171#endif
172#ifndef OCRNL
173# define OCRNL 0
174#endif
175#ifndef OFDEL
176# define OFDEL 0
177#endif
178#ifndef OFILL
179# define OFILL 0
180#endif
181#ifndef OLCUC
182# define OLCUC 0
183#endif
184#ifndef ONLCR
185# define ONLCR 0
186#endif
187#ifndef ONLRET
188# define ONLRET 0
189#endif
190#ifndef ONOCR
191# define ONOCR 0
192#endif
193#ifndef OXTABS
194# define OXTABS 0
195#endif
196#ifndef TABDLY
197# define TABDLY 0
198#endif
199#ifndef TAB1
200# define TAB1 0
201#endif
202#ifndef TAB2
203# define TAB2 0
204#endif
205#ifndef TOSTOP
206# define TOSTOP 0
207#endif
208#ifndef VDSUSP
209# define VDSUSP 0
210#endif
211#ifndef VEOL2
212# define VEOL2 0
213#endif
214#ifndef VFLUSHO
215# define VFLUSHO 0
216#endif
217#ifndef VLNEXT
218# define VLNEXT 0
219#endif
220#ifndef VREPRINT
221# define VREPRINT 0
222#endif
223#ifndef VSTATUS
224# define VSTATUS 0
225#endif
226#ifndef VSWTCH
227# define VSWTCH 0
228#endif
229#ifndef VTDLY
230# define VTDLY 0
231#endif
232#ifndef VWERASE
233# define VWERASE 0
234#endif
235#ifndef XCASE
236# define XCASE 0
237#endif
Denys Vlasenko271c0ce2011-01-24 16:36:15 +0100238#ifndef IUTF8
239# define IUTF8 0
240#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200241
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000242/* Which speeds to set */
Eric Andersen98e599c2001-02-14 18:47:33 +0000243enum speed_setting {
244 input_speed, output_speed, both_speeds
245};
246
Denis Vlasenko79deb662006-09-19 15:12:12 +0000247/* Which member(s) of 'struct termios' a mode uses */
Denis Vlasenko20b253d2006-09-19 14:24:23 +0000248enum {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000249 /* Do NOT change the order or values, as mode_type_flag()
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000250 * depends on them */
Eric Andersen98e599c2001-02-14 18:47:33 +0000251 control, input, output, local, combination
252};
253
Denis Vlasenko79deb662006-09-19 15:12:12 +0000254/* Flags for 'struct mode_info' */
255#define SANE_SET 1 /* Set in 'sane' mode */
256#define SANE_UNSET 2 /* Unset in 'sane' mode */
257#define REV 4 /* Can be turned off by prepending '-' */
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000258#define OMIT 8 /* Don't display value */
Eric Andersen98e599c2001-02-14 18:47:33 +0000259
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000260
261/* Each mode.
262 * This structure should be kept as small as humanly possible.
263 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000264struct mode_info {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000265 const uint8_t type; /* Which structure element to change */
266 const uint8_t flags; /* Setting and display options */
267 /* only these values are ever used, so... */
268#if (CSIZE | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY) < 0x100
269 const uint8_t mask;
270#elif (CSIZE | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY) < 0x10000
271 const uint16_t mask;
272#else
Bernhard Reutner-Fischer21fc7402007-01-17 19:44:24 +0000273 const tcflag_t mask; /* Other bits to turn off for this mode */
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000274#endif
275 /* was using short here, but ppc32 was unhappy */
Bernhard Reutner-Fischer21fc7402007-01-17 19:44:24 +0000276 const tcflag_t bits; /* Bits to set for this mode */
Eric Andersen98e599c2001-02-14 18:47:33 +0000277};
278
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000279enum {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000280 /* Must match mode_name[] and mode_info[] order! */
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000281 IDX_evenp = 0,
282 IDX_parity,
283 IDX_oddp,
284 IDX_nl,
285 IDX_ek,
286 IDX_sane,
287 IDX_cooked,
288 IDX_raw,
289 IDX_pass8,
290 IDX_litout,
291 IDX_cbreak,
292 IDX_crt,
293 IDX_dec,
Jeremie Koenig138ce542010-07-30 06:01:37 +0200294#if IXANY
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000295 IDX_decctlq,
296#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200297#if TABDLY || OXTABS
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000298 IDX_tabs,
299#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200300#if XCASE && IUCLC && OLCUC
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000301 IDX_lcase,
302 IDX_LCASE,
303#endif
304};
Denis Vlasenkob2abef32007-01-01 18:18:04 +0000305
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000306#define MI_ENTRY(N,T,F,B,M) N "\0"
Manuel Novoa III cad53642003-03-19 09:13:01 +0000307
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000308/* Mode names given on command line */
309static const char mode_name[] =
310 MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 )
311 MI_ENTRY("parity", combination, REV | OMIT, 0, 0 )
312 MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 )
313 MI_ENTRY("nl", combination, REV | OMIT, 0, 0 )
314 MI_ENTRY("ek", combination, OMIT, 0, 0 )
315 MI_ENTRY("sane", combination, OMIT, 0, 0 )
316 MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 )
317 MI_ENTRY("raw", combination, REV | OMIT, 0, 0 )
318 MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 )
319 MI_ENTRY("litout", combination, REV | OMIT, 0, 0 )
320 MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 )
321 MI_ENTRY("crt", combination, OMIT, 0, 0 )
322 MI_ENTRY("dec", combination, OMIT, 0, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200323#if IXANY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000324 MI_ENTRY("decctlq", combination, REV | OMIT, 0, 0 )
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000325#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200326#if TABDLY || OXTABS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000327 MI_ENTRY("tabs", combination, REV | OMIT, 0, 0 )
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000328#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200329#if XCASE && IUCLC && OLCUC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000330 MI_ENTRY("lcase", combination, REV | OMIT, 0, 0 )
331 MI_ENTRY("LCASE", combination, REV | OMIT, 0, 0 )
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000332#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000333 MI_ENTRY("parenb", control, REV, PARENB, 0 )
334 MI_ENTRY("parodd", control, REV, PARODD, 0 )
335 MI_ENTRY("cs5", control, 0, CS5, CSIZE)
336 MI_ENTRY("cs6", control, 0, CS6, CSIZE)
337 MI_ENTRY("cs7", control, 0, CS7, CSIZE)
338 MI_ENTRY("cs8", control, 0, CS8, CSIZE)
339 MI_ENTRY("hupcl", control, REV, HUPCL, 0 )
340 MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 )
341 MI_ENTRY("cstopb", control, REV, CSTOPB, 0 )
342 MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 )
343 MI_ENTRY("clocal", control, REV, CLOCAL, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200344#if CRTSCTS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000345 MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000346#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000347 MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 )
348 MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 )
349 MI_ENTRY("ignpar", input, REV, IGNPAR, 0 )
350 MI_ENTRY("parmrk", input, REV, PARMRK, 0 )
351 MI_ENTRY("inpck", input, REV, INPCK, 0 )
352 MI_ENTRY("istrip", input, REV, ISTRIP, 0 )
353 MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 )
354 MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 )
355 MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 )
356 MI_ENTRY("ixon", input, REV, IXON, 0 )
357 MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100358 MI_ENTRY("tandem", input, OMIT | REV, IXOFF, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200359#if IUCLC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000360 MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000361#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200362#if IXANY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000363 MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000364#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200365#if IMAXBEL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000366 MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000367#endif
Denys Vlasenko271c0ce2011-01-24 16:36:15 +0100368#if IUTF8
369 MI_ENTRY("iutf8", input, SANE_UNSET | REV, IUTF8, 0 )
370#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000371 MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200372#if OLCUC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000373 MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000374#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200375#if OCRNL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000376 MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000377#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200378#if ONLCR
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000379 MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000380#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200381#if ONOCR
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000382 MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000383#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200384#if ONLRET
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000385 MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000386#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200387#if OFILL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000388 MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000389#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200390#if OFDEL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000391 MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000392#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200393#if NLDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000394 MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY)
395 MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000396#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200397#if CRDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000398 MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY)
399 MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY)
400 MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY)
401 MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000402#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000403
Jeremie Koenig138ce542010-07-30 06:01:37 +0200404#if TABDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000405 MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200406# if TAB2
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000407 MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200408# endif
409# if TAB1
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000410 MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200411# endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000412 MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000413#else
Jeremie Koenig138ce542010-07-30 06:01:37 +0200414# if OXTABS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000415 MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000416# endif
417#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000418
Jeremie Koenig138ce542010-07-30 06:01:37 +0200419#if BSDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000420 MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY)
421 MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000422#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200423#if VTDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000424 MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY)
425 MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000426#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200427#if FFDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000428 MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY)
429 MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000430#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000431 MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 )
432 MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200433#if IEXTEN
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000434 MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000435#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000436 MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 )
437 MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100438 MI_ENTRY("crterase", local, OMIT | REV, ECHOE, 0 )
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000439 MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 )
440 MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 )
441 MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200442#if XCASE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000443 MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000444#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200445#if TOSTOP
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000446 MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000447#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200448#if ECHOPRT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000449 MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100450 MI_ENTRY("prterase", local, OMIT | REV, ECHOPRT, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000451#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200452#if ECHOCTL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000453 MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100454 MI_ENTRY("ctlecho", local, OMIT | REV, ECHOCTL, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000455#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200456#if ECHOKE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000457 MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100458 MI_ENTRY("crtkill", local, OMIT | REV, ECHOKE, 0 )
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000459#endif
460 ;
461
462#undef MI_ENTRY
463#define MI_ENTRY(N,T,F,B,M) { T, F, M, B },
464
465static const struct mode_info mode_info[] = {
466 /* This should be verbatim cut-n-paste copy of the above MI_ENTRYs */
467 MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 )
468 MI_ENTRY("parity", combination, REV | OMIT, 0, 0 )
469 MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 )
470 MI_ENTRY("nl", combination, REV | OMIT, 0, 0 )
471 MI_ENTRY("ek", combination, OMIT, 0, 0 )
472 MI_ENTRY("sane", combination, OMIT, 0, 0 )
473 MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 )
474 MI_ENTRY("raw", combination, REV | OMIT, 0, 0 )
475 MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 )
476 MI_ENTRY("litout", combination, REV | OMIT, 0, 0 )
477 MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 )
478 MI_ENTRY("crt", combination, OMIT, 0, 0 )
479 MI_ENTRY("dec", combination, OMIT, 0, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200480#if IXANY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000481 MI_ENTRY("decctlq", combination, REV | OMIT, 0, 0 )
482#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200483#if TABDLY || OXTABS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000484 MI_ENTRY("tabs", combination, REV | OMIT, 0, 0 )
485#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200486#if XCASE && IUCLC && OLCUC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000487 MI_ENTRY("lcase", combination, REV | OMIT, 0, 0 )
488 MI_ENTRY("LCASE", combination, REV | OMIT, 0, 0 )
489#endif
490 MI_ENTRY("parenb", control, REV, PARENB, 0 )
491 MI_ENTRY("parodd", control, REV, PARODD, 0 )
492 MI_ENTRY("cs5", control, 0, CS5, CSIZE)
493 MI_ENTRY("cs6", control, 0, CS6, CSIZE)
494 MI_ENTRY("cs7", control, 0, CS7, CSIZE)
495 MI_ENTRY("cs8", control, 0, CS8, CSIZE)
496 MI_ENTRY("hupcl", control, REV, HUPCL, 0 )
497 MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 )
498 MI_ENTRY("cstopb", control, REV, CSTOPB, 0 )
499 MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 )
500 MI_ENTRY("clocal", control, REV, CLOCAL, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200501#if CRTSCTS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000502 MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 )
503#endif
504 MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 )
505 MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 )
506 MI_ENTRY("ignpar", input, REV, IGNPAR, 0 )
507 MI_ENTRY("parmrk", input, REV, PARMRK, 0 )
508 MI_ENTRY("inpck", input, REV, INPCK, 0 )
509 MI_ENTRY("istrip", input, REV, ISTRIP, 0 )
510 MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 )
511 MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 )
512 MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 )
513 MI_ENTRY("ixon", input, REV, IXON, 0 )
514 MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100515 MI_ENTRY("tandem", input, OMIT | REV, IXOFF, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200516#if IUCLC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000517 MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 )
518#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200519#if IXANY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000520 MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 )
521#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200522#if IMAXBEL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000523 MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 )
524#endif
Denys Vlasenko271c0ce2011-01-24 16:36:15 +0100525#if IUTF8
526 MI_ENTRY("iutf8", input, SANE_UNSET | REV, IUTF8, 0 )
527#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000528 MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200529#if OLCUC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000530 MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 )
531#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200532#if OCRNL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000533 MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 )
534#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200535#if ONLCR
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000536 MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 )
537#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200538#if ONOCR
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000539 MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 )
540#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200541#if ONLRET
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000542 MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 )
543#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200544#if OFILL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000545 MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 )
546#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200547#if OFDEL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000548 MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 )
549#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200550#if NLDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000551 MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY)
552 MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY)
553#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200554#if CRDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000555 MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY)
556 MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY)
557 MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY)
558 MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY)
559#endif
560
Jeremie Koenig138ce542010-07-30 06:01:37 +0200561#if TABDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000562 MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200563# if TAB2
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000564 MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200565# endif
566# if TAB1
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000567 MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200568# endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000569 MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY)
570#else
Jeremie Koenig138ce542010-07-30 06:01:37 +0200571# if OXTABS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000572 MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 )
573# endif
574#endif
575
Jeremie Koenig138ce542010-07-30 06:01:37 +0200576#if BSDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000577 MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY)
578 MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY)
579#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200580#if VTDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000581 MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY)
582 MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY)
583#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200584#if FFDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000585 MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY)
586 MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY)
587#endif
588 MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 )
589 MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200590#if IEXTEN
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000591 MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 )
592#endif
593 MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 )
594 MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100595 MI_ENTRY("crterase", local, OMIT | REV, ECHOE, 0 )
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000596 MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 )
597 MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 )
598 MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200599#if XCASE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000600 MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 )
601#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200602#if TOSTOP
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000603 MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 )
604#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200605#if ECHOPRT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000606 MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100607 MI_ENTRY("prterase", local, OMIT | REV, ECHOPRT, 0 )
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000608#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200609#if ECHOCTL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000610 MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100611 MI_ENTRY("ctlecho", local, OMIT | REV, ECHOCTL, 0 )
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000612#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200613#if ECHOKE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000614 MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100615 MI_ENTRY("crtkill", local, OMIT | REV, ECHOKE, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000616#endif
Eric Andersen98e599c2001-02-14 18:47:33 +0000617};
618
Rob Landleybc68cd12006-03-10 19:22:06 +0000619enum {
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000620 NUM_mode_info = ARRAY_SIZE(mode_info)
Rob Landleybc68cd12006-03-10 19:22:06 +0000621};
Eric Andersen98e599c2001-02-14 18:47:33 +0000622
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000623
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000624/* Control characters */
Eric Andersen98e599c2001-02-14 18:47:33 +0000625struct control_info {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000626 const uint8_t saneval; /* Value to set for 'stty sane' */
627 const uint8_t offset; /* Offset in c_cc */
Eric Andersen98e599c2001-02-14 18:47:33 +0000628};
629
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000630enum {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000631 /* Must match control_name[] and control_info[] order! */
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000632 CIDX_intr = 0,
633 CIDX_quit,
634 CIDX_erase,
635 CIDX_kill,
636 CIDX_eof,
637 CIDX_eol,
Jeremie Koenig138ce542010-07-30 06:01:37 +0200638#if VEOL2
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000639 CIDX_eol2,
640#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200641#if VSWTCH
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000642 CIDX_swtch,
643#endif
644 CIDX_start,
645 CIDX_stop,
646 CIDX_susp,
Jeremie Koenig138ce542010-07-30 06:01:37 +0200647#if VDSUSP
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000648 CIDX_dsusp,
649#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200650#if VREPRINT
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000651 CIDX_rprnt,
652#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200653#if VWERASE
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000654 CIDX_werase,
655#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200656#if VLNEXT
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000657 CIDX_lnext,
658#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200659#if VFLUSHO
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000660 CIDX_flush,
661#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200662#if VSTATUS
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000663 CIDX_status,
664#endif
665 CIDX_min,
666 CIDX_time,
667};
Eric Andersen98e599c2001-02-14 18:47:33 +0000668
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000669#define CI_ENTRY(n,s,o) n "\0"
670
671/* Name given on command line */
672static const char control_name[] =
673 CI_ENTRY("intr", CINTR, VINTR )
674 CI_ENTRY("quit", CQUIT, VQUIT )
675 CI_ENTRY("erase", CERASE, VERASE )
676 CI_ENTRY("kill", CKILL, VKILL )
677 CI_ENTRY("eof", CEOF, VEOF )
678 CI_ENTRY("eol", CEOL, VEOL )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200679#if VEOL2
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000680 CI_ENTRY("eol2", CEOL2, VEOL2 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000681#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200682#if VSWTCH
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000683 CI_ENTRY("swtch", CSWTCH, VSWTCH )
Eric Andersen98e599c2001-02-14 18:47:33 +0000684#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000685 CI_ENTRY("start", CSTART, VSTART )
686 CI_ENTRY("stop", CSTOP, VSTOP )
687 CI_ENTRY("susp", CSUSP, VSUSP )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200688#if VDSUSP
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000689 CI_ENTRY("dsusp", CDSUSP, VDSUSP )
Eric Andersen98e599c2001-02-14 18:47:33 +0000690#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200691#if VREPRINT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000692 CI_ENTRY("rprnt", CRPRNT, VREPRINT)
Eric Andersen98e599c2001-02-14 18:47:33 +0000693#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200694#if VWERASE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000695 CI_ENTRY("werase", CWERASE, VWERASE )
Eric Andersen98e599c2001-02-14 18:47:33 +0000696#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200697#if VLNEXT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000698 CI_ENTRY("lnext", CLNEXT, VLNEXT )
Eric Andersen98e599c2001-02-14 18:47:33 +0000699#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200700#if VFLUSHO
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000701 CI_ENTRY("flush", CFLUSHO, VFLUSHO )
Eric Andersen98e599c2001-02-14 18:47:33 +0000702#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200703#if VSTATUS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000704 CI_ENTRY("status", CSTATUS, VSTATUS )
Eric Andersen98e599c2001-02-14 18:47:33 +0000705#endif
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000706 /* These must be last because of the display routines */
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000707 CI_ENTRY("min", 1, VMIN )
708 CI_ENTRY("time", 0, VTIME )
709 ;
710
711#undef CI_ENTRY
712#define CI_ENTRY(n,s,o) { s, o },
713
714static const struct control_info control_info[] = {
715 /* This should be verbatim cut-n-paste copy of the above CI_ENTRYs */
716 CI_ENTRY("intr", CINTR, VINTR )
717 CI_ENTRY("quit", CQUIT, VQUIT )
718 CI_ENTRY("erase", CERASE, VERASE )
719 CI_ENTRY("kill", CKILL, VKILL )
720 CI_ENTRY("eof", CEOF, VEOF )
721 CI_ENTRY("eol", CEOL, VEOL )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200722#if VEOL2
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000723 CI_ENTRY("eol2", CEOL2, VEOL2 )
724#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200725#if VSWTCH
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000726 CI_ENTRY("swtch", CSWTCH, VSWTCH )
727#endif
728 CI_ENTRY("start", CSTART, VSTART )
729 CI_ENTRY("stop", CSTOP, VSTOP )
730 CI_ENTRY("susp", CSUSP, VSUSP )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200731#if VDSUSP
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000732 CI_ENTRY("dsusp", CDSUSP, VDSUSP )
733#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200734#if VREPRINT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000735 CI_ENTRY("rprnt", CRPRNT, VREPRINT)
736#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200737#if VWERASE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000738 CI_ENTRY("werase", CWERASE, VWERASE )
739#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200740#if VLNEXT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000741 CI_ENTRY("lnext", CLNEXT, VLNEXT )
742#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200743#if VFLUSHO
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000744 CI_ENTRY("flush", CFLUSHO, VFLUSHO )
745#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200746#if VSTATUS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000747 CI_ENTRY("status", CSTATUS, VSTATUS )
748#endif
749 /* These must be last because of the display routines */
750 CI_ENTRY("min", 1, VMIN )
751 CI_ENTRY("time", 0, VTIME )
Eric Andersen98e599c2001-02-14 18:47:33 +0000752};
753
Rob Landleybc68cd12006-03-10 19:22:06 +0000754enum {
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000755 NUM_control_info = ARRAY_SIZE(control_info)
Rob Landleybc68cd12006-03-10 19:22:06 +0000756};
Eric Andersen98e599c2001-02-14 18:47:33 +0000757
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000758
759struct globals {
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100760 const char *device_name;
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000761 /* The width of the screen, for output wrapping */
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100762 unsigned max_col;
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000763 /* Current position, to know when to wrap */
764 unsigned current_col;
765 char buf[10];
Denys Vlasenko98a4c7c2010-02-04 15:00:15 +0100766} FIX_ALIASING;
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000767#define G (*(struct globals*)&bb_common_bufsiz1)
Denis Vlasenko7049ff82008-06-25 09:53:17 +0000768#define INIT_G() do { \
769 G.device_name = bb_msg_standard_input; \
770 G.max_col = 80; \
771} while (0)
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000772
Eric Andersen8876fb22003-06-20 09:01:58 +0000773
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000774/* Return a string that is the printable representation of character CH */
Denis Vlasenko79deb662006-09-19 15:12:12 +0000775/* Adapted from 'cat' by Torbjorn Granlund */
Denis Vlasenko240a1cf2007-04-08 16:07:02 +0000776static const char *visible(unsigned ch)
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000777{
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000778 char *bpout = G.buf;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000779
780 if (ch == _POSIX_VDISABLE)
781 return "<undef>";
782
783 if (ch >= 128) {
784 ch -= 128;
785 *bpout++ = 'M';
786 *bpout++ = '-';
787 }
788
789 if (ch < 32) {
790 *bpout++ = '^';
791 *bpout++ = ch + 64;
792 } else if (ch < 127) {
793 *bpout++ = ch;
794 } else {
795 *bpout++ = '^';
796 *bpout++ = '?';
797 }
798
799 *bpout = '\0';
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000800 return G.buf;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000801}
802
803static tcflag_t *mode_type_flag(unsigned type, const struct termios *mode)
804{
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000805 static const uint8_t tcflag_offsets[] ALIGN1 = {
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000806 offsetof(struct termios, c_cflag), /* control */
807 offsetof(struct termios, c_iflag), /* input */
808 offsetof(struct termios, c_oflag), /* output */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000809 offsetof(struct termios, c_lflag) /* local */
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000810 };
811
812 if (type <= local) {
813 return (tcflag_t*) (((char*)mode) + tcflag_offsets[type]);
814 }
815 return NULL;
816}
817
Denis Vlasenkoc7cc5a92009-04-19 01:27:20 +0000818static void set_speed_or_die(enum speed_setting type, const char *arg,
819 struct termios *mode)
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000820{
821 speed_t baud;
822
Bernhard Reutner-Fischer4950f012007-01-17 19:44:59 +0000823 baud = tty_value_to_baud(xatou(arg));
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000824
825 if (type != output_speed) { /* either input or both */
826 cfsetispeed(mode, baud);
827 }
828 if (type != input_speed) { /* either output or both */
829 cfsetospeed(mode, baud);
830 }
831}
832
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000833static NORETURN void perror_on_device_and_die(const char *fmt)
Eric Andersen8876fb22003-06-20 09:01:58 +0000834{
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000835 bb_perror_msg_and_die(fmt, G.device_name);
Eric Andersen8876fb22003-06-20 09:01:58 +0000836}
837
Denis Vlasenko20b253d2006-09-19 14:24:23 +0000838static void perror_on_device(const char *fmt)
839{
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000840 bb_perror_msg(fmt, G.device_name);
Denis Vlasenko20b253d2006-09-19 14:24:23 +0000841}
842
Eric Andersen98e599c2001-02-14 18:47:33 +0000843/* Print format string MESSAGE and optional args.
844 Wrap to next line first if it won't fit.
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000845 Print a space first unless MESSAGE will start a new line */
Eric Andersen98e599c2001-02-14 18:47:33 +0000846static void wrapf(const char *message, ...)
847{
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +0000848 char buf[128];
Eric Andersen98e599c2001-02-14 18:47:33 +0000849 va_list args;
Denis Vlasenko77ad97f2008-05-13 02:27:31 +0000850 unsigned buflen;
Eric Andersen98e599c2001-02-14 18:47:33 +0000851
852 va_start(args, message);
Bernhard Reutner-Fischer8eb05492007-01-17 19:46:33 +0000853 buflen = vsnprintf(buf, sizeof(buf), message, args);
Eric Andersen98e599c2001-02-14 18:47:33 +0000854 va_end(args);
Bernhard Reutner-Fischer1a250d92007-01-18 08:41:22 +0000855 /* We seem to be called only with suitable lengths, but check if
856 somebody failed to adhere to this assumption just to be sure. */
857 if (!buflen || buflen >= sizeof(buf)) return;
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +0000858
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000859 if (G.current_col > 0) {
860 G.current_col++;
Denis Vlasenko79deb662006-09-19 15:12:12 +0000861 if (buf[0] != '\n') {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000862 if (G.current_col + buflen >= G.max_col) {
Denis Vlasenko4daad902007-09-27 10:20:47 +0000863 bb_putchar('\n');
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000864 G.current_col = 0;
Denis Vlasenko79deb662006-09-19 15:12:12 +0000865 } else
Denis Vlasenko4daad902007-09-27 10:20:47 +0000866 bb_putchar(' ');
Denis Vlasenko79deb662006-09-19 15:12:12 +0000867 }
Eric Andersen98e599c2001-02-14 18:47:33 +0000868 }
869 fputs(buf, stdout);
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000870 G.current_col += buflen;
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +0000871 if (buf[buflen-1] == '\n')
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000872 G.current_col = 0;
Eric Andersen98e599c2001-02-14 18:47:33 +0000873}
874
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100875static void newline(void)
876{
877 if (G.current_col != 0)
878 wrapf("\n");
879}
880
Jeremie Koenig138ce542010-07-30 06:01:37 +0200881#ifdef TIOCGWINSZ
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100882static void set_window_size(int rows, int cols)
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000883{
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000884 struct winsize win = { 0, 0, 0, 0 };
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000885
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000886 if (ioctl(STDIN_FILENO, TIOCGWINSZ, &win)) {
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000887 if (errno != EINVAL) {
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000888 goto bail;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000889 }
890 memset(&win, 0, sizeof(win));
891 }
892
893 if (rows >= 0)
894 win.ws_row = rows;
895 if (cols >= 0)
896 win.ws_col = cols;
897
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000898 if (ioctl(STDIN_FILENO, TIOCSWINSZ, (char *) &win))
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000899bail:
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000900 perror_on_device("%s");
901}
Jeremie Koenig138ce542010-07-30 06:01:37 +0200902#endif
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000903
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100904static void display_window_size(int fancy)
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000905{
906 const char *fmt_str = "%s\0%s: no size information for this device";
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000907 unsigned width, height;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000908
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000909 if (get_terminal_width_height(STDIN_FILENO, &width, &height)) {
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000910 if ((errno != EINVAL) || ((fmt_str += 2), !fancy)) {
911 perror_on_device(fmt_str);
912 }
913 } else {
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100914 wrapf(fancy ? "rows %u; columns %u;" : "%u %u\n",
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000915 height, width);
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000916 }
917}
918
Eric Andersen98e599c2001-02-14 18:47:33 +0000919static const struct suffix_mult stty_suffixes[] = {
Denis Vlasenkof8689632007-07-27 15:06:25 +0000920 { "b", 512 },
921 { "k", 1024 },
922 { "B", 1024 },
Denys Vlasenko043b1e52009-09-06 12:47:55 +0200923 { "", 0 }
Eric Andersen98e599c2001-02-14 18:47:33 +0000924};
925
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000926static const struct mode_info *find_mode(const char *name)
927{
Denis Vlasenkoda42bd52008-01-27 23:24:31 +0000928 int i = index_in_strings(mode_name, name);
929 return i >= 0 ? &mode_info[i] : NULL;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000930}
931
932static const struct control_info *find_control(const char *name)
933{
Denis Vlasenkoda42bd52008-01-27 23:24:31 +0000934 int i = index_in_strings(control_name, name);
935 return i >= 0 ? &control_info[i] : NULL;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000936}
937
938enum {
939 param_need_arg = 0x80,
Denis Vlasenko9ace6132007-04-19 19:55:54 +0000940 param_line = 1 | 0x80,
941 param_rows = 2 | 0x80,
942 param_cols = 3 | 0x80,
943 param_columns = 4 | 0x80,
944 param_size = 5,
945 param_speed = 6,
946 param_ispeed = 7 | 0x80,
947 param_ospeed = 8 | 0x80,
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000948};
949
Denis Vlasenkoc7cc5a92009-04-19 01:27:20 +0000950static int find_param(const char *name)
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000951{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000952 static const char params[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000953 "line\0" /* 1 */
954 "rows\0" /* 2 */
955 "cols\0" /* 3 */
956 "columns\0" /* 4 */
957 "size\0" /* 5 */
958 "speed\0" /* 6 */
959 "ispeed\0"
960 "ospeed\0";
961 int i = index_in_strings(params, name) + 1;
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000962 if (i == 0)
Bernhard Reutner-Fischercbd6e652007-02-04 11:13:57 +0000963 return 0;
Denis Vlasenko9ace6132007-04-19 19:55:54 +0000964 if (i != 5 && i != 6)
Bernhard Reutner-Fischercbd6e652007-02-04 11:13:57 +0000965 i |= 0x80;
Bernhard Reutner-Fischera6e31ad2007-01-17 19:45:14 +0000966 return i;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000967}
968
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000969static int recover_mode(const char *arg, struct termios *mode)
970{
971 int i, n;
Denis Vlasenko240a1cf2007-04-08 16:07:02 +0000972 unsigned chr;
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000973 unsigned long iflag, oflag, cflag, lflag;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000974
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000975 /* Scan into temporaries since it is too much trouble to figure out
976 the right format for 'tcflag_t' */
977 if (sscanf(arg, "%lx:%lx:%lx:%lx%n",
978 &iflag, &oflag, &cflag, &lflag, &n) != 4)
979 return 0;
980 mode->c_iflag = iflag;
981 mode->c_oflag = oflag;
982 mode->c_cflag = cflag;
983 mode->c_lflag = lflag;
984 arg += n;
985 for (i = 0; i < NCCS; ++i) {
986 if (sscanf(arg, ":%x%n", &chr, &n) != 1)
987 return 0;
988 mode->c_cc[i] = chr;
989 arg += n;
990 }
991
992 /* Fail if there are too many fields */
993 if (*arg != '\0')
994 return 0;
995
996 return 1;
997}
998
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +0000999static void display_recoverable(const struct termios *mode,
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001000 int UNUSED_PARAM dummy)
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001001{
1002 int i;
1003 printf("%lx:%lx:%lx:%lx",
1004 (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
1005 (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
1006 for (i = 0; i < NCCS; ++i)
1007 printf(":%x", (unsigned int) mode->c_cc[i]);
Denis Vlasenko4daad902007-09-27 10:20:47 +00001008 bb_putchar('\n');
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001009}
1010
1011static void display_speed(const struct termios *mode, int fancy)
1012{
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001013 //____________________ 01234567 8 9
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001014 const char *fmt_str = "%lu %lu\n\0ispeed %lu baud; ospeed %lu baud;";
1015 unsigned long ispeed, ospeed;
1016
Denys Vlasenkoe54cfc52011-01-24 18:30:35 +01001017 ispeed = cfgetispeed(mode);
1018 ospeed = cfgetospeed(mode);
1019 if (ispeed == 0 || ispeed == ospeed) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001020 ispeed = ospeed; /* in case ispeed was 0 */
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001021 //________ 0123 4 5 6 7 8 9
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001022 fmt_str = "%lu\n\0\0\0\0\0speed %lu baud;";
1023 }
1024 if (fancy) fmt_str += 9;
1025 wrapf(fmt_str, tty_baud_to_value(ispeed), tty_baud_to_value(ospeed));
1026}
1027
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001028static void do_display(const struct termios *mode, int all)
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001029{
1030 int i;
1031 tcflag_t *bitsp;
1032 unsigned long mask;
1033 int prev_type = control;
1034
1035 display_speed(mode, 1);
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001036 if (all)
1037 display_window_size(1);
Denys Vlasenkoe54cfc52011-01-24 18:30:35 +01001038#ifdef __linux__
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001039 wrapf("line = %u;\n", mode->c_line);
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001040#else
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001041 newline();
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001042#endif
1043
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001044 for (i = 0; i != CIDX_min; ++i) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001045 /* If swtch is the same as susp, don't print both */
1046#if VSWTCH == VSUSP
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001047 if (i == CIDX_swtch)
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001048 continue;
1049#endif
1050 /* If eof uses the same slot as min, only print whichever applies */
1051#if VEOF == VMIN
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001052 if (!(mode->c_lflag & ICANON)
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001053 && (i == CIDX_eof || i == CIDX_eol)
1054 ) {
1055 continue;
1056 }
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001057#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001058 wrapf("%s = %s;", nth_string(control_name, i),
Denys Vlasenko60cb48c2013-01-14 15:57:44 +01001059 visible(mode->c_cc[control_info[i].offset]));
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001060 }
1061#if VEOF == VMIN
1062 if ((mode->c_lflag & ICANON) == 0)
1063#endif
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001064 wrapf("min = %u; time = %u;", mode->c_cc[VMIN], mode->c_cc[VTIME]);
1065 newline();
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001066
1067 for (i = 0; i < NUM_mode_info; ++i) {
1068 if (mode_info[i].flags & OMIT)
1069 continue;
1070 if (mode_info[i].type != prev_type) {
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001071 newline();
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001072 prev_type = mode_info[i].type;
1073 }
1074
1075 bitsp = mode_type_flag(mode_info[i].type, mode);
1076 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001077 if ((*bitsp & mask) == mode_info[i].bits) {
1078 if (all || (mode_info[i].flags & SANE_UNSET))
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001079 wrapf("-%s"+1, nth_string(mode_name, i));
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001080 } else {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001081 if ((all && mode_info[i].flags & REV)
1082 || (!all && (mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV))
1083 ) {
1084 wrapf("-%s", nth_string(mode_name, i));
1085 }
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001086 }
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001087 }
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001088 newline();
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001089}
1090
1091static void sane_mode(struct termios *mode)
1092{
1093 int i;
1094 tcflag_t *bitsp;
1095
1096 for (i = 0; i < NUM_control_info; ++i) {
1097#if VMIN == VEOF
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001098 if (i == CIDX_min)
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001099 break;
1100#endif
1101 mode->c_cc[control_info[i].offset] = control_info[i].saneval;
1102 }
1103
1104 for (i = 0; i < NUM_mode_info; ++i) {
1105 if (mode_info[i].flags & SANE_SET) {
1106 bitsp = mode_type_flag(mode_info[i].type, mode);
1107 *bitsp = (*bitsp & ~((unsigned long)mode_info[i].mask))
1108 | mode_info[i].bits;
1109 } else if (mode_info[i].flags & SANE_UNSET) {
1110 bitsp = mode_type_flag(mode_info[i].type, mode);
1111 *bitsp = *bitsp & ~((unsigned long)mode_info[i].mask)
1112 & ~mode_info[i].bits;
1113 }
1114 }
1115}
1116
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001117static void set_mode(const struct mode_info *info, int reversed,
1118 struct termios *mode)
1119{
1120 tcflag_t *bitsp;
1121
1122 bitsp = mode_type_flag(info->type, mode);
1123
1124 if (bitsp) {
1125 if (reversed)
1126 *bitsp = *bitsp & ~info->mask & ~info->bits;
1127 else
1128 *bitsp = (*bitsp & ~info->mask) | info->bits;
1129 return;
1130 }
1131
1132 /* Combination mode */
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001133 if (info == &mode_info[IDX_evenp] || info == &mode_info[IDX_parity]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001134 if (reversed)
1135 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1136 else
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02001137 mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001138 } else if (info == &mode_info[IDX_oddp]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001139 if (reversed)
1140 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1141 else
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02001142 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001143 } else if (info == &mode_info[IDX_nl]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001144 if (reversed) {
1145 mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02001146 mode->c_oflag = (mode->c_oflag | ONLCR) & ~OCRNL & ~ONLRET;
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001147 } else {
1148 mode->c_iflag = mode->c_iflag & ~ICRNL;
1149 if (ONLCR) mode->c_oflag = mode->c_oflag & ~ONLCR;
1150 }
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001151 } else if (info == &mode_info[IDX_ek]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001152 mode->c_cc[VERASE] = CERASE;
1153 mode->c_cc[VKILL] = CKILL;
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001154 } else if (info == &mode_info[IDX_sane]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001155 sane_mode(mode);
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001156 } else if (info == &mode_info[IDX_cbreak]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001157 if (reversed)
1158 mode->c_lflag |= ICANON;
1159 else
1160 mode->c_lflag &= ~ICANON;
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001161 } else if (info == &mode_info[IDX_pass8]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001162 if (reversed) {
1163 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1164 mode->c_iflag |= ISTRIP;
1165 } else {
1166 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1167 mode->c_iflag &= ~ISTRIP;
1168 }
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001169 } else if (info == &mode_info[IDX_litout]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001170 if (reversed) {
1171 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1172 mode->c_iflag |= ISTRIP;
1173 mode->c_oflag |= OPOST;
1174 } else {
1175 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1176 mode->c_iflag &= ~ISTRIP;
1177 mode->c_oflag &= ~OPOST;
1178 }
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001179 } else if (info == &mode_info[IDX_raw] || info == &mode_info[IDX_cooked]) {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001180 if ((info == &mode_info[IDX_raw] && reversed)
1181 || (info == &mode_info[IDX_cooked] && !reversed)
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001182 ) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001183 /* Cooked mode */
1184 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
1185 mode->c_oflag |= OPOST;
1186 mode->c_lflag |= ISIG | ICANON;
1187#if VMIN == VEOF
1188 mode->c_cc[VEOF] = CEOF;
1189#endif
1190#if VTIME == VEOL
1191 mode->c_cc[VEOL] = CEOL;
1192#endif
1193 } else {
1194 /* Raw mode */
1195 mode->c_iflag = 0;
1196 mode->c_oflag &= ~OPOST;
1197 mode->c_lflag &= ~(ISIG | ICANON | XCASE);
1198 mode->c_cc[VMIN] = 1;
1199 mode->c_cc[VTIME] = 0;
1200 }
1201 }
Jeremie Koenig138ce542010-07-30 06:01:37 +02001202#if IXANY
1203 else if (info == &mode_info[IDX_decctlq]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001204 if (reversed)
1205 mode->c_iflag |= IXANY;
1206 else
1207 mode->c_iflag &= ~IXANY;
1208 }
Jeremie Koenig138ce542010-07-30 06:01:37 +02001209#endif
1210#if TABDLY
1211 else if (info == &mode_info[IDX_tabs]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001212 if (reversed)
1213 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
1214 else
1215 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
1216 }
Jeremie Koenig138ce542010-07-30 06:01:37 +02001217#endif
1218#if OXTABS
1219 else if (info == &mode_info[IDX_tabs]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001220 if (reversed)
1221 mode->c_oflag |= OXTABS;
1222 else
1223 mode->c_oflag &= ~OXTABS;
Jeremie Koenig138ce542010-07-30 06:01:37 +02001224 }
1225#endif
1226#if XCASE && IUCLC && OLCUC
1227 else if (info==&mode_info[IDX_lcase] || info==&mode_info[IDX_LCASE]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001228 if (reversed) {
1229 mode->c_lflag &= ~XCASE;
1230 mode->c_iflag &= ~IUCLC;
1231 mode->c_oflag &= ~OLCUC;
1232 } else {
1233 mode->c_lflag |= XCASE;
1234 mode->c_iflag |= IUCLC;
1235 mode->c_oflag |= OLCUC;
1236 }
Jeremie Koenig138ce542010-07-30 06:01:37 +02001237 }
1238#endif
1239 else if (info == &mode_info[IDX_crt]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001240 mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001241 } else if (info == &mode_info[IDX_dec]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001242 mode->c_cc[VINTR] = 3; /* ^C */
1243 mode->c_cc[VERASE] = 127; /* DEL */
1244 mode->c_cc[VKILL] = 21; /* ^U */
1245 mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
1246 if (IXANY) mode->c_iflag &= ~IXANY;
1247 }
1248}
1249
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001250static void set_control_char_or_die(const struct control_info *info,
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001251 const char *arg, struct termios *mode)
1252{
1253 unsigned char value;
1254
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001255 if (info == &control_info[CIDX_min] || info == &control_info[CIDX_time])
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001256 value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
1257 else if (arg[0] == '\0' || arg[1] == '\0')
1258 value = arg[0];
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001259 else if (strcmp(arg, "^-") == 0 || strcmp(arg, "undef") == 0)
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001260 value = _POSIX_VDISABLE;
1261 else if (arg[0] == '^') { /* Ignore any trailing junk (^Cjunk) */
1262 value = arg[1] & 0x1f; /* Non-letters get weird results */
1263 if (arg[1] == '?')
1264 value = 127;
1265 } else
1266 value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
1267 mode->c_cc[info->offset] = value;
1268}
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001269
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001270#define STTY_require_set_attr (1 << 0)
1271#define STTY_speed_was_set (1 << 1)
1272#define STTY_verbose_output (1 << 2)
1273#define STTY_recoverable_output (1 << 3)
1274#define STTY_noargs (1 << 4)
1275
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00001276int stty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denys Vlasenkoe992bae2009-11-28 15:18:53 +01001277int stty_main(int argc UNUSED_PARAM, char **argv)
Eric Andersen98e599c2001-02-14 18:47:33 +00001278{
1279 struct termios mode;
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001280 void (*output_func)(const struct termios *, int);
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001281 const char *file_name = NULL;
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001282 int display_all = 0;
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001283 int stty_state;
1284 int k;
1285
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001286 INIT_G();
1287
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001288 stty_state = STTY_noargs;
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001289 output_func = do_display;
Eric Andersen98e599c2001-02-14 18:47:33 +00001290
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001291 /* First pass: only parse/verify command line params */
1292 k = 0;
1293 while (argv[++k]) {
1294 const struct mode_info *mp;
1295 const struct control_info *cp;
1296 const char *arg = argv[k];
1297 const char *argnext = argv[k+1];
1298 int param;
Eric Andersen98e599c2001-02-14 18:47:33 +00001299
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001300 if (arg[0] == '-') {
1301 int i;
1302 mp = find_mode(arg+1);
1303 if (mp) {
1304 if (!(mp->flags & REV))
Bernhard Reutner-Fischer4fa566d2007-01-17 19:42:30 +00001305 goto invalid_argument;
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001306 stty_state &= ~STTY_noargs;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001307 continue;
1308 }
1309 /* It is an option - parse it */
1310 i = 0;
1311 while (arg[++i]) {
1312 switch (arg[i]) {
1313 case 'a':
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001314 stty_state |= STTY_verbose_output;
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001315 output_func = do_display;
1316 display_all = 1;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001317 break;
1318 case 'g':
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001319 stty_state |= STTY_recoverable_output;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001320 output_func = display_recoverable;
1321 break;
1322 case 'F':
1323 if (file_name)
1324 bb_error_msg_and_die("only one device may be specified");
1325 file_name = &arg[i+1]; /* "-Fdevice" ? */
1326 if (!file_name[0]) { /* nope, "-F device" */
1327 int p = k+1; /* argv[p] is argnext */
1328 file_name = argnext;
1329 if (!file_name)
1330 bb_error_msg_and_die(bb_msg_requires_arg, "-F");
1331 /* remove -F param from arg[vc] */
Denys Vlasenkoe992bae2009-11-28 15:18:53 +01001332 while (argv[p]) {
1333 argv[p] = argv[p+1];
1334 ++p;
1335 }
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001336 }
1337 goto end_option;
1338 default:
Bernhard Reutner-Fischer4fa566d2007-01-17 19:42:30 +00001339 goto invalid_argument;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001340 }
1341 }
Denis Vlasenko240a1cf2007-04-08 16:07:02 +00001342 end_option:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001343 continue;
Eric Andersen98e599c2001-02-14 18:47:33 +00001344 }
1345
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001346 mp = find_mode(arg);
1347 if (mp) {
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001348 stty_state &= ~STTY_noargs;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001349 continue;
1350 }
1351
1352 cp = find_control(arg);
1353 if (cp) {
1354 if (!argnext)
1355 bb_error_msg_and_die(bb_msg_requires_arg, arg);
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001356 /* called for the side effect of xfunc death only */
1357 set_control_char_or_die(cp, argnext, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001358 stty_state &= ~STTY_noargs;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001359 ++k;
1360 continue;
1361 }
1362
1363 param = find_param(arg);
1364 if (param & param_need_arg) {
1365 if (!argnext)
1366 bb_error_msg_and_die(bb_msg_requires_arg, arg);
1367 ++k;
1368 }
1369
1370 switch (param) {
Denys Vlasenkoe54cfc52011-01-24 18:30:35 +01001371#ifdef __linux__
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001372 case param_line:
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +00001373# ifndef TIOCGWINSZ
Denis Vlasenko13858992006-10-08 12:49:22 +00001374 xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
Eric Andersen98e599c2001-02-14 18:47:33 +00001375 break;
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +00001376# endif /* else fall-through */
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001377#endif
1378#ifdef TIOCGWINSZ
1379 case param_rows:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001380 case param_cols:
Denis Vlasenko9ace6132007-04-19 19:55:54 +00001381 case param_columns:
Denis Vlasenko13858992006-10-08 12:49:22 +00001382 xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001383 break;
1384 case param_size:
1385#endif
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001386 case param_speed:
1387 break;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001388 case param_ispeed:
1389 /* called for the side effect of xfunc death only */
1390 set_speed_or_die(input_speed, argnext, &mode);
1391 break;
1392 case param_ospeed:
1393 /* called for the side effect of xfunc death only */
1394 set_speed_or_die(output_speed, argnext, &mode);
1395 break;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001396 default:
1397 if (recover_mode(arg, &mode) == 1) break;
Bernhard Reutner-Fischer4950f012007-01-17 19:44:59 +00001398 if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) break;
Denis Vlasenko240a1cf2007-04-08 16:07:02 +00001399 invalid_argument:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001400 bb_error_msg_and_die("invalid argument '%s'", arg);
1401 }
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001402 stty_state &= ~STTY_noargs;
Eric Andersen98e599c2001-02-14 18:47:33 +00001403 }
1404
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001405 /* Specifying both -a and -g is an error */
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001406 if ((stty_state & (STTY_verbose_output | STTY_recoverable_output)) ==
Denys Vlasenko5dd1f472011-10-21 19:45:13 +02001407 (STTY_verbose_output | STTY_recoverable_output)
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001408 ) {
Denys Vlasenko5dd1f472011-10-21 19:45:13 +02001409 bb_error_msg_and_die("-a and -g are mutually exclusive");
1410 }
1411 /* Specifying -a or -g with non-options is an error */
1412 if ((stty_state & (STTY_verbose_output | STTY_recoverable_output))
1413 && !(stty_state & STTY_noargs)
1414 ) {
1415 bb_error_msg_and_die("modes may not be set when -a or -g is used");
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001416 }
Eric Andersen98e599c2001-02-14 18:47:33 +00001417
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001418 /* Now it is safe to start doing things */
Eric Andersen98e599c2001-02-14 18:47:33 +00001419 if (file_name) {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001420 G.device_name = file_name;
Denys Vlasenkoab19ede2009-11-11 21:05:42 +01001421 xmove_fd(xopen_nonblocking(G.device_name), STDIN_FILENO);
1422 ndelay_off(STDIN_FILENO);
Eric Andersen98e599c2001-02-14 18:47:33 +00001423 }
1424
1425 /* Initialize to all zeroes so there is no risk memcmp will report a
Denis Vlasenko9efb0702006-09-19 14:17:10 +00001426 spurious difference in an uninitialized portion of the structure */
Eric Andersen98e599c2001-02-14 18:47:33 +00001427 memset(&mode, 0, sizeof(mode));
"Vladimir N. Oleynik"9b9a9202006-01-30 12:23:46 +00001428 if (tcgetattr(STDIN_FILENO, &mode))
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001429 perror_on_device_and_die("%s");
Eric Andersen98e599c2001-02-14 18:47:33 +00001430
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001431 if (stty_state & (STTY_verbose_output | STTY_recoverable_output | STTY_noargs)) {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001432 get_terminal_width_height(STDOUT_FILENO, &G.max_col, NULL);
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001433 output_func(&mode, display_all);
Eric Andersen98e599c2001-02-14 18:47:33 +00001434 return EXIT_SUCCESS;
1435 }
1436
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001437 /* Second pass: perform actions */
Eric Andersenfc059092002-06-06 11:35:29 +00001438 k = 0;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001439 while (argv[++k]) {
1440 const struct mode_info *mp;
1441 const struct control_info *cp;
1442 const char *arg = argv[k];
1443 const char *argnext = argv[k+1];
1444 int param;
Eric Andersen98e599c2001-02-14 18:47:33 +00001445
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001446 if (arg[0] == '-') {
1447 mp = find_mode(arg+1);
1448 if (mp) {
1449 set_mode(mp, 1 /* reversed */, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001450 stty_state |= STTY_require_set_attr;
Eric Andersenfc059092002-06-06 11:35:29 +00001451 }
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001452 /* It is an option - already parsed. Skip it */
1453 continue;
Eric Andersen98e599c2001-02-14 18:47:33 +00001454 }
Mark Whitley446dd272001-03-02 20:00:54 +00001455
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001456 mp = find_mode(arg);
1457 if (mp) {
1458 set_mode(mp, 0 /* non-reversed */, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001459 stty_state |= STTY_require_set_attr;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001460 continue;
1461 }
Mark Whitley446dd272001-03-02 20:00:54 +00001462
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001463 cp = find_control(arg);
1464 if (cp) {
1465 ++k;
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001466 set_control_char_or_die(cp, argnext, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001467 stty_state |= STTY_require_set_attr;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001468 continue;
1469 }
Mark Whitley446dd272001-03-02 20:00:54 +00001470
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001471 param = find_param(arg);
1472 if (param & param_need_arg) {
1473 ++k;
1474 }
1475
1476 switch (param) {
Denys Vlasenkoe54cfc52011-01-24 18:30:35 +01001477#ifdef __linux__
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001478 case param_line:
Denis Vlasenko13858992006-10-08 12:49:22 +00001479 mode.c_line = xatoul_sfx(argnext, stty_suffixes);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001480 stty_state |= STTY_require_set_attr;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001481 break;
Eric Andersen98e599c2001-02-14 18:47:33 +00001482#endif
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001483#ifdef TIOCGWINSZ
1484 case param_cols:
Denys Vlasenko9f5a5772009-12-11 14:17:02 +01001485 case param_columns:
Denis Vlasenko13858992006-10-08 12:49:22 +00001486 set_window_size(-1, xatoul_sfx(argnext, stty_suffixes));
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001487 break;
1488 case param_size:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001489 display_window_size(0);
1490 break;
1491 case param_rows:
Denis Vlasenko13858992006-10-08 12:49:22 +00001492 set_window_size(xatoul_sfx(argnext, stty_suffixes), -1);
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001493 break;
1494#endif
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001495 case param_speed:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001496 display_speed(&mode, 0);
1497 break;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001498 case param_ispeed:
1499 set_speed_or_die(input_speed, argnext, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001500 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001501 break;
1502 case param_ospeed:
1503 set_speed_or_die(output_speed, argnext, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001504 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001505 break;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001506 default:
1507 if (recover_mode(arg, &mode) == 1)
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001508 stty_state |= STTY_require_set_attr;
Bernhard Reutner-Fischer4950f012007-01-17 19:44:59 +00001509 else /* true: if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) */{
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001510 set_speed_or_die(both_speeds, arg, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001511 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001512 } /* else - impossible (caught in the first pass):
1513 bb_error_msg_and_die("invalid argument '%s'", arg); */
Eric Andersen98e599c2001-02-14 18:47:33 +00001514 }
Eric Andersen98e599c2001-02-14 18:47:33 +00001515 }
1516
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001517 if (stty_state & STTY_require_set_attr) {
Eric Andersen98e599c2001-02-14 18:47:33 +00001518 struct termios new_mode;
1519
"Vladimir N. Oleynik"9b9a9202006-01-30 12:23:46 +00001520 if (tcsetattr(STDIN_FILENO, TCSADRAIN, &mode))
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001521 perror_on_device_and_die("%s");
Eric Andersen98e599c2001-02-14 18:47:33 +00001522
1523 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
1524 it performs *any* of the requested operations. This means it
Denis Vlasenko79deb662006-09-19 15:12:12 +00001525 can report 'success' when it has actually failed to perform
Eric Andersen98e599c2001-02-14 18:47:33 +00001526 some proper subset of the requested operations. To detect
1527 this partial failure, get the current terminal attributes and
Denis Vlasenko9efb0702006-09-19 14:17:10 +00001528 compare them to the requested ones */
Eric Andersen98e599c2001-02-14 18:47:33 +00001529
1530 /* Initialize to all zeroes so there is no risk memcmp will report a
Denis Vlasenko9efb0702006-09-19 14:17:10 +00001531 spurious difference in an uninitialized portion of the structure */
Eric Andersen98e599c2001-02-14 18:47:33 +00001532 memset(&new_mode, 0, sizeof(new_mode));
"Vladimir N. Oleynik"9b9a9202006-01-30 12:23:46 +00001533 if (tcgetattr(STDIN_FILENO, &new_mode))
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001534 perror_on_device_and_die("%s");
Eric Andersen98e599c2001-02-14 18:47:33 +00001535
Eric Andersen98e599c2001-02-14 18:47:33 +00001536 if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) {
Jeremie Koenig138ce542010-07-30 06:01:37 +02001537#if CIBAUD
Eric Andersen98e599c2001-02-14 18:47:33 +00001538 /* SunOS 4.1.3 (at least) has the problem that after this sequence,
1539 tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
1540 sometimes (m1 != m2). The only difference is in the four bits
1541 of the c_cflag field corresponding to the baud rate. To save
1542 Sun users a little confusion, don't report an error if this
1543 happens. But suppress the error only if we haven't tried to
1544 set the baud rate explicitly -- otherwise we'd never give an
Denis Vlasenko9efb0702006-09-19 14:17:10 +00001545 error for a true failure to set the baud rate */
Eric Andersen98e599c2001-02-14 18:47:33 +00001546
1547 new_mode.c_cflag &= (~CIBAUD);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001548 if ((stty_state & STTY_speed_was_set)
1549 || memcmp(&mode, &new_mode, sizeof(mode)) != 0)
Eric Andersen98e599c2001-02-14 18:47:33 +00001550#endif
Denis Vlasenko89f0b342006-11-18 22:04:09 +00001551 perror_on_device_and_die("%s: cannot perform all requested operations");
Eric Andersen98e599c2001-02-14 18:47:33 +00001552 }
1553 }
1554
1555 return EXIT_SUCCESS;
1556}