<commit_before>/*****************************************************************************
 * This file is part of the Gluon Development Platform                       *
 * Copyright (c) 2011 Laszlo Papp <djszapi@archlinux.us>                     *
 *                                                                           *
 * This program is free software; you can redistribute it and/or modify      *
 * it under the terms of the GNU General Public License as published by      *
 * the Free Software Foundation; either version 2 of the License, or         *
 * (at your option) any later version.                                       *
 *                                                                           *
 * This program is distributed in the hope that it will be useful,           *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of            *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 * GNU General Public License for more details.                              *
 *                                                                           *
 * You should have received a copy of the GNU General Public License along   *
 * with this program; if not, write to the Free Software Foundation, Inc.,   *
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.               *
 *****************************************************************************/

#include "mainwindow.h"

#include "lib/models/gameitemsmodel.h"

#include "input/inputmanager.h"

#include "engine/game.h"
#include "engine/gameproject.h"
#include "engine/scene.h"
#include "graphics/renderwidget.h"

#include <KDE/KPushButton>
#include <KDE/KFileDialog>
#include <KDE/KUrl>
#include <KDE/KLocalizedString>
#include <KDE/KMenuBar>
#include <KDE/KToolBar>
#include <KDE/KStatusBar>
#include <KDE/KAction>
#include <KDE/KActionCollection>
#include <KDE/KStandardAction>
#include <KDE/KConfig>
#include <KDE/KShortcutsDialog>
#include <KDE/KEditToolBar>

#include <QtGui/QStatusBar>
#include <QtGui/QListView>
#include <QtGui/QVBoxLayout>
#include <QtGui/QLabel>
#include <QtCore/QTimer>
#include <QtCore/QDebug>

using namespace GluonKDEPlayer;

class MainWindow::MainWindowPrivate
{
    public:
        MainWindowPrivate() {}

        GluonGraphics::RenderWidget* widget;

        QString title;
        QString fileName;

        int msecElapsed;
        int frameCount;
};

MainWindow::MainWindow(const QString& filename )
    : KXmlGuiWindow()
    , d( new MainWindowPrivate )
    , m_gamesOverlay( new GamesOverlay( this ) )
    , m_layout( new QGridLayout )
    , m_project( new GluonEngine::GameProject )
{
    setCentralWidget( m_gamesOverlay );
    setupActions();
    setupGUI();
    showGames();
}

MainWindow::~MainWindow ( )
{
}

void MainWindow::setupActions()
{
    KStandardAction::quit( this, SLOT( close() ), actionCollection() );
    KStandardAction::showMenubar( menuBar(), SLOT(setVisible(bool)), actionCollection());
    KStandardAction::showStatusbar( statusBar(), SLOT(setVisible(bool)), actionCollection());
    setStandardToolBarMenuEnabled(true);
    createStandardStatusBarAction();

    KStandardAction::keyBindings(this, SLOT(optionsConfigureKeys()), actionCollection()); // options_configure_keybinding
    KStandardAction::configureToolbars(this, SLOT(optionsConfigureToolbars()), actionCollection()); // options_configure_toolbars

    m_recentFiles = KStandardAction::openRecent( this, SLOT( openProject( KUrl ) ), actionCollection() );
    // d->recentFiles->loadEntries( KGlobal::config()->group( "Recent Files" ) );

    KAction* login = new KAction( KIcon( "im-user" ), i18n( "Login" ), actionCollection() );
    actionCollection()->addAction( "community_login", login );
    connect( login, SIGNAL( triggered( bool ) ), SLOT( mLogin() ) );

    KAction* logout = new KAction( KIcon( "media-playback-start" ), i18n( "Logout" ), actionCollection() );
    actionCollection()->addAction( "community_logout", logout );
    connect( logout, SIGNAL( triggered( bool ) ), SLOT( mLogout() ) );

    KAction* details = new KAction( KIcon( "media-playback-start" ), i18n( "Details" ), actionCollection() );
    actionCollection()->addAction( "community_details", details );
    connect( details, SIGNAL( triggered( bool ) ), SLOT( mDetails() ) );

    KAction* registration = new KAction( KIcon( "list-add-user" ), i18n( "Registration" ), actionCollection() );
    actionCollection()->addAction( "community_registration", registration );
    connect( registration, SIGNAL( triggered( bool ) ), SLOT( mRegistration() ) );

    KAction* forgottenPassword = new KAction( KIcon( "help-hint" ), i18n( "Forgotten password" ), actionCollection() );
    actionCollection()->addAction( "community_forgotten_password", forgottenPassword );
    connect( forgottenPassword, SIGNAL( triggered( bool ) ), SLOT( mForgottenPassword() ) );

    KAction* play = new KAction( KIcon( "media-playback-start" ), i18n( "Play Game" ), actionCollection() );
    actionCollection()->addAction( "playGame", play );
    connect( play, SIGNAL( triggered( bool ) ), SLOT( openProject() ) );

    KAction* pause = new KAction( KIcon( "media-playback-pause" ), i18n( "Pause Game" ), actionCollection() );
    actionCollection()->addAction( "pauseGame", pause );
    connect( pause, SIGNAL( triggered( bool ) ), SLOT( pauseGame() ) );

    KAction* stop = new KAction( KIcon( "media-playback-stop" ), i18n( "Stop Game" ), actionCollection() );
    actionCollection()->addAction( "stopGame", stop );
    connect( stop, SIGNAL( triggered( bool ) ), SLOT( stopGame() ) );

    KStandardAction::quit(kapp, SLOT(quit()), actionCollection());
}

void MainWindow::startGame( )
{
    GluonCore::GluonObjectFactory::instance()->loadPlugins();

    m_project->loadFromFile( m_gameFileName );

    setWindowFilePath( m_gameFileName );
    d->title = windowTitle();

    GluonEngine::Game::instance()->setGameProject( m_project );
    GluonEngine::Game::instance()->setCurrentScene( m_project->entryPoint() );

    setFocus();

    // if( GluonEngine::Game::instance()->isRunning() )
    // {
        // GluonEngine::Game::instance()->setPause( false );
        // stateChanged( "paused", StateReverse );
    // }
    // else
    // {
        // stateChanged( "playing" );

        // QString currentSceneName = GluonEngine::Game::instance()->currentScene()->fullyQualifiedName();
        // saveProject();

        //Set the focus to the entire window, so that we do not accidentally trigger actions
        // setFocus();

        //Start the game loop
        //Note that this starts an infinite loop in Game
        GluonEngine::Game::instance()->runGame();
        QApplication::instance()->exit();
        //This happens after we exit the game loop
        // stateChanged( "playing", StateReverse );

        // openProject( d->fileName );
        // GluonEngine::Game::instance()->setCurrentScene( currentSceneName );
        // GluonEngine::Game::instance()->initializeAll();
    // }
}

void MainWindow::pauseGame()
{
    GluonEngine::Game::instance()->setPause( true );
    stateChanged( "paused" );
}

void MainWindow::stopGame()
{
    GluonEngine::Game::instance()->stopGame();
}

// void MainWindow::saveProperties(KConfigGroup &config)
// {
    // if (!m_part)
        // loadPart();

    // m_part->saveProperties(config);
    // config.writeEntry("docked", isHidden());
// }

// void MainWindow::readProperties(const KConfigGroup & config)
// {
    // if (!m_part)
        // loadPart();
    // m_part->readProperties(config);
    // setVisible( !Settings::showTrayIcon() || !config.readEntry("docked", false) );
// }

// TODO: move to part?
void MainWindow::optionsConfigureKeys()
{
    KShortcutsDialog dlg( KShortcutsEditor::AllActions,
    KShortcutsEditor::LetterShortcutsAllowed, this );

    dlg.addCollection(actionCollection());
    // if (m_part)
        // dlg.addCollection(m_part->actionCollection());

    dlg.configure();
}

// TODO: move to part?
 void MainWindow::optionsConfigureToolbars()
{
    // saveMainWindowSettings(KGlobal::config().data()->group( autoSaveGroup()) );
    // KEditToolBar dlg(factory());
    // connect(&dlg, SIGNAL(newToolBarConfig()),
            // this, SLOT(applyNewToolbarConfig()));
    // dlg.exec();
}

void MainWindow::mLogin( )
{
}

void MainWindow::mLogout( )
{
}

void MainWindow::mHome()
{
}

void MainWindow::mDetails()
{
}

void MainWindow::mRegistration()
{
}

void MainWindow::mForgottenPassword()
{
}

void MainWindow::closeEvent( QCloseEvent* event )
{
    GluonEngine::Game::instance()->stopGame();
    QWidget::closeEvent( event );
}

void MainWindow::resizeEvent( QResizeEvent* event )
{
    m_viewportWidth = event->size().width();
    m_viewportHeight = event->size().height();
    glViewport( 0, 0, m_viewportWidth, m_viewportHeight );
}

void MainWindow::showGames()
{
    m_gamesOverlay->setGeometry( geometry() );
    connect( m_gamesOverlay, SIGNAL( gameToPlaySelected( QModelIndex ) ), SLOT( setProject( QModelIndex ) ) );
}

void MainWindow::setProject( const QModelIndex& index )
{
    m_gameFileName = index.data(GluonPlayer::GameItemsModel::ProjectFileNameRole).toString();
    m_gamesOverlay->hide();
    openProject();
}

void MainWindow::openProject()
{
    if( m_gameFileName.isEmpty() )
    {
        return;
    }

    d->widget = new GluonGraphics::RenderWidget( this );
    setCentralWidget( d->widget );

    connect( GluonEngine::Game::instance(), SIGNAL( painted( int ) ), d->widget, SLOT( updateGL() ) );
    connect( GluonEngine::Game::instance(), SIGNAL( painted( int ) ), SLOT( countFrames( int ) ) );
    connect( GluonEngine::Game::instance(), SIGNAL( updated( int ) ), SLOT( updateTitle( int ) ) );

    GluonInput::InputManager::instance()->setFilteredObject(d->widget);
    QTimer::singleShot( 1000, this, SLOT( startGame() ) );
}

void MainWindow::activated( QModelIndex index )
{
    if( index.isValid() )
    {
    }
}

void MainWindow::updateTitle( int msec )
{
    d->msecElapsed += msec;

    static int fps = 0;
    if( d->msecElapsed > 1000 )
    {
        fps = d->frameCount;
        d->frameCount = 0;
        d->msecElapsed = 0;
    }

    setWindowTitle( d->title + QString( " (%1 FPS)" ).arg( fps ) );
}

void MainWindow::countFrames( int /* time */ )
{
    d->frameCount++;
}

<commit_msg>Fix the simple user input issue in the kdeext player.<commit_after>/*****************************************************************************
 * This file is part of the Gluon Development Platform                       *
 * Copyright (c) 2011 Laszlo Papp <djszapi@archlinux.us>                     *
 *                                                                           *
 * This program is free software; you can redistribute it and/or modify      *
 * it under the terms of the GNU General Public License as published by      *
 * the Free Software Foundation; either version 2 of the License, or         *
 * (at your option) any later version.                                       *
 *                                                                           *
 * This program is distributed in the hope that it will be useful,           *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of            *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
 * GNU General Public License for more details.                              *
 *                                                                           *
 * You should have received a copy of the GNU General Public License along   *
 * with this program; if not, write to the Free Software Foundation, Inc.,   *
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.               *
 *****************************************************************************/

#include "mainwindow.h"

#include "lib/models/gameitemsmodel.h"

#include "input/inputmanager.h"

#include "engine/game.h"
#include "engine/gameproject.h"
#include "engine/scene.h"
#include "graphics/renderwidget.h"

#include <KDE/KPushButton>
#include <KDE/KFileDialog>
#include <KDE/KUrl>
#include <KDE/KLocalizedString>
#include <KDE/KMenuBar>
#include <KDE/KToolBar>
#include <KDE/KStatusBar>
#include <KDE/KAction>
#include <KDE/KActionCollection>
#include <KDE/KStandardAction>
#include <KDE/KConfig>
#include <KDE/KShortcutsDialog>
#include <KDE/KEditToolBar>

#include <QtGui/QStatusBar>
#include <QtGui/QListView>
#include <QtGui/QVBoxLayout>
#include <QtGui/QLabel>
#include <QtCore/QTimer>
#include <QtCore/QDebug>

