1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

os: add File.reopen and File.eof methods (#15184)

This commit is contained in:
Reuben Thomas 2022-07-28 14:21:23 +01:00 committed by GitHub
parent 3d0a48b1bb
commit ed56c3957e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 90 additions and 24 deletions

View File

@ -1,6 +1,7 @@
module os module os
pub struct File { pub struct File {
mut:
cfile voidptr // Using void* instead of FILE* cfile voidptr // Using void* instead of FILE*
pub: pub:
fd int fd int
@ -19,6 +20,18 @@ fn C._fseeki64(&C.FILE, u64, int) int
fn C.getc(&C.FILE) int fn C.getc(&C.FILE) int
fn C.freopen(&char, &char, &C.FILE) &C.FILE
fn C._wfreopen(&u16, &u16, &C.FILE) &C.FILE
fn fix_windows_path(path string) string {
mut p := path
$if windows {
p = path.replace('/', '\\')
}
return p
}
// open_file can be used to open or create a file with custom flags and permissions and returns a `File` object. // open_file can be used to open or create a file with custom flags and permissions and returns a `File` object.
pub fn open_file(path string, mode string, options ...int) ?File { pub fn open_file(path string, mode string, options ...int) ?File {
mut flags := 0 mut flags := 0
@ -55,10 +68,7 @@ pub fn open_file(path string, mode string, options ...int) ?File {
permission = 0x0100 | 0x0080 permission = 0x0100 | 0x0080
} }
} }
mut p := path p := fix_windows_path(path)
$if windows {
p = path.replace('/', '\\')
}
fd := C.open(&char(p.str), flags, permission) fd := C.open(&char(p.str), flags, permission)
if fd == -1 { if fd == -1 {
return error(posix_get_error_msg(C.errno)) return error(posix_get_error_msg(C.errno))
@ -160,6 +170,26 @@ pub fn stderr() File {
} }
} }
// eof returns true, when the end of file has been reached
pub fn (f &File) eof() bool {
return C.feof(f.cfile) != 0
}
// reopen allows a `File` to be reused. It is mostly useful for reopening standard input and output.
pub fn (mut f File) reopen(path string, mode string) ? {
p := fix_windows_path(path)
mut cfile := &C.FILE(0)
$if windows {
cfile = C._wfreopen(p.to_wide(), mode.to_wide(), f.cfile)
} $else {
cfile = C.freopen(&char(p.str), &char(mode.str), f.cfile)
}
if isnil(cfile) {
return error('Failed to reopen file "$path"')
}
f.cfile = cfile
}
// read implements the Reader interface. // read implements the Reader interface.
pub fn (f &File) read(mut buf []u8) ?int { pub fn (f &File) read(mut buf []u8) ?int {
if buf.len == 0 { if buf.len == 0 {

View File

@ -1,5 +1,21 @@
import os import os
const tfolder = os.join_path(os.temp_dir(), 'v', 'tests', 'os_file_test')
const tfile = os.join_path_single(tfolder, 'test_file')
fn testsuite_begin() ? {
os.rmdir_all(tfolder) or {}
assert !os.is_dir(tfolder)
os.mkdir_all(tfolder)?
os.chdir(tfolder)?
assert os.is_dir(tfolder)
}
fn testsuite_end() ? {
os.rmdir_all(tfolder) or {}
}
struct Point { struct Point {
x f64 x f64
y f64 y f64
@ -40,25 +56,6 @@ const (
another_permission = Permissions.read | .write another_permission = Permissions.read | .write
) )
const (
tfolder = os.join_path_single(os.temp_dir(), 'os_file_test')
tfile = os.join_path_single(tfolder, 'test_file')
)
fn testsuite_begin() ? {
os.rmdir_all(tfolder) or {}
assert !os.is_dir(tfolder)
os.mkdir_all(tfolder)?
os.chdir(tfolder)?
assert os.is_dir(tfolder)
}
fn testsuite_end() ? {
os.chdir(os.wd_at_startup)?
os.rmdir_all(tfolder)?
assert !os.is_dir(tfolder)
}
// test_read_bytes_into_newline_text tests reading text from a file with newlines. // test_read_bytes_into_newline_text tests reading text from a file with newlines.
// This test simulates reading a larger text file step by step into a buffer and // This test simulates reading a larger text file step by step into a buffer and
// returning on each newline, even before the buffer is full, and reaching EOF before // returning on each newline, even before the buffer is full, and reaching EOF before
@ -370,3 +367,42 @@ fn test_tell() ? {
assert pos == size - 5 assert pos == size - 5
} }
} }
fn test_reopen() ? {
tfile1 := os.join_path_single(tfolder, 'tfile1')
tfile2 := os.join_path_single(tfolder, 'tfile2')
os.write_file(tfile1, 'Hello World!\nGood\r morning.\nBye 1.')?
os.write_file(tfile2, 'Another file\nAnother line.\nBye 2.')?
assert os.file_size(tfile1) > 0
assert os.file_size(tfile2) > 0
mut line_buffer := []u8{len: 1024}
mut f2 := os.open(tfile2)?
x := f2.read_bytes_into_newline(mut line_buffer)?
assert !f2.eof()
assert x > 0
assert line_buffer#[..x].bytestr() == 'Another file\n'
// Note: after this call, f2 should be using the file `tfile1`:
f2.reopen(tfile1, 'r')?
assert !f2.eof()
z := f2.read(mut line_buffer)?
assert f2.eof()
assert z > 0
content := line_buffer#[..z].bytestr()
// dump(content)
assert content.starts_with('Hello World')
assert content.ends_with('Bye 1.')
}
fn test_eof() ? {
os.write_file(tfile, 'Hello World!\n')?
mut f := os.open(tfile)?
f.read_bytes(10)
assert !f.eof()
f.read_bytes(100)
assert f.eof()
}

View File

@ -27,7 +27,7 @@ fn testsuite_begin() {
fn testsuite_end() { fn testsuite_end() {
os.chdir(os.wd_at_startup) or {} os.chdir(os.wd_at_startup) or {}
os.rmdir_all(tfolder) or {} os.rmdir_all(tfolder) or {}
assert !os.is_dir(tfolder) // assert !os.is_dir(tfolder)
// eprintln('testsuite_end , tfolder = $tfolder removed.') // eprintln('testsuite_end , tfolder = $tfolder removed.')
} }