Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ Gemfile.lock
*.bundle
*.dll
*.so
lib/ffi/io/console/version.rb
jruby/lib/io/console/version.rb
10 changes: 5 additions & 5 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ if RUBY_ENGINE == "ruby" || RUBY_ENGINE == "truffleruby"
task :test => :compile
end

ffi_version_file = "lib/ffi/#{name}/version.rb"
task ffi_version_file => "#{name.tr('/', '-')}.gemspec" do |t|
jruby_version_file = "jruby/lib/#{name}/version.rb"
task jruby_version_file => "#{name.tr('/', '-')}.gemspec" do |t|
version = <<~RUBY
class IO
module Console
Expand All @@ -26,14 +26,14 @@ task ffi_version_file => "#{name.tr('/', '-')}.gemspec" do |t|
end
end

task :build => ffi_version_file
task :test => ffi_version_file if RUBY_ENGINE == "jruby"
task :build => jruby_version_file
task :test => jruby_version_file if RUBY_ENGINE == "jruby"

Rake::TestTask.new(:test) do |t|
if extask
t.libs = [extask.lib_dir.chomp("/"+File.dirname(name))]
elsif RUBY_ENGINE == "jruby"
t.libs.unshift "lib/ffi"
t.libs.unshift "jruby/lib"
end
t.libs << "test/lib"
t.ruby_opts << "-rhelper"
Expand Down
22 changes: 11 additions & 11 deletions io-console.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -36,18 +36,18 @@ Gem::Specification.new do |s|
if Gem::Platform === s.platform and s.platform =~ 'java'
s.files.delete_if {|f| f.start_with?("ext/")}
s.extensions.clear
s.require_paths.unshift('lib/ffi')
s.require_paths.unshift('jruby/lib')
s.files.concat(%w[
lib/ffi/io/console.rb
lib/ffi/io/console/bsd_console.rb
lib/ffi/io/console/common.rb
lib/ffi/io/console/linux_console.rb
lib/ffi/io/console/native_console.rb
lib/ffi/io/console/stty_console.rb
lib/ffi/io/console/stub_console.rb
lib/ffi/io/console/windows_constants.rb
lib/ffi/io/console/windows_console.rb
lib/ffi/io/console/version.rb
jruby/lib/io/console.rb
jruby/lib/io/console/backend/ffi/termios.rb
jruby/lib/io/console/backend/ffi/windows.rb
jruby/lib/io/console/backend/stty.rb
jruby/lib/io/console/backend/stub.rb
jruby/lib/io/console/common.rb
jruby/lib/io/console/constants/bsd.rb
jruby/lib/io/console/constants/linux.rb
jruby/lib/io/console/constants/windows.rb
jruby/lib/io/console/version.rb
])
end

Expand Down
27 changes: 14 additions & 13 deletions lib/ffi/io/console.rb → jruby/lib/io/console.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,28 +36,29 @@ class Mode
deprecate_constant :ConsoleMode
end

libs = []
backends = []
# If Linux or BSD, try to load the native version
case RbConfig::CONFIG['host_os'].downcase
when /darwin|openbsd|freebsd|netbsd/
libs << 'bsd' << 'stty'
when /linux/
libs << 'linux' << 'stty'
case RbConfig::CONFIG['host_os']
when /darwin|openbsd|freebsd|netbsd/i
backends << %w[ffi/termios bsd] << %w[stty]
when /linux/i
backends << %w[ffi/termios linux] << %w[stty]
when /mswin|win32|ming/i
require_relative 'console/windows_constants'
require_relative 'console/windows_console'
require_relative 'console/constants/windows'
require_relative 'console/backend/ffi/windows'
return
else
libs << 'stty'
backends << %w[stty]
end

return if libs.any? do |lib|
require_relative "console/#{lib}_console"
return if backends.any? do |backend, constants|
require_relative "console/constants/#{constants}" if constants
require_relative "console/backend/#{backend}"
rescue Exception => ex
warn "failed to load #{lib} console support: #{ex}" if $VERBOSE
warn "failed to load #{backend.split('/', 2).first} console support: #{ex}" if $VERBOSE
else
true
end

# If still not ready, just use stubbed version
require_relative "console/stub_console"
require_relative 'console/backend/stub'
Original file line number Diff line number Diff line change
@@ -1,8 +1,72 @@
require 'ffi'

case RbConfig::CONFIG['host_os']
when /darwin/i
tested_platforms = /i386|x86_64|aarch64/
unless tested_platforms.match?(FFI::Platform::ARCH)
raise LoadError, "native console on MacOS only supported on #{tested_platforms.source.gsub('|', ', ')}"
end
when /linux/i
tested_platforms = /i386|x86_64|powerpc64|aarch64|s390x/
unless tested_platforms.match?(FFI::Platform::ARCH)
warn "native console only tested on #{tested_platforms.source.gsub('|', ', ')}"
end
end

