<commit_before>/*****************************************************************************
// * This source file is part of ArkGameFrame                                *
// * For the latest info, see https://github.com/ArkGame                     *
// *                                                                         *
// * Copyright(c) 2013 - 2017 ArkGame authors.                               *
// *                                                                         *
// * Licensed under the Apache License, Version 2.0 (the "License");         *
// * you may not use this file except in compliance with the License.        *
// * You may obtain a copy of the License at                                 *
// *                                                                         *
// *     http://www.apache.org/licenses/LICENSE-2.0                          *
// *                                                                         *
// * Unless required by applicable law or agreed to in writing, software     *
// * distributed under the License is distributed on an "AS IS" BASIS,       *
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.*
// * See the License for the specific language governing permissions and     *
// * limitations under the License.                                          *
// *                                                                         *
// *                                                                         *
// * @file      AFCNetClient.cpp                                              *
// * @author    Ark Game Tech                                                *
// * @date      2015-12-15                                                   *
// * @brief     AFCNetClient                                                  *
*****************************************************************************/
#include "AFCNetClient.h"
#include <string.h>

#if ARK_PLATFORM == PLATFORM_WIN
#include <WS2tcpip.h>
#include <winsock2.h>
#pragma  comment(lib,"Ws2_32.lib")
#pragma  comment(lib,"event.lib")
#pragma  comment(lib,"event_core.lib")
#elif ARK_PLATFORM == PLATFORM_APPLE
#include <arpa/inet.h>
#endif

#include "event2/bufferevent_struct.h"
#include "event2/event.h"

bool AFCNetClient::Execute()
{
    ProcessMsgLogicThread();
    return true;
}

void AFCNetClient::ProcessMsgLogicThread()
{
    {
        AFScopeRdLock xGuard(mRWLock);
        ProcessMsgLogicThread(m_pClientObject.get());
    }

    if(NULL  != m_pClientObject.get() && m_pClientObject->NeedRemove())
    {
        AFScopeWrLock xGuard(mRWLock);
        m_pClientObject.release();
    }

}

void AFCNetClient::ProcessMsgLogicThread(NetObject* pObject)
{
    if(NULL ==  pObject)
    {
        return;
    }

    //Handle Msg;
    const int nReceiveCount = pObject->mqMsgFromNet.Count();
    for(size_t i = 0; (i < nReceiveCount); i++)
    {
        MsgFromNetInfo* pMsgFromNet(NULL);
        if(!pObject->mqMsgFromNet.Pop(pMsgFromNet))
        {
            break;
        }

        if(!pMsgFromNet)
        {
            continue;
        }

        switch(pMsgFromNet->nType)
        {
        case RECIVEDATA:
            {
                int nRet = 0;
                if(mRecvCB)
                {
                    mRecvCB(pMsgFromNet->xHead.GetMsgID(), pMsgFromNet->strMsg.c_str(), pMsgFromNet->strMsg.size(), pObject->GetClientID());
                }
            }
            break;
        case CONNECTED:
            {
                mEventCB((NetEventType)pMsgFromNet->nType, pMsgFromNet->xClientID, mnServerID);
            }
            break;
        case DISCONNECTED:
            {
                mEventCB((NetEventType)pMsgFromNet->nType, pMsgFromNet->xClientID, mnServerID);
                pObject->SetNeedRemove(true);
            }
            break;
        default:
            break;
        }

        delete pMsgFromNet;
    }
}
void AFCNetClient::Initialization(const std::string& strAddrPort, const int nServerID)
{
#ifdef _MSC_VER
    WSADATA wsa_data;
    WSAStartup(MAKEWORD(2, 2), &wsa_data);
#endif

    mstrIPPort = strAddrPort;
    mnServerID = nServerID;
    m_pThread.reset(new evpp::EventLoopThread);
    m_pThread->set_name("TCPClientThread");
    m_pThread->Start();

    m_pClient.reset(new evpp::TCPClient(m_pThread->loop(), mstrIPPort, "TCPPingPongClient"));
    m_pClient->SetConnectionCallback(std::bind(&AFCNetClient::OnClientConnection, std::placeholders::_1, (void*) this));
    m_pClient->SetMessageCallback(std::bind(&AFCNetClient::OnMessage, std::placeholders::_1, std::placeholders::_2, (void*)this));
    m_pClient->set_auto_reconnect(false);
    m_pClient->Connect();

    bWorking = true;
}

bool AFCNetClient::Final()
{
    CloseSocketAll();
    m_pThread->Stop(true);
    bWorking = false;
    return true;
}

bool AFCNetClient::CloseSocketAll()
{
    m_pClient->Disconnect();
    return true;
}

bool AFCNetClient::SendMsg(const char* msg, const uint32_t nLen, const AFGUID& xClient)
{
    if(nLen <= 0)
    {
        return false;
    }

    if(m_pClient->conn().get())
    {
        m_pClient->conn()->Send(msg, nLen);
    }

    return false;
}

bool AFCNetClient::CloseNetObject(const AFGUID& xClient)
{
    m_pClient->Disconnect();
    return true;
}

bool AFCNetClient::DismantleNet(NetObject* pObject)
{
    for(; pObject->GetBuffLen() >= AFIMsgHead::AF_Head::NF_HEAD_LENGTH;)
    {
        AFCMsgHead xHead;
        int nMsgBodyLength = DeCode(pObject->GetBuff(), pObject->GetBuffLen(), xHead);
        if(nMsgBodyLength >= 0 && xHead.GetMsgID() > 0)
        {
            mRecvCB(xHead.GetMsgID(), pObject->GetBuff() + AFIMsgHead::AF_Head::NF_HEAD_LENGTH, nMsgBodyLength, pObject->GetClientID());
            MsgFromNetInfo* pNetInfo = new  MsgFromNetInfo(pObject->GetConnPtr());
            pNetInfo->xHead = xHead;
            pNetInfo->nType = RECIVEDATA;
            pNetInfo->strMsg.append(pObject->GetBuff() + AFIMsgHead::AF_Head::NF_HEAD_LENGTH, nMsgBodyLength);
            pObject->mqMsgFromNet.Push(pNetInfo);
            pObject->RemoveBuff(nMsgBodyLength + AFIMsgHead::AF_Head::NF_HEAD_LENGTH);
        }
        break;
    }

    return true;
}

void AFCNetClient::log_cb(int severity, const char* msg)
{

}

bool AFCNetClient::IsServer()
{
    return false;
}

bool AFCNetClient::Log(int severity, const char* msg)
{
    log_cb(severity, msg);
    return true;
}

bool AFCNetClient::StopAfter(double dTime)
{
    m_pThread->loop()->RunAfter(evpp::Duration(dTime), [&]()
    {
        bWorking = false;
    });
    return true;
}

void AFCNetClient::OnClientConnection(const evpp::TCPConnPtr& conn, void* pData)
{
    AFCNetClient * pClient = (AFCNetClient*)(pData);
    if(pClient)
    {
        conn->SetTCPNoDelay(true);
        pClient->OnClientConnectionInner(conn);
    }
}

void AFCNetClient::OnClientConnectionInner(const evpp::TCPConnPtr& conn)
{
    if(conn->IsConnected())
    {
        conn->SetTCPNoDelay(true);
        MsgFromNetInfo* pMsg = new MsgFromNetInfo(conn);
        pMsg->xClientID = conn->id();
        pMsg->nType = CONNECTED;
        {
            AFScopeWrLock xGuard(mRWLock);

            NetObject* pObject = new NetObject(this, pMsg->xClientID, conn);
            conn->set_context(evpp::Any(pObject));
            m_pClientObject.reset(pObject);
            pObject->mqMsgFromNet.Push(pMsg);
        }
    }
    else
    {
        MsgFromNetInfo* pMsg = new MsgFromNetInfo(conn);
        pMsg->xClientID = conn->id();
        pMsg->nType = DISCONNECTED;

        //主线程不能直接删除。不然这里就野了
        if(!conn->context().IsEmpty())
        {
            NetObject* pObject = evpp::any_cast<NetObject*>(conn->context());
            pObject->mqMsgFromNet.Push(pMsg);
            conn->set_context(evpp::Any(nullptr));
        }

    }
}

void AFCNetClient::OnMessage(const evpp::TCPConnPtr& conn, evpp::Buffer* msg, void* pData)
{
    AFCNetClient * pNet = (AFCNetClient*)pData;
    if(pNet)
    {
        pNet->OnMessageInner(conn, msg);
    }
}

void AFCNetClient::OnMessageInner(const evpp::TCPConnPtr& conn, evpp::Buffer* msg)
{
    nReceiverSize += msg->length();
    NetObject* pObject = evpp::any_cast<NetObject*>(conn->context());
    if(pObject)
    {
        evpp::Slice xMsgBuff;
        if(msg)
        {
            xMsgBuff = msg->NextAll();
            pObject->AddBuff(xMsgBuff.data(), xMsgBuff.size());
            DismantleNet(pObject);
        }
    }
}

bool AFCNetClient::SendMsgWithOutHead(const int16_t nMsgID, const char* msg, const uint32_t nLen, const AFGUID & xClientID)
{
    std::string strOutData;
    int nAllLen = EnCode(nMsgID, msg, nLen, strOutData);
    if(nAllLen == nLen + AFIMsgHead::AF_Head::NF_HEAD_LENGTH)
    {
        return SendMsg(strOutData.c_str(), strOutData.length(), xClientID);
    }

    return false;
}

int AFCNetClient::EnCode(const uint16_t unMsgID, const char* strData, const uint32_t unDataLen, std::string & strOutData)
{
    AFCMsgHead xHead;
    xHead.SetMsgID(unMsgID);
    xHead.SetBodyLength(unDataLen);

    char szHead[AFIMsgHead::AF_Head::NF_HEAD_LENGTH] = { 0 };
    xHead.EnCode(szHead);

    strOutData.clear();
    strOutData.append(szHead, AFIMsgHead::AF_Head::NF_HEAD_LENGTH);
    strOutData.append(strData, unDataLen);

    return xHead.GetBodyLength() + AFIMsgHead::AF_Head::NF_HEAD_LENGTH;
}

int AFCNetClient::DeCode(const char* strData, const uint32_t unAllLen, AFCMsgHead & xHead)
{
    if(unAllLen < AFIMsgHead::AF_Head::NF_HEAD_LENGTH)
    {
        return -1;
    }

    if(AFIMsgHead::AF_Head::NF_HEAD_LENGTH != xHead.DeCode(strData))
    {
        return -2;
    }

    if(xHead.GetBodyLength() > (unAllLen - AFIMsgHead::AF_Head::NF_HEAD_LENGTH))
    {
        return -3;
    }
    return xHead.GetBodyLength();
}

<commit_msg>modify net module ,fix SetTCPNoDelay's error<commit_after>/*****************************************************************************
// * This source file is part of ArkGameFrame                                *
// * For the latest info, see https://github.com/ArkGame                     *
// *                                                                         *
// * Copyright(c) 2013 - 2017 ArkGame authors.                               *
// *                                                                         *
// * Licensed under the Apache License, Version 2.0 (the "License");         *
// * you may not use this file except in compliance with the License.        *
// * You may obtain a copy of the License at                                 *
// *                                                                         *
// *     http://www.apache.org/licenses/LICENSE-2.0                          *
// *                                                                         *
// * Unless required by applicable law or agreed to in writing, software     *
// * distributed under the License is distributed on an "AS IS" BASIS,       *
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.*
// * See the License for the specific language governing permissions and     *
// * limitations under the License.                                          *
// *                                                                         *
// *                                                                         *
// * @file      AFCNetClient.cpp                                              *
// * @author    Ark Game Tech                                                *
// * @date      2015-12-15                                                   *
// * @brief     AFCNetClient                                                  *
*****************************************************************************/
#include "AFCNetClient.h"
#include <string.h>

#if ARK_PLATFORM == PLATFORM_WIN
#include <WS2tcpip.h>
#include <winsock2.h>
#pragma  comment(lib,"Ws2_32.lib")
#pragma  comment(lib,"event.lib")
#pragma  comment(lib,"event_core.lib")
#elif ARK_PLATFORM == PLATFORM_APPLE
#include <arpa/inet.h>
#endif

