<commit_before>// Copyright (C) 2016 Elviss Strazdins
// This file is part of the Ouzel engine.

#include <algorithm>
#include "Engine.h"
#include "CompileConfig.h"
#include "Cache.h"
#include "localization/Localization.h"
#include "utils/Utils.h"
#include "graphics/Renderer.h"
#include "audio/Audio.h"
#include "scene/SceneManager.h"
#include "events/EventDispatcher.h"

#if OUZEL_PLATFORM_MACOS
#include "macos/WindowMacOS.h"
#include "macos/RendererOGLMacOS.h"
#elif OUZEL_PLATFORM_IOS
#include "ios/WindowIOS.h"
#include "ios/RendererOGLIOS.h"
#elif OUZEL_PLATFORM_TVOS
#include "tvos/WindowTVOS.h"
#include "tvos/RendererOGLTVOS.h"
#elif OUZEL_PLATFORM_ANDROID
#include "android/WindowAndroid.h"
#include "android/InputAndroid.h"
#elif OUZEL_PLATFORM_LINUX
#include "linux/WindowLinux.h"
#include "linux/RendererOGLLinux.h"
#include "linux/InputLinux.h"
#elif OUZEL_PLATFORM_WINDOWS
#include "win/WindowWin.h"
#elif OUZEL_PLATFORM_RASPBIAN
#include "rpi/WindowRPI.h"
#include "rpi/RendererOGLRPI.h"
#include "rpi/InputRPI.h"
#endif

#if OUZEL_SUPPORTS_OPENGL || OUZEL_SUPPORTS_OPENGLES
#include "opengl/RendererOGL.h"
#endif

#if OUZEL_SUPPORTS_DIRECT3D11
#include "direct3d11/RendererD3D11.h"
#endif

#if OUZEL_SUPPORTS_METAL
#include "metal/RendererMetal.h"
#endif

#if OUZEL_SUPPORTS_OPENAL
#include "openal/AudioAL.h"
#endif

#if OUZEL_SUPPORTS_XAUDIO2
#include "xaudio2/AudioXA2.h"
#endif

#if OUZEL_SUPPORTS_OPENSL
#include "opensl/AudioSL.h"
#endif

#if OUZEL_PLATFORM_MACOS || OUZEL_PLATFORM_IOS || OUZEL_PLATFORM_TVOS
#include "apple/AudioALApple.h"
#include "apple/InputApple.h"
#elif OUZEL_PLATFORM_WINDOWS
#include "win/InputWin.h"
#endif

#ifdef OPENAL
#undef OPENAL
#endif

namespace ouzel
{
    ouzel::Engine* sharedEngine = nullptr;

    Engine::Engine():
        currentFPS(0.0f), accumulatedFPS(0.0f), running(false), active(true)
    {
        sharedEngine = this;
    }

    Engine::~Engine()
    {
        running = false;
        active = false;

        if (updateThread.joinable()) updateThread.join();
        sceneManager->setScene(nullptr);
    }

    std::set<graphics::Renderer::Driver> Engine::getAvailableRenderDrivers()
    {
        static std::set<graphics::Renderer::Driver> availableDrivers;

        if (availableDrivers.empty())
        {
#if OUZEL_SUPPORTS_OPENGL || OUZEL_SUPPORTS_OPENGLES
            availableDrivers.insert(graphics::Renderer::Driver::OPENGL);
#endif

#if OUZEL_SUPPORTS_DIRECT3D11
            availableDrivers.insert(graphics::Renderer::Driver::DIRECT3D11);
#endif

#if OUZEL_SUPPORTS_METAL
            if (graphics::RendererMetal::available())
            {
                availableDrivers.insert(graphics::Renderer::Driver::METAL);
            }
#endif
        }

        return availableDrivers;
    }

    std::set<audio::Audio::Driver> Engine::getAvailableAudioDrivers()
    {
        static std::set<audio::Audio::Driver> availableDrivers;

        if (availableDrivers.empty())
        {
#if OUZEL_SUPPORTS_OPENAL
            availableDrivers.insert(audio::Audio::Driver::OPENAL);
#endif

#if OUZEL_SUPPORTS_XAUDIO2
            availableDrivers.insert(audio::Audio::Driver::XAUDIO2);
#endif

#if OUZEL_SUPPORTS_OPENSL
            availableDrivers.insert(audio::Audio::Driver::OPENSL);
#endif
        }

        return availableDrivers;
    }

    bool Engine::init(Settings& newSettings, const std::function<void(void)>& beginCallback)
    {
        settings = newSettings;

        if (settings.renderDriver == graphics::Renderer::Driver::DEFAULT)
        {
            auto availableDrivers = getAvailableRenderDrivers();

            if (availableDrivers.find(graphics::Renderer::Driver::METAL) != availableDrivers.end())
            {
                settings.renderDriver = graphics::Renderer::Driver::METAL;
            }
            else if (availableDrivers.find(graphics::Renderer::Driver::DIRECT3D11) != availableDrivers.end())
            {
                settings.renderDriver = graphics::Renderer::Driver::DIRECT3D11;
            }
            else if (availableDrivers.find(graphics::Renderer::Driver::OPENGL) != availableDrivers.end())
            {
                settings.renderDriver = graphics::Renderer::Driver::OPENGL;
            }
            else
            {
                log("Failed to select render driver");
                return false;
            }
        }

#if OUZEL_PLATFORM_MACOS
        window.reset(new WindowMacOS(settings.size, settings.resizable, settings.fullscreen, settings.title));
#elif OUZEL_PLATFORM_IOS
        window.reset(new WindowIOS(settings.size, settings.resizable, settings.fullscreen, settings.title));
#elif OUZEL_PLATFORM_TVOS
        window.reset(new WindowTVOS(settings.size, settings.resizable, settings.fullscreen, settings.title));
#elif OUZEL_PLATFORM_ANDROID
        window.reset(new WindowAndroid(settings.size, settings.resizable, settings.fullscreen, settings.title));
#elif OUZEL_PLATFORM_LINUX
        window.reset(new WindowLinux(settings.size, settings.resizable, settings.fullscreen, settings.title));
#elif OUZEL_PLATFORM_WINDOWS
        window.reset(new WindowWin(settings.size, settings.resizable, settings.fullscreen, settings.title));
#elif OUZEL_PLATFORM_RASPBIAN
        window.reset(new WindowRPI(settings.size, settings.resizable, settings.fullscreen, settings.title));
#endif

        eventDispatcher.reset(new EventDispatcher());
        cache.reset(new Cache());
        sceneManager.reset(new scene::SceneManager());

#if OUZEL_PLATFORM_MACOS || OUZEL_PLATFORM_IOS || OUZEL_PLATFORM_TVOS
        input.reset(new input::InputApple());
#elif OUZEL_PLATFORM_ANDROID
        input.reset(new input::InputAndroid());
#elif OUZEL_PLATFORM_LINUX
        input.reset(new input::InputLinux());
#elif OUZEL_PLATFORM_WINDOWS
        input.reset(new input::InputWin());
#elif OUZEL_PLATFORM_RASPBIAN
        input.reset(new input::InputRPI());
#else
        input.reset(new input::Input());
#endif

        localization.reset(new Localization());

        switch (settings.renderDriver)
        {
            case graphics::Renderer::Driver::NONE:
                log("Not using render driver");
                renderer.reset(new graphics::Renderer());
                break;
#if OUZEL_SUPPORTS_OPENGL || OUZEL_SUPPORTS_OPENGLES
            case graphics::Renderer::Driver::OPENGL:
                log("Using OpenGL render driver");
    #if OUZEL_PLATFORM_MACOS
                renderer.reset(new graphics::RendererOGLMacOS());
    #elif OUZEL_PLATFORM_IOS
                renderer.reset(new graphics::RendererOGLIOS());
    #elif OUZEL_PLATFORM_TVOS
                renderer.reset(new graphics::RendererOGLTVOS());
    #elif OUZEL_PLATFORM_LINUX
                renderer.reset(new graphics::RendererOGLLinux());
    #elif OUZEL_PLATFORM_RASPBIAN
                renderer.reset(new graphics::RendererOGLRPI());
    #else
                renderer.reset(new graphics::RendererOGL());
    #endif
                break;
#endif
#if OUZEL_SUPPORTS_DIRECT3D11
            case graphics::Renderer::Driver::DIRECT3D11:
                log("Using Direct3D 11 render driver");
                renderer.reset(new graphics::RendererD3D11());
                break;
#endif
#if OUZEL_SUPPORTS_METAL
            case graphics::Renderer::Driver::METAL:
                log("Using Metal render driver");
                renderer.reset(new graphics::RendererMetal());
                break;
#endif
            default:
                log("Unsupported render driver");
                return false;
        }

        if (!window->init())
        {
            return false;
        }

        if (!renderer->init(window,
                            settings.sampleCount,
                            settings.textureFiltering,
                            settings.verticalSync))
        {
            return false;
        }

        if (settings.audioDriver == audio::Audio::Driver::DEFAULT)
        {
            auto availableDrivers = getAvailableAudioDrivers();

            if (availableDrivers.find(audio::Audio::Driver::OPENAL) != availableDrivers.end())
            {
                settings.audioDriver = audio::Audio::Driver::OPENAL;
            }
            else if (availableDrivers.find(audio::Audio::Driver::XAUDIO2) != availableDrivers.end())
            {
                settings.audioDriver = audio::Audio::Driver::XAUDIO2;
            }
            else if (availableDrivers.find(audio::Audio::Driver::OPENSL) != availableDrivers.end())
            {
                settings.audioDriver = audio::Audio::Driver::OPENSL;
            }
            else
            {
                log("Failed to select render driver");
                return false;
            }
        }

        switch (settings.audioDriver)
        {
            case audio::Audio::Driver::NONE:
                log("Not using audio driver");
                audio.reset(new audio::Audio());
                break;
#if OUZEL_SUPPORTS_OPENAL
            case audio::Audio::Driver::OPENAL:
                log("Using OpenAL audio driver");
    #if OUZEL_PLATFORM_MACOS || OUZEL_PLATFORM_IOS || OUZEL_PLATFORM_TVOS
                audio.reset(new audio::AudioALApple());
    #else
                audio.reset(new audio::AudioAL());
    #endif
                break;
#endif
#if OUZEL_SUPPORTS_XAUDIO2
            case audio::Audio::Driver::XAUDIO2:
                log("Using XAudio 2 audio driver");
                audio.reset(new audio::AudioXA2());
                break;
#endif
#if OUZEL_SUPPORTS_OPENSL
            case audio::Audio::Driver::OPENSL:
                log("Using OpenSL ES audio driver");
                audio.reset(new audio::AudioSL());
                break;
#endif
            default:
                log("Unsupported render driver");
                return false;
        }

        if (!audio->init())
        {
            return false;
        }

        updateThread = std::thread(&Engine::run, this, beginCallback);

        return true;
    }

    void Engine::exit()
    {
        running = false;
        active = false;
    }

    void Engine::begin()
    {
        previousUpdateTime = previousFrameTime = std::chrono::steady_clock::now();
        running = true;
    }

    void Engine::end()
    {
        running = false;
        active = false;
        if (updateThread.joinable()) updateThread.join();
    }

    void Engine::pause()
    {
        running = false;
    }

    void Engine::resume()
    {
        previousUpdateTime = previousFrameTime = std::chrono::steady_clock::now();
        running = true;
    }

    void Engine::run(const std::function<void(void)>& beginCallback)
    {
        beginCallback();

        while (active)
        {
            if (running)
            {
                std::chrono::steady_clock::time_point currentTime = std::chrono::steady_clock::now();
                auto diff = std::chrono::duration_cast<std::chrono::nanoseconds>(currentTime - previousUpdateTime);
                previousUpdateTime = currentTime;

                float delta = diff.count() / 1000000000.0f;

                input->update();
                eventDispatcher->update();

                if (sharedEngine->getRenderer()->getRefillDrawQueue())
                {
                    sceneManager->draw();
                    renderer->flushDrawCommands();
                }

                for (updateCallbackIterator = updateCallbacks.begin(); updateCallbackIterator != updateCallbacks.end();)
                {
                    updateCallbackDeleted = false;

                    const UpdateCallback* updateCallback = *updateCallbackIterator;
                    if (updateCallback && updateCallback->callback)
                    {
                        updateCallback->callback(delta);
                    }

                    // current element wasn't delete from the list
                    if (!updateCallbackDeleted)
                    {
                        ++updateCallbackIterator;
                    }
                }
            }
        }
    }

