<commit_before>/*
 * Copyright 2007-2021 CM4all GmbH
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "HTML.hxx"
#include "Class.hxx"
#include "util/CharUtil.hxx"
#include "util/StringView.hxx"

#include <assert.h>
#include <string.h>

[[gnu::pure]]
static const char *
html_unescape_find(StringView p) noexcept
{
	return p.Find('&');
}

[[gnu::pure]]
static const char *
find_semicolon(const char *p, const char *end) noexcept
{
	while (p < end) {
		if (*p == ';')
			return p;
		else if (!IsAlphaASCII(*p))
			break;

		++p;
	}

	return nullptr;
}

static size_t
html_unescape(StringView _p, char *q) noexcept
{
	const char *p = _p.begin(), *const p_end = _p.end(), *const q_start = q;

	const char *amp;
	while ((amp = (const char *)memchr(p, '&', p_end - p)) != nullptr) {
		memmove(q, p, amp - p);
		q += amp - p;

		StringView entity;
		entity.data = amp + 1;

		const char *semicolon = find_semicolon(entity.data, p_end);
		if (semicolon == nullptr) {
			*q++ = '&';
			p = amp + 1;
			continue;
		}

		entity.size = semicolon - entity.data;

		if (entity.Equals("amp"))
			*q++ = '&';
		else if (entity.Equals("quot"))
			*q++ = '"';
		else if (entity.Equals("lt"))
			*q++ = '<';
		else if (entity.Equals("gt"))
			*q++ = '>';
		else if (entity.Equals("apos"))
			*q++ = '\'';

		p = semicolon + 1;
	}

	memmove(q, p, p_end - p);
	q += p_end - p;

	return q - q_start;
}

static size_t
html_escape_size(StringView _p) noexcept
{
	const char *p = _p.begin(), *const end = _p.end();

	size_t size = 0;
	while (p < end) {
		switch (*p++) {
		case '&':
			size += 5;
			break;

		case '"':
		case '\'':
			size += 6;
			break;

		case '<':
		case '>':
			size += 4;
			break;

		default:
			++size;
		}
	}

	return size;
}

static const char *
html_escape_find(StringView _p) noexcept
{
	const char *p = _p.begin(), *const end = _p.end();

	while (p < end) {
		switch (*p) {
		case '&':
		case '"':
		case '\'':
		case '<':
		case '>':
			return p;

		default:
			++p;
		}
	}

	return nullptr;
}

static StringView
html_escape_char(char ch) noexcept
{
	switch (ch) {
	case '&':
		return "&";

	case '"':
		return """;

	case '\'':
		return "'";

	case '<':
		return "<";

	case '>':
		return ">";

	default:
		assert(false);
		return nullptr;
	}
}

static size_t
html_escape(StringView _p, char *q) noexcept
{
	const char *p = _p.begin(), *const p_end = _p.end(), *const q_start = q;

	while (p < p_end) {
		char ch = *p++;
		switch (ch) {
		case '&':
			q = (char *)mempcpy(q, "&", 5);
			break;

		case '"':
			q = (char *)mempcpy(q, """, 6);
			break;

		case '\'':
			q = (char *)mempcpy(q, "'", 6);
			break;

		case '<':
			q = (char *)mempcpy(q, "<", 4);
			break;

		case '>':
			q = (char *)mempcpy(q, ">", 4);
			break;

		default:
			*q++ = ch;
		}
	}

	return q - q_start;
}

const struct escape_class html_escape_class = {
	html_unescape_find,
	html_unescape,
	html_escape_find,
	html_escape_char,
	html_escape_size,
	html_escape,
};
<commit_msg>escape/HTML: use StringView::Split()<commit_after>/*
 * Copyright 2007-2021 CM4all GmbH
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "HTML.hxx"
#include "Class.hxx"
#include "util/CharUtil.hxx"
#include "util/StringView.hxx"

#include <assert.h>
#include <string.h>

[[gnu::pure]]
static const char *
html_unescape_find(StringView p) noexcept
{
	return p.Find('&');
}

static size_t
html_unescape(StringView src, char *q) noexcept
{
	const char *const q_start = q;

	while (true) {
		const auto [before_ampersand, after_ampersand] = src.Split('&');

		memmove(q, before_ampersand.data, before_ampersand.size);
		q += before_ampersand.size;

		if (after_ampersand == nullptr)
			break;

		auto [entity, rest] = after_ampersand.Split(';');
		if (rest == nullptr) {
			*q++ = '&';
			src = after_ampersand;
			continue;
		}

		if (entity.Equals("amp"))
			*q++ = '&';
		else if (entity.Equals("quot"))
			*q++ = '"';
		else if (entity.Equals("lt"))
			*q++ = '<';
		else if (entity.Equals("gt"))
			*q++ = '>';
		else if (entity.Equals("apos"))
			*q++ = '\'';
		else {
			*q++ = '&';
			src = after_ampersand;
			continue;
		}

		src = rest;
	}

	return q - q_start;
}

static size_t
html_escape_size(StringView _p) noexcept
{
	const char *p = _p.begin(), *const end = _p.end();

	size_t size = 0;
	while (p < end) {
		switch (*p++) {
		case '&':
			size += 5;
			break;

		case '"':
		case '\'':
			size += 6;
			break;

		case '<':
		case '>':
			size += 4;
			break;

		default:
			++size;
		}
	}

	return size;
}

static const char *
html_escape_find(StringView _p) noexcept
{
	const char *p = _p.begin(), *const end = _p.end();

	while (p < end) {
		switch (*p) {
		case '&':
		case '"':
		case '\'':
		case '<':
		case '>':
			return p;

		default:
			++p;
		}
	}

	return nullptr;
}

static StringView
html_escape_char(char ch) noexcept
{
	switch (ch) {
	case '&':
		return "&";

	case '"':
		return """;

	case '\'':
		return "'";

	case '<':
		return "<";

	case '>':
		return ">";

	default:
		assert(false);
		return nullptr;
	}
}

static size_t
html_escape(StringView _p, char *q) noexcept
{
	const char *p = _p.begin(), *const p_end = _p.end(), *const q_start = q;

	while (p < p_end) {
		char ch = *p++;
		switch (ch) {
		case '&':
			q = (char *)mempcpy(q, "&", 5);
			break;

		case '"':
			q = (char *)mempcpy(q, """, 6);
			break;

		case '\'':
			q = (char *)mempcpy(q, "'", 6);
			break;

		case '<':
			q = (char *)mempcpy(q, "<", 4);
			break;

		case '>':
			q = (char *)mempcpy(q, ">", 4);
			break;

		default:
			*q++ = ch;
		}
	}

	return q - q_start;
}

const struct escape_class html_escape_class = {
	html_unescape_find,
	html_unescape,
	html_escape_find,
	html_escape_char,
	html_escape_size,
	html_escape,
};
<|endoftext|>


<commit_before>#include "virtualview.hpp"
#include "qglbuilder.h"
#include "qglscenenode.h"
#include "qglteapot.h"
#include "QGLAbstractScene.h"

void VirtualView::initializeGL(QGLPainter *painter)
{
    Q_UNUSED(painter);
    this->m_scene = QGLAbstractScene::loadScene(QLatin1String("../Go_GUI/models/example_board.3ds"));
	QGLSceneNode* scene_camera = this->m_scene->mainNode()->findChild<QGLSceneNode *>("Camera001");
	QString s = QString::number(scene_camera->position().y());

	this->camera()->setEye(QVector3D(50.0f, 0.0f, -80.0f));
	this->camera()->setUpVector(QVector3D(0.0f, 0.0f, -1.0f));
	this->camera()->setCenter(QVector3D(0.0f,0.0f,0.0f));

	QList<QGLSceneNode* > l = this->m_scene->mainNode()->allChildren();
	std::vector<QString> vstrings;
	for (QGLSceneNode* a : l)
		vstrings.push_back(a->objectName());
	QGLSceneNode* stone1 = this->m_scene->mainNode()->findChild<QGLSceneNode *>("Sphere001");

	QGLMaterial* m = new QGLMaterial();
	m->setColor(QColor(255,255,255));
	if (stone1){
		QString s = stone1->objectName();
		stone1->setMaterial(m);
	}
	if (m_scene)
         m_main = m_scene->mainNode();

	QQuaternion xt = QQuaternion::fromAxisAndAngle(1.0f, 0.0f, 0.0f, -90.0f);
    QQuaternion yt = QQuaternion::fromAxisAndAngle(0.0f, 1.0f, 0.0f, 30.0f);
	m_pose = yt * xt;
}

VirtualView::~VirtualView()
{
    delete m_scene;
}

void VirtualView::paintGL(QGLPainter *painter)
{
	painter->modelViewMatrix().rotate(m_pose);

	if (m_main)
		m_main->draw(painter);

}<commit_msg>added critical error when file not found<commit_after>#include "virtualview.hpp"
#include "qglbuilder.h"
#include "qglscenenode.h"
#include "qglteapot.h"
#include "QGLAbstractScene.h"
#include <QMessageBox>

#include <string>

void VirtualView::initializeGL(QGLPainter *painter)
{
    Q_UNUSED(painter);
    this->m_scene = QGLAbstractScene::loadScene(QLatin1String("../Go_GUI/models/example_board.3ds"));
	if (this->m_scene == NULL)
		QMessageBox::critical(this->parent, "file not found!", QString("The 3ds file of go-board was not found!"));
	QGLSceneNode* scene_camera = this->m_scene->mainNode()->findChild<QGLSceneNode *>("Camera001");
	QString s = QString::number(scene_camera->position().y());

	this->camera()->setEye(QVector3D(50.0f, 0.0f, -80.0f));
	this->camera()->setUpVector(QVector3D(0.0f, 0.0f, -1.0f));
	this->camera()->setCenter(QVector3D(0.0f,0.0f,0.0f));

	QList<QGLSceneNode* > l = this->m_scene->mainNode()->allChildren();
	std::vector<QString> vstrings;
	for (QGLSceneNode* a : l)
		vstrings.push_back(a->objectName());
	QGLSceneNode* stone1 = this->m_scene->mainNode()->findChild<QGLSceneNode *>("Sphere001");

	QGLMaterial* m = new QGLMaterial();
	m->setColor(QColor(255,255,255));
	if (stone1){
		QString s = stone1->objectName();
		stone1->setMaterial(m);
	}
	if (m_scene)
         m_main = m_scene->mainNode();

	QQuaternion xt = QQuaternion::fromAxisAndAngle(1.0f, 0.0f, 0.0f, -90.0f);
    QQuaternion yt = QQuaternion::fromAxisAndAngle(0.0f, 1.0f, 0.0f, 30.0f);
	m_pose = yt * xt;
}

VirtualView::~VirtualView()
{
    delete m_scene;
}

void VirtualView::paintGL(QGLPainter *painter)
{
	painter->modelViewMatrix().rotate(m_pose);

	if (m_main)
		m_main->draw(painter);

}<|endoftext|>


<commit_before>/*
 * C++ wrappers for libevent.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#ifndef EVENT_HXX
#define EVENT_HXX

#include "Base.hxx"

#include <inline/compiler.h>

#include <event.h>

class Event {
    struct event event;

public:
    Event() = default;

    Event(EventBase &base, evutil_socket_t fd, short mask,
          event_callback_fn callback, void *ctx) {
        Set(base, fd, mask, callback, ctx);
    }

    Event(evutil_socket_t fd, short mask,
          event_callback_fn callback, void *ctx) {
        Set(fd, mask, callback, ctx);
    }

    Event(const Event &other) = delete;
    Event &operator=(const Event &other) = delete;

    gcc_pure
    evutil_socket_t GetFd() const {
        return event_get_fd(&event);
    }

    gcc_pure
    short GetEvents() const {
        return event_get_events(&event);
    }

    gcc_pure
    event_callback_fn GetCallback() const {
        return event_get_callback(&event);
    }

    gcc_pure
    void *GetCallbackArg() const {
        return event_get_callback_arg(&event);
    }

    void Set(EventBase &base, evutil_socket_t fd, short mask,
             event_callback_fn callback, void *ctx) {
        ::event_assign(&event, base.Get(), fd, mask, callback, ctx);
    }

    void Set(evutil_socket_t fd, short mask,
             event_callback_fn callback, void *ctx) {
        ::event_set(&event, fd, mask, callback, ctx);
    }

    bool Add(const struct timeval *timeout=nullptr) {
        return ::event_add(&event, timeout) == 0;
    }

    bool Add(const struct timeval &timeout) {
        return Add(&timeout);
    }

    void SetTimer(event_callback_fn callback, void *ctx) {
        ::evtimer_set(&event, callback, ctx);
    }

    void SetSignal(int sig, event_callback_fn callback, void *ctx) {
        ::evsignal_set(&event, sig, callback, ctx);
    }

    void Delete() {
        ::event_del(&event);
    }

    void MakeActive(short events) {
        event_active(&event, events, 0);
    }

    gcc_pure
    bool IsPending(short events) const {
        return ::event_pending(&event, events, nullptr);
    }

    gcc_pure
    bool IsTimerPending() const {
        return IsPending(EV_TIMEOUT);
    }
};

#endif
<commit_msg>event/Event: call event_debug_unassign() in destructor<commit_after>/*
 * C++ wrappers for libevent.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#ifndef EVENT_HXX
#define EVENT_HXX

#include "Base.hxx"

#include <inline/compiler.h>

#include <event.h>

class Event {
    struct event event;

public:
    Event() = default;

    Event(EventBase &base, evutil_socket_t fd, short mask,
          event_callback_fn callback, void *ctx) {
        Set(base, fd, mask, callback, ctx);
    }

    Event(evutil_socket_t fd, short mask,
          event_callback_fn callback, void *ctx) {
        Set(fd, mask, callback, ctx);
    }

#ifndef NDEBUG
    ~Event() {
        event_debug_unassign(&event);
    }
#endif

    Event(const Event &other) = delete;
    Event &operator=(const Event &other) = delete;

    gcc_pure
    evutil_socket_t GetFd() const {
        return event_get_fd(&event);
    }

    gcc_pure
    short GetEvents() const {
        return event_get_events(&event);
    }

    gcc_pure
    event_callback_fn GetCallback() const {
        return event_get_callback(&event);
    }

    gcc_pure
    void *GetCallbackArg() const {
        return event_get_callback_arg(&event);
    }

    void Set(EventBase &base, evutil_socket_t fd, short mask,
             event_callback_fn callback, void *ctx) {
        ::event_assign(&event, base.Get(), fd, mask, callback, ctx);
    }

    void Set(evutil_socket_t fd, short mask,
             event_callback_fn callback, void *ctx) {
        ::event_set(&event, fd, mask, callback, ctx);
    }

    bool Add(const struct timeval *timeout=nullptr) {
        return ::event_add(&event, timeout) == 0;
    }

    bool Add(const struct timeval &timeout) {
        return Add(&timeout);
    }

    void SetTimer(event_callback_fn callback, void *ctx) {
        ::evtimer_set(&event, callback, ctx);
    }

    void SetSignal(int sig, event_callback_fn callback, void *ctx) {
        ::evsignal_set(&event, sig, callback, ctx);
    }

    void Delete() {
        ::event_del(&event);
    }

    void MakeActive(short events) {
        event_active(&event, events, 0);
    }

    gcc_pure
    bool IsPending(short events) const {
        return ::event_pending(&event, events, nullptr);
    }

    gcc_pure
    bool IsTimerPending() const {
        return IsPending(EV_TIMEOUT);
    }
};

#endif
<|endoftext|>


<commit_before>#include "includes.h"

namespace fancy {

  FancyObject::FancyObject(Class_p _class) :
    _class(_class)
  {
    init_slots();
  }

  FancyObject::~FancyObject()
  {
  }

  Class_p FancyObject::get_class() const
  {
    return this->_class;
  }

  void FancyObject::set_class(Class_p klass)
  {
    if(klass) {
      this->_class = klass;
      init_slots();
    }
  }

  FancyObject_p FancyObject::get_slot(const string &slotname) const
  {
    object_map::const_iterator it = this->slots.find(slotname);
    if(it != this->slots.end()) {
      return it->second;
    } else {
      return nil;
    }
  }

  FancyObject_p FancyObject::get_slot(const Identifier_p slotname) const
  {
    assert(slotname);
    return this->get_slot(slotname->name());
  }

  void FancyObject::set_slot(const string &slotname, const FancyObject_p value)
  {
    assert(value);
    this->slots[slotname] = value;
  }

  void FancyObject::set_slot(const Identifier_p slotname, const FancyObject_p value)
  {
    assert(slotname);
    this->set_slot(slotname->name(), value);
  }

  void FancyObject::init_slots()
  {
    if(this->_class) {
      vector<string>::iterator it;
      for(it = this->_class->instance_slotnames().begin();
          it != this->_class->instance_slotnames().end();
          it++){
        this->slots[*it] = nil;
      }
    }
  }

  FancyObject_p FancyObject::equal(const FancyObject_p other) const
  {
    if(!IS_CLASSINSTANCE(other))
      return nil;

    FancyObject_p other_instance = dynamic_cast<FancyObject_p>(other);

    if(this->_class->equal(other_instance->_class) != nil) {
      // TODO: compare slotvalues for both instances
      return nil;
    } else {
      return nil;
    }
  }

  FancyObject_p FancyObject::eval(Scope *scope)
  {
    return this;
  }

  OBJ_TYPE FancyObject::type() const
  {
    return OBJ_CLASSINSTANCE;
  }

  string FancyObject::to_s() const
  {
    return "<Unkown FancyObject>";
  }

  string FancyObject::inspect() const
  {
    return this->to_s();
  }

  FancyObject_p FancyObject::call_method(const string &method_name, FancyObject_p *arguments, int argc, Scope *scope)
  {
    Callable_p method = this->get_method(method_name);
    if(method) {
      return method->call(this, arguments, argc, scope);
    } else {
      // handle unkown messages, if unkown_message:with_params is defined
      if(Callable_p unkown_message_method = this->get_method("unknown_message:with_params:")) {
        int size = sizeof(arguments) / sizeof(arguments[0]);
        vector<FancyObject_p> arr_vec(arguments, &arguments[size]);
        FancyObject_p new_args[2] = { String::from_value(method_name), new Array(arr_vec) };
        return unkown_message_method->call(this, new_args, 2, scope);
      }

      // in this case no method is found and we raise a MethodNotFoundError
      FancyException_p except = new MethodNotFoundError(method_name, this->_class);
      throw except;
      return nil;
    }
  }

  void FancyObject::def_singleton_method(const string &name, Callable_p method)
  {
    assert(method);
    this->_singleton_methods[name] = method;
  }

  bool FancyObject::responds_to(const string &method_name)
  {
    if(this->get_method(method_name)) {
      return true;
    } else {
      return false;
    }
  }

  Callable_p FancyObject::get_method(const string &method_name)
  {
    // first of all, check singleton methods
    method_map::const_iterator it = this->_singleton_methods.find(method_name);
    if(it != this->_singleton_methods.end()) {
      return it->second;
    } else {
      return this->_class->find_method(method_name);
    }
  }

  string FancyObject::docstring() const
  {
    return _docstring;
  }

  void FancyObject::set_docstring(const string &docstring)
  {
    _docstring = docstring;
  }
}
<commit_msg>call method without args if none given<commit_after>#include "includes.h"

namespace fancy {

  FancyObject::FancyObject(Class_p _class) :
    _class(_class)
  {
    init_slots();
  }

  FancyObject::~FancyObject()
  {
  }

  Class_p FancyObject::get_class() const
  {
    return this->_class;
  }

  void FancyObject::set_class(Class_p klass)
  {
    if(klass) {
      this->_class = klass;
      init_slots();
    }
  }

  FancyObject_p FancyObject::get_slot(const string &slotname) const
  {
    object_map::const_iterator it = this->slots.find(slotname);
    if(it != this->slots.end()) {
      return it->second;
    } else {
      return nil;
    }
  }

  FancyObject_p FancyObject::get_slot(const Identifier_p slotname) const
  {
    assert(slotname);
    return this->get_slot(slotname->name());
  }

  void FancyObject::set_slot(const string &slotname, const FancyObject_p value)
  {
    assert(value);
    this->slots[slotname] = value;
  }

  void FancyObject::set_slot(const Identifier_p slotname, const FancyObject_p value)
  {
    assert(slotname);
    this->set_slot(slotname->name(), value);
  }

  void FancyObject::init_slots()
  {
    if(this->_class) {
      vector<string>::iterator it;
      for(it = this->_class->instance_slotnames().begin();
          it != this->_class->instance_slotnames().end();
          it++){
        this->slots[*it] = nil;
      }
    }
  }

  FancyObject_p FancyObject::equal(const FancyObject_p other) const
  {
    if(!IS_CLASSINSTANCE(other))
      return nil;

    FancyObject_p other_instance = dynamic_cast<FancyObject_p>(other);

    if(this->_class->equal(other_instance->_class) != nil) {
      // TODO: compare slotvalues for both instances
      return nil;
    } else {
      return nil;
    }
  }

  FancyObject_p FancyObject::eval(Scope *scope)
  {
    return this;
  }

  OBJ_TYPE FancyObject::type() const
  {
    return OBJ_CLASSINSTANCE;
  }

  string FancyObject::to_s() const
  {
    return "<Unkown FancyObject>";
  }

  string FancyObject::inspect() const
  {
    return this->to_s();
  }

  FancyObject_p FancyObject::call_method(const string &method_name, FancyObject_p *arguments, int argc, Scope *scope)
  {
    Callable_p method = this->get_method(method_name);
    if(method) {
      if(argc == 0) {
        return method->call(this, scope);
      }
      return method->call(this, arguments, argc, scope);
    } else {
      // handle unkown messages, if unkown_message:with_params is defined
      if(Callable_p unkown_message_method = this->get_method("unknown_message:with_params:")) {
        int size = sizeof(arguments) / sizeof(arguments[0]);
        vector<FancyObject_p> arr_vec(arguments, &arguments[size]);
        FancyObject_p new_args[2] = { String::from_value(method_name), new Array(arr_vec) };
        return unkown_message_method->call(this, new_args, 2, scope);
      }

      // in this case no method is found and we raise a MethodNotFoundError
      FancyException_p except = new MethodNotFoundError(method_name, this->_class);
      throw except;
      return nil;
    }
  }

  void FancyObject::def_singleton_method(const string &name, Callable_p method)
  {
    assert(method);
    this->_singleton_methods[name] = method;
  }

  bool FancyObject::responds_to(const string &method_name)
  {
    if(this->get_method(method_name)) {
      return true;
    } else {
      return false;
    }
  }

  Callable_p FancyObject::get_method(const string &method_name)
  {
    // first of all, check singleton methods
    method_map::const_iterator it = this->_singleton_methods.find(method_name);
    if(it != this->_singleton_methods.end()) {
      return it->second;
    } else {
      return this->_class->find_method(method_name);
    }
  }

  string FancyObject::docstring() const
  {
    return _docstring;
  }

  void FancyObject::set_docstring(const string &docstring)
  {
    _docstring = docstring;
  }
}
<|endoftext|>


<commit_before>#include <string>
#include <memory>

#include "../worker_platform.h"
#include "../worker_thread.h"
#include "../../message.h"
#include "../../log.h"
#include "../../result.h"

using std::string;
using std::unique_ptr;

class LinuxWorkerPlatform : public WorkerPlatform {
public:
  LinuxWorkerPlatform(WorkerThread *thread) : WorkerPlatform(thread) {};

  Result<> wake() override
  {
    return ok_result();
  }

  Result<> listen() override
  {
    return ok_result();
  }

  Result<bool> handle_add_command(
    const CommandID command,
    const ChannelID channel,
    const string &root_path) override
  {
    return ok_result(true);
  }

  Result<bool> handle_remove_command(
    const CommandID command,
    const ChannelID channel) override
  {
    return ok_result(true);
  }
};

unique_ptr<WorkerPlatform> WorkerPlatform::for_worker(WorkerThread *thread)
{
  return unique_ptr<WorkerPlatform>(new LinuxWorkerPlatform(thread));
}
<commit_msg>Implement the command channel<commit_after>#include <string>
#include <memory>
#include <poll.h>

#include "../worker_platform.h"
#include "../worker_thread.h"
#include "../../message.h"
#include "../../log.h"
#include "../../result.h"
#include "../../helper/linux/helper.h"
#include "pipe.h"

using std::string;
using std::unique_ptr;

class LinuxWorkerPlatform : public WorkerPlatform {
public:
  LinuxWorkerPlatform(WorkerThread *thread) :
    WorkerPlatform(thread),
    pipe("worker pipe")
  {
    //
  };

  Result<> wake() override
  {
    return pipe.signal();
  }

  Result<> listen() override
  {
    pollfd to_poll[1];
    to_poll[0].fd = pipe.get_read_fd();
    to_poll[0].events = POLLIN;
    to_poll[0].revents = 0;

    while (true) {
      int result = poll(to_poll, 1, -1);

      if (result < 0) {
        return errno_result<>("Unable to poll");
      } else if (result == 0) {
        return error_result("Unexpected poll() timeout");
      }

      if (to_poll[0].revents & (POLLIN | POLLERR)) {
        Result<> hr = handle_commands();
        if (hr.is_error()) return hr;

        Result<> cr = pipe.consume();
        if (cr.is_error()) return cr;
      }
    }

    return error_result("Polling loop exited unexpectedly");
  }

  Result<bool> handle_add_command(
    const CommandID command,
    const ChannelID channel,
    const string &root_path) override
  {
    return ok_result(true);
  }

  Result<bool> handle_remove_command(
    const CommandID command,
    const ChannelID channel) override
  {
    return ok_result(true);
  }

private:
  Pipe pipe;
};

unique_ptr<WorkerPlatform> WorkerPlatform::for_worker(WorkerThread *thread)
{
  return unique_ptr<WorkerPlatform>(new LinuxWorkerPlatform(thread));
}
<|endoftext|>


<commit_before>/*
 * This file is a part of Xpiks - cross platform application for
 * keywording and uploading images for microstocks
 * Copyright (C) 2014-2017 Taras Kushnir <kushnirTV@gmail.com>
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include "artworksrepository.h"
#include <QDir>
#include <QSet>
#include <QFileInfo>
#include <QRegExp>
#include "../Common/defines.h"
#include "../Helpers/indiceshelper.h"
#include "../Commands/commandmanager.h"
#include "../Models/filteredartitemsproxymodel.h"

namespace Models {
    ArtworksRepository::ArtworksRepository(QObject *parent) :
        AbstractListModel(parent),
        m_LastUnavailableFilesCount(0),
        m_LastID(0)
    {
        QObject::connect(&m_FilesWatcher, &QFileSystemWatcher::fileChanged,
                     this, &ArtworksRepository::checkFileUnavailable);

        m_Timer.setInterval(4000); //4 sec
        m_Timer.setSingleShot(true); //single shot
        QObject::connect(&m_Timer, &QTimer::timeout, this, &ArtworksRepository::onAvailabilityTimer);
    }

    void ArtworksRepository::updateCountsForExistingDirectories() {
        emit dataChanged(index(0), index(rowCount() - 1), QVector<int>() << UsedImagesCountRole << IsSelectedRole);
    }

    void ArtworksRepository::cleanupEmptyDirectories() {
        LOG_DEBUG << "#";
        size_t count = m_DirectoriesList.size();
        QVector<int> indicesToRemove;
        indicesToRemove.reserve((int)count);

        for (size_t i = 0; i < count; ++i) {
            auto &directory = m_DirectoriesList[i];
            if (directory.m_FilesCount == 0) {
                indicesToRemove.append((int)i);
            }
        }

        if (!indicesToRemove.isEmpty()) {
            LOG_INFO << indicesToRemove.length() << "empty directory(ies)...";

            QVector<QPair<int, int> > rangesToRemove;
            Helpers::indicesToRanges(indicesToRemove, rangesToRemove);
            removeItemsAtIndices(rangesToRemove);

            updateSelectedState();
        }
    }

    void ArtworksRepository::stopListeningToUnavailableFiles() {
        LOG_DEBUG << "#";

        QStringList files = m_FilesWatcher.files();
        if (!files.isEmpty()) {
            m_FilesWatcher.removePaths(files);
        }

        QStringList directories = m_FilesWatcher.directories();
        if (!directories.isEmpty()) {
            m_FilesWatcher.removePaths(directories);
        }
    }

    bool ArtworksRepository::beginAccountingFiles(const QStringList &items) {
        int count = getNewDirectoriesCount(items);
        bool shouldAccountFiles = count > 0;
        if (shouldAccountFiles) {
            beginInsertRows(QModelIndex(), rowCount(), rowCount() + count - 1);
        }

        return shouldAccountFiles;
    }

    void ArtworksRepository::endAccountingFiles(bool filesWereAccounted) {
        if (filesWereAccounted) {
            endInsertRows();
        }
    }

    /*virtual */
    int ArtworksRepository::getNewDirectoriesCount(const QStringList &items) const {
        QSet<QString> filteredFiles;

        foreach (const QString &filepath, items) {
            if (!m_FilesSet.contains(filepath)) {
                filteredFiles.insert(filepath);
            }
        }

        QSet<QString> filteredDirectories;

        foreach (const QString &filepath, filteredFiles) {
            QString directory;
            if (checkFileExists(filepath, directory)) {
                filteredDirectories.insert(directory);
            }
        }

        int count = 0;
        size_t phony;
        foreach (const QString &directory, filteredDirectories) {
            if (!tryFindDirectory(directory, phony)) {
                count++;
            }
        }

        return count;
    }

    int ArtworksRepository::getNewFilesCount(const QStringList &items) const {
        int count = 0;
        QSet<QString> itemsSet = QSet<QString>::fromList(items);

        foreach (const QString &filepath, itemsSet) {
            if (!m_FilesSet.contains(filepath)) {
                count++;
            }
        }

        return count;
    }

    bool ArtworksRepository::isDirectoryIncluded(qint64 directoryID) const {
        bool isSelected = false;
        const size_t size = m_DirectoriesList.size();
        size_t index = m_DirectoryIdToIndex.value(directoryID, size);
        if (index < size) {
            isSelected = m_DirectoriesList[index].m_IsSelected;
        }

        return isSelected;
    }

    bool ArtworksRepository::accountFile(const QString &filepath, qint64 &directoryID) {
        bool wasModified = false;
        QString absolutePath;

        if (this->checkFileExists(filepath, absolutePath) &&
                !m_FilesSet.contains(filepath)) {

            int occurances = 0;
            size_t index;
            bool alreadyExists = tryFindDirectory(absolutePath, index);

            if (!alreadyExists) {
                qint64 id = generateNextID();
                LOG_INFO << "Adding new directory" << absolutePath << "with index" << m_DirectoriesList.size() << "and id" << id;
                m_DirectoriesList.emplace_back(absolutePath, id, 0, true);
                index = m_DirectoriesList.size() - 1;
                m_DirectoryIdToIndex[id] = index;
                directoryID = id;
                emit artworksSourcesCountChanged();
#ifdef CORE_TESTS
                if (m_CommandManager != nullptr)
#endif
                {
                    m_CommandManager->addToRecentDirectories(absolutePath);
                }
            } else {
                auto &item = m_DirectoriesList[index];
                occurances = item.m_FilesCount;
                directoryID = item.m_Id;
            }

            // watchFilePath(filepath);
            m_FilesSet.insert(filepath);
            m_DirectoriesList[index].m_FilesCount = occurances + 1;
            wasModified = true;
        }

        return wasModified;
    }

    void ArtworksRepository::accountVector(const QString &vectorPath) {
        watchFilePath(vectorPath);
    }

    bool ArtworksRepository::removeFile(const QString &filepath, qint64 directoryID) {
        bool result = false;

        if (m_FilesSet.contains(filepath)) {
            Q_ASSERT(m_DirectoryIdToIndex.contains(directoryID));
            auto existingIndex = m_DirectoryIdToIndex[directoryID];
            auto &item = m_DirectoriesList[existingIndex];
            item.m_FilesCount--;
            m_FilesWatcher.removePath(filepath);
            m_FilesSet.remove(filepath);
            result = true;
        }

        return result;
    }

    void ArtworksRepository::removeVector(const QString &vectorPath) {
        m_FilesWatcher.removePath(vectorPath);
    }

    void ArtworksRepository::purgeUnavailableFiles() {
        LOG_DEBUG << "#";
        m_UnavailableFiles.clear();
        m_LastUnavailableFilesCount = 0;
    }

    void ArtworksRepository::watchFilePaths(const QStringList &filePaths) {
#ifndef CORE_TESTS
        if (!filePaths.empty()) {
            m_FilesWatcher.addPaths(filePaths);
        }
#else
        Q_UNUSED(filePaths);
#endif
    }

    void ArtworksRepository::unwatchFilePaths(const QStringList &filePaths) {
#ifndef CORE_TESTS
        if (!filePaths.empty()) {
            m_FilesWatcher.removePaths(filePaths);
        }
#else
        Q_UNUSED(filePaths);
#endif
    }

    void ArtworksRepository::updateFilesCounts() {
        if (m_DirectoriesList.empty()) { return; }

        auto first = this->index(0);
        auto last = this->index(rowCount() - 1);
        emit dataChanged(first, last, QVector<int>() << UsedImagesCountRole);
    }

    void ArtworksRepository::updateSelectedState() {
        if (m_DirectoriesList.empty()) { return; }

        auto first = this->index(0);
        auto last = this->index(rowCount() - 1);
        emit dataChanged(first, last, QVector<int>() << IsSelectedRole);
    }

    void ArtworksRepository::watchFilePath(const QString &filepath) {
#ifndef CORE_TESTS
        m_FilesWatcher.addPath(filepath);
#else
        Q_UNUSED(filepath);
#endif
    }

    bool ArtworksRepository::isFileUnavailable(const QString &filepath) const {
        bool isUnavailable = false;

        if (m_UnavailableFiles.contains(filepath)) {
#if defined(CORE_TESTS) || defined(INTEGRATION_TESTS)
            {
#else
            if(!QFileInfo(filepath).exists()) {
#endif

                isUnavailable = true;
            }
        }

        return isUnavailable;
    }

#ifdef INTEGRATION_TESTS
    void ArtworksRepository::resetEverything() {
        m_DirectoriesList.clear();
        m_FilesSet.clear();
        m_DirectoryIdToIndex.clear();
    }
#endif

    int ArtworksRepository::rowCount(const QModelIndex &parent) const {
        Q_UNUSED(parent);
        return (int)m_DirectoriesList.size();
    }

    QVariant ArtworksRepository::data(const QModelIndex &index, int role) const {
        int row = index.row();
        if ((row < 0) || (row >= (int)m_DirectoriesList.size())) {
            return QVariant();
        }

        auto &directory = m_DirectoriesList.at(index.row());

        switch (role) {
        case PathRole: {
            QDir dir(directory.m_AbsolutePath);
            return dir.dirName();
        }
        case UsedImagesCountRole:
            return directory.m_FilesCount;
        case IsSelectedRole:
            return !allAreSelected() && directory.m_IsSelected;
        default:
            return QVariant();
        }
    }

    void ArtworksRepository::selectDirectory(int row) {
        if ((row < 0) || (row >= (int)m_DirectoriesList.size())) {
            return;
        }

        auto &directory = m_DirectoriesList.at(row);

        bool oldValue = directory.m_IsSelected;
        bool newValue = !oldValue;
        if (changeSelectedState(row, newValue, oldValue)) {
            updateSelectedState();
#ifndef CORE_TESTS
            LOG_DEBUG << "Updating artworks";
            auto *filteredArtItemsModel = m_CommandManager->getFilteredArtItemsModel();
            Q_ASSERT(filteredArtItemsModel != NULL);
            filteredArtItemsModel->updateFilter();
#endif
        }
    }

    bool ArtworksRepository::setDirectorySelected(size_t index, bool value) {
        auto &directory = m_DirectoriesList[index];
        bool changed = directory.m_IsSelected != value;
        directory.m_IsSelected = value;

        return changed;
    }

    bool ArtworksRepository::changeSelectedState(int row, bool newValue, bool oldValue) {
        if (oldValue == newValue) { return false; }

        bool anySelectionChanged = false;

        const size_t count = m_DirectoriesList.size();
        if (count == 1) {
            Q_ASSERT(row == 0);
            anySelectionChanged = setDirectorySelected(row, true);
            return anySelectionChanged;
        }

        const size_t selectedCount = retrieveSelectedDirsCount();
        const bool allAreSelected = selectedCount == count;
        const bool wasSelected = (oldValue == true);
        const bool onlyOneSelected = (selectedCount == 1);
        const bool isUnselected = (newValue == false);

        if (allAreSelected && (count > 1)) {
            Q_ASSERT(newValue == false);
            unselectAllDirectories();
            setDirectorySelected(row, true);
            anySelectionChanged = true;
        } else if (onlyOneSelected && wasSelected && isUnselected) {
            selectAllDirectories();
            anySelectionChanged = true;
        } else {
            anySelectionChanged = setDirectorySelected(row, newValue);
        }

        return anySelectionChanged;
    }

    bool ArtworksRepository::setAllSelected(bool value) {
        bool anyChange = false;
        size_t size = m_DirectoriesList.size();

        for (size_t i = 0; i < size; i++) {
            if (setDirectorySelected(i, value)) {
                anyChange = true;
            }
        }

        if (anyChange) {
            updateSelectedState();
        }

        return anyChange;
    }

    size_t ArtworksRepository::retrieveSelectedDirsCount() const {
        size_t count = 0;

        for (auto &directory: m_DirectoriesList) {
            if (directory.m_IsSelected) {
                count++;
            }
        }

        return count;
    }

    bool ArtworksRepository::allAreSelected() const {
        bool anyUnselected = false;

        for (auto &item: m_DirectoriesList) {
            if (!item.m_IsSelected) {
                anyUnselected = true;
                break;
            }
        }

        return !anyUnselected;
    }

    bool ArtworksRepository::tryFindDirectory(const QString &directoryPath, size_t &index) const {
        bool found = false;
        const size_t size = m_DirectoriesList.size();

        for (size_t i = 0; i < size; ++i) {
            auto &item = m_DirectoriesList[i];
            if (item.m_AbsolutePath == directoryPath) {
                found = true;
                index = i;
                break;
            }
        }

        return found;
    }

    QHash<int, QByteArray> ArtworksRepository::roleNames() const {
        QHash<int, QByteArray> roles;
        roles[PathRole] = "path";
        roles[UsedImagesCountRole] = "usedimagescount";
        roles[IsSelectedRole] = "isselected";
        return roles;
    }

    /*virtual */
    bool ArtworksRepository::checkFileExists(const QString &filename, QString &directory) const {
        bool exists = false;
        QFileInfo fi(filename);

#ifndef CORE_TESTS
        exists = fi.exists();
#else
        exists = true;
#endif

        if (exists) {
            directory = fi.absolutePath();
        }

        return exists;
    }

    void ArtworksRepository::checkFileUnavailable(const QString &path) {
        LOG_INFO << "File changed:" << path;

        QFileInfo fi(path);
        if (!fi.exists()) {
            LOG_INFO << "File become unavailable:" << path;
            m_UnavailableFiles.insert(fi.absoluteFilePath());
            LOG_DEBUG << "Starting availability timer...";
            m_Timer.start();
        }
    }

    void ArtworksRepository::onAvailabilityTimer() {
        int currentUnavailableSize = m_UnavailableFiles.size();
        LOG_INFO << "Current:" << currentUnavailableSize << "Last:" << m_LastUnavailableFilesCount;

        if (currentUnavailableSize > m_LastUnavailableFilesCount) {
            m_LastUnavailableFilesCount = currentUnavailableSize;
            emit filesUnavailable();
        }
    }
}