#include "event2/bufferevent_struct.h"
#include "event2/event.h"

bool AFCNetClient::Execute()
{
    ProcessMsgLogicThread();
    return true;
}

void AFCNetClient::ProcessMsgLogicThread()
{
    {
        AFScopeRdLock xGuard(mRWLock);
        ProcessMsgLogicThread(m_pClientObject.get());
    }

    if(NULL  != m_pClientObject.get() && m_pClientObject->NeedRemove())
    {
        AFScopeWrLock xGuard(mRWLock);
        m_pClientObject.release();
    }

}

void AFCNetClient::ProcessMsgLogicThread(NetObject* pObject)
{
    if(NULL ==  pObject)
    {
        return;
    }

    //Handle Msg;
    const int nReceiveCount = pObject->mqMsgFromNet.Count();
    for(size_t i = 0; (i < nReceiveCount); i++)
    {
        MsgFromNetInfo* pMsgFromNet(NULL);
        if(!pObject->mqMsgFromNet.Pop(pMsgFromNet))
        {
            break;
        }

        if(!pMsgFromNet)
        {
            continue;
        }

        switch(pMsgFromNet->nType)
        {
        case RECIVEDATA:
            {
                int nRet = 0;
                if(mRecvCB)
                {
                    mRecvCB(pMsgFromNet->xHead.GetMsgID(), pMsgFromNet->strMsg.c_str(), pMsgFromNet->strMsg.size(), pObject->GetClientID());
                }
            }
            break;
        case CONNECTED:
            {
                mEventCB((NetEventType)pMsgFromNet->nType, pMsgFromNet->xClientID, mnServerID);
            }
            break;
        case DISCONNECTED:
            {
                mEventCB((NetEventType)pMsgFromNet->nType, pMsgFromNet->xClientID, mnServerID);
                pObject->SetNeedRemove(true);
            }
            break;
        default:
            break;
        }

        delete pMsgFromNet;
    }
}
void AFCNetClient::Initialization(const std::string& strAddrPort, const int nServerID)
{
#ifdef _MSC_VER
    WSADATA wsa_data;
    WSAStartup(MAKEWORD(2, 2), &wsa_data);
#endif

    mstrIPPort = strAddrPort;
    mnServerID = nServerID;
    m_pThread.reset(new evpp::EventLoopThread);
    m_pThread->set_name("TCPClientThread");
    m_pThread->Start();

    m_pClient.reset(new evpp::TCPClient(m_pThread->loop(), mstrIPPort, "TCPPingPongClient"));
    m_pClient->SetConnectionCallback(std::bind(&AFCNetClient::OnClientConnection, std::placeholders::_1, (void*) this));
    m_pClient->SetMessageCallback(std::bind(&AFCNetClient::OnMessage, std::placeholders::_1, std::placeholders::_2, (void*)this));
    m_pClient->set_auto_reconnect(false);
    m_pClient->Connect();

    bWorking = true;
}

bool AFCNetClient::Final()
{
    CloseSocketAll();
    m_pThread->Stop(true);
    bWorking = false;
    return true;
}

bool AFCNetClient::CloseSocketAll()
{
    m_pClient->Disconnect();
    return true;
}

bool AFCNetClient::SendMsg(const char* msg, const uint32_t nLen, const AFGUID& xClient)
{
    if(nLen <= 0)
    {
        return false;
    }

    if(m_pClient->conn().get())
    {
        m_pClient->conn()->Send(msg, nLen);
    }

    return false;
}

bool AFCNetClient::CloseNetObject(const AFGUID& xClient)
{
    m_pClient->Disconnect();
    return true;
}

bool AFCNetClient::DismantleNet(NetObject* pObject)
{
    for(; pObject->GetBuffLen() >= AFIMsgHead::AF_Head::NF_HEAD_LENGTH;)
    {
        AFCMsgHead xHead;
        int nMsgBodyLength = DeCode(pObject->GetBuff(), pObject->GetBuffLen(), xHead);
        if(nMsgBodyLength >= 0 && xHead.GetMsgID() > 0)
        {
            mRecvCB(xHead.GetMsgID(), pObject->GetBuff() + AFIMsgHead::AF_Head::NF_HEAD_LENGTH, nMsgBodyLength, pObject->GetClientID());
            MsgFromNetInfo* pNetInfo = new  MsgFromNetInfo(pObject->GetConnPtr());
            pNetInfo->xHead = xHead;
            pNetInfo->nType = RECIVEDATA;
            pNetInfo->strMsg.append(pObject->GetBuff() + AFIMsgHead::AF_Head::NF_HEAD_LENGTH, nMsgBodyLength);
            pObject->mqMsgFromNet.Push(pNetInfo);
            pObject->RemoveBuff(nMsgBodyLength + AFIMsgHead::AF_Head::NF_HEAD_LENGTH);
        }
        break;
    }

    return true;
}

void AFCNetClient::log_cb(int severity, const char* msg)
{

}

bool AFCNetClient::IsServer()
{
    return false;
}

bool AFCNetClient::Log(int severity, const char* msg)
{
    log_cb(severity, msg);
    return true;
}

bool AFCNetClient::StopAfter(double dTime)
{
    m_pThread->loop()->RunAfter(evpp::Duration(dTime), [&]()
    {
        bWorking = false;
    });
    return true;
}

void AFCNetClient::OnClientConnection(const evpp::TCPConnPtr& conn, void* pData)
{
    AFCNetClient * pClient = (AFCNetClient*)(pData);
    if(pClient)
    {
        pClient->OnClientConnectionInner(conn);
    }
}

void AFCNetClient::OnClientConnectionInner(const evpp::TCPConnPtr& conn)
{
    if(conn->IsConnected())
    {
        conn->SetTCPNoDelay(true);
        MsgFromNetInfo* pMsg = new MsgFromNetInfo(conn);
        pMsg->xClientID = conn->id();
        pMsg->nType = CONNECTED;
        {
            AFScopeWrLock xGuard(mRWLock);

            NetObject* pObject = new NetObject(this, pMsg->xClientID, conn);
            conn->set_context(evpp::Any(pObject));
            m_pClientObject.reset(pObject);
            pObject->mqMsgFromNet.Push(pMsg);
        }
    }
    else
    {
        MsgFromNetInfo* pMsg = new MsgFromNetInfo(conn);
        pMsg->xClientID = conn->id();
        pMsg->nType = DISCONNECTED;

        //主线程不能直接删除。不然这里就野了
        if(!conn->context().IsEmpty())
        {
            NetObject* pObject = evpp::any_cast<NetObject*>(conn->context());
            pObject->mqMsgFromNet.Push(pMsg);
            conn->set_context(evpp::Any(nullptr));
        }

    }
}

void AFCNetClient::OnMessage(const evpp::TCPConnPtr& conn, evpp::Buffer* msg, void* pData)
{
    AFCNetClient * pNet = (AFCNetClient*)pData;
    if(pNet)
    {
        pNet->OnMessageInner(conn, msg);
    }
}

void AFCNetClient::OnMessageInner(const evpp::TCPConnPtr& conn, evpp::Buffer* msg)
{
    nReceiverSize += msg->length();
    NetObject* pObject = evpp::any_cast<NetObject*>(conn->context());
    if(pObject)
    {
        evpp::Slice xMsgBuff;
        if(msg)
        {
            xMsgBuff = msg->NextAll();
            pObject->AddBuff(xMsgBuff.data(), xMsgBuff.size());
            DismantleNet(pObject);
        }
    }
}

bool AFCNetClient::SendMsgWithOutHead(const int16_t nMsgID, const char* msg, const uint32_t nLen, const AFGUID & xClientID)
{
    std::string strOutData;
    int nAllLen = EnCode(nMsgID, msg, nLen, strOutData);
    if(nAllLen == nLen + AFIMsgHead::AF_Head::NF_HEAD_LENGTH)
    {
        return SendMsg(strOutData.c_str(), strOutData.length(), xClientID);
    }

    return false;
}

int AFCNetClient::EnCode(const uint16_t unMsgID, const char* strData, const uint32_t unDataLen, std::string & strOutData)
{
    AFCMsgHead xHead;
    xHead.SetMsgID(unMsgID);
    xHead.SetBodyLength(unDataLen);

    char szHead[AFIMsgHead::AF_Head::NF_HEAD_LENGTH] = { 0 };
    xHead.EnCode(szHead);

    strOutData.clear();
    strOutData.append(szHead, AFIMsgHead::AF_Head::NF_HEAD_LENGTH);
    strOutData.append(strData, unDataLen);

    return xHead.GetBodyLength() + AFIMsgHead::AF_Head::NF_HEAD_LENGTH;
}

int AFCNetClient::DeCode(const char* strData, const uint32_t unAllLen, AFCMsgHead & xHead)
{
    if(unAllLen < AFIMsgHead::AF_Head::NF_HEAD_LENGTH)
    {
        return -1;
    }

    if(AFIMsgHead::AF_Head::NF_HEAD_LENGTH != xHead.DeCode(strData))
    {
        return -2;
    }

    if(xHead.GetBodyLength() > (unAllLen - AFIMsgHead::AF_Head::NF_HEAD_LENGTH))
    {
        return -3;
    }
    return xHead.GetBodyLength();
}

<|endoftext|>


<commit_before>#ifndef CORE_HPP_INCLUDED
#define CORE_HPP_INCLUDED

#include <yaml/config.hpp>
#include <yaml/detail/have_type.hpp>
#include <yaml/detail/cond.hpp>
#include <yaml/detail/template_fitting.hpp>
#include <yaml/detail/placeholders.hpp>
#include <yaml/detail/force.hpp>
#include <yaml/detail/take_from_variadic.hpp>

#include <type_traits>
#include <cstddef>

BEGIN_YAML_NSP

BEGIN_DETAIL_NSP

template<typename...> struct ls;

/// \brief Creates the initial placeholders of a given template. Is used to
///        initialize curried functions.
template<template<class...> class T> class initial_placeholders {

  template<std::size_t S, typename... As> struct impl {

    using type = typename cond<
      fitting_t<T, As...>,
      ls<As...>,
      impl<(S + 1), As..., ph<S + 1>>>::type;
  };

public:

  using type = typename impl<0, ph<0>>::type;
};

/// \brief Used to represent the state of a curried function.
///        N:  is the number of arguments.
///        M:  is the number of placeholders
///        Ss: the arguments
template<std::size_t N, std::size_t M, typename... Ss>
struct curried_func_state;

/// \brief Used to represent the arguments passed to a curried function.
///        N:  is the number of arguments.
///        M:  is the number of placeholders
///        As: the arguments
/// \NOTE  'form' stands for formalized
template<std::size_t M, std::size_t K, typename... As> struct form_args;

/// \brief To codify a curried function: T is the template, and S the state.
template<template<class...> class T, typename S> struct curried_func;

/// \brief Creates a curried function from a template.
template<template<class...> class T> class create_curried_func {

  template<typename> struct helper;

  template<typename... As> struct helper<ls<As...>> {
    const static std::size_t size = sizeof...(As);
    using state_t = curried_func_state<size, size, As...>;
    using type = curried_func<T, state_t>;
  };

public:

  using type = typename helper<typename initial_placeholders<T>::type>::type;
};

template<template<class...> class T>
using curried_func_t = typename create_curried_func<T>::type;

/// \brief Converts a list of arguments to a formalized list of N arguments.
///        For example it introduce missing placeholders.
template<std::size_t N, typename... As> class formalize_args {

  template<typename, typename...> struct impl;

  template<std::size_t M, std::size_t K, typename... U>
  struct impl<form_args<M, K, U...>> {
    using type = typename cond<
      std::integral_constant<bool, (sizeof...(U) == M)>,
      form_args<M, K, U...>,
      impl<form_args<M, K + 1, U..., ph<K>>>>::type;
  };

  template<
    std::size_t M, std::size_t K, std::size_t P, typename... U, typename... R>
  struct impl<form_args<M, K, U...>, ph<P>, R...> {
    using type = typename impl<form_args<M, K + 1, U..., ph<P>>, R...>::type;
  };

  template<
    std::size_t M, std::size_t K, typename... U, typename F, typename... R>
  struct impl<form_args<M, K, U...>, F, R...> {
    using type = typename impl<form_args<M, K, U..., F>, R...>::type;
  };

public:

  using type = typename impl<form_args<N, 0>, As...>::type;

};

