<commit_before>/*
 * The BENG request struct.  This is only used by the handlers
 * (handler.c, file-handler.c etc.).
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "request.hxx"
#include "bp_connection.hxx"
#include "bp_instance.hxx"
#include "session.hxx"
#include "session_manager.hxx"
#include "http_server/Request.hxx"
#include "cookie_server.hxx"
#include "bot.h"
#include "shm/dpool.hxx"
#include "pbuffer.hxx"
#include "strmap.hxx"
#include "crc.h"
#include "format.h"
#include "expiry.h"

#include <daemon/log.h>

static const struct strmap *
request_get_cookies(Request &request)
{
    if (request.cookies != nullptr)
        return request.cookies;

    const char *cookie = request.request.headers->Get("cookie");
    if (cookie == nullptr)
        return nullptr;

    request.cookies = strmap_new(&request.pool);
    cookie_map_parse(request.cookies, cookie, &request.pool);

    return request.cookies;
}

static Session *
request_load_session(Request &request, const char *session_id)
{
    assert(!request.stateless);
    assert(!request.session_id.IsDefined());
    assert(session_id != nullptr);

    if (!request.session_id.Parse(session_id))
        return nullptr;

    auto *session = request.GetSession();
    if (session == nullptr)
        return nullptr;

    if (!session->translate.IsNull())
        request.translate.request.session = DupBuffer(request.pool,
                                                      session->translate);

    if (session->site != nullptr)
        request.connection.site_name = p_strdup(&request.pool,
                                                session->site);

    if (!session->cookie_sent)
        request.send_session_cookie = true;

    session->is_new = false;

    return session;
}

static const char *
build_session_cookie_name(struct pool *pool, const BpConfig *config,
                          const struct strmap *headers)
{
    if (headers == nullptr || !config->dynamic_session_cookie)
        return config->session_cookie;

    const char *host = headers->Get("host");
    if (host == nullptr || *host == 0)
        return config->session_cookie;

    size_t length = strlen(config->session_cookie);
    char *name = PoolAlloc<char>(*pool, length + 5);
    memcpy(name, config->session_cookie, length);
    format_uint16_hex_fixed(name + length, crc16_string(0, host));
    name[length + 4] = 0;
    return name;
}

static const char *
request_get_uri_session_id(const Request &request)
{
    assert(!request.stateless);

    return strmap_get_checked(request.args, "session");
}

static const char *
request_get_cookie_session_id(Request &request)
{
    assert(!request.stateless);
    assert(request.session_cookie != nullptr);

    const auto *cookies = request_get_cookies(request);

    return strmap_get_checked(cookies, request.session_cookie);
}

void
Request::DetermineSession()
{
    session_realm = nullptr;

    const char *user_agent = request.headers->Get("user-agent");
    stateless = user_agent == nullptr || user_agent_is_bot(user_agent);
    if (stateless) {
        /* don't propagate a stale session id to processed URIs */
        if (args != nullptr)
            args->Remove("session");
        return;
    }

    session_cookie = build_session_cookie_name(&pool,
                                               &instance.config,
                                               request.headers);

    const char *sid = request_get_uri_session_id(*this);
    bool cookie_received = false;
    if (sid == nullptr || *sid == 0) {
        sid = request_get_cookie_session_id(*this);
        if (sid == nullptr)
            return;

        cookie_received = true;
    }

    auto *session = request_load_session(*this, sid);
    if (session == nullptr) {
        if (!cookie_received && args != nullptr)
            /* remove invalid session id from URI args */
            args->Remove("session");

        return;
    }

    if (!cookie_received) {
        const char *p = request_get_cookie_session_id(*this);
        if (p != nullptr && strcmp(p, sid) == 0)
            cookie_received = true;
    }

    if (cookie_received) {
        session->cookie_received = true;

        if (args != nullptr)
            /* we're using cookies, and we can safely remove the
               session id from the args */
            args->Remove("session");
    }

    session_realm = p_strdup(&pool, session->realm);

    session_put(session);
}

Session *
Request::MakeSession()
{
    if (stateless)
        return nullptr;

    auto *session = GetSession();
    if (session != nullptr)
        return session;

    session = session_new(realm);
    if (session == nullptr) {
        daemon_log(1, "Failed to allocate a session\n");
        return nullptr;
    }

    session_id = session->id;
    send_session_cookie = true;

    if (args == nullptr)
        args = strmap_new(&pool);
    args->Set("session", session_id.Format(session_id_string));

    return session;
}

void
Request::IgnoreSession()
{
    if (!session_id.IsDefined())
        return;

    assert(!stateless);

    if (args != nullptr)
        args->Remove("session");

    session_id.Clear();
    send_session_cookie = false;
}

void
Request::DiscardSession()
{
    if (!session_id.IsDefined())
        return;

    assert(!stateless);

    if (args != nullptr)
        args->Remove("session");

    session_delete(session_id);
    session_id.Clear();
    send_session_cookie = false;
}

/**
 * Determine the realm name, consider the override by the translation
 * server.  Guaranteed to return non-nullptr.
 */
static const char *
get_request_realm(struct pool *pool, const struct strmap *request_headers,
                  const TranslateResponse &response,
                  ConstBuffer<void> auth_base)
{
    if (response.realm != nullptr)
        return response.realm;

    if (response.realm_from_auth_base) {
        assert(!auth_base.IsNull());
        // TODO: what if AUTH contains null bytes?
        return p_strndup(pool, (const char *)auth_base.data, auth_base.size);
    }

    const char *host = strmap_get_checked(request_headers, "host");
    if (host != nullptr)
        return p_strdup_lower(pool, host);

    /* fall back to empty string as the default realm if there is no
       "Host" header */
    return "";
}

void
Request::ApplyTranslateRealm(const TranslateResponse &response,
                             ConstBuffer<void> auth_base)
{
    if (realm != nullptr)
        /* was already called by Request::HandleAuth(), and no need to
           check again */
        return;

    realm = get_request_realm(&pool, request.headers, response, auth_base);

    if (session_realm != nullptr && strcmp(realm, session_realm) != 0) {
        daemon_log(2, "ignoring spoofed session id from another realm (session='%s', request='%s', uri='%s')\n",
                   session_realm, realm, request.uri);
        IgnoreSession();
    }
}

Session *
Request::ApplyTranslateSession(const TranslateResponse &response)
{
    if (response.session.IsNull() && response.user == nullptr &&
        response.session_site == nullptr &&
        response.language == nullptr)
        return nullptr;

    auto *session = GetSession();

    if (!response.session.IsNull()) {
        if (response.session.IsEmpty()) {
            /* clear translate session */

            if (session != nullptr)
                session->ClearTranslate();
        } else {
            /* set new translate session */

            if (session == nullptr)
                session = MakeSession();

            if (session != nullptr)
                session->SetTranslate(response.session);
        }
    }

    if (response.session_site != nullptr) {
        if (*response.session_site == 0) {
            /* clear site */

            if (session != nullptr)
                session->ClearSite();
        } else {
            /* set new site */

            if (session == nullptr)
                session = MakeSession();

            if (session != nullptr)
                session->SetSite(response.session_site);

            connection.site_name = response.session_site;
        }
    }

    if (response.user != nullptr) {
        if (*response.user == 0) {
            /* log out */

            if (session != nullptr)
                session->ClearUser();
        } else {
            /* log in */

            if (session == nullptr)
                session = MakeSession();

            if (session != nullptr)
                session->SetUser(response.user, response.user_max_age);
        }
    } else if (session != nullptr && session->user != nullptr &&
               session->user_expires > 0 &&
               is_expired(session->user_expires)) {
        daemon_log(4, "user '%s' has expired\n", session->user);
        d_free(&session->pool, session->user);
        session->user = nullptr;
    }

    if (response.language != nullptr) {
        if (*response.language == 0) {
            /* reset language setting */

            if (session != nullptr)
                session->ClearLanguage();
        } else {
            /* override language */

            if (session == nullptr)
                session = MakeSession();

            if (session != nullptr)
                session->SetLanguage(response.language);
        }
    }

    return session;
}
<commit_msg>request_session: use Session::ClearUser()<commit_after>/*
 * The BENG request struct.  This is only used by the handlers
 * (handler.c, file-handler.c etc.).
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "request.hxx"
#include "bp_connection.hxx"
#include "bp_instance.hxx"
#include "session.hxx"
#include "session_manager.hxx"
#include "http_server/Request.hxx"
#include "cookie_server.hxx"
#include "bot.h"
#include "pbuffer.hxx"
#include "strmap.hxx"
#include "crc.h"
#include "format.h"
#include "expiry.h"

#include <daemon/log.h>

static const struct strmap *
request_get_cookies(Request &request)
{
    if (request.cookies != nullptr)
        return request.cookies;

    const char *cookie = request.request.headers->Get("cookie");
    if (cookie == nullptr)
        return nullptr;

    request.cookies = strmap_new(&request.pool);
    cookie_map_parse(request.cookies, cookie, &request.pool);

    return request.cookies;
}

static Session *
request_load_session(Request &request, const char *session_id)
{
    assert(!request.stateless);
    assert(!request.session_id.IsDefined());
    assert(session_id != nullptr);

    if (!request.session_id.Parse(session_id))
        return nullptr;

    auto *session = request.GetSession();
    if (session == nullptr)
        return nullptr;

    if (!session->translate.IsNull())
        request.translate.request.session = DupBuffer(request.pool,
                                                      session->translate);

    if (session->site != nullptr)
        request.connection.site_name = p_strdup(&request.pool,
                                                session->site);

    if (!session->cookie_sent)
        request.send_session_cookie = true;

    session->is_new = false;

    return session;
}

static const char *
build_session_cookie_name(struct pool *pool, const BpConfig *config,
                          const struct strmap *headers)
{
    if (headers == nullptr || !config->dynamic_session_cookie)
        return config->session_cookie;

    const char *host = headers->Get("host");
    if (host == nullptr || *host == 0)
        return config->session_cookie;

    size_t length = strlen(config->session_cookie);
    char *name = PoolAlloc<char>(*pool, length + 5);
    memcpy(name, config->session_cookie, length);
    format_uint16_hex_fixed(name + length, crc16_string(0, host));
    name[length + 4] = 0;
    return name;
}

static const char *
request_get_uri_session_id(const Request &request)
{
    assert(!request.stateless);

    return strmap_get_checked(request.args, "session");
}

static const char *
request_get_cookie_session_id(Request &request)
{
    assert(!request.stateless);
    assert(request.session_cookie != nullptr);

    const auto *cookies = request_get_cookies(request);

    return strmap_get_checked(cookies, request.session_cookie);
}

void
Request::DetermineSession()
{
    session_realm = nullptr;

    const char *user_agent = request.headers->Get("user-agent");
    stateless = user_agent == nullptr || user_agent_is_bot(user_agent);
    if (stateless) {
        /* don't propagate a stale session id to processed URIs */
        if (args != nullptr)
            args->Remove("session");
        return;
    }

    session_cookie = build_session_cookie_name(&pool,
                                               &instance.config,
                                               request.headers);

    const char *sid = request_get_uri_session_id(*this);
    bool cookie_received = false;
    if (sid == nullptr || *sid == 0) {
        sid = request_get_cookie_session_id(*this);
        if (sid == nullptr)
            return;

        cookie_received = true;
    }

    auto *session = request_load_session(*this, sid);
    if (session == nullptr) {
        if (!cookie_received && args != nullptr)
            /* remove invalid session id from URI args */
            args->Remove("session");

        return;
    }

    if (!cookie_received) {
        const char *p = request_get_cookie_session_id(*this);
        if (p != nullptr && strcmp(p, sid) == 0)
            cookie_received = true;
    }

    if (cookie_received) {
        session->cookie_received = true;

        if (args != nullptr)
            /* we're using cookies, and we can safely remove the
               session id from the args */
            args->Remove("session");
    }

    session_realm = p_strdup(&pool, session->realm);

    session_put(session);
}

