<commit_before>//
// Copyright (c) Microsoft. All rights reserved.
// Copyright (c) Geoff Norton. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//

/*++

Module Name:

    seh-unwind.cpp

Abstract:

    Implementation of exception API functions based on
    the Unwind API.

--*/

#ifndef FEATURE_PAL_SXS
#error FEATURE_PAL_SXS needs to be defined for this file.
#endif // !FEATURE_PAL_SXS

#include "pal/context.h"
#include <dlfcn.h>
#include <exception>
#define UNW_LOCAL_ONLY
#include <libunwind.h>

//----------------------------------------------------------------------
// Virtual Unwinding
//----------------------------------------------------------------------

#if UNWIND_CONTEXT_IS_UCONTEXT_T
static void WinContextToUnwindContext(CONTEXT *winContext, unw_context_t *unwContext)
{
#if defined(_AMD64_)
    unwContext->uc_mcontext.gregs[REG_RIP] = winContext->Rip;
    unwContext->uc_mcontext.gregs[REG_RSP] = winContext->Rsp;
    unwContext->uc_mcontext.gregs[REG_RBP] = winContext->Rbp;
    unwContext->uc_mcontext.gregs[REG_RBX] = winContext->Rbx;
    unwContext->uc_mcontext.gregs[REG_R12] = winContext->R12;
    unwContext->uc_mcontext.gregs[REG_R13] = winContext->R13;
    unwContext->uc_mcontext.gregs[REG_R14] = winContext->R14;
    unwContext->uc_mcontext.gregs[REG_R15] = winContext->R15;
#else
#error unsupported architecture
#endif
}
#else
static void WinContextToUnwindCursor(CONTEXT *winContext, unw_cursor_t *cursor)
{
#if defined(_AMD64_)
    unw_set_reg(cursor, UNW_REG_IP, winContext->Rip);
    unw_set_reg(cursor, UNW_REG_SP, winContext->Rsp);
    unw_set_reg(cursor, UNW_X86_64_RBP, winContext->Rbp);
    unw_set_reg(cursor, UNW_X86_64_RBX, winContext->Rbx);
    unw_set_reg(cursor, UNW_X86_64_R12, winContext->R12);
    unw_set_reg(cursor, UNW_X86_64_R13, winContext->R13);
    unw_set_reg(cursor, UNW_X86_64_R14, winContext->R14);
    unw_set_reg(cursor, UNW_X86_64_R15, winContext->R15);
#else
#error unsupported architecture
#endif
}
#endif

static void UnwindContextToWinContext(unw_cursor_t *cursor, CONTEXT *winContext)
{
#if defined(_AMD64_)
    unw_get_reg(cursor, UNW_REG_IP, (unw_word_t *) &winContext->Rip);
    unw_get_reg(cursor, UNW_REG_SP, (unw_word_t *) &winContext->Rsp);
    unw_get_reg(cursor, UNW_X86_64_RBP, (unw_word_t *) &winContext->Rbp);
    unw_get_reg(cursor, UNW_X86_64_RBX, (unw_word_t *) &winContext->Rbx);
    unw_get_reg(cursor, UNW_X86_64_R12, (unw_word_t *) &winContext->R12);
    unw_get_reg(cursor, UNW_X86_64_R13, (unw_word_t *) &winContext->R13);
    unw_get_reg(cursor, UNW_X86_64_R14, (unw_word_t *) &winContext->R14);
    unw_get_reg(cursor, UNW_X86_64_R15, (unw_word_t *) &winContext->R15);
#else
#error unsupported architecture
#endif
}

static void GetContextPointer(unw_cursor_t *cursor, int reg, PDWORD64 *contextPointer)
{
#if defined(__APPLE__)
    //OSXTODO
#else
    unw_save_loc_t saveLoc;
    unw_get_save_loc(cursor, reg, &saveLoc);
    if (saveLoc.type == UNW_SLT_MEMORY)
    {
        *contextPointer = (PDWORD64)saveLoc.u.addr;
    }
#endif
}

static void GetContextPointers(unw_cursor_t *cursor, KNONVOLATILE_CONTEXT_POINTERS *contextPointers)
{
#if defined(_AMD64_)
    GetContextPointer(cursor, UNW_X86_64_RBP, &contextPointers->Rbp);
    GetContextPointer(cursor, UNW_X86_64_RBX, &contextPointers->Rbx);
    GetContextPointer(cursor, UNW_X86_64_R12, &contextPointers->R12);
    GetContextPointer(cursor, UNW_X86_64_R13, &contextPointers->R13);
    GetContextPointer(cursor, UNW_X86_64_R14, &contextPointers->R14);
    GetContextPointer(cursor, UNW_X86_64_R15, &contextPointers->R15);
#else
#error unsupported architecture
#endif
}

BOOL PAL_VirtualUnwind(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *contextPointers)
{
    int st;
    unw_context_t unwContext;
    unw_cursor_t cursor;

#if UNWIND_CONTEXT_IS_UCONTEXT_T
    WinContextToUnwindContext(context, &unwContext);
#else
    st = unw_getcontext(&unwContext);
    if (st < 0)
    {
        return FALSE;
    }
#endif

    st = unw_init_local(&cursor, &unwContext);
    if (st < 0)
    {
        return FALSE;
    }

#if !UNWIND_CONTEXT_IS_UCONTEXT_T
    // Set the unwind context to the specified windows context
    WinContextToUnwindCursor(context, &cursor);
#endif

    st = unw_step(&cursor);
    if (st < 0)
    {
        return FALSE;
    }

    // Update the passed in windows context to reflect the unwind
    UnwindContextToWinContext(&cursor, context);

    if (contextPointers != NULL)
    {
        GetContextPointers(&cursor, contextPointers);
    }

    return TRUE;
}

PAL_NORETURN
static void RtlpRaiseException(EXCEPTION_RECORD *ExceptionRecord)
{
    // Capture the context of RtlpRaiseException.
    CONTEXT ContextRecord;
    ZeroMemory(&ContextRecord, sizeof(CONTEXT));
    ContextRecord.ContextFlags = CONTEXT_FULL;
    CONTEXT_CaptureContext(&ContextRecord);

    // Find the caller of RtlpRaiseException.
    PAL_VirtualUnwind(&ContextRecord, NULL);

    // The frame we're looking at now is RaiseException. We have to unwind one
    // level further to get the actual context user code could be resumed at.
    PAL_VirtualUnwind(&ContextRecord, NULL);
#if defined(_X86_)
    ExceptionRecord->ExceptionAddress = (void *) ContextRecord.Eip;
#elif defined(_AMD64_)
    ExceptionRecord->ExceptionAddress = (void *) ContextRecord.Rip;
#else
#error unsupported architecture
#endif

    EXCEPTION_POINTERS pointers;
    pointers.ExceptionRecord = ExceptionRecord;
    pointers.ContextRecord = &ContextRecord;

    SEHRaiseException(InternalGetCurrentThread(), &pointers, 0);
}

PAL_NORETURN
void SEHRaiseException(CPalThread *pthrCurrent,
                       PEXCEPTION_POINTERS lpExceptionPointers,
                       int signal_code)
{
    throw PAL_SEHException(lpExceptionPointers->ExceptionRecord, lpExceptionPointers->ContextRecord);
}

/*++
Function:
  RaiseException

See MSDN doc.
--*/
// no PAL_NORETURN, as callers must assume this can return for continuable exceptions.
VOID
PALAPI
RaiseException(IN DWORD dwExceptionCode,
               IN DWORD dwExceptionFlags,
               IN DWORD nNumberOfArguments,
               IN CONST ULONG_PTR *lpArguments)
{
    // PERF_ENTRY_ONLY is used here because RaiseException may or may not
    // return. We can not get latency data without PERF_EXIT. For this reason,
    // PERF_ENTRY_ONLY is used to profile frequency only.
    PERF_ENTRY_ONLY(RaiseException);
    ENTRY("RaiseException(dwCode=%#x, dwFlags=%#x, nArgs=%u, lpArguments=%p)\n",
          dwExceptionCode, dwExceptionFlags, nNumberOfArguments, lpArguments);

    /* Validate parameters */
    if (dwExceptionCode & RESERVED_SEH_BIT)
    {
        WARN("Exception code %08x has bit 28 set; clearing it.\n", dwExceptionCode);
        dwExceptionCode ^= RESERVED_SEH_BIT;
    }

    if (nNumberOfArguments > EXCEPTION_MAXIMUM_PARAMETERS)
    {
        nNumberOfArguments = EXCEPTION_MAXIMUM_PARAMETERS;
    }

    EXCEPTION_RECORD exceptionRecord;
    ZeroMemory(&exceptionRecord, sizeof(EXCEPTION_RECORD));

    exceptionRecord.ExceptionCode = dwExceptionCode;
    exceptionRecord.ExceptionFlags = dwExceptionFlags;
    exceptionRecord.ExceptionRecord = NULL;
    exceptionRecord.ExceptionAddress = NULL; // will be set by RtlpRaiseException
    exceptionRecord.NumberParameters = nNumberOfArguments;
    if (nNumberOfArguments)
    {
        if (nNumberOfArguments > EXCEPTION_MAXIMUM_PARAMETERS)
        {
            WARN("Number of arguments (%d) exceeds the limit "
                 "EXCEPTION_MAXIMUM_PARAMETERS (%d); ignoring extra parameters.\n",
                  nNumberOfArguments, EXCEPTION_MAXIMUM_PARAMETERS);
            nNumberOfArguments = EXCEPTION_MAXIMUM_PARAMETERS;
        }
        CopyMemory(exceptionRecord.ExceptionInformation, lpArguments,
                   nNumberOfArguments * sizeof(ULONG_PTR));
    }
    RtlpRaiseException(&exceptionRecord);

    LOGEXIT("RaiseException returns\n");
}
<commit_msg>Remove duplicate check for number of exception arguments<commit_after>//
// Copyright (c) Microsoft. All rights reserved.
// Copyright (c) Geoff Norton. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//

/*++

Module Name:

    seh-unwind.cpp

Abstract:

    Implementation of exception API functions based on
    the Unwind API.

--*/

#ifndef FEATURE_PAL_SXS
#error FEATURE_PAL_SXS needs to be defined for this file.
#endif // !FEATURE_PAL_SXS

#include "pal/context.h"
#include <dlfcn.h>
#include <exception>
#define UNW_LOCAL_ONLY
#include <libunwind.h>

//----------------------------------------------------------------------
// Virtual Unwinding
//----------------------------------------------------------------------

#if UNWIND_CONTEXT_IS_UCONTEXT_T
static void WinContextToUnwindContext(CONTEXT *winContext, unw_context_t *unwContext)
{
#if defined(_AMD64_)
    unwContext->uc_mcontext.gregs[REG_RIP] = winContext->Rip;
    unwContext->uc_mcontext.gregs[REG_RSP] = winContext->Rsp;
    unwContext->uc_mcontext.gregs[REG_RBP] = winContext->Rbp;
    unwContext->uc_mcontext.gregs[REG_RBX] = winContext->Rbx;
    unwContext->uc_mcontext.gregs[REG_R12] = winContext->R12;
    unwContext->uc_mcontext.gregs[REG_R13] = winContext->R13;
    unwContext->uc_mcontext.gregs[REG_R14] = winContext->R14;
    unwContext->uc_mcontext.gregs[REG_R15] = winContext->R15;
#else
#error unsupported architecture
#endif
}
#else
static void WinContextToUnwindCursor(CONTEXT *winContext, unw_cursor_t *cursor)
{
#if defined(_AMD64_)
    unw_set_reg(cursor, UNW_REG_IP, winContext->Rip);
    unw_set_reg(cursor, UNW_REG_SP, winContext->Rsp);
    unw_set_reg(cursor, UNW_X86_64_RBP, winContext->Rbp);
    unw_set_reg(cursor, UNW_X86_64_RBX, winContext->Rbx);
    unw_set_reg(cursor, UNW_X86_64_R12, winContext->R12);
    unw_set_reg(cursor, UNW_X86_64_R13, winContext->R13);
    unw_set_reg(cursor, UNW_X86_64_R14, winContext->R14);
    unw_set_reg(cursor, UNW_X86_64_R15, winContext->R15);
#else
#error unsupported architecture
#endif
}
#endif

static void UnwindContextToWinContext(unw_cursor_t *cursor, CONTEXT *winContext)
{
#if defined(_AMD64_)
    unw_get_reg(cursor, UNW_REG_IP, (unw_word_t *) &winContext->Rip);
    unw_get_reg(cursor, UNW_REG_SP, (unw_word_t *) &winContext->Rsp);
    unw_get_reg(cursor, UNW_X86_64_RBP, (unw_word_t *) &winContext->Rbp);
    unw_get_reg(cursor, UNW_X86_64_RBX, (unw_word_t *) &winContext->Rbx);
    unw_get_reg(cursor, UNW_X86_64_R12, (unw_word_t *) &winContext->R12);
    unw_get_reg(cursor, UNW_X86_64_R13, (unw_word_t *) &winContext->R13);
    unw_get_reg(cursor, UNW_X86_64_R14, (unw_word_t *) &winContext->R14);
    unw_get_reg(cursor, UNW_X86_64_R15, (unw_word_t *) &winContext->R15);
#else
#error unsupported architecture
#endif
}

