source: MondoRescue/branches/3.2/mindi-busybox/coreutils/stty.c@ 3232

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