diff --git a/vlib/os/file.v b/vlib/os/file.v index 28a5d23d52..6b5d2758d3 100644 --- a/vlib/os/file.v +++ b/vlib/os/file.v @@ -1,5 +1,7 @@ module os +import strings + pub struct File { cfile voidptr // Using void* instead of FILE* pub: @@ -88,3 +90,63 @@ pub fn (mut f File) flush() { } C.fflush(f.cfile) } + +// open_stdin - return an os.File for stdin, so that you can use .get_line on it too. +pub fn open_stdin() File { + return File{ + fd: 0 + cfile: C.stdin + is_opened: true + } +} + +// File.get_line - get a single line from the file. NB: the ending newline is *included*. +pub fn (mut f File) get_line() ?string { + if !f.is_opened { + return error('file is closed') + } + $if !windows { + mut zbuf := byteptr(0) + mut zblen := size_t(0) + mut zx := 0 + unsafe { + zx = C.getline(&zbuf, &zblen, f.cfile) + if zx == -1 { + C.free(zbuf) + if C.errno == 0 { + return error('end of file') + } + return error(posix_get_error_msg(C.errno)) + } + return zbuf.vstring_with_len(zx) + } + } + // + // using C.fgets is less efficient than f.get_line_getline, + // but is available everywhere, while C.getline does not work + // on windows + // + buf := [4096]byte{} + mut res := strings.new_builder(1024) + mut x := 0 + for { + unsafe { + x = C.fgets(charptr(buf), 4096, f.cfile) + } + if x == 0 { + if res.len > 0 { + break + } + return error('end of file') + } + bufbp := byteptr(buf) + mut blen := vstrlen(bufbp) + res.write_bytes(bufbp, blen) + unsafe { + if blen == 0 || bufbp[blen-1] == `\n` || bufbp[blen-1] == `\r` { + break + } + } + } + return res.str() +} diff --git a/vlib/os/os.v b/vlib/os/os.v index 2e69851944..6bf2f0f6cf 100644 --- a/vlib/os/os.v +++ b/vlib/os/os.v @@ -928,7 +928,7 @@ pub fn executable() string { eprintln('os.executable() failed at reading /proc/curproc/exe to get exe path') return executable_fallback() } - return result.vstring_with_len(count) + return unsafe { result.vstring_with_len(count) } } $if dragonfly { mut result := vcalloc(max_path_len) diff --git a/vlib/os/os_test.v b/vlib/os/os_test.v index 535b86b88d..bfebb9c0ed 100644 --- a/vlib/os/os_test.v +++ b/vlib/os/os_test.v @@ -43,6 +43,23 @@ fn test_open_file() { os.rm(filename) } +fn test_file_get_line() { + filename := './fgetline.txt' + os.write_file(filename, 'line 1\nline 2') + mut f := os.open_file(filename, 'r', 0) or { + assert false + return + } + line1 := f.get_line() or { '' } + line2 := f.get_line() or { '' } + f.close() + // + //eprintln('line1: $line1') + //eprintln('line2: $line2') + assert line1 == 'line 1\n' + assert line2 == 'line 2' +} + fn test_create_file() { filename := './test1.txt' hello := 'hello world!'