static void GetContextPointer(unw_cursor_t *cursor, int reg, PDWORD64 *contextPointer)
{
#if defined(__APPLE__)
    //OSXTODO
#else
    unw_save_loc_t saveLoc;
    unw_get_save_loc(cursor, reg, &saveLoc);
    if (saveLoc.type == UNW_SLT_MEMORY)
    {
        *contextPointer = (PDWORD64)saveLoc.u.addr;
    }
#endif
}

static void GetContextPointers(unw_cursor_t *cursor, KNONVOLATILE_CONTEXT_POINTERS *contextPointers)
{
#if defined(_AMD64_)
    GetContextPointer(cursor, UNW_X86_64_RBP, &contextPointers->Rbp);
    GetContextPointer(cursor, UNW_X86_64_RBX, &contextPointers->Rbx);
    GetContextPointer(cursor, UNW_X86_64_R12, &contextPointers->R12);
    GetContextPointer(cursor, UNW_X86_64_R13, &contextPointers->R13);
    GetContextPointer(cursor, UNW_X86_64_R14, &contextPointers->R14);
    GetContextPointer(cursor, UNW_X86_64_R15, &contextPointers->R15);
#else
#error unsupported architecture
#endif
}

BOOL PAL_VirtualUnwind(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *contextPointers)
{
    int st;
    unw_context_t unwContext;
    unw_cursor_t cursor;

#if UNWIND_CONTEXT_IS_UCONTEXT_T
    WinContextToUnwindContext(context, &unwContext);
#else
    st = unw_getcontext(&unwContext);
    if (st < 0)
    {
        return FALSE;
    }
#endif

    st = unw_init_local(&cursor, &unwContext);
    if (st < 0)
    {
        return FALSE;
    }

#if !UNWIND_CONTEXT_IS_UCONTEXT_T
    // Set the unwind context to the specified windows context
    WinContextToUnwindCursor(context, &cursor);
#endif

    st = unw_step(&cursor);
    if (st < 0)
    {
        return FALSE;
    }

    // Update the passed in windows context to reflect the unwind
    UnwindContextToWinContext(&cursor, context);

    if (contextPointers != NULL)
    {
        GetContextPointers(&cursor, contextPointers);
    }

    return TRUE;
}

PAL_NORETURN
static void RtlpRaiseException(EXCEPTION_RECORD *ExceptionRecord)
{
    // Capture the context of RtlpRaiseException.
    CONTEXT ContextRecord;
    ZeroMemory(&ContextRecord, sizeof(CONTEXT));
    ContextRecord.ContextFlags = CONTEXT_FULL;
    CONTEXT_CaptureContext(&ContextRecord);

    // Find the caller of RtlpRaiseException.
    PAL_VirtualUnwind(&ContextRecord, NULL);

    // The frame we're looking at now is RaiseException. We have to unwind one
    // level further to get the actual context user code could be resumed at.
    PAL_VirtualUnwind(&ContextRecord, NULL);
#if defined(_X86_)
    ExceptionRecord->ExceptionAddress = (void *) ContextRecord.Eip;
#elif defined(_AMD64_)
    ExceptionRecord->ExceptionAddress = (void *) ContextRecord.Rip;
#else
#error unsupported architecture
#endif

    EXCEPTION_POINTERS pointers;
    pointers.ExceptionRecord = ExceptionRecord;
    pointers.ContextRecord = &ContextRecord;

    SEHRaiseException(InternalGetCurrentThread(), &pointers, 0);
}

PAL_NORETURN
void SEHRaiseException(CPalThread *pthrCurrent,
                       PEXCEPTION_POINTERS lpExceptionPointers,
                       int signal_code)
{
    throw PAL_SEHException(lpExceptionPointers->ExceptionRecord, lpExceptionPointers->ContextRecord);
}

/*++
Function:
  RaiseException

See MSDN doc.
--*/
// no PAL_NORETURN, as callers must assume this can return for continuable exceptions.
VOID
PALAPI
RaiseException(IN DWORD dwExceptionCode,
               IN DWORD dwExceptionFlags,
               IN DWORD nNumberOfArguments,
               IN CONST ULONG_PTR *lpArguments)
{
    // PERF_ENTRY_ONLY is used here because RaiseException may or may not
    // return. We can not get latency data without PERF_EXIT. For this reason,
    // PERF_ENTRY_ONLY is used to profile frequency only.
    PERF_ENTRY_ONLY(RaiseException);
    ENTRY("RaiseException(dwCode=%#x, dwFlags=%#x, nArgs=%u, lpArguments=%p)\n",
          dwExceptionCode, dwExceptionFlags, nNumberOfArguments, lpArguments);

    /* Validate parameters */
    if (dwExceptionCode & RESERVED_SEH_BIT)
    {
        WARN("Exception code %08x has bit 28 set; clearing it.\n", dwExceptionCode);
        dwExceptionCode ^= RESERVED_SEH_BIT;
    }

    if (nNumberOfArguments > EXCEPTION_MAXIMUM_PARAMETERS)
    {
        WARN("Number of arguments (%d) exceeds the limit "
            "EXCEPTION_MAXIMUM_PARAMETERS (%d); ignoring extra parameters.\n",
            nNumberOfArguments, EXCEPTION_MAXIMUM_PARAMETERS);
        nNumberOfArguments = EXCEPTION_MAXIMUM_PARAMETERS;
    }

    EXCEPTION_RECORD exceptionRecord;
    ZeroMemory(&exceptionRecord, sizeof(EXCEPTION_RECORD));

    exceptionRecord.ExceptionCode = dwExceptionCode;
    exceptionRecord.ExceptionFlags = dwExceptionFlags;
    exceptionRecord.ExceptionRecord = NULL;
    exceptionRecord.ExceptionAddress = NULL; // will be set by RtlpRaiseException
    exceptionRecord.NumberParameters = nNumberOfArguments;
    if (nNumberOfArguments)
    {
        CopyMemory(exceptionRecord.ExceptionInformation, lpArguments,
                   nNumberOfArguments * sizeof(ULONG_PTR));
    }
    RtlpRaiseException(&exceptionRecord);

    LOGEXIT("RaiseException returns\n");
}
<|endoftext|>


<commit_before>#include <exprtk/exprtk.hpp>

#include <memory>

#include <possumwood_sdk/node_implementation.h>
#include <possumwood_sdk/source_editor.h>

#include <QPainter>
#include <QPushButton>
#include <QMenu>

#include <luabind/luabind.hpp>

#include "datatypes/state.h"
#include "datatypes/context.h"

namespace {

dependency_graph::InAttr<std::string> a_src;
dependency_graph::InAttr<possumwood::lua::Context> a_context;
dependency_graph::OutAttr<float> a_out;

class Popup : public QMenu {
	public:
		Popup(QWidget* parent) : QMenu(parent) {
		}

		void addItem(const std::string& name) {
			addAction(name.c_str());
		}

	private:
};

class Editor : public possumwood::SourceEditor {
	public:
		Editor() : SourceEditor(a_src), m_popup(nullptr) {
			m_varsButton = new QPushButton("Variables");
			buttonsLayout()->insertWidget(0, m_varsButton);

			widget()->connect(m_varsButton, &QPushButton::pressed, [this]() {
				if(m_popup)
					m_popup->popup(
						m_varsButton->mapToGlobal(QPoint(0,-m_popup->sizeHint().height()))
					);
			});
		}

	protected:
		virtual void valueChanged(const dependency_graph::Attr& attr) override {
			if(attr == a_context) {
				if(m_popup)
					m_popup->deleteLater();

				populateVariableList();
			}

			else
				SourceEditor::valueChanged(attr);
		}

		void populateVariableList() {
			if(m_popup)
				m_popup->deleteLater();

			m_popup = new Popup(m_varsButton);

			m_popup->connect(m_popup, &Popup::triggered, [this](QAction* action) {
				QString text = action->text();
				while(!text.isEmpty() && !QChar(text[0]).isLetterOrNumber())
					text = text.mid(1, text.length()-1);
				if(text.indexOf('\t') >= 0)
					text = text.mid(0, text.indexOf('\t'));

				editorWidget()->insertPlainText(text);
			});

			// variables
			unsigned ctr = 0;
			for(auto& s : values().get(a_context).variables()) {
				m_popup->addItem(s.name() + "\t" + s.str());
				++ctr;
			}
		}

	private:
		QPushButton* m_varsButton;

		Popup* m_popup;
};

dependency_graph::State compute(dependency_graph::Values& data) {
	dependency_graph::State result;

	const std::string& src = data.get(a_src);

	// Create a new lua state
	possumwood::lua::State state(data.get(a_context));

	// Define a lua function that we can call
	luaL_dostring(state, src.c_str());

	const float out = luabind::call_function<float>(state, "main");
	data.set(a_out, out);

	return result;
}

void init(possumwood::Metadata& meta) {
	meta.addAttribute(a_src, "source", std::string("function main()\n  return 0\nend\n"));
	meta.addAttribute(a_context, "context");
	meta.addAttribute(a_out, "out");

	meta.addInfluence(a_src, a_out);
	meta.addInfluence(a_context, a_out);

	meta.setCompute(&compute);
	meta.setEditor<Editor>();
}

possumwood::NodeImplementation s_impl("lua/script", init);

}
<commit_msg>Added exception handling for Lua Script - now print outs detailed error message in the status bar<commit_after>#include <exprtk/exprtk.hpp>

#include <memory>

#include <possumwood_sdk/node_implementation.h>
#include <possumwood_sdk/source_editor.h>

#include <QPainter>
#include <QPushButton>
#include <QMenu>

#include <luabind/luabind.hpp>

#include "datatypes/state.h"
#include "datatypes/context.h"

namespace {

dependency_graph::InAttr<std::string> a_src;
dependency_graph::InAttr<possumwood::lua::Context> a_context;
dependency_graph::OutAttr<float> a_out;

class Popup : public QMenu {
	public:
		Popup(QWidget* parent) : QMenu(parent) {
		}

		void addItem(const std::string& name) {
			addAction(name.c_str());
		}

	private:
};

class Editor : public possumwood::SourceEditor {
	public:
		Editor() : SourceEditor(a_src), m_popup(nullptr) {
			m_varsButton = new QPushButton("Variables");
			buttonsLayout()->insertWidget(0, m_varsButton);

			widget()->connect(m_varsButton, &QPushButton::pressed, [this]() {
				if(m_popup)
					m_popup->popup(
						m_varsButton->mapToGlobal(QPoint(0,-m_popup->sizeHint().height()))
					);
			});
		}

	protected:
		virtual void valueChanged(const dependency_graph::Attr& attr) override {
			if(attr == a_context) {
				if(m_popup)
					m_popup->deleteLater();

				populateVariableList();
			}

			else
				SourceEditor::valueChanged(attr);
		}

		void populateVariableList() {
			if(m_popup)
				m_popup->deleteLater();

			m_popup = new Popup(m_varsButton);

			m_popup->connect(m_popup, &Popup::triggered, [this](QAction* action) {
				QString text = action->text();
				while(!text.isEmpty() && !QChar(text[0]).isLetterOrNumber())
					text = text.mid(1, text.length()-1);
				if(text.indexOf('\t') >= 0)
					text = text.mid(0, text.indexOf('\t'));

				editorWidget()->insertPlainText(text);
			});

			// variables
			unsigned ctr = 0;
			for(auto& s : values().get(a_context).variables()) {
				m_popup->addItem(s.name() + "\t" + s.str());
				++ctr;
			}
		}

	private:
		QPushButton* m_varsButton;

		Popup* m_popup;
};

dependency_graph::State compute(dependency_graph::Values& data) {
	dependency_graph::State result;

	const std::string& src = data.get(a_src);

	// Create a new lua state
	possumwood::lua::State state(data.get(a_context));

	// Define a lua function that we can call
	luaL_dostring(state, src.c_str());

	try {
		const float out = luabind::call_function<float>(state, "main");
		data.set(a_out, out);
	}
	catch(const luabind::error& err) {
		throw std::runtime_error(lua_tostring(err.state(), -1));
	}

	return result;
}

void init(possumwood::Metadata& meta) {
	meta.addAttribute(a_src, "source", std::string("function main()\n  return 0\nend\n"));
	meta.addAttribute(a_context, "context");
	meta.addAttribute(a_out, "out");

	meta.addInfluence(a_src, a_out);
	meta.addInfluence(a_context, a_out);

	meta.setCompute(&compute);
	meta.setEditor<Editor>();
}

possumwood::NodeImplementation s_impl("lua/script", init);

}
<|endoftext|>


