blob: af2347161f1be8cb0514737d0a9d524c7ade2c20 [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"
29//usage: "\nOptions:"
30//usage: "\n -F DEVICE Open device instead of stdin"
31//usage: "\n -a Print all current settings in human-readable form"
32//usage: "\n -g Print in stty-readable form"
33//usage: "\n [SETTING] See manpage"
34
Denis Vlasenkob6adbf12007-05-26 19:00:18 +000035#include "libbb.h"
Eric Andersen98e599c2001-02-14 18:47:33 +000036
Eric Andersen98e599c2001-02-14 18:47:33 +000037#ifndef _POSIX_VDISABLE
38# define _POSIX_VDISABLE ((unsigned char) 0)
39#endif
40
41#define Control(c) ((c) & 0x1f)
Denis Vlasenko9efb0702006-09-19 14:17:10 +000042/* Canonical values for control characters */
Eric Andersen98e599c2001-02-14 18:47:33 +000043#ifndef CINTR
Denis Vlasenko9efb0702006-09-19 14:17:10 +000044# define CINTR Control('c')
Eric Andersen98e599c2001-02-14 18:47:33 +000045#endif
46#ifndef CQUIT
47# define CQUIT 28
48#endif
49#ifndef CERASE
50# define CERASE 127
51#endif
52#ifndef CKILL
Denis Vlasenko9efb0702006-09-19 14:17:10 +000053# define CKILL Control('u')
Eric Andersen98e599c2001-02-14 18:47:33 +000054#endif
55#ifndef CEOF
Denis Vlasenko9efb0702006-09-19 14:17:10 +000056# define CEOF Control('d')
Eric Andersen98e599c2001-02-14 18:47:33 +000057#endif
58#ifndef CEOL
59# define CEOL _POSIX_VDISABLE
60#endif
61#ifndef CSTART
Denis Vlasenko9efb0702006-09-19 14:17:10 +000062# define CSTART Control('q')
Eric Andersen98e599c2001-02-14 18:47:33 +000063#endif
64#ifndef CSTOP
Denis Vlasenko9efb0702006-09-19 14:17:10 +000065# define CSTOP Control('s')
Eric Andersen98e599c2001-02-14 18:47:33 +000066#endif
67#ifndef CSUSP
Denis Vlasenko9efb0702006-09-19 14:17:10 +000068# define CSUSP Control('z')
Eric Andersen98e599c2001-02-14 18:47:33 +000069#endif
70#if defined(VEOL2) && !defined(CEOL2)
71# define CEOL2 _POSIX_VDISABLE
72#endif
Denys Vlasenko271c0ce2011-01-24 16:36:15 +010073/* glibc-2.12.1 uses only VSWTC name */
74#if defined(VSWTC) && !defined(VSWTCH)
75# define VSWTCH VSWTC
76#endif
Denis Vlasenko9efb0702006-09-19 14:17:10 +000077/* ISC renamed swtch to susp for termios, but we'll accept either name */
Eric Andersen98e599c2001-02-14 18:47:33 +000078#if defined(VSUSP) && !defined(VSWTCH)
79# define VSWTCH VSUSP
80# define CSWTCH CSUSP
81#endif
82#if defined(VSWTCH) && !defined(CSWTCH)
83# define CSWTCH _POSIX_VDISABLE
84#endif
85
Denis Vlasenko79deb662006-09-19 15:12:12 +000086/* SunOS 5.3 loses (^Z doesn't work) if 'swtch' is the same as 'susp'.
87 So the default is to disable 'swtch.' */
Denis Vlasenkoff131b92007-04-10 15:42:06 +000088#if defined(__sparc__) && defined(__svr4__)
Eric Andersen98e599c2001-02-14 18:47:33 +000089# undef CSWTCH
90# define CSWTCH _POSIX_VDISABLE
91#endif
92
Denis Vlasenkoff131b92007-04-10 15:42:06 +000093#if defined(VWERSE) && !defined(VWERASE) /* AIX-3.2.5 */
Eric Andersen98e599c2001-02-14 18:47:33 +000094# define VWERASE VWERSE
95#endif
Denis Vlasenkoff131b92007-04-10 15:42:06 +000096#if defined(VDSUSP) && !defined(CDSUSP)
Denis Vlasenko9efb0702006-09-19 14:17:10 +000097# define CDSUSP Control('y')
Eric Andersen98e599c2001-02-14 18:47:33 +000098#endif
Mark Whitley446dd272001-03-02 20:00:54 +000099#if !defined(VREPRINT) && defined(VRPRNT) /* Irix 4.0.5 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000100# define VREPRINT VRPRNT
101#endif
102#if defined(VREPRINT) && !defined(CRPRNT)
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000103# define CRPRNT Control('r')
Eric Andersen98e599c2001-02-14 18:47:33 +0000104#endif
105#if defined(VWERASE) && !defined(CWERASE)
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000106# define CWERASE Control('w')
Eric Andersen98e599c2001-02-14 18:47:33 +0000107#endif
108#if defined(VLNEXT) && !defined(CLNEXT)
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000109# define CLNEXT Control('v')
Eric Andersen98e599c2001-02-14 18:47:33 +0000110#endif
111#if defined(VDISCARD) && !defined(VFLUSHO)
112# define VFLUSHO VDISCARD
113#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000114#if defined(VFLUSH) && !defined(VFLUSHO) /* Ultrix 4.2 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000115# define VFLUSHO VFLUSH
116#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000117#if defined(CTLECH) && !defined(ECHOCTL) /* Ultrix 4.3 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000118# define ECHOCTL CTLECH
119#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000120#if defined(TCTLECH) && !defined(ECHOCTL) /* Ultrix 4.2 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000121# define ECHOCTL TCTLECH
122#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000123#if defined(CRTKIL) && !defined(ECHOKE) /* Ultrix 4.2 and 4.3 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000124# define ECHOKE CRTKIL
125#endif
126#if defined(VFLUSHO) && !defined(CFLUSHO)
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000127# define CFLUSHO Control('o')
Eric Andersen98e599c2001-02-14 18:47:33 +0000128#endif
129#if defined(VSTATUS) && !defined(CSTATUS)
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000130# define CSTATUS Control('t')
Eric Andersen98e599c2001-02-14 18:47:33 +0000131#endif
132
Jeremie Koenig138ce542010-07-30 06:01:37 +0200133/* Save us from #ifdef forest plague */
134#ifndef BSDLY
135# define BSDLY 0
136#endif
137#ifndef CIBAUD
138# define CIBAUD 0
139#endif
140#ifndef CRDLY
141# define CRDLY 0
142#endif
143#ifndef CRTSCTS
144# define CRTSCTS 0
145#endif
146#ifndef ECHOCTL
147# define ECHOCTL 0
148#endif
149#ifndef ECHOKE
150# define ECHOKE 0
151#endif
152#ifndef ECHOPRT
153# define ECHOPRT 0
154#endif
155#ifndef FFDLY
156# define FFDLY 0
157#endif
158#ifndef IEXTEN
159# define IEXTEN 0
160#endif
161#ifndef IMAXBEL
162# define IMAXBEL 0
163#endif
164#ifndef IUCLC
165# define IUCLC 0
166#endif
167#ifndef IXANY
168# define IXANY 0
169#endif
170#ifndef NLDLY
171# define NLDLY 0
172#endif
173#ifndef OCRNL
174# define OCRNL 0
175#endif
176#ifndef OFDEL
177# define OFDEL 0
178#endif
179#ifndef OFILL
180# define OFILL 0
181#endif
182#ifndef OLCUC
183# define OLCUC 0
184#endif
185#ifndef ONLCR
186# define ONLCR 0
187#endif
188#ifndef ONLRET
189# define ONLRET 0
190#endif
191#ifndef ONOCR
192# define ONOCR 0
193#endif
194#ifndef OXTABS
195# define OXTABS 0
196#endif
197#ifndef TABDLY
198# define TABDLY 0
199#endif
200#ifndef TAB1
201# define TAB1 0
202#endif
203#ifndef TAB2
204# define TAB2 0
205#endif
206#ifndef TOSTOP
207# define TOSTOP 0
208#endif
209#ifndef VDSUSP
210# define VDSUSP 0
211#endif
212#ifndef VEOL2
213# define VEOL2 0
214#endif
215#ifndef VFLUSHO
216# define VFLUSHO 0
217#endif
218#ifndef VLNEXT
219# define VLNEXT 0
220#endif
221#ifndef VREPRINT
222# define VREPRINT 0
223#endif
224#ifndef VSTATUS
225# define VSTATUS 0
226#endif
227#ifndef VSWTCH
228# define VSWTCH 0
229#endif
230#ifndef VTDLY
231# define VTDLY 0
232#endif
233#ifndef VWERASE
234# define VWERASE 0
235#endif
236#ifndef XCASE
237# define XCASE 0
238#endif
Denys Vlasenko271c0ce2011-01-24 16:36:15 +0100239#ifndef IUTF8
240# define IUTF8 0
241#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200242
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000243/* Which speeds to set */
Eric Andersen98e599c2001-02-14 18:47:33 +0000244enum speed_setting {
245 input_speed, output_speed, both_speeds
246};
247
Denis Vlasenko79deb662006-09-19 15:12:12 +0000248/* Which member(s) of 'struct termios' a mode uses */
Denis Vlasenko20b253d2006-09-19 14:24:23 +0000249enum {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000250 /* Do NOT change the order or values, as mode_type_flag()
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000251 * depends on them */
Eric Andersen98e599c2001-02-14 18:47:33 +0000252 control, input, output, local, combination
253};
254
Denis Vlasenko79deb662006-09-19 15:12:12 +0000255/* Flags for 'struct mode_info' */
256#define SANE_SET 1 /* Set in 'sane' mode */
257#define SANE_UNSET 2 /* Unset in 'sane' mode */
258#define REV 4 /* Can be turned off by prepending '-' */
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000259#define OMIT 8 /* Don't display value */
Eric Andersen98e599c2001-02-14 18:47:33 +0000260
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000261
262/* Each mode.
263 * This structure should be kept as small as humanly possible.
264 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000265struct mode_info {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000266 const uint8_t type; /* Which structure element to change */
267 const uint8_t flags; /* Setting and display options */
268 /* only these values are ever used, so... */
269#if (CSIZE | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY) < 0x100
270 const uint8_t mask;
271#elif (CSIZE | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY) < 0x10000
272 const uint16_t mask;
273#else
Bernhard Reutner-Fischer21fc7402007-01-17 19:44:24 +0000274 const tcflag_t mask; /* Other bits to turn off for this mode */
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000275#endif
276 /* was using short here, but ppc32 was unhappy */
Bernhard Reutner-Fischer21fc7402007-01-17 19:44:24 +0000277 const tcflag_t bits; /* Bits to set for this mode */
Eric Andersen98e599c2001-02-14 18:47:33 +0000278};
279
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000280enum {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000281 /* Must match mode_name[] and mode_info[] order! */
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000282 IDX_evenp = 0,
283 IDX_parity,
284 IDX_oddp,
285 IDX_nl,
286 IDX_ek,
287 IDX_sane,
288 IDX_cooked,
289 IDX_raw,
290 IDX_pass8,
291 IDX_litout,
292 IDX_cbreak,
293 IDX_crt,
294 IDX_dec,
Jeremie Koenig138ce542010-07-30 06:01:37 +0200295#if IXANY
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000296 IDX_decctlq,
297#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200298#if TABDLY || OXTABS
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000299 IDX_tabs,
300#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200301#if XCASE && IUCLC && OLCUC
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000302 IDX_lcase,
303 IDX_LCASE,
304#endif
305};
Denis Vlasenkob2abef32007-01-01 18:18:04 +0000306
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000307#define MI_ENTRY(N,T,F,B,M) N "\0"
Manuel Novoa III cad53642003-03-19 09:13:01 +0000308
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000309/* Mode names given on command line */
310static const char mode_name[] =
311 MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 )
312 MI_ENTRY("parity", combination, REV | OMIT, 0, 0 )
313 MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 )
314 MI_ENTRY("nl", combination, REV | OMIT, 0, 0 )
315 MI_ENTRY("ek", combination, OMIT, 0, 0 )
316 MI_ENTRY("sane", combination, OMIT, 0, 0 )
317 MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 )
318 MI_ENTRY("raw", combination, REV | OMIT, 0, 0 )
319 MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 )
320 MI_ENTRY("litout", combination, REV | OMIT, 0, 0 )
321 MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 )
322 MI_ENTRY("crt", combination, OMIT, 0, 0 )
323 MI_ENTRY("dec", combination, OMIT, 0, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200324#if IXANY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000325 MI_ENTRY("decctlq", combination, REV | OMIT, 0, 0 )
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000326#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200327#if TABDLY || OXTABS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000328 MI_ENTRY("tabs", combination, REV | OMIT, 0, 0 )
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000329#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200330#if XCASE && IUCLC && OLCUC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000331 MI_ENTRY("lcase", combination, REV | OMIT, 0, 0 )
332 MI_ENTRY("LCASE", combination, REV | OMIT, 0, 0 )
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000333#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000334 MI_ENTRY("parenb", control, REV, PARENB, 0 )
335 MI_ENTRY("parodd", control, REV, PARODD, 0 )
336 MI_ENTRY("cs5", control, 0, CS5, CSIZE)
337 MI_ENTRY("cs6", control, 0, CS6, CSIZE)
338 MI_ENTRY("cs7", control, 0, CS7, CSIZE)
339 MI_ENTRY("cs8", control, 0, CS8, CSIZE)
340 MI_ENTRY("hupcl", control, REV, HUPCL, 0 )
341 MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 )
342 MI_ENTRY("cstopb", control, REV, CSTOPB, 0 )
343 MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 )
344 MI_ENTRY("clocal", control, REV, CLOCAL, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200345#if CRTSCTS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000346 MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000347#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000348 MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 )
349 MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 )
350 MI_ENTRY("ignpar", input, REV, IGNPAR, 0 )
351 MI_ENTRY("parmrk", input, REV, PARMRK, 0 )
352 MI_ENTRY("inpck", input, REV, INPCK, 0 )
353 MI_ENTRY("istrip", input, REV, ISTRIP, 0 )
354 MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 )
355 MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 )
356 MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 )
357 MI_ENTRY("ixon", input, REV, IXON, 0 )
358 MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100359 MI_ENTRY("tandem", input, OMIT | REV, IXOFF, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200360#if IUCLC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000361 MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000362#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200363#if IXANY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000364 MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000365#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200366#if IMAXBEL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000367 MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000368#endif
Denys Vlasenko271c0ce2011-01-24 16:36:15 +0100369#if IUTF8
370 MI_ENTRY("iutf8", input, SANE_UNSET | REV, IUTF8, 0 )
371#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000372 MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200373#if OLCUC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000374 MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000375#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200376#if OCRNL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000377 MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000378#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200379#if ONLCR
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000380 MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000381#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200382#if ONOCR
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000383 MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000384#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200385#if ONLRET
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000386 MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000387#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200388#if OFILL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000389 MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000390#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200391#if OFDEL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000392 MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000393#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200394#if NLDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000395 MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY)
396 MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000397#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200398#if CRDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000399 MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY)
400 MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY)
401 MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY)
402 MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000403#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000404
Jeremie Koenig138ce542010-07-30 06:01:37 +0200405#if TABDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000406 MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200407# if TAB2
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000408 MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200409# endif
410# if TAB1
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000411 MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200412# endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000413 MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000414#else
Jeremie Koenig138ce542010-07-30 06:01:37 +0200415# if OXTABS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000416 MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000417# endif
418#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000419
Jeremie Koenig138ce542010-07-30 06:01:37 +0200420#if BSDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000421 MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY)
422 MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000423#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200424#if VTDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000425 MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY)
426 MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000427#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200428#if FFDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000429 MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY)
430 MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000431#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000432 MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 )
433 MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200434#if IEXTEN
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000435 MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000436#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000437 MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 )
438 MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100439 MI_ENTRY("crterase", local, OMIT | REV, ECHOE, 0 )
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000440 MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 )
441 MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 )
442 MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200443#if XCASE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000444 MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000445#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200446#if TOSTOP
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000447 MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000448#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200449#if ECHOPRT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000450 MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100451 MI_ENTRY("prterase", local, OMIT | REV, ECHOPRT, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000452#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200453#if ECHOCTL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000454 MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100455 MI_ENTRY("ctlecho", local, OMIT | REV, ECHOCTL, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000456#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200457#if ECHOKE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000458 MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100459 MI_ENTRY("crtkill", local, OMIT | REV, ECHOKE, 0 )
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000460#endif
461 ;
462
463#undef MI_ENTRY
464#define MI_ENTRY(N,T,F,B,M) { T, F, M, B },
465
466static const struct mode_info mode_info[] = {
467 /* This should be verbatim cut-n-paste copy of the above MI_ENTRYs */
468 MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 )
469 MI_ENTRY("parity", combination, REV | OMIT, 0, 0 )
470 MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 )
471 MI_ENTRY("nl", combination, REV | OMIT, 0, 0 )
472 MI_ENTRY("ek", combination, OMIT, 0, 0 )
473 MI_ENTRY("sane", combination, OMIT, 0, 0 )
474 MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 )
475 MI_ENTRY("raw", combination, REV | OMIT, 0, 0 )
476 MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 )
477 MI_ENTRY("litout", combination, REV | OMIT, 0, 0 )
478 MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 )
479 MI_ENTRY("crt", combination, OMIT, 0, 0 )
480 MI_ENTRY("dec", combination, OMIT, 0, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200481#if IXANY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000482 MI_ENTRY("decctlq", combination, REV | OMIT, 0, 0 )
483#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200484#if TABDLY || OXTABS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000485 MI_ENTRY("tabs", combination, REV | OMIT, 0, 0 )
486#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200487#if XCASE && IUCLC && OLCUC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000488 MI_ENTRY("lcase", combination, REV | OMIT, 0, 0 )
489 MI_ENTRY("LCASE", combination, REV | OMIT, 0, 0 )
490#endif
491 MI_ENTRY("parenb", control, REV, PARENB, 0 )
492 MI_ENTRY("parodd", control, REV, PARODD, 0 )
493 MI_ENTRY("cs5", control, 0, CS5, CSIZE)
494 MI_ENTRY("cs6", control, 0, CS6, CSIZE)
495 MI_ENTRY("cs7", control, 0, CS7, CSIZE)
496 MI_ENTRY("cs8", control, 0, CS8, CSIZE)
497 MI_ENTRY("hupcl", control, REV, HUPCL, 0 )
498 MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 )
499 MI_ENTRY("cstopb", control, REV, CSTOPB, 0 )
500 MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 )
501 MI_ENTRY("clocal", control, REV, CLOCAL, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200502#if CRTSCTS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000503 MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 )
504#endif
505 MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 )
506 MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 )
507 MI_ENTRY("ignpar", input, REV, IGNPAR, 0 )
508 MI_ENTRY("parmrk", input, REV, PARMRK, 0 )
509 MI_ENTRY("inpck", input, REV, INPCK, 0 )
510 MI_ENTRY("istrip", input, REV, ISTRIP, 0 )
511 MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 )
512 MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 )
513 MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 )
514 MI_ENTRY("ixon", input, REV, IXON, 0 )
515 MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100516 MI_ENTRY("tandem", input, OMIT | REV, IXOFF, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200517#if IUCLC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000518 MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 )
519#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200520#if IXANY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000521 MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 )
522#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200523#if IMAXBEL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000524 MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 )
525#endif
Denys Vlasenko271c0ce2011-01-24 16:36:15 +0100526#if IUTF8
527 MI_ENTRY("iutf8", input, SANE_UNSET | REV, IUTF8, 0 )
528#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000529 MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200530#if OLCUC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000531 MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 )
532#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200533#if OCRNL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000534 MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 )
535#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200536#if ONLCR
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000537 MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 )
538#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200539#if ONOCR
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000540 MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 )
541#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200542#if ONLRET
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000543 MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 )
544#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200545#if OFILL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000546 MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 )
547#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200548#if OFDEL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000549 MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 )
550#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200551#if NLDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000552 MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY)
553 MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY)
554#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200555#if CRDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000556 MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY)
557 MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY)
558 MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY)
559 MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY)
560#endif
561
Jeremie Koenig138ce542010-07-30 06:01:37 +0200562#if TABDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000563 MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200564# if TAB2
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000565 MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200566# endif
567# if TAB1
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000568 MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200569# endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000570 MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY)
571#else
Jeremie Koenig138ce542010-07-30 06:01:37 +0200572# if OXTABS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000573 MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 )
574# endif
575#endif
576
Jeremie Koenig138ce542010-07-30 06:01:37 +0200577#if BSDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000578 MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY)
579 MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY)
580#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200581#if VTDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000582 MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY)
583 MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY)
584#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200585#if FFDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000586 MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY)
587 MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY)
588#endif
589 MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 )
590 MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200591#if IEXTEN
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000592 MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 )
593#endif
594 MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 )
595 MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100596 MI_ENTRY("crterase", local, OMIT | REV, ECHOE, 0 )
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000597 MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 )
598 MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 )
599 MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200600#if XCASE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000601 MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 )
602#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200603#if TOSTOP
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000604 MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 )
605#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200606#if ECHOPRT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000607 MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100608 MI_ENTRY("prterase", local, OMIT | REV, ECHOPRT, 0 )
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000609#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200610#if ECHOCTL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000611 MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100612 MI_ENTRY("ctlecho", local, OMIT | REV, ECHOCTL, 0 )
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000613#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200614#if ECHOKE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000615 MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100616 MI_ENTRY("crtkill", local, OMIT | REV, ECHOKE, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000617#endif
Eric Andersen98e599c2001-02-14 18:47:33 +0000618};
619
Rob Landleybc68cd12006-03-10 19:22:06 +0000620enum {
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000621 NUM_mode_info = ARRAY_SIZE(mode_info)
Rob Landleybc68cd12006-03-10 19:22:06 +0000622};
Eric Andersen98e599c2001-02-14 18:47:33 +0000623
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000624
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000625/* Control characters */
Eric Andersen98e599c2001-02-14 18:47:33 +0000626struct control_info {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000627 const uint8_t saneval; /* Value to set for 'stty sane' */
628 const uint8_t offset; /* Offset in c_cc */
Eric Andersen98e599c2001-02-14 18:47:33 +0000629};
630
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000631enum {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000632 /* Must match control_name[] and control_info[] order! */
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000633 CIDX_intr = 0,
634 CIDX_quit,
635 CIDX_erase,
636 CIDX_kill,
637 CIDX_eof,
638 CIDX_eol,
Jeremie Koenig138ce542010-07-30 06:01:37 +0200639#if VEOL2
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000640 CIDX_eol2,
641#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200642#if VSWTCH
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000643 CIDX_swtch,
644#endif
645 CIDX_start,
646 CIDX_stop,
647 CIDX_susp,
Jeremie Koenig138ce542010-07-30 06:01:37 +0200648#if VDSUSP
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000649 CIDX_dsusp,
650#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200651#if VREPRINT
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000652 CIDX_rprnt,
653#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200654#if VWERASE
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000655 CIDX_werase,
656#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200657#if VLNEXT
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000658 CIDX_lnext,
659#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200660#if VFLUSHO
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000661 CIDX_flush,
662#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200663#if VSTATUS
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000664 CIDX_status,
665#endif
666 CIDX_min,
667 CIDX_time,
668};
Eric Andersen98e599c2001-02-14 18:47:33 +0000669
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000670#define CI_ENTRY(n,s,o) n "\0"
671
672/* Name given on command line */
673static const char control_name[] =
674 CI_ENTRY("intr", CINTR, VINTR )
675 CI_ENTRY("quit", CQUIT, VQUIT )
676 CI_ENTRY("erase", CERASE, VERASE )
677 CI_ENTRY("kill", CKILL, VKILL )
678 CI_ENTRY("eof", CEOF, VEOF )
679 CI_ENTRY("eol", CEOL, VEOL )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200680#if VEOL2
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000681 CI_ENTRY("eol2", CEOL2, VEOL2 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000682#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200683#if VSWTCH
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000684 CI_ENTRY("swtch", CSWTCH, VSWTCH )
Eric Andersen98e599c2001-02-14 18:47:33 +0000685#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000686 CI_ENTRY("start", CSTART, VSTART )
687 CI_ENTRY("stop", CSTOP, VSTOP )
688 CI_ENTRY("susp", CSUSP, VSUSP )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200689#if VDSUSP
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000690 CI_ENTRY("dsusp", CDSUSP, VDSUSP )
Eric Andersen98e599c2001-02-14 18:47:33 +0000691#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200692#if VREPRINT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000693 CI_ENTRY("rprnt", CRPRNT, VREPRINT)
Eric Andersen98e599c2001-02-14 18:47:33 +0000694#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200695#if VWERASE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000696 CI_ENTRY("werase", CWERASE, VWERASE )
Eric Andersen98e599c2001-02-14 18:47:33 +0000697#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200698#if VLNEXT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000699 CI_ENTRY("lnext", CLNEXT, VLNEXT )
Eric Andersen98e599c2001-02-14 18:47:33 +0000700#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200701#if VFLUSHO
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000702 CI_ENTRY("flush", CFLUSHO, VFLUSHO )
Eric Andersen98e599c2001-02-14 18:47:33 +0000703#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200704#if VSTATUS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000705 CI_ENTRY("status", CSTATUS, VSTATUS )
Eric Andersen98e599c2001-02-14 18:47:33 +0000706#endif
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000707 /* These must be last because of the display routines */
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000708 CI_ENTRY("min", 1, VMIN )
709 CI_ENTRY("time", 0, VTIME )
710 ;
711
712#undef CI_ENTRY
713#define CI_ENTRY(n,s,o) { s, o },
714
715static const struct control_info control_info[] = {
716 /* This should be verbatim cut-n-paste copy of the above CI_ENTRYs */
717 CI_ENTRY("intr", CINTR, VINTR )
718 CI_ENTRY("quit", CQUIT, VQUIT )
719 CI_ENTRY("erase", CERASE, VERASE )
720 CI_ENTRY("kill", CKILL, VKILL )
721 CI_ENTRY("eof", CEOF, VEOF )
722 CI_ENTRY("eol", CEOL, VEOL )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200723#if VEOL2
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000724 CI_ENTRY("eol2", CEOL2, VEOL2 )
725#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200726#if VSWTCH
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000727 CI_ENTRY("swtch", CSWTCH, VSWTCH )
728#endif
729 CI_ENTRY("start", CSTART, VSTART )
730 CI_ENTRY("stop", CSTOP, VSTOP )
731 CI_ENTRY("susp", CSUSP, VSUSP )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200732#if VDSUSP
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000733 CI_ENTRY("dsusp", CDSUSP, VDSUSP )
734#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200735#if VREPRINT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000736 CI_ENTRY("rprnt", CRPRNT, VREPRINT)
737#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200738#if VWERASE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000739 CI_ENTRY("werase", CWERASE, VWERASE )
740#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200741#if VLNEXT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000742 CI_ENTRY("lnext", CLNEXT, VLNEXT )
743#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200744#if VFLUSHO
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000745 CI_ENTRY("flush", CFLUSHO, VFLUSHO )
746#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200747#if VSTATUS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000748 CI_ENTRY("status", CSTATUS, VSTATUS )
749#endif
750 /* These must be last because of the display routines */
751 CI_ENTRY("min", 1, VMIN )
752 CI_ENTRY("time", 0, VTIME )
Eric Andersen98e599c2001-02-14 18:47:33 +0000753};
754
Rob Landleybc68cd12006-03-10 19:22:06 +0000755enum {
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000756 NUM_control_info = ARRAY_SIZE(control_info)
Rob Landleybc68cd12006-03-10 19:22:06 +0000757};
Eric Andersen98e599c2001-02-14 18:47:33 +0000758
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000759
760struct globals {
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100761 const char *device_name;
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000762 /* The width of the screen, for output wrapping */
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100763 unsigned max_col;
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000764 /* Current position, to know when to wrap */
765 unsigned current_col;
766 char buf[10];
Denys Vlasenko98a4c7c2010-02-04 15:00:15 +0100767} FIX_ALIASING;
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000768#define G (*(struct globals*)&bb_common_bufsiz1)
Denis Vlasenko7049ff82008-06-25 09:53:17 +0000769#define INIT_G() do { \
770 G.device_name = bb_msg_standard_input; \
771 G.max_col = 80; \
772} while (0)
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000773
Eric Andersen8876fb22003-06-20 09:01:58 +0000774
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000775/* Return a string that is the printable representation of character CH */
Denis Vlasenko79deb662006-09-19 15:12:12 +0000776/* Adapted from 'cat' by Torbjorn Granlund */
Denis Vlasenko240a1cf2007-04-08 16:07:02 +0000777static const char *visible(unsigned ch)
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000778{
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000779 char *bpout = G.buf;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000780
781 if (ch == _POSIX_VDISABLE)
782 return "<undef>";
783
784 if (ch >= 128) {
785 ch -= 128;
786 *bpout++ = 'M';
787 *bpout++ = '-';
788 }
789
790 if (ch < 32) {
791 *bpout++ = '^';
792 *bpout++ = ch + 64;
793 } else if (ch < 127) {
794 *bpout++ = ch;
795 } else {
796 *bpout++ = '^';
797 *bpout++ = '?';
798 }
799
800 *bpout = '\0';
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000801 return G.buf;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000802}
803
804static tcflag_t *mode_type_flag(unsigned type, const struct termios *mode)
805{
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000806 static const uint8_t tcflag_offsets[] ALIGN1 = {
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000807 offsetof(struct termios, c_cflag), /* control */
808 offsetof(struct termios, c_iflag), /* input */
809 offsetof(struct termios, c_oflag), /* output */
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000810 offsetof(struct termios, c_lflag) /* local */
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000811 };
812
813 if (type <= local) {
814 return (tcflag_t*) (((char*)mode) + tcflag_offsets[type]);
815 }
816 return NULL;
817}
818
Denis Vlasenkoc7cc5a92009-04-19 01:27:20 +0000819static void set_speed_or_die(enum speed_setting type, const char *arg,
820 struct termios *mode)
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000821{
822 speed_t baud;
823
Bernhard Reutner-Fischer4950f012007-01-17 19:44:59 +0000824 baud = tty_value_to_baud(xatou(arg));
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000825
826 if (type != output_speed) { /* either input or both */
827 cfsetispeed(mode, baud);
828 }
829 if (type != input_speed) { /* either output or both */
830 cfsetospeed(mode, baud);
831 }
832}
833
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000834static NORETURN void perror_on_device_and_die(const char *fmt)
Eric Andersen8876fb22003-06-20 09:01:58 +0000835{
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000836 bb_perror_msg_and_die(fmt, G.device_name);
Eric Andersen8876fb22003-06-20 09:01:58 +0000837}
838
Denis Vlasenko20b253d2006-09-19 14:24:23 +0000839static void perror_on_device(const char *fmt)
840{
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000841 bb_perror_msg(fmt, G.device_name);
Denis Vlasenko20b253d2006-09-19 14:24:23 +0000842}
843
Eric Andersen98e599c2001-02-14 18:47:33 +0000844/* Print format string MESSAGE and optional args.
845 Wrap to next line first if it won't fit.
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000846 Print a space first unless MESSAGE will start a new line */
Eric Andersen98e599c2001-02-14 18:47:33 +0000847static void wrapf(const char *message, ...)
848{
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +0000849 char buf[128];
Eric Andersen98e599c2001-02-14 18:47:33 +0000850 va_list args;
Denis Vlasenko77ad97f2008-05-13 02:27:31 +0000851 unsigned buflen;
Eric Andersen98e599c2001-02-14 18:47:33 +0000852
853 va_start(args, message);
Bernhard Reutner-Fischer8eb05492007-01-17 19:46:33 +0000854 buflen = vsnprintf(buf, sizeof(buf), message, args);
Eric Andersen98e599c2001-02-14 18:47:33 +0000855 va_end(args);
Bernhard Reutner-Fischer1a250d92007-01-18 08:41:22 +0000856 /* We seem to be called only with suitable lengths, but check if
857 somebody failed to adhere to this assumption just to be sure. */
858 if (!buflen || buflen >= sizeof(buf)) return;
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +0000859
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000860 if (G.current_col > 0) {
861 G.current_col++;
Denis Vlasenko79deb662006-09-19 15:12:12 +0000862 if (buf[0] != '\n') {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000863 if (G.current_col + buflen >= G.max_col) {
Denis Vlasenko4daad902007-09-27 10:20:47 +0000864 bb_putchar('\n');
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000865 G.current_col = 0;
Denis Vlasenko79deb662006-09-19 15:12:12 +0000866 } else
Denis Vlasenko4daad902007-09-27 10:20:47 +0000867 bb_putchar(' ');
Denis Vlasenko79deb662006-09-19 15:12:12 +0000868 }
Eric Andersen98e599c2001-02-14 18:47:33 +0000869 }
870 fputs(buf, stdout);
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000871 G.current_col += buflen;
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +0000872 if (buf[buflen-1] == '\n')
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000873 G.current_col = 0;
Eric Andersen98e599c2001-02-14 18:47:33 +0000874}
875
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100876static void newline(void)
877{
878 if (G.current_col != 0)
879 wrapf("\n");
880}
881
Jeremie Koenig138ce542010-07-30 06:01:37 +0200882#ifdef TIOCGWINSZ
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100883static void set_window_size(int rows, int cols)
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000884{
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000885 struct winsize win = { 0, 0, 0, 0 };
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000886
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000887 if (ioctl(STDIN_FILENO, TIOCGWINSZ, &win)) {
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000888 if (errno != EINVAL) {
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000889 goto bail;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000890 }
891 memset(&win, 0, sizeof(win));
892 }
893
894 if (rows >= 0)
895 win.ws_row = rows;
896 if (cols >= 0)
897 win.ws_col = cols;
898
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000899 if (ioctl(STDIN_FILENO, TIOCSWINSZ, (char *) &win))
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000900bail:
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000901 perror_on_device("%s");
902}
Jeremie Koenig138ce542010-07-30 06:01:37 +0200903#endif
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000904
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100905static void display_window_size(int fancy)
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000906{
907 const char *fmt_str = "%s\0%s: no size information for this device";
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000908 unsigned width, height;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000909
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000910 if (get_terminal_width_height(STDIN_FILENO, &width, &height)) {
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000911 if ((errno != EINVAL) || ((fmt_str += 2), !fancy)) {
912 perror_on_device(fmt_str);
913 }
914 } else {
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100915 wrapf(fancy ? "rows %u; columns %u;" : "%u %u\n",
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000916 height, width);
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000917 }
918}
919
Eric Andersen98e599c2001-02-14 18:47:33 +0000920static const struct suffix_mult stty_suffixes[] = {
Denis Vlasenkof8689632007-07-27 15:06:25 +0000921 { "b", 512 },
922 { "k", 1024 },
923 { "B", 1024 },
Denys Vlasenko043b1e52009-09-06 12:47:55 +0200924 { "", 0 }
Eric Andersen98e599c2001-02-14 18:47:33 +0000925};
926
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000927static const struct mode_info *find_mode(const char *name)
928{
Denis Vlasenkoda42bd52008-01-27 23:24:31 +0000929 int i = index_in_strings(mode_name, name);
930 return i >= 0 ? &mode_info[i] : NULL;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000931}
932
933static const struct control_info *find_control(const char *name)
934{
Denis Vlasenkoda42bd52008-01-27 23:24:31 +0000935 int i = index_in_strings(control_name, name);
936 return i >= 0 ? &control_info[i] : NULL;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000937}
938
939enum {
940 param_need_arg = 0x80,
Denis Vlasenko9ace6132007-04-19 19:55:54 +0000941 param_line = 1 | 0x80,
942 param_rows = 2 | 0x80,
943 param_cols = 3 | 0x80,
944 param_columns = 4 | 0x80,
945 param_size = 5,
946 param_speed = 6,
947 param_ispeed = 7 | 0x80,
948 param_ospeed = 8 | 0x80,
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000949};
950
Denis Vlasenkoc7cc5a92009-04-19 01:27:20 +0000951static int find_param(const char *name)
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000952{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000953 static const char params[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000954 "line\0" /* 1 */
955 "rows\0" /* 2 */
956 "cols\0" /* 3 */
957 "columns\0" /* 4 */
958 "size\0" /* 5 */
959 "speed\0" /* 6 */
960 "ispeed\0"
961 "ospeed\0";
962 int i = index_in_strings(params, name) + 1;
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000963 if (i == 0)
Bernhard Reutner-Fischercbd6e652007-02-04 11:13:57 +0000964 return 0;
Denis Vlasenko9ace6132007-04-19 19:55:54 +0000965 if (i != 5 && i != 6)
Bernhard Reutner-Fischercbd6e652007-02-04 11:13:57 +0000966 i |= 0x80;
Bernhard Reutner-Fischera6e31ad2007-01-17 19:45:14 +0000967 return i;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000968}
969
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000970static int recover_mode(const char *arg, struct termios *mode)
971{
972 int i, n;
Denis Vlasenko240a1cf2007-04-08 16:07:02 +0000973 unsigned chr;
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000974 unsigned long iflag, oflag, cflag, lflag;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000975
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000976 /* Scan into temporaries since it is too much trouble to figure out
977 the right format for 'tcflag_t' */
978 if (sscanf(arg, "%lx:%lx:%lx:%lx%n",
979 &iflag, &oflag, &cflag, &lflag, &n) != 4)
980 return 0;
981 mode->c_iflag = iflag;
982 mode->c_oflag = oflag;
983 mode->c_cflag = cflag;
984 mode->c_lflag = lflag;
985 arg += n;
986 for (i = 0; i < NCCS; ++i) {
987 if (sscanf(arg, ":%x%n", &chr, &n) != 1)
988 return 0;
989 mode->c_cc[i] = chr;
990 arg += n;
991 }
992
993 /* Fail if there are too many fields */
994 if (*arg != '\0')
995 return 0;
996
997 return 1;
998}
999
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001000static void display_recoverable(const struct termios *mode,
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +00001001 int UNUSED_PARAM dummy)
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001002{
1003 int i;
1004 printf("%lx:%lx:%lx:%lx",
1005 (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
1006 (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
1007 for (i = 0; i < NCCS; ++i)
1008 printf(":%x", (unsigned int) mode->c_cc[i]);
Denis Vlasenko4daad902007-09-27 10:20:47 +00001009 bb_putchar('\n');
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001010}
1011
1012static void display_speed(const struct termios *mode, int fancy)
1013{
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001014 //____________________ 01234567 8 9
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001015 const char *fmt_str = "%lu %lu\n\0ispeed %lu baud; ospeed %lu baud;";
1016 unsigned long ispeed, ospeed;
1017
Denys Vlasenkoe54cfc52011-01-24 18:30:35 +01001018 ispeed = cfgetispeed(mode);
1019 ospeed = cfgetospeed(mode);
1020 if (ispeed == 0 || ispeed == ospeed) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001021 ispeed = ospeed; /* in case ispeed was 0 */
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001022 //________ 0123 4 5 6 7 8 9
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001023 fmt_str = "%lu\n\0\0\0\0\0speed %lu baud;";
1024 }
1025 if (fancy) fmt_str += 9;
1026 wrapf(fmt_str, tty_baud_to_value(ispeed), tty_baud_to_value(ospeed));
1027}
1028
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001029static void do_display(const struct termios *mode, int all)
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001030{
1031 int i;
1032 tcflag_t *bitsp;
1033 unsigned long mask;
1034 int prev_type = control;
1035
1036 display_speed(mode, 1);
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001037 if (all)
1038 display_window_size(1);
Denys Vlasenkoe54cfc52011-01-24 18:30:35 +01001039#ifdef __linux__
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001040 wrapf("line = %u;\n", mode->c_line);
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001041#else
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001042 newline();
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001043#endif
1044
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001045 for (i = 0; i != CIDX_min; ++i) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001046 /* If swtch is the same as susp, don't print both */
1047#if VSWTCH == VSUSP
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001048 if (i == CIDX_swtch)
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001049 continue;
1050#endif
1051 /* If eof uses the same slot as min, only print whichever applies */
1052#if VEOF == VMIN
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001053 if (!(mode->c_lflag & ICANON)
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001054 && (i == CIDX_eof || i == CIDX_eol)
1055 ) {
1056 continue;
1057 }
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001058#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001059 wrapf("%s = %s;", nth_string(control_name, i),
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001060 visible(mode->c_cc[control_info[i].offset]));
1061 }
1062#if VEOF == VMIN
1063 if ((mode->c_lflag & ICANON) == 0)
1064#endif
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001065 wrapf("min = %u; time = %u;", mode->c_cc[VMIN], mode->c_cc[VTIME]);
1066 newline();
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001067
1068 for (i = 0; i < NUM_mode_info; ++i) {
1069 if (mode_info[i].flags & OMIT)
1070 continue;
1071 if (mode_info[i].type != prev_type) {
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001072 newline();
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001073 prev_type = mode_info[i].type;
1074 }
1075
1076 bitsp = mode_type_flag(mode_info[i].type, mode);
1077 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001078 if ((*bitsp & mask) == mode_info[i].bits) {
1079 if (all || (mode_info[i].flags & SANE_UNSET))
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001080 wrapf("-%s"+1, nth_string(mode_name, i));
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001081 } else {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001082 if ((all && mode_info[i].flags & REV)
1083 || (!all && (mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV))
1084 ) {
1085 wrapf("-%s", nth_string(mode_name, i));
1086 }
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001087 }
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001088 }
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001089 newline();
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001090}
1091
1092static void sane_mode(struct termios *mode)
1093{
1094 int i;
1095 tcflag_t *bitsp;
1096
1097 for (i = 0; i < NUM_control_info; ++i) {
1098#if VMIN == VEOF
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001099 if (i == CIDX_min)
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001100 break;
1101#endif
1102 mode->c_cc[control_info[i].offset] = control_info[i].saneval;
1103 }
1104
1105 for (i = 0; i < NUM_mode_info; ++i) {
1106 if (mode_info[i].flags & SANE_SET) {
1107 bitsp = mode_type_flag(mode_info[i].type, mode);
1108 *bitsp = (*bitsp & ~((unsigned long)mode_info[i].mask))
1109 | mode_info[i].bits;
1110 } else if (mode_info[i].flags & SANE_UNSET) {
1111 bitsp = mode_type_flag(mode_info[i].type, mode);
1112 *bitsp = *bitsp & ~((unsigned long)mode_info[i].mask)
1113 & ~mode_info[i].bits;
1114 }
1115 }
1116}
1117
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001118static void set_mode(const struct mode_info *info, int reversed,
1119 struct termios *mode)
1120{
1121 tcflag_t *bitsp;
1122
1123 bitsp = mode_type_flag(info->type, mode);
1124
1125 if (bitsp) {
1126 if (reversed)
1127 *bitsp = *bitsp & ~info->mask & ~info->bits;
1128 else
1129 *bitsp = (*bitsp & ~info->mask) | info->bits;
1130 return;
1131 }
1132
1133 /* Combination mode */
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001134 if (info == &mode_info[IDX_evenp] || info == &mode_info[IDX_parity]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001135 if (reversed)
1136 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1137 else
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02001138 mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001139 } else if (info == &mode_info[IDX_oddp]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001140 if (reversed)
1141 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1142 else
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02001143 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001144 } else if (info == &mode_info[IDX_nl]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001145 if (reversed) {
1146 mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02001147 mode->c_oflag = (mode->c_oflag | ONLCR) & ~OCRNL & ~ONLRET;
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001148 } else {
1149 mode->c_iflag = mode->c_iflag & ~ICRNL;
1150 if (ONLCR) mode->c_oflag = mode->c_oflag & ~ONLCR;
1151 }
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001152 } else if (info == &mode_info[IDX_ek]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001153 mode->c_cc[VERASE] = CERASE;
1154 mode->c_cc[VKILL] = CKILL;
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001155 } else if (info == &mode_info[IDX_sane]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001156 sane_mode(mode);
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001157 } else if (info == &mode_info[IDX_cbreak]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001158 if (reversed)
1159 mode->c_lflag |= ICANON;
1160 else
1161 mode->c_lflag &= ~ICANON;
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001162 } else if (info == &mode_info[IDX_pass8]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001163 if (reversed) {
1164 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1165 mode->c_iflag |= ISTRIP;
1166 } else {
1167 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1168 mode->c_iflag &= ~ISTRIP;
1169 }
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001170 } else if (info == &mode_info[IDX_litout]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001171 if (reversed) {
1172 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1173 mode->c_iflag |= ISTRIP;
1174 mode->c_oflag |= OPOST;
1175 } else {
1176 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1177 mode->c_iflag &= ~ISTRIP;
1178 mode->c_oflag &= ~OPOST;
1179 }
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001180 } else if (info == &mode_info[IDX_raw] || info == &mode_info[IDX_cooked]) {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001181 if ((info == &mode_info[IDX_raw] && reversed)
1182 || (info == &mode_info[IDX_cooked] && !reversed)
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001183 ) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001184 /* Cooked mode */
1185 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
1186 mode->c_oflag |= OPOST;
1187 mode->c_lflag |= ISIG | ICANON;
1188#if VMIN == VEOF
1189 mode->c_cc[VEOF] = CEOF;
1190#endif
1191#if VTIME == VEOL
1192 mode->c_cc[VEOL] = CEOL;
1193#endif
1194 } else {
1195 /* Raw mode */
1196 mode->c_iflag = 0;
1197 mode->c_oflag &= ~OPOST;
1198 mode->c_lflag &= ~(ISIG | ICANON | XCASE);
1199 mode->c_cc[VMIN] = 1;
1200 mode->c_cc[VTIME] = 0;
1201 }
1202 }
Jeremie Koenig138ce542010-07-30 06:01:37 +02001203#if IXANY
1204 else if (info == &mode_info[IDX_decctlq]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001205 if (reversed)
1206 mode->c_iflag |= IXANY;
1207 else
1208 mode->c_iflag &= ~IXANY;
1209 }
Jeremie Koenig138ce542010-07-30 06:01:37 +02001210#endif
1211#if TABDLY
1212 else if (info == &mode_info[IDX_tabs]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001213 if (reversed)
1214 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
1215 else
1216 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
1217 }
Jeremie Koenig138ce542010-07-30 06:01:37 +02001218#endif
1219#if OXTABS
1220 else if (info == &mode_info[IDX_tabs]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001221 if (reversed)
1222 mode->c_oflag |= OXTABS;
1223 else
1224 mode->c_oflag &= ~OXTABS;
Jeremie Koenig138ce542010-07-30 06:01:37 +02001225 }
1226#endif
1227#if XCASE && IUCLC && OLCUC
1228 else if (info==&mode_info[IDX_lcase] || info==&mode_info[IDX_LCASE]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001229 if (reversed) {
1230 mode->c_lflag &= ~XCASE;
1231 mode->c_iflag &= ~IUCLC;
1232 mode->c_oflag &= ~OLCUC;
1233 } else {
1234 mode->c_lflag |= XCASE;
1235 mode->c_iflag |= IUCLC;
1236 mode->c_oflag |= OLCUC;
1237 }
Jeremie Koenig138ce542010-07-30 06:01:37 +02001238 }
1239#endif
1240 else if (info == &mode_info[IDX_crt]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001241 mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001242 } else if (info == &mode_info[IDX_dec]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001243 mode->c_cc[VINTR] = 3; /* ^C */
1244 mode->c_cc[VERASE] = 127; /* DEL */
1245 mode->c_cc[VKILL] = 21; /* ^U */
1246 mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
1247 if (IXANY) mode->c_iflag &= ~IXANY;
1248 }
1249}
1250
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001251static void set_control_char_or_die(const struct control_info *info,
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001252 const char *arg, struct termios *mode)
1253{
1254 unsigned char value;
1255
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001256 if (info == &control_info[CIDX_min] || info == &control_info[CIDX_time])
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001257 value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
1258 else if (arg[0] == '\0' || arg[1] == '\0')
1259 value = arg[0];
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001260 else if (strcmp(arg, "^-") == 0 || strcmp(arg, "undef") == 0)
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001261 value = _POSIX_VDISABLE;
1262 else if (arg[0] == '^') { /* Ignore any trailing junk (^Cjunk) */
1263 value = arg[1] & 0x1f; /* Non-letters get weird results */
1264 if (arg[1] == '?')
1265 value = 127;
1266 } else
1267 value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
1268 mode->c_cc[info->offset] = value;
1269}
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001270
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001271#define STTY_require_set_attr (1 << 0)
1272#define STTY_speed_was_set (1 << 1)
1273#define STTY_verbose_output (1 << 2)
1274#define STTY_recoverable_output (1 << 3)
1275#define STTY_noargs (1 << 4)
1276
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00001277int stty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denys Vlasenkoe992bae2009-11-28 15:18:53 +01001278int stty_main(int argc UNUSED_PARAM, char **argv)
Eric Andersen98e599c2001-02-14 18:47:33 +00001279{
1280 struct termios mode;
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001281 void (*output_func)(const struct termios *, int);
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001282 const char *file_name = NULL;
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001283 int display_all = 0;
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001284 int stty_state;
1285 int k;
1286
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001287 INIT_G();
1288
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001289 stty_state = STTY_noargs;
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001290 output_func = do_display;
Eric Andersen98e599c2001-02-14 18:47:33 +00001291
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001292 /* First pass: only parse/verify command line params */
1293 k = 0;
1294 while (argv[++k]) {
1295 const struct mode_info *mp;
1296 const struct control_info *cp;
1297 const char *arg = argv[k];
1298 const char *argnext = argv[k+1];
1299 int param;
Eric Andersen98e599c2001-02-14 18:47:33 +00001300
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001301 if (arg[0] == '-') {
1302 int i;
1303 mp = find_mode(arg+1);
1304 if (mp) {
1305 if (!(mp->flags & REV))
Bernhard Reutner-Fischer4fa566d2007-01-17 19:42:30 +00001306 goto invalid_argument;
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001307 stty_state &= ~STTY_noargs;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001308 continue;
1309 }
1310 /* It is an option - parse it */
1311 i = 0;
1312 while (arg[++i]) {
1313 switch (arg[i]) {
1314 case 'a':
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001315 stty_state |= STTY_verbose_output;
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001316 output_func = do_display;
1317 display_all = 1;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001318 break;
1319 case 'g':
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001320 stty_state |= STTY_recoverable_output;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001321 output_func = display_recoverable;
1322 break;
1323 case 'F':
1324 if (file_name)
1325 bb_error_msg_and_die("only one device may be specified");
1326 file_name = &arg[i+1]; /* "-Fdevice" ? */
1327 if (!file_name[0]) { /* nope, "-F device" */
1328 int p = k+1; /* argv[p] is argnext */
1329 file_name = argnext;
1330 if (!file_name)
1331 bb_error_msg_and_die(bb_msg_requires_arg, "-F");
1332 /* remove -F param from arg[vc] */
Denys Vlasenkoe992bae2009-11-28 15:18:53 +01001333 while (argv[p]) {
1334 argv[p] = argv[p+1];
1335 ++p;
1336 }
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001337 }
1338 goto end_option;
1339 default:
Bernhard Reutner-Fischer4fa566d2007-01-17 19:42:30 +00001340 goto invalid_argument;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001341 }
1342 }
Denis Vlasenko240a1cf2007-04-08 16:07:02 +00001343 end_option:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001344 continue;
Eric Andersen98e599c2001-02-14 18:47:33 +00001345 }
1346
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001347 mp = find_mode(arg);
1348 if (mp) {
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001349 stty_state &= ~STTY_noargs;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001350 continue;
1351 }
1352
1353 cp = find_control(arg);
1354 if (cp) {
1355 if (!argnext)
1356 bb_error_msg_and_die(bb_msg_requires_arg, arg);
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001357 /* called for the side effect of xfunc death only */
1358 set_control_char_or_die(cp, argnext, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001359 stty_state &= ~STTY_noargs;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001360 ++k;
1361 continue;
1362 }
1363
1364 param = find_param(arg);
1365 if (param & param_need_arg) {
1366 if (!argnext)
1367 bb_error_msg_and_die(bb_msg_requires_arg, arg);
1368 ++k;
1369 }
1370
1371 switch (param) {
Denys Vlasenkoe54cfc52011-01-24 18:30:35 +01001372#ifdef __linux__
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001373 case param_line:
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +00001374# ifndef TIOCGWINSZ
Denis Vlasenko13858992006-10-08 12:49:22 +00001375 xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
Eric Andersen98e599c2001-02-14 18:47:33 +00001376 break;
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +00001377# endif /* else fall-through */
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001378#endif
1379#ifdef TIOCGWINSZ
1380 case param_rows:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001381 case param_cols:
Denis Vlasenko9ace6132007-04-19 19:55:54 +00001382 case param_columns:
Denis Vlasenko13858992006-10-08 12:49:22 +00001383 xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001384 break;
1385 case param_size:
1386#endif
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001387 case param_speed:
1388 break;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001389 case param_ispeed:
1390 /* called for the side effect of xfunc death only */
1391 set_speed_or_die(input_speed, argnext, &mode);
1392 break;
1393 case param_ospeed:
1394 /* called for the side effect of xfunc death only */
1395 set_speed_or_die(output_speed, argnext, &mode);
1396 break;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001397 default:
1398 if (recover_mode(arg, &mode) == 1) break;
Bernhard Reutner-Fischer4950f012007-01-17 19:44:59 +00001399 if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) break;
Denis Vlasenko240a1cf2007-04-08 16:07:02 +00001400 invalid_argument:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001401 bb_error_msg_and_die("invalid argument '%s'", arg);
1402 }
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001403 stty_state &= ~STTY_noargs;
Eric Andersen98e599c2001-02-14 18:47:33 +00001404 }
1405
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001406 /* Specifying both -a and -g is an error */
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001407 if ((stty_state & (STTY_verbose_output | STTY_recoverable_output)) ==
Bernhard Reutner-Fischer4fa566d2007-01-17 19:42:30 +00001408 (STTY_verbose_output | STTY_recoverable_output))
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001409 bb_error_msg_and_die("verbose and stty-readable output styles are mutually exclusive");
1410 /* Specifying -a or -g with non-options is an error */
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001411 if (!(stty_state & STTY_noargs)
1412 && (stty_state & (STTY_verbose_output | STTY_recoverable_output))
1413 ) {
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001414 bb_error_msg_and_die("modes may not be set when specifying an output style");
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001415 }
Eric Andersen98e599c2001-02-14 18:47:33 +00001416
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001417 /* Now it is safe to start doing things */
Eric Andersen98e599c2001-02-14 18:47:33 +00001418 if (file_name) {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001419 G.device_name = file_name;
Denys Vlasenkoab19ede2009-11-11 21:05:42 +01001420 xmove_fd(xopen_nonblocking(G.device_name), STDIN_FILENO);
1421 ndelay_off(STDIN_FILENO);
Eric Andersen98e599c2001-02-14 18:47:33 +00001422 }
1423
1424 /* Initialize to all zeroes so there is no risk memcmp will report a
Denis Vlasenko9efb0702006-09-19 14:17:10 +00001425 spurious difference in an uninitialized portion of the structure */
Eric Andersen98e599c2001-02-14 18:47:33 +00001426 memset(&mode, 0, sizeof(mode));
"Vladimir N. Oleynik"9b9a9202006-01-30 12:23:46 +00001427 if (tcgetattr(STDIN_FILENO, &mode))
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001428 perror_on_device_and_die("%s");
Eric Andersen98e599c2001-02-14 18:47:33 +00001429
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001430 if (stty_state & (STTY_verbose_output | STTY_recoverable_output | STTY_noargs)) {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001431 get_terminal_width_height(STDOUT_FILENO, &G.max_col, NULL);
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001432 output_func(&mode, display_all);
Eric Andersen98e599c2001-02-14 18:47:33 +00001433 return EXIT_SUCCESS;
1434 }
1435
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001436 /* Second pass: perform actions */
Eric Andersenfc059092002-06-06 11:35:29 +00001437 k = 0;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001438 while (argv[++k]) {
1439 const struct mode_info *mp;
1440 const struct control_info *cp;
1441 const char *arg = argv[k];
1442 const char *argnext = argv[k+1];
1443 int param;
Eric Andersen98e599c2001-02-14 18:47:33 +00001444
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001445 if (arg[0] == '-') {
1446 mp = find_mode(arg+1);
1447 if (mp) {
1448 set_mode(mp, 1 /* reversed */, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001449 stty_state |= STTY_require_set_attr;
Eric Andersenfc059092002-06-06 11:35:29 +00001450 }
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001451 /* It is an option - already parsed. Skip it */
1452 continue;
Eric Andersen98e599c2001-02-14 18:47:33 +00001453 }
Mark Whitley446dd272001-03-02 20:00:54 +00001454
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001455 mp = find_mode(arg);
1456 if (mp) {
1457 set_mode(mp, 0 /* non-reversed */, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001458 stty_state |= STTY_require_set_attr;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001459 continue;
1460 }
Mark Whitley446dd272001-03-02 20:00:54 +00001461
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001462 cp = find_control(arg);
1463 if (cp) {
1464 ++k;
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001465 set_control_char_or_die(cp, argnext, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001466 stty_state |= STTY_require_set_attr;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001467 continue;
1468 }
Mark Whitley446dd272001-03-02 20:00:54 +00001469
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001470 param = find_param(arg);
1471 if (param & param_need_arg) {
1472 ++k;
1473 }
1474
1475 switch (param) {
Denys Vlasenkoe54cfc52011-01-24 18:30:35 +01001476#ifdef __linux__
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001477 case param_line:
Denis Vlasenko13858992006-10-08 12:49:22 +00001478 mode.c_line = xatoul_sfx(argnext, stty_suffixes);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001479 stty_state |= STTY_require_set_attr;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001480 break;
Eric Andersen98e599c2001-02-14 18:47:33 +00001481#endif
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001482#ifdef TIOCGWINSZ
1483 case param_cols:
Denys Vlasenko9f5a5772009-12-11 14:17:02 +01001484 case param_columns:
Denis Vlasenko13858992006-10-08 12:49:22 +00001485 set_window_size(-1, xatoul_sfx(argnext, stty_suffixes));
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001486 break;
1487 case param_size:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001488 display_window_size(0);
1489 break;
1490 case param_rows:
Denis Vlasenko13858992006-10-08 12:49:22 +00001491 set_window_size(xatoul_sfx(argnext, stty_suffixes), -1);
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001492 break;
1493#endif
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001494 case param_speed:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001495 display_speed(&mode, 0);
1496 break;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001497 case param_ispeed:
1498 set_speed_or_die(input_speed, argnext, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001499 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001500 break;
1501 case param_ospeed:
1502 set_speed_or_die(output_speed, argnext, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001503 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001504 break;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001505 default:
1506 if (recover_mode(arg, &mode) == 1)
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001507 stty_state |= STTY_require_set_attr;
Bernhard Reutner-Fischer4950f012007-01-17 19:44:59 +00001508 else /* true: if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) */{
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001509 set_speed_or_die(both_speeds, arg, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001510 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001511 } /* else - impossible (caught in the first pass):
1512 bb_error_msg_and_die("invalid argument '%s'", arg); */
Eric Andersen98e599c2001-02-14 18:47:33 +00001513 }
Eric Andersen98e599c2001-02-14 18:47:33 +00001514 }
1515
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001516 if (stty_state & STTY_require_set_attr) {
Eric Andersen98e599c2001-02-14 18:47:33 +00001517 struct termios new_mode;
1518
"Vladimir N. Oleynik"9b9a9202006-01-30 12:23:46 +00001519 if (tcsetattr(STDIN_FILENO, TCSADRAIN, &mode))
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001520 perror_on_device_and_die("%s");
Eric Andersen98e599c2001-02-14 18:47:33 +00001521
1522 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
1523 it performs *any* of the requested operations. This means it
Denis Vlasenko79deb662006-09-19 15:12:12 +00001524 can report 'success' when it has actually failed to perform
Eric Andersen98e599c2001-02-14 18:47:33 +00001525 some proper subset of the requested operations. To detect
1526 this partial failure, get the current terminal attributes and
Denis Vlasenko9efb0702006-09-19 14:17:10 +00001527 compare them to the requested ones */
Eric Andersen98e599c2001-02-14 18:47:33 +00001528
1529 /* Initialize to all zeroes so there is no risk memcmp will report a
Denis Vlasenko9efb0702006-09-19 14:17:10 +00001530 spurious difference in an uninitialized portion of the structure */
Eric Andersen98e599c2001-02-14 18:47:33 +00001531 memset(&new_mode, 0, sizeof(new_mode));
"Vladimir N. Oleynik"9b9a9202006-01-30 12:23:46 +00001532 if (tcgetattr(STDIN_FILENO, &new_mode))
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001533 perror_on_device_and_die("%s");
Eric Andersen98e599c2001-02-14 18:47:33 +00001534
Eric Andersen98e599c2001-02-14 18:47:33 +00001535 if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) {
Jeremie Koenig138ce542010-07-30 06:01:37 +02001536#if CIBAUD
Eric Andersen98e599c2001-02-14 18:47:33 +00001537 /* SunOS 4.1.3 (at least) has the problem that after this sequence,
1538 tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
1539 sometimes (m1 != m2). The only difference is in the four bits
1540 of the c_cflag field corresponding to the baud rate. To save
1541 Sun users a little confusion, don't report an error if this
1542 happens. But suppress the error only if we haven't tried to
1543 set the baud rate explicitly -- otherwise we'd never give an
Denis Vlasenko9efb0702006-09-19 14:17:10 +00001544 error for a true failure to set the baud rate */
Eric Andersen98e599c2001-02-14 18:47:33 +00001545
1546 new_mode.c_cflag &= (~CIBAUD);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001547 if ((stty_state & STTY_speed_was_set)
1548 || memcmp(&mode, &new_mode, sizeof(mode)) != 0)
Eric Andersen98e599c2001-02-14 18:47:33 +00001549#endif
Denis Vlasenko89f0b342006-11-18 22:04:09 +00001550 perror_on_device_and_die("%s: cannot perform all requested operations");
Eric Andersen98e599c2001-02-14 18:47:33 +00001551 }
1552 }
1553
1554 return EXIT_SUCCESS;
1555}