Session *
Request::MakeSession()
{
    if (stateless)
        return nullptr;

    auto *session = GetSession();
    if (session != nullptr)
        return session;

    session = session_new(realm);
    if (session == nullptr) {
        daemon_log(1, "Failed to allocate a session\n");
        return nullptr;
    }

    session_id = session->id;
    send_session_cookie = true;

    if (args == nullptr)
        args = strmap_new(&pool);
    args->Set("session", session_id.Format(session_id_string));

    return session;
}

void
Request::IgnoreSession()
{
    if (!session_id.IsDefined())
        return;

    assert(!stateless);

    if (args != nullptr)
        args->Remove("session");

    session_id.Clear();
    send_session_cookie = false;
}

void
Request::DiscardSession()
{
    if (!session_id.IsDefined())
        return;

    assert(!stateless);

    if (args != nullptr)
        args->Remove("session");

    session_delete(session_id);
    session_id.Clear();
    send_session_cookie = false;
}

/**
 * Determine the realm name, consider the override by the translation
 * server.  Guaranteed to return non-nullptr.
 */
static const char *
get_request_realm(struct pool *pool, const struct strmap *request_headers,
                  const TranslateResponse &response,
                  ConstBuffer<void> auth_base)
{
    if (response.realm != nullptr)
        return response.realm;

    if (response.realm_from_auth_base) {
        assert(!auth_base.IsNull());
        // TODO: what if AUTH contains null bytes?
        return p_strndup(pool, (const char *)auth_base.data, auth_base.size);
    }

    const char *host = strmap_get_checked(request_headers, "host");
    if (host != nullptr)
        return p_strdup_lower(pool, host);

    /* fall back to empty string as the default realm if there is no
       "Host" header */
    return "";
}

void
Request::ApplyTranslateRealm(const TranslateResponse &response,
                             ConstBuffer<void> auth_base)
{
    if (realm != nullptr)
        /* was already called by Request::HandleAuth(), and no need to
           check again */
        return;

    realm = get_request_realm(&pool, request.headers, response, auth_base);

    if (session_realm != nullptr && strcmp(realm, session_realm) != 0) {
        daemon_log(2, "ignoring spoofed session id from another realm (session='%s', request='%s', uri='%s')\n",
                   session_realm, realm, request.uri);
        IgnoreSession();
    }
}

Session *
Request::ApplyTranslateSession(const TranslateResponse &response)
{
    if (response.session.IsNull() && response.user == nullptr &&
        response.session_site == nullptr &&
        response.language == nullptr)
        return nullptr;

    auto *session = GetSession();

    if (!response.session.IsNull()) {
        if (response.session.IsEmpty()) {
            /* clear translate session */

            if (session != nullptr)
                session->ClearTranslate();
        } else {
            /* set new translate session */

            if (session == nullptr)
                session = MakeSession();

            if (session != nullptr)
                session->SetTranslate(response.session);
        }
    }

    if (response.session_site != nullptr) {
        if (*response.session_site == 0) {
            /* clear site */

            if (session != nullptr)
                session->ClearSite();
        } else {
            /* set new site */

            if (session == nullptr)
                session = MakeSession();

            if (session != nullptr)
                session->SetSite(response.session_site);

            connection.site_name = response.session_site;
        }
    }

    if (response.user != nullptr) {
        if (*response.user == 0) {
            /* log out */

            if (session != nullptr)
                session->ClearUser();
        } else {
            /* log in */

            if (session == nullptr)
                session = MakeSession();

            if (session != nullptr)
                session->SetUser(response.user, response.user_max_age);
        }
    } else if (session != nullptr && session->user != nullptr &&
               session->user_expires > 0 &&
               is_expired(session->user_expires)) {
        daemon_log(4, "user '%s' has expired\n", session->user);
        session->ClearUser();
    }

    if (response.language != nullptr) {
        if (*response.language == 0) {
            /* reset language setting */

            if (session != nullptr)
                session->ClearLanguage();
        } else {
            /* override language */

            if (session == nullptr)
                session = MakeSession();

            if (session != nullptr)
                session->SetLanguage(response.language);
        }
    }

    return session;
}
<|endoftext|>


<commit_before>#pragma once

#include <iostream>
#include <string>
#include <memory>
#include <map>
#include <SFML/Graphics.hpp>

#if __APPLE__
#include "ResourcePath.hpp"
#endif

#include "cpp_std_11.hpp"

template <typename T>
class ResourceManager
{
public:
    static ResourceManager* instance()
    {
	if(m_instance == nullptr)
	{
	    m_instance.reset(new ResourceManager<T>());
	}
	return m_instance.get();
    }

    T& get(const std::string& nom_fichier)
    {
        std::string filename = nom_fichier;
#if __APPLE__
        filename = resourcePath() + nom_fichier;
#endif

	if(m_resources.find(filename) == m_resources.end())
	{
	    std::cout << "chargement de " << filename << std::endl;
	    m_resources.insert(std::pair<std::string, T*>(filename, new T));
	    m_resources[filename]->loadFromFile(filename);
	}
	return *m_resources.at(filename);
    }

    ~ResourceManager() { std::cout << "Delete loader" << std::endl; }
private:
    ResourceManager() { std::cout << "Create loader" << std::endl; }
    using Ptr = std::unique_ptr<ResourceManager<T>>;

    //friend make_unique<ResourceManager<T>>();

    static Ptr m_instance;
    std::map<std::string, T*> m_resources;
};

template <typename T>
typename ResourceManager<T>::Ptr ResourceManager<T>::m_instance = nullptr;

using FontManager = ResourceManager<sf::Font>;
using TextureManager = ResourceManager<sf::Texture>;
<commit_msg>Fix typo.<commit_after>#pragma once

#include <iostream>
#include <string>
#include <memory>
#include <map>
#include <SFML/Graphics.hpp>

#if __APPLE__
#include "ResourcePath.hpp"
#endif

#include "cpp_std_11.hpp"

template <typename T>
class ResourceManager
{
	public:
		static ResourceManager* instance()
		{
			if(m_instance == nullptr)
			{
				m_instance.reset(new ResourceManager<T>());
			}
			return m_instance.get();
		}

		T& get(const std::string& nom_fichier);

		~ResourceManager() = default;
	private:
		ResourceManager() = default;
		using Ptr = std::unique_ptr<ResourceManager<T>>;

	    static Ptr m_instance;

    	std::map<std::string, T*> m_resources;
};

template <typename T>
T& ResourceManager<T>::get(const std::string& nom_fichier)
{
	std::string filename = nom_fichier;
	#if __APPLE__
	filename = resourcePath() + nom_fichier;
	#endif

	if(m_resources.find(filename) == m_resources.end())
	{
		std::cout << "chargement de " << filename << std::endl;
		m_resources.insert(std::pair<std::string, T*>(filename, new T));
		m_resources[filename]->loadFromFile(filename);
	}
	return *m_resources.at(filename);
}

template <typename T>
typename ResourceManager<T>::Ptr ResourceManager<T>::m_instance = nullptr;

using FontManager = ResourceManager<sf::Font>;
using TextureManager = ResourceManager<sf::Texture>;
<|endoftext|>


<commit_before>// Copyright (c) 2011 Seiya Tokui <beam.web@gmail.com>. All Rights Reserved.
// This source code is distributed under MIT License in LICENSE file.

#ifndef ELOG_HPP_
#define ELOG_HPP_

#include <chrono>
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <type_traits>
#include <utility>

namespace LOG
{

// meta functions

template<typename T, typename U = void>
struct enable_if_exist
{ typedef U type; };

template<typename T>
struct identity
{ typedef T type; };

template<typename T,
         typename enable_if_exist<typename T::value_type, int>::type = 0,
         typename enable_if_exist<typename T::iterator, int>::type = 0>
std::true_type
is_range_fn(int);

template<typename T,
          typename std::enable_if<std::is_array<T>::value, int>::type = 0>
std::true_type
is_range_fn(int);

template<typename>
std::false_type
is_range_fn(...);

template<typename T>
struct is_range
    : identity<decltype(is_range_fn<T>(0))>::type
{};

template<typename T,
         typename enable_if_exist<typename T::first_type>::type = 0,
         typename enable_if_exist<typename T::second_type>::type = 0>
std::true_type
is_pair_fn(int);

template<typename T>
std::false_type
is_pair_fn(...);

template<typename T>
struct is_pair
    : identity<decltype(is_pair_fn<T>(0))>::type
{};

// static variables definition

enum avoid_odr
{ AVOID_ODR };

template<typename T, avoid_odr = AVOID_ODR>
struct static_holder
{ static T value; };

template<typename T, avoid_odr A>
T static_holder<T, A>::value;

// pretty print to stream

template<typename T, typename Stream>
void
pretty_print_internal(const T& t, Stream& stream, ...)
{ stream << t; }

template<typename T,
         typename Stream,
         typename std::enable_if<is_pair<T>::value, int>::type = 0>
void
pretty_print_internal(const T& pair, Stream& stream, int)
{
  stream << '(';
  pretty_print_internal(pair.first, stream, 0);
  stream << ", ";
  pretty_print_internal(pair.second, stream, 0);
  stream << ')';
}

template<typename T,
         typename Stream,
         typename std::enable_if<is_range<T>::value, int>::type = 0>
void
pretty_print_internal(const T& range, Stream& stream, int)
{
  stream << '[';

  bool is_tail = false;
  for (const auto& elem : range) {
    if (is_tail) stream << ", ";

    is_tail = true;
    pretty_print_internal(elem, stream, 0);
  }

  stream << ']';
}

template<typename Stream>
void
pretty_print_internal(signed char t, Stream& stream, int)
{ stream << static_cast<int>(t); }

template<typename Stream>
void
pretty_print_internal(unsigned char t, Stream& stream, int)
{ stream << static_cast<unsigned int>(t); }

template<typename T, typename Stream>
void
pretty_print(const T& t, Stream& stream)
{ pretty_print_internal(t, stream, 0); }

template<typename Stream>
void
pretty_print_timesec(Stream& stream, double sec)
{
  stream << sec << " sec";

  long long min = sec / 60;
  sec -= min * 60;
  long long hour = min / 60;
  min -= hour * 60;
  long long day = hour / 24;
  hour -= day * 24;

  if (min > 0) {
    stream << " (";
    if (hour > 0) {
      if (day > 0) stream << day << "d ";
      stream << hour << "h ";
    }
    stream << min << "m ";
    stream << sec << "s)";
  }
}

// argument list to stream
template<typename Stream>
Stream&
print_arguments(Stream& stream)
{ return stream; }

template<typename Stream, typename T, typename ... Args>
Stream&
print_arguments(Stream& stream, const T& t, Args... args)
{
  stream << t;
  return print_arguments(stream, args...);
}

// logger

struct logger_base
{
  virtual
  ~logger_base()
  {};

