v/vlib/os/file.c.v

183 lines
4.1 KiB
V

module os
pub struct File {
cfile voidptr // Using void* instead of FILE*
pub:
fd int
pub mut:
is_opened bool
}
struct FileInfo {
name string
size int
}
// **************************** Write ops ***************************
// write implements the Writer interface
pub fn (mut f File) write(buf []byte) ?int {
if !f.is_opened {
return error('file is not opened')
}
/*
$if linux {
$if !android {
C.syscall(sys_write, f.fd, s.str, s.len)
return
}
}
*/
written := int(C.fwrite(buf.data, buf.len, 1, f.cfile))
if written == 0 && buf.len != 0 {
return error('0 bytes written')
}
return written
}
pub fn (mut f File) writeln(s string) ?int {
if !f.is_opened {
return error('file is not opened')
}
/*
$if linux {
$if !android {
snl := s + '\n'
C.syscall(sys_write, f.fd, snl.str, snl.len)
return
}
}
*/
// TODO perf
written := int(C.fwrite(s.str, s.len, 1, f.cfile))
if written == 0 && s.len != 0 {
return error('0 bytes written')
}
x := C.fputs('\n', f.cfile)
if x < 0 {
return error('could not add newline')
}
return (written + 1)
}
pub fn (mut f File) write_string(s string) ?int {
if !f.is_opened {
return error('file is not opened')
}
// TODO perf
written := int(C.fwrite(s.str, s.len, 1, f.cfile))
if written == 0 && s.len != 0 {
return error('0 bytes written')
}
return written
}
// write_to implements the RandomWriter interface
pub fn (mut f File) write_to(pos int, buf []byte) ?int {
C.fseek(f.cfile, pos, C.SEEK_SET)
res := int(C.fwrite(buf.data, 1, buf.len, f.cfile))
C.fseek(f.cfile, 0, C.SEEK_END)
return res
}
[unsafe]
pub fn (mut f File) write_bytes(data voidptr, size int) int {
return int(C.fwrite(data, 1, size, f.cfile))
}
[unsafe]
pub fn (mut f File) write_bytes_at(data voidptr, size int, pos int) int {
C.fseek(f.cfile, pos, C.SEEK_SET)
res := int(C.fwrite(data, 1, size, f.cfile))
C.fseek(f.cfile, 0, C.SEEK_END)
return res
}
// **************************** Read ops ***************************
// read_bytes reads bytes from the beginning of the file
pub fn (f &File) read_bytes(size int) []byte {
return f.read_bytes_at(size, 0)
}
// read_bytes_at reads bytes at the given position in the file
pub fn (f &File) read_bytes_at(size int, pos int) []byte {
mut arr := []byte{len: size}
nreadbytes := f.read_bytes_into(pos, mut arr) or {
// return err
return []
}
return arr[0..nreadbytes]
}
// read_bytes_into fills `buf` with bytes at the given position in the file.
// `buf` must have length greater than zero.
// Returns number of bytes read or an error.
pub fn (f &File) read_bytes_into(pos int, mut buf []byte) ?int {
if buf.len == 0 {
panic(@FN + ': `buf.len` == 0')
}
// Note: fseek errors if pos == os.file_size, which we accept
C.fseek(f.cfile, pos, C.SEEK_SET)
// errno is only set if fread fails, so clear it first to tell
C.errno = 0
nbytes := int(C.fread(buf.data, 1, buf.len, f.cfile))
if C.errno != 0 {
return error(posix_get_error_msg(C.errno))
}
$if debug {
C.fseek(f.cfile, 0, C.SEEK_SET)
}
return nbytes
}
// read implements the Reader interface
pub fn (f &File) read(mut buf []byte) ?int {
if buf.len == 0 {
return 0
}
C.errno = 0
nbytes := int(C.fread(buf.data, 1, buf.len, f.cfile))
if C.errno != 0 {
return error(posix_get_error_msg(C.errno))
}
return nbytes
}
// read_at reads buf.len bytes from pos in the file
pub fn (f &File) read_at(pos int, mut buf []byte) ?int {
if buf.len == 0 {
return 0
}
C.fseek(f.cfile, pos, C.SEEK_SET)
C.errno = 0
nbytes := int(C.fread(buf.data, 1, buf.len, f.cfile))
if C.errno != 0 {
return error(posix_get_error_msg(C.errno))
}
return nbytes
}
// **************************** Utility ops ***********************
// flush writes any unwritten data in stream's buffer
pub fn (mut f File) flush() {
if !f.is_opened {
return
}
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
}
}
pub fn (mut f File) write_str(s string) ? {
if !f.is_opened {
return error('file is closed')
}
f.write(s.bytes()) ?
}