aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2006-09-19 14:31:44 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2006-09-19 14:31:44 +0000
commitdebaf2fe024748cd559e86eba41bb503882bf9ff (patch)
tree9e6273aa7867a32f20a9db0420846d2271f81b0d
parent20b253d2d8e87587a3b9913ac76a49cdafa002ad (diff)
downloadbusybox-w32-debaf2fe024748cd559e86eba41bb503882bf9ff.tar.gz
busybox-w32-debaf2fe024748cd559e86eba41bb503882bf9ff.tar.bz2
busybox-w32-debaf2fe024748cd559e86eba41bb503882bf9ff.zip
stty: reorder code, reducing need in forward declarations.
added few missed bits of error checking for parameters.
-rw-r--r--coreutils/stty.c409
1 files changed, 198 insertions, 211 deletions
diff --git a/coreutils/stty.c b/coreutils/stty.c
index 7fa5feb0d..378e03e90 100644
--- a/coreutils/stty.c
+++ b/coreutils/stty.c
@@ -371,30 +371,74 @@ enum {
371 371
372/* The width of the screen, for output wrapping */ 372/* The width of the screen, for output wrapping */
373static int max_col; 373static int max_col;
374
375/* Current position, to know when to wrap */ 374/* Current position, to know when to wrap */
376static int current_col; 375static int current_col;
376static const char *device_name = bb_msg_standard_input;
377 377
378static const char * visible(unsigned int ch); 378/* Return a string that is the printable representation of character CH */
379static int recover_mode(const char *arg, struct termios *mode); 379/* Adapted from `cat' by Torbjorn Granlund */
380static int screen_columns(void); 380static const char *visible(unsigned int ch)
381static void set_mode(const struct mode_info *info, 381{
382 int reversed, struct termios *mode); 382 static char buf[10];
383static speed_t string_to_baud(const char *arg); 383 char *bpout = buf;
384static tcflag_t* mode_type_flag(unsigned type, const struct termios *mode);
385static void display_all(const struct termios *mode);
386static void display_changed(const struct termios *mode);
387static void display_recoverable(const struct termios *mode);
388static void display_speed(const struct termios *mode, int fancy);
389static void display_window_size(int fancy);
390static void sane_mode(struct termios *mode);
391static void set_control_char_or_die(const struct control_info *info,
392 const char *arg, struct termios *mode);
393static void set_speed(enum speed_setting type,
394 const char *arg, struct termios *mode);
395static void set_window_size(int rows, int cols);
396 384
397static const char *device_name = bb_msg_standard_input; 385 if (ch == _POSIX_VDISABLE)
386 return "<undef>";
387
388 if (ch >= 128) {
389 ch -= 128;
390 *bpout++ = 'M';
391 *bpout++ = '-';
392 }
393
394 if (ch < 32) {
395 *bpout++ = '^';
396 *bpout++ = ch + 64;
397 } else if (ch < 127) {
398 *bpout++ = ch;
399 } else {
400 *bpout++ = '^';
401 *bpout++ = '?';
402 }
403
404 *bpout = '\0';
405 return buf;
406}
407
408static tcflag_t *mode_type_flag(unsigned type, const struct termios *mode)
409{
410 static const unsigned char tcflag_offsets[] = {
411 offsetof(struct termios, c_cflag), /* control */
412 offsetof(struct termios, c_iflag), /* input */
413 offsetof(struct termios, c_oflag), /* output */
414 offsetof(struct termios, c_lflag), /* local */
415 };
416
417 if (type <= local) {
418 return (tcflag_t*) (((char*)mode) + tcflag_offsets[type]);
419 }
420 return NULL;
421}
422
423static speed_t string_to_baud_or_die(const char *arg)
424{
425 return tty_value_to_baud(bb_xparse_number(arg, 0));
426}
427
428static void set_speed_or_die(enum speed_setting type, const char *arg,
429 struct termios *mode)
430{
431 speed_t baud;
432
433 baud = string_to_baud_or_die(arg);
434
435 if (type != output_speed) { /* either input or both */
436 cfsetispeed(mode, baud);
437 }
438 if (type != input_speed) { /* either output or both */
439 cfsetospeed(mode, baud);
440 }
441}
398 442
399static ATTRIBUTE_NORETURN void perror_on_device_and_die(const char *fmt) 443static ATTRIBUTE_NORETURN void perror_on_device_and_die(const char *fmt)
400{ 444{
@@ -438,6 +482,103 @@ static void wrapf(const char *message, ...)
438 current_col = 0; 482 current_col = 0;
439} 483}
440 484
485#ifdef TIOCGWINSZ
486
487static int get_win_size(struct winsize *win)
488{
489 return ioctl(STDIN_FILENO, TIOCGWINSZ, (char *) win);
490}
491
492static void set_window_size(int rows, int cols)
493{
494 struct winsize win;
495
496 if (get_win_size(&win)) {
497 if (errno != EINVAL) {
498 perror_on_device("%s");
499 return;
500 }
501 memset(&win, 0, sizeof(win));
502 }
503
504 if (rows >= 0)
505 win.ws_row = rows;
506 if (cols >= 0)
507 win.ws_col = cols;
508
509# ifdef TIOCSSIZE
510 /* Alexander Dupuy <dupuy@cs.columbia.edu> wrote:
511 The following code deals with a bug in the SunOS 4.x (and 3.x?) kernel.
512 This comment from sys/ttold.h describes Sun's twisted logic - a better
513 test would have been (ts_lines > 64k || ts_cols > 64k || ts_cols == 0).
514 At any rate, the problem is gone in Solaris 2.x */
515
516 if (win.ws_row == 0 || win.ws_col == 0) {
517 struct ttysize ttysz;
518
519 ttysz.ts_lines = win.ws_row;
520 ttysz.ts_cols = win.ws_col;
521
522 win.ws_row = win.ws_col = 1;
523
524 if ((ioctl(STDIN_FILENO, TIOCSWINSZ, (char *) &win) != 0)
525 || (ioctl(STDIN_FILENO, TIOCSSIZE, (char *) &ttysz) != 0)) {
526 perror_on_device("%s");
527 }
528 return;
529 }
530# endif
531
532 if (ioctl(STDIN_FILENO, TIOCSWINSZ, (char *) &win))
533 perror_on_device("%s");
534}
535
536static void display_window_size(int fancy)
537{
538 const char *fmt_str = "%s\0%s: no size information for this device";
539 struct winsize win;
540
541 if (get_win_size(&win)) {
542 if ((errno != EINVAL) || ((fmt_str += 2), !fancy)) {
543 perror_on_device(fmt_str);
544 }
545 } else {
546 wrapf(fancy ? "rows %d; columns %d;" : "%d %d\n",
547 win.ws_row, win.ws_col);
548 }
549}
550
551#else /* !TIOCGWINSZ */
552
553static inline void display_window_size(int fancy) {}
554
555#endif /* !TIOCGWINSZ */
556
557static int screen_columns(void)
558{
559 int columns;
560 const char *s;
561
562#ifdef TIOCGWINSZ
563 struct winsize win;
564
565 /* With Solaris 2.[123], this ioctl fails and errno is set to
566 EINVAL for telnet (but not rlogin) sessions.
567 On ISC 3.0, it fails for the console and the serial port
568 (but it works for ptys).
569 It can also fail on any system when stdout isn't a tty.
570 In case of any failure, just use the default */
571 if (get_win_size(&win) == 0 && win.ws_col > 0)
572 return win.ws_col;
573#endif
574
575 columns = 80;
576 if ((s = getenv("COLUMNS"))) {
577 columns = atoi(s);
578 }
579 return columns;
580}
581
441static const struct suffix_mult stty_suffixes[] = { 582static const struct suffix_mult stty_suffixes[] = {
442 {"b", 512 }, 583 {"b", 512 },
443 {"k", 1024}, 584 {"k", 1024},
@@ -469,9 +610,9 @@ enum {
469 param_rows = 2 | 0x80, 610 param_rows = 2 | 0x80,
470 param_cols = 3 | 0x80, 611 param_cols = 3 | 0x80,
471 param_size = 4, 612 param_size = 4,
472 param_ispeed = 5 | 0x80, 613 param_speed = 5,
473 param_ospeed = 6 | 0x80, 614 param_ispeed = 6 | 0x80,
474 param_speed = 7, 615 param_ospeed = 7 | 0x80,
475}; 616};
476 617
477static int find_param(const char *name) 618static int find_param(const char *name)
@@ -485,13 +626,24 @@ static int find_param(const char *name)
485 if (streq(name, "columns")) return param_cols; 626 if (streq(name, "columns")) return param_cols;
486 if (streq(name, "size")) return param_size; 627 if (streq(name, "size")) return param_size;
487#endif 628#endif
629 if (streq(name, "speed")) return param_speed;
488 if (streq(name, "ispeed")) return param_ispeed; 630 if (streq(name, "ispeed")) return param_ispeed;
489 if (streq(name, "ospeed")) return param_ospeed; 631 if (streq(name, "ospeed")) return param_ospeed;
490 if (streq(name, "speed")) return param_speed;
491 return 0; 632 return 0;
492} 633}
493 634
494 635
636static int recover_mode(const char *arg, struct termios *mode);
637static void set_mode(const struct mode_info *info,
638 int reversed, struct termios *mode);
639static void display_all(const struct termios *mode);
640static void display_changed(const struct termios *mode);
641static void display_recoverable(const struct termios *mode);
642static void display_speed(const struct termios *mode, int fancy);
643static void sane_mode(struct termios *mode);
644static void set_control_char_or_die(const struct control_info *info,
645 const char *arg, struct termios *mode);
646
495int stty_main(int argc, char **argv) 647int stty_main(int argc, char **argv)
496{ 648{
497 struct termios mode; 649 struct termios mode;
@@ -602,13 +754,19 @@ end_option:
602 break; 754 break;
603 case param_size: 755 case param_size:
604#endif 756#endif
757 case param_speed:
758 break;
605 case param_ispeed: 759 case param_ispeed:
760 /* called for the side effect of xfunc death only */
761 set_speed_or_die(input_speed, argnext, &mode);
762 break;
606 case param_ospeed: 763 case param_ospeed:
607 case param_speed: 764 /* called for the side effect of xfunc death only */
765 set_speed_or_die(output_speed, argnext, &mode);
608 break; 766 break;
609 default: 767 default:
610 if (recover_mode(arg, &mode) == 1) break; 768 if (recover_mode(arg, &mode) == 1) break;
611 if (string_to_baud(arg) != (speed_t) -1) break; 769 if (string_to_baud_or_die(arg) != (speed_t) -1) break;
612 bb_error_msg_and_die("invalid argument '%s'", arg); 770 bb_error_msg_and_die("invalid argument '%s'", arg);
613 } 771 }
614 noargs = 0; 772 noargs = 0;
@@ -643,7 +801,6 @@ end_option:
643 801
644 if (verbose_output || recoverable_output || noargs) { 802 if (verbose_output || recoverable_output || noargs) {
645 max_col = screen_columns(); 803 max_col = screen_columns();
646 current_col = 0;
647 output_func(&mode); 804 output_func(&mode);
648 return EXIT_SUCCESS; 805 return EXIT_SUCCESS;
649 } 806 }
@@ -697,32 +854,31 @@ end_option:
697 break; 854 break;
698 case param_size: 855 case param_size:
699 max_col = screen_columns(); 856 max_col = screen_columns();
700 current_col = 0;
701 display_window_size(0); 857 display_window_size(0);
702 break; 858 break;
703 case param_rows: 859 case param_rows:
704 set_window_size((int) bb_xparse_number(argnext, stty_suffixes), -1); 860 set_window_size((int) bb_xparse_number(argnext, stty_suffixes), -1);
705 break; 861 break;
706#endif 862#endif
863 case param_speed:
864 max_col = screen_columns();
865 display_speed(&mode, 0);
866 break;
707 case param_ispeed: 867 case param_ispeed:
708 set_speed(input_speed, argnext, &mode); 868 set_speed_or_die(input_speed, argnext, &mode);
709 speed_was_set = 1; 869 speed_was_set = 1;
710 require_set_attr = 1; 870 require_set_attr = 1;
711 break; 871 break;
712 case param_ospeed: 872 case param_ospeed:
713 set_speed(output_speed, argnext, &mode); 873 set_speed_or_die(output_speed, argnext, &mode);
714 speed_was_set = 1; 874 speed_was_set = 1;
715 require_set_attr = 1; 875 require_set_attr = 1;
716 break; 876 break;
717 case param_speed:
718 max_col = screen_columns();
719 display_speed(&mode, 0);
720 break;
721 default: 877 default:
722 if (recover_mode(arg, &mode) == 1) 878 if (recover_mode(arg, &mode) == 1)
723 require_set_attr = 1; 879 require_set_attr = 1;
724 else /* true: if (string_to_baud(arg) != (speed_t) -1) */ { 880 else /* true: if (string_to_baud_or_die(arg) != (speed_t) -1) */ {
725 set_speed(both_speeds, arg, &mode); 881 set_speed_or_die(both_speeds, arg, &mode);
726 speed_was_set = 1; 882 speed_was_set = 1;
727 require_set_attr = 1; 883 require_set_attr = 1;
728 } /* else - impossible (caught in the first pass): 884 } /* else - impossible (caught in the first pass):
@@ -805,8 +961,8 @@ end_option:
805#define ECHOKE 0 961#define ECHOKE 0
806#endif 962#endif
807 963
808static void 964static void set_mode(const struct mode_info *info, int reversed,
809set_mode(const struct mode_info *info, int reversed, struct termios *mode) 965 struct termios *mode)
810{ 966{
811 tcflag_t *bitsp; 967 tcflag_t *bitsp;
812 968
@@ -932,9 +1088,8 @@ set_mode(const struct mode_info *info, int reversed, struct termios *mode)
932 } 1088 }
933} 1089}
934 1090
935static void 1091static void set_control_char_or_die(const struct control_info *info,
936set_control_char_or_die(const struct control_info *info, const char *arg, 1092 const char *arg, struct termios *mode)
937 struct termios *mode)
938{ 1093{
939 unsigned char value; 1094 unsigned char value;
940 1095
@@ -945,143 +1100,14 @@ set_control_char_or_die(const struct control_info *info, const char *arg,
945 else if (streq(arg, "^-") || streq(arg, "undef")) 1100 else if (streq(arg, "^-") || streq(arg, "undef"))
946 value = _POSIX_VDISABLE; 1101 value = _POSIX_VDISABLE;
947 else if (arg[0] == '^') { /* Ignore any trailing junk (^Cjunk) */ 1102 else if (arg[0] == '^') { /* Ignore any trailing junk (^Cjunk) */
1103 value = arg[1] & 0x1f; /* Non-letters get weird results */
948 if (arg[1] == '?') 1104 if (arg[1] == '?')
949 value = 127; 1105 value = 127;
950 else
951 value = arg[1] & 0x1f; /* Non-letters get weird results */
952 } else 1106 } else
953 value = bb_xparse_number(arg, stty_suffixes); 1107 value = bb_xparse_number(arg, stty_suffixes);
954 mode->c_cc[info->offset] = value; 1108 mode->c_cc[info->offset] = value;
955} 1109}
956 1110
957static void
958set_speed(enum speed_setting type, const char *arg, struct termios *mode)
959{
960 speed_t baud;
961
962 baud = string_to_baud(arg);
963
964 if (type != output_speed) { /* either input or both */
965 cfsetispeed(mode, baud);
966 }
967 if (type != input_speed) { /* either output or both */
968 cfsetospeed(mode, baud);
969 }
970}
971
972#ifdef TIOCGWINSZ
973
974static int get_win_size(struct winsize *win)
975{
976 return ioctl(STDIN_FILENO, TIOCGWINSZ, (char *) win);
977}
978
979static void
980set_window_size(int rows, int cols)
981{
982 struct winsize win;
983
984 if (get_win_size(&win)) {
985 if (errno != EINVAL) {
986 perror_on_device("%s");
987 return;
988 }
989 memset(&win, 0, sizeof(win));
990 }
991
992 if (rows >= 0)
993 win.ws_row = rows;
994 if (cols >= 0)
995 win.ws_col = cols;
996
997# ifdef TIOCSSIZE
998 /* Alexander Dupuy <dupuy@cs.columbia.edu> wrote:
999 The following code deals with a bug in the SunOS 4.x (and 3.x?) kernel.
1000 This comment from sys/ttold.h describes Sun's twisted logic - a better
1001 test would have been (ts_lines > 64k || ts_cols > 64k || ts_cols == 0).
1002 At any rate, the problem is gone in Solaris 2.x */
1003
1004 if (win.ws_row == 0 || win.ws_col == 0) {
1005 struct ttysize ttysz;
1006
1007 ttysz.ts_lines = win.ws_row;
1008 ttysz.ts_cols = win.ws_col;
1009
1010 win.ws_row = win.ws_col = 1;
1011
1012 if ((ioctl(STDIN_FILENO, TIOCSWINSZ, (char *) &win) != 0)
1013 || (ioctl(STDIN_FILENO, TIOCSSIZE, (char *) &ttysz) != 0)) {
1014 perror_on_device("%s");
1015 }
1016 return;
1017 }
1018# endif
1019
1020 if (ioctl(STDIN_FILENO, TIOCSWINSZ, (char *) &win))
1021 perror_on_device("%s");
1022}
1023
1024static void display_window_size(int fancy)
1025{
1026 const char *fmt_str = "%s\0%s: no size information for this device";
1027 struct winsize win;
1028
1029 if (get_win_size(&win)) {
1030 if ((errno != EINVAL) || ((fmt_str += 2), !fancy)) {
1031 perror_on_device(fmt_str);
1032 }
1033 } else {
1034 wrapf(fancy ? "rows %d; columns %d;" : "%d %d\n",
1035 win.ws_row, win.ws_col);
1036 }
1037}
1038
1039#else /* !TIOCGWINSZ */
1040
1041static inline void display_window_size(int fancy) {}
1042
1043#endif /* !TIOCGWINSZ */
1044
1045static int screen_columns(void)
1046{
1047 int columns;
1048 const char *s;
1049
1050#ifdef TIOCGWINSZ
1051 struct winsize win;
1052
1053 /* With Solaris 2.[123], this ioctl fails and errno is set to
1054 EINVAL for telnet (but not rlogin) sessions.
1055 On ISC 3.0, it fails for the console and the serial port
1056 (but it works for ptys).
1057 It can also fail on any system when stdout isn't a tty.
1058 In case of any failure, just use the default */
1059 if (get_win_size(&win) == 0 && win.ws_col > 0)
1060 return win.ws_col;
1061#endif
1062
1063 columns = 80;
1064 if ((s = getenv("COLUMNS"))) {
1065 columns = atoi(s);
1066 }
1067 return columns;
1068}
1069
1070static tcflag_t *mode_type_flag(unsigned type, const struct termios *mode)
1071{
1072 static const unsigned char tcflag_offsets[] = {
1073 offsetof(struct termios, c_cflag), /* control */
1074 offsetof(struct termios, c_iflag), /* input */
1075 offsetof(struct termios, c_oflag), /* output */
1076 offsetof(struct termios, c_lflag), /* local */
1077 };
1078
1079 if (type <= local) {
1080 return (tcflag_t*) (((char*)mode) + tcflag_offsets[type]);
1081 }
1082 return NULL;
1083}
1084
1085static void display_changed(const struct termios *mode) 1111static void display_changed(const struct termios *mode)
1086{ 1112{
1087 int i; 1113 int i;
@@ -1140,8 +1166,7 @@ static void display_changed(const struct termios *mode)
1140 if (current_col) wrapf("\n"); 1166 if (current_col) wrapf("\n");
1141} 1167}
1142 1168
1143static void 1169static void display_all(const struct termios *mode)
1144display_all(const struct termios *mode)
1145{ 1170{
1146 int i; 1171 int i;
1147 tcflag_t *bitsp; 1172 tcflag_t *bitsp;
@@ -1214,7 +1239,6 @@ static void display_speed(const struct termios *mode, int fancy)
1214static void display_recoverable(const struct termios *mode) 1239static void display_recoverable(const struct termios *mode)
1215{ 1240{
1216 int i; 1241 int i;
1217
1218 printf("%lx:%lx:%lx:%lx", 1242 printf("%lx:%lx:%lx:%lx",
1219 (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag, 1243 (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
1220 (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag); 1244 (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
@@ -1253,11 +1277,6 @@ static int recover_mode(const char *arg, struct termios *mode)
1253 return 1; 1277 return 1;
1254} 1278}
1255 1279
1256static speed_t string_to_baud(const char *arg)
1257{
1258 return tty_value_to_baud(bb_xparse_number(arg, 0));
1259}
1260
1261static void sane_mode(struct termios *mode) 1280static void sane_mode(struct termios *mode)
1262{ 1281{
1263 int i; 1282 int i;
@@ -1283,35 +1302,3 @@ static void sane_mode(struct termios *mode)
1283 } 1302 }
1284 } 1303 }
1285} 1304}
1286
1287/* Return a string that is the printable representation of character CH */
1288/* Adapted from `cat' by Torbjorn Granlund */
1289
1290static const char *visible(unsigned int ch)
1291{
1292 static char buf[10];
1293 char *bpout = buf;
1294
1295 if (ch == _POSIX_VDISABLE) {
1296 return "<undef>";
1297 }
1298
1299 if (ch >= 128) {
1300 ch -= 128;
1301 *bpout++ = 'M';
1302 *bpout++ = '-';
1303 }
1304
1305 if (ch < 32) {
1306 *bpout++ = '^';
1307 *bpout++ = ch + 64;
1308 } else if (ch < 127) {
1309 *bpout++ = ch;
1310 } else {
1311 *bpout++ = '^';
1312 *bpout++ = '?';
1313 }
1314
1315 *bpout = '\0';
1316 return buf;
1317}