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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
#include "std/base.toc", base;
#include "std/mem.toc", mem;
str_to_cstr ::= fn(s: []char) []char {
ret := mem.news(char, s.len+1);
mem.mem_copy(&ret[0], &s[0], s.len);
ret
}
#if base.PLATFORM_IS_UNIX {
// @TODO: use syscall instead
write ::= #foreign("write", base.libc) fn(#C int, #C &"const void", #C size_t) #C long;
open ::= #foreign("open", base.libc) fn (#C &"const char", #C int) #C int;
O_RDONLY ::= 0x00;
O_WRONLY ::= 0x01;
O_CREAT ::= 0x40;
RawFile ::= int;
raw_file_write ::= fn(file: RawFile, buf: &void, size: int) bool {
while size > 0 {
bytes_written := write(file as #C int, buf, size as #C size_t);
if bytes_written < 0 {
return false;
}
size -= bytes_written;
buf += bytes_written;
}
true
}
raw_stdout ::= fn() RawFile {
1
}
raw_stderr ::= fn() RawFile {
2
}
file_open_write ::= fn(name: []char) f: RawFile, success: bool {
cstr := str_to_cstr(name);
defer mem.dels(cstr);
// @TODO: switch to bitwise or when that exists
f = open(&cstr[0], (O_WRONLY + O_CREAT) as #C int) as RawFile;
success = f != -1;
}
} else {
// @TODO: on windows, use WriteFile
fwrite ::= #foreign("fwrite", base.libc) fn(#C &"const void", #C size_t, #C size_t, &void) #C size_t;
RawFile ::= &void;
raw_file_write ::= fn(file: RawFile, buf: &void, size: int) bool {
bytes_written := fwrite(buf, 1, size, file) as int;
bytes_written == size
}
raw_stdout ::= fn() RawFile {
#builtin("stdout")
}
raw_stderr ::= fn() RawFile {
#builtin("stdout")
}
file_open_write ::= fn(name: []char) f: RawFile, success: bool {
cstr := base.str_to_cstr(name);
defer mem.dels(cstr);
mode := "w\0";
f = fopen(&cstr[0], &mode[0]);
success = f != null;
}
}
File ::= struct {
BUFSZ ::= 4096;
raw : RawFile;
written : int; // ranges from 0 to FILE_BUFSZ-1
nobuffer : bool; // if true, flush after every write
buffer : [BUFSZ]char;
}
raw_file_to_file ::= fn(raw : RawFile) f: File {
f.raw = raw;
}
std_out, std_err : File;
file_flush ::= fn(use f: &File) {
raw_file_write(raw, &buffer[0], written);
written = 0;
}
file_writes ::= fn(use f: &File, s : []char) {
if f.nobuffer {
raw_file_write(raw, &s[0], s.len);
return;
}
if written + s.len > BUFSZ {
file_flush(f);
if s.len > BUFSZ {
raw_file_write(raw, &s[0], s.len);
} else {
mem.mem_copy(&buffer[0], &s[0], s.len);
written = s.len;
}
} else {
mem.mem_copy(&buffer[written], &s[0], s.len);
written += s.len;
}
}
io_init ::= fn() {
std_out = raw_file_to_file(raw_stdout());
std_out.nobuffer = true;
std_err = raw_file_to_file(raw_stderr());
std_err.nobuffer = true;
}
|