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