  virtual
  void
  write(const std::string& message) const = 0;
};

// TODO: Support multi-thread use
struct stream_logger
    : logger_base
{
  stream_logger()
      : os_(&std::clog)
  {}

  void
  set_stream(std::ostream& os)
  { os_ = &os; }

  virtual
  void
  write(const std::string& message) const
  { (*os_) << message; }

 private:
  std::ostream* os_;
};

struct global_logger_holder
{
  global_logger_holder()
      : logger(&static_holder<stream_logger>::value)
  {}

  logger_base* logger;
};

inline
logger_base&
get_logger()
{ return *static_holder<global_logger_holder>::value.logger; }

inline
void
set_stream(std::ostream& os)
{ static_holder<stream_logger>::value.set_stream(os); }

// message construction and emission

struct message_builder
{
  template<typename T>
  void
  operator()(const T& t)
  { pretty_print(t, oss_); }

  std::string
  get() const
  { return oss_.str(); }

 private:
  std::ostringstream oss_;
};

struct log_emitter
{
  log_emitter()
      : logger_(get_logger())
  {}

  explicit
  log_emitter(logger_base& logger)
      : logger_(logger)
  {}

  template<typename T>
  log_emitter&
  operator<<(const T& t)
  {
    message_builder_(t);
    return *this;
  }

  void
  emit() const
  { logger_.write(message_builder_.get()); }

 private:
  logger_base& logger_;
  message_builder message_builder_;
};

struct log_emission_trigger
{
  void
  operator&(const log_emitter& emitter) const
  { emitter.emit(); }
};

struct check_error
    : std::exception
{};

struct check_emission_trigger
{
  void
  operator&(const log_emitter& emitter) const
  {
    emitter.emit();
    throw check_error();
  }
};

// benchmark

struct benchmark
{
  benchmark()
      : logger_(get_logger()),
        start_(std::chrono::system_clock::now()),
        done_(false)
  {}

  explicit
  benchmark(logger_base& logger)
      : logger_(logger),
        start_(std::chrono::system_clock::now()),
        done_(false)
  {}

  explicit
  operator bool() const
  { return false; }

  ~benchmark()
  { if (!done_) push_message(); }

  template<typename T>
  benchmark&
  operator<<(const T& t)
  {
    title_builder_ << t;
    return *this;
  }

  std::chrono::system_clock::duration
  duration() const
  { return std::chrono::system_clock::now() - start_; }

  double
  seconds() const
  {
    const auto d = duration();
    const auto us = std::chrono::duration_cast<std::chrono::microseconds>(d);
    return static_cast<double>(us.count()) / 1000000;
  }

  void
  push_message()
  {
    done_ = true;

    log_emitter emitter(logger_);
    emitter << title_builder_.get() << ": ";
    pretty_print_timesec(emitter, seconds());
    emitter.emit();
  }

 private:
  logger_base& logger_;
  std::chrono::system_clock::time_point start_;

  message_builder title_builder_;

  bool done_;
};

}  // namespace LOG

#define LOG() ::LOG::log_emission_trigger() & ::LOG::log_emitter()

#define CHECK(cond) \
  (cond) ? (void)0 : \
  ::LOG::check_emission_trigger() & ::LOG::log_emitter()

#define BENCHMARK(varname, ...) \
  if (auto varname = ::LOG::benchmark()); \
  else if (!&::LOG::print_arguments(varname, __VA_ARGS__)); \
  else

#endif  // ELOG_HPP_
<commit_msg>fix bugs<commit_after>// Copyright (c) 2011 Seiya Tokui <beam.web@gmail.com>. All Rights Reserved.
// This source code is distributed under MIT License in LICENSE file.

#ifndef ELOG_HPP_
#define ELOG_HPP_

#include <chrono>
#include <iostream>
#include <iterator>
#include <sstream>
#include <stdexcept>
#include <type_traits>
#include <utility>

namespace LOG
{

// meta functions

template<typename T, typename U = void>
struct enable_if_exist
{ typedef U type; };

template<typename T>
struct identity
{ typedef T type; };

template<typename T,
         typename enable_if_exist<typename T::value_type, int>::type = 0,
         typename enable_if_exist<typename T::iterator, int>::type = 0>
std::true_type
is_range_fn(int);

template<typename T,
          typename std::enable_if<std::is_array<T>::value, int>::type = 0>
std::true_type
is_range_fn(int);

template<typename>
std::false_type
is_range_fn(...);

template<typename T>
struct is_range
    : identity<decltype(is_range_fn<T>(0))>::type
{};

template<typename T>
struct range_value
{
  typedef typename std::iterator_traits<typename T::iterator>::value_type type;
};

template<typename T, std::size_t N>
struct range_value<T[N]>
{ typedef T type; };

template<typename T,
         typename enable_if_exist<typename T::first_type, int>::type = 0,
         typename enable_if_exist<typename T::second_type, int>::type = 0>
std::true_type
is_pair_fn(int);

template<typename T>
std::false_type
is_pair_fn(...);

template<typename T>
struct is_pair
    : identity<decltype(is_pair_fn<T>(0))>::type
{};

// static variables definition

enum avoid_odr
{ AVOID_ODR };

template<typename T, avoid_odr = AVOID_ODR>
struct static_holder
{ static T value; };

template<typename T, avoid_odr A>
T static_holder<T, A>::value;

// pretty print to stream

template<typename T, typename Stream>
inline void
pretty_print_internal(const T& t, Stream& stream, ...)
{ stream << t; }

template<typename T,
         typename Stream,
         typename std::enable_if<is_pair<T>::value, int>::type = 0>
void
pretty_print_internal(const T& pair, Stream& stream, int)
{
  stream << '(';
  pretty_print_internal(pair.first, stream, 0);
  stream << ", ";
  pretty_print_internal(pair.second, stream, 0);
  stream << ')';
}

template<typename Range,
         typename Value =
         typename std::decay<typename range_value<Range>::type>::type>
struct range_pretty_printer
{
  template<typename Stream>
  void
  operator()(const Range& range, Stream& stream) const
  {
    stream << '[';

    bool is_tail = false;
    for (const auto& elem : range) {
      if (is_tail) stream << ", ";

      is_tail = true;
      pretty_print_internal(elem, stream, 0);
    }

    stream << ']';
  }
};

template<typename Range>
struct range_pretty_printer<Range, char>
{
  template<typename Stream>
  void
  operator()(const Range& str, Stream& stream) const
  { for (const auto ch : str) stream << ch; }
};

template<typename T,
         typename Stream,
         typename std::enable_if<is_range<T>::value, int>::type = 0>
inline void
pretty_print_internal(const T& range, Stream& stream, int)
{ range_pretty_printer<T>()(range, stream); }

template<typename T,
         typename Stream,
         typename std::enable_if<
           std::is_same<T, signed char>::value, int>::type = 0>
inline void
pretty_print_internal(T sc, Stream& stream, int)
{ stream << static_cast<int>(sc); }

template<typename T,
         typename Stream,
         typename std::enable_if<
           std::is_same<T, unsigned char>::value, int>::type = 0>
inline void
pretty_print_internal(T uc, Stream& stream, int)
{ stream << static_cast<unsigned int>(uc); }

template<typename T, typename Stream>
inline void
pretty_print(const T& t, Stream& stream)
{ pretty_print_internal(t, stream, 0); }

template<typename Stream>
void
pretty_print_timesec(Stream& stream, double sec)
{
  stream << sec << " sec";

  long long min = sec / 60;
  sec -= min * 60;
  long long hour = min / 60;
  min -= hour * 60;
  long long day = hour / 24;
  hour -= day * 24;

  if (min > 0) {
    stream << " (";
    if (hour > 0) {
      if (day > 0) stream << day << "d ";
      stream << hour << "h ";
    }
    stream << min << "m ";
    stream << sec << "s)";
  }
}

// argument list to stream
template<typename Stream>
Stream&
print_arguments(Stream& stream)
{ return stream; }

template<typename Stream, typename T, typename ... Args>
Stream&
print_arguments(Stream& stream, const T& t, Args... args)
{
  stream << t;
  return print_arguments(stream, args...);
}

// logger

struct logger_base
{
  virtual
  ~logger_base()
  {};

  virtual
  void
  write(const std::string& message) const = 0;
};

// TODO: Support multi-thread use
struct stream_logger
    : logger_base
{
  stream_logger()
      : os_(&std::clog)
  {}

  void
  set_stream(std::ostream& os)
  { os_ = &os; }

  virtual
  void
  write(const std::string& message) const
  { (*os_) << message << std::endl; }

 private:
  std::ostream* os_;
};

struct global_logger_holder
{
  global_logger_holder()
      : logger(&static_holder<stream_logger>::value)
  {}

  logger_base* logger;
};

inline
logger_base&
get_logger()
{ return *static_holder<global_logger_holder>::value.logger; }

inline
void
set_stream(std::ostream& os)
{ static_holder<stream_logger>::value.set_stream(os); }

// message construction and emission

struct message_builder
{
  message_builder()
  {}

  message_builder(const message_builder& mb)
  {
    oss_ << mb.oss_.str();
  }

  template<typename T>
  void
  operator()(const T& t)
  { pretty_print(t, oss_); }

  std::string
  get() const
  { return oss_.str(); }

 private:
  std::ostringstream oss_;
};

struct log_emitter
{
  log_emitter()
      : logger_(get_logger())
  {}

  explicit
  log_emitter(logger_base& logger)
      : logger_(logger)
  {}

  template<typename T>
  log_emitter&
  operator<<(const T& t)
  {
    message_builder_(t);
    return *this;
  }

  void
  emit() const
  { logger_.write(message_builder_.get()); }

