<commit_before>#include "file.h"
#include "file_p.h"

#include "abstractfileengine.h"
#include "abstractfileengine_p.h"
#include "abstractfileengineplugin.h"
#include "pluginmanager_p.h"

#include <QtCore/QFutureWatcher>

void FilePrivate::init()
{
    state = File::Closed;
    openMode = QIODevice::NotOpen;
    bufferSize = 10*1024*1024; // 10 Mb
    chunkSize = 4*1024; // 4 Kb
    engine = AbstractFileEngine::emptyEngine();
}

void FilePrivate::openFinished(bool ok)
{
    Q_Q(File);
    if (ok) {
        state = File::Opened;
//        size = size;
        q->QIODevice::open(openMode);
        if (openMode & QIODevice::Unbuffered)
            buffer.reserve(chunkSize);
        else
            buffer.reserve(bufferSize);
        if (openMode & QIODevice::ReadOnly)
            engine->read(chunkSize);
    } else {
        state = File::Closed;
    }
    openMode = QIODevice::NotOpen;
}

void FilePrivate::readFinished(const char *data, qint64 length)
{
    Q_Q(File);
    if (length <= 0)
        return;

    int oldSize = buffer.size();
    buffer.resize(oldSize + length);
    memmove(buffer.data() + oldSize, data, length);
    qint64 maxlen = bufferSize - buffer.size();
    maxlen = qMin<qint64>(maxlen, chunkSize);
    maxlen = qMin(q->size() - (q->pos() + buffer.size()), maxlen);
    if (maxlen > 0)
        engine->read(maxlen);
    emit q->readyRead();
}

File::File(QObject *parent) :
    QIODevice(parent),
    d_ptr(new FilePrivate(this))
{
    Q_D(File);
    d->init();
}

File::File(const QUrl &url, QObject *parent) :
    QIODevice(parent),
    d_ptr(new FilePrivate(this))
{
    Q_D(File);
    d->init();

    setUrl(url);
}

File::~File()
{
    Q_D(File);
    close();
    if (d->engine != AbstractFileEngine::emptyEngine())
        delete d->engine;
    delete d_ptr;
}

bool File::open(QIODevice::OpenMode mode)
{
    Q_D(File);
    asyncOpen(mode);
    waitForOpened();
    return d->state == State::Opened;
}

void File::asyncOpen(QIODevice::OpenMode mode)
{
    Q_D(File);
    if (d->state != File::Closed)
        return;
    d->state = File::Opening;
    d->openMode = mode;
    d->engine->open(mode);
}

bool File::waitForOpened(int msecs)
{
    Q_D(File);
    return d->engine->waitForOpened(msecs);
}

void File::close()
{
    Q_D(File);
    d->state = File::Closed;
    d->engine->close();
    QIODevice::close();
}

qint64 File::size() const
{
    Q_D(const File);
    return d->engine->size();
}

bool File::seek(qint64 pos)
{
    Q_D(File);
    QIODevice::seek(pos);
    return d->engine->seek(pos);
}

bool File::atEnd() const
{
    return pos() == size();
}

qint64 File::bytesAvailable() const
{
    Q_D(const File);
    return d->buffer.size();
}

qint64 File::bytesToWrite() const
{
    return 0;
}

bool File::waitForBytesWritten(int msecs)
{
    Q_D(File);
    return d->engine->waitForBytesWritten(msecs);
}

bool File::waitForReadyRead(int msecs)
{
    Q_D(File);
    if (!isOpen())
        return false;
    if (bytesAvailable() > 0)
        return true;
    return d->engine->waitForReadyRead(msecs);
}

QUrl File::url() const
{
    Q_D(const File);
    return d->url;
}

void File::setUrl(const QUrl &url)
{
    Q_D(File);
    if (d->url == url)
        return;

    d->url = url;
    d->engine = PluginManager::createFileEngine(url);
    if (!d->engine) {
        d->engine = AbstractFileEngine::emptyEngine();
        setErrorString(tr("Unsupported scheme %1").arg(url.scheme()));
    } else {
        d->engine->d_ptr->file = this;
    }
    emit urlChanged(url);
}

int File::bufferSize() const
{
    Q_D(const File);
    return d->bufferSize;
}

void File::setBufferSize(int size)
{
    Q_D(File);
    if (d->bufferSize == size)
        return;

    d->bufferSize = size;
    emit bufferSizeChanged(size);
}

File::State File::state() const
{
    Q_D(const File);
    return d->state;
}

qint64 File::readData(char *data, qint64 maxlen)
{
    Q_D(File);

    maxlen = qMin(qint64(d->buffer.size()), maxlen);
    if (maxlen == 0)
        return 0;

    memmove(data, d->buffer.constData(), maxlen);
    d->buffer = d->buffer.mid(maxlen);

//    d->engine->read();

    return maxlen;
}

qint64 File::writeData(const char *data, qint64 maxlen)
{
    return -1;
}

void File::onOpenFinished()
{
    Q_D(File);
    QFutureWatcher<bool> *watcher = static_cast<QFutureWatcher<bool> *>(sender());
    bool ok = watcher->future().result();
    if (ok) {
        d->state = File::Opened;
//        size = size;
        QIODevice::open(d->openMode | QIODevice::Unbuffered);
//        if (d->openMode & QIODevice::Unbuffered)
//            d->buffer.reserve(d->chunkSize);
//        else
            d->buffer.reserve(d->bufferSize);
        if (d->openMode & QIODevice::ReadOnly)
            d->engine->read(d->chunkSize);
    } else {
        d->state = File::Closed;
    }
    d->openMode = QIODevice::NotOpen;
    delete watcher;
}
<commit_msg>Fix maxlen in openFinished.<commit_after>#include "file.h"
#include "file_p.h"

#include "abstractfileengine.h"
#include "abstractfileengine_p.h"
#include "abstractfileengineplugin.h"
#include "pluginmanager_p.h"

#include <QtCore/QFutureWatcher>

void FilePrivate::init()
{
    state = File::Closed;
    openMode = QIODevice::NotOpen;
    bufferSize = 10*1024*1024; // 10 Mb
    chunkSize = 4*1024; // 4 Kb
    engine = AbstractFileEngine::emptyEngine();
}

void FilePrivate::openFinished(bool ok)
{
    Q_Q(File);
    if (ok) {
        state = File::Opened;
//        size = size;
        q->QIODevice::open(openMode);
        if (openMode & QIODevice::Unbuffered)
            buffer.reserve(chunkSize);
        else
            buffer.reserve(bufferSize);
        if (openMode & QIODevice::ReadOnly) {
            qint64 maxlen = qMin<qint64>(chunkSize, q->size());
            engine->read(maxlen);
        }
    } else {
        state = File::Closed;
    }
    openMode = QIODevice::NotOpen;
}

void FilePrivate::readFinished(const char *data, qint64 length)
{
    Q_Q(File);
    if (length <= 0)
        return;

    int oldSize = buffer.size();
    buffer.resize(oldSize + length);
    memmove(buffer.data() + oldSize, data, length);
    qint64 maxlen = bufferSize - buffer.size();
    maxlen = qMin<qint64>(maxlen, chunkSize);
    maxlen = qMin(q->size() - (q->pos() + buffer.size()), maxlen);
    if (maxlen > 0)
        engine->read(maxlen);
    emit q->readyRead();
}

File::File(QObject *parent) :
    QIODevice(parent),
    d_ptr(new FilePrivate(this))
{
    Q_D(File);
    d->init();
}

File::File(const QUrl &url, QObject *parent) :
    QIODevice(parent),
    d_ptr(new FilePrivate(this))
{
    Q_D(File);
    d->init();

    setUrl(url);
}

File::~File()
{
    Q_D(File);
    close();
    if (d->engine != AbstractFileEngine::emptyEngine())
        delete d->engine;
    delete d_ptr;
}

bool File::open(QIODevice::OpenMode mode)
{
    Q_D(File);
    asyncOpen(mode);
    waitForOpened();
    return d->state == State::Opened;
}

void File::asyncOpen(QIODevice::OpenMode mode)
{
    Q_D(File);
    if (d->state != File::Closed)
        return;
    d->state = File::Opening;
    d->openMode = mode;
    d->engine->open(mode);
}

bool File::waitForOpened(int msecs)
{
    Q_D(File);
    return d->engine->waitForOpened(msecs);
}

void File::close()
{
    Q_D(File);
    d->state = File::Closed;
    d->engine->close();
    QIODevice::close();
}

qint64 File::size() const
{
    Q_D(const File);
    return d->engine->size();
}

bool File::seek(qint64 pos)
{
    Q_D(File);
    QIODevice::seek(pos);
    return d->engine->seek(pos);
}

bool File::atEnd() const
{
    return pos() == size();
}

qint64 File::bytesAvailable() const
{
    Q_D(const File);
    return d->buffer.size();
}

qint64 File::bytesToWrite() const
{
    return 0;
}

bool File::waitForBytesWritten(int msecs)
{
    Q_D(File);
    return d->engine->waitForBytesWritten(msecs);
}

bool File::waitForReadyRead(int msecs)
{
    Q_D(File);
    if (!isOpen())
        return false;
    if (bytesAvailable() > 0)
        return true;
    return d->engine->waitForReadyRead(msecs);
}

QUrl File::url() const
{
    Q_D(const File);
    return d->url;
}

void File::setUrl(const QUrl &url)
{
    Q_D(File);
    if (d->url == url)
        return;

    d->url = url;
    d->engine = PluginManager::createFileEngine(url);
    if (!d->engine) {
        d->engine = AbstractFileEngine::emptyEngine();
        setErrorString(tr("Unsupported scheme %1").arg(url.scheme()));
    } else {
        d->engine->d_ptr->file = this;
    }
    emit urlChanged(url);
}

int File::bufferSize() const
{
    Q_D(const File);
    return d->bufferSize;
}

void File::setBufferSize(int size)
{
    Q_D(File);
    if (d->bufferSize == size)
        return;

    d->bufferSize = size;
    emit bufferSizeChanged(size);
}

File::State File::state() const
{
    Q_D(const File);
    return d->state;
}

qint64 File::readData(char *data, qint64 maxlen)
{
    Q_D(File);

    maxlen = qMin(qint64(d->buffer.size()), maxlen);
    if (maxlen == 0)
        return 0;

    memmove(data, d->buffer.constData(), maxlen);
    d->buffer = d->buffer.mid(maxlen);

//    d->engine->read();

    return maxlen;
}

qint64 File::writeData(const char *data, qint64 maxlen)
{
    return -1;
}

void File::onOpenFinished()
{
    Q_D(File);
    QFutureWatcher<bool> *watcher = static_cast<QFutureWatcher<bool> *>(sender());
    bool ok = watcher->future().result();
    if (ok) {
        d->state = File::Opened;
//        size = size;
        QIODevice::open(d->openMode | QIODevice::Unbuffered);
//        if (d->openMode & QIODevice::Unbuffered)
//            d->buffer.reserve(d->chunkSize);
//        else
            d->buffer.reserve(d->bufferSize);
        if (d->openMode & QIODevice::ReadOnly)
            d->engine->read(d->chunkSize);
    } else {
        d->state = File::Closed;
    }
    d->openMode = QIODevice::NotOpen;
    delete watcher;
}
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
// Copyright 2006 - 2010, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the
//
//     Free Software Foundation, Inc.,
//     51 Franklin Street, Fifth Floor,
//     Boston, MA
//     02110-1301
//     USA
//
////////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <vector>
#include <string>
#include <strings.h>
#include <ctype.h>
#include "Context.h"
#include "util.h"
#include "text.h"

extern Context context;

static const char* newline = "\n";
static const char* noline  = "";

///////////////////////////////////////////////////////////////////////////////
void wrapText (
  std::vector <std::string>& lines,
  const std::string& text,
  const int width)
{
  std::string copy = text;
  std::string line;

  while (copy.length ())
  {
    extractLine (copy, line, width);
    lines.push_back (line);
  }
}

