Magellan Linux

Annotation of /trunk/mkinitrd-magellan/busybox/coreutils/stty.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 816 - (hide annotations) (download)
Fri Apr 24 18:33:46 2009 UTC (15 years, 1 month ago) by niro
File MIME type: text/plain
File size: 42626 byte(s)
-updated to busybox-1.13.4
1 niro 532 /* vi: set sw=4 ts=4: */
2     /* stty -- change and print terminal line settings
3     Copyright (C) 1990-1999 Free Software Foundation, Inc.
4    
5     Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
6     */
7     /* 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    
20     Special for busybox ported by Vladimir Oleynik <dzo@simtreas.ru> 2001
21    
22     */
23    
24 niro 816 #include "libbb.h"
25 niro 532
26     #ifndef _POSIX_VDISABLE
27     # define _POSIX_VDISABLE ((unsigned char) 0)
28     #endif
29    
30     #define Control(c) ((c) & 0x1f)
31     /* Canonical values for control characters */
32     #ifndef CINTR
33     # define CINTR Control('c')
34     #endif
35     #ifndef CQUIT
36     # define CQUIT 28
37     #endif
38     #ifndef CERASE
39     # define CERASE 127
40     #endif
41     #ifndef CKILL
42     # define CKILL Control('u')
43     #endif
44     #ifndef CEOF
45     # define CEOF Control('d')
46     #endif
47     #ifndef CEOL
48     # define CEOL _POSIX_VDISABLE
49     #endif
50     #ifndef CSTART
51     # define CSTART Control('q')
52     #endif
53     #ifndef CSTOP
54     # define CSTOP Control('s')
55     #endif
56     #ifndef CSUSP
57     # define CSUSP Control('z')
58     #endif
59     #if defined(VEOL2) && !defined(CEOL2)
60     # define CEOL2 _POSIX_VDISABLE
61     #endif
62     /* ISC renamed swtch to susp for termios, but we'll accept either name */
63     #if defined(VSUSP) && !defined(VSWTCH)
64     # define VSWTCH VSUSP
65     # define CSWTCH CSUSP
66     #endif
67     #if defined(VSWTCH) && !defined(CSWTCH)
68     # define CSWTCH _POSIX_VDISABLE
69     #endif
70    
71     /* SunOS 5.3 loses (^Z doesn't work) if 'swtch' is the same as 'susp'.
72     So the default is to disable 'swtch.' */
73 niro 816 #if defined(__sparc__) && defined(__svr4__)
74 niro 532 # undef CSWTCH
75     # define CSWTCH _POSIX_VDISABLE
76     #endif
77    
78 niro 816 #if defined(VWERSE) && !defined(VWERASE) /* AIX-3.2.5 */
79 niro 532 # define VWERASE VWERSE
80     #endif
81 niro 816 #if defined(VDSUSP) && !defined(CDSUSP)
82 niro 532 # define CDSUSP Control('y')
83     #endif
84     #if !defined(VREPRINT) && defined(VRPRNT) /* Irix 4.0.5 */
85     # define VREPRINT VRPRNT
86     #endif
87     #if defined(VREPRINT) && !defined(CRPRNT)
88     # define CRPRNT Control('r')
89     #endif
90     #if defined(VWERASE) && !defined(CWERASE)
91     # define CWERASE Control('w')
92     #endif
93     #if defined(VLNEXT) && !defined(CLNEXT)
94     # define CLNEXT Control('v')
95     #endif
96     #if defined(VDISCARD) && !defined(VFLUSHO)
97     # define VFLUSHO VDISCARD
98     #endif
99     #if defined(VFLUSH) && !defined(VFLUSHO) /* Ultrix 4.2 */
100     # define VFLUSHO VFLUSH
101     #endif
102     #if defined(CTLECH) && !defined(ECHOCTL) /* Ultrix 4.3 */
103     # define ECHOCTL CTLECH
104     #endif
105     #if defined(TCTLECH) && !defined(ECHOCTL) /* Ultrix 4.2 */
106     # define ECHOCTL TCTLECH
107     #endif
108     #if defined(CRTKIL) && !defined(ECHOKE) /* Ultrix 4.2 and 4.3 */
109     # define ECHOKE CRTKIL
110     #endif
111     #if defined(VFLUSHO) && !defined(CFLUSHO)
112     # define CFLUSHO Control('o')
113     #endif
114     #if defined(VSTATUS) && !defined(CSTATUS)
115     # define CSTATUS Control('t')
116     #endif
117    
118     /* Which speeds to set */
119     enum speed_setting {
120     input_speed, output_speed, both_speeds
121     };
122    
123     /* Which member(s) of 'struct termios' a mode uses */
124     enum {
125     /* Do NOT change the order or values, as mode_type_flag()
126     * depends on them */
127     control, input, output, local, combination
128     };
129    
130     /* Flags for 'struct mode_info' */
131     #define SANE_SET 1 /* Set in 'sane' mode */
132     #define SANE_UNSET 2 /* Unset in 'sane' mode */
133     #define REV 4 /* Can be turned off by prepending '-' */
134     #define OMIT 8 /* Don't display value */
135    
136 niro 816
137     /* Each mode.
138     * This structure should be kept as small as humanly possible.
139     */
140 niro 532 struct mode_info {
141 niro 816 const uint8_t type; /* Which structure element to change */
142     const uint8_t flags; /* Setting and display options */
143     /* only these values are ever used, so... */
144     #if (CSIZE | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY) < 0x100
145     const uint8_t mask;
146     #elif (CSIZE | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY) < 0x10000
147     const uint16_t mask;
148     #else
149 niro 532 const tcflag_t mask; /* Other bits to turn off for this mode */
150 niro 816 #endif
151     /* was using short here, but ppc32 was unhappy */
152 niro 532 const tcflag_t bits; /* Bits to set for this mode */
153     };
154    
155 niro 816 enum {
156     /* Must match mode_name[] and mode_info[] order! */
157     IDX_evenp = 0,
158     IDX_parity,
159     IDX_oddp,
160     IDX_nl,
161     IDX_ek,
162     IDX_sane,
163     IDX_cooked,
164     IDX_raw,
165     IDX_pass8,
166     IDX_litout,
167     IDX_cbreak,
168     IDX_crt,
169     IDX_dec,
170     #ifdef IXANY
171     IDX_decctlq,
172     #endif
173     #if defined(TABDLY) || defined(OXTABS)
174     IDX_tabs,
175     #endif
176     #if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
177     IDX_lcase,
178     IDX_LCASE,
179     #endif
180     };
181 niro 532
182 niro 816 #define MI_ENTRY(N,T,F,B,M) N "\0"
183 niro 532
184 niro 816 /* Mode names given on command line */
185     static const char mode_name[] =
186     MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 )
187     MI_ENTRY("parity", combination, REV | OMIT, 0, 0 )
188     MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 )
189     MI_ENTRY("nl", combination, REV | OMIT, 0, 0 )
190     MI_ENTRY("ek", combination, OMIT, 0, 0 )
191     MI_ENTRY("sane", combination, OMIT, 0, 0 )
192     MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 )
193     MI_ENTRY("raw", combination, REV | OMIT, 0, 0 )
194     MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 )
195     MI_ENTRY("litout", combination, REV | OMIT, 0, 0 )
196     MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 )
197     MI_ENTRY("crt", combination, OMIT, 0, 0 )
198     MI_ENTRY("dec", combination, OMIT, 0, 0 )
199     #ifdef IXANY
200     MI_ENTRY("decctlq", combination, REV | OMIT, 0, 0 )
201     #endif
202     #if defined(TABDLY) || defined(OXTABS)
203     MI_ENTRY("tabs", combination, REV | OMIT, 0, 0 )
204     #endif
205     #if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
206     MI_ENTRY("lcase", combination, REV | OMIT, 0, 0 )
207     MI_ENTRY("LCASE", combination, REV | OMIT, 0, 0 )
208     #endif
209     MI_ENTRY("parenb", control, REV, PARENB, 0 )
210     MI_ENTRY("parodd", control, REV, PARODD, 0 )
211     MI_ENTRY("cs5", control, 0, CS5, CSIZE)
212     MI_ENTRY("cs6", control, 0, CS6, CSIZE)
213     MI_ENTRY("cs7", control, 0, CS7, CSIZE)
214     MI_ENTRY("cs8", control, 0, CS8, CSIZE)
215     MI_ENTRY("hupcl", control, REV, HUPCL, 0 )
216     MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 )
217     MI_ENTRY("cstopb", control, REV, CSTOPB, 0 )
218     MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 )
219     MI_ENTRY("clocal", control, REV, CLOCAL, 0 )
220 niro 532 #ifdef CRTSCTS
221 niro 816 MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 )
222 niro 532 #endif
223 niro 816 MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 )
224     MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 )
225     MI_ENTRY("ignpar", input, REV, IGNPAR, 0 )
226     MI_ENTRY("parmrk", input, REV, PARMRK, 0 )
227     MI_ENTRY("inpck", input, REV, INPCK, 0 )
228     MI_ENTRY("istrip", input, REV, ISTRIP, 0 )
229     MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 )
230     MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 )
231     MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 )
232     MI_ENTRY("ixon", input, REV, IXON, 0 )
233     MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 )
234     MI_ENTRY("tandem", input, REV | OMIT, IXOFF, 0 )
235 niro 532 #ifdef IUCLC
236 niro 816 MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 )
237 niro 532 #endif
238     #ifdef IXANY
239 niro 816 MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 )
240 niro 532 #endif
241     #ifdef IMAXBEL
242 niro 816 MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 )
243 niro 532 #endif
244 niro 816 MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 )
245 niro 532 #ifdef OLCUC
246 niro 816 MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 )
247 niro 532 #endif
248     #ifdef OCRNL
249 niro 816 MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 )
250 niro 532 #endif
251     #ifdef ONLCR
252 niro 816 MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 )
253 niro 532 #endif
254     #ifdef ONOCR
255 niro 816 MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 )
256 niro 532 #endif
257     #ifdef ONLRET
258 niro 816 MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 )
259 niro 532 #endif
260     #ifdef OFILL
261 niro 816 MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 )
262 niro 532 #endif
263     #ifdef OFDEL
264 niro 816 MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 )
265 niro 532 #endif
266     #ifdef NLDLY
267 niro 816 MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY)
268     MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY)
269 niro 532 #endif
270     #ifdef CRDLY
271 niro 816 MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY)
272     MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY)
273     MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY)
274     MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY)
275 niro 532 #endif
276    
277     #ifdef TABDLY
278 niro 816 MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY)
279     MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY)
280     MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY)
281     MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY)
282 niro 532 #else
283     # ifdef OXTABS
284 niro 816 MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 )
285 niro 532 # endif
286     #endif
287    
288     #ifdef BSDLY
289 niro 816 MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY)
290     MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY)
291 niro 532 #endif
292     #ifdef VTDLY
293 niro 816 MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY)
294     MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY)
295 niro 532 #endif
296     #ifdef FFDLY
297 niro 816 MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY)
298     MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY)
299 niro 532 #endif
300 niro 816 MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 )
301     MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 )
302 niro 532 #ifdef IEXTEN
303 niro 816 MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 )
304 niro 532 #endif
305 niro 816 MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 )
306     MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 )
307     MI_ENTRY("crterase", local, REV | OMIT, ECHOE, 0 )
308     MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 )
309     MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 )
310     MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 )
311 niro 532 #ifdef XCASE
312 niro 816 MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 )
313 niro 532 #endif
314     #ifdef TOSTOP
315 niro 816 MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 )
316 niro 532 #endif
317     #ifdef ECHOPRT
318 niro 816 MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 )
319     MI_ENTRY("prterase", local, REV | OMIT, ECHOPRT, 0 )
320 niro 532 #endif
321     #ifdef ECHOCTL
322 niro 816 MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 )
323     MI_ENTRY("ctlecho", local, REV | OMIT, ECHOCTL, 0 )
324 niro 532 #endif
325     #ifdef ECHOKE
326 niro 816 MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 )
327     MI_ENTRY("crtkill", local, REV | OMIT, ECHOKE, 0 )
328 niro 532 #endif
329 niro 816 ;
330    
331     #undef MI_ENTRY
332     #define MI_ENTRY(N,T,F,B,M) { T, F, M, B },
333    
334     static const struct mode_info mode_info[] = {
335     /* This should be verbatim cut-n-paste copy of the above MI_ENTRYs */
336     MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 )
337     MI_ENTRY("parity", combination, REV | OMIT, 0, 0 )
338     MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 )
339     MI_ENTRY("nl", combination, REV | OMIT, 0, 0 )
340     MI_ENTRY("ek", combination, OMIT, 0, 0 )
341     MI_ENTRY("sane", combination, OMIT, 0, 0 )
342     MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 )
343     MI_ENTRY("raw", combination, REV | OMIT, 0, 0 )
344     MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 )
345     MI_ENTRY("litout", combination, REV | OMIT, 0, 0 )
346     MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 )
347     MI_ENTRY("crt", combination, OMIT, 0, 0 )
348     MI_ENTRY("dec", combination, OMIT, 0, 0 )
349 niro 532 #ifdef IXANY
350 niro 816 MI_ENTRY("decctlq", combination, REV | OMIT, 0, 0 )
351 niro 532 #endif
352     #if defined(TABDLY) || defined(OXTABS)
353 niro 816 MI_ENTRY("tabs", combination, REV | OMIT, 0, 0 )
354 niro 532 #endif
355     #if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
356 niro 816 MI_ENTRY("lcase", combination, REV | OMIT, 0, 0 )
357     MI_ENTRY("LCASE", combination, REV | OMIT, 0, 0 )
358 niro 532 #endif
359 niro 816 MI_ENTRY("parenb", control, REV, PARENB, 0 )
360     MI_ENTRY("parodd", control, REV, PARODD, 0 )
361     MI_ENTRY("cs5", control, 0, CS5, CSIZE)
362     MI_ENTRY("cs6", control, 0, CS6, CSIZE)
363     MI_ENTRY("cs7", control, 0, CS7, CSIZE)
364     MI_ENTRY("cs8", control, 0, CS8, CSIZE)
365     MI_ENTRY("hupcl", control, REV, HUPCL, 0 )
366     MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 )
367     MI_ENTRY("cstopb", control, REV, CSTOPB, 0 )
368     MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 )
369     MI_ENTRY("clocal", control, REV, CLOCAL, 0 )
370     #ifdef CRTSCTS
371     MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 )
372     #endif
373     MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 )
374     MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 )
375     MI_ENTRY("ignpar", input, REV, IGNPAR, 0 )
376     MI_ENTRY("parmrk", input, REV, PARMRK, 0 )
377     MI_ENTRY("inpck", input, REV, INPCK, 0 )
378     MI_ENTRY("istrip", input, REV, ISTRIP, 0 )
379     MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 )
380     MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 )
381     MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 )
382     MI_ENTRY("ixon", input, REV, IXON, 0 )
383     MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 )
384     MI_ENTRY("tandem", input, REV | OMIT, IXOFF, 0 )
385     #ifdef IUCLC
386     MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 )
387     #endif
388     #ifdef IXANY
389     MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 )
390     #endif
391     #ifdef IMAXBEL
392     MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 )
393     #endif
394     MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 )
395     #ifdef OLCUC
396     MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 )
397     #endif
398     #ifdef OCRNL
399     MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 )
400     #endif
401     #ifdef ONLCR
402     MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 )
403     #endif
404     #ifdef ONOCR
405     MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 )
406     #endif
407     #ifdef ONLRET
408     MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 )
409     #endif
410     #ifdef OFILL
411     MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 )
412     #endif
413     #ifdef OFDEL
414     MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 )
415     #endif
416     #ifdef NLDLY
417     MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY)
418     MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY)
419     #endif
420     #ifdef CRDLY
421     MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY)
422     MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY)
423     MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY)
424     MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY)
425     #endif
426    
427     #ifdef TABDLY
428     MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY)
429     MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY)
430     MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY)
431     MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY)
432     #else
433     # ifdef OXTABS
434     MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 )
435     # endif
436     #endif
437    
438     #ifdef BSDLY
439     MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY)
440     MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY)
441     #endif
442     #ifdef VTDLY
443     MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY)
444     MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY)
445     #endif
446     #ifdef FFDLY
447     MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY)
448     MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY)
449     #endif
450     MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 )
451     MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 )
452     #ifdef IEXTEN
453     MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 )
454     #endif
455     MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 )
456     MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 )
457     MI_ENTRY("crterase", local, REV | OMIT, ECHOE, 0 )
458     MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 )
459     MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 )
460     MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 )
461     #ifdef XCASE
462     MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 )
463     #endif
464     #ifdef TOSTOP
465     MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 )
466     #endif
467     #ifdef ECHOPRT
468     MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 )
469     MI_ENTRY("prterase", local, REV | OMIT, ECHOPRT, 0 )
470     #endif
471     #ifdef ECHOCTL
472     MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 )
473     MI_ENTRY("ctlecho", local, REV | OMIT, ECHOCTL, 0 )
474     #endif
475     #ifdef ECHOKE
476     MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 )
477     MI_ENTRY("crtkill", local, REV | OMIT, ECHOKE, 0 )
478     #endif
479 niro 532 };
480    
481     enum {
482 niro 816 NUM_mode_info = ARRAY_SIZE(mode_info)
483 niro 532 };
484    
485 niro 816
486     /* Control characters */
487 niro 532 struct control_info {
488 niro 816 const uint8_t saneval; /* Value to set for 'stty sane' */
489     const uint8_t offset; /* Offset in c_cc */
490 niro 532 };
491    
492 niro 816 enum {
493     /* Must match control_name[] and control_info[] order! */
494     CIDX_intr = 0,
495     CIDX_quit,
496     CIDX_erase,
497     CIDX_kill,
498     CIDX_eof,
499     CIDX_eol,
500     #ifdef VEOL2
501     CIDX_eol2,
502     #endif
503     #ifdef VSWTCH
504     CIDX_swtch,
505     #endif
506     CIDX_start,
507     CIDX_stop,
508     CIDX_susp,
509     #ifdef VDSUSP
510     CIDX_dsusp,
511     #endif
512     #ifdef VREPRINT
513     CIDX_rprnt,
514     #endif
515     #ifdef VWERASE
516     CIDX_werase,
517     #endif
518     #ifdef VLNEXT
519     CIDX_lnext,
520     #endif
521     #ifdef VFLUSHO
522     CIDX_flush,
523     #endif
524     #ifdef VSTATUS
525     CIDX_status,
526     #endif
527     CIDX_min,
528     CIDX_time,
529     };
530 niro 532
531 niro 816 #define CI_ENTRY(n,s,o) n "\0"
532    
533     /* Name given on command line */
534     static const char control_name[] =
535     CI_ENTRY("intr", CINTR, VINTR )
536     CI_ENTRY("quit", CQUIT, VQUIT )
537     CI_ENTRY("erase", CERASE, VERASE )
538     CI_ENTRY("kill", CKILL, VKILL )
539     CI_ENTRY("eof", CEOF, VEOF )
540     CI_ENTRY("eol", CEOL, VEOL )
541     #ifdef VEOL2
542     CI_ENTRY("eol2", CEOL2, VEOL2 )
543     #endif
544     #ifdef VSWTCH
545     CI_ENTRY("swtch", CSWTCH, VSWTCH )
546     #endif
547     CI_ENTRY("start", CSTART, VSTART )
548     CI_ENTRY("stop", CSTOP, VSTOP )
549     CI_ENTRY("susp", CSUSP, VSUSP )
550     #ifdef VDSUSP
551     CI_ENTRY("dsusp", CDSUSP, VDSUSP )
552     #endif
553     #ifdef VREPRINT
554     CI_ENTRY("rprnt", CRPRNT, VREPRINT)
555     #endif
556     #ifdef VWERASE
557     CI_ENTRY("werase", CWERASE, VWERASE )
558     #endif
559     #ifdef VLNEXT
560     CI_ENTRY("lnext", CLNEXT, VLNEXT )
561     #endif
562     #ifdef VFLUSHO
563     CI_ENTRY("flush", CFLUSHO, VFLUSHO )
564     #endif
565     #ifdef VSTATUS
566     CI_ENTRY("status", CSTATUS, VSTATUS )
567     #endif
568     /* These must be last because of the display routines */
569     CI_ENTRY("min", 1, VMIN )
570     CI_ENTRY("time", 0, VTIME )
571     ;
572    
573     #undef CI_ENTRY
574     #define CI_ENTRY(n,s,o) { s, o },
575    
576 niro 532 static const struct control_info control_info[] = {
577 niro 816 /* This should be verbatim cut-n-paste copy of the above CI_ENTRYs */
578     CI_ENTRY("intr", CINTR, VINTR )
579     CI_ENTRY("quit", CQUIT, VQUIT )
580     CI_ENTRY("erase", CERASE, VERASE )
581     CI_ENTRY("kill", CKILL, VKILL )
582     CI_ENTRY("eof", CEOF, VEOF )
583     CI_ENTRY("eol", CEOL, VEOL )
584 niro 532 #ifdef VEOL2
585 niro 816 CI_ENTRY("eol2", CEOL2, VEOL2 )
586 niro 532 #endif
587     #ifdef VSWTCH
588 niro 816 CI_ENTRY("swtch", CSWTCH, VSWTCH )
589 niro 532 #endif
590 niro 816 CI_ENTRY("start", CSTART, VSTART )
591     CI_ENTRY("stop", CSTOP, VSTOP )
592     CI_ENTRY("susp", CSUSP, VSUSP )
593 niro 532 #ifdef VDSUSP
594 niro 816 CI_ENTRY("dsusp", CDSUSP, VDSUSP )
595 niro 532 #endif
596     #ifdef VREPRINT
597 niro 816 CI_ENTRY("rprnt", CRPRNT, VREPRINT)
598 niro 532 #endif
599     #ifdef VWERASE
600 niro 816 CI_ENTRY("werase", CWERASE, VWERASE )
601 niro 532 #endif
602     #ifdef VLNEXT
603 niro 816 CI_ENTRY("lnext", CLNEXT, VLNEXT )
604 niro 532 #endif
605     #ifdef VFLUSHO
606 niro 816 CI_ENTRY("flush", CFLUSHO, VFLUSHO )
607 niro 532 #endif
608     #ifdef VSTATUS
609 niro 816 CI_ENTRY("status", CSTATUS, VSTATUS )
610 niro 532 #endif
611     /* These must be last because of the display routines */
612 niro 816 CI_ENTRY("min", 1, VMIN )
613     CI_ENTRY("time", 0, VTIME )
614 niro 532 };
615    
616     enum {
617 niro 816 NUM_control_info = ARRAY_SIZE(control_info)
618 niro 532 };
619    
620    
621 niro 816 struct globals {
622     const char *device_name; // = bb_msg_standard_input;
623     /* The width of the screen, for output wrapping */
624     unsigned max_col; // = 80;
625     /* Current position, to know when to wrap */
626     unsigned current_col;
627     char buf[10];
628     };
629     #define G (*(struct globals*)&bb_common_bufsiz1)
630     #define INIT_G() do { \
631     G.device_name = bb_msg_standard_input; \
632     G.max_col = 80; \
633     } while (0)
634    
635    
636 niro 532 /* Return a string that is the printable representation of character CH */
637     /* Adapted from 'cat' by Torbjorn Granlund */
638 niro 816 static const char *visible(unsigned ch)
639 niro 532 {
640 niro 816 char *bpout = G.buf;
641 niro 532
642     if (ch == _POSIX_VDISABLE)
643     return "<undef>";
644    
645     if (ch >= 128) {
646     ch -= 128;
647     *bpout++ = 'M';
648     *bpout++ = '-';
649     }
650    
651     if (ch < 32) {
652     *bpout++ = '^';
653     *bpout++ = ch + 64;
654     } else if (ch < 127) {
655     *bpout++ = ch;
656     } else {
657     *bpout++ = '^';
658     *bpout++ = '?';
659     }
660    
661     *bpout = '\0';
662 niro 816 return G.buf;
663 niro 532 }
664    
665     static tcflag_t *mode_type_flag(unsigned type, const struct termios *mode)
666     {
667 niro 816 static const uint8_t tcflag_offsets[] ALIGN1 = {
668 niro 532 offsetof(struct termios, c_cflag), /* control */
669     offsetof(struct termios, c_iflag), /* input */
670     offsetof(struct termios, c_oflag), /* output */
671 niro 816 offsetof(struct termios, c_lflag) /* local */
672 niro 532 };
673    
674     if (type <= local) {
675     return (tcflag_t*) (((char*)mode) + tcflag_offsets[type]);
676     }
677     return NULL;
678     }
679    
680 niro 816 static void set_speed_or_die(enum speed_setting type, const char *const arg,
681 niro 532 struct termios * const mode)
682     {
683     speed_t baud;
684    
685     baud = tty_value_to_baud(xatou(arg));
686    
687     if (type != output_speed) { /* either input or both */
688     cfsetispeed(mode, baud);
689     }
690     if (type != input_speed) { /* either output or both */
691     cfsetospeed(mode, baud);
692     }
693     }
694    
695 niro 816 static NORETURN void perror_on_device_and_die(const char *fmt)
696 niro 532 {
697 niro 816 bb_perror_msg_and_die(fmt, G.device_name);
698 niro 532 }
699    
700     static void perror_on_device(const char *fmt)
701     {
702 niro 816 bb_perror_msg(fmt, G.device_name);
703 niro 532 }
704    
705     /* Print format string MESSAGE and optional args.
706     Wrap to next line first if it won't fit.
707     Print a space first unless MESSAGE will start a new line */
708     static void wrapf(const char *message, ...)
709     {
710     char buf[128];
711     va_list args;
712 niro 816 unsigned buflen;
713 niro 532
714     va_start(args, message);
715     buflen = vsnprintf(buf, sizeof(buf), message, args);
716     va_end(args);
717     /* We seem to be called only with suitable lengths, but check if
718     somebody failed to adhere to this assumption just to be sure. */
719     if (!buflen || buflen >= sizeof(buf)) return;
720    
721 niro 816 if (G.current_col > 0) {
722     G.current_col++;
723 niro 532 if (buf[0] != '\n') {
724 niro 816 if (G.current_col + buflen >= G.max_col) {
725     bb_putchar('\n');
726     G.current_col = 0;
727 niro 532 } else
728 niro 816 bb_putchar(' ');
729 niro 532 }
730     }
731     fputs(buf, stdout);
732 niro 816 G.current_col += buflen;
733 niro 532 if (buf[buflen-1] == '\n')
734 niro 816 G.current_col = 0;
735 niro 532 }
736    
737     static void set_window_size(const int rows, const int cols)
738     {
739 niro 816 struct winsize win = { 0, 0, 0, 0 };
740 niro 532
741     if (ioctl(STDIN_FILENO, TIOCGWINSZ, &win)) {
742     if (errno != EINVAL) {
743     goto bail;
744     }
745     memset(&win, 0, sizeof(win));
746     }
747    
748     if (rows >= 0)
749     win.ws_row = rows;
750     if (cols >= 0)
751     win.ws_col = cols;
752    
753     if (ioctl(STDIN_FILENO, TIOCSWINSZ, (char *) &win))
754     bail:
755     perror_on_device("%s");
756     }
757    
758     static void display_window_size(const int fancy)
759     {
760     const char *fmt_str = "%s\0%s: no size information for this device";
761     unsigned width, height;
762    
763     if (get_terminal_width_height(STDIN_FILENO, &width, &height)) {
764     if ((errno != EINVAL) || ((fmt_str += 2), !fancy)) {
765     perror_on_device(fmt_str);
766     }
767     } else {
768     wrapf(fancy ? "rows %d; columns %d;" : "%d %d\n",
769     height, width);
770     }
771     }
772    
773     static const struct suffix_mult stty_suffixes[] = {
774 niro 816 { "b", 512 },
775     { "k", 1024 },
776     { "B", 1024 },
777     { }
778 niro 532 };
779    
780     static const struct mode_info *find_mode(const char *name)
781     {
782 niro 816 int i = index_in_strings(mode_name, name);
783     return i >= 0 ? &mode_info[i] : NULL;
784 niro 532 }
785    
786     static const struct control_info *find_control(const char *name)
787     {
788 niro 816 int i = index_in_strings(control_name, name);
789     return i >= 0 ? &control_info[i] : NULL;
790 niro 532 }
791    
792     enum {
793     param_need_arg = 0x80,
794 niro 816 param_line = 1 | 0x80,
795     param_rows = 2 | 0x80,
796     param_cols = 3 | 0x80,
797     param_columns = 4 | 0x80,
798     param_size = 5,
799     param_speed = 6,
800     param_ispeed = 7 | 0x80,
801     param_ospeed = 8 | 0x80,
802 niro 532 };
803    
804 niro 816 static int find_param(const char *const name)
805 niro 532 {
806 niro 816 static const char params[] ALIGN1 =
807     "line\0" /* 1 */
808     "rows\0" /* 2 */
809     "cols\0" /* 3 */
810     "columns\0" /* 4 */
811     "size\0" /* 5 */
812     "speed\0" /* 6 */
813     "ispeed\0"
814     "ospeed\0";
815     int i = index_in_strings(params, name) + 1;
816     if (i == 0)
817 niro 532 return 0;
818 niro 816 if (i != 5 && i != 6)
819 niro 532 i |= 0x80;
820     return i;
821     }
822    
823     static int recover_mode(const char *arg, struct termios *mode)
824     {
825     int i, n;
826 niro 816 unsigned chr;
827 niro 532 unsigned long iflag, oflag, cflag, lflag;
828    
829     /* Scan into temporaries since it is too much trouble to figure out
830     the right format for 'tcflag_t' */
831     if (sscanf(arg, "%lx:%lx:%lx:%lx%n",
832     &iflag, &oflag, &cflag, &lflag, &n) != 4)
833     return 0;
834     mode->c_iflag = iflag;
835     mode->c_oflag = oflag;
836     mode->c_cflag = cflag;
837     mode->c_lflag = lflag;
838     arg += n;
839     for (i = 0; i < NCCS; ++i) {
840     if (sscanf(arg, ":%x%n", &chr, &n) != 1)
841     return 0;
842     mode->c_cc[i] = chr;
843     arg += n;
844     }
845    
846     /* Fail if there are too many fields */
847     if (*arg != '\0')
848     return 0;
849    
850     return 1;
851     }
852    
853     static void display_recoverable(const struct termios *mode,
854 niro 816 int UNUSED_PARAM dummy)
855 niro 532 {
856     int i;
857     printf("%lx:%lx:%lx:%lx",
858     (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
859     (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
860     for (i = 0; i < NCCS; ++i)
861     printf(":%x", (unsigned int) mode->c_cc[i]);
862 niro 816 bb_putchar('\n');
863 niro 532 }
864    
865     static void display_speed(const struct termios *mode, int fancy)
866     {
867     //01234567 8 9
868     const char *fmt_str = "%lu %lu\n\0ispeed %lu baud; ospeed %lu baud;";
869     unsigned long ispeed, ospeed;
870    
871     ospeed = ispeed = cfgetispeed(mode);
872     if (ispeed == 0 || ispeed == (ospeed = cfgetospeed(mode))) {
873     ispeed = ospeed; /* in case ispeed was 0 */
874 niro 816 //0123 4 5 6 7 8 9
875 niro 532 fmt_str = "%lu\n\0\0\0\0\0speed %lu baud;";
876     }
877     if (fancy) fmt_str += 9;
878     wrapf(fmt_str, tty_baud_to_value(ispeed), tty_baud_to_value(ospeed));
879     }
880    
881     static void do_display(const struct termios *mode, const int all)
882     {
883     int i;
884     tcflag_t *bitsp;
885     unsigned long mask;
886     int prev_type = control;
887    
888     display_speed(mode, 1);
889     if (all)
890     display_window_size(1);
891     #ifdef HAVE_C_LINE
892     wrapf("line = %d;\n", mode->c_line);
893     #else
894     wrapf("\n");
895     #endif
896    
897 niro 816 for (i = 0; i != CIDX_min; ++i) {
898 niro 532 /* If swtch is the same as susp, don't print both */
899     #if VSWTCH == VSUSP
900 niro 816 if (i == CIDX_swtch)
901 niro 532 continue;
902     #endif
903     /* If eof uses the same slot as min, only print whichever applies */
904     #if VEOF == VMIN
905     if ((mode->c_lflag & ICANON) == 0
906 niro 816 && (i == CIDX_eof || i == CIDX_eol)
907     ) {
908     continue;
909     }
910 niro 532 #endif
911 niro 816 wrapf("%s = %s;", nth_string(control_name, i),
912 niro 532 visible(mode->c_cc[control_info[i].offset]));
913     }
914     #if VEOF == VMIN
915     if ((mode->c_lflag & ICANON) == 0)
916     #endif
917     wrapf("min = %d; time = %d;", mode->c_cc[VMIN], mode->c_cc[VTIME]);
918 niro 816 if (G.current_col) wrapf("\n");
919 niro 532
920     for (i = 0; i < NUM_mode_info; ++i) {
921     if (mode_info[i].flags & OMIT)
922     continue;
923     if (mode_info[i].type != prev_type) {
924     /* wrapf("\n"); */
925 niro 816 if (G.current_col) wrapf("\n");
926 niro 532 prev_type = mode_info[i].type;
927     }
928    
929     bitsp = mode_type_flag(mode_info[i].type, mode);
930     mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
931     if ((*bitsp & mask) == mode_info[i].bits) {
932     if (all || (mode_info[i].flags & SANE_UNSET))
933 niro 816 wrapf("-%s"+1, nth_string(mode_name, i));
934 niro 532 } else {
935 niro 816 if ((all && mode_info[i].flags & REV)
936     || (!all && (mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV))
937     ) {
938     wrapf("-%s", nth_string(mode_name, i));
939     }
940 niro 532 }
941     }
942 niro 816 if (G.current_col) wrapf("\n");
943 niro 532 }
944    
945     static void sane_mode(struct termios *mode)
946     {
947     int i;
948     tcflag_t *bitsp;
949    
950     for (i = 0; i < NUM_control_info; ++i) {
951     #if VMIN == VEOF
952 niro 816 if (i == CIDX_min)
953 niro 532 break;
954     #endif
955     mode->c_cc[control_info[i].offset] = control_info[i].saneval;
956     }
957    
958     for (i = 0; i < NUM_mode_info; ++i) {
959     if (mode_info[i].flags & SANE_SET) {
960     bitsp = mode_type_flag(mode_info[i].type, mode);
961     *bitsp = (*bitsp & ~((unsigned long)mode_info[i].mask))
962     | mode_info[i].bits;
963     } else if (mode_info[i].flags & SANE_UNSET) {
964     bitsp = mode_type_flag(mode_info[i].type, mode);
965     *bitsp = *bitsp & ~((unsigned long)mode_info[i].mask)
966     & ~mode_info[i].bits;
967     }
968     }
969     }
970    
971     /* Save set_mode from #ifdef forest plague */
972     #ifndef ONLCR
973     #define ONLCR 0
974     #endif
975     #ifndef OCRNL
976     #define OCRNL 0
977     #endif
978     #ifndef ONLRET
979     #define ONLRET 0
980     #endif
981     #ifndef XCASE
982     #define XCASE 0
983     #endif
984     #ifndef IXANY
985     #define IXANY 0
986     #endif
987     #ifndef TABDLY
988     #define TABDLY 0
989     #endif
990     #ifndef OXTABS
991     #define OXTABS 0
992     #endif
993     #ifndef IUCLC
994     #define IUCLC 0
995     #endif
996     #ifndef OLCUC
997     #define OLCUC 0
998     #endif
999     #ifndef ECHOCTL
1000     #define ECHOCTL 0
1001     #endif
1002     #ifndef ECHOKE
1003     #define ECHOKE 0
1004     #endif
1005    
1006     static void set_mode(const struct mode_info *info, int reversed,
1007     struct termios *mode)
1008     {
1009     tcflag_t *bitsp;
1010    
1011     bitsp = mode_type_flag(info->type, mode);
1012    
1013     if (bitsp) {
1014     if (reversed)
1015     *bitsp = *bitsp & ~info->mask & ~info->bits;
1016     else
1017     *bitsp = (*bitsp & ~info->mask) | info->bits;
1018     return;
1019     }
1020    
1021     /* Combination mode */
1022 niro 816 if (info == &mode_info[IDX_evenp] || info == &mode_info[IDX_parity]) {
1023 niro 532 if (reversed)
1024     mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1025     else
1026     mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
1027 niro 816 } else if (info == &mode_info[IDX_oddp]) {
1028 niro 532 if (reversed)
1029     mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1030     else
1031     mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
1032 niro 816 } else if (info == &mode_info[IDX_nl]) {
1033 niro 532 if (reversed) {
1034     mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
1035     mode->c_oflag = (mode->c_oflag | ONLCR) & ~OCRNL & ~ONLRET;
1036     } else {
1037     mode->c_iflag = mode->c_iflag & ~ICRNL;
1038     if (ONLCR) mode->c_oflag = mode->c_oflag & ~ONLCR;
1039     }
1040 niro 816 } else if (info == &mode_info[IDX_ek]) {
1041 niro 532 mode->c_cc[VERASE] = CERASE;
1042     mode->c_cc[VKILL] = CKILL;
1043 niro 816 } else if (info == &mode_info[IDX_sane]) {
1044 niro 532 sane_mode(mode);
1045 niro 816 } else if (info == &mode_info[IDX_cbreak]) {
1046 niro 532 if (reversed)
1047     mode->c_lflag |= ICANON;
1048     else
1049     mode->c_lflag &= ~ICANON;
1050 niro 816 } else if (info == &mode_info[IDX_pass8]) {
1051 niro 532 if (reversed) {
1052     mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1053     mode->c_iflag |= ISTRIP;
1054     } else {
1055     mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1056     mode->c_iflag &= ~ISTRIP;
1057     }
1058 niro 816 } else if (info == &mode_info[IDX_litout]) {
1059 niro 532 if (reversed) {
1060     mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1061     mode->c_iflag |= ISTRIP;
1062     mode->c_oflag |= OPOST;
1063     } else {
1064     mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1065     mode->c_iflag &= ~ISTRIP;
1066     mode->c_oflag &= ~OPOST;
1067     }
1068 niro 816 } else if (info == &mode_info[IDX_raw] || info == &mode_info[IDX_cooked]) {
1069     if ((info == &mode_info[IDX_raw] && reversed)
1070     || (info == &mode_info[IDX_cooked] && !reversed)
1071     ) {
1072 niro 532 /* Cooked mode */
1073     mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
1074     mode->c_oflag |= OPOST;
1075     mode->c_lflag |= ISIG | ICANON;
1076     #if VMIN == VEOF
1077     mode->c_cc[VEOF] = CEOF;
1078     #endif
1079     #if VTIME == VEOL
1080     mode->c_cc[VEOL] = CEOL;
1081     #endif
1082     } else {
1083     /* Raw mode */
1084     mode->c_iflag = 0;
1085     mode->c_oflag &= ~OPOST;
1086     mode->c_lflag &= ~(ISIG | ICANON | XCASE);
1087     mode->c_cc[VMIN] = 1;
1088     mode->c_cc[VTIME] = 0;
1089     }
1090     }
1091 niro 816 else if (IXANY && info == &mode_info[IDX_decctlq]) {
1092 niro 532 if (reversed)
1093     mode->c_iflag |= IXANY;
1094     else
1095     mode->c_iflag &= ~IXANY;
1096     }
1097 niro 816 else if (TABDLY && info == &mode_info[IDX_tabs]) {
1098 niro 532 if (reversed)
1099     mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
1100     else
1101     mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
1102     }
1103 niro 816 else if (OXTABS && info == &mode_info[IDX_tabs]) {
1104 niro 532 if (reversed)
1105     mode->c_oflag |= OXTABS;
1106     else
1107     mode->c_oflag &= ~OXTABS;
1108 niro 816 } else
1109     if (XCASE && IUCLC && OLCUC
1110     && (info == &mode_info[IDX_lcase] || info == &mode_info[IDX_LCASE])
1111     ) {
1112 niro 532 if (reversed) {
1113     mode->c_lflag &= ~XCASE;
1114     mode->c_iflag &= ~IUCLC;
1115     mode->c_oflag &= ~OLCUC;
1116     } else {
1117     mode->c_lflag |= XCASE;
1118     mode->c_iflag |= IUCLC;
1119     mode->c_oflag |= OLCUC;
1120     }
1121 niro 816 } else if (info == &mode_info[IDX_crt]) {
1122 niro 532 mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
1123 niro 816 } else if (info == &mode_info[IDX_dec]) {
1124 niro 532 mode->c_cc[VINTR] = 3; /* ^C */
1125     mode->c_cc[VERASE] = 127; /* DEL */
1126     mode->c_cc[VKILL] = 21; /* ^U */
1127     mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
1128     if (IXANY) mode->c_iflag &= ~IXANY;
1129     }
1130     }
1131    
1132     static void set_control_char_or_die(const struct control_info *info,
1133     const char *arg, struct termios *mode)
1134     {
1135     unsigned char value;
1136    
1137 niro 816 if (info == &control_info[CIDX_min] || info == &control_info[CIDX_time])
1138 niro 532 value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
1139     else if (arg[0] == '\0' || arg[1] == '\0')
1140     value = arg[0];
1141     else if (!strcmp(arg, "^-") || !strcmp(arg, "undef"))
1142     value = _POSIX_VDISABLE;
1143     else if (arg[0] == '^') { /* Ignore any trailing junk (^Cjunk) */
1144     value = arg[1] & 0x1f; /* Non-letters get weird results */
1145     if (arg[1] == '?')
1146     value = 127;
1147     } else
1148     value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
1149     mode->c_cc[info->offset] = value;
1150     }
1151    
1152 niro 816 #define STTY_require_set_attr (1 << 0)
1153     #define STTY_speed_was_set (1 << 1)
1154     #define STTY_verbose_output (1 << 2)
1155     #define STTY_recoverable_output (1 << 3)
1156     #define STTY_noargs (1 << 4)
1157    
1158     int stty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1159 niro 532 int stty_main(int argc, char **argv)
1160     {
1161     struct termios mode;
1162     void (*output_func)(const struct termios *, const int);
1163     const char *file_name = NULL;
1164     int display_all = 0;
1165     int stty_state;
1166     int k;
1167    
1168 niro 816 INIT_G();
1169    
1170 niro 532 stty_state = STTY_noargs;
1171     output_func = do_display;
1172    
1173     /* First pass: only parse/verify command line params */
1174     k = 0;
1175     while (argv[++k]) {
1176     const struct mode_info *mp;
1177     const struct control_info *cp;
1178     const char *arg = argv[k];
1179     const char *argnext = argv[k+1];
1180     int param;
1181    
1182     if (arg[0] == '-') {
1183     int i;
1184     mp = find_mode(arg+1);
1185     if (mp) {
1186     if (!(mp->flags & REV))
1187     goto invalid_argument;
1188     stty_state &= ~STTY_noargs;
1189     continue;
1190     }
1191     /* It is an option - parse it */
1192     i = 0;
1193     while (arg[++i]) {
1194     switch (arg[i]) {
1195     case 'a':
1196     stty_state |= STTY_verbose_output;
1197     output_func = do_display;
1198     display_all = 1;
1199     break;
1200     case 'g':
1201     stty_state |= STTY_recoverable_output;
1202     output_func = display_recoverable;
1203     break;
1204     case 'F':
1205     if (file_name)
1206     bb_error_msg_and_die("only one device may be specified");
1207     file_name = &arg[i+1]; /* "-Fdevice" ? */
1208     if (!file_name[0]) { /* nope, "-F device" */
1209     int p = k+1; /* argv[p] is argnext */
1210     file_name = argnext;
1211     if (!file_name)
1212     bb_error_msg_and_die(bb_msg_requires_arg, "-F");
1213     /* remove -F param from arg[vc] */
1214     --argc;
1215     while (argv[p]) { argv[p] = argv[p+1]; ++p; }
1216     }
1217     goto end_option;
1218     default:
1219     goto invalid_argument;
1220     }
1221     }
1222 niro 816 end_option:
1223 niro 532 continue;
1224     }
1225    
1226     mp = find_mode(arg);
1227     if (mp) {
1228     stty_state &= ~STTY_noargs;
1229     continue;
1230     }
1231    
1232     cp = find_control(arg);
1233     if (cp) {
1234     if (!argnext)
1235     bb_error_msg_and_die(bb_msg_requires_arg, arg);
1236     /* called for the side effect of xfunc death only */
1237     set_control_char_or_die(cp, argnext, &mode);
1238     stty_state &= ~STTY_noargs;
1239     ++k;
1240     continue;
1241     }
1242    
1243     param = find_param(arg);
1244     if (param & param_need_arg) {
1245     if (!argnext)
1246     bb_error_msg_and_die(bb_msg_requires_arg, arg);
1247     ++k;
1248     }
1249    
1250     switch (param) {
1251     #ifdef HAVE_C_LINE
1252     case param_line:
1253     # ifndef TIOCGWINSZ
1254     xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
1255     break;
1256     # endif /* else fall-through */
1257     #endif
1258     #ifdef TIOCGWINSZ
1259     case param_rows:
1260     case param_cols:
1261 niro 816 case param_columns:
1262 niro 532 xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
1263     break;
1264     case param_size:
1265     #endif
1266     case param_speed:
1267     break;
1268     case param_ispeed:
1269     /* called for the side effect of xfunc death only */
1270     set_speed_or_die(input_speed, argnext, &mode);
1271     break;
1272     case param_ospeed:
1273     /* called for the side effect of xfunc death only */
1274     set_speed_or_die(output_speed, argnext, &mode);
1275     break;
1276     default:
1277     if (recover_mode(arg, &mode) == 1) break;
1278     if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) break;
1279 niro 816 invalid_argument:
1280 niro 532 bb_error_msg_and_die("invalid argument '%s'", arg);
1281     }
1282     stty_state &= ~STTY_noargs;
1283     }
1284    
1285     /* Specifying both -a and -g is an error */
1286     if ((stty_state & (STTY_verbose_output | STTY_recoverable_output)) ==
1287     (STTY_verbose_output | STTY_recoverable_output))
1288     bb_error_msg_and_die("verbose and stty-readable output styles are mutually exclusive");
1289     /* Specifying -a or -g with non-options is an error */
1290     if (!(stty_state & STTY_noargs) &&
1291     (stty_state & (STTY_verbose_output | STTY_recoverable_output)))
1292     bb_error_msg_and_die("modes may not be set when specifying an output style");
1293    
1294     /* Now it is safe to start doing things */
1295     if (file_name) {
1296     int fd, fdflags;
1297 niro 816 G.device_name = file_name;
1298     fd = xopen(G.device_name, O_RDONLY | O_NONBLOCK);
1299 niro 532 if (fd != STDIN_FILENO) {
1300     dup2(fd, STDIN_FILENO);
1301     close(fd);
1302     }
1303     fdflags = fcntl(STDIN_FILENO, F_GETFL);
1304     if (fdflags < 0 ||
1305     fcntl(STDIN_FILENO, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
1306     perror_on_device_and_die("%s: cannot reset non-blocking mode");
1307     }
1308    
1309     /* Initialize to all zeroes so there is no risk memcmp will report a
1310     spurious difference in an uninitialized portion of the structure */
1311     memset(&mode, 0, sizeof(mode));
1312     if (tcgetattr(STDIN_FILENO, &mode))
1313     perror_on_device_and_die("%s");
1314    
1315     if (stty_state & (STTY_verbose_output | STTY_recoverable_output | STTY_noargs)) {
1316 niro 816 get_terminal_width_height(STDOUT_FILENO, &G.max_col, NULL);
1317 niro 532 output_func(&mode, display_all);
1318     return EXIT_SUCCESS;
1319     }
1320    
1321     /* Second pass: perform actions */
1322     k = 0;
1323     while (argv[++k]) {
1324     const struct mode_info *mp;
1325     const struct control_info *cp;
1326     const char *arg = argv[k];
1327     const char *argnext = argv[k+1];
1328     int param;
1329    
1330     if (arg[0] == '-') {
1331     mp = find_mode(arg+1);
1332     if (mp) {
1333     set_mode(mp, 1 /* reversed */, &mode);
1334     stty_state |= STTY_require_set_attr;
1335     }
1336     /* It is an option - already parsed. Skip it */
1337     continue;
1338     }
1339    
1340     mp = find_mode(arg);
1341     if (mp) {
1342     set_mode(mp, 0 /* non-reversed */, &mode);
1343     stty_state |= STTY_require_set_attr;
1344     continue;
1345     }
1346    
1347     cp = find_control(arg);
1348     if (cp) {
1349     ++k;
1350     set_control_char_or_die(cp, argnext, &mode);
1351     stty_state |= STTY_require_set_attr;
1352     continue;
1353     }
1354    
1355     param = find_param(arg);
1356     if (param & param_need_arg) {
1357     ++k;
1358     }
1359    
1360     switch (param) {
1361     #ifdef HAVE_C_LINE
1362     case param_line:
1363     mode.c_line = xatoul_sfx(argnext, stty_suffixes);
1364     stty_state |= STTY_require_set_attr;
1365     break;
1366     #endif
1367     #ifdef TIOCGWINSZ
1368     case param_cols:
1369     set_window_size(-1, xatoul_sfx(argnext, stty_suffixes));
1370     break;
1371     case param_size:
1372     display_window_size(0);
1373     break;
1374     case param_rows:
1375     set_window_size(xatoul_sfx(argnext, stty_suffixes), -1);
1376     break;
1377     #endif
1378     case param_speed:
1379     display_speed(&mode, 0);
1380     break;
1381     case param_ispeed:
1382     set_speed_or_die(input_speed, argnext, &mode);
1383     stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
1384     break;
1385     case param_ospeed:
1386     set_speed_or_die(output_speed, argnext, &mode);
1387     stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
1388     break;
1389     default:
1390     if (recover_mode(arg, &mode) == 1)
1391     stty_state |= STTY_require_set_attr;
1392     else /* true: if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) */{
1393     set_speed_or_die(both_speeds, arg, &mode);
1394     stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
1395     } /* else - impossible (caught in the first pass):
1396     bb_error_msg_and_die("invalid argument '%s'", arg); */
1397     }
1398     }
1399    
1400     if (stty_state & STTY_require_set_attr) {
1401     struct termios new_mode;
1402    
1403     if (tcsetattr(STDIN_FILENO, TCSADRAIN, &mode))
1404     perror_on_device_and_die("%s");
1405    
1406     /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
1407     it performs *any* of the requested operations. This means it
1408     can report 'success' when it has actually failed to perform
1409     some proper subset of the requested operations. To detect
1410     this partial failure, get the current terminal attributes and
1411     compare them to the requested ones */
1412    
1413     /* Initialize to all zeroes so there is no risk memcmp will report a
1414     spurious difference in an uninitialized portion of the structure */
1415     memset(&new_mode, 0, sizeof(new_mode));
1416     if (tcgetattr(STDIN_FILENO, &new_mode))
1417     perror_on_device_and_die("%s");
1418    
1419     if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) {
1420     #ifdef CIBAUD
1421     /* SunOS 4.1.3 (at least) has the problem that after this sequence,
1422     tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
1423     sometimes (m1 != m2). The only difference is in the four bits
1424     of the c_cflag field corresponding to the baud rate. To save
1425     Sun users a little confusion, don't report an error if this
1426     happens. But suppress the error only if we haven't tried to
1427     set the baud rate explicitly -- otherwise we'd never give an
1428     error for a true failure to set the baud rate */
1429    
1430     new_mode.c_cflag &= (~CIBAUD);
1431     if ((stty_state & STTY_speed_was_set)
1432     || memcmp(&mode, &new_mode, sizeof(mode)) != 0)
1433     #endif
1434     perror_on_device_and_die("%s: cannot perform all requested operations");
1435     }
1436     }
1437    
1438     return EXIT_SUCCESS;
1439     }