    bool Engine::draw()
    {
        std::chrono::steady_clock::time_point currentTime = std::chrono::steady_clock::now();
        auto diff = std::chrono::duration_cast<std::chrono::nanoseconds>(currentTime - previousFrameTime);
        previousFrameTime = currentTime;

        float delta = diff.count() / 1000000000.0f;

        if (delta > 0.0f)
        {
            currentFPS = 1.0f / delta;
        }

        accumulatedTime += delta;
        currentAccumulatedFPS += 1.0f;

        if (accumulatedTime > 1.0f)
        {
            accumulatedFPS = currentAccumulatedFPS;
            accumulatedTime = 0.0f;
            currentAccumulatedFPS = 0.0f;
        }

        if (!renderer->present())
        {
            return false;
        }

        return active;
    }

    void Engine::scheduleUpdate(const UpdateCallback& callback)
    {
        std::list<const UpdateCallback*>::iterator i = std::find(updateCallbacks.begin(), updateCallbacks.end(), &callback);

        if (i == updateCallbacks.end())
        {
            updateCallbacks.push_back(&callback);

            updateCallbacks.sort([](const UpdateCallback* a, const UpdateCallback* b) {
                return a->priority < b->priority;
            });
        }
    }

    void Engine::unscheduleUpdate(const UpdateCallback& callback)
    {
        std::list<const UpdateCallback*>::iterator i = std::find(updateCallbacks.begin(), updateCallbacks.end(), &callback);

        if (i != updateCallbacks.end())
        {
            // increment the iterator if current element is deleted
            if (i == updateCallbackIterator)
            {
                updateCallbackIterator = updateCallbacks.erase(i);
                updateCallbackDeleted = true;
            }
            else
            {
                updateCallbacks.erase(i);
            }
        }
    }
}
<commit_msg>Destroy scene manager the first<commit_after>// Copyright (C) 2016 Elviss Strazdins
// This file is part of the Ouzel engine.

#include <algorithm>
#include "Engine.h"
#include "CompileConfig.h"
#include "Cache.h"
#include "localization/Localization.h"
#include "utils/Utils.h"
#include "graphics/Renderer.h"
#include "audio/Audio.h"
#include "scene/SceneManager.h"
#include "events/EventDispatcher.h"

#if OUZEL_PLATFORM_MACOS
#include "macos/WindowMacOS.h"
#include "macos/RendererOGLMacOS.h"
#elif OUZEL_PLATFORM_IOS
#include "ios/WindowIOS.h"
#include "ios/RendererOGLIOS.h"
#elif OUZEL_PLATFORM_TVOS
#include "tvos/WindowTVOS.h"
#include "tvos/RendererOGLTVOS.h"
#elif OUZEL_PLATFORM_ANDROID
#include "android/WindowAndroid.h"
#include "android/InputAndroid.h"
#elif OUZEL_PLATFORM_LINUX
#include "linux/WindowLinux.h"
#include "linux/RendererOGLLinux.h"
#include "linux/InputLinux.h"
#elif OUZEL_PLATFORM_WINDOWS
#include "win/WindowWin.h"
#elif OUZEL_PLATFORM_RASPBIAN
#include "rpi/WindowRPI.h"
#include "rpi/RendererOGLRPI.h"
#include "rpi/InputRPI.h"
#endif

#if OUZEL_SUPPORTS_OPENGL || OUZEL_SUPPORTS_OPENGLES
#include "opengl/RendererOGL.h"
#endif

#if OUZEL_SUPPORTS_DIRECT3D11
#include "direct3d11/RendererD3D11.h"
#endif

#if OUZEL_SUPPORTS_METAL
#include "metal/RendererMetal.h"
#endif

#if OUZEL_SUPPORTS_OPENAL
#include "openal/AudioAL.h"
#endif

#if OUZEL_SUPPORTS_XAUDIO2
#include "xaudio2/AudioXA2.h"
#endif

#if OUZEL_SUPPORTS_OPENSL
#include "opensl/AudioSL.h"
#endif

#if OUZEL_PLATFORM_MACOS || OUZEL_PLATFORM_IOS || OUZEL_PLATFORM_TVOS
#include "apple/AudioALApple.h"
#include "apple/InputApple.h"
#elif OUZEL_PLATFORM_WINDOWS
#include "win/InputWin.h"
#endif

#ifdef OPENAL
#undef OPENAL
#endif

namespace ouzel
{
    ouzel::Engine* sharedEngine = nullptr;

    Engine::Engine():
        currentFPS(0.0f), accumulatedFPS(0.0f), running(false), active(true)
    {
        sharedEngine = this;
    }

    Engine::~Engine()
    {
        running = false;
        active = false;

        if (updateThread.joinable()) updateThread.join();
        sceneManager.reset();
    }

    std::set<graphics::Renderer::Driver> Engine::getAvailableRenderDrivers()
    {
        static std::set<graphics::Renderer::Driver> availableDrivers;

        if (availableDrivers.empty())
        {
#if OUZEL_SUPPORTS_OPENGL || OUZEL_SUPPORTS_OPENGLES
            availableDrivers.insert(graphics::Renderer::Driver::OPENGL);
#endif

#if OUZEL_SUPPORTS_DIRECT3D11
            availableDrivers.insert(graphics::Renderer::Driver::DIRECT3D11);
#endif

#if OUZEL_SUPPORTS_METAL
            if (graphics::RendererMetal::available())
            {
                availableDrivers.insert(graphics::Renderer::Driver::METAL);
            }
#endif
        }

        return availableDrivers;
    }

    std::set<audio::Audio::Driver> Engine::getAvailableAudioDrivers()
    {
        static std::set<audio::Audio::Driver> availableDrivers;

        if (availableDrivers.empty())
        {
#if OUZEL_SUPPORTS_OPENAL
            availableDrivers.insert(audio::Audio::Driver::OPENAL);
#endif

#if OUZEL_SUPPORTS_XAUDIO2
            availableDrivers.insert(audio::Audio::Driver::XAUDIO2);
#endif

#if OUZEL_SUPPORTS_OPENSL
            availableDrivers.insert(audio::Audio::Driver::OPENSL);
#endif
        }

        return availableDrivers;
    }

    bool Engine::init(Settings& newSettings, const std::function<void(void)>& beginCallback)
    {
        settings = newSettings;

        if (settings.renderDriver == graphics::Renderer::Driver::DEFAULT)
        {
            auto availableDrivers = getAvailableRenderDrivers();

            if (availableDrivers.find(graphics::Renderer::Driver::METAL) != availableDrivers.end())
            {
                settings.renderDriver = graphics::Renderer::Driver::METAL;
            }
            else if (availableDrivers.find(graphics::Renderer::Driver::DIRECT3D11) != availableDrivers.end())
            {
                settings.renderDriver = graphics::Renderer::Driver::DIRECT3D11;
            }
            else if (availableDrivers.find(graphics::Renderer::Driver::OPENGL) != availableDrivers.end())
            {
                settings.renderDriver = graphics::Renderer::Driver::OPENGL;
            }
            else
            {
                log("Failed to select render driver");
                return false;
            }
        }

#if OUZEL_PLATFORM_MACOS
        window.reset(new WindowMacOS(settings.size, settings.resizable, settings.fullscreen, settings.title));
#elif OUZEL_PLATFORM_IOS
        window.reset(new WindowIOS(settings.size, settings.resizable, settings.fullscreen, settings.title));
#elif OUZEL_PLATFORM_TVOS
        window.reset(new WindowTVOS(settings.size, settings.resizable, settings.fullscreen, settings.title));
#elif OUZEL_PLATFORM_ANDROID
        window.reset(new WindowAndroid(settings.size, settings.resizable, settings.fullscreen, settings.title));
#elif OUZEL_PLATFORM_LINUX
        window.reset(new WindowLinux(settings.size, settings.resizable, settings.fullscreen, settings.title));
#elif OUZEL_PLATFORM_WINDOWS
        window.reset(new WindowWin(settings.size, settings.resizable, settings.fullscreen, settings.title));
#elif OUZEL_PLATFORM_RASPBIAN
        window.reset(new WindowRPI(settings.size, settings.resizable, settings.fullscreen, settings.title));
#endif

        eventDispatcher.reset(new EventDispatcher());
        cache.reset(new Cache());
        sceneManager.reset(new scene::SceneManager());

#if OUZEL_PLATFORM_MACOS || OUZEL_PLATFORM_IOS || OUZEL_PLATFORM_TVOS
        input.reset(new input::InputApple());
#elif OUZEL_PLATFORM_ANDROID
        input.reset(new input::InputAndroid());
#elif OUZEL_PLATFORM_LINUX
        input.reset(new input::InputLinux());
#elif OUZEL_PLATFORM_WINDOWS
        input.reset(new input::InputWin());
#elif OUZEL_PLATFORM_RASPBIAN
        input.reset(new input::InputRPI());
#else
        input.reset(new input::Input());
#endif

        localization.reset(new Localization());

        switch (settings.renderDriver)
        {
            case graphics::Renderer::Driver::NONE:
                log("Not using render driver");
                renderer.reset(new graphics::Renderer());
                break;
#if OUZEL_SUPPORTS_OPENGL || OUZEL_SUPPORTS_OPENGLES
            case graphics::Renderer::Driver::OPENGL:
                log("Using OpenGL render driver");
    #if OUZEL_PLATFORM_MACOS
                renderer.reset(new graphics::RendererOGLMacOS());
    #elif OUZEL_PLATFORM_IOS
                renderer.reset(new graphics::RendererOGLIOS());
    #elif OUZEL_PLATFORM_TVOS
                renderer.reset(new graphics::RendererOGLTVOS());
    #elif OUZEL_PLATFORM_LINUX
                renderer.reset(new graphics::RendererOGLLinux());
    #elif OUZEL_PLATFORM_RASPBIAN
                renderer.reset(new graphics::RendererOGLRPI());
    #else
                renderer.reset(new graphics::RendererOGL());
    #endif
                break;
#endif
#if OUZEL_SUPPORTS_DIRECT3D11
            case graphics::Renderer::Driver::DIRECT3D11:
                log("Using Direct3D 11 render driver");
                renderer.reset(new graphics::RendererD3D11());
                break;
#endif
#if OUZEL_SUPPORTS_METAL
            case graphics::Renderer::Driver::METAL:
                log("Using Metal render driver");
                renderer.reset(new graphics::RendererMetal());
                break;
#endif
            default:
                log("Unsupported render driver");
                return false;
        }

        if (!window->init())
        {
            return false;
        }

        if (!renderer->init(window,
                            settings.sampleCount,
                            settings.textureFiltering,
                            settings.verticalSync))
        {
            return false;
        }

        if (settings.audioDriver == audio::Audio::Driver::DEFAULT)
        {
            auto availableDrivers = getAvailableAudioDrivers();

            if (availableDrivers.find(audio::Audio::Driver::OPENAL) != availableDrivers.end())
            {
                settings.audioDriver = audio::Audio::Driver::OPENAL;
            }
            else if (availableDrivers.find(audio::Audio::Driver::XAUDIO2) != availableDrivers.end())
            {
                settings.audioDriver = audio::Audio::Driver::XAUDIO2;
            }
            else if (availableDrivers.find(audio::Audio::Driver::OPENSL) != availableDrivers.end())
            {
                settings.audioDriver = audio::Audio::Driver::OPENSL;
            }
            else
            {
                log("Failed to select render driver");
                return false;
            }
        }

        switch (settings.audioDriver)
        {
            case audio::Audio::Driver::NONE:
                log("Not using audio driver");
                audio.reset(new audio::Audio());
                break;
#if OUZEL_SUPPORTS_OPENAL
            case audio::Audio::Driver::OPENAL:
                log("Using OpenAL audio driver");
    #if OUZEL_PLATFORM_MACOS || OUZEL_PLATFORM_IOS || OUZEL_PLATFORM_TVOS
                audio.reset(new audio::AudioALApple());
    #else
                audio.reset(new audio::AudioAL());
    #endif
                break;
#endif
#if OUZEL_SUPPORTS_XAUDIO2
            case audio::Audio::Driver::XAUDIO2:
                log("Using XAudio 2 audio driver");
                audio.reset(new audio::AudioXA2());
                break;
#endif
#if OUZEL_SUPPORTS_OPENSL
            case audio::Audio::Driver::OPENSL:
                log("Using OpenSL ES audio driver");
                audio.reset(new audio::AudioSL());
                break;
#endif
            default:
                log("Unsupported render driver");
                return false;
        }

        if (!audio->init())
        {
            return false;
        }

        updateThread = std::thread(&Engine::run, this, beginCallback);

        return true;
    }