<commit_msg>Assert for bugs #466 and #467<commit_after>/*
 * This file is a part of Xpiks - cross platform application for
 * keywording and uploading images for microstocks
 * Copyright (C) 2014-2017 Taras Kushnir <kushnirTV@gmail.com>
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include "artworksrepository.h"
#include <QDir>
#include <QSet>
#include <QFileInfo>
#include <QRegExp>
#include "../Common/defines.h"
#include "../Helpers/indiceshelper.h"
#include "../Commands/commandmanager.h"
#include "../Models/filteredartitemsproxymodel.h"

namespace Models {
    ArtworksRepository::ArtworksRepository(QObject *parent) :
        AbstractListModel(parent),
        m_LastUnavailableFilesCount(0),
        m_LastID(0)
    {
        QObject::connect(&m_FilesWatcher, &QFileSystemWatcher::fileChanged,
                     this, &ArtworksRepository::checkFileUnavailable);

        m_Timer.setInterval(4000); //4 sec
        m_Timer.setSingleShot(true); //single shot
        QObject::connect(&m_Timer, &QTimer::timeout, this, &ArtworksRepository::onAvailabilityTimer);
    }

    void ArtworksRepository::updateCountsForExistingDirectories() {
        emit dataChanged(index(0), index(rowCount() - 1), QVector<int>() << UsedImagesCountRole << IsSelectedRole);
    }

