aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-03-25 00:07:12 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-03-25 00:07:12 +0000
commit59f351ccda4c66785b864086bf23868768ca6f61 (patch)
treef57eab03adfd44de984d03190a0e19dd5ca66f05 /shell
parentf39653e3060427b4a48f70e486d7c71729bffd96 (diff)
downloadbusybox-w32-59f351ccda4c66785b864086bf23868768ca6f61.tar.gz
busybox-w32-59f351ccda4c66785b864086bf23868768ca6f61.tar.bz2
busybox-w32-59f351ccda4c66785b864086bf23868768ca6f61.zip
ash: add read -u; fix read -t and read -n; add testsuite entries.
Diffstat (limited to 'shell')
-rw-r--r--shell/ash.c122
-rw-r--r--shell/ash_test/ash-read/read_n.right3
-rwxr-xr-xshell/ash_test/ash-read/read_n.tests3
-rw-r--r--shell/ash_test/ash-read/read_r.right2
-rwxr-xr-xshell/ash_test/ash-read/read_r.tests2
-rw-r--r--shell/ash_test/ash-read/read_t.right4
-rwxr-xr-xshell/ash_test/ash-read/read_t.tests10
7 files changed, 91 insertions, 55 deletions
diff --git a/shell/ash.c b/shell/ash.c
index d9ce202fd..2b6133d20 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -11672,10 +11672,18 @@ typedef enum __rlimit_resource rlim_t;
11672#endif 11672#endif
11673 11673
11674/* 11674/*
11675 * The read builtin. The -e option causes backslashes to escape the 11675 * The read builtin. Options:
11676 * following character. 11676 * -r Do not interpret '\' specially
11677 * 11677 * -s Turn off echo (tty only)
11678 * -n NCHARS Read NCHARS max
11679 * -p PROMPT Display PROMPT on stderr (if input is from tty)
11680 * -t SECONDS Timeout after SECONDS (tty or pipe only)
11681 * -u FD Read from given FD instead of fd 0
11678 * This uses unbuffered input, which may be avoidable in some cases. 11682 * This uses unbuffered input, which may be avoidable in some cases.
11683 * TODO: bash also has:
11684 * -a ARRAY Read into array[0],[1],etc
11685 * -d DELIM End on DELIM char, not newline
11686 * -e Use line editing (tty only)
11679 */ 11687 */
11680static int 11688static int
11681readcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) 11689readcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
@@ -11690,31 +11698,23 @@ readcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
11690 int startword; 11698 int startword;
11691 int status; 11699 int status;
11692 int i; 11700 int i;
11701 int fd = 0;
11693#if ENABLE_ASH_READ_NCHARS 11702#if ENABLE_ASH_READ_NCHARS
11694 int n_flag = 0; 11703 int nchars = 0; /* if != 0, -n is in effect */
11695 int nchars = 0;
11696 int silent = 0; 11704 int silent = 0;
11697 struct termios tty, old_tty; 11705 struct termios tty, old_tty;
11698#endif 11706#endif
11699#if ENABLE_ASH_READ_TIMEOUT 11707#if ENABLE_ASH_READ_TIMEOUT
11700 fd_set set; 11708 unsigned end_ms = 0;
11701 struct timeval ts; 11709 unsigned timeout = 0;
11702
11703 ts.tv_sec = ts.tv_usec = 0;
11704#endif 11710#endif
11705 11711
11706 rflag = 0; 11712 rflag = 0;
11707 prompt = NULL; 11713 prompt = NULL;
11708#if ENABLE_ASH_READ_NCHARS && ENABLE_ASH_READ_TIMEOUT 11714 while ((i = nextopt("p:u:r"
11709 while ((i = nextopt("p:rt:n:s")) != '\0') 11715 USE_ASH_READ_TIMEOUT("t:")
11710#elif ENABLE_ASH_READ_NCHARS 11716 USE_ASH_READ_NCHARS("n:s")
11711 while ((i = nextopt("p:rn:s")) != '\0') 11717 )) != '\0') {
11712#elif ENABLE_ASH_READ_TIMEOUT
11713 while ((i = nextopt("p:rt:")) != '\0')
11714#else
11715 while ((i = nextopt("p:r")) != '\0')
11716#endif
11717 {
11718 switch (i) { 11718 switch (i) {
11719 case 'p': 11719 case 'p':
11720 prompt = optionarg; 11720 prompt = optionarg;
@@ -11724,7 +11724,7 @@ readcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
11724 nchars = bb_strtou(optionarg, NULL, 10); 11724 nchars = bb_strtou(optionarg, NULL, 10);
11725 if (nchars < 0 || errno) 11725 if (nchars < 0 || errno)
11726 ash_msg_and_raise_error("invalid count"); 11726 ash_msg_and_raise_error("invalid count");
11727 n_flag = nchars; /* just a flag "nchars is nonzero" */ 11727 /* nchars == 0: off (bash 3.2 does this too) */
11728 break; 11728 break;
11729 case 's': 11729 case 's':
11730 silent = 1; 11730 silent = 1;
@@ -11732,6 +11732,11 @@ readcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
11732#endif 11732#endif
11733#if ENABLE_ASH_READ_TIMEOUT 11733#if ENABLE_ASH_READ_TIMEOUT
11734 case 't': 11734 case 't':
11735 timeout = bb_strtou(optionarg, NULL, 10);
11736 if (errno || timeout > UINT_MAX / 2048)
11737 ash_msg_and_raise_error("invalid timeout");
11738 timeout *= 1000;
11739#if 0 /* even bash have no -t N.NNN support */
11735 ts.tv_sec = bb_strtou(optionarg, &p, 10); 11740 ts.tv_sec = bb_strtou(optionarg, &p, 10);
11736 ts.tv_usec = 0; 11741 ts.tv_usec = 0;
11737 /* EINVAL means number is ok, but not terminated by NUL */ 11742 /* EINVAL means number is ok, but not terminated by NUL */
@@ -11755,16 +11760,22 @@ readcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
11755 if (!(ts.tv_sec | ts.tv_usec)) { /* both are 0? */ 11760 if (!(ts.tv_sec | ts.tv_usec)) { /* both are 0? */
11756 ash_msg_and_raise_error("invalid timeout"); 11761 ash_msg_and_raise_error("invalid timeout");
11757 } 11762 }
11763#endif /* if 0 */
11758 break; 11764 break;
11759#endif 11765#endif
11760 case 'r': 11766 case 'r':
11761 rflag = 1; 11767 rflag = 1;
11762 break; 11768 break;
11769 case 'u':
11770 fd = bb_strtou(optionarg, NULL, 10);
11771 if (fd < 0 || errno)
11772 ash_msg_and_raise_error("invalid file descriptor");
11773 break;
11763 default: 11774 default:
11764 break; 11775 break;
11765 } 11776 }
11766 } 11777 }
11767 if (prompt && isatty(0)) { 11778 if (prompt && isatty(fd)) {
11768 out2str(prompt); 11779 out2str(prompt);
11769 } 11780 }
11770 ap = argptr; 11781 ap = argptr;
@@ -11774,46 +11785,48 @@ readcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
11774 if (ifs == NULL) 11785 if (ifs == NULL)
11775 ifs = defifs; 11786 ifs = defifs;
11776#if ENABLE_ASH_READ_NCHARS 11787#if ENABLE_ASH_READ_NCHARS
11777 if (n_flag || silent) { 11788 tcgetattr(fd, &tty);
11778 if (tcgetattr(0, &tty) != 0) { 11789 old_tty = tty;
11779 /* Not a tty */ 11790 if (nchars || silent) {
11780 n_flag = 0; 11791 if (nchars) {
11781 silent = 0; 11792 tty.c_lflag &= ~ICANON;
11782 } else { 11793 tty.c_cc[VMIN] = nchars < 256 ? nchars : 255;
11783 old_tty = tty;
11784 if (n_flag) {
11785 tty.c_lflag &= ~ICANON;
11786 tty.c_cc[VMIN] = nchars < 256 ? nchars : 255;
11787 }
11788 if (silent) {
11789 tty.c_lflag &= ~(ECHO | ECHOK | ECHONL);
11790 }
11791 tcsetattr(0, TCSANOW, &tty);
11792 } 11794 }
11793 } 11795 if (silent) {
11794#endif 11796 tty.c_lflag &= ~(ECHO | ECHOK | ECHONL);
11795#if ENABLE_ASH_READ_TIMEOUT
11796 if (ts.tv_sec || ts.tv_usec) {
11797 FD_ZERO(&set);
11798 FD_SET(0, &set);
11799
11800 /* poll-based wait produces bigger code, using select */
11801 i = select(1, &set, NULL, NULL, &ts);
11802 if (!i) { /* timed out! */
11803#if ENABLE_ASH_READ_NCHARS
11804 if (n_flag)
11805 tcsetattr(0, TCSANOW, &old_tty);
11806#endif
11807 return 1;
11808 } 11797 }
11798 /* if tcgetattr failed, tcsetattr will fail too.
11799 * Ignoring, it's harmless. */
11800 tcsetattr(fd, TCSANOW, &tty);
11809 } 11801 }
11810#endif 11802#endif
11803
11811 status = 0; 11804 status = 0;
11812 startword = 1; 11805 startword = 1;
11813 backslash = 0; 11806 backslash = 0;
11807#if ENABLE_ASH_READ_TIMEOUT
11808 if (timeout) /* NB: ensuring end_ms is nonzero */
11809 end_ms = ((unsigned)(monotonic_us() / 1000) + timeout) | 1;
11810#endif
11814 STARTSTACKSTR(p); 11811 STARTSTACKSTR(p);
11815 do { 11812 do {
11816 if (nonblock_safe_read(0, &c, 1) != 1) { 11813#if ENABLE_ASH_READ_TIMEOUT
11814 if (end_ms) {
11815 struct pollfd pfd[1];
11816 pfd[0].fd = fd;
11817 pfd[0].events = POLLIN;
11818 timeout = end_ms - (unsigned)(monotonic_us() / 1000);
11819 if ((int)timeout <= 0 /* already late? */
11820 || safe_poll(pfd, 1, timeout) != 1 /* no? wait... */
11821 ) { /* timed out! */
11822#if ENABLE_ASH_READ_NCHARS
11823 tcsetattr(fd, TCSANOW, &old_tty);
11824#endif
11825 return 1;
11826 }
11827 }
11828#endif
11829 if (nonblock_safe_read(fd, &c, 1) != 1) {
11817 status = 1; 11830 status = 1;
11818 break; 11831 break;
11819 } 11832 }
@@ -11848,14 +11861,13 @@ readcmd(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
11848 } 11861 }
11849/* end of do {} while: */ 11862/* end of do {} while: */
11850#if ENABLE_ASH_READ_NCHARS 11863#if ENABLE_ASH_READ_NCHARS
11851 while (!n_flag || --nchars); 11864 while (--nchars);
11852#else 11865#else
11853 while (1); 11866 while (1);
11854#endif 11867#endif
11855 11868
11856#if ENABLE_ASH_READ_NCHARS 11869#if ENABLE_ASH_READ_NCHARS
11857 if (n_flag || silent) 11870 tcsetattr(fd, TCSANOW, &old_tty);
11858 tcsetattr(0, TCSANOW, &old_tty);
11859#endif 11871#endif
11860 11872
11861 STACKSTRNUL(p); 11873 STACKSTRNUL(p);
diff --git a/shell/ash_test/ash-read/read_n.right b/shell/ash_test/ash-read/read_n.right
new file mode 100644
index 000000000..1f81af0bc
--- /dev/null
+++ b/shell/ash_test/ash-read/read_n.right
@@ -0,0 +1,3 @@
1test
2tes
3tes
diff --git a/shell/ash_test/ash-read/read_n.tests b/shell/ash_test/ash-read/read_n.tests
new file mode 100755
index 000000000..12423ba6e
--- /dev/null
+++ b/shell/ash_test/ash-read/read_n.tests
@@ -0,0 +1,3 @@
1echo 'test' | (read reply; echo "$reply")
2echo 'test' | (read -n 3 reply; echo "$reply")
3echo 'test' | (read -n3 reply; echo "$reply")
diff --git a/shell/ash_test/ash-read/read_r.right b/shell/ash_test/ash-read/read_r.right
new file mode 100644
index 000000000..3536bf757
--- /dev/null
+++ b/shell/ash_test/ash-read/read_r.right
@@ -0,0 +1,2 @@
1testbest
2test\
diff --git a/shell/ash_test/ash-read/read_r.tests b/shell/ash_test/ash-read/read_r.tests
new file mode 100755
index 000000000..2c4cc6106
--- /dev/null
+++ b/shell/ash_test/ash-read/read_r.tests
@@ -0,0 +1,2 @@
1echo -e 'test\\\nbest' | (read reply; echo "$reply")
2echo -e 'test\\\nbest' | (read -r reply; echo "$reply")
diff --git a/shell/ash_test/ash-read/read_t.right b/shell/ash_test/ash-read/read_t.right
new file mode 100644
index 000000000..04126cbe6
--- /dev/null
+++ b/shell/ash_test/ash-read/read_t.right
@@ -0,0 +1,4 @@
1><
2><
3>test<
4>test<
diff --git a/shell/ash_test/ash-read/read_t.tests b/shell/ash_test/ash-read/read_t.tests
new file mode 100755
index 000000000..d65f1aeaa
--- /dev/null
+++ b/shell/ash_test/ash-read/read_t.tests
@@ -0,0 +1,10 @@
1# bash 3.2 outputs:
2
3# ><
4{ echo -n 'te'; sleep 2; echo 'st'; } | (read -t 1 reply; echo ">$reply<")
5# ><
6{ sleep 2; echo 'test'; } | (read -t 1 reply; echo ">$reply<")
7# >test<
8{ echo -n 'te'; sleep 1; echo 'st'; } | (read -t 2 reply; echo ">$reply<")
9# >test<
10{ sleep 1; echo 'test'; } | (read -t 2 reply; echo ">$reply<")