Compare commits

...

2 Commits

Author SHA1 Message Date
Johannes Kapfhammer c0d288e9e8 enable freopen to make some guides on the internet work 2019-10-28 21:28:31 +01:00
Johannes Kapfhammer 080e3f1261 add functions to redirect input/output
those two multiply the output into a file:

void redirect_output(const char *filename);
void redirect_output(std::string const &filename)

those two read everything from a file:

redirect_input(const char *filename);
redirect_input(std::string const& filename);

both can be resetted using:

void reset_input();
reset_output();
2019-10-28 21:26:54 +01:00
4 changed files with 105 additions and 4 deletions

View File

@ -27,6 +27,9 @@ signed main() {
a.foo(); a.foo();
a.bar(3,4,"hi"); a.bar(3,4,"hi");
print("this should not be in the output file");
redirect_output("example.out");
auto [i, j] = read<int, int>(); auto [i, j] = read<int, int>();
print(i, j); print(i, j);
@ -68,4 +71,12 @@ signed main() {
print(map<int, string>{{3,"three"},{1,"one"}}); print(map<int, string>{{3,"three"},{1,"one"}});
print(tuple{unordered_map<int, string>{{3,"three"},{1,"one"}}}); print(tuple{unordered_map<int, string>{{3,"three"},{1,"one"}}});
print(unordered_set<int>{3,1,4}); print(unordered_set<int>{3,1,4});
redirect_input("example.in");
print("reading from example.in:", read_string());
redirect_input("example.in");
print("reading from example.in:", read_string());
print("this is the last line on example.out");
reset_output();
print("this is stdout only");
} }

View File

@ -31,7 +31,6 @@ snprintf(char *buffer, std::size_t buf_size, const char *format, ...);
#define puts puts_is_evil #define puts puts_is_evil
#define fputs fputs_is_evil #define fputs fputs_is_evil
#define fgets fgets_is_evil #define fgets fgets_is_evil
#define freopen freopen_is_evil
#define fopen fopen_is_evil #define fopen fopen_is_evil
#define fclose fclose_is_evil #define fclose fclose_is_evil
#define fflush fflush_is_evil #define fflush fflush_is_evil
@ -48,8 +47,6 @@ snprintf(char *buffer, std::size_t buf_size, const char *format, ...);
[[deprecated("<cstdio> is evil. Use cin/cout.")]] char * [[deprecated("<cstdio> is evil. Use cin/cout.")]] char *
fgets(char *str, int count, FILE *stream); fgets(char *str, int count, FILE *stream);
[[deprecated("<cstdio> is evil. Use cin/cout.")]] std::FILE * [[deprecated("<cstdio> is evil. Use cin/cout.")]] std::FILE *
freopen(const char *filename, const char *mode, std::FILE *stream);
[[deprecated("<cstdio> is evil. Use cin/cout.")]] std::FILE *
fopen(const char *filename, const char *mode); fopen(const char *filename, const char *mode);
[[deprecated("<cstdio> is evil. Use cin/cout.")]] int [[deprecated("<cstdio> is evil. Use cin/cout.")]] int
fclose(std::FILE *stream); fclose(std::FILE *stream);

View File

@ -0,0 +1,93 @@
#include <ostream>
#include <streambuf>
namespace soi {
namespace redirect {
class teebuf : public std::streambuf {
std::streambuf *sb1_;
std::streambuf *sb2_;
int overflow(int c) {
using traits = std::streambuf::traits_type;
bool rc = true;
if (!traits::eq_int_type(traits::eof(), c)) {
traits::eq_int_type(this->sb1_->sputc(c), traits::eof()) && (rc = false);
traits::eq_int_type(this->sb2_->sputc(c), traits::eof()) && (rc = false);
}
return rc ? traits::not_eof(c) : traits::eof();
}
int sync() {
bool rc = false;
this->sb1_->pubsync() != -1 || (rc = false);
this->sb2_->pubsync() != -1 || (rc = false);
return rc ? -1 : 0;
}
public:
teebuf(std::streambuf *sb1, std::streambuf *sb2) : sb1_(sb1), sb2_(sb2) {}
};
static std::streambuf *checked_rdbuf(std::ios &stream, const char *filename,
const char *action) {
if (!stream) {
std::cerr << "ERROR: can't open to file " << filename << " for " << action
<< '\n';
std::exit(-1);
}
return stream.rdbuf();
}
struct output_redirector {
std::ofstream fout;
teebuf tee;
std::streambuf *old_cout;
output_redirector(const char *filename)
: fout(filename),
tee(checked_rdbuf(fout, filename, "writing"), std::cout.rdbuf()),
old_cout(std::cout.rdbuf(&tee)) {}
~output_redirector() { std::cout.rdbuf(old_cout); }
};
struct input_redirector {
std::ifstream fin;
std::streambuf *old_cin;
input_redirector(const char *filename)
: fin(filename),
old_cin(std::cin.rdbuf(checked_rdbuf(fin, filename, "reading"))) {}
~input_redirector() { std::cin.rdbuf(old_cin); }
};
std::forward_list<output_redirector> output_redirectors;
std::unique_ptr<input_redirector> the_input_redirector;
} // namespace redirect
} // namespace soi
void redirect_output(const char *filename) {
soi::redirect::output_redirectors.emplace_front(filename);
}
void redirect_output(std::string const &filename) {
redirect_output(filename.c_str());
}
void reset_output() {
soi::redirect::output_redirectors.clear();
}
void reset_input() {
soi::redirect::the_input_redirector.reset();
}
void redirect_input(const char *filename) {
reset_input();
auto next = new soi::redirect::input_redirector(filename);
soi::redirect::the_input_redirector.reset(next);
}
void redirect_input(std::string const &filename) {
redirect_input(filename.c_str());
}

View File

@ -77,7 +77,7 @@ soi_initializer soi_initializer_{false};
} // end namespace soi } // end namespace soi
#include "bits/soi-io.hpp" #include "bits/soi-io.hpp"
#include "bits/soi-redirect.hpp"
#include "bits/soi-deprecate.hpp" #include "bits/soi-deprecate.hpp"
#define int int64_t #define int int64_t