    void ArtworksRepository::cleanupEmptyDirectories() {
        LOG_DEBUG << "#";
        size_t count = m_DirectoriesList.size();
        QVector<int> indicesToRemove;
        indicesToRemove.reserve((int)count);

        for (size_t i = 0; i < count; ++i) {
            auto &directory = m_DirectoriesList[i];
            if (directory.m_FilesCount == 0) {
                indicesToRemove.append((int)i);
            }
        }

        if (!indicesToRemove.isEmpty()) {
            LOG_INFO << indicesToRemove.length() << "empty directory(ies)...";

            QVector<QPair<int, int> > rangesToRemove;
            Helpers::indicesToRanges(indicesToRemove, rangesToRemove);
            removeItemsAtIndices(rangesToRemove);

            updateSelectedState();
        }
    }

    void ArtworksRepository::stopListeningToUnavailableFiles() {
        LOG_DEBUG << "#";

        QStringList files = m_FilesWatcher.files();
        if (!files.isEmpty()) {
            m_FilesWatcher.removePaths(files);
        }

        QStringList directories = m_FilesWatcher.directories();
        if (!directories.isEmpty()) {
            m_FilesWatcher.removePaths(directories);
        }
    }

    bool ArtworksRepository::beginAccountingFiles(const QStringList &items) {
        int count = getNewDirectoriesCount(items);
        bool shouldAccountFiles = count > 0;
        if (shouldAccountFiles) {
            beginInsertRows(QModelIndex(), rowCount(), rowCount() + count - 1);
        }

        return shouldAccountFiles;
    }