    void Engine::exit()
    {
        running = false;
        active = false;
    }

    void Engine::begin()
    {
        previousUpdateTime = previousFrameTime = std::chrono::steady_clock::now();
        running = true;
    }

    void Engine::end()
    {
        running = false;
        active = false;
        if (updateThread.joinable()) updateThread.join();
    }

    void Engine::pause()
    {
        running = false;
    }

    void Engine::resume()
    {
        previousUpdateTime = previousFrameTime = std::chrono::steady_clock::now();
        running = true;
    }

    void Engine::run(const std::function<void(void)>& beginCallback)
    {
        beginCallback();

        while (active)
        {
            if (running)
            {
                std::chrono::steady_clock::time_point currentTime = std::chrono::steady_clock::now();
                auto diff = std::chrono::duration_cast<std::chrono::nanoseconds>(currentTime - previousUpdateTime);
                previousUpdateTime = currentTime;

                float delta = diff.count() / 1000000000.0f;

                input->update();
                eventDispatcher->update();

                if (sharedEngine->getRenderer()->getRefillDrawQueue())
                {
                    sceneManager->draw();
                    renderer->flushDrawCommands();
                }

                for (updateCallbackIterator = updateCallbacks.begin(); updateCallbackIterator != updateCallbacks.end();)
                {
                    updateCallbackDeleted = false;

                    const UpdateCallback* updateCallback = *updateCallbackIterator;
                    if (updateCallback && updateCallback->callback)
                    {
                        updateCallback->callback(delta);
                    }

                    // current element wasn't delete from the list
                    if (!updateCallbackDeleted)
                    {
                        ++updateCallbackIterator;
                    }
                }
            }
        }
    }

    bool Engine::draw()
    {
        std::chrono::steady_clock::time_point currentTime = std::chrono::steady_clock::now();
        auto diff = std::chrono::duration_cast<std::chrono::nanoseconds>(currentTime - previousFrameTime);
        previousFrameTime = currentTime;

        float delta = diff.count() / 1000000000.0f;

        if (delta > 0.0f)
        {
            currentFPS = 1.0f / delta;
        }

        accumulatedTime += delta;
        currentAccumulatedFPS += 1.0f;

        if (accumulatedTime > 1.0f)
        {
            accumulatedFPS = currentAccumulatedFPS;
            accumulatedTime = 0.0f;
            currentAccumulatedFPS = 0.0f;
        }

        if (!renderer->present())
        {
            return false;
        }

        return active;
    }

    void Engine::scheduleUpdate(const UpdateCallback& callback)
    {
        std::list<const UpdateCallback*>::iterator i = std::find(updateCallbacks.begin(), updateCallbacks.end(), &callback);

        if (i == updateCallbacks.end())
        {
            updateCallbacks.push_back(&callback);

            updateCallbacks.sort([](const UpdateCallback* a, const UpdateCallback* b) {
                return a->priority < b->priority;
            });
        }
    }

    void Engine::unscheduleUpdate(const UpdateCallback& callback)
    {
        std::list<const UpdateCallback*>::iterator i = std::find(updateCallbacks.begin(), updateCallbacks.end(), &callback);

        if (i != updateCallbacks.end())
        {
            // increment the iterator if current element is deleted
            if (i == updateCallbackIterator)
            {
                updateCallbackIterator = updateCallbacks.erase(i);
                updateCallbackDeleted = true;
            }
            else
            {
                updateCallbacks.erase(i);
            }
        }
    }
}
<|endoftext|>


<commit_before>#include <map>
#include <string>
#include <utility>

#define PAM_SM_AUTH
#include <security/pam_modules.h>
#include <security/pam_ext.h>

#define LDAP_DEPRECATED 1
#include <ldap.h>

typedef std::map<std::string, std::string> ArgMap;

static bool verify(const char* host,
                   const char* binddn,
                   const char* pw)
{
    LDAP* ld;

    if (ldap_initialize(&ld, host)) {
        return false;
    }

    int rc = ldap_simple_bind_s(ld, binddn, pw);
    return rc == LDAP_SUCCESS;
}

static ArgMap get_args(int argc,
                       const char** argv)
{
    ArgMap arguments;

    for (int i = 0; i < argc; i++) {
        std::string arg(argv[i]);
        std::string::size_type pos = arg.find("=");
        if (pos != std::string::npos) {
            std::string key = arg.substr(0, pos);
            std::string value = "";

            if (arg.length() > pos+1) {
                value = arg.substr(pos+1);
            }

            arguments.insert(std::make_pair(key, value));
        }
    }

    return arguments;
}

static void replace_all(std::string& s,
                        const std::string& search_s,
                        const std::string& replace_s)
{
    std::string::size_type last_pos = 0;
    while ((last_pos = s.find(search_s, last_pos)) != std::string::npos) {
        s.replace(last_pos, search_s.length(), replace_s);
    }
}

PAM_EXTERN int pam_sm_authenticate(pam_handle_t* pamh,
                                   int flags,
                                   int argc,
                                   const char** argv)
{
    const char* user;
    const char* pass;
    ArgMap arguments = get_args(argc, argv);

    if (pam_get_user(pamh, &user, NULL) != PAM_SUCCESS) {
        return PAM_AUTH_ERR;
    }
    if (pam_get_authtok(pamh, PAM_AUTHTOK, &pass, NULL) != PAM_SUCCESS) {
        return PAM_AUTH_ERR;
    }

    // ensure uri and binddn PAM parameters were specified
    if (arguments.find("uri") == arguments.end() ||
        arguments.find("binddn") == arguments.end()) {
        return PAM_AUTH_ERR;
    }

    std::string binddn = arguments["binddn"];
    replace_all(binddn, "%s", user);

    // check against ldap database
    if (verify(arguments["uri"].c_str(), binddn.c_str(), pass)) {
        return PAM_SUCCESS;
    } else {
        return PAM_AUTH_ERR;
    }
}

PAM_EXTERN int pam_sm_setcred(pam_handle_t* pamh,
                              int flags,
                              int argc,
                              const char** argv)
{
    return PAM_SUCCESS;
}
<commit_msg>add basic LDAP to PAM error code translation<commit_after>#include <map>
#include <string>
#include <utility>

#define PAM_SM_AUTH
#include <security/pam_modules.h>
#include <security/pam_ext.h>

#define LDAP_DEPRECATED 1
#include <ldap.h>

typedef std::map<std::string, std::string> ArgMap;

static int ldap_to_pam_rc(int ldap_rc)
{
    switch (ldap_rc) {
    case LDAP_SUCCESS:
        /* everything was fine */
        return PAM_SUCCESS;
    case LDAP_UNAVAILABLE:
    case LDAP_TIMELIMIT_EXCEEDED:
    case LDAP_OPERATIONS_ERROR:
    case LDAP_BUSY:
    case LDAP_LOOP_DETECT:
    case LDAP_SERVER_DOWN:
    case LDAP_TIMEOUT:
    case LDAP_CONNECT_ERROR:
    case LDAP_NO_RESULTS_RETURNED:
        /* cannot access LDAP correctly */
        return PAM_AUTHINFO_UNAVAIL;
    }

    /* something else went wrong */
    return PAM_AUTH_ERR;
}

static int verify(const char* host,
                  const char* binddn,
                  const char* pw)
{
    LDAP* ld;
    int ldap_rc, pam_rc;

    ldap_rc = ldap_initialize(&ld, host);
    pam_rc = ldap_to_pam_rc(ldap_rc);
    if (pam_rc != PAM_SUCCESS)
        return pam_rc;

    ldap_rc = ldap_simple_bind_s(ld, binddn, pw);
    return ldap_to_pam_rc(ldap_rc);
}

static ArgMap get_args(int argc,
                       const char** argv)
{
    ArgMap arguments;

    for (int i = 0; i < argc; i++) {
        std::string arg(argv[i]);
        std::string::size_type pos = arg.find("=");
        if (pos != std::string::npos) {
            std::string key = arg.substr(0, pos);
            std::string value = "";

            if (arg.length() > pos+1) {
                value = arg.substr(pos+1);
            }

            arguments.insert(std::make_pair(key, value));
        }
    }

    return arguments;
}

static void replace_all(std::string& s,
                        const std::string& search_s,
                        const std::string& replace_s)
{
    std::string::size_type last_pos = 0;
    while ((last_pos = s.find(search_s, last_pos)) != std::string::npos) {
        s.replace(last_pos, search_s.length(), replace_s);
    }
}

PAM_EXTERN int pam_sm_authenticate(pam_handle_t* pamh,
                                   int flags,
                                   int argc,
                                   const char** argv)
{
    const char* user;
    const char* pass;
    ArgMap arguments = get_args(argc, argv);

    if (pam_get_user(pamh, &user, NULL) != PAM_SUCCESS) {
        return PAM_AUTH_ERR;
    }
    if (pam_get_authtok(pamh, PAM_AUTHTOK, &pass, NULL) != PAM_SUCCESS) {
        return PAM_AUTH_ERR;
    }

    // ensure uri and binddn PAM parameters were specified
    if (arguments.find("uri") == arguments.end() ||
        arguments.find("binddn") == arguments.end()) {
        return PAM_AUTH_ERR;
    }

    std::string binddn = arguments["binddn"];
    replace_all(binddn, "%s", user);

    // check against ldap database
    return verify(arguments["uri"].c_str(), binddn.c_str(), pass);
}

PAM_EXTERN int pam_sm_setcred(pam_handle_t* pamh,
                              int flags,
                              int argc,
                              const char** argv)
{
    return PAM_SUCCESS;
}
<|endoftext|>


<commit_before>// Copyright (c) 2018 Matthew J. Smith and Overkit contributors
// License: MIT (http://opensource.org/licenses/MIT)

#ifndef OVK_CORE_PUBLIC_RANGE_INL_INCLUDED
#define OVK_CORE_PUBLIC_RANGE_INL_INCLUDED

#include <ovk/core/ovkRange.h>

#include <ovk/core/ovkGlobal.h>

