Skip to content

Commit

Permalink
[builtins/read] Implement read -d
Browse files Browse the repository at this point in the history
Addresses issue #356.
  • Loading branch information
Andy Chu committed Mar 18, 2020
1 parent a197b58 commit 492f80c
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 11 deletions.
4 changes: 2 additions & 2 deletions core/process_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,11 @@ def testStdinRedirect(self):

r = redirect.Path(Id.Redir_Less, 0, PATH)
fd_state.Push([r], waiter)
line1 = builtin_misc.ReadLineFromStdin()
line1 = builtin_misc.ReadLineFromStdin(None)
fd_state.Pop()

fd_state.Push([r], waiter)
line2 = builtin_misc.ReadLineFromStdin()
line2 = builtin_misc.ReadLineFromStdin(None)
fd_state.Pop()

# sys.stdin.readline() would erroneously return 'two' because of buffering.
Expand Down
2 changes: 1 addition & 1 deletion oil_lang/builtin_oil.py
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ def Run(self, cmd_val):
raise args.UsageError('got extra argument', span_id=next_spid)

# TODO: use a more efficient function in C
line = builtin_misc.ReadLineFromStdin()
line = builtin_misc.ReadLineFromStdin(None)
if not line: # EOF
return 1

Expand Down
27 changes: 22 additions & 5 deletions osh/builtin_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
from asdl import runtime
from core import state
from core import ui
from core.util import log
from frontend import args
from frontend import arg_def
from mycpp import mylib
Expand All @@ -51,7 +52,7 @@
except ImportError:
help_index = None

from typing import Any, IO, TYPE_CHECKING
from typing import Any, Optional, IO, TYPE_CHECKING
if TYPE_CHECKING:
from _devbuild.gen.runtime_asdl import value__Str
from core.pyutil import _FileResourceLoader
Expand All @@ -60,6 +61,8 @@
from osh.cmd_exec import Executor
from osh.split import SplitContext

_ = log

#
# Abstract base class
#
Expand Down Expand Up @@ -166,18 +169,25 @@ def _AppendParts(s, spans, max_results, join_next, parts):
READ_SPEC.ShortFlag('-r')
READ_SPEC.ShortFlag('-n', args.Int)
READ_SPEC.ShortFlag('-a', args.Str) # name of array to read into
READ_SPEC.ShortFlag('-d', args.Str)


# sys.stdin.readline() in Python has buffering! TODO: Rewrite this tight loop
# 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():
def ReadLineFromStdin(delim_char):
# type: (Optional[str]) -> str
"""Read a line, or read up until delim_char if set."""
chars = []
while True:
c = posix.read(0, 1)
if not c:
break

if c == delim_char:
break

chars.append(c)

if c == '\n':
Expand All @@ -194,8 +204,8 @@ def __init__(self, splitter, mem):
def Run(self, cmd_val):
# type: (cmd_value__Argv) -> int
arg, i = READ_SPEC.ParseCmdVal(cmd_val)

names = cmd_val.argv[i:]

if arg.n is not None: # read a certain number of bytes
stdin = sys.stdin.fileno()
try:
Expand Down Expand Up @@ -240,13 +250,20 @@ def Run(self, cmd_val):
else:
max_results = len(names)

if arg.d is not None:
if len(arg.d):
delim_char = arg.d[0]
else:
delim_char = '\0' # -d '' delimits by NUL
else:
delim_char = None # read a line

# We have to read more than one line if there is a line continuation (and
# it's not -r).

parts = []
join_next = False
while True:
line = ReadLineFromStdin()
line = ReadLineFromStdin(delim_char)
#log('LINE %r', line)
if not line: # EOF
status = 1
Expand Down
14 changes: 12 additions & 2 deletions spec/builtin-io.test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -449,11 +449,16 @@ v1=a,b,c
v1=d v2=e,f
v1=g v2=h v3=i
## END
## N-I dash/ash STDOUT:
## N-I dash STDOUT:
v1=
v1= v2=
v1= v2= v3=
## END
## BUG ash STDOUT:
v1=a,b,c
v1=d,e,f v2=
v1=g,h,i v2= v3=
## END

#### read -d '' (null-separated records)
printf 'a,b,c\0d,e,f\0g,h,i' | {
Expand All @@ -470,8 +475,13 @@ v1=a,b,c
v1=d v2=e,f
v1=g v2=h v3=i
## END
## N-I dash/ash STDOUT:
## N-I dash STDOUT:
v1=
v1= v2=
v1= v2= v3=
## END
## BUG ash STDOUT:
v1=a,b,cd,e,fg,h,i
v1= v2=
v1= v2= v3=
## END
2 changes: 1 addition & 1 deletion test/spec.sh
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ builtin-eval-source() {
}

builtin-io() {
sh-spec spec/builtin-io.test.sh --osh-failures-allowed 2 \
sh-spec spec/builtin-io.test.sh \
${REF_SHELLS[@]} $ZSH $BUSYBOX_ASH $OSH_LIST "$@"
}

Expand Down

0 comments on commit 492f80c

Please sign in to comment.