Bash-4.3 distribution sources and documentation
[platform/upstream/bash.git] / builtins / read.def
index d407857..56945b9 100644 (file)
@@ -1,7 +1,7 @@
 This file is read.def, from which is created read.c.
 It implements the builtin "read" in Bash.
 
-Copyright (C) 1987-2010 Free Software Foundation, Inc.
+Copyright (C) 1987-2012 Free Software Foundation, Inc.
 
 This file is part of GNU Bash, the Bourne Again SHell.
 
@@ -51,15 +51,17 @@ Options:
   -r           do not allow backslashes to escape any characters
   -s           do not echo input coming from a terminal
   -t timeout   time out and return failure if a complete line of input is
-               not read withint TIMEOUT seconds.  The value of the TMOUT
+               not read within TIMEOUT seconds.  The value of the TMOUT
                variable is the default timeout.  TIMEOUT may be a
-               fractional number.  If TIMEOUT is 0, read returns success only
-               if input is available on the specified file descriptor.  The
+               fractional number.  If TIMEOUT is 0, read returns immediately,
+               without trying to read any data, returning success only if
+               input is available on the specified file descriptor.  The
                exit status is greater than 128 if the timeout is exceeded
   -u fd                read from file descriptor FD instead of the standard input
 
 Exit Status:
