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