/// \brief Transition function from a curried state to another.
template<typename S, typename A> class next_state;

template<
  std::size_t N, std::size_t M, std::size_t K, typename... Ss, typename... As>
class next_state<curried_func_state<N, M, Ss...>, form_args<M, K, As...>> {

  template<typename Ss, typename As, typename Rs> struct impl;

  template<typename... As, typename... Rs>
  struct impl<ls<>, ls<As...>, ls<Rs...>> {
    using type = curried_func_state<N, K, Rs...>;
  };

  template<typename S, typename... Ss, typename... As, typename... Rs>
  struct impl<ls<S, Ss...>, ls<As...>, ls<Rs...>> {
    using type = typename impl<ls<Ss...>, ls<As...>, ls<Rs..., S>>::type;
  };

  template<std::size_t P, typename... Ss, typename... As, typename... Rs>
  struct impl<ls<ph<P>, Ss...>, ls<As...>, ls<Rs...>> {
    using it = typename take_from_variadic<P, As...>::type;
    using type = typename impl<ls<Ss...>, ls<As...>, ls<Rs..., it>>::type;
  };

public:

  using type = typename impl<ls<Ss...>, ls<As...>, ls<>>::type;

};

/// \brief Apply a set of arguments to a curried function.
template<typename F, typename... As> class apply {

  template<typename, typename...> struct impl;

  template<
    template<class...> class T,
    std::size_t N,
    std::size_t M,
    typename... Ss,
    typename... Args>
  struct impl<curried_func<T, curried_func_state<N, M, Ss...>>, Args...> {

    using form_args = typename formalize_args<M, Args...>::type;
    using current_state = curried_func_state<N, M, Ss...>;
    using next_state = typename next_state<current_state, form_args>::type;

    template<typename> struct helper;

    template<std::size_t N, std::size_t K, typename... Rs>
    struct helper<curried_func_state<N, K, Rs...>> {
      using type = curried_func<T, curried_func_state<N, K, Rs...>>;
    };

    template<std::size_t N, typename... Rs>
    struct helper<curried_func_state<N, 0, Rs...>> {
      using type = typename T<Rs...>::type;
    };

    using type = typename helper<next_state>::type;

  };

public:

  using type = typename impl<F, As...>::type;
};

template<typename F, typename... As>
using apply_t = typename apply<F, As...>::type;

template<typename T1, typename T2> struct pair {
  using first_type = T1;
  using second_type = T2;
  using type = pair<T1, T2>;
};

/// \brief Creates a pair from two types.
using make_pair = create_curried_func<pair>;

template<typename F> struct flip_tmpl {
  using type = typename apply<F, _1, _0>::type;
};

/// \brief flip F takes its (first) two arguments in the reverse order of F.
using flip = curried_func_t<flip_tmpl>;

END_DETAIL_NSP

using DETAIL_NSP_REF curried_func_t;
using DETAIL_NSP_REF apply;
using DETAIL_NSP_REF apply_t;
using DETAIL_NSP_REF force_t;
using DETAIL_NSP_REF is_same;
using DETAIL_NSP_REF pair;
using DETAIL_NSP_REF make_pair;
using DETAIL_NSP_REF flip;

END_YAML_NSP

#endif CORE_HPP_INCLUDED<commit_msg>nothing type added<commit_after>#ifndef CORE_HPP_INCLUDED
#define CORE_HPP_INCLUDED

#include <yaml/config.hpp>
#include <yaml/detail/have_type.hpp>
#include <yaml/detail/cond.hpp>
#include <yaml/detail/template_fitting.hpp>
#include <yaml/detail/placeholders.hpp>
#include <yaml/detail/force.hpp>
#include <yaml/detail/take_from_variadic.hpp>

#include <type_traits>
#include <cstddef>

BEGIN_YAML_NSP

BEGIN_DETAIL_NSP

template<typename...> struct ls;

/// \brief Creates the initial placeholders of a given template. Is used to
///        initialize curried functions.
template<template<class...> class T> class initial_placeholders {

  template<std::size_t S, typename... As> struct impl {

    using type = typename cond<
      fitting_t<T, As...>,
      ls<As...>,
      impl<(S + 1), As..., ph<S + 1>>>::type;
  };

public:

  using type = typename impl<0, ph<0>>::type;
};

/// \brief Used to represent the state of a curried function.
///        N:  is the number of arguments.
///        M:  is the number of placeholders
///        Ss: the arguments
template<std::size_t N, std::size_t M, typename... Ss>
struct curried_func_state;

/// \brief Used to represent the arguments passed to a curried function.
///        N:  is the number of arguments.
///        M:  is the number of placeholders
///        As: the arguments
/// \NOTE  'form' stands for formalized
template<std::size_t M, std::size_t K, typename... As> struct form_args;

/// \brief To codify a curried function: T is the template, and S the state.
template<template<class...> class T, typename S> struct curried_func;

/// \brief Creates a curried function from a template.
template<template<class...> class T> class create_curried_func {

  template<typename> struct helper;

  template<typename... As> struct helper<ls<As...>> {
    const static std::size_t size = sizeof...(As);
    using state_t = curried_func_state<size, size, As...>;
    using type = curried_func<T, state_t>;
  };

public:

  using type = typename helper<typename initial_placeholders<T>::type>::type;
};

template<template<class...> class T>
using curried_func_t = typename create_curried_func<T>::type;

/// \brief Converts a list of arguments to a formalized list of N arguments.
///        For example it introduce missing placeholders.
template<std::size_t N, typename... As> class formalize_args {

  template<typename, typename...> struct impl;

  template<std::size_t M, std::size_t K, typename... U>
  struct impl<form_args<M, K, U...>> {
    using type = typename cond<
      std::integral_constant<bool, (sizeof...(U) == M)>,
      form_args<M, K, U...>,
      impl<form_args<M, K + 1, U..., ph<K>>>>::type;
  };

  template<
    std::size_t M, std::size_t K, std::size_t P, typename... U, typename... R>
  struct impl<form_args<M, K, U...>, ph<P>, R...> {
    using type = typename impl<form_args<M, K + 1, U..., ph<P>>, R...>::type;
  };

  template<
    std::size_t M, std::size_t K, typename... U, typename F, typename... R>
  struct impl<form_args<M, K, U...>, F, R...> {
    using type = typename impl<form_args<M, K, U..., F>, R...>::type;
  };

public:

  using type = typename impl<form_args<N, 0>, As...>::type;

};

/// \brief Transition function from a curried state to another.
template<typename S, typename A> class next_state;

template<
  std::size_t N, std::size_t M, std::size_t K, typename... Ss, typename... As>
class next_state<curried_func_state<N, M, Ss...>, form_args<M, K, As...>> {

  template<typename Ss, typename As, typename Rs> struct impl;

  template<typename... As, typename... Rs>
  struct impl<ls<>, ls<As...>, ls<Rs...>> {
    using type = curried_func_state<N, K, Rs...>;
  };

  template<typename S, typename... Ss, typename... As, typename... Rs>
  struct impl<ls<S, Ss...>, ls<As...>, ls<Rs...>> {
    using type = typename impl<ls<Ss...>, ls<As...>, ls<Rs..., S>>::type;
  };

  template<std::size_t P, typename... Ss, typename... As, typename... Rs>
  struct impl<ls<ph<P>, Ss...>, ls<As...>, ls<Rs...>> {
    using it = typename take_from_variadic<P, As...>::type;
    using type = typename impl<ls<Ss...>, ls<As...>, ls<Rs..., it>>::type;
  };

public:

  using type = typename impl<ls<Ss...>, ls<As...>, ls<>>::type;

};

/// \brief Apply a set of arguments to a curried function.
template<typename F, typename... As> class apply {

  template<typename, typename...> struct impl;

  template<
    template<class...> class T,
    std::size_t N,
    std::size_t M,
    typename... Ss,
    typename... Args>
  struct impl<curried_func<T, curried_func_state<N, M, Ss...>>, Args...> {

    using form_args = typename formalize_args<M, Args...>::type;
    using current_state = curried_func_state<N, M, Ss...>;
    using next_state = typename next_state<current_state, form_args>::type;

    template<typename> struct helper;

    template<std::size_t N, std::size_t K, typename... Rs>
    struct helper<curried_func_state<N, K, Rs...>> {
      using type = curried_func<T, curried_func_state<N, K, Rs...>>;
    };

    template<std::size_t N, typename... Rs>
    struct helper<curried_func_state<N, 0, Rs...>> {
      using type = typename T<Rs...>::type;
    };

    using type = typename helper<next_state>::type;

  };

public:

  using type = typename impl<F, As...>::type;
};

template<typename F, typename... As>
using apply_t = typename apply<F, As...>::type;

template<typename T1, typename T2> struct pair {
  using first_type = T1;
  using second_type = T2;
  using type = pair<T1, T2>;
};

/// \brief Creates a pair from two types.
using make_pair = create_curried_func<pair>;

template<typename F> struct flip_tmpl {
  using type = typename apply<F, _1, _0>::type;
};

/// \brief flip F takes its (first) two arguments in the reverse order of F.
using flip = curried_func_t<flip_tmpl>;

struct nothing { };

END_DETAIL_NSP

using DETAIL_NSP_REF curried_func_t;
using DETAIL_NSP_REF apply;
using DETAIL_NSP_REF apply_t;
using DETAIL_NSP_REF force_t;
using DETAIL_NSP_REF is_same;
using DETAIL_NSP_REF pair;
using DETAIL_NSP_REF make_pair;
using DETAIL_NSP_REF flip;
using DETAIL_NSP_REF nothing;

END_YAML_NSP

#endif CORE_HPP_INCLUDED<|endoftext|>


<commit_before>#include <stdio.h>
#include <node.h>
#include "nan.h"

#include "blake2.h"
#include "avon.h"
#include "streamer.h"

#define HERE() ({fprintf(stderr, "@%d\n", __LINE__);})

using namespace v8;

//------ operate on files

class FileWorker : public Nan::AsyncWorker
{
	public:
		FileWorker(Nan::Callback *callback, int algo, char* fname)
		: Nan::AsyncWorker(callback)
			, algorithm(algo)
			, filename(fname)
		{
		}

		~FileWorker()
		{
		}

		void Execute()
		{
			blake2fn streamFunc;

			switch (algorithm)
			{
				case B:
					streamFunc = blake2b_stream;
					length = BLAKE2B_OUTBYTES;
					break;

				case BP:
					streamFunc = blake2bp_stream;
					length = BLAKE2B_OUTBYTES;
					break;

				case S:
					streamFunc = blake2s_stream;
					length = BLAKE2S_OUTBYTES;
					break;

				case SP:
					streamFunc = blake2sp_stream;
					length = BLAKE2S_OUTBYTES;
					break;

				default:
					SetErrorMessage("Unknown hash type.");
					return;
			}

			FILE *f = NULL;
			f = fopen(filename, "rb");

			if (!f)
			{
				SetErrorMessage("Could not open file to hash.");
				return;
			}

			if (streamFunc(f, hash, length) < 0)
			{
				SetErrorMessage("Failed to calculate hash.");
				return;
			}

			fclose(f);
		}

		void HandleOKCallback()
		{
			Nan::HandleScope();
			Local<Value> argv[] =
			{
				Nan::Null(),
				Nan::CopyBuffer(hash, length).ToLocalChecked()
			};
			callback->Call(2, argv);
		};

	private:
		int algorithm;
		char* filename;
		size_t length;
		// The 2S hashes emit 32 bytes instead of 64, so we get away with this size.
		char hash[BLAKE2B_OUTBYTES];
};

