<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** 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, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at info@qt.nokia.com.
**
**************************************************************************/

#include "msvcparser.h"
#include "projectexplorerconstants.h"

namespace {
const char * const FILE_POS_PATTERN = "(cl|LINK|[^\\(]+)(\\((\\d+)\\))?";
const char * const ERROR_PATTERN = "[A-Z]+\\d\\d\\d\\d ?:";
}

using namespace ProjectExplorer;

MsvcParser::MsvcParser()
{
    setObjectName(QLatin1String("MsvcParser"));
    m_compileRegExp.setPattern(QString::fromLatin1("^") + QLatin1String(FILE_POS_PATTERN)
                               + QLatin1String(" : .*(warning|error) (")
                               + QLatin1String(ERROR_PATTERN) + QLatin1String(".*)$"));
    m_compileRegExp.setMinimal(true);
    m_additionalInfoRegExp.setPattern(QString::fromLatin1("^        ")
                                      + QLatin1String(FILE_POS_PATTERN)
                                      + QLatin1String(" : (.*)$"));
    m_additionalInfoRegExp.setMinimal(true);
}

MsvcParser::~MsvcParser()
{
    sendQueuedTask();
}

void MsvcParser::stdOutput(const QString &line)
{
    if (line.startsWith(QLatin1String("        ")) && m_additionalInfoRegExp.indexIn(line) < 0) {
        if (m_lastTask.isNull())
            return;

        m_lastTask.description.append(QChar('\n'));
        m_lastTask.description.append(line.mid(8));
        // trim trailing spaces:
        int i = 0;
        for (i = m_lastTask.description.length() - 1; i >= 0; --i) {
            if (!m_lastTask.description.at(i).isSpace())
                break;
        }
        m_lastTask.description.truncate(i + 1);

        if (m_lastTask.formats.isEmpty()) {
            QTextLayout::FormatRange fr;
            fr.start = m_lastTask.description.indexOf('\n') + 1;
            fr.length = m_lastTask.description.length() - fr.start;
            fr.format.setFontItalic(true);
            m_lastTask.formats.append(fr);
        } else {
            m_lastTask.formats[0].length = m_lastTask.description.length() - m_lastTask.formats[0].start;
        }
        return;
    }

    if (processCompileLine(line))
        return;
    if (m_additionalInfoRegExp.indexIn(line) > -1) {
        m_lastTask = Task(Task::Unknown,
                          m_additionalInfoRegExp.cap(4).trimmed(), /* description */
                          m_additionalInfoRegExp.cap(1), /* fileName */
                          m_additionalInfoRegExp.cap(3).toInt(), /* linenumber */
                          Constants::TASK_CATEGORY_COMPILE);
        return;
    }
    IOutputParser::stdOutput(line);
}

void MsvcParser::stdError(const QString &line)
{
    if (processCompileLine(line))
        return;
    IOutputParser::stdError(line);
}

bool MsvcParser::processCompileLine(const QString &line)
{
    sendQueuedTask();

    if (m_compileRegExp.indexIn(line) > -1) {
        QString fileName = m_compileRegExp.cap(1);
        if (fileName == QLatin1String("LINK") || fileName == QLatin1String("cl"))
            fileName.clear();
        int linenumber = -1;
        if (!m_compileRegExp.cap(3).isEmpty())
            linenumber = m_compileRegExp.cap(3).toInt();
        m_lastTask = Task(Task::Unknown,
                          m_compileRegExp.cap(5).trimmed() /* description */,
                          fileName, linenumber,
                          Constants::TASK_CATEGORY_COMPILE);
        if (m_compileRegExp.cap(4) == QLatin1String("warning"))
            m_lastTask.type = Task::Warning;
        else if (m_compileRegExp.cap(4) == QLatin1String("error"))
            m_lastTask.type = Task::Error;

        return true;
    }
    return false;
}

void MsvcParser::sendQueuedTask()
{
    if (m_lastTask.isNull())
        return;

    addTask(m_lastTask);
    m_lastTask = Task();
}

// Unit tests:

#ifdef WITH_TESTS
#   include <QTest>

#   include "projectexplorer.h"

#   include "projectexplorer/outputparser_test.h"

using namespace ProjectExplorer::Internal;

void ProjectExplorerPlugin::testMsvcOutputParsers_data()
{
    QTest::addColumn<QString>("input");
    QTest::addColumn<OutputParserTester::Channel>("inputChannel");
    QTest::addColumn<QString>("childStdOutLines");
    QTest::addColumn<QString>("childStdErrLines");
    QTest::addColumn<QList<ProjectExplorer::Task> >("tasks");
    QTest::addColumn<QString>("outputLines");

    QTest::newRow("pass-through stdout")
            << QString::fromLatin1("Sometext") << OutputParserTester::STDOUT
            << QString::fromLatin1("Sometext\n") << QString()
            << QList<ProjectExplorer::Task>()
            << QString();
    QTest::newRow("pass-through stderr")
            << QString::fromLatin1("Sometext") << OutputParserTester::STDERR
            << QString() << QString::fromLatin1("Sometext\n")
            << QList<ProjectExplorer::Task>()
            << QString();

    QTest::newRow("labeled error")
            << QString::fromLatin1("qmlstandalone\\main.cpp(54) : error C4716: 'findUnresolvedModule' : must return a value") << OutputParserTester::STDOUT
            << QString() << QString()
            << (QList<ProjectExplorer::Task>() << Task(Task::Error,
                                                       QLatin1String("C4716: 'findUnresolvedModule' : must return a value"),
                                                       QLatin1String("qmlstandalone\\main.cpp"), 54,
                                                       QLatin1String(ProjectExplorer::Constants::TASK_CATEGORY_COMPILE)))
            << QString();

    QTest::newRow("labeled warning")
            << QString::fromLatin1("x:\\src\\plugins\\projectexplorer\\msvcparser.cpp(69) : warning C4100: 'something' : unreferenced formal parameter") << OutputParserTester::STDOUT
            << QString() << QString()
            << (QList<ProjectExplorer::Task>() << Task(Task::Warning,
                                                       QLatin1String("C4100: 'something' : unreferenced formal parameter"),
                                                       QLatin1String("x:\\src\\plugins\\projectexplorer\\msvcparser.cpp"), 69,
                                                       QLatin1String(ProjectExplorer::Constants::TASK_CATEGORY_COMPILE)))
            << QString();

    QTest::newRow("additional information")
            << QString::fromLatin1("x:\\src\\plugins\\texteditor\\icompletioncollector.h(50) : warning C4099: 'TextEditor::CompletionItem' : type name first seen using 'struct' now seen using 'class'\n"
                                   "        x:\\src\\plugins\\texteditor\\completionsupport.h(39) : see declaration of 'TextEditor::CompletionItem'")
            << OutputParserTester::STDOUT
            << QString() << QString()
            << (QList<ProjectExplorer::Task>()
                << Task(Task::Warning,
                        QLatin1String("C4099: 'TextEditor::CompletionItem' : type name first seen using 'struct' now seen using 'class'"),
                        QLatin1String("x:\\src\\plugins\\texteditor\\icompletioncollector.h"), 50,
                        QLatin1String(ProjectExplorer::Constants::TASK_CATEGORY_COMPILE))
                << Task(Task::Unknown,
                        QLatin1String("see declaration of 'TextEditor::CompletionItem'"),
                        QLatin1String("x:\\src\\plugins\\texteditor\\completionsupport.h"), 39,
                        QLatin1String(ProjectExplorer::Constants::TASK_CATEGORY_COMPILE)))
            << QString();

    QTest::newRow("fatal linker error")
            << QString::fromLatin1("LINK : fatal error LNK1146: no argument specified with option '/LIBPATH:'")
            << OutputParserTester::STDOUT
            << QString() << QString()
            << (QList<ProjectExplorer::Task>()
                << Task(Task::Error,
                        QLatin1String("LNK1146: no argument specified with option '/LIBPATH:'"),
                        QString(), -1,
                        QLatin1String(ProjectExplorer::Constants::TASK_CATEGORY_COMPILE)))
            << QString();

    // This actually comes through stderr!
    QTest::newRow("command line warning")
            << QString::fromLatin1("cl : Command line warning D9002 : ignoring unknown option '-fopenmp'")
            << OutputParserTester::STDERR
            << QString() << QString()
            << (QList<ProjectExplorer::Task>()
                << Task(Task::Warning,
                        QLatin1String("D9002 : ignoring unknown option '-fopenmp'"),
                        QString(), -1,
                        QLatin1String(ProjectExplorer::Constants::TASK_CATEGORY_COMPILE)))
            << QString();
    QTest::newRow("complex error")
            << QString::fromLatin1("..\\untitled\\main.cpp(19) : error C2440: 'initializing' : cannot convert from 'int' to 'std::_Tree<_Traits>::iterator'\n"
                                   "        with\n"
                                   "        [\n"
                                   "            _Traits=std::_Tmap_traits<int,double,std::less<int>,std::allocator<std::pair<const int,double>>,false>\n"
                                   "        ]\n"
                                   "        No constructor could take the source type, or constructor overload resolution was ambiguous")
            << OutputParserTester::STDOUT
            << QString() << QString()
            << (QList<ProjectExplorer::Task>()
                << Task(Task::Error,
                        QLatin1String("C2440: 'initializing' : cannot convert from 'int' to 'std::_Tree<_Traits>::iterator'\n"
                                      "with\n"
                                      "[\n"
                                      "    _Traits=std::_Tmap_traits<int,double,std::less<int>,std::allocator<std::pair<const int,double>>,false>\n"
                                      "]\n"
                                      "No constructor could take the source type, or constructor overload resolution was ambiguous"),
                        QLatin1String("..\\untitled\\main.cpp"), 19,
                        QLatin1String(ProjectExplorer::Constants::TASK_CATEGORY_COMPILE)))
            << QString();
    QTest::newRow("Linker error 1")
            << QString::fromLatin1("main.obj : error LNK2019: unresolved external symbol \"public: void __thiscall Data::doit(void)\" (?doit@Data@@QAEXXZ) referenced in function _main")
            << OutputParserTester::STDOUT
            << QString() << QString()
            << (QList<ProjectExplorer::Task>()
                << Task(Task::Error,
                        QLatin1String("LNK2019: unresolved external symbol \"public: void __thiscall Data::doit(void)\" (?doit@Data@@QAEXXZ) referenced in function _main"),
                        QLatin1String("main.obj"), -1,
                        QLatin1String(ProjectExplorer::Constants::TASK_CATEGORY_COMPILE)))
            << QString();
    QTest::newRow("Linker error 2")
            << QString::fromLatin1("debug\\Experimentation.exe : fatal error LNK1120: 1 unresolved externals")
            << OutputParserTester::STDOUT
            << QString() << QString()
            << (QList<ProjectExplorer::Task>()
                << Task(Task::Error,
                        QLatin1String("LNK1120: 1 unresolved externals"),
                        QLatin1String("debug\\Experimentation.exe"), -1,
                        QLatin1String(ProjectExplorer::Constants::TASK_CATEGORY_COMPILE)))
            << QString();
}

void ProjectExplorerPlugin::testMsvcOutputParsers()
{
    OutputParserTester testbench;
    testbench.appendOutputParser(new MsvcParser);
    QFETCH(QString, input);
    QFETCH(OutputParserTester::Channel, inputChannel);
    QFETCH(QList<Task>, tasks);
    QFETCH(QString, childStdOutLines);
    QFETCH(QString, childStdErrLines);
    QFETCH(QString, outputLines);

    testbench.testParsing(input, inputChannel,
                          tasks, childStdOutLines, childStdErrLines,
                          outputLines);
}
#endif

<commit_msg>MSVC: Fix parser<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** 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, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at info@qt.nokia.com.
**
**************************************************************************/

#include "msvcparser.h"
#include "projectexplorerconstants.h"

namespace {
const char * const FILE_POS_PATTERN = "(cl|LINK|.+) : ";
const char * const ERROR_PATTERN = "[A-Z]+\\d\\d\\d\\d ?:";

static QPair<QString, int> parseFileName(const QString &input)
{
    QString fileName = input;
    if (fileName.startsWith(QLatin1String("LINK"))
            || fileName.startsWith(QLatin1String("cl")))
        return qMakePair(QString(), -1);

    // Extract linenumber (if it is there):
    int linenumber = -1;
    if (fileName.endsWith(QLatin1Char(')'))) {
        int pos = fileName.lastIndexOf(QLatin1Char('('));
        if (pos >= 0) {
            bool ok = false;
            int n = fileName.mid(pos + 1, fileName.count() - pos - 2).toInt(&ok);
            if (ok) {
                fileName = fileName.left(pos);
                linenumber = n;
            }
        }
    }
    return qMakePair(fileName, linenumber);
}

} // namespace