using namespace GluonKDEPlayer;

class MainWindow::MainWindowPrivate
{
    public:
        MainWindowPrivate() {}

        GluonGraphics::RenderWidget* widget;

        QString title;
        QString fileName;

        int msecElapsed;
        int frameCount;
};

MainWindow::MainWindow(const QString& filename )
    : KXmlGuiWindow()
    , d( new MainWindowPrivate )
    , m_gamesOverlay( new GamesOverlay( this ) )
    , m_layout( new QGridLayout )
    , m_project( new GluonEngine::GameProject )
{
    setCentralWidget( m_gamesOverlay );
    setupActions();
    setupGUI();
    showGames();
}

MainWindow::~MainWindow ( )
{
}

void MainWindow::setupActions()
{
    KStandardAction::quit( this, SLOT( close() ), actionCollection() );
    KStandardAction::showMenubar( menuBar(), SLOT(setVisible(bool)), actionCollection());
    KStandardAction::showStatusbar( statusBar(), SLOT(setVisible(bool)), actionCollection());
    setStandardToolBarMenuEnabled(true);
    createStandardStatusBarAction();

    KStandardAction::keyBindings(this, SLOT(optionsConfigureKeys()), actionCollection()); // options_configure_keybinding
    KStandardAction::configureToolbars(this, SLOT(optionsConfigureToolbars()), actionCollection()); // options_configure_toolbars

    m_recentFiles = KStandardAction::openRecent( this, SLOT( openProject( KUrl ) ), actionCollection() );
    // d->recentFiles->loadEntries( KGlobal::config()->group( "Recent Files" ) );

    KAction* login = new KAction( KIcon( "im-user" ), i18n( "Login" ), actionCollection() );
    actionCollection()->addAction( "community_login", login );
    connect( login, SIGNAL( triggered( bool ) ), SLOT( mLogin() ) );

    KAction* logout = new KAction( KIcon( "media-playback-start" ), i18n( "Logout" ), actionCollection() );
    actionCollection()->addAction( "community_logout", logout );
    connect( logout, SIGNAL( triggered( bool ) ), SLOT( mLogout() ) );

    KAction* details = new KAction( KIcon( "media-playback-start" ), i18n( "Details" ), actionCollection() );
    actionCollection()->addAction( "community_details", details );
    connect( details, SIGNAL( triggered( bool ) ), SLOT( mDetails() ) );

    KAction* registration = new KAction( KIcon( "list-add-user" ), i18n( "Registration" ), actionCollection() );
    actionCollection()->addAction( "community_registration", registration );
    connect( registration, SIGNAL( triggered( bool ) ), SLOT( mRegistration() ) );

    KAction* forgottenPassword = new KAction( KIcon( "help-hint" ), i18n( "Forgotten password" ), actionCollection() );
    actionCollection()->addAction( "community_forgotten_password", forgottenPassword );
    connect( forgottenPassword, SIGNAL( triggered( bool ) ), SLOT( mForgottenPassword() ) );

    KAction* play = new KAction( KIcon( "media-playback-start" ), i18n( "Play Game" ), actionCollection() );
    actionCollection()->addAction( "playGame", play );
    connect( play, SIGNAL( triggered( bool ) ), SLOT( openProject() ) );

    KAction* pause = new KAction( KIcon( "media-playback-pause" ), i18n( "Pause Game" ), actionCollection() );
    actionCollection()->addAction( "pauseGame", pause );
    connect( pause, SIGNAL( triggered( bool ) ), SLOT( pauseGame() ) );

    KAction* stop = new KAction( KIcon( "media-playback-stop" ), i18n( "Stop Game" ), actionCollection() );
    actionCollection()->addAction( "stopGame", stop );
    connect( stop, SIGNAL( triggered( bool ) ), SLOT( stopGame() ) );

    KStandardAction::quit(kapp, SLOT(quit()), actionCollection());
}

void MainWindow::startGame( )
{
    GluonCore::GluonObjectFactory::instance()->loadPlugins();

    m_project->loadFromFile( m_gameFileName );

    setWindowFilePath( m_gameFileName );
    d->title = windowTitle();

    GluonEngine::Game::instance()->setGameProject( m_project );
    GluonEngine::Game::instance()->setCurrentScene( m_project->entryPoint() );

    d->widget->setFocus();

    // if( GluonEngine::Game::instance()->isRunning() )
    // {
        // GluonEngine::Game::instance()->setPause( false );
        // stateChanged( "paused", StateReverse );
    // }
    // else
    // {
        // stateChanged( "playing" );

        // QString currentSceneName = GluonEngine::Game::instance()->currentScene()->fullyQualifiedName();
        // saveProject();

        //Set the focus to the entire window, so that we do not accidentally trigger actions
        // setFocus();

        //Start the game loop
        //Note that this starts an infinite loop in Game
        GluonEngine::Game::instance()->runGame();
        QApplication::instance()->exit();
        //This happens after we exit the game loop
        // stateChanged( "playing", StateReverse );

        // openProject( d->fileName );
        // GluonEngine::Game::instance()->setCurrentScene( currentSceneName );
        // GluonEngine::Game::instance()->initializeAll();
    // }
}

void MainWindow::pauseGame()
{
    GluonEngine::Game::instance()->setPause( true );
    stateChanged( "paused" );
}

void MainWindow::stopGame()
{
    GluonEngine::Game::instance()->stopGame();
}

// void MainWindow::saveProperties(KConfigGroup &config)
// {
    // if (!m_part)
        // loadPart();

    // m_part->saveProperties(config);
    // config.writeEntry("docked", isHidden());
// }

// void MainWindow::readProperties(const KConfigGroup & config)
// {
    // if (!m_part)
        // loadPart();
    // m_part->readProperties(config);
    // setVisible( !Settings::showTrayIcon() || !config.readEntry("docked", false) );
// }

// TODO: move to part?
void MainWindow::optionsConfigureKeys()
{
    KShortcutsDialog dlg( KShortcutsEditor::AllActions,
    KShortcutsEditor::LetterShortcutsAllowed, this );

    dlg.addCollection(actionCollection());
    // if (m_part)
        // dlg.addCollection(m_part->actionCollection());

    dlg.configure();
}

// TODO: move to part?
 void MainWindow::optionsConfigureToolbars()
{
    // saveMainWindowSettings(KGlobal::config().data()->group( autoSaveGroup()) );
    // KEditToolBar dlg(factory());
    // connect(&dlg, SIGNAL(newToolBarConfig()),
            // this, SLOT(applyNewToolbarConfig()));
    // dlg.exec();
}

void MainWindow::mLogin( )
{
}

void MainWindow::mLogout( )
{
}

void MainWindow::mHome()
{
}

void MainWindow::mDetails()
{
}

void MainWindow::mRegistration()
{
}

void MainWindow::mForgottenPassword()
{
}

void MainWindow::closeEvent( QCloseEvent* event )
{
    GluonEngine::Game::instance()->stopGame();
    QWidget::closeEvent( event );
}

void MainWindow::resizeEvent( QResizeEvent* event )
{
    m_viewportWidth = event->size().width();
    m_viewportHeight = event->size().height();
    glViewport( 0, 0, m_viewportWidth, m_viewportHeight );
}

void MainWindow::showGames()
{
    m_gamesOverlay->setGeometry( geometry() );
    connect( m_gamesOverlay, SIGNAL( gameToPlaySelected( QModelIndex ) ), SLOT( setProject( QModelIndex ) ) );
}

void MainWindow::setProject( const QModelIndex& index )
{
    m_gameFileName = index.data(GluonPlayer::GameItemsModel::ProjectFileNameRole).toString();
    m_gamesOverlay->hide();
    openProject();
}

void MainWindow::openProject()
{
    if( m_gameFileName.isEmpty() )
    {
        return;
    }

    d->widget = new GluonGraphics::RenderWidget( this );
    setCentralWidget( d->widget );

    connect( GluonEngine::Game::instance(), SIGNAL( painted( int ) ), d->widget, SLOT( updateGL() ) );
    connect( GluonEngine::Game::instance(), SIGNAL( painted( int ) ), SLOT( countFrames( int ) ) );
    connect( GluonEngine::Game::instance(), SIGNAL( updated( int ) ), SLOT( updateTitle( int ) ) );

    GluonInput::InputManager::instance()->setFilteredObject(d->widget);
    QTimer::singleShot( 1000, this, SLOT( startGame() ) );
}

void MainWindow::activated( QModelIndex index )
{
    if( index.isValid() )
    {
    }
}

void MainWindow::updateTitle( int msec )
{
    d->msecElapsed += msec;

    static int fps = 0;
    if( d->msecElapsed > 1000 )
    {
        fps = d->frameCount;
        d->frameCount = 0;
        d->msecElapsed = 0;
    }

    setWindowTitle( d->title + QString( " (%1 FPS)" ).arg( fps ) );
}

void MainWindow::countFrames( int /* time */ )
{
    d->frameCount++;
}

<|endoftext|>


<commit_before>// Copyright (C) 2011, James Webber.
// Distributed under a 3-clause BSD license.  See COPYING.

#ifndef UTIL_ASSERTS_HPP_45mln30x
#define UTIL_ASSERTS_HPP_45mln30x

#include <iostream>
#include <cstdlib>
#include <cstring>

#include "btrace_defines.hpp"
#include "../btrace/assert.hpp"

namespace asserts {
  namespace detail {
    template<class T> T *check_pointer(int line, const char *file, T *p, const char *code) {
      if (p == NULL) {
        std::cerr
          << "nerve: " << file << ":" << line << ":\n"
          << "  expression: '" << code << "'\n"
          << "  must yield a non-null pointer" << std::endl;
        std::abort();
      }
      return p;
    }
  }
}

//! \ingroup grp_asserts
//! Abort with a sensible message.
#define NERVE_ABORT(msg__)\
  do {\
    std::cerr << "nerve: aborting: " << msg__ << std::endl;\
    std::abort();\
  } while (false);

//! \ingroup grp_asserts
//! Assertion with message.
#define NERVE_ASSERT(code__, msg__) BTRACE_ASSERT(code__, msg__)

//! \ingroup grp_asserts
//! Alias.
#define NERVE_ASSERT_PTR(var__) NERVE_ASSERT(var__ != NULL, #var__ " must not be null")

//! \ingroup grp_asserts
//! Check the pointer is non-null and return it.
#define NERVE_CHECK_PTR(expr__) BTRACE_ASSERT_PTR(expr__)

//! \ingroup grp_asserts
//! Assertion with message but don't abort afterwards.
#define NERVE_WASSERT(code__, msg__)\
  do {\
    if (! (code__)) {\
      std::cerr << "nerve: assert: '" << #code__ << "': " << msg__ << std::endl;\
    }\
  } while(false);

//! \ingroup grp_asserts
//! Something is not implemented
#define NERVE_NIMPL(what__)\
  do {\
    std::cerr << __FILE__ << ":" << __LINE__ << ": warning: " << std::endl;\
    std::cerr << "  in " << __PRETTY_FUNCTION__ << std::endl;\
    std::cerr << "  not implemented: " << what__ << std::endl;\
  } while (false);

//! \ingroup grp_asserts
//! Wipe memory.
#define NERVE_WIPE(p__, size__) std::memset(p__, 0, size__)

#endif
<commit_msg>Tidy up asserts a little more.<commit_after>// Copyright (C) 2011, James Webber.
// Distributed under a 3-clause BSD license.  See COPYING.

#ifndef UTIL_ASSERTS_HPP_45mln30x
#define UTIL_ASSERTS_HPP_45mln30x

#include <iostream>
#include <cstdlib>
#include <cstring>

#include "btrace_defines.hpp"
#include "../btrace/assert.hpp"

//! \ingroup grp_asserts
//! Abort with a sensible message.
#define NERVE_ABORT(msg__)\
  do {\
    std::cerr << "nerve: aborting: " << msg__ << std::endl;\
    std::abort();\
  } while (false);

//! \ingroup grp_asserts
//! Assertion with message.
#define NERVE_ASSERT(code__, msg__) BTRACE_ASSERT(code__, msg__)