#ifdef __cplusplus
extern "C" {
#endif

static inline void ovkDefaultRange(ovk_range *Range, int NumDims) {

  int iDim;

  Range->nd = NumDims;
  for (iDim = 0; iDim < Range->nd; ++iDim) {
    Range->b[iDim] = 0;
    Range->e[iDim] = 0;
  }
  for (iDim = Range->nd; iDim < OVK_MAX_DIMS; ++iDim) {
    Range->b[iDim] = 0;
    Range->e[iDim] = 1;
  }

}

static inline void ovkSetRange(ovk_range *Range, int NumDims, const int *Begin, const int *End) {

  int iDim;

  Range->nd = NumDims;
  for (iDim = 0; iDim < Range->nd; ++iDim) {
    Range->b[iDim] = Begin[iDim];
    Range->e[iDim] = End[iDim];
  }
  for (iDim = Range->nd; iDim < OVK_MAX_DIMS; ++iDim) {
    Range->b[iDim] = 0;
    Range->e[iDim] = 1;
  }

}

static inline void ovkRangeSize(const ovk_range *Range, int *Size) {

  int iDim;

  for (iDim = 0; iDim < OVK_MAX_DIMS; ++iDim) {
    Size[iDim] = Range->e[iDim] - Range->b[iDim];
  }

}

static inline void ovkRangeCount(const ovk_range *Range, size_t *Count) {

  int iDim;

  *Count = 1;

  for (iDim = 0; iDim < Range->nd; ++iDim) {
    *Count *= (size_t)(Range->e[iDim] - Range->b[iDim]);
  }

}

static inline void ovkRangeCountSmall(const ovk_range *Range, int *Count) {

  size_t CountLarge;

  ovkRangeCount(Range, &CountLarge);

  *Count = (int)CountLarge;

}

static inline void ovkRangeTupleToIndex(const ovk_range *Range, ovk_array_layout Layout,
  const int *Tuple, size_t *Index) {

  int iDim;
  size_t Stride;

  switch (Layout) {
  case OVK_COLUMN_MAJOR:
    *Index = 0;
    Stride = 1;
    for (iDim = 0; iDim < Range->nd; ++iDim) {
      *Index += Stride * (size_t)(Tuple[iDim] - Range->b[iDim]);
      Stride *= (size_t)(Range->e[iDim] - Range->b[iDim]);
    }
    break;
  case OVK_ROW_MAJOR:
    *Index = 0;
    Stride = 1;
    for (iDim = Range->nd-1; iDim >= 0; --iDim) {
      *Index += Stride * (size_t)(Tuple[iDim] - Range->b[iDim]);
      Stride *= (size_t)(Range->e[iDim] - Range->b[iDim]);
    }
    break;
  }

}

static inline void ovkRangeTupleToIndexSmall(const ovk_range *Range, ovk_array_layout Layout,
  const int *Tuple, int *Index) {

  size_t IndexLarge;

  ovkRangeTupleToIndex(Range, Layout, Tuple, &IndexLarge);

  *Index = (int)IndexLarge;

}

static inline void ovkRangeIndexToTuple(const ovk_range *Range, ovk_array_layout Layout,
  size_t Index, int *Tuple) {

  int iDim;
  size_t Stride;

  switch (Layout) {
  case OVK_COLUMN_MAJOR:
    Stride = 1;
    for (iDim = 0; iDim < Range->nd; ++iDim) {
      size_t N = Range->e[iDim] - Range->b[iDim];
      Tuple[iDim] = Range->b[iDim] + (int)((Index/Stride) % N);
      Stride *= N;
    }
    break;
  case OVK_ROW_MAJOR:
    Stride = 1;
    for (iDim = Range->nd-1; iDim >= 0; --iDim) {
      size_t N = Range->e[iDim] - Range->b[iDim];
      Tuple[iDim] = Range->b[iDim] + (int)((Index/Stride) % N);
      Stride *= N;
    }
    break;
  }

  for (iDim = Range->nd; iDim < OVK_MAX_DIMS; ++iDim) {
    Tuple[iDim] = 0;
  }

}

static inline bool ovkRangeIsEmpty(const ovk_range *Range) {

  return Range->e[0] <= Range->b[0] || Range->e[1] <= Range->b[1] || Range->e[2] <= Range->b[2];

}

static inline bool ovkRangeEquals(const ovk_range *LeftRange, const ovk_range *RightRange) {

  return LeftRange->nd == RightRange->nd &&
    LeftRange->b[0] == RightRange->b[0] &&
    LeftRange->b[1] == RightRange->b[1] &&
    LeftRange->b[2] == RightRange->b[2] &&
    LeftRange->e[0] == RightRange->e[0] &&
    LeftRange->e[1] == RightRange->e[1] &&
    LeftRange->e[2] == RightRange->e[2];

}

static inline bool ovkRangeContains(const ovk_range *Range, const int *Point) {

  int iDim;

  for (iDim = 0; iDim < OVK_MAX_DIMS; ++iDim) {
    if (Point[iDim] < Range->b[iDim] || Point[iDim] >= Range->e[iDim]) return false;
  }

  return true;

}

static inline bool ovkRangeIncludes(const ovk_range *Range, const ovk_range *OtherRange) {

  return ovkRangeIsEmpty(OtherRange) ||
    (Range->b[0] <= OtherRange->b[0] && Range->e[0] >= OtherRange->e[0] &&
    Range->b[1] <= OtherRange->b[1] && Range->e[1] >= OtherRange->e[1] &&
    Range->b[2] <= OtherRange->b[2] && Range->e[2] >= OtherRange->e[2]);

}

static inline bool ovkRangeOverlaps(const ovk_range *LeftRange, const ovk_range *RightRange) {

  return !ovkRangeIsEmpty(LeftRange) && !ovkRangeIsEmpty(RightRange) &&
    RightRange->e[0] > LeftRange->b[0] && LeftRange->e[0] > RightRange->b[0] &&
    RightRange->e[1] > LeftRange->b[1] && LeftRange->e[1] > RightRange->b[1] &&
    RightRange->e[2] > LeftRange->b[2] && LeftRange->e[2] > RightRange->b[2];

}

static inline void ovkRangeUnion(const ovk_range *LeftRange, const ovk_range *RightRange,
  ovk_range *UnionRange) {

  int iDim;

  if (ovkRangeIsEmpty(LeftRange)) {
    *UnionRange = *RightRange;
  } else if (ovkRangeIsEmpty(RightRange)) {
    *UnionRange = *LeftRange;
  } else {
    UnionRange->nd = LeftRange->nd;
    for (iDim = 0; iDim < UnionRange->nd; ++iDim) {
      UnionRange->b[iDim] = ovk_min(LeftRange->b[iDim], RightRange->b[iDim]);
      UnionRange->e[iDim] = ovk_max(LeftRange->e[iDim], RightRange->e[iDim]);
    }
    for (iDim = UnionRange->nd; iDim < OVK_MAX_DIMS; ++iDim) {
      UnionRange->b[iDim] = 0;
      UnionRange->e[iDim] = 1;
    }
  }

}

static inline void ovkRangeIntersect(const ovk_range *LeftRange, const ovk_range *RightRange,
  ovk_range *IntersectRange) {

  int iDim;

  IntersectRange->nd = LeftRange->nd;
  for (iDim = 0; iDim < IntersectRange->nd; ++iDim) {
    IntersectRange->b[iDim] = ovk_max(LeftRange->b[iDim], RightRange->b[iDim]);
    IntersectRange->e[iDim] = ovk_min(LeftRange->e[iDim], RightRange->e[iDim]);
  }
  for (iDim = IntersectRange->nd; iDim < OVK_MAX_DIMS; ++iDim) {
    IntersectRange->b[iDim] = 0;
    IntersectRange->e[iDim] = 1;
  }

}

static inline void ovkRangeClamp(const ovk_range *Range, int *Point) {

  int iDim;

  for (iDim = 0; iDim < OVK_MAX_DIMS; ++iDim) {
    if (Point[iDim] < Range->b[iDim]) {
      Point[iDim] = Range->b[iDim];
    } else if (Point[iDim] >= Range->e[iDim]) {
      Point[iDim] = Range->e[iDim]-1;
    }
  }

}

static inline void ovkRangeExtend(const ovk_range *Range, const int *Point, ovk_range *ExtendRange)
  {

  int iDim;

  ExtendRange->nd = Range->nd;
  if (ovkRangeIsEmpty(Range)) {
    for (iDim = 0; iDim < Range->nd; ++iDim) {
      ExtendRange->b[iDim] = Point[iDim];
      ExtendRange->e[iDim] = Point[iDim];
    }
  } else {
    for (iDim = 0; iDim < Range->nd; ++iDim) {
      ExtendRange->b[iDim] = ovk_min(Range->b[iDim], Point[iDim]);
      ExtendRange->e[iDim] = ovk_max(Range->e[iDim], Point[iDim]);
    }
  }
  for (iDim = Range->nd; iDim < OVK_MAX_DIMS; ++iDim) {
    ExtendRange->b[iDim] = 0;
    ExtendRange->e[iDim] = 1;
  }

}

#ifdef __cplusplus
}
#endif

#endif
<commit_msg>fixed bugs in ovkRangeExtend<commit_after>// Copyright (c) 2018 Matthew J. Smith and Overkit contributors
// License: MIT (http://opensource.org/licenses/MIT)

#ifndef OVK_CORE_PUBLIC_RANGE_INL_INCLUDED
#define OVK_CORE_PUBLIC_RANGE_INL_INCLUDED

#include <ovk/core/ovkRange.h>

#include <ovk/core/ovkGlobal.h>

