diff --git a/.gitignore b/.gitignore index 94a8695..007b88d 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ !*.m !*.cc !*.h +!*.hxx !*.rst !*.po !*.in diff --git a/CMakeLists.txt b/CMakeLists.txt index fdf73aa..6ea2b7a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -213,6 +213,11 @@ set(INTERFACE_FILES include/criterion/internal/preprocess.h include/criterion/internal/theories.h include/criterion/internal/parameterized.h + include/criterion/internal/stdio_filebuf.hxx + include/criterion/internal/stream.hxx + include/criterion/internal/hooks.h + include/criterion/internal/redirect.h + include/criterion/internal/stdio_filebuf.hxx ) # Generate the configure file diff --git a/include/criterion/hooks.h b/include/criterion/hooks.h index 5f622b2..a7559c6 100644 --- a/include/criterion/hooks.h +++ b/include/criterion/hooks.h @@ -24,8 +24,7 @@ #ifndef CRITERION_HOOKS_H_ # define CRITERION_HOOKS_H_ -# include "internal/common.h" -# include "types.h" +# include "internal/hooks.h" typedef enum { PRE_ALL, @@ -43,57 +42,6 @@ typedef enum { typedef void (*f_report_hook)(); -# define CR_HOOK_IDENTIFIER_(Suffix) CR_HOOK_IDENTIFIER__(__LINE__, Suffix) -# define CR_HOOK_IDENTIFIER__(Line, Suffix) CR_HOOK_IDENTIFIER___(Line, Suffix) -# define CR_HOOK_IDENTIFIER___(Line, Suffix) hook_l ## Line ## _ ## Suffix - -# ifdef __cplusplus -# define CR_HOOK_PROTOTYPE_ \ - extern "C" void CR_HOOK_IDENTIFIER_(impl) -# else -# define CR_HOOK_PROTOTYPE_ \ - void CR_HOOK_IDENTIFIER_(impl) -# endif - -// Section abbreviations -# define CR_HOOK_SECTION_PRE_ALL cr_pra -# define CR_HOOK_SECTION_PRE_SUITE cr_prs -# define CR_HOOK_SECTION_PRE_INIT cr_pri -# define CR_HOOK_SECTION_PRE_TEST cr_prt -# define CR_HOOK_SECTION_ASSERT cr_ast -# define CR_HOOK_SECTION_THEORY_FAIL cr_thf -# define CR_HOOK_SECTION_TEST_CRASH cr_tsc -# define CR_HOOK_SECTION_POST_TEST cr_pot -# define CR_HOOK_SECTION_POST_FINI cr_pof -# define CR_HOOK_SECTION_POST_SUITE cr_pos -# define CR_HOOK_SECTION_POST_ALL cr_poa - -# define CR_HOOK_SECTION(Kind) CR_HOOK_SECTION_ ## Kind - -# define CR_HOOK_SECTION_STRINGIFY__(Sec) #Sec -# define CR_HOOK_SECTION_STRINGIFY_(Sec) CR_HOOK_SECTION_STRINGIFY__(Sec) -# define CR_HOOK_SECTION_STRINGIFY(Kind) CR_HOOK_SECTION_STRINGIFY_(CR_HOOK_SECTION(Kind)) - -# define CR_HOOK_PARAM_TYPE_PRE_ALL struct criterion_test_set * -# define CR_HOOK_PARAM_TYPE_PRE_SUITE struct criterion_suite_set * -# define CR_HOOK_PARAM_TYPE_PRE_INIT struct criterion_test * -# define CR_HOOK_PARAM_TYPE_PRE_TEST struct criterion_test * -# define CR_HOOK_PARAM_TYPE_ASSERT struct criterion_assert_stats * -# define CR_HOOK_PARAM_TYPE_THEORY_FAIL struct criterion_theory_stats * -# define CR_HOOK_PARAM_TYPE_TEST_CRASH struct criterion_test_stats * -# define CR_HOOK_PARAM_TYPE_POST_TEST struct criterion_test_stats * -# define CR_HOOK_PARAM_TYPE_POST_FINI struct criterion_test_stats * -# define CR_HOOK_PARAM_TYPE_POST_SUITE struct criterion_suite_stats * -# define CR_HOOK_PARAM_TYPE_POST_ALL struct criterion_global_stats * - -# define CR_HOOK_PARAM_TYPE(Kind) CR_HOOK_PARAM_TYPE_ ## Kind - -# define ReportHook(Kind) \ - CR_HOOK_PROTOTYPE_(CR_HOOK_PARAM_TYPE(Kind)); \ - CR_SECTION_(CR_HOOK_SECTION_STRINGIFY(Kind)) \ - f_report_hook CR_HOOK_IDENTIFIER_(func) = \ - (f_report_hook) CR_HOOK_IDENTIFIER_(impl) \ - CR_SECTION_SUFFIX_; \ - CR_HOOK_PROTOTYPE_ +# define ReportHook(Kind) CR_REPORT_HOOK_IMPL(Kind) #endif /* !CRITERION_HOOKS_H_ */ diff --git a/include/criterion/internal/hooks.h b/include/criterion/internal/hooks.h new file mode 100644 index 0000000..cf33de5 --- /dev/null +++ b/include/criterion/internal/hooks.h @@ -0,0 +1,84 @@ +/* + * The MIT License (MIT) + * + * Copyright © 2015 Franklin "Snaipe" Mathieu + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef CRITERION_INTERNAL_HOOKS_H_ +# define CRITERION_INTERNAL_HOOKS_H_ + +# include "common.h" +# include "../types.h" + +# define CR_HOOK_IDENTIFIER_(Suffix) CR_HOOK_IDENTIFIER__(__LINE__, Suffix) +# define CR_HOOK_IDENTIFIER__(Line, Suffix) CR_HOOK_IDENTIFIER___(Line, Suffix) +# define CR_HOOK_IDENTIFIER___(Line, Suffix) hook_l ## Line ## _ ## Suffix + +# ifdef __cplusplus +# define CR_HOOK_PROTOTYPE_ \ + extern "C" void CR_HOOK_IDENTIFIER_(impl) +# else +# define CR_HOOK_PROTOTYPE_ \ + void CR_HOOK_IDENTIFIER_(impl) +# endif + +// Section abbreviations +# define CR_HOOK_SECTION_PRE_ALL cr_pra +# define CR_HOOK_SECTION_PRE_SUITE cr_prs +# define CR_HOOK_SECTION_PRE_INIT cr_pri +# define CR_HOOK_SECTION_PRE_TEST cr_prt +# define CR_HOOK_SECTION_ASSERT cr_ast +# define CR_HOOK_SECTION_THEORY_FAIL cr_thf +# define CR_HOOK_SECTION_TEST_CRASH cr_tsc +# define CR_HOOK_SECTION_POST_TEST cr_pot +# define CR_HOOK_SECTION_POST_FINI cr_pof +# define CR_HOOK_SECTION_POST_SUITE cr_pos +# define CR_HOOK_SECTION_POST_ALL cr_poa + +# define CR_HOOK_SECTION(Kind) CR_HOOK_SECTION_ ## Kind + +# define CR_HOOK_SECTION_STRINGIFY__(Sec) #Sec +# define CR_HOOK_SECTION_STRINGIFY_(Sec) CR_HOOK_SECTION_STRINGIFY__(Sec) +# define CR_HOOK_SECTION_STRINGIFY(Kind) CR_HOOK_SECTION_STRINGIFY_(CR_HOOK_SECTION(Kind)) + +# define CR_HOOK_PARAM_TYPE_PRE_ALL struct criterion_test_set * +# define CR_HOOK_PARAM_TYPE_PRE_SUITE struct criterion_suite_set * +# define CR_HOOK_PARAM_TYPE_PRE_INIT struct criterion_test * +# define CR_HOOK_PARAM_TYPE_PRE_TEST struct criterion_test * +# define CR_HOOK_PARAM_TYPE_ASSERT struct criterion_assert_stats * +# define CR_HOOK_PARAM_TYPE_THEORY_FAIL struct criterion_theory_stats * +# define CR_HOOK_PARAM_TYPE_TEST_CRASH struct criterion_test_stats * +# define CR_HOOK_PARAM_TYPE_POST_TEST struct criterion_test_stats * +# define CR_HOOK_PARAM_TYPE_POST_FINI struct criterion_test_stats * +# define CR_HOOK_PARAM_TYPE_POST_SUITE struct criterion_suite_stats * +# define CR_HOOK_PARAM_TYPE_POST_ALL struct criterion_global_stats * + +# define CR_HOOK_PARAM_TYPE(Kind) CR_HOOK_PARAM_TYPE_ ## Kind + +# define CR_REPORT_HOOK_IMPL(Kind) \ + CR_HOOK_PROTOTYPE_(CR_HOOK_PARAM_TYPE(Kind)); \ + CR_SECTION_(CR_HOOK_SECTION_STRINGIFY(Kind)) \ + f_report_hook CR_HOOK_IDENTIFIER_(func) = \ + (f_report_hook) CR_HOOK_IDENTIFIER_(impl) \ + CR_SECTION_SUFFIX_; \ + CR_HOOK_PROTOTYPE_ + + +#endif /* !CRITERION_INTERNAL_HOOKS_H_ */ diff --git a/include/criterion/internal/redirect.h b/include/criterion/internal/redirect.h new file mode 100644 index 0000000..64c003b --- /dev/null +++ b/include/criterion/internal/redirect.h @@ -0,0 +1,48 @@ +#ifndef CRITERION_INTERNAL_REDIRECT_H_ +# define CRITERION_INTERNAL_REDIRECT_H_ + +# include "common.h" +# include "assert.h" + +# define cr_assert_redir_op_(Fail, Fun, Op, File, Str, ...) \ + CR_EXPAND(cr_assert_impl( \ + Fail, \ + !(Fun((File), (Str)) Op 0), \ + dummy, \ + CRITERION_ASSERT_MSG_FILE_STR_MATCH, \ + (CR_STR(File), Str), \ + __VA_ARGS__ \ + )) + +# define cr_assert_redir_op_va_(Fail, Fun, Op, ...) \ + CR_EXPAND(cr_assert_redir_op_( \ + Fail, \ + Fun, \ + Op, \ + CR_VA_HEAD(__VA_ARGS__), \ + CR_VA_HEAD(CR_VA_TAIL(__VA_ARGS__)), \ + CR_VA_TAIL(CR_VA_TAIL(__VA_ARGS__)) \ + )) + +# define cr_assert_redir_f_op_(Fail, Fun, Op, File, Ref, ...) \ + CR_EXPAND(cr_assert_impl( \ + Fail, \ + !(Fun((File), (Ref)) Op 0), \ + dummy, \ + CRITERION_ASSERT_MSG_FILE_MATCH, \ + (CR_STR(File), CR_STR(Ref)), \ + __VA_ARGS__ \ + )) + +# define cr_assert_redir_f_op_va_(Fail, Fun, Op, ...) \ + CR_EXPAND(cr_assert_redir_op_( \ + Fail, \ + Fun, \ + Op, \ + CR_VA_HEAD(__VA_ARGS__), \ + CR_VA_HEAD(CR_VA_TAIL(__VA_ARGS__)), \ + CR_VA_TAIL(CR_VA_TAIL(__VA_ARGS__)) \ + )) + + +#endif /* !CRITERION_INTERNAL_REDIRECT_H_ */ diff --git a/include/criterion/internal/stdio_filebuf.hxx b/include/criterion/internal/stdio_filebuf.hxx new file mode 100644 index 0000000..0cb53d7 --- /dev/null +++ b/include/criterion/internal/stdio_filebuf.hxx @@ -0,0 +1,138 @@ +#ifndef CRITERION_INTERNAL_STDIO_FILEBUF_HXX_ +# define CRITERION_INTERNAL_STDIO_FILEBUF_HXX_ + +# include + +namespace criterion { namespace internal { + + template > + class stdio_sync_filebuf : public std::basic_streambuf { + public: + typedef Traits traits; + typedef std::basic_filebuf super; + typedef typename Traits::int_type int_type; + typedef typename Traits::pos_type pos_type; + typedef typename Traits::off_type off_type; + + stdio_sync_filebuf(std::FILE *file) + : file(file) + , lastchar(Traits::eof()) + {} + + stdio_sync_filebuf(stdio_sync_filebuf&& other) = default; + stdio_sync_filebuf& operator=(stdio_sync_filebuf&& other) = default; + + void swap(stdio_sync_filebuf& other) { + super::swap(other); + std::swap(file, other.file); + std::swap(lastchar, other.lastchar); + } + + protected: + int_type syncgetc(); + int_type syncungetc(int_type); + int_type syncputc(int_type); + + virtual std::streampos seekoff(std::streamoff off, + std::ios_base::seekdir dir, + std::ios_base::openmode = std::ios_base::in | std::ios_base::out) { + + int whence; + if (dir == std::ios_base::beg) + whence = SEEK_SET; + else if (dir == std::ios_base::cur) + whence = SEEK_CUR; + else + whence = SEEK_END; + + if (!fseek(file, off, whence)) + return std::streampos(std::ftell(file)); + return std::streamoff(-1); + } + + virtual std::streampos seekpos(std::streampos pos, + std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) { + return seekoff(std::streamoff(pos), std::ios_base::beg, mode); + } + + virtual std::streamsize xsgetn(CharT* s, std::streamsize n); + virtual std::streamsize xsputn(const CharT* s, std::streamsize n); + + virtual int sync() { + return std::fflush(file); + } + + virtual int_type underflow() { + int_type c = syncgetc(); + return syncungetc(c); + } + + virtual int_type uflow() { + return lastchar = syncgetc(); + } + + static inline bool is_eof(int_type c) { + static const int_type eof = Traits::eof(); + return Traits::eq_int_type(c, eof); + } + + virtual int_type overflow(int_type c = Traits::eof()) { + int_type ret; + if (is_eof(c)) { + if (std::fflush(file)) + ret = Traits::eof(); + else + ret = Traits::not_eof(c); + } else { + ret = syncputc(c); + } + return ret; + } + + virtual int_type pbackfail(int_type c = Traits::eof()) { + int_type ret = syncungetc(is_eof(c) && !is_eof(lastchar) ? lastchar : c); + lastchar = Traits::eof(); + return ret; + } + + private: + std::FILE *file; + bool file_open; + int_type lastchar; + }; + + template <> + inline stdio_sync_filebuf::int_type + stdio_sync_filebuf::syncgetc() { + return std::getc(file); + } + + template <> + inline stdio_sync_filebuf::int_type + stdio_sync_filebuf::syncungetc(stdio_sync_filebuf::int_type c) { + return std::ungetc(c, file); + } + + template <> + inline stdio_sync_filebuf::int_type + stdio_sync_filebuf::syncputc(stdio_sync_filebuf::int_type c) { + return std::putc(c, file); + } + + template <> + inline std::streamsize + stdio_sync_filebuf::xsgetn(char *s, std::streamsize n) { + std::streamsize res = std::fread(s, 1, n, file); + lastchar = res > 0 ? traits::to_int_type(s[res - 1]) : traits::eof(); + return res; + } + + template <> + inline std::streamsize + stdio_sync_filebuf::xsputn(const char *s, std::streamsize n) { + return std::fwrite(s, 1, n, file); + } + +}} + +#endif /* !CRITERION_INTERNAL_STDIO_FILEBUF_HXX_ */ diff --git a/include/criterion/internal/stream.hxx b/include/criterion/internal/stream.hxx new file mode 100644 index 0000000..d8c5a08 --- /dev/null +++ b/include/criterion/internal/stream.hxx @@ -0,0 +1,114 @@ +#ifndef CRITERION_INTERNAL_STREAM_HXX_ +# define CRITERION_INTERNAL_STREAM_HXX_ + +# include +# include +# include + +# include "stdio_filebuf.hxx" + +namespace criterion { namespace internal { + + template + class stream_mixin : public Super { +public: + stream_mixin(FILE* f) + : Super() + , fbuf(new stdio_sync_filebuf(f)) + , file(f) + { + std::ios::rdbuf(&*fbuf); + } + + stream_mixin(const stream_mixin& other) = delete; + stream_mixin& operator=(const stream_mixin& other) = delete; + + stream_mixin(stream_mixin&& other) : + fbuf(std::move(other.fbuf)), + file(std::move(other.file)) + {} + + stream_mixin& operator=(stream_mixin&& other) { + fbuf = std::move(other.fbuf); + file = std::move(other.file); + } + + void close(void) { + Super::flush(); + Super::close(); + std::fclose(file); + } + + private: + std::shared_ptr> fbuf; + std::FILE* file; + }; + + template + using ofstream_mixin = stream_mixin>; + + template + using ifstream_mixin = stream_mixin>; + + template + using fstream_mixin = stream_mixin>; + + template + class basic_ofstream : public ofstream_mixin { + public: + basic_ofstream(FILE* f) + : ofstream_mixin(f) + {} + + basic_ofstream(basic_ofstream&& other) + : ofstream_mixin(std::move(other)) + {} + }; + + template + class basic_ifstream : public ifstream_mixin { + public: + basic_ifstream(FILE* f) + : ifstream_mixin(f) + {} + + basic_ifstream(basic_ifstream&& other) + : ifstream_mixin(std::move(other)) + {} + }; + + template + class basic_fstream : public fstream_mixin { + public: + basic_fstream(FILE* f) + : fstream_mixin(f) + {} + + basic_fstream(basic_fstream&& other) + : fstream_mixin(std::move(other)) + {} + }; + + struct get_redirected_out_stream_ { + static inline basic_ofstream& call(std::FILE* f) { + static std::unique_ptr> stream; + + if (!stream) + stream.reset(new basic_ofstream(f)); + return *stream; + } + + }; + + struct get_redirected_in_stream_ { + static inline basic_ifstream& call(std::FILE* f) { + static std::unique_ptr> stream; + if (!stream) + stream.reset(new basic_ifstream(f)); + return *stream; + } + }; + +}} + +#endif /* !CRITERION_INTERNAL_STREAM_HXX_ */ diff --git a/include/criterion/redirect.h b/include/criterion/redirect.h index c00f42f..6fd5f58 100644 --- a/include/criterion/redirect.h +++ b/include/criterion/redirect.h @@ -25,12 +25,10 @@ # define CRITERION_REDIRECT_H_ # include "internal/common.h" -# include "assert.h" +# include "internal/redirect.h" # ifdef __cplusplus # include -# include -# include # else # include # endif @@ -52,46 +50,6 @@ CR_API CR_STDN FILE *cr_mock_file_size(size_t max_size); CR_END_C_API -# define cr_assert_redir_op_(Fail, Fun, Op, File, Str, ...) \ - CR_EXPAND(cr_assert_impl( \ - Fail, \ - !(Fun((File), (Str)) Op 0), \ - dummy, \ - CRITERION_ASSERT_MSG_FILE_STR_MATCH, \ - (CR_STR(File), Str), \ - __VA_ARGS__ \ - )) - -# define cr_assert_redir_op_va_(Fail, Fun, Op, ...) \ - CR_EXPAND(cr_assert_redir_op_( \ - Fail, \ - Fun, \ - Op, \ - CR_VA_HEAD(__VA_ARGS__), \ - CR_VA_HEAD(CR_VA_TAIL(__VA_ARGS__)), \ - CR_VA_TAIL(CR_VA_TAIL(__VA_ARGS__)) \ - )) - -# define cr_assert_redir_f_op_(Fail, Fun, Op, File, Ref, ...) \ - CR_EXPAND(cr_assert_impl( \ - Fail, \ - !(Fun((File), (Ref)) Op 0), \ - dummy, \ - CRITERION_ASSERT_MSG_FILE_MATCH, \ - (CR_STR(File), CR_STR(Ref)), \ - __VA_ARGS__ \ - )) - -# define cr_assert_redir_f_op_va_(Fail, Fun, Op, ...) \ - CR_EXPAND(cr_assert_redir_op_( \ - Fail, \ - Fun, \ - Op, \ - CR_VA_HEAD(__VA_ARGS__), \ - CR_VA_HEAD(CR_VA_TAIL(__VA_ARGS__)), \ - CR_VA_TAIL(CR_VA_TAIL(__VA_ARGS__)) \ - )) - # define cr_assert_file_contents_eq_str(...) CR_EXPAND(cr_assert_redir_op_va_(CR_FAIL_ABORT_, cr_file_match_str, ==, __VA_ARGS__)) # define cr_expect_file_contents_eq_str(...) CR_EXPAND(cr_assert_redir_op_va_(CR_FAIL_CONTINUES_, cr_file_match_str, ==, __VA_ARGS__)) @@ -129,250 +87,24 @@ CR_END_C_API # define cr_expect_stderr_neq(...) CR_EXPAND(cr_assert_redir_f_op_va_(CR_FAIL_CONTINUES_, cr_file_match_file, !=, cr_get_redirected_stderr(), __VA_ARGS__)) # ifdef __cplusplus +# include "internal/stream.hxx" + namespace criterion { - template > - class stdio_sync_filebuf : public std::basic_streambuf { - public: - typedef Traits traits; - typedef std::basic_filebuf super; - typedef typename Traits::int_type int_type; - typedef typename Traits::pos_type pos_type; - typedef typename Traits::off_type off_type; - - stdio_sync_filebuf(std::FILE *file) - : file(file) - , lastchar(Traits::eof()) - {} - - stdio_sync_filebuf(stdio_sync_filebuf&& other) = default; - stdio_sync_filebuf& operator=(stdio_sync_filebuf&& other) = default; - - void swap(stdio_sync_filebuf& other) { - super::swap(other); - std::swap(file, other.file); - std::swap(lastchar, other.lastchar); - } - - protected: - int_type syncgetc(); - int_type syncungetc(int_type); - int_type syncputc(int_type); - - virtual std::streampos seekoff(std::streamoff off, - std::ios_base::seekdir dir, - std::ios_base::openmode = std::ios_base::in | std::ios_base::out) { - - int whence; - if (dir == std::ios_base::beg) - whence = SEEK_SET; - else if (dir == std::ios_base::cur) - whence = SEEK_CUR; - else - whence = SEEK_END; - - if (!fseek(file, off, whence)) - return std::streampos(std::ftell(file)); - return std::streamoff(-1); - } - - virtual std::streampos seekpos(std::streampos pos, - std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) { - return seekoff(std::streamoff(pos), std::ios_base::beg, mode); - } - - virtual std::streamsize xsgetn(CharT* s, std::streamsize n); - virtual std::streamsize xsputn(const CharT* s, std::streamsize n); - - virtual int sync() { - return std::fflush(file); - } - - virtual int_type underflow() { - int_type c = syncgetc(); - return syncungetc(c); - } - - virtual int_type uflow() { - return lastchar = syncgetc(); - } - - static inline bool is_eof(int_type c) { - static const int_type eof = Traits::eof(); - return Traits::eq_int_type(c, eof); - } - - virtual int_type overflow(int_type c = Traits::eof()) { - int_type ret; - if (is_eof(c)) { - if (std::fflush(file)) - ret = Traits::eof(); - else - ret = Traits::not_eof(c); - } else { - ret = syncputc(c); - } - return ret; - } - - virtual int_type pbackfail(int_type c = Traits::eof()) { - int_type ret = syncungetc(is_eof(c) && !is_eof(lastchar) ? lastchar : c); - lastchar = Traits::eof(); - return ret; - } - - private: - std::FILE *file; - bool file_open; - int_type lastchar; - }; - - template <> - inline stdio_sync_filebuf::int_type - stdio_sync_filebuf::syncgetc() { - return std::getc(file); - } - - template <> - inline stdio_sync_filebuf::int_type - stdio_sync_filebuf::syncungetc(stdio_sync_filebuf::int_type c) { - return std::ungetc(c, file); - } - - template <> - inline stdio_sync_filebuf::int_type - stdio_sync_filebuf::syncputc(stdio_sync_filebuf::int_type c) { - return std::putc(c, file); - } - - template <> - inline std::streamsize - stdio_sync_filebuf::xsgetn(char *s, std::streamsize n) { - std::streamsize res = std::fread(s, 1, n, file); - lastchar = res > 0 ? traits::to_int_type(s[res - 1]) : traits::eof(); - return res; - } - - template <> - inline std::streamsize - stdio_sync_filebuf::xsputn(const char *s, std::streamsize n) { - return std::fwrite(s, 1, n, file); - } - - template - class stream_mixin : public Super { -public: - stream_mixin(FILE* f) - : Super() - , fbuf(new stdio_sync_filebuf(f)) - , file(f) - { - std::ios::rdbuf(&*fbuf); - } - - stream_mixin(const stream_mixin& other) = delete; - stream_mixin& operator=(const stream_mixin& other) = delete; - - stream_mixin(stream_mixin&& other) : - fbuf(std::move(other.fbuf)), - file(std::move(other.file)) - {} - - stream_mixin& operator=(stream_mixin&& other) { - fbuf = std::move(other.fbuf); - file = std::move(other.file); - } - - void close(void) { - Super::flush(); - Super::close(); - std::fclose(file); - } - - private: - std::shared_ptr> fbuf; - std::FILE* file; - }; - - template - using ofstream_mixin = stream_mixin>; - - template - using ifstream_mixin = stream_mixin>; - - template - using fstream_mixin = stream_mixin>; - - template - class basic_ofstream : public ofstream_mixin { - public: - basic_ofstream(FILE* f) - : ofstream_mixin(f) - {} - - basic_ofstream(basic_ofstream&& other) - : ofstream_mixin(std::move(other)) - {} - }; - - template - class basic_ifstream : public ifstream_mixin { - public: - basic_ifstream(FILE* f) - : ifstream_mixin(f) - {} - - basic_ifstream(basic_ifstream&& other) - : ifstream_mixin(std::move(other)) - {} - }; - - template - class basic_fstream : public fstream_mixin { - public: - basic_fstream(FILE* f) - : fstream_mixin(f) - {} - - basic_fstream(basic_fstream&& other) - : fstream_mixin(std::move(other)) - {} - }; - - using ofstream = basic_ofstream; - using ifstream = basic_ifstream; - using fstream = basic_fstream; - - struct get_redirected_out_stream_ { - static inline ofstream& call(std::FILE* f) { - static std::unique_ptr stream; - - if (!stream) - stream.reset(new ofstream(f)); - return *stream; - } - - }; - - struct get_redirected_in_stream_ { - static inline ifstream& call(std::FILE* f) { - static std::unique_ptr stream; - if (!stream) - stream.reset(new ifstream(f)); - return *stream; - } - }; + using ofstream = internal::basic_ofstream; + using ifstream = internal::basic_ifstream; + using fstream = internal::basic_fstream; static inline ofstream& get_redirected_cin(void) { - return get_redirected_out_stream_::call(cr_get_redirected_stdin()); + return internal::get_redirected_out_stream_::call(cr_get_redirected_stdin()); } static inline ifstream& get_redirected_cout(void) { - return get_redirected_in_stream_::call(cr_get_redirected_stdout()); + return internal::get_redirected_in_stream_::call(cr_get_redirected_stdout()); } static inline ifstream& get_redirected_cerr(void) { - return get_redirected_in_stream_::call(cr_get_redirected_stderr()); + return internal::get_redirected_in_stream_::call(cr_get_redirected_stderr()); } # if __GNUC__ >= 5