commit b9fdbbc5f173bac432fd716792304b7797465813
parent fba5c36a64ffcf04660dc7fe0449bb267a783ea0
Author: Alexey Yerin <yyp@disroot.org>
Date: Sun, 2 Jan 2022 17:18:33 +0300
bufio: use caller allocation
fixed() and dynamic() return a memstream, and buffered() returns
bufstream. This also removes the need for static_buffered() hack.
Similarly to strio, bufio::finish() is removed as the streams do not
allocate themselves.
Necessary update is adding '&' to uses of bufio streams.
Signed-off-by: Alexey Yerin <yyp@disroot.org>
Diffstat:
21 files changed, 182 insertions(+), 243 deletions(-)
diff --git a/bufio/buffered.ha b/bufio/buffered.ha
@@ -34,21 +34,9 @@ export fn buffered(
src: io::handle,
rbuf: []u8,
wbuf: []u8,
-) io::handle = {
- let s = alloc(bufstream { ... });
- let st = static_buffered(src, rbuf, wbuf, s);
- st.closer = &buffered_close;
- return st;
-};
-
-export fn static_buffered(
- src: io::handle,
- rbuf: []u8,
- wbuf: []u8,
- s: *bufstream,
-) *io::stream = {
+) bufstream = {
static let flush_default = ['\n': u32: u8];
- *s = bufstream {
+ let s = bufstream {
stream = io::stream {
closer = &buffered_close_static,
...
@@ -69,7 +57,7 @@ export fn static_buffered(
assert(rbuf: *[*]u8 != wbuf: *[*]u8,
"Cannot use bufio::buffered with same buffer for reads and writes");
};
- return &s.stream;
+ return s;
};
fn getstream(in: io::handle) *bufstream = {
@@ -78,8 +66,7 @@ fn getstream(in: io::handle) *bufstream = {
};
// Flushes pending writes to the underlying stream.
-export fn flush(s: io::handle) (io::error | void) = {
- let s = getstream(s);
+export fn flush(s: *bufstream) (io::error | void) = {
if (s.wavail == 0) {
return;
};
@@ -90,22 +77,19 @@ export fn flush(s: io::handle) (io::error | void) = {
// Sets the list of bytes which will cause the stream to flush when written. By
// default, the stream will flush when a newline (\n) is written.
-export fn setflush(s: io::handle, b: []u8) void = {
- let s = getstream(s);
+export fn setflush(s: *bufstream, b: []u8) void = {
s.flush = b;
};
// Unreads a slice of bytes. The next read calls on this buffer will consume the
// un-read data before consuming further data from the underlying source, or any
// buffered data.
-export fn unread(s: io::handle, buf: []u8) void = {
- let s = getstream(s);
+export fn unread(s: *bufstream, buf: []u8) void = {
append(s.unread, buf...);
};
// Unreads a rune; see [[unread]].
-export fn unreadrune(s: io::handle, rn: rune) void = {
- let s = getstream(s);
+export fn unreadrune(s: *bufstream, rn: rune) void = {
const buf = utf8::encoderune(rn);
insert(s.unread[0], buf...);
};
@@ -120,18 +104,10 @@ export fn isbuffered(in: io::handle) bool = {
};
};
-fn buffered_close(s: *io::stream) void = {
- assert(s.closer == &buffered_close);
- if (s.writer != null) {
- flush(s)!;
- };
- free(s);
-};
-
fn buffered_close_static(s: *io::stream) void = {
assert(s.closer == &buffered_close_static);
if (s.writer != null) {
- flush(s)!;
+ flush(s: *bufstream)!;
};
};
@@ -188,7 +164,7 @@ fn buffered_write(s: *io::stream, buf: const []u8) (size | io::error) = {
for (len(buf) > 0) {
let avail = len(s.wbuffer) - s.wavail;
if (avail == 0) {
- flush(&s.stream)?;
+ flush(s)?;
avail = len(s.wbuffer);
};
@@ -200,7 +176,7 @@ fn buffered_write(s: *io::stream, buf: const []u8) (size | io::error) = {
};
if (doflush) {
- flush(&s.stream)?;
+ flush(s)?;
};
return z;
@@ -209,54 +185,53 @@ fn buffered_write(s: *io::stream, buf: const []u8) (size | io::error) = {
@test fn buffered_read() void = {
let sourcebuf: []u8 = [1, 3, 3, 7];
let source = fixed(sourcebuf, io::mode::READ);
- let fb = source: *memstream;
- defer io::close(source);
+ defer io::close(&source);
let rbuf: [1024]u8 = [0...];
let f = buffered(source, rbuf, []);
- defer io::close(f);
+ defer io::close(&f);
let buf: [1024]u8 = [0...];
- assert(io::read(f, buf[..2]) as size == 2);
- assert(fb.pos == len(fb.buf), "fixed stream was not fully consumed");
+ assert(io::read(&f, buf[..2]) as size == 2);
+ assert(source.pos == len(source.buf), "fixed stream was not fully consumed");
assert(bytes::equal(buf[..2], [1, 3]));
- assert(io::read(f, buf[2..]) as size == 2);
+ assert(io::read(&f, buf[2..]) as size == 2);
assert(bytes::equal(buf[..4], [1, 3, 3, 7]));
- assert(io::read(f, buf) is io::EOF);
+ assert(io::read(&f, buf) is io::EOF);
let sourcebuf: [32]u8 = [1, 3, 3, 7, 0...];
let source = fixed(sourcebuf, io::mode::READ);
- let fb = source: *memstream;
+ let source = source: *memstream;
defer io::close(source);
let rbuf: [16]u8 = [0...];
let f = buffered(source, rbuf, []);
- defer io::close(f);
+ defer io::close(&f);
let buf: [32]u8 = [0...];
- assert(io::read(f, buf) as size == 16);
- assert(fb.pos == 16);
+ assert(io::read(&f, buf) as size == 16);
+ assert(source.pos == 16);
- assert(io::read(f, buf[16..]) as size == 16);
+ assert(io::read(&f, buf[16..]) as size == 16);
assert(bytes::equal(buf, sourcebuf));
- assert(io::read(f, buf) is io::EOF);
- assert(fb.pos == len(fb.buf));
+ assert(io::read(&f, buf) is io::EOF);
+ assert(source.pos == len(source.buf));
};
@test fn buffered_write() void = {
// Normal case
let sink = dynamic(io::mode::WRITE);
- defer io::close(sink);
+ defer io::close(&sink);
let wbuf: [1024]u8 = [0...];
let f = buffered(sink, [], wbuf);
- defer io::close(f);
+ defer io::close(&f);
- assert(io::write(f, [1, 3, 3, 7]) as size == 4);
+ assert(io::write(&f, [1, 3, 3, 7]) as size == 4);
assert(len(buffer(sink)) == 0);
- assert(io::write(f, [1, 3, 3, 7]) as size == 4);
- assert(flush(f) is void);
+ assert(io::write(&f, [1, 3, 3, 7]) as size == 4);
+ assert(flush(&f) is void);
assert(bytes::equal(buffer(sink), [1, 3, 3, 7, 1, 3, 3, 7]));
// Test flushing via buffer exhaustion
@@ -266,11 +241,11 @@ fn buffered_write(s: *io::stream, buf: const []u8) (size | io::error) = {
let wbuf: [4]u8 = [0...];
let f = buffered(sink, [], wbuf);
- assert(io::write(f, [1, 3, 3, 7]) as size == 4);
+ assert(io::write(&f, [1, 3, 3, 7]) as size == 4);
assert(len(buffer(sink)) == 0);
- assert(io::write(f, [1, 3, 3, 7]) as size == 4);
+ assert(io::write(&f, [1, 3, 3, 7]) as size == 4);
assert(bytes::equal(buffer(sink), [1, 3, 3, 7]));
- io::close(f); // Should flush
+ io::close(&f); // Should flush
assert(bytes::equal(buffer(sink), [1, 3, 3, 7, 1, 3, 3, 7]));
// Test flushing via flush characters
@@ -280,8 +255,8 @@ fn buffered_write(s: *io::stream, buf: const []u8) (size | io::error) = {
let wbuf: [1024]u8 = [0...];
let f = buffered(sink, [], wbuf);
- assert(io::write(f, strings::toutf8("hello")) as size == 5);
+ assert(io::write(&f, strings::toutf8("hello")) as size == 5);
assert(len(buffer(sink)) == 0);
- assert(io::write(f, strings::toutf8(" world!\n")) as size == 8);
+ assert(io::write(&f, strings::toutf8(" world!\n")) as size == 8);
assert(bytes::equal(buffer(sink), strings::toutf8("hello world!\n")));
};
diff --git a/bufio/memstream.ha b/bufio/memstream.ha
@@ -3,24 +3,22 @@ use io;
use strings;
use errors;
-type memstream = struct {
+export type memstream = struct {
stream: io::stream,
buf: []u8,
pos: size,
};
-// Creates an [[io::stream]] for a fixed, caller-supplied buffer. Supports
+// Creates a stream for a fixed, caller-supplied buffer. Supports
// either read or write, but not both. Readable streams are seekable. The
-// program aborts if writes would exceed the buffer's capacity.
-export fn fixed(in: []u8, mode: io::mode) *io::stream = {
- let s = alloc(memstream {
- stream = io::stream {
- closer = &fixed_close,
- ...
- },
+// program aborts if writes would exceed the buffer's capacity. The stream
+// doesn't have to be closed.
+export fn fixed(in: []u8, mode: io::mode) memstream = {
+ let s = memstream {
+ stream = io::stream { ... },
buf = in,
pos = 0,
- });
+ };
if (mode & io::mode::READ == io::mode::READ) {
assert(mode & io::mode::WRITE != io::mode::WRITE);
s.stream.reader = &read;
@@ -30,7 +28,7 @@ export fn fixed(in: []u8, mode: io::mode) *io::stream = {
assert(mode & io::mode::READ != io::mode::READ);
s.stream.writer = &fixed_write;
};
- return &s.stream;
+ return s;
};
fn fixed_write(s: *io::stream, buf: const []u8) (size | io::error) = {
@@ -45,24 +43,20 @@ fn fixed_write(s: *io::stream, buf: const []u8) (size | io::error) = {
return n;
};
-fn fixed_close(s: *io::stream) void = free(s);
-
// Creates an [[io::stream]] which dynamically allocates a buffer to store writes
// into. Subsequent reads will consume the buffered data. Upon failure to
// allocate sufficient memory to store writes, the program aborts.
//
-// Calling [[io::close]] on this stream will free the buffer. Call
-// [[bufio::finish]] instead to free up resources associated with the stream,
-// but transfer ownership of the buffer to the caller.
-export fn dynamic(mode: io::mode) *io::stream = dynamic_from([], mode);
+// Calling [[io::close]] on this stream will free the buffer. If stream's
+// data is transferred via [[buffer]], it shouldn't be closed as long as the
+// data is freed.
+export fn dynamic(mode: io::mode) memstream = dynamic_from([], mode);
// Like [[dynamic]], but takes an existing slice as input. Writes are appended
// to it and reads consume bytes from the initial buffer, plus any additional
-// writes. Like [[dynamic]], calling [[io::close]] will free the buffer, and
-// [[bufio::finish]] can be used to return ownership of the buffer to the
-// caller.
-export fn dynamic_from(in: []u8, mode: io::mode) *io::stream = {
- let s = alloc(memstream {
+// writes. Like [[dynamic]], calling [[io::close]] will free the buffer.
+export fn dynamic_from(in: []u8, mode: io::mode) memstream = {
+ let s = memstream {
stream = io::stream {
closer = &dynamic_close,
seeker = &seek,
@@ -70,55 +64,33 @@ export fn dynamic_from(in: []u8, mode: io::mode) *io::stream = {
},
buf = in,
pos = 0,
- }): *io::stream;
+ };
if (mode & io::mode::READ == io::mode::READ) {
- s.reader = &read;
+ s.stream.reader = &read;
};
if (mode & io::mode::WRITE == io::mode::WRITE) {
- s.writer = &dynamic_write;
+ s.stream.writer = &dynamic_write;
};
return s;
};
-fn getmemstream(in: io::handle) *memstream = {
- match (in) {
- case io::file =>
- abort("Invalid use of bufio with unbuffered file");
- case let st: *io::stream =>
- assert(st.closer == &dynamic_close);
- return st: *memstream;
- };
-};
-
-// Closes the stream without freeing the dynamic buffer, instead transferring
-// ownership of it to the caller.
-export fn finish(in: io::handle) []u8 = {
- let s = getmemstream(in);
- let buf = s.buf;
- free(s);
- return buf;
-};
-
-// Returns the current buffer.
-export fn buffer(in: io::handle) []u8 = {
- const s = getmemstream(in);
- return s.buf;
+// Returns the current buffer of a [[fixed]] or [[dynamic]] stream.
+export fn buffer(in: *memstream) []u8 = {
+ return in.buf;
};
// Resets the dynamic buffer's length to zero, but keeps the allocated memory
// around for future writes.
-export fn reset(in: io::handle) void = {
- const s = getmemstream(in);
- s.pos = 0;
- s.buf = s.buf[..0];
+export fn reset(in: *memstream) void = {
+ in.pos = 0;
+ in.buf = in.buf[..0];
};
// Truncates the dynamic buffer, freeing memory associated with it and setting
// its length to zero.
-export fn truncate(in: io::handle) (void | errors::unsupported) = {
- let s = getmemstream(in);
- s.pos = 0;
- delete(s.buf[..]);
+export fn truncate(in: *memstream) (void | errors::unsupported) = {
+ in.pos = 0;
+ delete(in.buf[..]);
};
fn dynamic_write(s: *io::stream, buf: const []u8) (size | io::error) = {
@@ -131,7 +103,6 @@ fn dynamic_write(s: *io::stream, buf: const []u8) (size | io::error) = {
fn dynamic_close(s: *io::stream) void = {
const s = s: *memstream;
free(s.buf);
- free(s);
};
fn read(s: *io::stream, buf: []u8) (size | io::EOF | io::error) = {
@@ -178,59 +149,59 @@ fn seek(
@test fn dynamic() void = {
let s = dynamic(io::mode::RDWR);
- assert(io::write(s, [1, 2, 3]) as size == 3);
- assert(bytes::equal(buffer(s), [1, 2, 3]));
- assert(io::write(s, [4, 5]) as size == 2);
- assert(bytes::equal(buffer(s), [1, 2, 3, 4, 5]));
+ assert(io::write(&s, [1, 2, 3]) as size == 3);
+ assert(bytes::equal(buffer(&s), [1, 2, 3]));
+ assert(io::write(&s, [4, 5]) as size == 2);
+ assert(bytes::equal(buffer(&s), [1, 2, 3, 4, 5]));
let buf: [2]u8 = [0...];
- assert(io::seek(s, 0, io::whence::SET) as io::off == 0: io::off);
- assert(io::read(s, buf[..]) as size == 2 && bytes::equal(buf, [1, 2]));
- assert(io::read(s, buf[..]) as size == 2 && bytes::equal(buf, [3, 4]));
- assert(io::read(s, buf[..]) as size == 1 && buf[0] == 5);
- assert(io::read(s, buf[..]) is io::EOF);
- assert(io::write(s, [6, 7, 8]) as size == 3);
- assert(bytes::equal(buffer(s), [1, 2, 3, 4, 5, 6, 7, 8]));
+ assert(io::seek(&s, 0, io::whence::SET) as io::off == 0: io::off);
+ assert(io::read(&s, buf[..]) as size == 2 && bytes::equal(buf, [1, 2]));
+ assert(io::read(&s, buf[..]) as size == 2 && bytes::equal(buf, [3, 4]));
+ assert(io::read(&s, buf[..]) as size == 1 && buf[0] == 5);
+ assert(io::read(&s, buf[..]) is io::EOF);
+ assert(io::write(&s, [6, 7, 8]) as size == 3);
+ assert(bytes::equal(buffer(&s), [1, 2, 3, 4, 5, 6, 7, 8]));
reset(s);
- assert(len(buffer(s)) == 0);
- assert(io::write(s, [1, 2, 3]) as size == 3);
- assert(truncate(s) is void);
- assert(len(buffer(s)) == 0);
+ assert(len(buffer(&s)) == 0);
+ assert(io::write(&s, [1, 2, 3]) as size == 3);
+ assert(truncate(&s) is void);
+ assert(len(buffer(&s)) == 0);
let sl: []u8 = alloc([1, 2, 3]);
let s = dynamic_from(sl, io::mode::WRITE);
- assert(io::write(s, [0, 0]) as size == 2);
- assert(io::seek(s, 0, io::whence::END) as io::off == 5: io::off);
- assert(io::write(s, [4, 5, 6]) as size == 3);
- assert(bytes::equal(buffer(s), [0, 0, 1, 2, 3, 4, 5, 6]));
- assert(io::read(s, buf[..]) as io::error is errors::unsupported);
- io::close(s);
+ assert(io::write(&s, [0, 0]) as size == 2);
+ assert(io::seek(&s, 0, io::whence::END) as io::off == 5: io::off);
+ assert(io::write(&s, [4, 5, 6]) as size == 3);
+ assert(bytes::equal(buffer(&s), [0, 0, 1, 2, 3, 4, 5, 6]));
+ assert(io::read(&s, buf[..]) as io::error is errors::unsupported);
+ io::close(&s);
sl = alloc([1, 2]);
let s = dynamic_from(sl, io::mode::READ);
- assert(io::read(s, buf[..1]) as size == 1 && buf[0] == 1);
- assert(io::seek(s, 1, io::whence::CUR) as io::off == 2: io::off);
- assert(io::read(s, buf[..]) is io::EOF);
- assert(io::write(s, [1, 2]) as io::error is errors::unsupported);
- io::close(s);
+ assert(io::read(&s, buf[..1]) as size == 1 && buf[0] == 1);
+ assert(io::seek(&s, 1, io::whence::CUR) as io::off == 2: io::off);
+ assert(io::read(&s, buf[..]) is io::EOF);
+ assert(io::write(&s, [1, 2]) as io::error is errors::unsupported);
+ io::close(&s);
};
@test fn fixed() void = {
let buf: [1024]u8 = [0...];
let stream = fixed(buf, io::mode::WRITE);
- defer io::close(stream);
+ defer io::close(&stream);
let n = 0z;
- n += io::write(stream, strings::toutf8("hello ")) as size;
- n += io::write(stream, strings::toutf8("world")) as size;
+ n += io::write(&stream, strings::toutf8("hello ")) as size;
+ n += io::write(&stream, strings::toutf8("world")) as size;
assert(bytes::equal(buf[..n], strings::toutf8("hello world")));
- assert(io::seek(stream, 6, io::whence::SET)
+ assert(io::seek(&stream, 6, io::whence::SET)
as io::error is errors::unsupported);
let out: [2]u8 = [0...];
let s = fixed([1u8, 2u8], io::mode::READ);
- defer io::close(s);
- assert(io::read(s, out[..1]) as size == 1 && out[0] == 1);
- assert(io::seek(s, 1, io::whence::CUR) as io::off == 2: io::off);
- assert(io::read(s, buf[..]) is io::EOF);
- assert(io::write(s, [1, 2]) as io::error is errors::unsupported);
+ defer io::close(&s);
+ assert(io::read(&s, out[..1]) as size == 1 && out[0] == 1);
+ assert(io::seek(&s, 1, io::whence::CUR) as io::off == 2: io::off);
+ assert(io::read(&s, buf[..]) is io::EOF);
+ assert(io::write(&s, [1, 2]) as io::error is errors::unsupported);
};
diff --git a/cmd/hare/subcmds.ha b/cmd/hare/subcmds.ha
@@ -539,7 +539,7 @@ fn version(args: []str) void = {
fmt::printfln("HAREPATH\t{}", items)!;
case let env: str =>
fmt::printf("HAREPATH\t")!;
- bufio::flush(os::stdout)!;
+ bufio::flush(&os::stdout_bufio)!;
fmt::errorf("(from environment)")!;
const items = strings::split(env, ":");
defer free(items);
diff --git a/cmd/harec/context.ha b/cmd/harec/context.ha
@@ -1,10 +1,11 @@
+use bufio;
use io;
use hare::types;
use hare::unit;
type context = struct {
out: io::handle,
- buf: io::handle,
+ buf: bufio::memstream,
store: *types::typestore,
unit: *unit::unit,
arch: struct {
diff --git a/cmd/harec/gen.ha b/cmd/harec/gen.ha
@@ -25,7 +25,7 @@ fn gen(out: io::handle, store: *types::typestore, unit: *unit::unit) void = {
},
...
};
- defer io::close(ctx.buf);
+ defer io::close(&ctx.buf);
for (let i = 0z; i < len(unit.decls); i += 1) {
match (unit.decls[i].decl) {
case let func: unit::decl_func =>
@@ -73,20 +73,20 @@ fn gen_func(ctx: *context, decl: *unit::decl) void = {
// on-demand at the start of the function, rather than spread out
// through the body. This is more reliable on qbe's ARM backend, and
// generates better IL besides.
- bufio::reset(ctx.buf);
+ bufio::reset(&ctx.buf);
- fmt::fprintln(ctx.buf, mklabel(ctx, "body"))!;
+ fmt::fprintln(&ctx.buf, mklabel(ctx, "body"))!;
const rval = gen_expr(ctx, body);
if (!body.terminates) {
if (has_rval) {
- emit(ctx.buf, void, qinstr::RET, rval);
+ emit(&ctx.buf, void, qinstr::RET, rval);
} else {
- emit(ctx.buf, void, qinstr::RET);
+ emit(&ctx.buf, void, qinstr::RET);
};
};
- io::write(ctx.out, bufio::buffer(ctx.buf))!;
+ io::write(ctx.out, bufio::buffer(&ctx.buf))!;
fmt::fprintln(ctx.out, "}\n")!;
};
@@ -103,7 +103,7 @@ fn gen_store(ctx: *context, object: value, value: value) void = {
case => void; // Handled below
};
const instr = qinstr_store(ctx, object._type);
- emit(ctx.buf, void, instr, value, object);
+ emit(&ctx.buf, void, instr, value, object);
};
fn gen_load(ctx: *context, object: value) value = {
@@ -121,7 +121,7 @@ fn gen_load(ctx: *context, object: value) value = {
const instr = qinstr_load(ctx, object._type);
const temp = mktemp(ctx);
const ty = qtype_lookup(ctx, object._type, false);
- emit(ctx.buf, (ty, temp), instr, object);
+ emit(&ctx.buf, (ty, temp), instr, object);
return value {
value = temp,
_type = object._type,
@@ -196,7 +196,7 @@ fn gen_binding(ctx: *context, expr: *unit::expr) value = {
// const lval, instr = allocval(value);
const instr = qinstr_alloc(value._type);
const lval = mklval(ctx, value);
- emit(ctx.buf, lval, instr, value._type.sz);
+ emit(&ctx.buf, lval, instr, value._type.sz);
gen_expr_at(ctx, item.init, value);
};
return vvoid;
@@ -238,9 +238,9 @@ fn gen_return(ctx: *context, expr: *unit::expr) value = {
const rexpr = expr.expr as unit::_return;
match (rexpr) {
case null =>
- emit(ctx.buf, void, qinstr::RET);
+ emit(&ctx.buf, void, qinstr::RET);
case let expr: *unit::expr =>
- emit(ctx.buf, void, qinstr::RET, gen_expr(ctx, expr));
+ emit(&ctx.buf, void, qinstr::RET, gen_expr(ctx, expr));
};
return vvoid;
};
diff --git a/cmd/harec/main.ha b/cmd/harec/main.ha
@@ -69,9 +69,9 @@ export fn main() void = {
defer io::close(input);
static let buf: [os::BUFSIZ]u8 = [0...];
let bufin = bufio::buffered(input, buf, []);
- defer io::close(bufin);
+ defer io::close(&bufin);
- let lexer = lex::init(bufin, cmd.args[i]);
+ let lexer = lex::init(&bufin, cmd.args[i]);
let su = match (parse::subunit(&lexer)) {
case let err: parse::error =>
printerr(err);
diff --git a/cmd/haredoc/docstr.ha b/cmd/haredoc/docstr.ha
@@ -21,7 +21,7 @@ type docstate = enum {
};
type parser = struct {
- src: io::handle,
+ src: bufio::bufstream,
state: docstate,
};
@@ -34,14 +34,14 @@ fn parsedoc(in: io::handle) parser = {
};
fn scandoc(par: *parser) (token | void) = {
- const rn = match (bufio::scanrune(par.src)!) {
+ const rn = match (bufio::scanrune(&par.src)!) {
case let rn: rune =>
yield rn;
case io::EOF =>
return;
};
- bufio::unreadrune(par.src, rn);
+ bufio::unreadrune(&par.src, rn);
switch (par.state) {
case docstate::TEXT =>
switch (rn) {
@@ -72,18 +72,18 @@ fn scantext(par: *parser) (token | void) = {
// TODO: Collapse whitespace
const buf = strio::dynamic();
for (true) {
- const rn = match (bufio::scanrune(par.src)!) {
+ const rn = match (bufio::scanrune(&par.src)!) {
case io::EOF => break;
case let rn: rune =>
yield rn;
};
switch (rn) {
case '[' =>
- bufio::unreadrune(par.src, rn);
+ bufio::unreadrune(&par.src, rn);
break;
case '\n' =>
strio::appendrune(&buf, rn)!;
- const rn = match (bufio::scanrune(par.src)!) {
+ const rn = match (bufio::scanrune(&par.src)!) {
case io::EOF => break;
case let rn: rune =>
yield rn;
@@ -92,7 +92,7 @@ fn scantext(par: *parser) (token | void) = {
par.state = docstate::PARAGRAPH;
break;
};
- bufio::unreadrune(par.src, rn);
+ bufio::unreadrune(&par.src, rn);
case =>
strio::appendrune(&buf, rn)!;
};
@@ -105,7 +105,7 @@ fn scantext(par: *parser) (token | void) = {
};
fn scanref(par: *parser) (token | void) = {
- match (bufio::scanrune(par.src)!) {
+ match (bufio::scanrune(&par.src)!) {
case io::EOF =>
return;
case let rn: rune =>
@@ -113,12 +113,12 @@ fn scanref(par: *parser) (token | void) = {
abort();
};
};
- match (bufio::scanrune(par.src)!) {
+ match (bufio::scanrune(&par.src)!) {
case io::EOF =>
return;
case let rn: rune =>
if (rn != '[') {
- bufio::unreadrune(par.src, rn);
+ bufio::unreadrune(&par.src, rn);
return strings::dup("["): text;
};
};
@@ -127,11 +127,11 @@ fn scanref(par: *parser) (token | void) = {
defer io::close(&buf);
// TODO: Handle invalid syntax here
for (true) {
- match (bufio::scanrune(par.src)!) {
+ match (bufio::scanrune(&par.src)!) {
case let rn: rune =>
switch (rn) {
case ']' =>
- bufio::scanrune(par.src) as rune; // ]
+ bufio::scanrune(&par.src) as rune; // ]
break;
case =>
strio::appendrune(&buf, rn)!;
@@ -146,7 +146,7 @@ fn scanref(par: *parser) (token | void) = {
fn scansample(par: *parser) (token | void) = {
let nws = 0z;
for (true) {
- match (bufio::scanrune(par.src)!) {
+ match (bufio::scanrune(&par.src)!) {
case io::EOF =>
return;
case let rn: rune =>
@@ -156,7 +156,7 @@ fn scansample(par: *parser) (token | void) = {
case '\t' =>
nws += 8;
case =>
- bufio::unreadrune(par.src, rn);
+ bufio::unreadrune(&par.src, rn);
break;
};
};
@@ -168,7 +168,7 @@ fn scansample(par: *parser) (token | void) = {
let cont = true;
let buf = strio::dynamic();
for (cont) {
- const rn = match (bufio::scanrune(par.src)!) {
+ const rn = match (bufio::scanrune(&par.src)!) {
case io::EOF => break;
case let rn: rune =>
yield rn;
@@ -183,7 +183,7 @@ fn scansample(par: *parser) (token | void) = {
// Consume whitespace
for (let i = 0z; i < nws) {
- match (bufio::scanrune(par.src)!) {
+ match (bufio::scanrune(&par.src)!) {
case io::EOF => break;
case let rn: rune =>
switch (rn) {
@@ -195,7 +195,7 @@ fn scansample(par: *parser) (token | void) = {
strio::appendrune(&buf, rn)!;
i = 0;
case =>
- bufio::unreadrune(par.src, rn);
+ bufio::unreadrune(&par.src, rn);
cont = false;
break;
};
@@ -216,7 +216,7 @@ fn scansample(par: *parser) (token | void) = {
fn scanlist(par: *parser) (token | void) = {
let items: list = [];
for (true) {
- match (bufio::scanrune(par.src)!) {
+ match (bufio::scanrune(&par.src)!) {
case io::EOF => break;
case let rn: rune =>
if (rn != '-') {
@@ -224,7 +224,7 @@ fn scanlist(par: *parser) (token | void) = {
};
};
// XXX: multi-line list items
- append(items, match (bufio::scanline(par.src)!) {
+ append(items, match (bufio::scanline(&par.src)!) {
case io::EOF => break;
case let u: []u8 =>
yield strings::fromutf8(u);
diff --git a/cmd/haredoc/html.ha b/cmd/haredoc/html.ha
@@ -270,7 +270,7 @@ fn details(ctx: *context, decl: ast::decl) (void | error) = {
if (len(decl.docs) != 0) {
const buf = strings::toutf8(decl.docs);
- markup_html(ctx, bufio::fixed(buf, io::mode::READ))?;
+ markup_html(ctx, &bufio::fixed(buf, io::mode::READ))?;
} else {
fmt::fprintln(ctx.out, "</details>")?;
};
diff --git a/crypto/argon2/argon2.ha b/crypto/argon2/argon2.ha
@@ -37,7 +37,7 @@ type mode = enum {
// implementation of argon2 does not process hashes in parallel, though it will
// still compute the correct hash if this value is greater than one.
//
-// 'version' specifies the version of the argon2 function. The implementation
+// 'version' specifies the version of the argon2 function. The implementation
// currently only supports version 1.3. Use [[VERSION]] here.
//
// 'secret' and 'data' are optional byte arrays that are applied to the initial
@@ -99,7 +99,7 @@ type context = struct {
// is recommended, and 4 bytes is the minimum.
//
// The argon2d mode uses data-dependent memory access and is suitable for
-// applications with no threats of side-channel timing attacks.
+// applications with no threats of side-channel timing attacks.
export fn argon2d(
dest: []u8,
password: []u8,
@@ -338,26 +338,25 @@ fn varhash(dest: []u8, block: []u8) void = {
let v: [64]u8 = [0...];
let h = blake2b::blake2b([], 64);
let destbuf = bufio::fixed(dest, io::mode::WRITE);
- defer io::close(destbuf);
hash_leputu32(&h, len(dest): u32);
hash::write(&h, block);
hash::sum(&h, v[..]);
- io::write(destbuf, v[..32])!;
+ io::write(&destbuf, v[..32])!;
for (let i = 1z; i < r; i += 1) {
hash::reset(&h);
hash::write(&h, v[..]);
hash::sum(&h, v[..]);
- io::write(destbuf, v[..32])!;
+ io::write(&destbuf, v[..32])!;
};
const remainder = len(dest) - 32 * r;
let hend = blake2b::blake2b([], remainder);
hash::write(&hend, v[..]);
hash::finish(&hend, v[..remainder]);
- io::write(destbuf, v[..remainder])!;
+ io::write(&destbuf, v[..remainder])!;
};
fn divceil(dividend: u32, divisor: u32) u32 = {
diff --git a/encoding/base64/base64.ha b/encoding/base64/base64.ha
@@ -124,9 +124,8 @@ export fn decode_static(
in: io::handle,
) (size | errors::invalid | io::error) = {
let buf = bufio::fixed(out, io::mode::WRITE);
- defer io::close(buf);
let dec = decoder(alphabet, in);
- match (io::copy(buf, &dec)) {
+ match (io::copy(&buf, &dec)) {
case let err: io::error =>
match (err) {
case errors::invalid =>
@@ -162,14 +161,13 @@ export fn decodestr_static(
export fn decodeslice(alphabet: []u8, in: []u8) ([]u8 | errors::invalid) = {
let out = bufio::dynamic(io::mode::WRITE);
let in = bufio::fixed(in, io::mode::READ);
- defer io::close(in);
- let dec = decoder(alphabet, in);
- match (io::copy(out, &dec)) {
+ let dec = decoder(alphabet, &in);
+ match (io::copy(&out, &dec)) {
case io::error =>
- io::close(out);
+ io::close(&out);
return errors::invalid;
case size =>
- return bufio::finish(out);
+ return bufio::buffer(&out);
};
};
@@ -181,8 +179,7 @@ export fn decodeslice_static(
in: []u8,
) (size | errors::invalid) = {
let in = bufio::fixed(in, io::mode::READ);
- defer io::close(in); // bufio::finish?
- match (decode_static(alphabet, out, in)) {
+ match (decode_static(alphabet, out, &in)) {
case let s: size =>
return s;
case errors::invalid =>
diff --git a/fmt/fmt.ha b/fmt/fmt.ha
@@ -37,16 +37,15 @@ export fn errorfln(fmt: str, args: field...) (io::error | size) =
// caller must free the return value.
export fn asprintf(fmt: str, args: field...) str = {
let buf = bufio::dynamic(io::mode::WRITE);
- assert(fprintf(buf, fmt, args...) is size);
- return strings::fromutf8_unsafe(bufio::finish(buf));
+ assert(fprintf(&buf, fmt, args...) is size);
+ return strings::fromutf8_unsafe(bufio::buffer(&buf));
};
// Formats text for printing and writes it into a caller supplied buffer. The
// returned string is borrowed from this buffer.
export fn bsprintf(buf: []u8, fmt: str, args: field...) str = {
let sink = bufio::fixed(buf, io::mode::WRITE);
- defer io::close(sink);
- let l = fprintf(sink, fmt, args...) as size;
+ let l = fprintf(&sink, fmt, args...) as size;
return strings::fromutf8_unsafe(buf[..l]);
};
@@ -92,8 +91,8 @@ export fn errorln(args: formattable...) (io::error | size) =
// the return value.
export fn asprint(args: formattable...) str = {
let buf = bufio::dynamic(io::mode::WRITE);
- assert(fprint(buf, args...) is size);
- return strings::fromutf8_unsafe(bufio::finish(buf));
+ assert(fprint(&buf, args...) is size);
+ return strings::fromutf8_unsafe(bufio::buffer(&buf));
};
// Formats values for printing using the default format modifiers and writes
@@ -101,8 +100,7 @@ export fn asprint(args: formattable...) str = {
// is borrowed from this buffer.
export fn bsprint(buf: []u8, args: formattable...) str = {
let sink = bufio::fixed(buf, io::mode::WRITE);
- defer io::close(sink);
- assert(fprint(sink, args...) is size);
+ assert(fprint(&sink, args...) is size);
return strings::fromutf8_unsafe(buf);
};
diff --git a/format/xml/parser.ha b/format/xml/parser.ha
@@ -22,15 +22,16 @@ export fn parse(in: io::handle) (*parser | error) = {
// stack is so that we have a consistent address for the bufio buffer.
// This is kind of lame, maybe we can avoid that.
let par = alloc(parser {
- in = in,
close = false,
namebuf = strio::dynamic(),
entbuf = strio::dynamic(),
textbuf = strio::dynamic(),
...
});
- if (!bufio::isbuffered(in)) {
- par.in = bufio::buffered(par.in, par.buf[..], []);
+ if (bufio::isbuffered(in)) {
+ par.in = in as *io::stream: *bufio::bufstream;
+ } else {
+ par.in = alloc(bufio::buffered(par.in, par.buf[..], []));
par.close = true;
};
prolog(par)?;
@@ -41,7 +42,7 @@ export fn parse(in: io::handle) (*parser | error) = {
// underlying I/O handle.
export fn parser_free(par: *parser) void = {
if (par.close) {
- io::close(par.in);
+ free(par.in);
};
io::close(&par.namebuf);
io::close(&par.entbuf);
diff --git a/format/xml/types.ha b/format/xml/types.ha
@@ -1,10 +1,11 @@
+use bufio;
use encoding::utf8;
use io;
use os;
use strio;
export type parser = struct {
- in: io::handle,
+ in: *bufio::bufstream,
buf: [os::BUFSIZ]u8,
close: bool,
state: state,
diff --git a/fs/mem/stream.ha b/fs/mem/stream.ha
@@ -6,7 +6,7 @@ use types;
type stream = struct {
io::stream,
- source: *io::stream,
+ source: bufio::memstream,
inode: *inode,
appnd: bool,
};
@@ -40,43 +40,43 @@ fn stream_open(
ino.opencount = types::SIZE_MAX;
s.source = bufio::dynamic_from(f, mode);
if (!appnd) {
- bufio::truncate(s.source)?;
+ bufio::truncate(&s.source)?;
};
};
- io::seek(s.source, 0, io::whence::SET)?;
+ io::seek(&s.source, 0, io::whence::SET)?;
return s;
};
fn read(s: *io::stream, buf: []u8) (size | io::EOF | io::error) = {
- return io::read((s: *stream).source, buf);
+ return io::read(&(s: *stream).source, buf);
};
fn write(s: *io::stream, buf: const []u8) (size | io::error) = {
let s = s: *stream;
if (s.appnd) {
- io::seek(s.source, 0, io::whence::END)?;
+ io::seek(&s.source, 0, io::whence::END)?;
};
- let sz = io::write(s.source, buf)?;
- s.inode.data = bufio::buffer(s.source);
+ let sz = io::write(&s.source, buf)?;
+ s.inode.data = bufio::buffer(&s.source);
return sz;
};
fn seek(s: *io::stream, off: io::off, w: io::whence) (io::off | io::error) = {
- return io::seek((s: *stream).source, off, w);
+ return io::seek(&(s: *stream).source, off, w);
};
fn stream_close(s: *io::stream) void = {
let s = s: *stream;
defer free(s);
if (s.writer == null) {
- io::close(s.source);
+ io::close(&s.source);
s.inode.opencount -= 1;
if (s.inode.opencount > 0) {
return;
};
} else {
s.inode.opencount = 0;
- bufio::finish(s.source);
+ io::close(&s.source);
};
if (s.inode.parent == null) {
diff --git a/hare/module/manifest.ha b/hare/module/manifest.ha
@@ -67,7 +67,7 @@ export fn manifest_load(ctx: *context, ident: ast::ident) (manifest | error) = {
let buf: [4096]u8 = [0...];
let file = bufio::buffered(file, buf, []);
for (true) {
- let line = match (bufio::scanline(file)?) {
+ let line = match (bufio::scanline(&file)?) {
case io::EOF =>
break;
case let line: []u8 =>
diff --git a/hare/parse/ident.ha b/hare/parse/ident.ha
@@ -42,7 +42,6 @@ export fn ident(lexer: *lex::lexer) (ast::ident | error) = {
// caller needn't provide a lexer instance.
export fn identstr(in: str) (ast::ident | error) = {
const buf = bufio::fixed(strings::toutf8(in), io::mode::READ);
- defer io::close(buf);
- const lexer = lex::init(buf, "<string>");
+ const lexer = lex::init(&buf, "<string>");
return ident(&lexer);
};
diff --git a/os/+linux/stdfd.ha b/os/+linux/stdfd.ha
@@ -1,12 +1,12 @@
use bufio;
use io;
-let static_stdin_bufio: bufio::bufstream = bufio::bufstream {
+export let stdin_bufio: bufio::bufstream = bufio::bufstream {
source = 0,
...
};
-let static_stdout_bufio: bufio::bufstream = bufio::bufstream {
+export let stdout_bufio: bufio::bufstream = bufio::bufstream {
source = 1,
...
};
@@ -31,10 +31,12 @@ export def BUFSIZ: size = 4096; // 4 KiB
@init fn init_stdfd() void = {
static let stdinbuf: [BUFSIZ]u8 = [0...];
- stdin = bufio::static_buffered(0, stdinbuf, [], &static_stdin_bufio);
+ stdin_bufio = bufio::buffered(0, stdinbuf, []);
+ stdin = &stdin_bufio;
static let stdoutbuf: [BUFSIZ]u8 = [0...];
- stdout = bufio::static_buffered(1, [], stdoutbuf, &static_stdout_bufio);
+ stdout_bufio = bufio::buffered(0, [], stdoutbuf);
+ stdout = &stdout_bufio;
};
@fini fn fini_stdfd() void = {
diff --git a/path/join.ha b/path/join.ha
@@ -18,15 +18,15 @@ export fn join(paths: str...) str = {
l -= 1;
};
for (let q = 0z; q < l) {
- let w = io::write(sink, buf[q..l]) as size;
+ let w = io::write(&sink, buf[q..l]) as size;
q += w;
};
if (i + 1 < len(paths)) {
- assert(io::write(sink, [PATHSEP]) as size == 1);
+ assert(io::write(&sink, [PATHSEP]) as size == 1);
};
};
- return strings::fromutf8_unsafe(bufio::finish(sink));
+ return strings::fromutf8_unsafe(bufio::buffer(&sink));
};
@test fn join() void = {
diff --git a/unix/hosts/lookup.ha b/unix/hosts/lookup.ha
@@ -29,9 +29,7 @@ export fn lookup(name: str) []ip::addr = {
};
const scanner = bufio::fixed(line, io::mode::READ);
- defer io::close(scanner);
-
- const tok = match (bufio::scantok(scanner, ' ', '\t')!) {
+ const tok = match (bufio::scantok(&scanner, ' ', '\t')!) {
case io::EOF =>
break;
case let tok: []u8 =>
@@ -41,7 +39,7 @@ export fn lookup(name: str) []ip::addr = {
const addr = ip::parse(strings::fromutf8(tok))!;
for (true) {
- const tok = match (bufio::scantok(scanner, ' ', '\t')!) {
+ const tok = match (bufio::scantok(&scanner, ' ', '\t')!) {
case io::EOF =>
break;
case let tok: []u8 =>
diff --git a/unix/resolvconf/load.ha b/unix/resolvconf/load.ha
@@ -38,9 +38,7 @@ export fn load() []ip::addr = {
};
const scanner = bufio::fixed(line, io::mode::READ);
- defer io::close(scanner);
-
- const tok = match (bufio::scantok(scanner, ' ', '\t')!) {
+ const tok = match (bufio::scantok(&scanner, ' ', '\t')!) {
case io::EOF =>
break;
case let tok: []u8 =>
@@ -51,7 +49,7 @@ export fn load() []ip::addr = {
continue;
};
- const tok = match (bufio::scantok(scanner, ' ')!) {
+ const tok = match (bufio::scantok(&scanner, ' ')!) {
case io::EOF =>
break;
case let tok: []u8 =>
diff --git a/uuid/uuid.ha b/uuid/uuid.ha
@@ -145,8 +145,7 @@ export fn decode(in: io::handle) (uuid | invalid | io::error) = {
// Decodes a UUID from a string.
export fn decodestr(in: str) (uuid | invalid) = {
let buf = bufio::fixed(strings::toutf8(in), io::mode::READ);
- defer io::close(buf);
- match (decode(buf)) {
+ match (decode(&buf)) {
case let err: io::error =>
abort();
case invalid =>