#ifdef __cplusplus
extern "C" {
#endif

static inline void ovkDefaultRange(ovk_range *Range, int NumDims) {

  int iDim;

  Range->nd = NumDims;
  for (iDim = 0; iDim < Range->nd; ++iDim) {
    Range->b[iDim] = 0;
    Range->e[iDim] = 0;
  }
  for (iDim = Range->nd; iDim < OVK_MAX_DIMS; ++iDim) {
    Range->b[iDim] = 0;
    Range->e[iDim] = 1;
  }

}

static inline void ovkSetRange(ovk_range *Range, int NumDims, const int *Begin, const int *End) {

  int iDim;

  Range->nd = NumDims;
  for (iDim = 0; iDim < Range->nd; ++iDim) {
    Range->b[iDim] = Begin[iDim];
    Range->e[iDim] = End[iDim];
  }
  for (iDim = Range->nd; iDim < OVK_MAX_DIMS; ++iDim) {
    Range->b[iDim] = 0;
    Range->e[iDim] = 1;
  }

}

static inline void ovkRangeSize(const ovk_range *Range, int *Size) {

  int iDim;

  for (iDim = 0; iDim < OVK_MAX_DIMS; ++iDim) {
    Size[iDim] = Range->e[iDim] - Range->b[iDim];
  }

}

static inline void ovkRangeCount(const ovk_range *Range, size_t *Count) {

  int iDim;

  *Count = 1;

  for (iDim = 0; iDim < Range->nd; ++iDim) {
    *Count *= (size_t)(Range->e[iDim] - Range->b[iDim]);
  }

}

static inline void ovkRangeCountSmall(const ovk_range *Range, int *Count) {

  size_t CountLarge;

  ovkRangeCount(Range, &CountLarge);

  *Count = (int)CountLarge;

}

static inline void ovkRangeTupleToIndex(const ovk_range *Range, ovk_array_layout Layout,
  const int *Tuple, size_t *Index) {

  int iDim;
  size_t Stride;

  switch (Layout) {
  case OVK_COLUMN_MAJOR:
    *Index = 0;
    Stride = 1;
    for (iDim = 0; iDim < Range->nd; ++iDim) {
      *Index += Stride * (size_t)(Tuple[iDim] - Range->b[iDim]);
      Stride *= (size_t)(Range->e[iDim] - Range->b[iDim]);
    }
    break;
  case OVK_ROW_MAJOR:
    *Index = 0;
    Stride = 1;
    for (iDim = Range->nd-1; iDim >= 0; --iDim) {
      *Index += Stride * (size_t)(Tuple[iDim] - Range->b[iDim]);
      Stride *= (size_t)(Range->e[iDim] - Range->b[iDim]);
    }
    break;
  }

}

static inline void ovkRangeTupleToIndexSmall(const ovk_range *Range, ovk_array_layout Layout,
  const int *Tuple, int *Index) {

  size_t IndexLarge;

  ovkRangeTupleToIndex(Range, Layout, Tuple, &IndexLarge);

  *Index = (int)IndexLarge;

}

static inline void ovkRangeIndexToTuple(const ovk_range *Range, ovk_array_layout Layout,
  size_t Index, int *Tuple) {

  int iDim;
  size_t Stride;

  switch (Layout) {
  case OVK_COLUMN_MAJOR:
    Stride = 1;
    for (iDim = 0; iDim < Range->nd; ++iDim) {
      size_t N = Range->e[iDim] - Range->b[iDim];
      Tuple[iDim] = Range->b[iDim] + (int)((Index/Stride) % N);
      Stride *= N;
    }
    break;
  case OVK_ROW_MAJOR:
    Stride = 1;
    for (iDim = Range->nd-1; iDim >= 0; --iDim) {
      size_t N = Range->e[iDim] - Range->b[iDim];
      Tuple[iDim] = Range->b[iDim] + (int)((Index/Stride) % N);
      Stride *= N;
    }
    break;
  }

  for (iDim = Range->nd; iDim < OVK_MAX_DIMS; ++iDim) {
    Tuple[iDim] = 0;
  }

}

static inline bool ovkRangeIsEmpty(const ovk_range *Range) {

  return Range->e[0] <= Range->b[0] || Range->e[1] <= Range->b[1] || Range->e[2] <= Range->b[2];

}

static inline bool ovkRangeEquals(const ovk_range *LeftRange, const ovk_range *RightRange) {

  return LeftRange->nd == RightRange->nd &&
    LeftRange->b[0] == RightRange->b[0] &&
    LeftRange->b[1] == RightRange->b[1] &&
    LeftRange->b[2] == RightRange->b[2] &&
    LeftRange->e[0] == RightRange->e[0] &&
    LeftRange->e[1] == RightRange->e[1] &&
    LeftRange->e[2] == RightRange->e[2];

}

static inline bool ovkRangeContains(const ovk_range *Range, const int *Point) {

  int iDim;

  for (iDim = 0; iDim < OVK_MAX_DIMS; ++iDim) {
    if (Point[iDim] < Range->b[iDim] || Point[iDim] >= Range->e[iDim]) return false;
  }

  return true;

}

static inline bool ovkRangeIncludes(const ovk_range *Range, const ovk_range *OtherRange) {

  return ovkRangeIsEmpty(OtherRange) ||
    (Range->b[0] <= OtherRange->b[0] && Range->e[0] >= OtherRange->e[0] &&
    Range->b[1] <= OtherRange->b[1] && Range->e[1] >= OtherRange->e[1] &&
    Range->b[2] <= OtherRange->b[2] && Range->e[2] >= OtherRange->e[2]);

}

static inline bool ovkRangeOverlaps(const ovk_range *LeftRange, const ovk_range *RightRange) {

  return !ovkRangeIsEmpty(LeftRange) && !ovkRangeIsEmpty(RightRange) &&
    RightRange->e[0] > LeftRange->b[0] && LeftRange->e[0] > RightRange->b[0] &&
    RightRange->e[1] > LeftRange->b[1] && LeftRange->e[1] > RightRange->b[1] &&
    RightRange->e[2] > LeftRange->b[2] && LeftRange->e[2] > RightRange->b[2];

}

static inline void ovkRangeUnion(const ovk_range *LeftRange, const ovk_range *RightRange,
  ovk_range *UnionRange) {

  int iDim;

  if (ovkRangeIsEmpty(LeftRange)) {
    *UnionRange = *RightRange;
  } else if (ovkRangeIsEmpty(RightRange)) {
    *UnionRange = *LeftRange;
  } else {
    UnionRange->nd = LeftRange->nd;
    for (iDim = 0; iDim < UnionRange->nd; ++iDim) {
      UnionRange->b[iDim] = ovk_min(LeftRange->b[iDim], RightRange->b[iDim]);
      UnionRange->e[iDim] = ovk_max(LeftRange->e[iDim], RightRange->e[iDim]);
    }
    for (iDim = UnionRange->nd; iDim < OVK_MAX_DIMS; ++iDim) {
      UnionRange->b[iDim] = 0;
      UnionRange->e[iDim] = 1;
    }
  }

}

static inline void ovkRangeIntersect(const ovk_range *LeftRange, const ovk_range *RightRange,
  ovk_range *IntersectRange) {

  int iDim;

  IntersectRange->nd = LeftRange->nd;
  for (iDim = 0; iDim < IntersectRange->nd; ++iDim) {
    IntersectRange->b[iDim] = ovk_max(LeftRange->b[iDim], RightRange->b[iDim]);
    IntersectRange->e[iDim] = ovk_min(LeftRange->e[iDim], RightRange->e[iDim]);
  }
  for (iDim = IntersectRange->nd; iDim < OVK_MAX_DIMS; ++iDim) {
    IntersectRange->b[iDim] = 0;
    IntersectRange->e[iDim] = 1;
  }

}

static inline void ovkRangeClamp(const ovk_range *Range, int *Point) {

  int iDim;

  for (iDim = 0; iDim < OVK_MAX_DIMS; ++iDim) {
    if (Point[iDim] < Range->b[iDim]) {
      Point[iDim] = Range->b[iDim];
    } else if (Point[iDim] >= Range->e[iDim]) {
      Point[iDim] = Range->e[iDim]-1;
    }
  }

}

static inline void ovkRangeExtend(const ovk_range *Range, const int *Point, ovk_range *ExtendRange)
  {

  int iDim;

  ExtendRange->nd = Range->nd;
  if (ovkRangeIsEmpty(Range)) {
    for (iDim = 0; iDim < Range->nd; ++iDim) {
      ExtendRange->b[iDim] = Point[iDim];
      ExtendRange->e[iDim] = Point[iDim]+1;
    }
  } else {
    for (iDim = 0; iDim < Range->nd; ++iDim) {
      ExtendRange->b[iDim] = ovk_min(Range->b[iDim], Point[iDim]);
      ExtendRange->e[iDim] = ovk_max(Range->e[iDim], Point[iDim]+1);
    }
  }
  for (iDim = Range->nd; iDim < OVK_MAX_DIMS; ++iDim) {
    ExtendRange->b[iDim] = 0;
    ExtendRange->e[iDim] = 1;
  }

}

#ifdef __cplusplus
}
#endif

#endif
<|endoftext|>


<commit_before>// Copyright (c) 2017 offa
// Copyright 2011 Ciaran McHale.
//
// 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 "danek/internal/UidIdentifierProcessor.h"
#include "danek/internal/Util.h"
#include "danek/internal/Compat.h"
#include "danek/ConfigurationException.h"
#include "danek/StringVector.h"
#include <sstream>
#include <string.h>
#include <ctype.h>
#include <stdio.h>

namespace danek
{
    UidIdentifierProcessor::UidIdentifierProcessor() : m_count(0)
    {
    }

    //----------------------------------------------------------------------
    // Spelling must be in one of the following forms:
    //      - "foo"                 -->  "foo"
    //      - "uid-<foo>"           -->  "uid-<digits>-<foo>"
    //      - "uid-<digits>-<foo>"  -->  "uid-<new-digits>-<foo>"
    // where "<foo>" does NOT start with a digit or "-"
    //----------------------------------------------------------------------

    void UidIdentifierProcessor::expand(StringBuffer& spelling)
    {
        //--------
        // Common case optimizations
        //--------
        if (strchr(spelling.str().c_str(), '.') == nullptr)
        {
            spelling = expandOne(spelling.str());
            return;
        }
        if (strstr(spelling.str().c_str(), "uid-") == nullptr)
        {
            return;
        }

        //--------
        // Let's break apart the scoped name, expand each local part
        // and then recombine the parts into an expanded scoped name.
        //--------
        StringBuffer buf;
        StringBuffer msg;
        StringBuffer result;

        StringVector vec{util::splitScopes(spelling.str())};
        const int len = vec.size();
        for (int i = 0; i < len; ++i)
        {
            buf = vec[i];
            try
            {
                buf = expandOne(buf.str());
            }
            catch (const ConfigurationException&)
            {
                msg << "'" << spelling << "' is not a legal identifier";
                throw ConfigurationException(msg.str());
            }
            result.append(buf);
            if (i < len - 1)
            {
                result.append(".");
            }
        }
        spelling = result;
    }

    std::string UidIdentifierProcessor::expandOne(const std::string& spelling)
    {
        //--------
        // If spelling does not start with "uid-" then do nothing.
        //--------
        const char* ptr = spelling.c_str();

        if (strncmp(ptr, "uid-", 4) != 0)
        {
            return spelling;
        }

        char digits[10]; // big enough for 9 digits
        StringBuffer msg;
        msg << "'" << spelling << "' is not a legal identifier";

        //--------
        // Check for "uid-" (with no suffix), because that is illegal
        //--------
        if (ptr[4] == '\0')
        {
            throw ConfigurationException(msg.str());
        }
        if (ptr[4] == '-')
        {
            // illegal: "uid--foo"
            throw ConfigurationException(msg.str());
        }

        if (!isdigit(ptr[4]))
        {
            //--------
            // "uid-foo"  --> "uid-<digits>-foo"
            //--------
            compat::checkAssertion(m_count < 1000 * 1000 * 1000);
            sprintf(digits, "%09ld", m_count);
            ++m_count;
            const std::string suffix = &(spelling.c_str()[4]); // deep copy

            std::stringstream ss;
            ss << "uid-" << digits << "-" << suffix;
            return ss.str();
        }

        ptr += 4; // skip over "uid-"
        int count = 0;
        while (isdigit(*ptr))
        {
            ++ptr;
            ++count;
        }
        compat::checkAssertion(count > 0);
        if (*ptr == '\0' || *ptr != '-')
        {
            // illegal: "uid-<digits>" or "uid-<digits>foo"
            throw ConfigurationException(msg.str());
        }
        ++ptr; // point to just after "uid-<digits>-"
        if (*ptr == '\0')
        {
            // illegal: "uid-<digits>-"
            throw ConfigurationException(msg.str());
        }
        if (*ptr == '-')
        {
            // illegal: "uid-<digits>--"
            throw ConfigurationException(msg.str());
        }
        if (isdigit(*(ptr)))
        {
            // illegal: "uid-<digits>-<digits>foo"
            throw ConfigurationException(msg.str());
        }
        compat::checkAssertion(m_count < 1000 * 1000 * 1000);
        sprintf(digits, "%09ld", m_count);
        ++m_count;
        const std::string suffix = ptr; // deep copy just after "uid-<digits>-"

        std::stringstream ss;
        ss << "uid-" << digits << "-" << suffix;
        return ss.str();
    }

    const char* UidIdentifierProcessor::unexpand(const char* spelling, StringBuffer& buf) const

    {
        //--------
        // Common case optimizations
        //--------
        if (strchr(spelling, '.') == nullptr)
        {
            return unexpandOne(spelling, buf);
        }
        if (strstr(spelling, "uid-") == nullptr)
        {
            return spelling;
        }

        //--------
        // Let's break apart the scoped name, unexpand each local part
        // and then recombine the parts into an unexpanded scoped name.
        //--------
        StringBuffer result;
        StringBuffer msg;
        const char* str;

        StringVector vec{util::splitScopes(spelling)};
        const int len = vec.size();
        for (int i = 0; i < len; ++i)
        {
            try
            {
                str = unexpandOne(vec[i].c_str(), buf);
            }
            catch (const ConfigurationException&)
            {
                msg << "'" << spelling << "' is not a legal identifier";
                throw ConfigurationException(msg.str());
            }
            result.append(str);
            if (i < len - 1)
            {
                result.append(".");
            }
        }
        buf = result.str();
        return buf.str().c_str();
    }

    const char* UidIdentifierProcessor::unexpandOne(const char* spelling, StringBuffer& buf) const

    {
        int count;
        const char* ptr;

        //--------
        // If spelling does not start with "uid-<digits>-" then do nothing.
        //--------
        ptr = spelling;
        if (strncmp(ptr, "uid-", 4) != 0)
        {
            return spelling;
        }
        ptr += 4; // skip over "uid-"
        count = 0;
        while (isdigit(*ptr))
        {
            ++ptr;
            ++count;
        }
        if (count == 0 || *ptr != '-')
        {
            return spelling;
        }

        //--------
        // Okay, let's returned a modified spelling.
        //--------
        StringBuffer suffix;

        suffix = (ptr + 1); // deep copy from just after "uid-<digits>-"
        buf.clear();
        buf << "uid-" << suffix;
        return buf.str().c_str();
    }
}
<commit_msg>C Api replaced.<commit_after>// Copyright (c) 2017 offa
// Copyright 2011 Ciaran McHale.
//
// 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 "danek/internal/UidIdentifierProcessor.h"
#include "danek/internal/Util.h"
#include "danek/internal/Compat.h"
#include "danek/ConfigurationException.h"
#include "danek/StringVector.h"
#include <sstream>
#include <iomanip>
#include <string.h>
#include <ctype.h>
#include <stdio.h>

namespace danek
{
    namespace
    {
        std::string formatCount(std::size_t count)
        {
            constexpr std::size_t numDigits = 9;
            std::ostringstream ss;
            ss << std::setw(numDigits) << std::setfill('0') << count;
            return ss.str();
        }
    }

    UidIdentifierProcessor::UidIdentifierProcessor() : m_count(0)
    {
    }

