module os // low level operations with file descriptors/handles $if !windows { #include } $if windows { #include } #flag windows -lws2_32 // fd_close closes the file descriptor. It returns 0 on success. pub fn fd_close(fd int) int { if fd == -1 { return 0 } return C.close(fd) } // fd_write writes the given string to the file descriptor. // It blocks until all the data in the string is written. pub fn fd_write(fd int, s string) { if fd == -1 { return } mut sp := s.str mut remaining := s.len for remaining > 0 { written := C.write(fd, sp, remaining) if written < 0 { return } remaining = remaining - written sp = unsafe { voidptr(sp + written) } } } // fd_slurp reads all the remaining data from the file descriptor. pub fn fd_slurp(fd int) []string { mut res := []string{} if fd == -1 { return res } for { s, b := fd_read(fd, 4096) if b <= 0 { break } res << s } return res } // fd_read reads data from the file descriptor. It returns the read data, and how many bytes were read. pub fn fd_read(fd int, maxbytes int) (string, int) { if fd == -1 { return '', 0 } unsafe { mut buf := malloc_noscan(maxbytes + 1) nbytes := C.read(fd, buf, maxbytes) if nbytes < 0 { free(buf) return '', nbytes } buf[nbytes] = 0 return tos(buf, nbytes), nbytes } } [typedef] pub struct C.fd_set {} pub struct C.timeval { tv_sec u64 tv_usec u64 } fn C.@select(ndfs int, readfds &C.fd_set, writefds &C.fd_set, exceptfds &C.fd_set, timeout &C.timeval) int // These are C macros, but from the V's point of view, can be treated as C functions: fn C.FD_ZERO(fdset &C.fd_set) fn C.FD_SET(fd int, fdset &C.fd_set) fn C.FD_ISSET(fd int, fdset &C.fd_set) int // fd_is_pending returns true, when there is pending data, waiting to be read from file descriptor `fd`. // If the file descriptor is closed, or if reading from it, will block (there is no data), fd_is_pending returns false. pub fn fd_is_pending(fd int) bool { read_set := C.fd_set{} C.FD_ZERO(&read_set) C.FD_SET(fd, &read_set) mut ts := C.timeval{ tv_sec: 0 tv_usec: 0 } res := C.@select(fd + 1, &read_set, C.NULL, C.NULL, &ts) if res > 0 { if C.FD_ISSET(fd, &read_set) != 0 { return true } } return false }