aboutsummaryrefslogtreecommitdiff
path: root/src/lib/std.zc
diff options
context:
space:
mode:
authorGravatar zinc <zinc@downsta.ir> 2026-10-15 02:46:57 +0330
committerGravatar zinc <zinc@downsta.ir> 2026-10-15 02:46:57 +0330
commit54d316a531ddb8e293711761e4f29e93d282599c (patch)
treee062d2ef306dd9c9e28b293804d48b72789e0174 /src/lib/std.zc
parentrt: gc_drops finalizes a droppable value that reaches itself (a cycle, or a d... (diff)
std: File, the first user of drops: std.Host.open(path, mode) returns an owned std.File (or null) with write and read, and its drop closes the descriptor; Host.writefile is built on it; file_drop.zc, learn and readme
Diffstat (limited to 'src/lib/std.zc')
-rw-r--r--src/lib/std.zc38
1 files changed, 33 insertions, 5 deletions
diff --git a/src/lib/std.zc b/src/lib/std.zc
index 772b887..745a921 100644
--- a/src/lib/std.zc
+++ b/src/lib/std.zc
@@ -344,6 +344,24 @@ struct Num {
// are its arguments. Host.raw fills it on each call.
int rawblk[7];
+// an open file, from Host.open. its drop closes the descriptor, so the file is
+// closed when its owner's block ends, when it is freed, or when the collector
+// reclaims it (docs/SPEC.md 6.15). called as f.write(s), f.read(buf, n).
+struct File {
+ int fd;
+ // writes a string.
+ // s: the text to write
+ // returns: how many bytes were written, negative on an error
+ int write(char* s) { return rt.syscall(rt.SYS_WRITE, this.fd, s, rt.len_w(s)); }
+ // reads bytes, one to a word.
+ // buf: where they go
+ // n: the most to read
+ // returns: how many were read, 0 at the end of the file, negative on an error
+ int read(char* buf, int n) { return rt.syscall(rt.SYS_READ, this.fd, buf, n); }
+ // the file dies: close its descriptor
+ void drop() { rt.syscall(rt.SYS_CLOSE, this.fd, 0, 0); }
+}
+
// calls into the host that runs the vm: the environment, the clock, files and
// raw system calls. called as std.Host.name(args).
struct Host {
@@ -373,17 +391,27 @@ struct Host {
// returns: the time in seconds since 1970
static int now() { return rt.syscall(rt.SYS_TIME, 0, 0, 0); }
+ // opens a file. the result owns the descriptor: its drop closes it (see File).
+ // path: the file's name
+ // mode: 0 to read, 1 to write (the file is replaced, or created)
+ // returns: the open file, or null if it could not be opened
+ static File*.u open(char* path, int mode) {
+ int fd = rt.syscall(rt.SYS_OPEN, path, mode, 0);
+ if (fd < 0) return 0;
+ File* f = rt.new(File);
+ f.fd = fd;
+ return f;
+ }
+
// writes a string to a file, replacing what was there. the file is created if
// it is missing.
// path: the file's name
// s: the text to write
// returns: how many bytes were written, -1 if the file could not be opened
static int writefile(char* path, char* s) {
- int fd = rt.syscall(rt.SYS_OPEN, path, 1, 0), n;
- if (fd < 0) return -1;
- n = rt.syscall(rt.SYS_WRITE, fd, s, rt.len_w(s));
- rt.syscall(rt.SYS_CLOSE, fd, 0, 0);
- return n;
+ File* f = Host.open(path, 1);
+ if (!f) return -1;
+ return f.write(s); // f's drop closes the file after the write
}
}