NAN_METHOD(HashFile)
{
	int algo = info[0]->Uint32Value();
	Nan::Utf8String* name = new Nan::Utf8String(info[1]);
	Nan::Callback *callback = new Nan::Callback(info[2].As<Function>());
	Nan::AsyncQueueWorker(new FileWorker(callback, algo, **name));
}

NAN_METHOD(HashBufferSync)
{
	int algo = info[0]->Uint32Value();
	Local<Object> buffer = info[1].As<Object>();
	size_t length = node::Buffer::Length(buffer);
	char* data = node::Buffer::Data(buffer);

	blake2bufferfn func;
	size_t resultLen;
	char hash[BLAKE2B_OUTBYTES];

	switch (algo)
	{
		case B:
			func = blake2b_buffer;
			resultLen = BLAKE2B_OUTBYTES;
			break;

		case BP:
			func = blake2bp_buffer;
			resultLen = BLAKE2B_OUTBYTES;
			break;

		case S:
			func = blake2s_buffer;
			resultLen = BLAKE2S_OUTBYTES;
			break;

		case SP:
			func = blake2sp_buffer;
			resultLen = BLAKE2S_OUTBYTES;
			break;

		default:
			Nan::ThrowTypeError("Unknown hash type.");
			return;
	}

	if (func(data, length, hash) < 0)
	{
		Nan::ThrowTypeError("Failed to calculate hash.");
		return;
	}

	info.GetReturnValue().Set(Nan::CopyBuffer(hash, resultLen).ToLocalChecked());
}

// ------------ ceremony

NAN_MODULE_INIT(InitAll)
{
	Nan::Set(target,
		Nan::New<String>("b2_file").ToLocalChecked(),
		Nan::GetFunction(Nan::New<FunctionTemplate>(HashFile)).ToLocalChecked()
	);
	Nan::Set(target,
		Nan::New<String>("b2_buffer").ToLocalChecked(),
		Nan::GetFunction(Nan::New<FunctionTemplate>(HashBufferSync)).ToLocalChecked()
	);
	AvonStream::Initialize(target);
}

NODE_MODULE(blake2, InitAll)
<commit_msg>Pass async_resource to callback<commit_after>#include <stdio.h>
#include <node.h>
#include "nan.h"

#include "blake2.h"
#include "avon.h"
#include "streamer.h"

#define HERE() ({fprintf(stderr, "@%d\n", __LINE__);})

using namespace v8;

//------ operate on files

class FileWorker : public Nan::AsyncWorker
{
	public:
		FileWorker(Nan::Callback *callback, int algo, char* fname)
		: Nan::AsyncWorker(callback)
			, algorithm(algo)
			, filename(fname)
		{
		}

		~FileWorker()
		{
		}

		void Execute()
		{
			blake2fn streamFunc;

			switch (algorithm)
			{
				case B:
					streamFunc = blake2b_stream;
					length = BLAKE2B_OUTBYTES;
					break;

				case BP:
					streamFunc = blake2bp_stream;
					length = BLAKE2B_OUTBYTES;
					break;

				case S:
					streamFunc = blake2s_stream;
					length = BLAKE2S_OUTBYTES;
					break;

				case SP:
					streamFunc = blake2sp_stream;
					length = BLAKE2S_OUTBYTES;
					break;

				default:
					SetErrorMessage("Unknown hash type.");
					return;
			}

			FILE *f = NULL;
			f = fopen(filename, "rb");

			if (!f)
			{
				SetErrorMessage("Could not open file to hash.");
				return;
			}

			if (streamFunc(f, hash, length) < 0)
			{
				SetErrorMessage("Failed to calculate hash.");
				return;
			}

			fclose(f);
		}

		void HandleOKCallback()
		{
			Nan::HandleScope();
			Local<Value> argv[] =
			{
				Nan::Null(),
				Nan::CopyBuffer(hash, length).ToLocalChecked()
			};
			callback->Call(2, argv, async_resource);
		};

	private:
		int algorithm;
		char* filename;
		size_t length;
		// The 2S hashes emit 32 bytes instead of 64, so we get away with this size.
		char hash[BLAKE2B_OUTBYTES];
};

NAN_METHOD(HashFile)
{
	int algo = info[0]->Uint32Value();
	Nan::Utf8String* name = new Nan::Utf8String(info[1]);
	Nan::Callback *callback = new Nan::Callback(info[2].As<Function>());
	Nan::AsyncQueueWorker(new FileWorker(callback, algo, **name));
}

NAN_METHOD(HashBufferSync)
{
	int algo = info[0]->Uint32Value();
	Local<Object> buffer = info[1].As<Object>();
	size_t length = node::Buffer::Length(buffer);
	char* data = node::Buffer::Data(buffer);

	blake2bufferfn func;
	size_t resultLen;
	char hash[BLAKE2B_OUTBYTES];

	switch (algo)
	{
		case B:
			func = blake2b_buffer;
			resultLen = BLAKE2B_OUTBYTES;
			break;

		case BP:
			func = blake2bp_buffer;
			resultLen = BLAKE2B_OUTBYTES;
			break;

		case S:
			func = blake2s_buffer;
			resultLen = BLAKE2S_OUTBYTES;
			break;

		case SP:
			func = blake2sp_buffer;
			resultLen = BLAKE2S_OUTBYTES;
			break;

		default:
			Nan::ThrowTypeError("Unknown hash type.");
			return;
	}

	if (func(data, length, hash) < 0)
	{
		Nan::ThrowTypeError("Failed to calculate hash.");
		return;
	}

	info.GetReturnValue().Set(Nan::CopyBuffer(hash, resultLen).ToLocalChecked());
}

// ------------ ceremony

NAN_MODULE_INIT(InitAll)
{
	Nan::Set(target,
		Nan::New<String>("b2_file").ToLocalChecked(),
		Nan::GetFunction(Nan::New<FunctionTemplate>(HashFile)).ToLocalChecked()
	);
	Nan::Set(target,
		Nan::New<String>("b2_buffer").ToLocalChecked(),
		Nan::GetFunction(Nan::New<FunctionTemplate>(HashBufferSync)).ToLocalChecked()
	);
	AvonStream::Initialize(target);
}

NODE_MODULE(blake2, InitAll)
<|endoftext|>


<commit_before>#include "mem/ast/dumper/XmlDumper.hpp"

namespace mem { namespace ast { namespace dumper {

std::string
XmlDumper::dump (node::Node* root)
{
   std::ostringstream res;
   res << "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
   this->dump_node(res, root, 0);
   return res.str();
}

void
XmlDumper::dump_node (std::ostringstream& dump, node::Node* node, unsigned int level)
{
   dump << this->get_indent(level);
   dump << "<";

   dump << node::Node::get_type_name(node->gType());
   if (node->isText())
   {
      dump << " text=\"";
      dump << ((node::Text*)node)->_value;
      dump << "\"";
   }

   if (node->gBoundSymbol() != NULL)
   {
      dump << " bound_type=\"";
      dump << node->gBoundSymbol()->gQualifiedName();
      dump << "\"";
   }

   if (node->gExprType() != NULL)
   {
      dump << " expr_type=\"";
      dump << node->gExprType()->gQualifiedName();
      dump << "\"";
   }

   if (node->gPosition() != NULL)
   {
      dump << " line=\"";
      dump << node->gPosition()->gLine();
      dump << "\"";
   }

   switch (node->gType())
   {
      case MEM_NODE_NUMBER:
         dump << " val=\"";
         dump << static_cast<node::Number*>(node)->getStringFromVal();
         dump << "\"";
         break;

      case MEM_NODE_FILE:
         dump << " id=\"";
         dump << static_cast<node::File*>(node)->_id;
         dump << "\"";
         break;

      default:
         break;
   }

   if (node->hasChildren())
   {
      dump << ">\n";
      for (size_t i = 0 ; i < node->_child_count ; ++i)
      {
         this->dump_node(dump, node->getChild(i), level+1);
      }
      dump << this->get_indent(level);
      dump << "</";
      dump << node::Node::get_type_name(node->_type);
      dump << ">\n";
   }
   else
   {
      dump << " />\n";
   }
}

std::string
XmlDumper::get_indent (unsigned int level)
{
   std::string indent = "";
   for (unsigned int i = 0 ; i < level ; ++i)
   {
      indent += "   ";
   }
   return indent;
}

} } }
<commit_msg>Better formatting of AST XML dump<commit_after>#include "mem/ast/dumper/XmlDumper.hpp"

namespace mem { namespace ast { namespace dumper {

std::string
XmlDumper::dump (node::Node* root)
{
   std::ostringstream res;
   res << "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
   this->dump_node(res, root, 0);
   return res.str();
}

void
XmlDumper::dump_node (std::ostringstream& dump, node::Node* node, unsigned int level)
{
   dump << this->get_indent(level);
   dump << "<";

   dump << node::Node::get_type_name(node->gType());
   if (node->isText())
   {
      dump << " text=\"";
      dump << ((node::Text*)node)->_value;
      dump << "\"";
   }

   if (node->gBoundSymbol() != NULL)
   {
      dump << " bound=\"";
      dump << node->gBoundSymbol()->gQualifiedName();
      dump << "\"";
   }

   if (node->gExprType() != NULL)
   {
      dump << " type=\"";
      dump << node->gExprType()->gQualifiedName();
      dump << "\"";
   }

   if (node->gPosition() != NULL)
   {
      dump << " line=\"";
      dump << node->gPosition()->gLine();
      dump << "\"";
   }

   switch (node->gType())
   {
      case MEM_NODE_NUMBER:
         dump << " val=\"";
         dump << static_cast<node::Number*>(node)->getStringFromVal();
         dump << "\"";
         break;

      case MEM_NODE_FILE:
         dump << " id=\"";
         dump << static_cast<node::File*>(node)->_id;
         dump << "\"";
         break;

      default:
         break;
   }

   if (node->hasChildren())
   {
      dump << ">\n";
      for (size_t i = 0 ; i < node->_child_count ; ++i)
      {
         this->dump_node(dump, node->getChild(i), level+1);
      }
      dump << this->get_indent(level);
      dump << "</";
      dump << node::Node::get_type_name(node->_type);
      dump << ">\n";
   }
   else
   {
      dump << " />\n";
   }
}

std::string
XmlDumper::get_indent (unsigned int level)
{
   std::string indent = "";
   for (unsigned int i = 0 ; i < level ; ++i)
   {
      indent += "   ";
   }
   return indent;
}

} } }
<|endoftext|>


<commit_before>#define CATCH_CONFIG_MAIN
#include <catch.hpp>

#include <cstring>
#include <string>

#include "../include/fixed_string.hpp"
#include "../include/tokenaizer.hpp"

TEST_CASE("fixed string test", "[basic_fixed_string]")
{
        using namespace fappy;

        constexpr auto max_size_ = 10;

        fixed_string_char<max_size_> str;

        REQUIRE(str.size() == 0);
        REQUIRE(str.max_size() == max_size_);

        SECTION("assign string shorter than max size")
        {
                const char* str__ = "gsomix";
                str               = str__;
                REQUIRE(str.size() == std::strlen(str__));
                REQUIRE(str.as_std_string() == std::string(str__));
        }
        SECTION("assign string larger than max size")
        {
                const char* str__ = "forneverbatmann";
                str               = str__;
                REQUIRE(str.size() == str.max_size());
                REQUIRE(str.as_std_string() == std::string(str__, str__ + 10));
        }
        SECTION("strip left")
        {
                const char* str__ = "   gsomix";
                str               = str__;
                str.strip_left();
                REQUIRE(str.as_std_string() == std::string("gsomix"));
        }
        SECTION("strip right")
        {
                const char* str__ = "gsomix   ";
                str               = str__;
                str.strip_right();
                REQUIRE(str.as_std_string() == std::string("gsomix"));
        }
        SECTION("trim")
        {
                const char* str__ = "  gsomix  ";
                str               = str__;
                str.trim();
                REQUIRE(str.as_std_string() == std::string("gsomix"));
        }

        SECTION("tokenaizer test")
        {
                auto tokens = tokenaizer<std::string>("Gsomix street.").tokens();
                (void)tokens;
        }

        SECTION("test breaker")
        {
                REQUIRE(1 == 0);
        }
}
<commit_msg>Now we heal tests<commit_after>#define CATCH_CONFIG_MAIN
#include <catch.hpp>