//! \ingroup grp_asserts
//! Alias.
#define NERVE_ASSERT_PTR(var__) NERVE_ASSERT(var__ != NULL, #var__ " must not be null")

//! \ingroup grp_asserts
//! Check the pointer is non-null and return it.
#define NERVE_CHECK_PTR(expr__) BTRACE_ASSERT_PTR(expr__)

//! \ingroup grp_asserts
//! Assertion with message but don't abort afterwards.
#define NERVE_WASSERT(code__, msg__)\
  do {\
    if (! (code__)) {\
      std::cerr << "nerve: assert: '" << #code__ << "': " << msg__ << std::endl;\
    }\
  } while(false);

//! \ingroup grp_asserts
//! Something is not implemented
#define NERVE_NIMPL(what__)\
  do {\
    std::cerr << __FILE__ << ":" << __LINE__ << ": warning: " << std::endl;\
    std::cerr << "  in " << __PRETTY_FUNCTION__ << std::endl;\
    std::cerr << "  not implemented: " << what__ << std::endl;\
  } while (false);

//! \ingroup grp_asserts
//! Wipe memory.
#ifndef NERVE_DEVELOPER
#  error "Need NERVE_DEVELOPER."
#elif NERVE_DEVELOPER
#  define NERVE_WIPE(p__, size__) std::memset(p__, 0, size__)
#else
#  define NERVE_WIPE(p__, size__)
#endif

#endif
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 Luke San Antonio
 * All rights reserved.
 */
#include "server_protocol.h"
#include "../common/log.h"
namespace redc { namespace net
{
  void init_server(Server_Context& ctx) noexcept
  {
    ctx.host = std::move(*make_server_host(ctx.port, ctx.max_peers).ok());
  }

  void step_remote_client(Server_Context& ctx,
                          Client_State_And_Buffer& client,
                          ENetEvent const& event) noexcept
  {
    // We can assume we got a recieve event I guess.
    switch(client.state)
    {
      case Remote_Client_State::Version:
      {
        // Recieve version
        if(!recieve_data(client.version, event.packet))
        {
          // Err, ignore:
          break;
        }

        // Make sure the version is correct
        Version_Okay versions_okay;
        versions_okay.protocol =
          client.version.protocol_version == CLIENT_PROTOCOL_VERSION;
        versions_okay.client = client.version.client_version == 1;

        // Inform the client
        send_data(versions_okay, event.peer);

        if(!versions_okay.protocol || !versions_okay.client)
        {
          if(!versions_okay.protocol && versions_okay.client)
          {
            log_i("Rejecting client (game version = %) because we don't know "
                  "protocol version %",
                  client.version.client_version,
                  client.version.protocol_version);
          }
          else if(versions_okay.protocol && !versions_okay.client)
          {
            log_i("Rejecting client (protocol version = %) because we don't "
                  "know game client version %",
                  client.version.protocol_version,
                  client.version.client_version);
          }
          else if(!versions_okay.protocol && !versions_okay.client)
          {
            log_i("Rejecting client because we don't know protocol version % "
                  "or game client version %",
                  client.version.protocol_version,
                  client.version.client_version);
          }

          // Disconnect the peer and jump ship.
          enet_peer_disconnect_later(event.peer, 0);

          break;
        }

        client.state = Remote_Client_State::Name;

        break;
      }
      case Remote_Client_State::Name:
      {
        if(!recieve_data(client.player_name, event.packet)) break;

        send_data(ctx.info, event.peer);
        client.state = Remote_Client_State::Inventory;

        break;
      }
      case Remote_Client_State::Inventory:
      {
        // Failed to read inventory
        if(!recieve_data(client.inventory, event.packet)) break;

        send_data(true, event.peer);
        client.state = Remote_Client_State::Team_Id;

        break;
      }
      case Remote_Client_State::Team_Id:
      {
        // Failed to read team id.
        if(!recieve_data(client.team, event.packet)) break;

        Spawn_Information spawn_info;

        // TODO: Fill in spawn information

        send_data(spawn_info, event.peer);
        client.state = Remote_Client_State::Playing;

        break;
      }
      case Remote_Client_State::Playing:
      default:
      {
        Input cur_input;
        if(!recieve_data(cur_input, event.packet))
        {
          // Possibly handle other types of packets.
          break;
        }

        client.inputs.push_back(cur_input);

        break;
      }
    }
  }

  Client_Vector_Iter find_client_by_peer(Client_Vector& cts,
                                         ENetPeer* peer) noexcept
  {
    return std::find_if(std::begin(cts), std::end(cts),
      [&peer](auto& client_state)
      {
        return client_state.peer == peer;
      });
  }

  void step_server(Server_Context& ctx, ENetEvent const& event) noexcept
  {
    switch(event.type)
    {
      case ENET_EVENT_TYPE_CONNECT:
      {
        // Oh boy!
        Client_State_And_Buffer client;

        // We only know this information, we'll fill out the rest later.
        client.peer = event.peer;
        client.state = Remote_Client_State::Version;

        // Keep track of it, of course
        ctx.clients.push_back(std::move(client));

        // At this point we will recieve it's version info.
        break;
      }
      case ENET_EVENT_TYPE_RECEIVE:
      {
        // Progress the state of the client. Jesus Christ that scares me.
        // Abstract that, obviously!

        auto client_find = find_client_by_peer(ctx.clients, event.peer);

        // Find the corect client state and buffer object that will tell us
        // what we are actually recieving
        if(client_find == ctx.clients.end())
        {
          // I don't know when this would happen. Something went quite wrong
          log_e("Recieving data from unknown client - ignoring!");
          break;
        }

        // Recieve whatever we need to recieve, etc.
        step_remote_client(ctx, *client_find, event);

        // Don't forget to destory the packet!
        enet_packet_destroy(event.packet);

        break;
      }
      case ENET_EVENT_TYPE_DISCONNECT:
      default:
      {
        log_i("Disconnect event");

        // TODO:
        // Find an iterator to the right client and remove it from the list of
        // clients.
        auto client_find = find_client_by_peer(ctx.clients, event.peer);

        if(client_find == ctx.clients.end())
        {
          // wat
        }
        else
        {
          // Remove it from our clients list.
          ctx.clients.erase(client_find);
          // No need to remove it from teams but we do have to notify everyone
          // that this player no longer exists.
        }

        break;
      }
    }
  }
} }
<commit_msg>Fix typos<commit_after>/*
 * Copyright (C) 2015 Luke San Antonio
 * All rights reserved.
 */
#include "server_protocol.h"
#include "../common/log.h"
namespace redc { namespace net
{
  void init_server(Server_Context& ctx) noexcept
  {
    ctx.host = std::move(*make_server_host(ctx.port, ctx.max_peers).ok());
  }

  void step_remote_client(Server_Context& ctx,
                          Client_State_And_Buffer& client,
                          ENetEvent const& event) noexcept
  {
    // We can assume we got a receive event I guess.
    switch(client.state)
    {
      case Remote_Client_State::Version:
      {
        // Receive version
        if(!recieve_data(client.version, event.packet))
        {
          // Err, ignore:
          break;
        }

        // Make sure the version is correct
        Version_Okay versions_okay;
        versions_okay.protocol =
          client.version.protocol_version == CLIENT_PROTOCOL_VERSION;
        versions_okay.client = client.version.client_version == 1;

        // Inform the client
        send_data(versions_okay, event.peer);

        if(!versions_okay.protocol || !versions_okay.client)
        {
          if(!versions_okay.protocol && versions_okay.client)
          {
            log_i("Rejecting client (game version = %) because we don't know "
                  "protocol version %",
                  client.version.client_version,
                  client.version.protocol_version);
          }
          else if(versions_okay.protocol && !versions_okay.client)
          {
            log_i("Rejecting client (protocol version = %) because we don't "
                  "know game client version %",
                  client.version.protocol_version,
                  client.version.client_version);
          }
          else if(!versions_okay.protocol && !versions_okay.client)
          {
            log_i("Rejecting client because we don't know protocol version % "
                  "or game client version %",
                  client.version.protocol_version,
                  client.version.client_version);
          }

          // Disconnect the peer and jump ship.
          enet_peer_disconnect_later(event.peer, 0);

          break;
        }

        client.state = Remote_Client_State::Name;

        break;
      }
      case Remote_Client_State::Name:
      {
        if(!recieve_data(client.player_name, event.packet)) break;

        send_data(ctx.info, event.peer);
        client.state = Remote_Client_State::Inventory;

        break;
      }
      case Remote_Client_State::Inventory:
      {
        // Failed to read inventory
        if(!recieve_data(client.inventory, event.packet)) break;

        send_data(true, event.peer);
        client.state = Remote_Client_State::Team_Id;

        break;
      }
      case Remote_Client_State::Team_Id:
      {
        // Failed to read team id.
        if(!recieve_data(client.team, event.packet)) break;

        Spawn_Information spawn_info;

        // TODO: Fill in spawn information

        send_data(spawn_info, event.peer);
        client.state = Remote_Client_State::Playing;

        break;
      }
      case Remote_Client_State::Playing:
      default:
      {
        Input cur_input;
        if(!recieve_data(cur_input, event.packet))
        {
          // Possibly handle other types of packets.
          break;
        }

        client.inputs.push_back(cur_input);

        break;
      }
    }
  }

  Client_Vector_Iter find_client_by_peer(Client_Vector& cts,
                                         ENetPeer* peer) noexcept
  {
    return std::find_if(std::begin(cts), std::end(cts),
      [&peer](auto& client_state)
      {
        return client_state.peer == peer;
      });
  }

  void step_server(Server_Context& ctx, ENetEvent const& event) noexcept
  {
    switch(event.type)
    {
      case ENET_EVENT_TYPE_CONNECT:
      {
        // Oh boy!
        Client_State_And_Buffer client;

        // We only know this information, we'll fill out the rest later.
        client.peer = event.peer;
        client.state = Remote_Client_State::Version;

        // Keep track of it, of course
        ctx.clients.push_back(std::move(client));

        // At this point we will receive it's version info.
        break;
      }
      case ENET_EVENT_TYPE_RECEIVE:
      {
        // Progress the state of the client. Jesus Christ that scares me.
        // Abstract that, obviously!

        auto client_find = find_client_by_peer(ctx.clients, event.peer);

        // Find the correct client state and buffer object that will tell us
        // what we are actually receiving
        if(client_find == ctx.clients.end())
        {
          // I don't know when this would happen. Something went quite wrong
          log_e("Receiving data from unknown client - ignoring!");
          break;
        }

        // Receive whatever we need to receive, etc.
        step_remote_client(ctx, *client_find, event);

        // Don't forget to destroy the packet!
        enet_packet_destroy(event.packet);

        break;
      }
      case ENET_EVENT_TYPE_DISCONNECT:
      default:
      {
        log_i("Disconnect event");

        // TODO:
        // Find an iterator to the right client and remove it from the list of
        // clients.
        auto client_find = find_client_by_peer(ctx.clients, event.peer);

        if(client_find == ctx.clients.end())
        {
          // wat
          // RIP
          // A client we don't know just disconnected from us.
        }
        else
        {
          // Remove it from our clients list.
          ctx.clients.erase(client_find);
          // No need to remove it from teams but we do have to notify everyone
          // that this player no longer exists.
        }

        break;
      }
    }
  }
} }
<|endoftext|>


