os: move file methods to vlib/os/file.c.v, document them, add new file.read_struct and file.write_struct and tests
parent
6097045b46
commit
5e0e44eb69
|
@ -20,7 +20,7 @@ fn read_file(file string, cap int) []string {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_file_reader() {
|
fn test_file_reader() {
|
||||||
for cap := 64; cap <= 10000; cap += 256 {
|
for cap := 1; cap <= 10000; cap += 256 {
|
||||||
lines := read_file(@FILE, cap)
|
lines := read_file(@FILE, cap)
|
||||||
assert lines.last() == '// my last line'
|
assert lines.last() == '// my last line'
|
||||||
}
|
}
|
||||||
|
|
215
vlib/os/file.c.v
215
vlib/os/file.c.v
|
@ -13,8 +13,132 @@ struct FileInfo {
|
||||||
size int
|
size int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
mut flags := 0
|
||||||
|
for m in mode {
|
||||||
|
match m {
|
||||||
|
`w` { flags |= o_create | o_trunc }
|
||||||
|
`a` { flags |= o_create | o_append }
|
||||||
|
`r` { flags |= o_rdonly }
|
||||||
|
`b` { flags |= o_binary }
|
||||||
|
`s` { flags |= o_sync }
|
||||||
|
`n` { flags |= o_nonblock }
|
||||||
|
`c` { flags |= o_noctty }
|
||||||
|
`+` { flags |= o_rdwr }
|
||||||
|
else {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if mode == 'r+' {
|
||||||
|
flags = o_rdwr
|
||||||
|
}
|
||||||
|
if mode == 'w' {
|
||||||
|
flags = o_wronly | o_create | o_trunc
|
||||||
|
}
|
||||||
|
if mode == 'a' {
|
||||||
|
flags = o_wronly | o_create | o_append
|
||||||
|
}
|
||||||
|
mut permission := 0o666
|
||||||
|
if options.len > 0 {
|
||||||
|
permission = options[0]
|
||||||
|
}
|
||||||
|
$if windows {
|
||||||
|
if permission < 0o600 {
|
||||||
|
permission = 0x0100
|
||||||
|
} else {
|
||||||
|
permission = 0x0100 | 0x0080
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mut p := path
|
||||||
|
$if windows {
|
||||||
|
p = path.replace('/', '\\')
|
||||||
|
}
|
||||||
|
fd := C.open(charptr(p.str), flags, permission)
|
||||||
|
if fd == -1 {
|
||||||
|
return error(posix_get_error_msg(C.errno))
|
||||||
|
}
|
||||||
|
cfile := C.fdopen(fd, charptr(mode.str))
|
||||||
|
if isnil(cfile) {
|
||||||
|
return error('Failed to open or create file "$path"')
|
||||||
|
}
|
||||||
|
return File{
|
||||||
|
cfile: cfile
|
||||||
|
fd: fd
|
||||||
|
is_opened: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// open tries to open a file for reading and returns back a read-only `File` object.
|
||||||
|
pub fn open(path string) ?File {
|
||||||
|
/*
|
||||||
|
$if linux {
|
||||||
|
$if !android {
|
||||||
|
fd := C.syscall(sys_open, path.str, 511)
|
||||||
|
if fd == -1 {
|
||||||
|
return error('failed to open file "$path"')
|
||||||
|
}
|
||||||
|
return File{
|
||||||
|
fd: fd
|
||||||
|
is_opened: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
cfile := vfopen(path, 'rb') ?
|
||||||
|
fd := fileno(cfile)
|
||||||
|
return File{
|
||||||
|
cfile: cfile
|
||||||
|
fd: fd
|
||||||
|
is_opened: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// create creates or opens a file at a specified location and returns a write-only `File` object.
|
||||||
|
pub fn create(path string) ?File {
|
||||||
|
/*
|
||||||
|
// NB: android/termux/bionic is also a kind of linux,
|
||||||
|
// but linux syscalls there sometimes fail,
|
||||||
|
// while the libc version should work.
|
||||||
|
$if linux {
|
||||||
|
$if !android {
|
||||||
|
//$if macos {
|
||||||
|
// fd = C.syscall(398, path.str, 0x601, 0x1b6)
|
||||||
|
//}
|
||||||
|
//$if linux {
|
||||||
|
fd = C.syscall(sys_creat, path.str, 511)
|
||||||
|
//}
|
||||||
|
if fd == -1 {
|
||||||
|
return error('failed to create file "$path"')
|
||||||
|
}
|
||||||
|
file = File{
|
||||||
|
fd: fd
|
||||||
|
is_opened: true
|
||||||
|
}
|
||||||
|
return file
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
cfile := vfopen(path, 'wb') ?
|
||||||
|
fd := fileno(cfile)
|
||||||
|
return File{
|
||||||
|
cfile: cfile
|
||||||
|
fd: fd
|
||||||
|
is_opened: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// **************************** Write ops ***************************
|
// **************************** Write ops ***************************
|
||||||
// write implements the Writer interface
|
// write implements the Writer interface.
|
||||||
|
// It returns how many bytes were actually written.
|
||||||
pub fn (mut f File) write(buf []byte) ?int {
|
pub fn (mut f File) write(buf []byte) ?int {
|
||||||
if !f.is_opened {
|
if !f.is_opened {
|
||||||
return error('file is not opened')
|
return error('file is not opened')
|
||||||
|
@ -22,8 +146,8 @@ pub fn (mut f File) write(buf []byte) ?int {
|
||||||
/*
|
/*
|
||||||
$if linux {
|
$if linux {
|
||||||
$if !android {
|
$if !android {
|
||||||
C.syscall(sys_write, f.fd, s.str, s.len)
|
res := C.syscall(sys_write, f.fd, s.str, s.len)
|
||||||
return
|
return res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
@ -34,6 +158,8 @@ pub fn (mut f File) write(buf []byte) ?int {
|
||||||
return written
|
return written
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// writeln writes the string `s` into the file, and appends a \n character.
|
||||||
|
// It returns how many bytes were written, including the \n character.
|
||||||
pub fn (mut f File) writeln(s string) ?int {
|
pub fn (mut f File) writeln(s string) ?int {
|
||||||
if !f.is_opened {
|
if !f.is_opened {
|
||||||
return error('file is not opened')
|
return error('file is not opened')
|
||||||
|
@ -59,6 +185,8 @@ pub fn (mut f File) writeln(s string) ?int {
|
||||||
return (written + 1)
|
return (written + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// write_string writes the string `s` into the file
|
||||||
|
// It returns how many bytes were actually written.
|
||||||
pub fn (mut f File) write_string(s string) ?int {
|
pub fn (mut f File) write_string(s string) ?int {
|
||||||
if !f.is_opened {
|
if !f.is_opened {
|
||||||
return error('file is not opened')
|
return error('file is not opened')
|
||||||
|
@ -71,19 +199,34 @@ pub fn (mut f File) write_string(s string) ?int {
|
||||||
return written
|
return written
|
||||||
}
|
}
|
||||||
|
|
||||||
// write_to implements the RandomWriter interface
|
// write_to implements the RandomWriter interface.
|
||||||
|
// It returns how many bytes were actually written.
|
||||||
|
// It resets the seek position to the end of the file.
|
||||||
pub fn (mut f File) write_to(pos int, buf []byte) ?int {
|
pub fn (mut f File) write_to(pos int, buf []byte) ?int {
|
||||||
|
if !f.is_opened {
|
||||||
|
return error('file is not opened')
|
||||||
|
}
|
||||||
C.fseek(f.cfile, pos, C.SEEK_SET)
|
C.fseek(f.cfile, pos, C.SEEK_SET)
|
||||||
res := int(C.fwrite(buf.data, 1, buf.len, f.cfile))
|
res := int(C.fwrite(buf.data, 1, buf.len, f.cfile))
|
||||||
|
if res == 0 && buf.len != 0 {
|
||||||
|
return error('0 bytes written')
|
||||||
|
}
|
||||||
C.fseek(f.cfile, 0, C.SEEK_END)
|
C.fseek(f.cfile, 0, C.SEEK_END)
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// write_bytes writes `size` bytes to the file, starting from the address in `data`.
|
||||||
|
// NB: write_bytes is unsafe and should be used carefully, since if you pass invalid
|
||||||
|
// pointers to it, it will cause your programs to segfault.
|
||||||
[unsafe]
|
[unsafe]
|
||||||
pub fn (mut f File) write_bytes(data voidptr, size int) int {
|
pub fn (mut f File) write_bytes(data voidptr, size int) int {
|
||||||
return int(C.fwrite(data, 1, size, f.cfile))
|
return int(C.fwrite(data, 1, size, f.cfile))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// write_bytes_at writes `size` bytes to the file, starting from the address in `data`,
|
||||||
|
// at byte offset `pos`, counting from the start of the file (pos 0).
|
||||||
|
// NB: write_bytes_at is unsafe and should be used carefully, since if you pass invalid
|
||||||
|
// pointers to it, it will cause your programs to segfault.
|
||||||
[unsafe]
|
[unsafe]
|
||||||
pub fn (mut f File) write_bytes_at(data voidptr, size int, pos int) int {
|
pub fn (mut f File) write_bytes_at(data voidptr, size int, pos int) int {
|
||||||
C.fseek(f.cfile, pos, C.SEEK_SET)
|
C.fseek(f.cfile, pos, C.SEEK_SET)
|
||||||
|
@ -93,12 +236,13 @@ pub fn (mut f File) write_bytes_at(data voidptr, size int, pos int) int {
|
||||||
}
|
}
|
||||||
|
|
||||||
// **************************** Read ops ***************************
|
// **************************** Read ops ***************************
|
||||||
// read_bytes reads bytes from the beginning of the file
|
// read_bytes reads bytes from the beginning of the file.
|
||||||
|
// Utility method, same as .read_bytes_at(size, 0).
|
||||||
pub fn (f &File) read_bytes(size int) []byte {
|
pub fn (f &File) read_bytes(size int) []byte {
|
||||||
return f.read_bytes_at(size, 0)
|
return f.read_bytes_at(size, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// read_bytes_at reads bytes at the given position in the file
|
// read_bytes_at reads `size` bytes at the given position in the file.
|
||||||
pub fn (f &File) read_bytes_at(size int, pos int) []byte {
|
pub fn (f &File) read_bytes_at(size int, pos int) []byte {
|
||||||
mut arr := []byte{len: size}
|
mut arr := []byte{len: size}
|
||||||
nreadbytes := f.read_bytes_into(pos, mut arr) or {
|
nreadbytes := f.read_bytes_into(pos, mut arr) or {
|
||||||
|
@ -109,8 +253,8 @@ pub fn (f &File) read_bytes_at(size int, pos int) []byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
// read_bytes_into fills `buf` with bytes at the given position in the file.
|
// read_bytes_into fills `buf` with bytes at the given position in the file.
|
||||||
// `buf` must have length greater than zero.
|
// `buf` *must* have length greater than zero.
|
||||||
// Returns number of bytes read or an error.
|
// Returns the number of read bytes, or an error.
|
||||||
pub fn (f &File) read_bytes_into(pos int, mut buf []byte) ?int {
|
pub fn (f &File) read_bytes_into(pos int, mut buf []byte) ?int {
|
||||||
if buf.len == 0 {
|
if buf.len == 0 {
|
||||||
panic(@FN + ': `buf.len` == 0')
|
panic(@FN + ': `buf.len` == 0')
|
||||||
|
@ -129,7 +273,7 @@ pub fn (f &File) read_bytes_into(pos int, mut buf []byte) ?int {
|
||||||
return nbytes
|
return nbytes
|
||||||
}
|
}
|
||||||
|
|
||||||
// read implements the Reader interface
|
// read implements the Reader interface.
|
||||||
pub fn (f &File) read(mut buf []byte) ?int {
|
pub fn (f &File) read(mut buf []byte) ?int {
|
||||||
if buf.len == 0 {
|
if buf.len == 0 {
|
||||||
return 0
|
return 0
|
||||||
|
@ -142,7 +286,7 @@ pub fn (f &File) read(mut buf []byte) ?int {
|
||||||
return nbytes
|
return nbytes
|
||||||
}
|
}
|
||||||
|
|
||||||
// read_at reads buf.len bytes from pos in the file
|
// read_at reads `buf.len` bytes starting at file byte offset `pos`, in `buf`.
|
||||||
pub fn (f &File) read_at(pos int, mut buf []byte) ?int {
|
pub fn (f &File) read_at(pos int, mut buf []byte) ?int {
|
||||||
if buf.len == 0 {
|
if buf.len == 0 {
|
||||||
return 0
|
return 0
|
||||||
|
@ -157,7 +301,7 @@ pub fn (f &File) read_at(pos int, mut buf []byte) ?int {
|
||||||
}
|
}
|
||||||
|
|
||||||
// **************************** Utility ops ***********************
|
// **************************** Utility ops ***********************
|
||||||
// flush writes any unwritten data in stream's buffer
|
// flush writes any buffered unwritten data left in the file stream.
|
||||||
pub fn (mut f File) flush() {
|
pub fn (mut f File) flush() {
|
||||||
if !f.is_opened {
|
if !f.is_opened {
|
||||||
return
|
return
|
||||||
|
@ -165,18 +309,49 @@ pub fn (mut f File) flush() {
|
||||||
C.fflush(f.cfile)
|
C.fflush(f.cfile)
|
||||||
}
|
}
|
||||||
|
|
||||||
// open_stdin - return an os.File for stdin, so that you can use .get_line on it too.
|
// write_str writes the bytes of a string into a file,
|
||||||
pub fn open_stdin() File {
|
// *including* the terminating 0 byte.
|
||||||
return File{
|
|
||||||
fd: 0
|
|
||||||
cfile: C.stdin
|
|
||||||
is_opened: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn (mut f File) write_str(s string) ? {
|
pub fn (mut f File) write_str(s string) ? {
|
||||||
if !f.is_opened {
|
if !f.is_opened {
|
||||||
return error('file is closed')
|
return error('file is closed')
|
||||||
}
|
}
|
||||||
f.write(s.bytes()) ?
|
f.write(s.bytes()) ?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// read_struct reads a single struct of type `T`
|
||||||
|
pub fn (mut f File) read_struct<T>(mut t T) ? {
|
||||||
|
if !f.is_opened {
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
tsize := int(sizeof(*t))
|
||||||
|
if tsize == 0 {
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
C.errno = 0
|
||||||
|
nbytes := int(C.fread(t, 1, tsize, f.cfile))
|
||||||
|
if C.errno != 0 {
|
||||||
|
return error(posix_get_error_msg(C.errno))
|
||||||
|
}
|
||||||
|
if nbytes != tsize {
|
||||||
|
return error_with_code('incomplete struct read', nbytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// write_struct writes a single struct of type `T`
|
||||||
|
pub fn (mut f File) write_struct<T>(t &T) ? {
|
||||||
|
if !f.is_opened {
|
||||||
|
return error('file is not opened')
|
||||||
|
}
|
||||||
|
tsize := int(sizeof(*t))
|
||||||
|
if tsize == 0 {
|
||||||
|
return error('struct size is 0')
|
||||||
|
}
|
||||||
|
C.errno = 0
|
||||||
|
nbytes := int(C.fwrite(t, 1, tsize, f.cfile))
|
||||||
|
if C.errno != 0 {
|
||||||
|
return error(posix_get_error_msg(C.errno))
|
||||||
|
}
|
||||||
|
if nbytes != tsize {
|
||||||
|
return error_with_code('incomplete struct write', nbytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
import os
|
||||||
|
|
||||||
|
struct Point {
|
||||||
|
x f64
|
||||||
|
y f64
|
||||||
|
z f64
|
||||||
|
}
|
||||||
|
|
||||||
|
const unit_point = Point{1.0, 1.0, 1.0}
|
||||||
|
|
||||||
|
const tfolder = os.join_path(os.temp_dir(), 'os_file_test')
|
||||||
|
|
||||||
|
const tfile = os.join_path(tfolder, 'test_file')
|
||||||
|
|
||||||
|
const another_point = Point{0.25, 2.25, 6.25}
|
||||||
|
|
||||||
|
fn testsuite_begin() {
|
||||||
|
os.rmdir_all(tfolder) or { }
|
||||||
|
assert !os.is_dir(tfolder)
|
||||||
|
os.mkdir_all(tfolder) or { panic(err) }
|
||||||
|
os.chdir(tfolder)
|
||||||
|
assert os.is_dir(tfolder)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn testsuite_end() {
|
||||||
|
os.chdir(os.wd_at_startup)
|
||||||
|
os.rmdir_all(tfolder) or { panic(err) }
|
||||||
|
assert !os.is_dir(tfolder)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_write_struct() {
|
||||||
|
size_of_point := int(sizeof(Point))
|
||||||
|
mut f := os.open_file(tfile, 'w') or { panic(err) }
|
||||||
|
f.write_struct(another_point) or { panic(err) }
|
||||||
|
f.close()
|
||||||
|
x := os.read_file(tfile) or { panic(err) }
|
||||||
|
y := unsafe { byteptr(memdup(&another_point, size_of_point)).vstring_with_len(size_of_point) }
|
||||||
|
assert x == y
|
||||||
|
$if debug {
|
||||||
|
eprintln(x.bytes())
|
||||||
|
eprintln(y.bytes())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_read_struct() {
|
||||||
|
mut f := os.open_file(tfile, 'w') or { panic(err) }
|
||||||
|
f.write_struct(another_point) or { panic(err) }
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
f = os.open_file(tfile, 'r') or { panic(err) }
|
||||||
|
mut p := Point{}
|
||||||
|
f.read_struct(mut p) or { panic(err) }
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
assert p == another_point
|
||||||
|
}
|
139
vlib/os/os_c.v
139
vlib/os/os_c.v
|
@ -214,74 +214,6 @@ pub fn fileno(cfile voidptr) int {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// open_append opens `path` file for appending.
|
|
||||||
pub fn open_append(path string) ?File {
|
|
||||||
mut file := File{}
|
|
||||||
$if windows {
|
|
||||||
wpath := path.replace('/', '\\').to_wide()
|
|
||||||
mode := 'ab'
|
|
||||||
file = File{
|
|
||||||
cfile: C._wfopen(wpath, mode.to_wide())
|
|
||||||
}
|
|
||||||
} $else {
|
|
||||||
cpath := path.str
|
|
||||||
file = File{
|
|
||||||
cfile: C.fopen(charptr(cpath), 'ab')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if isnil(file.cfile) {
|
|
||||||
return error('failed to create(append) file "$path"')
|
|
||||||
}
|
|
||||||
file.is_opened = true
|
|
||||||
return file
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 {
|
|
||||||
mut flags := 0
|
|
||||||
for m in mode {
|
|
||||||
match m {
|
|
||||||
`r` { flags |= o_rdonly }
|
|
||||||
`w` { flags |= o_create | o_trunc }
|
|
||||||
`b` { flags |= o_binary }
|
|
||||||
`a` { flags |= o_create | o_append }
|
|
||||||
`s` { flags |= o_sync }
|
|
||||||
`n` { flags |= o_nonblock }
|
|
||||||
`c` { flags |= o_noctty }
|
|
||||||
`+` { flags |= o_rdwr }
|
|
||||||
else {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mut permission := 0o666
|
|
||||||
if options.len > 0 {
|
|
||||||
permission = options[0]
|
|
||||||
}
|
|
||||||
$if windows {
|
|
||||||
if permission < 0o600 {
|
|
||||||
permission = 0x0100
|
|
||||||
} else {
|
|
||||||
permission = 0x0100 | 0x0080
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mut p := path
|
|
||||||
$if windows {
|
|
||||||
p = path.replace('/', '\\')
|
|
||||||
}
|
|
||||||
fd := C.open(charptr(p.str), flags, permission)
|
|
||||||
if fd == -1 {
|
|
||||||
return error(posix_get_error_msg(C.errno))
|
|
||||||
}
|
|
||||||
cfile := C.fdopen(fd, charptr(mode.str))
|
|
||||||
if isnil(cfile) {
|
|
||||||
return error('Failed to open or create file "$path"')
|
|
||||||
}
|
|
||||||
return File{
|
|
||||||
cfile: cfile
|
|
||||||
fd: fd
|
|
||||||
is_opened: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// vpopen system starts the specified command, waits for it to complete, and returns its code.
|
// vpopen system starts the specified command, waits for it to complete, and returns its code.
|
||||||
fn vpopen(path string) voidptr {
|
fn vpopen(path string) voidptr {
|
||||||
// *C.FILE {
|
// *C.FILE {
|
||||||
|
@ -850,64 +782,27 @@ pub fn chmod(path string, mode int) {
|
||||||
C.chmod(charptr(path.str), mode)
|
C.chmod(charptr(path.str), mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
// open tries to open a file for reading and returns back a read-only `File` object.
|
// open_append opens `path` file for appending.
|
||||||
pub fn open(path string) ?File {
|
pub fn open_append(path string) ?File {
|
||||||
/*
|
mut file := File{}
|
||||||
$if linux {
|
$if windows {
|
||||||
$if !android {
|
wpath := path.replace('/', '\\').to_wide()
|
||||||
fd := C.syscall(sys_open, path.str, 511)
|
mode := 'ab'
|
||||||
if fd == -1 {
|
|
||||||
return error('failed to open file "$path"')
|
|
||||||
}
|
|
||||||
return File{
|
|
||||||
fd: fd
|
|
||||||
is_opened: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
cfile := vfopen(path, 'rb') ?
|
|
||||||
fd := fileno(cfile)
|
|
||||||
return File{
|
|
||||||
cfile: cfile
|
|
||||||
fd: fd
|
|
||||||
is_opened: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// create creates or opens a file at a specified location and returns a write-only `File` object.
|
|
||||||
pub fn create(path string) ?File {
|
|
||||||
/*
|
|
||||||
// NB: android/termux/bionic is also a kind of linux,
|
|
||||||
// but linux syscalls there sometimes fail,
|
|
||||||
// while the libc version should work.
|
|
||||||
$if linux {
|
|
||||||
$if !android {
|
|
||||||
//$if macos {
|
|
||||||
// fd = C.syscall(398, path.str, 0x601, 0x1b6)
|
|
||||||
//}
|
|
||||||
//$if linux {
|
|
||||||
fd = C.syscall(sys_creat, path.str, 511)
|
|
||||||
//}
|
|
||||||
if fd == -1 {
|
|
||||||
return error('failed to create file "$path"')
|
|
||||||
}
|
|
||||||
file = File{
|
file = File{
|
||||||
fd: fd
|
cfile: C._wfopen(wpath, mode.to_wide())
|
||||||
is_opened: true
|
|
||||||
}
|
}
|
||||||
|
} $else {
|
||||||
|
cpath := path.str
|
||||||
|
file = File{
|
||||||
|
cfile: C.fopen(charptr(cpath), 'ab')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if isnil(file.cfile) {
|
||||||
|
return error('failed to create(append) file "$path"')
|
||||||
|
}
|
||||||
|
file.is_opened = true
|
||||||
return file
|
return file
|
||||||
}
|
}
|
||||||
}
|
|
||||||
*/
|
|
||||||
cfile := vfopen(path, 'wb') ?
|
|
||||||
fd := fileno(cfile)
|
|
||||||
return File{
|
|
||||||
cfile: cfile
|
|
||||||
fd: fd
|
|
||||||
is_opened: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// execvp - loads and executes a new child process, *in place* of the current process.
|
// execvp - loads and executes a new child process, *in place* of the current process.
|
||||||
// The child process executable is located in `cmdpath`.
|
// The child process executable is located in `cmdpath`.
|
||||||
|
|
Loading…
Reference in New Issue