////////////////////////////////////////////////////////////////////////////////
void split (
  std::vector<std::string>& results,
  const std::string& input,
  const char delimiter)
{
  results.clear ();
  std::string::size_type start = 0;
  std::string::size_type i;
  while ((i = input.find (delimiter, start)) != std::string::npos)
  {
    results.push_back (input.substr (start, i - start));
    start = i + 1;
  }

  if (input.length ())
    results.push_back (input.substr (start));
}

////////////////////////////////////////////////////////////////////////////////
void split_minimal (
  std::vector<std::string>& results,
  const std::string& input,
  const char delimiter)
{
  results.clear ();
  std::string::size_type start = 0;
  std::string::size_type i;
  while ((i = input.find (delimiter, start)) != std::string::npos)
  {
    if (i != start)
      results.push_back (input.substr (start, i - start));
    start = i + 1;
  }

  if (input.length ())
    results.push_back (input.substr (start));
}

////////////////////////////////////////////////////////////////////////////////
void split (
  std::vector<std::string>& results,
  const std::string& input,
  const std::string& delimiter)
{
  results.clear ();
  std::string::size_type length = delimiter.length ();

  std::string::size_type start = 0;
  std::string::size_type i;
  while ((i = input.find (delimiter, start)) != std::string::npos)
  {
    results.push_back (input.substr (start, i - start));
    start = i + length;
  }

  if (input.length ())
    results.push_back (input.substr (start));
}

////////////////////////////////////////////////////////////////////////////////
void split_minimal (
  std::vector<std::string>& results,
  const std::string& input,
  const std::string& delimiter)
{
  results.clear ();
  std::string::size_type length = delimiter.length ();

  std::string::size_type start = 0;
  std::string::size_type i;
  while ((i = input.find (delimiter, start)) != std::string::npos)
  {
    if (i != start)
      results.push_back (input.substr (start, i - start));
    start = i + length;
  }

  if (input.length ())
    results.push_back (input.substr (start));
}

////////////////////////////////////////////////////////////////////////////////
void join (
  std::string& result,
  const std::string& separator,
  const std::vector<std::string>& items)
{
  result = "";
  unsigned int size = items.size ();
  for (unsigned int i = 0; i < size; ++i)
  {
    result += items[i];
    if (i < size - 1)
      result += separator;
  }
}

////////////////////////////////////////////////////////////////////////////////
std::string trimLeft (const std::string& in, const std::string& t /*= " "*/)
{
  std::string out = in;
  return out.erase (0, in.find_first_not_of (t));
}

////////////////////////////////////////////////////////////////////////////////
std::string trimRight (const std::string& in, const std::string& t /*= " "*/)
{
  std::string out = in;
  return out.erase (out.find_last_not_of (t) + 1);
}

////////////////////////////////////////////////////////////////////////////////
std::string trim (const std::string& in, const std::string& t /*= " "*/)
{
  std::string out = in;
  return trimLeft (trimRight (out, t), t);
}

////////////////////////////////////////////////////////////////////////////////
// Remove enclosing balanced quotes.  Assumes trimmed text.
std::string unquoteText (const std::string& input)
{
  std::string output = input;

  if (output.length () > 1)
  {
    char quote = output[0];
    if ((quote == '\'' || quote == '"') &&
        output[output.length () - 1] == quote)
      return output.substr (1, output.length () - 2);
  }

  return output;
}

////////////////////////////////////////////////////////////////////////////////
void extractLine (std::string& text, std::string& line, int length)
{
  size_t eol = text.find ("\n");

  // Special case: found \n in first length characters.
  if (eol != std::string::npos && eol < (unsigned) length)
  {
    line = text.substr (0, eol); // strip \n
    text = text.substr (eol + 1);
    return;
  }

  // Special case: no \n, and less than length characters total.
  // special case: text.find ("\n") == std::string::npos && text.length () < length
  if (eol == std::string::npos && text.length () <= (unsigned) length)
  {
    line = text;
    text = "";
    return;
  }

  // Safe to ASSERT text.length () > length

  // Look for the last space prior to length
  eol = length;
  while (eol && text[eol] != ' ' && text[eol] != '\n')
    --eol;

  // If a space was found, break there.
  if (eol)
  {
    line = text.substr (0, eol);
    text = text.substr (eol + 1);
  }

  // If no space was found, hyphenate.
  else
  {
    if (length > 1)
    {
      line = text.substr (0, length - 1) + "-";
      text = text.substr (length - 1);
    }
    else
    {
      line = text.substr (0, 1);
      text = text.substr (length);
    }
  }
}

////////////////////////////////////////////////////////////////////////////////
std::string commify (const std::string& data)
{
  // First scan for decimal point and end of digits.
  int decimalPoint = -1;
  int end          = -1;

  int i;
  for (int i = 0; i < (int) data.length (); ++i)
  {
    if (isdigit (data[i]))
      end = i;

    if (data[i] == '.')
      decimalPoint = i;
  }

  std::string result;
  if (decimalPoint != -1)
  {
    // In reverse order, transfer all digits up to, and including the decimal
    // point.
    for (i = (int) data.length () - 1; i >= decimalPoint; --i)
      result += data[i];

    int consecutiveDigits = 0;
    for (; i >= 0; --i)
    {
      if (isdigit (data[i]))
      {
        result += data[i];

        if (++consecutiveDigits == 3 && i && isdigit (data[i - 1]))
        {
          result += ',';
          consecutiveDigits = 0;
        }
      }
      else
        result += data[i];
    }
  }
  else
  {
    // In reverse order, transfer all digits up to, but not including the last
    // digit.
    for (i = (int) data.length () - 1; i > end; --i)
      result += data[i];

    int consecutiveDigits = 0;
    for (; i >= 0; --i)
    {
      if (isdigit (data[i]))
      {
        result += data[i];

        if (++consecutiveDigits == 3 && i && isdigit (data[i - 1]))
        {
          result += ',';
          consecutiveDigits = 0;
        }
      }
      else
        result += data[i];
    }
  }

  // reverse result into data.
  std::string done;
  for (int i = (int) result.length () - 1; i >= 0; --i)
    done += result[i];

  return done;
}

////////////////////////////////////////////////////////////////////////////////
std::string lowerCase (const std::string& input)
{
  std::string output = input;
  for (int i = 0; i < (int) input.length (); ++i)
    if (isupper (input[i]))
      output[i] = tolower (input[i]);

  return output;
}

////////////////////////////////////////////////////////////////////////////////
std::string upperCase (const std::string& input)
{
  std::string output = input;
  for (int i = 0; i < (int) input.length (); ++i)
    if (islower (input[i]))
      output[i] = toupper (input[i]);

  return output;
}

////////////////////////////////////////////////////////////////////////////////
std::string ucFirst (const std::string& input)
{
  std::string output = input;

  if (output.length () > 0)
    output[0] = toupper (output[0]);

  return output;
}

////////////////////////////////////////////////////////////////////////////////
const char* optionalBlankLine ()
{
  if (context.config.getBoolean ("blanklines") == true) // no i18n
    return newline;

  return noline;
}

////////////////////////////////////////////////////////////////////////////////
void guess (
  const std::string& type,
  std::vector<std::string>& options,
  std::string& candidate)
{
  std::vector <std::string> matches;
  autoComplete (candidate, options, matches);
  if (1 == matches.size ())
    candidate = matches[0];

  else if (0 == matches.size ())
    candidate = "";

  else
  {
    std::string error = "Ambiguous "; // TODO i18n
    error += type;
    error += " '";
    error += candidate;
    error += "' - could be either of "; // TODO i18n
    for (size_t i = 0; i < matches.size (); ++i)
    {
      if (i)
        error += ", ";
      error += matches[i];
    }

    throw error;
  }
}

////////////////////////////////////////////////////////////////////////////////
bool digitsOnly (const std::string& input)
{
  for (size_t i = 0; i < input.length (); ++i)
    if (!isdigit (input[i]))
      return false;

  return true;
}

////////////////////////////////////////////////////////////////////////////////
bool noSpaces (const std::string& input)
{
  for (size_t i = 0; i < input.length (); ++i)
    if (isspace (input[i]))
      return false;

  return true;
}

////////////////////////////////////////////////////////////////////////////////
bool noVerticalSpace (const std::string& input)
{
  if (input.find_first_of ("\n\r\f") != std::string::npos)
    return false;

  return true;
}

////////////////////////////////////////////////////////////////////////////////
//          Input: hello, world
// Result for pos: y......y....
bool isWordStart (const std::string& input, std::string::size_type pos)
{
  // Short circuit: no input means no word start.
  if (input.length () == 0)
    return false;

  // If pos is the first alphanumeric character of the string.
  if (pos == 0 && isalnum (input[pos]))
    return true;

  // If pos is not the first alphanumeric character, but there is a preceding
  // non-alphanumeric character.
  if (pos > 0 && isalnum (input[pos]) && !isalnum (input[pos - 1]))
    return true;

  return false;
}

////////////////////////////////////////////////////////////////////////////////
//          Input: hello, world
// Result for pos: ....y......y
bool isWordEnd (const std::string& input, std::string::size_type pos)
{
  // Short circuit: no input means no word start.
  if (input.length () == 0)
    return false;

  // If pos is the last alphanumeric character of the string.
  if (pos == input.length () - 1 && isalnum (input[pos]))
    return true;

  // If pos is not the last alphanumeric character, but there is a following
  // non-alphanumeric character.
  if (pos < input.length () - 1 && isalnum (input[pos]) && !isalnum (input[pos + 1]))
    return true;

  return false;
}

////////////////////////////////////////////////////////////////////////////////
bool compare (
  const std::string& left,
  const std::string& right,
  bool sensitive /*= true*/)
{
  // Use strcasecmp if required.
  if (!sensitive)
    return strcasecmp (left.c_str (), right.c_str ()) == 0 ? true : false;

  // Otherwise, just use std::string::operator==.
  return left == right;
}

////////////////////////////////////////////////////////////////////////////////
std::string::size_type find (
  const std::string& text,
  const std::string& pattern,
  bool sensitive /*= true*/)
{
  // Implement a sensitive find, which is really just a loop withing a loop,
  // comparing lower-case versions of each character in turn.
  if (!sensitive)
  {
    // Handle empty pattern.
    const char* p = pattern.c_str ();
    size_t len = pattern.length ();
    if (len == 0)
      return 0;

    // Evaluate these once, for performance reasons.
    const char* t = text.c_str ();
    const char* start = t;
    const char* end = start + text.size ();

    for (; t < end - len; ++t)
    {
      int diff;
      for (size_t i = 0; i < len; ++i)
        if ((diff = tolower (t[i]) - tolower (p[i])))
          break;

      // diff == 0 means there was no break from the loop, which only occurs
      // when a difference is detected.  Therefore, the loop terminated, and
      // diff is zero.
      if (diff == 0)
        return t - start;
    }

    return std::string::npos;
  }

  // Otherwise, just use std::string::find.
  return text.find (pattern);
}

////////////////////////////////////////////////////////////////////////////////
std::string::size_type find (
  const std::string& text,
  const std::string& pattern,
  std::string::size_type begin,
  bool sensitive /*= true*/)
{
  // Implement a sensitive find, which is really just a loop withing a loop,
  // comparing lower-case versions of each character in turn.
  if (!sensitive)
  {
    // Handle empty pattern.
    const char* p = pattern.c_str ();
    size_t len = pattern.length ();
    if (len == 0)
      return 0;

    // Handle bad begin.
    if (begin >= len)
      return std::string::npos;

    // Evaluate these once, for performance reasons.
    const char* t = text.c_str ();
    const char* start = t + begin;
    const char* end = start + text.size ();

    for (; t < end - len; ++t)
    {
      int diff;
      for (size_t i = 0; i < len; ++i)
        if ((diff = tolower (t[i]) - tolower (p[i])))
          break;

      // diff == 0 means there was no break from the loop, which only occurs
      // when a difference is detected.  Therefore, the loop terminated, and
      // diff is zero.
      if (diff == 0)
        return t - start;
    }

    return std::string::npos;
  }

  // Otherwise, just use std::string::find.
  return text.find (pattern, begin);
}