module IO::Console::LibC
include IO::Console::Constants
extend FFI::Library
ffi_lib FFI::Library::LIBC

typedef TCFLAG_TYPE, :tcflag_t
typedef SPEED_TYPE, :speed_t

class Termios < FFI::Struct
constants = IO::Console::Constants
fields = [
:c_iflag, :tcflag_t,
:c_oflag, :tcflag_t,
:c_cflag, :tcflag_t,
:c_lflag, :tcflag_t,
]
fields.concat([:c_line, :uchar]) if constants::TERMIOS_HAS_LINE
fields.concat([
:c_cc, [:uchar, constants::NCCS],
:c_ispeed, :speed_t,
:c_ospeed, :speed_t,
])
layout(*fields)
end

class Winsize < FFI::Struct
layout \
:ws_row, :ushort,
:ws_col, :ushort,
:ws_xpixel, :ushort,
:ws_ypixel, :ushort
end

attach_function :tcsetattr, [:int, :int, :pointer], :int
attach_function :tcgetattr, [:int, :pointer], :int
attach_function :cfgetispeed, [:pointer], :speed_t
attach_function :cfgetospeed, [:pointer], :speed_t
attach_function :cfsetispeed, [:pointer, :speed_t], :int
attach_function :cfsetospeed, [:pointer, :speed_t], :int
attach_function :cfmakeraw, [:pointer], :void
attach_function :tcflush, [:int, :int], :int
attach_function :ioctl, [:int, :ulong, :varargs], :int
end

# Common logic that uses native calls for console
module IO::Console
def ttymode
termios = LibC::Termios.new
if LibC.tcgetattr(self.fileno, termios) != 0
result = if LibC.const_defined?(:TIOCGETA)
LibC.ioctl(fileno, LibC::TIOCGETA, :pointer, termios.pointer)
else
LibC.tcgetattr(fileno, termios.pointer)
end
if result != 0
raise SystemCallError.new(respond_to?(:path) ? path : "tcgetattr", FFI.errno)
end

Expand All @@ -15,7 +79,12 @@ def ttymode
private :ttymode

def ttymode_set(termios)
if LibC.tcsetattr(self.fileno, LibC::TCSANOW, termios) != 0
result = if LibC.const_defined?(:TIOCSETA)
LibC.ioctl(fileno, LibC::TIOCSETA, :pointer, termios.pointer)
else
LibC.tcsetattr(fileno, LibC::TCSANOW, termios.pointer)
end
if result != 0
raise SystemCallError.new(respond_to?(:path) ? path : "tcsetattr(TCSANOW)", FFI.errno)
end
end
Expand All @@ -34,7 +103,7 @@ def ttymode_yield(block, **opts, &setup)
private :ttymode_yield

TTY_RAW = Proc.new do |t, min: 1, time: nil, intr: nil|
LibC.cfmakeraw(t)
LibC.cfmakeraw(t.pointer)
t[:c_lflag] &= ~(LibC::ECHOE|LibC::ECHOK)
if min >= 0
t[:c_cc][LibC::VMIN] = min
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
require 'ffi'

module IO::Console::Windows
STD_INPUT_HANDLE = -10
STD_OUTPUT_HANDLE = -11
WAIT_OBJECT_0 = 0
WAIT_TIMEOUT = 258
ENABLE_WRAP_AT_EOL_OUTPUT = 2
ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4

module Native
extend FFI::Library
ffi_convention :stdcall
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,22 +1,14 @@
require 'ffi'

tested_platforms = %w[i386 x86_64]

if RbConfig::CONFIG['host_os'].downcase =~ /darwin/ && FFI::Platform::ARCH !~ /#{tested_platforms.join('|')}/
raise LoadError.new("native console on MacOS only supported on #{tested_platforms.join(', ')}")
end

module IO::Console::LibC
extend FFI::Library
ffi_lib FFI::Library::LIBC

if RbConfig::CONFIG['host_os'].downcase =~ /darwin/
typedef :ulong, :tcflag_t
typedef :ulong, :speed_t
module IO::Console::Constants
if /darwin/i.match?(RbConfig::CONFIG['host_os'])
TCFLAG_TYPE = :ulong
SPEED_TYPE = :ulong
TIOCGETA = 0x40487413
TIOCSETA = 0x80487414
else
typedef :uint, :tcflag_t
typedef :uint, :speed_t
TCFLAG_TYPE = :uint
SPEED_TYPE = :uint
end
TERMIOS_HAS_LINE = false

