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.
|
|
|
|
*/
|
|
|
|
|
2015-07-13 19:08:55 +00:00
|
|
|
#ifndef OSTD_IO_HH
|
|
|
|
#define OSTD_IO_HH
|
2015-06-30 18:25:40 +00:00
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
2015-07-13 19:08:55 +00:00
|
|
|
#include "ostd/platform.hh"
|
|
|
|
#include "ostd/string.hh"
|
|
|
|
#include "ostd/stream.hh"
|
|
|
|
#include "ostd/format.hh"
|
2015-06-30 18:25:40 +00:00
|
|
|
|
2015-07-13 19:07:14 +00:00
|
|
|
namespace ostd {
|
2015-06-30 18:25:40 +00:00
|
|
|
|
|
|
|
enum class StreamMode {
|
2016-03-26 17:26:37 +00:00
|
|
|
read = 0, write, append, read_u, write_u, append_u
|
2015-06-30 18:25:40 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
namespace detail {
|
2016-06-23 18:18:35 +00:00
|
|
|
static char const *filemodes[] = {
|
2016-03-26 17:26:37 +00:00
|
|
|
"rb", "wb", "ab", "rb+", "wb+", "ab+"
|
2015-06-30 18:25:40 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
struct FileStream: Stream {
|
|
|
|
FileStream(): p_f(), p_owned(false) {}
|
2016-06-23 18:18:35 +00:00
|
|
|
FileStream(FileStream const &) = delete;
|
2015-06-30 18:25:40 +00:00
|
|
|
FileStream(FileStream &&s): p_f(s.p_f), p_owned(s.p_owned) {
|
|
|
|
s.p_f = nullptr;
|
|
|
|
s.p_owned = false;
|
|
|
|
}
|
|
|
|
|
2016-03-26 15:19:00 +00:00
|
|
|
FileStream(ConstCharRange path, StreamMode mode = StreamMode::read): p_f() {
|
2015-06-30 18:25:40 +00:00
|
|
|
open(path, mode);
|
|
|
|
}
|
|
|
|
|
|
|
|
FileStream(FILE *f): p_f(f), p_owned(false) {}
|
|
|
|
|
|
|
|
~FileStream() { close(); }
|
|
|
|
|
2016-06-23 18:18:35 +00:00
|
|
|
FileStream &operator=(FileStream const &) = delete;
|
2015-06-30 18:25:40 +00:00
|
|
|
FileStream &operator=(FileStream &&s) {
|
|
|
|
close();
|
|
|
|
swap(s);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2016-03-26 15:19:00 +00:00
|
|
|
bool open(ConstCharRange path, StreamMode mode = StreamMode::read) {
|
2015-09-04 17:25:17 +00:00
|
|
|
if (p_f || (path.size() > FILENAME_MAX)) return false;
|
2015-07-21 21:30:53 +00:00
|
|
|
char buf[FILENAME_MAX + 1];
|
|
|
|
memcpy(buf, &path[0], path.size());
|
|
|
|
buf[path.size()] = '\0';
|
|
|
|
p_f = fopen(buf, detail::filemodes[Size(mode)]);
|
2015-06-30 18:25:40 +00:00
|
|
|
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) {
|
2015-07-13 19:08:55 +00:00
|
|
|
#ifndef OSTD_PLATFORM_WIN32
|
2015-06-30 18:25:40 +00:00
|
|
|
return fseeko(p_f, pos, int(whence)) >= 0;
|
2015-07-01 19:59:05 +00:00
|
|
|
#else
|
|
|
|
return _fseeki64(p_f, pos, int(whence)) >= 0;
|
|
|
|
#endif
|
2015-06-30 18:25:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
StreamOffset tell() const {
|
2015-07-13 19:08:55 +00:00
|
|
|
#ifndef OSTD_PLATFORM_WIN32
|
2015-06-30 18:25:40 +00:00
|
|
|
return ftello(p_f);
|
2015-07-01 19:59:05 +00:00
|
|
|
#else
|
|
|
|
return _ftelli64(p_f);
|
|
|
|
#endif
|
2015-06-30 18:25:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool flush() { return !fflush(p_f); }
|
|
|
|
|
2015-07-05 22:59:36 +00:00
|
|
|
Size read_bytes(void *buf, Size count) {
|
2015-06-30 18:25:40 +00:00
|
|
|
return fread(buf, 1, count, p_f);
|
|
|
|
}
|
|
|
|
|
2016-06-23 18:18:35 +00:00
|
|
|
Size write_bytes(void const *buf, Size count) {
|
2015-06-30 18:25:40 +00:00
|
|
|
return fwrite(buf, 1, count, p_f);
|
|
|
|
}
|
|
|
|
|
2015-07-01 19:59:05 +00:00
|
|
|
int getchar() {
|
|
|
|
return fgetc(p_f);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool putchar(int c) {
|
|
|
|
return fputc(c, p_f) != EOF;
|
|
|
|
}
|
|
|
|
|
2015-06-30 18:25:40 +00:00
|
|
|
void swap(FileStream &s) {
|
2015-07-13 19:07:14 +00:00
|
|
|
ostd::swap(p_f, s.p_f);
|
|
|
|
ostd::swap(p_owned, s.p_owned);
|
2015-06-30 18:25:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FILE *get_file() { return p_f; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
FILE *p_f;
|
|
|
|
bool p_owned;
|
|
|
|
};
|
|
|
|
|
2016-07-06 16:05:32 +00:00
|
|
|
static FileStream in(stdin);
|
|
|
|
static FileStream out(stdout);
|
|
|
|
static FileStream err(stderr);
|
2015-06-30 18:25:40 +00:00
|
|
|
|
|
|
|
/* no need to call anything from FileStream, prefer simple calls... */
|
|
|
|
|
2015-07-21 21:21:54 +00:00
|
|
|
namespace detail {
|
|
|
|
struct IoNat {};
|
2015-06-30 18:25:40 +00:00
|
|
|
|
2015-07-21 21:21:54 +00:00
|
|
|
inline void write_impl(ConstCharRange s) {
|
2016-07-06 16:05:32 +00:00
|
|
|
fwrite(&s[0], 1, s.size(), stdout);
|
2015-07-21 21:21:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
2016-06-23 18:18:35 +00:00
|
|
|
inline void write_impl(T const &v, EnableIf<
|
|
|
|
!IsConstructible<ConstCharRange, T const &>, IoNat
|
2015-07-22 01:06:36 +00:00
|
|
|
> = IoNat()) {
|
2015-07-21 21:21:54 +00:00
|
|
|
write(ostd::to_string(v));
|
|
|
|
}
|
2015-06-30 18:25:40 +00:00
|
|
|
}
|
|
|
|
|
2015-06-30 21:41:01 +00:00
|
|
|
template<typename T>
|
2016-06-23 18:18:35 +00:00
|
|
|
inline void write(T const &v) {
|
2015-07-21 21:21:54 +00:00
|
|
|
detail::write_impl(v);
|
2015-06-30 21:41:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T, typename ...A>
|
2016-06-23 18:18:35 +00:00
|
|
|
inline void write(T const &v, A const &...args) {
|
2015-07-05 22:59:36 +00:00
|
|
|
write(v);
|
2015-06-30 21:41:01 +00:00
|
|
|
write(args...);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
2016-06-23 18:18:35 +00:00
|
|
|
inline void writeln(T const &v) {
|
2015-07-21 21:21:54 +00:00
|
|
|
write(v);
|
2016-07-06 16:05:32 +00:00
|
|
|
putc('\n', stdout);
|
2015-06-30 21:41:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T, typename ...A>
|
2016-06-23 18:18:35 +00:00
|
|
|
inline void writeln(T const &v, A const &...args) {
|
2015-07-05 22:59:36 +00:00
|
|
|
write(v);
|
2015-06-30 21:41:01 +00:00
|
|
|
write(args...);
|
2016-07-06 16:05:32 +00:00
|
|
|
putc('\n', stdout);
|
2015-06-30 21:41:01 +00:00
|
|
|
}
|
|
|
|
|
2015-07-01 01:22:42 +00:00
|
|
|
template<typename ...A>
|
2016-06-23 18:18:35 +00:00
|
|
|
inline void writef(ConstCharRange fmt, A const &...args) {
|
2015-07-01 17:51:39 +00:00
|
|
|
char buf[512];
|
2015-07-05 22:59:36 +00:00
|
|
|
Ptrdiff need = format(detail::FormatOutRange<sizeof(buf)>(buf),
|
|
|
|
fmt, args...);
|
2015-07-03 20:13:54 +00:00
|
|
|
if (need < 0) return;
|
2015-07-05 22:59:36 +00:00
|
|
|
else if (Size(need) < sizeof(buf)) {
|
2016-07-06 16:05:32 +00:00
|
|
|
fwrite(buf, 1, need, stdout);
|
2015-07-01 01:22:42 +00:00
|
|
|
return;
|
|
|
|
}
|
2015-07-05 22:59:36 +00:00
|
|
|
Vector<char> s;
|
2015-07-01 17:51:39 +00:00
|
|
|
s.reserve(need);
|
2015-07-05 22:59:36 +00:00
|
|
|
format(detail::UnsafeWritefRange(s.data()), fmt, args...);
|
2016-07-06 16:05:32 +00:00
|
|
|
fwrite(s.data(), 1, need, stdout);
|
2015-07-01 01:22:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template<typename ...A>
|
2016-06-23 18:18:35 +00:00
|
|
|
inline void writefln(ConstCharRange fmt, A const &...args) {
|
2015-07-01 17:51:39 +00:00
|
|
|
writef(fmt, args...);
|
2016-07-06 16:05:32 +00:00
|
|
|
putc('\n', stdout);
|
2015-07-01 01:22:42 +00:00
|
|
|
}
|
|
|
|
|
2015-07-13 19:07:14 +00:00
|
|
|
} /* namespace ostd */
|
2015-06-30 18:25:40 +00:00
|
|
|
|
2016-02-07 21:17:15 +00:00
|
|
|
#endif
|