////////////////////////////////////////////////////////////////////////////////
<commit_msg>Enhancement - caseless find<commit_after>////////////////////////////////////////////////////////////////////////////////
// task - a command line task list manager.
//
// Copyright 2006 - 2010, Paul Beckingham.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the
//
//     Free Software Foundation, Inc.,
//     51 Franklin Street, Fifth Floor,
//     Boston, MA
//     02110-1301
//     USA
//
////////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <vector>
#include <string>
#include <strings.h>
#include <ctype.h>
#include "Context.h"
#include "util.h"
#include "text.h"

extern Context context;

static const char* newline = "\n";
static const char* noline  = "";

///////////////////////////////////////////////////////////////////////////////
void wrapText (
  std::vector <std::string>& lines,
  const std::string& text,
  const int width)
{
  std::string copy = text;
  std::string line;

  while (copy.length ())
  {
    extractLine (copy, line, width);
    lines.push_back (line);
  }
}

////////////////////////////////////////////////////////////////////////////////
void split (
  std::vector<std::string>& results,
  const std::string& input,
  const char delimiter)
{
  results.clear ();
  std::string::size_type start = 0;
  std::string::size_type i;
  while ((i = input.find (delimiter, start)) != std::string::npos)
  {
    results.push_back (input.substr (start, i - start));
    start = i + 1;
  }

  if (input.length ())
    results.push_back (input.substr (start));
}

////////////////////////////////////////////////////////////////////////////////
void split_minimal (
  std::vector<std::string>& results,
  const std::string& input,
  const char delimiter)
{
  results.clear ();
  std::string::size_type start = 0;
  std::string::size_type i;
  while ((i = input.find (delimiter, start)) != std::string::npos)
  {
    if (i != start)
      results.push_back (input.substr (start, i - start));
    start = i + 1;
  }

  if (input.length ())
    results.push_back (input.substr (start));
}

////////////////////////////////////////////////////////////////////////////////
void split (
  std::vector<std::string>& results,
  const std::string& input,
  const std::string& delimiter)
{
  results.clear ();
  std::string::size_type length = delimiter.length ();

  std::string::size_type start = 0;
  std::string::size_type i;
  while ((i = input.find (delimiter, start)) != std::string::npos)
  {
    results.push_back (input.substr (start, i - start));
    start = i + length;
  }

  if (input.length ())
    results.push_back (input.substr (start));
}

////////////////////////////////////////////////////////////////////////////////
void split_minimal (
  std::vector<std::string>& results,
  const std::string& input,
  const std::string& delimiter)
{
  results.clear ();
  std::string::size_type length = delimiter.length ();

  std::string::size_type start = 0;
  std::string::size_type i;
  while ((i = input.find (delimiter, start)) != std::string::npos)
  {
    if (i != start)
      results.push_back (input.substr (start, i - start));
    start = i + length;
  }

  if (input.length ())
    results.push_back (input.substr (start));
}

////////////////////////////////////////////////////////////////////////////////
void join (
  std::string& result,
  const std::string& separator,
  const std::vector<std::string>& items)
{
  result = "";
  unsigned int size = items.size ();
  for (unsigned int i = 0; i < size; ++i)
  {
    result += items[i];
    if (i < size - 1)
      result += separator;
  }
}

////////////////////////////////////////////////////////////////////////////////
std::string trimLeft (const std::string& in, const std::string& t /*= " "*/)
{
  std::string out = in;
  return out.erase (0, in.find_first_not_of (t));
}

////////////////////////////////////////////////////////////////////////////////
std::string trimRight (const std::string& in, const std::string& t /*= " "*/)
{
  std::string out = in;
  return out.erase (out.find_last_not_of (t) + 1);
}

////////////////////////////////////////////////////////////////////////////////
std::string trim (const std::string& in, const std::string& t /*= " "*/)
{
  std::string out = in;
  return trimLeft (trimRight (out, t), t);
}

////////////////////////////////////////////////////////////////////////////////
// Remove enclosing balanced quotes.  Assumes trimmed text.
std::string unquoteText (const std::string& input)
{
  std::string output = input;

  if (output.length () > 1)
  {
    char quote = output[0];
    if ((quote == '\'' || quote == '"') &&
        output[output.length () - 1] == quote)
      return output.substr (1, output.length () - 2);
  }

  return output;
}

////////////////////////////////////////////////////////////////////////////////
void extractLine (std::string& text, std::string& line, int length)
{
  size_t eol = text.find ("\n");

  // Special case: found \n in first length characters.
  if (eol != std::string::npos && eol < (unsigned) length)
  {
    line = text.substr (0, eol); // strip \n
    text = text.substr (eol + 1);
    return;
  }

  // Special case: no \n, and less than length characters total.
  // special case: text.find ("\n") == std::string::npos && text.length () < length
  if (eol == std::string::npos && text.length () <= (unsigned) length)
  {
    line = text;
    text = "";
    return;
  }

  // Safe to ASSERT text.length () > length

  // Look for the last space prior to length
  eol = length;
  while (eol && text[eol] != ' ' && text[eol] != '\n')
    --eol;

  // If a space was found, break there.
  if (eol)
  {
    line = text.substr (0, eol);
    text = text.substr (eol + 1);
  }

  // If no space was found, hyphenate.
  else
  {
    if (length > 1)
    {
      line = text.substr (0, length - 1) + "-";
      text = text.substr (length - 1);
    }
    else
    {
      line = text.substr (0, 1);
      text = text.substr (length);
    }
  }
}

////////////////////////////////////////////////////////////////////////////////
std::string commify (const std::string& data)
{
  // First scan for decimal point and end of digits.
  int decimalPoint = -1;
  int end          = -1;

  int i;
  for (int i = 0; i < (int) data.length (); ++i)
  {
    if (isdigit (data[i]))
      end = i;

    if (data[i] == '.')
      decimalPoint = i;
  }

  std::string result;
  if (decimalPoint != -1)
  {
    // In reverse order, transfer all digits up to, and including the decimal
    // point.
    for (i = (int) data.length () - 1; i >= decimalPoint; --i)
      result += data[i];

    int consecutiveDigits = 0;
    for (; i >= 0; --i)
    {
      if (isdigit (data[i]))
      {
        result += data[i];

        if (++consecutiveDigits == 3 && i && isdigit (data[i - 1]))
        {
          result += ',';
          consecutiveDigits = 0;
        }
      }
      else
        result += data[i];
    }
  }
  else
  {
    // In reverse order, transfer all digits up to, but not including the last
    // digit.
    for (i = (int) data.length () - 1; i > end; --i)
      result += data[i];

    int consecutiveDigits = 0;
    for (; i >= 0; --i)
    {
      if (isdigit (data[i]))
      {
        result += data[i];

        if (++consecutiveDigits == 3 && i && isdigit (data[i - 1]))
        {
          result += ',';
          consecutiveDigits = 0;
        }
      }
      else
        result += data[i];
    }
  }

  // reverse result into data.
  std::string done;
  for (int i = (int) result.length () - 1; i >= 0; --i)
    done += result[i];

  return done;
}

////////////////////////////////////////////////////////////////////////////////
std::string lowerCase (const std::string& input)
{
  std::string output = input;
  for (int i = 0; i < (int) input.length (); ++i)
    if (isupper (input[i]))
      output[i] = tolower (input[i]);

  return output;
}

////////////////////////////////////////////////////////////////////////////////
std::string upperCase (const std::string& input)
{
  std::string output = input;
  for (int i = 0; i < (int) input.length (); ++i)
    if (islower (input[i]))
      output[i] = toupper (input[i]);

  return output;
}

////////////////////////////////////////////////////////////////////////////////
std::string ucFirst (const std::string& input)
{
  std::string output = input;

  if (output.length () > 0)
    output[0] = toupper (output[0]);

  return output;
}

////////////////////////////////////////////////////////////////////////////////
const char* optionalBlankLine ()
{
  if (context.config.getBoolean ("blanklines") == true) // no i18n
    return newline;

  return noline;
}

////////////////////////////////////////////////////////////////////////////////
void guess (
  const std::string& type,
  std::vector<std::string>& options,
  std::string& candidate)
{
  std::vector <std::string> matches;
  autoComplete (candidate, options, matches);
  if (1 == matches.size ())
    candidate = matches[0];

  else if (0 == matches.size ())
    candidate = "";

  else
  {
    std::string error = "Ambiguous "; // TODO i18n
    error += type;
    error += " '";
    error += candidate;
    error += "' - could be either of "; // TODO i18n
    for (size_t i = 0; i < matches.size (); ++i)
    {
      if (i)
        error += ", ";
      error += matches[i];
    }

    throw error;
  }
}

////////////////////////////////////////////////////////////////////////////////
bool digitsOnly (const std::string& input)
{
  for (size_t i = 0; i < input.length (); ++i)
    if (!isdigit (input[i]))
      return false;

  return true;
}

////////////////////////////////////////////////////////////////////////////////
bool noSpaces (const std::string& input)
{
  for (size_t i = 0; i < input.length (); ++i)
    if (isspace (input[i]))
      return false;

  return true;
}

////////////////////////////////////////////////////////////////////////////////
bool noVerticalSpace (const std::string& input)
{
  if (input.find_first_of ("\n\r\f") != std::string::npos)
    return false;

  return true;
}

////////////////////////////////////////////////////////////////////////////////
//          Input: hello, world
// Result for pos: y......y....
bool isWordStart (const std::string& input, std::string::size_type pos)
{
  // Short circuit: no input means no word start.
  if (input.length () == 0)
    return false;

  // If pos is the first alphanumeric character of the string.
  if (pos == 0 && isalnum (input[pos]))
    return true;

  // If pos is not the first alphanumeric character, but there is a preceding
  // non-alphanumeric character.
  if (pos > 0 && isalnum (input[pos]) && !isalnum (input[pos - 1]))
    return true;

  return false;
}

////////////////////////////////////////////////////////////////////////////////
//          Input: hello, world
// Result for pos: ....y......y
bool isWordEnd (const std::string& input, std::string::size_type pos)
{
  // Short circuit: no input means no word start.
  if (input.length () == 0)
    return false;

  // If pos is the last alphanumeric character of the string.
  if (pos == input.length () - 1 && isalnum (input[pos]))
    return true;

  // If pos is not the last alphanumeric character, but there is a following
  // non-alphanumeric character.
  if (pos < input.length () - 1 && isalnum (input[pos]) && !isalnum (input[pos + 1]))
    return true;

  return false;
}

////////////////////////////////////////////////////////////////////////////////
bool compare (
  const std::string& left,
  const std::string& right,
  bool sensitive /*= true*/)
{
  // Use strcasecmp if required.
  if (!sensitive)
    return strcasecmp (left.c_str (), right.c_str ()) == 0 ? true : false;

  // Otherwise, just use std::string::operator==.
  return left == right;
}

////////////////////////////////////////////////////////////////////////////////
std::string::size_type find (
  const std::string& text,
  const std::string& pattern,
  bool sensitive /*= true*/)
{
  // Implement a sensitive find, which is really just a loop withing a loop,
  // comparing lower-case versions of each character in turn.
  if (!sensitive)
  {
    // Handle empty pattern.
    const char* p = pattern.c_str ();
    size_t len = pattern.length ();
    if (len == 0)
      return 0;

    // Evaluate these once, for performance reasons.
    const char* t = text.c_str ();
    const char* start = t;
    const char* end = start + text.size ();

    for (; t < end - len; ++t)
    {
      int diff;
      for (size_t i = 0; i < len; ++i)
        if ((diff = tolower (t[i]) - tolower (p[i])))
          break;

      // diff == 0 means there was no break from the loop, which only occurs
      // when a difference is detected.  Therefore, the loop terminated, and
      // diff is zero.
      if (diff == 0)
        return t - start;
    }

    return std::string::npos;
  }

  // Otherwise, just use std::string::find.
  return text.find (pattern);
}

