Первые шаги 2024 / std.check.src.stream.cpp

ru en cn

с начала прошло: 42 д. 17:30
страница обновлена: 10.11.2024 02:29

std.check.src.stream.cpp: src/stream.cpp

#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
Дальневосточный федеральный университет