<commit_before>/* Copyright (c) 2015 In Cheol, Kang
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:

 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.

 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include "tcp_acceptor.h"

#include "event/event.h"
#include "event/event_dispatcher.h"

namespace eznetpp {
namespace net {
namespace tcp {

tcp_acceptor::tcp_acceptor(void) {
}

tcp_acceptor::~tcp_acceptor(void) {
}

int tcp_acceptor::open(int port, int backlog) {
  int ret = bind_and_listen(port, backlog);

  if (ret != 0)
    return ret;

  set_nonblocking();
  set_reuseaddr();

  return 0;
}

void tcp_acceptor::recv(void) {
  struct sockaddr_in client_addr;
  socklen_t client_addr_len = sizeof(client_addr);

  int sock_fd = ::accept(_sd, (struct sockaddr *)&client_addr, &client_addr_len);
  _last_errno = errno;

  if (sock_fd == -1) {
    if (errno == EAGAIN || errno == EWOULDBLOCK) {
      return;
    }
  }

  eznetpp::event::event_dispatcher::instance().push_event(new eznetpp::event::io_event
      (eznetpp::event::event_type::tcp_accept, sock_fd, inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), this));
}

void tcp_acceptor::close(void) {
  ::close(_sd);
  _sd = -1;

  eznetpp::event::event_dispatcher::instance().push_event(
      new eznetpp::event::io_event(eznetpp::event::event_type::close, this));
}

int tcp_acceptor::bind_and_listen(int port, int backlog) {
  struct sockaddr_in server_addr;
  bzero(&server_addr, sizeof(server_addr));
  server_addr.sin_family = AF_INET;
  server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  server_addr.sin_port = htons(port);

  int ret = ::bind(_sd, (struct sockaddr *)&server_addr, sizeof(server_addr));

  if (ret != 0) {
    eznetpp::util::logger::instance().log(eznetpp::util::logger::log_level::error
                           , __FILE__, __FUNCTION__, __LINE__
                           , "::bind() error(%d)", errno);

    ::close(_sd);
    _sd = -1;
    return errno;
  }

  ret = ::listen(_sd, backlog);

  if (ret != 0) {
    eznetpp::util::logger::instance().log(eznetpp::util::logger::log_level::error
                           , __FILE__, __FUNCTION__, __LINE__
                           , "::listen() error(%d)", errno);

    ::close(_sd);
    _sd = -1;
    return errno;
  }

  return 0;
}

}  // namespace tcp
}  // namespace net
}  // namespace eznetpp
<commit_msg>Modify the code to improve the performance for accepting the client<commit_after>/* Copyright (c) 2015 In Cheol, Kang
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:

 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.

 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include "tcp_acceptor.h"

#include "event/event.h"
#include "event/event_dispatcher.h"

namespace eznetpp {
namespace net {
namespace tcp {

tcp_acceptor::tcp_acceptor(void) {
}

tcp_acceptor::~tcp_acceptor(void) {
}

int tcp_acceptor::open(int port, int backlog) {
  int ret = bind_and_listen(port, backlog);

  if (ret != 0)
    return ret;

  set_nonblocking();
  set_reuseaddr();

  return 0;
}

void tcp_acceptor::recv(void) {
  while (1) {
    struct sockaddr_in client_addr;
    socklen_t client_addr_len = sizeof(client_addr);

    int sock_fd = ::accept(_sd, (struct sockaddr *)&client_addr, &client_addr_len);
    _last_errno = errno;

    if (sock_fd == -1) {
      if (errno == EAGAIN || errno == EWOULDBLOCK) {
        break;
      }
    }

    eznetpp::event::event_dispatcher::instance().push_event(new eznetpp::event::io_event
        (eznetpp::event::event_type::tcp_accept, sock_fd, inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), this));
  }
}

void tcp_acceptor::close(void) {
  ::close(_sd);
  _sd = -1;

  eznetpp::event::event_dispatcher::instance().push_event(
      new eznetpp::event::io_event(eznetpp::event::event_type::close, this));
}

int tcp_acceptor::bind_and_listen(int port, int backlog) {
  struct sockaddr_in server_addr;
  bzero(&server_addr, sizeof(server_addr));
  server_addr.sin_family = AF_INET;
  server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  server_addr.sin_port = htons(port);

  int ret = ::bind(_sd, (struct sockaddr *)&server_addr, sizeof(server_addr));

  if (ret != 0) {
    eznetpp::util::logger::instance().log(eznetpp::util::logger::log_level::error
                           , __FILE__, __FUNCTION__, __LINE__
                           , "::bind() error(%d)", errno);

    ::close(_sd);
    _sd = -1;
    return errno;
  }

  ret = ::listen(_sd, backlog);

  if (ret != 0) {
    eznetpp::util::logger::instance().log(eznetpp::util::logger::log_level::error
                           , __FILE__, __FUNCTION__, __LINE__
                           , "::listen() error(%d)", errno);

    ::close(_sd);
    _sd = -1;
    return errno;
  }

  return 0;
}

}  // namespace tcp
}  // namespace net
}  // namespace eznetpp
<|endoftext|>


<commit_before>#include "API.hpp"
#include "ros/ros.h"
#include <ros/console.h>
#include "api_application/Announce.h"
#include <vector>

class API
{
    public:
	API(int argc, char **argv)
	{
		idCounter = 0;
		ros::init(argc, argv, "api_server");
		ros::NodeHandle n;
		ros::ServiceServer service = n.advertiseService("announce", API::announce);
		ROS_INFO("Ready to deliver IDs.");
		ros::spin();
		return 0;
	}

	bool announce(api_application::Announce::Request &req, api_application::Announce::Response &res)
	{
	    res.id = idCounter++;
	    switch (req.type) {
		case 0:
		    cameras.push_back({res.id, req.camera_id});
		    break;
		case 1:
		    quadcopters.push_back(res.id);
		    break;
		case 2:
		    controllers.push_back(res.id);
		    break;
		case 3:
		    positions.push_back(res.id);
		    break;
		default:
		    ROS_ERROR("Malformed register attempt!");
		    res.id = -1;
		    return false;
	    }
	    ROS_INFO("Registered new module with type %d and id %d", req.type, res.id);
	    return true;
	}

	private:
	    int idCounter;

	    //the ids of modules by category
	    std::vector<int[2]> cameras; //first value is the module id, second the camera id
	    std::vector<int> quadcopters;
	    std::vector<int> controllers;
	    std::vector<int> positions;
};<commit_msg>Corrected callback function<commit_after>#include "API.hpp"
#include "ros/ros.h"
#include <ros/console.h>
#include "api_application/Announce.h"
#include <vector>

class API
{
    public:
	API(int argc, char **argv)
	{
		idCounter = 0;
		ros::init(argc, argv, "api_server");
		ros::NodeHandle n;
		ros::ServiceServer service = n.advertiseService("announce", &API::announce, this);
		ROS_INFO("Ready to deliver IDs.");
		ros::spin();
	}

	bool announce(api_application::Announce::Request &req, api_application::Announce::Response &res)
	{
	    res.id = idCounter++;
	    switch (req.type) {
		case 0:
		    cameras.push_back({res.id, req.camera_id});
		    break;
		case 1:
		    quadcopters.push_back(res.id);
		    break;
		case 2:
		    controllers.push_back(res.id);
		    break;
		case 3:
		    positions.push_back(res.id);
		    break;
		default:
		    ROS_ERROR("Malformed register attempt!");
		    res.id = -1;
		    return false;
	    }
	    ROS_INFO("Registered new module with type %d and id %d", req.type, res.id);
	    return true;
	}

	private:
	    int idCounter;

	    //the ids of modules by category
	    std::vector<int[2]> cameras; //first value is the module id, second the camera id
	    std::vector<int> quadcopters;
	    std::vector<int> controllers;
	    std::vector<int> positions;
};<|endoftext|>


<commit_before>/*
 * Copyright 2014-2017 Kacper Kasper <kacperkasper@gmail.com>
 * All rights reserved. Distributed under the terms of the MIT license.
 */

#include "App.h"

#include <AboutWindow.h>
#include <Alert.h>
#include <Catalog.h>
#include <Directory.h>
#include <Entry.h>
#include <File.h>
#include <FindDirectory.h>
#include <Path.h>

#include <string>
#include <vector>

#include "AppPreferencesWindow.h"
#include "EditorWindow.h"
#include "FindWindow.h"
#include "Preferences.h"
#include "Styler.h"
#include "QuitAlert.h"

#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "App"

App::App()
	:
	BApplication(gAppMime),
	fLastActiveWindow(nullptr),
	fAppPreferencesWindow(nullptr),
	fFindWindow(nullptr),
	fPreferences(nullptr)
{
}

App::~App()
{
	EditorWindow* window;
	while(fWindows.CountItems() > 0) {
		window = fWindows.RemoveItemAt(0);
		if(fWindows.CountItems() == 0) {
			fPreferences->fWindowRect = window->Frame();
		}
		if(window->LockLooper())
		{
			window->Quit();
		}
	}

	fPreferences->Save(fPreferencesFile.Path());
	delete fPreferences;
}

void
App::Init()
{
	BPath settingsPath;
	find_directory(B_USER_SETTINGS_DIRECTORY, &settingsPath);
	settingsPath.Append(gAppName);
	BDirectory preferencesDir(settingsPath.Path());
	if(preferencesDir.InitCheck() == B_ENTRY_NOT_FOUND) {
		preferencesDir.CreateDirectory(settingsPath.Path(), &preferencesDir);
	}

	fPreferencesFile.SetTo(&preferencesDir, "settings");
	fPreferences = new Preferences();
	fPreferences->Load(fPreferencesFile.Path());
	fPreferences->fSettingsPath = settingsPath;
	EditorWindow::SetPreferences(fPreferences);

	Languages::LoadLanguages();
}

void
App::AboutRequested()
{
	const char* specialThanks[] = {
		B_TRANSLATE("Neil Hodgson, for Scintilla editing component and SciTE editor."),
		nullptr
	};

	BAboutWindow* window = new BAboutWindow(gAppName, gAppMime);
	window->AddCopyright(2016, "Kacper Kasper");
	window->AddDescription(
		B_TRANSLATE("Code editor for Haiku based on Scintilla editing component."));
	window->AddSpecialThanks(specialThanks);
	window->AddExtraInfo(B_TRANSLATE("Distributed on MIT license terms."));
	window->Show();
}

bool
App::QuitRequested()
{
	BObjectList<EditorWindow> unsaved;
	std::vector<std::string> unsavedPaths;
	EditorWindow* current;
	for(int i = 0; current = fWindows.ItemAt(i); ++i) {
		if(current->IsModified()) {
			unsaved.AddItem(current);
			unsavedPaths.push_back(std::string(current->OpenedFilePath()));
		}
	}
	if(unsaved.IsEmpty()) {
		return true;
	}
	QuitAlert* quitAlert = new QuitAlert(unsavedPaths);
	auto filesToSave = quitAlert->Go();
	if(filesToSave.empty()) {
		fLastActiveWindow->Activate();
		return false;
	}
	for(int i = 0; current = unsaved.ItemAt(i); ++i) {
		if(filesToSave[i] == false) continue;
		BMessage reply;
		BMessage save(SAVE_FILE);
		BMessenger messenger((BWindow*) current);
		messenger.SendMessage(&save, &reply);
			// FIXME: this is smelly
	}
	return true;
}

void
App::ReadyToRun()
{
	if(CountWindows() == 0) {
		PostMessage(WINDOW_NEW);
	}
}

void
App::ArgvReceived(int32 argc, char** argv)
{
	entry_ref ref;
	BEntry entry;
	for(int32 i = 1; i < argc; ++i) {
		Sci_Position line = -1;
		Sci_Position column = -1;
		BString argument(argv[i]);
		BString filename;
		BString lineStr, columnStr;
		// first :
		int32 pos = argument.FindFirst(':');
		if(pos != B_ERROR) {
			argument.CopyInto(filename, 0, pos);
			// second :
			int32 pos2 = argument.FindFirst(':', pos + 1);
			if(pos2 != B_ERROR) {
				argument.CopyInto(lineStr, pos + 1, pos2);
				argument.CopyInto(columnStr, pos2 + 1, argument.Length());
			} else {
				argument.CopyInto(lineStr, pos + 1, argument.Length());
			}
			line = strtol(lineStr.String(), nullptr, 10) - 1;
			column = strtol(columnStr.String(), nullptr, 10) - 1;
		} else {
			filename = argument;
		}
		entry.SetTo(filename);
		entry.GetRef(&ref);
		EditorWindow* window = new EditorWindow();
		window->OpenFile(&ref, line, column);
		window->Show();
		fWindows.AddItem(window);
	}
}

void
App::RefsReceived(BMessage* message)
{
	int32 count;
	if(message->GetInfo("refs", nullptr, &count) != B_OK) {
		return;
	}
	entry_ref ref;
	for(int32 i = 0; i < count; ++i) {
		if(message->FindRef("refs", i, &ref) == B_OK) {
			EditorWindow* window = new EditorWindow();
			window->OpenFile(&ref);
			window->Show();
			fWindows.AddItem(window);
		}
	}
}

