diff --git a/posix.cc b/posix.cc index d8f9bb62..be5f8eba 100644 --- a/posix.cc +++ b/posix.cc @@ -30,7 +30,7 @@ #include "posix.h" -#include +#include #include #include @@ -96,12 +96,35 @@ void fmt::BufferedFile::close() { } int fmt::BufferedFile::fileno() const { + assert(file_ && "File has been closed"); int fd = FMT_POSIX_CALL(fileno(file_)); if (fd == -1) throw SystemError(errno, "cannot get file descriptor"); return fd; } +void fmt::BufferedFile::flush() const { + assert(file_ && "File has been closed"); + if (FMT_SYSTEM(fflush(file_)) != 0) { + throw SystemError(errno, "cannot flush file"); + } +} + +void fmt::BufferedFile::write(fmt::StringRef str) { + assert(file_ && "File has been closed"); + size_t result = FMT_SYSTEM(fwrite(str.c_str(), str.size(), 1, file_)); + if (result < str.size()) { + // FIXME: Will fwrite set errno? + throw SystemError(errno, "failed to write raw string, only {} character(s) written", result); + } +} + +void fmt::BufferedFile::write(char c) { + assert(file_ && "File has been closed"); + if (FMT_SYSTEM(fputc(c, file_)) == EOF) + throw SystemError(errno, "failed to write '{}'", c); +} + fmt::File::File(fmt::StringRef path, int oflag) { int mode = S_IRUSR | S_IWUSR; #ifdef _WIN32 diff --git a/posix.h b/posix.h index a2cf2b13..995784fa 100644 --- a/posix.h +++ b/posix.h @@ -33,6 +33,7 @@ #include #include +#include #include "format.h" @@ -45,7 +46,7 @@ // Fix warnings about deprecated symbols. # define FMT_POSIX(call) _##call # else -# define FMT_POSIX(call) call +# define FMT_POSIX(call) ::call # endif #endif @@ -53,7 +54,7 @@ #ifdef FMT_SYSTEM # define FMT_POSIX_CALL(call) FMT_SYSTEM(call) #else -# define FMT_SYSTEM(call) call +# define FMT_SYSTEM(call) ::call # ifdef _WIN32 // Fix warnings about deprecated symbols. # define FMT_POSIX_CALL(call) ::_##call @@ -188,12 +189,34 @@ public: // Returns the pointer to a FILE object representing this file. FILE *get() const FMT_NOEXCEPT { return file_; } + // Returns the system file number of this file int fileno() const; + // Flushes the buffer of this file + void flush() const; + + // Writes raw string without formatting + void write(fmt::StringRef str); + + // Writes a single charactor without formatting + void write(char c); + + // Writes a new line + void writeln() { + write('\n'); + } + void print(fmt::StringRef format_str, const ArgList &args) { + assert(file_ && "File has been closed"); fmt::print(file_, format_str, args); } + void printf(fmt::StringRef format_str, const ArgList &args) { + assert(file_ && "File has been closed"); + fmt::fprintf(file_, format_str, args); + } + FMT_VARIADIC(void, print, fmt::StringRef) + FMT_VARIADIC(void, printf, fmt::StringRef) }; // A file. Closed file is represented by a File object with descriptor -1. diff --git a/test/posix-test.cc b/test/posix-test.cc index c9529688..fe18cd62 100644 --- a/test/posix-test.cc +++ b/test/posix-test.cc @@ -178,6 +178,18 @@ int test::fileno(FILE *stream) { return ::FMT_POSIX(fileno(stream)); } +int test::fflush(FILE *stream) { + return ::fflush(stream); +} + +int test::fwrite(const void *str, size_t size, size_t count, FILE *stream) { + return ::fwrite(str, size, count, stream); +} + +int test::fputc(int ch, FILE *stream) { + return ::fputc(ch, stream); +} + #ifndef _WIN32 # define EXPECT_RETRY(statement, func, message) \ func##_count = 1; \ diff --git a/test/posix-test.h b/test/posix-test.h index 4768cb94..7ab69bcb 100644 --- a/test/posix-test.h +++ b/test/posix-test.h @@ -73,7 +73,10 @@ int pipe(int *pfds, unsigned psize, int textmode); FILE *fopen(const char *filename, const char *mode); int fclose(FILE *stream); int fileno(FILE *stream); +int fflush(FILE *stream); +int fwrite(const void *str, size_t size, size_t count, FILE *stream); +int fputc(int ch, FILE *stream); } // namespace test #define FMT_SYSTEM(call) test::call