 private:
  logger_base& logger_;
  message_builder message_builder_;
};

struct log_emission_trigger
{
  void
  operator&(const log_emitter& emitter) const
  { emitter.emit(); }
};

struct check_error
    : std::exception
{};

struct check_emission_trigger
{
  void
  operator&(const log_emitter& emitter) const
  {
    emitter.emit();
    throw check_error();
  }
};

// benchmark

struct benchmark
{
  benchmark()
      : logger_(get_logger()),
        start_(std::chrono::system_clock::now()),
        done_(false)
  {}

  explicit
  benchmark(logger_base& logger)
      : logger_(logger),
        start_(std::chrono::system_clock::now()),
        done_(false)
  {}

  benchmark(const benchmark& b)
      : logger_(b.logger_),
        start_(b.start_),
        title_builder_(b.title_builder_),
        done_(b.done_)
  {}

  explicit
  operator bool() const
  { return false; }

  ~benchmark()
  { if (!done_) push_message(); }

  template<typename T>
  benchmark&
  operator<<(const T& t)
  {
    title_builder_(t);
    return *this;
  }

  std::chrono::system_clock::duration
  duration() const
  { return std::chrono::system_clock::now() - start_; }

  double
  seconds() const
  {
    const auto d = duration();
    const auto us = std::chrono::duration_cast<std::chrono::microseconds>(d);
    return static_cast<double>(us.count()) / 1000000;
  }

  void
  push_message()
  {
    done_ = true;

    log_emitter emitter(logger_);
    emitter << title_builder_.get() << ": ";
    pretty_print_timesec(emitter, seconds());
    emitter.emit();
  }

 private:
  logger_base& logger_;
  std::chrono::system_clock::time_point start_;

  message_builder title_builder_;

  bool done_;
};

}  // namespace LOG

#define LOG() ::LOG::log_emission_trigger() & ::LOG::log_emitter()

#define CHECK(cond) \
  (cond) ? (void)0 : \
  ::LOG::check_emission_trigger() & ::LOG::log_emitter()

#define BENCHMARK(varname, ...) \
  if (auto varname = ::LOG::benchmark()); \
  else if (!&::LOG::print_arguments(varname, __VA_ARGS__)); \
  else

#endif  // ELOG_HPP_
<|endoftext|>


<commit_before>#include <configcontainer.h>
#include <configparser.h>
#include <logger.h>
#include <sstream>
#include <iostream>

#include <sys/types.h>
#include <pwd.h>

namespace newsbeuter
{

configcontainer::configcontainer()
{
	// create the config options and set their resp. default value and type
	config_data["show-read-feeds"] = configdata("yes", configdata::BOOL);
	config_data["browser"]         = configdata("lynx", configdata::PATH);
	config_data["use-proxy"]       = configdata("no", configdata::BOOL);
	config_data["auto-reload"]     = configdata("no", configdata::BOOL);
	config_data["reload-time"]     = configdata("30", configdata::INT);
	config_data["max-items"]       = configdata("0", configdata::INT);
	config_data["save-path"]       = configdata("~/", configdata::PATH);
	config_data["download-path"]   = configdata("~/", configdata::PATH);
	config_data["max-downloads"]   = configdata("1", configdata::INT);
	config_data["podcast-auto-enqueue"] = configdata("no", configdata::BOOL);
	config_data["player"]          = configdata("", configdata::PATH);
	config_data["cleanup-on-quit"] = configdata("yes", configdata::BOOL);
	config_data["user-agent"]      = configdata("", configdata::STR);
	config_data["refresh-on-startup"] = configdata("no", configdata::BOOL);
	config_data["suppress-first-reload"] = configdata("no", configdata::BOOL);
	config_data["cache-file"]      = configdata("", configdata::PATH);
	config_data["proxy"]           = configdata("", configdata::STR);
	config_data["proxy-auth"]      = configdata("", configdata::STR);
	config_data["confirm-exit"]    = configdata("no", configdata::BOOL);
	config_data["error-log"]       = configdata("", configdata::PATH);
	config_data["notify-screen"]   = configdata("no", configdata::BOOL);
	config_data["notify-xterm"]    = configdata("no", configdata::BOOL);
	config_data["notify-program"]  = configdata("", configdata::PATH);
}

configcontainer::~configcontainer()
{
}

void configcontainer::register_commands(configparser& cfgparser)
{
	// this registers the config options defined above in the configuration parser
	// -> if the resp. config option is encountered, it is passed to the configcontainer
	for (std::map<std::string,configdata>::iterator it=config_data.begin();it!=config_data.end();++it) {
		cfgparser.register_handler(it->first, this);
	}
}

action_handler_status configcontainer::handle_action(const std::string& action, const std::vector<std::string>& params) {
	configdata& cfgdata = config_data[action];

	// configdata::INVALID indicates that the action didn't exist, and that the returned object was created ad-hoc.
	if (cfgdata.type == configdata::INVALID) {
		GetLogger().log(LOG_WARN, "configcontainer::handler_action: unknown action %s", action.c_str());
		return AHS_INVALID_COMMAND;
	}

	GetLogger().log(LOG_DEBUG, "configcontainer::handle_action: action = %s, type = %u", action.c_str(), cfgdata.type);

	switch (cfgdata.type) {
		case configdata::BOOL:
			if (params.size() < 1) {
				return AHS_TOO_FEW_PARAMS;
			}
			if (!is_bool(params[0])) {
				return AHS_INVALID_PARAMS;
			}
			cfgdata.value = params[0];
			return AHS_OK;

		case configdata::INT:
			if (params.size() < 1) {
				return AHS_TOO_FEW_PARAMS;
			}
			if (!is_int(params[0])) {
				return AHS_INVALID_PARAMS;
			}
			cfgdata.value = params[0];
			return AHS_OK;

		case configdata::STR:
			if (params.size() < 1) {
				return AHS_TOO_FEW_PARAMS;
			}
			cfgdata.value = params[0];
			return AHS_OK;

		case configdata::PATH: {
			if (params.size() < 1) {
				return AHS_TOO_FEW_PARAMS;
			}

			// a path config option is a bit more difficult to handle, because we need to replace
			// a possible "~/" at the beginning of the string with the user's home directory.

			const char * homedir;
			std::string filepath;

			if (!(homedir = ::getenv("HOME"))) {
				struct passwd * spw = ::getpwuid(::getuid());
				if (spw) {
						homedir = spw->pw_dir;
				} else {
						homedir = "";
				}
			}

			if (strcmp(homedir,"")!=0) {
				if (params[0] == "~") {
					filepath.append(homedir);
				} else if (params[0].substr(0,2) == "~/") {
					filepath.append(homedir);
					filepath.append(1,'/');
					filepath.append(params[0].substr(2,params[0].length()-2));
				}
			} else {
				filepath.append(params[0]);
			}

			cfgdata.value = filepath;
			return AHS_OK;
		}
		default:
			// should not happen
			return AHS_INVALID_COMMAND;
	}

	// should not happen
	return AHS_INVALID_COMMAND;
}

bool configcontainer::is_bool(const std::string& s) {
	const char * bool_values[] = { "yes", "no", "true", "false", 0 };
	for (int i=0; bool_values[i] ; ++i) {
		if (s == bool_values[i])
			return true;
	}
	return false;
}

bool configcontainer::is_int(const std::string& s) {
	const char * s1 = s.c_str();
	for (;*s1;s1++) {
		if (!isdigit(*s1))
			return false;
	}
	return true;
}

std::string configcontainer::get_configvalue(const std::string& key) {
	return config_data[key].value;
}

int configcontainer::get_configvalue_as_int(const std::string& key) {
	std::istringstream is(config_data[key].value);
	int i;
	is >> i;
	return i;
}

bool configcontainer::get_configvalue_as_bool(const std::string& key) {
	if (config_data[key].value == "true" || config_data[key].value == "yes")
		return true;
	return false;
}

void configcontainer::set_configvalue(const std::string& key, const std::string& value) {
	GetLogger().log(LOG_DEBUG,"configcontainer::set_configvalue(%s,%s) called", key.c_str(), value.c_str());
	config_data[key].value = value;
}

}
<commit_msg>Andreas Krennmair: 	fix "~" resolving when PATH values never got set in the configuration.<commit_after>#include <configcontainer.h>
#include <configparser.h>
#include <logger.h>
#include <sstream>
#include <iostream>

#include <sys/types.h>
#include <pwd.h>