void
App::MessageReceived(BMessage* message)
{
	switch(message->what) {
	case ACTIVE_WINDOW_CHANGED: {
		if(message->FindPointer("window", (void**) &fLastActiveWindow) != B_OK) {
			fLastActiveWindow = nullptr;
		}
	} break;
	case APP_PREFERENCES_CHANGED: {
		for(uint32 i = 0, count = fWindows.CountItems(); i < count; i++) {
			BMessenger messenger((BWindow*) fWindows.ItemAt(i));
			messenger.SendMessage(message);
		}
	} break;
	case APP_PREFERENCES_QUITTING: {
		fAppPreferencesWindow = nullptr;
	} break;
	case FINDWINDOW_FIND:
	case FINDWINDOW_REPLACE:
	case FINDWINDOW_REPLACEFIND:
	case FINDWINDOW_REPLACEALL: {
		// TODO: == nullptr should never happen, alert if it somehow does?
		if(fLastActiveWindow != nullptr) {
			BMessenger messenger((BWindow*) fLastActiveWindow);
			messenger.SendMessage(message);
		}
	} break;
	case FINDWINDOW_QUITTING: {
		fFindWindow = nullptr;
	} break;
	case MAINMENU_EDIT_APP_PREFERENCES: {
		if(fAppPreferencesWindow == nullptr) {
			fAppPreferencesWindow = new AppPreferencesWindow(fPreferences);
		}
		fAppPreferencesWindow->Show();
		fAppPreferencesWindow->Activate();
	} break;
	case MAINMENU_SEARCH_FINDREPLACE: {
		if(fFindWindow == nullptr) {
			fFindWindow = new FindWindow();
		}
		fFindWindow->Show();
		fFindWindow->Activate();
	} break;
	case WINDOW_NEW: {
		EditorWindow* window = new EditorWindow();
		window->Show();
		fWindows.AddItem(window);
	} break;
	case WINDOW_CLOSE: {
		EditorWindow* window;
		if(message->FindPointer("window", (void**) &window) == B_OK) {
			fWindows.RemoveItem(window);
		}
		if(fWindows.CountItems() == 0) {
			fPreferences->fWindowRect = window->Frame();
			Quit();
		}
	} break;
	default:
		BApplication::MessageReceived(message);
	break;
	}
}
<commit_msg>Handle parameters from /bin/open.<commit_after>/*
 * Copyright 2014-2017 Kacper Kasper <kacperkasper@gmail.com>
 * All rights reserved. Distributed under the terms of the MIT license.
 */

#include "App.h"

#include <AboutWindow.h>
#include <Alert.h>
#include <Catalog.h>
#include <Directory.h>
#include <Entry.h>
#include <File.h>
#include <FindDirectory.h>
#include <Path.h>

#include <string>
#include <vector>

#include "AppPreferencesWindow.h"
#include "EditorWindow.h"
#include "FindWindow.h"
#include "Preferences.h"
#include "Styler.h"
#include "QuitAlert.h"

#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "App"

App::App()
	:
	BApplication(gAppMime),
	fLastActiveWindow(nullptr),
	fAppPreferencesWindow(nullptr),
	fFindWindow(nullptr),
	fPreferences(nullptr)
{
}

App::~App()
{
	EditorWindow* window;
	while(fWindows.CountItems() > 0) {
		window = fWindows.RemoveItemAt(0);
		if(fWindows.CountItems() == 0) {
			fPreferences->fWindowRect = window->Frame();
		}
		if(window->LockLooper())
		{
			window->Quit();
		}
	}

	fPreferences->Save(fPreferencesFile.Path());
	delete fPreferences;
}

void
App::Init()
{
	BPath settingsPath;
	find_directory(B_USER_SETTINGS_DIRECTORY, &settingsPath);
	settingsPath.Append(gAppName);
	BDirectory preferencesDir(settingsPath.Path());
	if(preferencesDir.InitCheck() == B_ENTRY_NOT_FOUND) {
		preferencesDir.CreateDirectory(settingsPath.Path(), &preferencesDir);
	}

	fPreferencesFile.SetTo(&preferencesDir, "settings");
	fPreferences = new Preferences();
	fPreferences->Load(fPreferencesFile.Path());
	fPreferences->fSettingsPath = settingsPath;
	EditorWindow::SetPreferences(fPreferences);

	Languages::LoadLanguages();
}

void
App::AboutRequested()
{
	const char* specialThanks[] = {
		B_TRANSLATE("Neil Hodgson, for Scintilla editing component and SciTE editor."),
		nullptr
	};

	BAboutWindow* window = new BAboutWindow(gAppName, gAppMime);
	window->AddCopyright(2016, "Kacper Kasper");
	window->AddDescription(
		B_TRANSLATE("Code editor for Haiku based on Scintilla editing component."));
	window->AddSpecialThanks(specialThanks);
	window->AddExtraInfo(B_TRANSLATE("Distributed on MIT license terms."));
	window->Show();
}

bool
App::QuitRequested()
{
	BObjectList<EditorWindow> unsaved;
	std::vector<std::string> unsavedPaths;
	EditorWindow* current;
	for(int i = 0; current = fWindows.ItemAt(i); ++i) {
		if(current->IsModified()) {
			unsaved.AddItem(current);
			unsavedPaths.push_back(std::string(current->OpenedFilePath()));
		}
	}
	if(unsaved.IsEmpty()) {
		return true;
	}
	QuitAlert* quitAlert = new QuitAlert(unsavedPaths);
	auto filesToSave = quitAlert->Go();
	if(filesToSave.empty()) {
		fLastActiveWindow->Activate();
		return false;
	}
	for(int i = 0; current = unsaved.ItemAt(i); ++i) {
		if(filesToSave[i] == false) continue;
		BMessage reply;
		BMessage save(SAVE_FILE);
		BMessenger messenger((BWindow*) current);
		messenger.SendMessage(&save, &reply);
			// FIXME: this is smelly
	}
	return true;
}

void
App::ReadyToRun()
{
	if(CountWindows() == 0) {
		PostMessage(WINDOW_NEW);
	}
}

void
App::ArgvReceived(int32 argc, char** argv)
{
	entry_ref ref;
	BEntry entry;
	for(int32 i = 1; i < argc; ++i) {
		Sci_Position line = -1;
		Sci_Position column = -1;
		BString argument(argv[i]);
		BString filename;
		BString lineStr, columnStr;
		// first :
		int32 pos = argument.FindFirst(':');
		if(pos != B_ERROR) {
			argument.CopyInto(filename, 0, pos);
			// second :
			int32 pos2 = argument.FindFirst(':', pos + 1);
			if(pos2 != B_ERROR) {
				argument.CopyInto(lineStr, pos + 1, pos2);
				argument.CopyInto(columnStr, pos2 + 1, argument.Length());
			} else {
				argument.CopyInto(lineStr, pos + 1, argument.Length());
			}
			line = strtol(lineStr.String(), nullptr, 10) - 1;
			column = strtol(columnStr.String(), nullptr, 10) - 1;
		} else {
			filename = argument;
		}
		entry.SetTo(filename);
		entry.GetRef(&ref);
		EditorWindow* window = new EditorWindow();
		window->OpenFile(&ref, line, column);
		window->Show();
		fWindows.AddItem(window);
	}
}

void
App::RefsReceived(BMessage* message)
{
	int32 count;
	if(message->GetInfo("refs", nullptr, &count) != B_OK) {
		return;
	}
	entry_ref ref;
	for(int32 i = 0; i < count; ++i) {
		if(message->FindRef("refs", i, &ref) == B_OK) {
			Sci_Position line = message->GetInt32("be:line", 0) - 1;
			Sci_Position column = message->GetInt32("be:column", 0) - 1;
			EditorWindow* window = new EditorWindow();
			window->OpenFile(&ref, line, column);
			window->Show();
			fWindows.AddItem(window);
		}
	}
}

void
App::MessageReceived(BMessage* message)
{
	switch(message->what) {
	case ACTIVE_WINDOW_CHANGED: {
		if(message->FindPointer("window", (void**) &fLastActiveWindow) != B_OK) {
			fLastActiveWindow = nullptr;
		}
	} break;
	case APP_PREFERENCES_CHANGED: {
		for(uint32 i = 0, count = fWindows.CountItems(); i < count; i++) {
			BMessenger messenger((BWindow*) fWindows.ItemAt(i));
			messenger.SendMessage(message);
		}
	} break;
	case APP_PREFERENCES_QUITTING: {
		fAppPreferencesWindow = nullptr;
	} break;
	case FINDWINDOW_FIND:
	case FINDWINDOW_REPLACE:
	case FINDWINDOW_REPLACEFIND:
	case FINDWINDOW_REPLACEALL: {
		// TODO: == nullptr should never happen, alert if it somehow does?
		if(fLastActiveWindow != nullptr) {
			BMessenger messenger((BWindow*) fLastActiveWindow);
			messenger.SendMessage(message);
		}
	} break;
	case FINDWINDOW_QUITTING: {
		fFindWindow = nullptr;
	} break;
	case MAINMENU_EDIT_APP_PREFERENCES: {
		if(fAppPreferencesWindow == nullptr) {
			fAppPreferencesWindow = new AppPreferencesWindow(fPreferences);
		}
		fAppPreferencesWindow->Show();
		fAppPreferencesWindow->Activate();
	} break;
	case MAINMENU_SEARCH_FINDREPLACE: {
		if(fFindWindow == nullptr) {
			fFindWindow = new FindWindow();
		}
		fFindWindow->Show();
		fFindWindow->Activate();
	} break;
	case WINDOW_NEW: {
		EditorWindow* window = new EditorWindow();
		window->Show();
		fWindows.AddItem(window);
	} break;
	case WINDOW_CLOSE: {
		EditorWindow* window;
		if(message->FindPointer("window", (void**) &window) == B_OK) {
			fWindows.RemoveItem(window);
		}
		if(fWindows.CountItems() == 0) {
			fPreferences->fWindowRect = window->Frame();
			Quit();
		}
	} break;
	default:
		BApplication::MessageReceived(message);
	break;
	}
}
<|endoftext|>