    //----------------------------------------------------------------------
    // Spelling must be in one of the following forms:
    //      - "foo"                 -->  "foo"
    //      - "uid-<foo>"           -->  "uid-<digits>-<foo>"
    //      - "uid-<digits>-<foo>"  -->  "uid-<new-digits>-<foo>"
    // where "<foo>" does NOT start with a digit or "-"
    //----------------------------------------------------------------------

    void UidIdentifierProcessor::expand(StringBuffer& spelling)
    {
        //--------
        // Common case optimizations
        //--------
        if (strchr(spelling.str().c_str(), '.') == nullptr)
        {
            spelling = expandOne(spelling.str());
            return;
        }
        if (strstr(spelling.str().c_str(), "uid-") == nullptr)
        {
            return;
        }

        //--------
        // Let's break apart the scoped name, expand each local part
        // and then recombine the parts into an expanded scoped name.
        //--------
        StringBuffer buf;
        StringBuffer msg;
        StringBuffer result;

        StringVector vec{util::splitScopes(spelling.str())};
        const int len = vec.size();
        for (int i = 0; i < len; ++i)
        {
            buf = vec[i];
            try
            {
                buf = expandOne(buf.str());
            }
            catch (const ConfigurationException&)
            {
                msg << "'" << spelling << "' is not a legal identifier";
                throw ConfigurationException(msg.str());
            }
            result.append(buf);
            if (i < len - 1)
            {
                result.append(".");
            }
        }
        spelling = result;
    }

    std::string UidIdentifierProcessor::expandOne(const std::string& spelling)
    {
        //--------
        // If spelling does not start with "uid-" then do nothing.
        //--------
        const char* ptr = spelling.c_str();

        if (strncmp(ptr, "uid-", 4) != 0)
        {
            return spelling;
        }

        StringBuffer msg;
        msg << "'" << spelling << "' is not a legal identifier";

        //--------
        // Check for "uid-" (with no suffix), because that is illegal
        //--------
        if (ptr[4] == '\0')
        {
            throw ConfigurationException(msg.str());
        }
        if (ptr[4] == '-')
        {
            // illegal: "uid--foo"
            throw ConfigurationException(msg.str());
        }

        if (!isdigit(ptr[4]))
        {
            //--------
            // "uid-foo"  --> "uid-<digits>-foo"
            //--------
            compat::checkAssertion(m_count < 1000 * 1000 * 1000);
            const std::string suffix = &(spelling.c_str()[4]); // deep copy

            std::stringstream ss;
            ss << "uid-" << formatCount(m_count) << "-" << suffix;
            ++m_count;
            return ss.str();
        }

        ptr += 4; // skip over "uid-"
        int count = 0;
        while (isdigit(*ptr))
        {
            ++ptr;
            ++count;
        }
        compat::checkAssertion(count > 0);
        if (*ptr == '\0' || *ptr != '-')
        {
            // illegal: "uid-<digits>" or "uid-<digits>foo"
            throw ConfigurationException(msg.str());
        }
        ++ptr; // point to just after "uid-<digits>-"
        if (*ptr == '\0')
        {
            // illegal: "uid-<digits>-"
            throw ConfigurationException(msg.str());
        }
        if (*ptr == '-')
        {
            // illegal: "uid-<digits>--"
            throw ConfigurationException(msg.str());
        }
        if (isdigit(*(ptr)))
        {
            // illegal: "uid-<digits>-<digits>foo"
            throw ConfigurationException(msg.str());
        }
        compat::checkAssertion(m_count < 1000 * 1000 * 1000);
        const std::string suffix = ptr; // deep copy just after "uid-<digits>-"

        std::stringstream ss;
        ss << "uid-" << formatCount(m_count) << "-" << suffix;
        ++m_count;
        return ss.str();
    }

    const char* UidIdentifierProcessor::unexpand(const char* spelling, StringBuffer& buf) const

    {
        //--------
        // Common case optimizations
        //--------
        if (strchr(spelling, '.') == nullptr)
        {
            return unexpandOne(spelling, buf);
        }
        if (strstr(spelling, "uid-") == nullptr)
        {
            return spelling;
        }

        //--------
        // Let's break apart the scoped name, unexpand each local part
        // and then recombine the parts into an unexpanded scoped name.
        //--------
        StringBuffer result;
        StringBuffer msg;
        const char* str;

        StringVector vec{util::splitScopes(spelling)};
        const int len = vec.size();
        for (int i = 0; i < len; ++i)
        {
            try
            {
                str = unexpandOne(vec[i].c_str(), buf);
            }
            catch (const ConfigurationException&)
            {
                msg << "'" << spelling << "' is not a legal identifier";
                throw ConfigurationException(msg.str());
            }
            result.append(str);
            if (i < len - 1)
            {
                result.append(".");
            }
        }
        buf = result.str();
        return buf.str().c_str();
    }

    const char* UidIdentifierProcessor::unexpandOne(const char* spelling, StringBuffer& buf) const

    {
        int count;
        const char* ptr;

        //--------
        // If spelling does not start with "uid-<digits>-" then do nothing.
        //--------
        ptr = spelling;
        if (strncmp(ptr, "uid-", 4) != 0)
        {
            return spelling;
        }
        ptr += 4; // skip over "uid-"
        count = 0;
        while (isdigit(*ptr))
        {
            ++ptr;
            ++count;
        }
        if (count == 0 || *ptr != '-')
        {
            return spelling;
        }

        //--------
        // Okay, let's returned a modified spelling.
        //--------
        StringBuffer suffix;

        suffix = (ptr + 1); // deep copy from just after "uid-<digits>-"
        buf.clear();
        buf << "uid-" << suffix;
        return buf.str().c_str();
    }
}
<|endoftext|>


<commit_before>#include "exists.h"
#include <sys/stat.h>

namespace z
{
	namespace file
	{
		bool exists(const zpath& pathname)
		{
			struct stat info;

			if (stat((char*)pathname.cstring(), &info) != 0)
				return true; //directory item exists
			else
				return false; //does not exist
		}
	}
}
<commit_msg>fix file existence check<commit_after>#include "exists.h"
#include <sys/stat.h>

namespace z
{
	namespace file
	{
		bool exists(const zpath& pathname)
		{
			struct stat info;

			if (stat((char*)pathname.cstring(), &info) == 0)
				return true; //directory item exists
			else
				return false; //does not exist
		}
	}
}
<|endoftext|>


<commit_before>/**
 * Copyright (c) Sjors Gielen, 2011
 * See LICENSE for license.
 */

#include <QtCore/QList>
#include <QtCore/QDebug>
#include <QtCore/QFile>
#include <QtNetwork/QTcpServer>
#include <QtNetwork/QTcpSocket>
#include <QtNetwork/QHostAddress>
#include <QtNetwork/QHostInfo>
#include <QtNetwork/QLocalServer>
#include <QtNetwork/QLocalSocket>
#define __STDC_LIMIT_MACROS
#include <stdint.h>

#include "socketplugin.h"
#include "pluginmanager.h"
#include "davinci.h"

SocketPlugin::SocketPlugin( PluginManager *man )
: Plugin( "SocketPlugin", man )
{}

SocketPlugin::~SocketPlugin() {
	qDeleteAll(sockets_);
	qDeleteAll(tcpServers_);
}

void SocketPlugin::init() {
	int sockets = getConfig("sockets").toInt();
	for(int i = 1; i <= sockets; ++i) {
		QString socket = getConfig("socket" + QString::number(i)).toString();
		int colon = socket.indexOf(':');
		if(colon == -1) {
			qWarning() << "(SocketPlugin) Did not understand socket option " << i << ":" << socket;
			continue;
		}
		QString socketType = socket.left(colon);
		socket = socket.mid(colon + 1);
		if(socketType == "unix") {
			QFile::remove(socket);
			QLocalServer *server = new QLocalServer();
			if(!server->listen(socket)) {
				qWarning() << "(SocketPlugin) Failed to start listening for local connections on "
				           << socket << ": " << server->errorString();
				continue;
			}
			connect(server, SIGNAL(newConnection()),
			        this,   SLOT(newLocalConnection()));
			localServers_.append(server);
		} else if(socketType == "tcp") {
			colon = socket.indexOf(':');
			QString tcpHost, tcpPort;
			if(colon == -1) {
				tcpHost = "localhost";
				tcpPort = socket;
			} else {
				tcpHost = socket.left(colon);
				tcpPort = socket.mid(colon + 1);
			}
			bool ok = false;
			unsigned int port = tcpPort.toUInt(&ok);
			if(!ok || port > UINT16_MAX) {
				qWarning() << "(SocketPlugin) Invalid TCP port number for socket " << i;
				continue;
			}
			QHostAddress host(tcpHost);
			if(tcpHost == "*") {
				host = QHostAddress::Any;
			} else if(host.isNull()) {
				QHostInfo info = QHostInfo::fromName(tcpHost);
				if(info.error() != QHostInfo::NoError || info.addresses().length() == 0) {
					qWarning() << "(SocketPlugin) Couldn't resolve TCP host for socket "
					           << i << ": " << info.errorString();
					continue;
				}
				host = info.addresses().at(0);
			}
			QTcpServer *server = new QTcpServer();
			if(!server->listen(host, port)) {
				qWarning() << "(SocketPlugin) Failed to start listening for TCP connections: " << server->errorString();
				continue;
			}
			connect(server, SIGNAL(newConnection()),
			        this,   SLOT(newTcpConnection()));
			tcpServers_.append(server);
		} else {
			qWarning() << "(SocketPlugin) Skipping socket " << i << ": unknown type " << socketType;
		}
	}
}

void SocketPlugin::newTcpConnection() {
	for(int i = 0; i < tcpServers_.length(); ++i) {
		QTcpServer *s = tcpServers_[i];
		if(!s->isListening()) {
			qWarning() << "Something is wrong: TCP server is not listening anymore\n";
			qWarning() << s->serverAddress() << s->serverPort() << s->errorString();
			continue;
		}
		while(s->hasPendingConnections()) {
			QTcpSocket *sock = s->nextPendingConnection();
			sock->setParent(this);
			connect(sock, SIGNAL(readyRead()), this, SLOT(poll()));
			sockets_.append(sock);
		}
	}
}

void SocketPlugin::newLocalConnection() {
	for(int i = 0; i < localServers_.length(); ++i) {
		QLocalServer *s = localServers_[i];
		if(!s->isListening()) {
			qWarning() << "Something is wrong: local server is not listening anymore\n";
			qWarning() << s->serverName() << s->errorString();
			continue;
		}
		while(s->hasPendingConnections()) {
			QLocalSocket *sock = s->nextPendingConnection();
			sock->setParent(this);
			connect(sock, SIGNAL(readyRead()), this, SLOT(poll()));
			sockets_.append(sock);
		}
	}
}

void SocketPlugin::poll() {
	QList<int> toRemove_;
	for(int i = 0; i < sockets_.length(); ++i) {
		QIODevice *dev = sockets_[i];
		if(!dev->isOpen()) {
			toRemove_.append(i);
			continue;
		}
		while(dev->isOpen() && dev->canReadLine()) {
			QByteArray line = dev->readLine().trimmed();
			handle(dev, line);
		}
	}
	foreach(int i, toRemove_) {
		sockets_.removeAt(i);
	}
}