namespace newsbeuter
{

configcontainer::configcontainer()
{
	// create the config options and set their resp. default value and type
	config_data["show-read-feeds"] = configdata("yes", configdata::BOOL);
	config_data["browser"]         = configdata("lynx", configdata::PATH);
	config_data["use-proxy"]       = configdata("no", configdata::BOOL);
	config_data["auto-reload"]     = configdata("no", configdata::BOOL);
	config_data["reload-time"]     = configdata("30", configdata::INT);
	config_data["max-items"]       = configdata("0", configdata::INT);
	config_data["save-path"]       = configdata("~/", configdata::PATH);
	config_data["download-path"]   = configdata("~/", configdata::PATH);
	config_data["max-downloads"]   = configdata("1", configdata::INT);
	config_data["podcast-auto-enqueue"] = configdata("no", configdata::BOOL);
	config_data["player"]          = configdata("", configdata::PATH);
	config_data["cleanup-on-quit"] = configdata("yes", configdata::BOOL);
	config_data["user-agent"]      = configdata("", configdata::STR);
	config_data["refresh-on-startup"] = configdata("no", configdata::BOOL);
	config_data["suppress-first-reload"] = configdata("no", configdata::BOOL);
	config_data["cache-file"]      = configdata("", configdata::PATH);
	config_data["proxy"]           = configdata("", configdata::STR);
	config_data["proxy-auth"]      = configdata("", configdata::STR);
	config_data["confirm-exit"]    = configdata("no", configdata::BOOL);
	config_data["error-log"]       = configdata("", configdata::PATH);
	config_data["notify-screen"]   = configdata("no", configdata::BOOL);
	config_data["notify-xterm"]    = configdata("no", configdata::BOOL);
	config_data["notify-program"]  = configdata("", configdata::PATH);
}

configcontainer::~configcontainer()
{
}

void configcontainer::register_commands(configparser& cfgparser)
{
	// this registers the config options defined above in the configuration parser
	// -> if the resp. config option is encountered, it is passed to the configcontainer
	for (std::map<std::string,configdata>::iterator it=config_data.begin();it!=config_data.end();++it) {
		cfgparser.register_handler(it->first, this);
	}
}

action_handler_status configcontainer::handle_action(const std::string& action, const std::vector<std::string>& params) {
	configdata& cfgdata = config_data[action];

	// configdata::INVALID indicates that the action didn't exist, and that the returned object was created ad-hoc.
	if (cfgdata.type == configdata::INVALID) {
		GetLogger().log(LOG_WARN, "configcontainer::handler_action: unknown action %s", action.c_str());
		return AHS_INVALID_COMMAND;
	}

	GetLogger().log(LOG_DEBUG, "configcontainer::handle_action: action = %s, type = %u", action.c_str(), cfgdata.type);

	switch (cfgdata.type) {
		case configdata::BOOL:
			if (params.size() < 1) {
				return AHS_TOO_FEW_PARAMS;
			}
			if (!is_bool(params[0])) {
				return AHS_INVALID_PARAMS;
			}
			cfgdata.value = params[0];
			return AHS_OK;

		case configdata::INT:
			if (params.size() < 1) {
				return AHS_TOO_FEW_PARAMS;
			}
			if (!is_int(params[0])) {
				return AHS_INVALID_PARAMS;
			}
			cfgdata.value = params[0];
			return AHS_OK;

		case configdata::STR:
		case configdata::PATH:
			if (params.size() < 1) {
				return AHS_TOO_FEW_PARAMS;
			}
			cfgdata.value = params[0];
			return AHS_OK;

		default:
			// should not happen
			return AHS_INVALID_COMMAND;
	}

	// should not happen
	return AHS_INVALID_COMMAND;
}

bool configcontainer::is_bool(const std::string& s) {
	const char * bool_values[] = { "yes", "no", "true", "false", 0 };
	for (int i=0; bool_values[i] ; ++i) {
		if (s == bool_values[i])
			return true;
	}
	return false;
}

bool configcontainer::is_int(const std::string& s) {
	const char * s1 = s.c_str();
	for (;*s1;s1++) {
		if (!isdigit(*s1))
			return false;
	}
	return true;
}

std::string configcontainer::get_configvalue(const std::string& key) {
	std::string retval = config_data[key].value;
	if (config_data[key].type == configdata::PATH) {
		const char * homedir;
		std::string filepath;

		if (!(homedir = ::getenv("HOME"))) {
			struct passwd * spw = ::getpwuid(::getuid());
			if (spw) {
					homedir = spw->pw_dir;
			} else {
					homedir = "";
			}
		}

		if (strcmp(homedir,"")!=0) {
			if (retval == "~") {
				filepath.append(homedir);
			} else if (retval.substr(0,2) == "~/") {
				filepath.append(homedir);
				filepath.append(1,'/');
				filepath.append(retval.substr(2,retval.length()-2));
			}
		} else {
			filepath.append(retval);
		}
		retval = filepath;
	}

	return retval;
}

int configcontainer::get_configvalue_as_int(const std::string& key) {
	std::istringstream is(config_data[key].value);
	int i;
	is >> i;
	return i;
}

bool configcontainer::get_configvalue_as_bool(const std::string& key) {
	if (config_data[key].value == "true" || config_data[key].value == "yes")
		return true;
	return false;
}

void configcontainer::set_configvalue(const std::string& key, const std::string& value) {
	GetLogger().log(LOG_DEBUG,"configcontainer::set_configvalue(%s,%s) called", key.c_str(), value.c_str());
	config_data[key].value = value;
}

}
<|endoftext|>


<commit_before>#include "bot.h"

#include <boost/regex/pattern_except.hpp>
#include <boost/regex.hpp>
#include <iostream>
#include <string>
#include <sstream>

#include "connection.h"
#include "logger.h"

namespace geecxx
{

Bot::Bot()
{
}

Bot::~Bot()
{
    if (_connection) {
        quit();
        _connection->close();
    }
}

bool Bot::init(const ConfigurationProvider& configuration)
{
    _connection.reset(new Connection(configuration.getServer(), std::to_string(configuration.getPortNumber())));
    if (!_connection) {
        return false;
    }
    _connection->setExternalReadHandler([this](const std::string& m){
        this->_readHandler(m);
    });
    _connection->setExternalWriteHandler([this]() { _writeHandler(); });
    if(!_connection->open()) {
        return false;
    }
    nick(configuration.getNickname());
    join(configuration.getChannelName(), configuration.getChannelKey());

    return true;
}

void Bot::run()
{
    _connection->run();
}

void Bot::nick(const std::string& nickname)
{
    LOG_INFO("nick: " + nickname);
    _connection->writeMessage(std::string("NICK ") + nickname);
    _connection->writeMessage(std::string("USER ") + nickname + " * * :" + nickname);
}

void Bot::join(const std::string& channel, const std::string& key)
{
    LOG_INFO(std::string("JOIN ") + channel + " " + key);
    _connection->writeMessage(std::string("JOIN ") + channel + " " + key);
    _currentChannel = channel;
}

void Bot::say(const std::string& message)
{
   msg(_currentChannel, message);
}

void Bot::msg(const std::string& receiver, const std::string& message)
{
    _connection->writeMessage(std::string("PRIVMSG ") + receiver + " :" + message);
}

void Bot::pong(const std::string& serverName)
{
    _connection->writeMessage(std::string("PONG ") + serverName);
}

void Bot::quit()
{
    _connection->writeMessage(std::string("QUIT : Shutting down."));
}

std::istringstream& Bot::_skipToContent(std::istringstream& iss)
{
    char c = 0;
    while(!iss.eof() && c != ':') {
        iss >> c;
    }
    return iss;
}

void Bot::_readHandler(const std::string& message)
{
    LOG_DEBUG("Reading: " + message);

    std::istringstream iss(message);
    std::string command;
    std::string sender = "";
    iss >> command;

    if (command.size() > 1 && command[0] == ':') {
    //this is probably a privmsg
        size_t pos = command.find('!');
        if (pos != std::string::npos) {
            sender = command.substr(1, pos - 1);
            iss >> command;
        }
    }

    if (command == "PRIVMSG") {
        std::string recipient;
        iss >> recipient;
        LOG_DEBUG("PRIVMSG FROM " + sender + " TO " + recipient);

        std::string result;
        if (_parseURL(message, result)) {
            LOG_DEBUG("Found URL: " + result);
            if (recipient[0] == '#') {
                say(result);
            } else {
                msg(sender, result);
            }
        }
    } else if (command == "PING") {
        _skipToContent(iss);
        std::string host;
        iss >> host;
        pong(host);
    }

}

void Bot::_writeHandler()
{
    std::string line, comm;
    while (_connection->isAlive()) {
        std::getline(std::cin, line);
        std::istringstream iss(line);

        iss >> comm;
        if (comm == "/n") {
            iss >> comm;
            nick(comm);
        } else if (comm == "/j") {
            iss >> comm;
            join(comm);
        } else if (comm == "/m") {
            iss >> comm;
            msg(comm, iss.str());
        } else if (comm == "/s") {
            say(iss.str());
        } else if (comm == "/q") {
            iss >> comm;
            quit();
        }
    }
}

bool Bot::_parseURL(const std::string& message, std::string& result)
{
    boost::regex urlRegex;
    try {
        // Source of the regular expression:
        // http://daringfireball.net/2010/07/improved_regex_for_matching_urls
        urlRegex.assign(R"((?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))",
                         boost::regex::ECMAScript);
    } catch(boost::regex_error& error) {
        std::cerr << "Invalid regular expression: " << error.what() << std::endl;
        return false;
    }

    boost::smatch matchedElements;
    bool containsURL = boost::regex_search(message, matchedElements, urlRegex);
    result = matchedElements[0];

    return containsURL;
}

}

<commit_msg>Minor fix: privmsg check to answer to the channel or a specific user<commit_after>#include "bot.h"

#include <boost/regex/pattern_except.hpp>
#include <boost/regex.hpp>
#include <iostream>
#include <string>
#include <sstream>

#include "connection.h"
#include "logger.h"

namespace geecxx
{

Bot::Bot()
{
}

Bot::~Bot()
{
    if (_connection) {
        quit();
        _connection->close();
    }
}

bool Bot::init(const ConfigurationProvider& configuration)
{
    _connection.reset(new Connection(configuration.getServer(), std::to_string(configuration.getPortNumber())));
    if (!_connection) {
        return false;
    }
    _connection->setExternalReadHandler([this](const std::string& m){
        this->_readHandler(m);
    });
    _connection->setExternalWriteHandler([this]() { _writeHandler(); });
    if(!_connection->open()) {
        return false;
    }
    nick(configuration.getNickname());
    join(configuration.getChannelName(), configuration.getChannelKey());

    return true;
}

void Bot::run()
{
    _connection->run();
}

void Bot::nick(const std::string& nickname)
{
    LOG_INFO("nick: " + nickname);
    _connection->writeMessage(std::string("NICK ") + nickname);
    _connection->writeMessage(std::string("USER ") + nickname + " * * :" + nickname);
}

void Bot::join(const std::string& channel, const std::string& key)
{
    LOG_INFO(std::string("JOIN ") + channel + " " + key);
    _connection->writeMessage(std::string("JOIN ") + channel + " " + key);
    _currentChannel = channel;
}

void Bot::say(const std::string& message)
{
   msg(_currentChannel, message);
}

void Bot::msg(const std::string& receiver, const std::string& message)
{
    _connection->writeMessage(std::string("PRIVMSG ") + receiver + " :" + message);
}

void Bot::pong(const std::string& serverName)
{
    _connection->writeMessage(std::string("PONG ") + serverName);
}

void Bot::quit()
{
    _connection->writeMessage(std::string("QUIT : Shutting down."));
}

std::istringstream& Bot::_skipToContent(std::istringstream& iss)
{
    char c = 0;
    while(!iss.eof() && c != ':') {
        iss >> c;
    }
    return iss;
}

void Bot::_readHandler(const std::string& message)
{
    LOG_DEBUG("Reading: " + message);

    std::istringstream iss(message);
    std::string command;
    std::string sender = "";
    iss >> command;

    if (command.size() > 1 && command[0] == ':') {
    //this is probably a privmsg
        size_t pos = command.find('!');
        if (pos != std::string::npos) {
            sender = command.substr(1, pos - 1);
            iss >> command;
        }
    }

    if (command == "PRIVMSG") {
        std::string recipient;
        iss >> recipient;
        LOG_DEBUG("PRIVMSG FROM " + sender + " TO " + recipient);

        std::string result;
        if (_parseURL(message, result)) {
            LOG_DEBUG("Found URL: " + result);
            if (recipient == _currentChannel) {
                say(result);
            } else {
                msg(sender, result);
            }
        }
    } else if (command == "PING") {
        _skipToContent(iss);
        std::string host;
        iss >> host;
        pong(host);
    }

}

void Bot::_writeHandler()
{
    std::string line, comm;
    while (_connection->isAlive()) {
        std::getline(std::cin, line);
        std::istringstream iss(line);

        iss >> comm;
        if (comm == "/n") {
            iss >> comm;
            nick(comm);
        } else if (comm == "/j") {
            iss >> comm;
            join(comm);
        } else if (comm == "/m") {
            iss >> comm;
            msg(comm, iss.str());
        } else if (comm == "/s") {
            say(iss.str());
        } else if (comm == "/q") {
            iss >> comm;
            quit();
        }
    }
}

bool Bot::_parseURL(const std::string& message, std::string& result)
{
    boost::regex urlRegex;
    try {
        // Source of the regular expression:
        // http://daringfireball.net/2010/07/improved_regex_for_matching_urls
        urlRegex.assign(R"((?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))",
                         boost::regex::ECMAScript);
    } catch(boost::regex_error& error) {
        std::cerr << "Invalid regular expression: " << error.what() << std::endl;
        return false;
    }

    boost::smatch matchedElements;
    bool containsURL = boost::regex_search(message, matchedElements, urlRegex);
    result = matchedElements[0];

    return containsURL;
}

}