    void ArtworksRepository::endAccountingFiles(bool filesWereAccounted) {
        if (filesWereAccounted) {
            endInsertRows();
        }
    }

    /*virtual */
    int ArtworksRepository::getNewDirectoriesCount(const QStringList &items) const {
        QSet<QString> filteredFiles;

        foreach (const QString &filepath, items) {
            if (!m_FilesSet.contains(filepath)) {
                filteredFiles.insert(filepath);
            }
        }

        QSet<QString> filteredDirectories;

        foreach (const QString &filepath, filteredFiles) {
            QString directory;
            if (checkFileExists(filepath, directory)) {
                filteredDirectories.insert(directory);
            }
        }

        int count = 0;
        size_t phony;
        foreach (const QString &directory, filteredDirectories) {
            if (!tryFindDirectory(directory, phony)) {
                count++;
            }
        }

        return count;
    }

    int ArtworksRepository::getNewFilesCount(const QStringList &items) const {
        int count = 0;
        QSet<QString> itemsSet = QSet<QString>::fromList(items);

        foreach (const QString &filepath, itemsSet) {
            if (!m_FilesSet.contains(filepath)) {
                count++;
            }
        }

        return count;
    }

    bool ArtworksRepository::isDirectoryIncluded(qint64 directoryID) const {
        bool isSelected = false;
        const size_t size = m_DirectoriesList.size();
        size_t index = m_DirectoryIdToIndex.value(directoryID, size);
        if (index < size) {
            isSelected = m_DirectoriesList[index].m_IsSelected;
        }

        return isSelected;
    }

    bool ArtworksRepository::accountFile(const QString &filepath, qint64 &directoryID) {
        bool wasModified = false;
        QString absolutePath;

        if (this->checkFileExists(filepath, absolutePath) &&
                !m_FilesSet.contains(filepath)) {

            int occurances = 0;
            size_t index;
            bool alreadyExists = tryFindDirectory(absolutePath, index);

            if (!alreadyExists) {
                qint64 id = generateNextID();
                LOG_INFO << "Adding new directory" << absolutePath << "with index" << m_DirectoriesList.size() << "and id" << id;
                m_DirectoriesList.emplace_back(absolutePath, id, 0, true);
                index = m_DirectoriesList.size() - 1;
                m_DirectoryIdToIndex[id] = index;
                directoryID = id;
                emit artworksSourcesCountChanged();
#ifdef CORE_TESTS
                if (m_CommandManager != nullptr)
#endif
                {
                    m_CommandManager->addToRecentDirectories(absolutePath);
                }
            } else {
                auto &item = m_DirectoriesList[index];
                occurances = item.m_FilesCount;
                directoryID = item.m_Id;
            }

            // watchFilePath(filepath);
            m_FilesSet.insert(filepath);
            m_DirectoriesList[index].m_FilesCount = occurances + 1;
            wasModified = true;
        }

        return wasModified;
    }

    void ArtworksRepository::accountVector(const QString &vectorPath) {
        watchFilePath(vectorPath);
    }

    bool ArtworksRepository::removeFile(const QString &filepath, qint64 directoryID) {
        bool result = false;

        if (m_FilesSet.contains(filepath)) {
            Q_ASSERT(m_DirectoryIdToIndex.contains(directoryID));
            auto existingIndex = m_DirectoryIdToIndex[directoryID];
            Q_ASSERT((0 <= existingIndex) && (existingIndex < m_DirectoriesList.size()));
            auto &item = m_DirectoriesList[existingIndex];
            item.m_FilesCount--;
            m_FilesWatcher.removePath(filepath);
            m_FilesSet.remove(filepath);
            result = true;
        }

        return result;
    }

    void ArtworksRepository::removeVector(const QString &vectorPath) {
        m_FilesWatcher.removePath(vectorPath);
    }

    void ArtworksRepository::purgeUnavailableFiles() {
        LOG_DEBUG << "#";
        m_UnavailableFiles.clear();
        m_LastUnavailableFilesCount = 0;
    }

    void ArtworksRepository::watchFilePaths(const QStringList &filePaths) {
#ifndef CORE_TESTS
        if (!filePaths.empty()) {
            m_FilesWatcher.addPaths(filePaths);
        }
#else
        Q_UNUSED(filePaths);
#endif
    }

    void ArtworksRepository::unwatchFilePaths(const QStringList &filePaths) {
#ifndef CORE_TESTS
        if (!filePaths.empty()) {
            m_FilesWatcher.removePaths(filePaths);
        }
#else
        Q_UNUSED(filePaths);
#endif
    }

    void ArtworksRepository::updateFilesCounts() {
        if (m_DirectoriesList.empty()) { return; }

        auto first = this->index(0);
        auto last = this->index(rowCount() - 1);
        emit dataChanged(first, last, QVector<int>() << UsedImagesCountRole);
    }

    void ArtworksRepository::updateSelectedState() {
        if (m_DirectoriesList.empty()) { return; }

        auto first = this->index(0);
        auto last = this->index(rowCount() - 1);
        emit dataChanged(first, last, QVector<int>() << IsSelectedRole);
    }

    void ArtworksRepository::watchFilePath(const QString &filepath) {
#ifndef CORE_TESTS
        m_FilesWatcher.addPath(filepath);
#else
        Q_UNUSED(filepath);
#endif
    }