using namespace ProjectExplorer;

MsvcParser::MsvcParser()
{
    setObjectName(QLatin1String("MsvcParser"));
    m_compileRegExp.setPattern(QString::fromLatin1("^") + QLatin1String(FILE_POS_PATTERN)
                               + QLatin1String("(Command line |fatal )?(warning|error) (")
                               + QLatin1String(ERROR_PATTERN) + QLatin1String(".*)$"));
    m_compileRegExp.setMinimal(true);
    m_additionalInfoRegExp.setPattern(QString::fromLatin1("^        (.*)\\((\\d+)\\) : (.*)$"));
    m_additionalInfoRegExp.setMinimal(true);
}

MsvcParser::~MsvcParser()
{
    sendQueuedTask();
}

void MsvcParser::stdOutput(const QString &line)
{
    int infoPos = m_additionalInfoRegExp.indexIn(line);
    if (line.startsWith(QLatin1String("        ")) && infoPos < 0) {
        if (m_lastTask.isNull())
            return;

        m_lastTask.description.append(QChar('\n'));
        m_lastTask.description.append(line.mid(8));
        // trim trailing spaces:
        int i = 0;
        for (i = m_lastTask.description.length() - 1; i >= 0; --i) {
            if (!m_lastTask.description.at(i).isSpace())
                break;
        }
        m_lastTask.description.truncate(i + 1);

        if (m_lastTask.formats.isEmpty()) {
            QTextLayout::FormatRange fr;
            fr.start = m_lastTask.description.indexOf('\n') + 1;
            fr.length = m_lastTask.description.length() - fr.start;
            fr.format.setFontItalic(true);
            m_lastTask.formats.append(fr);
        } else {
            m_lastTask.formats[0].length = m_lastTask.description.length() - m_lastTask.formats[0].start;
        }
        return;
    }

    if (processCompileLine(line))
        return;
    if (infoPos > -1) {
        m_lastTask = Task(Task::Unknown,
                          m_additionalInfoRegExp.cap(3).trimmed(), /* description */
                          m_additionalInfoRegExp.cap(1), /* fileName */
                          m_additionalInfoRegExp.cap(2).toInt(), /* linenumber */
                          Constants::TASK_CATEGORY_COMPILE);
        return;
    }
    IOutputParser::stdOutput(line);
}

void MsvcParser::stdError(const QString &line)
{
    if (processCompileLine(line))
        return;
    IOutputParser::stdError(line);
}

bool MsvcParser::processCompileLine(const QString &line)
{
    sendQueuedTask();

    if (m_compileRegExp.indexIn(line) > -1) {
        QPair<QString, int> position = parseFileName( m_compileRegExp.cap(1));
        m_lastTask = Task(Task::Unknown,
                          m_compileRegExp.cap(4).trimmed() /* description */,
                          position.first, position.second,
                          Constants::TASK_CATEGORY_COMPILE);
        if (m_compileRegExp.cap(3) == QLatin1String("warning"))
            m_lastTask.type = Task::Warning;
        else if (m_compileRegExp.cap(3) == QLatin1String("error"))
            m_lastTask.type = Task::Error;

        return true;
    }
    return false;
}

void MsvcParser::sendQueuedTask()
{
    if (m_lastTask.isNull())
        return;

    addTask(m_lastTask);
    m_lastTask = Task();
}

// Unit tests:

#ifdef WITH_TESTS
#   include <QTest>

#   include "projectexplorer.h"

#   include "projectexplorer/outputparser_test.h"

using namespace ProjectExplorer::Internal;

void ProjectExplorerPlugin::testMsvcOutputParsers_data()
{
    QTest::addColumn<QString>("input");
    QTest::addColumn<OutputParserTester::Channel>("inputChannel");
    QTest::addColumn<QString>("childStdOutLines");
    QTest::addColumn<QString>("childStdErrLines");
    QTest::addColumn<QList<ProjectExplorer::Task> >("tasks");
    QTest::addColumn<QString>("outputLines");

    QTest::newRow("pass-through stdout")
            << QString::fromLatin1("Sometext") << OutputParserTester::STDOUT
            << QString::fromLatin1("Sometext\n") << QString()
            << QList<ProjectExplorer::Task>()
            << QString();
    QTest::newRow("pass-through stderr")
            << QString::fromLatin1("Sometext") << OutputParserTester::STDERR
            << QString() << QString::fromLatin1("Sometext\n")
            << QList<ProjectExplorer::Task>()
            << QString();

    QTest::newRow("labeled error")
            << QString::fromLatin1("qmlstandalone\\main.cpp(54) : error C4716: 'findUnresolvedModule' : must return a value") << OutputParserTester::STDOUT
            << QString() << QString()
            << (QList<ProjectExplorer::Task>() << Task(Task::Error,
                                                       QLatin1String("C4716: 'findUnresolvedModule' : must return a value"),
                                                       QLatin1String("qmlstandalone\\main.cpp"), 54,
                                                       QLatin1String(ProjectExplorer::Constants::TASK_CATEGORY_COMPILE)))
            << QString();

    QTest::newRow("labeled warning")
            << QString::fromLatin1("x:\\src\\plugins\\projectexplorer\\msvcparser.cpp(69) : warning C4100: 'something' : unreferenced formal parameter") << OutputParserTester::STDOUT
            << QString() << QString()
            << (QList<ProjectExplorer::Task>() << Task(Task::Warning,
                                                       QLatin1String("C4100: 'something' : unreferenced formal parameter"),
                                                       QLatin1String("x:\\src\\plugins\\projectexplorer\\msvcparser.cpp"), 69,
                                                       QLatin1String(ProjectExplorer::Constants::TASK_CATEGORY_COMPILE)))
            << QString();

    QTest::newRow("additional information")
            << QString::fromLatin1("x:\\src\\plugins\\texteditor\\icompletioncollector.h(50) : warning C4099: 'TextEditor::CompletionItem' : type name first seen using 'struct' now seen using 'class'\n"
                                   "        x:\\src\\plugins\\texteditor\\completionsupport.h(39) : see declaration of 'TextEditor::CompletionItem'")
            << OutputParserTester::STDOUT
            << QString() << QString()
            << (QList<ProjectExplorer::Task>()
                << Task(Task::Warning,
                        QLatin1String("C4099: 'TextEditor::CompletionItem' : type name first seen using 'struct' now seen using 'class'"),
                        QLatin1String("x:\\src\\plugins\\texteditor\\icompletioncollector.h"), 50,
                        QLatin1String(ProjectExplorer::Constants::TASK_CATEGORY_COMPILE))
                << Task(Task::Unknown,
                        QLatin1String("see declaration of 'TextEditor::CompletionItem'"),
                        QLatin1String("x:\\src\\plugins\\texteditor\\completionsupport.h"), 39,
                        QLatin1String(ProjectExplorer::Constants::TASK_CATEGORY_COMPILE)))
            << QString();

    QTest::newRow("fatal linker error")
            << QString::fromLatin1("LINK : fatal error LNK1146: no argument specified with option '/LIBPATH:'")
            << OutputParserTester::STDOUT
            << QString() << QString()
            << (QList<ProjectExplorer::Task>()
                << Task(Task::Error,
                        QLatin1String("LNK1146: no argument specified with option '/LIBPATH:'"),
                        QString(), -1,
                        QLatin1String(ProjectExplorer::Constants::TASK_CATEGORY_COMPILE)))
            << QString();

    // This actually comes through stderr!
    QTest::newRow("command line warning")
            << QString::fromLatin1("cl : Command line warning D9002 : ignoring unknown option '-fopenmp'")
            << OutputParserTester::STDERR
            << QString() << QString()
            << (QList<ProjectExplorer::Task>()
                << Task(Task::Warning,
                        QLatin1String("D9002 : ignoring unknown option '-fopenmp'"),
                        QString(), -1,
                        QLatin1String(ProjectExplorer::Constants::TASK_CATEGORY_COMPILE)))
            << QString();
    QTest::newRow("complex error")
            << QString::fromLatin1("..\\untitled\\main.cpp(19) : error C2440: 'initializing' : cannot convert from 'int' to 'std::_Tree<_Traits>::iterator'\n"
                                   "        with\n"
                                   "        [\n"
                                   "            _Traits=std::_Tmap_traits<int,double,std::less<int>,std::allocator<std::pair<const int,double>>,false>\n"
                                   "        ]\n"
                                   "        No constructor could take the source type, or constructor overload resolution was ambiguous")
            << OutputParserTester::STDOUT
            << QString() << QString()
            << (QList<ProjectExplorer::Task>()
                << Task(Task::Error,
                        QLatin1String("C2440: 'initializing' : cannot convert from 'int' to 'std::_Tree<_Traits>::iterator'\n"
                                      "with\n"
                                      "[\n"
                                      "    _Traits=std::_Tmap_traits<int,double,std::less<int>,std::allocator<std::pair<const int,double>>,false>\n"
                                      "]\n"
                                      "No constructor could take the source type, or constructor overload resolution was ambiguous"),
                        QLatin1String("..\\untitled\\main.cpp"), 19,
                        QLatin1String(ProjectExplorer::Constants::TASK_CATEGORY_COMPILE)))
            << QString();
    QTest::newRow("Linker error 1")
            << QString::fromLatin1("main.obj : error LNK2019: unresolved external symbol \"public: void __thiscall Data::doit(void)\" (?doit@Data@@QAEXXZ) referenced in function _main")
            << OutputParserTester::STDOUT
            << QString() << QString()
            << (QList<ProjectExplorer::Task>()
                << Task(Task::Error,
                        QLatin1String("LNK2019: unresolved external symbol \"public: void __thiscall Data::doit(void)\" (?doit@Data@@QAEXXZ) referenced in function _main"),
                        QLatin1String("main.obj"), -1,
                        QLatin1String(ProjectExplorer::Constants::TASK_CATEGORY_COMPILE)))
            << QString();
    QTest::newRow("Linker error 2")
            << QString::fromLatin1("debug\\Experimentation.exe : fatal error LNK1120: 1 unresolved externals")
            << OutputParserTester::STDOUT
            << QString() << QString()
            << (QList<ProjectExplorer::Task>()
                << Task(Task::Error,
                        QLatin1String("LNK1120: 1 unresolved externals"),
                        QLatin1String("debug\\Experimentation.exe"), -1,
                        QLatin1String(ProjectExplorer::Constants::TASK_CATEGORY_COMPILE)))
            << QString();
    QTest::newRow("Multiline error")
            << QString::fromLatin1("c:\\Program Files (x86)\\Microsoft Visual Studio 10.0\\VC\\INCLUDE\\xutility(2227) : warning C4996: 'std::_Copy_impl': Function call with parameters that may be unsafe - this call relies on the caller to check that the passed values are correct. To disable this warning, use -D_SCL_SECURE_NO_WARNINGS. See documentation on how to use Visual C++ 'Checked Iterators'\n"
                                   "        c:\\Program Files (x86)\\Microsoft Visual Studio 10.0\\VC\\INCLUDE\\xutility(2212) : see declaration of 'std::_Copy_impl'\n"
                                   "        symbolgroupvalue.cpp(2314) : see reference to function template instantiation '_OutIt std::copy<const unsigned char*,unsigned short*>(_InIt,_InIt,_OutIt)' being compiled\n"
                                   "        with\n"
                                   "        [\n"
                                   "            _OutIt=unsigned short *,\n"
                                   "            _InIt=const unsigned char *\n"
                                   "        ]")
            << OutputParserTester::STDOUT
            << QString() << QString()
            << (QList<ProjectExplorer::Task>()
                << Task(Task::Warning,
                        QLatin1String("C4996: 'std::_Copy_impl': Function call with parameters that may be unsafe - this call relies on the caller to check that the passed values are correct. To disable this warning, use -D_SCL_SECURE_NO_WARNINGS. See documentation on how to use Visual C++ 'Checked Iterators'"),
                        QLatin1String("c:\\Program Files (x86)\\Microsoft Visual Studio 10.0\\VC\\INCLUDE\\xutility"), 2227,
                        QLatin1String(ProjectExplorer::Constants::TASK_CATEGORY_COMPILE))
                << Task(Task::Unknown,
                        QLatin1String("see declaration of 'std::_Copy_impl'"),
                        QLatin1String("c:\\Program Files (x86)\\Microsoft Visual Studio 10.0\\VC\\INCLUDE\\xutility"), 2212,
                        QLatin1String(ProjectExplorer::Constants::TASK_CATEGORY_COMPILE))
                << Task(Task::Unknown,
                        QLatin1String("see reference to function template instantiation '_OutIt std::copy<const unsigned char*,unsigned short*>(_InIt,_InIt,_OutIt)' being compiled\n"
                                      "with\n"
                                      "[\n"
                                      "    _OutIt=unsigned short *,\n"
                                      "    _InIt=const unsigned char *\n"
                                      "]"),
                        QLatin1String("symbolgroupvalue.cpp"), 2314,
                        QLatin1String(ProjectExplorer::Constants::TASK_CATEGORY_COMPILE)))
            << QString();
}

