#include <unistd.h>
#include <errno.h>
import openkal.stream;
namespace {
int translate(int e) {
switch (e) {
case EBADF: case EINVAL: case EFAULT: return kal_err_invalid;
case EAGAIN: return kal_err_again;
case ENOMEM: return kal_err_no_memory;
case ENOSPC: case EFBIG: return kal_err_no_space;
case EACCES: case EPERM: return kal_err_permission;
case EPIPE: case ECONNRESET: return kal_err_closed;
case ENOTSUP: return kal_err_not_supported;
default: return kal_err_io;
}
}
}
extern "C" {
kal_stream kal_stdin (void) { return kal_stream{0}; }
kal_stream kal_stdout(void) { return kal_stream{1}; }
kal_stream kal_stderr(void) { return kal_stream{2}; }
kal_io_result kal_stream_write(kal_stream s, const void* buf, kal_uintptr len) {
const auto* p = static_cast<const unsigned char*>(buf);
kal_uintptr done = 0;
while (done < len) {
const auto r = ::write(static_cast<int>(s.h), p + done, len - done);
if (r < 0) {
if (errno == EINTR) continue;
return { done, translate(errno) };
}
if (r == 0) break;
done += static_cast<kal_uintptr>(r);
}
return { done, done == len ? kal_ok : kal_err_io };
}
kal_io_result kal_stream_read(kal_stream s, void* buf, kal_uintptr len) {
for (;;) {
const auto r = ::read(static_cast<int>(s.h), buf, len);
if (r < 0) {
if (errno == EINTR) continue;
return { 0, translate(errno) };
}
return { static_cast<kal_uintptr>(r), kal_ok };
}
}
int kal_stream_flush(kal_stream) {
return kal_ok;
}
}