Skip to content

Commit

Permalink
Support Android API levels 24 - 27 (crystal-lang#13884)
Browse files Browse the repository at this point in the history
  • Loading branch information
HertzDevil authored Oct 12, 2023
1 parent 4867d81 commit 1d0a7ab
Show file tree
Hide file tree
Showing 8 changed files with 80 additions and 20 deletions.
6 changes: 5 additions & 1 deletion lib/reply/src/term_size.cr
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,10 @@ end
{% end %}
{% end %}

fun ioctl(fd : Int, request : ULong, ...) : Int
{% if flag?(:android) %}
fun ioctl(__fd : Int, __request : Int, ...) : Int
{% else %}
fun ioctl(fd : Int, request : ULong, ...) : Int
{% end %}
end
{% end %}
2 changes: 1 addition & 1 deletion src/crystal/iconv.cr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{% if flag?(:use_libiconv) || flag?(:win32) %}
{% if flag?(:use_libiconv) || flag?(:win32) || (flag?(:android) && LibC::ANDROID_API < 28) %}
require "./lib_iconv"
private USE_LIBICONV = true
{% else %}
Expand Down
68 changes: 59 additions & 9 deletions src/crystal/system/unix/file_descriptor.cr
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
require "c/fcntl"
require "io/evented"
require "termios"
{% if flag?(:android) && LibC::ANDROID_API < 28 %}
require "c/sys/ioctl"
{% end %}

# :nodoc:
module Crystal::System::FileDescriptor
Expand Down Expand Up @@ -198,7 +201,7 @@ module Crystal::System::FileDescriptor
system_console_mode do |mode|
flags = LibC::ECHO | LibC::ECHOE | LibC::ECHOK | LibC::ECHONL
mode.c_lflag = enable ? (mode.c_lflag | flags) : (mode.c_lflag & ~flags)
if LibC.tcsetattr(fd, LibC::TCSANOW, pointerof(mode)) != 0
if FileDescriptor.tcsetattr(fd, LibC::TCSANOW, pointerof(mode)) != 0
raise IO::Error.from_errno("tcsetattr")
end
yield
Expand All @@ -208,13 +211,13 @@ module Crystal::System::FileDescriptor
private def system_raw(enable : Bool, & : ->)
system_console_mode do |mode|
if enable
LibC.cfmakeraw(pointerof(mode))
FileDescriptor.cfmakeraw(pointerof(mode))
else
mode.c_iflag |= LibC::BRKINT | LibC::ISTRIP | LibC::ICRNL | LibC::IXON
mode.c_oflag |= LibC::OPOST
mode.c_lflag |= LibC::ECHO | LibC::ECHOE | LibC::ECHOK | LibC::ECHONL | LibC::ICANON | LibC::ISIG | LibC::IEXTEN
end
if LibC.tcsetattr(fd, LibC::TCSANOW, pointerof(mode)) != 0
if FileDescriptor.tcsetattr(fd, LibC::TCSANOW, pointerof(mode)) != 0
raise IO::Error.from_errno("tcsetattr")
end
yield
Expand All @@ -223,13 +226,60 @@ module Crystal::System::FileDescriptor

@[AlwaysInline]
private def system_console_mode(&)
if LibC.tcgetattr(fd, out mode) != 0
raise IO::Error.from_errno("tcgetattr")
before = FileDescriptor.tcgetattr(fd)
begin
yield before
ensure
FileDescriptor.tcsetattr(fd, LibC::TCSANOW, pointerof(before))
end
end

@[AlwaysInline]
def self.tcgetattr(fd)
termios = uninitialized LibC::Termios
ret = {% if flag?(:android) && !LibC.has_method?(:tcgetattr) %}
LibC.ioctl(fd, LibC::TCGETS, pointerof(termios))
{% else %}
LibC.tcgetattr(fd, pointerof(termios))
{% end %}
raise IO::Error.from_errno("tcgetattr") if ret != 0
termios
end

@[AlwaysInline]
def self.tcsetattr(fd, optional_actions, termios_p)
{% if flag?(:android) && !LibC.has_method?(:tcsetattr) %}
optional_actions = optional_actions.value if optional_actions.is_a?(Termios::LineControl)
cmd = case optional_actions
when LibC::TCSANOW
LibC::TCSETS
when LibC::TCSADRAIN
LibC::TCSETSW
when LibC::TCSAFLUSH
LibC::TCSETSF
else
Errno.value = Errno::EINVAL
return LibC::Int.new(-1)
end

LibC.ioctl(fd, cmd, termios_p)
{% else %}
LibC.tcsetattr(fd, optional_actions, termios_p)
{% end %}
end

before = mode
ret = yield mode
LibC.tcsetattr(fd, LibC::TCSANOW, pointerof(before))
ret
@[AlwaysInline]
def self.cfmakeraw(termios_p)
{% if flag?(:android) && !LibC.has_method?(:cfmakeraw) %}
s.value.c_iflag &= ~(LibC::IGNBRK | LibC::BRKINT | LibC::PARMRK | LibC::ISTRIP | LibC::INLCR | LibC::IGNCR | LibC::ICRNL | LibC::IXON)
s.value.c_oflag &= ~LibC::OPOST
s.value.c_lflag &= ~(LibC::ECHO | LibC::ECHONL | LibC::ICANON | LibC::ISIG | LibC::IEXTEN)
s.value.c_cflag &= ~(LibC::CSIZE | LibC::PARENB)
s.value.c_cflag |= LibC::CS8
s.value.c_cc[LibC::VMIN] = 1
s.value.c_cc[LibC::VTIME] = 0
{% else %}
LibC.cfmakeraw(termios_p)
{% end %}
end
end
8 changes: 4 additions & 4 deletions src/io/console.cr
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ class IO::FileDescriptor < IO
@[Deprecated]
macro noecho_from_tc_mode!
mode.c_lflag &= ~(Termios::LocalMode.flags(ECHO, ECHOE, ECHOK, ECHONL).value)
LibC.tcsetattr(fd, Termios::LineControl::TCSANOW, pointerof(mode))
Crystal::System::FileDescriptor.tcsetattr(fd, Termios::LineControl::TCSANOW, pointerof(mode))
end

@[Deprecated]
Expand All @@ -109,12 +109,12 @@ class IO::FileDescriptor < IO
Termios::LocalMode::ICANON |
Termios::LocalMode::ISIG |
Termios::LocalMode::IEXTEN).value
LibC.tcsetattr(fd, Termios::LineControl::TCSANOW, pointerof(mode))
Crystal::System::FileDescriptor.tcsetattr(fd, Termios::LineControl::TCSANOW, pointerof(mode))
end