////////////////////////////////////////////////////////////////////////////////
std::string::size_type find (
  const std::string& text,
  const std::string& pattern,
  std::string::size_type begin,
  bool sensitive /*= true*/)
{
  // Implement a sensitive find, which is really just a loop withing a loop,
  // comparing lower-case versions of each character in turn.
  if (!sensitive)
  {
    // Handle empty pattern.
    const char* p = pattern.c_str ();
    size_t len = pattern.length ();
    if (len == 0)
      return 0;

    // Handle bad begin.
    if (begin >= text.length ())
      return std::string::npos;

    // Evaluate these once, for performance reasons.
    const char* start = text.c_str ();
    const char* t = start + begin;
    const char* end = start + text.size ();

    for (; t < end - len; ++t)
    {
      int diff;
      for (size_t i = 0; i < len; ++i)
        if ((diff = tolower (t[i]) - tolower (p[i])))
          break;

      // diff == 0 means there was no break from the loop, which only occurs
      // when a difference is detected.  Therefore, the loop terminated, and
      // diff is zero.
      if (diff == 0)
        return t - start;
    }

    return std::string::npos;
  }

  // Otherwise, just use std::string::find.
  return text.find (pattern, begin);
}

////////////////////////////////////////////////////////////////////////////////
<|endoftext|>


<commit_before>#include "token.h"

namespace flora {

Token Tokens::LookupKeyword(const std::string &identifier) {
  auto result = lookup_table_.find(identifier);
  return result == lookup_table_.end() ? result->second : Token::Identifier;
}

#define T(name, literal, precedence) #name,
const char *Tokens::name_[Tokens::TOKEN_COUNT] = {
  TOKEN_LIST(T, T)
};
#undef T

#define T(name, literal, precedence) #literal,
const char *Tokens::literal_[Tokens::TOKEN_COUNT] = {
  TOKEN_LIST(T, T)
};
#undef T

#define T(name, literal, precedence) precedence,
const int Tokens::precedence_[Tokens::TOKEN_COUNT] = {
  TOKEN_LIST(T, T)
};
#undef T

std::unordered_map<std::string, Token> Tokens::lookup_table_;

void Tokens::InitializeKeywordLookupTable() {
#define K(name, literal, precedence) lookup_table_[std::string(literal)] = Token::name;
#define T(name, literal, precedence)
  TOKEN_LIST(K, T)
#undef K
#undef T
}

Tokens::Tokens() {
  InitializeKeywordLookupTable();
}

}<commit_msg>Fixed a logical error that cause segment fault.<commit_after>#include "token.h"

namespace flora {

Token Tokens::LookupKeyword(const std::string &identifier) {
  auto result = lookup_table_.find(identifier);
  return result == lookup_table_.end() ? Token::Identifier : result->second;
}

#define T(name, literal, precedence) #name,
const char *Tokens::name_[Tokens::TOKEN_COUNT] = {
  TOKEN_LIST(T, T)
};
#undef T

#define T(name, literal, precedence) #literal,
const char *Tokens::literal_[Tokens::TOKEN_COUNT] = {
  TOKEN_LIST(T, T)
};
#undef T

#define T(name, literal, precedence) precedence,
const int Tokens::precedence_[Tokens::TOKEN_COUNT] = {
  TOKEN_LIST(T, T)
};
#undef T

std::unordered_map<std::string, Token> Tokens::lookup_table_;

void Tokens::InitializeKeywordLookupTable() {
#define K(name, literal, precedence) lookup_table_[std::string(literal)] = Token::name;
#define T(name, literal, precedence)
  TOKEN_LIST(K, T)
#undef K
#undef T
}

Tokens::Tokens() {
  InitializeKeywordLookupTable();
}

Tokens Tokens::singleton;

}<|endoftext|>


<commit_before>#include "tree.h"
#include "entry_points.h"
#include "oid.h"
#include "repository.h"

/******************************************************************************/
// Tree

static void _git_tree_free(git_tree *tree)
{
    git_object_free((git_object *)tree);
}

Tree::Tree(git_tree *_tree)
{
    tree = boost::shared_ptr<git_tree>(_tree, _git_tree_free);
}

Rcpp::Reference Tree::id()
{
    const git_oid *result = git_tree_id(tree.get());
    return OID::create(result);
}

size_t Tree::entry_count()
{
    return git_tree_entrycount(tree.get());
}

static int walk_cb(const char *root, const git_tree_entry *entry, void *payload)
{
    Rcpp::Function *f = (Rcpp::Function *)payload;
    int r = Rcpp::as<int>((*f)(std::string(root)));
    return r;
}

int Tree::walk_pre(Rcpp::Function fcall)
{
    git_tree_walk(tree.get(), GIT_TREEWALK_PRE, &walk_cb, &fcall);
}

int Tree::walk_post(Rcpp::Function fcall)
{
    git_tree_walk(tree.get(), GIT_TREEWALK_POST, &walk_cb, &fcall);
}

Rcpp::Reference Tree::entry_by_index(size_t idx)
{
    BEGIN_RCPP
        const git_tree_entry *entry = git_tree_entry_byindex(tree.get(), idx);
    if (entry == NULL)
        throw Rcpp::exception("entry not found");
    git_tree_entry *dup;
    int err = git_tree_entry_dup(&dup, entry);
    if (err)
	throw Rcpp::exception("entry duplication failed");
    return TreeEntry::create(dup);
    END_RCPP
}

Rcpp::Reference Tree::entry_by_name(std::string name)
{
    BEGIN_RCPP
    const git_tree_entry *entry = git_tree_entry_byname(tree.get(), name.c_str());
    if (entry == NULL)
        throw Rcpp::exception("entry not found");
    git_tree_entry *dup;
    int err = git_tree_entry_dup(&dup, entry);
    if (err)
        throw Rcpp::exception("entry duplication failed");
    return TreeEntry::create(dup);
    END_RCPP
}

Rcpp::Reference Tree::entry_by_path(std::string name)
{
    BEGIN_RCPP
    git_tree_entry *entry;
    int err = git_tree_entry_bypath(&entry, tree.get(), name.c_str());
    if (err)
        throw Rcpp::exception("entry not found");
    return TreeEntry::create(entry);
    END_RCPP
}

Rcpp::Reference Tree::entry_by_oid(SEXP oid)
{
    BEGIN_RCPP
    const git_tree_entry *entry = git_tree_entry_byid(tree.get(), OID::from_sexp(oid));
    if (entry == NULL)
        throw Rcpp::exception("entry not found");
    git_tree_entry *dup;
    int err = git_tree_entry_dup(&dup, entry);
    if (err)
        throw Rcpp::exception("entry duplication failed");
    return TreeEntry::create(dup);
    END_RCPP
}

/******************************************************************************/
// TreeEntry

TreeEntry::TreeEntry(git_tree_entry *_entry)
{
    tree_entry = boost::shared_ptr<git_tree_entry>(_entry, git_tree_entry_free);
}

int TreeEntry::file_mode()
{
    return git_tree_entry_filemode(tree_entry.get());
}

Rcpp::Reference TreeEntry::id()
{
    return OID::create(git_tree_entry_id(tree_entry.get()));
}

std::string TreeEntry::name()
{
    return std::string(git_tree_entry_name(tree_entry.get()));
}

SEXP TreeEntry::object(SEXP _repo)
{
    BEGIN_RCPP
    git_repository *repo = (git_repository*)Repository::from_sexp(_repo);
    git_object *result;
    int err = git_tree_entry_to_object(&result, repo, tree_entry.get());
    if (err)
        throw Rcpp::exception("object lookup failed");
    return object_to_sexp(result);
    END_RCPP
}

int TreeEntry::type()
{
    return git_tree_entry_type(tree_entry.get());
}

RCPP_MODULE(guitar_tree) {
    using namespace Rcpp;
    class_<Tree>("Tree")
        .method("id", &Tree::id)
        .method("entry_count", &Tree::entry_count)
        .method("walk_pre", &Tree::walk_pre)
        .method("walk_post", &Tree::walk_post)
        .method("entry_by_index", &Tree::entry_by_index)
        .method("entry_by_name", &Tree::entry_by_name)
        .method("entry_by_oid", &Tree::entry_by_oid)
        .method("entry_by_path", &Tree::entry_by_path)
        ;
    class_<TreeEntry>("TreeEntry")
        .method("file_mode", &TreeEntry::file_mode)
        .method("id", &TreeEntry::id)
        .method("name", &TreeEntry::name)
        .method("object", &TreeEntry::object)
        .method("type", &TreeEntry::type)
        ;
}
<commit_msg>fix missing return<commit_after>#include "tree.h"
#include "entry_points.h"
#include "oid.h"
#include "repository.h"

/******************************************************************************/
// Tree

static void _git_tree_free(git_tree *tree)
{
    git_object_free((git_object *)tree);
}

Tree::Tree(git_tree *_tree)
{
    tree = boost::shared_ptr<git_tree>(_tree, _git_tree_free);
}

Rcpp::Reference Tree::id()
{
    const git_oid *result = git_tree_id(tree.get());
    return OID::create(result);
}

size_t Tree::entry_count()
{
    return git_tree_entrycount(tree.get());
}

static int walk_cb(const char *root, const git_tree_entry *entry, void *payload)
{
    Rcpp::Function *f = (Rcpp::Function *)payload;
    int r = Rcpp::as<int>((*f)(std::string(root)));
    return r;
}

int Tree::walk_pre(Rcpp::Function fcall)
{
    return git_tree_walk(tree.get(), GIT_TREEWALK_PRE, &walk_cb, &fcall);
}

int Tree::walk_post(Rcpp::Function fcall)
{
    return git_tree_walk(tree.get(), GIT_TREEWALK_POST, &walk_cb, &fcall);
}

Rcpp::Reference Tree::entry_by_index(size_t idx)
{
    BEGIN_RCPP
        const git_tree_entry *entry = git_tree_entry_byindex(tree.get(), idx);
    if (entry == NULL)
        throw Rcpp::exception("entry not found");
    git_tree_entry *dup;
    int err = git_tree_entry_dup(&dup, entry);
    if (err)
	throw Rcpp::exception("entry duplication failed");
    return TreeEntry::create(dup);
    END_RCPP
}

Rcpp::Reference Tree::entry_by_name(std::string name)
{
    BEGIN_RCPP
    const git_tree_entry *entry = git_tree_entry_byname(tree.get(), name.c_str());
    if (entry == NULL)
        throw Rcpp::exception("entry not found");
    git_tree_entry *dup;
    int err = git_tree_entry_dup(&dup, entry);
    if (err)
        throw Rcpp::exception("entry duplication failed");
    return TreeEntry::create(dup);
    END_RCPP
}

Rcpp::Reference Tree::entry_by_path(std::string name)
{
    BEGIN_RCPP
    git_tree_entry *entry;
    int err = git_tree_entry_bypath(&entry, tree.get(), name.c_str());
    if (err)
        throw Rcpp::exception("entry not found");
    return TreeEntry::create(entry);
    END_RCPP
}

Rcpp::Reference Tree::entry_by_oid(SEXP oid)
{
    BEGIN_RCPP
    const git_tree_entry *entry = git_tree_entry_byid(tree.get(), OID::from_sexp(oid));
    if (entry == NULL)
        throw Rcpp::exception("entry not found");
    git_tree_entry *dup;
    int err = git_tree_entry_dup(&dup, entry);
    if (err)
        throw Rcpp::exception("entry duplication failed");
    return TreeEntry::create(dup);
    END_RCPP
}

/******************************************************************************/
// TreeEntry

TreeEntry::TreeEntry(git_tree_entry *_entry)
{
    tree_entry = boost::shared_ptr<git_tree_entry>(_entry, git_tree_entry_free);
}

int TreeEntry::file_mode()
{
    return git_tree_entry_filemode(tree_entry.get());
}

Rcpp::Reference TreeEntry::id()
{
    return OID::create(git_tree_entry_id(tree_entry.get()));
}