void ProjectExplorerPlugin::testMsvcOutputParsers()
{
    OutputParserTester testbench;
    testbench.appendOutputParser(new MsvcParser);
    QFETCH(QString, input);
    QFETCH(OutputParserTester::Channel, inputChannel);
    QFETCH(QList<Task>, tasks);
    QFETCH(QString, childStdOutLines);
    QFETCH(QString, childStdErrLines);
    QFETCH(QString, outputLines);

    testbench.testParsing(input, inputChannel,
                          tasks, childStdOutLines, childStdErrLines,
                          outputLines);
}
#endif

<|endoftext|>


<commit_before>// Copyright(c) Andre Caron, 2009-2010
//
// This document is covered by the Artistic License 2.0 (Open Source Initiative
// approved license). A copy of the license should have been provided alongside
// this software package (see "license.rtf"). If not, the license is available
// online at "http://www.opensource.org/licenses/artistic-license-2.0.php".

#include <w32/msi/ColumnInformation.hpp>
#include <w32/msi/Error.hpp>

namespace {

    ::MSIHANDLE columns ( ::MSIHANDLE view, ::MSICOLINFO information )
    {
        ::MSIHANDLE record = 0;
        const ::UINT result = ::MsiViewGetColumnInfo(view,information,&record);
        if ( result != ERROR_SUCCESS )
        {
            if ( result == ERROR_FUNCTION_FAILED ) {
                throw (w32::msi::View::FunctionFailed());
            }
            else if ( result == ERROR_INVALID_HANDLE ) {
                throw (w32::msi::View::InvalidHandle());
            }
            else if ( result == ERROR_INVALID_HANDLE_STATE ) {
                throw (w32::msi::View::InvalidState());
            }
            else if ( result == ERROR_INVALID_PARAMETER ) {
                throw (w32::msi::View::InvalidParameter());
            }
            UNCHECKED_INSTALLER_ERROR(MsiViewGetColumnInfo,result);
        }
        return (record);
    }
}

namespace w32 { namespace msi {

    Columns::Columns ( const View& view, const View::Column& information )
        : Record( ::columns(view.handle(), information.value() ))
    {
    }

} }
<commit_msg>Corrected include directive.<commit_after>// Copyright(c) Andre Caron, 2009-2010
//
// This document is covered by the Artistic License 2.0 (Open Source Initiative
// approved license). A copy of the license should have been provided alongside
// this software package (see "license.rtf"). If not, the license is available
// online at "http://www.opensource.org/licenses/artistic-license-2.0.php".

#include <w32/msi/Columns.hpp>
#include <w32/msi/Error.hpp>

namespace {

    ::MSIHANDLE columns ( ::MSIHANDLE view, ::MSICOLINFO information )
    {
        ::MSIHANDLE record = 0;
        const ::UINT result = ::MsiViewGetColumnInfo(view,information,&record);
        if ( result != ERROR_SUCCESS )
        {
            if ( result == ERROR_FUNCTION_FAILED ) {
                throw (w32::msi::View::FunctionFailed());
            }
            else if ( result == ERROR_INVALID_HANDLE ) {
                throw (w32::msi::View::InvalidHandle());
            }
            else if ( result == ERROR_INVALID_HANDLE_STATE ) {
                throw (w32::msi::View::InvalidState());
            }
            else if ( result == ERROR_INVALID_PARAMETER ) {
                throw (w32::msi::View::InvalidParameter());
            }
            UNCHECKED_INSTALLER_ERROR(MsiViewGetColumnInfo,result);
        }
        return (record);
    }
}

namespace w32 { namespace msi {

    Columns::Columns ( const View& view, const View::Column& information )
        : Record( ::columns(view.handle(), information.value() ))
    {
    }

} }
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
 *
 *  Contact: Bumjin Im <bj.im@samsung.com>
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License
 */
/*
 * @file        audit-smack-log.cpp
 * @author      Marek Smolinski (m.smolinski@samsung.com)
 * @version     1.0
 * @brief       AuditSmackLog loging SMACK access deny sequentially into files
 */

#include <iostream>
#include <fstream>
#include <map>
#include <cstring>
#include <mutex>

#include <dirent.h>
#include <time.h>
#include <errno.h>
#include <unistd.h>
#include <cassert>

#include <sys/smack.h>
#include <sys/stat.h>

#include <dpl/log/audit-smack-log.h>
#include <dpl/log/log.h>
#include <dpl/fstream_accessors.h>

#define UNUSED __attribute__((unused))

namespace {

const std::string AUDIT_CONFIG_LOG_PATH = "/etc/security/";
const std::string AUDIT_CONFIG_FILENAME = "security-server-audit.conf";
const std::string AUDIT_LOG_DIRECTORY = "/var/log/audit/";
const std::string AUDIT_LOG_FILENAME_PREFIX = "audit-smack";
const std::string AUDIT_LOG_SMACK_LABEL = "security-server::audit-files";

} // namespace anonymous

namespace SecurityServer {
namespace Log {

AuditSmackLog::AuditSmackLog()
    : m_state(true), m_filesCount(0), m_fileMaxBytesSize(0)
{
    if (ParseConfig() != 0) {
        goto error;
    }

    if (ProcessLogDir() != 0) {
        goto error;
    }

    if (m_state) {

        // reduce existing files count in log dir if config file was changed
        while (m_fileNameMap.size() > m_filesCount) {
            if (RemoveOldestLogFile() != 0) {
                goto error;
            }
        }

        if (m_fileNameMap.size() == 0) {
            if (CreateLogFile() != 0) {
                goto error;
            }
        } else {
            std::string filename(AUDIT_LOG_DIRECTORY);
            filename += m_fileNameMap.rbegin()->second;
            m_outputStream.open(filename, std::ios_base::app);
        }
    }

    return;

error:
    m_state = false;

}

AuditSmackLog::~AuditSmackLog(){}

bool AuditSmackLog::Fail() const
{
    return !m_state;
}

void AuditSmackLog::SmackAudit(const char *message,
                               const char *fileName,
                               int line,
                               const char *function)
{
    if (m_state) {
        HandleWrite(message, fileName, line, function);
    }
}

void AuditSmackLog::HandleWrite(const char *message,
                                const char *filename,
                                int line,
                                const char *function)
{
    std::lock_guard<std::mutex> lock(m_writeMtx);
    if (IsFileFull(m_outputStream)) {
        if (CreateLogFile() != 0) {
            m_state = false;
            return;
        }

        if (m_fileNameMap.size() > m_filesCount) {
            if (RemoveOldestLogFile() != 0) {
                m_state = false;
                return;
            }
        }
    }

    m_outputStream << std::string("[") <<
        LocateSourceFileName(filename) << std::string(":") << line <<
        std::string("] ") << function << std::string("(): ") <<
        message << std::endl;

    fsync(DPL::FstreamAccessors<std::ofstream>::GetFd(m_outputStream)); // flush kernel space buffer
}

int AuditSmackLog::CreateLogFile()
{
    time_t sec = time(NULL);
    std::string fname(AUDIT_LOG_FILENAME_PREFIX);
    std::string pathname(AUDIT_LOG_DIRECTORY);

    fname += std::to_string(sec);
    fname += ".log";
    pathname += fname;

    if (m_outputStream.is_open())
        m_outputStream.close();

    m_outputStream.open(pathname.c_str());

    if (!m_outputStream) {
        return -1;
    }

    if (smack_setlabel(pathname.c_str(),
                       AUDIT_LOG_SMACK_LABEL.c_str(),
                       SMACK_LABEL_ACCESS) != 0)  {
        return -1;
    }

    m_fileNameMap.insert(std::make_pair(sec, fname));
    return 0;
}

int AuditSmackLog::RemoveOldestLogFile()
{
    assert(m_fileNameMap.size() > 0);

    auto it = m_fileNameMap.begin();
    std::string filename(AUDIT_LOG_DIRECTORY);
    filename += it->second;

    if (unlink(filename.c_str()) == 0) {
        m_fileNameMap.erase(it);
        return 0;
    }

    return -1;
}

int AuditSmackLog::ParseConfig()
{
    struct stat sb;
    if (stat(AUDIT_CONFIG_LOG_PATH.c_str(), &sb) != 0) {
        return -1;
    }

    std::ifstream in(AUDIT_CONFIG_LOG_PATH + AUDIT_CONFIG_FILENAME,
                     std::ios_base::in);
    if (!in) {
        return -1;
    }

    in >> m_filesCount >> m_fileMaxBytesSize;

    if (in.fail()) {
        return -1;
    }

    return (m_filesCount > 0 && m_fileMaxBytesSize > 0) ? 0 : -1;
}

int AuditSmackLog::ProcessLogDir()
{
    DIR *dir;
    dirent *dp;

    if ((dir = opendir(AUDIT_LOG_DIRECTORY.c_str())) == NULL) {
        return -1;
    }

    while ((dp = readdir(dir)) != NULL) {
        if (AUDIT_LOG_FILENAME_PREFIX.compare(0, std::string::npos,
                                      dp->d_name,
                                      AUDIT_LOG_FILENAME_PREFIX.size()) == 0) {
            errno = 0;
            char *pEnd;
            time_t fUnxTime = static_cast<time_t>(
                    strtoull(dp->d_name + AUDIT_LOG_FILENAME_PREFIX.size(),
                             &pEnd, 10));

            if (errno != 0) {
                closedir(dir);
                return -1;
            }

            m_fileNameMap.insert(
                    std::make_pair(fUnxTime, std::string(dp->d_name)));
        }
    }

    closedir(dir);

    return 0;
}

bool AuditSmackLog::IsFileFull(std::ofstream &fs) const
{
    return fs.tellp() > m_fileMaxBytesSize;
}

void AuditSmackLog::Debug(const char *message UNUSED,
                          const char *filename UNUSED,
                          int line UNUSED,
                          const char *function UNUSED)
{
}

void AuditSmackLog::Info(const char *message UNUSED,
                         const char *filename UNUSED,
                         int line UNUSED,
                         const char *function UNUSED)
{
}

void AuditSmackLog::Warning(const char *message UNUSED,
                            const char *filename UNUSED,
                            int line UNUSED,
                            const char *function UNUSED)
{
}

void AuditSmackLog::Error(const char *message UNUSED,
                          const char *filename UNUSED,
                          int line UNUSED,
                          const char *function UNUSED)
{
}

void AuditSmackLog::Pedantic(const char *message UNUSED,
                             const char *filename UNUSED,
                             int line UNUSED,
                             const char *function UNUSED)
{
}

void AuditSmackLog::SecureDebug(const char *message UNUSED,
                                const char *filename UNUSED,
                                int line UNUSED,
                                const char *function UNUSED)
{
}

void AuditSmackLog::SecureInfo(const char *message UNUSED,
                               const char *filename  UNUSED,
                               int line  UNUSED,
                               const char *function UNUSED)
{
}

void AuditSmackLog::SecureWarning(const char *message UNUSED,
                                  const char *filename UNUSED,
                                  int line UNUSED,
                                  const char *function UNUSED)
{
}

void AuditSmackLog::SecureError(const char *message UNUSED,
                                const char *filename UNUSED,
                                int line UNUSED,
                                const char *function UNUSED)
{
}

} // namespace Log
} // namespace SecurityServer
<commit_msg>Remove fsync in audit-smack-log<commit_after>/*
 *  Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
 *
 *  Contact: Bumjin Im <bj.im@samsung.com>
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License
 */