<commit_before>/**************************************************************************
**
** Copyright (C) 2012 - 2014 BlackBerry Limited. All rights reserved.
**
** Contact: BlackBerry (qt@blackberry.com)
** Contact: KDAB (info@kdab.com)
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company.  For licensing terms and
** conditions see http://www.qt.io/terms-conditions.  For further information
** use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, The Qt Company gives you certain additional
** rights.  These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "qnxqtversion.h"

#include "qnxbaseqtconfigwidget.h"
#include "qnxconstants.h"
#include "qnxutils.h"

#include <coreplugin/featureprovider.h>
#include <qtsupport/qtsupportconstants.h>
#include <utils/environment.h>
#include <utils/hostosinfo.h>

#include <QDir>

namespace Qnx {
namespace Internal {

static char SDK_PATH_KEY[] = "SDKPath";
static char ARCH_KEY[] = "Arch";

QnxQtVersion::QnxQtVersion() : m_arch(UnknownArch)
{ }

QnxQtVersion::QnxQtVersion(QnxArchitecture arch, const Utils::FileName &path, bool isAutoDetected,
                           const QString &autoDetectionSource) :
    QtSupport::BaseQtVersion(path, isAutoDetected, autoDetectionSource),
    m_arch(arch)
{
    setUnexpandedDisplayName(defaultUnexpandedDisplayName(path, false));
}

QnxQtVersion *QnxQtVersion::clone() const
{
    return new QnxQtVersion(*this);
}

QString QnxQtVersion::type() const
{
    return QLatin1String(Constants::QNX_QNX_QT);
}

QString QnxQtVersion::description() const
{
    //: Qt Version is meant for QNX
    return QCoreApplication::translate("Qnx::Internal::QnxQtVersion", "QNX %1").arg(archString());
}

Core::FeatureSet QnxQtVersion::availableFeatures() const
{
    Core::FeatureSet features = QtSupport::BaseQtVersion::availableFeatures();
    features |= Core::FeatureSet(Constants::QNX_QNX_FEATURE);
    features.remove(Core::Feature(QtSupport::Constants::FEATURE_QT_CONSOLE));
    features.remove(Core::Feature(QtSupport::Constants::FEATURE_QT_WEBKIT));
    return features;
}

QString QnxQtVersion::platformName() const
{
    return QString::fromLatin1(Constants::QNX_QNX_PLATFORM_NAME);
}

QString QnxQtVersion::platformDisplayName() const
{
    return QCoreApplication::translate("Qnx::Internal::QnxQtVersion", "QNX");
}

QString QnxQtVersion::qnxHost() const
{
    if (!m_environmentUpToDate)
        updateEnvironment();

    foreach (const Utils::EnvironmentItem &item, m_qnxEnv) {
        if (item.name == QLatin1String(Constants::QNX_HOST_KEY))
            return item.value;
    }

    return QString();
}

QString QnxQtVersion::qnxTarget() const
{
    if (!m_environmentUpToDate)
        updateEnvironment();

    foreach (const Utils::EnvironmentItem &item, m_qnxEnv) {
        if (item.name == QLatin1String(Constants::QNX_TARGET_KEY))
            return item.value;
    }

    return QString();
}

QnxArchitecture QnxQtVersion::architecture() const
{
    return m_arch;
}

QString QnxQtVersion::archString() const
{
    switch (m_arch) {
    case X86:
        return QLatin1String("x86");
    case ArmLeV7:
        return QLatin1String("ARMle-v7");
    case UnknownArch:
        return QString();
    }
    return QString();
}

QVariantMap QnxQtVersion::toMap() const
{
    QVariantMap result = BaseQtVersion::toMap();
    result.insert(QLatin1String(SDK_PATH_KEY), sdkPath());
    result.insert(QLatin1String(ARCH_KEY), m_arch);
    return result;
}

void QnxQtVersion::fromMap(const QVariantMap &map)
{
    BaseQtVersion::fromMap(map);
    setSdkPath(QDir::fromNativeSeparators(map.value(QLatin1String(SDK_PATH_KEY)).toString()));
    m_arch = static_cast<QnxArchitecture>(map.value(QLatin1String(ARCH_KEY), UnknownArch).toInt());
}

QList<ProjectExplorer::Abi> QnxQtVersion::detectQtAbis() const
{
    ensureMkSpecParsed();
    return qtAbisFromLibrary(qtCorePaths(versionInfo(), qtVersionString()));
}

void QnxQtVersion::addToEnvironment(const ProjectExplorer::Kit *k, Utils::Environment &env) const
{
    QtSupport::BaseQtVersion::addToEnvironment(k, env);
    updateEnvironment();
    env.modify(m_qnxEnv);

    env.prependOrSetLibrarySearchPath(versionInfo().value(QLatin1String("QT_INSTALL_LIBS")));
}

Utils::Environment QnxQtVersion::qmakeRunEnvironment() const
{
    if (!sdkPath().isEmpty())
        updateEnvironment();

    Utils::Environment env = Utils::Environment::systemEnvironment();
    env.modify(m_qnxEnv);

    return env;
}

QtSupport::QtConfigWidget *QnxQtVersion::createConfigurationWidget() const
{
    return new QnxBaseQtConfigWidget(const_cast<QnxQtVersion *>(this));
}

bool QnxQtVersion::isValid() const
{
    return QtSupport::BaseQtVersion::isValid() && !sdkPath().isEmpty();
}

QString QnxQtVersion::invalidReason() const
{
    if (sdkPath().isEmpty())
        return QCoreApplication::translate("Qnx::Internal::QnxQtVersion", "No SDK path was set up");
    return QtSupport::BaseQtVersion::invalidReason();
}

QString QnxQtVersion::sdkPath() const
{
    return m_sdkPath;
}

void QnxQtVersion::setSdkPath(const QString &sdkPath)
{
    if (m_sdkPath == sdkPath)
        return;

    m_sdkPath = sdkPath;
    m_environmentUpToDate = false;
}

void QnxQtVersion::updateEnvironment() const
{
    if (!m_environmentUpToDate) {
        m_qnxEnv = environment();
        m_environmentUpToDate = true;
    }
}

QList<Utils::EnvironmentItem> QnxQtVersion::environment() const
{
    return QnxUtils::qnxEnvironment(sdkPath());
}

} // namespace Internal
} // namespace Qnx
<commit_msg>QNX: fix message punctuation<commit_after>/**************************************************************************
**
** Copyright (C) 2012 - 2014 BlackBerry Limited. All rights reserved.
**
** Contact: BlackBerry (qt@blackberry.com)
** Contact: KDAB (info@kdab.com)
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company.  For licensing terms and
** conditions see http://www.qt.io/terms-conditions.  For further information
** use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, The Qt Company gives you certain additional
** rights.  These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "qnxqtversion.h"

#include "qnxbaseqtconfigwidget.h"
#include "qnxconstants.h"
#include "qnxutils.h"

#include <coreplugin/featureprovider.h>
#include <qtsupport/qtsupportconstants.h>
#include <utils/environment.h>
#include <utils/hostosinfo.h>

#include <QDir>

namespace Qnx {
namespace Internal {

static char SDK_PATH_KEY[] = "SDKPath";
static char ARCH_KEY[] = "Arch";

QnxQtVersion::QnxQtVersion() : m_arch(UnknownArch)
{ }

QnxQtVersion::QnxQtVersion(QnxArchitecture arch, const Utils::FileName &path, bool isAutoDetected,
                           const QString &autoDetectionSource) :
    QtSupport::BaseQtVersion(path, isAutoDetected, autoDetectionSource),
    m_arch(arch)
{
    setUnexpandedDisplayName(defaultUnexpandedDisplayName(path, false));
}

QnxQtVersion *QnxQtVersion::clone() const
{
    return new QnxQtVersion(*this);
}

QString QnxQtVersion::type() const
{
    return QLatin1String(Constants::QNX_QNX_QT);
}

QString QnxQtVersion::description() const
{
    //: Qt Version is meant for QNX
    return QCoreApplication::translate("Qnx::Internal::QnxQtVersion", "QNX %1").arg(archString());
}

Core::FeatureSet QnxQtVersion::availableFeatures() const
{
    Core::FeatureSet features = QtSupport::BaseQtVersion::availableFeatures();
    features |= Core::FeatureSet(Constants::QNX_QNX_FEATURE);
    features.remove(Core::Feature(QtSupport::Constants::FEATURE_QT_CONSOLE));
    features.remove(Core::Feature(QtSupport::Constants::FEATURE_QT_WEBKIT));
    return features;
}

QString QnxQtVersion::platformName() const
{
    return QString::fromLatin1(Constants::QNX_QNX_PLATFORM_NAME);
}

QString QnxQtVersion::platformDisplayName() const
{
    return QCoreApplication::translate("Qnx::Internal::QnxQtVersion", "QNX");
}

QString QnxQtVersion::qnxHost() const
{
    if (!m_environmentUpToDate)
        updateEnvironment();

    foreach (const Utils::EnvironmentItem &item, m_qnxEnv) {
        if (item.name == QLatin1String(Constants::QNX_HOST_KEY))
            return item.value;
    }

    return QString();
}

QString QnxQtVersion::qnxTarget() const
{
    if (!m_environmentUpToDate)
        updateEnvironment();

    foreach (const Utils::EnvironmentItem &item, m_qnxEnv) {
        if (item.name == QLatin1String(Constants::QNX_TARGET_KEY))
            return item.value;
    }

    return QString();
}

QnxArchitecture QnxQtVersion::architecture() const
{
    return m_arch;
}

QString QnxQtVersion::archString() const
{
    switch (m_arch) {
    case X86:
        return QLatin1String("x86");
    case ArmLeV7:
        return QLatin1String("ARMle-v7");
    case UnknownArch:
        return QString();
    }
    return QString();
}

QVariantMap QnxQtVersion::toMap() const
{
    QVariantMap result = BaseQtVersion::toMap();
    result.insert(QLatin1String(SDK_PATH_KEY), sdkPath());
    result.insert(QLatin1String(ARCH_KEY), m_arch);
    return result;
}

void QnxQtVersion::fromMap(const QVariantMap &map)
{
    BaseQtVersion::fromMap(map);
    setSdkPath(QDir::fromNativeSeparators(map.value(QLatin1String(SDK_PATH_KEY)).toString()));
    m_arch = static_cast<QnxArchitecture>(map.value(QLatin1String(ARCH_KEY), UnknownArch).toInt());
}

QList<ProjectExplorer::Abi> QnxQtVersion::detectQtAbis() const
{
    ensureMkSpecParsed();
    return qtAbisFromLibrary(qtCorePaths(versionInfo(), qtVersionString()));
}

void QnxQtVersion::addToEnvironment(const ProjectExplorer::Kit *k, Utils::Environment &env) const
{
    QtSupport::BaseQtVersion::addToEnvironment(k, env);
    updateEnvironment();
    env.modify(m_qnxEnv);

    env.prependOrSetLibrarySearchPath(versionInfo().value(QLatin1String("QT_INSTALL_LIBS")));
}

Utils::Environment QnxQtVersion::qmakeRunEnvironment() const
{
    if (!sdkPath().isEmpty())
        updateEnvironment();

    Utils::Environment env = Utils::Environment::systemEnvironment();
    env.modify(m_qnxEnv);

    return env;
}

QtSupport::QtConfigWidget *QnxQtVersion::createConfigurationWidget() const
{
    return new QnxBaseQtConfigWidget(const_cast<QnxQtVersion *>(this));
}

bool QnxQtVersion::isValid() const
{
    return QtSupport::BaseQtVersion::isValid() && !sdkPath().isEmpty();
}

QString QnxQtVersion::invalidReason() const
{
    if (sdkPath().isEmpty())
        return QCoreApplication::translate("Qnx::Internal::QnxQtVersion", "No SDK path was set up.");
    return QtSupport::BaseQtVersion::invalidReason();
}

QString QnxQtVersion::sdkPath() const
{
    return m_sdkPath;
}

void QnxQtVersion::setSdkPath(const QString &sdkPath)
{
    if (m_sdkPath == sdkPath)
        return;

    m_sdkPath = sdkPath;
    m_environmentUpToDate = false;
}

void QnxQtVersion::updateEnvironment() const
{
    if (!m_environmentUpToDate) {
        m_qnxEnv = environment();
        m_environmentUpToDate = true;
    }
}

QList<Utils::EnvironmentItem> QnxQtVersion::environment() const
{
    return QnxUtils::qnxEnvironment(sdkPath());
}

} // namespace Internal
} // namespace Qnx
<|endoftext|>


<commit_before>#ifdef _WIN32

#include <pd_backend.h>
#include <assert.h>
#include <stdio.h>
#include <Dbgeng.h>
#include <string>

struct DbgEngPlugin : public DebugBaseEventCallbacks
{
	PDDebugState state = PDDebugState_noTarget;
	bool hasValidTarget = false;

	std::string targetName;

	IDebugClient* debugClient = nullptr;
	IDebugControl* debugControl = nullptr;

	// IUnknown
	STDMETHOD_(ULONG, AddRef)(THIS);
	STDMETHOD_(ULONG, Release)(THIS);

	// IDebugEventCallbacks
	STDMETHOD(GetInterestMask)(THIS_
		OUT PULONG Mask);
	STDMETHOD(Breakpoint)(THIS_
		IN PDEBUG_BREAKPOINT Bp);
	STDMETHOD(Exception)(THIS_
		IN PEXCEPTION_RECORD64 Exception, IN ULONG FirstChance);
	STDMETHOD(CreateProcess)(THIS_
		IN ULONG64 ImageFileHandle,
		IN ULONG64 Handle,
		IN ULONG64 BaseOffset,
		IN ULONG ModuleSize,
		IN PCSTR ModuleName,
		IN PCSTR ImageName,
		IN ULONG CheckSum,
		IN ULONG TimeDateStamp,
		IN ULONG64 InitialThreadHandle,
		IN ULONG64 ThreadDataOffset,
		IN ULONG64 StartOffset);
	STDMETHOD(LoadModule)(THIS_
		IN ULONG64 ImageFileHandle,
		IN ULONG64 BaseOffset,
		IN ULONG ModuleSize,
		IN PCSTR ModuleName,
		IN PCSTR ImageName,
		IN ULONG CheckSum,
		IN ULONG TimeDateStamp);
	STDMETHOD(SessionStatus)(THIS_
		IN ULONG Status);
};

STDMETHODIMP_(ULONG) DbgEngPlugin::AddRef(THIS)
{
	return 1;
}

STDMETHODIMP_(ULONG) DbgEngPlugin::Release(THIS)
{
	return 0;
}

STDMETHODIMP DbgEngPlugin::GetInterestMask(THIS_
	OUT PULONG Mask)
{
	*Mask =
		DEBUG_EVENT_BREAKPOINT |
		DEBUG_EVENT_EXCEPTION |
		DEBUG_EVENT_CREATE_PROCESS |
		DEBUG_EVENT_LOAD_MODULE |
		DEBUG_EVENT_SESSION_STATUS;
	return S_OK;
}

STDMETHODIMP DbgEngPlugin::Breakpoint(THIS_
	IN PDEBUG_BREAKPOINT Bp)
{
	printf("DbgEngPlugin: Breakpoint\n");
	return S_OK;
}

STDMETHODIMP DbgEngPlugin::Exception(THIS_
	IN PEXCEPTION_RECORD64 Exception,
	IN ULONG FirstChance)
{
	printf("DbgEngPlugin: Exception\n");
	return S_OK;
}

STDMETHODIMP DbgEngPlugin::CreateProcess(THIS_
	IN ULONG64 ImageFileHandle,
	IN ULONG64 Handle,
	IN ULONG64 BaseOffset,
	IN ULONG ModuleSize,
	IN PCSTR ModuleName,
	IN PCSTR ImageName,
	IN ULONG CheckSum,
	IN ULONG TimeDateStamp,
	IN ULONG64 InitialThreadHandle,
	IN ULONG64 ThreadDataOffset,
	IN ULONG64 StartOffset)
{
	printf("DbgEngPlugin: CreateProcess\n");
	return S_OK;
}

STDMETHODIMP DbgEngPlugin::LoadModule(THIS_
	IN ULONG64 ImageFileHandle,
	IN ULONG64 BaseOffset,
	IN ULONG ModuleSize,
	IN PCSTR ModuleName,
	IN PCSTR ImageName,
	IN ULONG CheckSum,
	IN ULONG TimeDateStamp)
{
	printf("DbgEngPlugin: LoadModule\n");
	return S_OK;
}

STDMETHODIMP DbgEngPlugin::SessionStatus(THIS_
	IN ULONG Status)
{
	switch (Status)
	{
		case DEBUG_SESSION_ACTIVE:
			printf("DbgEngPlugin: SessionStatus DEBUG_SESSION_ACTIVE\n");
			break;
		case DEBUG_SESSION_END_SESSION_ACTIVE_TERMINATE:
			printf("DbgEngPlugin: SessionStatus DEBUG_SESSION_END_SESSION_ACTIVE_TERMINATE\n");
			break;
		case DEBUG_SESSION_END_SESSION_ACTIVE_DETACH:
			printf("DbgEngPlugin: SessionStatus DEBUG_SESSION_END_SESSION_ACTIVE_DETACH\n");
			break;
		case DEBUG_SESSION_END_SESSION_PASSIVE:
			printf("DbgEngPlugin: SessionStatus DEBUG_SESSION_END_SESSION_PASSIVE\n");
			break;
		case DEBUG_SESSION_END:
			printf("DbgEngPlugin: SessionStatus DEBUG_SESSION_END\n");
			break;
		case DEBUG_SESSION_REBOOT:
			printf("DbgEngPlugin: SessionStatus DEBUG_SESSION_REBOOT\n");
			break;
		case DEBUG_SESSION_HIBERNATE:
			printf("DbgEngPlugin: SessionStatus DEBUG_SESSION_HIBERNATE\n");
			break;
		case DEBUG_SESSION_FAILURE:
			printf("DbgEngPlugin: SessionStatus DEBUG_SESSION_FAILURE\n");
			break;
	}

	return S_OK;
}

static void updateDbgEngEvent(DbgEngPlugin* plugin, PDWriter* writer)
{
	HRESULT hr = plugin->debugControl->WaitForEvent(DEBUG_WAIT_DEFAULT, 100);

	if (hr == S_FALSE)
	{
		// WaitForEvent timeout occurred
		return;
	}

	// TODO: check and handle execution status
}

void onRun(DbgEngPlugin* plugin)
{
	printf("DbgEngPlugin: onRun\n");

	if (plugin->state == PDDebugState_noTarget)
	{
		assert(!plugin->targetName.empty());

		HRESULT hr = plugin->debugClient->CreateProcess(0, PSTR(plugin->targetName.c_str()), DEBUG_ONLY_THIS_PROCESS);
		assert(SUCCEEDED(hr));

		if (SUCCEEDED(hr))
		{
			printf("Error: could not create process '%s'\n", plugin->targetName.c_str());
		}
		else
		{
			printf("Valid target %s\n", plugin->targetName.c_str());
		}

		plugin->state = PDDebugState_running;
	}
}

void onStop(DbgEngPlugin* plugin)
{
	printf("DbgEngPlugin: onStop\n");
}

static void onBreak(DbgEngPlugin* plugin)
{
	printf("DbgEngPlugin: onBreak\n");
}

static void onStep(DbgEngPlugin* plugin)
{
	printf("DbgEngPlugin: onStep\n");
}

static void onStepOver(DbgEngPlugin* plugin)
{
	printf("DbgEngPlugin: onStepOver\n");
}

static void onStepOut(DbgEngPlugin* plugin)
{
	printf("DbgEngPlugin: onStepOut\n");
}

static void doAction(DbgEngPlugin* plugin, PDAction action)
{
	printf("DbgEngPlugin: doAction\n");

	switch (action)
	{
	case PDAction_stop: onStop(plugin); break;
	case PDAction_break: onBreak(plugin); break;
	case PDAction_run: onRun(plugin); break;
	case PDAction_step: onStep(plugin); break;
	case PDAction_stepOut: onStepOut(plugin); break;
	case PDAction_stepOver: onStepOver(plugin); break;
	}
}

static void setExceptionLocation(DbgEngPlugin* plugin, PDWriter* writer)
{
	printf("DbgEngPlugin: setExceptionLocation\n");
}

static void setCallstack(DbgEngPlugin* plugin, PDWriter* writer)
{
	printf("DbgEngPlugin: setCallstack\n");
}

static void setExecutable(DbgEngPlugin* plugin, PDReader* reader)
{
	printf("DbgEngPlugin: setExecutable\n");

	const char* filename = 0;

	PDRead_findString(reader, &filename, "filename", 0);

	if (!filename)
	{
		printf("Unable to find filename which is required when starting a LLDB debug session\n");
		return;
	}

	printf("found filename \"%s\"\n", filename);

	plugin->targetName = filename;
}

static void setLocals(DbgEngPlugin* plugin, PDWriter* writer)
{
	printf("DbgEngPlugin: setLocals\n");
}

static void setBreakpoint(DbgEngPlugin* plugin, PDReader* reader, PDWriter* writer)
{
	printf("DbgEngPlugin: setBreakpoint\n");
}

static void eventAction(DbgEngPlugin* plugin, PDReader* reader)
{
	printf("DbgEngPlugin: eventAction\n");

	uint32_t action = 0;

	printf("DbgEngPlugin; %d\n", (PDRead_findU32(reader, &action, "action", 0) & 0xff) >> 8);
	printf("DbgEngPlugin: got action (from event) %d\n", action);

	doAction(plugin, (PDAction)action);
}

static const char* eventTypes[] =
{
	"PDEventType_none",
	"PDEventType_getLocals",
	"PDEventType_setLocals",
	"PDEventType_getCallstack",
	"PDEventType_setCallstack",
	"PDEventType_getWatch",
	"PDEventType_setWatch",
	"PDEventType_getRegisters",
	"PDEventType_setRegisters",
	"PDEventType_getMemory",
	"PDEventType_setMemory",
	"PDEventType_getTty",
	"PDEventType_setTty",
	"PDEventType_getExceptionLocation",
	"PDEventType_setExceptionLocation",
	"PDEventType_getDisassembly",
	"PDEventType_setDisassembly",
	"PDEventType_setBreakpoint",
	"PDEventType_getBreakpoint",
	"PDEventType_setExecutable",
	"PDEventType_attachToProcess",
	"PDEventType_attachToRemoteSession",
	"PDEventType_action",
};

static void processEvents(DbgEngPlugin* plugin, PDReader* reader, PDWriter* writer)
{
	printf("DbgEngPlugin: processEvents\n");

	PDEventType event;

	while ((event = (PDEventType)PDRead_getEvent(reader)))
	{
		printf("DbgEngPlugin: %d Got event %s\n", (int)event, eventTypes[event]);

		switch (event)
		{
		case PDEventType_getExceptionLocation: setExceptionLocation(plugin, writer); break;
		case PDEventType_getCallstack: setCallstack(plugin, writer); break;
		case PDEventType_setExecutable: setExecutable(plugin, reader); break;
		case PDEventType_getLocals: setLocals(plugin, writer); break;
		case PDEventType_setBreakpoint: setBreakpoint(plugin, reader, writer); break;
		case PDEventType_action: eventAction(plugin, reader); break;
		}
	}
}

void* createInstance(ServiceFunc* serviceFunc)
{
	DbgEngPlugin* plugin = new DbgEngPlugin;

	HRESULT hr = DebugCreate(__uuidof(IDebugClient), (void**)&plugin->debugClient);
	assert(SUCCEEDED(hr));

	hr = plugin->debugClient->SetEventCallbacks(plugin);
	assert(SUCCEEDED(hr));

	hr = plugin->debugClient->QueryInterface(__uuidof(IDebugControl), (void**)&plugin->debugControl);
	assert(SUCCEEDED(hr));

	return plugin;
}

void destroyInstance(void* userData)
{
	DbgEngPlugin* plugin = reinterpret_cast<DbgEngPlugin*>(userData);

	if (plugin->debugControl)
	{
		plugin->debugControl->Release();
		plugin->debugControl = nullptr;
	}

	if (plugin->debugClient)
	{
		plugin->debugClient->Release();
		plugin->debugClient = nullptr;
	}

	delete plugin;
}

static PDDebugState update(void* userData, PDAction action, PDReader* reader, PDWriter* writer)
{
	DbgEngPlugin* plugin = reinterpret_cast<DbgEngPlugin*>(userData);

	processEvents(plugin, reader, writer);

	doAction(plugin, action);

	if (plugin->state == PDDebugState_running)
	{
		updateDbgEngEvent(plugin, writer);
	}

	return plugin->state;
}

static PDBackendPlugin plugin =
{
	"Microsoft Debugger Engine",
	createInstance,
	destroyInstance,
	update,
};

extern "C" PD_EXPORT void InitPlugin(RegisterPlugin* registerPlugin, void* privateData)
{
	registerPlugin(PD_BACKEND_API_VERSION, &plugin, privateData);
}

#endif
<commit_msg>Added basic stack tracing<commit_after>#ifdef _WIN32

#include <pd_backend.h>
#include <assert.h>
#include <stdio.h>
#include <Dbgeng.h>
#include <string>

struct DbgEngPlugin : public DebugBaseEventCallbacks
{
	PDDebugState state = PDDebugState_noTarget;
	bool hasValidTarget = false;

	std::string targetName;

	IDebugClient* debugClient = nullptr;
	IDebugControl* debugControl = nullptr;

	// IUnknown
	STDMETHOD_(ULONG, AddRef)(THIS);
	STDMETHOD_(ULONG, Release)(THIS);

	// IDebugEventCallbacks
	STDMETHOD(GetInterestMask)(THIS_
		OUT PULONG Mask);
	STDMETHOD(Breakpoint)(THIS_
		IN PDEBUG_BREAKPOINT Bp);
	STDMETHOD(Exception)(THIS_
		IN PEXCEPTION_RECORD64 Exception, IN ULONG FirstChance);
	STDMETHOD(CreateProcess)(THIS_
		IN ULONG64 ImageFileHandle,
		IN ULONG64 Handle,
		IN ULONG64 BaseOffset,
		IN ULONG ModuleSize,
		IN PCSTR ModuleName,
		IN PCSTR ImageName,
		IN ULONG CheckSum,
		IN ULONG TimeDateStamp,
		IN ULONG64 InitialThreadHandle,
		IN ULONG64 ThreadDataOffset,
		IN ULONG64 StartOffset);
	STDMETHOD(LoadModule)(THIS_
		IN ULONG64 ImageFileHandle,
		IN ULONG64 BaseOffset,
		IN ULONG ModuleSize,
		IN PCSTR ModuleName,
		IN PCSTR ImageName,
		IN ULONG CheckSum,
		IN ULONG TimeDateStamp);
	STDMETHOD(SessionStatus)(THIS_
		IN ULONG Status);
};

STDMETHODIMP_(ULONG) DbgEngPlugin::AddRef(THIS)
{
	return 1;
}

STDMETHODIMP_(ULONG) DbgEngPlugin::Release(THIS)
{
	return 0;
}

STDMETHODIMP DbgEngPlugin::GetInterestMask(THIS_
	OUT PULONG Mask)
{
	*Mask =
		DEBUG_EVENT_BREAKPOINT |
		DEBUG_EVENT_EXCEPTION |
		DEBUG_EVENT_CREATE_PROCESS |
		DEBUG_EVENT_LOAD_MODULE |
		DEBUG_EVENT_SESSION_STATUS;
	return S_OK;
}

STDMETHODIMP DbgEngPlugin::Breakpoint(THIS_
	IN PDEBUG_BREAKPOINT Bp)
{
	printf("DbgEngPlugin: Breakpoint\n");
	return S_OK;
}

STDMETHODIMP DbgEngPlugin::Exception(THIS_
	IN PEXCEPTION_RECORD64 Exception,
	IN ULONG FirstChance)
{
	printf("DbgEngPlugin: Exception\n");
	state = PDDebugState_stopException;
	return S_OK;
}

STDMETHODIMP DbgEngPlugin::CreateProcess(THIS_
	IN ULONG64 ImageFileHandle,
	IN ULONG64 Handle,
	IN ULONG64 BaseOffset,
	IN ULONG ModuleSize,
	IN PCSTR ModuleName,
	IN PCSTR ImageName,
	IN ULONG CheckSum,
	IN ULONG TimeDateStamp,
	IN ULONG64 InitialThreadHandle,
	IN ULONG64 ThreadDataOffset,
	IN ULONG64 StartOffset)
{
	printf("DbgEngPlugin: CreateProcess\n");
	return S_OK;
}

STDMETHODIMP DbgEngPlugin::LoadModule(THIS_
	IN ULONG64 ImageFileHandle,
	IN ULONG64 BaseOffset,
	IN ULONG ModuleSize,
	IN PCSTR ModuleName,
	IN PCSTR ImageName,
	IN ULONG CheckSum,
	IN ULONG TimeDateStamp)
{
	printf("DbgEngPlugin: LoadModule\n");
	return S_OK;
}

STDMETHODIMP DbgEngPlugin::SessionStatus(THIS_
	IN ULONG Status)
{
	switch (Status)
	{
		case DEBUG_SESSION_ACTIVE:
			printf("DbgEngPlugin: SessionStatus DEBUG_SESSION_ACTIVE\n");
			break;
		case DEBUG_SESSION_END_SESSION_ACTIVE_TERMINATE:
			printf("DbgEngPlugin: SessionStatus DEBUG_SESSION_END_SESSION_ACTIVE_TERMINATE\n");
			break;
		case DEBUG_SESSION_END_SESSION_ACTIVE_DETACH:
			printf("DbgEngPlugin: SessionStatus DEBUG_SESSION_END_SESSION_ACTIVE_DETACH\n");
			break;
		case DEBUG_SESSION_END_SESSION_PASSIVE:
			printf("DbgEngPlugin: SessionStatus DEBUG_SESSION_END_SESSION_PASSIVE\n");
			break;
		case DEBUG_SESSION_END:
			printf("DbgEngPlugin: SessionStatus DEBUG_SESSION_END\n");
			break;
		case DEBUG_SESSION_REBOOT:
			printf("DbgEngPlugin: SessionStatus DEBUG_SESSION_REBOOT\n");
			break;
		case DEBUG_SESSION_HIBERNATE:
			printf("DbgEngPlugin: SessionStatus DEBUG_SESSION_HIBERNATE\n");
			break;
		case DEBUG_SESSION_FAILURE:
			printf("DbgEngPlugin: SessionStatus DEBUG_SESSION_FAILURE\n");
			break;
	}

	return S_OK;
}

static void updateDbgEngEvent(DbgEngPlugin* plugin, PDWriter* writer)
{
	HRESULT hr = plugin->debugControl->WaitForEvent(DEBUG_WAIT_DEFAULT, 100);

	if (hr == S_FALSE)
	{
		// WaitForEvent timeout occurred
		return;
	}

	// TODO: check and handle execution status
}

void onRun(DbgEngPlugin* plugin)
{
	printf("DbgEngPlugin: onRun\n");

	if (plugin->state == PDDebugState_noTarget)
	{
		assert(!plugin->targetName.empty());

		HRESULT hr = plugin->debugClient->CreateProcess(0, PSTR(plugin->targetName.c_str()), DEBUG_ONLY_THIS_PROCESS);
		assert(SUCCEEDED(hr));

		if (!SUCCEEDED(hr))
		{
			printf("Error: could not create process '%s'\n", plugin->targetName.c_str());
		}
		else
		{
			printf("Valid target %s\n", plugin->targetName.c_str());
		}

		plugin->state = PDDebugState_running;
	}
}

void onStop(DbgEngPlugin* plugin)
{
	printf("DbgEngPlugin: onStop\n");
}

static void onBreak(DbgEngPlugin* plugin)
{
	printf("DbgEngPlugin: onBreak\n");
}

static void onStep(DbgEngPlugin* plugin)
{
	printf("DbgEngPlugin: onStep\n");
}

static void onStepOver(DbgEngPlugin* plugin)
{
	printf("DbgEngPlugin: onStepOver\n");
}

static void onStepOut(DbgEngPlugin* plugin)
{
	printf("DbgEngPlugin: onStepOut\n");
}

static void doAction(DbgEngPlugin* plugin, PDAction action)
{
	printf("DbgEngPlugin: doAction\n");

	switch (action)
	{
	case PDAction_stop: onStop(plugin); break;
	case PDAction_break: onBreak(plugin); break;
	case PDAction_run: onRun(plugin); break;
	case PDAction_step: onStep(plugin); break;
	case PDAction_stepOut: onStepOut(plugin); break;
	case PDAction_stepOver: onStepOver(plugin); break;
	}
}

static void setExceptionLocation(DbgEngPlugin* plugin, PDWriter* writer)
{
	printf("DbgEngPlugin: setExceptionLocation\n");
}

static void setCallstack(DbgEngPlugin* plugin, PDWriter* writer)
{
	const ULONG maxFrames = 1024;
	DEBUG_STACK_FRAME frames[maxFrames];
	ULONG frameSize = sizeof(frames[0]);
	ULONG framesFilled = 0;

	plugin->debugControl->GetStackTrace(0, 0, 0, frames, frameSize, &framesFilled);
	printf("DbgEngPlugin: setCallstack\n");

	if (framesFilled == 0)
		return;

	PDWrite_eventBegin(writer, PDEventType_setCallstack);
	PDWrite_arrayBegin(writer, "callstack");

	for (ULONG i = 0; i < framesFilled; ++i)
	{
		const DEBUG_STACK_FRAME& frame = frames[i];

		PDWrite_arrayEntryBegin(writer);
		PDWrite_u64(writer, "address", frame.InstructionOffset);
		PDWrite_arrayEntryEnd(writer);
	}

	PDWrite_arrayEnd(writer);
	PDWrite_eventEnd(writer);
}

static void setExecutable(DbgEngPlugin* plugin, PDReader* reader)
{
	printf("DbgEngPlugin: setExecutable\n");

	const char* filename = 0;

	PDRead_findString(reader, &filename, "filename", 0);

	if (!filename)
	{
		printf("Unable to find filename which is required when starting a LLDB debug session\n");
		return;
	}

	printf("found filename \"%s\"\n", filename);

	plugin->targetName = filename;
}

static void setLocals(DbgEngPlugin* plugin, PDWriter* writer)
{
	printf("DbgEngPlugin: setLocals\n");
}

static void setBreakpoint(DbgEngPlugin* plugin, PDReader* reader, PDWriter* writer)
{
	printf("DbgEngPlugin: setBreakpoint\n");
}

static void eventAction(DbgEngPlugin* plugin, PDReader* reader)
{
	printf("DbgEngPlugin: eventAction\n");

	uint32_t action = 0;

	printf("DbgEngPlugin; %d\n", (PDRead_findU32(reader, &action, "action", 0) & 0xff) >> 8);
	printf("DbgEngPlugin: got action (from event) %d\n", action);

	doAction(plugin, (PDAction)action);
}

static const char* eventTypes[] =
{
	"PDEventType_none",
	"PDEventType_getLocals",
	"PDEventType_setLocals",
	"PDEventType_getCallstack",
	"PDEventType_setCallstack",
	"PDEventType_getWatch",
	"PDEventType_setWatch",
	"PDEventType_getRegisters",
	"PDEventType_setRegisters",
	"PDEventType_getMemory",
	"PDEventType_setMemory",
	"PDEventType_getTty",
	"PDEventType_setTty",
	"PDEventType_getExceptionLocation",
	"PDEventType_setExceptionLocation",
	"PDEventType_getDisassembly",
	"PDEventType_setDisassembly",
	"PDEventType_setBreakpoint",
	"PDEventType_getBreakpoint",
	"PDEventType_setExecutable",
	"PDEventType_attachToProcess",
	"PDEventType_attachToRemoteSession",
	"PDEventType_action",
};

static void processEvents(DbgEngPlugin* plugin, PDReader* reader, PDWriter* writer)
{
	printf("DbgEngPlugin: processEvents\n");

	PDEventType event;

	while ((event = (PDEventType)PDRead_getEvent(reader)))
	{
		printf("DbgEngPlugin: %d Got event %s\n", (int)event, eventTypes[event]);

		switch (event)
		{
		case PDEventType_getExceptionLocation: setExceptionLocation(plugin, writer); break;
		case PDEventType_getCallstack: setCallstack(plugin, writer); break;
		case PDEventType_setExecutable: setExecutable(plugin, reader); break;
		case PDEventType_getLocals: setLocals(plugin, writer); break;
		case PDEventType_setBreakpoint: setBreakpoint(plugin, reader, writer); break;
		case PDEventType_action: eventAction(plugin, reader); break;
		}
	}
}

void* createInstance(ServiceFunc* serviceFunc)
{
	DbgEngPlugin* plugin = new DbgEngPlugin;

	HRESULT hr = DebugCreate(__uuidof(IDebugClient), (void**)&plugin->debugClient);
	assert(SUCCEEDED(hr));

	hr = plugin->debugClient->SetEventCallbacks(plugin);
	assert(SUCCEEDED(hr));

	hr = plugin->debugClient->QueryInterface(__uuidof(IDebugControl), (void**)&plugin->debugControl);
	assert(SUCCEEDED(hr));

	return plugin;
}

void destroyInstance(void* userData)
{
	DbgEngPlugin* plugin = reinterpret_cast<DbgEngPlugin*>(userData);

	if (plugin->debugControl)
	{
		plugin->debugControl->Release();
		plugin->debugControl = nullptr;
	}

	if (plugin->debugClient)
	{
		plugin->debugClient->Release();
		plugin->debugClient = nullptr;
	}

	delete plugin;
}

static PDDebugState update(void* userData, PDAction action, PDReader* reader, PDWriter* writer)
{
	DbgEngPlugin* plugin = reinterpret_cast<DbgEngPlugin*>(userData);

	processEvents(plugin, reader, writer);

	doAction(plugin, action);

	if (plugin->state == PDDebugState_running)
	{
		updateDbgEngEvent(plugin, writer);
	}

	return plugin->state;
}

static PDBackendPlugin plugin =
{
	"Microsoft Debugger Engine",
	createInstance,
	destroyInstance,
	update,
};

extern "C" PD_EXPORT void InitPlugin(RegisterPlugin* registerPlugin, void* privateData)
{
	registerPlugin(PD_BACKEND_API_VERSION, &plugin, privateData);
}

#endif
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "settingspage.h"
#include "locatorconstants.h"

#include "locatorplugin.h"
#include "ilocatorfilter.h"
#include "directoryfilter.h"

#include <coreplugin/coreconstants.h>
#include <utils/QtConcurrentTools>
#include <utils/qtcassert.h>

#include <QCoreApplication>

Q_DECLARE_METATYPE(Locator::ILocatorFilter*)

using namespace Locator;
using namespace Locator::Internal;

SettingsPage::SettingsPage(LocatorPlugin *plugin)
    : m_plugin(plugin), m_page(0)
{
    setId(Constants::FILTER_OPTIONS_PAGE);
    setDisplayName(QCoreApplication::translate("Locator", Locator::Constants::FILTER_OPTIONS_PAGE));
    setCategory(Core::Constants::SETTINGS_CATEGORY_CORE);
    setDisplayCategory(QCoreApplication::translate("Core", Core::Constants::SETTINGS_TR_CATEGORY_CORE));
    setCategoryIcon(QLatin1String(Core::Constants::SETTINGS_CATEGORY_CORE_ICON));
}

QWidget *SettingsPage::createPage(QWidget *parent)
{

    m_page = new QWidget(parent);
    m_ui.setupUi(m_page);
    connect(m_ui.filterList, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
            this, SLOT(updateButtonStates()));
    connect(m_ui.filterList, SIGNAL(itemActivated(QListWidgetItem*)),
            this, SLOT(configureFilter(QListWidgetItem*)));
    connect(m_ui.editButton, SIGNAL(clicked()),
            this, SLOT(configureFilter()));
    connect(m_ui.addButton, SIGNAL(clicked()),
            this, SLOT(addCustomFilter()));
    connect(m_ui.removeButton, SIGNAL(clicked()),
            this, SLOT(removeCustomFilter()));

    m_ui.refreshInterval->setValue(m_plugin->refreshInterval());
    m_filters = m_plugin->filters();
    m_customFilters = m_plugin->customFilters();
    saveFilterStates();
    updateFilterList();
    if (m_searchKeywords.isEmpty()) {
        m_searchKeywords = m_ui.refreshIntervalLabel->text();
        m_searchKeywords.remove(QLatin1Char('&'));
    }
    return m_page;
}

void SettingsPage::apply()
{
    // Delete removed filters and clear added filters
    qDeleteAll(m_removedFilters);
    m_removedFilters.clear();
    m_addedFilters.clear();

    // Pass the new configuration on to the plugin
    m_plugin->setFilters(m_filters);
    m_plugin->setCustomFilters(m_customFilters);
    m_plugin->setRefreshInterval(m_ui.refreshInterval->value());
    requestRefresh();
    m_plugin->saveSettings();
    saveFilterStates();
}

void SettingsPage::finish()
{
    // If settings were applied, this shouldn't change anything. Otherwise it
    // makes sure the filter states aren't changed permanently.
    restoreFilterStates();

    // Delete added filters and clear removed filters
    qDeleteAll(m_addedFilters);
    m_addedFilters.clear();
    m_removedFilters.clear();

    // Further cleanup
    m_filters.clear();
    m_customFilters.clear();
    m_refreshFilters.clear();
}

void SettingsPage::requestRefresh()
{
    if (!m_refreshFilters.isEmpty())
        m_plugin->refresh(m_refreshFilters);
}

void SettingsPage::saveFilterStates()
{
    m_filterStates.clear();
    foreach (ILocatorFilter *filter, m_filters)
        m_filterStates.insert(filter, filter->saveState());
}

void SettingsPage::restoreFilterStates()
{
    foreach (ILocatorFilter *filter, m_filterStates.keys())
        filter->restoreState(m_filterStates.value(filter));
}

void SettingsPage::updateFilterList()
{
    m_ui.filterList->clear();
    foreach (ILocatorFilter *filter, m_filters) {
        if (filter->isHidden())
            continue;

        QString title;
        if (filter->isIncludedByDefault())
            title = filter->displayName();
        else
            title = tr("%1 (prefix: %2)").arg(filter->displayName()).arg(filter->shortcutString());
        QListWidgetItem *item = new QListWidgetItem(title);
        item->setData(Qt::UserRole, qVariantFromValue(filter));
        m_ui.filterList->addItem(item);
    }
    if (m_ui.filterList->count() > 0)
        m_ui.filterList->setCurrentRow(0);
}

void SettingsPage::updateButtonStates()
{
    QListWidgetItem *item = m_ui.filterList->currentItem();
    ILocatorFilter *filter = (item ? item->data(Qt::UserRole).value<ILocatorFilter *>() : 0);
    m_ui.editButton->setEnabled(filter && filter->isConfigurable());
    m_ui.removeButton->setEnabled(filter && m_customFilters.contains(filter));
}

void SettingsPage::configureFilter(QListWidgetItem *item)
{
    if (!item)
        item = m_ui.filterList->currentItem();
    QTC_ASSERT(item, return);
    ILocatorFilter *filter = item->data(Qt::UserRole).value<ILocatorFilter *>();
    QTC_ASSERT(filter, return);

    if (!filter->isConfigurable())
        return;
    bool needsRefresh = false;
    filter->openConfigDialog(m_page, needsRefresh);
    if (needsRefresh && !m_refreshFilters.contains(filter))
        m_refreshFilters.append(filter);
    updateFilterList();
}

void SettingsPage::addCustomFilter()
{
    ILocatorFilter *filter = new DirectoryFilter;
    bool needsRefresh = false;
    if (filter->openConfigDialog(m_page, needsRefresh)) {
        m_filters.append(filter);
        m_addedFilters.append(filter);
        m_customFilters.append(filter);
        m_refreshFilters.append(filter);
        updateFilterList();
    }
}

void SettingsPage::removeCustomFilter()
{
    QListWidgetItem *item = m_ui.filterList->currentItem();
    QTC_ASSERT(item, return);
    ILocatorFilter *filter = item->data(Qt::UserRole).value<ILocatorFilter *>();
    QTC_ASSERT(m_customFilters.contains(filter), return);
    m_filters.removeAll(filter);
    m_customFilters.removeAll(filter);
    m_refreshFilters.removeAll(filter);
    if (m_addedFilters.contains(filter)) {
        m_addedFilters.removeAll(filter);
        delete filter;
    } else {
        m_removedFilters.append(filter);
    }
    updateFilterList();
}

bool SettingsPage::matches(const QString &s) const
{
    return m_searchKeywords.contains(s, Qt::CaseInsensitive);
}
<commit_msg>Locator settings: replicate tool tip also on spinbox<commit_after>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "settingspage.h"
#include "locatorconstants.h"

#include "locatorplugin.h"
#include "ilocatorfilter.h"
#include "directoryfilter.h"

#include <coreplugin/coreconstants.h>
#include <utils/QtConcurrentTools>
#include <utils/qtcassert.h>

#include <QCoreApplication>

Q_DECLARE_METATYPE(Locator::ILocatorFilter*)

using namespace Locator;
using namespace Locator::Internal;

SettingsPage::SettingsPage(LocatorPlugin *plugin)
    : m_plugin(plugin), m_page(0)
{
    setId(Constants::FILTER_OPTIONS_PAGE);
    setDisplayName(QCoreApplication::translate("Locator", Locator::Constants::FILTER_OPTIONS_PAGE));
    setCategory(Core::Constants::SETTINGS_CATEGORY_CORE);
    setDisplayCategory(QCoreApplication::translate("Core", Core::Constants::SETTINGS_TR_CATEGORY_CORE));
    setCategoryIcon(QLatin1String(Core::Constants::SETTINGS_CATEGORY_CORE_ICON));
}

QWidget *SettingsPage::createPage(QWidget *parent)
{

    m_page = new QWidget(parent);
    m_ui.setupUi(m_page);
    m_ui.refreshInterval->setToolTip(m_ui.refreshIntervalLabel->toolTip());
    connect(m_ui.filterList, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)),
            this, SLOT(updateButtonStates()));
    connect(m_ui.filterList, SIGNAL(itemActivated(QListWidgetItem*)),
            this, SLOT(configureFilter(QListWidgetItem*)));
    connect(m_ui.editButton, SIGNAL(clicked()),
            this, SLOT(configureFilter()));
    connect(m_ui.addButton, SIGNAL(clicked()),
            this, SLOT(addCustomFilter()));
    connect(m_ui.removeButton, SIGNAL(clicked()),
            this, SLOT(removeCustomFilter()));

    m_ui.refreshInterval->setValue(m_plugin->refreshInterval());
    m_filters = m_plugin->filters();
    m_customFilters = m_plugin->customFilters();
    saveFilterStates();
    updateFilterList();
    if (m_searchKeywords.isEmpty()) {
        m_searchKeywords = m_ui.refreshIntervalLabel->text();
        m_searchKeywords.remove(QLatin1Char('&'));
    }
    return m_page;
}

void SettingsPage::apply()
{
    // Delete removed filters and clear added filters
    qDeleteAll(m_removedFilters);
    m_removedFilters.clear();
    m_addedFilters.clear();

    // Pass the new configuration on to the plugin
    m_plugin->setFilters(m_filters);
    m_plugin->setCustomFilters(m_customFilters);
    m_plugin->setRefreshInterval(m_ui.refreshInterval->value());
    requestRefresh();
    m_plugin->saveSettings();
    saveFilterStates();
}

void SettingsPage::finish()
{
    // If settings were applied, this shouldn't change anything. Otherwise it
    // makes sure the filter states aren't changed permanently.
    restoreFilterStates();

    // Delete added filters and clear removed filters
    qDeleteAll(m_addedFilters);
    m_addedFilters.clear();
    m_removedFilters.clear();

    // Further cleanup
    m_filters.clear();
    m_customFilters.clear();
    m_refreshFilters.clear();
}

void SettingsPage::requestRefresh()
{
    if (!m_refreshFilters.isEmpty())
        m_plugin->refresh(m_refreshFilters);
}

void SettingsPage::saveFilterStates()
{
    m_filterStates.clear();
    foreach (ILocatorFilter *filter, m_filters)
        m_filterStates.insert(filter, filter->saveState());
}

void SettingsPage::restoreFilterStates()
{
    foreach (ILocatorFilter *filter, m_filterStates.keys())
        filter->restoreState(m_filterStates.value(filter));
}

void SettingsPage::updateFilterList()
{
    m_ui.filterList->clear();
    foreach (ILocatorFilter *filter, m_filters) {
        if (filter->isHidden())
            continue;

        QString title;
        if (filter->isIncludedByDefault())
            title = filter->displayName();
        else
            title = tr("%1 (prefix: %2)").arg(filter->displayName()).arg(filter->shortcutString());
        QListWidgetItem *item = new QListWidgetItem(title);
        item->setData(Qt::UserRole, qVariantFromValue(filter));
        m_ui.filterList->addItem(item);
    }
    if (m_ui.filterList->count() > 0)
        m_ui.filterList->setCurrentRow(0);
}

void SettingsPage::updateButtonStates()
{
    QListWidgetItem *item = m_ui.filterList->currentItem();
    ILocatorFilter *filter = (item ? item->data(Qt::UserRole).value<ILocatorFilter *>() : 0);
    m_ui.editButton->setEnabled(filter && filter->isConfigurable());
    m_ui.removeButton->setEnabled(filter && m_customFilters.contains(filter));
}

void SettingsPage::configureFilter(QListWidgetItem *item)
{
    if (!item)
        item = m_ui.filterList->currentItem();
    QTC_ASSERT(item, return);
    ILocatorFilter *filter = item->data(Qt::UserRole).value<ILocatorFilter *>();
    QTC_ASSERT(filter, return);

    if (!filter->isConfigurable())
        return;
    bool needsRefresh = false;
    filter->openConfigDialog(m_page, needsRefresh);
    if (needsRefresh && !m_refreshFilters.contains(filter))
        m_refreshFilters.append(filter);
    updateFilterList();
}

void SettingsPage::addCustomFilter()
{
    ILocatorFilter *filter = new DirectoryFilter;
    bool needsRefresh = false;
    if (filter->openConfigDialog(m_page, needsRefresh)) {
        m_filters.append(filter);
        m_addedFilters.append(filter);
        m_customFilters.append(filter);
        m_refreshFilters.append(filter);
        updateFilterList();
    }
}

void SettingsPage::removeCustomFilter()
{
    QListWidgetItem *item = m_ui.filterList->currentItem();
    QTC_ASSERT(item, return);
    ILocatorFilter *filter = item->data(Qt::UserRole).value<ILocatorFilter *>();
    QTC_ASSERT(m_customFilters.contains(filter), return);
    m_filters.removeAll(filter);
    m_customFilters.removeAll(filter);
    m_refreshFilters.removeAll(filter);
    if (m_addedFilters.contains(filter)) {
        m_addedFilters.removeAll(filter);
        delete filter;
    } else {
        m_removedFilters.append(filter);
    }
    updateFilterList();
}

bool SettingsPage::matches(const QString &s) const
{
    return m_searchKeywords.contains(s, Qt::CaseInsensitive);
}
<|endoftext|>


<commit_before>/** \file    SysLog.h
 *  \brief   Declaration of class SysLog.
 *  \author  Dr. Johannes Ruscheinski
 */