# Special Control Characters
VEOF = 0 # ICANON
Expand Down Expand Up @@ -124,51 +116,6 @@ module IO::Console::LibC
IOCPARM_MASK = 0x1fff
IOC_OUT = 0x40000000
IOC_IN = 0x80000000

def self._IOC(inout,group,num,len)
inout | ((len & IOCPARM_MASK) << 16) | ((group.ord << 8) | num)
end

def self._IOR(g,n,t)
self._IOC(IOC_OUT, g, n, find_type(t).size)
end

def self._IOW(g,n,t)
self._IOC(IOC_IN, g, n, find_type(t).size)
end


class Termios < FFI::Struct
layout \
:c_iflag, :tcflag_t,
:c_oflag, :tcflag_t,
:c_cflag, :tcflag_t,
:c_lflag, :tcflag_t,
:c_cc, [ :uchar, NCCS ],
:c_ispeed, :speed_t,
:c_ospeed, :speed_t
end

class Winsize < FFI::Struct
layout \
:ws_row, :ushort,
:ws_col, :ushort,
:ws_xpixel, :ushort,
:ws_ypixel, :ushort
end

TIOCGWINSZ = _IOR('t', 104, Winsize) # get window size
TIOCSWINSZ = _IOW('t', 103, Winsize) # set window size

attach_function :tcsetattr, [ :int, :int, Termios ], :int
attach_function :tcgetattr, [ :int, Termios ], :int
attach_function :cfgetispeed, [ Termios ], :speed_t
attach_function :cfgetospeed, [ Termios ], :speed_t
attach_function :cfsetispeed, [ Termios, :speed_t ], :int
attach_function :cfsetospeed, [ Termios, :speed_t ], :int
attach_function :cfmakeraw, [ Termios ], :int
attach_function :tcflush, [ :int, :int ], :int
attach_function :ioctl, [ :int, :ulong, :varargs ], :int
TIOCGWINSZ = 0x40087468
TIOCSWINSZ = 0x80087467
end

require_relative 'native_console'
Original file line number Diff line number Diff line change
@@ -1,17 +1,7 @@
require 'ffi'

tested_platforms = %w[i386 x86_64 powerpc64 aarch64 s390x]

unless FFI::Platform::ARCH =~ /#{tested_platforms.join('|')}/
warn "native console only tested on #{tested_platforms.join(', ')}"
end

module IO::Console::LibC
extend FFI::Library
ffi_lib FFI::Library::LIBC

typedef :uint, :tcflag_t
typedef :uint, :speed_t
module IO::Console::Constants
TCFLAG_TYPE = :uint
SPEED_TYPE = :uint
TERMIOS_HAS_LINE = true

VINTR = 0
VQUIT = 1
Expand Down Expand Up @@ -168,39 +158,6 @@ module IO::Console::LibC
TCSADRAIN = 1
TCSAFLUSH = 2
NCCS = 32
class Termios < FFI::Struct
layout \
:c_iflag, :tcflag_t,
:c_oflag, :tcflag_t,
:c_cflag, :tcflag_t,
:c_lflag, :tcflag_t,
:c_line, :uchar,
:c_cc, [ :uchar, NCCS ],
:c_ispeed, :speed_t,
:c_ospeed, :speed_t
end

class Winsize < FFI::Struct
layout \
:ws_row, :ushort,
:ws_col, :ushort,
:ws_xpixel, :ushort,
:ws_ypixel, :ushort
end


TIOCGWINSZ = 0x5413
TIOCSWINSZ = 0x5414

attach_function :tcsetattr, [ :int, :int, Termios ], :int
attach_function :tcgetattr, [ :int, Termios ], :int
attach_function :cfgetispeed, [ Termios ], :speed_t
attach_function :cfgetospeed, [ Termios ], :speed_t
attach_function :cfsetispeed, [ Termios, :speed_t ], :int
attach_function :cfsetospeed, [ Termios, :speed_t ], :int
attach_function :cfmakeraw, [ Termios ], :int
attach_function :tcflush, [ :int, :int ], :int
attach_function :ioctl, [ :int, :ulong, :varargs ], :int
end

require_relative 'native_console'
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
module IO::Console::Windows
STD_INPUT_HANDLE = -10
STD_OUTPUT_HANDLE = -11
WAIT_OBJECT_0 = 0
WAIT_TIMEOUT = 258
ENABLE_WRAP_AT_EOL_OUTPUT = 2
ENABLE_VIRTUAL_TERMINAL_PROCESSING = 4

VK_TAB = 0x09
VK_RETURN = 0x0d
VK_SHIFT = 0x10
Expand Down