From 20f9bdfa8ea345aa0038e5e16824a4bcabb630ff Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Sat, 27 Feb 2021 12:50:15 +0200 Subject: [PATCH] os: fixes for os.input(), os.get_raw_stdin(), os.get_raw_line() in case of stdin EOF --- vlib/builtin/cfns.c.v | 2 +- vlib/os/os.v | 21 ++++++++++++++++----- vlib/os/os_c.v | 29 ++++++++++++++++++----------- vlib/term/README.md | 11 +++++++---- 4 files changed, 42 insertions(+), 21 deletions(-) diff --git a/vlib/builtin/cfns.c.v b/vlib/builtin/cfns.c.v index 0907d79f99..5cb47e6e39 100644 --- a/vlib/builtin/cfns.c.v +++ b/vlib/builtin/cfns.c.v @@ -263,7 +263,7 @@ fn C._waccess() int fn C._wremove() int -fn C.ReadConsole() voidptr +fn C.ReadConsole(in_input_handle voidptr, out_buffer voidptr, in_chars_to_read u32, out_read_chars &u32, in_input_control voidptr) bool fn C.WriteConsole() voidptr diff --git a/vlib/os/os.v b/vlib/os/os.v index d0b7548a4a..c3c7341e10 100644 --- a/vlib/os/os.v +++ b/vlib/os/os.v @@ -200,11 +200,23 @@ pub fn file_name(path string) string { return path.all_after_last(path_separator) } -// input returns a one-line string from stdin, after printing a prompt. -pub fn input(prompt string) string { +// input_opt returns a one-line string from stdin, after printing a prompt. +// In the event of error (end of input), it returns `none`. +pub fn input_opt(prompt string) ?string { print(prompt) flush() - return get_line() + res := get_raw_line() + if res.len > 0 { + return res.trim_right('\r\n') + } + return none +} + +// input returns a one-line string from stdin, after printing a prompt. +// In the event of error (end of input), it returns ''. +pub fn input(prompt string) string { + res := input_opt(prompt) or { return '' } + return res } // get_line returns a one-line string from stdin @@ -212,9 +224,8 @@ pub fn get_line() string { str := get_raw_line() $if windows { return str.trim_right('\r\n') - } $else { - return str.trim_right('\n') } + return str.trim_right('\n') } // get_lines returns an array of strings read from from stdin. diff --git a/vlib/os/os_c.v b/vlib/os/os_c.v index 0af029a8f3..e48721c41d 100644 --- a/vlib/os/os_c.v +++ b/vlib/os/os_c.v @@ -476,14 +476,20 @@ pub fn get_raw_line() string { h_input := C.GetStdHandle(C.STD_INPUT_HANDLE) mut bytes_read := 0 if is_atty(0) > 0 { - C.ReadConsole(h_input, buf, max_line_chars * 2, C.LPDWORD(&bytes_read), + x := C.ReadConsole(h_input, buf, max_line_chars * 2, C.LPDWORD(&bytes_read), 0) + if !x { + return tos(buf, 0) + } return string_from_wide2(&u16(buf), bytes_read) } mut offset := 0 for { pos := buf + offset res := C.ReadFile(h_input, pos, 1, C.LPDWORD(&bytes_read), 0) + if !res && offset == 0 { + return tos(buf, 0) + } if !res || bytes_read == 0 { break } @@ -497,15 +503,9 @@ pub fn get_raw_line() string { } } $else { max := size_t(0) - mut buf := charptr(0) + buf := charptr(0) nr_chars := unsafe { C.getline(&buf, &max, C.stdin) } - // defer { unsafe{ free(buf) } } - if nr_chars == 0 || nr_chars == -1 { - return '' - } - return unsafe { tos3(buf) } - // res := tos_clone(buf) - // return res + return unsafe { tos(byteptr(buf), if nr_chars < 0 { 0 } else { nr_chars }) } } } @@ -527,7 +527,6 @@ pub fn get_raw_stdin() []byte { } buf = v_realloc(buf, offset + block_bytes + (block_bytes - bytes_read)) } - C.CloseHandle(h_input) return array{ element_size: 1 data: voidptr(buf) @@ -536,7 +535,15 @@ pub fn get_raw_stdin() []byte { } } } $else { - panic('get_raw_stdin not implemented on this platform...') + max := size_t(0) + buf := charptr(0) + nr_chars := unsafe { C.getline(&buf, &max, C.stdin) } + return array{ + element_size: 1 + data: voidptr(buf) + len: if nr_chars < 0 { 0 } else { nr_chars } + cap: int(max) + } } } diff --git a/vlib/term/README.md b/vlib/term/README.md index 5a9a42ac30..870822662e 100644 --- a/vlib/term/README.md +++ b/vlib/term/README.md @@ -22,15 +22,18 @@ fn main() { term.set_cursor_position(x: width / 2, y: height / 2) // now we point the cursor to the middle of the terminal println(term.strikethrough(term.bright_green('hello world'))) // Print green text term.set_cursor_position(x: 0, y: height) // Sets the position of the cursor to the bottom of the terminal - mut var := os.input('press q to quit: ') // Keep prompting until the user presses the q key for { - if var == 'q' { + if var := os.input_opt('press q to quit: ') { + if var != 'q' { + continue + } break - } else { - var = os.input('press q to quit: ') } + println('') + break } + println('Goodbye.') } ```