/*
 *  Copyright 2020 University Library of Tübingen
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include "SysLog.h"

SysLog::SysLog(const std::string &message_prefix, const int option, const int facility) {
    ::openlog(message_prefix.c_str(), option, facility);
    ::setlogmask(LOG_EMERG | LOG_ALERT | LOG_CRIT | LOG_ERR | LOG_WARNING | LOG_NOTICE | LOG_INFO);
}

SysLog::~SysLog() {
    ::closelog();
}

void SysLog::log(const LogLevel level, const std::string &message) {
    ::syslog(level, "%s", message.c_str());
}
<commit_msg>Use progran name as default log entry prefix.<commit_after>/** \file    SysLog.h
 *  \brief   Declaration of class SysLog.
 *  \author  Dr. Johannes Ruscheinski
 */

/*
 *  Copyright 2020 University Library of Tübingen
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include "SysLog.h"

SysLog::SysLog(const std::string &message_prefix, const int option, const int facility) {
    ::openlog(message_prefix.empty() ? nullptr : message_prefix.c_str(), option, facility);
    ::setlogmask(LOG_EMERG | LOG_ALERT | LOG_CRIT | LOG_ERR | LOG_WARNING | LOG_NOTICE | LOG_INFO);
}

SysLog::~SysLog() {
    ::closelog();
}

void SysLog::log(const LogLevel level, const std::string &message) {
    ::syslog(level, "%s", message.c_str());
}
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include <com/sun/star/text/TableColumnSeparator.hpp>
#include "TagLogger.hxx"
#include "PropertyMapHelper.hxx"

namespace writerfilter
{
namespace dmapper
{

using namespace ::com::sun::star;

void lcl_DumpTableColumnSeparators(const TagLogger::Pointer_t& pLogger, const uno::Any & rTableColumnSeparators)
{
    (void) pLogger;
    (void) rTableColumnSeparators;
#ifdef DEBUG_WRITERFILTER
    uno::Sequence<text::TableColumnSeparator> aSeq;
    rTableColumnSeparators >>= aSeq;

    pLogger->startElement("property.TableColumnSeparators");

    sal_uInt32 nLength = aSeq.getLength();
    for (sal_uInt32 n = 0; n < nLength; ++n)
    {
        pLogger->startElement("separator");

        pLogger->attribute("position", aSeq[n].Position);
        pLogger->attribute("visible", aSeq[n].IsVisible);

        pLogger->endElement();
    }

    pLogger->endElement();
#endif // DEBUG_WRITERFILTER
}

#ifdef DEBUG_WRITERFILTER
void lcl_DumpPropertyValues(const TagLogger::Pointer_t pLogger, beans::PropertyValues & rValues)
{
    pLogger->startElement("propertyValues");

    beans::PropertyValue * pValues = rValues.getArray();

    for (sal_Int32 n = 0; n < rValues.getLength(); ++n)
    {
        pLogger->startElement("propertyValue");

        pLogger->attribute("name", pValues[n].Name);

        try
        {
            sal_Int32 aInt = 0;
            pValues[n].Value >>= aInt;
            pLogger->attribute("value", aInt);
        }
        catch (...)
        {
        }

        if ( pValues[n].Name == "TableColumnSeparators" )
        {
            lcl_DumpTableColumnSeparators(pLogger, pValues[n].Value);
        }

        pLogger->endElement();
    }
    pLogger->endElement();
}

void lcl_DumpPropertyValueSeq(const TagLogger::Pointer_t pLogger, PropertyValueSeq_t & rPropValSeq)
{
    pLogger->startElement("PropertyValueSeq");

    beans::PropertyValues * pValues = rPropValSeq.getArray();

    for (sal_Int32 n = 0; n < rPropValSeq.getLength(); ++n)
    {
        lcl_DumpPropertyValues(pLogger, pValues[n]);
    }

    pLogger->endElement();
}
#endif // DEBUG_WRITERFILTER

}
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>Booleans are logged via sal_uInt32 here<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include <com/sun/star/text/TableColumnSeparator.hpp>
#include "TagLogger.hxx"
#include "PropertyMapHelper.hxx"

namespace writerfilter
{
namespace dmapper
{

using namespace ::com::sun::star;

void lcl_DumpTableColumnSeparators(const TagLogger::Pointer_t& pLogger, const uno::Any & rTableColumnSeparators)
{
    (void) pLogger;
    (void) rTableColumnSeparators;
#ifdef DEBUG_WRITERFILTER
    uno::Sequence<text::TableColumnSeparator> aSeq;
    rTableColumnSeparators >>= aSeq;

    pLogger->startElement("property.TableColumnSeparators");

    sal_uInt32 nLength = aSeq.getLength();
    for (sal_uInt32 n = 0; n < nLength; ++n)
    {
        pLogger->startElement("separator");

        pLogger->attribute("position", aSeq[n].Position);
        pLogger->attribute("visible", sal_uInt32(aSeq[n].IsVisible));

        pLogger->endElement();
    }

    pLogger->endElement();
#endif // DEBUG_WRITERFILTER
}

#ifdef DEBUG_WRITERFILTER
void lcl_DumpPropertyValues(const TagLogger::Pointer_t pLogger, beans::PropertyValues & rValues)
{
    pLogger->startElement("propertyValues");

    beans::PropertyValue * pValues = rValues.getArray();

    for (sal_Int32 n = 0; n < rValues.getLength(); ++n)
    {
        pLogger->startElement("propertyValue");

        pLogger->attribute("name", pValues[n].Name);

        try
        {
            sal_Int32 aInt = 0;
            pValues[n].Value >>= aInt;
            pLogger->attribute("value", aInt);
        }
        catch (...)
        {
        }

        if ( pValues[n].Name == "TableColumnSeparators" )
        {
            lcl_DumpTableColumnSeparators(pLogger, pValues[n].Value);
        }

        pLogger->endElement();
    }
    pLogger->endElement();
}

void lcl_DumpPropertyValueSeq(const TagLogger::Pointer_t pLogger, PropertyValueSeq_t & rPropValSeq)
{
    pLogger->startElement("PropertyValueSeq");

    beans::PropertyValues * pValues = rPropValSeq.getArray();

    for (sal_Int32 n = 0; n < rPropValSeq.getLength(); ++n)
    {
        lcl_DumpPropertyValues(pLogger, pValues[n]);
    }

    pLogger->endElement();
}
#endif // DEBUG_WRITERFILTER

}
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>// ROS
#include <ros/ros.h>
#include <tf/transform_listener.h>
#include <tf_conversions/tf_eigen.h>
#include <XmlRpcValue.h>

// for debugging
#include <iostream>

// stl
#include <vector>
#include <set>

// MoveIt!
#include <moveit/collision_detection/collision_robot.h>
#include <moveit/robot_model_loader/robot_model_loader.h>
#include <moveit/robot_state/robot_state.h>
#include <moveit/planning_scene/planning_scene.h>

// joint states
#include <sensor_msgs/JointState.h>

// predicator
#include <predicator_msgs/PredicateList.h>
#include <predicator_msgs/PredicateStatement.h>

// boost includes
#include <boost/bind/bind.hpp>

using planning_scene::PlanningScene;
using robot_model_loader::RobotModelLoader;
using robot_model::RobotModelPtr;
using robot_state::RobotState;
using collision_detection::CollisionRobot;

std::vector<RobotModelPtr> robots;
std::vector<RobotState *> states;
std::vector<PlanningScene *> scenes;
std::vector<ros::Subscriber> subs;

/**
 * joint_state_callback()
 * Update the robot state variable values
 */