std::string TreeEntry::name()
{
    return std::string(git_tree_entry_name(tree_entry.get()));
}

SEXP TreeEntry::object(SEXP _repo)
{
    BEGIN_RCPP
    git_repository *repo = (git_repository*)Repository::from_sexp(_repo);
    git_object *result;
    int err = git_tree_entry_to_object(&result, repo, tree_entry.get());
    if (err)
        throw Rcpp::exception("object lookup failed");
    return object_to_sexp(result);
    END_RCPP
}

int TreeEntry::type()
{
    return git_tree_entry_type(tree_entry.get());
}

RCPP_MODULE(guitar_tree) {
    using namespace Rcpp;
    class_<Tree>("Tree")
        .method("id", &Tree::id)
        .method("entry_count", &Tree::entry_count)
        .method("walk_pre", &Tree::walk_pre)
        .method("walk_post", &Tree::walk_post)
        .method("entry_by_index", &Tree::entry_by_index)
        .method("entry_by_name", &Tree::entry_by_name)
        .method("entry_by_oid", &Tree::entry_by_oid)
        .method("entry_by_path", &Tree::entry_by_path)
        ;
    class_<TreeEntry>("TreeEntry")
        .method("file_mode", &TreeEntry::file_mode)
        .method("id", &TreeEntry::id)
        .method("name", &TreeEntry::name)
        .method("object", &TreeEntry::object)
        .method("type", &TreeEntry::type)
        ;
}
<|endoftext|>


<commit_before>#ifndef units_hh_INCLUDED
#define units_hh_INCLUDED

#include "hash.hh"

#include <type_traits>

namespace Kakoune
{

template<typename RealType, typename ValueType = int>
class StronglyTypedNumber
{
public:
    [[gnu::always_inline]]
    explicit constexpr StronglyTypedNumber(ValueType value)
        : m_value(value)
    {
        static_assert(std::is_base_of<StronglyTypedNumber, RealType>::value,
                     "RealType is not derived from StronglyTypedNumber");
    }

    [[gnu::always_inline]]
    constexpr friend RealType operator+(RealType lhs, RealType rhs)
    { return RealType(lhs.m_value + rhs.m_value); }

    [[gnu::always_inline]]
    constexpr friend RealType operator-(RealType lhs, RealType rhs)
    { return RealType(lhs.m_value - rhs.m_value); }

    [[gnu::always_inline]]
    constexpr friend RealType operator*(RealType lhs, RealType rhs)
    { return RealType(lhs.m_value * rhs.m_value); }

    [[gnu::always_inline]]
    constexpr friend RealType operator/(RealType lhs, RealType rhs)
    { return RealType(lhs.m_value / rhs.m_value); }

    [[gnu::always_inline]]
    RealType& operator+=(RealType other)
    { m_value += other.m_value; return static_cast<RealType&>(*this); }

    [[gnu::always_inline]]
    RealType& operator-=(RealType other)
    { m_value -= other.m_value; return static_cast<RealType&>(*this); }

    [[gnu::always_inline]]
    RealType& operator*=(RealType other)
    { m_value *= other.m_value; return static_cast<RealType&>(*this); }

    [[gnu::always_inline]]
    RealType& operator/=(RealType other)
    { m_value /= other.m_value; return static_cast<RealType&>(*this); }

    [[gnu::always_inline]]
    RealType& operator++()
    { ++m_value; return static_cast<RealType&>(*this); }

    [[gnu::always_inline]]
    RealType& operator--()
    { --m_value; return static_cast<RealType&>(*this); }

    [[gnu::always_inline]]
    RealType operator++(int)
    { RealType backup(static_cast<RealType&>(*this)); ++m_value; return backup; }

    [[gnu::always_inline]]
    RealType operator--(int)
    { RealType backup(static_cast<RealType&>(*this)); --m_value; return backup; }

    [[gnu::always_inline]]
    constexpr RealType operator-() const { return RealType(-m_value); }

    [[gnu::always_inline]]
    constexpr friend RealType operator%(RealType lhs, RealType rhs)
    { return RealType(lhs.m_value % rhs.m_value); }

    [[gnu::always_inline]]
    RealType& operator%=(RealType other)
    { m_value %= other.m_value; return static_cast<RealType&>(*this); }

    [[gnu::always_inline]]
    constexpr friend bool operator==(RealType lhs, RealType rhs)
    { return lhs.m_value == rhs.m_value; }

    [[gnu::always_inline]]
    constexpr friend bool operator!=(RealType lhs, RealType rhs)
    { return lhs.m_value != rhs.m_value; }

    [[gnu::always_inline]]
    constexpr friend bool operator<(RealType lhs, RealType rhs)
    { return lhs.m_value < rhs.m_value; }

    [[gnu::always_inline]]
    constexpr friend bool operator<=(RealType lhs, RealType rhs)
    { return lhs.m_value <= rhs.m_value; }

    [[gnu::always_inline]]
    constexpr friend bool operator>(RealType lhs, RealType rhs)
    { return lhs.m_value > rhs.m_value; }

    [[gnu::always_inline]]
    constexpr friend bool operator>=(RealType lhs, RealType rhs)
    { return lhs.m_value >= rhs.m_value; }

    [[gnu::always_inline]]
    constexpr bool operator!() const
    { return not m_value; }

    [[gnu::always_inline]]
    explicit constexpr operator ValueType() const { return m_value; }
    [[gnu::always_inline]]
    explicit constexpr operator bool() const { return m_value; }

    friend size_t hash_value(RealType val) { return hash_value(val.m_value); }
    friend size_t abs(RealType val) { return val.m_value < ValueType(0) ? -val.m_value : val.m_value; }

private:
    ValueType m_value;
};

struct LineCount : public StronglyTypedNumber<LineCount, int>
{
    [[gnu::always_inline]]
    constexpr LineCount(int value = 0) : StronglyTypedNumber<LineCount>(value) {}
};

[[gnu::always_inline]]
inline constexpr LineCount operator"" _line(unsigned long long int value)
{
    return LineCount(value);
}

struct ByteCount : public StronglyTypedNumber<ByteCount, int>
{
    [[gnu::always_inline]]
    constexpr ByteCount(int value = 0) : StronglyTypedNumber<ByteCount>(value) {}
};

[[gnu::always_inline]]
inline constexpr ByteCount operator"" _byte(unsigned long long int value)
{
    return ByteCount(value);
}

struct CharCount : public StronglyTypedNumber<CharCount, int>
{
    [[gnu::always_inline]]
    constexpr CharCount(int value = 0) : StronglyTypedNumber<CharCount>(value) {}
};

[[gnu::always_inline]]
inline constexpr CharCount operator"" _char(unsigned long long int value)
{
    return CharCount(value);
}

}

#endif // units_hh_INCLUDED
<commit_msg>Add checked, explicit conversion from strongly typed number for size_t<commit_after>#ifndef units_hh_INCLUDED
#define units_hh_INCLUDED

#include "assert.hh"
#include "hash.hh"

#include <type_traits>

namespace Kakoune
{

template<typename RealType, typename ValueType = int>
class StronglyTypedNumber
{
public:
    [[gnu::always_inline]]
    explicit constexpr StronglyTypedNumber(ValueType value)
        : m_value(value)
    {
        static_assert(std::is_base_of<StronglyTypedNumber, RealType>::value,
                     "RealType is not derived from StronglyTypedNumber");
    }

    [[gnu::always_inline]]
    constexpr friend RealType operator+(RealType lhs, RealType rhs)
    { return RealType(lhs.m_value + rhs.m_value); }

    [[gnu::always_inline]]
    constexpr friend RealType operator-(RealType lhs, RealType rhs)
    { return RealType(lhs.m_value - rhs.m_value); }

    [[gnu::always_inline]]
    constexpr friend RealType operator*(RealType lhs, RealType rhs)
    { return RealType(lhs.m_value * rhs.m_value); }

    [[gnu::always_inline]]
    constexpr friend RealType operator/(RealType lhs, RealType rhs)
    { return RealType(lhs.m_value / rhs.m_value); }

    [[gnu::always_inline]]
    RealType& operator+=(RealType other)
    { m_value += other.m_value; return static_cast<RealType&>(*this); }

    [[gnu::always_inline]]
    RealType& operator-=(RealType other)
    { m_value -= other.m_value; return static_cast<RealType&>(*this); }

    [[gnu::always_inline]]
    RealType& operator*=(RealType other)
    { m_value *= other.m_value; return static_cast<RealType&>(*this); }

    [[gnu::always_inline]]
    RealType& operator/=(RealType other)
    { m_value /= other.m_value; return static_cast<RealType&>(*this); }

    [[gnu::always_inline]]
    RealType& operator++()
    { ++m_value; return static_cast<RealType&>(*this); }

    [[gnu::always_inline]]
    RealType& operator--()
    { --m_value; return static_cast<RealType&>(*this); }

    [[gnu::always_inline]]
    RealType operator++(int)
    { RealType backup(static_cast<RealType&>(*this)); ++m_value; return backup; }

    [[gnu::always_inline]]
    RealType operator--(int)
    { RealType backup(static_cast<RealType&>(*this)); --m_value; return backup; }

    [[gnu::always_inline]]
    constexpr RealType operator-() const { return RealType(-m_value); }

    [[gnu::always_inline]]
    constexpr friend RealType operator%(RealType lhs, RealType rhs)
    { return RealType(lhs.m_value % rhs.m_value); }

    [[gnu::always_inline]]
    RealType& operator%=(RealType other)
    { m_value %= other.m_value; return static_cast<RealType&>(*this); }

    [[gnu::always_inline]]
    constexpr friend bool operator==(RealType lhs, RealType rhs)
    { return lhs.m_value == rhs.m_value; }

    [[gnu::always_inline]]
    constexpr friend bool operator!=(RealType lhs, RealType rhs)
    { return lhs.m_value != rhs.m_value; }

    [[gnu::always_inline]]
    constexpr friend bool operator<(RealType lhs, RealType rhs)
    { return lhs.m_value < rhs.m_value; }

    [[gnu::always_inline]]
    constexpr friend bool operator<=(RealType lhs, RealType rhs)
    { return lhs.m_value <= rhs.m_value; }

    [[gnu::always_inline]]
    constexpr friend bool operator>(RealType lhs, RealType rhs)
    { return lhs.m_value > rhs.m_value; }

    [[gnu::always_inline]]
    constexpr friend bool operator>=(RealType lhs, RealType rhs)
    { return lhs.m_value >= rhs.m_value; }

    [[gnu::always_inline]]
    constexpr bool operator!() const
    { return not m_value; }

    [[gnu::always_inline]]
    explicit constexpr operator ValueType() const { return m_value; }
    [[gnu::always_inline]]
    explicit constexpr operator bool() const { return m_value; }

    friend size_t hash_value(RealType val) { return hash_value(val.m_value); }
    friend size_t abs(RealType val) { return val.m_value < ValueType(0) ? -val.m_value : val.m_value; }

    explicit operator size_t() { kak_assert(m_value >= 0); return (size_t)m_value; }

protected:
    ValueType m_value;
};

struct LineCount : public StronglyTypedNumber<LineCount, int>
{
    [[gnu::always_inline]]
    constexpr LineCount(int value = 0) : StronglyTypedNumber<LineCount>(value) {}
};

[[gnu::always_inline]]
inline constexpr LineCount operator"" _line(unsigned long long int value)
{
    return LineCount(value);
}

struct ByteCount : public StronglyTypedNumber<ByteCount, int>
{
    [[gnu::always_inline]]
    constexpr ByteCount(int value = 0) : StronglyTypedNumber<ByteCount>(value) {}
};

[[gnu::always_inline]]
inline constexpr ByteCount operator"" _byte(unsigned long long int value)
{
    return ByteCount(value);
}

struct CharCount : public StronglyTypedNumber<CharCount, int>
{
    [[gnu::always_inline]]
    constexpr CharCount(int value = 0) : StronglyTypedNumber<CharCount>(value) {}
};

[[gnu::always_inline]]
inline constexpr CharCount operator"" _char(unsigned long long int value)
{
    return CharCount(value);
}

}

