<commit_before>#include "api/plugin_instance.h"
#include "core/core.h"
#include "core/log.h"
#include "core/math.h"
#include "core/plugin_handler.h"
#include "session/session.h"
#include "settings.h"
//#include <imgui.h>
#include "ui/imgui_setup.h"
#include "ui/menu.h"
#include "ui/dialogs.h"
#include "ui/cursor.h"
#include "ui/ui_render.h"
#include "ui/ui_statusbar.h"
#include "input/input_state.h"

#include <bgfx.h>
#include <bgfxplatform.h>
#include <stdio.h>
#include <stdlib.h>
#include <bx/timer.h>

#ifdef PRODBG_WIN
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif

#include <remotery.h>
#include <assert.h>

#include <foundation/environment.h>
#include <foundation/fs.h>
#include <foundation/string.h>
#include <foundation/path.h>

// TODO: Fix me

int Window_buildPluginMenu(PluginData** plugins, int count);
void Window_addMenu(const char* name, PDMenuItem* items, uint32_t idOffset);

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

struct Context
{
    InputState inputState;
    int width;
    int height;
    uint64_t time;
    Session* session;   // one session right now
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static Context s_context;
//Remotery* s_remotery;

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static const char* s_plugins[] =
{
    "sourcecode_plugin",
    "disassembly_plugin",
    "locals_plugin",
    "callstack_plugin",
    "registers_plugin",
    "breakpoints_plugin",
    "hex_memory_plugin",
    "console_plugin",
    "c64_vice_plugin",
#ifdef PRODBG_MAC
    "lldb_plugin",
#endif
#ifdef PRODBG_WIN
    "dbgeng_plugin",
#endif
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void loadLayout(Session* session, float width, float height)
{
    // TODO: Fix convesion

    if (Session_loadLayout(session, "data/current_layout.json", (int)width, (int)height))
        return;

    if (Session_loadLayout(session, "data/default_layout.json", (int)width, (int)height))
        return;

    Session_createDockingGrid(session, (int)width, (int)height);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

uint32_t findMenuIdRange(PDMenu* menu)
{
    uint32_t idStart = uint32_t(~0);
    uint32_t idEnd = 0;

    while (menu->name)
    {
        PDMenuItem* menuItems = menu->items;

        while (menuItems->name)
        {
            const uint16_t id = menuItems->id;

            if (id > idEnd)
                idEnd = id;

            if (id < idStart)
                idStart = id;

            menuItems++;
        }

        menu++;
    }

    return (idEnd << 16) | idStart;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void createMenusForPlugins()
{
    int count = 0;

    PluginData** plugins = PluginHandler_getBackendPlugins(&count);

    uint32_t menuIdStart = PRODBG_MENU_PLUGINS_START;

    for (int i = 0; i < count; ++i)
    {
        PluginData* pluginData = plugins[i];

        PDBackendPlugin* plugin = (PDBackendPlugin*)pluginData->plugin;

        if (!plugin)
            continue;

        if (!plugin->registerMenu)
            continue;

        PDMenu* menus = plugin->registerMenu();
        uint32_t menuRange = findMenuIdRange(menus);

        while (menus->name)
        {
            Window_addMenu(menus->name, menus->items, menuIdStart);
            menus++;
        }

        pluginData->menuStart = menuIdStart;
        pluginData->menuEnd = menuIdStart + (menuRange >> 16);

        menuIdStart += (menuRange >> 16);
    }
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static bool findDataDirectory()
{
	// check if the data dir is directly here

	if (fs_is_directory("data"))
		return true;

	const char* exe_file_path = environment_executable_path();
	const char* exe_path = path_directory_name(exe_file_path );

	char* path = string_clone(exe_path);

	// search max 10 levels up

	for (int i = 0; i < 10; ++i)
	{
	#if defined(PRODBG_WIN)
		path = string_append(path, "\\..");
	#else
		path = string_append(path, "/..");
	#endif

		environment_set_current_working_directory(path);

		if (fs_is_directory("data"))
			return true;
	}

	return false;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_create(void* window, int width, int height)
{
    Context* context = &s_context;
    //Rect settingsRect;
    //

	Core_init();

	findDataDirectory();

    context->session = Session_create();
    context->time = bx::getHPCounter();

#if PRODBG_USING_DOCKING
    loadLayout(context->session, (float)width, (float)(height - g_statusBarSize));
#endif

    /*
       if (RMT_ERROR_NONE != rmt_CreateGlobalInstance(&s_remotery))
       {
        pd_error("Unable to setup Remotery");
        return;
       }
     */

    //Settings_getWindowRect(&settingsRect);
    //width = settingsRect.width;
    //height = settingsRect.height;

    (void)window;

    for (uint32_t i = 0; i < sizeof_array(s_plugins); ++i)
    {
        PluginHandler_addPlugin(OBJECT_DIR, s_plugins[i]);
    }

#if BX_PLATFORM_OSX
    bgfx::osxSetNSWindow(window);
#elif BX_PLATFORM_WINDOWS
    bgfx::winSetHwnd((HWND)window);
#else
    //bgfx::winSetHwnd(0);
#endif

    bgfx::init();
    bgfx::reset(width, height);
    bgfx::setViewSeq(0, true);

    context->width = width;
    context->height = height;

    IMGUI_setup(width, height);

    Cursor_init();
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static void updateDock(Context* context)
{
    UIDockingGrid* grid = Session_getDockingGrid(context->session);
    const InputState* inputState = &context->inputState;

    switch (UIDock_getSizingState(grid))
    {
        case UIDockSizerDir_None:
        {
            Cunsor_setType(CursorType_Default);
            break;
        }

        case UIDockSizerDir_Horz:
        {
            Cunsor_setType(CursorType_SizeHorizontal);
            break;
        }

        case UIDockSizerDir_Vert:
        {
            Cunsor_setType(CursorType_SizeVertical);
            break;
        }

        case UIDockSizerDir_Both:
        {
            Cunsor_setType(CursorType_SizeAll);
            break;
        }
    }

    UIDock_update(grid, inputState);
    UIDock_renderSizers(grid);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_update()
{
    Context* context = &s_context;

    rmt_ScopedCPUSample(ProDBG_update);

    bgfx::setViewRect(0, 0, 0, (uint16_t)context->width, (uint16_t)context->height);
    bgfx::setViewClear(0, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, 0x101010ff, 1.0f, 0);
    bgfx::submit(0);

    uint64_t currentTime = bx::getHPCounter();
    uint64_t deltaTick = currentTime - context->time;
    context->time = currentTime;

    float deltaTimeMs = (float)(((double)deltaTick) / (double)bx::getHPFrequency());

#if PRODBG_USING_DOCKING
    updateDock(context);
#endif
    {
        rmt_ScopedCPUSample(IMGUI_preUpdate);
        IMGUI_preUpdate(&context->inputState, deltaTimeMs);
    }

    // TODO: Support multiple sessions

    {
        rmt_ScopedCPUSample(Session_update);
        Session_update(context->session);
    }

    UIStatusBar_render();

    //renderTest();

    /*

       bool show = true;

       ImGui::Begin("ImGui Test", &show, ImVec2(550, 480), true, ImGuiWindowFlags_ShowBorders);

       if (ImGui::Button("Test0r testing!"))
       {
        printf("test\n");
       }

       ImGui::End();
     */

    {
        rmt_ScopedCPUSample(IMGUI_postUpdate);
        IMGUI_postUpdate();
    }

    {
        rmt_ScopedCPUSample(bgfx_frame);
        bgfx::frame();
    }
}

// Temprory test for monkey

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_setWindowSize(int width, int height)
{
    Context* context = &s_context;

    context->width = width;
    context->height = height;

    bgfx::reset(width, height);
    IMGUI_updateSize(width, height);

#if PRODBG_USING_DOCKING
    UIDock_updateSize(Session_getDockingGrid(context->session), width, height - (int)g_statusBarSize);
#endif

    ProDBG_update();
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_applicationLaunched()
{
    int pluginCount = 0;
    Window_buildPluginMenu(PluginHandler_getViewPlugins(&pluginCount), pluginCount);
    createMenusForPlugins();
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_destroy()
{
    Context* context = &s_context;

    //rmt_DestroyGlobalInstance(s_remotery);

    UIDock_saveLayout(Session_getDockingGrid(context->session),
                      "data/current_layout.json", (float)context->width, (float)(context->height - g_statusBarSize));

	Session_destroy(context->session);

    Settings_save();
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_timedUpdate()
{
    ProDBG_update();
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static void onLoadRunExec(Session* session, const char* filename)
{
    PluginData* pluginData = PluginHandler_findPlugin(0, "lldb_plugin", "LLDB Mac", true);

    if (!pluginData)
    {
        pd_error("Unable to find LLDB Mac backend\n");
        return;
    }

    Session_startLocal(session, (PDBackendPlugin*)pluginData->plugin, filename);

    // Temp test
    // Session_startLocal(context->session, (PDBackendPlugin*)pluginData->plugin, "t2-output/macosx-clang-debug-default/ProDBG.app/Contents/MacOS/prodbg");
    // Session_startLocal(context->session, (PDBackendPlugin*)pluginData->plugin, OBJECT_DIR "/crashing_native");
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Events

void ProDBG_event(int eventId)
{
    Context* context = &s_context;

    int count;

    PluginData** pluginsData = PluginHandler_getViewPlugins(&count);

    pd_info("eventId 0x%x\n", eventId);

    Vec2 mousePos = context->inputState.mousePos;

#if PRODBG_USING_DOCKING
    if (eventId & PRODBG_MENU_POPUP_SPLIT_HORZ_SHIFT)
    {
        UIDockingGrid* grid = Session_getDockingGrid(context->session);
        UIDock* dockAtMouse = UIDock_getDockAt(grid, (int)mousePos.x, (int)mousePos.y);

        eventId &= (PRODBG_MENU_POPUP_SPLIT_HORZ_SHIFT - 1);

        ViewPluginInstance* instance = PluginInstance_createViewPlugin(pluginsData[eventId]);
        UIDock_splitHorizontal(Session_getDockingGrid(context->session), dockAtMouse, instance);

        Session_addViewPlugin(context->session, instance);
        return;
    }

    if (eventId & PRODBG_MENU_POPUP_SPLIT_VERT_SHIFT)
    {

        UIDockingGrid* grid = Session_getDockingGrid(context->session);
        UIDock* dockAtMouse = UIDock_getDockAt(grid, (int)mousePos.x, (int)mousePos.y);

        eventId &= (PRODBG_MENU_POPUP_SPLIT_VERT_SHIFT - 1);

        ViewPluginInstance* instance = PluginInstance_createViewPlugin(pluginsData[eventId]);
        UIDock_splitVertical(Session_getDockingGrid(context->session), dockAtMouse, instance);

        Session_addViewPlugin(context->session, instance);
        return;
    }

#endif

    // TODO: This code really needs to be made more robust.

    if (eventId >= PRODBG_MENU_PLUGIN_START && eventId < PRODBG_MENU_PLUGIN_START + 9)
    {
        ViewPluginInstance* instance = PluginInstance_createViewPlugin(pluginsData[eventId - PRODBG_MENU_PLUGIN_START]);

        UIDockingGrid* grid = Session_getDockingGrid(context->session);
        UIDock* dockAtMouse = UIDock_getDockAt(grid, 0, 0);
        UIDock_splitVertical(Session_getDockingGrid(context->session), dockAtMouse, instance);

        Session_addViewPlugin(context->session, instance);
        return;
    }

    switch (eventId)
    {
        case PRODBG_MENU_FILE_OPEN_AND_RUN_EXE:
        {
            char filename[4096];

            if (Dialog_open(filename))
            {
                onLoadRunExec(context->session, filename);
            }

            break;
        }

        case PRODBG_MENU_FILE_OPEN_SOURCE:
        {
            char filename[4096];

            if (Dialog_open(filename))
            {
                Session_loadSourceFile(context->session, filename);
            }

            break;
        }

        case PRODBG_MENU_DEBUG_START:
        {
            Session_action(context->session, PDAction_run);
            printf("run....\n");
            break;
        }

        case PRODBG_MENU_DEBUG_ATTACH_TO_REMOTE:
        {
            Session_startRemote(context->session, "127.0.0.1", 1340);
            break;
        }

        case PRODBG_MENU_DEBUG_TOGGLE_BREAKPOINT:
        {
            Session_toggleBreakpointCurrentLine(context->session);
            break;
        }

        case PRODBG_MENU_DEBUG_STEP_OVER:
        {
            Session_stepOver(context->session);
            break;
        }

        case PRODBG_MENU_DEBUG_STEP_IN:
        {
            Session_stepIn(context->session);
            break;
        }
    }

    if (eventId >= PRODBG_MENU_PLUGINS_START)
    {
        Session_onMenu(context->session, eventId);
    }
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_scroll(const PDMouseWheelEvent& wheelEvent)
{
    Context* context = &s_context;
    context->inputState.scrollEvent = wheelEvent;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_setMousePos(float x, float y)
{
    Context* context = &s_context;

    context->inputState.mousePos.x = x;
    context->inputState.mousePos.y = y;

    IMGUI_setInputState(&context->inputState);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_setMouseState(int button, int state)
{
    Context* context = &s_context;
    (void)button;

    InputState* inputState = &context->inputState;

    // TODO: Proper mouse support

    inputState->mouseDown[0] = !!state;

    IMGUI_setInputState(inputState);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_keyDown(int key, int modifier)
{
    IMGUI_setKeyDown(key, modifier);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_keyUp(int key, int modifier)
{
    IMGUI_setKeyUp(key, modifier);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_addChar(unsigned short c)
{
    IMGUI_addInputCharacter(c);
}

<commit_msg>Hopefully fixed windows build<commit_after>#include "api/plugin_instance.h"
#include "core/core.h"
#include "core/log.h"
#include "core/math.h"
#include "core/plugin_handler.h"
#include "session/session.h"
#include "settings.h"
//#include <imgui.h>
#include "ui/imgui_setup.h"
#include "ui/menu.h"
#include "ui/dialogs.h"
#include "ui/cursor.h"
#include "ui/ui_render.h"
#include "ui/ui_statusbar.h"
#include "input/input_state.h"

#include <bgfx.h>
#include <bgfxplatform.h>
#include <stdio.h>
#include <stdlib.h>
#include <bx/timer.h>

#include <remotery.h>
#include <assert.h>

#include <foundation/environment.h>
#include <foundation/fs.h>
#include <foundation/string.h>
#include <foundation/path.h>

// TODO: Fix me

int Window_buildPluginMenu(PluginData** plugins, int count);
void Window_addMenu(const char* name, PDMenuItem* items, uint32_t idOffset);

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

struct Context
{
    InputState inputState;
    int width;
    int height;
    uint64_t time;
    Session* session;   // one session right now
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static Context s_context;
//Remotery* s_remotery;

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static const char* s_plugins[] =
{
    "sourcecode_plugin",
    "disassembly_plugin",
    "locals_plugin",
    "callstack_plugin",
    "registers_plugin",
    "breakpoints_plugin",
    "hex_memory_plugin",
    "console_plugin",
    "c64_vice_plugin",
#ifdef PRODBG_MAC
    "lldb_plugin",
#endif
#ifdef PRODBG_WIN
    "dbgeng_plugin",
#endif
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void loadLayout(Session* session, float width, float height)
{
    // TODO: Fix convesion

    if (Session_loadLayout(session, "data/current_layout.json", (int)width, (int)height))
        return;

    if (Session_loadLayout(session, "data/default_layout.json", (int)width, (int)height))
        return;

    Session_createDockingGrid(session, (int)width, (int)height);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

uint32_t findMenuIdRange(PDMenu* menu)
{
    uint32_t idStart = uint32_t(~0);
    uint32_t idEnd = 0;

    while (menu->name)
    {
        PDMenuItem* menuItems = menu->items;

        while (menuItems->name)
        {
            const uint16_t id = menuItems->id;

            if (id > idEnd)
                idEnd = id;

            if (id < idStart)
                idStart = id;

            menuItems++;
        }

        menu++;
    }

    return (idEnd << 16) | idStart;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void createMenusForPlugins()
{
    int count = 0;

    PluginData** plugins = PluginHandler_getBackendPlugins(&count);

    uint32_t menuIdStart = PRODBG_MENU_PLUGINS_START;

    for (int i = 0; i < count; ++i)
    {
        PluginData* pluginData = plugins[i];

        PDBackendPlugin* plugin = (PDBackendPlugin*)pluginData->plugin;

        if (!plugin)
            continue;

        if (!plugin->registerMenu)
            continue;

        PDMenu* menus = plugin->registerMenu();
        uint32_t menuRange = findMenuIdRange(menus);

        while (menus->name)
        {
            Window_addMenu(menus->name, menus->items, menuIdStart);
            menus++;
        }

        pluginData->menuStart = menuIdStart;
        pluginData->menuEnd = menuIdStart + (menuRange >> 16);

        menuIdStart += (menuRange >> 16);
    }
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static bool findDataDirectory()
{
	// check if the data dir is directly here

	if (fs_is_directory("data"))
		return true;

	const char* exe_file_path = environment_executable_path();
	const char* exe_path = path_directory_name(exe_file_path );

	char* path = string_clone(exe_path);

	// search max 10 levels up

	for (int i = 0; i < 10; ++i)
	{
	#if defined(PRODBG_WIN)
		path = string_append(path, "\\..");
	#else
		path = string_append(path, "/..");
	#endif

		environment_set_current_working_directory(path);

		if (fs_is_directory("data"))
			return true;
	}

	return false;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_create(void* window, int width, int height)
{
    Context* context = &s_context;
    //Rect settingsRect;
    //

	Core_init();

	findDataDirectory();

    context->session = Session_create();
    context->time = bx::getHPCounter();

#if PRODBG_USING_DOCKING
    loadLayout(context->session, (float)width, (float)(height - g_statusBarSize));
#endif

    /*
       if (RMT_ERROR_NONE != rmt_CreateGlobalInstance(&s_remotery))
       {
        pd_error("Unable to setup Remotery");
        return;
       }
     */

    //Settings_getWindowRect(&settingsRect);
    //width = settingsRect.width;
    //height = settingsRect.height;

    (void)window;

    for (uint32_t i = 0; i < sizeof_array(s_plugins); ++i)
    {
        PluginHandler_addPlugin(OBJECT_DIR, s_plugins[i]);
    }

#if BX_PLATFORM_OSX
    bgfx::osxSetNSWindow(window);
#elif BX_PLATFORM_WINDOWS
    bgfx::winSetHwnd((HWND)window);
#else
    //bgfx::winSetHwnd(0);
#endif

    bgfx::init();
    bgfx::reset(width, height);
    bgfx::setViewSeq(0, true);

    context->width = width;
    context->height = height;

    IMGUI_setup(width, height);

    Cursor_init();
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static void updateDock(Context* context)
{
    UIDockingGrid* grid = Session_getDockingGrid(context->session);
    const InputState* inputState = &context->inputState;

    switch (UIDock_getSizingState(grid))
    {
        case UIDockSizerDir_None:
        {
            Cunsor_setType(CursorType_Default);
            break;
        }

        case UIDockSizerDir_Horz:
        {
            Cunsor_setType(CursorType_SizeHorizontal);
            break;
        }

        case UIDockSizerDir_Vert:
        {
            Cunsor_setType(CursorType_SizeVertical);
            break;
        }

        case UIDockSizerDir_Both:
        {
            Cunsor_setType(CursorType_SizeAll);
            break;
        }
    }

    UIDock_update(grid, inputState);
    UIDock_renderSizers(grid);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_update()
{
    Context* context = &s_context;

    rmt_ScopedCPUSample(ProDBG_update);

    bgfx::setViewRect(0, 0, 0, (uint16_t)context->width, (uint16_t)context->height);
    bgfx::setViewClear(0, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, 0x101010ff, 1.0f, 0);
    bgfx::submit(0);

    uint64_t currentTime = bx::getHPCounter();
    uint64_t deltaTick = currentTime - context->time;
    context->time = currentTime;

    float deltaTimeMs = (float)(((double)deltaTick) / (double)bx::getHPFrequency());

#if PRODBG_USING_DOCKING
    updateDock(context);
#endif
    {
        rmt_ScopedCPUSample(IMGUI_preUpdate);
        IMGUI_preUpdate(&context->inputState, deltaTimeMs);
    }

    // TODO: Support multiple sessions

    {
        rmt_ScopedCPUSample(Session_update);
        Session_update(context->session);
    }

    UIStatusBar_render();

    //renderTest();

    /*

       bool show = true;

       ImGui::Begin("ImGui Test", &show, ImVec2(550, 480), true, ImGuiWindowFlags_ShowBorders);

       if (ImGui::Button("Test0r testing!"))
       {
        printf("test\n");
       }

       ImGui::End();
     */

    {
        rmt_ScopedCPUSample(IMGUI_postUpdate);
        IMGUI_postUpdate();
    }

    {
        rmt_ScopedCPUSample(bgfx_frame);
        bgfx::frame();
    }
}

// Temprory test for monkey

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_setWindowSize(int width, int height)
{
    Context* context = &s_context;

    context->width = width;
    context->height = height;

    bgfx::reset(width, height);
    IMGUI_updateSize(width, height);

#if PRODBG_USING_DOCKING
    UIDock_updateSize(Session_getDockingGrid(context->session), width, height - (int)g_statusBarSize);
#endif

    ProDBG_update();
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_applicationLaunched()
{
    int pluginCount = 0;
    Window_buildPluginMenu(PluginHandler_getViewPlugins(&pluginCount), pluginCount);
    createMenusForPlugins();
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_destroy()
{
    Context* context = &s_context;

    //rmt_DestroyGlobalInstance(s_remotery);

    UIDock_saveLayout(Session_getDockingGrid(context->session),
                      "data/current_layout.json", (float)context->width, (float)(context->height - g_statusBarSize));

	Session_destroy(context->session);

    Settings_save();
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_timedUpdate()
{
    ProDBG_update();
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

static void onLoadRunExec(Session* session, const char* filename)
{
    PluginData* pluginData = PluginHandler_findPlugin(0, "lldb_plugin", "LLDB Mac", true);

    if (!pluginData)
    {
        pd_error("Unable to find LLDB Mac backend\n");
        return;
    }

    Session_startLocal(session, (PDBackendPlugin*)pluginData->plugin, filename);

    // Temp test
    // Session_startLocal(context->session, (PDBackendPlugin*)pluginData->plugin, "t2-output/macosx-clang-debug-default/ProDBG.app/Contents/MacOS/prodbg");
    // Session_startLocal(context->session, (PDBackendPlugin*)pluginData->plugin, OBJECT_DIR "/crashing_native");
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Events

void ProDBG_event(int eventId)
{
    Context* context = &s_context;

    int count;

    PluginData** pluginsData = PluginHandler_getViewPlugins(&count);

    pd_info("eventId 0x%x\n", eventId);

    Vec2 mousePos = context->inputState.mousePos;

#if PRODBG_USING_DOCKING
    if (eventId & PRODBG_MENU_POPUP_SPLIT_HORZ_SHIFT)
    {
        UIDockingGrid* grid = Session_getDockingGrid(context->session);
        UIDock* dockAtMouse = UIDock_getDockAt(grid, (int)mousePos.x, (int)mousePos.y);

        eventId &= (PRODBG_MENU_POPUP_SPLIT_HORZ_SHIFT - 1);

        ViewPluginInstance* instance = PluginInstance_createViewPlugin(pluginsData[eventId]);
        UIDock_splitHorizontal(Session_getDockingGrid(context->session), dockAtMouse, instance);

        Session_addViewPlugin(context->session, instance);
        return;
    }

    if (eventId & PRODBG_MENU_POPUP_SPLIT_VERT_SHIFT)
    {

        UIDockingGrid* grid = Session_getDockingGrid(context->session);
        UIDock* dockAtMouse = UIDock_getDockAt(grid, (int)mousePos.x, (int)mousePos.y);

        eventId &= (PRODBG_MENU_POPUP_SPLIT_VERT_SHIFT - 1);

        ViewPluginInstance* instance = PluginInstance_createViewPlugin(pluginsData[eventId]);
        UIDock_splitVertical(Session_getDockingGrid(context->session), dockAtMouse, instance);

        Session_addViewPlugin(context->session, instance);
        return;
    }

#endif

    // TODO: This code really needs to be made more robust.

    if (eventId >= PRODBG_MENU_PLUGIN_START && eventId < PRODBG_MENU_PLUGIN_START + 9)
    {
        ViewPluginInstance* instance = PluginInstance_createViewPlugin(pluginsData[eventId - PRODBG_MENU_PLUGIN_START]);

        UIDockingGrid* grid = Session_getDockingGrid(context->session);
        UIDock* dockAtMouse = UIDock_getDockAt(grid, 0, 0);
        UIDock_splitVertical(Session_getDockingGrid(context->session), dockAtMouse, instance);

        Session_addViewPlugin(context->session, instance);
        return;
    }

    switch (eventId)
    {
        case PRODBG_MENU_FILE_OPEN_AND_RUN_EXE:
        {
            char filename[4096];

            if (Dialog_open(filename))
            {
                onLoadRunExec(context->session, filename);
            }

            break;
        }

        case PRODBG_MENU_FILE_OPEN_SOURCE:
        {
            char filename[4096];

            if (Dialog_open(filename))
            {
                Session_loadSourceFile(context->session, filename);
            }

            break;
        }

        case PRODBG_MENU_DEBUG_START:
        {
            Session_action(context->session, PDAction_run);
            printf("run....\n");
            break;
        }

        case PRODBG_MENU_DEBUG_ATTACH_TO_REMOTE:
        {
            Session_startRemote(context->session, "127.0.0.1", 1340);
            break;
        }

        case PRODBG_MENU_DEBUG_TOGGLE_BREAKPOINT:
        {
            Session_toggleBreakpointCurrentLine(context->session);
            break;
        }

        case PRODBG_MENU_DEBUG_STEP_OVER:
        {
            Session_stepOver(context->session);
            break;
        }

        case PRODBG_MENU_DEBUG_STEP_IN:
        {
            Session_stepIn(context->session);
            break;
        }
    }

    if (eventId >= PRODBG_MENU_PLUGINS_START)
    {
        Session_onMenu(context->session, eventId);
    }
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_scroll(const PDMouseWheelEvent& wheelEvent)
{
    Context* context = &s_context;
    context->inputState.scrollEvent = wheelEvent;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_setMousePos(float x, float y)
{
    Context* context = &s_context;

    context->inputState.mousePos.x = x;
    context->inputState.mousePos.y = y;

    IMGUI_setInputState(&context->inputState);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_setMouseState(int button, int state)
{
    Context* context = &s_context;
    (void)button;

    InputState* inputState = &context->inputState;

    // TODO: Proper mouse support

    inputState->mouseDown[0] = !!state;

    IMGUI_setInputState(inputState);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_keyDown(int key, int modifier)
{
    IMGUI_setKeyDown(key, modifier);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_keyUp(int key, int modifier)
{
    IMGUI_setKeyUp(key, modifier);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void ProDBG_addChar(unsigned short c)
{
    IMGUI_addInputCharacter(c);
}

<|endoftext|>


<commit_before>#include <iostream>
#include <string>
#include <signal.h>

#include "thirdparty/tclap/CmdLine.h"

#include <imq/vm.h>
#include <imq/parser.h>
#include <imq/result.h>
#include <imq/library.h>
#include <imq/value.h>
#include <imq/image.h>
#include <imq/errors.h>
#include <imq/cast.h>
#include <imq/platform.h>

using namespace imq;

bool bRunning = true;

void sigint_handler(int sig)
{
	bRunning = false;
}

Result iqc_stop(VMachine* vm, int32_t argCount, QValue* args, QValue* result)
{
	bRunning = false;
	return true;
}

struct InputArg
{
	std::string name;
	QValue value;
};

struct IOPair
{
	std::string name;
	std::string value;
};

struct IOPairException
{
	IOPairException(const std::string& err)
		: err(err)
	{
	}

	std::string err;
};

Result saveOutputs(VMachine* vm, const std::vector<IOPair> outputs, bool errorOnInvalidVariable)
{
	for (auto pair : outputs)
	{
		QValue value;
		Result res = vm->getRootContext()->getValue(pair.name, &value);
		if (!res)
		{
			if (errorOnInvalidVariable)
				return res;
			else
				continue;
		}

		QObject* obj;
		if (!value.getObject(&obj))
			return Result(false, "Output " + pair.name + " is not a QObject");

		QImage* img = objectCast<QImage>(obj);
		if (!img)
			return Result(false, "Output " + pair.name + " is not a QImage");

		res = img->saveToFile(pair.value.data());
		if (!res)
			return res;
	}

	return true;
}

std::vector<IOPair> parseIOPairs(const std::vector<std::string>& strings)
{
	std::vector<IOPair> results;
	results.reserve(strings.size());
	for (auto str : strings)
	{
		auto eqPos = str.find_first_of('=');
		if (eqPos == std::string::npos)
			throw IOPairException("Invalid expression (missing '=') in " + str);

		IOPair pair;
		pair.name = str.substr(0, eqPos);
		pair.value = str.substr(eqPos + 1);

		results.push_back(pair);
	}

	return results;
}

/* on hold until we have string qvalue support
std::vector<InputArg> parseInputs(VMachine* vm, QueryParser* parser, const std::vector<std::string>& inputStrings)
{
	auto pairs = parseIOPairs(inputStrings);
	std::vector<InputArg> results;
	results.reserve(pairs.size());
	for (auto pair : pairs)
	{
		VExpression* expr;
		Result res = parser->parseExpression(pair.value, &expr);
		if (!res)
			throw IOPairException("Input parser - " + res.getErr());

		InputArg arg;
		arg.name = pair.name;

		res = expr->execute(vm->getRootContext(), &arg.value);
		if (!res)
			throw IOPairException("Input parser - " + res.getErr());

		results.push_back(arg);
	}

	return results;
}
*/

bool execute(VMachine* vm, VBlock* block, const std::vector<IOPair>& outputs, bool bDebugMode)
{
	if (block)
	{
		Result res = vm->execute(block);
		if (!res)
		{
			std::cerr << res.getErr() << std::endl;
			delete block;

			return false;
		}

		res = saveOutputs(vm, outputs, true);
		if (!res)
		{
			std::cerr << res.getErr() << std::endl;
			delete block;
			return false;
		}

		delete block;
		return true;
	}

	vm->getRootContext()->setValue("exit", QValue::Function(vm, iqc_stop));

	QueryParser parser;
	parser.setDebugMode(bDebugMode);

	Result res;
	QValue lastResult;

	signal(SIGINT, sigint_handler);

	while (bRunning)
	{
		lastResult = QValue();
		std::cout << "> ";
		std::string line;
		std::getline(std::cin, line);
		if (line.empty())
			continue;

		res = parser.parseString(line, &block);
		if (!res)
		{
			std::cout << "parse error: " << res.getErr() << std::endl;
			continue;
		}

		if (!block)
			continue;

		block->setEmitLastResult(&lastResult);

		res = vm->execute(block);
		if (!res)
		{
			std::cout << "runtime error: " << res.getErr() << std::endl;
		}

		if (lastResult.getType() != QValue::Type::Nil)
		{
			std::cout << lastResult.toString() << std::endl;
		}

		res = saveOutputs(vm, outputs, false);
		if (!res)
		{
			std::cout << "output save error: " << res.getErr() << std::endl;
		}

		delete block;

		vm->getGC()->collect(true);
	}

	return true;
}

int main(int argc, char** argv)
{
	TCLAP::CmdLine cmd("Interactive frontend to imquery", ' ', IMQ_VERSION_STR);

	TCLAP::ValueArg<std::string> fileArg("f", "file", "The script file to load.", false, "", "string", cmd);
	TCLAP::SwitchArg debugArg("d", "debug", "Enable parser debug mode", cmd, false);

	TCLAP::MultiArg<std::string> inputArg("i", "input", "Inputs, in the form name=filepath", false, "string", cmd);
	TCLAP::MultiArg<std::string> outputArg("o", "output", "Outputs, in the form name=filepath", false, "string", cmd);

	try
	{
		cmd.parse(argc, argv);
	}
	catch (const TCLAP::ArgException& e)
	{
		std::cerr << "error: " << e.error() << " for arg " << e.argId() << std::endl;
		return EXIT_FAILURE;
	}

	VMachine vm;

	std::vector<IOPair> inputs;
	std::vector<IOPair> outputs;

	try
	{
		inputs = parseIOPairs(inputArg.getValue());
		outputs = parseIOPairs(outputArg.getValue());
	}
	catch (const IOPairException& e)
	{
		std::cerr << e.err << std::endl;
		return EXIT_FAILURE;
	}

	for (auto pair : inputs)
	{
		std::cout << "Loading input " << pair.name << " from " << pair.value << std::endl;

		QImage* img;
		Result res = QImage::loadFromFile(&vm, pair.value.data(), &img);
		if (!res)
		{
			std::cerr << "Unable to load input " << pair.name << ": " << res.getErr() << std::endl;
			return EXIT_FAILURE;
		}

		vm.getRootContext()->setInput(pair.name, QValue::Object(img));
	}

	VBlock* block = nullptr;

	Result res = register_stdlib(&vm);
	if (!res)
	{
		std::cerr << "Unable to register stdlib: " << res.getErr() << std::endl;
		return EXIT_FAILURE;
	}

	if (fileArg.isSet())
	{
		QueryParser parser;
		res = parser.parseFile(fileArg.getValue(), &block);
		if (!res)
		{
			std::cerr << res.getErr() << std::endl;
			return EXIT_FAILURE;
		}
	}

	return execute(&vm, block, outputs, debugArg.getValue()) ? EXIT_SUCCESS : EXIT_FAILURE;
}<commit_msg>undo sigint changes, causes unwanted behavior on linux (will fix later)<commit_after>#include <iostream>
#include <string>
#include <signal.h>

#include "thirdparty/tclap/CmdLine.h"

#include <imq/vm.h>
#include <imq/parser.h>
#include <imq/result.h>
#include <imq/library.h>
#include <imq/value.h>
#include <imq/image.h>
#include <imq/errors.h>
#include <imq/cast.h>
#include <imq/platform.h>

using namespace imq;

bool bRunning = true;

Result iqc_stop(VMachine* vm, int32_t argCount, QValue* args, QValue* result)
{
	bRunning = false;
	return true;
}

struct InputArg
{
	std::string name;
	QValue value;
};

struct IOPair
{
	std::string name;
	std::string value;
};

struct IOPairException
{
	IOPairException(const std::string& err)
		: err(err)
	{
	}

	std::string err;
};

Result saveOutputs(VMachine* vm, const std::vector<IOPair> outputs, bool errorOnInvalidVariable)
{
	for (auto pair : outputs)
	{
		QValue value;
		Result res = vm->getRootContext()->getValue(pair.name, &value);
		if (!res)
		{
			if (errorOnInvalidVariable)
				return res;
			else
				continue;
		}

		QObject* obj;
		if (!value.getObject(&obj))
			return Result(false, "Output " + pair.name + " is not a QObject");

		QImage* img = objectCast<QImage>(obj);
		if (!img)
			return Result(false, "Output " + pair.name + " is not a QImage");

		res = img->saveToFile(pair.value.data());
		if (!res)
			return res;
	}

	return true;
}

std::vector<IOPair> parseIOPairs(const std::vector<std::string>& strings)
{
	std::vector<IOPair> results;
	results.reserve(strings.size());
	for (auto str : strings)
	{
		auto eqPos = str.find_first_of('=');
		if (eqPos == std::string::npos)
			throw IOPairException("Invalid expression (missing '=') in " + str);

		IOPair pair;
		pair.name = str.substr(0, eqPos);
		pair.value = str.substr(eqPos + 1);

		results.push_back(pair);
	}

	return results;
}

/* on hold until we have string qvalue support
std::vector<InputArg> parseInputs(VMachine* vm, QueryParser* parser, const std::vector<std::string>& inputStrings)
{
	auto pairs = parseIOPairs(inputStrings);
	std::vector<InputArg> results;
	results.reserve(pairs.size());
	for (auto pair : pairs)
	{
		VExpression* expr;
		Result res = parser->parseExpression(pair.value, &expr);
		if (!res)
			throw IOPairException("Input parser - " + res.getErr());

		InputArg arg;
		arg.name = pair.name;

		res = expr->execute(vm->getRootContext(), &arg.value);
		if (!res)
			throw IOPairException("Input parser - " + res.getErr());

		results.push_back(arg);
	}

	return results;
}
*/

bool execute(VMachine* vm, VBlock* block, const std::vector<IOPair>& outputs, bool bDebugMode)
{
	if (block)
	{
		Result res = vm->execute(block);
		if (!res)
		{
			std::cerr << res.getErr() << std::endl;
			delete block;

			return false;
		}

		res = saveOutputs(vm, outputs, true);
		if (!res)
		{
			std::cerr << res.getErr() << std::endl;
			delete block;
			return false;
		}

		delete block;
		return true;
	}

	vm->getRootContext()->setValue("exit", QValue::Function(vm, iqc_stop));

	QueryParser parser;
	parser.setDebugMode(bDebugMode);

	Result res;
	QValue lastResult;

	while (bRunning)
	{
		lastResult = QValue();
		std::cout << "> ";
		std::string line;
		std::getline(std::cin, line);
		if (line.empty())
			continue;

		res = parser.parseString(line, &block);
		if (!res)
		{
			std::cout << "parse error: " << res.getErr() << std::endl;
			continue;
		}

		if (!block)
			continue;

		block->setEmitLastResult(&lastResult);

		res = vm->execute(block);
		if (!res)
		{
			std::cout << "runtime error: " << res.getErr() << std::endl;
		}

		if (lastResult.getType() != QValue::Type::Nil)
		{
			std::cout << lastResult.toString() << std::endl;
		}

		res = saveOutputs(vm, outputs, false);
		if (!res)
		{
			std::cout << "output save error: " << res.getErr() << std::endl;
		}

		delete block;

		vm->getGC()->collect(true);
	}

	return true;
}

int main(int argc, char** argv)
{
	TCLAP::CmdLine cmd("Interactive frontend to imquery", ' ', IMQ_VERSION_STR);

	TCLAP::ValueArg<std::string> fileArg("f", "file", "The script file to load.", false, "", "string", cmd);
	TCLAP::SwitchArg debugArg("d", "debug", "Enable parser debug mode", cmd, false);

	TCLAP::MultiArg<std::string> inputArg("i", "input", "Inputs, in the form name=filepath", false, "string", cmd);
	TCLAP::MultiArg<std::string> outputArg("o", "output", "Outputs, in the form name=filepath", false, "string", cmd);

	try
	{
		cmd.parse(argc, argv);
	}
	catch (const TCLAP::ArgException& e)
	{
		std::cerr << "error: " << e.error() << " for arg " << e.argId() << std::endl;
		return EXIT_FAILURE;
	}

	VMachine vm;

	std::vector<IOPair> inputs;
	std::vector<IOPair> outputs;

	try
	{
		inputs = parseIOPairs(inputArg.getValue());
		outputs = parseIOPairs(outputArg.getValue());
	}
	catch (const IOPairException& e)
	{
		std::cerr << e.err << std::endl;
		return EXIT_FAILURE;
	}

	for (auto pair : inputs)
	{
		std::cout << "Loading input " << pair.name << " from " << pair.value << std::endl;

		QImage* img;
		Result res = QImage::loadFromFile(&vm, pair.value.data(), &img);
		if (!res)
		{
			std::cerr << "Unable to load input " << pair.name << ": " << res.getErr() << std::endl;
			return EXIT_FAILURE;
		}

		vm.getRootContext()->setInput(pair.name, QValue::Object(img));
	}

	VBlock* block = nullptr;

	Result res = register_stdlib(&vm);
	if (!res)
	{
		std::cerr << "Unable to register stdlib: " << res.getErr() << std::endl;
		return EXIT_FAILURE;
	}

	if (fileArg.isSet())
	{
		QueryParser parser;
		res = parser.parseFile(fileArg.getValue(), &block);
		if (!res)
		{
			std::cerr << res.getErr() << std::endl;
			return EXIT_FAILURE;
		}
	}

	return execute(&vm, block, outputs, debugArg.getValue()) ? EXIT_SUCCESS : EXIT_FAILURE;
}<|endoftext|>


<commit_before>//
// gsl-lite is based on GSL: Guideline Support Library,
// https://github.com/microsoft/gsl
//
// Copyright (c) 2015 Martin Moene
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
//
// This code is licensed under the MIT License (MIT).
//
// 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 "gsl-lite.t.h"
#include <functional>

CASE( "finally: Allows lambda to run" )
{
#if gsl_CPP11_OR_GREATER
    struct F { static void incr( int & i ) { i += 1; } };

    int i = 0;
    {
        auto _ = finally( [&]() { F::incr( i ); } );
        EXPECT( i == 0 );
    }
    EXPECT( i == 1 );
#else
    EXPECT( !!"lambda is not available (no C++11)" );
#endif
}

CASE( "finally: Allows function with bind" )
{
#if gsl_CPP11_OR_GREATER
    struct F { static void incr( int & i ) { i += 1; } };

    int i = 0;
    {
        auto _ = finally( std::bind( &F::incr, std::ref( i ) ) );
        EXPECT( i == 0 );
    }
    EXPECT( i == 1 );
#else
    EXPECT( !!"auto and std::ref perhaps not available (no C++11)" );
#endif
}

int g_i = 0;

CASE( "finally: Allows pointer to function" )
{
    struct F { static void incr() { g_i += 1; } };

#if gsl_CPP11_OR_GREATER

    g_i = 0;
    {
        auto _ = finally( &F::incr );
        EXPECT( g_i == 0 );
    }
    EXPECT( g_i == 1 );
#else
    g_i = 0;
    {
        final_act _ = finally( &F::incr );
        EXPECT( g_i == 0 );
    }
    EXPECT( g_i == 1 );
#endif
}

CASE( "finally: Allows to move final_act" )
{
#if gsl_CPP11_OR_GREATER
    struct F { static void incr( int & i ) { i += 1; } };

    int i = 0;
    {
        auto _1 = finally( [&]() { F::incr( i ); } );
        {
            auto _2 = std::move( _1 );
            EXPECT( i == 0 );
        }
        EXPECT( i == 1 );
        {
            auto _2 = std::move( _1 );
            EXPECT( i == 1 );
        }
        EXPECT( i == 1 );
    }
    EXPECT( i == 1 );
#else
    struct F { static void incr() { g_i += 1; } };

    g_i = 0;
    {
        final_act _1 = finally( &F::incr );
        {
            final_act _2 = _1;
            EXPECT( g_i == 0 );
        }
        EXPECT( g_i == 1 );
        {
            final_act _2 = _1;
            EXPECT( g_i == 1 );
        }
        EXPECT( g_i == 1 );
    }
    EXPECT( g_i == 1 );
#endif
}

CASE( "finally: Allows moving final_act to throw" "[.]")
{
#if gsl_CPP11_OR_GREATER
    struct action
    {
        int & i_;
        void operator()(){ i_ += 1; }
        action( int & i ) : i_( i ) {}
        action( action && other ) : i_( other.i_) { throw std::runtime_error("action move-ctor"); }
    };

    int i = 0;
    {
        {
            EXPECT_THROWS( finally( action( i ) ) );
        }
        EXPECT( i == 1 );
    }

    // ...
#else
    EXPECT( !!"lambda is not available (no C++11)" );
#endif
}

CASE( "narrow_cast<>: Allows narrowing without value loss" )
{
    EXPECT( narrow_cast<char>( 120 ) == 120 );
}

CASE( "narrow_cast<>: Allows narrowing with value loss" )
{
    EXPECT( narrow_cast<unsigned char>( 300 ) == 44 );
}

CASE( "narrow<>(): Allows narrowing without value loss" )
{
    EXPECT( narrow<char>( 120 ) == 120 );
}

CASE( "narrow<>(): Terminates when narrowing with value loss" )
{
    EXPECT_THROWS_AS( narrow<char>( 300 ), narrowing_error );
}

CASE( "narrow<>(): Terminates when narrowing with sign loss" )
{
    EXPECT_THROWS_AS( narrow<unsigned>( -42 ), narrowing_error );
}

// end of file
<commit_msg>Make g_i unit scope<commit_after>//
// gsl-lite is based on GSL: Guideline Support Library,
// https://github.com/microsoft/gsl
//
// Copyright (c) 2015 Martin Moene
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
//
// This code is licensed under the MIT License (MIT).
//
// 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 "gsl-lite.t.h"
#include <functional>

CASE( "finally: Allows lambda to run" )
{
#if gsl_CPP11_OR_GREATER
    struct F { static void incr( int & i ) { i += 1; } };

    int i = 0;
    {
        auto _ = finally( [&]() { F::incr( i ); } );
        EXPECT( i == 0 );
    }
    EXPECT( i == 1 );
#else
    EXPECT( !!"lambda is not available (no C++11)" );
#endif
}

CASE( "finally: Allows function with bind" )
{
#if gsl_CPP11_OR_GREATER
    struct F { static void incr( int & i ) { i += 1; } };

    int i = 0;
    {
        auto _ = finally( std::bind( &F::incr, std::ref( i ) ) );
        EXPECT( i == 0 );
    }
    EXPECT( i == 1 );
#else
    EXPECT( !!"auto and std::ref perhaps not available (no C++11)" );
#endif
}

namespace{ int g_i = 0; }

CASE( "finally: Allows pointer to function" )
{
    struct F { static void incr() { g_i += 1; } };

#if gsl_CPP11_OR_GREATER

    g_i = 0;
    {
        auto _ = finally( &F::incr );
        EXPECT( g_i == 0 );
    }
    EXPECT( g_i == 1 );
#else
    g_i = 0;
    {
        final_act _ = finally( &F::incr );
        EXPECT( g_i == 0 );
    }
    EXPECT( g_i == 1 );
#endif
}

CASE( "finally: Allows to move final_act" )
{
#if gsl_CPP11_OR_GREATER
    struct F { static void incr( int & i ) { i += 1; } };

    int i = 0;
    {
        auto _1 = finally( [&]() { F::incr( i ); } );
        {
            auto _2 = std::move( _1 );
            EXPECT( i == 0 );
        }
        EXPECT( i == 1 );
        {
            auto _2 = std::move( _1 );
            EXPECT( i == 1 );
        }
        EXPECT( i == 1 );
    }
    EXPECT( i == 1 );
#else
    struct F { static void incr() { g_i += 1; } };

    g_i = 0;
    {
        final_act _1 = finally( &F::incr );
        {
            final_act _2 = _1;
            EXPECT( g_i == 0 );
        }
        EXPECT( g_i == 1 );
        {
            final_act _2 = _1;
            EXPECT( g_i == 1 );
        }
        EXPECT( g_i == 1 );
    }
    EXPECT( g_i == 1 );
#endif
}

CASE( "finally: Allows moving final_act to throw" "[.]")
{
#if gsl_CPP11_OR_GREATER
    struct action
    {
        int & i_;
        void operator()(){ i_ += 1; }
        action( int & i ) : i_( i ) {}
        action( action && other ) : i_( other.i_) { throw std::runtime_error("action move-ctor"); }
    };

    int i = 0;
    {
        {
            EXPECT_THROWS( finally( action( i ) ) );
        }
        EXPECT( i == 1 );
    }

    // ...
#else
    EXPECT( !!"lambda is not available (no C++11)" );
#endif
}

CASE( "narrow_cast<>: Allows narrowing without value loss" )
{
    EXPECT( narrow_cast<char>( 120 ) == 120 );
}

CASE( "narrow_cast<>: Allows narrowing with value loss" )
{
    EXPECT( narrow_cast<unsigned char>( 300 ) == 44 );
}

CASE( "narrow<>(): Allows narrowing without value loss" )
{
    EXPECT( narrow<char>( 120 ) == 120 );
}

CASE( "narrow<>(): Terminates when narrowing with value loss" )
{
    EXPECT_THROWS_AS( narrow<char>( 300 ), narrowing_error );
}

CASE( "narrow<>(): Terminates when narrowing with sign loss" )
{
    EXPECT_THROWS_AS( narrow<unsigned>( -42 ), narrowing_error );
}

// end of file
<|endoftext|>


<commit_before>#include <sql_show.h>
#include "binlog_dump_list.h"
#include <sql_repl.h>

extern I_List<THD> threads;
extern HASH slave_list;
extern const LEX_STRING command_name[];

class thread_info :public ilink
{
public:
  static void *operator new(size_t size)
  {
    return (void*) sql_alloc((uint) size);
  }
  static void operator delete(void *ptr __attribute__((unused)),
                              size_t size __attribute__((unused)))
  { TRASH(ptr, size); }

  THD *thd;
  ulong thread_id;
  const char *host, *status, *user;
  uint32 port;
};

//Copy from sql_show.cc
static const char *thread_state_info(THD *tmp)
{
	if (tmp->net.reading_or_writing) {
		if (tmp->net.reading_or_writing == 2)
			return "Writing to net";
		else if (tmp->command == COM_SLEEP)
			return "";
		else
			return "Reading from net";
	}
	else {
		if (tmp->proc_info)
			return tmp->proc_info;
		else if (tmp->mysys_var && tmp->mysys_var->current_cond)
			return "Waiting on cond";
		else
			return NULL;
	}
}

static int fill_is_table(THD *thd, TABLE_LIST *tables, COND *cond) {
	I_List<thread_info> thread_infos;

	//collect thread infos
	mysql_mutex_lock(&LOCK_thread_count);
    I_List_iterator<THD> iter(threads);
    THD *tmp;
    #ifdef DEBUG_PLUGIN
    	fprintf(stderr, "[binlog_dump_list] start fill IS table\n");
    #endif
    while (tmp=iter++) {
    	if (tmp->system_thread || tmp->vio_ok()) {
   			#ifdef DEBUG_PLUGIN
    			fprintf(stderr, "[binlog_dump_list] found one thread\n");
    		#endif
    		Security_context *tmp_sctx = tmp->security_ctx;
    		if (NULL == tmp_sctx) {
                fprintf(stderr, "[binlog_dump_list] got THD->security_ctx == NULL, maybe the plugin is not compatible with the mysqld, make sure the version is match, so is --with-debug\n");
				mysql_mutex_unlock(&LOCK_thread_count);
                return 1;
    		}

		    #ifdef DEBUG_PLUGIN
	    		fprintf(stderr, "[binlog_dump_list] thread command is %s\n", command_name[tmp->command].str);
		    #endif
    		if (NULL == tmp->command || 0 != strcmp("Binlog Dump", command_name[tmp->command].str)) {
    			continue;
    		}

    		//thread_id
    		thread_info *thd_info = new thread_info;
    		thd_info->thd = tmp;
    		thd_info->thread_id = tmp->thread_id;

			//host
			if (thd_info->host= (char*) thd->alloc(LIST_PROCESS_HOST_LEN+1)) {
	    		my_snprintf((char *) thd_info->host, LIST_PROCESS_HOST_LEN, "%s", tmp_sctx->host_or_ip);
			} else {
				fprintf(stderr, "[binlog_dump_list] cannot allocate thd_info->host\n");
				mysql_mutex_unlock(&LOCK_thread_count);
                return 1;
			}

			//user
        	thd_info->user= thd->strdup(tmp_sctx->user ? tmp_sctx->user :
                                    (tmp->system_thread ? "system user" : "unauthenticated user"));

			//status
        	mysql_mutex_lock(&tmp->LOCK_thd_data);
      		struct st_my_thread_var *mysys_var;
	        if (mysys_var= tmp->mysys_var)
	        	mysql_mutex_lock(&mysys_var->mutex); //thread_state_info will use mysys_var lock
        	thd_info->status= thread_state_info(tmp);
	        if (mysys_var)
	        	mysql_mutex_unlock(&mysys_var->mutex);
        	mysql_mutex_unlock(&tmp->LOCK_thd_data);

    		thread_infos.append(thd_info);
    	}
	}
	mysql_mutex_unlock(&LOCK_thread_count);

	//collect slave info

	mysql_mutex_lock(&LOCK_slave_list);
	for (uint i = 0; i < slave_list.records; ++i)
	{
	    #ifdef DEBUG_PLUGIN
			fprintf(stderr, "[binlog_dump_list] found one slave info\n");
		#endif
		SLAVE_INFO* si = (SLAVE_INFO*) my_hash_element(&slave_list, i);
    	I_List_iterator<thread_info> iter(thread_infos);
    	thread_info *info;
    	while ((info = iter++) && (info->thd != si->thd));
    	if (NULL != info) {
    		info->port = (uint32) si->port;
    	}
	}
	mysql_mutex_unlock(&LOCK_slave_list);

	//fill IS table
	CHARSET_INFO *cs = system_charset_info;
	TABLE *table = tables->table;
	thread_info *thd_info;
	while (thd_info = thread_infos.get()) {
		table->field[0]->store(thd_info->thread_id);
		table->field[1]->store(thd_info->host, strlen(thd_info->host), cs);
		table->field[2]->store(thd_info->port);
		table->field[3]->store(thd_info->user, strlen(thd_info->user), cs);
		table->field[4]->store(thd_info->status, strlen(thd_info->status), cs);
		if (schema_table_store_record(thd, table))
			return 1;
	}

	return 0;
}

static int init_plugin(void *p) {
	ST_SCHEMA_TABLE *schema = (ST_SCHEMA_TABLE*) p;
	schema->fields_info = is_table_fields;
	schema->fill_table = fill_is_table;
	fprintf(stderr, "binlog_dump_list plugin started\n");

	//print sizeof(some struct), in case that the plugin is not compiled compatible with mysqld
    #ifdef DEBUG_PLUGIN
		fprintf(stderr, "[binlog_dump_list] sizeof(Statement)=%d\n", sizeof(Statement));
		fprintf(stderr, "[binlog_dump_list] sizeof(Open_tables_state)=%d\n", sizeof(Open_tables_state));
		fprintf(stderr, "[binlog_dump_list] sizeof(THD)=%d\n", sizeof(THD));
		fprintf(stderr, "[binlog_dump_list] sizeof(NET)=%d\n", sizeof(NET));
		fprintf(stderr, "[binlog_dump_list] sizeof(Protocol_text)=%d\n", sizeof(Protocol_text));
		fprintf(stderr, "[binlog_dump_list] sizeof(Protocol_binary)=%d\n", sizeof(Protocol_binary));
		fprintf(stderr, "[binlog_dump_list] sizeof(Protocol)=%d\n", sizeof(Protocol));
		fprintf(stderr, "[binlog_dump_list] sizeof(rand_struct)=%d\n", sizeof(rand_struct));
		fprintf(stderr, "[binlog_dump_list] sizeof(system_variables)=%d\n", sizeof(system_variables));
		fprintf(stderr, "[binlog_dump_list] sizeof(system_status_var)=%d\n", sizeof(system_status_var));
		fprintf(stderr, "[binlog_dump_list] sizeof(THR_LOCK_INFO)=%d\n", sizeof(THR_LOCK_INFO));
		fprintf(stderr, "[binlog_dump_list] sizeof(mysql_mutex_t)=%d\n", sizeof(mysql_mutex_t));
		fprintf(stderr, "[binlog_dump_list] sizeof(Statement_map)=%d\n", sizeof(Statement_map));
		fprintf(stderr, "[binlog_dump_list] sizeof(Security_context)=%d\n", sizeof(Security_context));
    #endif
	return 0;
}

static int deinit_plugin(void *p) {
	fprintf(stderr, "binlog_dump_list plugin stopped\n");
	return 0;
}
<commit_msg>format code<commit_after>#include <sql_show.h>
#include "binlog_dump_list.h"
#include <sql_repl.h>

extern I_List<THD> threads;
extern HASH slave_list;
extern const LEX_STRING command_name[];

class thread_info : public ilink
{
public:
    static void *operator new(size_t size)
    {
        return (void *) sql_alloc((uint) size);
    }
    static void operator delete(void *ptr __attribute__((unused)),
                                size_t size __attribute__((unused)))
    {
        TRASH(ptr, size);
    }

    THD *thd;
    ulong thread_id;
    const char *host, *status, *user;
    uint32 port;
};

//Copy from sql_show.cc
static const char *thread_state_info(THD *tmp)
{
    if (tmp->net.reading_or_writing)
    {
        if (tmp->net.reading_or_writing == 2)
            return "Writing to net";
        else if (tmp->command == COM_SLEEP)
            return "";
        else
            return "Reading from net";
    }
    else
    {
        if (tmp->proc_info)
            return tmp->proc_info;
        else if (tmp->mysys_var && tmp->mysys_var->current_cond)
            return "Waiting on cond";
        else
            return NULL;
    }
}

static int fill_is_table(THD *thd, TABLE_LIST *tables, COND *cond)
{
    I_List<thread_info> thread_infos;

    //collect thread infos
    mysql_mutex_lock(&LOCK_thread_count);
    I_List_iterator<THD> iter(threads);
    THD *tmp;
#ifdef DEBUG_PLUGIN
    fprintf(stderr, "[binlog_dump_list] start fill IS table\n");
#endif
    while (tmp = iter++)
    {
        if (tmp->system_thread || tmp->vio_ok())
        {
#ifdef DEBUG_PLUGIN
            fprintf(stderr, "[binlog_dump_list] found one thread\n");
#endif
            Security_context *tmp_sctx = tmp->security_ctx;
            if (NULL == tmp_sctx)
            {
                fprintf(stderr, "[binlog_dump_list] got THD->security_ctx == NULL, maybe the plugin is not compatible with the mysqld, make sure the version is match, so is --with-debug\n");
                mysql_mutex_unlock(&LOCK_thread_count);
                return 1;
            }

#ifdef DEBUG_PLUGIN
            fprintf(stderr, "[binlog_dump_list] thread command is %s\n", command_name[tmp->command].str);
#endif
            if (NULL == tmp->command || 0 != strcmp("Binlog Dump", command_name[tmp->command].str))
            {
                continue;
            }

            //thread_id
            thread_info *thd_info = new thread_info;
            thd_info->thd = tmp;
            thd_info->thread_id = tmp->thread_id;

            //host
            if (thd_info->host = (char *) thd->alloc(LIST_PROCESS_HOST_LEN + 1))
            {
                my_snprintf((char *) thd_info->host, LIST_PROCESS_HOST_LEN, "%s", tmp_sctx->host_or_ip);
            }
            else
            {
                fprintf(stderr, "[binlog_dump_list] cannot allocate thd_info->host\n");
                mysql_mutex_unlock(&LOCK_thread_count);
                return 1;
            }

            //user
            thd_info->user = thd->strdup(tmp_sctx->user ? tmp_sctx->user :
                                         (tmp->system_thread ? "system user" : "unauthenticated user"));

            //status
            mysql_mutex_lock(&tmp->LOCK_thd_data);
            struct st_my_thread_var *mysys_var;
            if (mysys_var = tmp->mysys_var)
                mysql_mutex_lock(&mysys_var->mutex); //thread_state_info will use mysys_var lock
            thd_info->status = thread_state_info(tmp);
            if (mysys_var)
                mysql_mutex_unlock(&mysys_var->mutex);
            mysql_mutex_unlock(&tmp->LOCK_thd_data);

            thread_infos.append(thd_info);
        }
    }
    mysql_mutex_unlock(&LOCK_thread_count);

    //collect slave info

    mysql_mutex_lock(&LOCK_slave_list);
    for (uint i = 0; i < slave_list.records; ++i)
    {
#ifdef DEBUG_PLUGIN
        fprintf(stderr, "[binlog_dump_list] found one slave info\n");
#endif
        SLAVE_INFO *si = (SLAVE_INFO *) my_hash_element(&slave_list, i);
        I_List_iterator<thread_info> iter(thread_infos);
        thread_info *info;
        while ((info = iter++) && (info->thd != si->thd));
        if (NULL != info)
        {
            info->port = (uint32) si->port;
        }
    }
    mysql_mutex_unlock(&LOCK_slave_list);

    //fill IS table
    CHARSET_INFO *cs = system_charset_info;
    TABLE *table = tables->table;
    thread_info *thd_info;
    while (thd_info = thread_infos.get())
    {
        table->field[0]->store(thd_info->thread_id);
        table->field[1]->store(thd_info->host, strlen(thd_info->host), cs);
        table->field[2]->store(thd_info->port);
        table->field[3]->store(thd_info->user, strlen(thd_info->user), cs);
        table->field[4]->store(thd_info->status, strlen(thd_info->status), cs);
        if (schema_table_store_record(thd, table))
            return 1;
    }

    return 0;
}

static int init_plugin(void *p)
{
    ST_SCHEMA_TABLE *schema = (ST_SCHEMA_TABLE *) p;
    schema->fields_info = is_table_fields;
    schema->fill_table = fill_is_table;
    fprintf(stderr, "binlog_dump_list plugin started\n");

    //print sizeof(some struct), in case that the plugin is not compiled compatible with mysqld
#ifdef DEBUG_PLUGIN
    fprintf(stderr, "[binlog_dump_list] sizeof(Statement)=%d\n", sizeof(Statement));
    fprintf(stderr, "[binlog_dump_list] sizeof(Open_tables_state)=%d\n", sizeof(Open_tables_state));
    fprintf(stderr, "[binlog_dump_list] sizeof(THD)=%d\n", sizeof(THD));
    fprintf(stderr, "[binlog_dump_list] sizeof(NET)=%d\n", sizeof(NET));
    fprintf(stderr, "[binlog_dump_list] sizeof(Protocol_text)=%d\n", sizeof(Protocol_text));
    fprintf(stderr, "[binlog_dump_list] sizeof(Protocol_binary)=%d\n", sizeof(Protocol_binary));
    fprintf(stderr, "[binlog_dump_list] sizeof(Protocol)=%d\n", sizeof(Protocol));
    fprintf(stderr, "[binlog_dump_list] sizeof(rand_struct)=%d\n", sizeof(rand_struct));
    fprintf(stderr, "[binlog_dump_list] sizeof(system_variables)=%d\n", sizeof(system_variables));
    fprintf(stderr, "[binlog_dump_list] sizeof(system_status_var)=%d\n", sizeof(system_status_var));
    fprintf(stderr, "[binlog_dump_list] sizeof(THR_LOCK_INFO)=%d\n", sizeof(THR_LOCK_INFO));
    fprintf(stderr, "[binlog_dump_list] sizeof(mysql_mutex_t)=%d\n", sizeof(mysql_mutex_t));
    fprintf(stderr, "[binlog_dump_list] sizeof(Statement_map)=%d\n", sizeof(Statement_map));
    fprintf(stderr, "[binlog_dump_list] sizeof(Security_context)=%d\n", sizeof(Security_context));
#endif
    return 0;
}

static int deinit_plugin(void *p)
{
    fprintf(stderr, "binlog_dump_list plugin stopped\n");
    return 0;
}
<|endoftext|>


<commit_before>/* bzflag
 * Copyright (c) 1993 - 2003 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#include <algorithm>
#include <functional>
#include <iostream>
#include <map>
#include <string>
#include <vector>

#include "BZAdminUI.h"
#if (defined(HAVE_CURSES_H) || defined (HAVE_NCURSES_H))
#include "CursesUI.h"
#endif
#include "OptionParser.h"
#include "ServerLink.h"
#include "StdBothUI.h"
#include "StdInUI.h"
#include "StdOutUI.h"
#include "UIMap.h"

// causes persistent rebuilding to obtain build versioning
#include "version.h"

using namespace std;

// function prototypes
/** Checks for new packets from the server, ignores them or stores a
    text message in str. Tells ui about new or removed players. Returns
    false if no interesting packets have arrived. */
bool getServerString(ServerLink& sLink, string& str, BZAdminUI& ui);

/** Sends the message msg to the server. */
void sendMessage(ServerLink& sLink, const string& msg, PlayerId target);

/** Formats an incoming message. */
string formatMessage(const string& msg, PlayerId src,
		     PlayerId dst, TeamColor dstTeam, PlayerId me);

// some global variables
map<PlayerId, string> players;
TeamColor myTeam(ObserverTeam);
struct CLOptions {
  CLOptions() : ui("curses"), showHelp(false) { }
  string ui;
  bool showHelp;
} clOptions;

// Here we go.
int main(int argc, char** argv) {

  // no curses, use stdboth instead
  const UIMap::map_t& interfaces(UIMap::getInstance().getMap());
  if (interfaces.find("curses") == interfaces.end())
    clOptions.ui = "stdboth";

  // build a usage string with all interfaces
  UIMap::map_t::const_iterator uiIter;
  string uiUsage;
  for (uiIter = interfaces.begin(); uiIter != interfaces.end(); ++uiIter)
    uiUsage += uiIter->first + '|';
  uiUsage = string("[-ui ") + uiUsage.substr(0, uiUsage.size() - 1) + ']';

  // register and parse command line arguments
  OptionParser op;
  op.registerVariable("ui", clOptions.ui, uiUsage,
		      "choose a user interface");
  op.registerVariable("help", clOptions.showHelp, "[-help]",
		      "print this help message");
  if (!op.parse(argc, argv)) {
    cerr<<op.getError()<<endl;
    op.printUsage(cout, argv[0]);
    cout<<"CALLSIGN@HOST[:PORT] [COMMAND] [COMMAND] ..."<<endl;
    return 1;
  }
  if (clOptions.showHelp) {
    cout<<"bzadmin "<<getAppVersion()<<endl;
    op.printUsage(cout, argv[0]);
    cout<<"CALLSIGN@HOST[:PORT] [COMMAND] [COMMAND] ..."<<endl<<endl;
    op.printHelp(cout);
    return 0;
  }

  // check that the ui is valid
  uiIter = UIMap::getInstance().getMap().find(clOptions.ui);
  if (uiIter == UIMap::getInstance().getMap().end()) {
    cerr<<"There is no interface called \""<<clOptions.ui<<"\"."<<endl;
    return 1;
  }

  // check that we have callsign and host in the right format and extract them
  if (op.getParameters().size() == 0) {
    cerr<<"You have to specify callsign@host."<<endl;
    return 1;
  }
  const string& namehost = op.getParameters()[0];
  int atPos = namehost.find('@');
  if (atPos == -1) {
    cerr<<"You have to specify callsign@host."<<endl;
    return 1;
  }
  string name = namehost.substr(0, atPos);
  string host = namehost.substr(atPos + 1);
  int port = ServerPort;
  int cPos = host.find(':');
  if (cPos != -1) {
    port = atoi(host.substr(cPos + 1).c_str());
    host = host.substr(0, cPos);
  }

  // connect to the server
  Address a(host);
  ServerLink sLink(a, port);
  if (sLink.getState() != ServerLink::Okay) {
    cerr<<"Could not connect to "<<host<<':'<<port<<'.'<<endl;
    return 0;
  }
  sLink.sendEnter(TankPlayer, myTeam, name.c_str(), "");
  if (sLink.getState() != ServerLink::Okay) {
    cerr<<"Rejected."<<endl;
    return 0;
  }

  // if we got commands as arguments, send them and exit
  if (op.getParameters().size() > 1) {
    for (unsigned int i = 1; i < op.getParameters().size(); ++i)
      sendMessage(sLink, op.getParameters()[i], AllPlayers);
    return 0;
  }

  // choose UI
  BZAdminUI*  ui = uiIter->second(players, sLink.getId());

  // main loop
  string str;
  PlayerId me = sLink.getId();
  try {
    while (true) {
      while (getServerString(sLink, str, *ui))
	ui->outputMessage(str);
      if (ui->checkCommand(str)) {
	if (str == "/quit")
	  break;
	sendMessage(sLink, str, ui->getTarget());
	// private messages to other players aren't sent back to us, print here
	if (players.count(ui->getTarget()))
	  ui->outputMessage(formatMessage(str, me,
					  ui->getTarget(), NoTeam, me));
      }
    }

    // we need to know that the server has processed all our messages
    // send a private message to ourself and wait for it to come back
    // this assumes that the order of messages isn't changed along the way
    if (sLink.getState() == ServerLink::Okay) {
      sendMessage(sLink, "bzadminping", me);
      string expected = formatMessage("bzadminping", me, me, NoTeam, me);
      do {
	getServerString(sLink, str, *ui);
      } while (str != expected);
    }
  }
  catch (const string& error) {
    ui->outputMessage(string("--- ERROR: ") + error);
  }
  delete ui;

  return 0;
}

bool getServerString(ServerLink& sLink, string& str, BZAdminUI& ui) {
  uint16_t code, len;
  char inbuf[MaxPacketLen];
  int e;
  std::string dstName, srcName;
  str = "";

  /* read until we have a package that we want, or until there are no more
     packages for 100 ms */
  while ((e = sLink.read(code, len, inbuf, 100)) == 1) {
    void* vbuf = inbuf;
    PlayerId p;
    switch (code) {

    case MsgAddPlayer:

      vbuf = nboUnpackUByte(vbuf, p);

      uint16_t team, type, wins, losses, tks;
      char callsign[CallSignLen];
      char email[EmailLen];
      vbuf = nboUnpackUShort(vbuf, type);
      vbuf = nboUnpackUShort(vbuf, team);
      vbuf = nboUnpackUShort(vbuf, wins);
      vbuf = nboUnpackUShort(vbuf, losses);
      vbuf = nboUnpackUShort(vbuf, tks);
      vbuf = nboUnpackString(vbuf, callsign, CallSignLen);
      vbuf = nboUnpackString(vbuf, email, EmailLen);
      players[p] = callsign;
      if (p != sLink.getId())
	ui.addedPlayer(p);
      str = str + "*** '" + callsign + "' joined the game.";
      return true;

    case MsgRemovePlayer:
      vbuf = nboUnpackUByte(vbuf, p);
      str = str + "*** '" + players[p] + "' left the game.";
      ui.removingPlayer(p);
      players.erase(p);
      return true;

    case MsgMessage:

      // unpack the message header
      PlayerId src;
      PlayerId dst;
      PlayerId me = sLink.getId();
      vbuf = nboUnpackUByte(vbuf, src);
      vbuf = nboUnpackUByte(vbuf, dst);

      // is the message for me?
      TeamColor dstTeam = (dst >= 244 && dst <= 250 ?
			   TeamColor(250 - dst) : NoTeam);
      if (dst == AllPlayers || src == me || dst == me || dstTeam == myTeam) {
	str = (char*)vbuf;
	if (str == "CLIENTQUERY") {
	  sendMessage(sLink, string("bzadmin ") + getAppVersion(), src);
	  ui.outputMessage("    [Sent versioninfo per request]");
	}
	else {
	  str = formatMessage((char*)vbuf, src, dst, dstTeam, me);
	  return true;
	}
      }
    }
  }

  if (e == -1) {
    throw string("Server communication error");
  }

  return false;
}

void sendMessage(ServerLink& sLink, const string& msg, PlayerId target) {
  char buffer[MessageLen];
  char buffer2[1 + MessageLen];
  void* buf = buffer2;

  buf = nboPackUByte(buf, target);
  memset(buffer, 0, MessageLen);
  strncpy(buffer, msg.c_str(), MessageLen);
  nboPackString(buffer2 + 1, buffer, MessageLen);
  sLink.send(MsgMessage, sizeof(buffer2), buffer2);
}

string formatMessage(const string& msg, PlayerId src,
		     PlayerId dst, TeamColor dstTeam, PlayerId me) {
  string formatted = "    ";

  // get sender and receiver
  const string srcName = (src == ServerPlayer ? "SERVER" :
			  (players.count(src) ? players[src] : "(UNKNOWN)"));
  const string dstName = (players.count(dst) ? players[dst] : "(UNKNOWN)");

  // direct message to or from me
  if (dst == me || players.count(dst)) {
    if (!(src == me && dst == me)) {
      formatted += "[";
      if (src == me) {
	formatted += "->";
	formatted += dstName;
      }
      else {
	formatted += srcName;
	formatted += "->";
      }
      formatted += "] ";
    }
    formatted += msg;
  }

  // public or team message
  else {
    if (dstTeam != NoTeam)
      formatted += "[Team] ";
    formatted += srcName;
    formatted += ": ";
    formatted += msg;
  }

  return formatted;
}
<commit_msg>Distinguish between communication error and superkill<commit_after>/* bzflag
 * Copyright (c) 1993 - 2003 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#include <algorithm>
#include <functional>
#include <iostream>
#include <map>
#include <string>
#include <vector>

#include "BZAdminUI.h"
#if (defined(HAVE_CURSES_H) || defined (HAVE_NCURSES_H))
#include "CursesUI.h"
#endif
#include "OptionParser.h"
#include "ServerLink.h"
#include "StdBothUI.h"
#include "StdInUI.h"
#include "StdOutUI.h"
#include "UIMap.h"

// causes persistent rebuilding to obtain build versioning
#include "version.h"

using namespace std;

// function prototypes
/** Checks for new packets from the server, ignores them or stores a
    text message in str. Tells ui about new or removed players. Returns
    false if no interesting packets have arrived. */
bool getServerString(ServerLink& sLink, string& str, BZAdminUI& ui);

/** Sends the message msg to the server. */
void sendMessage(ServerLink& sLink, const string& msg, PlayerId target);

/** Formats an incoming message. */
string formatMessage(const string& msg, PlayerId src,
		     PlayerId dst, TeamColor dstTeam, PlayerId me);

// some global variables
map<PlayerId, string> players;
TeamColor myTeam(ObserverTeam);
struct CLOptions {
  CLOptions() : ui("curses"), showHelp(false) { }
  string ui;
  bool showHelp;
} clOptions;

// Here we go.
int main(int argc, char** argv) {

  // no curses, use stdboth instead
  const UIMap::map_t& interfaces(UIMap::getInstance().getMap());
  if (interfaces.find("curses") == interfaces.end())
    clOptions.ui = "stdboth";

  // build a usage string with all interfaces
  UIMap::map_t::const_iterator uiIter;
  string uiUsage;
  for (uiIter = interfaces.begin(); uiIter != interfaces.end(); ++uiIter)
    uiUsage += uiIter->first + '|';
  uiUsage = string("[-ui ") + uiUsage.substr(0, uiUsage.size() - 1) + ']';

  // register and parse command line arguments
  OptionParser op;
  op.registerVariable("ui", clOptions.ui, uiUsage,
		      "choose a user interface");
  op.registerVariable("help", clOptions.showHelp, "[-help]",
		      "print this help message");
  if (!op.parse(argc, argv)) {
    cerr<<op.getError()<<endl;
    op.printUsage(cout, argv[0]);
    cout<<"CALLSIGN@HOST[:PORT] [COMMAND] [COMMAND] ..."<<endl;
    return 1;
  }
  if (clOptions.showHelp) {
    cout<<"bzadmin "<<getAppVersion()<<endl;
    op.printUsage(cout, argv[0]);
    cout<<"CALLSIGN@HOST[:PORT] [COMMAND] [COMMAND] ..."<<endl<<endl;
    op.printHelp(cout);
    return 0;
  }

  // check that the ui is valid
  uiIter = UIMap::getInstance().getMap().find(clOptions.ui);
  if (uiIter == UIMap::getInstance().getMap().end()) {
    cerr<<"There is no interface called \""<<clOptions.ui<<"\"."<<endl;
    return 1;
  }

  // check that we have callsign and host in the right format and extract them
  if (op.getParameters().size() == 0) {
    cerr<<"You have to specify callsign@host."<<endl;
    return 1;
  }
  const string& namehost = op.getParameters()[0];
  int atPos = namehost.find('@');
  if (atPos == -1) {
    cerr<<"You have to specify callsign@host."<<endl;
    return 1;
  }
  string name = namehost.substr(0, atPos);
  string host = namehost.substr(atPos + 1);
  int port = ServerPort;
  int cPos = host.find(':');
  if (cPos != -1) {
    port = atoi(host.substr(cPos + 1).c_str());
    host = host.substr(0, cPos);
  }

  // connect to the server
  Address a(host);
  ServerLink sLink(a, port);
  if (sLink.getState() != ServerLink::Okay) {
    cerr<<"Could not connect to "<<host<<':'<<port<<'.'<<endl;
    return 0;
  }
  sLink.sendEnter(TankPlayer, myTeam, name.c_str(), "");
  if (sLink.getState() != ServerLink::Okay) {
    cerr<<"Rejected."<<endl;
    return 0;
  }

  // if we got commands as arguments, send them and exit
  if (op.getParameters().size() > 1) {
    for (unsigned int i = 1; i < op.getParameters().size(); ++i)
      sendMessage(sLink, op.getParameters()[i], AllPlayers);
    return 0;
  }

  // choose UI
  BZAdminUI*  ui = uiIter->second(players, sLink.getId());

  // main loop
  string str;
  PlayerId me = sLink.getId();
  try {
    while (true) {
      while (getServerString(sLink, str, *ui))
	ui->outputMessage(str);
      if (ui->checkCommand(str)) {
	if (str == "/quit")
	  break;
	sendMessage(sLink, str, ui->getTarget());
	// private messages to other players aren't sent back to us, print here
	if (players.count(ui->getTarget()))
	  ui->outputMessage(formatMessage(str, me,
					  ui->getTarget(), NoTeam, me));
      }
    }

    // we need to know that the server has processed all our messages
    // send a private message to ourself and wait for it to come back
    // this assumes that the order of messages isn't changed along the way
    if (sLink.getState() == ServerLink::Okay) {
      sendMessage(sLink, "bzadminping", me);
      string expected = formatMessage("bzadminping", me, me, NoTeam, me);
      do {
	getServerString(sLink, str, *ui);
      } while (str != expected);
    }
  }
  catch (const string& error) {
    ui->outputMessage(string("--- ERROR: ") + error);
  }
  delete ui;

  return 0;
}

bool getServerString(ServerLink& sLink, string& str, BZAdminUI& ui) {
  uint16_t code, len;
  char inbuf[MaxPacketLen];
  int e;
  std::string dstName, srcName;
  str = "";

  /* read until we have a package that we want, or until there are no more
     packages for 100 ms */
  while ((e = sLink.read(code, len, inbuf, 100)) == 1) {
    void* vbuf = inbuf;
    PlayerId p;
    switch (code) {

    case MsgAddPlayer:

      vbuf = nboUnpackUByte(vbuf, p);

      uint16_t team, type, wins, losses, tks;
      char callsign[CallSignLen];
      char email[EmailLen];
      vbuf = nboUnpackUShort(vbuf, type);
      vbuf = nboUnpackUShort(vbuf, team);
      vbuf = nboUnpackUShort(vbuf, wins);
      vbuf = nboUnpackUShort(vbuf, losses);
      vbuf = nboUnpackUShort(vbuf, tks);
      vbuf = nboUnpackString(vbuf, callsign, CallSignLen);
      vbuf = nboUnpackString(vbuf, email, EmailLen);
      players[p] = callsign;
      if (p != sLink.getId())
	ui.addedPlayer(p);
      str = str + "*** '" + callsign + "' joined the game.";
      return true;

    case MsgRemovePlayer:
      vbuf = nboUnpackUByte(vbuf, p);
      str = str + "*** '" + players[p] + "' left the game.";
      ui.removingPlayer(p);
      players.erase(p);
      return true;

    case MsgSuperKill:
      throw string("Server forced a disconnect");

    case MsgMessage:

      // unpack the message header
      PlayerId src;
      PlayerId dst;
      PlayerId me = sLink.getId();
      vbuf = nboUnpackUByte(vbuf, src);
      vbuf = nboUnpackUByte(vbuf, dst);

      // is the message for me?
      TeamColor dstTeam = (dst >= 244 && dst <= 250 ?
			   TeamColor(250 - dst) : NoTeam);
      if (dst == AllPlayers || src == me || dst == me || dstTeam == myTeam) {
	str = (char*)vbuf;
	if (str == "CLIENTQUERY") {
	  sendMessage(sLink, string("bzadmin ") + getAppVersion(), src);
	  ui.outputMessage("    [Sent versioninfo per request]");
	}
	else {
	  str = formatMessage((char*)vbuf, src, dst, dstTeam, me);
	  return true;
	}
      }
    }
  }

  if (e == -1) {
    throw string("Server communication error");
  }

  return false;
}

void sendMessage(ServerLink& sLink, const string& msg, PlayerId target) {
  char buffer[MessageLen];
  char buffer2[1 + MessageLen];
  void* buf = buffer2;

  buf = nboPackUByte(buf, target);
  memset(buffer, 0, MessageLen);
  strncpy(buffer, msg.c_str(), MessageLen);
  nboPackString(buffer2 + 1, buffer, MessageLen);
  sLink.send(MsgMessage, sizeof(buffer2), buffer2);
}

string formatMessage(const string& msg, PlayerId src,
		     PlayerId dst, TeamColor dstTeam, PlayerId me) {
  string formatted = "    ";

  // get sender and receiver
  const string srcName = (src == ServerPlayer ? "SERVER" :
			  (players.count(src) ? players[src] : "(UNKNOWN)"));
  const string dstName = (players.count(dst) ? players[dst] : "(UNKNOWN)");

  // direct message to or from me
  if (dst == me || players.count(dst)) {
    if (!(src == me && dst == me)) {
      formatted += "[";
      if (src == me) {
	formatted += "->";
	formatted += dstName;
      }
      else {
	formatted += srcName;
	formatted += "->";
      }
      formatted += "] ";
    }
    formatted += msg;
  }

  // public or team message
  else {
    if (dstTeam != NoTeam)
      formatted += "[Team] ";
    formatted += srcName;
    formatted += ": ";
    formatted += msg;
  }

  return formatted;
}
<|endoftext|>


<commit_before>///////////////////////////////////////
/// file: expression.cpp
/// 计算中缀表达式
///////////////////////////////////////

#include <iostream>
#include "sqstack.h"
using namespace std;

///
/// 运算符之间的优先级关系
///
char Precede(char opl, char opr)
{
    // 语法错误
    if(opl=='(' && opr=='#') return 'X';
    if(opl=='#' && opr==')') return 'X';
    if(opl==')' && opr=='(') return 'X';
    // 括号匹配的情况
    if(opl=='#' && opr=='#') return '=';
    if(opl=='(' && opr==')') return '=';
    // 全 > 的情况
    if(opl==')' || opr==')' || opr=='#') return '>';
    // 全 < 的情况
    if(opl=='(' || opr=='(' || opl=='#') return '<';
    // 剩余 +-*/ 中 > 的情况
    if(opl=='*' || opl=='/' || opr=='+' || opr=='-') return '>';
    // 其他为 < 的情况
    if(opr=='*' || opr=='/') return '<';
    return 'X';  // 其他意外情况
}

///
/// 执行计算
///
int Operate(int a, char theta, int b)
{
    switch(theta) {
    case '+': return a+b;
    case '-': return a-b;
    case '*': return a*b;
    case '/': return a/b;
    }
    throw "Unknown operator";
}

/// 读取运算符或操作数，返回读取的第一个字符
/// 若为运算符，isop 为 true 且 op 返回运算符
/// 否则，num 返回操作数
char Read(bool& isop, char& op, int& num)
{
    char c = cin.peek();  // 查看输入流中的下一个字符
    while(isspace(c)) { cin.ignore(1); c = cin.peek(); } // 跳过空白
    isop = c<'0' || c>'9';  // 非数字即为运算符
    isop ? (cin >> op) : (cin >> num); // 读取运算符或操作数
    return c;
}

///
/// 输入表达式计算结果
/// 操作数为非负整数，运算符包括+-*/()，以#结尾
///
int EvaluateExpression() {
    char c, x;
    bool isop;  // 当前输入是运算符时为 true
    char op;    // 当前输入的运算符
    int num;    // 当前输入的操作数
    SqStack<char> optr;  // 运算符栈
    SqStack<int>  opnd;  // 操作数栈
    char theta;
    int a, b;
    // 初始化运算符和操作数栈
    InitStack(optr);
    InitStack(opnd);
    // 表达式开始
    Push(optr, '#');
    // 读取一个运算符 op 或操作数 num，读取操作数时 isop 为真
    c = Read(isop, op, num); // c 为第一个字符
    // 当表达式未结束或还有未计算的运算符时继续
    while(c!='#' || GetTop(optr)!='#') {
        // 处理运算符或操作数
        if(! isop) { // 遇到操作数，直接入栈，继续读取
            Push(opnd, num);
            c = Read(isop, op, num);
        } else {  // 遇到运算符，根据优先级分别处理
            switch(Precede(GetTop(optr), op)) {
            case '<':  // 栈顶运算符优先级低，运算符入栈，继续读取
                Push(optr, op);
                c = Read(isop, op, num);
                break;
            case '=':  // 脱括号，继续读取
                Pop(optr, x);
                c = Read(isop, op, num);
                break;
            case '>':  // 栈顶运算符优先级高，执行运算，结果入栈
                Pop(optr, theta);
                Pop(opnd, b); Pop(opnd, a);
                Push(opnd, Operate(a, theta, b));
                break;
            }
        }
    }

    return GetTop(opnd);  // 返回运算结果
}

int main()
{
    cout << "Input an expression (support +-*/() and end with #)" << endl;
    int result = EvaluateExpression();
    cout << result << endl;

    return 0;
}<commit_msg>Change function Read<commit_after>///////////////////////////////////////
/// file: expression.cpp
/// 计算中缀表达式
///////////////////////////////////////

#include <iostream>
#include "sqstack.h"
using namespace std;

///
/// 运算符之间的优先级关系
///
char Precede(char opl, char opr)
{
    // 语法错误
    if(opl=='(' && opr=='#') return 'X';
    if(opl=='#' && opr==')') return 'X';
    if(opl==')' && opr=='(') return 'X';
    // 括号匹配的情况
    if(opl=='#' && opr=='#') return '=';
    if(opl=='(' && opr==')') return '=';
    // 全 > 的情况
    if(opl==')' || opr==')' || opr=='#') return '>';
    // 全 < 的情况
    if(opl=='(' || opr=='(' || opl=='#') return '<';
    // 剩余 +-*/ 中 > 的情况
    if(opl=='*' || opl=='/' || opr=='+' || opr=='-') return '>';
    // 其他为 < 的情况
    if(opr=='*' || opr=='/') return '<';
    return 'X';  // 其他意外情况
}

///
/// 执行计算
///
int Operate(int a, char theta, int b)
{
    switch(theta) {
    case '+': return a+b;
    case '-': return a-b;
    case '*': return a*b;
    case '/': return a/b;
    }
    throw "Unknown operator";
}

/// 读取运算符或操作数，分别返回 OPERATOR 或 OPERAND
/// op 返回运算符，num 返回操作数
enum {OPERATOR,OPERAND};
int Read(char& op, int& num)
{
    char c = cin.peek();  // 查看输入流中的下一个字符
    while(isspace(c)) { cin.ignore(1); c = cin.peek(); } // 跳过空白
    if(c>='0' && c<='9') {  // 数字开头即为操作数
        cin >> num; // 读取操作数
        return OPERAND;
    } else {  // 非数字即为运算符
        cin >> op;  // 读取运算符
        return OPERATOR;
    }
}

///
/// 输入表达式计算结果
/// 操作数为非负整数，运算符包括+-*/()，以#结尾
///
int EvaluateExpression() {
    char c, x;
    int isop;   // 当前输入是运算符（OPERATOR）或操作数（OPERAND）
    char op;    // 当前输入的运算符
    int num;    // 当前输入的操作数
    SqStack<char> optr;  // 运算符栈
    SqStack<int>  opnd;  // 操作数栈
    char theta;
    int a, b;
    // 初始化运算符和操作数栈
    InitStack(optr);
    InitStack(opnd);
    // 表达式开始
    Push(optr, '#');
    // 读取一个运算符 op 或操作数 num
    isop = Read(op, num);
    // 当表达式未结束或还有未计算的运算符时继续
    while(isop==OPERAND || op!='#' || GetTop(optr)!='#') {
        // 处理运算符或操作数
        if(isop==OPERAND) { // 遇到操作数，直接入栈，继续读取
            Push(opnd, num);
            isop = Read(op, num);
        } else {  // 遇到运算符，根据优先级分别处理
            switch(Precede(GetTop(optr), op)) {
            case '<':  // 栈顶运算符优先级低，运算符入栈，继续读取
                Push(optr, op);
                isop = Read(op, num);
                break;
            case '=':  // 脱括号，继续读取
                Pop(optr, x);
                isop = Read(op, num);
                break;
            case '>':  // 栈顶运算符优先级高，执行运算，结果入栈
                Pop(optr, theta);
                Pop(opnd, b); Pop(opnd, a);
                Push(opnd, Operate(a, theta, b));
                break;
            }
        }
    }

    return GetTop(opnd);  // 返回运算结果
}

int main()
{
    cout << "Input an expression (support +-*/() and end with #)" << endl;
    int result = EvaluateExpression();
    cout << result << endl;

    return 0;
}<|endoftext|>


<commit_before>#include "mcrt/mcrt.hh"
<commit_msg>We don't really need this.<commit_after><|endoftext|>


<commit_before>
#include <v8.h>
#include <node.h>
#include <node_buffer.h>
#include <node_object_wrap.h>
#include <delay_load_hook.h>
#include "../deps/opus/include/opus.h"
#include "common.h"
#include <nan.h>

#include <string.h>

using namespace node;
using namespace v8;

#define FRAME_SIZE 960
#define MAX_FRAME_SIZE 6*960
#define MAX_PACKET_SIZE (3*1276)
#define BITRATE 64000

const char* getDecodeError( int decodedSamples ) {
	switch( decodedSamples ) {
		case OPUS_BAD_ARG:
			return "One or more invalid/out of range arguments";
		case OPUS_BUFFER_TOO_SMALL:
			return "The mode struct passed is invalid";
		case OPUS_INTERNAL_ERROR:
			return "An internal error was detected";
		case OPUS_INVALID_PACKET:
			return "The compressed data passed is corrupted";
		case OPUS_UNIMPLEMENTED:
			return "Invalid/unsupported request number.";
		case OPUS_INVALID_STATE:
			return "An encoder or decoder structure is invalid or already freed.";
		case OPUS_ALLOC_FAIL:
			return "Memory allocation has failed";
		default:
			return "Unknown OPUS error";
	}
}

class OpusEncoder : public ObjectWrap {
	private:
		OpusEncoder* encoder;
		OpusDecoder* decoder;

		opus_int32 rate;
		int channels;
		int application;

		unsigned char outOpus[ MAX_PACKET_SIZE ];
		opus_int16* outPcm;

	protected:
		int EnsureEncoder() {
			if( encoder != NULL ) return 0;
			int error;
			encoder = opus_encoder_create( rate, channels, application, &error );
			return error;
		}
		int EnsureDecoder() {
			if( decoder != NULL ) return 0;
			int error;
			decoder = opus_decoder_create( rate, channels, &error );
			return error;
		}

	public:
	   	OpusEncoder( opus_int32 rate, int channels, int application ):
			encoder( NULL ), decoder( NULL ),
			rate( rate ), channels( channels ), application( application ) {

			outPcm = new opus_int16[ channels * MAX_FRAME_SIZE ];
		}

		~OpusEncoder() {
			if( encoder != NULL )
				opus_encoder_destroy( encoder );
			if( decoder != NULL )
				opus_decoder_destroy( decoder );

			encoder = NULL;
			decoder = NULL;

			delete outPcm;
			outPcm = NULL;
		}

		static NAN_METHOD(Encode) {

			// Unwrap the encoder.
			OpusEncoder* self = ObjectWrap::Unwrap<OpusEncoder>( info.This() );
			self->EnsureEncoder();

			// Read the functiona rguments
			REQ_OBJ_ARG( 0, pcmBuffer );
			OPT_INT_ARG( 1, maxPacketSize, MAX_PACKET_SIZE );

			// Read the PCM data.
			char* pcmData = Buffer::Data(pcmBuffer);
			opus_int16* pcm = reinterpret_cast<opus_int16*>( pcmData );
			int frameSize = Buffer::Length( pcmBuffer ) / 2 / self->channels;

			// Encode the samples.
			int compressedLength = opus_encode( self->encoder, pcm, frameSize, &(self->outOpus[0]), maxPacketSize );

			// Create a new result buffer.
			Local<Object> actualBuffer = Nan::NewBuffer(reinterpret_cast<char*>(self->outOpus), compressedLength ).ToLocalChecked();
			info.GetReturnValue().Set( actualBuffer );
		}

		static NAN_METHOD(Decode) {

			REQ_OBJ_ARG( 0, compressedBuffer );

			// Read the compressed data.
			unsigned char* compressedData = (unsigned char*)Buffer::Data( compressedBuffer );
			size_t compressedDataLength = Buffer::Length( compressedBuffer );

			OpusEncoder* self = ObjectWrap::Unwrap<OpusEncoder>( info.This() );
			self->EnsureDecoder();

			// Encode the samples.
			int decodedSamples = opus_decode(
					self->decoder,
					compressedData,
					compressedDataLength,
					&(self->outPcm[0]),
				   	MAX_FRAME_SIZE, /* decode_fex */ 0 );

			if( decodedSamples < 0 ) {
				return Nan::ThrowTypeError( getDecodeError( decodedSamples ) );
			}

			// Create a new result buffer.
			int decodedLength = decodedSamples * 2 * self->channels;
			Local<Object> actualBuffer = Nan::NewBuffer( reinterpret_cast<char*>(self->outPcm), decodedLength ).ToLocalChecked();
			info.GetReturnValue().Set( actualBuffer );
		}

		static NAN_METHOD(SetBitrate) {

			REQ_INT_ARG( 0, bitrate );

			OpusEncoder* self = ObjectWrap::Unwrap<OpusEncoder>( info.This() );
			self->EnsureEncoder();

			opus_encoder_ctl( self->encoder, OPUS_SET_BITRATE( bitrate ) );
		}

		static NAN_METHOD(GetBitrate) {

			OpusEncoder* self = ObjectWrap::Unwrap<OpusEncoder>( info.This() );
			self->EnsureEncoder();

			opus_int32 bitrate;
			opus_encoder_ctl( self->encoder, OPUS_GET_BITRATE( &bitrate ) );

			info.GetReturnValue().Set( Nan::New<v8::Integer>( bitrate ) );
		}

		static NAN_METHOD(New) {

			if( !info.IsConstructCall()) {
				return Nan::ThrowTypeError("Use the new operator to construct the OpusEncoder.");
			}

			OPT_INT_ARG(0, rate, 48000);
			OPT_INT_ARG(1, channels, 1);
			OPT_INT_ARG(2, application, OPUS_APPLICATION_AUDIO);

			OpusEncoder* encoder = new OpusEncoder( rate, channels, application );

			encoder->Wrap( info.This() );
			info.GetReturnValue().Set(info.This());
		}

		static void Init(Handle<Object> exports) {
			Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate>(New);
			tpl->SetClassName(Nan::New<String>("OpusEncoder").ToLocalChecked());
			tpl->InstanceTemplate()->SetInternalFieldCount(1);

			tpl->PrototypeTemplate()->Set( Nan::New<String>("encode").ToLocalChecked(),
				Nan::New<FunctionTemplate>( Encode )->GetFunction() );

			tpl->PrototypeTemplate()->Set( Nan::New<String>("decode").ToLocalChecked(),
				Nan::New<FunctionTemplate>( Decode )->GetFunction() );

			tpl->PrototypeTemplate()->Set( Nan::New<String>("setBitrate").ToLocalChecked(),
				Nan::New<FunctionTemplate>( SetBitrate )->GetFunction() );

			tpl->PrototypeTemplate()->Set( Nan::New<String>("getBitrate").ToLocalChecked(),
				Nan::New<FunctionTemplate>( GetBitrate )->GetFunction() );

			//v8::Persistent<v8::FunctionTemplate> constructor;
			//NanAssignPersistent(constructor, tpl);
			exports->Set(Nan::New<String>("OpusEncoder").ToLocalChecked(), tpl->GetFunction());
		}
};

void NodeInit(Handle<Object> exports) {
	OpusEncoder::Init( exports );
}

NODE_MODULE(node_opus, NodeInit)
<commit_msg>Use copybuffer not newbuffer after iojs 3.0.0<commit_after>
#include <v8.h>
#include <node.h>
#include <node_buffer.h>
#include <node_object_wrap.h>
#include <delay_load_hook.h>
#include "../deps/opus/include/opus.h"
#include "common.h"
#include <nan.h>

#include <string.h>

using namespace node;
using namespace v8;

#define FRAME_SIZE 960
#define MAX_FRAME_SIZE 6*960
#define MAX_PACKET_SIZE (3*1276)
#define BITRATE 64000

const char* getDecodeError( int decodedSamples ) {
	switch( decodedSamples ) {
		case OPUS_BAD_ARG:
			return "One or more invalid/out of range arguments";
		case OPUS_BUFFER_TOO_SMALL:
			return "The mode struct passed is invalid";
		case OPUS_INTERNAL_ERROR:
			return "An internal error was detected";
		case OPUS_INVALID_PACKET:
			return "The compressed data passed is corrupted";
		case OPUS_UNIMPLEMENTED:
			return "Invalid/unsupported request number.";
		case OPUS_INVALID_STATE:
			return "An encoder or decoder structure is invalid or already freed.";
		case OPUS_ALLOC_FAIL:
			return "Memory allocation has failed";
		default:
			return "Unknown OPUS error";
	}
}

class OpusEncoder : public ObjectWrap {
	private:
		OpusEncoder* encoder;
		OpusDecoder* decoder;

		opus_int32 rate;
		int channels;
		int application;

		unsigned char outOpus[ MAX_PACKET_SIZE ];
		opus_int16* outPcm;

	protected:
		int EnsureEncoder() {
			if( encoder != NULL ) return 0;
			int error;
			encoder = opus_encoder_create( rate, channels, application, &error );
			return error;
		}
		int EnsureDecoder() {
			if( decoder != NULL ) return 0;
			int error;
			decoder = opus_decoder_create( rate, channels, &error );
			return error;
		}

	public:
	   	OpusEncoder( opus_int32 rate, int channels, int application ):
			encoder( NULL ), decoder( NULL ),
			rate( rate ), channels( channels ), application( application ) {

			outPcm = new opus_int16[ channels * MAX_FRAME_SIZE ];
		}

		~OpusEncoder() {
			if( encoder != NULL )
				opus_encoder_destroy( encoder );
			if( decoder != NULL )
				opus_decoder_destroy( decoder );

			encoder = NULL;
			decoder = NULL;

			delete outPcm;
			outPcm = NULL;
		}

		static NAN_METHOD(Encode) {

			// Unwrap the encoder.
			OpusEncoder* self = ObjectWrap::Unwrap<OpusEncoder>( info.This() );
			self->EnsureEncoder();

			// Read the functiona rguments
			REQ_OBJ_ARG( 0, pcmBuffer );
			OPT_INT_ARG( 1, maxPacketSize, MAX_PACKET_SIZE );

			// Read the PCM data.
			char* pcmData = Buffer::Data(pcmBuffer);
			opus_int16* pcm = reinterpret_cast<opus_int16*>( pcmData );
			int frameSize = Buffer::Length( pcmBuffer ) / 2 / self->channels;

			// Encode the samples.
			int compressedLength = opus_encode( self->encoder, pcm, frameSize, &(self->outOpus[0]), maxPacketSize );

			// Create a new result buffer.
			Local<Object> actualBuffer = Nan::CopyBuffer(reinterpret_cast<char*>(self->outOpus), compressedLength ).ToLocalChecked();
			info.GetReturnValue().Set( actualBuffer );
		}

		static NAN_METHOD(Decode) {

			REQ_OBJ_ARG( 0, compressedBuffer );

			// Read the compressed data.
			unsigned char* compressedData = (unsigned char*)Buffer::Data( compressedBuffer );
			size_t compressedDataLength = Buffer::Length( compressedBuffer );

			OpusEncoder* self = ObjectWrap::Unwrap<OpusEncoder>( info.This() );
			self->EnsureDecoder();

			// Encode the samples.
			int decodedSamples = opus_decode(
					self->decoder,
					compressedData,
					compressedDataLength,
					&(self->outPcm[0]),
				   	MAX_FRAME_SIZE, /* decode_fex */ 0 );

			if( decodedSamples < 0 ) {
				return Nan::ThrowTypeError( getDecodeError( decodedSamples ) );
			}

			// Create a new result buffer.
			int decodedLength = decodedSamples * 2 * self->channels;
			Local<Object> actualBuffer = Nan::CopyBuffer( reinterpret_cast<char*>(self->outPcm), decodedLength ).ToLocalChecked();
			info.GetReturnValue().Set( actualBuffer );
		}

		static NAN_METHOD(SetBitrate) {

			REQ_INT_ARG( 0, bitrate );

			OpusEncoder* self = ObjectWrap::Unwrap<OpusEncoder>( info.This() );
			self->EnsureEncoder();

			opus_encoder_ctl( self->encoder, OPUS_SET_BITRATE( bitrate ) );
		}

		static NAN_METHOD(GetBitrate) {

			OpusEncoder* self = ObjectWrap::Unwrap<OpusEncoder>( info.This() );
			self->EnsureEncoder();

			opus_int32 bitrate;
			opus_encoder_ctl( self->encoder, OPUS_GET_BITRATE( &bitrate ) );

			info.GetReturnValue().Set( Nan::New<v8::Integer>( bitrate ) );
		}

		static NAN_METHOD(New) {

			if( !info.IsConstructCall()) {
				return Nan::ThrowTypeError("Use the new operator to construct the OpusEncoder.");
			}

			OPT_INT_ARG(0, rate, 48000);
			OPT_INT_ARG(1, channels, 1);
			OPT_INT_ARG(2, application, OPUS_APPLICATION_AUDIO);

			OpusEncoder* encoder = new OpusEncoder( rate, channels, application );

			encoder->Wrap( info.This() );
			info.GetReturnValue().Set(info.This());
		}

		static void Init(Handle<Object> exports) {
			Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate>(New);
			tpl->SetClassName(Nan::New<String>("OpusEncoder").ToLocalChecked());
			tpl->InstanceTemplate()->SetInternalFieldCount(1);

			tpl->PrototypeTemplate()->Set( Nan::New<String>("encode").ToLocalChecked(),
				Nan::New<FunctionTemplate>( Encode )->GetFunction() );

			tpl->PrototypeTemplate()->Set( Nan::New<String>("decode").ToLocalChecked(),
				Nan::New<FunctionTemplate>( Decode )->GetFunction() );

			tpl->PrototypeTemplate()->Set( Nan::New<String>("setBitrate").ToLocalChecked(),
				Nan::New<FunctionTemplate>( SetBitrate )->GetFunction() );

			tpl->PrototypeTemplate()->Set( Nan::New<String>("getBitrate").ToLocalChecked(),
				Nan::New<FunctionTemplate>( GetBitrate )->GetFunction() );

			//v8::Persistent<v8::FunctionTemplate> constructor;
			//NanAssignPersistent(constructor, tpl);
			exports->Set(Nan::New<String>("OpusEncoder").ToLocalChecked(), tpl->GetFunction());
		}
};

void NodeInit(Handle<Object> exports) {
	OpusEncoder::Init( exports );
}

NODE_MODULE(node_opus, NodeInit)
<|endoftext|>