void joint_state_callback(const sensor_msgs::JointState::ConstPtr &msg, RobotState *state) {
  state->setVariableValues(*msg);
}

/**
 * cleanup()
 * Delete memory allocated for robot states and subscribers
 */
void cleanup() {
  for (typename std::vector<RobotState *>::iterator it = states.begin();
       it != states.end();
       ++it)
  {
    delete *it;
  }

  for (typename std::vector<PlanningScene *>::iterator it = scenes.begin();
       it != scenes.end();
       ++it)
  {
    delete *it;
  }
}

int main(int argc, char **argv) {

  double padding; // how much padding do we give robot links?
  int verbosity; // how much should get printed for debugging purposes
  std::map<std::string, std::string> floating_frames;
  std::string world_frame;

  ros::init(argc, argv, "predicator_robot_interaction_node");

  ros::NodeHandle nh;
  ros::NodeHandle nh_tilde("~");

  XmlRpc::XmlRpcValue descriptions;
  XmlRpc::XmlRpcValue topics;
  XmlRpc::XmlRpcValue floating; // set of floating root joints that need to be updated

  nh_tilde.param("verbosity", verbosity, 0);
  nh_tilde.param("padding", padding, 0.01);
  nh_tilde.param("world_frame", world_frame, std::string("/world"));

  ros::Publisher pub = nh.advertise<predicator_msgs::PredicateList>("/predicator/input", 1000);
  tf::TransformListener listener;

  if(nh_tilde.hasParam("description_list")) {
    nh_tilde.param("description_list", descriptions, descriptions);
  } else {
    ROS_ERROR("No list of robot description parameters!");
    exit(-1);
  }

  if(nh_tilde.hasParam("joint_state_topic_list")) {
    nh_tilde.param("joint_state_topic_list", topics, topics);
  } else {
    ROS_ERROR("No list of joint state topics!");
    exit(-1);
  }

  if(nh_tilde.hasParam("floating_root_list")) {
    nh_tilde.param("floating_root_list", floating, floating);
  } else {
    ROS_INFO("No list of robots with floating root joints given.");
  }

  if(descriptions.size() != topics.size()) {
    ROS_WARN("An unequal number of joint state and robot topics was provided!");
  }

  // read in topics and descriptions
  for(unsigned int i = 0; i < descriptions.size(); ++i) {
    std::string desc;
    std::string topic;

    if(descriptions[i].getType() == XmlRpc::XmlRpcValue::TypeString) {
      desc = static_cast<std::string>(descriptions[i]);
      if(verbosity > 0) {
        std::cout << "Robot Description parameter name: " << desc << std::endl;
      }
    } else {
      ROS_WARN("Description %u was not of type \"string\"!", i);
      continue;
    }

    // create a robot model with state desc
    robot_model_loader::RobotModelLoader robot_model_loader(desc);
    robot_model::RobotModelPtr model = robot_model_loader.getModel();
    PlanningScene *scene = new PlanningScene(model);
    scene->getCollisionRobotNonConst()->setPadding(padding);
    scene->propogateRobotPadding();

    robots.push_back(model);
    scenes.push_back(scene);

    RobotState *state = new RobotState(model);
    states.push_back(state);

    if(i < topics.size() && topics[i].getType() == XmlRpc::XmlRpcValue::TypeString) {
      topic = static_cast<std::string>(topics[i]);
      if(verbosity > 0) {
        std::cout << "JointState topic name: " << topic << std::endl;
      }

      // create the subscriber
      subs.push_back(nh.subscribe<sensor_msgs::JointState>
                     (topic, 1000,
                      boost::bind(joint_state_callback, _1, state)));
    } else if (verbosity > 0) {
      ROS_WARN("no topic corresponding to description %s!", desc.c_str());
    }
  }

  // read in root TF frames
  for(unsigned int i = 0; i < floating.size(); ++i) {
    std::string id = floating[i]["id"];
    std::string frame = floating[i]["frame"];

    floating_frames[id] = frame;
  }

  // define spin rate
  ros::Rate rate(30);

  // print out information on all the different joints
  if(verbosity > 0) {
    unsigned int i = 0;
    for(typename std::vector<PlanningScene *>::iterator it1 = scenes.begin();
        it1 != scenes.end();
        ++it1, ++i)
    {
      collision_detection::CollisionRobotConstPtr robot1 = (*it1)->getCollisionRobot();
      // -----------------------------------------------------------
      std::cout << std::endl;
      std::cout << "PRINTING STATE INFO:";
      std::cout << robot1->getRobotModel()->getName() << std::endl;
      std::cout << robots[i]->getRootJointName() << std::endl;
      states[i]->update(true);
      states[i]->printStateInfo(std::cout);
      // -----------------------------------------------------------
    }
  }

  // start main loop
  while(ros::ok()) {
    ros::spinOnce();

    predicator_msgs::PredicateList output;
    output.header.frame_id = ros::this_node::getName();

    unsigned int i = 0;

    // make sure base frames are up to date
    // some objects, such as free-floating robots (aka the ring) need to be updated by TF
    // not sure why this doesn't work naturally
    for(typename std::vector<PlanningScene *>::iterator it1 = scenes.begin();
        it1 != scenes.end();
        ++it1, ++i)
    {

      collision_detection::CollisionRobotConstPtr robot1 = (*it1)->getCollisionRobot();
      std::string name = robot1->getRobotModel()->getName();

      if(floating_frames.find(name) != floating_frames.end()) {
        std::string base_frame = floating_frames[name];

        tf::StampedTransform transform;
        Eigen::Affine3d t;

        try{
          listener.lookupTransform(world_frame, base_frame,
                                   ros::Time(0), transform);
          tf::transformTFToEigen(transform,t);
          states[i]->setJointPositions(robot1->getRobotModel()->getRootJointName(), t);
        }
        catch (tf::TransformException ex){
          ROS_ERROR("%s",ex.what());
        }

        if(verbosity > 1) {
          std::cout << "----------------------------" << std::endl;
          std::cout << "PRINTING STATE INFO:";
          std::cout << robot1->getRobotModel()->getName() << std::endl;
          std::cout << robots[i]->getRootJointName() << std::endl;
          states[i]->update(true);
          states[i]->printStateInfo(std::cout);
        }

      } else {
        continue;
      }
    }

    // main collision checking loop
    // checks for all pairs of objects, determines collisions and distances
    // publishes the relationships between all of these objects
    i = 0;
    for(typename std::vector<PlanningScene *>::iterator it1 = scenes.begin();
        it1 != scenes.end();
        ++it1, ++i)
    {

      collision_detection::CollisionRobotConstPtr robot1 = (*it1)->getCollisionRobot();

      typename std::vector<PlanningScene *>::iterator it2 = it1;
      unsigned int j = i+1;
      for(++it2; it2 != scenes.end(); ++it2, ++j) {

        collision_detection::CollisionRobotConstPtr robot2 = (*it2)->getCollisionRobot();

        collision_detection::CollisionRequest req;
        collision_detection::CollisionResult res;
        req.contacts = true;
        req.max_contacts = 1000;

        // force an update
        // source: https://groups.google.com/forum/#!topic/moveit-users/O9CEef6sxbE
        states[i]->update(true);
        states[j]->update(true);
        robot1->checkOtherCollision(req, res, *states[i], *robot2, *states[j]);
        double dist = robot1->distanceOther(*states[i], *robot2, *states[j]);

        predicator_msgs::PredicateStatement ps_dist;
        ps_dist.predicate = "distance";
        ps_dist.value = dist;
        ps_dist.num_params = 2;
        ps_dist.params[0] = robot1->getRobotModel()->getName();
        ps_dist.params[1] = robot2->getRobotModel()->getName();

        output.statements.push_back(ps_dist);

        // iterate over all collisions
        for(collision_detection::CollisionResult::ContactMap::const_iterator cit = res.contacts.begin();
            cit != res.contacts.end();
            ++cit)
        {
          predicator_msgs::PredicateStatement ps;
          ps.predicate = "touching";
          ps.value = 1.0;
          ps.num_params = 2;
          ps.params[0] = cit->first.first;
          ps.params[1] = cit->first.second;
          output.statements.push_back(ps);
        }

        if (verbosity > 1) {
          std::cout << "(" << robot1->getRobotModel()->getName()
            << ", " << robot2->getRobotModel()->getName()
            << ": Distance to collision: " << dist << std::endl;
        }
      }
    }

    pub.publish(output);

    rate.sleep();
  }

  cleanup();
}
<commit_msg>print both the forward and inverse of predicates; aka, flip the parameters around so that we have both touching(x, y) and touching(y, x)<commit_after>// ROS
#include <ros/ros.h>
#include <tf/transform_listener.h>
#include <tf_conversions/tf_eigen.h>
#include <XmlRpcValue.h>