#endif // units_hh_INCLUDED
<|endoftext|>


<commit_before>/**
* Released under the same permissive MIT-license as Urho3D.
* https://raw.githubusercontent.com/urho3d/Urho3D/master/License.txt
*/

#include <string>

#include <Urho3D/Urho3D.h>
#include <Urho3D/Core/CoreEvents.h>
#include <Urho3D/Engine/Application.h>
#include <Urho3D/Engine/Engine.h>
#include <Urho3D/Input/Input.h>
#include <Urho3D/Input/InputEvents.h>
#include <Urho3D/Resource/ResourceCache.h>
#include <Urho3D/Resource/XMLFile.h>
#include <Urho3D/IO/Log.h>
#include <Urho3D/UI/UI.h>
#include <Urho3D/UI/Text.h>
#include <Urho3D/UI/Font.h>
#include <Urho3D/UI/Button.h>
#include <Urho3D/UI/UIEvents.h>
#include <Urho3D/Scene/Scene.h>
#include <Urho3D/Scene/SceneEvents.h>
#include <Urho3D/Graphics/Graphics.h>
#include <Urho3D/Graphics/Camera.h>
#include <Urho3D/Graphics/Geometry.h>
#include <Urho3D/Graphics/Renderer.h>
#include <Urho3D/Graphics/DebugRenderer.h>
#include <Urho3D/Graphics/Octree.h>
#include <Urho3D/Graphics/Light.h>
#include <Urho3D/Graphics/Model.h>
#include <Urho3D/Graphics/StaticModel.h>
#include <Urho3D/Graphics/Material.h>
#include <Urho3D/Graphics/Skybox.h>

using namespace Urho3D;

class MyApp : public Application
{
public:
    int framecount_;
    float time_;
    SharedPtr<Text> text_;
    SharedPtr<Scene> scene_;
    SharedPtr<Node> boxNode_;
    Node* cameraNode_;

    MyApp(Context * context) : Application(context),framecount_(0),time_(0)
    {
    }

    virtual void Setup()
    {
        engineParameters_["FullScreen"]=false;
        engineParameters_["WindowWidth"]=1280;
        engineParameters_["WindowHeight"]=720;
        engineParameters_["WindowResizable"]=true;
    }

    virtual void Start()
    {
        ResourceCache* cache=GetSubsystem<ResourceCache>();

        GetSubsystem<Input>()->SetMouseVisible(true);
        GetSubsystem<Input>()->SetMouseGrabbed(false);

        GetSubsystem<UI>()->GetRoot()->SetDefaultStyle(cache->GetResource<XMLFile>("UI/DefaultStyle.xml"));
        text_=new Text(context_);
        text_->SetText("Keys: tab = toggle mouse, AWSD = move camera, Shift = fast mode, Esc = quit.\nWait a bit to see FPS.");
        text_->SetFont(cache->GetResource<Font>("Fonts/Anonymous Pro.ttf"),20);
        text_->SetColor(Color(.3,0,.3));
        text_->SetHorizontalAlignment(HA_CENTER);
        text_->SetVerticalAlignment(VA_TOP);
        GetSubsystem<UI>()->GetRoot()->AddChild(text_);
        Button* button=new Button(context_);
        GetSubsystem<UI>()->GetRoot()->AddChild(button);
        button->SetName("Button Quit");
        button->SetStyle("Button");
        button->SetSize(32,32);
        button->SetPosition(16,16);

        GetSubsystem<Input>()->SetMouseVisible(false);
        GetSubsystem<Input>()->SetMouseGrabbed(true);

        scene_=new Scene(context_);
        scene_->CreateComponent<Octree>();
        scene_->CreateComponent<DebugRenderer>();

        Node* skyNode=scene_->CreateChild("Sky");
        skyNode->SetScale(500.0f); // The scale actually does not matter
        Skybox* skybox=skyNode->CreateComponent<Skybox>();
        skybox->SetModel(cache->GetResource<Model>("Models/Box.mdl"));
        skybox->SetMaterial(cache->GetResource<Material>("Materials/Skybox.xml"));

        boxNode_=scene_->CreateChild("Box");
        boxNode_->SetPosition(Vector3(0,0,5));
        StaticModel* boxObject=boxNode_->CreateComponent<StaticModel>();
        boxObject->SetModel(cache->GetResource<Model>("Models/Box.mdl"));
        boxObject->SetMaterial(cache->GetResource<Material>("Materials/Stone.xml"));

        for(int x=-30;x<30;x+=3)
            for(int y=-30;y<30;y+=3)
            {
                Node* boxNode_=scene_->CreateChild("Box");
                boxNode_->SetPosition(Vector3(x,-3,y));
                StaticModel* boxObject=boxNode_->CreateComponent<StaticModel>();
                boxObject->SetModel(cache->GetResource<Model>("Models/Box.mdl"));
                boxObject->SetMaterial(cache->GetResource<Material>("Materials/Stone.xml"));
                boxObject->SetCastShadows(true);
            }

        cameraNode_=scene_->CreateChild("Camera");
        Camera* camera=cameraNode_->CreateComponent<Camera>();
        camera->SetFarClip(2000);

        {
            Node* lightNode=scene_->CreateChild("Light");
            lightNode->SetPosition(Vector3(-5,10,5));
            Light* light=lightNode->CreateComponent<Light>();
            light->SetLightType(LIGHT_POINT);
            light->SetRange(50);
            light->SetBrightness(1.2);
            light->SetColor(Color(1,.5,.8,1));
        }
        {
            Node* lightNode=scene_->CreateChild("Light");
            lightNode->SetPosition(Vector3(5,-3,5));
            Light* light=lightNode->CreateComponent<Light>();
            light->SetLightType(LIGHT_POINT);
            light->SetRange(50);
            light->SetBrightness(1.2);
            light->SetColor(Color(.5,.8,1,1));
        }
        {
            Light* light=cameraNode_->CreateComponent<Light>();
            light->SetLightType(LIGHT_POINT);
            light->SetRange(10);
            light->SetBrightness(2.0);
            light->SetColor(Color(.8,1,.8,1.0));
        }

        Renderer* renderer=GetSubsystem<Renderer>();
        SharedPtr<Viewport> viewport(new Viewport(context_,scene_,cameraNode_->GetComponent<Camera>()));
        renderer->SetViewport(0,viewport);

        SubscribeToEvent(E_BEGINFRAME,HANDLER(MyApp,HandleBeginFrame));
        SubscribeToEvent(E_KEYDOWN,HANDLER(MyApp,HandleKeyDown));
        SubscribeToEvent(E_UIMOUSECLICK,HANDLER(MyApp,HandleControlClicked));
        SubscribeToEvent(E_UPDATE,HANDLER(MyApp,HandleUpdate));
        SubscribeToEvent(E_POSTUPDATE,HANDLER(MyApp,HandlePostUpdate));
        SubscribeToEvent(E_RENDERUPDATE,HANDLER(MyApp,HandleRenderUpdate));
        SubscribeToEvent(E_POSTRENDERUPDATE,HANDLER(MyApp,HandlePostRenderUpdate));
        SubscribeToEvent(E_ENDFRAME,HANDLER(MyApp,HandleEndFrame));
    }
    virtual void Stop()
    {
    }

    void HandleKeyDown(StringHash eventType,VariantMap& eventData)
    {
        using namespace KeyDown;
        int key=eventData[P_KEY].GetInt();
        if(key==KEY_ESC)
            engine_->Exit();

        if(key==KEY_TAB)
        {
            GetSubsystem<Input>()->SetMouseVisible(!GetSubsystem<Input>()->IsMouseVisible());
            GetSubsystem<Input>()->SetMouseGrabbed(!GetSubsystem<Input>()->IsMouseGrabbed());
        }
    }

    void HandleControlClicked(StringHash eventType,VariantMap& eventData)
    {
        // Query the clicked UI element.
        UIElement* clicked=static_cast<UIElement*>(eventData[UIMouseClick::P_ELEMENT].GetPtr());
        if(clicked)
            if(clicked->GetName()=="Button Quit")   // check if the quit button was clicked
                engine_->Exit();
    }

    void HandleUpdate(StringHash eventType,VariantMap& eventData)
    {
        float timeStep=eventData[Update::P_TIMESTEP].GetFloat();
        framecount_++;
        time_+=timeStep;
        // Movement speed as world units per second
        float MOVE_SPEED=10.0f;
        // Mouse sensitivity as degrees per pixel
        const float MOUSE_SENSITIVITY=0.1f;

        if(time_ >=1)
        {
            std::string str;
            str.append("Keys: tab = toggle mouse, AWSD = move camera, Shift = fast mode, Esc = quit.\n");
            str.append(std::to_string(framecount_));
            str.append(" frames in ");
            str.append(std::to_string(time_));
            str.append(" seconds = ");
            str.append(std::to_string((float)framecount_ / time_));
            str.append(" fps");
            String s(str.c_str(),str.size());
            text_->SetText(s);
            framecount_=0;
            time_=0;
        }

        // Rotate the box thingy.
        // A much nicer way of doing this would be with a LogicComponent.
        // With LogicComponents it is easy to control things like movement
        // and animation from some IDE, console or just in game.
        // Alas, it is out of the scope for our simple example.
        boxNode_->Rotate(Quaternion(8*timeStep,16*timeStep,0));

        Input* input=GetSubsystem<Input>();
        if(input->GetQualifierDown(1))  // 1 is shift, 2 is ctrl, 4 is alt
            MOVE_SPEED*=10;
        if(input->GetKeyDown('W'))
            cameraNode_->Translate(Vector3(0,0, 1)*MOVE_SPEED*timeStep);
        if(input->GetKeyDown('S'))
            cameraNode_->Translate(Vector3(0,0,-1)*MOVE_SPEED*timeStep);
        if(input->GetKeyDown('A'))
            cameraNode_->Translate(Vector3(-1,0,0)*MOVE_SPEED*timeStep);
        if(input->GetKeyDown('D'))
            cameraNode_->Translate(Vector3( 1,0,0)*MOVE_SPEED*timeStep);

        if(!GetSubsystem<Input>()->IsMouseVisible())
        {
            // Use this frame's mouse motion to adjust camera node yaw and pitch. Clamp the pitch between -90 and 90 degrees
            IntVector2 mouseMove=input->GetMouseMove();
            // avoid the weird extrem values before moving the mouse
            if(mouseMove.x_>-2000000000&&mouseMove.y_>-2000000000)
            {
                static float yaw_=0;
                static float pitch_=0;
                yaw_+=MOUSE_SENSITIVITY*mouseMove.x_;
                pitch_+=MOUSE_SENSITIVITY*mouseMove.y_;
                pitch_=Clamp(pitch_,-90.0f,90.0f);
                // Reset rotation and set yaw and pitch again
                cameraNode_->SetDirection(Vector3::FORWARD);
                cameraNode_->Yaw(yaw_);
                cameraNode_->Pitch(pitch_);
            }
        }
    }

    void HandleBeginFrame(StringHash eventType,VariantMap& eventData)
    {
    }
    void HandlePostUpdate(StringHash eventType,VariantMap& eventData)
    {
    }
    void HandleRenderUpdate(StringHash eventType, VariantMap & eventData)
    {
    }
    void HandlePostRenderUpdate(StringHash eventType, VariantMap & eventData)
    {
    }
    void HandleEndFrame(StringHash eventType,VariantMap& eventData)
    {
    }
};

/**
* This macro is expaneded to (roughly, depending on OS) this:
*
* > int RunApplication()
* > {
* > Urho3D::SharedPtr<Urho3D::Context> context(new Urho3D::Context());
* > Urho3D::SharedPtr<className> application(new className(context));
* > return application->Run();
* > }
* >
* > int main(int argc, char** argv)
* > {
* > Urho3D::ParseArguments(argc, argv);
* > return function;
* > }
*/
DEFINE_APPLICATION_MAIN(MyApp)
<commit_msg>...missed a comment<commit_after>/**
* Released under the same permissive MIT-license as Urho3D.
* https://raw.githubusercontent.com/urho3d/Urho3D/master/License.txt
*/