    bool ArtworksRepository::isFileUnavailable(const QString &filepath) const {
        bool isUnavailable = false;

        if (m_UnavailableFiles.contains(filepath)) {
#if defined(CORE_TESTS) || defined(INTEGRATION_TESTS)
            {
#else
            if(!QFileInfo(filepath).exists()) {
#endif

                isUnavailable = true;
            }
        }

        return isUnavailable;
    }

#ifdef INTEGRATION_TESTS
    void ArtworksRepository::resetEverything() {
        m_DirectoriesList.clear();
        m_FilesSet.clear();
        m_DirectoryIdToIndex.clear();
    }
#endif

    int ArtworksRepository::rowCount(const QModelIndex &parent) const {
        Q_UNUSED(parent);
        return (int)m_DirectoriesList.size();
    }

    QVariant ArtworksRepository::data(const QModelIndex &index, int role) const {
        int row = index.row();
        if ((row < 0) || (row >= (int)m_DirectoriesList.size())) {
            return QVariant();
        }

        auto &directory = m_DirectoriesList.at(index.row());

        switch (role) {
        case PathRole: {
            QDir dir(directory.m_AbsolutePath);
            return dir.dirName();
        }
        case UsedImagesCountRole:
            return directory.m_FilesCount;
        case IsSelectedRole:
            return !allAreSelected() && directory.m_IsSelected;
        default:
            return QVariant();
        }
    }

    void ArtworksRepository::selectDirectory(int row) {
        if ((row < 0) || (row >= (int)m_DirectoriesList.size())) {
            return;
        }

        auto &directory = m_DirectoriesList.at(row);

        bool oldValue = directory.m_IsSelected;
        bool newValue = !oldValue;
        if (changeSelectedState(row, newValue, oldValue)) {
            updateSelectedState();
#ifndef CORE_TESTS
            LOG_DEBUG << "Updating artworks";
            auto *filteredArtItemsModel = m_CommandManager->getFilteredArtItemsModel();
            Q_ASSERT(filteredArtItemsModel != NULL);
            filteredArtItemsModel->updateFilter();
#endif
        }
    }

    bool ArtworksRepository::setDirectorySelected(size_t index, bool value) {
        auto &directory = m_DirectoriesList[index];
        bool changed = directory.m_IsSelected != value;
        directory.m_IsSelected = value;

        return changed;
    }

    bool ArtworksRepository::changeSelectedState(int row, bool newValue, bool oldValue) {
        if (oldValue == newValue) { return false; }

        bool anySelectionChanged = false;

        const size_t count = m_DirectoriesList.size();
        if (count == 1) {
            Q_ASSERT(row == 0);
            anySelectionChanged = setDirectorySelected(row, true);
            return anySelectionChanged;
        }

        const size_t selectedCount = retrieveSelectedDirsCount();
        const bool allAreSelected = selectedCount == count;
        const bool wasSelected = (oldValue == true);
        const bool onlyOneSelected = (selectedCount == 1);
        const bool isUnselected = (newValue == false);

        if (allAreSelected && (count > 1)) {
            Q_ASSERT(newValue == false);
            unselectAllDirectories();
            setDirectorySelected(row, true);
            anySelectionChanged = true;
        } else if (onlyOneSelected && wasSelected && isUnselected) {
            selectAllDirectories();
            anySelectionChanged = true;
        } else {
            anySelectionChanged = setDirectorySelected(row, newValue);
        }

        return anySelectionChanged;
    }

    bool ArtworksRepository::setAllSelected(bool value) {
        bool anyChange = false;
        size_t size = m_DirectoriesList.size();

        for (size_t i = 0; i < size; i++) {
            if (setDirectorySelected(i, value)) {
                anyChange = true;
            }
        }

        if (anyChange) {
            updateSelectedState();
        }

        return anyChange;
    }

    size_t ArtworksRepository::retrieveSelectedDirsCount() const {
        size_t count = 0;

        for (auto &directory: m_DirectoriesList) {
            if (directory.m_IsSelected) {
                count++;
            }
        }

        return count;
    }

    bool ArtworksRepository::allAreSelected() const {
        bool anyUnselected = false;

        for (auto &item: m_DirectoriesList) {
            if (!item.m_IsSelected) {
                anyUnselected = true;
                break;
            }
        }

        return !anyUnselected;
    }

    bool ArtworksRepository::tryFindDirectory(const QString &directoryPath, size_t &index) const {
        bool found = false;
        const size_t size = m_DirectoriesList.size();

        for (size_t i = 0; i < size; ++i) {
            auto &item = m_DirectoriesList[i];
            if (item.m_AbsolutePath == directoryPath) {
                found = true;
                index = i;
                break;
            }
        }

        return found;
    }

    QHash<int, QByteArray> ArtworksRepository::roleNames() const {
        QHash<int, QByteArray> roles;
        roles[PathRole] = "path";
        roles[UsedImagesCountRole] = "usedimagescount";
        roles[IsSelectedRole] = "isselected";
        return roles;
    }

    /*virtual */
    bool ArtworksRepository::checkFileExists(const QString &filename, QString &directory) const {
        bool exists = false;
        QFileInfo fi(filename);

#ifndef CORE_TESTS
        exists = fi.exists();
#else
        exists = true;
#endif

        if (exists) {
            directory = fi.absolutePath();
        }

        return exists;
    }

    void ArtworksRepository::checkFileUnavailable(const QString &path) {
        LOG_INFO << "File changed:" << path;

        QFileInfo fi(path);
        if (!fi.exists()) {
            LOG_INFO << "File become unavailable:" << path;
            m_UnavailableFiles.insert(fi.absoluteFilePath());
            LOG_DEBUG << "Starting availability timer...";
            m_Timer.start();
        }
    }

    void ArtworksRepository::onAvailabilityTimer() {
        int currentUnavailableSize = m_UnavailableFiles.size();
        LOG_INFO << "Current:" << currentUnavailableSize << "Last:" << m_LastUnavailableFilesCount;

        if (currentUnavailableSize > m_LastUnavailableFilesCount) {
            m_LastUnavailableFilesCount = currentUnavailableSize;
            emit filesUnavailable();
        }
    }
}

<|endoftext|>


<commit_before>// hello_world.cpp
//
// Author: Daniel Clark, 2015

// Headers
#include <iostream>

// Main function
int main() {
    std::cout << "Hello, world!\n";

    return 0;
}
<commit_msg>Style updates and working with terminal<commit_after>// hello_world.cpp
//
// Author: Daniel Clark, 2015

// Headers
#include <iostream>

// Namespace
using namespace std;

// Main function
int main() {
    // Init variables
    int x;

    // Read input to x
    cin >> x;

    // Print statements to terminal
    cout << x/3 << ' ' << x*2;
    cout << "Hello, world!\n";

    return 0;
}
<|endoftext|>


<commit_before>/*-------------Anderson.cpp---------------------------------------------------//
*
*              Anderson.cpp -- Diffusion Monte Carlo for Schroedy
*
* Purpose: Implement the quantum Monte Carlo (diffusion) by Anderson:
*             http://www.huy-nguyen.com/wp-content/uploads/QMC-papers/Anderson-JChemPhys-1975.pdf
*          For H3+, with 3 protons and 2 electrons
*
*    Note: This algorithm may be improved by later work
*          A "psip" is an imaginary configuration of electrons in space.
*          Requires c++11 for random and Eigen for matrix
*          Protons assume to be at origin
*          A lot of this algorithm is more easily understood here:
*              http://www.thphys.uni-heidelberg.de/~wetzel/qmc2006/KOSZ96.pdf
*
*-----------------------------------------------------------------------------*/

#include <iostream>
#include <random>
#include <Eigen/Core>
#include <fstream>

#define DOF 6
#define SIZE 2000
#define DIMS (DOF + 1)

typedef Eigen::Matrix<double, // typename Scalar
   SIZE, // int RowsAtCompileTime,
   DIMS, // int ColsAtCompileTime,
   0> // int Options = 0,
   MatrixPSIP;

struct H3plus {
    MatrixPSIP pos;
    double Vref;
    int psipnum;
};

// Populate a distribution of particles for QMC
void populate(H3plus& state);

// Calculates energy of a configuration and stores it into the final element of
// the MatrixPSIP
void find_weights(H3plus& state);

// Branching scheme
void branch(H3plus& state);

// Random walking of matrix of position created in populate
void diffuse(H3plus& state);

/*----------------------------------------------------------------------------//
* MAIN
*-----------------------------------------------------------------------------*/

int main(){

    std::ofstream output("out.dat", std::ostream::out);
    H3plus state;

    state.Vref = 1;
    state.psipnum = 7;

    populate(state);

    for (size_t i = 0; i < state.psipnum; i++){
        std::cout << " final element is: " << state.pos(i,DIMS-1) << '\n';
    }

    diffuse(state);

    output << state.pos << '\n';

}

/*----------------------------------------------------------------------------//
* SUBROUTINES
*-----------------------------------------------------------------------------*/

// Populate a distribution of particles for QMC
// Unlike Anderson, we are initilizing each psip randomly from a distribution.
// This might screw things up, because
void populate(H3plus& state){

    std::default_random_engine generator;
    std::uniform_real_distribution<double> distribution(-1.0,1.0);

    for (size_t i = 0; i < state.psipnum; i++){
        for (size_t j = 0; j < state.pos.cols()-1; j++){
            state.pos(i,j) = distribution(generator);
        }
    }

    find_weights(state);

    for (size_t i = 0; i < state.psipnum; i++){
        std::cout << state.pos(i,DIMS-1) << '\n';
    }

}

// Calculates energy of a configuration and stores it into the final element of
// the MatrixPSIP
// Note: When calculating the potential, I am not sure whether we need to use
//       absolute value of distance or the distance, itself.
// Note: Inefficient. Can calculate energy on the fly with every generation of
//       psip. Think about it.
// Note: Vref will be a dummy variable for now.
void find_weights(H3plus& state){

    double dist;

    std::default_random_engine gen;
    std::uniform_real_distribution<double> distribution(0,1);

    // Note that this is specific to the Anderson paper
    // Finding the distance between electrons, then adding the distances
    // from the protons to the electrons.
    for (size_t i = 0; i < state.psipnum; i++){
        state.pos(i,DIMS-1) = 0;
        dist = sqrt((state.pos(i,0) - state.pos(i,3)) *
                    (state.pos(i,0) - state.pos(i,3)) +
                    (state.pos(i,1) - state.pos(i,4)) *
                    (state.pos(i,1) - state.pos(i,4)) +
                    (state.pos(i,2) - state.pos(i,5)) *
                    (state.pos(i,2) - state.pos(i,5)));
        for (size_t j = 0; j < state.pos.cols() - 1; j++){
            state.pos(i, DIMS-1) -= exp(-(state.Vref - (1.0 / state.pos(i,j))));
        }
        state.pos(i,DIMS-1) += 1.0 / dist;
        state.pos(i,DIMS-1) = (int)(state.pos(i,DIMS-1) * distribution(gen));
        if (state.pos(i,DIMS-1) > 3){
            state.pos(i,DIMS-1) = 3;
        }
        if (i == 0){state.pos(i,DIMS-1) = 0;}
        if (i == 1){state.pos(i,DIMS-1) = 2;}
        if (i == 2){state.pos(i,DIMS-1) = 0;}
        if (i == 3){state.pos(i,DIMS-1) = 2;}
        if (i == 4){state.pos(i,DIMS-1) = 0;}
        if (i == 5){state.pos(i,DIMS-1) = 2;}
        if (i == 6){state.pos(i,DIMS-1) = 0;}

    }
}

// Branching scheme
void branch(H3plus& state){

    for (size_t i = 0; i < state.psipnum; i++){
        std::cout << state.pos(i,DIMS-1) << '\n';
    }

    int variable, offset = 0, psip_old = state.psipnum, births = 0, off2;

    for (size_t i = 0; i < psip_old + births; i++){

        variable = state.pos(i, DIMS-1);

        switch (variable){
            // Destruction
            case 0: state.psipnum--;
                    offset++;
                    std::cout << "deleting particle" << '\t' << i << '\n';
                    break;

            // Creation of 1
            case 2: state.psipnum++;
                    births++;
                    for (size_t j = 0; j < state.pos.cols() - 1; j++){
                        state.pos(psip_old+births-1,j) = state.pos(i,j);
                    }
                    state.pos(psip_old+births-1,DIMS-1) = 1;
                    break;

            // Creation of 2
            case 3: state.psipnum += 2;
                    births += 2;
                    for (size_t k = 0; k < 2; k++){
                        for (size_t j = 0; j < state.pos.cols() - 1; j++){
                            state.pos(psip_old-k+births-1, j) = state.pos(i, j);
                            std::cout << state.pos(psip_old-k+births-1, j) << '\n';
                        }
                        state.pos(psip_old-k+births-1,DIMS-1) = 1;
                        std::cout << "writing: " << i << " to " << psip_old-k+births-1 << '\n';
                    }
                    break;

        }

        // Adjustment for offset
        off2 = 0;
        while (state.pos(i+ offset + off2, DIMS-1) == 0){
            off2++;
        }
        std::cout << "off2 is equal to: " << off2 << '\n';
        for (size_t j = 0; j < state.pos.cols(); j++){
            state.pos(i,j) = state.pos(i+offset+off2,j);
        }

    }

}

// Random walking of matrix of position created in populate
// Step 1: Move particles via 6D random walk
// Step 2: Destroy and create particles as need based on Anderson
// Step 3: check energy, end if needed.
void diffuse(H3plus& state){

    double dt = 0.1;

    // Let's initialize the randomness
    std::default_random_engine gen;
    std::normal_distribution<double> gaussian(0,1);

    // For now, I am going to set a definite number of timesteps
    // This will be replaced by a while loop in the future.
    for (size_t t = 0; t < 1; t++){
        for (size_t i = 0; i < state.psipnum; i++){
            for (size_t j = 0; j < state.pos.cols() - 1; j++){
                state.pos(i, j) += sqrt(dt) * gaussian(gen);
            }
        }
        branch(state);
    }

}
<commit_msg>now deals with deletions.<commit_after>/*-------------Anderson.cpp---------------------------------------------------//
*
*              Anderson.cpp -- Diffusion Monte Carlo for Schroedy
*
* Purpose: Implement the quantum Monte Carlo (diffusion) by Anderson:
*             http://www.huy-nguyen.com/wp-content/uploads/QMC-papers/Anderson-JChemPhys-1975.pdf
*          For H3+, with 3 protons and 2 electrons
*
*    Note: This algorithm may be improved by later work
*          A "psip" is an imaginary configuration of electrons in space.
*          Requires c++11 for random and Eigen for matrix
*          Protons assume to be at origin
*          A lot of this algorithm is more easily understood here:
*              http://www.thphys.uni-heidelberg.de/~wetzel/qmc2006/KOSZ96.pdf
*
*-----------------------------------------------------------------------------*/

#include <iostream>
#include <random>
#include <Eigen/Core>
#include <fstream>

#define DOF 6
#define SIZE 2000
#define DIMS (DOF + 1)

typedef Eigen::Matrix<double, // typename Scalar
   SIZE, // int RowsAtCompileTime,
   DIMS, // int ColsAtCompileTime,
   0> // int Options = 0,
   MatrixPSIP;

struct H3plus {
    MatrixPSIP pos;
    double Vref;
    int psipnum;
};

// Populate a distribution of particles for QMC
void populate(H3plus& state);

// Calculates energy of a configuration and stores it into the final element of
// the MatrixPSIP
void find_weights(H3plus& state);

// Branching scheme
void branch(H3plus& state);

// Random walking of matrix of position created in populate
void diffuse(H3plus& state);

// output certain elements in array
void arrayout(H3plus& state, int length);

/*----------------------------------------------------------------------------//
* MAIN
*-----------------------------------------------------------------------------*/

int main(){

    std::ofstream output("out.dat", std::ostream::out);
    H3plus state;

    state.Vref = 1;
    state.psipnum = 7;

    populate(state);

    for (size_t i = 0; i < state.psipnum; i++){
        std::cout << " final element is: " << state.pos(i,DIMS-1) << '\n';
    }

    diffuse(state);

    output << state.pos << '\n';

}

/*----------------------------------------------------------------------------//
* SUBROUTINES
*-----------------------------------------------------------------------------*/

// Populate a distribution of particles for QMC
// Unlike Anderson, we are initilizing each psip randomly from a distribution.
// This might screw things up, because
void populate(H3plus& state){

    std::default_random_engine generator;
    std::uniform_real_distribution<double> distribution(-1.0,1.0);

    for (size_t i = 0; i < state.psipnum; i++){
        for (size_t j = 0; j < state.pos.cols()-1; j++){
            state.pos(i,j) = distribution(generator);
        }
    }

    find_weights(state);

    for (size_t i = 0; i < state.psipnum; i++){
        std::cout << state.pos(i,DIMS-1) << '\n';
    }

}

// Calculates energy of a configuration and stores it into the final element of
// the MatrixPSIP
// Note: When calculating the potential, I am not sure whether we need to use
//       absolute value of distance or the distance, itself.
// Note: Inefficient. Can calculate energy on the fly with every generation of
//       psip. Think about it.
// Note: Vref will be a dummy variable for now.
void find_weights(H3plus& state){

    double dist;

    std::default_random_engine gen;
    std::uniform_real_distribution<double> distribution(0,1);

    // Note that this is specific to the Anderson paper
    // Finding the distance between electrons, then adding the distances
    // from the protons to the electrons.
    for (size_t i = 0; i < state.psipnum; i++){
        state.pos(i,DIMS-1) = 0;
        dist = sqrt((state.pos(i,0) - state.pos(i,3)) *
                    (state.pos(i,0) - state.pos(i,3)) +
                    (state.pos(i,1) - state.pos(i,4)) *
                    (state.pos(i,1) - state.pos(i,4)) +
                    (state.pos(i,2) - state.pos(i,5)) *
                    (state.pos(i,2) - state.pos(i,5)));
        for (size_t j = 0; j < state.pos.cols() - 1; j++){
            state.pos(i, DIMS-1) -= exp(-(state.Vref - (1.0 / state.pos(i,j))));
        }
        state.pos(i,DIMS-1) += 1.0 / dist;
        state.pos(i,DIMS-1) = (int)(state.pos(i,DIMS-1) * distribution(gen));
        if (state.pos(i,DIMS-1) > 3){
            state.pos(i,DIMS-1) = 3;
        }
        if (i == 0){state.pos(i,DIMS-1) = 0;}
        if (i == 1){state.pos(i,DIMS-1) = 2;}
        if (i == 2){state.pos(i,DIMS-1) = 0;}
        if (i == 3){state.pos(i,DIMS-1) = 2;}
        if (i == 4){state.pos(i,DIMS-1) = 0;}
        if (i == 5){state.pos(i,DIMS-1) = 2;}
        if (i == 6){state.pos(i,DIMS-1) = 0;}

    }
}

// Branching scheme
void branch(H3plus& state){

    int offarr[SIZE];

    for (size_t i = 0; i < state.psipnum; i++){
        std::cout << state.pos(i,DIMS-1) << '\n';
    }

    int variable, offset = 0, psip_old = state.psipnum, births = 0, tmpoffset,
        tmpi;

    for (size_t i = 0; i < psip_old + births; i++){

        std::cout << i << '\n';

        variable = state.pos(i, DIMS-1);

        switch (variable){
            // Destruction
            case 0: state.psipnum--;
                    break;

            // Creation of 1
            case 2: state.psipnum++;
                    births++;
                    for (size_t j = 0; j < state.pos.cols() - 1; j++){
                        state.pos(psip_old+births-1,j) = state.pos(i,j);
                    }
                    std::cout << "writing: " << i << " to " << psip_old+births-1 << '\n';
                    state.pos(psip_old+births-1,DIMS-1) = 1;
                    break;

            // Creation of 2
            case 3: state.psipnum += 2;
                    births += 2;
                    for (size_t k = 0; k < 2; k++){
                        for (size_t j = 0; j < state.pos.cols() - 1; j++){
                            state.pos(psip_old-k+births-1, j) = state.pos(i, j);
                            std::cout << state.pos(psip_old-k+births-1, j) << '\n';
                        }
                        state.pos(psip_old-k+births-1,DIMS-1) = 1;
                        std::cout << "writing: " << i << " to " << psip_old-k+births-1 << '\n';
                    }
                    break;

        }

        arrayout(state, 10);

    }

    // Adjustment for offset
    // Note: Account for the situation where offset is greater than arraysize
    for (size_t i = 0; i < SIZE; i++){
        if (state.pos(i,DIMS-1) != 0){
            for (size_t j = 0; j < state.pos.cols(); j++){
                state.pos(tmpi,j) = state.pos(i,j);
            }
            tmpi++;
        }
        if (i > state.psipnum){
            for (size_t j = 0; j < state.pos.cols(); j++){
                state.pos(tmpi,j) = 0;
            }

        }
    }

}

// Random walking of matrix of position created in populate
// Step 1: Move particles via 6D random walk
// Step 2: Destroy and create particles as need based on Anderson
// Step 3: check energy, end if needed.
void diffuse(H3plus& state){

    double dt = 0.1;

    // Let's initialize the randomness
    std::default_random_engine gen;
    std::normal_distribution<double> gaussian(0,1);

    // For now, I am going to set a definite number of timesteps
    // This will be replaced by a while loop in the future.
    for (size_t t = 0; t < 1; t++){
        for (size_t i = 0; i < state.psipnum; i++){
            for (size_t j = 0; j < state.pos.cols() - 1; j++){
                state.pos(i, j) += sqrt(dt) * gaussian(gen);
            }
        }
        branch(state);
    }

}

// output certain elements in array
void arrayout(H3plus& state, int length){

    for (size_t i = 0; i < length; i++){
        for (size_t j  = 0; j < 2; j++){
            std::cout << state.pos(i,DIMS - 1 - j) << '\t';
        }
        std::cout << '\n';
    }
}

<|endoftext|>


<commit_before>#include <errno.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/select.h>
#include <unistd.h>
#include <QtCore>
#include <stdexcept>

#include "hp34970hack.h"

// set DC voltage
// SENS:VOLT:DC ()
// 'SENS:VOLT:DC:RANG'+qs+', (@'+IntToStr(chan)+')';
// SENS:VOLT:DC:NPLC'+qs+', (@'+IntToStr(chan)+')'

// read value
// ROUT:SCAN ()
// READ?
//

// howto:
// conf:res (@101); :conf:volt (@103,104
// ROUT:SCAN (@101,103,104)

/*
procedure THall.ResBtnClick(Sender: TObject);
var s:string;
    kod:integer;
    cur,volp,voln,Ra,Rb,Rs,pomr,t:double;
begin
 ResBtn.Enabled:=false; HallBtn.Enabled:=false;
 OpenChannel('209,210');
 s:=EditCurr.Text; val(s,cur,kod);
 if not(kod=0) then begin
  ShowMessage('Failed to Convert'+#13+'Current to Number');
  exit;
 end;
 s:=EditT.Text; val(s,t,kod);
 if not(kod=0) then begin
  ShowMessage('Failed to Convert'+#13+'Thickness to Number');
  exit;
 end;
 t:=t/10;
 cur:=cur/1000; str(cur:5:3,s);
 { --- Measure R_a --- }
 SetCurrent(s);
 CloseChannel('201,202'); KPausa(300);
 ApplyCurrent(True);
 KPausa(500);
 volp:=-ReadValue(101);
 ApplyCurrent(False);
 str(-cur:6:4,s);
 SetCurrent(s);  KPausa(300);
 ApplyCurrent(True);
 KPausa(500);
 voln:=-ReadValue(101);
 ApplyCurrent(False);
 OpenChannel('201');
 Ra:=(volp-voln)/2/cur*t; str(Ra:7:5,s);
 EditRa.Text:=s;
 { --- Measure R_b --- }
 str(cur:6:4,s);
 SetCurrent(s);
 CloseChannel('203,205'); KPausa(300);
 ApplyCurrent(True);
 KPausa(500);
 volp:=ReadValue(102);
 ApplyCurrent(False);
 str(-cur:6:4,s);
 SetCurrent(s);  KPausa(300);
 ApplyCurrent(True);
 KPausa(500);
 voln:=ReadValue(102);
 ApplyCurrent(False);
 OpenChannel('202,203,205');
 Rb:=(volp-voln)/2/cur*t; str(Rb:7:5,s);
 EditRb.Text:=s;
 { --- Calculate R_s --- }
 Rs:=SolveRs(Ra,Rb,kod);   //(Ra+Rb)/2; kod:=0;
 if not(kod=0) then ShowMessage('Failed on Calculating Rs');
 str(Rs:7:5,s);
 EditRs.Text:=s;
 { --- Measure Field --- }
 CloseChannel('209,210');
 SetCurrent('0.001'); KPausa(300);
 ApplyCurrent(true);
 KPausa(500);
 pomr:=ReadValue(114)*1000;
 pomr:=-30.588+sqrt(934.773+0.392163*pomr);
 ApplyCurrent(false);
 str(pomr:4:2,s);
 EditB.Text:=s;
 ResBtn.Enabled:=true; HallBtn.Enabled:=true;
end;

procedure THall.HallBtnClick(Sender: TObject);
var s:string;
    kod:integer;
    cur,volp,voln,Ra,Rb,Rs,pomr,t:double;
begin
 ResBtn.Enabled:=false; HallBtn.Enabled:=false;
 OpenChannel('209,210');
 s:=EditCurr.Text; val(s,cur,kod);
 if not(kod=0) then begin
  ShowMessage('Failed to Convert'+#13+'Current to Number');
  exit;
 end;
 s:=EditT.Text; val(s,t,kod);
 if not(kod=0) then begin
  ShowMessage('Failed to Convert'+#13+'Thickness to Number');
  exit;
 end;
 t:=t/10;
 cur:=cur/1000; str(cur:6:4,s);
 { --- Measure R_b --- }
 SetCurrent(s);
 CloseChannel('202,204'); KPausa(300);
 ApplyCurrent(True);
 KPausa(500);
 volp:=ReadValue(104);
 ApplyCurrent(False);
 str(-cur:6:4,s);
 SetCurrent(s);  KPausa(300);
 ApplyCurrent(True);
 KPausa(500);
 voln:=ReadValue(104);
 ApplyCurrent(False);
 OpenChannel('202,204');
 Rb:=(volp-voln)/2/cur*t;
 s:=Format('%6.3e',[Rb]);
 Delete(s,Length(s)-2,2);
 EditVb.Text:=s;
 { --- Measure R_a --- }
 str(cur:6:4,s);
 SetCurrent(s);
 CloseChannel('201,203,206'); KPausa(300);
 ApplyCurrent(True);
 KPausa(500);
 volp:=ReadValue(103);
 ApplyCurrent(False);
 str(-cur:6:4,s);
 SetCurrent(s);  KPausa(300);
 ApplyCurrent(True);
 KPausa(500);
 voln:=ReadValue(103);
 ApplyCurrent(False);
 OpenChannel('201,203,206');
 Ra:=(volp-voln)/2/cur*t;
 s:=Format('%6.3e',[Ra]);
 Delete(s,Length(s)-2,2);
 EditVa.Text:=s;
 { --- Measure Field --- }
 CloseChannel('209,210');
 SetCurrent('0.001'); KPausa(300);
 ApplyCurrent(true);
 KPausa(500);
 pomr:=ReadValue(114)*1000;
 pomr:=-30.588+sqrt(934.773+0.392163*pomr);
 ApplyCurrent(false);
 str(pomr:4:2,s);
 EditB.Text:=s;
 { --- Calculate V/B/I --- }
 Rs:=Ra/pomr*10000;
 s:=Format('%6.3e',[Rs]);
 Delete(s,Length(s)-2,2);
 EditUB.Text:=s;
 ResBtn.Enabled:=true; HallBtn.Enabled:=true;
end;
*/

HP34970hack::HP34970hack() :
    QSerial()
{
}

HP34970hack::~HP34970hack()
{
    close();
}

void HP34970hack::close()
{
    QSerial::close();
}

void HP34970hack::sendCmd(QString cmd, long timeout)
{
    QString s;

    s = sendQuery(cmd, timeout);
    if (!s.isEmpty())
        throw new std::runtime_error("P34970hack::cmd response not empty.");
}

bool HP34970hack::open(QString port)
{
    const long timeout = (10l * 1000000l) / 9600l;

    close();

    if (!QSerial::open(port, QSerial::Baude9600, 300000, timeout))
        return false;

    QString s("syst:rem");

    write("\n");
    sendCmd("*RST", 500000);
    sendCmd(s);

    return true;
}

QString HP34970hack::sendQuery(QString cmd, long timeout)
{
    QString s;

    s = cmd.trimmed().append(";*OPC?\n");
    write(s);
    s = readLine(1024, timeout).trimmed();
    if (!s.endsWith('1'))
        throw new std::runtime_error("P34970hack::sendQuery failed read response.");
    if (s.endsWith(";1"))
        return s.left(s.size() - 2);

    return s.left(s.size() - 1);
}

QString HP34970hack::readCmd()
{
    QString s;

    s = sendQuery("read?");
    return s;
}

void HP34970hack::setChannel(int channel, bool open)
{
    // ROUT:SCAN (@101,103,104) pro nastaveni z ktereho portu read? čte hodnoty
}

void HP34970hack::setup()
{
    sendCmd("conf:volt (@101:104)");
    sendCmd("ROUT:CLOS (@201:206,209,210)");
    sendCmd("init", 2000000);
}

<commit_msg>Normalize SCPI commands.<commit_after>#include <errno.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/select.h>
#include <unistd.h>
#include <QtCore>
#include <stdexcept>

#include "hp34970hack.h"

// set DC voltage
// SENS:VOLT:DC ()
// 'SENS:VOLT:DC:RANG'+qs+', (@'+IntToStr(chan)+')';
// SENS:VOLT:DC:NPLC'+qs+', (@'+IntToStr(chan)+')'

// read value
// ROUT:SCAN ()
// READ?
//

// howto:
// conf:res (@101); :conf:volt (@103,104
// ROUT:SCAN (@101,103,104)

/*
procedure THall.ResBtnClick(Sender: TObject);
var s:string;
    kod:integer;
    cur,volp,voln,Ra,Rb,Rs,pomr,t:double;
begin
 ResBtn.Enabled:=false; HallBtn.Enabled:=false;
 OpenChannel('209,210');
 s:=EditCurr.Text; val(s,cur,kod);
 if not(kod=0) then begin
  ShowMessage('Failed to Convert'+#13+'Current to Number');
  exit;
 end;
 s:=EditT.Text; val(s,t,kod);
 if not(kod=0) then begin
  ShowMessage('Failed to Convert'+#13+'Thickness to Number');
  exit;
 end;
 t:=t/10;
 cur:=cur/1000; str(cur:5:3,s);
 { --- Measure R_a --- }
 SetCurrent(s);
 CloseChannel('201,202'); KPausa(300);
 ApplyCurrent(True);
 KPausa(500);
 volp:=-ReadValue(101);
 ApplyCurrent(False);
 str(-cur:6:4,s);
 SetCurrent(s);  KPausa(300);
 ApplyCurrent(True);
 KPausa(500);
 voln:=-ReadValue(101);
 ApplyCurrent(False);
 OpenChannel('201');
 Ra:=(volp-voln)/2/cur*t; str(Ra:7:5,s);
 EditRa.Text:=s;
 { --- Measure R_b --- }
 str(cur:6:4,s);
 SetCurrent(s);
 CloseChannel('203,205'); KPausa(300);
 ApplyCurrent(True);
 KPausa(500);
 volp:=ReadValue(102);
 ApplyCurrent(False);
 str(-cur:6:4,s);
 SetCurrent(s);  KPausa(300);
 ApplyCurrent(True);
 KPausa(500);
 voln:=ReadValue(102);
 ApplyCurrent(False);
 OpenChannel('202,203,205');
 Rb:=(volp-voln)/2/cur*t; str(Rb:7:5,s);
 EditRb.Text:=s;
 { --- Calculate R_s --- }
 Rs:=SolveRs(Ra,Rb,kod);   //(Ra+Rb)/2; kod:=0;
 if not(kod=0) then ShowMessage('Failed on Calculating Rs');
 str(Rs:7:5,s);
 EditRs.Text:=s;
 { --- Measure Field --- }
 CloseChannel('209,210');
 SetCurrent('0.001'); KPausa(300);
 ApplyCurrent(true);
 KPausa(500);
 pomr:=ReadValue(114)*1000;
 pomr:=-30.588+sqrt(934.773+0.392163*pomr);
 ApplyCurrent(false);
 str(pomr:4:2,s);
 EditB.Text:=s;
 ResBtn.Enabled:=true; HallBtn.Enabled:=true;
end;

procedure THall.HallBtnClick(Sender: TObject);
var s:string;
    kod:integer;
    cur,volp,voln,Ra,Rb,Rs,pomr,t:double;
begin
 ResBtn.Enabled:=false; HallBtn.Enabled:=false;
 OpenChannel('209,210');
 s:=EditCurr.Text; val(s,cur,kod);
 if not(kod=0) then begin
  ShowMessage('Failed to Convert'+#13+'Current to Number');
  exit;
 end;
 s:=EditT.Text; val(s,t,kod);
 if not(kod=0) then begin
  ShowMessage('Failed to Convert'+#13+'Thickness to Number');
  exit;
 end;
 t:=t/10;
 cur:=cur/1000; str(cur:6:4,s);
 { --- Measure R_b --- }
 SetCurrent(s);
 CloseChannel('202,204'); KPausa(300);
 ApplyCurrent(True);
 KPausa(500);
 volp:=ReadValue(104);
 ApplyCurrent(False);
 str(-cur:6:4,s);
 SetCurrent(s);  KPausa(300);
 ApplyCurrent(True);
 KPausa(500);
 voln:=ReadValue(104);
 ApplyCurrent(False);
 OpenChannel('202,204');
 Rb:=(volp-voln)/2/cur*t;
 s:=Format('%6.3e',[Rb]);
 Delete(s,Length(s)-2,2);
 EditVb.Text:=s;
 { --- Measure R_a --- }
 str(cur:6:4,s);
 SetCurrent(s);
 CloseChannel('201,203,206'); KPausa(300);
 ApplyCurrent(True);
 KPausa(500);
 volp:=ReadValue(103);
 ApplyCurrent(False);
 str(-cur:6:4,s);
 SetCurrent(s);  KPausa(300);
 ApplyCurrent(True);
 KPausa(500);
 voln:=ReadValue(103);
 ApplyCurrent(False);
 OpenChannel('201,203,206');
 Ra:=(volp-voln)/2/cur*t;
 s:=Format('%6.3e',[Ra]);
 Delete(s,Length(s)-2,2);
 EditVa.Text:=s;
 { --- Measure Field --- }
 CloseChannel('209,210');
 SetCurrent('0.001'); KPausa(300);
 ApplyCurrent(true);
 KPausa(500);
 pomr:=ReadValue(114)*1000;
 pomr:=-30.588+sqrt(934.773+0.392163*pomr);
 ApplyCurrent(false);
 str(pomr:4:2,s);
 EditB.Text:=s;
 { --- Calculate V/B/I --- }
 Rs:=Ra/pomr*10000;
 s:=Format('%6.3e',[Rs]);
 Delete(s,Length(s)-2,2);
 EditUB.Text:=s;
 ResBtn.Enabled:=true; HallBtn.Enabled:=true;
end;
*/

HP34970hack::HP34970hack() :
    QSerial()
{
}

HP34970hack::~HP34970hack()
{
    close();
}

void HP34970hack::close()
{
    QSerial::close();
}

void HP34970hack::sendCmd(QString cmd, long timeout)
{
    QString s;

    s = sendQuery(cmd, timeout);
    if (!s.isEmpty())
        throw new std::runtime_error("P34970hack::cmd response not empty.");
}

bool HP34970hack::open(QString port)
{
    const long timeout = (10l * 1000000l) / 9600l;

    close();

    if (!QSerial::open(port, QSerial::Baude9600, 300000, timeout))
        return false;

    write("\n");
    sendCmd("*RST;*CLS", 500000);
    sendCmd("SYST:REM");

    return true;
}

QString HP34970hack::sendQuery(QString cmd, long timeout)
{
    QString s;

    s = cmd.trimmed().append(";*OPC?\n");
    write(s);
    s = readLine(1024, timeout).trimmed();
    if (!s.endsWith('1'))
        throw new std::runtime_error("P34970hack::sendQuery failed read response.");
    if (s.endsWith(";1"))
        return s.left(s.size() - 2);

    return s.left(s.size() - 1);
}

QString HP34970hack::readCmd()
{
    QString s;

    s = sendQuery("READ?");
    return s;
}

void HP34970hack::setChannel(int channel, bool open)
{
    // ROUT:SCAN (@101,103,104) pro nastaveni z ktereho portu read? čte hodnoty
}

void HP34970hack::setup()
{
    sendCmd("CONF:VOLT (@101:104)");
    sendCmd("ROUT:CLOS (@201:206,209,210)");
    sendCmd("INIT", 2000000);
}

<|endoftext|>


<commit_before>/*

Copyright (c) 2008, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"

#include <cctype>
#include <algorithm>
#include <stdlib.h>

#include "libtorrent/config.hpp"
#include "libtorrent/http_parser.hpp"
#include "libtorrent/assert.hpp"
#include "libtorrent/escape_string.hpp"

using namespace libtorrent;

namespace libtorrent
{
	http_parser::http_parser()
		: m_recv_pos(0)
		, m_status_code(-1)
		, m_content_length(-1)
		, m_range_start(-1)
		, m_range_end(-1)
		, m_state(read_status)
		, m_recv_buffer(0, 0)
		, m_body_start_pos(0)
		, m_finished(false)
	{}

	boost::tuple<int, int> http_parser::incoming(
		buffer::const_interval recv_buffer, bool& error)
	{
		TORRENT_ASSERT(recv_buffer.left() >= m_recv_buffer.left());
		boost::tuple<int, int> ret(0, 0);
		int start_pos = m_recv_buffer.left();

		// early exit if there's nothing new in the receive buffer
		if (start_pos == recv_buffer.left()) return ret;
		m_recv_buffer = recv_buffer;

		if (m_state == error_state)
		{
			error = true;
			return ret;
		}

		char const* pos = recv_buffer.begin + m_recv_pos;
		if (m_state == read_status)
		{
			TORRENT_ASSERT(!m_finished);
			char const* newline = std::find(pos, recv_buffer.end, '\n');
			// if we don't have a full line yet, wait.
			if (newline == recv_buffer.end)
			{
				boost::get<1>(ret) += m_recv_buffer.left() - start_pos;
				return ret;
			}

			if (newline == pos)
			{
				m_state = error_state;
				error = true;
				return ret;
			}

			char const* line_end = newline;
			if (pos != line_end && *(line_end - 1) == '\r') --line_end;

			std::istringstream line(std::string(pos, line_end));
			++newline;
			int incoming = (int)std::distance(pos, newline);
			m_recv_pos += incoming;
			boost::get<1>(ret) += newline - (m_recv_buffer.begin + start_pos);
			pos = newline;

			line >> m_protocol;
			if (m_protocol.substr(0, 5) == "HTTP/")
			{
				line >> m_status_code;
				std::getline(line, m_server_message);
			}
			else
			{
				m_method = m_protocol;
				std::transform(m_method.begin(), m_method.end(), m_method.begin(), &to_lower);
				m_protocol.clear();
				line >> m_path >> m_protocol;
				m_status_code = 0;
			}
			m_state = read_header;
			start_pos = pos - recv_buffer.begin;
		}

		if (m_state == read_header)
		{
			TORRENT_ASSERT(!m_finished);
			char const* newline = std::find(pos, recv_buffer.end, '\n');
			std::string line;

			while (newline != recv_buffer.end && m_state == read_header)
			{
				// if the LF character is preceeded by a CR
				// charachter, don't copy it into the line string.
				char const* line_end = newline;
				if (pos != line_end && *(line_end - 1) == '\r') --line_end;
				line.assign(pos, line_end);
				++newline;
				m_recv_pos += newline - pos;
				pos = newline;

				std::string::size_type separator = line.find(':');
				if (separator == std::string::npos)
				{
					// this means we got a blank line,
					// the header is finished and the body
					// starts.
					m_state = read_body;
					// if this is a request (not a response)
					// we're done once we reach the end of the headers
					if (!m_method.empty()) m_finished = true;
					m_body_start_pos = m_recv_pos;
					break;
				}

				std::string name = line.substr(0, separator);
				std::transform(name.begin(), name.end(), name.begin(), &to_lower);
				++separator;
				// skip whitespace
				while (separator < line.size()
					&& (line[separator] == ' ' || line[separator] == '\t'))
					++separator;
				std::string value = line.substr(separator, std::string::npos);
				m_header.insert(std::make_pair(name, value));

				if (name == "content-length")
				{
					m_content_length = strtoll(value.c_str(), 0, 10);
				}
				else if (name == "content-range")
				{
					bool success = true;
					char const* ptr = value.c_str();

					// apparently some web servers do not send the "bytes"
					// in their content-range. Don't treat it as an error
					// if we can't find it, just assume the byte counters
					// start immediately
					if (string_begins_no_case("bytes ", ptr)) ptr += 6;
					char* end;
					m_range_start = strtoll(ptr, &end, 10);
					if (end == ptr) success = false;
					else if (*end != '-') success = false;
					else
					{
						ptr = end + 1;
						m_range_end = strtoll(ptr, &end, 10);
						if (end == ptr) success = false;
					}

					if (!success || m_range_end < m_range_start)
					{
						m_state = error_state;
						error = true;
						return ret;
					}
					// the http range is inclusive
					m_content_length = m_range_end - m_range_start + 1;
				}

				TORRENT_ASSERT(m_recv_pos <= (int)recv_buffer.left());
				newline = std::find(pos, recv_buffer.end, '\n');
			}
			boost::get<1>(ret) += newline - (m_recv_buffer.begin + start_pos);
		}

		if (m_state == read_body)
		{
			int incoming = recv_buffer.end - pos;
			if (m_recv_pos - m_body_start_pos + incoming > m_content_length
				&& m_content_length >= 0)
				incoming = m_content_length - m_recv_pos + m_body_start_pos;

			TORRENT_ASSERT(incoming >= 0);
			m_recv_pos += incoming;
			boost::get<0>(ret) += incoming;

			if (m_content_length >= 0
				&& m_recv_pos - m_body_start_pos >= m_content_length)
			{
				m_finished = true;
			}
		}
		return ret;
	}

	buffer::const_interval http_parser::get_body() const
	{
		TORRENT_ASSERT(m_state == read_body);
		if (m_content_length >= 0)
			return buffer::const_interval(m_recv_buffer.begin + m_body_start_pos
				, m_recv_buffer.begin + (std::min)(size_type(m_recv_pos)
				, m_body_start_pos + m_content_length));
		else
			return buffer::const_interval(m_recv_buffer.begin + m_body_start_pos
				, m_recv_buffer.begin + m_recv_pos);
	}

	void http_parser::reset()
	{
		m_recv_pos = 0;
		m_body_start_pos = 0;
		m_status_code = -1;
		m_content_length = -1;
		m_range_start = -1;
		m_range_end = -1;
		m_finished = false;
		m_state = read_status;
		m_recv_buffer.begin = 0;
		m_recv_buffer.end = 0;
		m_header.clear();
	}

}

<commit_msg>content length of http requests are assumed to be 0<commit_after>/*

Copyright (c) 2008, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"

#include <cctype>
#include <algorithm>
#include <stdlib.h>

#include "libtorrent/config.hpp"
#include "libtorrent/http_parser.hpp"
#include "libtorrent/assert.hpp"
#include "libtorrent/escape_string.hpp"

using namespace libtorrent;

namespace libtorrent
{
	http_parser::http_parser()
		: m_recv_pos(0)
		, m_status_code(-1)
		, m_content_length(-1)
		, m_range_start(-1)
		, m_range_end(-1)
		, m_state(read_status)
		, m_recv_buffer(0, 0)
		, m_body_start_pos(0)
		, m_finished(false)
	{}

	boost::tuple<int, int> http_parser::incoming(
		buffer::const_interval recv_buffer, bool& error)
	{
		TORRENT_ASSERT(recv_buffer.left() >= m_recv_buffer.left());
		boost::tuple<int, int> ret(0, 0);
		int start_pos = m_recv_buffer.left();

		// early exit if there's nothing new in the receive buffer
		if (start_pos == recv_buffer.left()) return ret;
		m_recv_buffer = recv_buffer;

		if (m_state == error_state)
		{
			error = true;
			return ret;
		}

		char const* pos = recv_buffer.begin + m_recv_pos;
		if (m_state == read_status)
		{
			TORRENT_ASSERT(!m_finished);
			char const* newline = std::find(pos, recv_buffer.end, '\n');
			// if we don't have a full line yet, wait.
			if (newline == recv_buffer.end)
			{
				boost::get<1>(ret) += m_recv_buffer.left() - start_pos;
				return ret;
			}

			if (newline == pos)
			{
				m_state = error_state;
				error = true;
				return ret;
			}

			char const* line_end = newline;
			if (pos != line_end && *(line_end - 1) == '\r') --line_end;

			std::istringstream line(std::string(pos, line_end));
			++newline;
			int incoming = (int)std::distance(pos, newline);
			m_recv_pos += incoming;
			boost::get<1>(ret) += newline - (m_recv_buffer.begin + start_pos);
			pos = newline;

			line >> m_protocol;
			if (m_protocol.substr(0, 5) == "HTTP/")
			{
				line >> m_status_code;
				std::getline(line, m_server_message);
			}
			else
			{
				m_method = m_protocol;
				std::transform(m_method.begin(), m_method.end(), m_method.begin(), &to_lower);
				// the content length is assumed to be 0 for requests
				m_content_length = 0;
				m_protocol.clear();
				line >> m_path >> m_protocol;
				m_status_code = 0;
			}
			m_state = read_header;
			start_pos = pos - recv_buffer.begin;
		}

		if (m_state == read_header)
		{
			TORRENT_ASSERT(!m_finished);
			char const* newline = std::find(pos, recv_buffer.end, '\n');
			std::string line;

			while (newline != recv_buffer.end && m_state == read_header)
			{
				// if the LF character is preceeded by a CR
				// charachter, don't copy it into the line string.
				char const* line_end = newline;
				if (pos != line_end && *(line_end - 1) == '\r') --line_end;
				line.assign(pos, line_end);
				++newline;
				m_recv_pos += newline - pos;
				pos = newline;

				std::string::size_type separator = line.find(':');
				if (separator == std::string::npos)
				{
					// this means we got a blank line,
					// the header is finished and the body
					// starts.
					m_state = read_body;
					// if this is a request (not a response)
					// we're done once we reach the end of the headers
					if (!m_method.empty()) m_finished = true;
					m_body_start_pos = m_recv_pos;
					break;
				}

				std::string name = line.substr(0, separator);
				std::transform(name.begin(), name.end(), name.begin(), &to_lower);
				++separator;
				// skip whitespace
				while (separator < line.size()
					&& (line[separator] == ' ' || line[separator] == '\t'))
					++separator;
				std::string value = line.substr(separator, std::string::npos);
				m_header.insert(std::make_pair(name, value));

				if (name == "content-length")
				{
					m_content_length = strtoll(value.c_str(), 0, 10);
				}
				else if (name == "content-range")
				{
					bool success = true;
					char const* ptr = value.c_str();

					// apparently some web servers do not send the "bytes"
					// in their content-range. Don't treat it as an error
					// if we can't find it, just assume the byte counters
					// start immediately
					if (string_begins_no_case("bytes ", ptr)) ptr += 6;
					char* end;
					m_range_start = strtoll(ptr, &end, 10);
					if (end == ptr) success = false;
					else if (*end != '-') success = false;
					else
					{
						ptr = end + 1;
						m_range_end = strtoll(ptr, &end, 10);
						if (end == ptr) success = false;
					}

					if (!success || m_range_end < m_range_start)
					{
						m_state = error_state;
						error = true;
						return ret;
					}
					// the http range is inclusive
					m_content_length = m_range_end - m_range_start + 1;
				}

				TORRENT_ASSERT(m_recv_pos <= (int)recv_buffer.left());
				newline = std::find(pos, recv_buffer.end, '\n');
			}
			boost::get<1>(ret) += newline - (m_recv_buffer.begin + start_pos);
		}

		if (m_state == read_body)
		{
			int incoming = recv_buffer.end - pos;
			if (m_recv_pos - m_body_start_pos + incoming > m_content_length
				&& m_content_length >= 0)
				incoming = m_content_length - m_recv_pos + m_body_start_pos;

			TORRENT_ASSERT(incoming >= 0);
			m_recv_pos += incoming;
			boost::get<0>(ret) += incoming;

			if (m_content_length >= 0
				&& m_recv_pos - m_body_start_pos >= m_content_length)
			{
				m_finished = true;
			}
		}
		return ret;
	}

	buffer::const_interval http_parser::get_body() const
	{
		TORRENT_ASSERT(m_state == read_body);
		if (m_content_length >= 0)
			return buffer::const_interval(m_recv_buffer.begin + m_body_start_pos
				, m_recv_buffer.begin + (std::min)(size_type(m_recv_pos)
				, m_body_start_pos + m_content_length));
		else
			return buffer::const_interval(m_recv_buffer.begin + m_body_start_pos
				, m_recv_buffer.begin + m_recv_pos);
	}

	void http_parser::reset()
	{
		m_recv_pos = 0;
		m_body_start_pos = 0;
		m_status_code = -1;
		m_content_length = -1;
		m_range_start = -1;
		m_range_end = -1;
		m_finished = false;
		m_state = read_status;
		m_recv_buffer.begin = 0;
		m_recv_buffer.end = 0;
		m_header.clear();
	}

}

<|endoftext|>