Skip to content

Commit

Permalink
[builtin/read] Exit code is 1 only when EOF is reached.
Browse files Browse the repository at this point in the history
Addresses issue #705.
  • Loading branch information
Andy Chu committed Apr 14, 2020
1 parent 9df5364 commit e401363
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 16 deletions.
25 changes: 13 additions & 12 deletions osh/builtin_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,27 +159,28 @@ def _AppendParts(s, spans, max_results, join_next, parts):
# in C? Less garbage probably.
# NOTE that dash, mksh, and zsh all read a single byte at a time. It appears
# to be required by POSIX? Could try libc getline and make this an option.

def ReadLineFromStdin(delim_char):
# type: (Optional[str]) -> Tuple[str, bool]
"""Read a portion of stdin.
If delim_char is set, read until that delimiter, but don't include it.
If not set, read a line, and include the newline.
"""
found_delim = False
eof = False
chars = []
while True:
c = posix.read(0, 1)
if not c:
eof = True
break

if c == delim_char:
found_delim = True
break

chars.append(c)

return ''.join(chars), found_delim
return ''.join(chars), eof


class Read(object):
Expand Down Expand Up @@ -249,19 +250,19 @@ def Run(self, cmd_val):
# it's not -r).
parts = []
join_next = False
status = 0
while True:
line, found_delim = ReadLineFromStdin(delim_char)
#log('LINE %r', line)
if len(line) == 0: # EOF
status = 1
break
line, eof = ReadLineFromStdin(delim_char)

status = 0
if not found_delim:
# odd bash behavior: fail if no newline, even though we're setting
# variables.
if eof:
# status 1 to terminate loop. (This is true even though we set
# variables).
status = 1

#log('LINE %r', line)
if len(line) == 0:
break

spans = self.splitter.SplitForRead(line, not arg.r)
done, join_next = _AppendParts(line, spans, max_results, join_next, parts)

Expand Down
3 changes: 2 additions & 1 deletion osh/word_parse_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,8 @@ def testMultiLine(self):
test_lib.AssertAsdlEqual(self, t, w)

def testUnicode(self):
words = u'\u007a \u03bb \u4e09 \U0001f618'.encode('utf-8')
words = 'z \xce\xbb \xe4\xb8\x89 \xf0\x9f\x98\x98'

w_parser = test_lib.InitWordParser(words)
w = w_parser.ReadWord(lex_mode_e.ShCommand)
self.assertEqual('z', w.parts[0].val)
Expand Down
2 changes: 0 additions & 2 deletions qsn_/qsn.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@
implementation could relax this.
TODO:
- Optimize common case encoding with native regex. IsPlainWord()
- maybe_decode() in addition to decode()
TODO for other implementations:
Expand Down
25 changes: 24 additions & 1 deletion spec/builtin-io.test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -216,9 +216,32 @@ echo "[$x]"
echo -n '' > $TMP/empty.txt
read x < $TMP/empty.txt
argv.py "status=$?" "$x"
## stdout: ['status=1', '']

# No variable name, behaves the same
read < $TMP/empty.txt
argv.py "status=$?" "$REPLY"

## STDOUT:
['status=1', '']
['status=1', '']
## END
## OK dash STDOUT:
['status=1', '']
['status=2', '']
## END
## status: 0


#### read with zero args
echo | read
echo status=$?
## STDOUT:
status=0
## END
## BUG dash STDOUT:
status=2
## END

#### Read builtin with no newline.
# This is odd because the variable is populated successfully. OSH/Oil might
# need a separate put reading feature that doesn't use IFS.
Expand Down

0 comments on commit e401363

Please sign in to comment.