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 is contained in:
Paul Fox 2005-09-07 16:56:02 +00:00
parent a70aa86e25
commit 02eb934b0f
2 changed files with 111 additions and 61 deletions

View File

@ -53,16 +53,22 @@ config CONFIG_ASH_JOB_CONTROL
help help
Enable job control in the ash shell. Enable job control in the ash shell.
config CONFIG_ASH_TIMEOUT config CONFIG_ASH_READ_NCHARS
bool " Enable read timeout support." bool " Enable 'read -n N' and 'read -s' support"
default n default n
depends on CONFIG_ASH_JOB_CONTROL depends on CONFIG_ASH
help 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 config CONFIG_ASH_READ_TIMEOUT
if no character input is read from the terminal within a set bool " Enable 'read -t S' support."
number of seconds. 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 config CONFIG_ASH_ALIAS
bool " Enable alias support" bool " Enable alias support"

View File

@ -105,7 +105,7 @@
#undef JOBS #undef JOBS
#endif #endif
#if JOBS #if JOBS || defined(CONFIG_ASH_READ_NCHARS)
#include <termios.h> #include <termios.h>
#endif #endif
@ -12598,34 +12598,80 @@ readcmd(int argc, char **argv)
char *prompt; char *prompt;
const char *ifs; const char *ifs;
char *p; 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 startword;
int status; int status;
int i; 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; rflag = 0;
prompt = NULL; prompt = NULL;
#if defined(CONFIG_ASH_TIMEOUT) #if defined(CONFIG_ASH_READ_NCHARS) && defined(CONFIG_ASH_READ_TIMEOUT)
timeout = 0; 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') while ((i = nextopt("p:rt:")) != '\0')
#else #else
while ((i = nextopt("p:r")) != '\0') while ((i = nextopt("p:r")) != '\0')
#endif #endif
{ {
if (i == 'p') switch(i) {
case 'p':
prompt = optionarg; prompt = optionarg;
else if (i == 'r') break;
rflag = 1; #if defined(CONFIG_ASH_READ_NCHARS)
#if defined(CONFIG_ASH_TIMEOUT) case 'n':
else nchars = strtol(optionarg, &p, 10);
timeout = atoi(optionarg); if (*p)
error("invalid count");
nch_flag = (nchars > 0);
break;
case 's':
silent = 1;
break;
#endif #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)) { if (prompt && isatty(0)) {
out2str(prompt); out2str(prompt);
@ -12634,49 +12680,42 @@ readcmd(int argc, char **argv)
error("arg count"); error("arg count");
if ((ifs = bltinlookup("IFS")) == NULL) if ((ifs = bltinlookup("IFS")) == NULL)
ifs = defifs; ifs = defifs;
#if defined(CONFIG_ASH_TIMEOUT) #if defined(CONFIG_ASH_READ_NCHARS)
c = 0; 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);
}
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);
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;
}
}
#endif #endif
status = 0; status = 0;
startword = 1; startword = 1;
backslash = 0; backslash = 0;
STARTSTACKSTR(p); STARTSTACKSTR(p);
#if defined(CONFIG_ASH_TIMEOUT) #if defined(CONFIG_ASH_READ_NCHARS)
if (timeout > 0) { while (!nch_flag || nchars--)
tcgetattr(0, &tty);
old_tty = tty;
/* cfmakeraw(...) disables too much; we just do this instead. */
tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
tcsetattr(0, TCSANOW, &tty);
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... */
}
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;)
#else #else
for (;;) for (;;)
#endif #endif
@ -12714,6 +12753,11 @@ put:
STPUTC(c, p); STPUTC(c, p);
} }
} }
#if defined(CONFIG_ASH_READ_NCHARS)
if (nch_flag || silent)
tcsetattr(0, TCSANOW, &old_tty);
#endif
STACKSTRNUL(p); STACKSTRNUL(p);
/* Remove trailing blanks */ /* Remove trailing blanks */
while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL) while ((char *)stackblock() <= --p && strchr(ifs, *p) != NULL)