about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2009-07-24 18:35:49 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2009-07-24 18:35:49 +0000
commit72f0b14a0448ecf50935a1f6c90337c3d1c969af (patch)
treebe65fa2ba994792e2f5a4764b3fbe71b91af7778
parent2c8142351681124e8ce5f8f44a8539ae4e7bbe33 (diff)
downloadzsh-72f0b14a0448ecf50935a1f6c90337c3d1c969af.tar.gz
zsh-72f0b14a0448ecf50935a1f6c90337c3d1c969af.tar.xz
zsh-72f0b14a0448ecf50935a1f6c90337c3d1c969af.zip
27188: improve read -q by using read -k code
-rw-r--r--ChangeLog8
-rw-r--r--Doc/Zsh/builtins.yo7
-rw-r--r--Src/builtin.c88
-rw-r--r--Test/B04read.ztst12
-rw-r--r--Test/D07multibyte.ztst6
5 files changed, 56 insertions, 65 deletions
diff --git a/ChangeLog b/ChangeLog
index 4a7d4ab6c..24be33402 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2009-07-24  Peter Stephenson  <p.w.stephenson@ntlworld.com>
+
+	* 27188: Doc/Zsh/builtins.yo, Src/builtin.c, Test/B04read.ztst,
+	Test/D07multibyte.ztst: Make read -q use the same code as read
+	-k, hence enabling support for -t with terminals, -p and -u.
+
 2009-07-21  Peter Stephenson  <pws@csr.com>
 
 	* 27181: Doc/Zsh/options.yo, Src/builtin.c: extend POSIX_CD to
@@ -12028,5 +12034,5 @@
 
 *****************************************************
 * This is used by the shell to define $ZSH_PATCHLEVEL
-* $Revision: 1.4749 $
+* $Revision: 1.4750 $
 *****************************************************
diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
index 4311e871e..6d1fffabf 100644
--- a/Doc/Zsh/builtins.yo
+++ b/Doc/Zsh/builtins.yo
@@ -1113,9 +1113,10 @@ item(tt(-q))(
 Read only one character from the terminal and set var(name) to
 `tt(y)' if this character was `tt(y)' or `tt(Y)' and to `tt(n)' otherwise.
 With this flag set the return status is zero only if the character was
-`tt(y)' or `tt(Y)'.  Note that this always reads from the terminal, even
-if used with the tt(-p) or tt(-u) or tt(-z) flags or with redirected input.
-This option may also be used within zle widgets.
+`tt(y)' or `tt(Y)'.  This option may be used with a timeout; if
+the read times out, or encounters end of file, status 2 is returned.
+Input is read from the terminal unless one of tt(-u)
+or tt(-p) is present.  This option may also be used within zle widgets.
 )
 item(tt(-k) [ var(num) ])(
 Read only one (or var(num)) characters.  All are assigned to the first
diff --git a/Src/builtin.c b/Src/builtin.c
index 88a54a902..2d5489c21 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -5040,8 +5040,8 @@ bin_read(char *name, char **args, Options ops, UNUSED(int func))
     if(OPT_ISSET(ops,'l') || OPT_ISSET(ops,'c'))
 	return compctlreadptr(name, args, ops, reply);
 
-    if ((OPT_ISSET(ops,'k') && !OPT_ISSET(ops,'u') &&
-	 !OPT_ISSET(ops,'p')) || OPT_ISSET(ops,'q')) {
+    if ((OPT_ISSET(ops,'k') || OPT_ISSET(ops,'q')) &&
+	!OPT_ISSET(ops,'u') && !OPT_ISSET(ops,'p')) {
 	if (!zleactive) {
 	    if (SHTTY == -1) {
 		/* need to open /dev/tty specially */
@@ -5065,7 +5065,7 @@ bin_read(char *name, char **args, Options ops, UNUSED(int func))
 		gettyinfo(&shttyinfo);
 	    /* attach to the tty */
 	    attachtty(mypgrp);
-	    if (!isem && OPT_ISSET(ops,'k'))
+	    if (!isem)
 		setcbreak();
 	    readfd = SHTTY;
 	}
@@ -5184,8 +5184,9 @@ bin_read(char *name, char **args, Options ops, UNUSED(int func))
 #endif
 	} else {
 	    if (readfd == -1 ||
-		!read_poll(readfd, &readchar, keys && !zleactive, timeout)) {
-		if (OPT_ISSET(ops,'k') && !zleactive && !isem)
+		!read_poll(readfd, &readchar, keys && !zleactive,
+			   timeout)) {
+		if (keys && !zleactive && !isem)
 		    settyinfo(&shttyinfo);
 		else if (resettty && SHTTY != -1)
 		    settyinfo(&saveti);
@@ -5194,7 +5195,7 @@ bin_read(char *name, char **args, Options ops, UNUSED(int func))
 		    shout = oshout;
 		    SHTTY = -1;
 		}
-		return 1;
+		return OPT_ISSET(ops,'q') ? 2 : 1;
 	    }
 	}
     }
@@ -5203,11 +5204,18 @@ bin_read(char *name, char **args, Options ops, UNUSED(int func))
     memset(&mbs, 0, sizeof(mbs));
 #endif
 
-    /* option -k means read only a given number of characters (default 1) */
-    if (OPT_ISSET(ops,'k')) {
+    /*
+     * option -k means read only a given number of characters (default 1)
+     * option -q means get one character, and interpret it as a Y or N
+     */
+    if (OPT_ISSET(ops,'k') || OPT_ISSET(ops,'q')) {
 	int eof = 0;
 	/* allocate buffer space for result */
+#ifdef MULTIBYTE_SUPPORT
+	bptr = buf = (char *)zalloc(nchars*MB_CUR_MAX+1);
+#else
 	bptr = buf = (char *)zalloc(nchars+1);
+#endif
 
 	do {
 	    if (izle) {
@@ -5295,6 +5303,17 @@ bin_read(char *name, char **args, Options ops, UNUSED(int func))
 	    }
 	}
 
+	if (OPT_ISSET(ops,'q'))
+	{
+	    /*
+	     * Keep eof as status but status is now whether we read
+	     * 'y' or 'Y'.  If we timed out, status is 2.
+	     */
+	    if (eof)
+		eof = 2;
+	    else
+		eof = (bptr - buf != 1 || (buf[0] != 'y' && buf[0] != 'Y'));
+	}
 	if (OPT_ISSET(ops,'e') || OPT_ISSET(ops,'E'))
 	    fwrite(buf, bptr - buf, 1, stdout);
 	if (!OPT_ISSET(ops,'e'))
@@ -5306,59 +5325,6 @@ bin_read(char *name, char **args, Options ops, UNUSED(int func))
 	return eof;
     }
 
-    /* option -q means get one character, and interpret it as a Y or N */
-    if (OPT_ISSET(ops,'q')) {
-	char readbuf[2];
-
-	/* set up the buffer */
-	readbuf[1] = '\0';
-
-	/* get, and store, reply */
-	if (izle) {
-#ifdef MULTIBYTE_SUPPORT
-	    int key;
-	    char c;
-
-	    for (;;) {
-		zleentry(ZLE_CMD_GET_KEY, izle_timeout, NULL, &key);
-		if (key < 0)
-		    break;
-		c = (char)key;
-		/*
-		 * If multibyte, it can't be y, so we don't care
-		 * what key gets set to; just read to end of character.
-		 */
-		if (!isset(MULTIBYTE) ||
-		    mbrlen(&c, 1, &mbs) != MB_INCOMPLETE)
-		    break;
-	    }
-#else
-	    int key;
-	    zleentry(ZLE_CMD_GET_KEY, izle_timeout, NULL, &key);
-#endif
-
-	    readbuf[0] = (key == 'y' ? 'y' : 'n');
-	} else {
-	    readbuf[0] = ((char)getquery(NULL, 0)) == 'y' ? 'y' : 'n';
-
-	    /* dispose of result appropriately, etc. */
-	    if (haso) {
-		fclose(shout);	/* close(SHTTY) */
-		shout = oshout;
-		SHTTY = -1;
-	    }
-	}
-
-	if (OPT_ISSET(ops,'e') || OPT_ISSET(ops,'E'))
-	    printf("%s\n", readbuf);
-	if (!OPT_ISSET(ops,'e'))
-	    setsparam(reply, ztrdup(readbuf));
-
-	if (resettty && SHTTY != -1)
-	    settyinfo(&saveti);
-	return readbuf[0] == 'n';
-    }
-
     /* All possible special types of input have been exhausted.  Take one line,
        and assign words to the parameters until they run out.  Leftover words go
        onto the last parameter.  If an array is specified, all the words become
diff --git a/Test/B04read.ztst b/Test/B04read.ztst
index d6b7ce0b1..2c87aa67a 100644
--- a/Test/B04read.ztst
+++ b/Test/B04read.ztst
@@ -24,6 +24,18 @@
 0:read specified number of chars
 >foo
 
+ for char in y Y n N X $'\n'; do
+   read -q -u0 <<<$char
+   print $?
+ done
+0:read yes or no, default no
+>0
+>0
+>1
+>1
+>1
+>1
+
  read -d: <<<foo:bar
  print $REPLY
 0:read up to delimiter
diff --git a/Test/D07multibyte.ztst b/Test/D07multibyte.ztst
index 3f4eaf9c0..53cbe2a1d 100644
--- a/Test/D07multibyte.ztst
+++ b/Test/D07multibyte.ztst
@@ -232,6 +232,12 @@
 <«»ignored
 >«»
 
+  read -q -u0 mb
+  print $?
+0:multibyte character makes read -q return false
+<«
+>1
+
   # See if the system grokks first-century Greek...
   ioh="Ἐν ἀρχῇ ἦν ὁ λόγος, καὶ ὁ λόγος ἦν πρὸς τὸν θεόν, καὶ θεὸς ἦν ὁ λόγος."
   for (( i = 1; i <= ${#ioh}; i++ )); do