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 /shell | |
| 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.
Diffstat (limited to 'shell')
| -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) |
