libostd/src/io.cc

139 lines
3.1 KiB
C++
Raw Normal View History

2017-03-09 19:21:01 +01:00
/* I/O streams implementation bits.
*
2017-04-06 20:14:52 +02:00
* This file is part of libostd. See COPYING.md for futher information.
2017-03-09 19:21:01 +01:00
*/
2017-04-09 16:44:45 +02:00
#include <cstddef>
2017-03-09 19:21:01 +01:00
#include <cstdio>
#include <cstdlib>
#include <cerrno>
2018-01-05 22:31:04 +01:00
#include "ostd/stream.hh"
2017-03-09 19:21:01 +01:00
#include "ostd/io.hh"
namespace ostd {
2018-01-05 22:31:04 +01:00
/* place the vtable in here */
stream_error::~stream_error() {}
stream::~stream() {}
2017-03-09 19:21:01 +01:00
static char const *filemodes[] = {
"rb", "wb", "ab", "rb+", "wb+", "ab+"
};
static void default_close(FILE *f) {
std::fclose(f);
}
2017-05-09 21:20:37 +02:00
OSTD_EXPORT bool file_stream::open(string_range path, stream_mode mode) {
2017-03-09 19:21:01 +01:00
if (p_f || (path.size() > FILENAME_MAX)) {
return false;
}
char buf[FILENAME_MAX + 1];
std::memcpy(buf, &path[0], path.size());
buf[path.size()] = '\0';
p_closef = nullptr;
2017-03-09 19:21:01 +01:00
#ifndef OSTD_PLATFORM_WIN32
2017-04-09 16:44:45 +02:00
p_f = std::fopen(buf, filemodes[std::size_t(mode)]);
2017-03-09 19:21:01 +01:00
#else
2017-04-09 16:44:45 +02:00
if (fopen_s(&p_f, buf, filemodes[std::size_t(mode)]) != 0) {
2017-03-09 19:21:01 +01:00
return false;
}
#endif
if (p_f) {
p_closef = default_close;
}
2017-03-09 19:21:01 +01:00
return is_open();
}
2017-05-09 21:20:37 +02:00
OSTD_EXPORT bool file_stream::open(FILE *fptr, close_function f) {
2017-03-09 19:21:01 +01:00
if (p_f) {
return false;
}
p_f = fptr;
p_closef = f;
2017-03-09 19:21:01 +01:00
return is_open();
}
2017-05-09 21:20:37 +02:00
OSTD_EXPORT void file_stream::close() {
if (p_f && p_closef) {
p_closef(p_f);
2017-03-09 19:21:01 +01:00
}
p_f = nullptr;
p_closef = nullptr;
2017-03-09 19:21:01 +01:00
}
2017-05-09 21:20:37 +02:00
OSTD_EXPORT bool file_stream::end() const {
2017-03-09 19:21:01 +01:00
return std::feof(p_f) != 0;
}
2017-05-09 21:20:37 +02:00
OSTD_EXPORT void file_stream::seek(stream_off_t pos, stream_seek whence) {
#if defined(OSTD_PLATFORM_POSIX)
2017-03-09 19:21:01 +01:00
if (fseeko(p_f, pos, int(whence)))
#elif defined(OSTD_PLATFORM_WIN32)
2017-03-09 19:21:01 +01:00
if (_fseeki64(p_f, pos, int(whence)))
#else
if (fseek(p_f, pos, int(whence)))
2017-03-09 19:21:01 +01:00
#endif
{
throw stream_error{errno, std::generic_category()};
}
}
2017-05-09 21:20:37 +02:00
OSTD_EXPORT stream_off_t file_stream::tell() const {
#if defined(OSTD_PLATFORM_POSIX)
2017-03-09 19:21:01 +01:00
auto ret = ftello(p_f);
#elif defined(OSTD_PLATFORM_WIN32)
2017-03-09 19:21:01 +01:00
auto ret = _ftelli64(p_f);
#else
auto ret = ftell(p_f);
2017-03-09 19:21:01 +01:00
#endif
if (ret < 0) {
throw stream_error{errno, std::generic_category()};
}
return ret;
}
2017-05-09 21:20:37 +02:00
OSTD_EXPORT void file_stream::flush() {
2017-03-09 19:21:01 +01:00
if (std::fflush(p_f)) {
throw stream_error{EIO, std::generic_category()};
}
}
2017-05-09 21:20:37 +02:00
OSTD_EXPORT std::size_t file_stream::read_bytes(void *buf, std::size_t count) {
2017-04-09 16:44:45 +02:00
std::size_t readn = std::fread(buf, 1, count, p_f);
2017-04-04 01:06:55 +02:00
if (readn != count) {
if (std::feof(p_f) != 0) {
return readn;
}
2017-03-09 19:21:01 +01:00
throw stream_error{EIO, std::generic_category()};
}
2017-04-04 01:06:55 +02:00
return readn;
2017-03-09 19:21:01 +01:00
}
2017-05-09 21:20:37 +02:00
OSTD_EXPORT void file_stream::write_bytes(void const *buf, std::size_t count) {
2017-03-09 19:21:01 +01:00
if (std::fwrite(buf, 1, count, p_f) != count) {
throw stream_error{EIO, std::generic_category()};
}
}
2017-05-09 21:20:37 +02:00
OSTD_EXPORT int file_stream::get_char() {
2017-03-09 19:21:01 +01:00
int ret = std::fgetc(p_f);
if (ret == EOF) {
throw stream_error{EIO, std::generic_category()};
}
return ret;
}
2017-05-09 21:20:37 +02:00
OSTD_EXPORT void file_stream::put_char(int c) {
2017-03-09 19:21:01 +01:00
if (std::fputc(c, p_f) == EOF) {
throw stream_error{EIO, std::generic_category()};
}
}
OSTD_EXPORT file_stream cin{stdin};
OSTD_EXPORT file_stream cout{stdout};
OSTD_EXPORT file_stream cerr{stderr};
} /* namespace ostd */