#include <cstring>
#include <string>

#include "../include/fixed_string.hpp"
#include "../include/tokenaizer.hpp"

TEST_CASE("fixed string test", "[basic_fixed_string]")
{
        using namespace fappy;

        constexpr auto max_size_ = 10;

        fixed_string_char<max_size_> str;

        REQUIRE(str.size() == 0);
        REQUIRE(str.max_size() == max_size_);

        SECTION("assign string shorter than max size")
        {
                const char* str__ = "gsomix";
                str               = str__;
                REQUIRE(str.size() == std::strlen(str__));
                REQUIRE(str.as_std_string() == std::string(str__));
        }
        SECTION("assign string larger than max size")
        {
                const char* str__ = "forneverbatmann";
                str               = str__;
                REQUIRE(str.size() == str.max_size());
                REQUIRE(str.as_std_string() == std::string(str__, str__ + 10));
        }
        SECTION("strip left")
        {
                const char* str__ = "   gsomix";
                str               = str__;
                str.strip_left();
                REQUIRE(str.as_std_string() == std::string("gsomix"));
        }
        SECTION("strip right")
        {
                const char* str__ = "gsomix   ";
                str               = str__;
                str.strip_right();
                REQUIRE(str.as_std_string() == std::string("gsomix"));
        }
        SECTION("trim")
        {
                const char* str__ = "  gsomix  ";
                str               = str__;
                str.trim();
                REQUIRE(str.as_std_string() == std::string("gsomix"));
        }

        SECTION("tokenaizer test")
        {
                auto tokens = tokenaizer<std::string>("Gsomix street.").tokens();
                (void)tokens;
        }
}
<|endoftext|>


<commit_before>#include <gtest/gtest.h>

int main(int argc, char **argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
<commit_msg>Remove main.cpp<commit_after><|endoftext|>


<commit_before>/***************************************************************************
 *   Copyright (c) 2009 Werner Mayer <wmayer[at]users.sourceforge.net>     *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include <FCConfig.h>

#if HAVE_CONFIG_H
#   include <config.h>
#endif // HAVE_CONFIG_H

#ifdef _MSC_VER
#   pragma warning(disable : 4005)
#endif

#include <QApplication>
#include <QIcon>
#include <QThread>
#if defined(Q_OS_WIN)
#include <windows.h>
#elif defined(Q_WS_X11)
#include <QX11EmbedWidget>
#endif
// FreeCAD Base header
#include <CXX/WrapPython.h>
#include <Base/Exception.h>
#include <Base/Factory.h>
#include <Base/Interpreter.h>
#include <App/Application.h>
#include <Gui/Application.h>
#include <Gui/BitmapFactory.h>
#include <Gui/MainWindow.h>
#include <Gui/SoFCDB.h>
#include <Gui/Quarter/Quarter.h>
#include <Inventor/SoDB.h>

static
QWidget* setupMainWindow();

class GUIThread : public QThread
{
public:
    GUIThread()
    {
    }
    void run()
    {
        static int argc = 0;
        static char **argv = {0};
        QApplication app(argc, argv);
        if (setupMainWindow()) {
            app.exec();
        }
    }
};

#if defined(Q_OS_WIN)
HHOOK hhook;

LRESULT CALLBACK
FilterProc(int nCode, WPARAM wParam, LPARAM lParam) {
    if (qApp)
        qApp->sendPostedEvents(0, -1); // special DeferredDelete
    return CallNextHookEx(hhook, nCode, wParam, lParam);
}
#endif

static PyObject *
FreeCADGui_showMainWindow(PyObject * /*self*/, PyObject *args)
{
    PyObject* inThread = Py_False;
    if (!PyArg_ParseTuple(args, "|O!", &PyBool_Type, &inThread))
        return NULL;

    static GUIThread* thr = 0;
    if (!qApp) {
        if (PyObject_IsTrue(inThread)) {
            if (!thr) thr = new GUIThread();
            thr->start();
        }
        else {
#if defined(Q_OS_WIN)
            static int argc = 0;
            static char **argv = {0};
            (void)new QApplication(argc, argv);
            // When QApplication is constructed
            hhook = SetWindowsHookEx(WH_GETMESSAGE,
                FilterProc, 0, GetCurrentThreadId());
#elif !defined(QT_NO_GLIB)
            static int argc = 0;
            static char **argv = {0};
            (void)new QApplication(argc, argv);
#else
            PyErr_SetString(PyExc_RuntimeError, "Must construct a QApplication before a QPaintDevice\n");
            return NULL;
#endif
        }
    }
    else if (!qobject_cast<QApplication*>(qApp)) {
        PyErr_SetString(PyExc_RuntimeError, "Cannot create widget when no GUI is being used\n");
        return NULL;
    }

    if (!thr) {
        if (!setupMainWindow()) {
            PyErr_SetString(PyExc_RuntimeError, "Cannot create main window\n");
            return NULL;
        }
    }

    Py_INCREF(Py_None);
    return Py_None;
}

static PyObject *
FreeCADGui_exec_loop(PyObject * /*self*/, PyObject *args)
{
    if (!PyArg_ParseTuple(args, ""))
        return NULL;

    if (!qApp) {
        PyErr_SetString(PyExc_RuntimeError, "Must construct a QApplication before a QPaintDevice\n");
        return NULL;
    }
    else if (!qobject_cast<QApplication*>(qApp)) {
        PyErr_SetString(PyExc_RuntimeError, "Cannot create widget when no GUI is being used\n");
        return NULL;
    }

    qApp->exec();

    Py_INCREF(Py_None);
    return Py_None;
}

static PyObject *
FreeCADGui_setupWithoutGUI(PyObject * /*self*/, PyObject *args)
{
    if (!PyArg_ParseTuple(args, ""))
        return NULL;

    if (!Gui::Application::Instance) {
        static Gui::Application *app = new Gui::Application(false);
        Q_UNUSED(app);
    }
    else {
        PyErr_SetString(PyExc_RuntimeError, "FreeCADGui already initialized");
        return 0;
    }

    if (!SoDB::isInitialized()) {
        // init the Inventor subsystem
        SoDB::init();
        SIM::Coin3D::Quarter::Quarter::init();
    }
    if (!Gui::SoFCDB::isInitialized()) {
        Gui::SoFCDB::init();
    }

    Py_INCREF(Py_None);
    return Py_None;
}

static PyObject *
FreeCADGui_embedToWindow(PyObject * /*self*/, PyObject *args)
{
    char* pointer;
    if (!PyArg_ParseTuple(args, "s", &pointer))
        return NULL;

    QWidget* widget = Gui::getMainWindow();
    if (!widget) {
        PyErr_SetString(Base::BaseExceptionFreeCADError, "No main window");
        return 0;
    }

    std::string pointer_str = pointer;
    std::stringstream str(pointer_str);

#if defined(Q_OS_WIN)
    void* window = 0;
    str >> window;
    HWND winid = (HWND)window;

    LONG oldLong = GetWindowLong(winid, GWL_STYLE);
    SetWindowLong(winid, GWL_STYLE,
    oldLong | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
    //SetWindowLong(widget->winId(), GWL_STYLE,
    //    WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
    SetParent((HWND)widget->winId(), winid);

    QEvent embeddingEvent(QEvent::EmbeddingControl);
    QApplication::sendEvent(widget, &embeddingEvent);
#elif defined(Q_WS_X11)
    WId winid;
    str >> winid;

    QX11EmbedWidget* x11 = new QX11EmbedWidget();
    widget->setParent(x11);
    x11->embedInto(winid);
    x11->show();
#else
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented for this platform");
    return 0;
#endif

    Py_INCREF(Py_None);
    return Py_None;
}

struct PyMethodDef FreeCADGui_methods[] = {
    {"showMainWindow",FreeCADGui_showMainWindow,METH_VARARGS,
     "showMainWindow() -- Show the main window\n"
     "If no main window does exist one gets created"},
    {"exec_loop",FreeCADGui_exec_loop,METH_VARARGS,
     "exec_loop() -- Starts the event loop\n"
     "Note: this will block the call until the event loop has terminated"},
    {"setupWithoutGUI",FreeCADGui_setupWithoutGUI,METH_VARARGS,
     "setupWithoutGUI() -- Uses this module without starting\n"
     "an event loop or showing up any GUI\n"},
    {"embedToWindow",FreeCADGui_embedToWindow,METH_VARARGS,
     "embedToWindow() -- Embeds the main window into another window\n"},
    {NULL, NULL, 0, NULL}  /* sentinel */
};

static
QWidget* setupMainWindow()
{
    if (!Gui::Application::Instance) {
        static Gui::Application *app = new Gui::Application(true);
        Q_UNUSED(app);
    }

    if (!Gui::MainWindow::getInstance()) {
        static bool hasMainWindow = false;
        if (hasMainWindow) {
            // if a main window existed and has been deleted it's not supported
            // to re-create it
            return 0;
        }

        Base::PyGILStateLocker lock;
        PyObject* input = PySys_GetObject("stdin");
        Gui::MainWindow *mw = new Gui::MainWindow();
        hasMainWindow = true;

        QIcon icon = qApp->windowIcon();
        if (icon.isNull())
            qApp->setWindowIcon(Gui::BitmapFactory().pixmap(App::Application::Config()["AppIcon"].c_str()));
        mw->setWindowIcon(qApp->windowIcon());
        QString appName = qApp->applicationName();
        if (!appName.isEmpty())
            mw->setWindowTitle(appName);
        else
            mw->setWindowTitle(QString::fromLatin1(App::Application::Config()["ExeName"].c_str()));

        if (!SoDB::isInitialized()) {
            // init the Inventor subsystem
            SoDB::init();
            SIM::Coin3D::Quarter::Quarter::init();
            Gui::SoFCDB::init();
        }

        static bool init = false;
        if (!init) {
            try {
                Base::Console().Log("Run Gui init script\n");
                Base::Interpreter().runString(Base::ScriptFactory().ProduceScript("FreeCADGuiInit"));
            }
            catch (const Base::Exception& e) {
                PyErr_Format(Base::BaseExceptionFreeCADError, "Error in FreeCADGuiInit.py: %s\n", e.what());
                return 0;
            }
            init = true;
        }

        qApp->setActiveWindow(mw);

        // Activate the correct workbench
        std::string start = App::Application::Config()["StartWorkbench"];
        Base::Console().Log("Init: Activating default workbench %s\n", start.c_str());
        start = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/General")->
                               GetASCII("AutoloadModule", start.c_str());
        // if the auto workbench is not visible then force to use the default workbech
        // and replace the wrong entry in the parameters
        QStringList wb = Gui::Application::Instance->workbenches();
        if (!wb.contains(QString::fromLatin1(start.c_str()))) {
            start = App::Application::Config()["StartWorkbench"];
            App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/General")->
                                  SetASCII("AutoloadModule", start.c_str());
        }

        Gui::Application::Instance->activateWorkbench(start.c_str());
        mw->loadWindowSettings();
        PySys_SetObject("stdin", input);
    }
    else {
        Gui::getMainWindow()->show();
    }

    return Gui::getMainWindow();
}

PyMOD_INIT_FUNC(FreeCADGui)
{
    try {
        Base::Interpreter().loadModule("FreeCAD");
        App::Application::Config()["AppIcon"] = "freecad";
        App::Application::Config()["SplashScreen"] = "freecadsplash";
        App::Application::Config()["CopyrightInfo"] = "\xc2\xa9 Juergen Riegel, Werner Mayer, Yorik van Havre 2001-2017\n";
        Gui::Application::initApplication();
#if PY_MAJOR_VERSION >= 3
        static struct PyModuleDef FreeCADGuiModuleDef = {
            PyModuleDef_HEAD_INIT,
            "FreeCADGui", "FreeCAD GUI module\n", -1,
            FreeCADGui_methods,
            NULL, NULL, NULL, NULL
        };
        PyObject* module = PyModule_Create(&FreeCADGuiModuleDef);
        return module;
#else
        Py_InitModule3("FreeCADGui", FreeCADGui_methods, "FreeCAD GUI module\n");
#endif
    }
    catch (const Base::Exception& e) {
        PyErr_Format(PyExc_ImportError, "%s\n", e.what());
    }
    catch (...) {
        PyErr_SetString(PyExc_ImportError, "Unknown runtime error occurred");
    }
#if PY_MAJOR_VERSION >= 3
    return 0;
#endif
}

<commit_msg>avoid to eventually try to init Gui twice<commit_after>/***************************************************************************
 *   Copyright (c) 2009 Werner Mayer <wmayer[at]users.sourceforge.net>     *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include <FCConfig.h>

#if HAVE_CONFIG_H
#   include <config.h>
#endif // HAVE_CONFIG_H

#ifdef _MSC_VER
#   pragma warning(disable : 4005)
#endif

#include <QApplication>
#include <QIcon>
#include <QThread>
#if defined(Q_OS_WIN)
#include <windows.h>
#elif defined(Q_WS_X11)
#include <QX11EmbedWidget>
#endif
// FreeCAD Base header
#include <CXX/WrapPython.h>
#include <Base/Exception.h>
#include <Base/Factory.h>
#include <Base/Interpreter.h>
#include <App/Application.h>
#include <Gui/Application.h>
#include <Gui/BitmapFactory.h>
#include <Gui/MainWindow.h>
#include <Gui/SoFCDB.h>
#include <Gui/Quarter/Quarter.h>
#include <Inventor/SoDB.h>

static
QWidget* setupMainWindow();

class GUIThread : public QThread
{
public:
    GUIThread()
    {
    }
    void run()
    {
        static int argc = 0;
        static char **argv = {0};
        QApplication app(argc, argv);
        if (setupMainWindow()) {
            app.exec();
        }
    }
};

#if defined(Q_OS_WIN)
HHOOK hhook;

LRESULT CALLBACK
FilterProc(int nCode, WPARAM wParam, LPARAM lParam) {
    if (qApp)
        qApp->sendPostedEvents(0, -1); // special DeferredDelete
    return CallNextHookEx(hhook, nCode, wParam, lParam);
}
#endif

static PyObject *
FreeCADGui_showMainWindow(PyObject * /*self*/, PyObject *args)
{
    PyObject* inThread = Py_False;
    if (!PyArg_ParseTuple(args, "|O!", &PyBool_Type, &inThread))
        return NULL;

    static GUIThread* thr = 0;
    if (!qApp) {
        if (PyObject_IsTrue(inThread)) {
            if (!thr) thr = new GUIThread();
            thr->start();
        }
        else {
#if defined(Q_OS_WIN)
            static int argc = 0;
            static char **argv = {0};
            (void)new QApplication(argc, argv);
            // When QApplication is constructed
            hhook = SetWindowsHookEx(WH_GETMESSAGE,
                FilterProc, 0, GetCurrentThreadId());
#elif !defined(QT_NO_GLIB)
            static int argc = 0;
            static char **argv = {0};
            (void)new QApplication(argc, argv);
#else
            PyErr_SetString(PyExc_RuntimeError, "Must construct a QApplication before a QPaintDevice\n");
            return NULL;
#endif
        }
    }
    else if (!qobject_cast<QApplication*>(qApp)) {
        PyErr_SetString(PyExc_RuntimeError, "Cannot create widget when no GUI is being used\n");
        return NULL;
    }

    if (!thr) {
        if (!setupMainWindow()) {
            PyErr_SetString(PyExc_RuntimeError, "Cannot create main window\n");
            return NULL;
        }
    }

    Py_INCREF(Py_None);
    return Py_None;
}