#include <string>

#include <Urho3D/Urho3D.h>
#include <Urho3D/Core/CoreEvents.h>
#include <Urho3D/Engine/Application.h>
#include <Urho3D/Engine/Engine.h>
#include <Urho3D/Input/Input.h>
#include <Urho3D/Input/InputEvents.h>
#include <Urho3D/Resource/ResourceCache.h>
#include <Urho3D/Resource/XMLFile.h>
#include <Urho3D/IO/Log.h>
#include <Urho3D/UI/UI.h>
#include <Urho3D/UI/Text.h>
#include <Urho3D/UI/Font.h>
#include <Urho3D/UI/Button.h>
#include <Urho3D/UI/UIEvents.h>
#include <Urho3D/Scene/Scene.h>
#include <Urho3D/Scene/SceneEvents.h>
#include <Urho3D/Graphics/Graphics.h>
#include <Urho3D/Graphics/Camera.h>
#include <Urho3D/Graphics/Geometry.h>
#include <Urho3D/Graphics/Renderer.h>
#include <Urho3D/Graphics/DebugRenderer.h>
#include <Urho3D/Graphics/Octree.h>
#include <Urho3D/Graphics/Light.h>
#include <Urho3D/Graphics/Model.h>
#include <Urho3D/Graphics/StaticModel.h>
#include <Urho3D/Graphics/Material.h>
#include <Urho3D/Graphics/Skybox.h>

using namespace Urho3D;

class MyApp : public Application
{
public:
    int framecount_;
    float time_;
    SharedPtr<Text> text_;
    SharedPtr<Scene> scene_;
    SharedPtr<Node> boxNode_;
    Node* cameraNode_;

    MyApp(Context * context) : Application(context),framecount_(0),time_(0)
    {
    }

    virtual void Setup()
    {
        engineParameters_["FullScreen"]=false;
        engineParameters_["WindowWidth"]=1280;
        engineParameters_["WindowHeight"]=720;
        engineParameters_["WindowResizable"]=true;
    }

    virtual void Start()
    {
        ResourceCache* cache=GetSubsystem<ResourceCache>();

        GetSubsystem<Input>()->SetMouseVisible(true);
        GetSubsystem<Input>()->SetMouseGrabbed(false);

        GetSubsystem<UI>()->GetRoot()->SetDefaultStyle(cache->GetResource<XMLFile>("UI/DefaultStyle.xml"));
        text_=new Text(context_);
        text_->SetText("Keys: tab = toggle mouse, AWSD = move camera, Shift = fast mode, Esc = quit.\nWait a bit to see FPS.");
        text_->SetFont(cache->GetResource<Font>("Fonts/Anonymous Pro.ttf"),20);
        text_->SetColor(Color(.3,0,.3));
        text_->SetHorizontalAlignment(HA_CENTER);
        text_->SetVerticalAlignment(VA_TOP);
        GetSubsystem<UI>()->GetRoot()->AddChild(text_);
        Button* button=new Button(context_);
        GetSubsystem<UI>()->GetRoot()->AddChild(button);
        button->SetName("Button Quit");
        button->SetStyle("Button");
        button->SetSize(32,32);
        button->SetPosition(16,16);

        GetSubsystem<Input>()->SetMouseVisible(false);
        GetSubsystem<Input>()->SetMouseGrabbed(true);

        scene_=new Scene(context_);
        scene_->CreateComponent<Octree>();
        scene_->CreateComponent<DebugRenderer>();

        Node* skyNode=scene_->CreateChild("Sky");
        skyNode->SetScale(500.0f); // The scale actually does not matter
        Skybox* skybox=skyNode->CreateComponent<Skybox>();
        skybox->SetModel(cache->GetResource<Model>("Models/Box.mdl"));
        skybox->SetMaterial(cache->GetResource<Material>("Materials/Skybox.xml"));

        boxNode_=scene_->CreateChild("Box");
        boxNode_->SetPosition(Vector3(0,0,5));
        StaticModel* boxObject=boxNode_->CreateComponent<StaticModel>();
        boxObject->SetModel(cache->GetResource<Model>("Models/Box.mdl"));
        boxObject->SetMaterial(cache->GetResource<Material>("Materials/Stone.xml"));

        for(int x=-30;x<30;x+=3)
            for(int y=-30;y<30;y+=3)
            {
                Node* boxNode_=scene_->CreateChild("Box");
                boxNode_->SetPosition(Vector3(x,-3,y));
                StaticModel* boxObject=boxNode_->CreateComponent<StaticModel>();
                boxObject->SetModel(cache->GetResource<Model>("Models/Box.mdl"));
                boxObject->SetMaterial(cache->GetResource<Material>("Materials/Stone.xml"));
                boxObject->SetCastShadows(true);
            }

        cameraNode_=scene_->CreateChild("Camera");
        Camera* camera=cameraNode_->CreateComponent<Camera>();
        camera->SetFarClip(2000);

        {
            Node* lightNode=scene_->CreateChild("Light");
            lightNode->SetPosition(Vector3(-5,10,5));
            Light* light=lightNode->CreateComponent<Light>();
            light->SetLightType(LIGHT_POINT);
            light->SetRange(50);
            light->SetBrightness(1.2);
            light->SetColor(Color(1,.5,.8,1));
        }
        {
            Node* lightNode=scene_->CreateChild("Light");
            lightNode->SetPosition(Vector3(5,-3,5));
            Light* light=lightNode->CreateComponent<Light>();
            light->SetLightType(LIGHT_POINT);
            light->SetRange(50);
            light->SetBrightness(1.2);
            light->SetColor(Color(.5,.8,1,1));
        }
        {
            Light* light=cameraNode_->CreateComponent<Light>();
            light->SetLightType(LIGHT_POINT);
            light->SetRange(10);
            light->SetBrightness(2.0);
            light->SetColor(Color(.8,1,.8,1.0));
        }

        Renderer* renderer=GetSubsystem<Renderer>();
        SharedPtr<Viewport> viewport(new Viewport(context_,scene_,cameraNode_->GetComponent<Camera>()));
        renderer->SetViewport(0,viewport);

        SubscribeToEvent(E_BEGINFRAME,HANDLER(MyApp,HandleBeginFrame));
        SubscribeToEvent(E_KEYDOWN,HANDLER(MyApp,HandleKeyDown));
        SubscribeToEvent(E_UIMOUSECLICK,HANDLER(MyApp,HandleControlClicked));
        SubscribeToEvent(E_UPDATE,HANDLER(MyApp,HandleUpdate));
        SubscribeToEvent(E_POSTUPDATE,HANDLER(MyApp,HandlePostUpdate));
        SubscribeToEvent(E_RENDERUPDATE,HANDLER(MyApp,HandleRenderUpdate));
        SubscribeToEvent(E_POSTRENDERUPDATE,HANDLER(MyApp,HandlePostRenderUpdate));
        SubscribeToEvent(E_ENDFRAME,HANDLER(MyApp,HandleEndFrame));
    }
    virtual void Stop()
    {
    }

    void HandleKeyDown(StringHash eventType,VariantMap& eventData)
    {
        using namespace KeyDown;
        int key=eventData[P_KEY].GetInt();
        if(key==KEY_ESC)
            engine_->Exit();

        if(key==KEY_TAB)
        {
            GetSubsystem<Input>()->SetMouseVisible(!GetSubsystem<Input>()->IsMouseVisible());
            GetSubsystem<Input>()->SetMouseGrabbed(!GetSubsystem<Input>()->IsMouseGrabbed());
        }
    }

    void HandleControlClicked(StringHash eventType,VariantMap& eventData)
    {
        // Query the clicked UI element.
        UIElement* clicked=static_cast<UIElement*>(eventData[UIMouseClick::P_ELEMENT].GetPtr());
        if(clicked)
            if(clicked->GetName()=="Button Quit")   // check if the quit button was clicked
                engine_->Exit();
    }

    void HandleUpdate(StringHash eventType,VariantMap& eventData)
    {
        float timeStep=eventData[Update::P_TIMESTEP].GetFloat();
        framecount_++;
        time_+=timeStep;
        // Movement speed as world units per second
        float MOVE_SPEED=10.0f;
        // Mouse sensitivity as degrees per pixel
        const float MOUSE_SENSITIVITY=0.1f;

        if(time_ >=1)
        {
            std::string str;
            str.append("Keys: tab = toggle mouse, AWSD = move camera, Shift = fast mode, Esc = quit.\n");
            str.append(std::to_string(framecount_));
            str.append(" frames in ");
            str.append(std::to_string(time_));
            str.append(" seconds = ");
            str.append(std::to_string((float)framecount_ / time_));
            str.append(" fps");
            String s(str.c_str(),str.size());
            text_->SetText(s);
            framecount_=0;
            time_=0;
        }

        // Rotate the box thingy.
        // A much nicer way of doing this would be with a LogicComponent.
        // With LogicComponents it is easy to control things like movement
        // and animation from some IDE, console or just in game.
        // Alas, it is out of the scope for our simple example.
        boxNode_->Rotate(Quaternion(8*timeStep,16*timeStep,0));

        Input* input=GetSubsystem<Input>();
        if(input->GetQualifierDown(1))  // 1 is shift, 2 is ctrl, 4 is alt
            MOVE_SPEED*=10;
        if(input->GetKeyDown('W'))
            cameraNode_->Translate(Vector3(0,0, 1)*MOVE_SPEED*timeStep);
        if(input->GetKeyDown('S'))
            cameraNode_->Translate(Vector3(0,0,-1)*MOVE_SPEED*timeStep);
        if(input->GetKeyDown('A'))
            cameraNode_->Translate(Vector3(-1,0,0)*MOVE_SPEED*timeStep);
        if(input->GetKeyDown('D'))
            cameraNode_->Translate(Vector3( 1,0,0)*MOVE_SPEED*timeStep);

        if(!GetSubsystem<Input>()->IsMouseVisible())
        {
            // Use this frame's mouse motion to adjust camera node yaw and pitch. Clamp the pitch between -90 and 90 degrees
            IntVector2 mouseMove=input->GetMouseMove();
            // avoid the weird extrem values before moving the mouse
            if(mouseMove.x_>-2000000000&&mouseMove.y_>-2000000000)
            {
                static float yaw_=0;
                static float pitch_=0;
                yaw_+=MOUSE_SENSITIVITY*mouseMove.x_;
                pitch_+=MOUSE_SENSITIVITY*mouseMove.y_;
                pitch_=Clamp(pitch_,-90.0f,90.0f);
                // Reset rotation and set yaw and pitch again
                cameraNode_->SetDirection(Vector3::FORWARD);
                cameraNode_->Yaw(yaw_);
                cameraNode_->Pitch(pitch_);
            }
        }
    }

    void HandleBeginFrame(StringHash eventType,VariantMap& eventData)
    {
    }
    void HandlePostUpdate(StringHash eventType,VariantMap& eventData)
    {
    }
    void HandleRenderUpdate(StringHash eventType, VariantMap & eventData)
    {
    }
    void HandlePostRenderUpdate(StringHash eventType, VariantMap & eventData)
    {
    }
    void HandleEndFrame(StringHash eventType,VariantMap& eventData)
    {
    }
};

DEFINE_APPLICATION_MAIN(MyApp)
<|endoftext|>


<commit_before>/***

Copyright 2013-2016 Dave Cridland
Copyright 2014-2016 Surevine Ltd

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.

***/

#include <string>
#include <config.h>
#include <unistd.h>
#include <iostream>
#include <string.h>
#include <log.h>
#include <signal.h>
#include <fstream>
#include <router.h>
#define UNW_LOCAL_ONLY
#include <libunwind.h>

namespace {
    class BootConfig {
    public:
        std::string config_file = "./metre.conf.xml";
        std::string boot_method = "";