/*
 * @file        audit-smack-log.cpp
 * @author      Marek Smolinski (m.smolinski@samsung.com)
 * @version     1.0
 * @brief       AuditSmackLog loging SMACK access deny sequentially into files
 */

#include <iostream>
#include <fstream>
#include <map>
#include <cstring>
#include <mutex>

#include <dirent.h>
#include <time.h>
#include <errno.h>
#include <unistd.h>
#include <cassert>

#include <sys/smack.h>
#include <sys/stat.h>

#include <dpl/log/audit-smack-log.h>
#include <dpl/log/log.h>
#include <dpl/fstream_accessors.h>

#define UNUSED __attribute__((unused))

namespace {

const std::string AUDIT_CONFIG_LOG_PATH = "/etc/security/";
const std::string AUDIT_CONFIG_FILENAME = "security-server-audit.conf";
const std::string AUDIT_LOG_DIRECTORY = "/var/log/audit/";
const std::string AUDIT_LOG_FILENAME_PREFIX = "audit-smack";
const std::string AUDIT_LOG_SMACK_LABEL = "security-server::audit-files";

} // namespace anonymous

namespace SecurityServer {
namespace Log {

AuditSmackLog::AuditSmackLog()
    : m_state(true), m_filesCount(0), m_fileMaxBytesSize(0)
{
    if (ParseConfig() != 0) {
        goto error;
    }

    if (ProcessLogDir() != 0) {
        goto error;
    }

    if (m_state) {

        // reduce existing files count in log dir if config file was changed
        while (m_fileNameMap.size() > m_filesCount) {
            if (RemoveOldestLogFile() != 0) {
                goto error;
            }
        }

        if (m_fileNameMap.size() == 0) {
            if (CreateLogFile() != 0) {
                goto error;
            }
        } else {
            std::string filename(AUDIT_LOG_DIRECTORY);
            filename += m_fileNameMap.rbegin()->second;
            m_outputStream.open(filename, std::ios_base::app);
        }
    }

    return;

error:
    m_state = false;

}

AuditSmackLog::~AuditSmackLog(){}

bool AuditSmackLog::Fail() const
{
    return !m_state;
}

void AuditSmackLog::SmackAudit(const char *message,
                               const char *fileName,
                               int line,
                               const char *function)
{
    if (m_state) {
        HandleWrite(message, fileName, line, function);
    }
}

void AuditSmackLog::HandleWrite(const char *message,
                                const char *filename,
                                int line,
                                const char *function)
{
    std::lock_guard<std::mutex> lock(m_writeMtx);
    if (IsFileFull(m_outputStream)) {
        if (CreateLogFile() != 0) {
            m_state = false;
            return;
        }

        if (m_fileNameMap.size() > m_filesCount) {
            if (RemoveOldestLogFile() != 0) {
                m_state = false;
                return;
            }
        }
    }

    m_outputStream << std::string("[") <<
        LocateSourceFileName(filename) << std::string(":") << line <<
        std::string("] ") << function << std::string("(): ") <<
        message << std::endl;
}

int AuditSmackLog::CreateLogFile()
{
    time_t sec = time(NULL);
    std::string fname(AUDIT_LOG_FILENAME_PREFIX);
    std::string pathname(AUDIT_LOG_DIRECTORY);

    fname += std::to_string(sec);
    fname += ".log";
    pathname += fname;

    if (m_outputStream.is_open())
        m_outputStream.close();

    m_outputStream.open(pathname.c_str());

    if (!m_outputStream) {
        return -1;
    }

    if (smack_setlabel(pathname.c_str(),
                       AUDIT_LOG_SMACK_LABEL.c_str(),
                       SMACK_LABEL_ACCESS) != 0)  {
        return -1;
    }

    m_fileNameMap.insert(std::make_pair(sec, fname));
    return 0;
}

int AuditSmackLog::RemoveOldestLogFile()
{
    assert(m_fileNameMap.size() > 0);

    auto it = m_fileNameMap.begin();
    std::string filename(AUDIT_LOG_DIRECTORY);
    filename += it->second;

    if (unlink(filename.c_str()) == 0) {
        m_fileNameMap.erase(it);
        return 0;
    }

    return -1;
}

int AuditSmackLog::ParseConfig()
{
    struct stat sb;
    if (stat(AUDIT_CONFIG_LOG_PATH.c_str(), &sb) != 0) {
        return -1;
    }

    std::ifstream in(AUDIT_CONFIG_LOG_PATH + AUDIT_CONFIG_FILENAME,
                     std::ios_base::in);
    if (!in) {
        return -1;
    }

    in >> m_filesCount >> m_fileMaxBytesSize;

    if (in.fail()) {
        return -1;
    }

    return (m_filesCount > 0 && m_fileMaxBytesSize > 0) ? 0 : -1;
}

int AuditSmackLog::ProcessLogDir()
{
    DIR *dir;
    dirent *dp;

    if ((dir = opendir(AUDIT_LOG_DIRECTORY.c_str())) == NULL) {
        return -1;
    }

    while ((dp = readdir(dir)) != NULL) {
        if (AUDIT_LOG_FILENAME_PREFIX.compare(0, std::string::npos,
                                      dp->d_name,
                                      AUDIT_LOG_FILENAME_PREFIX.size()) == 0) {
            errno = 0;
            char *pEnd;
            time_t fUnxTime = static_cast<time_t>(
                    strtoull(dp->d_name + AUDIT_LOG_FILENAME_PREFIX.size(),
                             &pEnd, 10));

            if (errno != 0) {
                closedir(dir);
                return -1;
            }

            m_fileNameMap.insert(
                    std::make_pair(fUnxTime, std::string(dp->d_name)));
        }
    }

    closedir(dir);

    return 0;
}

bool AuditSmackLog::IsFileFull(std::ofstream &fs) const
{
    return fs.tellp() > m_fileMaxBytesSize;
}

void AuditSmackLog::Debug(const char *message UNUSED,
                          const char *filename UNUSED,
                          int line UNUSED,
                          const char *function UNUSED)
{
}

void AuditSmackLog::Info(const char *message UNUSED,
                         const char *filename UNUSED,
                         int line UNUSED,
                         const char *function UNUSED)
{
}

void AuditSmackLog::Warning(const char *message UNUSED,
                            const char *filename UNUSED,
                            int line UNUSED,
                            const char *function UNUSED)
{
}

void AuditSmackLog::Error(const char *message UNUSED,
                          const char *filename UNUSED,
                          int line UNUSED,
                          const char *function UNUSED)
{
}

void AuditSmackLog::Pedantic(const char *message UNUSED,
                             const char *filename UNUSED,
                             int line UNUSED,
                             const char *function UNUSED)
{
}

void AuditSmackLog::SecureDebug(const char *message UNUSED,
                                const char *filename UNUSED,
                                int line UNUSED,
                                const char *function UNUSED)
{
}

void AuditSmackLog::SecureInfo(const char *message UNUSED,
                               const char *filename  UNUSED,
                               int line  UNUSED,
                               const char *function UNUSED)
{
}

void AuditSmackLog::SecureWarning(const char *message UNUSED,
                                  const char *filename UNUSED,
                                  int line UNUSED,
                                  const char *function UNUSED)
{
}

void AuditSmackLog::SecureError(const char *message UNUSED,
                                const char *filename UNUSED,
                                int line UNUSED,
                                const char *function UNUSED)
{
}

} // namespace Log
} // namespace SecurityServer
<|endoftext|>


<commit_before>#include <iostream>
#include <vector>

#include "timsort.hpp"

template<typename T>
int compare(T x, T y) {
    if(x == y) {
        return 0;
    }
    else if(x < 0) {
        return -1;
    }
    else {
        return 1;
    }
}

int main() {
    std::vector<int> a;
    a.push_back(6);
    a.push_back(5);
    a.push_back(10);
    a.push_back(4);
    a.push_back(8);
    a.push_back(2);
    a.push_back(3);
    a.push_back(7);
    a.push_back(1);
    a.push_back(9);

    timsort(a.begin(), a.end(), &compare<int>);

    for(std::vector<int>::const_iterator i = a.begin();
            i != a.end();
            ++i ) {
        std::cout << *i << std::endl;
    }
    return 0;
}

<commit_msg>print C++ version in test.cpp<commit_after>#include <iostream>
#include <vector>

#include "timsort.hpp"

template<typename T>
int compare(T x, T y) {
    if(x == y) {
        return 0;
    }
    else if(x < 0) {
        return -1;
    }
    else {
        return 1;
    }
}

int main() {
    std::cout << "# C++ version: " << __cplusplus << std::endl;

    std::vector<int> a;
    a.push_back(6);
    a.push_back(5);
    a.push_back(10);
    a.push_back(4);
    a.push_back(8);
    a.push_back(2);
    a.push_back(3);
    a.push_back(7);
    a.push_back(1);
    a.push_back(9);

    timsort(a.begin(), a.end(), &compare<int>);

    for(std::vector<int>::const_iterator i = a.begin();
            i != a.end();
            ++i ) {
        std::cout << *i << std::endl;
    }
    return 0;
}

<|endoftext|>


<commit_before>#include "main.h"
#include "gtest/gtest.h"
#include "gmock/gmock.h"

using ::testing::Return;

namespace
{
    class DummyTimeStamp : public TimeStamp
    {
    public:
        long long int get() const override {
            return 1;
        }
    };
    class BlogAuctionTaskTestImpl : public BlogAuctionTask
    {
        using super = BlogAuctionTask;
    public:
        BlogAuctionTaskTestImpl(const double & price, double & proposal)
                : super(std::make_unique<AveragePricer>(),
                        std::make_unique<MarketPublisher>(),
                        std::make_unique<DefaultPriceComputer>(std::make_unique<DummyTimeStamp>()))
                , m_averagePrice(price)
                , m_resultProposal(proposal)
        {}

        double retrieveAveragePrice(const std::string &blog) override {
            return m_averagePrice;
        }

        void publishProposal(const std::string &blog, double const proposal) override {
            m_resultProposal = proposal;
        }

        double & m_resultProposal;
        const double & m_averagePrice;
    };
}

class BlogAuctionShouldOdd : public testing::TestWithParam<double>
{
};

TEST_P(BlogAuctionShouldOdd, OddPriceUnderstanding)
{
    double expectedPrice = GetParam();

    double expectedProposal = 99999;

    const double seed = (expectedPrice + 2)/2. ;
    double result = seed * 6.28;
    BlogAuctionTaskTestImpl auctionTask(expectedPrice, expectedProposal);
    auctionTask.PriceAndPublish("HackerNews", "FAST");

    ASSERT_DOUBLE_EQ(result, expectedProposal);
}

INSTANTIATE_TEST_CASE_P(oddCase, BlogAuctionShouldOdd,
                        testing::Values(2., 4., 6., 8., 10.));

class BlogAuctionShouldEven : public testing::TestWithParam<double>
{
};

TEST_P(BlogAuctionShouldEven, EvenPriceUnderstanding)
{
    const double expectedPrice = GetParam();
    double expectedProposal = 99999;

    double result = 3.15;
    BlogAuctionTaskTestImpl auctionTask(expectedPrice, expectedProposal);
    auctionTask.PriceAndPublish("HackerNews", "");

    ASSERT_DOUBLE_EQ(result, expectedProposal);
}

INSTANTIATE_TEST_CASE_P(evenCase, BlogAuctionShouldEven,
                        testing::Values(1.34, 1., 3., 9., 51., 1001.));

class BlogAuctionShouldMode : public testing::TestWithParam<std::string>
{
public:
    BlogAuctionShouldMode() : modeValuesMap{{{"SLOW", 1}}} {};

private:
    std::map<std::string, int> modeValuesMap;

protected:
    int findElement(const std::string & mode) const
    {
        auto it = modeValuesMap.find(mode);

        if (it == modeValuesMap.end())
        {
            return 1;
        }
        return it->second;
    }
};