<commit_before>/* -*- c-basic-offset: 2 -*- */
/* Copyright(C) 2012 Brazil

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License version 2.1 as published by the Free Software Foundation.

  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
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include <groonga/tokenizer.h>

#include <kytea/kytea.h>

#include <string.h>

#include <string>
#include <vector>

namespace {

grn_plugin_mutex *kytea_mutex = NULL;
kytea::KyteaConfig *kytea_config = NULL;
kytea::Kytea *kytea_tagger = NULL;
kytea::StringUtil *kytea_util = NULL;

void kytea_init(grn_ctx *ctx);
void kytea_fin(grn_ctx *ctx);

void kytea_init(grn_ctx *ctx) {
  if ((kytea_mutex != NULL) || (kytea_config != NULL) ||
      (kytea_tagger != NULL) || (kytea_util != NULL)) {
    GRN_PLUGIN_ERROR(ctx, GRN_TOKENIZER_ERROR,
                     "[tokenizer] TokenKytea is already initialized");
    return;
  }

  kytea_mutex = grn_plugin_mutex_create(ctx);
  if (kytea_mutex == NULL) {
    kytea_fin(ctx);
    GRN_PLUGIN_ERROR(ctx, GRN_NO_MEMORY_AVAILABLE,
                     "[tokenizer] grn_plugin_mutex_create() failed");
    return;
  }

  kytea::KyteaConfig * const config = static_cast<kytea::KyteaConfig *>(
      GRN_PLUGIN_MALLOC(ctx, sizeof(kytea::KyteaConfig)));
  if (config != NULL) try {
    new (config) kytea::KyteaConfig;
    kytea_config = config;
    try {
      kytea_config->setDebug(0);
      kytea_config->setOnTraining(false);
      kytea_config->parseRunCommandLine(0, NULL);
    } catch (...) {
      kytea_fin(ctx);
      GRN_PLUGIN_ERROR(ctx, GRN_TOKENIZER_ERROR,
                       "[tokenizer] kytea::KyteaConfig settings failed");
      return;
    }
  } catch (...) {
    GRN_PLUGIN_FREE(ctx, config);
    kytea_fin(ctx);
    GRN_PLUGIN_ERROR(ctx, GRN_TOKENIZER_ERROR,
                     "[tokenizer] kytea::KyteaConfig initialization failed");
    return;
  } else {
    kytea_fin(ctx);
    GRN_PLUGIN_ERROR(ctx, GRN_NO_MEMORY_AVAILABLE,
                     "[tokenizer] memory allocation to kytea::KyteaConfig failed");
    return;
  }

  kytea::Kytea * const tagger = static_cast<kytea::Kytea *>(
      GRN_PLUGIN_MALLOC(ctx, sizeof(kytea::Kytea)));
  if (tagger != NULL) try {
    new (tagger) kytea::Kytea;
    kytea_tagger = tagger;
    try {
      kytea_tagger->readModel(kytea_config->getModelFile().c_str());
    } catch (...) {
      kytea_fin(ctx);
      GRN_PLUGIN_ERROR(ctx, GRN_TOKENIZER_ERROR,
                       "[tokenizer] kytea::Kytea::readModel() failed");
      return;
    }
  } catch (...) {
    GRN_PLUGIN_FREE(ctx, tagger);
    kytea_fin(ctx);
    GRN_PLUGIN_ERROR(ctx, GRN_TOKENIZER_ERROR,
                     "[tokenizer] kytea::Kytea initialization failed");
    return;
  } else {
    kytea_fin(ctx);
    GRN_PLUGIN_ERROR(ctx, GRN_NO_MEMORY_AVAILABLE,
                     "[tokenizer] memory allocation to kytea::Kytea failed");
    return;
  }

  try {
    kytea_util = kytea_tagger->getStringUtil();
  } catch (...) {
    kytea_fin(ctx);
    GRN_PLUGIN_ERROR(ctx, GRN_TOKENIZER_ERROR,
                     "[tokenizer] kytea::Kytea::getStringUtil() failed");
    return;
  }
}

void kytea_fin(grn_ctx *ctx) {
  kytea_util = NULL;

  if (kytea_tagger != NULL) {
    kytea_tagger->~Kytea();
    GRN_PLUGIN_FREE(ctx, kytea_tagger);
    kytea_tagger = NULL;
  }

  if (kytea_config != NULL) {
    kytea_config->~KyteaConfig();
    GRN_PLUGIN_FREE(ctx, kytea_config);
    kytea_config = NULL;
  }

  if (kytea_mutex != NULL) {
    grn_plugin_mutex_destroy(ctx, kytea_mutex);
    kytea_mutex = NULL;
  }
}

struct grn_tokenizer_kytea {
  grn_tokenizer_query *query;
  kytea::KyteaSentence sentence;
  std::vector<std::string> tokens;
  std::size_t id;
  grn_tokenizer_token token;

  grn_tokenizer_kytea() : query(NULL), sentence(), tokens(), id(0), token() {}
  ~grn_tokenizer_kytea() {}
};

void grn_tokenizer_kytea_init(grn_ctx *ctx, grn_tokenizer_kytea *tokenizer) {
  new (tokenizer) grn_tokenizer_kytea;
  grn_tokenizer_token_init(ctx, &tokenizer->token);
}

void grn_tokenizer_kytea_fin(grn_ctx *ctx, grn_tokenizer_kytea *tokenizer) {
  grn_tokenizer_token_fin(ctx, &tokenizer->token);
  if (tokenizer->query != NULL) {
    grn_tokenizer_query_destroy(ctx, tokenizer->query);
  }
  tokenizer->~grn_tokenizer_kytea();
}

grn_obj *grn_kytea_init(grn_ctx *ctx, int num_args, grn_obj **args,
                        grn_user_data *user_data) {
  grn_tokenizer_query * const query =
      grn_tokenizer_query_create(ctx, num_args, args);
  if (query == NULL) {
    return NULL;
  }

  grn_tokenizer_kytea * const tokenizer = static_cast<grn_tokenizer_kytea *>(
      GRN_PLUGIN_MALLOC(ctx, sizeof(grn_tokenizer_kytea)));
  if (!tokenizer) {
    grn_tokenizer_query_destroy(ctx, query);
    GRN_PLUGIN_ERROR(ctx, GRN_NO_MEMORY_AVAILABLE,
                     "[tokenizer] memory allocation to grn_tokenizer_kytea failed");
    return NULL;
  }

  try {
    grn_tokenizer_kytea_init(ctx, tokenizer);
  } catch (...) {
    grn_tokenizer_query_destroy(ctx, query);
    GRN_PLUGIN_ERROR(ctx, GRN_TOKENIZER_ERROR,
                     "[tokenizer] tokenizer initialization failed");
    return NULL;
  }

  tokenizer->query = query;

  grn_obj *normalized_query = query->normalized_query;
  const char *normalized_string;
  unsigned int normalized_string_length;
  grn_string_get_normalized(ctx,
                            normalized_query,
                            &normalized_string,
                            &normalized_string_length,
                            NULL);

  grn_plugin_mutex_lock(ctx, kytea_mutex);
  try {
    const std::string str(normalized_string, normalized_string_length);
    const kytea::KyteaString &surface_str = kytea_util->mapString(str);
    const kytea::KyteaString &normalized_str = kytea_util->normalize(surface_str);
    tokenizer->sentence = kytea::KyteaSentence(surface_str, normalized_str);
    kytea_tagger->calculateWS(tokenizer->sentence);
  } catch (...) {
    grn_plugin_mutex_unlock(ctx, kytea_mutex);
    GRN_PLUGIN_ERROR(ctx, GRN_TOKENIZER_ERROR,
                     "[tokenizer] tokenization failed");
    return NULL;
  }
  grn_plugin_mutex_unlock(ctx, kytea_mutex);

  try {
    for (std::size_t i = 0; i < tokenizer->sentence.words.size(); ++i) {
      const std::string &token =
          kytea_util->showString(tokenizer->sentence.words[i].surface);
      const char *ptr = token.c_str();
      unsigned int left = static_cast<unsigned int>(token.length());
      while (left > 0) {
        const int char_length =
            grn_tokenizer_charlen(ctx, ptr, left, query->encoding);
        if ((char_length == 0) ||
            (grn_tokenizer_isspace(ctx, ptr, left, query->encoding) != 0)) {
          break;
        }
        ptr += char_length;
        left -= char_length;
      }
      if (left == 0) {
        tokenizer->tokens.push_back(token);
      }
    }
  } catch (...) {
    GRN_PLUGIN_ERROR(ctx, GRN_TOKENIZER_ERROR,
                     "[tokenizer] adjustment failed");
    return NULL;
  }

  user_data->ptr = tokenizer;
  return NULL;
}

grn_obj *grn_kytea_next(grn_ctx *ctx, int num_args, grn_obj **args,
                        grn_user_data *user_data) {
  grn_tokenizer_kytea * const tokenizer =
      static_cast<grn_tokenizer_kytea *>(user_data->ptr);
  const grn_tokenizer_status status =
      ((tokenizer->id + 1) < tokenizer->tokens.size()) ?
          GRN_TOKENIZER_CONTINUE : GRN_TOKENIZER_LAST;
  if (tokenizer->id < tokenizer->tokens.size()) {
    const std::string &token = tokenizer->tokens[tokenizer->id++];
    grn_tokenizer_token_push(ctx, &tokenizer->token,
                             token.c_str(), token.length(), status);
  } else {
    grn_tokenizer_token_push(ctx, &tokenizer->token, "", 0, status);
  }
  return NULL;
}

grn_obj *grn_kytea_fin(grn_ctx *ctx, int num_args, grn_obj **args,
                       grn_user_data *user_data) {
  grn_tokenizer_kytea * const tokenizer =
      static_cast<grn_tokenizer_kytea *>(user_data->ptr);
  if (tokenizer != NULL) {
    grn_tokenizer_kytea_fin(ctx, tokenizer);
    GRN_PLUGIN_FREE(ctx, tokenizer);
  }
  return NULL;
}

}  // namespace

extern "C" {

/*
  GRN_PLUGIN_INIT() is called to initialize this plugin. Note that an error
  code must be set in `ctx->rc' on failure.
 */
grn_rc GRN_PLUGIN_INIT(grn_ctx *ctx) {
  kytea_init(ctx);
  return ctx->rc;
}

/*
  GRN_PLUGIN_REGISTER() registers this plugin to the database associated with
  `ctx'. The registration requires the plugin name and the functions to be
  called for tokenization.
 */
grn_rc GRN_PLUGIN_REGISTER(grn_ctx *ctx) {
  return grn_tokenizer_register(ctx, "TokenKytea", 10, grn_kytea_init,
                                grn_kytea_next, grn_kytea_fin);
}

/*
  GRN_PLUGIN_FIN() is called to finalize the plugin that was initialized by
  GRN_PLUGIN_INIT().
 */
