libostd/ostd/io.hh

217 lines
4.7 KiB
C++
Raw Normal View History

/* Standard I/O implementation for OctaSTD.
*
* This file is part of OctaSTD. See COPYING.md for futher information.
*/
2015-07-13 21:08:55 +02:00
#ifndef OSTD_IO_HH
#define OSTD_IO_HH
#include <stdio.h>
2017-01-25 01:44:22 +01:00
#include <vector>
2015-07-13 21:08:55 +02:00
#include "ostd/platform.hh"
#include "ostd/string.hh"
#include "ostd/stream.hh"
#include "ostd/format.hh"
2015-07-13 21:07:14 +02:00
namespace ostd {
enum class StreamMode {
2016-03-26 18:26:37 +01:00
read = 0, write, append, read_u, write_u, append_u
};
namespace detail {
2016-06-23 20:18:35 +02:00
static char const *filemodes[] = {
2016-03-26 18:26:37 +01:00
"rb", "wb", "ab", "rb+", "wb+", "ab+"
};
}
struct FileStream: Stream {
FileStream(): p_f(), p_owned(false) {}
2016-06-23 20:18:35 +02:00
FileStream(FileStream const &) = delete;
FileStream(FileStream &&s): p_f(s.p_f), p_owned(s.p_owned) {
s.p_f = nullptr;
s.p_owned = false;
}
2016-03-26 16:19:00 +01:00
FileStream(ConstCharRange path, StreamMode mode = StreamMode::read): p_f() {
open(path, mode);
}
FileStream(FILE *f): p_f(f), p_owned(false) {}
~FileStream() { close(); }
2016-06-23 20:18:35 +02:00
FileStream &operator=(FileStream const &) = delete;
FileStream &operator=(FileStream &&s) {
close();
swap(s);
return *this;
}
2016-03-26 16:19:00 +01:00
bool open(ConstCharRange path, StreamMode mode = StreamMode::read) {
if (p_f || (path.size() > FILENAME_MAX)) {
return false;
}
2015-07-21 23:30:53 +02:00
char buf[FILENAME_MAX + 1];
memcpy(buf, &path[0], path.size());
buf[path.size()] = '\0';
2016-07-06 19:31:21 +02:00
p_owned = false;
#ifndef OSTD_PLATFORM_WIN32
2017-01-30 19:11:39 +01:00
p_f = fopen(buf, detail::filemodes[size_t(mode)]);
2016-07-06 19:31:21 +02:00
#else
2017-01-30 19:11:39 +01:00
if (fopen_s(&p_f, buf, detail::filemodes[size_t(mode)]) != 0) {
2016-07-06 19:31:21 +02:00
return false;
}
2016-07-06 19:31:21 +02:00
#endif
p_owned = !!p_f;
return is_open();
}
bool open(FILE *f) {
if (p_f) {
return false;
}
p_f = f;
p_owned = false;
return is_open();
}
bool is_open() const { return p_f != nullptr; }
bool is_owned() const { return p_owned; }
void close() {
if (p_f && p_owned) {
fclose(p_f);
}
p_f = nullptr;
p_owned = false;
}
bool end() const {
return feof(p_f) != 0;
}
bool seek(StreamOffset pos, StreamSeek whence = StreamSeek::set) {
2015-07-13 21:08:55 +02:00
#ifndef OSTD_PLATFORM_WIN32
return fseeko(p_f, pos, int(whence)) >= 0;
#else
return _fseeki64(p_f, pos, int(whence)) >= 0;
#endif
}
StreamOffset tell() const {
2015-07-13 21:08:55 +02:00
#ifndef OSTD_PLATFORM_WIN32
return ftello(p_f);
#else
return _ftelli64(p_f);
#endif
}
bool flush() { return !fflush(p_f); }
2017-01-30 19:11:39 +01:00
size_t read_bytes(void *buf, size_t count) {
return fread(buf, 1, count, p_f);
}
2017-01-30 19:11:39 +01:00
size_t write_bytes(void const *buf, size_t count) {
return fwrite(buf, 1, count, p_f);
}
int getchar() {
return fgetc(p_f);
}
bool putchar(int c) {
return fputc(c, p_f) != EOF;
}
void swap(FileStream &s) {
2017-01-29 15:56:02 +01:00
using std::swap;
swap(p_f, s.p_f);
swap(p_owned, s.p_owned);
}
FILE *get_file() { return p_f; }
private:
FILE *p_f;
bool p_owned;
};
2017-01-29 15:56:02 +01:00
inline void swap(FileStream &a, FileStream &b) {
a.swap(b);
}
static FileStream in(stdin);
static FileStream out(stdout);
static FileStream err(stderr);
/* no need to call anything from FileStream, prefer simple calls... */
2015-07-21 23:21:54 +02:00
namespace detail {
/* lightweight output range for direct stdout */
struct StdoutRange: OutputRange<StdoutRange> {
using Value = char;
using Reference = char &;
using Size = size_t;
using Difference = ptrdiff_t;
StdoutRange() {}
bool put(char c) {
return putchar(c) != EOF;
}
};
inline size_t range_put_n(StdoutRange &, char const *p, size_t n) {
return fwrite(p, 1, n, stdout);
}
}
template<typename T>
2016-06-23 20:18:35 +02:00
inline void write(T const &v) {
format(detail::StdoutRange{}, FormatSpec{'s'}, v);
}
template<typename T, typename ...A>
2016-06-23 20:18:35 +02:00
inline void write(T const &v, A const &...args) {
write(v);
write(args...);
}
template<typename T>
2016-06-23 20:18:35 +02:00
inline void writeln(T const &v) {
2015-07-21 23:21:54 +02:00
write(v);
2017-02-11 01:28:14 +01:00
if (putchar('\n') == EOF) {
/* consistency with format module */
throw format_error{"stream EOF"};
}
}
template<typename T, typename ...A>
2016-06-23 20:18:35 +02:00
inline void writeln(T const &v, A const &...args) {
write(v);
write(args...);
2017-02-11 01:28:14 +01:00
if (putchar('\n') == EOF) {
throw format_error{"stream EOF"};
}
}
2015-07-01 03:22:42 +02:00
template<typename ...A>
2016-06-23 20:18:35 +02:00
inline void writef(ConstCharRange fmt, A const &...args) {
format(detail::StdoutRange{}, fmt, args...);
2015-07-01 03:22:42 +02:00
}
template<typename ...A>
2016-06-23 20:18:35 +02:00
inline void writefln(ConstCharRange fmt, A const &...args) {
writef(fmt, args...);
2017-02-11 01:28:14 +01:00
if (putchar('\n') == EOF) {
throw format_error{"stream EOF"};
}
2015-07-01 03:22:42 +02:00
}
2015-07-13 21:07:14 +02:00
} /* namespace ostd */
2016-02-07 22:17:15 +01:00
#endif