static PyObject *
FreeCADGui_exec_loop(PyObject * /*self*/, PyObject *args)
{
    if (!PyArg_ParseTuple(args, ""))
        return NULL;

    if (!qApp) {
        PyErr_SetString(PyExc_RuntimeError, "Must construct a QApplication before a QPaintDevice\n");
        return NULL;
    }
    else if (!qobject_cast<QApplication*>(qApp)) {
        PyErr_SetString(PyExc_RuntimeError, "Cannot create widget when no GUI is being used\n");
        return NULL;
    }

    qApp->exec();

    Py_INCREF(Py_None);
    return Py_None;
}

static PyObject *
FreeCADGui_setupWithoutGUI(PyObject * /*self*/, PyObject *args)
{
    if (!PyArg_ParseTuple(args, ""))
        return NULL;

    if (!Gui::Application::Instance) {
        static Gui::Application *app = new Gui::Application(false);
        Q_UNUSED(app);
    }
    else {
        PyErr_SetString(PyExc_RuntimeError, "FreeCADGui already initialized");
        return 0;
    }

    if (!SoDB::isInitialized()) {
        // init the Inventor subsystem
        SoDB::init();
        SIM::Coin3D::Quarter::Quarter::init();
    }
    if (!Gui::SoFCDB::isInitialized()) {
        Gui::SoFCDB::init();
    }

    Py_INCREF(Py_None);
    return Py_None;
}

