1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
|
// Simple I/O Library
// Write byte array to stdout
val p = { u8[~] str -> write(1,str); };
val p_noInline = { u8[~] str -> write(1,str); };
// Write to stderr
val err = { u8[~] str -> write(libc.STDERR,str); };
// Read until EOF, including after short reads. Return an empty array for an
// empty stream, or null on error with errno preserved (partial data discarded).
val read = { i32 fd ->
val chunk = new u8[8*1024];
i64 ptr = chunk;
val buf = new aryu8();
while( true ) {
i64 rez = libc.read(fd,ptr,chunk#);
if( rez < 0 ) {
if( libc.errno() == libc.EINTR ) continue;
return null;
}
if( rez == 0 ) break;
if( buf.len+rez > 4294967295 ) {
libc.set_errno(libc.EOVERFLOW);
return null;
}
u32 count = rez;
buf._grow(count);
ary.copy(buf.buf,buf.len,chunk,0,count);
buf.len += count;
}
val out = new u8[buf.len];
return ary.copy(out,0,buf.buf,0,buf.len);
};
// Write all bytes, returning the count or -1 with errno set. An error can
// follow a successfully written prefix; it does not undo that prefix.
val write = { i32 fd, u8[~] str ->
writeOff(fd,str,0,str#);
};
// Write a slice, capping len at the remaining bytes. An offset past the end
// is invalid, including for an empty write. A valid empty slice returns zero.
// Invalid arguments return -1;
val writeOff = { i32 fd, u8[~] str, u32 off, u32 len ->
if( off > str# ) return libc.set_errno(libc.EINVAL);
if( len > str# - off ) len = str# - off;
i64 ptr = str;
ptr += off;
i64 done = 0;
while( done < len ) {
i64 rez = libc.write(fd,ptr+done,len-done);
if( rez < 0 ) {
if( libc.errno() == libc.EINTR ) continue;
return -1;
}
if( rez == 0 ) {
libc.set_errno(libc.EIO);
return -1;
}
done += rez;
}
return done;
};
// Return stdin as a u8[].
val stdin = { -> read(0); };
// One byte, without Enter or echo. Restores the previous terminal mode before
// returning. Files/pipes also work. Returns 0..255, or -1 with libc.errno() set
// to libc.EOF or an OS error. Ctrl-C is byte 3; escape/UTF-8 sequences are multiple bytes.
val getch = { -> libc.simple_getch(); };
// Create file for writing. Return fd, or -1 and errno has the error code
val create = { u8[~] str ->
i64 ptr = sys.aryu8.str0(str);
i32 perms = 6*64 + 6*8 + 6; // 0666
return libc.creat(ptr, perms);
};
// Open file for reading. Return fd, or -1 and errno has the error code
val open = { u8[~] str ->
i64 ptr = sys.aryu8.str0(str);
return libc.open(ptr, sys.libc.O_RDONLY, 0);
};
// Close an open fd. Return 0, or -1 and errno has the error code
val close = { i32 fd -> return libc.close(fd); };
// Remove a file. Return 0, or -1 and errno has the error code
val remove = { u8[~] str ->
i64 ptr = sys.aryu8.str0(str);
return libc.unlink(ptr);
};
|