#include "error.hpp" #include "formatter.hpp" #include "stream.hpp" // Disable annoying warning 4996: "'function' was declared deprecated" #if CHECK_MSC_VERSION(14, 0) # pragma warning(push) # pragma warning(disable: 4996) #endif namespace Check { const Decision Stream::FormatErrorResult[3] = { // 0 = InputStream, 1 = OutputStream, 2 = AnswerStream UnhandledError, PresentationError, UnhandledError }; void Stream::initialize() { file = NULL; type = InputStream; closed = endFound = true; boolFmt = IntegerBoolean; trueStr.reserve(DefaultTrueFalseLength); falseStr.reserve(DefaultTrueFalseLength); endFileMode = FailAtEnd; spaceMode = SkipWhite; charsBeforeWord = &SpaceChars; commonBuffer.reserve(DefaultTrueFalseLength); } Stream &Stream::read(char &symbol) { const int value = CHECK_GETC(file); symbol = static_cast(value); endFound = (value == EOF); if (endFound && endFileMode == FailAtEnd) incite(FormatErrorResult[type]); return *this; } Stream &Stream::read( char *word, const size_t maxLength, const CharSet &before, const CharSet &after, const bool putbackLast) { // If it's impossible to read anything, do not touch the stream if (maxLength == 0) return *this; skip(before); if (CHECK_FEOF(file)) { endFound = true; if (endFileMode == FailAtEnd) incite(FormatErrorResult[type]); else return *this; } for (size_t count = 0; count + 1 != maxLength; ++count) { const int symbol = CHECK_GETC(file); if (symbol == EOF || after.contains(symbol)) { if (putbackLast) CHECK_UNGETC(symbol, file); break; } *word = static_cast(symbol); ++word; } *word = '\0'; return *this; } Stream &Stream::read( std::string &word, const CharSet &before, const CharSet &after, const bool putbackLast) { skip(before); if (CHECK_FEOF(file)) { endFound = true; if (endFileMode == FailAtEnd) incite(FormatErrorResult[type]); else return *this; } word.clear(); size_t count = 0; static char buffer[StringReadBufferSize]; int symbol = CHECK_GETC(file); while (symbol != EOF && !after.contains(symbol)) { if (count == StringReadBufferSize) { word.append(buffer, count); count = 0; } buffer[count] = static_cast(symbol); ++count; symbol = CHECK_GETC(file); } word.append(buffer, count); if (putbackLast) CHECK_UNGETC(symbol, file); return *this; } void Stream::open(const char *fileName, const StreamMode openMode) { close(); name = fileName; type = openMode; endFound = false; // File should be opened as text to handle new lines correctly (on Windows) file = fopen(name.c_str(), "rt"); if (file == NULL) raise( FormatErrorResult[type], "File \'%s\' cannot be opened", name.c_str()); closed = false; } void Stream::close() { if (!closed) { // Mark the file as closed not to try to close it again after fail closed = endFound = true; if (fclose(file) != 0) raise( UnhandledError, "File \'%s\' cannot be closed", name.c_str()); file = NULL; } } Stream &Stream::skip(const CharSet &charSet) { if (charSet.isEmpty()) return *this; int symbol; do symbol = CHECK_GETC(file); while (symbol != EOF && charSet.contains(symbol)); CHECK_UNGETC(symbol, file); return *this; } Stream &Stream::skip(const CharSet &charSet, const size_t maxLength) { if (maxLength == 0 || charSet.isEmpty()) return *this; size_t count = 0; int symbol = CHECK_GETC(file); while (symbol != EOF && charSet.contains(symbol)) { ++count; if (count == maxLength) return *this; symbol = CHECK_GETC(file); } CHECK_UNGETC(symbol, file); return *this; } int Stream::peek() { const int symbol = CHECK_GETC(file); endFound = (symbol == EOF); CHECK_UNGETC(symbol, file); return symbol; } Stream &Stream::putback(const char symbol) { if (CHECK_UNGETC(symbol, file) == EOF) incite(UnhandledError, "Symbol cannot be put back"); return *this; } Stream &Stream::get(char &symbol, const CharSet &charSet) { read(symbol); if (!(endFound || charSet.contains(symbol))) raise( FormatErrorResult[type], "Unexpected symbol \'%c\'", symbol); return *this; } Stream &Stream::operator >> (bool &value) { switch (boolFmt) { case IntegerBoolean: { int number; (*this) >> number; value = (number != 0); } break; case StringBoolean: { get(commonBuffer); if (commonBuffer == trueStr) value = true; else if (commonBuffer == falseStr) value = false; else raise( FormatErrorResult[type], "Unexpected boolean value %s", quote(commonBuffer).c_str()); } break; default: { incite(UnhandledError, "Undefined boolean format"); } break; } return *this; } void Stream::setWhiteMode(const WhitespaceMode value) { spaceMode = value; charsBeforeWord = (value == SkipWhite ? &SpaceChars : &NoneChars); } } #if CHECK_MSC_VERSION(14, 0) # pragma warning(pop) #endif