aboutsummaryrefslogtreecommitdiff
path: root/coreutils/stty.c
diff options
context:
space:
mode:
Diffstat (limited to 'coreutils/stty.c')
-rw-r--r--coreutils/stty.c493
1 files changed, 206 insertions, 287 deletions
diff --git a/coreutils/stty.c b/coreutils/stty.c
index a67a17c0f..a3a98d9ef 100644
--- a/coreutils/stty.c
+++ b/coreutils/stty.c
@@ -30,9 +30,9 @@
30 30
31//#define TEST 31//#define TEST
32 32
33#include <stddef.h>
33#include <termios.h> 34#include <termios.h>
34#include <sys/ioctl.h> 35#include <sys/ioctl.h>
35#include <getopt.h>
36 36
37#include <sys/param.h> 37#include <sys/param.h>
38#include <unistd.h> 38#include <unistd.h>
@@ -155,13 +155,10 @@ enum speed_setting {
155 input_speed, output_speed, both_speeds 155 input_speed, output_speed, both_speeds
156}; 156};
157 157
158/* What to output and how. */
159enum output_type {
160 changed, all, recoverable /* Default, -a, -g. */
161};
162
163/* Which member(s) of `struct termios' a mode uses. */ 158/* Which member(s) of `struct termios' a mode uses. */
164enum mode_type { 159enum mode_type {
160 /* Do NOT change the order or values, as mode_type_flag()
161 * depends on them. */
165 control, input, output, local, combination 162 control, input, output, local, combination
166}; 163};
167 164
@@ -199,156 +196,159 @@ static const char stty_dec [] = "dec";
199/* Each mode. */ 196/* Each mode. */
200struct mode_info { 197struct mode_info {
201 const char *name; /* Name given on command line. */ 198 const char *name; /* Name given on command line. */
202 enum mode_type type; /* Which structure element to change. */ 199 /* enum mode_type type; */
200 char type; /* Which structure element to change. */
203 char flags; /* Setting and display options. */ 201 char flags; /* Setting and display options. */
202 unsigned short mask; /* Other bits to turn off for this mode. */
204 unsigned long bits; /* Bits to set for this mode. */ 203 unsigned long bits; /* Bits to set for this mode. */
205 unsigned long mask; /* Other bits to turn off for this mode. */
206}; 204};
207 205
206#define MI_ENTRY(N,T,F,B,M) { N, T, F, M, B }
207
208static const struct mode_info mode_info[] = { 208static const struct mode_info mode_info[] = {
209 {"parenb", control, REV, PARENB, 0 }, 209 MI_ENTRY("parenb", control, REV, PARENB, 0 ),
210 {"parodd", control, REV, PARODD, 0 }, 210 MI_ENTRY("parodd", control, REV, PARODD, 0 ),
211 {"cs5", control, 0, CS5, CSIZE}, 211 MI_ENTRY("cs5", control, 0, CS5, CSIZE),
212 {"cs6", control, 0, CS6, CSIZE}, 212 MI_ENTRY("cs6", control, 0, CS6, CSIZE),
213 {"cs7", control, 0, CS7, CSIZE}, 213 MI_ENTRY("cs7", control, 0, CS7, CSIZE),
214 {"cs8", control, 0, CS8, CSIZE}, 214 MI_ENTRY("cs8", control, 0, CS8, CSIZE),
215 {"hupcl", control, REV, HUPCL, 0 }, 215 MI_ENTRY("hupcl", control, REV, HUPCL, 0 ),
216 {"hup", control, REV | OMIT, HUPCL, 0 }, 216 MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 ),
217 {"cstopb", control, REV, CSTOPB, 0 }, 217 MI_ENTRY("cstopb", control, REV, CSTOPB, 0 ),
218 {"cread", control, SANE_SET | REV, CREAD, 0 }, 218 MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 ),
219 {"clocal", control, REV, CLOCAL, 0 }, 219 MI_ENTRY("clocal", control, REV, CLOCAL, 0 ),
220#ifdef CRTSCTS 220#ifdef CRTSCTS
221 {"crtscts", control, REV, CRTSCTS, 0 }, 221 MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 ),
222#endif 222#endif
223 {"ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 }, 223 MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 ),
224 {"brkint", input, SANE_SET | REV, BRKINT, 0 }, 224 MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 ),
225 {"ignpar", input, REV, IGNPAR, 0 }, 225 MI_ENTRY("ignpar", input, REV, IGNPAR, 0 ),
226 {"parmrk", input, REV, PARMRK, 0 }, 226 MI_ENTRY("parmrk", input, REV, PARMRK, 0 ),
227 {"inpck", input, REV, INPCK, 0 }, 227 MI_ENTRY("inpck", input, REV, INPCK, 0 ),
228 {"istrip", input, REV, ISTRIP, 0 }, 228 MI_ENTRY("istrip", input, REV, ISTRIP, 0 ),
229 {"inlcr", input, SANE_UNSET | REV, INLCR, 0 }, 229 MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 ),
230 {"igncr", input, SANE_UNSET | REV, IGNCR, 0 }, 230 MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 ),
231 {"icrnl", input, SANE_SET | REV, ICRNL, 0 }, 231 MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 ),
232 {"ixon", input, REV, IXON, 0 }, 232 MI_ENTRY("ixon", input, REV, IXON, 0 ),
233 {"ixoff", input, SANE_UNSET | REV, IXOFF, 0 }, 233 MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 ),
234 {"tandem", input, REV | OMIT, IXOFF, 0 }, 234 MI_ENTRY("tandem", input, REV | OMIT, IXOFF, 0 ),
235#ifdef IUCLC 235#ifdef IUCLC
236 {"iuclc", input, SANE_UNSET | REV, IUCLC, 0 }, 236 MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 ),
237#endif 237#endif
238#ifdef IXANY 238#ifdef IXANY
239 {"ixany", input, SANE_UNSET | REV, IXANY, 0 }, 239 MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 ),
240#endif 240#endif
241#ifdef IMAXBEL 241#ifdef IMAXBEL
242 {"imaxbel", input, SANE_SET | REV, IMAXBEL, 0 }, 242 MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 ),
243#endif 243#endif
244 {"opost", output, SANE_SET | REV, OPOST, 0 }, 244 MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 ),
245#ifdef OLCUC 245#ifdef OLCUC
246 {"olcuc", output, SANE_UNSET | REV, OLCUC, 0 }, 246 MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 ),
247#endif 247#endif
248#ifdef OCRNL 248#ifdef OCRNL
249 {"ocrnl", output, SANE_UNSET | REV, OCRNL, 0 }, 249 MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 ),
250#endif 250#endif
251#ifdef ONLCR 251#ifdef ONLCR
252 {"onlcr", output, SANE_SET | REV, ONLCR, 0 }, 252 MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 ),
253#endif 253#endif
254#ifdef ONOCR 254#ifdef ONOCR
255 {"onocr", output, SANE_UNSET | REV, ONOCR, 0 }, 255 MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 ),
256#endif 256#endif
257#ifdef ONLRET 257#ifdef ONLRET
258 {"onlret", output, SANE_UNSET | REV, ONLRET, 0 }, 258 MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 ),
259#endif 259#endif
260#ifdef OFILL 260#ifdef OFILL
261 {"ofill", output, SANE_UNSET | REV, OFILL, 0 }, 261 MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 ),
262#endif 262#endif
263#ifdef OFDEL 263#ifdef OFDEL
264 {"ofdel", output, SANE_UNSET | REV, OFDEL, 0 }, 264 MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 ),
265#endif 265#endif
266#ifdef NLDLY 266#ifdef NLDLY
267 {"nl1", output, SANE_UNSET, NL1, NLDLY}, 267 MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY),
268 {"nl0", output, SANE_SET, NL0, NLDLY}, 268 MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY),
269#endif 269#endif
270#ifdef CRDLY 270#ifdef CRDLY
271 {"cr3", output, SANE_UNSET, CR3, CRDLY}, 271 MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY),
272 {"cr2", output, SANE_UNSET, CR2, CRDLY}, 272 MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY),
273 {"cr1", output, SANE_UNSET, CR1, CRDLY}, 273 MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY),
274 {"cr0", output, SANE_SET, CR0, CRDLY}, 274 MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY),
275#endif 275#endif
276 276
277#ifdef TABDLY 277#ifdef TABDLY
278 {"tab3", output, SANE_UNSET, TAB3, TABDLY}, 278 MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY),
279 {"tab2", output, SANE_UNSET, TAB2, TABDLY}, 279 MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY),
280 {"tab1", output, SANE_UNSET, TAB1, TABDLY}, 280 MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY),
281 {"tab0", output, SANE_SET, TAB0, TABDLY}, 281 MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY),
282#else 282#else
283# ifdef OXTABS 283# ifdef OXTABS
284 {"tab3", output, SANE_UNSET, OXTABS, 0 }, 284 MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 ),
285# endif 285# endif
286#endif 286#endif
287 287
288#ifdef BSDLY 288#ifdef BSDLY
289 {"bs1", output, SANE_UNSET, BS1, BSDLY}, 289 MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY),
290 {"bs0", output, SANE_SET, BS0, BSDLY}, 290 MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY),
291#endif 291#endif
292#ifdef VTDLY 292#ifdef VTDLY
293 {"vt1", output, SANE_UNSET, VT1, VTDLY}, 293 MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY),
294 {"vt0", output, SANE_SET, VT0, VTDLY}, 294 MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY),
295#endif 295#endif
296#ifdef FFDLY 296#ifdef FFDLY
297 {"ff1", output, SANE_UNSET, FF1, FFDLY}, 297 MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY),
298 {"ff0", output, SANE_SET, FF0, FFDLY}, 298 MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY),
299#endif 299#endif
300 {"isig", local, SANE_SET | REV, ISIG, 0 }, 300 MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 ),
301 {"icanon", local, SANE_SET | REV, ICANON, 0 }, 301 MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 ),
302#ifdef IEXTEN 302#ifdef IEXTEN
303 {"iexten", local, SANE_SET | REV, IEXTEN, 0 }, 303 MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 ),
304#endif 304#endif
305 {"echo", local, SANE_SET | REV, ECHO, 0 }, 305 MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 ),
306 {"echoe", local, SANE_SET | REV, ECHOE, 0 }, 306 MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 ),
307 {"crterase", local, REV | OMIT, ECHOE, 0 }, 307 MI_ENTRY("crterase", local, REV | OMIT, ECHOE, 0 ),
308 {"echok", local, SANE_SET | REV, ECHOK, 0 }, 308 MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 ),
309 {"echonl", local, SANE_UNSET | REV, ECHONL, 0 }, 309 MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 ),
310 {"noflsh", local, SANE_UNSET | REV, NOFLSH, 0 }, 310 MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 ),
311#ifdef XCASE 311#ifdef XCASE
312 {"xcase", local, SANE_UNSET | REV, XCASE, 0 }, 312 MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 ),
313#endif 313#endif
314#ifdef TOSTOP 314#ifdef TOSTOP
315 {"tostop", local, SANE_UNSET | REV, TOSTOP, 0 }, 315 MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 ),
316#endif 316#endif
317#ifdef ECHOPRT 317#ifdef ECHOPRT
318 {"echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 }, 318 MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 ),
319 {"prterase", local, REV | OMIT, ECHOPRT, 0 }, 319 MI_ENTRY("prterase", local, REV | OMIT, ECHOPRT, 0 ),
320#endif 320#endif
321#ifdef ECHOCTL 321#ifdef ECHOCTL
322 {"echoctl", local, SANE_SET | REV, ECHOCTL, 0 }, 322 MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 ),
323 {"ctlecho", local, REV | OMIT, ECHOCTL, 0 }, 323 MI_ENTRY("ctlecho", local, REV | OMIT, ECHOCTL, 0 ),
324#endif 324#endif
325#ifdef ECHOKE 325#ifdef ECHOKE
326 {"echoke", local, SANE_SET | REV, ECHOKE, 0 }, 326 MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 ),
327 {"crtkill", local, REV | OMIT, ECHOKE, 0 }, 327 MI_ENTRY("crtkill", local, REV | OMIT, ECHOKE, 0 ),
328#endif 328#endif
329 {evenp, combination, REV | OMIT, 0, 0 }, 329 MI_ENTRY(evenp, combination, REV | OMIT, 0, 0 ),
330 {parity, combination, REV | OMIT, 0, 0 }, 330 MI_ENTRY(parity, combination, REV | OMIT, 0, 0 ),
331 {stty_oddp, combination, REV | OMIT, 0, 0 }, 331 MI_ENTRY(stty_oddp, combination, REV | OMIT, 0, 0 ),
332 {stty_nl, combination, REV | OMIT, 0, 0 }, 332 MI_ENTRY(stty_nl, combination, REV | OMIT, 0, 0 ),
333 {stty_ek, combination, OMIT, 0, 0 }, 333 MI_ENTRY(stty_ek, combination, OMIT, 0, 0 ),
334 {stty_sane, combination, OMIT, 0, 0 }, 334 MI_ENTRY(stty_sane, combination, OMIT, 0, 0 ),
335 {cooked, combination, REV | OMIT, 0, 0 }, 335 MI_ENTRY(cooked, combination, REV | OMIT, 0, 0 ),
336 {raw, combination, REV | OMIT, 0, 0 }, 336 MI_ENTRY(raw, combination, REV | OMIT, 0, 0 ),
337 {stty_pass8, combination, REV | OMIT, 0, 0 }, 337 MI_ENTRY(stty_pass8, combination, REV | OMIT, 0, 0 ),
338 {litout, combination, REV | OMIT, 0, 0 }, 338 MI_ENTRY(litout, combination, REV | OMIT, 0, 0 ),
339 {cbreak, combination, REV | OMIT, 0, 0 }, 339 MI_ENTRY(cbreak, combination, REV | OMIT, 0, 0 ),
340#ifdef IXANY 340#ifdef IXANY
341 {decctlq, combination, REV | OMIT, 0, 0 }, 341 MI_ENTRY(decctlq, combination, REV | OMIT, 0, 0 ),
342#endif 342#endif
343#if defined (TABDLY) || defined (OXTABS) 343#if defined (TABDLY) || defined (OXTABS)
344 {stty_tabs, combination, REV | OMIT, 0, 0 }, 344 MI_ENTRY(stty_tabs, combination, REV | OMIT, 0, 0 ),
345#endif 345#endif
346#if defined(XCASE) && defined(IUCLC) && defined(OLCUC) 346#if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
347 {stty_lcase, combination, REV | OMIT, 0, 0 }, 347 MI_ENTRY(stty_lcase, combination, REV | OMIT, 0, 0 ),
348 {stty_LCASE, combination, REV | OMIT, 0, 0 }, 348 MI_ENTRY(stty_LCASE, combination, REV | OMIT, 0, 0 ),
349#endif 349#endif
350 {stty_crt, combination, OMIT, 0, 0 }, 350 MI_ENTRY(stty_crt, combination, OMIT, 0, 0 ),
351 {stty_dec, combination, OMIT, 0, 0 }, 351 MI_ENTRY(stty_dec, combination, OMIT, 0, 0 ),
352}; 352};
353 353
354static const int NUM_mode_info = 354static const int NUM_mode_info =
@@ -359,7 +359,7 @@ static const int NUM_mode_info =
359struct control_info { 359struct control_info {
360 const char *name; /* Name given on command line. */ 360 const char *name; /* Name given on command line. */
361 unsigned char saneval; /* Value to set for `stty sane'. */ 361 unsigned char saneval; /* Value to set for `stty sane'. */
362 int offset; /* Offset in c_cc. */ 362 unsigned char offset; /* Offset in c_cc. */
363}; 363};
364 364
365/* Control characters. */ 365/* Control characters. */
@@ -408,7 +408,6 @@ static const int NUM_control_info =
408 408
409 409
410static const char * visible(unsigned int ch); 410static const char * visible(unsigned int ch);
411static unsigned long baud_to_value(speed_t speed);
412static int recover_mode(char *arg, struct termios *mode); 411static int recover_mode(char *arg, struct termios *mode);
413static int screen_columns(void); 412static int screen_columns(void);
414static int set_mode(const struct mode_info *info, 413static int set_mode(const struct mode_info *info,
@@ -416,12 +415,11 @@ static int set_mode(const struct mode_info *info,
416static speed_t string_to_baud(const char *arg); 415static speed_t string_to_baud(const char *arg);
417static tcflag_t* mode_type_flag(enum mode_type type, struct termios *mode); 416static tcflag_t* mode_type_flag(enum mode_type type, struct termios *mode);
418static void display_all(struct termios *mode, int fd, 417static void display_all(struct termios *mode, int fd,
419 const char *device_name); 418 const char *device_name);
420static void display_changed(struct termios *mode); 419static void display_changed(struct termios *mode, int fd,
421static void display_recoverable(struct termios *mode); 420 const char *device_name);
422static void display_settings(enum output_type output_type, 421static void display_recoverable(struct termios *mode, int fd,
423 struct termios *mode, int fd, 422 const char *device_name);
424 const char *device_name);
425static void display_speed(struct termios *mode, int fancy); 423static void display_speed(struct termios *mode, int fancy);
426static void display_window_size(int fancy, int fd, 424static void display_window_size(int fancy, int fd,
427 const char *device_name); 425 const char *device_name);
@@ -479,7 +477,7 @@ extern int main(int argc, char **argv)
479#endif 477#endif
480{ 478{
481 struct termios mode; 479 struct termios mode;
482 enum output_type output_type; 480 void (*output_func)(struct termios *, int, const char *);
483 int optc; 481 int optc;
484 int require_set_attr; 482 int require_set_attr;
485 int speed_was_set; 483 int speed_was_set;
@@ -491,7 +489,7 @@ extern int main(int argc, char **argv)
491 int fd; 489 int fd;
492 const char *device_name; 490 const char *device_name;
493 491
494 output_type = changed; 492 output_func = display_changed;
495 verbose_output = 0; 493 verbose_output = 0;
496 recoverable_output = 0; 494 recoverable_output = 0;
497 495
@@ -502,17 +500,17 @@ extern int main(int argc, char **argv)
502 switch (optc) { 500 switch (optc) {
503 case 'a': 501 case 'a':
504 verbose_output = 1; 502 verbose_output = 1;
505 output_type = all; 503 output_func = display_all;
506 break; 504 break;
507 505
508 case 'g': 506 case 'g':
509 recoverable_output = 1; 507 recoverable_output = 1;
510 output_type = recoverable; 508 output_func = display_recoverable;
511 break; 509 break;
512 510
513 case 'F': 511 case 'F':
514 if (file_name) 512 if (file_name)
515 error_msg_and_die("only one device may be specified"); 513 bb_error_msg_and_die("only one device may be specified");
516 file_name = optarg; 514 file_name = optarg;
517 break; 515 break;
518 516
@@ -529,12 +527,12 @@ extern int main(int argc, char **argv)
529 noargs = 0; 527 noargs = 0;
530 528
531 /* Specifying both -a and -g gets an error. */ 529 /* Specifying both -a and -g gets an error. */
532 if (verbose_output && recoverable_output) 530 if (verbose_output & recoverable_output)
533 error_msg_and_die ("verbose and stty-readable output styles are mutually exclusive"); 531 bb_error_msg_and_die ("verbose and stty-readable output styles are mutually exclusive");
534 532
535 /* Specifying any other arguments with -a or -g gets an error. */ 533 /* Specifying any other arguments with -a or -g gets an error. */
536 if (!noargs && (verbose_output || recoverable_output)) 534 if (~noargs & (verbose_output | recoverable_output))
537 error_msg_and_die ("modes may not be set when specifying an output style"); 535 bb_error_msg_and_die ("modes may not be set when specifying an output style");
538 536
539 /* FIXME: it'd be better not to open the file until we've verified 537 /* FIXME: it'd be better not to open the file until we've verified
540 that all arguments are valid. Otherwise, we could end up doing 538 that all arguments are valid. Otherwise, we could end up doing
@@ -547,26 +545,26 @@ extern int main(int argc, char **argv)
547 device_name = file_name; 545 device_name = file_name;
548 fd = open(device_name, O_RDONLY | O_NONBLOCK); 546 fd = open(device_name, O_RDONLY | O_NONBLOCK);
549 if (fd < 0) 547 if (fd < 0)
550 perror_msg_and_die("%s", device_name); 548 bb_perror_msg_and_die("%s", device_name);
551 if ((fdflags = fcntl(fd, F_GETFL)) == -1 549 if ((fdflags = fcntl(fd, F_GETFL)) == -1
552 || fcntl(fd, F_SETFL, fdflags & ~O_NONBLOCK) < 0) 550 || fcntl(fd, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
553 perror_msg_and_die("%s: couldn't reset non-blocking mode", 551 bb_perror_msg_and_die("%s: couldn't reset non-blocking mode",
554 device_name); 552 device_name);
555 } else { 553 } else {
556 fd = 0; 554 fd = 0;
557 device_name = "standard input"; 555 device_name = bb_msg_standard_input;
558 } 556 }
559 557
560 /* Initialize to all zeroes so there is no risk memcmp will report a 558 /* Initialize to all zeroes so there is no risk memcmp will report a
561 spurious difference in an uninitialized portion of the structure. */ 559 spurious difference in an uninitialized portion of the structure. */
562 memset(&mode, 0, sizeof(mode)); 560 memset(&mode, 0, sizeof(mode));
563 if (tcgetattr(fd, &mode)) 561 if (tcgetattr(fd, &mode))
564 perror_msg_and_die("%s", device_name); 562 bb_perror_msg_and_die("%s", device_name);
565 563
566 if (verbose_output || recoverable_output || noargs) { 564 if (verbose_output | recoverable_output | noargs) {
567 max_col = screen_columns(); 565 max_col = screen_columns();
568 current_col = 0; 566 current_col = 0;
569 display_settings(output_type, &mode, fd, device_name); 567 output_func(&mode, fd, device_name);
570 return EXIT_SUCCESS; 568 return EXIT_SUCCESS;
571 } 569 }
572 570
@@ -610,13 +608,13 @@ extern int main(int argc, char **argv)
610 } 608 }
611 609
612 if (match_found == 0 && reversed) 610 if (match_found == 0 && reversed)
613 error_msg_and_die("invalid argument `%s'", --argv[k]); 611 bb_error_msg_and_die("invalid argument `%s'", --argv[k]);
614 612
615 if (match_found == 0) 613 if (match_found == 0)
616 for (i = 0; i < NUM_control_info; ++i) 614 for (i = 0; i < NUM_control_info; ++i)
617 if (STREQ(argv[k], control_info[i].name)) { 615 if (STREQ(argv[k], control_info[i].name)) {
618 if (k == argc - 1) 616 if (k == argc - 1)
619 error_msg_and_die("missing argument to `%s'", argv[k]); 617 bb_error_msg_and_die("missing argument to `%s'", argv[k]);
620 match_found = 1; 618 match_found = 1;
621 ++k; 619 ++k;
622 set_control_char(&control_info[i], argv[k], &mode); 620 set_control_char(&control_info[i], argv[k], &mode);
@@ -627,14 +625,14 @@ extern int main(int argc, char **argv)
627 if (match_found == 0) { 625 if (match_found == 0) {
628 if (STREQ(argv[k], "ispeed")) { 626 if (STREQ(argv[k], "ispeed")) {
629 if (k == argc - 1) 627 if (k == argc - 1)
630 error_msg_and_die("missing argument to `%s'", argv[k]); 628 bb_error_msg_and_die("missing argument to `%s'", argv[k]);
631 ++k; 629 ++k;
632 set_speed(input_speed, argv[k], &mode); 630 set_speed(input_speed, argv[k], &mode);
633 speed_was_set = 1; 631 speed_was_set = 1;
634 require_set_attr = 1; 632 require_set_attr = 1;
635 } else if (STREQ(argv[k], "ospeed")) { 633 } else if (STREQ(argv[k], "ospeed")) {
636 if (k == argc - 1) 634 if (k == argc - 1)
637 error_msg_and_die("missing argument to `%s'", argv[k]); 635 bb_error_msg_and_die("missing argument to `%s'", argv[k]);
638 ++k; 636 ++k;
639 set_speed(output_speed, argv[k], &mode); 637 set_speed(output_speed, argv[k], &mode);
640 speed_was_set = 1; 638 speed_was_set = 1;
@@ -643,16 +641,16 @@ extern int main(int argc, char **argv)
643#ifdef TIOCGWINSZ 641#ifdef TIOCGWINSZ
644 else if (STREQ(argv[k], "rows")) { 642 else if (STREQ(argv[k], "rows")) {
645 if (k == argc - 1) 643 if (k == argc - 1)
646 error_msg_and_die("missing argument to `%s'", argv[k]); 644 bb_error_msg_and_die("missing argument to `%s'", argv[k]);
647 ++k; 645 ++k;
648 set_window_size((int) parse_number(argv[k], stty_suffixes), 646 set_window_size((int) bb_xparse_number(argv[k], stty_suffixes),
649 -1, fd, device_name); 647 -1, fd, device_name);
650 } else if (STREQ(argv[k], "cols") || STREQ(argv[k], "columns")) { 648 } else if (STREQ(argv[k], "cols") || STREQ(argv[k], "columns")) {
651 if (k == argc - 1) 649 if (k == argc - 1)
652 error_msg_and_die("missing argument to `%s'", argv[k]); 650 bb_error_msg_and_die("missing argument to `%s'", argv[k]);
653 ++k; 651 ++k;
654 set_window_size(-1, 652 set_window_size(-1,
655 (int) parse_number(argv[k], stty_suffixes), 653 (int) bb_xparse_number(argv[k], stty_suffixes),
656 fd, device_name); 654 fd, device_name);
657 } else if (STREQ(argv[k], "size")) { 655 } else if (STREQ(argv[k], "size")) {
658 max_col = screen_columns(); 656 max_col = screen_columns();
@@ -663,9 +661,9 @@ extern int main(int argc, char **argv)
663#ifdef HAVE_C_LINE 661#ifdef HAVE_C_LINE
664 else if (STREQ(argv[k], "line")) { 662 else if (STREQ(argv[k], "line")) {
665 if (k == argc - 1) 663 if (k == argc - 1)
666 error_msg_and_die("missing argument to `%s'", argv[k]); 664 bb_error_msg_and_die("missing argument to `%s'", argv[k]);
667 ++k; 665 ++k;
668 mode.c_line = parse_number(argv[k], stty_suffixes); 666 mode.c_line = bb_xparse_number(argv[k], stty_suffixes);
669 require_set_attr = 1; 667 require_set_attr = 1;
670 } 668 }
671#endif 669#endif
@@ -679,7 +677,7 @@ extern int main(int argc, char **argv)
679 speed_was_set = 1; 677 speed_was_set = 1;
680 require_set_attr = 1; 678 require_set_attr = 1;
681 } else 679 } else
682 error_msg_and_die("invalid argument `%s'", argv[k]); 680 bb_error_msg_and_die("invalid argument `%s'", argv[k]);
683 } 681 }
684 } 682 }
685 683
@@ -687,7 +685,7 @@ extern int main(int argc, char **argv)
687 struct termios new_mode; 685 struct termios new_mode;
688 686
689 if (tcsetattr(fd, TCSADRAIN, &mode)) 687 if (tcsetattr(fd, TCSADRAIN, &mode))
690 perror_msg_and_die("%s", device_name); 688 bb_perror_msg_and_die("%s", device_name);
691 689
692 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if 690 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
693 it performs *any* of the requested operations. This means it 691 it performs *any* of the requested operations. This means it
@@ -700,7 +698,7 @@ extern int main(int argc, char **argv)
700 spurious difference in an uninitialized portion of the structure. */ 698 spurious difference in an uninitialized portion of the structure. */
701 memset(&new_mode, 0, sizeof(new_mode)); 699 memset(&new_mode, 0, sizeof(new_mode));
702 if (tcgetattr(fd, &new_mode)) 700 if (tcgetattr(fd, &new_mode))
703 perror_msg_and_die("%s", device_name); 701 bb_perror_msg_and_die("%s", device_name);
704 702
705 /* Normally, one shouldn't use memcmp to compare structures that 703 /* Normally, one shouldn't use memcmp to compare structures that
706 may have `holes' containing uninitialized data, but we have been 704 may have `holes' containing uninitialized data, but we have been
@@ -723,7 +721,7 @@ extern int main(int argc, char **argv)
723 new_mode.c_cflag &= (~CIBAUD); 721 new_mode.c_cflag &= (~CIBAUD);
724 if (speed_was_set || memcmp(&mode, &new_mode, sizeof(mode)) != 0) 722 if (speed_was_set || memcmp(&mode, &new_mode, sizeof(mode)) != 0)
725#endif 723#endif
726 error_msg_and_die ("%s: unable to perform all requested operations", 724 bb_error_msg_and_die ("%s: unable to perform all requested operations",
727 device_name); 725 device_name);
728 } 726 }
729 } 727 }
@@ -896,9 +894,9 @@ set_mode(const struct mode_info *info, int reversed, struct termios *mode)
896#endif 894#endif
897 } 895 }
898 } else if (reversed) 896 } else if (reversed)
899 *bitsp = *bitsp & ~info->mask & ~info->bits; 897 *bitsp = *bitsp & ~((unsigned long)info->mask) & ~info->bits;
900 else 898 else
901 *bitsp = (*bitsp & ~info->mask) | info->bits; 899 *bitsp = (*bitsp & ~((unsigned long)info->mask)) | info->bits;
902 900
903 return 1; 901 return 1;
904} 902}
@@ -910,7 +908,7 @@ set_control_char(const struct control_info *info, const char *arg,
910 unsigned char value; 908 unsigned char value;
911 909
912 if (info->name == stty_min || info->name == stty_time) 910 if (info->name == stty_min || info->name == stty_time)
913 value = parse_number(arg, stty_suffixes); 911 value = bb_xparse_number(arg, stty_suffixes);
914 else if (arg[0] == '\0' || arg[1] == '\0') 912 else if (arg[0] == '\0' || arg[1] == '\0')
915 value = arg[0]; 913 value = arg[0];
916 else if (STREQ(arg, "^-") || STREQ(arg, "undef")) 914 else if (STREQ(arg, "^-") || STREQ(arg, "undef"))
@@ -921,7 +919,7 @@ set_control_char(const struct control_info *info, const char *arg,
921 else 919 else
922 value = arg[1] & ~0140; /* Non-letters get weird results. */ 920 value = arg[1] & ~0140; /* Non-letters get weird results. */
923 } else 921 } else
924 value = parse_number(arg, stty_suffixes); 922 value = bb_xparse_number(arg, stty_suffixes);
925 mode->c_cc[info->offset] = value; 923 mode->c_cc[info->offset] = value;
926} 924}
927 925
@@ -931,10 +929,13 @@ set_speed(enum speed_setting type, const char *arg, struct termios *mode)
931 speed_t baud; 929 speed_t baud;
932 930
933 baud = string_to_baud(arg); 931 baud = string_to_baud(arg);
934 if (type == input_speed || type == both_speeds) 932
933 if (type != output_speed) { /* either input or both */
935 cfsetispeed(mode, baud); 934 cfsetispeed(mode, baud);
936 if (type == output_speed || type == both_speeds) 935 }
936 if (type != input_speed) { /* either output or both */
937 cfsetospeed(mode, baud); 937 cfsetospeed(mode, baud);
938 }
938} 939}
939 940
940#ifdef TIOCGWINSZ 941#ifdef TIOCGWINSZ
@@ -953,7 +954,7 @@ set_window_size(int rows, int cols, int fd, const char *device_name)
953 954
954 if (get_win_size(fd, &win)) { 955 if (get_win_size(fd, &win)) {
955 if (errno != EINVAL) 956 if (errno != EINVAL)
956 perror_msg_and_die("%s", device_name); 957 bb_perror_msg_and_die("%s", device_name);
957 memset(&win, 0, sizeof(win)); 958 memset(&win, 0, sizeof(win));
958 } 959 }
959 960
@@ -975,32 +976,28 @@ set_window_size(int rows, int cols, int fd, const char *device_name)
975 ttysz.ts_lines = win.ws_row; 976 ttysz.ts_lines = win.ws_row;
976 ttysz.ts_cols = win.ws_col; 977 ttysz.ts_cols = win.ws_col;
977 978
978 win.ws_row = 1; 979 win.ws_row = win.ws_col = 1;
979 win.ws_col = 1;
980
981 if (ioctl(fd, TIOCSWINSZ, (char *) &win))
982 perror_msg_and_die("%s", device_name);
983 980
984 if (ioctl(fd, TIOCSSIZE, (char *) &ttysz)) 981 if ((ioctl(fd, TIOCSWINSZ, (char *) &win) != 0)
985 perror_msg_and_die("%s", device_name); 982 || (ioctl(fd, TIOCSSIZE, (char *) &ttysz) != 0)) {
983 bb_perror_msg_and_die("%s", device_name);
986 return; 984 return;
987 } 985 }
988# endif 986# endif
989 987
990 if (ioctl(fd, TIOCSWINSZ, (char *) &win)) 988 if (ioctl(fd, TIOCSWINSZ, (char *) &win))
991 perror_msg_and_die("%s", device_name); 989 bb_perror_msg_and_die("%s", device_name);
992} 990}
993 991
994static void display_window_size(int fancy, int fd, const char *device_name) 992static void display_window_size(int fancy, int fd, const char *device_name)
995{ 993{
994 const char *fmt_str = "%s" "\0" "%s: no size information for this device";
996 struct winsize win; 995 struct winsize win;
997 996
998 if (get_win_size(fd, &win)) { 997 if (get_win_size(fd, &win)) {
999 if (errno != EINVAL) 998 if ((errno != EINVAL) || ((fmt_str += 2), !fancy)) {
1000 perror_msg_and_die("%s", device_name); 999 bb_perror_msg_and_die(fmt_str, device_name);
1001 if (!fancy) 1000 }
1002 perror_msg_and_die("%s: no size information for this device",
1003 device_name);
1004 } else { 1001 } else {
1005 wrapf(fancy ? "rows %d; columns %d;" : "%d %d\n", 1002 wrapf(fancy ? "rows %d; columns %d;" : "%d %d\n",
1006 win.ws_row, win.ws_col); 1003 win.ws_row, win.ws_col);
@@ -1012,6 +1009,9 @@ static void display_window_size(int fancy, int fd, const char *device_name)
1012 1009
1013static int screen_columns(void) 1010static int screen_columns(void)
1014{ 1011{
1012 int columns;
1013 const char *s;
1014
1015#ifdef TIOCGWINSZ 1015#ifdef TIOCGWINSZ
1016 struct winsize win; 1016 struct winsize win;
1017 1017
@@ -1025,51 +1025,29 @@ static int screen_columns(void)
1025 return win.ws_col; 1025 return win.ws_col;
1026#endif 1026#endif
1027 1027
1028 if (getenv("COLUMNS")) 1028 columns = 80;
1029 return atoi(getenv("COLUMNS")); 1029 if ((s = getenv("COLUMNS"))) {
1030 return 80; 1030 columns = atoi(s);
1031}
1032
1033static tcflag_t *mode_type_flag(enum mode_type type, struct termios *mode)
1034{
1035 switch (type) {
1036 case control:
1037 return &mode->c_cflag;
1038
1039 case input:
1040 return &mode->c_iflag;
1041
1042 case output:
1043 return &mode->c_oflag;
1044
1045 case local:
1046 return &mode->c_lflag;
1047
1048 default: /* combination: */
1049 return NULL;
1050 } 1031 }
1032 return columns;
1051} 1033}
1052 1034
1053static void 1035static tcflag_t *mode_type_flag(enum mode_type type, struct termios *mode)
1054display_settings(enum output_type output_type, struct termios *mode,
1055 int fd, const char *device_name)
1056{ 1036{
1057 switch (output_type) { 1037 static const unsigned char tcflag_offsets[] = {
1058 case changed: 1038 offsetof(struct termios, c_cflag), /* control */
1059 display_changed(mode); 1039 offsetof(struct termios, c_iflag), /* input */
1060 break; 1040 offsetof(struct termios, c_oflag), /* output */
1061 1041 offsetof(struct termios, c_lflag) /* local */
1062 case all: 1042 };
1063 display_all(mode, fd, device_name); 1043
1064 break; 1044 if (((unsigned int) type) <= local) {
1065 1045 return (tcflag_t *)(((char *) mode) + tcflag_offsets[(int)type]);
1066 case recoverable:
1067 display_recoverable(mode);
1068 break;
1069 } 1046 }
1047 return NULL;
1070} 1048}
1071 1049
1072static void display_changed(struct termios *mode) 1050static void display_changed(struct termios *mode, int fd, const char *device_name)
1073{ 1051{
1074 int i; 1052 int i;
1075 int empty_line; 1053 int empty_line;
@@ -1206,18 +1184,25 @@ display_all(struct termios *mode, int fd, const char *device_name)
1206 1184
1207static void display_speed(struct termios *mode, int fancy) 1185static void display_speed(struct termios *mode, int fancy)
1208{ 1186{
1209 if (cfgetispeed(mode) == 0 || cfgetispeed(mode) == cfgetospeed(mode)) 1187 unsigned long ispeed, ospeed;
1210 wrapf(fancy ? "speed %lu baud;" : "%lu\n", 1188 const char *fmt_str =
1211 baud_to_value(cfgetospeed(mode))); 1189 "%lu %lu\n\0" "ispeed %lu baud; ospeed %lu baud;\0"
1212 else 1190 "%lu\n\0" "\0\0\0\0" "speed %lu baud;";
1213 wrapf(fancy ? "ispeed %lu baud; ospeed %lu baud;" : "%lu %lu\n", 1191
1214 baud_to_value(cfgetispeed(mode)), 1192 ospeed = ispeed = cfgetispeed(mode);
1215 baud_to_value(cfgetospeed(mode))); 1193 if (ispeed == 0 || ispeed == (ospeed = cfgetospeed(mode))) {
1194 ispeed = ospeed; /* in case ispeed was 0 */
1195 fmt_str += 43;
1196 }
1197 if (fancy) {
1198 fmt_str += 9;
1199 }
1200 wrapf(fmt_str, bb_baud_to_value(ispeed), bb_baud_to_value(ospeed));
1216 if (!fancy) 1201 if (!fancy)
1217 current_col = 0; 1202 current_col = 0;
1218} 1203}
1219 1204
1220static void display_recoverable(struct termios *mode) 1205static void display_recoverable(struct termios *mode, int fd, const char *device_name)
1221{ 1206{
1222 int i; 1207 int i;
1223 1208
@@ -1259,62 +1244,9 @@ static int recover_mode(char *arg, struct termios *mode)
1259 return 1; 1244 return 1;
1260} 1245}
1261 1246
1262struct speed_map {
1263 speed_t speed; /* Internal form. */
1264 unsigned long value; /* Numeric value. */
1265};
1266
1267static const struct speed_map speeds[] = {
1268 {B0, 0},
1269 {B50, 50},
1270 {B75, 75},
1271 {B110, 110},
1272 {B134, 134},
1273 {B150, 150},
1274 {B200, 200},
1275 {B300, 300},
1276 {B600, 600},
1277 {B1200, 1200},
1278 {B1800, 1800},
1279 {B2400, 2400},
1280 {B4800, 4800},
1281 {B9600, 9600},
1282 {B19200, 19200},
1283 {B38400, 38400},
1284#ifdef B57600
1285 {B57600, 57600},
1286#endif
1287#ifdef B115200
1288 {B115200, 115200},
1289#endif
1290#ifdef B230400
1291 {B230400, 230400},
1292#endif
1293#ifdef B460800
1294 {B460800, 460800},
1295#endif
1296};
1297
1298static const int NUM_SPEEDS = (sizeof(speeds) / sizeof(struct speed_map));
1299
1300static speed_t string_to_baud(const char *arg) 1247static speed_t string_to_baud(const char *arg)
1301{ 1248{
1302 int i; 1249 return bb_value_to_baud(bb_xparse_number(arg, 0));
1303
1304 for (i = 0; i < NUM_SPEEDS; ++i)
1305 if (parse_number(arg, 0) == speeds[i].value)
1306 return speeds[i].speed;
1307 return (speed_t) - 1;
1308}
1309
1310static unsigned long baud_to_value(speed_t speed)
1311{
1312 int i;
1313
1314 for (i = 0; i < NUM_SPEEDS; ++i)
1315 if (speed == speeds[i].speed)
1316 return speeds[i].value;
1317 return 0;
1318} 1250}
1319 1251
1320static void sane_mode(struct termios *mode) 1252static void sane_mode(struct termios *mode)
@@ -1333,10 +1265,12 @@ static void sane_mode(struct termios *mode)
1333 for (i = 0; i < NUM_mode_info; ++i) { 1265 for (i = 0; i < NUM_mode_info; ++i) {
1334 if (mode_info[i].flags & SANE_SET) { 1266 if (mode_info[i].flags & SANE_SET) {
1335 bitsp = mode_type_flag(mode_info[i].type, mode); 1267 bitsp = mode_type_flag(mode_info[i].type, mode);
1336 *bitsp = (*bitsp & ~mode_info[i].mask) | mode_info[i].bits; 1268 *bitsp = (*bitsp & ~((unsigned long)mode_info[i].mask))
1269 | mode_info[i].bits;
1337 } else if (mode_info[i].flags & SANE_UNSET) { 1270 } else if (mode_info[i].flags & SANE_UNSET) {
1338 bitsp = mode_type_flag(mode_info[i].type, mode); 1271 bitsp = mode_type_flag(mode_info[i].type, mode);
1339 *bitsp = *bitsp & ~mode_info[i].mask & ~mode_info[i].bits; 1272 *bitsp = *bitsp & ~((unsigned long)mode_info[i].mask)
1273 & ~mode_info[i].bits;
1340 } 1274 }
1341 } 1275 }
1342} 1276}
@@ -1349,47 +1283,32 @@ static const char *visible(unsigned int ch)
1349 static char buf[10]; 1283 static char buf[10];
1350 char *bpout = buf; 1284 char *bpout = buf;
1351 1285
1352 if (ch == _POSIX_VDISABLE) 1286 if (ch == _POSIX_VDISABLE) {
1353 return "<undef>"; 1287 return "<undef>";
1288 }
1354 1289
1355 if (ch >= 32) { 1290 if (ch >= 128) {
1356 if (ch < 127) 1291 ch -= 128;
1357 *bpout++ = ch; 1292 *bpout++ = 'M';
1358 else if (ch == 127) { 1293 *bpout++ = '-';
1359 *bpout++ = '^'; 1294 }
1360 *bpout++ = '?'; 1295
1361 } else { 1296 if (ch < 32) {
1362 *bpout++ = 'M', *bpout++ = '-';
1363 if (ch >= 128 + 32) {
1364 if (ch < 128 + 127)
1365 *bpout++ = ch - 128;
1366 else {
1367 *bpout++ = '^';
1368 *bpout++ = '?';
1369 }
1370 } else {
1371 *bpout++ = '^';
1372 *bpout++ = ch - 128 + 64;
1373 }
1374 }
1375 } else {
1376 *bpout++ = '^'; 1297 *bpout++ = '^';
1377 *bpout++ = ch + 64; 1298 *bpout++ = ch + 64;
1299 } else if (ch < 127) {
1300 *bpout++ = ch;
1301 } else {
1302 *bpout++ = '^';
1303 *bpout++ = '?';
1378 } 1304 }
1305
1379 *bpout = '\0'; 1306 *bpout = '\0';
1380 return (const char *) buf; 1307 return (const char *) buf;
1381} 1308}
1382 1309
1383#ifdef TEST 1310#ifdef TEST
1384 1311
1385const char *applet_name = "stty"; 1312const char *bb_applet_name = "stty";
1386 1313
1387#endif 1314#endif
1388
1389/*
1390Local Variables:
1391c-file-style: "linux"
1392c-basic-offset: 4
1393tab-width: 4
1394End:
1395*/