grn_rc GRN_PLUGIN_FIN(grn_ctx *ctx) {
  kytea_fin(ctx);
  return GRN_SUCCESS;
}

}  // extern "C"
<commit_msg>kytea: support tokenized delimiter<commit_after>/* -*- c-basic-offset: 2 -*- */
/* Copyright(C) 2012 Brazil

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License version 2.1 as published by the Free Software Foundation.

  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
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include <groonga/tokenizer.h>

#include <kytea/kytea.h>

#include <string.h>

#include <string>
#include <vector>

namespace {

grn_plugin_mutex *kytea_mutex = NULL;
kytea::KyteaConfig *kytea_config = NULL;
kytea::Kytea *kytea_tagger = NULL;
kytea::StringUtil *kytea_util = NULL;

void kytea_init(grn_ctx *ctx);
void kytea_fin(grn_ctx *ctx);

void kytea_init(grn_ctx *ctx) {
  if ((kytea_mutex != NULL) || (kytea_config != NULL) ||
      (kytea_tagger != NULL) || (kytea_util != NULL)) {
    GRN_PLUGIN_ERROR(ctx, GRN_TOKENIZER_ERROR,
                     "[tokenizer] TokenKytea is already initialized");
    return;
  }

  kytea_mutex = grn_plugin_mutex_create(ctx);
  if (kytea_mutex == NULL) {
    kytea_fin(ctx);
    GRN_PLUGIN_ERROR(ctx, GRN_NO_MEMORY_AVAILABLE,
                     "[tokenizer] grn_plugin_mutex_create() failed");
    return;
  }

  kytea::KyteaConfig * const config = static_cast<kytea::KyteaConfig *>(
      GRN_PLUGIN_MALLOC(ctx, sizeof(kytea::KyteaConfig)));
  if (config != NULL) try {
    new (config) kytea::KyteaConfig;
    kytea_config = config;
    try {
      kytea_config->setDebug(0);
      kytea_config->setOnTraining(false);
      kytea_config->parseRunCommandLine(0, NULL);
    } catch (...) {
      kytea_fin(ctx);
      GRN_PLUGIN_ERROR(ctx, GRN_TOKENIZER_ERROR,
                       "[tokenizer] kytea::KyteaConfig settings failed");
      return;
    }
  } catch (...) {
    GRN_PLUGIN_FREE(ctx, config);
    kytea_fin(ctx);
    GRN_PLUGIN_ERROR(ctx, GRN_TOKENIZER_ERROR,
                     "[tokenizer] kytea::KyteaConfig initialization failed");
    return;
  } else {
    kytea_fin(ctx);
    GRN_PLUGIN_ERROR(ctx, GRN_NO_MEMORY_AVAILABLE,
                     "[tokenizer] memory allocation to kytea::KyteaConfig failed");
    return;
  }

  kytea::Kytea * const tagger = static_cast<kytea::Kytea *>(
      GRN_PLUGIN_MALLOC(ctx, sizeof(kytea::Kytea)));
  if (tagger != NULL) try {
    new (tagger) kytea::Kytea;
    kytea_tagger = tagger;
    try {
      kytea_tagger->readModel(kytea_config->getModelFile().c_str());
    } catch (...) {
      kytea_fin(ctx);
      GRN_PLUGIN_ERROR(ctx, GRN_TOKENIZER_ERROR,
                       "[tokenizer] kytea::Kytea::readModel() failed");
      return;
    }
  } catch (...) {
    GRN_PLUGIN_FREE(ctx, tagger);
    kytea_fin(ctx);
    GRN_PLUGIN_ERROR(ctx, GRN_TOKENIZER_ERROR,
                     "[tokenizer] kytea::Kytea initialization failed");
    return;
  } else {
    kytea_fin(ctx);
    GRN_PLUGIN_ERROR(ctx, GRN_NO_MEMORY_AVAILABLE,
                     "[tokenizer] memory allocation to kytea::Kytea failed");
    return;
  }

  try {
    kytea_util = kytea_tagger->getStringUtil();
  } catch (...) {
    kytea_fin(ctx);
    GRN_PLUGIN_ERROR(ctx, GRN_TOKENIZER_ERROR,
                     "[tokenizer] kytea::Kytea::getStringUtil() failed");
    return;
  }
}

void kytea_fin(grn_ctx *ctx) {
  kytea_util = NULL;

  if (kytea_tagger != NULL) {
    kytea_tagger->~Kytea();
    GRN_PLUGIN_FREE(ctx, kytea_tagger);
    kytea_tagger = NULL;
  }

  if (kytea_config != NULL) {
    kytea_config->~KyteaConfig();
    GRN_PLUGIN_FREE(ctx, kytea_config);
    kytea_config = NULL;
  }

  if (kytea_mutex != NULL) {
    grn_plugin_mutex_destroy(ctx, kytea_mutex);
    kytea_mutex = NULL;
  }
}

struct grn_tokenizer_kytea {
  grn_tokenizer_query *query;
  kytea::KyteaSentence sentence;
  std::vector<std::string> tokens;
  std::size_t id;
  grn_tokenizer_token token;
  bool have_tokenized_delimiter;
  const char *rest_query_string;
  unsigned int rest_query_string_length;

  grn_tokenizer_kytea() :
    query(NULL),
    sentence(),
    tokens(),
    id(0),
    token(),
    have_tokenized_delimiter(false),
    rest_query_string(NULL)
  {
  }
  ~grn_tokenizer_kytea() {}
};

void grn_tokenizer_kytea_init(grn_ctx *ctx, grn_tokenizer_kytea *tokenizer) {
  new (tokenizer) grn_tokenizer_kytea;
  grn_tokenizer_token_init(ctx, &tokenizer->token);
}

void grn_tokenizer_kytea_fin(grn_ctx *ctx, grn_tokenizer_kytea *tokenizer) {
  grn_tokenizer_token_fin(ctx, &tokenizer->token);
  if (tokenizer->query != NULL) {
    grn_tokenizer_query_destroy(ctx, tokenizer->query);
  }
  tokenizer->~grn_tokenizer_kytea();
}

grn_obj *grn_kytea_init(grn_ctx *ctx, int num_args, grn_obj **args,
                        grn_user_data *user_data) {
  grn_tokenizer_query * const query =
      grn_tokenizer_query_create(ctx, num_args, args);
  if (query == NULL) {
    return NULL;
  }

  grn_tokenizer_kytea * const tokenizer = static_cast<grn_tokenizer_kytea *>(
      GRN_PLUGIN_MALLOC(ctx, sizeof(grn_tokenizer_kytea)));
  if (!tokenizer) {
    grn_tokenizer_query_destroy(ctx, query);
    GRN_PLUGIN_ERROR(ctx, GRN_NO_MEMORY_AVAILABLE,
                     "[tokenizer] memory allocation to grn_tokenizer_kytea failed");
    return NULL;
  }

  try {
    grn_tokenizer_kytea_init(ctx, tokenizer);
  } catch (...) {
    grn_tokenizer_query_destroy(ctx, query);
    GRN_PLUGIN_ERROR(ctx, GRN_TOKENIZER_ERROR,
                     "[tokenizer] tokenizer initialization failed");
    return NULL;
  }

  tokenizer->query = query;

  grn_obj *normalized_query = query->normalized_query;
  const char *normalized_string;
  unsigned int normalized_string_length;
  grn_string_get_normalized(ctx,
                            normalized_query,
                            &normalized_string,
                            &normalized_string_length,
                            NULL);
  tokenizer->have_tokenized_delimiter =
    grn_tokenizer_have_tokenized_delimiter(ctx,
                                           normalized_string,
                                           normalized_string_length,
                                           query->encoding);

  if (tokenizer->have_tokenized_delimiter) {
    tokenizer->rest_query_string = normalized_string;
    tokenizer->rest_query_string_length = normalized_string_length;
  } else {
  grn_plugin_mutex_lock(ctx, kytea_mutex);
  try {
    const std::string str(normalized_string, normalized_string_length);
    const kytea::KyteaString &surface_str = kytea_util->mapString(str);
    const kytea::KyteaString &normalized_str = kytea_util->normalize(surface_str);
    tokenizer->sentence = kytea::KyteaSentence(surface_str, normalized_str);
    kytea_tagger->calculateWS(tokenizer->sentence);
  } catch (...) {
    grn_plugin_mutex_unlock(ctx, kytea_mutex);
    GRN_PLUGIN_ERROR(ctx, GRN_TOKENIZER_ERROR,
                     "[tokenizer] tokenization failed");
    return NULL;
  }
  grn_plugin_mutex_unlock(ctx, kytea_mutex);

  try {
    for (std::size_t i = 0; i < tokenizer->sentence.words.size(); ++i) {
      const std::string &token =
          kytea_util->showString(tokenizer->sentence.words[i].surface);
      const char *ptr = token.c_str();
      unsigned int left = static_cast<unsigned int>(token.length());
      while (left > 0) {
        const int char_length =
            grn_tokenizer_charlen(ctx, ptr, left, query->encoding);
        if ((char_length == 0) ||
            (grn_tokenizer_isspace(ctx, ptr, left, query->encoding) != 0)) {
          break;
        }
        ptr += char_length;
        left -= char_length;
      }
      if (left == 0) {
        tokenizer->tokens.push_back(token);
      }
    }
  } catch (...) {
    GRN_PLUGIN_ERROR(ctx, GRN_TOKENIZER_ERROR,
                     "[tokenizer] adjustment failed");
    return NULL;
  }
  }

  user_data->ptr = tokenizer;
  return NULL;
}

grn_obj *grn_kytea_next(grn_ctx *ctx, int num_args, grn_obj **args,
                        grn_user_data *user_data) {
  grn_tokenizer_kytea * const tokenizer =
      static_cast<grn_tokenizer_kytea *>(user_data->ptr);

  if (tokenizer->have_tokenized_delimiter) {
    unsigned int rest_query_string_length =
      tokenizer->rest_query_string_length;
    const char *rest_query_string =
      grn_tokenizer_tokenized_delimiter_next(ctx,
                                             &(tokenizer->token),
                                             tokenizer->rest_query_string,
                                             rest_query_string_length,
                                             tokenizer->query->encoding);
    if (rest_query_string) {
      tokenizer->rest_query_string_length -=
        rerest_query_string - tokenizer->rest_query_string;
    }
    tokenizer->rest_query_string = rest_query_string;
  } else {
  const grn_tokenizer_status status =
      ((tokenizer->id + 1) < tokenizer->tokens.size()) ?
          GRN_TOKENIZER_CONTINUE : GRN_TOKENIZER_LAST;
  if (tokenizer->id < tokenizer->tokens.size()) {
    const std::string &token = tokenizer->tokens[tokenizer->id++];
    grn_tokenizer_token_push(ctx, &tokenizer->token,
                             token.c_str(), token.length(), status);
  } else {
    grn_tokenizer_token_push(ctx, &tokenizer->token, "", 0, status);
  }
  }

  return NULL;
}

grn_obj *grn_kytea_fin(grn_ctx *ctx, int num_args, grn_obj **args,
                       grn_user_data *user_data) {
  grn_tokenizer_kytea * const tokenizer =
      static_cast<grn_tokenizer_kytea *>(user_data->ptr);
  if (tokenizer != NULL) {
    grn_tokenizer_kytea_fin(ctx, tokenizer);
    GRN_PLUGIN_FREE(ctx, tokenizer);
  }
  return NULL;
}

}  // namespace

extern "C" {

/*
  GRN_PLUGIN_INIT() is called to initialize this plugin. Note that an error
  code must be set in `ctx->rc' on failure.
 */
grn_rc GRN_PLUGIN_INIT(grn_ctx *ctx) {
  kytea_init(ctx);
  return ctx->rc;
}

/*
  GRN_PLUGIN_REGISTER() registers this plugin to the database associated with
  `ctx'. The registration requires the plugin name and the functions to be
  called for tokenization.
 */
grn_rc GRN_PLUGIN_REGISTER(grn_ctx *ctx) {
  return grn_tokenizer_register(ctx, "TokenKytea", 10, grn_kytea_init,
                                grn_kytea_next, grn_kytea_fin);
}

/*
  GRN_PLUGIN_FIN() is called to finalize the plugin that was initialized by
  GRN_PLUGIN_INIT().
 */
grn_rc GRN_PLUGIN_FIN(grn_ctx *ctx) {
  kytea_fin(ctx);
  return GRN_SUCCESS;
}

}  // extern "C"
<|endoftext|>


<commit_before>/** \copyright
 * Copyright (c) 2015, Balazs Racz
 * 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.
 *
 * 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 HOLDER 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.
 *
 * \file ConfigEntry.hxx
 *
 * Configuration option reader classes.
 *
 * @author Balazs Racz
 * @date 31 May 2015
 */

#ifndef _NMRANET_CONFIGENTRY_HXX_
#define _NMRANET_CONFIGENTRY_HXX_

#include <sys/types.h>
#include <stdint.h>
#include <endian.h>

#include "nmranet/ConfigRenderer.hxx"

namespace nmranet
{

/// Class representing a particular location in the configuration space. All
/// typed configuration objects (atoms as well as groups) will be subclasses of
/// this.
class ConfigReference
{
public:
    /// Initializes the config reference from a configuration space offset.
    ///
    /// @param offset is the integer offset (0-based) in the address space for
    /// configuration.
    constexpr explicit ConfigReference(unsigned offset)
        : offset_(offset)
    {
    }

    /// Initializes the config reference from an existing config reference.
    ///
    /// @param ref is the existing (or saved) config reference.
    constexpr explicit ConfigReference(const ConfigReference &ref)
        : offset_(ref.offset())
    {
    }

    constexpr unsigned offset() const
    {
        return offset_;
    }

protected:
    /// zero-based offset from the beginning of the configuration file.
    unsigned offset_;
};

///
/// Base class for individual configuration entries. Defines helper methods for
/// reading and writing.
///
class ConfigEntryBase : public ConfigReference
{
public:
    INHERIT_CONSTEXPR_CONSTRUCTOR(ConfigEntryBase, ConfigReference)

    static constexpr GroupConfigOptions group_opts()
    {
        return GroupConfigOptions();
    }

protected:
    /// Reads a given typed variable from the configuration file. DOes not do
    /// any binary conversion (only reads raw data).
    ///
    /// @param fd file to read data from.
    ///
    /// @return the raw value read from the configuration file.
    ///
    template <class T> T raw_read(int fd) const
    {
        T ret;
        repeated_read(fd, &ret, sizeof(T));
        return ret;
    }

    /// Writes a given typed variable to the configuration file. Does not do
    /// any binary conversion.
    ///
    /// @param fd file to write data to.
    ///
    /// @param value the raw value to write to the configuration file.
    ///
    template <class T> void raw_write(int fd, const T &value) const
    {
        repeated_write(fd, &value, sizeof(T));
    }

    /// Performs a reliable read from the given FD. Crashes if the read fails.
    ///
    /// @param fd the file to read data from
    /// @param buf the location to write data to
    /// @param size how many bytes to read
    ///
    void repeated_read(int fd, void *buf, size_t size) const;

