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.
This commit was genuinely broken at the time (not related to our build system): scripts/config/mkconfigs.c (2005-08-01 - 2006-10-05 arasi) uretilen bbconfigopts.h icine .config satirlarini kacissiz, ham newline'larla gömüyordu - gecerli C degildi, busybox'un kendi bb_mkdep araci bile parse edemiyordu (7d219aab7 ile duzeltildi, mkconfigs shell scripte cevrildi)
No binary (build failed)
—
(log yok)
| @@ -53,16 +53,22 @@ config CONFIG_ASH_JOB_CONTROL | |
| help | |
| Enable job control in the ash shell. | |
| - | config CONFIG_ASH_TIMEOUT |
| - | bool " Enable read timeout support." |
| + | config CONFIG_ASH_READ_NCHARS |
| + | bool " Enable 'read -n N' and 'read -s' support" |
| default n | |
| - | depends on CONFIG_ASH_JOB_CONTROL |
| + | depends on CONFIG_ASH |
| help | |
| - | This option provides read -t <seconds> support. |
| + | 'read -n N' will return a value after N characters have been read. |
| + | 'read -s' will read without echoing the user's input. |
| - | read builtin which allows the function to pass control back |
| - | if no character input is read from the terminal within a set |
| - | number of seconds. |
| + | config CONFIG_ASH_READ_TIMEOUT |
| + | bool " Enable 'read -t S' support." |
| + | default n |
| + | depends on CONFIG_ASH |
| + | help |
| + | 'read -t S' will return a value after S seconds have passed. |
| + | This implementation will allow fractional seconds, expressed |
| + | as a decimal fraction, e.g. 'read -t 2.5 foo'. |
| config CONFIG_ASH_ALIAS | |
| bool " Enable alias support" | |
| @@ -105,7 +105,7 @@ | |
| #undef JOBS | |
| #endif | |
| - | #if JOBS |
| + | #if JOBS || defined(CONFIG_ASH_READ_NCHARS) |
| #include <termios.h> | |
| #endif | |
| @@ -12598,34 +12598,80 @@ readcmd(int argc, char **argv) | |
| char *prompt; | |
| const char *ifs; | |
| char *p; | |
| - | #if defined(CONFIG_ASH_TIMEOUT) |
| - | fd_set set; |
| - | int timeout; |
| - | struct timeval timeout_struct; |
| - | struct termios tty, old_tty; |
| - | #endif |
| int startword; | |
| int status; | |
| int i; | |
| + | #if defined(CONFIG_ASH_READ_NCHARS) |
| + | int nch_flag = 0; |
| + | int nchars = 0; |
| + | int silent = 0; |
| + | struct termios tty, old_tty; |
| + | #endif |
| + | #if defined(CONFIG_ASH_READ_TIMEOUT) |
| + | fd_set set; |
| + | struct timeval ts; |
| + | |
| + | ts.tv_sec = ts.tv_usec = 0; |
| + | #endif |
| rflag = 0; | |
| prompt = NULL; | |
| - | #if defined(CONFIG_ASH_TIMEOUT) |
| - | timeout = 0; |
| - | |
| + | #if defined(CONFIG_ASH_READ_NCHARS) && defined(CONFIG_ASH_READ_TIMEOUT) |
| + | while ((i = nextopt("p:rt:n:s")) != '\0') |
| + | #elif defined(CONFIG_ASH_READ_NCHARS) |
| + | while ((i = nextopt("p:rn:s")) != '\0') |
| + | #elif defined(CONFIG_ASH_READ_TIMEOUT) |
| while ((i = nextopt("p:rt:")) != '\0') | |
| #else | |
| while ((i = nextopt("p:r")) != '\0') | |
| #endif | |
| { | |
| - | if (i == 'p') |
| + | switch(i) { |
| + | case 'p': |
| prompt = optionarg; | |
| - | else if (i == 'r') |
| - | rflag = 1; |
| - | #if defined(CONFIG_ASH_TIMEOUT) |
| - | else |
| - | timeout = atoi(optionarg); |
| + | break; |
| + | #if defined(CONFIG_ASH_READ_NCHARS) |
| + | case 'n': |
| + | nchars = strtol(optionarg, &p, 10); |
| + | if (*p) |
| + | error("invalid count"); |
| + | nch_flag = (nchars > 0); |
| + | break; |
| + | case 's': |
| + | silent = 1; |
| + | break; |
| #endif | |
| + | #if defined(CONFIG_ASH_READ_TIMEOUT) |
| + | case 't': |
| + | ts.tv_sec = strtol(optionarg, &p, 10); |
| + | ts.tv_usec = 0; |
| + | if (*p == '.') { |
| + | char *p2; |
| + | if (*++p) { |
| + | int scale; |
| + | ts.tv_usec = strtol(p, &p2, 10); |
| + | if (*p2) |
| + | error("invalid timeout"); |
| + | scale = p2 - p; |
| + | /* normalize to usec */ |
| + | if (scale > 6) |
| + | error("invalid timeout"); |
| + | while (scale++ < 6) |
| + | ts.tv_usec *= 10; |
| + | } |
| + | } else if (*p) { |
| + | error("invalid timeout"); |
| + | } |
| + | if ( ! ts.tv_sec && ! ts.tv_usec) |
| + | error("invalid timeout"); |
| + | break; |
| + | #endif |
| + | case 'r': |
| + | rflag = 1; |
| + | break; |
| + | default: |
| + | break; |
| + | } |
| } | |
| if (prompt && isatty(0)) { | |
| out2str(prompt); | |
| @@ -12634,49 +12680,42 @@ readcmd(int argc, char **argv) | |
| error("arg count"); | |
| if ((ifs = bltinlookup("IFS")) == NULL) | |
| ifs = defifs; | |
| - | #if defined(CONFIG_ASH_TIMEOUT) |
| - | c = 0; |
| - | #endif |
| - | status = 0; |
| - | startword = 1; |
| - | backslash = 0; |
| - | |
| - | STARTSTACKSTR(p); |
| - | #if defined(CONFIG_ASH_TIMEOUT) |
| - | if (timeout > 0) { |
| + | #if defined(CONFIG_ASH_READ_NCHARS) |
| + | if (nch_flag || silent) { |
| tcgetattr(0, &tty); | |
| old_tty = tty; | |
| + | if (nch_flag) { |
| + | tty.c_lflag &= ~ICANON; |
| + | tty.c_cc[VMIN] = nchars; |
| + | } |
| + | if (silent) { |
| + | tty.c_lflag &= ~(ECHO|ECHOK|ECHONL); |
| - | /* cfmakeraw(...) disables too much; we just do this instead. */ |
| - | tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN); |
| + | } |
| tcsetattr(0, TCSANOW, &tty); | |
| - | |
| + | } |
| + | #endif |
| + | #if defined(CONFIG_ASH_READ_TIMEOUT) |
| + | if (ts.tv_sec || ts.tv_usec) { |
| FD_ZERO (&set); | |
| FD_SET (0, &set); | |
| - | timeout_struct.tv_sec = timeout; |
| - | timeout_struct.tv_usec = 0; |
| - | |
| - | if ((i = select (FD_SETSIZE, &set, NULL, NULL, &timeout_struct)) == 1) |
| - | { |
| - | read(0, &c, 1); |
| - | if(c == '\n' || c == 4) /* Handle newlines and EOF */ |
| - | i = 0; /* Don't read further... */ |
| - | else |
| - | STPUTC(c, p); /* Keep reading... */ |
| + | i = select (FD_SETSIZE, &set, NULL, NULL, &ts); |
| + | if (!i) { |
| + | #if defined(CONFIG_ASH_READ_NCHARS) |
| + | if (nch_flag) |
| + | tcsetattr(0, TCSANOW, &old_tty); |
| + | #endif |
| + | return 1; |
| } | |
| - | tcsetattr(0, TCSANOW, &old_tty); |
| - | |
| - | /* Echo the character so the user knows it was read... |
| - | Yes, this can be done by setting the ECHO flag, but that |
| - | echoes ^D and other control characters at this state */ |
| - | if(c != 0) |
| - | write(1, &c, 1); |
| - | |
| - | } else |
| - | i = 1; |
| - | |
| - | for (;i == 1;) |
| + | } |
| + | #endif |
| + | status = 0; |
| + | startword = 1; |
| + | backslash = 0; |
| + | STARTSTACKSTR(p); |
| + | #if defined(CONFIG_ASH_READ_NCHARS) |
| + | while (!nch_flag || nchars--) |
| #else | |
| for (;;) | |
| #endif | |
| @@ -12714,6 +12753,11 @@ put: | |
| STPUTC(c, p); | |
| } | |
| } | |
| + | #if defined(CONFIG_ASH_READ_NCHARS) |
| + | if (nch_flag || silent) |
| + | tcsetattr(0, TCSANOW, &old_tty); |
| + | #endif |
| + | |
| STACKSTRNUL(p); | |
| /* Remove trailing blanks */ | |
| while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL) | |