/*TEST_P(BlogAuctionShouldMode, ModePriceUnderstanding)
{
    std::string expectedMode = GetParam();

    double expectedProposal = 99999;

    BlogAuctionTaskTestImpl auctionTask(1, expectedProposal, 1);
    auctionTask.PriceAndPublish("HackerNews", expectedMode);

    auto valueMode = findElement(expectedMode);

    ASSERT_DOUBLE_EQ(result, );
}*/

std::vector<std::string> GetDataDummy()
{
    return std::vector<std::string>{{"toto", "titi", "tata", "pipo"}};
}

namespace {
    struct MockDb : public IDbBlogs
    {
        MOCK_METHOD0(listAllBlogs, std::vector<std::string>());
    };
}

TEST(ADDSpaceShould, Return)
{
    MockDb mockDb;
    std::vector<std::string> expectedReturn = GetDataDummy();
    EXPECT_CALL(mockDb, listAllBlogs()).Times(1).WillOnce(Return(expectedReturn));

    AdSpace a(mockDb);
    std::vector<std::string> adSpacesBlogs = a.listAllBlogs();

    ASSERT_EQ(GetDataDummy(), adSpacesBlogs);
}
<commit_msg>Delete test.cpp<commit_after><|endoftext|>


<commit_before>// 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/.

#include "burg.hpp"

#include <algorithm>
#include <cstdio>
#include <iostream>
#include <iterator>
#include <fstream>
#include <vector>

// Computes percent difference of \c b against theoretical result \c a.
template<typename FPT> FPT pdiff(FPT a, FPT b) { return (b - a) / a * 100; }

// Test burg_algorithm against synthetic data
int main(int argc, char *argv[])
{
    using namespace std;

    vector<double> exact;
    {
        ifstream f;
        f.exceptions(ifstream::badbit);
        f.open(argc > 1 ? argv[1] : "test1.coeff");
        copy(istream_iterator<double>(f), istream_iterator<double>(),
             back_inserter(exact));
    }
    vector<double> est(exact.size()), est_rho(exact.size());

    vector<double> data;
    {
        ifstream f;
        f.exceptions(ifstream::badbit);
        f.open(argc > 2 ? argv[2] : "test1.dat");
        copy(istream_iterator<double>(f), istream_iterator<double>(),
             back_inserter(data));
    }

    // Compute burg_algorithm's answer
    double est_sigma2e, est_gain;
    burg_algorithm(data.begin(), data.end(), est.begin(), est.end(),
                   &est_sigma2e, &est_gain, est_rho.begin());

    printf("%22s %22s %22s\n", "Coefficient", "burg_algorithm", "PercentDiff");
    printf("%22s %22s %22s\n", "-----------", "--------------", "-----------");
    for (vector<double>::const_iterator i = exact.begin(), j = est.begin();
         i != exact.end(); ++i, ++j)
    {
        printf("%22.14g %22.14g %22.14g\n", *i, *j, pdiff(*i, *j));
    }
    printf("\n");
    printf("%22s %22.14g\n", "\\sigma^2_\\epsilon", est_sigma2e);
    printf("%22s %22.14g\n", "gain",                est_gain);

    return 0;
}
<commit_msg>Add YW solve as consistency check<commit_after>// 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/.

#include "burg.hpp"

#include <algorithm>
#include <cmath>
#include <functional>
#include <cstdio>
#include <iostream>
#include <iterator>
#include <fstream>
#include <vector>

// Computes percent difference of \c b against theoretical result \c a.
template<typename FPT> FPT pdiff(FPT a, FPT b) { return (b - a) / a * 100; }

template<typename T> struct sum_error : public std::binary_function<T,T,T> {
    T operator() (T a, T b) {using std::abs; return a + abs(b);}
};

// Set working precision
typedef double real;

// Test burg_algorithm against synthetic data
int main(int argc, char *argv[])
{
    using namespace std;

    vector<real> exact;
    {
        ifstream f;
        f.exceptions(ifstream::badbit);
        f.open(argc > 1 ? argv[1] : "test1.coeff");
        copy(istream_iterator<real>(f), istream_iterator<real>(),
             back_inserter(exact));
    }
    vector<real> est(exact.size()), cor(exact.size());

    vector<real> data;
    {
        ifstream f;
        f.exceptions(ifstream::badbit);
        f.open(argc > 2 ? argv[2] : "test1.dat");
        copy(istream_iterator<real>(f), istream_iterator<real>(),
             back_inserter(data));
    }

    // Use burg_algorithm to fit an AR model and characterize it completely
    real sigma2e, gain;
    burg_algorithm(data.begin(), data.end(), est.begin(), est.end(),
                   &sigma2e, &gain, cor.begin());

    // Solve Yule-Walker equations using Zohar's algorithm as consistency check
    // Given right hand side containing rho_1, ..., rho_p the solution should
    // be -a_1, ..., -a_p on success so adding to it a_1, ..., a_p gives errors.
    vector<real> rhs(cor);
    zohar_linear_solve(cor.begin(), --cor.end(), cor.begin(), rhs.begin());
    transform(rhs.begin(), rhs.end(), est.begin(), rhs.begin(), plus<real>());
    real res = accumulate(rhs.begin(), rhs.end(), real(0), sum_error<real>());

    printf("%22s %22s %22s\n", "Coefficient", "burg_algorithm", "PercentDiff");
    printf("%22s %22s %22s\n", "-----------", "--------------", "-----------");
    for (vector<real>::const_iterator i = exact.begin(), j = est.begin();
         i != exact.end(); ++i, ++j)
    {
        printf("%22.14g %22.14g %22.14g\n", *i, *j, pdiff(*i, *j));
    }
    printf("\n");
    printf("%22s %22.14g\n", "Yule-Walker residual:", res);
    printf("%22s %22.14g\n", "\\sigma^2_\\epsilon:",  sigma2e);
    printf("%22s %22.14g\n", "signal gain:",          gain);

    return 0;
}
<|endoftext|>


<commit_before>/*
 * test.cpp
 *
 *  Created on: Jan 2, 2017
 *      Author: karl
 */

#include <cv.h>
#include <highgui.h>

using namespace cv;

//#include <stdio>
//#include <dirent.h>
#include <cstdlib>
#include <cmath>
#include <ctgmath>
#include <math.h>       /* sin */
#define PI 3.14159265
using std::cout;
using std::endl;

//points in images (x, y)
class ImagePoint : public Point {
public:
	ImagePoint(int x, int y) {
		this->x = x;
		this->y = y;
	}
};

//points in theta, phi, z.
class AnglePoint {
public:
	AnglePoint(float theta, float phi, float z)
		: theta(theta), phi(phi), z(z)
		{ }
	float theta;
	float phi;
	float z;
};

class LinearEqn {
public:
	float m;
	float b;

	LinearEqn(float m, float b)
			: m(m), b(b) { } // simple constructor
	LinearEqn(const LinearEqn &eqn)
		: m(eqn.m), b(eqn.b) { } // copy constructor
	~LinearEqn() { } // destructor

	float y(float x) {
		return m*x + b;
	}

	Point2f Intersection(LinearEqn eqn) {
		float x = (eqn.b - this->b) / (this->m - eqn.m);
		float y = this->m*x + this->b;
		return Point2f(x,y);
	}
};

// this accounts to creating a type in order to handle a single variable
// wouldn't a vector of vectors work just fine?
//class AnglePointMap: Mat {
//public:
//	AnglePointMap(int height, int numAngles) : Mat(height, numAngles, CV_32FC3) {}
//	void set(int y, int x, AnglePoint pt) {
//
//	}
//	AnglePoint get(int y, int x) {
//
//	}
//};

using AnglePointMap = vector<vector<AnglePoint>>;

//a 2d map of any type. must provide own functionality for resizing
template<typename T>class VectorMap {
public:
	vector<vector<T>> vmap;
	int height;
	int width;

	VectorMap(int height, int width, T defaultFill) : height(height), width(width) {
		vmap.reserve(height);
		for (int h=0; h<height; ++h){
			vmap.push_back( vector<T>(width, defaultFill));
		}
	}
//	VectorMap(&VectorMap obj) : VectorMap(obj.height, obj.width, ) { }

	void set(const int y, const int x, T& pt) {
		vmap.at(y).at(x) = pt;
	}
	T get(const int y, const int x) {
		return vmap.at(y).at(x);
	}
	void doFunc(void (*func)(VectorMap&, VectorMap&, int, int), VectorMap& toMap) { //B //
		for (int h=0; h < height; ++h) {
			for (int w=0; w < width; ++w) {
				func(*this,toMap,h,w); //
			}
		}
	}
};

void funcDoIntersections(VectorMap<LinearEqn>& from, VectorMap<Point2f>& to, int h, int w) { // to
	LinearEqn curr = from.get(h,w);
	LinearEqn next = from.get(h,(w+1)%from.width);

	Point2f intersection = curr.Intersection(next);
	to.set(h,w,intersection);
}

void dispImage(Mat image) {
	namedWindow( "Display Image", CV_WINDOW_AUTOSIZE );
	imshow( "Display Image", image );
	waitKey(0);
}

void dispEdge(const vector<ImagePoint> edges, Mat img, const int centerCol = 0) {
	cout << "edges: " << edges.size() << endl;
	for(auto vert: edges) {
		circle(img, vert, 3, Scalar(0,0,255), 2);
	}
	if (centerCol > 0) {
		for (int r = 0; r<img.rows; ++r) {
			img.at<Vec3b>(r,centerCol) = Vec3b(0,0,255);
		}
	}
	dispImage(img);
}

vector<ImagePoint> detectEdges(const Mat hsv, const int NUMVERTSTEPS, const int CENTERCOL) {
	//Mat detectEdges(Mat hsv) {
	vector<ImagePoint> edges;
	edges.reserve(NUMVERTSTEPS);
	int pixelstep = hsv.rows / NUMVERTSTEPS;

//	int edges[hsv.rows/10] = {};
	//Mat edges (1, hsv.rows/10, CV_16UC2, 0);

	int r = 0, i = 0;
	while (r < hsv.rows) {
		bool found = false;
		for (int c=0; c < hsv.cols; c++) {
			//hue from 205-265, saturation > 50%, value > 30% ?
			Vec3b pt = hsv.at<Vec3b>(r,c);

			//why the hell is the hue value so small? It never goes above 17.
			if (int(pt.val[0]) > 100 && int(pt.val[0]) < 135 &&
					int(pt.val[1]) > 125 &&
					int(pt.val[2]) > 100) {
				//save point
				ImagePoint vert (c,r);
				edges.push_back(vert);
				//edges.at<Point>(i) = vert;

				//skip to next row
				found = true;
				break;
			}
		}
		if (!found) { edges.push_back(ImagePoint(CENTERCOL,r)); }

		i = i + 1;
		r = r + pixelstep;
	}
	return edges;
}

//Certainly not optimized for speed lolz
//also, this is only valid for orthographic views.
vector<Point3f> getCartesion(vector<Point> points, int theta, int centerCol) {
	vector<Point3f> polar;  // r, theta, z representation
	for (auto point: points) {
		Point3f ppt (abs(centerCol - point.x), theta, point.y);
		polar.push_back(ppt);
	}

	vector<Point3f> cartesian;  // x, y, z representation
	for (auto point: polar) {
		Point3f ppt (point.x * cos(point.y * PI / 180.),
				point.x * sin(point.y * PI / 180.),
				point.z);
		polar.push_back(ppt);
	}

	return cartesian;
}

vector<AnglePoint> getThetas(const vector<ImagePoint> edges, const float focalDist, const float phi) {
	vector<AnglePoint> thetas;
	thetas.reserve(edges.size());
	for (auto edge: edges) {
		float theta = atan(edge.x/focalDist);
		thetas.push_back(AnglePoint(theta, phi, edge.y));
	}
	return thetas;
}

//class OrthoFrameGetter {
//public:
//
//};

//vector<string> filenames(const char* dir) {
//	DIR *dirp;
//	int len = strlen(dir);
//	dirp = opendir(".");
//	while ((dp = readdir(dirp)) != NULL)
//		   if (dp->d_namlen == len && !strcmp(dp->d_name, dir)) {
//				   (void)closedir(dirp);
//				   return FOUND;
//		   }
//	(void)closedir(dirp);
//	return NOT_FOUND;
//}

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

	vector<string> filenames = {"0.jpg"}; //, "30.jpg", "60.jpg",
