mirror of
https://github.com/ruby/ruby.git
synced 2025-08-15 13:39:04 +02:00
When reading from stdin, put a wrapper around the IO object
The purpose of this commit is to fix Bug #21188. We need to detect when stdin has run in to an EOF case. Unfortunately we can't _call_ the eof function on IO because it will block. Here is a short script to demonstrate the issue: ```ruby x = STDIN.gets puts x puts x.eof? ``` If you run the script, then type some characters (but _NOT_ a newline), then hit Ctrl-D twice, it will print the input string. Unfortunately, calling `eof?` will try to read from STDIN again causing us to need a 3rd Ctrl-D to exit the program. Before introducing the EOF callback to Prism, the input loop looked kind of like this: ```ruby loop do str = STDIN.gets process(str) if str.nil? p :DONE end end ``` Which required 3 Ctrl-D to exit. If we naively changed it to something like this: ```ruby loop do str = STDIN.gets process(str) if STDIN.eof? p :DONE end end ``` It would still require 3 Ctrl-D because `eof?` would block. In this patch, we're wrapping the IO object, checking the buffer for a newline and length, and then using that to simulate a non-blocking eof? method. This commit wraps STDIN and emulates a non-blocking `eof` function. [Bug #21188]
This commit is contained in:
parent
1c6b36af18
commit
89d89fa49d
5 changed files with 66 additions and 13 deletions
|
@ -86,6 +86,7 @@ module Prism
|
|||
end
|
||||
|
||||
callback :pm_parse_stream_fgets_t, [:pointer, :int, :pointer], :pointer
|
||||
callback :pm_parse_stream_feof_t, [:pointer], :int
|
||||
enum :pm_string_init_result_t, %i[PM_STRING_INIT_SUCCESS PM_STRING_INIT_ERROR_GENERIC PM_STRING_INIT_ERROR_DIRECTORY]
|
||||
enum :pm_string_query_t, [:PM_STRING_QUERY_ERROR, -1, :PM_STRING_QUERY_FALSE, :PM_STRING_QUERY_TRUE]
|
||||
|
||||
|
@ -101,7 +102,7 @@ module Prism
|
|||
"pm_string_query_local",
|
||||
"pm_string_query_constant",
|
||||
"pm_string_query_method_name",
|
||||
[:pm_parse_stream_fgets_t]
|
||||
[:pm_parse_stream_fgets_t, :pm_parse_stream_feof_t]
|
||||
)
|
||||
|
||||
load_exported_functions_from(
|
||||
|
@ -281,12 +282,14 @@ module Prism
|
|||
end
|
||||
}
|
||||
|
||||
eof_callback = -> (_) { stream.eof? }
|
||||
|
||||
# In the pm_serialize_parse_stream function it accepts a pointer to the
|
||||
# IO object as a void* and then passes it through to the callback as the
|
||||
# third argument, but it never touches it itself. As such, since we have
|
||||
# access to the IO object already through the closure of the lambda, we
|
||||
# can pass a null pointer here and not worry.
|
||||
LibRubyParser.pm_serialize_parse_stream(buffer.pointer, nil, callback, dump_options(options))
|
||||
LibRubyParser.pm_serialize_parse_stream(buffer.pointer, nil, callback, eof_callback, dump_options(options))
|
||||
Prism.load(source, buffer.read, options.fetch(:freeze, false))
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue