diff options
author | Paul Fox <pgf@brightstareng.com> | 2005-09-07 16:56:02 +0000 |
---|---|---|
committer | Paul Fox <pgf@brightstareng.com> | 2005-09-07 16:56:02 +0000 |
commit | 02eb934b0f7120cfb783536d6b27f7e092fb991b (patch) | |
tree | 1e877e7458d4d84d4e26ebcf92435021c23872d1 | |
parent | a70aa86e25bd7969e846aff64206458b56b66c2c (diff) | |
download | busybox-w32-02eb934b0f7120cfb783536d6b27f7e092fb991b.tar.gz busybox-w32-02eb934b0f7120cfb783536d6b27f7e092fb991b.tar.bz2 busybox-w32-02eb934b0f7120cfb783536d6b27f7e092fb991b.zip |
committing:
Summary 0000242: ash: read -t broken
this also implements -n and -s options to read. (they're configured
together because most of their code is in common, and separating them
seemed silly.
-rw-r--r-- | shell/Config.in | 20 | ||||
-rw-r--r-- | shell/ash.c | 146 |
2 files changed, 108 insertions, 58 deletions
diff --git a/shell/Config.in b/shell/Config.in index f9fb8488f..eb4616672 100644 --- a/shell/Config.in +++ b/shell/Config.in | |||
@@ -53,16 +53,22 @@ config CONFIG_ASH_JOB_CONTROL | |||
53 | help | 53 | help |
54 | Enable job control in the ash shell. | 54 | Enable job control in the ash shell. |
55 | 55 | ||
56 | config CONFIG_ASH_TIMEOUT | 56 | config CONFIG_ASH_READ_NCHARS |
57 | bool " Enable read timeout support." | 57 | bool " Enable 'read -n N' and 'read -s' support" |
58 | default n | 58 | default n |
59 | depends on CONFIG_ASH_JOB_CONTROL | 59 | depends on CONFIG_ASH |
60 | help | 60 | help |
61 | This option provides read -t <seconds> support. | 61 | 'read -n N' will return a value after N characters have been read. |
62 | 'read -s' will read without echoing the user's input. | ||
62 | 63 | ||
63 | read builtin which allows the function to pass control back | 64 | config CONFIG_ASH_READ_TIMEOUT |
64 | if no character input is read from the terminal within a set | 65 | bool " Enable 'read -t S' support." |
65 | number of seconds. | 66 | default n |
67 | depends on CONFIG_ASH | ||
68 | help | ||
69 | 'read -t S' will return a value after S seconds have passed. | ||
70 | This implementation will allow fractional seconds, expressed | ||
71 | as a decimal fraction, e.g. 'read -t 2.5 foo'. | ||
66 | 72 | ||
67 | config CONFIG_ASH_ALIAS | 73 | config CONFIG_ASH_ALIAS |
68 | bool " Enable alias support" | 74 | bool " Enable alias support" |
diff --git a/shell/ash.c b/shell/ash.c index 5f6f7c6d3..7271535aa 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -105,7 +105,7 @@ | |||
105 | #undef JOBS | 105 | #undef JOBS |
106 | #endif | 106 | #endif |
107 | 107 | ||
108 | #if JOBS | 108 | #if JOBS || defined(CONFIG_ASH_READ_NCHARS) |
109 | #include <termios.h> | 109 | #include <termios.h> |
110 | #endif | 110 | #endif |
111 | 111 | ||
@@ -12598,34 +12598,80 @@ readcmd(int argc, char **argv) | |||
12598 | char *prompt; | 12598 | char *prompt; |
12599 | const char *ifs; | 12599 | const char *ifs; |
12600 | char *p; | 12600 | char *p; |
12601 | #if defined(CONFIG_ASH_TIMEOUT) | ||
12602 | fd_set set; | ||
12603 | int timeout; | ||
12604 | struct timeval timeout_struct; | ||
12605 | struct termios tty, old_tty; | ||
12606 | #endif | ||
12607 | int startword; | 12601 | int startword; |
12608 | int status; | 12602 | int status; |
12609 | int i; | 12603 | int i; |
12604 | #if defined(CONFIG_ASH_READ_NCHARS) | ||
12605 | int nch_flag = 0; | ||
12606 | int nchars = 0; | ||
12607 | int silent = 0; | ||
12608 | struct termios tty, old_tty; | ||
12609 | #endif | ||
12610 | #if defined(CONFIG_ASH_READ_TIMEOUT) | ||
12611 | fd_set set; | ||
12612 | struct timeval ts; | ||
12613 | |||
12614 | ts.tv_sec = ts.tv_usec = 0; | ||
12615 | #endif | ||
12610 | 12616 | ||
12611 | rflag = 0; | 12617 | rflag = 0; |
12612 | prompt = NULL; | 12618 | prompt = NULL; |
12613 | #if defined(CONFIG_ASH_TIMEOUT) | 12619 | #if defined(CONFIG_ASH_READ_NCHARS) && defined(CONFIG_ASH_READ_TIMEOUT) |
12614 | timeout = 0; | 12620 | while ((i = nextopt("p:rt:n:s")) != '\0') |
12615 | 12621 | #elif defined(CONFIG_ASH_READ_NCHARS) | |
12622 | while ((i = nextopt("p:rn:s")) != '\0') | ||
12623 | #elif defined(CONFIG_ASH_READ_TIMEOUT) | ||
12616 | while ((i = nextopt("p:rt:")) != '\0') | 12624 | while ((i = nextopt("p:rt:")) != '\0') |
12617 | #else | 12625 | #else |
12618 | while ((i = nextopt("p:r")) != '\0') | 12626 | while ((i = nextopt("p:r")) != '\0') |
12619 | #endif | 12627 | #endif |
12620 | { | 12628 | { |
12621 | if (i == 'p') | 12629 | switch(i) { |
12630 | case 'p': | ||
12622 | prompt = optionarg; | 12631 | prompt = optionarg; |
12623 | else if (i == 'r') | 12632 | break; |
12624 | rflag = 1; | 12633 | #if defined(CONFIG_ASH_READ_NCHARS) |
12625 | #if defined(CONFIG_ASH_TIMEOUT) | 12634 | case 'n': |
12626 | else | 12635 | nchars = strtol(optionarg, &p, 10); |
12627 | timeout = atoi(optionarg); | 12636 | if (*p) |
12637 | error("invalid count"); | ||
12638 | nch_flag = (nchars > 0); | ||
12639 | break; | ||
12640 | case 's': | ||
12641 | silent = 1; | ||
12642 | break; | ||
12628 | #endif | 12643 | #endif |
12644 | #if defined(CONFIG_ASH_READ_TIMEOUT) | ||
12645 | case 't': | ||
12646 | ts.tv_sec = strtol(optionarg, &p, 10); | ||
12647 | ts.tv_usec = 0; | ||
12648 | if (*p == '.') { | ||
12649 | char *p2; | ||
12650 | if (*++p) { | ||
12651 | int scale; | ||
12652 | ts.tv_usec = strtol(p, &p2, 10); | ||
12653 | if (*p2) | ||
12654 | error("invalid timeout"); | ||
12655 | scale = p2 - p; | ||
12656 | /* normalize to usec */ | ||
12657 | if (scale > 6) | ||
12658 | error("invalid timeout"); | ||
12659 | while (scale++ < 6) | ||
12660 | ts.tv_usec *= 10; | ||
12661 | } | ||
12662 | } else if (*p) { | ||
12663 | error("invalid timeout"); | ||
12664 | } | ||
12665 | if ( ! ts.tv_sec && ! ts.tv_usec) | ||
12666 | error("invalid timeout"); | ||
12667 | break; | ||
12668 | #endif | ||
12669 | case 'r': | ||
12670 | rflag = 1; | ||
12671 | break; | ||
12672 | default: | ||
12673 | break; | ||
12674 | } | ||
12629 | } | 12675 | } |
12630 | if (prompt && isatty(0)) { | 12676 | if (prompt && isatty(0)) { |
12631 | out2str(prompt); | 12677 | out2str(prompt); |
@@ -12634,49 +12680,42 @@ readcmd(int argc, char **argv) | |||
12634 | error("arg count"); | 12680 | error("arg count"); |
12635 | if ((ifs = bltinlookup("IFS")) == NULL) | 12681 | if ((ifs = bltinlookup("IFS")) == NULL) |
12636 | ifs = defifs; | 12682 | ifs = defifs; |
12637 | #if defined(CONFIG_ASH_TIMEOUT) | 12683 | #if defined(CONFIG_ASH_READ_NCHARS) |
12638 | c = 0; | 12684 | if (nch_flag || silent) { |
12639 | #endif | ||
12640 | status = 0; | ||
12641 | startword = 1; | ||
12642 | backslash = 0; | ||
12643 | |||
12644 | STARTSTACKSTR(p); | ||
12645 | #if defined(CONFIG_ASH_TIMEOUT) | ||
12646 | if (timeout > 0) { | ||
12647 | tcgetattr(0, &tty); | 12685 | tcgetattr(0, &tty); |
12648 | old_tty = tty; | 12686 | old_tty = tty; |
12687 | if (nch_flag) { | ||
12688 | tty.c_lflag &= ~ICANON; | ||
12689 | tty.c_cc[VMIN] = nchars; | ||
12690 | } | ||
12691 | if (silent) { | ||
12692 | tty.c_lflag &= ~(ECHO|ECHOK|ECHONL); | ||
12649 | 12693 | ||
12650 | /* cfmakeraw(...) disables too much; we just do this instead. */ | 12694 | } |
12651 | tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN); | ||
12652 | tcsetattr(0, TCSANOW, &tty); | 12695 | tcsetattr(0, TCSANOW, &tty); |
12653 | 12696 | } | |
12697 | #endif | ||
12698 | #if defined(CONFIG_ASH_READ_TIMEOUT) | ||
12699 | if (ts.tv_sec || ts.tv_usec) { | ||
12654 | FD_ZERO (&set); | 12700 | FD_ZERO (&set); |
12655 | FD_SET (0, &set); | 12701 | FD_SET (0, &set); |
12656 | 12702 | ||
12657 | timeout_struct.tv_sec = timeout; | 12703 | i = select (FD_SETSIZE, &set, NULL, NULL, &ts); |
12658 | timeout_struct.tv_usec = 0; | 12704 | if (!i) { |
12659 | 12705 | #if defined(CONFIG_ASH_READ_NCHARS) | |
12660 | if ((i = select (FD_SETSIZE, &set, NULL, NULL, &timeout_struct)) == 1) | 12706 | if (nch_flag) |
12661 | { | 12707 | tcsetattr(0, TCSANOW, &old_tty); |
12662 | read(0, &c, 1); | 12708 | #endif |
12663 | if(c == '\n' || c == 4) /* Handle newlines and EOF */ | 12709 | return 1; |
12664 | i = 0; /* Don't read further... */ | ||
12665 | else | ||
12666 | STPUTC(c, p); /* Keep reading... */ | ||
12667 | } | 12710 | } |
12668 | tcsetattr(0, TCSANOW, &old_tty); | 12711 | } |
12669 | 12712 | #endif | |
12670 | /* Echo the character so the user knows it was read... | 12713 | status = 0; |
12671 | Yes, this can be done by setting the ECHO flag, but that | 12714 | startword = 1; |
12672 | echoes ^D and other control characters at this state */ | 12715 | backslash = 0; |
12673 | if(c != 0) | 12716 | STARTSTACKSTR(p); |
12674 | write(1, &c, 1); | 12717 | #if defined(CONFIG_ASH_READ_NCHARS) |
12675 | 12718 | while (!nch_flag || nchars--) | |
12676 | } else | ||
12677 | i = 1; | ||
12678 | |||
12679 | for (;i == 1;) | ||
12680 | #else | 12719 | #else |
12681 | for (;;) | 12720 | for (;;) |
12682 | #endif | 12721 | #endif |
@@ -12714,6 +12753,11 @@ put: | |||
12714 | STPUTC(c, p); | 12753 | STPUTC(c, p); |
12715 | } | 12754 | } |
12716 | } | 12755 | } |
12756 | #if defined(CONFIG_ASH_READ_NCHARS) | ||
12757 | if (nch_flag || silent) | ||
12758 | tcsetattr(0, TCSANOW, &old_tty); | ||
12759 | #endif | ||
12760 | |||
12717 | STACKSTRNUL(p); | 12761 | STACKSTRNUL(p); |
12718 | /* Remove trailing blanks */ | 12762 | /* Remove trailing blanks */ |
12719 | while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL) | 12763 | while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL) |