void SocketPlugin::handle(QIODevice *dev, const QByteArray &line) {
	if(!dev->isOpen()) return;
	const QList<Network*> &networks = manager()->bot()->networks();
	if(line.startsWith("?networks")) {
		QString response;
		foreach(const Network *n, networks) {
			response += n->networkName() + " ";
		}
		response = response.left(response.length() - 1);
		dev->write(QString(response + "\n").toLatin1());
	} else if(line.startsWith("?channels ")) {
		QString network = line.mid(10);
		const Network *net = 0;
		foreach(const Network *n, networks) {
			if(n->networkName() == network) {
				net = n; break;
			}
		}
		if(net == 0) {
			dev->write(QString("NAK '" + network + "'\n").toLatin1());
			return;
		} else {
			// TODO FIXME
			dev->write("TODO\n");
		}
	} else if(line.startsWith("!msg ")) {
		int space1 = line.indexOf(' ', 5);
		int space2 = line.indexOf(' ', space1 + 1);
		if(space1 == -1 || space2 == -1) {
			dev->write("Usage: !msg <net> <chan> <len>\n");
			return;
		}
		QString network = line.mid(5, space1 - 5);
		QString channel = line.mid(space1 + 1, space2 - space1 - 1);
		QString len     = line.mid(space2 + 1);

		unsigned int length = len.toUInt();
		if(length == 0 || length > 512) {
			qWarning() << "Invalid length " << length << " in SocketPlugin";
			dev->write("NAK, invalid length\n");
			return;
		}

		Network *net = 0;
		foreach(Network *n, networks) {
			if(n->networkName() == network) {
				net = n; break;
			}
		}
		if(net == 0) {
			dev->write(QString("NAK '" + network + "'\n").toLatin1());
			return;
		} else {
			// TODO: check if channel is joined
			QByteArray message;
			int tries = 5;
			while((unsigned int)message.length() < length && tries >= 0) {
				dev->waitForReadyRead(100);
				message.append(dev->read(length - message.length()));
				tries--;
			}
			if((unsigned int)message.length() == length) {
				net->say(channel, message);
				dev->write("ACK\n");
			} else {
				qWarning() << "Didn't write data: reading took too long.";
				qWarning() << "Wanted " << length << "bytes, got " << message.length();
				dev->close(); // unread data still coming, ignore it
				return;
			}
		}
	} else {
		dev->write("This is DaZeus 2.0 SocketPlugin. Usage:\n");
		dev->write("?networks, ?channels <net>, !msg <net> <chan> <len>\n");
	}
}
<commit_msg>Read new contents into a char*, and turn it into QString using fromUtf8() in one go.<commit_after>/**
 * Copyright (c) Sjors Gielen, 2011
 * See LICENSE for license.
 */

#include <QtCore/QList>
#include <QtCore/QDebug>
#include <QtCore/QFile>
#include <QtNetwork/QTcpServer>
#include <QtNetwork/QTcpSocket>
#include <QtNetwork/QHostAddress>
#include <QtNetwork/QHostInfo>
#include <QtNetwork/QLocalServer>
#include <QtNetwork/QLocalSocket>
#define __STDC_LIMIT_MACROS
#include <stdint.h>

#include "socketplugin.h"
#include "pluginmanager.h"
#include "davinci.h"

SocketPlugin::SocketPlugin( PluginManager *man )
: Plugin( "SocketPlugin", man )
{}

SocketPlugin::~SocketPlugin() {
	qDeleteAll(sockets_);
	qDeleteAll(tcpServers_);
}

void SocketPlugin::init() {
	int sockets = getConfig("sockets").toInt();
	for(int i = 1; i <= sockets; ++i) {
		QString socket = getConfig("socket" + QString::number(i)).toString();
		int colon = socket.indexOf(':');
		if(colon == -1) {
			qWarning() << "(SocketPlugin) Did not understand socket option " << i << ":" << socket;
			continue;
		}
		QString socketType = socket.left(colon);
		socket = socket.mid(colon + 1);
		if(socketType == "unix") {
			QFile::remove(socket);
			QLocalServer *server = new QLocalServer();
			if(!server->listen(socket)) {
				qWarning() << "(SocketPlugin) Failed to start listening for local connections on "
				           << socket << ": " << server->errorString();
				continue;
			}
			connect(server, SIGNAL(newConnection()),
			        this,   SLOT(newLocalConnection()));
			localServers_.append(server);
		} else if(socketType == "tcp") {
			colon = socket.indexOf(':');
			QString tcpHost, tcpPort;
			if(colon == -1) {
				tcpHost = "localhost";
				tcpPort = socket;
			} else {
				tcpHost = socket.left(colon);
				tcpPort = socket.mid(colon + 1);
			}
			bool ok = false;
			unsigned int port = tcpPort.toUInt(&ok);
			if(!ok || port > UINT16_MAX) {
				qWarning() << "(SocketPlugin) Invalid TCP port number for socket " << i;
				continue;
			}
			QHostAddress host(tcpHost);
			if(tcpHost == "*") {
				host = QHostAddress::Any;
			} else if(host.isNull()) {
				QHostInfo info = QHostInfo::fromName(tcpHost);
				if(info.error() != QHostInfo::NoError || info.addresses().length() == 0) {
					qWarning() << "(SocketPlugin) Couldn't resolve TCP host for socket "
					           << i << ": " << info.errorString();
					continue;
				}
				host = info.addresses().at(0);
			}
			QTcpServer *server = new QTcpServer();
			if(!server->listen(host, port)) {
				qWarning() << "(SocketPlugin) Failed to start listening for TCP connections: " << server->errorString();
				continue;
			}
			connect(server, SIGNAL(newConnection()),
			        this,   SLOT(newTcpConnection()));
			tcpServers_.append(server);
		} else {
			qWarning() << "(SocketPlugin) Skipping socket " << i << ": unknown type " << socketType;
		}
	}
}

void SocketPlugin::newTcpConnection() {
	for(int i = 0; i < tcpServers_.length(); ++i) {
		QTcpServer *s = tcpServers_[i];
		if(!s->isListening()) {
			qWarning() << "Something is wrong: TCP server is not listening anymore\n";
			qWarning() << s->serverAddress() << s->serverPort() << s->errorString();
			continue;
		}
		while(s->hasPendingConnections()) {
			QTcpSocket *sock = s->nextPendingConnection();
			sock->setParent(this);
			connect(sock, SIGNAL(readyRead()), this, SLOT(poll()));
			sockets_.append(sock);
		}
	}
}

void SocketPlugin::newLocalConnection() {
	for(int i = 0; i < localServers_.length(); ++i) {
		QLocalServer *s = localServers_[i];
		if(!s->isListening()) {
			qWarning() << "Something is wrong: local server is not listening anymore\n";
			qWarning() << s->serverName() << s->errorString();
			continue;
		}
		while(s->hasPendingConnections()) {
			QLocalSocket *sock = s->nextPendingConnection();
			sock->setParent(this);
			connect(sock, SIGNAL(readyRead()), this, SLOT(poll()));
			sockets_.append(sock);
		}
	}
}

void SocketPlugin::poll() {
	QList<int> toRemove_;
	for(int i = 0; i < sockets_.length(); ++i) {
		QIODevice *dev = sockets_[i];
		if(!dev->isOpen()) {
			toRemove_.append(i);
			continue;
		}
		while(dev->isOpen() && dev->canReadLine()) {
			QByteArray line = dev->readLine().trimmed();
			handle(dev, line);
		}
	}
	foreach(int i, toRemove_) {
		sockets_.removeAt(i);
	}
}

void SocketPlugin::handle(QIODevice *dev, const QByteArray &line) {
	if(!dev->isOpen()) return;
	const QList<Network*> &networks = manager()->bot()->networks();
	if(line.startsWith("?networks")) {
		QString response;
		foreach(const Network *n, networks) {
			response += n->networkName() + " ";
		}
		response = response.left(response.length() - 1);
		dev->write(QString(response + "\n").toLatin1());
	} else if(line.startsWith("?channels ")) {
		QString network = line.mid(10);
		const Network *net = 0;
		foreach(const Network *n, networks) {
			if(n->networkName() == network) {
				net = n; break;
			}
		}
		if(net == 0) {
			dev->write(QString("NAK '" + network + "'\n").toLatin1());
			return;
		} else {
			// TODO FIXME
			dev->write("TODO\n");
		}
	} else if(line.startsWith("!msg ")) {
		int space1 = line.indexOf(' ', 5);
		int space2 = line.indexOf(' ', space1 + 1);
		if(space1 == -1 || space2 == -1) {
			dev->write("Usage: !msg <net> <chan> <len>\\n<payload, utf8 encoded>\n");
			return;
		}
		QString network = line.mid(5, space1 - 5);
		QString channel = line.mid(space1 + 1, space2 - space1 - 1);
		QString len     = line.mid(space2 + 1);

		unsigned int length = len.toUInt();
		if(length == 0 || length > 512) {
			qWarning() << "Invalid length " << length << " in SocketPlugin";
			dev->write("NAK, invalid length\n");
			dev->close();
			return;
		}

		char *rawMessage = new char[length];
		unsigned int lengthRead = 0;
		int tries = 5;
		while(lengthRead < length && tries >= 0) {
			dev->waitForReadyRead(100);
			int lengthRest = length - lengthRead;
			char *messagePart = new char[lengthRest];
			long partRead = dev->read(messagePart, lengthRest);
			if(partRead >= 0) {
				memcpy(rawMessage, messagePart, partRead);
				lengthRead += partRead;
			}
			delete [] messagePart;
			tries--;
		}

		if(lengthRead < length) {
			qWarning() << "Didn't write data: reading took too long.";
			qWarning() << "Wanted " << length << "bytes, got " << lengthRead;
			dev->close(); // unread data still coming, ignore it
			return;
		}

		QString message = QString::fromUtf8(rawMessage, lengthRead);
		delete [] rawMessage;

		foreach(Network *n, networks) {
			if(n->networkName() == network) {
				n->say(channel, message);
				dev->write("ACK\n");
				return;
			}
		}
		qWarning() << "Request for communication to network " << network << ", but that network isn't joined, dropping";
		dev->write(QString("NAK '" + network + "'\n").toLatin1());
	} else {
		dev->write("This is DaZeus 2.0 SocketPlugin. Usage:\n");
		dev->write("?networks, ?channels <net>, !msg <net> <chan> <len>\n");
	}
}
<|endoftext|>


<commit_before>#include <list>
#include <string>
#include <iostream>
namespace edn {
  using std::cout;
  using std::endl;
  using std::string;
  using std::list;

  enum TokenType {
    TokenString,
    TokenAtom,
    TokenParen
  };

  struct EdnToken {
    TokenType type;
    int line;
    string value;
  };

  enum NodeType {
    EdnNil,
    EdnSymbol,
    EdnKeyword,
    EdnBool,
    EdnInt,
    EdnFloat,
    EdnString,
    EdnChar,

    EdnList,
    EdnVector,
    EdnMap,
    EdnSet,

    EdnDiscard,
    EdnTagged
  };

  struct EdnNode {
    NodeType type;
    int line;
    string value;
    list<EdnNode> values;
  };

  void createToken(TokenType type, int line, string value, list<EdnToken> &tokens) {
    EdnToken token;
    token.type = type;
    token.line = line;
    token.value = value;
    tokens.push_back(token);
  }

  list<EdnToken> lex(string edn) {
    string::iterator it;
    int line = 1;
    char escapeChar = '\\';
    bool escaping = false;
    bool inString = false;
    string stringContent = "";
    bool inComment = false;
    string token = "";
    string paren = "";
    list<EdnToken> tokens;

    for (it = edn.begin(); it != edn.end(); ++it) {
      if (*it == '\n' || *it == '\r') line++;

      if (!inString && *it == ';' && !escaping) inComment = true;

      if (inComment) {
        if (*it == '\n') {
          inComment = false;
          if (token != "") {
              createToken(TokenAtom, line, token, tokens);
              token = "";
          }
          continue;
        }
      }

      if (*it == '"' && !escaping) {
        if (inString) {
          createToken(TokenString, line, stringContent, tokens);
          inString = false;
        } else {
          stringContent = "";
          inString = true;
        }
        continue;
      }

      if (inString) {
        if (*it == escapeChar && !escaping) {
          escaping = true;
          continue;
        }

        if (escaping) {
          escaping = false;
          if (*it == 't' || *it == 'n' || *it == 'f' || *it == 'r') stringContent += escapeChar;
        }
        stringContent += *it;
      } else if (*it == '(' || *it == ')' || *it == '[' || *it == ']' || *it == '{' ||
                 *it == '}' || *it == '\t' || *it == '\n' || *it == '\r' || * it == ' ') {
        if (token != "") {
          createToken(TokenAtom, line, token, tokens);
          token = "";
        }
        if (*it == '(' || *it == ')' || *it == '[' || *it == ']' || *it == '{' || *it == '}') {
          paren = "";
          paren += *it;
          createToken(TokenParen, line, paren, tokens);
        }
      } else {
        if (escaping) {
          escaping = false;
        } else if (*it == escapeChar) {
          escaping = true;
        }

        if (token == "#_") {
          createToken(TokenAtom, line, token, tokens);
          token = "";
        }
        token += *it;
      }
    }
    if (token != "") {
      createToken(TokenAtom, line, token, tokens);
    }

    return tokens;
  }