//			"90.jpg", "120.jpg", "150.jpg",
//			"240.jpg", "270.jpg", "300.jpg", "330.jpg"};

	Mat image;
	//image = imread( argv[1], 1 );
	Rect roi (1000,1000,500,500); //user input
	int CENTERCOL = 417; //user input or determined by machine architecture
	int NUMANGLES = filenames.size();
	int NUMVERTSTEPS = 10;
	float FOCALDIST = 200;

	AnglePointMap apMap;
	apMap.reserve(NUMANGLES);

	float phi = 0;
	for (unsigned int i = 0; i < filenames.size(); ++i) {
		// Region of Interest
		image = imread( "pics/"+filenames[i], 1 );
		Mat image_roi(image, Rect(2500, 500, 800, 600)); // x0, y0, w, h
		Mat hsv;
		cvtColor(image_roi, hsv, CV_BGR2HSV);

		//Mat edges = detectEdges(hsv);
		vector<ImagePoint> edges = detectEdges(hsv, NUMVERTSTEPS, CENTERCOL);

		vector<AnglePoint> anglePoints = getThetas(edges, FOCALDIST, phi);
		phi = phi + 30.0;

		apMap.push_back(anglePoints);

		//dispEdge(edges, image_roi, CENTERCOL);
	}

	//now have a 2d vector of AnglePoints. Build the map.
	//VectorMap considers the texture as rolled off. Need to transpose the AnglePoints.
	//This is starting to look an awfull lot like i'm just writing a linear algebra library.
	VectorMap<LinearEqn> eqns (NUMVERTSTEPS, NUMANGLES, LinearEqn(0,0));
	for (int h=0; h<NUMVERTSTEPS; ++h) {
		for (int w=0; w<NUMANGLES; ++w) {
			AnglePoint pt = apMap.at(w).at(h);
			float m = tan(pt.theta);
			float b = m*FOCALDIST;
			LinearEqn thiseqn (m,b);
			eqns.set(h,w, thiseqn);
		}
	}

	//Now have a map of linear equations.. no obvious float range problems so far.
	//Build Intersection Points? Can I do this in the existing map?
	//Give LinearEqn knowledge of its adjacent item?
	VectorMap<Point2f> intersections (NUMVERTSTEPS, NUMANGLES, Point2f(0,0));;
	eqns.doFunc(&funcDoIntersections, intersections); //;, intersections

//	dispEdge(edges, image_roi, centerCol);
//	Mat clipped;
//	inRange(hsv, Scalar(100, 100, 100), Scalar(135,255,255), clipped);
//
//	dispImage(clipped);

	return 0;
}

<commit_msg>Added DoIntersection. Don't forget to add the 3rd dimension to the LinearEqn class...<commit_after>/*
 * test.cpp
 *
 *  Created on: Jan 2, 2017
 *      Author: karl
 */

#include <cv.h>
#include <highgui.h>

using namespace cv;

//#include <stdio>
//#include <dirent.h>
#include <cstdlib>
#include <cmath>
#include <ctgmath>
#include <math.h>       /* sin */
#define PI 3.14159265
using std::cout;
using std::endl;

//points in images (x, y)
class ImagePoint : public Point {
public:
	ImagePoint(int x, int y) {
		this->x = x;
		this->y = y;
	}
};

//points in theta, phi, z.
class AnglePoint {
public:
	AnglePoint(float theta, float phi, float z)
		: theta(theta), phi(phi), z(z)
		{ }
	float theta;
	float phi;
	float z;
};

class LinearEqn {
public:
	float m;
	float b;

	LinearEqn(float m, float b)
			: m(m), b(b) { } // simple constructor
	LinearEqn(const LinearEqn &eqn)
		: m(eqn.m), b(eqn.b) { } // copy constructor
	~LinearEqn() { } // destructor

	float y(float x) {
		return m*x + b;
	}

	Point2f Intersection(LinearEqn eqn) {
		float x = (eqn.b - this->b) / (this->m - eqn.m);
		float y = this->m*x + this->b;
		return Point2f(x,y);
	}
};

// this accounts to creating a type in order to handle a single variable
// wouldn't a vector of vectors work just fine?
//class AnglePointMap: Mat {
//public:
//	AnglePointMap(int height, int numAngles) : Mat(height, numAngles, CV_32FC3) {}
//	void set(int y, int x, AnglePoint pt) {
//
//	}
//	AnglePoint get(int y, int x) {
//
//	}
//};

using AnglePointMap = vector<vector<AnglePoint>>;

//a 2d map of any type. must provide own functionality for resizing
template<typename T>class VectorMap {
public:
	vector<vector<T>> vmap;
	int height;
	int width;

	VectorMap(int height, int width, T defaultFill) : height(height), width(width) {
		vmap.reserve(height);
		for (int h=0; h<height; ++h){
			vmap.push_back( vector<T>(width, defaultFill));
		}
	}
//	VectorMap(&VectorMap obj) : VectorMap(obj.height, obj.width, ) { }

	void set(const int y, const int x, T& pt) {
		vmap.at(y).at(x) = pt;
	}
	T get(const int y, const int x) {
		return vmap.at(y).at(x);
	}
//	void doFunc(VectorMap<Point2f>& toMap, void (*func)(VectorMap&, VectorMap&, int, int) ) { //B //
//		for (int h=0; h < height; ++h) {
//			for (int w=0; w < width; ++w) {
//				func(*this,toMap,h,w); //
//			}
//		}
//	}
};

//void funcDoIntersections(VectorMap<LinearEqn>& from, VectorMap<Point2f>& to, int h, int w) { // to
//	LinearEqn curr = from.get(h,w);
//	LinearEqn next = from.get(h,(w+1)%from.width);
//
//	Point2f intersection = curr.Intersection(next);
//	to.set(h,w,intersection);
//}

void DoIntersection(VectorMap<LinearEqn>& from, VectorMap<Point2f>& to) {
	LinearEqn curr (0,0);
	LinearEqn next (0,0);
	for (int h=0; h < from.height; ++h) {
		for (int w=0; w < from.width; ++w) {
			curr = from.get(h,w);
			next = from.get(h,(w+1)%from.width);

			Point2f intersection = curr.Intersection(next);
			to.set(h,w,intersection);
		}
	}
}

void DoMidpoints(VectorMap<Point2f>& from, VectorMap<Point2f>& to) {

}

void dispImage(Mat image) {
	namedWindow( "Display Image", CV_WINDOW_AUTOSIZE );
	imshow( "Display Image", image );
	waitKey(0);
}

void dispEdge(const vector<ImagePoint> edges, Mat img, const int centerCol = 0) {
	cout << "edges: " << edges.size() << endl;
	for(auto vert: edges) {
		circle(img, vert, 3, Scalar(0,0,255), 2);
	}
	if (centerCol > 0) {
		for (int r = 0; r<img.rows; ++r) {
			img.at<Vec3b>(r,centerCol) = Vec3b(0,0,255);
		}
	}
	dispImage(img);
}

vector<ImagePoint> detectEdges(const Mat hsv, const int NUMVERTSTEPS, const int CENTERCOL) {
	//Mat detectEdges(Mat hsv) {
	vector<ImagePoint> edges;
	edges.reserve(NUMVERTSTEPS);
	int pixelstep = hsv.rows / NUMVERTSTEPS;

//	int edges[hsv.rows/10] = {};
	//Mat edges (1, hsv.rows/10, CV_16UC2, 0);

	int r = 0, i = 0;
	while (r < hsv.rows) {
		bool found = false;
		for (int c=0; c < hsv.cols; c++) {
			//hue from 205-265, saturation > 50%, value > 30% ?
			Vec3b pt = hsv.at<Vec3b>(r,c);

			//why the hell is the hue value so small? It never goes above 17.
			if (int(pt.val[0]) > 100 && int(pt.val[0]) < 135 &&
					int(pt.val[1]) > 125 &&
					int(pt.val[2]) > 100) {
				//save point
				ImagePoint vert (c,r);
				edges.push_back(vert);
				//edges.at<Point>(i) = vert;

				//skip to next row
				found = true;
				break;
			}
		}
		if (!found) { edges.push_back(ImagePoint(CENTERCOL,r)); }

		i = i + 1;
		r = r + pixelstep;
	}
	return edges;
}

//Certainly not optimized for speed lolz
//also, this is only valid for orthographic views.
vector<Point3f> getCartesion(vector<Point> points, int theta, int centerCol) {
	vector<Point3f> polar;  // r, theta, z representation
	for (auto point: points) {
		Point3f ppt (abs(centerCol - point.x), theta, point.y);
		polar.push_back(ppt);
	}

	vector<Point3f> cartesian;  // x, y, z representation
	for (auto point: polar) {
		Point3f ppt (point.x * cos(point.y * PI / 180.),
				point.x * sin(point.y * PI / 180.),
				point.z);
		polar.push_back(ppt);
	}

	return cartesian;
}

vector<AnglePoint> getThetas(const vector<ImagePoint> edges, const float focalDist, const float phi) {
	vector<AnglePoint> thetas;
	thetas.reserve(edges.size());
	for (auto edge: edges) {
		float theta = atan(edge.x/focalDist);
		thetas.push_back(AnglePoint(theta, phi, edge.y));
	}
	return thetas;
}

//class OrthoFrameGetter {
//public:
//
//};

//vector<string> filenames(const char* dir) {
//	DIR *dirp;
//	int len = strlen(dir);
//	dirp = opendir(".");
//	while ((dp = readdir(dirp)) != NULL)
//		   if (dp->d_namlen == len && !strcmp(dp->d_name, dir)) {
//				   (void)closedir(dirp);
//				   return FOUND;
//		   }
//	(void)closedir(dirp);
//	return NOT_FOUND;
//}

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

	vector<string> filenames = {"0.jpg"}; //, "30.jpg", "60.jpg",
//			"90.jpg", "120.jpg", "150.jpg",
//			"240.jpg", "270.jpg", "300.jpg", "330.jpg"};

	Mat image;
	//image = imread( argv[1], 1 );
	Rect roi (1000,1000,500,500); //user input
	int CENTERCOL = 417; //user input or determined by machine architecture
	int NUMANGLES = filenames.size();
	int NUMVERTSTEPS = 10;
	float FOCALDIST = 200;

	AnglePointMap apMap;
	apMap.reserve(NUMANGLES);

	float phi = 0;
	for (unsigned int i = 0; i < filenames.size(); ++i) {
		// Region of Interest
		image = imread( "pics/"+filenames[i], 1 );
		Mat image_roi(image, Rect(2500, 500, 800, 600)); // x0, y0, w, h
		Mat hsv;
		cvtColor(image_roi, hsv, CV_BGR2HSV);

		//Mat edges = detectEdges(hsv);
		vector<ImagePoint> edges = detectEdges(hsv, NUMVERTSTEPS, CENTERCOL);

		vector<AnglePoint> anglePoints = getThetas(edges, FOCALDIST, phi);
		phi = phi + 30.0;

		apMap.push_back(anglePoints);

		//dispEdge(edges, image_roi, CENTERCOL);
	}

	//now have a 2d vector of AnglePoints. Build the map.
	//VectorMap considers the texture as rolled off. Need to transpose the AnglePoints.
	//This is starting to look an awfull lot like i'm just writing a linear algebra library.
	VectorMap<LinearEqn> eqns (NUMVERTSTEPS, NUMANGLES, LinearEqn(0,0));
	for (int h=0; h<NUMVERTSTEPS; ++h) {
		for (int w=0; w<NUMANGLES; ++w) {
			AnglePoint pt = apMap.at(w).at(h);
			float m = tan(pt.theta);
			float b = m*FOCALDIST;
			LinearEqn thiseqn (m,b);
			eqns.set(h,w, thiseqn);
		}
	}

	//Now have a map of linear equations.. no obvious float range problems so far.
	//Build Intersection Points? Can I do this in the existing map?
	//Give LinearEqn knowledge of its adjacent item?
	VectorMap<Point2f> intersections (NUMVERTSTEPS, NUMANGLES, Point2f(0,0));;
	//Beqns.doFunc(intersections, &funcDoIntersections); //;, intersections
	DoIntersection(eqns, intersections);

	VectorMap<Point2f> midpoints (NUMVERTSTEPS, NUMANGLES, Point2f(0,0));;
	DoMidpoints(intersections, midpoints);

//	dispEdge(edges, image_roi, centerCol);
//	Mat clipped;
//	inRange(hsv, Scalar(100, 100, 100), Scalar(135,255,255), clipped);
//
//	dispImage(clipped);

	return 0;
}

