런타임에 open/read/close 와 명령줄을 넣었다. std.io 가 그 위에 파일 열기, 읽기, 쓰기, 그리고 명령줄을 조각으로 나누는 것을 얹는다. 인용부호 처리는 런타임이 알 일이 아니라 라이브러리가 할 일이다. 길에서 고친 것들: - *T 가 타입 시스템에 실체가 없어서 덩어리로 취급됐다. 이제 진짜 종류다 -- 주소일 뿐이고 추적할 대여도 실행할 drop 도 없는 Copy 타입. 그 결과 &u8 이 *u8 에 자동으로 맞지 않게 됐는데, 그게 맞다: R9 는 그 변환을 unsafe 안의 @ptr_cast 로만 허용한다. - raw 포인터에 정수를 더하면 더 뒤의 주소다. 소유자나 대여에는 허용하지 않는다 -- 자기 자리가 있는 것에서 걸어나가는 것이 *T 의 용도다. - @volatile_load / @volatile_store / @ptr_cast 를 내린다. - undefined 가 선언된 타입을 따른다. 없으면 손으로 타이핑할 수 있는 것보다 큰 버퍼를 선언할 방법이 아예 없었다. R8 이 정확히 동작하는 것도 확인했다: 참조성 파라미터가 둘인 함수는 슬라이스를 반환할 수 없다. 어디서 파생됐는지 시그니처가 말하지 않기 때문이다. exec.py 24/24.
121 lines
3.6 KiB
Plaintext
121 lines
3.6 KiB
Plaintext
unit std.io;
|
|
import std.sys;
|
|
|
|
// A writer is a handle and nothing else: an integer the runtime understands.
|
|
// It stores no reference and no context pointer, so it is Copy and can be
|
|
// passed and returned freely (SPEC 5 R8).
|
|
pub enum Writer { Null, Stdout, Stderr }
|
|
|
|
pub fn write(w: Writer, bytes: []u8) -> usize {
|
|
if w == Writer.Null { return bytes.n; }
|
|
var handle: i32 = 1;
|
|
if w == Writer.Stderr { handle = 2; }
|
|
var done: i32 = 0;
|
|
unsafe { done = sys.raw_write(handle, @ptr_cast(u8, &bytes[0]), bytes.n); }
|
|
if done < 0 { return 0; }
|
|
return done as usize;
|
|
}
|
|
|
|
pub fn print(bytes: []u8) -> usize {
|
|
return write(Writer.Stdout, bytes);
|
|
}
|
|
|
|
pub fn println(bytes: []u8) -> usize {
|
|
let n: usize = write(Writer.Stdout, bytes);
|
|
return n + write(Writer.Stdout, "\n");
|
|
}
|
|
|
|
// Files. A handle is what the operating system gave back; -1 means it did not
|
|
// give one. The path has to be NUL terminated because that is what the system
|
|
// call wants, and `to_cstr` is how a Ferro string becomes one.
|
|
|
|
pub fn open_read(path: []mut u8) -> !i32 {
|
|
var handle: i32 = 0;
|
|
unsafe { handle = sys.raw_open(@ptr_cast(u8, &path[0]), 0); }
|
|
if handle == 0 - 1 { return error.NoSuchFile; }
|
|
return handle;
|
|
}
|
|
|
|
pub fn open_write(path: []mut u8) -> !i32 {
|
|
var handle: i32 = 0;
|
|
unsafe { handle = sys.raw_open(@ptr_cast(u8, &path[0]), 1); }
|
|
if handle == 0 - 1 { return error.CannotWrite; }
|
|
return handle;
|
|
}
|
|
|
|
pub fn read(handle: i32, into: []mut u8) -> !usize {
|
|
var got: i32 = 0;
|
|
unsafe { got = sys.raw_read(handle, @ptr_cast(u8, &into[0]), into.n); }
|
|
if got < 0 { return error.ReadFailed; }
|
|
return got as usize;
|
|
}
|
|
|
|
pub fn close(handle: i32) -> void {
|
|
sys.raw_close(handle);
|
|
}
|
|
|
|
/// Put `text` into `buf` with a NUL after it and say how many bytes that took,
|
|
/// the NUL included. A system call cannot be told a length, so it needs this.
|
|
///
|
|
/// The length comes back rather than a slice of `buf`: with two reference-like
|
|
/// parameters the signature cannot say which one a returned slice came from,
|
|
/// and R8 will not guess.
|
|
pub fn to_cstr(buf: []mut u8, text: []u8) -> usize {
|
|
var i: usize = 0;
|
|
while i < text.n {
|
|
if i + 1 >= buf.n { break; }
|
|
buf[i] = text[i];
|
|
i = i + 1;
|
|
}
|
|
if i < buf.n { buf[i] = 0; }
|
|
return i + 1;
|
|
}
|
|
|
|
pub fn write_file(handle: i32, bytes: []u8) -> !usize {
|
|
var done: i32 = 0;
|
|
unsafe { done = sys.raw_write(handle, @ptr_cast(u8, &bytes[0]), bytes.n); }
|
|
if done < 0 { return error.WriteFailed; }
|
|
return done as usize;
|
|
}
|
|
|
|
/// Copy the command line into `buf` and say how long it is. It arrives as one
|
|
/// string with the program's own name first; `arg` picks a piece out of it.
|
|
pub fn cmdline(buf: []mut u8) -> usize {
|
|
let raw: *u8 = sys.raw_cmdline();
|
|
var i: usize = 0;
|
|
unsafe {
|
|
while i + 1 < buf.n {
|
|
let c: u8 = @volatile_load(raw + i);
|
|
if c == 0 { break; }
|
|
buf[i] = c;
|
|
i = i + 1;
|
|
}
|
|
}
|
|
return i;
|
|
}
|
|
|
|
/// The `n`th whitespace-separated piece of `line`, or an empty slice when
|
|
/// there is no such piece. Quoting is not handled; nothing here needs it yet.
|
|
pub fn arg(line: []u8, n: usize) -> []u8 {
|
|
var at: usize = 0;
|
|
var seen: usize = 0;
|
|
while at < line.n {
|
|
while at < line.n {
|
|
if line[at] != 32 { break; }
|
|
at = at + 1;
|
|
}
|
|
var stop: usize = at;
|
|
while stop < line.n {
|
|
if line[stop] == 32 { break; }
|
|
stop = stop + 1;
|
|
}
|
|
if stop > at {
|
|
if seen == n { return line[at..stop]; }
|
|
seen = seen + 1;
|
|
}
|
|
at = stop;
|
|
}
|
|
return line[0..0];
|
|
}
|
|
|