  bool validSymbol(string value) {
    return false;
  }

  bool validNil(string value) {
    return (value == "nil");
  }

  bool validBool(string value) {
    return (value == "true" || value == "false");
  }

  bool validInt(string value) {
    return false;
  }

  bool validFloat(string value) {
    return false;
  }

  bool validChar(string value) {
    return (value.at(0) == '\\' && value.length() == 2);
  }

  EdnNode handleAtom(EdnToken token) {
    EdnNode node;
    node.type = EdnString; // just for debug until rest of valid funcs are working
    node.line = token.line;
    node.value = token.value;

    if (validNil(token.value)) {
      node.type = EdnNil;
    }
    else if (validSymbol(token.value)) {
      if (token.value.at(0) == ':') {
        node.type = EdnKeyword;
      } else {
        node.type = EdnSymbol;
      }
    }
    else if (token.type == TokenString) {
      node.type = EdnString;
    }
    else if (validChar(token.value)) {
      node.type = EdnChar;
    }
    else if (validBool(token.value)) {
      node.type = EdnBool;
    }
    else if (validInt(token.value)) {
      node.type = EdnInt;
    }
    else if (validFloat(token.value)) {
      node.type = EdnFloat;
    }

    return node;
  }

  EdnNode handleCollection(EdnToken token, list<EdnNode> values) {
    EdnNode node;
    node.line = token.line;
    node.values = values;

    if (token.value == "(") {
      node.type = EdnList;
    }
    else if (token.value == "[") {
      node.type = EdnVector;
    }
    if (token.value == "{") {
      node.type = EdnMap;
    }
    return node;
  }

  EdnNode handleTagged(EdnToken token, EdnNode value) {
    EdnNode node;
    node.line = token.line;

    string tagName = token.value.substr(1, token.value.length() - 2);

    if (tagName == "_") {
      node.type = EdnDiscard;
    } else if (tagName == "") {
      //special case where we return early as # { is a set - thus tagname is empty
      node.type = EdnSet;
      if (value.type != EdnMap) {
        throw "Was expection a { } after hash to build set";
      }
      node.values = value.values;
      return node;
    } else {
      node.type = EdnTagged;
    }

    if (!validSymbol(tagName)) {
      throw "Invalid tag name at line: ";
    }

    EdnToken symToken;
    symToken.type = TokenAtom;
    symToken.line = token.line;
    symToken.value = tagName;

    list<EdnNode> values;
    values.push_back(handleAtom(symToken));
    values.push_back(value);

    node.values = values;
    return node;
  }

  EdnToken shiftToken(list<EdnToken> &tokens) {
    EdnToken nextToken = tokens.front();
    tokens.pop_front();
    return nextToken;
  }

  EdnNode readAhead(EdnToken token, list<EdnToken> &tokens) {
    if (token.type == TokenParen) {

      EdnToken nextToken;
      list<EdnNode> L;
      string closeParen;
      if (token.value == "(") closeParen = ")";
      if (token.value == "[") closeParen = "]";
      if (token.value == "{") closeParen = "}";

      while (true) {
        if (tokens.empty()) throw "unexpected end of list";

        nextToken = shiftToken(tokens);

        if (nextToken.value == closeParen) {
          return handleCollection(token, L);
        } else {
          L.push_back(readAhead(nextToken, tokens));
        }
      }
    } else if (token.value == ")" || token.value == "]" || token.value == "}") {
      throw "Unexpected " + token.value;
    } else {
      if (token.value.at(0) == '#') {
        return handleTagged(token, readAhead(shiftToken(tokens), tokens));
      } else {
        return handleAtom(token);
      }
    }
  }

  string pprint(EdnNode node) {
    if (node.type == EdnList || node.type == EdnSet || node.type == EdnVector || node.type == EdnMap) {
      string vals = "";
      for (list<EdnNode>::iterator it=node.values.begin(); it != node.values.end(); ++it) {
        if (vals.length() > 0) {
          vals += " ";
        }
        vals += pprint(*it);
      }

      switch (node.type) {
        case EdnList: return "(" + vals + ")";
        case EdnMap: return "{" + vals + "}";
        case EdnVector: return "[" + vals + "]";
      }
    } else {
      return node.value;
    }
  }

  EdnNode read(string edn) {
    list<EdnToken> tokens = lex(edn);

    if (tokens.size() == 0) {
      throw "No parsable tokens found in string";
    }

    return readAhead(shiftToken(tokens), tokens);
  }
}
<commit_msg>printing tags properly<commit_after>#include <list>
#include <string>
#include <iostream>
namespace edn {
  using std::cout;
  using std::endl;
  using std::string;
  using std::list;

  enum TokenType {
    TokenString,
    TokenAtom,
    TokenParen
  };

  struct EdnToken {
    TokenType type;
    int line;
    string value;
  };

  enum NodeType {
    EdnNil,
    EdnSymbol,
    EdnKeyword,
    EdnBool,
    EdnInt,
    EdnFloat,
    EdnString,
    EdnChar,

    EdnList,
    EdnVector,
    EdnMap,
    EdnSet,

    EdnDiscard,
    EdnTagged
  };

  struct EdnNode {
    NodeType type;
    int line;
    string value;
    list<EdnNode> values;
  };

  void createToken(TokenType type, int line, string value, list<EdnToken> &tokens) {
    EdnToken token;
    token.type = type;
    token.line = line;
    token.value = value;
    tokens.push_back(token);
  }

  list<EdnToken> lex(string edn) {
    string::iterator it;
    int line = 1;
    char escapeChar = '\\';
    bool escaping = false;
    bool inString = false;
    string stringContent = "";
    bool inComment = false;
    string token = "";
    string paren = "";
    list<EdnToken> tokens;

    for (it = edn.begin(); it != edn.end(); ++it) {
      if (*it == '\n' || *it == '\r') line++;

      if (!inString && *it == ';' && !escaping) inComment = true;

      if (inComment) {
        if (*it == '\n') {
          inComment = false;
          if (token != "") {
              createToken(TokenAtom, line, token, tokens);
              token = "";
          }
          continue;
        }
      }

      if (*it == '"' && !escaping) {
        if (inString) {
          createToken(TokenString, line, stringContent, tokens);
          inString = false;
        } else {
          stringContent = "";
          inString = true;
        }
        continue;
      }

      if (inString) {
        if (*it == escapeChar && !escaping) {
          escaping = true;
          continue;
        }

        if (escaping) {
          escaping = false;
          if (*it == 't' || *it == 'n' || *it == 'f' || *it == 'r') stringContent += escapeChar;
        }
        stringContent += *it;
      } else if (*it == '(' || *it == ')' || *it == '[' || *it == ']' || *it == '{' ||
                 *it == '}' || *it == '\t' || *it == '\n' || *it == '\r' || * it == ' ') {
        if (token != "") {
          createToken(TokenAtom, line, token, tokens);
          token = "";
        }
        if (*it == '(' || *it == ')' || *it == '[' || *it == ']' || *it == '{' || *it == '}') {
          paren = "";
          paren += *it;
          createToken(TokenParen, line, paren, tokens);
        }
      } else {
        if (escaping) {
          escaping = false;
        } else if (*it == escapeChar) {
          escaping = true;
        }

        if (token == "#_") {
          createToken(TokenAtom, line, token, tokens);
          token = "";
        }
        token += *it;
      }
    }
    if (token != "") {
      createToken(TokenAtom, line, token, tokens);
    }

    return tokens;
  }

  bool validSymbol(string value) {
    return true;
  }

  bool validNil(string value) {
    return (value == "nil");
  }

  bool validBool(string value) {
    return (value == "true" || value == "false");
  }

  bool validInt(string value) {
    return false;
  }

  bool validFloat(string value) {
    return false;
  }

  bool validChar(string value) {
    return (value.at(0) == '\\' && value.length() == 2);
  }

  EdnNode handleAtom(EdnToken token) {
    EdnNode node;
    node.type = EdnString; // just for debug until rest of valid funcs are working
    node.line = token.line;
    node.value = token.value;

    if (validNil(token.value)) {
      node.type = EdnNil;
    }
    else if (validSymbol(token.value)) {
      if (token.value.at(0) == ':') {
        node.type = EdnKeyword;
      } else {
        node.type = EdnSymbol;
      }
    }
    else if (token.type == TokenString) {
      node.type = EdnString;
    }
    else if (validChar(token.value)) {
      node.type = EdnChar;
    }
    else if (validBool(token.value)) {
      node.type = EdnBool;
    }
    else if (validInt(token.value)) {
      node.type = EdnInt;
    }
    else if (validFloat(token.value)) {
      node.type = EdnFloat;
    }

    return node;
  }

  EdnNode handleCollection(EdnToken token, list<EdnNode> values) {
    EdnNode node;
    node.line = token.line;
    node.values = values;

    if (token.value == "(") {
      node.type = EdnList;
    }
    else if (token.value == "[") {
      node.type = EdnVector;
    }
    if (token.value == "{") {
      node.type = EdnMap;
    }
    return node;
  }

  EdnNode handleTagged(EdnToken token, EdnNode value) {
    EdnNode node;
    node.line = token.line;

    string tagName = token.value.substr(1, token.value.length() - 1);
    if (tagName == "_") {
      node.type = EdnDiscard;
    } else if (tagName == "") {
      //special case where we return early as # { is a set - thus tagname is empty
      node.type = EdnSet;
      if (value.type != EdnMap) {
        throw "Was expection a { } after hash to build set";
      }
      node.values = value.values;
      return node;
    } else {
      node.type = EdnTagged;
    }

    if (!validSymbol(tagName)) {
      throw "Invalid tag name at line: ";
    }

    EdnToken symToken;
    symToken.type = TokenAtom;
    symToken.line = token.line;
    symToken.value = tagName;

    list<EdnNode> values;
    values.push_back(handleAtom(symToken));
    values.push_back(value);

    node.values = values;
    return node;
  }

  EdnToken shiftToken(list<EdnToken> &tokens) {
    EdnToken nextToken = tokens.front();
    tokens.pop_front();
    return nextToken;
  }

  EdnNode readAhead(EdnToken token, list<EdnToken> &tokens) {
    if (token.type == TokenParen) {

      EdnToken nextToken;
      list<EdnNode> L;
      string closeParen;
      if (token.value == "(") closeParen = ")";
      if (token.value == "[") closeParen = "]";
      if (token.value == "{") closeParen = "}";

      while (true) {
        if (tokens.empty()) throw "unexpected end of list";

        nextToken = shiftToken(tokens);

        if (nextToken.value == closeParen) {
          return handleCollection(token, L);
        } else {
          L.push_back(readAhead(nextToken, tokens));
        }
      }
    } else if (token.value == ")" || token.value == "]" || token.value == "}") {
      throw "Unexpected " + token.value;
    } else {
      if (token.value.at(0) == '#') {
        return handleTagged(token, readAhead(shiftToken(tokens), tokens));
      } else {
        return handleAtom(token);
      }
    }
  }

  string pprint(EdnNode node) {
    if (node.type == EdnList || node.type == EdnSet || node.type == EdnVector || node.type == EdnMap) {
      string vals = "";
      for (list<EdnNode>::iterator it=node.values.begin(); it != node.values.end(); ++it) {
        if (vals.length() > 0) {
          vals += " ";
        }
        vals += pprint(*it);
      }

      switch (node.type) {
        case EdnList: return "(" + vals + ")";
        case EdnMap: return "{" + vals + "}";
        case EdnVector: return "[" + vals + "]";
      }
    } else if (node.type == EdnTagged) {
      return "#" + pprint(node.values.front()) + " " + pprint(node.values.back());
    } else {
      return node.value;
    }
  }

  EdnNode read(string edn) {
    list<EdnToken> tokens = lex(edn);

    if (tokens.size() == 0) {
      throw "No parsable tokens found in string";
    }

    return readAhead(shiftToken(tokens), tokens);
  }
}
<|endoftext|>