hush: fix IFS handling in read
No binary (build failed)
—
(log yok)
| @@ -0,0 +1,9 @@ | |
| + | |X|Y:Z:| |
| + | |X|Y:Z| |
| + | |X|Y| |
| + | |X|Y| |
| + | |X|| |
| + | |X|| |
| + | ||| |
| + | Whitespace should be trimmed too: |
| + | |X|Y| |
| @@ -0,0 +1,9 @@ | |
| + | echo "X:Y:Z:" | (IFS=": " read x y; echo "|$x|$y|") |
| + | echo "X:Y:Z" | (IFS=": " read x y; echo "|$x|$y|") |
| + | echo "X:Y:" | (IFS=": " read x y; echo "|$x|$y|") |
| + | echo "X:Y" | (IFS=": " read x y; echo "|$x|$y|") |
| + | echo "X:" | (IFS=": " read x y; echo "|$x|$y|") |
| + | echo "X" | (IFS=": " read x y; echo "|$x|$y|") |
| + | echo "" | (IFS=": " read x y; echo "|$x|$y|") |
| + | echo Whitespace should be trimmed too: |
| + | echo "X:Y : " | (IFS=": " read x y; echo "|$x|$y|") |
| @@ -274,9 +274,44 @@ shell_builtin_read(void FAST_FUNC (*setvar)(const char *name, const char *val), | |
| if (argv[0]) { | |
| /* Remove trailing space $IFS chars */ | |
| - | while (--bufpos >= 0 && isspace(buffer[bufpos]) && strchr(ifs, buffer[bufpos]) != NULL) |
| + | while (--bufpos >= 0 |
| + | && isspace(buffer[bufpos]) |
| + | && strchr(ifs, buffer[bufpos]) != NULL |
| + | ) { |
| continue; | |
| + | } |
| buffer[bufpos + 1] = '\0'; | |
| + | |
| + | /* Last variable takes the entire remainder with delimiters |
| + | * (sans trailing whitespace $IFS), |
| + | * but ***only "if there are fewer vars than fields"(c)***! |
| + | * The "X:Y:" case below: there are two fields, |
| + | * and therefore last delimiter (:) is eaten: |
| + | * IFS=": " |
| + | * echo "X:Y:Z:" | (read x y; echo "|$x|$y|") # |X|Y:Z:| |
| + | * echo "X:Y:Z" | (read x y; echo "|$x|$y|") # |X|Y:Z| |
| + | * echo "X:Y:" | (read x y; echo "|$x|$y|") # |X|Y|, not |X|Y:| |
| + | * echo "X:Y : " | (read x y; echo "|$x|$y|") # |X|Y| |
| + | */ |
| + | if (bufpos >= 0 |
| + | && strchr(ifs, buffer[bufpos]) != NULL |
| + | ) { |
| + | /* There _is_ a non-whitespace IFS char */ |
| + | /* Skip whitespace IFS char before it */ |
| + | while (--bufpos >= 0 |
| + | && isspace(buffer[bufpos]) |
| + | && strchr(ifs, buffer[bufpos]) != NULL |
| + | ) { |
| + | continue; |
| + | } |
| + | /* Are there $IFS chars? */ |
| + | if (strcspn(buffer, ifs) >= ++bufpos) { |
| + | /* No: last var takes one field, not more */ |
| + | /* So, drop trailing IFS delims */ |
| + | buffer[bufpos] = '\0'; |
| + | } |
| + | } |
| + | |
| /* Use the remainder as a value for the next variable */ | |
| setvar(*argv, buffer); | |
| /* Set the rest to "" */ | |