// for debugging
#include <iostream>

// stl
#include <vector>
#include <set>

// MoveIt!
#include <moveit/collision_detection/collision_robot.h>
#include <moveit/robot_model_loader/robot_model_loader.h>
#include <moveit/robot_state/robot_state.h>
#include <moveit/planning_scene/planning_scene.h>

// joint states
#include <sensor_msgs/JointState.h>

// predicator
#include <predicator_msgs/PredicateList.h>
#include <predicator_msgs/PredicateStatement.h>

// boost includes
#include <boost/bind/bind.hpp>

using planning_scene::PlanningScene;
using robot_model_loader::RobotModelLoader;
using robot_model::RobotModelPtr;
using robot_state::RobotState;
using collision_detection::CollisionRobot;

std::vector<RobotModelPtr> robots;
std::vector<RobotState *> states;
std::vector<PlanningScene *> scenes;
std::vector<ros::Subscriber> subs;

/**
 * joint_state_callback()
 * Update the robot state variable values
 */
void joint_state_callback(const sensor_msgs::JointState::ConstPtr &msg, RobotState *state) {
  state->setVariableValues(*msg);
}

/**
 * cleanup()
 * Delete memory allocated for robot states and subscribers
 */
void cleanup() {
  for (typename std::vector<RobotState *>::iterator it = states.begin();
       it != states.end();
       ++it)
  {
    delete *it;
  }

  for (typename std::vector<PlanningScene *>::iterator it = scenes.begin();
       it != scenes.end();
       ++it)
  {
    delete *it;
  }
}