        BootConfig(int argc, char *argv[]) {
            for (int i = 1; argv[i]; ++i) {
                char opt;
                switch (argv[i][0]) {
                    case '-':
                    case '/':
                        opt = argv[i][1];
                        break;
                    default:
                        std::cerr << "Don't understand commandline arg " << argv[i] << std::endl;
                        exit(2);
                }
                ++i;
                if (!argv[i]) {
                    std::cerr << "Missing argument for option '" << opt << "'" << std::endl;
                    exit(2);
                }
                switch (opt) {
                    case 'c':
                        config_file = argv[i];
                        break;
                    case 'd':
                        boot_method = argv[i];
                        break;
                    default:
                        std::cerr << "Unknown switch " << opt << std::endl;
                        exit(2);
                }
            }
        }
    };

    std::unique_ptr<BootConfig> bc;
    std::unique_ptr<Metre::Config> config;

    void hup_handler(int) {
        //config.reset(new Metre::Config(bc->config_file));
        //Metre::Router::reload();
        METRE_LOG(Metre::Log::INFO, "NOT Reloading config.");
    }

    void term_handler(int) {
        METRE_LOG(Metre::Log::INFO, "Shutdown received.");
        Metre::Router::quit();
    }

    void terminate_handler() {
        unw_cursor_t cursor;
        unw_context_t uc;

        unw_getcontext(&uc);
        unw_init_local(&cursor, &uc);
        auto eptr = std::current_exception();
        if (eptr) {
            try {
                std::rethrow_exception(eptr);
            } catch(const std::runtime_error & e) {
                std::cerr << "Uncaught runtime_error: " << e.what() << std::endl;
            } catch(const std::exception & e) {
                std::cerr << "Uncaught exception: " << e.what() << std::endl;
            } catch(...) {
                std::cerr << "Unknown exception caught" << std::endl;
            }
        } else {
            std::cerr << "std::terminate called with no exception" << std::endl;
        }
        while (unw_step(&cursor) > 0) {
            unw_word_t ip;
            unw_word_t sp;
            unw_get_reg(&cursor, UNW_REG_IP, &ip);
            unw_get_reg(&cursor, UNW_REG_SP, &sp);
            std::array<char, 1024> buffer;
            unw_word_t offset;
            unw_get_proc_name(&cursor, buffer.data(), buffer.size(), &offset);
            std::string proc_name(buffer.data());
            std::cerr << "ip = " << std::ios::hex << ip << ", sp = " << sp << ", " << proc_name << "+" << offset << std::ios::dec << std::endl;
        }
        std::abort();
    }
}

int main(int argc, char *argv[]) {
    try {
        // Firstly, load up the configuration.
        std::set_terminate(terminate_handler);
        bc = std::make_unique<BootConfig>(argc, argv);
        config = std::make_unique<Metre::Config>(bc->config_file);
        if (bc->boot_method.empty()) {
            bc->boot_method = config->boot_method();
        }
    } catch (std::runtime_error &e) {
        std::cout << "Error while loading config: " << e.what() << std::endl;
        return 1;
    }
    try {
        if (bc->boot_method == "sysv") {
            pid_t child = fork();
            if (child == -1) {
                std::cerr << "Fork failed: " << strerror(errno) << std::endl;
                exit(1);
            }
            if (child != 0) {
                // This is the parent; we exit here.
                return 0;
            }
            // We are the new child. Close fds, session, etc.
            close(0);
            close(1);
            close(2);
            config->log_init();
            config->write_runtime_config();
            if (-1 == setsid()) {
                METRE_LOG(Metre::Log::CRIT, "setsid() failed with " << strerror(errno));
            }
            // Now fork again. Like we did last summer.
            child = fork();
            if (child == -1) {
                METRE_LOG(Metre::Log::CRIT, "fork(2) failed with " << strerror(errno));
                exit(1);
            }
            if (child != 0) {
                std::ofstream pidfile(config->pidfile(), std::ios_base::trunc);
                pidfile << child << std::endl;
                return 0;
            }
            chdir(config->runtime_dir().c_str());
            signal(SIGPIPE, SIG_IGN);
            signal(SIGHUP, hup_handler);
            signal(SIGTERM, term_handler);
            Metre::Router::main([]() { return false; });
        } else if (bc->boot_method == "none") {
            config->log_init(true);
            config->write_runtime_config();
            signal(SIGPIPE, SIG_IGN);
            signal(SIGHUP, hup_handler);
            signal(SIGTERM, term_handler);
            signal(SIGINT, term_handler);
            Metre::Router::main([]() { return false; });
        } else if (bc->boot_method == "docker") {
            config->docker_setup();
            config->write_runtime_config();
            signal(SIGPIPE, SIG_IGN);
            signal(SIGHUP, hup_handler);
            signal(SIGTERM, term_handler);
            signal(SIGINT, term_handler);
            Metre::Router::main([]() { return false; });
        } else if (bc->boot_method == "systemd") {
            config->log_init(true);
            config->write_runtime_config();
            signal(SIGPIPE, SIG_IGN);
            signal(SIGHUP, hup_handler);
            signal(SIGTERM, term_handler);
            Metre::Router::main([]() { return false; });
        } else {
            std::cerr << "I don't know what " << bc->boot_method << " means." << std::endl;
            return 1;
        }
    } catch (std::runtime_error const &e) {
        std::cerr << "Error while loading config: " << e.what() << std::endl;
        return 2;
    }
    config.reset(nullptr);
    bc.reset(nullptr);
    return 0;
}

<commit_msg>Handle SEGV/BUS signals<commit_after>/***

Copyright 2013-2016 Dave Cridland
Copyright 2014-2016 Surevine Ltd

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.

***/

#include <string>
#include <config.h>
#include <unistd.h>
#include <iostream>
#include <string.h>
#include <log.h>
#include <signal.h>
#include <fstream>
#include <router.h>
#define UNW_LOCAL_ONLY
#include <libunwind.h>

namespace {
    class BootConfig {
    public:
        std::string config_file = "./metre.conf.xml";
        std::string boot_method = "";

        BootConfig(int argc, char *argv[]) {
            for (int i = 1; argv[i]; ++i) {
                char opt;
                switch (argv[i][0]) {
                    case '-':
                    case '/':
                        opt = argv[i][1];
                        break;
                    default:
                        std::cerr << "Don't understand commandline arg " << argv[i] << std::endl;
                        exit(2);
                }
                ++i;
                if (!argv[i]) {
                    std::cerr << "Missing argument for option '" << opt << "'" << std::endl;
                    exit(2);
                }
                switch (opt) {
                    case 'c':
                        config_file = argv[i];
                        break;
                    case 'd':
                        boot_method = argv[i];
                        break;
                    default:
                        std::cerr << "Unknown switch " << opt << std::endl;
                        exit(2);
                }
            }
        }
    };

    std::unique_ptr<BootConfig> bc;
    std::unique_ptr<Metre::Config> config;

    void hup_handler(int) {
        //config.reset(new Metre::Config(bc->config_file));
        //Metre::Router::reload();
        METRE_LOG(Metre::Log::INFO, "NOT Reloading config.");
    }

    void term_handler(int) {
        METRE_LOG(Metre::Log::INFO, "Shutdown received.");
        Metre::Router::quit();
    }

    void terminate_handler() {
        unw_cursor_t cursor;
        unw_context_t uc;

        unw_getcontext(&uc);
        unw_init_local(&cursor, &uc);
        auto eptr = std::current_exception();
        if (eptr) {
            try {
                std::rethrow_exception(eptr);
            } catch(const std::runtime_error & e) {
                std::cerr << "Uncaught runtime_error: " << e.what() << std::endl;
            } catch(const std::exception & e) {
                std::cerr << "Uncaught exception: " << e.what() << std::endl;
            } catch(...) {
                std::cerr << "Unknown exception caught" << std::endl;
            }
        } else {
            std::cerr << "std::terminate called with no exception" << std::endl;
        }
        while (unw_step(&cursor) > 0) {
            unw_word_t ip;
            unw_word_t sp;
            unw_get_reg(&cursor, UNW_REG_IP, &ip);
            unw_get_reg(&cursor, UNW_REG_SP, &sp);
            std::array<char, 1024> buffer;
            unw_word_t offset;
            unw_get_proc_name(&cursor, buffer.data(), buffer.size(), &offset);
            std::string proc_name(buffer.data());
            std::cerr << "ip = " << std::ios::hex << ip << ", sp = " << sp << ", " << proc_name << "+" << offset << std::ios::dec << std::endl;
        }
        std::abort();
    }

    void segv_handler(int s) {
        METRE_LOG(Metre::Log::INFO, "Fatal signal " << s);
        terminate_handler();
    }
}

int main(int argc, char *argv[]) {
    try {
        // Firstly, load up the configuration.
        std::set_terminate(terminate_handler);
        bc = std::make_unique<BootConfig>(argc, argv);
        config = std::make_unique<Metre::Config>(bc->config_file);
        if (bc->boot_method.empty()) {
            bc->boot_method = config->boot_method();
        }
    } catch (std::runtime_error &e) {
        std::cout << "Error while loading config: " << e.what() << std::endl;
        return 1;
    }
    try {
        if (bc->boot_method == "sysv") {
            pid_t child = fork();
            if (child == -1) {
                std::cerr << "Fork failed: " << strerror(errno) << std::endl;
                exit(1);
            }
            if (child != 0) {
                // This is the parent; we exit here.
                return 0;
            }
            // We are the new child. Close fds, session, etc.
            close(0);
            close(1);
            close(2);
            config->log_init();
            config->write_runtime_config();
            if (-1 == setsid()) {
                METRE_LOG(Metre::Log::CRIT, "setsid() failed with " << strerror(errno));
            }
            // Now fork again. Like we did last summer.
            child = fork();
            if (child == -1) {
                METRE_LOG(Metre::Log::CRIT, "fork(2) failed with " << strerror(errno));
                exit(1);
            }
            if (child != 0) {
                std::ofstream pidfile(config->pidfile(), std::ios_base::trunc);
                pidfile << child << std::endl;
                return 0;
            }
            chdir(config->runtime_dir().c_str());
            signal(SIGPIPE, SIG_IGN);
            signal(SIGHUP, hup_handler);
            signal(SIGTERM, term_handler);
            signal(SIGSEGV, segv_handler);
            signal(SIGBUS, segv_handler);
            Metre::Router::main([]() { return false; });
        } else if (bc->boot_method == "none") {
            config->log_init(true);
            config->write_runtime_config();
            signal(SIGPIPE, SIG_IGN);
            signal(SIGHUP, hup_handler);
            signal(SIGTERM, term_handler);
            signal(SIGINT, term_handler);
            signal(SIGSEGV, segv_handler);
            signal(SIGBUS, segv_handler);
            Metre::Router::main([]() { return false; });
        } else if (bc->boot_method == "docker") {
            config->docker_setup();
            config->write_runtime_config();
            signal(SIGPIPE, SIG_IGN);
            signal(SIGHUP, hup_handler);
            signal(SIGTERM, term_handler);
            signal(SIGINT, term_handler);
            signal(SIGSEGV, segv_handler);
            signal(SIGBUS, segv_handler);
            Metre::Router::main([]() { return false; });
        } else if (bc->boot_method == "systemd") {
            config->log_init(true);
            config->write_runtime_config();
            signal(SIGPIPE, SIG_IGN);
            signal(SIGHUP, hup_handler);
            signal(SIGTERM, term_handler);
            signal(SIGSEGV, segv_handler);
            signal(SIGBUS, segv_handler);
            Metre::Router::main([]() { return false; });
        } else {
            std::cerr << "I don't know what " << bc->boot_method << " means." << std::endl;
            return 1;
        }
    } catch (std::runtime_error const &e) {
        std::cerr << "Error while loading config: " << e.what() << std::endl;
        return 2;
    }
    config.reset(nullptr);
    bc.reset(nullptr);
    return 0;
}

<|endoftext|>