-The return code is zero, unless end-of-file is encountered, read times out,
+The return code is zero, unless end-of-file is encountered, read times out
+(in which case it's greater than 128), a variable assignment error occurs,
 or an invalid file descriptor is supplied as the argument to -u.
 $END
 
@@ -101,10 +103,17 @@ $END
 #  include "input.h"
 #endif
 
+#include "shmbutil.h"
+
 #if !defined(errno)
 extern int errno;
 #endif
 
+extern void run_pending_traps __P((void));
+
+extern int posixly_correct;
+extern int trapped_signal_received;
+
 struct ttsave
 {
   int fd;
@@ -127,15 +136,26 @@ static void ttyrestore __P((struct ttsave *));
 static sighandler sigalrm __P((int));
 static void reset_alarm __P((void));
 
-static procenv_t alrmbuf;
+/* Try this to see what the rest of the shell can do with the information. */
+procenv_t alrmbuf;
+int sigalrm_seen;
+
+static int reading;
 static SigHandler *old_alrm;
 static unsigned char delim;
 
+/* In all cases, SIGALRM just sets a flag that we check periodically.  This
+   avoids problems with the semi-tricky stuff we do with the xfree of
+   input_string at the top of the unwind-protect list (see below). */
+
+/* Set a flag that CHECK_ALRM can check.  This relies on zread calling
+   trap.c:check_signals_and_traps(), which knows about sigalrm_seen and
+   alrmbuf. */
 static sighandler
 sigalrm (s)
      int s;
 {
-  longjmp (alrmbuf, 1);
+  sigalrm_seen = 1;
 }
 
 static void
@@ -158,7 +178,7 @@ read_builtin (list)
   register char *varname;
   int size, i, nr, pass_next, saw_escape, eof, opt, retval, code, print_ps2;
   int input_is_tty, input_is_pipe, unbuffered_read, skip_ctlesc, skip_ctlnul;
-  int raw, edit, nchars, silent, have_timeout, ignore_delim, fd;
+  int raw, edit, nchars, silent, have_timeout, ignore_delim, fd, lastsig, t_errno;
   unsigned int tmsec, tmusec;
   long ival, uval;
   intmax_t intval;
@@ -199,6 +219,9 @@ read_builtin (list)
 #endif
   USE_VAR(list);
   USE_VAR(ps2);
+  USE_VAR(lastsig);
+
+  sigalrm_seen = reading = 0;
 
   i = 0;               /* Index into the string that we are reading. */
   raw = edit = 0;      /* Not reading raw input by default. */
@@ -306,6 +329,18 @@ read_builtin (list)
     return (input_avail (fd) ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
 #endif
 
+  /* Convenience: check early whether or not the first of possibly several
+     variable names is a valid identifier, and bail early if so. */
+#if defined (ARRAY_VARS)
+  if (list && legal_identifier (list->word->word) == 0 && valid_array_reference (list->word->word) == 0)
+#else
+  if (list && legal_identifier (list->word->word) == 0)
+#endif
+    {
+      sh_invalidid (list->word->word);
+      return (EXECUTION_FAILURE);
+    }
+
   /* If we're asked to ignore the delimiter, make sure we do. */
   if (ignore_delim)
     delim = -1;
@@ -380,14 +415,15 @@ read_builtin (list)
 
   if (tmsec > 0 || tmusec > 0)
     {
-      code = setjmp (alrmbuf);
+      code = setjmp_nosigs (alrmbuf);
       if (code)
        {
+         sigalrm_seen = 0;
          /* Tricky.  The top of the unwind-protect stack is the free of
             input_string.  We want to run all the rest and use input_string,
             so we have to save input_string temporarily, run the unwind-
-            protects, then restore input_string so we can use it later. */
-
+            protects, then restore input_string so we can use it later */
+         orig_input_string = 0;
          input_string[i] = '\0';       /* make sure it's terminated */
          if (i == 0)
            {
@@ -464,10 +500,12 @@ read_builtin (list)
   /* This *must* be the top unwind-protect on the stack, so the manipulation
      of the unwind-protect stack after the realloc() works right. */
   add_unwind_protect (xfree, input_string);
-  interrupt_immediately++;
-  terminate_immediately++;
 
-  unbuffered_read = (nchars > 0) || (delim != '\n') || input_is_pipe;
+  CHECK_ALRM;
+  if ((nchars > 0) && (input_is_tty == 0) && ignore_delim)     /* read -N */
+    unbuffered_read = 2;
+  else if ((nchars > 0) || (delim != '\n') || input_is_pipe)
+    unbuffered_read = 1;
 
   if (prompt && edit == 0)
     {
@@ -482,6 +520,8 @@ read_builtin (list)
   ps2 = 0;
   for (print_ps2 = eof = retval = 0;;)
     {
+      CHECK_ALRM;
+
 #if defined (READLINE)
       if (edit)
        {
@@ -492,7 +532,9 @@ read_builtin (list)
            }
          if (rlbuf == 0)
            {
+             reading = 1;
              rlbuf = edit_line (prompt ? prompt : "", itext);
+             reading = 0;
              rlind = 0;
            }
          if (rlbuf == 0)
@@ -515,26 +557,58 @@ read_builtin (list)
          print_ps2 = 0;
        }
 
-      if (unbuffered_read)
-       retval = zread (fd, &c, 1);
+#if 0
+      if (posixly_correct == 0)
+       interrupt_immediately++;
+#endif
+      reading = 1;
+      if (unbuffered_read == 2)
+       retval = posixly_correct ? zreadintr (fd, &c, 1) : zreadn (fd, &c, nchars - nr);
+      else if (unbuffered_read)
+       retval = posixly_correct ? zreadintr (fd, &c, 1) : zread (fd, &c, 1);
       else
-       retval = zreadc (fd, &c);
+       retval = posixly_correct ? zreadcintr (fd, &c) : zreadc (fd, &c);
+      reading = 0;
+#if 0
+      if (posixly_correct == 0)
+       interrupt_immediately--;
+#endif
 
       if (retval <= 0)
        {
+         if (retval < 0 && errno == EINTR)
+           {
+             lastsig = LASTSIG();
+             if (lastsig == 0)
+               lastsig = trapped_signal_received;
+             run_pending_traps ();     /* because interrupt_immediately is not set */
+           }
+         else
+           lastsig = 0;
+         CHECK_TERMSIG;
          eof = 1;
          break;
        }
 
+      CHECK_ALRM;
+
 #if defined (READLINE)
        }
 #endif
 
+      CHECK_ALRM;
       if (i + 4 >= size)       /* XXX was i + 2; use i + 4 for multibyte/read_mbchar */
        {
-         input_string = (char *)xrealloc (input_string, size += 128);
-         remove_unwind_protect ();
-         add_unwind_protect (xfree, input_string);
+         char *t;
+         t = (char *)xrealloc (input_string, size += 128);
+
+         /* Only need to change unwind-protect if input_string changes */
+         if (t != input_string)
+           {
+             input_string = t;
+             remove_unwind_protect ();
+             add_unwind_protect (xfree, input_string);
+           }
        }
 
       /* If the next character is to be accepted verbatim, a backslash
@@ -565,9 +639,12 @@ read_builtin (list)
          continue;
        }
 
-      if ((unsigned char)c == delim)
+      if (ignore_delim == 0 && (unsigned char)c == delim)
        break;
 
+      if (c == '\0' && delim != '\0')
+       continue;               /* skip NUL bytes in input */
+
       if ((skip_ctlesc == 0 && c == CTLESC) || (skip_ctlnul == 0 && c == CTLNUL))
        {
          saw_escape++;
@@ -576,9 +653,10 @@ read_builtin (list)
 
 add_char:
       input_string[i++] = c;
+      CHECK_ALRM;
 
 #if defined (HANDLE_MULTIBYTE)
-      if (nchars > 0 && MB_CUR_MAX > 1)
+      if (nchars > 0 && MB_CUR_MAX > 1 && is_basic (c) == 0)
        {
          input_string[i] = '\0';       /* for simplicity and debugging */
          i += read_mbchar (fd, input_string, i, c, unbuffered_read);
@@ -591,15 +669,16 @@ add_char:
        break;
     }
   input_string[i] = '\0';
+  CHECK_ALRM;
 
-#if 1
   if (retval < 0)
     {
-      builtin_error (_("read error: %d: %s"), fd, strerror (errno));
+      t_errno = errno;
+      if (errno != EINTR)
+       builtin_error (_("read error: %d: %s"), fd, strerror (errno));
       run_unwind_frame ("read_builtin");
-      return (EXECUTION_FAILURE);
+      return ((t_errno != EINTR) ? EXECUTION_FAILURE : 128+lastsig);
     }
-#endif
 
   if (tmsec > 0 || tmusec > 0)
     reset_alarm ();
@@ -631,9 +710,6 @@ add_char:
 
 assign_vars:
 
-  interrupt_immediately--;
-  terminate_immediately--;
-
 #if defined (ARRAY_VARS)
   /* If -a was given, take the string read, break it into a list of words,
      an assign them to `arrayname' in turn. */
@@ -658,6 +734,8 @@ assign_vars:
          xfree (input_string);
          return EXECUTION_FAILURE;     /* existing associative array */
        }
+      else if (invisible_p (var))
+       VUNSETATTR (var, att_invisible);
       array_flush (array_cell (var));
 
       alist = list_string (input_string, ifs_chars, 0);
@@ -703,7 +781,7 @@ assign_vars:
        var = bind_variable ("REPLY", input_string, 0);
       VUNSETATTR (var, att_invisible);
 
-      free (input_string);
+      xfree (input_string);
       return (retval);
     }
 
@@ -829,6 +907,7 @@ bind_read_variable (name, value)
      char *name, *value;
 {
   SHELL_VAR *v;
+
 #if defined (ARRAY_VARS)
   if (valid_array_reference (name) == 0)
     v = bind_variable (name, value, 0);
@@ -867,6 +946,7 @@ read_mbchar (fd, string, ind, ch, unbuffered)
       if (ret == (size_t)-2)
        {
          ps = ps_back;
+         /* We don't want to be interrupted during a multibyte char read */
          if (unbuffered)
            r = zread (fd, &c, 1);
          else
@@ -947,7 +1027,9 @@ edit_line (p, itext)
       rl_startup_hook = set_itext;
       deftext = itext;
     }
+
   ret = readline (p);
+
   rl_attempted_completion_function = old_attempted_completion_function;
   old_attempted_completion_function = (rl_completion_func_t *)NULL;