int main(int argc, char **argv) {

  double padding; // how much padding do we give robot links?
  int verbosity; // how much should get printed for debugging purposes
  std::map<std::string, std::string> floating_frames;
  std::string world_frame;

  ros::init(argc, argv, "predicator_robot_interaction_node");

  ros::NodeHandle nh;
  ros::NodeHandle nh_tilde("~");

  XmlRpc::XmlRpcValue descriptions;
  XmlRpc::XmlRpcValue topics;
  XmlRpc::XmlRpcValue floating; // set of floating root joints that need to be updated

  nh_tilde.param("verbosity", verbosity, 0);
  nh_tilde.param("padding", padding, 0.01);
  nh_tilde.param("world_frame", world_frame, std::string("/world"));

  ros::Publisher pub = nh.advertise<predicator_msgs::PredicateList>("/predicator/input", 1000);
  tf::TransformListener listener;

  if(nh_tilde.hasParam("description_list")) {
    nh_tilde.param("description_list", descriptions, descriptions);
  } else {
    ROS_ERROR("No list of robot description parameters!");
    exit(-1);
  }

  if(nh_tilde.hasParam("joint_state_topic_list")) {
    nh_tilde.param("joint_state_topic_list", topics, topics);
  } else {
    ROS_ERROR("No list of joint state topics!");
    exit(-1);
  }

  if(nh_tilde.hasParam("floating_root_list")) {
    nh_tilde.param("floating_root_list", floating, floating);
  } else {
    ROS_INFO("No list of robots with floating root joints given.");
  }

  if(descriptions.size() != topics.size()) {
    ROS_WARN("An unequal number of joint state and robot topics was provided!");
  }

  // read in topics and descriptions
  for(unsigned int i = 0; i < descriptions.size(); ++i) {
    std::string desc;
    std::string topic;

    if(descriptions[i].getType() == XmlRpc::XmlRpcValue::TypeString) {
      desc = static_cast<std::string>(descriptions[i]);
      if(verbosity > 0) {
        std::cout << "Robot Description parameter name: " << desc << std::endl;
      }
    } else {
      ROS_WARN("Description %u was not of type \"string\"!", i);
      continue;
    }

    // create a robot model with state desc
    robot_model_loader::RobotModelLoader robot_model_loader(desc);
    robot_model::RobotModelPtr model = robot_model_loader.getModel();
    PlanningScene *scene = new PlanningScene(model);
    scene->getCollisionRobotNonConst()->setPadding(padding);
    scene->propogateRobotPadding();

    robots.push_back(model);
    scenes.push_back(scene);

    RobotState *state = new RobotState(model);
    states.push_back(state);

    if(i < topics.size() && topics[i].getType() == XmlRpc::XmlRpcValue::TypeString) {
      topic = static_cast<std::string>(topics[i]);
      if(verbosity > 0) {
        std::cout << "JointState topic name: " << topic << std::endl;
      }

      // create the subscriber
      subs.push_back(nh.subscribe<sensor_msgs::JointState>
                     (topic, 1000,
                      boost::bind(joint_state_callback, _1, state)));
    } else if (verbosity > 0) {
      ROS_WARN("no topic corresponding to description %s!", desc.c_str());
    }
  }

  // read in root TF frames
  for(unsigned int i = 0; i < floating.size(); ++i) {
    std::string id = floating[i]["id"];
    std::string frame = floating[i]["frame"];

    floating_frames[id] = frame;
  }

  // define spin rate
  ros::Rate rate(30);

  // print out information on all the different joints
  if(verbosity > 0) {
    unsigned int i = 0;
    for(typename std::vector<PlanningScene *>::iterator it1 = scenes.begin();
        it1 != scenes.end();
        ++it1, ++i)
    {
      collision_detection::CollisionRobotConstPtr robot1 = (*it1)->getCollisionRobot();
      // -----------------------------------------------------------
      std::cout << std::endl;
      std::cout << "PRINTING STATE INFO:";
      std::cout << robot1->getRobotModel()->getName() << std::endl;
      std::cout << robots[i]->getRootJointName() << std::endl;
      states[i]->update(true);
      states[i]->printStateInfo(std::cout);
      // -----------------------------------------------------------
    }
  }

  // start main loop
  while(ros::ok()) {
    ros::spinOnce();

    predicator_msgs::PredicateList output;
    output.header.frame_id = ros::this_node::getName();

    unsigned int i = 0;

    // make sure base frames are up to date
    // some objects, such as free-floating robots (aka the ring) need to be updated by TF
    // not sure why this doesn't work naturally
    for(typename std::vector<PlanningScene *>::iterator it1 = scenes.begin();
        it1 != scenes.end();
        ++it1, ++i)
    {

      collision_detection::CollisionRobotConstPtr robot1 = (*it1)->getCollisionRobot();
      std::string name = robot1->getRobotModel()->getName();

      if(floating_frames.find(name) != floating_frames.end()) {
        std::string base_frame = floating_frames[name];

        tf::StampedTransform transform;
        Eigen::Affine3d t;

        try{
          listener.lookupTransform(world_frame, base_frame,
                                   ros::Time(0), transform);
          tf::transformTFToEigen(transform,t);
          states[i]->setJointPositions(robot1->getRobotModel()->getRootJointName(), t);
        }
        catch (tf::TransformException ex){
          ROS_ERROR("%s",ex.what());
        }

        if(verbosity > 1) {
          std::cout << "----------------------------" << std::endl;
          std::cout << "PRINTING STATE INFO:";
          std::cout << robot1->getRobotModel()->getName() << std::endl;
          std::cout << robots[i]->getRootJointName() << std::endl;
          states[i]->update(true);
          states[i]->printStateInfo(std::cout);
        }

      } else {
        continue;
      }
    }

    // main collision checking loop
    // checks for all pairs of objects, determines collisions and distances
    // publishes the relationships between all of these objects
    i = 0;
    for(typename std::vector<PlanningScene *>::iterator it1 = scenes.begin();
        it1 != scenes.end();
        ++it1, ++i)
    {

      collision_detection::CollisionRobotConstPtr robot1 = (*it1)->getCollisionRobot();

      typename std::vector<PlanningScene *>::iterator it2 = it1;
      unsigned int j = i+1;
      for(++it2; it2 != scenes.end(); ++it2, ++j) {
      //unsigned int j = 0;
      //for(typename std::vector<PlanningScene *>::iterator it2 = scenes.begin();
      //    it2 != scenes.end();
      //    ++it2, ++j)
      //{

        //if (i == j) continue;

        collision_detection::CollisionRobotConstPtr robot2 = (*it2)->getCollisionRobot();

        collision_detection::CollisionRequest req;
        collision_detection::CollisionResult res;
        req.contacts = true;
        req.max_contacts = 1000;

        // force an update
        // source: https://groups.google.com/forum/#!topic/moveit-users/O9CEef6sxbE
        states[i]->update(true);
        states[j]->update(true);
        robot1->checkOtherCollision(req, res, *states[i], *robot2, *states[j]);
        double dist = robot1->distanceOther(*states[i], *robot2, *states[j]);

        // write distance predicate
        predicator_msgs::PredicateStatement ps_dist;
        ps_dist.predicate = "distance";
        ps_dist.value = dist;
        ps_dist.num_params = 2;
        ps_dist.params[0] = robot1->getRobotModel()->getName();
        ps_dist.params[1] = robot2->getRobotModel()->getName();
        output.statements.push_back(ps_dist);

        // the reverse is also true, so write it as well
        predicator_msgs::PredicateStatement ps_dist2;
        ps_dist2.predicate = "distance";
        ps_dist2.value = dist;
        ps_dist2.num_params = 2;
        ps_dist2.params[0] = robot1->getRobotModel()->getName();
        ps_dist2.params[1] = robot2->getRobotModel()->getName();
        output.statements.push_back(ps_dist2);

        // iterate over all collisions
        for(collision_detection::CollisionResult::ContactMap::const_iterator cit = res.contacts.begin();
            cit != res.contacts.end();
            ++cit)
        {
          // write the correct predicate
          predicator_msgs::PredicateStatement ps;
          ps.predicate = "touching";
          ps.value = 1.0;
          ps.num_params = 2;
          ps.params[0] = cit->first.first;
          ps.params[1] = cit->first.second;
          output.statements.push_back(ps);

          // the reverse is also true, so update it
          predicator_msgs::PredicateStatement ps2;
          ps2.predicate = "touching";
          ps2.value = 1.0;
          ps2.num_params = 2;
          ps2.params[0] = cit->first.second;
          ps2.params[1] = cit->first.first;
          output.statements.push_back(ps2);
        }

        if (verbosity > 1) {
          std::cout << "(" << robot1->getRobotModel()->getName()
            << ", " << robot2->getRobotModel()->getName()
            << ": Distance to collision: " << dist << std::endl;
        }
      }
    }

    pub.publish(output);

    rate.sleep();
  }

  cleanup();
}
<|endoftext|>