From dc96eb95ba0f24fa68aba040718b86bfe2280a33 Mon Sep 17 00:00:00 2001 From: Hitalo Souza Date: Sat, 10 Jan 2026 15:23:00 +0000 Subject: [PATCH] os: add Pipe.write_string/1 (#26286) --- vlib/os/notify/notify_test.c.v | 88 ++++++++++++++------------------- vlib/os/pipe.c.v | 11 ++++- vlib/term/ui/termios_nix_test.v | 38 ++++++-------- 3 files changed, 62 insertions(+), 75 deletions(-) diff --git a/vlib/os/notify/notify_test.c.v b/vlib/os/notify/notify_test.c.v index c00f638e2..791d78e0f 100644 --- a/vlib/os/notify/notify_test.c.v +++ b/vlib/os/notify/notify_test.c.v @@ -3,34 +3,21 @@ import os import os.notify -// make a pipe and return the (read, write) file descriptors -fn make_pipe() !(int, int) { - $if linux || macos { - pipefd := [2]int{} - if C.pipe(&pipefd[0]) != 0 { - return error('error ${C.errno}: ' + os.posix_get_error_msg(C.errno)) - } - return pipefd[0], pipefd[1] - } - return -1, -1 -} - fn test_level_trigger() { // currently only linux and macos are supported $if linux || macos { mut notifier := notify.new()! - reader, writer := make_pipe()! + mut pipe := os.pipe()! defer { - os.fd_close(reader) - os.fd_close(writer) + pipe.close() notifier.close() or {} } - notifier.add(reader, .read)! + notifier.add(pipe.read_fd, .read)! - os.fd_write(writer, 'foobar') + pipe.write_string('foobar')! mut n := ¬ifier - check_read_event(mut n, reader, 'foo') - check_read_event(mut n, reader, 'bar') + check_read_event(mut n, pipe.read_fd, 'foo') + check_read_event(mut n, pipe.read_fd, 'bar') assert notifier.wait(0).len == 0 } @@ -40,18 +27,17 @@ fn test_edge_trigger() { // currently only linux and macos are supported $if linux || macos { mut notifier := notify.new()! - reader, writer := make_pipe()! + mut pipe := os.pipe()! defer { - os.fd_close(reader) - os.fd_close(writer) + pipe.close() notifier.close() or {} } - notifier.add(reader, .read, .edge_trigger)! + notifier.add(pipe.read_fd, .read, .edge_trigger)! mut n := ¬ifier - os.fd_write(writer, 'foobar') - check_read_event(mut n, reader, 'foo') + pipe.write_string('foobar')! + check_read_event(mut n, pipe.read_fd, 'foo') $if linux { assert notifier.wait(0).len == 0 @@ -75,7 +61,8 @@ fn test_edge_trigger() { // notifier.wait(0).len == 1 or 0 } - os.fd_write(writer, 'baz') + pipe.write_string('baz')! + check_read_event(mut n, pipe.read_fd, 'barbaz') // we do not get an event because there is still data // to be read // assert notifier.wait(0).len == 0 @@ -87,25 +74,24 @@ fn test_edge_trigger() { fn test_one_shot() { $if linux || macos { mut notifier := notify.new()! - reader, writer := make_pipe()! + mut pipe := os.pipe()! defer { - os.fd_close(reader) - os.fd_close(writer) + pipe.close() notifier.close() or {} } - notifier.add(reader, .read, .one_shot)! + notifier.add(pipe.read_fd, .read, .one_shot)! mut n := ¬ifier - os.fd_write(writer, 'foobar') - check_read_event(mut n, reader, 'foo') - os.fd_write(writer, 'baz') + pipe.write_string('foobar')! + check_read_event(mut n, pipe.read_fd, 'foo') + pipe.write_string('baz')! assert notifier.wait(0).len == 0 // rearm - notifier.modify(reader, .read)! - check_read_event(mut n, reader, 'barbaz') + notifier.modify(pipe.read_fd, .read)! + check_read_event(mut n, pipe.read_fd, 'barbaz') } } @@ -113,21 +99,21 @@ fn test_one_shot() { fn test_hangup() { $if linux { mut notifier := notify.new()! - reader, writer := make_pipe()! + mut pipe := os.pipe()! defer { - os.fd_close(reader) + os.fd_close(pipe.read_fd) notifier.close() or {} } - notifier.add(reader, .hangup)! + notifier.add(pipe.read_fd, .hangup)! assert notifier.wait(0).len == 0 // closing on the writer end of the pipe will // cause a hangup on the reader end - os.fd_close(writer) + os.fd_close(pipe.write_fd) events := notifier.wait(0) assert events.len == 1 - assert events[0].fd == reader + assert events[0].fd == pipe.read_fd assert events[0].kind.has(.hangup) } } @@ -135,20 +121,19 @@ fn test_hangup() { fn test_write() { $if linux || macos { mut notifier := notify.new()! - reader, writer := make_pipe()! + mut pipe := os.pipe()! defer { - os.fd_close(reader) - os.fd_close(writer) + pipe.close() notifier.close() or {} } - notifier.add(reader, .write)! + notifier.add(pipe.read_fd, .write)! assert notifier.wait(0).len == 0 - notifier.add(writer, .write)! + notifier.add(pipe.write_fd, .write)! events := notifier.wait(0) assert events.len == 1 - assert events[0].fd == writer + assert events[0].fd == pipe.write_fd assert events[0].kind.has(.write) } } @@ -156,21 +141,20 @@ fn test_write() { fn test_remove() { $if linux || macos { mut notifier := notify.new()! - reader, writer := make_pipe()! + mut pipe := os.pipe()! defer { - os.fd_close(reader) - os.fd_close(writer) + pipe.close() notifier.close() or {} } // level triggered - will keep getting events while // there is data to read - notifier.add(reader, .read)! - os.fd_write(writer, 'foobar') + notifier.add(pipe.read_fd, .read)! + pipe.write_string('foobar')! assert notifier.wait(0).len == 1 assert notifier.wait(0).len == 1 - notifier.remove(reader)! + notifier.remove(pipe.read_fd)! assert notifier.wait(0).len == 0 } } diff --git a/vlib/os/pipe.c.v b/vlib/os/pipe.c.v index b176318c6..a5236e438 100644 --- a/vlib/os/pipe.c.v +++ b/vlib/os/pipe.c.v @@ -23,7 +23,7 @@ pub fn fd_dup2(fd1 int, fd2 int) int { // Pipe represents a bidirectional communication channel @[noinit] pub struct Pipe { -mut: +pub mut: read_fd int = -1 write_fd int = -1 } @@ -77,6 +77,15 @@ pub fn (p &Pipe) write(buffer []u8) !int { return result } +// write_string writes data from the string to the pipe +pub fn (p &Pipe) write_string(s string) !int { + result := C.write(p.write_fd, voidptr(s.str), s.len) + if result == -1 { + return error('Write failed') + } + return result +} + // slurp reads all data from the pipe until EOF pub fn (mut p Pipe) slurp() []string { // Close write end to send EOF signal to the pipe diff --git a/vlib/term/ui/termios_nix_test.v b/vlib/term/ui/termios_nix_test.v index d35181793..ab7049808 100644 --- a/vlib/term/ui/termios_nix_test.v +++ b/vlib/term/ui/termios_nix_test.v @@ -1,29 +1,27 @@ module ui +import os + fn test_get_cursor_position_reads_valid_row_column_data() ! { - mut pipeset := [0, 0] mut original_stdin_fd := -1 unsafe { - if C.pipe(&pipeset[0]) == -1 { - return error('unable to create pipe: ${C.strerror(C.errno)}') - } + mut pipe := os.pipe()! fake_cursor_pos_data := '\033[45;70R' - written_bytes := C.write(pipeset[1], fake_cursor_pos_data.str, fake_cursor_pos_data.len) + written_bytes := pipe.write_string(fake_cursor_pos_data)! if written_bytes == -1 { - C.close(pipeset[0]) - C.close(pipeset[1]) + pipe.close() return error('error writing into pipe: ${C.strerror(C.errno)}') } - C.close(pipeset[1]) + C.close(pipe.write_fd) - if C.dup2(pipeset[0], C.STDIN_FILENO) == -1 { - C.close(pipeset[0]) + if C.dup2(pipe.read_fd, C.STDIN_FILENO) == -1 { + C.close(pipe.read_fd) return error('error redirecting stdin with dup2: ${C.strerror(C.errno)}') } - C.close(pipeset[0]) + C.close(pipe.read_fd) cursor_pos_x, cursor_pos_y := get_cursor_position() assert cursor_pos_x == 45 @@ -32,29 +30,25 @@ fn test_get_cursor_position_reads_valid_row_column_data() ! { } fn test_get_cursor_position_reads_empty_position_data() ! { - mut pipeset := [0, 0] mut original_stdin_fd := -1 unsafe { - if C.pipe(&pipeset[0]) == -1 { - return error('unable to create pipe: ${C.strerror(C.errno)}') - } + mut pipe := os.pipe()! fake_cursor_pos_data := '' - written_bytes := C.write(pipeset[1], fake_cursor_pos_data.str, fake_cursor_pos_data.len) + written_bytes := pipe.write_string(fake_cursor_pos_data)! if written_bytes == -1 { - C.close(pipeset[0]) - C.close(pipeset[1]) + pipe.close() return error('error writing into pipe: ${C.strerror(C.errno)}') } - C.close(pipeset[1]) + C.close(pipe.write_fd) - if C.dup2(pipeset[0], C.STDIN_FILENO) == -1 { - C.close(pipeset[0]) + if C.dup2(pipe.read_fd, C.STDIN_FILENO) == -1 { + C.close(pipe.read_fd) return error('error redirecting stdin with dup2: ${C.strerror(C.errno)}') } - C.close(pipeset[0]) + C.close(pipe.read_fd) cursor_pos_x, cursor_pos_y := get_cursor_position() assert cursor_pos_x == -1 -- 2.39.5