<|endoftext|>


<commit_before>#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <string.h>

using namespace std;

#define DEBUG   0
#define MOD     1000000007
#define N       3
#define M       4

// row, major diagonal, minor diagonal
unsigned int status[N][1 << M][1 << M][1 << M];
unsigned char board[N];

bool valid_current(char sta, char board, int m) {
    bool ret = true;

    int pre_pos = -1;
    for (size_t pos = 0; pos < m; pos++) {
        if (sta & (1 << pos)) {
            if (board && (1 << pos)) {
                // blocked
                ret = false;
                break;
            }
            else {
                if (0 > pre_pos) {
                    pre_pos = pos;
                }
                else {
                    // no blocked square between pre_pos and pos
                    ret = false;
                    break;
                }
            }
        }
        else {
            if (board && (1 << pos)) {
                // blocked, clean pre pos
                pre_pos = -1;
            }
        }
    }

    return ret;
}

bool valid_pre(char sta, char pre_sta, char pre_major, char pre_minor) {
    if (sta & pre_sta) {
        return false;
    }

    if (sta & (pre_major << 1)) {
        return false;
    }

    if (sta & (pre_minor >> 1)) {
        return false;
    }

    return true;
}

int main() {
    int t;

#if DEBUG
    FILE * fp = fopen("input.txt", "r");
    fscanf(fp, "%d", &t);
#else
    scanf("%d", &t);
#endif

    for (size_t i = 0; i < t; i++) {
        int n, m;

#if DEBUG
        fscanf(fp, "%d %d", &n, &m);
#else
        scanf("%d %d", &n, &m);
#endif

        for (size_t row = 0; row < n; row++) {
            board[row] = 0;

            char c[30];
#if DEBUG
            fscanf(fp, "%s", c);
#else
            scanf("%s", c);
#endif
            for (size_t col = 0; col < m; col++) {
                if ('#' == c[col]) {
                    // a blocked square
                    board[row] |= 1 << col;
                }
            }
        }

        // process
        memset(status, 0, sizeof(status));
        unsigned int ret = 0;
        for (size_t row = 0; row < n; row++) {
            for (char sta = 0; sta < (1 << m); sta++) {
                if (valid_current(sta, board[row], m)) {
                    if (0 == row) {
                        status[row][sta][sta][sta] = 1;
                        if ((n - 1) == row) {
                            // last row
                            ret ++;
                        }
                    }
                    else {
                        for (char pre_sta = 0; pre_sta < (1 << m); pre_sta++) {
                            for (char pre_major = 0; pre_major < (1 << m); pre_major++) {
                                for (char pre_minor = 0; pre_minor < (1 << m); pre_minor++) {
                                    if (status[row - 1][pre_sta][pre_major][pre_minor]) {
                                        if (valid_pre(sta, pre_sta, pre_major, pre_minor)) {
                                            // new_sta, new_major, new_minor
                                            char new_sta = 0;
                                            for (size_t pos = 0; pos < m; pos++) {
                                                if (board[row] & (1 << pos)) {
                                                    // blocked
                                                }
                                                else {
                                                    new_sta |= ((sta & (1 << pos)) | (pre_sta & (1 << pos)));
                                                }
                                            }

                                            char new_major = 0;
                                            for (size_t pos = 0; pos < m; pos++) {
                                                if (0 == pos) {
                                                    if (sta & 1) {
                                                        new_major = 1;
                                                    }
                                                }
                                                else {
                                                    if (board[row] & (1 << pos)) {
                                                        // blocked
                                                    }
                                                    else {
                                                        new_major |= ((sta & (1 << pos)) | (pre_major & (1 << (pos - 1))));
                                                    }
                                                }
                                            }

                                            char new_minor = 0;
                                            for (size_t pos = 0; pos < m; pos++) {
                                                if (m - 1 == pos) {
                                                    if (sta & (1 << pos)) {
                                                        new_minor |= (1 << pos);
                                                    }
                                                }
                                                else {
                                                    if (board[row] & (1 << pos)) {
                                                        // blocked
                                                    }
                                                    else {
                                                        new_minor |= ((sta & (1 << pos)) | (pre_minor & (1 << (pos + 1))));
                                                    }
                                                }
                                            }

                                            status[row][new_sta][new_major][new_minor] += status[row - 1][pre_sta][pre_major][pre_minor];
                                            status[row][new_sta][new_major][new_minor] %= MOD;

                                            if ((n - 1) == row) {
                                                // last row
                                                ret += status[row - 1][pre_sta][pre_major][pre_minor];
                                                ret %= MOD;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        ret += MOD - 1;
        ret %= MOD;

        printf("%u\n", ret);
    }

#if DEBUG
    fclose(fp);
#endif

    return 0;
}
<commit_msg>modify<commit_after>#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <string.h>

using namespace std;

#define DEBUG   0
#define MOD     1000000007
#define N       3
#define M       4

// row, major diagonal, minor diagonal
unsigned int status[N][1 << M][1 << M][1 << M];
unsigned char board[N];

bool valid_current(char sta, char board, int m) {
    bool ret = true;

    int pre_pos = -1;
    for (size_t pos = 0; pos < m; pos++) {
        if (sta & (1 << pos)) {
            if (board && (1 << pos)) {
                // blocked
                ret = false;
                break;
            }
            else {
                if (0 > pre_pos) {
                    pre_pos = pos;
                }
                else {
                    // no blocked square between pre_pos and pos
                    ret = false;
                    break;
                }
            }
        }
        else {
            if (board && (1 << pos)) {
                // blocked, clean pre pos
                pre_pos = -1;
            }
        }
    }

    return ret;
}

bool valid_pre(char sta, char pre_sta, char pre_major, char pre_minor) {
    if (sta & pre_sta) {
        return false;
    }

    if (sta & (pre_major << 1)) {
        return false;
    }

    if (sta & (pre_minor >> 1)) {
        return false;
    }

    return true;
}

int main() {
    int t;

#if DEBUG
    FILE * fp = fopen("input.txt", "r");
    fscanf(fp, "%d", &t);
#else
    scanf("%d", &t);
#endif

    for (size_t i = 0; i < t; i++) {
        int n, m;

#if DEBUG
        fscanf(fp, "%d %d", &n, &m);
#else
        scanf("%d %d", &n, &m);
#endif

        for (size_t row = 0; row < n; row++) {
            board[row] = 0;

            char c[30];
#if DEBUG
            fscanf(fp, "%s", c);
#else
            scanf("%s", c);
#endif
            for (size_t col = 0; col < m; col++) {
                if ('#' == c[col]) {
                    // a blocked square
                    board[row] |= 1 << col;
                }
            }
        }

        // process
        memset(status, 0, sizeof(status));
        unsigned int ret = 0;
        for (size_t row = 0; row < n; row++) {
            for (char sta = 0; sta < (1 << m); sta++) {
                if (valid_current(sta, board[row], m)) {
                    if (0 == row) {
                        status[row][sta][sta][sta] = 1;
                        if ((n - 1) == row) {
                            // last row
                            ret ++;
                        }
                    }
                    else {
                        for (char pre_sta = 0; pre_sta < (1 << m); pre_sta++) {
                            for (char pre_major = 0; pre_major < (1 << m); pre_major++) {
                                for (char pre_minor = 0; pre_minor < (1 << m); pre_minor++) {
                                    if (status[row - 1][pre_sta][pre_major][pre_minor]) {
                                        if (valid_pre(sta, pre_sta, pre_major, pre_minor)) {
                                            // new_sta, new_major, new_minor
                                            char new_sta = 0;
                                            for (size_t pos = 0; pos < m; pos++) {
                                                if (board[row] & (1 << pos)) {
                                                    // blocked
                                                }
                                                else {
                                                    new_sta |= ((sta & (1 << pos)) | (pre_sta & (1 << pos)));
                                                }
                                            }

                                            char new_major = 0;
                                            for (size_t pos = 0; pos < m; pos++) {
                                                if (0 == pos) {
                                                    if (sta & 1) {
                                                        new_major = 1;
                                                    }
                                                }
                                                else {
                                                    if (board[row] & (1 << pos)) {
                                                        // blocked
                                                    }
                                                    else {
                                                        if ((sta & (1 << pos)) || (pre_major & (1 << (pos - 1)))) {
                                                            new_major |= 1 << pos;
                                                        }
                                                    }
                                                }
                                            }

                                            char new_minor = 0;
                                            for (size_t pos = 0; pos < m; pos++) {
                                                if (m - 1 == pos) {
                                                    if (sta & (1 << pos)) {
                                                        new_minor |= (1 << pos);
                                                    }
                                                }
                                                else {
                                                    if (board[row] & (1 << pos)) {
                                                        // blocked
                                                    }
                                                    else {
                                                        if ((sta & (1 << pos)) || (pre_minor & (1 << (pos + 1)))) {
                                                            new_minor |= 1 << pos;
                                                        }
                                                    }
                                                }
                                            }

                                            status[row][new_sta][new_major][new_minor] += status[row - 1][pre_sta][pre_major][pre_minor];
                                            status[row][new_sta][new_major][new_minor] %= MOD;

                                            if ((n - 1) == row) {
                                                // last row
                                                ret += status[row - 1][pre_sta][pre_major][pre_minor];
                                                ret %= MOD;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        ret += MOD - 1;
        ret %= MOD;

        printf("%u\n", ret);
    }

#if DEBUG
    fclose(fp);
#endif

    return 0;
}
<|endoftext|>


<commit_before>#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>

#include <boost/filesystem.hpp>
#include <string>
#include <iostream>

#include <pwn/mesh/mesh.h>
#include <pwn/io/io.h>
#include <pwn/mesh/builder.h>
#include <boost/foreach.hpp>

#include "WavefrontObj.hpp"
#include "3ds.hpp"

#include "MilkshapeAscii.hpp"
#include "MilkshapeBinary.hpp"

using namespace std;

/** Writes a dot to std::out to display progress..
*/
struct WriteDotCallback : public pwn::convert::obj::VoidVoidCallback
{
	bool verbose;
	explicit WriteDotCallback(bool aVerbose)
		: verbose(aVerbose)
	{
	}

	void perform()
	{
		if( verbose ) std::cout << ".";
	}
};

namespace InputFormat
{
	enum Type
	{
		Unknown
		, Obj
		, Ms3d_ascii
		, Ms3d_binary
		, Studio3ds
	};
}

const InputFormat::Type SuggestFormat(const pwn::string& inputfile, const InputFormat::Type formatOveride)
{
	if( formatOveride != InputFormat::Unknown ) return formatOveride;
	const pwn::string ext = boost::filesystem::path(inputfile).extension();

	if( ext == ".obj" ) return InputFormat::Obj;
	else if( ext == ".3ds" ) return InputFormat::Studio3ds;
	else if( ext == ".txt" ) return InputFormat::Ms3d_ascii;
	else if( ext == ".ms3d" ) return InputFormat::Ms3d_binary;
	else return InputFormat::Unknown;
}

/**
 Supports: 3ds, obj, milkshape binary & milkshape ascii.
 Add support for x, collada, md2, md3, md5, an8, ogre mesh, dxf & blender
*/
bool Load(pwn::mesh::Builder* builder, pwn::mesh::Animation* animation, const pwn::string& inputfile, const InputFormat::Type formatOveride, bool verbose)
{
	const InputFormat::Type fileFormat = SuggestFormat(inputfile, formatOveride);

	if( verbose ) cout << "reading " << fileFormat << ".." << std::endl;

	switch(fileFormat)
	{
	case InputFormat::Obj:
		{
		WriteDotCallback wdc(verbose);
		pwn::convert::obj::read(builder, inputfile, wdc);
		builder->buildNormals();
		}
		return true;
	case InputFormat::Studio3ds:
		pwn::convert::studio3ds::read(builder, inputfile);
		builder->buildNormals();
		return true;
	case InputFormat::Ms3d_ascii:
		pwn::convert::milkshape::ascii::Read(builder, animation, inputfile);
		builder->buildNormals();
		return true;
	case InputFormat::Ms3d_binary:
		pwn::convert::milkshape::binary::Read(builder, animation, inputfile);
		builder->buildNormals();
		return true;
	default:
		std::cerr << "Unable to determine the kind of reader to use with " << inputfile;
		return false;
	}
}

struct ConvertMesh
{
	ConvertMesh(const pwn::string& in)
		: inputfile(in)
		, formatOveride(InputFormat::Unknown)
		, useModelScale(false)
		, modelScale(1)
		, texturedir(boost::filesystem::path(in).replace_extension().filename())
		, animdir("")
		, moutdir(boost::filesystem::path(in).directory_string())
	{
	}

	pwn::string inputfile;
	InputFormat::Type formatOveride;
	bool useModelScale;
	float modelScale;
	pwn::string texturedir;
	pwn::string animdir;
	pwn::string moutdir;
	std::vector<pwn::mesh::AnimationInformation> animationsToExtract;

	bool run(const pwn::string& argv0, const pwn::string& aoutdir, bool runStatistics, bool verbose, bool meshInfo, bool writeResult) const
	{
		const pwn::string outdir = outdir.empty() ? moutdir : aoutdir;
		try
		{
			pwn::mesh::Builder builder;
			pwn::mesh::Animation animation;
			if( Load(&builder, &animation, inputfile, formatOveride, verbose) == false ) return false;

			pwn::mesh::Flatouter flatouter(builder);
			flatouter.modify(&builder);
			flatouter.modify(&animation);

			if( useModelScale )
			{
				if( verbose ) cout << "scaling " << modelScale << ".." << std::endl;
				pwn::mesh::Scale(&builder, modelScale);
				animation.scale(modelScale);
			}

			if( verbose ) cout << endl;

			pwn::mesh::MoveTextures(&builder, texturedir);

			pwn::mesh::Mesh mesh = builder.asMesh();
			const pwn::uint32 validationErrors = mesh.validate(true);
			if( validationErrors != 0)
			{
				cerr << inputfile << " failed validation with " << validationErrors << " error(s)... ignoring file..." << endl;
				return false;
			}

			if( meshInfo )
			{
				cout
					<< "Mesh information: " << endl
					<< " positions: " << mesh.data().getCount() << endl
					<< " materials: " << mesh.getMaterials().size() << endl
					<< " triangles: " << mesh.getNumberOfTriangles() << endl
					<< endl;
			}

			if( writeResult )
			{
				if( verbose ) cout << "writing.." << endl;
				pwn::io::WriteTarget wt(argv0, outdir);
				pwn::io::Write(mesh, boost::filesystem::path(inputfile).replace_extension("mesh").filename());
			}

			BOOST_FOREACH(const pwn::mesh::AnimationInformation& ai, animationsToExtract)
			{
				pwn::mesh::Animation ani;
				animation.subanim(ai, &ani);

				pwn::string adir = animdir;
				if( adir.empty() )
				{
					adir = (
							boost::filesystem::path(outdir)
							/ boost::filesystem::path(inputfile).replace_extension().filename()
							)
						.directory_string();
				};

				pwn::io::WriteTarget wt(argv0, adir);
				pwn::io::Write(ani, boost::filesystem::path(ai.name).replace_extension("anim").filename());
			}

			if( verbose ) cout << endl << "done." << endl;

			return true;
		}
		catch(const pwn::string& str)
		{
			cerr << endl << str << endl;
			return false;
		}
		catch(const char* str)
		{
			cerr << endl << str << endl;
			return false;
		}
		catch(...)
		{
			cerr << endl << "general failue." << endl;
			return false;
		}
	}
};

void RunXml(const pwn::string& argv0, const pwn::string& filename)
{
	using boost::property_tree::ptree;

	try
	{
		ptree pt;
		read_xml(filename, pt);

		pwn::string outdir  = pt.get<pwn::string>("convert.outdir");
		bool runstats = pt.get("convert.runstats", false);
		bool verbose = pt.get("convert.verbose", false);
		bool displayMeshInfo = pt.get("convert.displayMeshInfo", false);
		bool writeResults = pt.get("convert.writeResults", true);

		std::vector<ConvertMesh> cm;

		BOOST_FOREACH(ptree::value_type &v, pt.get_child("convert.sources"))
		{
			if( v.first == "<xmlcomment>" ) continue;
			ptree source = v.second;
			const pwn::string inputfile = source.get<pwn::string>("file");
			ConvertMesh cmesh(inputfile);

			boost::optional<pwn::real> scale = source.get_optional<pwn::real>("scale");
			if( scale.is_initialized() )
			{
				cmesh.modelScale = scale.get();
				cmesh.useModelScale = true;
			}

			BOOST_FOREACH(ptree::value_type &an, source.get_child("animations"))
			{
				ptree anida = an.second;
				const pwn::string name = anida.get<pwn::string>("name");
				const pwn::uint32 start = anida.get<pwn::uint32>("start");
				const pwn::uint32 end = anida.get<pwn::uint32>("end");
				cmesh.animationsToExtract.push_back(pwn::mesh::AnimationInformation(start, end, name));
			}

			cm.push_back(cmesh);
		}

		BOOST_FOREACH(const ConvertMesh& cmesh, cm)
		{
			cmesh.run(argv0, outdir, runstats, verbose, displayMeshInfo, writeResults);
		}
	}
	catch (std::exception &e)
	{
		std::cout << "Error: " << e.what() << "\n";
		cin.get();
	}
}

int main(int argc, char* argv[])
{
	using namespace std;

	const pwn::string filename(argv[1]);
	RunXml(argv[0], filename);
	return 0;
}

<commit_msg>rewrite of arg handling first commit<commit_after>#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>

#include <boost/filesystem.hpp>
#include <string>
#include <iostream>

#include <pwn/mesh/mesh.h>
#include <pwn/io/io.h>
#include <pwn/mesh/builder.h>
#include <boost/foreach.hpp>

#include "WavefrontObj.hpp"
#include "3ds.hpp"

#include "MilkshapeAscii.hpp"
#include "MilkshapeBinary.hpp"
#include <pwn/assert.h>
#include <pwn/core/stringutils.h>
#include <boost/lexical_cast.hpp>

using namespace std;

/** Writes a dot to std::out to display progress..
*/
struct WriteDotCallback : public pwn::convert::obj::VoidVoidCallback
{
	bool verbose;
	explicit WriteDotCallback(bool aVerbose)
		: verbose(aVerbose)
	{
	}

	void perform()
	{
		if( verbose ) std::cout << ".";
	}
};

namespace InputFormat
{
	enum Type
	{
		Unknown
		, Obj
		, Ms3d_ascii
		, Ms3d_binary
		, Studio3ds
	};
}

const InputFormat::Type SuggestFormat(const pwn::string& ext)
{
	if( ext == ".obj" ) return InputFormat::Obj;
	else if( ext == ".3ds" ) return InputFormat::Studio3ds;
	else if( ext == ".txt" ) return InputFormat::Ms3d_ascii;
	else if( ext == ".ms3d" ) return InputFormat::Ms3d_binary;
	else return InputFormat::Unknown;
}

const InputFormat::Type SuggestFormat(const pwn::string& inputfile, const InputFormat::Type formatOveride)
{
	if( formatOveride != InputFormat::Unknown ) return formatOveride;
	const pwn::string ext = boost::filesystem::path(inputfile).extension();

	return SuggestFormat(ext);
}

const InputFormat::Type SuggestFormatData(const pwn::string& name)
{
	return SuggestFormat("." + name);
}

/**
 Supports: 3ds, obj, milkshape binary & milkshape ascii.
 Add support for x, collada, md2, md3, md5, an8, ogre mesh, dxf & blender
*/
bool Load(pwn::mesh::Builder* builder, pwn::mesh::Animation* animation, const pwn::string& inputfile, const InputFormat::Type formatOveride, bool verbose)
{
	const InputFormat::Type fileFormat = SuggestFormat(inputfile, formatOveride);

	if( verbose ) cout << "reading " << fileFormat << ".." << std::endl;

	switch(fileFormat)
	{
	case InputFormat::Obj:
		{
		WriteDotCallback wdc(verbose);
		pwn::convert::obj::read(builder, inputfile, wdc);
		builder->buildNormals();
		}
		return true;
	case InputFormat::Studio3ds:
		pwn::convert::studio3ds::read(builder, inputfile);
		builder->buildNormals();
		return true;
	case InputFormat::Ms3d_ascii:
		pwn::convert::milkshape::ascii::Read(builder, animation, inputfile);
		builder->buildNormals();
		return true;
	case InputFormat::Ms3d_binary:
		pwn::convert::milkshape::binary::Read(builder, animation, inputfile);
		builder->buildNormals();
		return true;
	default:
		std::cerr << "Unable to determine the kind of reader to use with " << inputfile;
		return false;
	}
}

typedef std::vector<pwn::mesh::AnimationInformation> AnimationExtract;

pwn::string SuggestTextureDirectory(const pwn::string& in)
{
	return boost::filesystem::path(in).replace_extension().filename();
}

pwn::string SuggestAnimationFile(const pwn::string& in)
{
	return boost::filesystem::path(in).replace_extension("animxml").filename();
}

pwn::string SuggestOutDirectory(const pwn::string& in)
{
	return boost::filesystem::path(in).directory_string();
}

struct ConvertData
{
	ConvertData()
		: useModelScale(false)
		, modelScale(1)
		, verbose(false)
		, meshInfo(false)
		, writeResult(true)
	{
	}

	bool useModelScale;
	float modelScale;
	pwn::string texturedir; // relative directory when loading textures from game
	pwn::string animdir; // if empty a default based on outdir is created
	pwn::string outdir; // if emppy a default based on input file is created
	bool runStatistics;
	bool verbose;
	bool meshInfo;
	bool writeResult;
};

bool Convert(const pwn::string& argv0, const ConvertData& cd, const AnimationExtract& animationsToExtract, const pwn::string& inputfile, InputFormat::Type formatOveride)
{
	pwn::string outdir =
		cd.outdir.empty() ? SuggestOutDirectory(inputfile) : cd.outdir;
	pwn::mesh::Builder builder;
	pwn::mesh::Animation animation;
	if( Load(&builder, &animation, inputfile, formatOveride, cd.verbose) == false ) return false;

	pwn::mesh::Flatouter flatouter(builder);
	flatouter.modify(&builder);
	flatouter.modify(&animation);

	if( cd.useModelScale )
	{
		if( cd.verbose ) cout << "scaling " << cd.modelScale << ".." << std::endl;
		pwn::mesh::Scale(&builder, cd.modelScale);
		animation.scale(cd.modelScale);
	}

	if( cd.verbose ) cout << endl;

	pwn::mesh::MoveTextures(&builder, cd.texturedir);

	pwn::mesh::Mesh mesh = builder.asMesh();
	const pwn::uint32 validationErrors = mesh.validate(true);
	if( validationErrors != 0)
	{
		cerr << inputfile << " failed validation with " << validationErrors << " error(s)... ignoring file..." << endl;
		return false;
	}

	if( cd.meshInfo )
	{
		cout
			<< "Mesh information: " << endl
			<< " positions: " << mesh.data().getCount() << endl
			<< " materials: " << mesh.getMaterials().size() << endl
			<< " triangles: " << mesh.getNumberOfTriangles() << endl
			<< endl;
	}

	if( cd.writeResult )
	{
		if( cd.verbose ) cout << "writing.." << endl;
		pwn::io::WriteTarget wt(argv0, outdir);
		pwn::io::Write(mesh, boost::filesystem::path(inputfile).replace_extension("mesh").filename());
	}

	BOOST_FOREACH(const pwn::mesh::AnimationInformation& ai, animationsToExtract)
	{
		pwn::mesh::Animation ani;
		animation.subanim(ai, &ani);

		pwn::string adir = cd.animdir;
		if( adir.empty() )
		{
			adir = (
				boost::filesystem::path(outdir)
				/ boost::filesystem::path(inputfile).replace_extension().filename()
				)
				.directory_string();
		};

		pwn::io::WriteTarget wt(argv0, adir);
		pwn::io::Write(ani, boost::filesystem::path(ai.name).replace_extension("anim").filename());
	}

	if( cd.verbose ) cout << endl << "done." << endl;

	return true;
}

AnimationExtract LoadAnimations(const pwn::string& filename)
{
	using boost::property_tree::ptree;

	AnimationExtract ae;
	ptree pt;
	read_xml(filename, pt);
	BOOST_FOREACH(ptree::value_type &an, pt.get_child("animations"))
	{
		ptree anida = an.second;
		const pwn::string name = anida.get<pwn::string>("name");
		const pwn::uint32 start = anida.get<pwn::uint32>("start");
		const pwn::uint32 end = anida.get<pwn::uint32>("end");
		ae.push_back(pwn::mesh::AnimationInformation(start, end, name));
	}

	return ae;
}

bool IsArgument(const std::string& str)
{
	Assert(!str.empty());
	return str[0] == '-' || str[1] == '/';
}

class app
{
public:
	app()
		: errors(0)
	{
	}

	void handle(int argc, char* argv[])
	{
		ConvertData arg;
		ConvertData old;
		InputFormat::Type formatOveride = InputFormat::Unknown;

		for(int i=0; i<argc; ++i)
		{
			if( IsArgument(argv[i]) )
			{
				const std::string name = pwn::core::ToLower(pwn::core::TrimLeft(argv[i], "-/"));
				const std::string val = i+1<argc ? argv[i+1] : "";
				if( name == "s" || name == "scale" )
				{
					arg.modelScale = boost::lexical_cast<float>(val);
					arg.useModelScale = true;
					++i;
				}
				else if ( name == "t" || name=="tex" || name == "texturedir" )
				{
					arg.texturedir = val;
					++i;
				}
				else if (name == "a" || name=="anim" || name == "animdir" )
				{
					arg.animdir = val;
					++i;
				}
				else if ( name == "o" || name=="out" || name == "outdir" )
				{
					arg.outdir == val;
					++i;
				}
				else if ( name=="s" || name=="stat" || name == "showstat" )
				{
					arg.runStatistics = true;
				}
				else if ( name == "i" || name == "info" )
				{
					arg.meshInfo = true;
				}
				else if( name == "w" || name=="nowrite" )
				{
					arg.writeResults = false;
				}
				else if ( name == "k" || name == "keep" )
				{
					arg = old;
				}
				else if (name == "f" || name=="format" || name=="force" )
				{
					formatOveride = SuggestFormatData(val);
					++i;
				}
			}
			else
			{
				const pwn::string file = argv[i];
				AnimationExtract animations = LoadAnimations(SuggestAnimationFile(file));
				Convert(argv[0], arg, animations, file, formatOveride);
				old = arg;
				arg = ConvertData();
				formatOveride = InputFormat::Unknown;
			}
		}
	}

	int errors;
};

int main(int argc, char* argv[])
{
	using namespace std;

	if( argc == 1 )
	{
		cout << "error usage: pwn-convert filename arguments";
		return 1;
	}

	app a;
	a.handle(argc, argv);

	return a.errors;
}

<|endoftext|>


<commit_before>/* The MIT License (MIT)
 *
 * Copyright (c) 2014-2018 David Medina and Tim Warburton
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 */
#include <stdlib.h>
#include <time.h>
#include <unistd.h>

#include <occa.hpp>
#include <occa/c/types.hpp>
#include <occa/tools/testing.hpp>

void testTypes();

int main(const int argc, const char **argv) {
  srand(time(NULL));

  testTypes();
}

void testTypes() {
#define TEST_OCCA_TYPE(value, OCCA_TYPE)        \
  do {                                          \
    occaType v = occa::c::newOccaType(value);   \
    ASSERT_EQ(v.type, OCCA_TYPE);               \
    occaFree(v);                                \
  } while (0)

  TEST_OCCA_TYPE((void*) NULL, OCCA_PTR);

  TEST_OCCA_TYPE(true, OCCA_BOOL);
  TEST_OCCA_TYPE((int8_t) 1, OCCA_INT8);
  TEST_OCCA_TYPE((uint8_t) 1, OCCA_UINT8);
  TEST_OCCA_TYPE((int16_t) 1, OCCA_INT16);
  TEST_OCCA_TYPE((uint16_t) 1, OCCA_UINT16);
  TEST_OCCA_TYPE((int32_t) 1, OCCA_INT32);
  TEST_OCCA_TYPE((uint32_t) 1, OCCA_UINT32);
  TEST_OCCA_TYPE((int64_t) 1, OCCA_INT64);
  TEST_OCCA_TYPE((uint64_t) 1, OCCA_UINT64);
  TEST_OCCA_TYPE((float) 1.0, OCCA_FLOAT);
  TEST_OCCA_TYPE((double) 1.0, OCCA_DOUBLE);

  TEST_OCCA_TYPE(occa::device(), OCCA_DEVICE);
  TEST_OCCA_TYPE(occa::kernel(), OCCA_KERNEL);
  TEST_OCCA_TYPE(occa::memory(), OCCA_MEMORY);
  TEST_OCCA_TYPE(occa::properties(), OCCA_PROPERTIES);

  ASSERT_THROW_START {
    occa::c::newOccaType(std::string());
  } ASSERT_THROW_END;

#undef TEST_OCCA_TYPE
}
<commit_msg>[CI] Updated c/types tests<commit_after>/* The MIT License (MIT)
 *
 * Copyright (c) 2014-2018 David Medina and Tim Warburton
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 */
#include <stdlib.h>
#include <time.h>
#include <unistd.h>

#include <occa.hpp>
#include <occa/c/types.hpp>
#include <occa/tools/testing.hpp>

void testTypes();

int main(const int argc, const char **argv) {
  srand(time(NULL));

  testTypes();
}

void testTypes() {
#define TEST_OCCA_TYPE(value, OCCA_TYPE)        \
  do {                                          \
    occaType v = occa::c::newOccaType(value);   \
    ASSERT_EQ(v.type, OCCA_TYPE);               \
    occaFree(v);                                \
  } while (0)

  TEST_OCCA_TYPE((void*) NULL, OCCA_PTR);

  TEST_OCCA_TYPE(true, OCCA_BOOL);
  TEST_OCCA_TYPE((int8_t) 1, OCCA_INT8);
  TEST_OCCA_TYPE((uint8_t) 1, OCCA_UINT8);
  TEST_OCCA_TYPE((int16_t) 1, OCCA_INT16);
  TEST_OCCA_TYPE((uint16_t) 1, OCCA_UINT16);
  TEST_OCCA_TYPE((int32_t) 1, OCCA_INT32);
  TEST_OCCA_TYPE((uint32_t) 1, OCCA_UINT32);
  TEST_OCCA_TYPE((int64_t) 1, OCCA_INT64);
  TEST_OCCA_TYPE((uint64_t) 1, OCCA_UINT64);
  TEST_OCCA_TYPE((float) 1.0, OCCA_FLOAT);
  TEST_OCCA_TYPE((double) 1.0, OCCA_DOUBLE);

  TEST_OCCA_TYPE(occa::device(), OCCA_DEVICE);
  TEST_OCCA_TYPE(occa::kernel(), OCCA_KERNEL);
  TEST_OCCA_TYPE(occa::memory(), OCCA_MEMORY);
  TEST_OCCA_TYPE(*(new occa::properties()), OCCA_PROPERTIES);

  ASSERT_THROW_START {
    occa::c::newOccaType<std::string>("hi");
  } ASSERT_THROW_END;

#undef TEST_OCCA_TYPE
}
<|endoftext|>