<|endoftext|>


<commit_before>#include <QString>
#include <QUrl>
#include "kernel.h"
#include "ilwisdata.h"
#include "ilwisobject.h"
#include "domain.h"
#include "catalog.h"
#include "symboltable.h"
#include "mastercatalog.h"
#include "ilwiscontext.h"
#include "OperationExpression.h"

using namespace Ilwis;

Parameter::Parameter() : _key(sUNDEF), _value(sUNDEF), _type(itUNKNOWN), _domain(sUNDEF) {
}

Parameter::Parameter(const QString &key, const QString &value, IlwisTypes tp, const SymbolTable &symtab) :
    Identity(key),
    _value(value),
    _domain(sUNDEF)
{
    _type = tp;
    if ( _type == itUNKNOWN)
        _type = Parameter::determineType(value, symtab);
}

Parameter::Parameter(const QString &value, IlwisTypes tp, const SymbolTable &symtab) : _domain(sUNDEF)
{
    _value = value;
    _type = tp;
    if ( _type == itUNKNOWN)
        _type = Parameter::determineType(_value, symtab);
}

Ilwis::Parameter::~Parameter()
{
}

QString Parameter::value() const
{
    return _value;
}

QString Parameter::domain() const
{
    return _domain;
}

void Parameter::domain(const QString &dom)
{
    _domain = dom;
}

IlwisTypes Parameter::valuetype() const
{
    return _type;
}

bool Parameter::isEqual(const Parameter &parm) const
{
    return parm.name() == name() && parm.value() == _value;
}

bool Parameter::isValid() const
{
    return !_value.isEmpty();
}

IlwisTypes Parameter::determineType(const QString& value, const SymbolTable &symtab) {
    IlwisTypes tp = IlwisObject::findType(value);
    if ( tp != itUNKNOWN)
        return tp;

    Symbol sym = symtab.getSymbol(value);
    if ( sym.isValid() && sym._type != itUNKNOWN)
        return sym._type;

    QString s = context()->workingCatalog()->resolve(value);
    IlwisTypes type = IlwisObject::findType(s) ;
    if ( type != itUNKNOWN)
        return type;

    if ( value.left(11) == ANONYMOUS_PREFIX) {
        QString sid = value.mid(12);
        bool ok;
        quint64 id = sid.toLongLong(&ok);
        if ( ok) {
            ESPIlwisObject obj =  mastercatalog()->get(id);
            if ( obj.get() != 0)
                return obj->ilwisType();
        }
    }

    tp = Domain::ilwType(value);

    return tp == itUNKNOWN ? itSTRING : tp;

}

//----------------------------------------

OperationExpression::OperationExpression()
{
}

Ilwis::OperationExpression::~OperationExpression()
{
}

OperationExpression::OperationExpression(const QString &e, const SymbolTable &symtab)
{
    setExpression(e, symtab);
}

void OperationExpression::setExpression(const QString &e, const SymbolTable &symtab) {
    _name = "";
    _inParameters.clear();
    _outParameters.clear();
    _type = otFunction;
    QString dummy = e;
    int index1 = e.indexOf(" ");
    int index2 = e.indexOf("=");
    int index3 = e.indexOf("[");
    bool isCommand = index1 != -1 && ( index1 < index2 || index2 == -1);
    if ( isCommand) {
        _type = otCommand;
        for(int i = 0; i < index1; ++i){
            if ( !(e[i].isDigit() || e[i].isLetter() || e[i] == '-')){
                _type = otFunction;
                break;
            }
        }
    }
    else if ( index3 != -1)
        _type = otSelection;

    if ( _type == otFunction) {
        parseFunctionExpression(e, symtab);
    } else if ( _type == otCommand) {
        parseCommandExpression(e, symtab);
    } else if ( _type == otSelection) {
        parseSelectors(e, symtab);
    }
}

void OperationExpression::parseCommandExpression(const QString &e, const SymbolTable &symtab) {
    if ( e.left(6) == "script"){ // special case , all after tyhe script statement is the script text
        _name = "script";
        QString rest = e.mid(7).trimmed();
        _inParameters.push_back(Parameter(rest, itSTRING, symtab));
        return;
    }
    int blockCount = 0;
    int quoteCount = 0;
    int count = 0;
    QList<int> indexes;
    foreach(const QChar& cu, e) {
        char c = cu.toLatin1(); // eessions are not internatiolized, so its allowed
        if ( c == '(' && quoteCount == 0)
            blockCount++;
        if ( c == ')' && quoteCount == 0)
            blockCount--;
        if ( c == '"' && quoteCount == 0)
            quoteCount++;
        else if ( c == '"' && quoteCount != 0)
            quoteCount--;

        if ( c == ' ' && blockCount == 0 && quoteCount == 0)
            indexes.push_back(count++);
        ++count;
    }
    indexes.push_back(count - 1);
    int current = 0;
    foreach(int index, indexes) {
        QString part = e.mid(current, index - current) ;
        part = part.trimmed();
        if ( current == 0)
            _name = part;
        else
            _inParameters.push_back(Parameter(part, itUNKNOWN, symtab));
        current = index;
    }
}

void  OperationExpression::parseSelectors(const QString& e, const SymbolTable &symtab) {
    int index = e.indexOf("[");
    int index2 = e.indexOf("=");
    int index3 = e.indexOf("{");
    QString selectPart = e.mid(index+1, e.size() - index - 2);
    QString inputMap = e.mid(index2+1, index - index2 - 1);
    _inParameters.push_back(Parameter(inputMap, itUNKNOWN, symtab));
    QString outputPart =  index3 == -1 ? e.left(index2) : e.left(index3);
    IlwisTypes valueType =  hasType(_inParameters.back().valuetype(), itCOVERAGE) ? itCOVERAGE : itTABLE;
    _outParameters.push_back(Parameter(outputPart, valueType, symtab));
    int index4=selectPart.indexOf(",");
    if ( index4 == -1) { //either id or number
        bool ok;
        int layer = selectPart.toUInt(&ok);
        if ( ok) {
            _inParameters.push_back(Parameter(QString("\"layer=%1\"").arg(layer),itSTRING,symtab));
        } else {
            _inParameters.push_back(Parameter(QString("\"attribute=%1\"").arg(selectPart), itSTRING, symtab));
        }
    } else {
        QStringList parts = selectPart.split(",");
        if ( parts.size() == 2) {
            _inParameters.push_back(Parameter(QString("\"box=%1\"").arg(selectPart),itSTRING, symtab));
        } else {
           _inParameters.push_back(Parameter(QString("\"polygon=%1\"").arg(selectPart), itSTRING, symtab));
        }
    }
    _name = "selection";

}

void OperationExpression::specialExpressions(const QString &e, const SymbolTable &symtab) {
    //TODO other cases of special expressions
    _name = "assignment";
    _inParameters.push_back(Parameter(e.mid(e.indexOf("=")+1),itCOVERAGE, symtab));

}

void OperationExpression::parseFunctionExpression(const QString &txt, const SymbolTable &symtab) {
    QString e = txt;
    int index = e.indexOf("(");
    if ( index == -1)
        specialExpressions(txt,symtab);

    int index2 = e.indexOf("=");
    if ( index != -1) {
        if ( _name == "") {
            if ( index2 != -1)
                _name = e.mid(index2+1, index - index2 - 1);
            else
                _name = e.left(index);
        }
    }

    QString start = e.left(index2);
    int blockCount = 0;
    int quoteCount = 0;
    int count = 0;
    int cur = 0;
    std::vector<int> indexes;
    if ( index2 != -1) {
        foreach(const QChar& cu, start) {
            char c = cu.toLatin1();
            if ( c == '{' && quoteCount == 0){
                blockCount++;
            }
            if ( c == '}' && quoteCount == 0){
                blockCount--;
            }

            if ( c == ',' || blockCount == 1)
                indexes.push_back(count++);
            ++count;
        }
        qint32 shift = 0;
        indexes.push_back(start.size());
        for(int i =0; i < indexes.size(); ++i) {
            int index3 = indexes[i];
            QString part = start.mid(cur, index3 - cur - shift) ;
            part = part.trimmed();
            _outParameters.push_back(Parameter(part,itUNKNOWN, symtab));
            shift = 1;
            cur = index3 + shift;
        }
    }
    if (index > 0) {
        int len =  e.size() - index - 2;
        QString rest = e.mid(index + 1 , len);
        //indexes.push_back(0);
        indexes.clear();
        blockCount = quoteCount = count = 0;
        foreach(const QChar& cu, rest) {
            char c = cu.toLatin1(); // eessions are not internatiolized, so its allowed
            if ( c == '(' && quoteCount == 0)
                blockCount++;
            if ( c == ')' && quoteCount == 0)
                blockCount--;
            if ( c == '"' && quoteCount == 0)
                quoteCount++;
            else if ( c == '"' && quoteCount != 0)
                quoteCount--;

            if ( c == ',' && blockCount == 0 && quoteCount == 0)
                indexes.push_back(++count);
            else
                ++count;
        }
        cur = 0;
        indexes.push_back(rest.size() + 1);
        for(int i =0; i < indexes.size(); ++i) {
            int index4 = indexes[i];
            QString part = rest.mid(cur, index4 - cur - 1) ;
            part = part.trimmed();
            _inParameters.push_back(Parameter(part,itUNKNOWN, symtab));
            cur = index4;
        }
    }
}

Parameter OperationExpression::parm(int index, bool in) const
{
    const QList<Parameter>& parameters = in ? _inParameters : _outParameters;
    if ( index < parameters.size())
        return parameters[index];

    return Parameter();
}

Parameter OperationExpression::parm(const QString searchValue, bool caseInsensitive, bool in) const
{
    const QList<Parameter>& parameters = in ? _inParameters : _outParameters;
    if ( !searchValue.isEmpty() ) {
        foreach(const Parameter& parm, parameters) {
            QString k2 = _type == otFunction ? parm.name(): parm.value();
            if ( caseInsensitive){
                QString k1 = searchValue.toLower();
                k2 = k2.toLower();
                if ( k1 == k2)
                    return parm;
            } else {
                if ( k2 == searchValue)
                return parm;
            }
        }
    }
    return Parameter();
}

QString OperationExpression::name(bool caseInsensitive) const
{
    if ( caseInsensitive)
        return _name.toLower();
    return  _name;
}

bool OperationExpression::matchesParameterCount(const QString& match, bool in) const {
    int count = parameterCount(in);
    if ( match.right(1) == "+") {
        QString n = match.left(match.size() - 1);
        return count >= n.toInt();
    }
    QStringList parts = match.split("|");
    foreach(const QString& part, parts) {
        bool ok;
        int index = part.toInt(&ok);
        if (!ok) {
            return ERROR0("Illegal metdata definition");
        }
        if ( index == count)
            return true;
    }
    return false;

}

int OperationExpression::parameterCount(bool in) const
{
    const QList<Parameter>& parameters = in ? _inParameters : _outParameters;

    return parameters.size();
}

bool OperationExpression::isValid() const
{
    return !_name.isEmpty();
}

QUrl Ilwis::OperationExpression::metaUrl(bool simple) const
{
    QString url = "ilwis://operations/" + _name;
    if ( !simple) {
        for(int i=0; i < _inParameters.size(); ++i) {
            if ( i == 0)
                url += "?";
            else
                url += "&";

            url += QString("pin::%1::type=%2").arg(i).arg(_outParameters[i].valuetype());
        }
        for(int i=0; i < _outParameters.size(); ++i) {
            if ( i == 0)
                url += "?";
            else
                url += "&";

            url += QString("pout::%1::type=%2").arg(i).arg(_outParameters[i].valuetype());
        }
    }
    return QUrl(url);

}

QString OperationExpression::toString() const
{
    QString expression;
    if ( _type == otFunction) {
        for(const Parameter& parm : _outParameters) {
            if ( expression != "")
                expression += ", ";
            if ( expression == "" )
                expression += "( ";

            expression += parm.value();

        }
        if ( expression != "")
            expression += " ) = ";
        expression += _name;
        expression += "( ";
        int count = 0;
        for(const Parameter& parm : _inParameters) {
            if ( count++ != 0)
                expression += ", ";
            expression += parm.value();
        }
        expression += ")"    ;
    }
    //TODO other cases

    return expression;
}

