2015-06-30 18:25:40 +00:00
|
|
|
/* Standard I/O implementation for OctaSTD.
|
|
|
|
*
|
|
|
|
* This file is part of OctaSTD. See COPYING.md for futher information.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef OCTA_IO_HH
|
|
|
|
#define OCTA_IO_HH
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
#include "octa/string.hh"
|
|
|
|
#include "octa/stream.hh"
|
2015-07-01 01:22:42 +00:00
|
|
|
#include "octa/format.hh"
|
2015-06-30 18:25:40 +00:00
|
|
|
|
|
|
|
namespace octa {
|
|
|
|
|
|
|
|
enum class StreamMode {
|
|
|
|
read, write, append,
|
|
|
|
update = 1 << 2
|
|
|
|
};
|
|
|
|
|
|
|
|
namespace detail {
|
|
|
|
static const char *filemodes[] = {
|
|
|
|
"rb", "wb", "ab", nullptr, "rb+", "wb+", "ab+"
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
struct FileStream: Stream {
|
|
|
|
FileStream(): p_f(), p_owned(false) {}
|
|
|
|
FileStream(const FileStream &) = delete;
|
|
|
|
FileStream(FileStream &&s): p_f(s.p_f), p_owned(s.p_owned) {
|
|
|
|
s.p_f = nullptr;
|
|
|
|
s.p_owned = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
FileStream(const octa::String &path, StreamMode mode): p_f() {
|
|
|
|
open(path, mode);
|
|
|
|
}
|
|
|
|
|
|
|
|
FileStream(FILE *f): p_f(f), p_owned(false) {}
|
|
|
|
|
|
|
|
~FileStream() { close(); }
|
|
|
|
|
|
|
|
FileStream &operator=(const FileStream &) = delete;
|
|
|
|
FileStream &operator=(FileStream &&s) {
|
|
|
|
close();
|
|
|
|
swap(s);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool open(const octa::String &path, StreamMode mode) {
|
|
|
|
if (p_f) return false;
|
|
|
|
p_f = fopen(path.data(), octa::detail::filemodes[octa::Size(mode)]);
|
|
|
|
p_owned = true;
|
|
|
|
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) {
|
|
|
|
return fseeko(p_f, pos, int(whence)) >= 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
StreamOffset tell() const {
|
|
|
|
return ftello(p_f);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool flush() { return !fflush(p_f); }
|
|
|
|
|
2015-06-30 22:07:28 +00:00
|
|
|
octa::Size read_bytes(void *buf, octa::Size count) {
|
2015-06-30 18:25:40 +00:00
|
|
|
return fread(buf, 1, count, p_f);
|
|
|
|
}
|
|
|
|
|
2015-06-30 22:07:28 +00:00
|
|
|
octa::Size write_bytes(const void *buf, octa::Size count) {
|
2015-06-30 18:25:40 +00:00
|
|
|
return fwrite(buf, 1, count, p_f);
|
|
|
|
}
|
|
|
|
|
|
|
|
void swap(FileStream &s) {
|
|
|
|
octa::swap(p_f, s.p_f);
|
|
|
|
octa::swap(p_owned, s.p_owned);
|
|
|
|
}
|
|
|
|
|
|
|
|
FILE *get_file() { return p_f; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
FILE *p_f;
|
|
|
|
bool p_owned;
|
|
|
|
};
|
|
|
|
|
|
|
|
static FileStream in(::stdin);
|
|
|
|
static FileStream out(::stdout);
|
|
|
|
static FileStream err(::stderr);
|
|
|
|
|
|
|
|
/* no need to call anything from FileStream, prefer simple calls... */
|
|
|
|
|
|
|
|
static inline void write(const char *s) {
|
|
|
|
fputs(s, ::stdout);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void write(const octa::String &s) {
|
|
|
|
fwrite(s.data(), 1, s.size(), ::stdout);
|
|
|
|
}
|
|
|
|
|
2015-06-30 21:41:01 +00:00
|
|
|
template<typename T>
|
|
|
|
static inline void write(const T &v) {
|
|
|
|
octa::write(octa::to_string(v));
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T, typename ...A>
|
|
|
|
static inline void write(const T &v, const A &...args) {
|
|
|
|
octa::write(v);
|
|
|
|
write(args...);
|
|
|
|
}
|
|
|
|
|
2015-06-30 18:25:40 +00:00
|
|
|
static inline void writeln(const char *s) {
|
|
|
|
octa::write(s);
|
|
|
|
putc('\n', ::stdout);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void writeln(const octa::String &s) {
|
|
|
|
octa::write(s);
|
|
|
|
putc('\n', ::stdout);
|
|
|
|
}
|
|
|
|
|
2015-06-30 21:41:01 +00:00
|
|
|
template<typename T>
|
|
|
|
static inline void writeln(const T &v) {
|
2015-06-30 22:07:28 +00:00
|
|
|
octa::writeln(octa::to_string(v));
|
2015-06-30 21:41:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T, typename ...A>
|
|
|
|
static inline void writeln(const T &v, const A &...args) {
|
|
|
|
octa::write(v);
|
|
|
|
write(args...);
|
|
|
|
putc('\n', ::stdout);
|
|
|
|
}
|
|
|
|
|
2015-07-01 01:22:42 +00:00
|
|
|
namespace detail {
|
|
|
|
struct FormatOutRange: octa::OutputRange<char> {
|
|
|
|
FormatOutRange(): needed(0) {}
|
|
|
|
octa::Size needed;
|
|
|
|
char buf[512];
|
|
|
|
void put(char v) {
|
|
|
|
if (needed < sizeof(buf))
|
|
|
|
buf[needed] = v;
|
|
|
|
++needed;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename ...A>
|
|
|
|
static inline void writef(const char *fmt, A &&...args) {
|
|
|
|
octa::detail::FormatOutRange writer1;
|
|
|
|
octa::formatted_write<octa::detail::FormatOutRange &>(writer1, fmt,
|
|
|
|
octa::forward<A>(args)...);
|
|
|
|
if (writer1.needed < sizeof(writer1.buf)) {
|
|
|
|
fwrite(writer1.buf, 1, writer1.needed, ::stdout);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
octa::String s;
|
|
|
|
s.reserve(writer1.needed);
|
|
|
|
s[writer1.needed] = '\0';
|
|
|
|
octa::formatted_write(s.iter(), fmt, octa::forward<A>(args)...);
|
|
|
|
fwrite(s.data(), 1, writer1.needed, ::stdout);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename ...A>
|
|
|
|
static inline void writef(const octa::String &fmt, A &&...args) {
|
|
|
|
writef(fmt.data(), octa::forward<A>(args)...);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename ...A>
|
|
|
|
static inline void writefln(const char *fmt, A &&...args) {
|
|
|
|
writef(fmt, octa::forward<A>(args)...);
|
|
|
|
putc('\n', ::stdout);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename ...A>
|
|
|
|
static inline void writefln(const octa::String &fmt, A &&...args) {
|
|
|
|
writef(fmt, octa::forward<A>(args)...);
|
|
|
|
putc('\n', ::stdout);
|
|
|
|
}
|
|
|
|
|
2015-07-01 00:46:01 +00:00
|
|
|
} /* namespace octa */
|
2015-06-30 18:25:40 +00:00
|
|
|
|
|
|
|
#endif
|