@[Deprecated]
macro raw_from_tc_mode!
LibC.cfmakeraw(pointerof(mode))
LibC.tcsetattr(fd, Termios::LineControl::TCSANOW, pointerof(mode))
Crystal::System::FileDescriptor.cfmakeraw(pointerof(mode))
Crystal::System::FileDescriptor.tcsetattr(fd, Termios::LineControl::TCSANOW, pointerof(mode))
end
end
2 changes: 1 addition & 1 deletion src/lib_c.cr
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ lib LibC

{% if flag?(:android) %}
{% default_api_version = 31 %}
{% min_supported_version = 28 %}
{% min_supported_version = 24 %}
{% api_version_var = env("ANDROID_PLATFORM") || env("ANDROID_NATIVE_API_LEVEL") %}
{% api_version = api_version_var ? api_version_var.gsub(/^android-/, "").to_i : default_api_version %}
{% raise "TODO: Support Android API level below #{min_supported_version}" unless api_version >= min_supported_version %}
Expand Down
4 changes: 2 additions & 2 deletions src/lib_c/aarch64-android/c/iconv.cr
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
require "./stddef"

lib LibC
type IconvT = Void*

{% if ANDROID_API >= 28 %}
type IconvT = Void*

fun iconv(__converter : IconvT, __src_buf : Char**, __src_bytes_left : SizeT*, __dst_buf : Char**, __dst_bytes_left : SizeT*) : SizeT
fun iconv_close(__converter : IconvT) : Int
fun iconv_open(__src_encoding : Char*, __dst_encoding : Char*) : IconvT
Expand Down
8 changes: 8 additions & 0 deletions src/lib_c/aarch64-android/c/sys/ioctl.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
lib LibC
TCGETS = 0x5401
TCSETS = 0x5402
TCSETSW = 0x5403
TCSETSF = 0x5404

fun ioctl(__fd : Int, __request : Int, ...) : Int
end
2 changes: 0 additions & 2 deletions src/lib_c/aarch64-android/c/termios.cr
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,6 @@ lib LibC
c_cc : StaticArray(CcT, 19) # cc_t[NCCS]
end

# TODO: defined inline for `21 <= ANDROID_API < 28` in terms of `ioctl`, but
# `lib/reply/src/term_size.cr` contains an incompatible definition of it
{% if ANDROID_API >= 28 %}
fun tcgetattr(__fd : Int, __t : Termios*) : Int
fun tcsetattr(__fd : Int, __optional_actions : Int, __t : Termios*) : Int
Expand Down

0 comments on commit 1d0a7ab

Please sign in to comment.