From 32114a679a232feba18006c57cb8753446e56e7e Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Mon, 31 Jul 2023 10:28:45 +0300 Subject: [PATCH] os,term.termios: add termios.set_state/2, state.disable_echo/0, use them in os.input_password, to fix `v -os wasm32_emscripten examples/2048/` --- cmd/tools/check_os_api_parity.v | 2 +- vlib/os/password_nix.c.v | 12 ++- vlib/term/termios/termios_android.c.v | 14 +++- vlib/term/termios/termios_darwin.c.v | 12 +++ vlib/term/termios/termios_default.c.v | 73 ++++++++++++------- vlib/term/termios/termios_dragonfly.c.v | 12 +++ vlib/term/termios/termios_freebsd.c.v | 12 +++ vlib/term/termios/termios_linux.c.v | 14 +++- vlib/term/termios/termios_openbsd.c.v | 12 +++ vlib/term/termios/termios_qnx.c.v | 12 +++ vlib/term/termios/termios_solaris.c.v | 12 +++ .../{termios_test.c.v => termios_test.v} | 4 +- vlib/term/termios/termios_windows.c.v | 10 +++ 13 files changed, 161 insertions(+), 40 deletions(-) rename vlib/term/termios/{termios_test.c.v => termios_test.v} (80%) diff --git a/cmd/tools/check_os_api_parity.v b/cmd/tools/check_os_api_parity.v index 032f73d45c..d4561ef67e 100644 --- a/cmd/tools/check_os_api_parity.v +++ b/cmd/tools/check_os_api_parity.v @@ -12,7 +12,7 @@ import term const ( base_os = 'linux' - os_names = ['linux', 'macos', 'windows'] + os_names = ['linux', 'macos', 'windows', 'freebsd', 'openbsd', 'solaris', 'termux'] skip_modules = [ 'builtin.bare', 'builtin.linux_bare.old', diff --git a/vlib/os/password_nix.c.v b/vlib/os/password_nix.c.v index 84c14d2974..2ab3f66efd 100644 --- a/vlib/os/password_nix.c.v +++ b/vlib/os/password_nix.c.v @@ -13,17 +13,15 @@ pub fn input_password(prompt string) !string { if termios.tcgetattr(0, mut old_state) != 0 { return last_error() } - defer { - termios.tcsetattr(0, C.TCSANOW, mut old_state) - println('') - } mut new_state := old_state - - new_state.c_lflag &= termios.invert(C.ECHO) // Disable echoing of characters - termios.tcsetattr(0, C.TCSANOW, mut new_state) + new_state.disable_echo() + termios.set_state(0, new_state) password := input_opt(prompt) or { return error('Failed to read password') } + termios.set_state(0, old_state) + + println('') return password } diff --git a/vlib/term/termios/termios_android.c.v b/vlib/term/termios/termios_android.c.v index 4f1a5d695f..dc37096ff6 100644 --- a/vlib/term/termios/termios_android.c.v +++ b/vlib/term/termios/termios_android.c.v @@ -41,7 +41,7 @@ fn C.ioctl(fd int, request u64, arg voidptr) int // for the underlying C.termios structure [inline] pub fn flag(value int) TcFlag { - return int(value) + return TcFlag(value) } // invert is a platform dependant way to bitwise NOT (~) TcFlag @@ -86,3 +86,15 @@ pub fn ioctl(fd int, request u64, arg voidptr) int { return C.ioctl(fd, request, arg) } } + +// set_state applies the flags in the `new_state` to the descriptor `fd`. +pub fn set_state(fd int, new_state Termios) int { + mut x := new_state + return tcsetattr(0, C.TCSANOW, mut x) +} + +// disable_echo disables echoing characters as they are typed, +// when that Termios state is later set with termios.set_state(fd,t) +pub fn (mut t Termios) disable_echo() { + t.c_lflag &= invert(C.ECHO) +} diff --git a/vlib/term/termios/termios_darwin.c.v b/vlib/term/termios/termios_darwin.c.v index 6c24143f45..5509a10602 100644 --- a/vlib/term/termios/termios_darwin.c.v +++ b/vlib/term/termios/termios_darwin.c.v @@ -84,3 +84,15 @@ pub fn ioctl(fd int, request u64, arg voidptr) int { return C.ioctl(fd, request, arg) } } + +// set_state applies the flags in the `new_state` to the descriptor `fd`. +pub fn set_state(fd int, new_state Termios) int { + mut x := new_state + return tcsetattr(0, C.TCSANOW, mut x) +} + +// disable_echo disables echoing characters as they are typed, +// when that Termios state is later set with termios.set_state(fd,t) +pub fn (mut t Termios) disable_echo() { + t.c_lflag &= invert(C.ECHO) +} diff --git a/vlib/term/termios/termios_default.c.v b/vlib/term/termios/termios_default.c.v index 0e4691b730..2f44fc3333 100644 --- a/vlib/term/termios/termios_default.c.v +++ b/vlib/term/termios/termios_default.c.v @@ -1,12 +1,6 @@ // Copyright (c) 2019-2023 Alexander Medvednikov. All rights reserved. // Use of this source code is governed by an MIT license // that can be found in the LICENSE file. -// -// TODO Mac version needs to be implemented -// Will serve as more advanced input method -// based on the work of https://github.com/AmokHuginnsson/replxx -// - module termios // not used but needed for function declarations @@ -14,45 +8,68 @@ type TcFlag = int type Speed = int type Cc = u8 -// flag provides a termios flag of the correct size -// for the underlying C.termios structure -// It is only implemented for Unix like OSes -pub fn flag(value int) TcFlag { - $compile_error('feature not available') -} - -// invert is a platform dependant way to bitwise NOT (~) TcFlag -// as its length varies across platforms -// It is only implemented for Unix like OSes -pub fn invert(value TcFlag) TcFlag { - $compile_error('feature not available') -} - -// termios definitions +// Termios definitions // Linux https://github.com/lattera/glibc/blob/master/sysdeps/unix/sysv/linux/bits/termios.h // OpenBSD https://github.com/openbsd/src/blob/master/sys/sys/termios.h // FreeBSD https://web.mit.edu/freebsd/head/sys/sys/_termios.h // Solaris https://github.com/omniti-labs/illumos-omnios/blob/master/usr/src/uts/common/sys/termios.h // DragonFly https://gitweb.dragonflybsd.org/dragonfly.git/blob_plain/HEAD:/sys/sys/_termios.h // QNX https://github.com/vocho/openqnx/blob/master/trunk/lib/c/public/termios.h - pub struct Termios { +pub mut: + c_iflag TcFlag + c_oflag TcFlag + c_cflag TcFlag + c_lflag TcFlag + c_line Cc + c_cc [32]Cc + c_ispeed Speed + c_ospeed Speed +} + +// flag provides a termios flag of the correct size +// for the underlying C.termios structure +pub fn flag(value int) TcFlag { + return TcFlag(value) +} + +// invert is a platform dependant way to bitwise NOT (~) TcFlag +// as its length varies across platforms +// It is only implemented for Unix like OSes +pub fn invert(value TcFlag) TcFlag { + return TcFlag(~int(value)) } // tcgetattr is an unsafe wrapper around C.termios and keeps its semantic // It is only implemented for Unix like OSes -pub fn tcgetattr(fd int, mut termios_p Termios) int { - $compile_error('feature not available') +pub fn tcgetattr(fd int, mut t Termios) int { + $compile_warn('termios.tcgetattr is not implemented on the platform') + eprintln('tcgetattr, fd: ${fd}, t: ${t}') + return 0 } // tcsetattr is an unsafe wrapper around C.termios and keeps its semantic // It is only implemented for Unix like OSes -pub fn tcsetattr(fd int, optional_actions int, mut termios_p Termios) int { - $compile_error('feature not available') +pub fn tcsetattr(fd int, optional_actions int, mut t Termios) int { + eprintln('tcsetattr, fd: ${fd}, optional_actions: ${optional_actions}, t: ${t}') + return 0 } // ioctl is an unsafe wrapper around C.ioctl and keeps its semantic -[inline] +// It is only implemented for Unix like OSes pub fn ioctl(fd int, request u64, arg voidptr) int { - $compile_error('feature not available') + eprintln('ioctl, fd: ${fd}, request: ${request}, arg: ${arg}') + return 0 +} + +// set_state applies the flags in the `new_state` to the descriptor `fd`. +pub fn set_state(fd int, new_state Termios) int { + eprintln('set_state, fd: ${fd} | new_state: ${new_state}') + return 0 +} + +// disable_echo disables echoing characters as they are typed +// when that Termios state is later set with termios.set_state(fd,t) +pub fn (mut t Termios) disable_echo() { + t.c_lflag &= invert(8) } diff --git a/vlib/term/termios/termios_dragonfly.c.v b/vlib/term/termios/termios_dragonfly.c.v index c3ab4392d6..c2df2a5b69 100644 --- a/vlib/term/termios/termios_dragonfly.c.v +++ b/vlib/term/termios/termios_dragonfly.c.v @@ -84,3 +84,15 @@ pub fn ioctl(fd int, request u64, arg voidptr) int { return C.ioctl(fd, request, arg) } } + +// set_state applies the flags in the `new_state` to the descriptor `fd`. +pub fn set_state(fd int, new_state Termios) int { + mut x := new_state + return tcsetattr(0, C.TCSANOW, mut x) +} + +// disable_echo disables echoing characters as they are typed, +// when that Termios state is later set with termios.set_state(fd,t) +pub fn (mut t Termios) disable_echo() { + t.c_lflag &= invert(C.ECHO) +} diff --git a/vlib/term/termios/termios_freebsd.c.v b/vlib/term/termios/termios_freebsd.c.v index b37202ff04..1503dbf05c 100644 --- a/vlib/term/termios/termios_freebsd.c.v +++ b/vlib/term/termios/termios_freebsd.c.v @@ -84,3 +84,15 @@ pub fn ioctl(fd int, request u64, arg voidptr) int { return C.ioctl(fd, request, arg) } } + +// set_state applies the flags in the `new_state` to the descriptor `fd`. +pub fn set_state(fd int, new_state Termios) int { + mut x := new_state + return tcsetattr(0, C.TCSANOW, mut x) +} + +// disable_echo disables echoing characters as they are typed, +// when that Termios state is later set with termios.set_state(fd,t) +pub fn (mut t Termios) disable_echo() { + t.c_lflag &= invert(C.ECHO) +} diff --git a/vlib/term/termios/termios_linux.c.v b/vlib/term/termios/termios_linux.c.v index 4f1a5d695f..dc37096ff6 100644 --- a/vlib/term/termios/termios_linux.c.v +++ b/vlib/term/termios/termios_linux.c.v @@ -41,7 +41,7 @@ fn C.ioctl(fd int, request u64, arg voidptr) int // for the underlying C.termios structure [inline] pub fn flag(value int) TcFlag { - return int(value) + return TcFlag(value) } // invert is a platform dependant way to bitwise NOT (~) TcFlag @@ -86,3 +86,15 @@ pub fn ioctl(fd int, request u64, arg voidptr) int { return C.ioctl(fd, request, arg) } } + +// set_state applies the flags in the `new_state` to the descriptor `fd`. +pub fn set_state(fd int, new_state Termios) int { + mut x := new_state + return tcsetattr(0, C.TCSANOW, mut x) +} + +// disable_echo disables echoing characters as they are typed, +// when that Termios state is later set with termios.set_state(fd,t) +pub fn (mut t Termios) disable_echo() { + t.c_lflag &= invert(C.ECHO) +} diff --git a/vlib/term/termios/termios_openbsd.c.v b/vlib/term/termios/termios_openbsd.c.v index ac8d0c1451..a2c93b9143 100644 --- a/vlib/term/termios/termios_openbsd.c.v +++ b/vlib/term/termios/termios_openbsd.c.v @@ -84,3 +84,15 @@ pub fn ioctl(fd int, request u64, arg voidptr) int { return C.ioctl(fd, request, arg) } } + +// set_state applies the flags in the `new_state` to the descriptor `fd`. +pub fn set_state(fd int, new_state Termios) int { + mut x := new_state + return tcsetattr(0, C.TCSANOW, mut x) +} + +// disable_echo disables echoing characters as they are typed, +// when that Termios state is later set with termios.set_state(fd,t) +pub fn (mut t Termios) disable_echo() { + t.c_lflag &= invert(C.ECHO) +} diff --git a/vlib/term/termios/termios_qnx.c.v b/vlib/term/termios/termios_qnx.c.v index bbed284e9b..f2adbe5ea3 100644 --- a/vlib/term/termios/termios_qnx.c.v +++ b/vlib/term/termios/termios_qnx.c.v @@ -86,3 +86,15 @@ pub fn ioctl(fd int, request u64, arg voidptr) int { return C.ioctl(fd, request, arg) } } + +// set_state applies the flags in the `new_state` to the descriptor `fd`. +pub fn set_state(fd int, new_state Termios) int { + mut x := new_state + return tcsetattr(0, C.TCSANOW, mut x) +} + +// disable_echo disables echoing characters as they are typed, +// when that Termios state is later set with termios.set_state(fd,t) +pub fn (mut t Termios) disable_echo() { + t.c_lflag &= invert(C.ECHO) +} diff --git a/vlib/term/termios/termios_solaris.c.v b/vlib/term/termios/termios_solaris.c.v index bf3d5a235e..faffdc3545 100644 --- a/vlib/term/termios/termios_solaris.c.v +++ b/vlib/term/termios/termios_solaris.c.v @@ -80,3 +80,15 @@ pub fn ioctl(fd int, request u64, arg voidptr) int { return C.ioctl(fd, request, arg) } } + +// set_state applies the flags in the `new_state` to the descriptor `fd`. +pub fn set_state(fd int, new_state Termios) int { + mut x := new_state + return tcsetattr(0, C.TCSANOW, mut x) +} + +// disable_echo disables echoing characters as they are typed, +// when that Termios state is later set with termios.set_state(fd,t) +pub fn (mut t Termios) disable_echo() { + t.c_lflag &= invert(C.ECHO) +} diff --git a/vlib/term/termios/termios_test.c.v b/vlib/term/termios/termios_test.v similarity index 80% rename from vlib/term/termios/termios_test.c.v rename to vlib/term/termios/termios_test.v index d5461cecfe..8fe37b8f19 100644 --- a/vlib/term/termios/termios_test.c.v +++ b/vlib/term/termios/termios_test.v @@ -13,8 +13,8 @@ fn test_termios() { tcgetattr(0, mut check_term) assert check_term.c_lflag == silent_term.c_lflag - tcsetattr(0, C.TCSANOW, mut orginal_term) + tcsetattr(0, C.TCSANOW, mut original_term) tcgetattr(0, mut check_term) - assert check_term.c_lflag == orginal_term.c_lflag + assert check_term.c_lflag == original_term.c_lflag } diff --git a/vlib/term/termios/termios_windows.c.v b/vlib/term/termios/termios_windows.c.v index d5675d2511..632393e2dd 100644 --- a/vlib/term/termios/termios_windows.c.v +++ b/vlib/term/termios/termios_windows.c.v @@ -47,3 +47,13 @@ pub fn tcsetattr(fd int, optional_actions int, mut termios_p Termios) int { pub fn ioctl(fd int, request u64, arg voidptr) int { return -1 } + +// set_state applies the flags in the `new_state` to the descriptor `fd`. +pub fn set_state(fd int, new_state Termios) int { + return -1 +} + +// disable_echo disables echoing characters as they are typed, +// when that Termios state is later set with termios.set_state(fd,t) +pub fn (mut t Termios) disable_echo() { +}