libostd/ostd/io.hh

157 lines
3.7 KiB
C++
Raw Normal View History

2017-04-06 20:14:52 +02:00
/* Standard I/O implementation for libostd.
*
2017-04-06 20:14:52 +02:00
* This file is part of libostd. See COPYING.md for futher information.
*/
2015-07-13 21:08:55 +02:00
#ifndef OSTD_IO_HH
#define OSTD_IO_HH
2017-03-09 19:21:01 +01:00
#include <cstdio>
#include <cerrno>
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 {
2017-02-16 20:39:05 +01:00
enum class stream_mode {
READ = 0, WRITE, APPEND, READ_U, WRITE_U, APPEND_U
};
2017-03-09 19:21:01 +01:00
struct OSTD_EXPORT file_stream: stream {
2017-02-16 20:39:05 +01:00
file_stream(): p_f(), p_owned(false) {}
file_stream(file_stream const &) = delete;
file_stream(file_stream &&s): p_f(s.p_f), p_owned(s.p_owned) {
s.p_f = nullptr;
s.p_owned = false;
}
2017-03-09 19:21:01 +01:00
file_stream(string_range path, stream_mode mode = stream_mode::READ):
p_f()
{
open(path, mode);
}
2017-02-16 20:39:05 +01:00
file_stream(FILE *f): p_f(f), p_owned(false) {}
2017-02-16 20:39:05 +01:00
~file_stream() { close(); }
2017-02-16 20:39:05 +01:00
file_stream &operator=(file_stream const &) = delete;
file_stream &operator=(file_stream &&s) {
close();
swap(s);
return *this;
}
2017-03-09 19:21:01 +01:00
bool open(string_range path, stream_mode mode = stream_mode::READ);
2017-03-09 19:21:01 +01:00
bool open(FILE *f);
bool is_open() const { return p_f != nullptr; }
bool is_owned() const { return p_owned; }
2017-03-09 19:21:01 +01:00
void close();
bool end() const;
2017-03-09 19:21:01 +01:00
void seek(stream_off_t pos, stream_seek whence = stream_seek::SET);
2017-03-09 19:21:01 +01:00
stream_off_t tell() const;
2017-03-09 19:21:01 +01:00
void flush();
2017-04-04 01:06:55 +02:00
size_t read_bytes(void *buf, size_t count);
2017-03-09 19:21:01 +01:00
void write_bytes(void const *buf, size_t count);
2017-03-09 19:21:01 +01:00
int get_char();
void put_char(int c);
2017-02-16 20:39:05 +01:00
void swap(file_stream &s) {
2017-01-29 15:56:02 +01:00
using std::swap;
swap(p_f, s.p_f);
swap(p_owned, s.p_owned);
}
2017-03-09 19:21:01 +01:00
FILE *get_file() const { return p_f; }
private:
FILE *p_f;
bool p_owned;
};
2017-02-16 20:39:05 +01:00
inline void swap(file_stream &a, file_stream &b) {
2017-01-29 15:56:02 +01:00
a.swap(b);
}
2017-03-09 19:21:01 +01:00
OSTD_EXPORT extern file_stream cin;
OSTD_EXPORT extern file_stream cout;
OSTD_EXPORT extern file_stream cerr;
2017-02-16 20:39:05 +01:00
/* no need to call anything from file_stream, prefer simple calls... */
2015-07-21 23:21:54 +02:00
namespace detail {
/* lightweight output range for direct stdout */
2017-02-16 20:39:05 +01:00
struct stdout_range: output_range<stdout_range> {
using value_type = char;
using reference = char &;
using size_type = size_t;
using difference_type = ptrdiff_t;
2017-02-16 20:39:05 +01:00
stdout_range() {}
void put(char c) {
2017-03-09 19:21:01 +01:00
if (std::putchar(c) == EOF) {
throw stream_error{EIO, std::generic_category()};
}
}
};
2017-02-19 18:46:43 +01:00
template<typename R>
inline void range_put_all(stdout_range &r, R range) {
if constexpr(
is_contiguous_range<R> &&
std::is_same_v<std::remove_const_t<range_value_t<R>>, char>
) {
2017-03-09 19:21:01 +01:00
if (std::fwrite(range.data(), 1, range.size(), stdout) != range.size()) {
throw stream_error{EIO, std::generic_category()};
2017-02-19 18:46:43 +01:00
}
} else {
for (; !range.empty(); range.pop_front()) {
r.put(range.front());
}
}
}
}
2017-03-02 20:01:01 +01:00
template<typename ...A>
inline void write(A const &...args) {
format_spec sp{'s', cout.getloc()};
2017-03-02 20:01:01 +01:00
(sp.format_value(detail::stdout_range{}, args), ...);
}
2017-03-02 20:01:01 +01:00
template<typename ...A>
inline void writeln(A const &...args) {
write(args...);
2017-03-09 19:21:01 +01:00
if (std::putchar('\n') == EOF) {
throw stream_error{EIO, std::generic_category()};
2017-02-11 01:28:14 +01:00
}
}
2015-07-01 03:22:42 +02:00
template<typename ...A>
2017-02-16 18:48:14 +01:00
inline void writef(string_range fmt, A const &...args) {
format_spec sp{fmt, cout.getloc()};
sp.format(detail::stdout_range{}, args...);
2015-07-01 03:22:42 +02:00
}
template<typename ...A>
2017-02-16 18:48:14 +01:00
inline void writefln(string_range fmt, A const &...args) {
writef(fmt, args...);
2017-03-09 19:21:01 +01:00
if (std::putchar('\n') == EOF) {
throw stream_error{EIO, std::generic_category()};
2017-02-11 01:28:14 +01:00
}
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