static PyObject *
FreeCADGui_embedToWindow(PyObject * /*self*/, PyObject *args)
{
    char* pointer;
    if (!PyArg_ParseTuple(args, "s", &pointer))
        return NULL;

    QWidget* widget = Gui::getMainWindow();
    if (!widget) {
        PyErr_SetString(Base::BaseExceptionFreeCADError, "No main window");
        return 0;
    }

    std::string pointer_str = pointer;
    std::stringstream str(pointer_str);

#if defined(Q_OS_WIN)
    void* window = 0;
    str >> window;
    HWND winid = (HWND)window;

    LONG oldLong = GetWindowLong(winid, GWL_STYLE);
    SetWindowLong(winid, GWL_STYLE,
    oldLong | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
    //SetWindowLong(widget->winId(), GWL_STYLE,
    //    WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
    SetParent((HWND)widget->winId(), winid);

    QEvent embeddingEvent(QEvent::EmbeddingControl);
    QApplication::sendEvent(widget, &embeddingEvent);
#elif defined(Q_WS_X11)
    WId winid;
    str >> winid;

    QX11EmbedWidget* x11 = new QX11EmbedWidget();
    widget->setParent(x11);
    x11->embedInto(winid);
    x11->show();
#else
    PyErr_SetString(PyExc_NotImplementedError, "Not implemented for this platform");
    return 0;
#endif

    Py_INCREF(Py_None);
    return Py_None;
}

struct PyMethodDef FreeCADGui_methods[] = {
    {"showMainWindow",FreeCADGui_showMainWindow,METH_VARARGS,
     "showMainWindow() -- Show the main window\n"
     "If no main window does exist one gets created"},
    {"exec_loop",FreeCADGui_exec_loop,METH_VARARGS,
     "exec_loop() -- Starts the event loop\n"
     "Note: this will block the call until the event loop has terminated"},
    {"setupWithoutGUI",FreeCADGui_setupWithoutGUI,METH_VARARGS,
     "setupWithoutGUI() -- Uses this module without starting\n"
     "an event loop or showing up any GUI\n"},
    {"embedToWindow",FreeCADGui_embedToWindow,METH_VARARGS,
     "embedToWindow() -- Embeds the main window into another window\n"},
    {NULL, NULL, 0, NULL}  /* sentinel */
};

static
QWidget* setupMainWindow()
{
    if (!Gui::Application::Instance) {
        static Gui::Application *app = new Gui::Application(true);
        Q_UNUSED(app);
    }

    if (!Gui::MainWindow::getInstance()) {
        static bool hasMainWindow = false;
        if (hasMainWindow) {
            // if a main window existed and has been deleted it's not supported
            // to re-create it
            return 0;
        }

        Base::PyGILStateLocker lock;
        PyObject* input = PySys_GetObject("stdin");
        Gui::MainWindow *mw = new Gui::MainWindow();
        hasMainWindow = true;

        QIcon icon = qApp->windowIcon();
        if (icon.isNull())
            qApp->setWindowIcon(Gui::BitmapFactory().pixmap(App::Application::Config()["AppIcon"].c_str()));
        mw->setWindowIcon(qApp->windowIcon());
        QString appName = qApp->applicationName();
        if (!appName.isEmpty())
            mw->setWindowTitle(appName);
        else
            mw->setWindowTitle(QString::fromLatin1(App::Application::Config()["ExeName"].c_str()));

        if (!SoDB::isInitialized()) {
            // init the Inventor subsystem
            SoDB::init();
            SIM::Coin3D::Quarter::Quarter::init();
            Gui::SoFCDB::init();
        }

        static bool init = false;
        if (!init) {
            try {
                Base::Console().Log("Run Gui init script\n");
                Base::Interpreter().runString(Base::ScriptFactory().ProduceScript("FreeCADGuiInit"));
            }
            catch (const Base::Exception& e) {
                PyErr_Format(Base::BaseExceptionFreeCADError, "Error in FreeCADGuiInit.py: %s\n", e.what());
                return 0;
            }
            init = true;
        }

        qApp->setActiveWindow(mw);

        // Activate the correct workbench
        std::string start = App::Application::Config()["StartWorkbench"];
        Base::Console().Log("Init: Activating default workbench %s\n", start.c_str());
        start = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/General")->
                               GetASCII("AutoloadModule", start.c_str());
        // if the auto workbench is not visible then force to use the default workbech
        // and replace the wrong entry in the parameters
        QStringList wb = Gui::Application::Instance->workbenches();
        if (!wb.contains(QString::fromLatin1(start.c_str()))) {
            start = App::Application::Config()["StartWorkbench"];
            App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/General")->
                                  SetASCII("AutoloadModule", start.c_str());
        }

        Gui::Application::Instance->activateWorkbench(start.c_str());
        mw->loadWindowSettings();
        PySys_SetObject("stdin", input);
    }
    else {
        Gui::getMainWindow()->show();
    }

    return Gui::getMainWindow();
}

PyMOD_INIT_FUNC(FreeCADGui)
{
    try {
        Base::Interpreter().loadModule("FreeCAD");
        App::Application::Config()["AppIcon"] = "freecad";
        App::Application::Config()["SplashScreen"] = "freecadsplash";
        App::Application::Config()["CopyrightInfo"] = "\xc2\xa9 Juergen Riegel, Werner Mayer, Yorik van Havre 2001-2017\n";
        // it's possible that the GUI is already initialized when the Gui version of the executable
        // is started in command mode
        if (Base::Type::fromName("Gui::BaseView").isBad())
            Gui::Application::initApplication();
#if PY_MAJOR_VERSION >= 3
        static struct PyModuleDef FreeCADGuiModuleDef = {
            PyModuleDef_HEAD_INIT,
            "FreeCADGui", "FreeCAD GUI module\n", -1,
            FreeCADGui_methods,
            NULL, NULL, NULL, NULL
        };
        PyObject* module = PyModule_Create(&FreeCADGuiModuleDef);
        return module;
#else
        Py_InitModule3("FreeCADGui", FreeCADGui_methods, "FreeCAD GUI module\n");
#endif
    }
    catch (const Base::Exception& e) {
        PyErr_Format(PyExc_ImportError, "%s\n", e.what());
    }
    catch (...) {
        PyErr_SetString(PyExc_ImportError, "Unknown runtime error occurred");
    }
#if PY_MAJOR_VERSION >= 3
    return 0;
#endif
}

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2002-2005 The Regents of The University of Michigan
 * 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 copyright holders 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.
 *
 * Authors: Ron Dreslinski
 */

/**
 * @file
 * Port Object Decleration. Ports are used to interface memory objects to
 * each other.  They will always come in pairs, and we refer to the other
 * port object as the peer.  These are used to make the design more
 * modular so that a specific interface between every type of objcet doesn't
 * have to be created.
 */

#ifndef __MEM_PORT_HH__
#define __MEM_PORT_HH__

#include <list>
#include <inttypes.h>

#include "base/misc.hh"
#include "base/range.hh"
#include "mem/packet.hh"
#include "mem/request.hh"

/** This typedef is used to clean up the parameter list of
 * getDeviceAddressRanges() and getPeerAddressRanges().  It's declared
 * outside the Port object since it's also used by some mem objects.
 * Eventually we should move this typedef to wherever Addr is
 * defined.
 */

typedef std::list<Range<Addr> > AddrRangeList;
typedef std::list<Range<Addr> >::iterator AddrRangeIter;

/**
 * Ports are used to interface memory objects to
 * each other.  They will always come in pairs, and we refer to the other
 * port object as the peer.  These are used to make the design more
 * modular so that a specific interface between every type of objcet doesn't
 * have to be created.
 *
 * Recv accesor functions are being called from the peer interface.
 * Send accessor functions are being called from the device the port is
 * associated with, and it will call the peer recv. accessor function.
 */
class Port
{
  private:

    /** Descriptive name (for DPRINTF output) */
    const std::string portName;

    /** A pointer to the peer port.  Ports always come in pairs, that way they
        can use a standardized interface to communicate between different
        memory objects. */
    Port *peer;

  public:

    /**
     * Constructor.
     *
     * @param _name Port name for DPRINTF output.  Should include name
     * of memory system object to which the port belongs.
     */
    Port(const std::string &_name)
        : portName(_name), peer(NULL)
    { }

    /** Return port name (for DPRINTF). */
    const std::string &name() const { return portName; }

    virtual ~Port() {};

    // mey be better to use subclasses & RTTI?
    /** Holds the ports status.  Currently just that a range recomputation needs
     * to be done. */
    enum Status {
        RangeChange
    };

    /** Function to set the pointer for the peer port.
        @todo should be called by the configuration stuff (python).
    */
    void setPeer(Port *port);

    /** Function to set the pointer for the peer port.
        @todo should be called by the configuration stuff (python).
    */
    Port *getPeer() { return peer; }

  protected:

    /** These functions are protected because they should only be
     * called by a peer port, never directly by any outside object. */

    /** Called to recive a timing call from the peer port. */
    virtual bool recvTiming(Packet *pkt) = 0;

    /** Called to recive a atomic call from the peer port. */
    virtual Tick recvAtomic(Packet *pkt) = 0;

    /** Called to recive a functional call from the peer port. */
    virtual void recvFunctional(Packet *pkt) = 0;

    /** Called to recieve a status change from the peer port. */
    virtual void recvStatusChange(Status status) = 0;

    /** Called by a peer port if the send was unsuccesful, and had to
        wait.  This shouldn't be valid for response paths (IO Devices).
        so it is set to panic if it isn't already defined.
    */
    virtual void recvRetry() { panic("??"); }

    /** Called by a peer port in order to determine the block size of the
        device connected to this port.  It sometimes doesn't make sense for
        this function to be called, a DMA interface doesn't really have a
        block size, so it is defaulted to a panic.
    */
    virtual int deviceBlockSize() { panic("??"); }

    /** The peer port is requesting us to reply with a list of the ranges we
        are responsible for.
        @param resp is a list of ranges responded to
        @param snoop is a list of ranges snooped
    */
    virtual void getDeviceAddressRanges(AddrRangeList &resp,
            AddrRangeList &snoop)
    { panic("??"); }

  public:

    /** Function called by associated memory device (cache, memory, iodevice)
        in order to send a timing request to the port.  Simply calls the peer
        port receive function.
        @return This function returns if the send was succesful in it's
        recieve. If it was a failure, then the port will wait for a recvRetry
        at which point it can possibly issue a successful sendTiming.  This is used in
        case a cache has a higher priority request come in while waiting for
        the bus to arbitrate.
    */
    bool sendTiming(Packet *pkt) { return peer->recvTiming(pkt); }

    /** Function called by the associated device to send an atomic
     *   access, an access in which the data is moved and the state is
     *   updated in one cycle, without interleaving with other memory
     *   accesses.  Returns estimated latency of access.
     */
    Tick sendAtomic(Packet *pkt)
        { return peer->recvAtomic(pkt); }

    /** Function called by the associated device to send a functional access,
        an access in which the data is instantly updated everywhere in the
        memory system, without affecting the current state of any block or
        moving the block.
    */
    void sendFunctional(Packet *pkt)
        { return peer->recvFunctional(pkt); }

    /** Called by the associated device to send a status change to the device
        connected to the peer interface.
    */
    void sendStatusChange(Status status) {peer->recvStatusChange(status); }

    /** When a timing access doesn't return a success, some time later the
        Retry will be sent.
    */
    void sendRetry() { return peer->recvRetry(); }

    /** Called by the associated device if it wishes to find out the blocksize
        of the device on attached to the peer port.
    */
    int peerBlockSize() { return peer->deviceBlockSize(); }

    /** Called by the associated device if it wishes to find out the address
        ranges connected to the peer ports devices.
    */
    void getPeerAddressRanges(AddrRangeList &resp, AddrRangeList &snoop)
    { peer->getDeviceAddressRanges(resp, snoop); }

    /** This function is a wrapper around sendFunctional()
        that breaks a larger, arbitrarily aligned access into
        appropriate chunks.  The default implementation can use
        getBlockSize() to determine the block size and go from there.
    */
    virtual void readBlob(Addr addr, uint8_t *p, int size);

    /** This function is a wrapper around sendFunctional()
        that breaks a larger, arbitrarily aligned access into
        appropriate chunks.  The default implementation can use
        getBlockSize() to determine the block size and go from there.
    */
    virtual void writeBlob(Addr addr, uint8_t *p, int size);

    /** Fill size bytes starting at addr with byte value val.  This
        should not need to be virtual, since it can be implemented in
        terms of writeBlob().  However, it shouldn't be
        performance-critical either, so it could be if we wanted to.
    */
    virtual void memsetBlob(Addr addr, uint8_t val, int size);

  private:

    /** Internal helper function for read/writeBlob().
     */
    void blobHelper(Addr addr, uint8_t *p, int size, Packet::Command cmd);
};

/** A simple functional port that is only meant for one way communication to
 * physical memory. It is only meant to be used to load data into memory before
 * the simulation begins.
 */

class FunctionalPort : public Port
{
  public:
    FunctionalPort(const std::string &_name)
        : Port(_name)
    {}

    virtual bool recvTiming(Packet *pkt) { panic("FuncPort is UniDir"); }
    virtual Tick recvAtomic(Packet *pkt) { panic("FuncPort is UniDir"); }
    virtual void recvFunctional(Packet *pkt) { panic("FuncPort is UniDir"); }
    virtual void recvStatusChange(Status status) {}

    /** a write function that also does an endian conversion. */
    template <typename T>
    inline void writeHtoG(Addr addr, T d);

    /** a read function that also does an endian conversion. */
    template <typename T>
    inline T readGtoH(Addr addr);

    template <typename T>
    inline void write(Addr addr, T d)
    {
        writeBlob(addr, (uint8_t*)&d, sizeof(T));
    }

    template <typename T>
    inline T read(Addr addr)
    {
        T d;
        readBlob(addr, (uint8_t*)&d, sizeof(T));
        return d;
    }
};

#endif //__MEM_PORT_HH__
<commit_msg>Allow ports to be created without a name.<commit_after>/*
 * Copyright (c) 2002-2005 The Regents of The University of Michigan
 * 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 copyright holders 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.
 *
 * Authors: Ron Dreslinski
 */

/**
 * @file
 * Port Object Decleration. Ports are used to interface memory objects to
 * each other.  They will always come in pairs, and we refer to the other
 * port object as the peer.  These are used to make the design more
 * modular so that a specific interface between every type of objcet doesn't
 * have to be created.
 */

#ifndef __MEM_PORT_HH__
#define __MEM_PORT_HH__

#include <list>
#include <inttypes.h>

#include "base/misc.hh"
#include "base/range.hh"
#include "mem/packet.hh"
#include "mem/request.hh"

/** This typedef is used to clean up the parameter list of
 * getDeviceAddressRanges() and getPeerAddressRanges().  It's declared
 * outside the Port object since it's also used by some mem objects.
 * Eventually we should move this typedef to wherever Addr is
 * defined.
 */

typedef std::list<Range<Addr> > AddrRangeList;
typedef std::list<Range<Addr> >::iterator AddrRangeIter;

/**
 * Ports are used to interface memory objects to
 * each other.  They will always come in pairs, and we refer to the other
 * port object as the peer.  These are used to make the design more
 * modular so that a specific interface between every type of objcet doesn't
 * have to be created.
 *
 * Recv accesor functions are being called from the peer interface.
 * Send accessor functions are being called from the device the port is
 * associated with, and it will call the peer recv. accessor function.
 */
class Port
{
  private:

    /** Descriptive name (for DPRINTF output) */
    mutable std::string portName;

    /** A pointer to the peer port.  Ports always come in pairs, that way they
        can use a standardized interface to communicate between different
        memory objects. */
    Port *peer;

  public:

    Port()
        : peer(NULL)
    { }

    /**
     * Constructor.
     *
     * @param _name Port name for DPRINTF output.  Should include name
     * of memory system object to which the port belongs.
     */
    Port(const std::string &_name)
        : portName(_name), peer(NULL)
    { }

    /** Return port name (for DPRINTF). */
    const std::string &name() const { return portName; }

    virtual ~Port() {};

    // mey be better to use subclasses & RTTI?
    /** Holds the ports status.  Currently just that a range recomputation needs
     * to be done. */
    enum Status {
        RangeChange
    };

    void setName(const std::string &name)
    { portName = name; }

    /** Function to set the pointer for the peer port.
        @todo should be called by the configuration stuff (python).
    */
    void setPeer(Port *port);

    /** Function to set the pointer for the peer port.
        @todo should be called by the configuration stuff (python).
    */
    Port *getPeer() { return peer; }

  protected:

    /** These functions are protected because they should only be
     * called by a peer port, never directly by any outside object. */

    /** Called to recive a timing call from the peer port. */
    virtual bool recvTiming(Packet *pkt) = 0;

    /** Called to recive a atomic call from the peer port. */
    virtual Tick recvAtomic(Packet *pkt) = 0;

    /** Called to recive a functional call from the peer port. */
    virtual void recvFunctional(Packet *pkt) = 0;

    /** Called to recieve a status change from the peer port. */
    virtual void recvStatusChange(Status status) = 0;

    /** Called by a peer port if the send was unsuccesful, and had to
        wait.  This shouldn't be valid for response paths (IO Devices).
        so it is set to panic if it isn't already defined.
    */
    virtual void recvRetry() { panic("??"); }

    /** Called by a peer port in order to determine the block size of the
        device connected to this port.  It sometimes doesn't make sense for
        this function to be called, a DMA interface doesn't really have a
        block size, so it is defaulted to a panic.
    */
    virtual int deviceBlockSize() { panic("??"); }

    /** The peer port is requesting us to reply with a list of the ranges we
        are responsible for.
        @param resp is a list of ranges responded to
        @param snoop is a list of ranges snooped
    */
    virtual void getDeviceAddressRanges(AddrRangeList &resp,
            AddrRangeList &snoop)
    { panic("??"); }

  public:

    /** Function called by associated memory device (cache, memory, iodevice)
        in order to send a timing request to the port.  Simply calls the peer
        port receive function.
        @return This function returns if the send was succesful in it's
        recieve. If it was a failure, then the port will wait for a recvRetry
        at which point it can possibly issue a successful sendTiming.  This is used in
        case a cache has a higher priority request come in while waiting for
        the bus to arbitrate.
    */
    bool sendTiming(Packet *pkt) { return peer->recvTiming(pkt); }

    /** Function called by the associated device to send an atomic
     *   access, an access in which the data is moved and the state is
     *   updated in one cycle, without interleaving with other memory
     *   accesses.  Returns estimated latency of access.
     */
    Tick sendAtomic(Packet *pkt)
        { return peer->recvAtomic(pkt); }

    /** Function called by the associated device to send a functional access,
        an access in which the data is instantly updated everywhere in the
        memory system, without affecting the current state of any block or
        moving the block.
    */
    void sendFunctional(Packet *pkt)
        { return peer->recvFunctional(pkt); }

    /** Called by the associated device to send a status change to the device
        connected to the peer interface.
    */
    void sendStatusChange(Status status) {peer->recvStatusChange(status); }

    /** When a timing access doesn't return a success, some time later the
        Retry will be sent.
    */
    void sendRetry() { return peer->recvRetry(); }

    /** Called by the associated device if it wishes to find out the blocksize
        of the device on attached to the peer port.
    */
    int peerBlockSize() { return peer->deviceBlockSize(); }

    /** Called by the associated device if it wishes to find out the address
        ranges connected to the peer ports devices.
    */
    void getPeerAddressRanges(AddrRangeList &resp, AddrRangeList &snoop)
    { peer->getDeviceAddressRanges(resp, snoop); }

    /** This function is a wrapper around sendFunctional()
        that breaks a larger, arbitrarily aligned access into
        appropriate chunks.  The default implementation can use
        getBlockSize() to determine the block size and go from there.
    */
    virtual void readBlob(Addr addr, uint8_t *p, int size);

    /** This function is a wrapper around sendFunctional()
        that breaks a larger, arbitrarily aligned access into
        appropriate chunks.  The default implementation can use
        getBlockSize() to determine the block size and go from there.
    */
    virtual void writeBlob(Addr addr, uint8_t *p, int size);

    /** Fill size bytes starting at addr with byte value val.  This
        should not need to be virtual, since it can be implemented in
        terms of writeBlob().  However, it shouldn't be
        performance-critical either, so it could be if we wanted to.
    */
    virtual void memsetBlob(Addr addr, uint8_t val, int size);

  private:

    /** Internal helper function for read/writeBlob().
     */
    void blobHelper(Addr addr, uint8_t *p, int size, Packet::Command cmd);
};

/** A simple functional port that is only meant for one way communication to
 * physical memory. It is only meant to be used to load data into memory before
 * the simulation begins.
 */

class FunctionalPort : public Port
{
  public:
    FunctionalPort(const std::string &_name)
        : Port(_name)
    {}

    virtual bool recvTiming(Packet *pkt) { panic("FuncPort is UniDir"); }
    virtual Tick recvAtomic(Packet *pkt) { panic("FuncPort is UniDir"); }
    virtual void recvFunctional(Packet *pkt) { panic("FuncPort is UniDir"); }
    virtual void recvStatusChange(Status status) {}

    /** a write function that also does an endian conversion. */
    template <typename T>
    inline void writeHtoG(Addr addr, T d);

    /** a read function that also does an endian conversion. */
    template <typename T>
    inline T readGtoH(Addr addr);

    template <typename T>
    inline void write(Addr addr, T d)
    {
        writeBlob(addr, (uint8_t*)&d, sizeof(T));
    }

    template <typename T>
    inline T read(Addr addr)
    {
        T d;
        readBlob(addr, (uint8_t*)&d, sizeof(T));
        return d;
    }
};

#endif //__MEM_PORT_HH__
<|endoftext|>


<commit_before><commit_msg>Fix for mac/linux unit_test<commit_after><|endoftext|>


<commit_before>/**
 * @file
 * @author  Mohammad S. Babaei <info@babaei.net>
 * @version 0.1.0
 *
 * @section LICENSE
 *
 * (The MIT License)
 *
 * Copyright (c) 2015 Mohammad S. Babaei
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * @section DESCRIPTION
 *
 * CMS welcome screen a.k.a. dashboard.
 */

#include <Wt/WString>
#include <Wt/WTemplate>
#include <Wt/WText>
#include <Wt/WWidget>
#include <boost/exception/diagnostic_information.hpp>
#include <boost/format.hpp>
#include <CoreLib/FileSystem.hpp>
#include <CoreLib/Log.hpp>
#include "CgiEnv.hpp"
#include "CmsDashboard.hpp"
#include "Div.hpp"
#include "Pool.hpp"

#define         UNKNOWN_ERROR       "Unknown error!"

using namespace std;
using namespace Wt;
using namespace CoreLib;
using namespace Website;

struct CmsDashboard::Impl : public Wt::WObject
{
public:
    CmsDashboard *m_parent;

public:
    explicit Impl(CmsDashboard *parent);

public:
};

CmsDashboard::CmsDashboard(CgiRoot *cgi) :
    Page(cgi),
    m_pimpl(std::make_unique<CmsDashboard::Impl>(this))
{
    this->clear();
    this->setId("CmsDashboardPage");
    this->addWidget(Layout());
    m_htmlRoot->addWidget(this);
}

WWidget *CmsDashboard::Layout()
{
    LOG_DEBUG(11111111111);
    Div *container = new Div("CmsDashboard", "container");

    try {
        std::string htmlData;
        std::string file;
        if (m_cgiEnv->GetCurrentLanguage() == CgiEnv::Language::Fa) {
            file = "../templates/cms-dashboard-fa.wtml";
        } else {
            file = "../templates/cms-dashboard.wtml";
        }

        if (CoreLib::FileSystem::Read(file, htmlData)) {
            /// Fill the template
            WTemplate *tmpl = new WTemplate(container);
            tmpl->setTemplateText(WString(htmlData), TextFormat::XHTMLUnsafeText);

            tmpl->bindWidget("welcome-message", new WText(tr("cms-dashboard-welcome-message")));

            tmpl->bindWidget("last-login-title", new WText(tr("cms-dashboard-last-login-info-title")));
            tmpl->bindWidget("last-login-ip-label", new WText(tr("cms-dashboard-last-login-info-ip")));
            tmpl->bindWidget("last-login-location-label", new WText(tr("cms-dashboard-last-login-info-location")));
            tmpl->bindWidget("last-login-user-agent-label", new WText(tr("cms-dashboard-last-login-info-user-agent")));
            tmpl->bindWidget("last-login-referer-label", new WText(tr("cms-dashboard-last-login-info-referer")));
            tmpl->bindWidget("last-login-time-label", new WText(tr("cms-dashboard-last-login-info-time")));

            tmpl->bindWidget("last-login-ip", new WText(WString::fromUTF8(m_cgiEnv->SignedInUser.LastLogin.IP)));
            tmpl->bindWidget("last-login-location", new WText(WString::fromUTF8(m_cgiEnv->SignedInUser.LastLogin.Location)));
            tmpl->bindWidget("last-login-user-agent", new WText(WString::fromUTF8(m_cgiEnv->SignedInUser.LastLogin.UserAgent)));
            tmpl->bindWidget("last-login-referer", new WText(WString::fromUTF8(m_cgiEnv->SignedInUser.LastLogin.Referer)));
            tmpl->bindWidget("last-login-time-gdate", new WText(WString::fromUTF8(m_cgiEnv->SignedInUser.LastLogin.LoginGDate)));
            tmpl->bindWidget("last-login-time-jdate", new WText(WString::fromUTF8(m_cgiEnv->SignedInUser.LastLogin.LoginJDate)));
            tmpl->bindWidget("last-login-time", new WText(WString::fromUTF8(m_cgiEnv->SignedInUser.LastLogin.LoginTime)));
        }
    }

    catch (boost::exception &ex) {
        LOG_ERROR(boost::diagnostic_information(ex));
    }

    catch (std::exception &ex) {
        LOG_ERROR(ex.what());
    }

    catch (...) {
        LOG_ERROR(UNKNOWN_ERROR);
    }

    return container;
}

CmsDashboard::Impl::Impl(CmsDashboard *parent)
    : m_parent(parent)
{

}

<commit_msg>Removed a debugging log<commit_after>/**
 * @file
 * @author  Mohammad S. Babaei <info@babaei.net>
 * @version 0.1.0
 *
 * @section LICENSE
 *
 * (The MIT License)
 *
 * Copyright (c) 2015 Mohammad S. Babaei
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * @section DESCRIPTION
 *
 * CMS welcome screen a.k.a. dashboard.
 */

#include <Wt/WString>
#include <Wt/WTemplate>
#include <Wt/WText>
#include <Wt/WWidget>
#include <boost/exception/diagnostic_information.hpp>
#include <boost/format.hpp>
#include <CoreLib/FileSystem.hpp>
#include <CoreLib/Log.hpp>
#include "CgiEnv.hpp"
#include "CmsDashboard.hpp"
#include "Div.hpp"
#include "Pool.hpp"

#define         UNKNOWN_ERROR       "Unknown error!"

using namespace std;
using namespace Wt;
using namespace CoreLib;
using namespace Website;

struct CmsDashboard::Impl : public Wt::WObject
{
public:
    CmsDashboard *m_parent;

public:
    explicit Impl(CmsDashboard *parent);

public:
};

CmsDashboard::CmsDashboard(CgiRoot *cgi) :
    Page(cgi),
    m_pimpl(std::make_unique<CmsDashboard::Impl>(this))
{
    this->clear();
    this->setId("CmsDashboardPage");
    this->addWidget(Layout());
    m_htmlRoot->addWidget(this);
}

WWidget *CmsDashboard::Layout()
{
    Div *container = new Div("CmsDashboard", "container");

    try {
        std::string htmlData;
        std::string file;
        if (m_cgiEnv->GetCurrentLanguage() == CgiEnv::Language::Fa) {
            file = "../templates/cms-dashboard-fa.wtml";
        } else {
            file = "../templates/cms-dashboard.wtml";
        }

        if (CoreLib::FileSystem::Read(file, htmlData)) {
            /// Fill the template
            WTemplate *tmpl = new WTemplate(container);
            tmpl->setTemplateText(WString(htmlData), TextFormat::XHTMLUnsafeText);

            tmpl->bindWidget("welcome-message", new WText(tr("cms-dashboard-welcome-message")));

            tmpl->bindWidget("last-login-title", new WText(tr("cms-dashboard-last-login-info-title")));
            tmpl->bindWidget("last-login-ip-label", new WText(tr("cms-dashboard-last-login-info-ip")));
            tmpl->bindWidget("last-login-location-label", new WText(tr("cms-dashboard-last-login-info-location")));
            tmpl->bindWidget("last-login-user-agent-label", new WText(tr("cms-dashboard-last-login-info-user-agent")));
            tmpl->bindWidget("last-login-referer-label", new WText(tr("cms-dashboard-last-login-info-referer")));
            tmpl->bindWidget("last-login-time-label", new WText(tr("cms-dashboard-last-login-info-time")));

            tmpl->bindWidget("last-login-ip", new WText(WString::fromUTF8(m_cgiEnv->SignedInUser.LastLogin.IP)));
            tmpl->bindWidget("last-login-location", new WText(WString::fromUTF8(m_cgiEnv->SignedInUser.LastLogin.Location)));
            tmpl->bindWidget("last-login-user-agent", new WText(WString::fromUTF8(m_cgiEnv->SignedInUser.LastLogin.UserAgent)));
            tmpl->bindWidget("last-login-referer", new WText(WString::fromUTF8(m_cgiEnv->SignedInUser.LastLogin.Referer)));
            tmpl->bindWidget("last-login-time-gdate", new WText(WString::fromUTF8(m_cgiEnv->SignedInUser.LastLogin.LoginGDate)));
            tmpl->bindWidget("last-login-time-jdate", new WText(WString::fromUTF8(m_cgiEnv->SignedInUser.LastLogin.LoginJDate)));
            tmpl->bindWidget("last-login-time", new WText(WString::fromUTF8(m_cgiEnv->SignedInUser.LastLogin.LoginTime)));
        }
    }

    catch (boost::exception &ex) {
        LOG_ERROR(boost::diagnostic_information(ex));
    }

    catch (std::exception &ex) {
        LOG_ERROR(ex.what());
    }

    catch (...) {
        LOG_ERROR(UNKNOWN_ERROR);
    }

    return container;
}

CmsDashboard::Impl::Impl(CmsDashboard *parent)
    : m_parent(parent)
{

}

<|endoftext|>