shell/read: fix "'read' without parameters" bash compat thingy
authorDenys Vlasenko <vda.linux@googlemail.com>
Tue, 12 Jan 2010 21:12:10 +0000 (22:12 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Tue, 12 Jan 2010 21:12:10 +0000 (22:12 +0100)
previous change:

function                                             old     new   delta
builtin_read                                          82    1074    +992
popstring                                            134     140      +6
readcmd                                             1034     148    -886
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/1 up/down: 998/-886)          Total: 112 bytes

this change:

builtin_read                                        1074    1096     +22
static.arg_REPLY                                       8       -      -8
------------------------------------------------------------------------------
(add/remove: 0/1 grow/shrink: 1/0 up/down: 22/-8)              Total: 14 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
shell/builtin_read.c

index 7f667e9..24cfe08 100644 (file)
@@ -31,8 +31,6 @@ builtin_read(void (*setvar)(const char *name, const char *val, int flags),
        const char *opt_u
 )
 {
-       static const char *const arg_REPLY[] = { "REPLY", NULL };
-
        unsigned end_ms; /* -t TIMEOUT */
        int fd; /* -u FD */
        int nchars; /* -n NUM */
@@ -94,8 +92,6 @@ builtin_read(void (*setvar)(const char *name, const char *val, int flags),
                fflush_all();
        }
 
-       if (argv[0] == NULL)
-               argv = (char**)arg_REPLY;
        if (ifs == NULL)
                ifs = defifs;
 
@@ -125,7 +121,6 @@ builtin_read(void (*setvar)(const char *name, const char *val, int flags),
        bufpos = 0;
        do {
                char c;
-               const char *is_ifs;
 
                if (end_ms) {
                        int timeout;
@@ -163,40 +158,53 @@ builtin_read(void (*setvar)(const char *name, const char *val, int flags),
                }
                if (c == '\n')
                        break;
-               /* $IFS splitting */
+
+               /* $IFS splitting. NOT done if we run "read"
+                * without variable names (bash compat).
+                * Thus, "read" and "read REPLY" are not the same.
+                */
+               if (argv[0]) {
 /* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 */
-               is_ifs = strchr(ifs, c);
-               if (startword && is_ifs) {
-                       if (isspace(c))
+                       const char *is_ifs = strchr(ifs, c);
+                       if (startword && is_ifs) {
+                               if (isspace(c))
+                                       continue;
+                               /* it is a non-space ifs char */
+                               startword--;
+                               if (startword == 1) /* first one? */
+                                       continue; /* yes, it is not next word yet */
+                       }
+                       startword = 0;
+                       if (argv[1] != NULL && is_ifs) {
+                               buffer[bufpos] = '\0';
+                               bufpos = 0;
+                               setvar(*argv, buffer, 0);
+                               argv++;
+                               /* can we skip one non-space ifs char? (2: yes) */
+                               startword = isspace(c) ? 2 : 1;
                                continue;
-                       /* it is a non-space ifs char */
-                       startword--;
-                       if (startword == 1) /* first one? */
-                               continue; /* yes, it is not next word yet */
-               }
-               startword = 0;
-               if (argv[1] != NULL && is_ifs) {
-                       buffer[bufpos] = '\0';
-                       bufpos = 0;
-                       setvar(*argv, buffer, 0);
-                       argv++;
-                       /* can we skip one non-space ifs char? (2: yes) */
-                       startword = isspace(c) ? 2 : 1;
-                       continue;
+                       }
                }
  put:
                bufpos++;
        } while (--nchars);
 
-       /* Remove trailing space ifs chars */
-       while (--bufpos >= 0 && isspace(buffer[bufpos]) && strchr(ifs, buffer[bufpos]) != NULL)
-               continue;
-       buffer[bufpos + 1] = '\0';
-
-       setvar(*argv, buffer, 0);
+       if (argv[0]) {
+               /* Remove trailing space $IFS chars */
+               while (--bufpos >= 0 && isspace(buffer[bufpos]) && strchr(ifs, buffer[bufpos]) != NULL)
+                       continue;
+               buffer[bufpos + 1] = '\0';
+               /* Use the remainder as a value for the next variable */
+               setvar(*argv, buffer, 0);
+               /* Set the rest to "" */
+               while (*++argv)
+                       setvar(*argv, "", 0);
+       } else {
+               /* Note: no $IFS removal */
+               buffer[bufpos] = '\0';
+               setvar("REPLY", buffer, 0);
+       }
 
-       while (*++argv != NULL)
-               setvar(*argv, "", 0);
  ret:
        free(buffer);
        if (read_flags & BUILTIN_READ_SILENT)