<commit_msg>solved bug with multiple output parameters<commit_after>#include <QString>
#include <QUrl>
#include "kernel.h"
#include "ilwisdata.h"
#include "ilwisobject.h"
#include "domain.h"
#include "catalog.h"
#include "symboltable.h"
#include "mastercatalog.h"
#include "ilwiscontext.h"
#include "OperationExpression.h"

using namespace Ilwis;

Parameter::Parameter() : _key(sUNDEF), _value(sUNDEF), _type(itUNKNOWN), _domain(sUNDEF) {
}

Parameter::Parameter(const QString &key, const QString &value, IlwisTypes tp, const SymbolTable &symtab) :
    Identity(key),
    _value(value),
    _domain(sUNDEF)
{
    _type = tp;
    if ( _type == itUNKNOWN)
        _type = Parameter::determineType(value, symtab);
}

Parameter::Parameter(const QString &value, IlwisTypes tp, const SymbolTable &symtab) : _domain(sUNDEF)
{
    _value = value;
    _type = tp;
    if ( _type == itUNKNOWN)
        _type = Parameter::determineType(_value, symtab);
}

Ilwis::Parameter::~Parameter()
{
}

QString Parameter::value() const
{
    return _value;
}

QString Parameter::domain() const
{
    return _domain;
}

void Parameter::domain(const QString &dom)
{
    _domain = dom;
}

IlwisTypes Parameter::valuetype() const
{
    return _type;
}

bool Parameter::isEqual(const Parameter &parm) const
{
    return parm.name() == name() && parm.value() == _value;
}

bool Parameter::isValid() const
{
    return !_value.isEmpty();
}

IlwisTypes Parameter::determineType(const QString& value, const SymbolTable &symtab) {
    IlwisTypes tp = IlwisObject::findType(value);
    if ( tp != itUNKNOWN)
        return tp;

    Symbol sym = symtab.getSymbol(value);
    if ( sym.isValid() && sym._type != itUNKNOWN)
        return sym._type;

    QString s = context()->workingCatalog()->resolve(value);
    IlwisTypes type = IlwisObject::findType(s) ;
    if ( type != itUNKNOWN)
        return type;

    if ( value.left(11) == ANONYMOUS_PREFIX) {
        QString sid = value.mid(12);
        bool ok;
        quint64 id = sid.toLongLong(&ok);
        if ( ok) {
            ESPIlwisObject obj =  mastercatalog()->get(id);
            if ( obj.get() != 0)
                return obj->ilwisType();
        }
    }

    tp = Domain::ilwType(value);

    return tp == itUNKNOWN ? itSTRING : tp;

}

//----------------------------------------

OperationExpression::OperationExpression()
{
}

Ilwis::OperationExpression::~OperationExpression()
{
}

OperationExpression::OperationExpression(const QString &e, const SymbolTable &symtab)
{
    setExpression(e, symtab);
}

void OperationExpression::setExpression(const QString &e, const SymbolTable &symtab) {
    _name = "";
    _inParameters.clear();
    _outParameters.clear();
    _type = otFunction;
    QString dummy = e;
    int index1 = e.indexOf(" ");
    int index2 = e.indexOf("=");
    int index3 = e.indexOf("[");
    bool isCommand = index1 != -1 && ( index1 < index2 || index2 == -1);
    if ( isCommand) {
        _type = otCommand;
        for(int i = 0; i < index1; ++i){
            if ( !(e[i].isDigit() || e[i].isLetter() || e[i] == '-')){
                _type = otFunction;
                break;
            }
        }
    }
    else if ( index3 != -1)
        _type = otSelection;

    if ( _type == otFunction) {
        parseFunctionExpression(e, symtab);
    } else if ( _type == otCommand) {
        parseCommandExpression(e, symtab);
    } else if ( _type == otSelection) {
        parseSelectors(e, symtab);
    }
}

void OperationExpression::parseCommandExpression(const QString &e, const SymbolTable &symtab) {
    if ( e.left(6) == "script"){ // special case , all after tyhe script statement is the script text
        _name = "script";
        QString rest = e.mid(7).trimmed();
        _inParameters.push_back(Parameter(rest, itSTRING, symtab));
        return;
    }
    int blockCount = 0;
    int quoteCount = 0;
    int count = 0;
    QList<int> indexes;
    foreach(const QChar& cu, e) {
        char c = cu.toLatin1(); // eessions are not internatiolized, so its allowed
        if ( c == '(' && quoteCount == 0)
            blockCount++;
        if ( c == ')' && quoteCount == 0)
            blockCount--;
        if ( c == '"' && quoteCount == 0)
            quoteCount++;
        else if ( c == '"' && quoteCount != 0)
            quoteCount--;

        if ( c == ' ' && blockCount == 0 && quoteCount == 0)
            indexes.push_back(count++);
        ++count;
    }
    indexes.push_back(count - 1);
    int current = 0;
    foreach(int index, indexes) {
        QString part = e.mid(current, index - current) ;
        part = part.trimmed();
        if ( current == 0)
            _name = part;
        else
            _inParameters.push_back(Parameter(part, itUNKNOWN, symtab));
        current = index;
    }
}

void  OperationExpression::parseSelectors(const QString& e, const SymbolTable &symtab) {
    int index = e.indexOf("[");
    int index2 = e.indexOf("=");
    int index3 = e.indexOf("{");
    QString selectPart = e.mid(index+1, e.size() - index - 2);
    QString inputMap = e.mid(index2+1, index - index2 - 1);
    _inParameters.push_back(Parameter(inputMap, itUNKNOWN, symtab));
    QString outputPart =  index3 == -1 ? e.left(index2) : e.left(index3);
    IlwisTypes valueType =  hasType(_inParameters.back().valuetype(), itCOVERAGE) ? itCOVERAGE : itTABLE;
    _outParameters.push_back(Parameter(outputPart, valueType, symtab));
    int index4=selectPart.indexOf(",");
    if ( index4 == -1) { //either id or number
        bool ok;
        int layer = selectPart.toUInt(&ok);
        if ( ok) {
            _inParameters.push_back(Parameter(QString("\"layer=%1\"").arg(layer),itSTRING,symtab));
        } else {
            _inParameters.push_back(Parameter(QString("\"attribute=%1\"").arg(selectPart), itSTRING, symtab));
        }
    } else {
        QStringList parts = selectPart.split(",");
        if ( parts.size() == 2) {
            _inParameters.push_back(Parameter(QString("\"box=%1\"").arg(selectPart),itSTRING, symtab));
        } else {
           _inParameters.push_back(Parameter(QString("\"polygon=%1\"").arg(selectPart), itSTRING, symtab));
        }
    }
    _name = "selection";

}

void OperationExpression::specialExpressions(const QString &e, const SymbolTable &symtab) {
    //TODO other cases of special expressions
    _name = "assignment";
    _inParameters.push_back(Parameter(e.mid(e.indexOf("=")+1),itCOVERAGE, symtab));

}

void OperationExpression::parseFunctionExpression(const QString &txt, const SymbolTable &symtab) {
    QString e = txt;
    int index = e.indexOf("(");
    if ( index == -1)
        specialExpressions(txt,symtab);

    int index2 = e.indexOf("=");
    if ( index != -1) {
        if ( _name == "") {
            if ( index2 != -1)
                _name = e.mid(index2+1, index - index2 - 1);
            else
                _name = e.left(index);
        }
    }

    QString start = e.left(index2);
    int blockCount = 0;
    int quoteCount = 0;
    int count = 0;
    int cur = 0;
    std::vector<int> indexes;
    if ( index2 != -1) {
        foreach(const QChar& cu, start) {
            char c = cu.toLatin1();
            if ( c == '{' && quoteCount == 0){
                blockCount++;
            }
            if ( c == '}' && quoteCount == 0){
                blockCount--;
            }

            if ( c == ',' || blockCount == 1)
                indexes.push_back(count++);
            ++count;
        }
        qint32 shift = 0;
        indexes.push_back(start.size());
        for(int i =0; i < indexes.size(); ++i) {
            int index3 = indexes[i];
            QString part = start.mid(cur, index3 - cur) ;
            part = part.trimmed();
            Parameter parm(part,itUNKNOWN, symtab);
            _outParameters.push_back(parm);
            shift = 1;
            cur = index3 + shift;
        }
    }
    if (index > 0) {
        int len =  e.size() - index - 2;
        QString rest = e.mid(index + 1 , len);
        //indexes.push_back(0);
        indexes.clear();
        blockCount = quoteCount = count = 0;
        foreach(const QChar& cu, rest) {
            char c = cu.toLatin1(); // eessions are not internatiolized, so its allowed
            if ( c == '(' && quoteCount == 0)
                blockCount++;
            if ( c == ')' && quoteCount == 0)
                blockCount--;
            if ( c == '"' && quoteCount == 0)
                quoteCount++;
            else if ( c == '"' && quoteCount != 0)
                quoteCount--;

            if ( c == ',' && blockCount == 0 && quoteCount == 0)
                indexes.push_back(++count);
            else
                ++count;
        }
        cur = 0;
        indexes.push_back(rest.size() + 1);
        for(int i =0; i < indexes.size(); ++i) {
            int index4 = indexes[i];
            QString part = rest.mid(cur, index4 - cur - 1) ;
            part = part.trimmed();
            _inParameters.push_back(Parameter(part,itUNKNOWN, symtab));
            cur = index4;
        }
    }
}

Parameter OperationExpression::parm(int index, bool in) const
{
    const QList<Parameter>& parameters = in ? _inParameters : _outParameters;
    if ( index < parameters.size())
        return parameters[index];

    return Parameter();
}

Parameter OperationExpression::parm(const QString searchValue, bool caseInsensitive, bool in) const
{
    const QList<Parameter>& parameters = in ? _inParameters : _outParameters;
    if ( !searchValue.isEmpty() ) {
        foreach(const Parameter& parm, parameters) {
            QString k2 = _type == otFunction ? parm.name(): parm.value();
            if ( caseInsensitive){
                QString k1 = searchValue.toLower();
                k2 = k2.toLower();
                if ( k1 == k2)
                    return parm;
            } else {
                if ( k2 == searchValue)
                return parm;
            }
        }
    }
    return Parameter();
}

QString OperationExpression::name(bool caseInsensitive) const
{
    if ( caseInsensitive)
        return _name.toLower();
    return  _name;
}

bool OperationExpression::matchesParameterCount(const QString& match, bool in) const {
    int count = parameterCount(in);
    if ( match.right(1) == "+") {
        QString n = match.left(match.size() - 1);
        return count >= n.toInt();
    }
    QStringList parts = match.split("|");
    foreach(const QString& part, parts) {
        bool ok;
        int index = part.toInt(&ok);
        if (!ok) {
            return ERROR0("Illegal metdata definition");
        }
        if ( index == count)
            return true;
    }
    return false;

}

int OperationExpression::parameterCount(bool in) const
{
    const QList<Parameter>& parameters = in ? _inParameters : _outParameters;

    return parameters.size();
}

bool OperationExpression::isValid() const
{
    return !_name.isEmpty();
}

QUrl Ilwis::OperationExpression::metaUrl(bool simple) const
{
    QString url = "ilwis://operations/" + _name;
    if ( !simple) {
        for(int i=0; i < _inParameters.size(); ++i) {
            if ( i == 0)
                url += "?";
            else
                url += "&";

            url += QString("pin::%1::type=%2").arg(i).arg(_outParameters[i].valuetype());
        }
        for(int i=0; i < _outParameters.size(); ++i) {
            if ( i == 0)
                url += "?";
            else
                url += "&";

            url += QString("pout::%1::type=%2").arg(i).arg(_outParameters[i].valuetype());
        }
    }
    return QUrl(url);

}

QString OperationExpression::toString() const
{
    QString expression;
    if ( _type == otFunction) {
        for(const Parameter& parm : _outParameters) {
            if ( expression != "")
                expression += ", ";
            if ( expression == "" )
                expression += "( ";

            expression += parm.value();

        }
        if ( expression != "")
            expression += " ) = ";
        expression += _name;
        expression += "( ";
        int count = 0;
        for(const Parameter& parm : _inParameters) {
            if ( count++ != 0)
                expression += ", ";
            expression += parm.value();
        }
        expression += ")"    ;
    }
    //TODO other cases

    return expression;
}

<|endoftext|>