    /// Performs a reliable write to the given FD. Crashes if the write fails.
    ///
    /// @param fd the file to write data to
    /// @param buf the location of the data to write
    /// @param size how many bytes to write
    ///
    void repeated_write(int fd, const void *buf, size_t size) const;
};

/// Implementation class for numeric configuration entries, templated by the
/// integer type.
template <class TR> class NumericConfigEntry : public ConfigEntryBase
{
public:
    INHERIT_CONSTEXPR_CONSTRUCTOR(NumericConfigEntry, ConfigEntryBase)

    /// Performs endian conversion.
    ///
    /// @param d network-byte-order data
    ///
    /// @return host-byte-order data
    ///
    static uint8_t endian_convert(uint8_t d)
    {
        return d;
    }
    /// Performs endian conversion.
    ///
    /// @param d network-byte-order data
    ///
    /// @return host-byte-order data
    ///
    static uint16_t endian_convert(uint16_t d)
    {
        return be16toh(d);
    }
    /// Performs endian conversion.
    ///
    /// @param d network-byte-order data
    ///
    /// @return host-byte-order data
    ///
    static uint32_t endian_convert(uint32_t d)
    {
        return be32toh(d);
    }
    /// Performs endian conversion.
    ///
    /// @param d network-byte-order data
    ///
    /// @return host-byte-order data
    ///
    static uint64_t endian_convert(uint64_t d)
    {
        return be64toh(d);
    }

    /// Storage bytes occupied by the instance in the config file.
    ///
    /// @return number of bytes that the config parser offset will be
    /// incremented by this entry.
    ///
    static constexpr unsigned size()
    {
        return sizeof(TR);
    }

    constexpr unsigned end_offset()
    {
        return offset() + size();
    }

    constexpr AtomConfigRenderer config_renderer() const
    {
        return AtomConfigRenderer("int", size());
    }

    /// Reads the data from the configuration file.
    ///
    /// @param fd file descriptor of the config file.
    ///
    /// @return value of the configuration atom that *this represents.
    ///
    TR read(int fd) const
    {
        return endian_convert(raw_read<TR>(fd));
    }

    /// Writes the data to the configuration file.
    ///
    /// @param fd file descriptor of the config file.
    ///
    /// @param value of the configuration atom that should be written.
    ///
    void write(int fd, TR d) const
    {
        raw_write(fd, endian_convert(d));
    }
};

using Uint8ConfigEntry = NumericConfigEntry<uint8_t>;
using Uint16ConfigEntry = NumericConfigEntry<uint16_t>;
using Uint32ConfigEntry = NumericConfigEntry<uint32_t>;
using Uint64ConfigEntry = NumericConfigEntry<uint64_t>;

/// Implementation class for event ID configuration entries.
class EventConfigEntry : public Uint64ConfigEntry
{
public:
    template <typename T>
    constexpr EventConfigEntry(T t)
        : Uint64ConfigEntry(t)
    {
    }

    constexpr AtomConfigRenderer config_renderer() const
    {
        return AtomConfigRenderer("eventid", AtomConfigRenderer::SKIP_SIZE);
    }
};

/// Implementation class for string configuration entries. The template
/// argument is the string size (total space in bytes used in the configuration
/// space including the NULL character).
template <unsigned SIZE> class StringConfigEntry : public ConfigEntryBase
{
public:
    INHERIT_CONSTEXPR_CONSTRUCTOR(StringConfigEntry, ConfigEntryBase)

    /// Storage bytes occupied by the instance in the config file.
    ///
    /// @return number of bytes that the config parser offset will be
    /// incremented by this entry.
    ///
    static constexpr unsigned size()
    {
        return SIZE;
    }

    static constexpr unsigned end_offset()
    {
        return offset() + size();
    }

    constexpr AtomConfigRenderer config_renderer() const
    {
        return AtomConfigRenderer("string", size());
    }

    string read(int fd) const
    {
        string s(size(), '\0');
        repeated_read(fd, &s[0], size());
        size_t real_len = strlen(s.c_str());
        s.resize(real_len);
        return s;
    }
};

} // namespace nmranet

#endif // _NMRANET_CONFIGENTRY_HXX_
<commit_msg>Makes the renderers static members.<commit_after>/** \copyright
 * Copyright (c) 2015, Balazs Racz
 * 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.
 *
 * 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 HOLDER 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.
 *
 * \file ConfigEntry.hxx
 *
 * Configuration option reader classes.
 *
 * @author Balazs Racz
 * @date 31 May 2015
 */

#ifndef _NMRANET_CONFIGENTRY_HXX_
#define _NMRANET_CONFIGENTRY_HXX_

#include <sys/types.h>
#include <stdint.h>
#include <endian.h>

#include "nmranet/ConfigRenderer.hxx"

namespace nmranet
{

/// Class representing a particular location in the configuration space. All
/// typed configuration objects (atoms as well as groups) will be subclasses of
/// this.
class ConfigReference
{
public:
    /// Initializes the config reference from a configuration space offset.
    ///
    /// @param offset is the integer offset (0-based) in the address space for
    /// configuration.
    constexpr explicit ConfigReference(unsigned offset)
        : offset_(offset)
    {
    }

    /// Initializes the config reference from an existing config reference.
    ///
    /// @param ref is the existing (or saved) config reference.
    constexpr explicit ConfigReference(const ConfigReference &ref)
        : offset_(ref.offset())
    {
    }

    constexpr unsigned offset() const
    {
        return offset_;
    }

protected:
    /// zero-based offset from the beginning of the configuration file.
    unsigned offset_;
};

///
/// Base class for individual configuration entries. Defines helper methods for
/// reading and writing.
///
class ConfigEntryBase : public ConfigReference
{
public:
    INHERIT_CONSTEXPR_CONSTRUCTOR(ConfigEntryBase, ConfigReference)

    static constexpr GroupConfigOptions group_opts()
    {
        return GroupConfigOptions();
    }

protected:
    /// Reads a given typed variable from the configuration file. DOes not do
    /// any binary conversion (only reads raw data).
    ///
    /// @param fd file to read data from.
    ///
    /// @return the raw value read from the configuration file.
    ///
    template <class T> T raw_read(int fd) const
    {
        T ret;
        repeated_read(fd, &ret, sizeof(T));
        return ret;
    }

    /// Writes a given typed variable to the configuration file. Does not do
    /// any binary conversion.
    ///
    /// @param fd file to write data to.
    ///
    /// @param value the raw value to write to the configuration file.
    ///
    template <class T> void raw_write(int fd, const T &value) const
    {
        repeated_write(fd, &value, sizeof(T));
    }

    /// Performs a reliable read from the given FD. Crashes if the read fails.
    ///
    /// @param fd the file to read data from
    /// @param buf the location to write data to
    /// @param size how many bytes to read
    ///
    void repeated_read(int fd, void *buf, size_t size) const;

    /// Performs a reliable write to the given FD. Crashes if the write fails.
    ///
    /// @param fd the file to write data to
    /// @param buf the location of the data to write
    /// @param size how many bytes to write
    ///
    void repeated_write(int fd, const void *buf, size_t size) const;
};

/// Implementation class for numeric configuration entries, templated by the
/// integer type.
template <class TR> class NumericConfigEntry : public ConfigEntryBase
{
public:
    INHERIT_CONSTEXPR_CONSTRUCTOR(NumericConfigEntry, ConfigEntryBase)

    /// Performs endian conversion.
    ///
    /// @param d network-byte-order data
    ///
    /// @return host-byte-order data
    ///
    static uint8_t endian_convert(uint8_t d)
    {
        return d;
    }
    /// Performs endian conversion.
    ///
    /// @param d network-byte-order data
    ///
    /// @return host-byte-order data
    ///
    static uint16_t endian_convert(uint16_t d)
    {
        return be16toh(d);
    }
    /// Performs endian conversion.
    ///
    /// @param d network-byte-order data
    ///
    /// @return host-byte-order data
    ///
    static uint32_t endian_convert(uint32_t d)
    {
        return be32toh(d);
    }
    /// Performs endian conversion.
    ///
    /// @param d network-byte-order data
    ///
    /// @return host-byte-order data
    ///
    static uint64_t endian_convert(uint64_t d)
    {
        return be64toh(d);
    }

    /// Storage bytes occupied by the instance in the config file.
    ///
    /// @return number of bytes that the config parser offset will be
    /// incremented by this entry.
    ///
    static constexpr unsigned size()
    {
        return sizeof(TR);
    }

    constexpr unsigned end_offset()
    {
        return offset() + size();
    }

    static constexpr AtomConfigRenderer config_renderer()
    {
        return AtomConfigRenderer("int", size());
    }

    /// Reads the data from the configuration file.
    ///
    /// @param fd file descriptor of the config file.
    ///
    /// @return value of the configuration atom that *this represents.
    ///
    TR read(int fd) const
    {
        return endian_convert(raw_read<TR>(fd));
    }

    /// Writes the data to the configuration file.
    ///
    /// @param fd file descriptor of the config file.
    ///
    /// @param value of the configuration atom that should be written.
    ///
    void write(int fd, TR d) const
    {
        raw_write(fd, endian_convert(d));
    }
};

using Uint8ConfigEntry = NumericConfigEntry<uint8_t>;
using Uint16ConfigEntry = NumericConfigEntry<uint16_t>;
using Uint32ConfigEntry = NumericConfigEntry<uint32_t>;
using Uint64ConfigEntry = NumericConfigEntry<uint64_t>;

/// Implementation class for event ID configuration entries.
class EventConfigEntry : public Uint64ConfigEntry
{
public:
    template <typename T>
    constexpr EventConfigEntry(T t)
        : Uint64ConfigEntry(t)
    {
    }

    static constexpr AtomConfigRenderer config_renderer()
    {
        return AtomConfigRenderer("eventid", AtomConfigRenderer::SKIP_SIZE);
    }
};

/// Implementation class for string configuration entries. The template
/// argument is the string size (total space in bytes used in the configuration
/// space including the NULL character).
template <unsigned SIZE> class StringConfigEntry : public ConfigEntryBase
{
public:
    INHERIT_CONSTEXPR_CONSTRUCTOR(StringConfigEntry, ConfigEntryBase)

    /// Storage bytes occupied by the instance in the config file.
    ///
    /// @return number of bytes that the config parser offset will be
    /// incremented by this entry.
    ///
    static constexpr unsigned size()
    {
        return SIZE;
    }

    static constexpr unsigned end_offset()
    {
        return offset() + size();
    }

    static constexpr AtomConfigRenderer config_renderer()
    {
        return AtomConfigRenderer("string", size());
    }

    string read(int fd) const
    {
        string s(size(), '\0');
        repeated_read(fd, &s[0], size());
        size_t real_len = strlen(s.c_str());
        s.resize(real_len);
        return s;
    }
};

} // namespace nmranet

#endif // _NMRANET_CONFIGENTRY_HXX_
<|endoftext|>


<commit_before>#include "tgbot/Bot.h"

#include "tgbot/EventBroadcaster.h"

#if __cplusplus < 201402L
namespace std {
    template<class T> struct _Unique_if {
        typedef unique_ptr<T> _Single_object;
    };

    template<class T> struct _Unique_if<T[]> {
        typedef unique_ptr<T[]> _Unknown_bound;
    };

    template<class T, size_t N> struct _Unique_if<T[N]> {
        typedef void _Known_bound;
    };

    template<class T, class... Args>
        typename _Unique_if<T>::_Single_object
        make_unique(Args&&... args) {
            return unique_ptr<T>(new T(std::forward<Args>(args)...));
        }

    template<class T>
        typename _Unique_if<T>::_Unknown_bound
        make_unique(size_t n) {
            typedef typename remove_extent<T>::type U;
            return unique_ptr<T>(new U[n]());
        }

    template<class T, class... Args>
        typename _Unique_if<T>::_Known_bound
        make_unique(Args&&...) = delete;
}
#endif

namespace TgBot {

Bot::Bot(std::string token, const HttpClient& httpClient)
    : _token(std::move(token))
    , _api(_token, httpClient)
    , _eventBroadcaster(std::make_unique<EventBroadcaster>())
    , _eventHandler(getEvents()) {
}

}
<commit_msg>Fix build error in versions below MSVC 12.0<commit_after>#include "tgbot/Bot.h"

#include "tgbot/EventBroadcaster.h"

#if __cplusplus == 201103L
namespace std {
    template<typename T>
    inline std::unique_ptr<T> make_unique() {
        return std::unique_ptr<T>(new T());
    }
}
#endif

namespace TgBot {

Bot::Bot(std::string token, const HttpClient& httpClient)
    : _token(std::move(token))
    , _api(_token, httpClient)
    , _eventBroadcaster(std::make_unique<EventBroadcaster>())
    , _eventHandler(getEvents()) {
}

}
<|endoftext|>