<commit_before>//=============================================================================================================
/**
* @file     mainwindow.cpp
* @author   Christoph Dinh <chdinh@nmr.mgh.harvard.edu>;
*           Lorenz Esch <Lorenz.Esch@tu-ilmenau.de>;
*           Matti Hamalainen <msh@nmr.mgh.harvard.edu>
* @version  1.0
* @date     January, 2017
*
* @section  LICENSE
*
* Copyright (C) 2017 Christoph Dinh, Lorenz Esch and Matti Hamalainen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that
* the following conditions are met:
*     * Redistributions of source code must retain the above copyright notice, this list of conditions and the
*       following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
*       the following disclaimer in the documentation and/or other materials provided with the distribution.
*     * Neither the name of MNE-CPP authors nor the names of its contributors may be used
*       to endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*
* @brief    Contains the implementation of the MainWindow class.
*
*/
//*************************************************************************************************************
//=============================================================================================================
// INCLUDES
//=============================================================================================================

#include "info.h"
#include "mainwindow.h"
#include "mdiview.h"
#include "../libs/anShared/Interfaces/IExtension.h"
#include "../libs/anShared/Management/analyzesettings.h"
#include "../libs/anShared/Management/analyzedata.h"
#include "../libs/anShared/Management/extensionmanager.h"

//*************************************************************************************************************
//=============================================================================================================
// QT INCLUDES
//=============================================================================================================

#include <QtWidgets>
#include <QMenu>
#include <QMenuBar>
#include <QDockWidget>
#include <QAction>
#include <QLabel>
#include <QTextEdit>
#include <QFileDialog>
#include <QtWidgets/QGridLayout>
#include <QStandardPaths>

//*************************************************************************************************************
//=============================================================================================================
// USED NAMESPACES
//=============================================================================================================

using namespace MNEANALYZE;
using namespace ANSHAREDLIB;

//*************************************************************************************************************
//=============================================================================================================
// CONST
//=============================================================================================================

const char* extensionsDir = "/mne_analyze_extensions";        /**< holds path to the extensions.*/

//*************************************************************************************************************
//=============================================================================================================
// DEFINE MEMBER METHODS
//=============================================================================================================

MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, m_pExtensionManager(new ANSHAREDLIB::ExtensionManager(this))
, m_pMdiView(Q_NULLPTR)
{
    fprintf(stderr, "%s - Version %s\n",
            CInfo::AppNameShort().toUtf8().constData(),
            CInfo::AppVersion().toUtf8().constData());

    setWindowState(Qt::WindowMaximized);
    setMinimumSize(400, 400);
    setWindowTitle(CInfo::AppNameShort());

    initGlobalSettings();
    initGlobalData();
    m_pExtensionManager->loadExtension(qApp->applicationDirPath()+extensionsDir);
    m_pExtensionManager->initExtensions(m_analyzeSettings, m_analyzeData);

    createActions();
    createMenus();
    createDockWindows();

    createMdiView();
}

//*************************************************************************************************************

MainWindow::~MainWindow()
{

}

//*************************************************************************************************************

void MainWindow::initGlobalSettings()
{
    m_analyzeSettings = AnalyzeSettings::SPtr(new AnalyzeSettings);
}

//*************************************************************************************************************

void MainWindow::initGlobalData()
{
    m_analyzeData = AnalyzeData::SPtr(new AnalyzeData);
}

//*************************************************************************************************************

void MainWindow::createActions()
{
    //File QMenu
    m_pActionOpenDataFile = new QAction(tr("&Open Fiff File"), this);
    m_pActionOpenDataFile->setShortcuts(QKeySequence::New);
    m_pActionOpenDataFile->setStatusTip(tr("Opens a Fiff File"));
    connect(m_pActionOpenDataFile, &QAction::triggered, this, &MainWindow::openFiffFile);

    m_pActionExit = new QAction(tr("E&xit"), this);
    m_pActionExit->setShortcuts(QKeySequence::Quit);
    m_pActionExit->setStatusTip(tr("Exit the application"));
    connect(m_pActionExit, &QAction::triggered, this, &MainWindow::close);

    //View QMenu
    m_pActionCascade = new QAction(tr("&Cascade"), this);
    m_pActionCascade->setStatusTip(tr("Cascade the windows in the mdi window"));
    connect(m_pActionCascade, &QAction::triggered, this->m_pMdiView, &MdiView::cascadeSubWindows);

    m_pActionTile = new QAction(tr("&Tile"), this);
    m_pActionTile->setStatusTip(tr("Tile the windows in the mdi window"));
    connect(m_pActionTile, &QAction::triggered, this->m_pMdiView, &MdiView::tileSubWindows);

    //Help QMenu
    m_pActionAbout = new QAction(tr("&About"), this);
    m_pActionAbout->setStatusTip(tr("Show the application's About box"));
    connect(m_pActionAbout, &QAction::triggered, this, &MainWindow::about);
}

//*************************************************************************************************************

void MainWindow::createMenus()
{
    m_pMenuFile = menuBar()->addMenu(tr("&File"));
    m_pMenuFile->addAction(m_pActionOpenDataFile);
    m_pMenuFile->addSeparator();
    m_pMenuFile->addAction(m_pActionExit);

    m_pMenuView = menuBar()->addMenu(tr("&View"));
    m_pMenuView->addAction(m_pActionCascade);
    m_pMenuView->addAction(m_pActionTile);

    menuBar()->addSeparator();

    m_pMenuHelp = menuBar()->addMenu(tr("&Help"));
    m_pMenuHelp->addAction(m_pActionAbout);
}

//*************************************************************************************************************

void MainWindow::createDockWindows()
{
    //Add Extension views to mdi
    for(int i = 0; i < m_pExtensionManager->getExtensions().size(); ++i) {
        IExtension* extension = m_pExtensionManager->getExtensions()[i];
        if(extension->hasControl() && extension->getControl()) {
            addDockWidget(Qt::LeftDockWidgetArea,extension->getControl());
        }
    }
}

//*************************************************************************************************************

void MainWindow::createMdiView()
{
    m_pMdiView = new MdiView(this);
    setCentralWidget(m_pMdiView);

    //Add Extension views to mdi
    for(int i = 0; i < m_pExtensionManager->getExtensions().size(); ++i) {
        IExtension* extension = m_pExtensionManager->getExtensions()[i];
        if(extension->hasView() && extension->getView()) {
            m_pMdiView->addSubWindow(extension->getView());
        }
    }

    m_pMdiView->cascadeSubWindows();
}

//*************************************************************************************************************

void MainWindow::openFiffFile()
{
    //Open a FIFF file

    //Get the path
    m_fiffFileName = QFileDialog::getOpenFileName(this,
                                                    ("Open File"),
                                                    "C:/",
                                                    ("fiff File(*.fiff)"));
    //Open file
    QFile m_fiffFile(m_fiffFileName);
}

//*************************************************************************************************************

void MainWindow::about()
{
    if(!m_pAboutWindow) {
        m_pAboutWindow = QSharedPointer<QWidget>(new QWidget());

        QGridLayout *gridLayout;
        QLabel *m_label_splashcreen;
        QTextEdit *m_textEdit_aboutText;

        m_pAboutWindow->setObjectName(QStringLiteral("AboutWindow"));
        m_pAboutWindow->resize(541, 708);
        QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
        sizePolicy.setHorizontalStretch(0);
        sizePolicy.setVerticalStretch(0);
        sizePolicy.setHeightForWidth(m_pAboutWindow->sizePolicy().hasHeightForWidth());
        m_pAboutWindow->setSizePolicy(sizePolicy);
        m_pAboutWindow->setMinimumSize(QSize(541, 708));
        m_pAboutWindow->setMaximumSize(QSize(541, 708));
        gridLayout = new QGridLayout(m_pAboutWindow.data());
        gridLayout->setObjectName(QStringLiteral("gridLayout"));
        m_label_splashcreen = new QLabel(m_pAboutWindow.data());
        m_label_splashcreen->setObjectName(QStringLiteral("m_label_splashcreen"));
        QSizePolicy sizePolicy1(QSizePolicy::Preferred, QSizePolicy::Preferred);
        sizePolicy1.setHorizontalStretch(0);
        sizePolicy1.setVerticalStretch(0);
        sizePolicy1.setHeightForWidth(m_label_splashcreen->sizePolicy().hasHeightForWidth());
        m_label_splashcreen->setSizePolicy(sizePolicy1);
        m_label_splashcreen->setMinimumSize(QSize(0, 0));
        m_label_splashcreen->setPixmap(QPixmap(QString::fromUtf8(":/images/splashscreen_mne_analyze.png")));
        m_label_splashcreen->setScaledContents(true);

        gridLayout->addWidget(m_label_splashcreen, 0, 0, 1, 1);

        m_textEdit_aboutText = new QTextEdit(m_pAboutWindow.data());
        m_textEdit_aboutText->setObjectName(QStringLiteral("m_textEdit_aboutText"));
        m_textEdit_aboutText->setEnabled(true);
        m_textEdit_aboutText->setReadOnly(true);
        m_textEdit_aboutText->setOverwriteMode(true);
        m_textEdit_aboutText->setTextInteractionFlags(Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse);

        gridLayout->addWidget(m_textEdit_aboutText, 1, 0, 1, 1);

        m_pAboutWindow->setWindowTitle(tr("About"));
        m_label_splashcreen->setText(QString());
        m_textEdit_aboutText->setHtml( tr("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
                                          "<meta name=\"qrichtext\" content=\"1\" />\n"
                                          "
Copyright (C) 2017 Christoph Dinh, Lorenz Esch, Matti Hamalainen. All rights reserved.
\n"
                                          "

\n"
                                          "
For more information visit the MNE-CPP/MNE Analyze project on its homepage:
\n"
                                          "

\n"
                                          "
http://www.mne-cpp.org
\n"
                                          "

\n"
                                          "
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\n"
                                          "

\n"
                                          "
Redistribution and use in source and binary forms, with or without modification, are permitted provided tha the following conditions are met:
\n"
                                          "

\n"
                                          "
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaime. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of MNE-CPP authors nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
"));

        m_pAboutWindow->setLayout(gridLayout);
    }

    m_pAboutWindow->show();
}
<commit_msg>[LIB-145] Fix MNE Analyze Initialization<commit_after>//=============================================================================================================
/**
* @file     mainwindow.cpp
* @author   Christoph Dinh <chdinh@nmr.mgh.harvard.edu>;
*           Lorenz Esch <Lorenz.Esch@tu-ilmenau.de>;
*           Matti Hamalainen <msh@nmr.mgh.harvard.edu>
* @version  1.0
* @date     January, 2017
*
* @section  LICENSE
*
* Copyright (C) 2017 Christoph Dinh, Lorenz Esch and Matti Hamalainen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that
* the following conditions are met:
*     * Redistributions of source code must retain the above copyright notice, this list of conditions and the
*       following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
*       the following disclaimer in the documentation and/or other materials provided with the distribution.
*     * Neither the name of MNE-CPP authors nor the names of its contributors may be used
*       to endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*
* @brief    Contains the implementation of the MainWindow class.
*
*/
//*************************************************************************************************************
//=============================================================================================================
// INCLUDES
//=============================================================================================================

#include "info.h"
#include "mainwindow.h"
#include "mdiview.h"
#include "../libs/anShared/Interfaces/IExtension.h"
#include "../libs/anShared/Management/analyzesettings.h"
#include "../libs/anShared/Management/analyzedata.h"
#include "../libs/anShared/Management/extensionmanager.h"

//*************************************************************************************************************
//=============================================================================================================
// QT INCLUDES
//=============================================================================================================

#include <QtWidgets>
#include <QMenu>
#include <QMenuBar>
#include <QDockWidget>
#include <QAction>
#include <QLabel>
#include <QTextEdit>
#include <QFileDialog>
#include <QtWidgets/QGridLayout>
#include <QStandardPaths>

//*************************************************************************************************************
//=============================================================================================================
// USED NAMESPACES
//=============================================================================================================

using namespace MNEANALYZE;
using namespace ANSHAREDLIB;

//*************************************************************************************************************
//=============================================================================================================
// CONST
//=============================================================================================================

const char* extensionsDir = "/mne_analyze_extensions";        /**< holds path to the extensions.*/

//*************************************************************************************************************
//=============================================================================================================
// DEFINE MEMBER METHODS
//=============================================================================================================

MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, m_pExtensionManager(new ANSHAREDLIB::ExtensionManager(this))
, m_pMdiView(Q_NULLPTR)
{
    fprintf(stderr, "%s - Version %s\n",
            CInfo::AppNameShort().toUtf8().constData(),
            CInfo::AppVersion().toUtf8().constData());

    setWindowState(Qt::WindowMaximized);
    setMinimumSize(400, 400);
    setWindowTitle(CInfo::AppNameShort());

    initGlobalSettings();
    initGlobalData();
    m_pExtensionManager->loadExtension(qApp->applicationDirPath()+extensionsDir);
    m_pExtensionManager->initExtensions(m_analyzeSettings, m_analyzeData);

    createDockWindows();
    createMdiView();

    createActions();
    createMenus();
}

//*************************************************************************************************************

MainWindow::~MainWindow()
{

}

//*************************************************************************************************************

void MainWindow::initGlobalSettings()
{
    m_analyzeSettings = AnalyzeSettings::SPtr(new AnalyzeSettings);
}

//*************************************************************************************************************

void MainWindow::initGlobalData()
{
    m_analyzeData = AnalyzeData::SPtr(new AnalyzeData);
}

//*************************************************************************************************************

void MainWindow::createActions()
{
    //File QMenu
    m_pActionOpenDataFile = new QAction(tr("&Open Fiff File"), this);
    m_pActionOpenDataFile->setShortcuts(QKeySequence::New);
    m_pActionOpenDataFile->setStatusTip(tr("Opens a Fiff File"));
    connect(m_pActionOpenDataFile, &QAction::triggered, this, &MainWindow::openFiffFile);

    m_pActionExit = new QAction(tr("E&xit"), this);
    m_pActionExit->setShortcuts(QKeySequence::Quit);
    m_pActionExit->setStatusTip(tr("Exit the application"));
    connect(m_pActionExit, &QAction::triggered, this, &MainWindow::close);

    //View QMenu
    m_pActionCascade = new QAction(tr("&Cascade"), this);
    m_pActionCascade->setStatusTip(tr("Cascade the windows in the mdi window"));
    connect(m_pActionCascade, &QAction::triggered, this->m_pMdiView, &MdiView::cascadeSubWindows);

    m_pActionTile = new QAction(tr("&Tile"), this);
    m_pActionTile->setStatusTip(tr("Tile the windows in the mdi window"));
    connect(m_pActionTile, &QAction::triggered, this->m_pMdiView, &MdiView::tileSubWindows);

    //Help QMenu
    m_pActionAbout = new QAction(tr("&About"), this);
    m_pActionAbout->setStatusTip(tr("Show the application's About box"));
    connect(m_pActionAbout, &QAction::triggered, this, &MainWindow::about);
}

//*************************************************************************************************************

void MainWindow::createMenus()
{
    m_pMenuFile = menuBar()->addMenu(tr("&File"));
    m_pMenuFile->addAction(m_pActionOpenDataFile);
    m_pMenuFile->addSeparator();
    m_pMenuFile->addAction(m_pActionExit);

    m_pMenuView = menuBar()->addMenu(tr("&View"));
    m_pMenuView->addAction(m_pActionCascade);
    m_pMenuView->addAction(m_pActionTile);

    menuBar()->addSeparator();

    m_pMenuHelp = menuBar()->addMenu(tr("&Help"));
    m_pMenuHelp->addAction(m_pActionAbout);
}

//*************************************************************************************************************

void MainWindow::createDockWindows()
{
    //Add Extension views to mdi
    for(int i = 0; i < m_pExtensionManager->getExtensions().size(); ++i) {
        IExtension* extension = m_pExtensionManager->getExtensions()[i];
        if(extension->hasControl() && extension->getControl()) {
            addDockWidget(Qt::LeftDockWidgetArea,extension->getControl());
        }
    }
}

//*************************************************************************************************************

void MainWindow::createMdiView()
{
    m_pMdiView = new MdiView(this);
    setCentralWidget(m_pMdiView);

    //Add Extension views to mdi
    for(int i = 0; i < m_pExtensionManager->getExtensions().size(); ++i) {
        IExtension* extension = m_pExtensionManager->getExtensions()[i];
        if(extension->hasView() && extension->getView()) {
            m_pMdiView->addSubWindow(extension->getView());
        }
    }

    m_pMdiView->cascadeSubWindows();
}

//*************************************************************************************************************

void MainWindow::openFiffFile()
{
    //Open a FIFF file

    //Get the path
    m_fiffFileName = QFileDialog::getOpenFileName(this,
                                                    ("Open File"),
                                                    "C:/",
                                                    ("fiff File(*.fiff)"));
    //Open file
    QFile m_fiffFile(m_fiffFileName);
}

//*************************************************************************************************************

void MainWindow::about()
{
    if(!m_pAboutWindow) {
        m_pAboutWindow = QSharedPointer<QWidget>(new QWidget());

        QGridLayout *gridLayout;
        QLabel *m_label_splashcreen;
        QTextEdit *m_textEdit_aboutText;

        m_pAboutWindow->setObjectName(QStringLiteral("AboutWindow"));
        m_pAboutWindow->resize(541, 708);
        QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
        sizePolicy.setHorizontalStretch(0);
        sizePolicy.setVerticalStretch(0);
        sizePolicy.setHeightForWidth(m_pAboutWindow->sizePolicy().hasHeightForWidth());
        m_pAboutWindow->setSizePolicy(sizePolicy);
        m_pAboutWindow->setMinimumSize(QSize(541, 708));
        m_pAboutWindow->setMaximumSize(QSize(541, 708));
        gridLayout = new QGridLayout(m_pAboutWindow.data());
        gridLayout->setObjectName(QStringLiteral("gridLayout"));
        m_label_splashcreen = new QLabel(m_pAboutWindow.data());
        m_label_splashcreen->setObjectName(QStringLiteral("m_label_splashcreen"));
        QSizePolicy sizePolicy1(QSizePolicy::Preferred, QSizePolicy::Preferred);
        sizePolicy1.setHorizontalStretch(0);
        sizePolicy1.setVerticalStretch(0);
        sizePolicy1.setHeightForWidth(m_label_splashcreen->sizePolicy().hasHeightForWidth());
        m_label_splashcreen->setSizePolicy(sizePolicy1);
        m_label_splashcreen->setMinimumSize(QSize(0, 0));
        m_label_splashcreen->setPixmap(QPixmap(QString::fromUtf8(":/images/splashscreen_mne_analyze.png")));
        m_label_splashcreen->setScaledContents(true);

        gridLayout->addWidget(m_label_splashcreen, 0, 0, 1, 1);

        m_textEdit_aboutText = new QTextEdit(m_pAboutWindow.data());
        m_textEdit_aboutText->setObjectName(QStringLiteral("m_textEdit_aboutText"));
        m_textEdit_aboutText->setEnabled(true);
        m_textEdit_aboutText->setReadOnly(true);
        m_textEdit_aboutText->setOverwriteMode(true);
        m_textEdit_aboutText->setTextInteractionFlags(Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse);

        gridLayout->addWidget(m_textEdit_aboutText, 1, 0, 1, 1);

        m_pAboutWindow->setWindowTitle(tr("About"));
        m_label_splashcreen->setText(QString());
        m_textEdit_aboutText->setHtml( tr("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
                                          "<meta name=\"qrichtext\" content=\"1\" />\n"
                                          "
Copyright (C) 2017 Christoph Dinh, Lorenz Esch, Matti Hamalainen. All rights reserved.
\n"
                                          "

\n"
                                          "
For more information visit the MNE-CPP/MNE Analyze project on its homepage:
\n"
                                          "

\n"
                                          "
http://www.mne-cpp.org
\n"
                                          "

\n"
                                          "
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\n"
                                          "

\n"
                                          "
Redistribution and use in source and binary forms, with or without modification, are permitted provided tha the following conditions are met:
\n"
                                          "

\n"
                                          "
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaime. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of MNE-CPP authors nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
"));

        m_pAboutWindow->setLayout(gridLayout);
    }

    m_pAboutWindow->show();
}
<|endoftext|>


<commit_before>//===-- lib/MC/Disassembler.cpp - Disassembler Public C Interface ---------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "Disassembler.h"
#include "llvm-c/Disassembler.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDisassembler.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstPrinter.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCRelocationInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/MCSymbolizer.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/TargetRegistry.h"

using namespace llvm;

// LLVMCreateDisasm() creates a disassembler for the TripleName.  Symbolic
// disassembly is supported by passing a block of information in the DisInfo
// parameter and specifying the TagType and callback functions as described in
// the header llvm-c/Disassembler.h .  The pointer to the block and the
// functions can all be passed as NULL.  If successful, this returns a
// disassembler context.  If not, it returns NULL.
//
LLVMDisasmContextRef
LLVMCreateDisasmCPUFeatures(const char *Triple, const char *CPU,
                            const char *Features, void *DisInfo, int TagType,
                            LLVMOpInfoCallback GetOpInfo,
                            LLVMSymbolLookupCallback SymbolLookUp) {
  // Get the target.
  std::string Error;
  const Target *TheTarget = TargetRegistry::lookupTarget(Triple, Error);
  if (!TheTarget)
    return nullptr;

  const MCRegisterInfo *MRI = TheTarget->createMCRegInfo(Triple);
  if (!MRI)
    return nullptr;

  // Get the assembler info needed to setup the MCContext.
  const MCAsmInfo *MAI = TheTarget->createMCAsmInfo(*MRI, Triple);
  if (!MAI)
    return nullptr;

  const MCInstrInfo *MII = TheTarget->createMCInstrInfo();
  if (!MII)
    return nullptr;

  const MCSubtargetInfo *STI = TheTarget->createMCSubtargetInfo(Triple, CPU,
                                                                Features);
  if (!STI)
    return nullptr;

  // Set up the MCContext for creating symbols and MCExpr's.
  MCContext *Ctx = new MCContext(MAI, MRI, nullptr);
  if (!Ctx)
    return nullptr;

  // Set up disassembler.
  MCDisassembler *DisAsm = TheTarget->createMCDisassembler(*STI, *Ctx);
  if (!DisAsm)
    return nullptr;

  std::unique_ptr<MCRelocationInfo> RelInfo(
      TheTarget->createMCRelocationInfo(Triple, *Ctx));
  if (!RelInfo)
    return nullptr;

  std::unique_ptr<MCSymbolizer> Symbolizer(TheTarget->createMCSymbolizer(
      Triple, GetOpInfo, SymbolLookUp, DisInfo, Ctx, RelInfo.release()));
  DisAsm->setSymbolizer(std::move(Symbolizer));

  // Set up the instruction printer.
  int AsmPrinterVariant = MAI->getAssemblerDialect();
  MCInstPrinter *IP = TheTarget->createMCInstPrinter(AsmPrinterVariant,
                                                     *MAI, *MII, *MRI, *STI);
  if (!IP)
    return nullptr;

  LLVMDisasmContext *DC = new LLVMDisasmContext(Triple, DisInfo, TagType,
                                                GetOpInfo, SymbolLookUp,
                                                TheTarget, MAI, MRI,
                                                STI, MII, Ctx, DisAsm, IP);
  if (!DC)
    return nullptr;

  DC->setCPU(CPU);
  return DC;
}

LLVMDisasmContextRef LLVMCreateDisasmCPU(const char *Triple, const char *CPU,
                                         void *DisInfo, int TagType,
                                         LLVMOpInfoCallback GetOpInfo,
                                         LLVMSymbolLookupCallback SymbolLookUp){
  return LLVMCreateDisasmCPUFeatures(Triple, CPU, "", DisInfo, TagType,
                                     GetOpInfo, SymbolLookUp);
}

LLVMDisasmContextRef LLVMCreateDisasm(const char *Triple, void *DisInfo,
                                      int TagType, LLVMOpInfoCallback GetOpInfo,
                                      LLVMSymbolLookupCallback SymbolLookUp) {
  return LLVMCreateDisasmCPUFeatures(Triple, "", "", DisInfo, TagType,
                                     GetOpInfo, SymbolLookUp);
}

//
// LLVMDisasmDispose() disposes of the disassembler specified by the context.
//
void LLVMDisasmDispose(LLVMDisasmContextRef DCR){
  LLVMDisasmContext *DC = (LLVMDisasmContext *)DCR;
  delete DC;
}

/// \brief Emits the comments that are stored in \p DC comment stream.
/// Each comment in the comment stream must end with a newline.
static void emitComments(LLVMDisasmContext *DC,
                         formatted_raw_ostream &FormattedOS) {
  // Flush the stream before taking its content.
  DC->CommentStream.flush();
  StringRef Comments = DC->CommentsToEmit.str();
  // Get the default information for printing a comment.
  const MCAsmInfo *MAI = DC->getAsmInfo();
  const char *CommentBegin = MAI->getCommentString();
  unsigned CommentColumn = MAI->getCommentColumn();
  bool IsFirst = true;
  while (!Comments.empty()) {
    if (!IsFirst)
      FormattedOS << '\n';
    // Emit a line of comments.
    FormattedOS.PadToColumn(CommentColumn);
    size_t Position = Comments.find('\n');
    FormattedOS << CommentBegin << ' ' << Comments.substr(0, Position);
    // Move after the newline character.
    Comments = Comments.substr(Position+1);
    IsFirst = false;
  }
  FormattedOS.flush();

  // Tell the comment stream that the vector changed underneath it.
  DC->CommentsToEmit.clear();
  DC->CommentStream.resync();
}

/// \brief Gets latency information for \p Inst form the itinerary
/// scheduling model, based on \p DC information.
/// \return The maximum expected latency over all the operands or -1
/// if no information are available.
static int getItineraryLatency(LLVMDisasmContext *DC, const MCInst &Inst) {
  const int NoInformationAvailable = -1;

  // Check if we have a CPU to get the itinerary information.
  if (DC->getCPU().empty())
    return NoInformationAvailable;

  // Get itinerary information.
  const MCSubtargetInfo *STI = DC->getSubtargetInfo();
  InstrItineraryData IID = STI->getInstrItineraryForCPU(DC->getCPU());
  // Get the scheduling class of the requested instruction.
  const MCInstrDesc& Desc = DC->getInstrInfo()->get(Inst.getOpcode());
  unsigned SCClass = Desc.getSchedClass();

  int Latency = 0;
  for (unsigned OpIdx = 0, OpIdxEnd = Inst.getNumOperands(); OpIdx != OpIdxEnd;
       ++OpIdx)
    Latency = std::max(Latency, IID.getOperandCycle(SCClass, OpIdx));

  return Latency;
}

/// \brief Gets latency information for \p Inst, based on \p DC information.
/// \return The maximum expected latency over all the definitions or -1
/// if no information are available.
static int getLatency(LLVMDisasmContext *DC, const MCInst &Inst) {
  // Try to compute scheduling information.
  const MCSubtargetInfo *STI = DC->getSubtargetInfo();
  const MCSchedModel SCModel = STI->getSchedModel();
  const int NoInformationAvailable = -1;

  // Check if we have a scheduling model for instructions.
  if (!SCModel.hasInstrSchedModel())
    // Try to fall back to the itinerary model if the scheduling model doesn't
    // have a scheduling table.  Note the default does not have a table.
    return getItineraryLatency(DC, Inst);

  // Get the scheduling class of the requested instruction.
  const MCInstrDesc& Desc = DC->getInstrInfo()->get(Inst.getOpcode());
  unsigned SCClass = Desc.getSchedClass();
  const MCSchedClassDesc *SCDesc = SCModel.getSchedClassDesc(SCClass);
  // Resolving the variant SchedClass requires an MI to pass to
  // SubTargetInfo::resolveSchedClass.
  if (!SCDesc || !SCDesc->isValid() || SCDesc->isVariant())
    return NoInformationAvailable;

  // Compute output latency.
  int Latency = 0;
  for (unsigned DefIdx = 0, DefEnd = SCDesc->NumWriteLatencyEntries;
       DefIdx != DefEnd; ++DefIdx) {
    // Lookup the definition's write latency in SubtargetInfo.
    const MCWriteLatencyEntry *WLEntry = STI->getWriteLatencyEntry(SCDesc,
                                                                   DefIdx);
    Latency = std::max(Latency, WLEntry->Cycles);
  }

  return Latency;
}

/// \brief Emits latency information in DC->CommentStream for \p Inst, based
/// on the information available in \p DC.
static void emitLatency(LLVMDisasmContext *DC, const MCInst &Inst) {
  int Latency = getLatency(DC, Inst);

  // Report only interesting latency.
  if (Latency < 2)
    return;

  DC->CommentStream << "Latency: " << Latency << '\n';
}

//
// LLVMDisasmInstruction() disassembles a single instruction using the
// disassembler context specified in the parameter DC.  The bytes of the
// instruction are specified in the parameter Bytes, and contains at least
// BytesSize number of bytes.  The instruction is at the address specified by
// the PC parameter.  If a valid instruction can be disassembled its string is
// returned indirectly in OutString which whos size is specified in the
// parameter OutStringSize.  This function returns the number of bytes in the
// instruction or zero if there was no valid instruction.  If this function
// returns zero the caller will have to pick how many bytes they want to step
// over by printing a .byte, .long etc. to continue.
//
size_t LLVMDisasmInstruction(LLVMDisasmContextRef DCR, uint8_t *Bytes,
                             uint64_t BytesSize, uint64_t PC, char *OutString,
                             size_t OutStringSize){
  LLVMDisasmContext *DC = (LLVMDisasmContext *)DCR;
  // Wrap the pointer to the Bytes, BytesSize and PC in a MemoryObject.
  ArrayRef<uint8_t> Data(Bytes, BytesSize);

  uint64_t Size;
  MCInst Inst;
  const MCDisassembler *DisAsm = DC->getDisAsm();
  MCInstPrinter *IP = DC->getIP();
  MCDisassembler::DecodeStatus S;
  SmallVector<char, 64> InsnStr;
  raw_svector_ostream Annotations(InsnStr);
  S = DisAsm->getInstruction(Inst, Size, Data, PC,
                             /*REMOVE*/ nulls(), Annotations);
  switch (S) {
  case MCDisassembler::Fail:
  case MCDisassembler::SoftFail:
    // FIXME: Do something different for soft failure modes?
    return 0;

  case MCDisassembler::Success: {
    Annotations.flush();
    StringRef AnnotationsStr = Annotations.str();

    SmallVector<char, 64> InsnStr;
    raw_svector_ostream OS(InsnStr);
    formatted_raw_ostream FormattedOS(OS);
    IP->printInst(&Inst, FormattedOS, AnnotationsStr);

    if (DC->getOptions() & LLVMDisassembler_Option_PrintLatency)
      emitLatency(DC, Inst);

    emitComments(DC, FormattedOS);
    OS.flush();

    assert(OutStringSize != 0 && "Output buffer cannot be zero size");
    size_t OutputSize = std::min(OutStringSize-1, InsnStr.size());
    std::memcpy(OutString, InsnStr.data(), OutputSize);
    OutString[OutputSize] = '\0'; // Terminate string.

    return Size;
  }
  }
  llvm_unreachable("Invalid DecodeStatus!");
}

//
// LLVMSetDisasmOptions() sets the disassembler's options.  It returns 1 if it
// can set all the Options and 0 otherwise.
//
int LLVMSetDisasmOptions(LLVMDisasmContextRef DCR, uint64_t Options){
  if (Options & LLVMDisassembler_Option_UseMarkup){
      LLVMDisasmContext *DC = (LLVMDisasmContext *)DCR;
      MCInstPrinter *IP = DC->getIP();
      IP->setUseMarkup(1);
      DC->addOptions(LLVMDisassembler_Option_UseMarkup);
      Options &= ~LLVMDisassembler_Option_UseMarkup;
  }
  if (Options & LLVMDisassembler_Option_PrintImmHex){
      LLVMDisasmContext *DC = (LLVMDisasmContext *)DCR;
      MCInstPrinter *IP = DC->getIP();
      IP->setPrintImmHex(1);
      DC->addOptions(LLVMDisassembler_Option_PrintImmHex);
      Options &= ~LLVMDisassembler_Option_PrintImmHex;
  }
  if (Options & LLVMDisassembler_Option_AsmPrinterVariant){
      LLVMDisasmContext *DC = (LLVMDisasmContext *)DCR;
      // Try to set up the new instruction printer.
      const MCAsmInfo *MAI = DC->getAsmInfo();
      const MCInstrInfo *MII = DC->getInstrInfo();
      const MCRegisterInfo *MRI = DC->getRegisterInfo();
      const MCSubtargetInfo *STI = DC->getSubtargetInfo();
      int AsmPrinterVariant = MAI->getAssemblerDialect();
      AsmPrinterVariant = AsmPrinterVariant == 0 ? 1 : 0;
      MCInstPrinter *IP = DC->getTarget()->createMCInstPrinter(
          AsmPrinterVariant, *MAI, *MII, *MRI, *STI);
      if (IP) {
        DC->setIP(IP);
        DC->addOptions(LLVMDisassembler_Option_AsmPrinterVariant);
        Options &= ~LLVMDisassembler_Option_AsmPrinterVariant;
      }
  }
  if (Options & LLVMDisassembler_Option_SetInstrComments) {
    LLVMDisasmContext *DC = (LLVMDisasmContext *)DCR;
    MCInstPrinter *IP = DC->getIP();
    IP->setCommentStream(DC->CommentStream);
    DC->addOptions(LLVMDisassembler_Option_SetInstrComments);
    Options &= ~LLVMDisassembler_Option_SetInstrComments;
  }
  if (Options & LLVMDisassembler_Option_PrintLatency) {
    LLVMDisasmContext *DC = (LLVMDisasmContext *)DCR;
    DC->addOptions(LLVMDisassembler_Option_PrintLatency);
    Options &= ~LLVMDisassembler_Option_PrintLatency;
  }
  return (Options == 0);
}
<commit_msg>Grammar and spelling.<commit_after>//===-- lib/MC/Disassembler.cpp - Disassembler Public C Interface ---------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "Disassembler.h"
#include "llvm-c/Disassembler.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDisassembler.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstPrinter.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCRelocationInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/MCSymbolizer.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/TargetRegistry.h"

using namespace llvm;

// LLVMCreateDisasm() creates a disassembler for the TripleName.  Symbolic
// disassembly is supported by passing a block of information in the DisInfo
// parameter and specifying the TagType and callback functions as described in
// the header llvm-c/Disassembler.h .  The pointer to the block and the
// functions can all be passed as NULL.  If successful, this returns a
// disassembler context.  If not, it returns NULL.
//
LLVMDisasmContextRef
LLVMCreateDisasmCPUFeatures(const char *Triple, const char *CPU,
                            const char *Features, void *DisInfo, int TagType,
                            LLVMOpInfoCallback GetOpInfo,
                            LLVMSymbolLookupCallback SymbolLookUp) {
  // Get the target.
  std::string Error;
  const Target *TheTarget = TargetRegistry::lookupTarget(Triple, Error);
  if (!TheTarget)
    return nullptr;

  const MCRegisterInfo *MRI = TheTarget->createMCRegInfo(Triple);
  if (!MRI)
    return nullptr;

  // Get the assembler info needed to setup the MCContext.
  const MCAsmInfo *MAI = TheTarget->createMCAsmInfo(*MRI, Triple);
  if (!MAI)
    return nullptr;

  const MCInstrInfo *MII = TheTarget->createMCInstrInfo();
  if (!MII)
    return nullptr;

  const MCSubtargetInfo *STI = TheTarget->createMCSubtargetInfo(Triple, CPU,
                                                                Features);
  if (!STI)
    return nullptr;

  // Set up the MCContext for creating symbols and MCExpr's.
  MCContext *Ctx = new MCContext(MAI, MRI, nullptr);
  if (!Ctx)
    return nullptr;

  // Set up disassembler.
  MCDisassembler *DisAsm = TheTarget->createMCDisassembler(*STI, *Ctx);
  if (!DisAsm)
    return nullptr;

  std::unique_ptr<MCRelocationInfo> RelInfo(
      TheTarget->createMCRelocationInfo(Triple, *Ctx));
  if (!RelInfo)
    return nullptr;

  std::unique_ptr<MCSymbolizer> Symbolizer(TheTarget->createMCSymbolizer(
      Triple, GetOpInfo, SymbolLookUp, DisInfo, Ctx, RelInfo.release()));
  DisAsm->setSymbolizer(std::move(Symbolizer));

  // Set up the instruction printer.
  int AsmPrinterVariant = MAI->getAssemblerDialect();
  MCInstPrinter *IP = TheTarget->createMCInstPrinter(AsmPrinterVariant,
                                                     *MAI, *MII, *MRI, *STI);
  if (!IP)
    return nullptr;

  LLVMDisasmContext *DC = new LLVMDisasmContext(Triple, DisInfo, TagType,
                                                GetOpInfo, SymbolLookUp,
                                                TheTarget, MAI, MRI,
                                                STI, MII, Ctx, DisAsm, IP);
  if (!DC)
    return nullptr;

  DC->setCPU(CPU);
  return DC;
}

LLVMDisasmContextRef LLVMCreateDisasmCPU(const char *Triple, const char *CPU,
                                         void *DisInfo, int TagType,
                                         LLVMOpInfoCallback GetOpInfo,
                                         LLVMSymbolLookupCallback SymbolLookUp){
  return LLVMCreateDisasmCPUFeatures(Triple, CPU, "", DisInfo, TagType,
                                     GetOpInfo, SymbolLookUp);
}

LLVMDisasmContextRef LLVMCreateDisasm(const char *Triple, void *DisInfo,
                                      int TagType, LLVMOpInfoCallback GetOpInfo,
                                      LLVMSymbolLookupCallback SymbolLookUp) {
  return LLVMCreateDisasmCPUFeatures(Triple, "", "", DisInfo, TagType,
                                     GetOpInfo, SymbolLookUp);
}

//
// LLVMDisasmDispose() disposes of the disassembler specified by the context.
//
void LLVMDisasmDispose(LLVMDisasmContextRef DCR){
  LLVMDisasmContext *DC = (LLVMDisasmContext *)DCR;
  delete DC;
}

/// \brief Emits the comments that are stored in \p DC comment stream.
/// Each comment in the comment stream must end with a newline.
static void emitComments(LLVMDisasmContext *DC,
                         formatted_raw_ostream &FormattedOS) {
  // Flush the stream before taking its content.
  DC->CommentStream.flush();
  StringRef Comments = DC->CommentsToEmit.str();
  // Get the default information for printing a comment.
  const MCAsmInfo *MAI = DC->getAsmInfo();
  const char *CommentBegin = MAI->getCommentString();
  unsigned CommentColumn = MAI->getCommentColumn();
  bool IsFirst = true;
  while (!Comments.empty()) {
    if (!IsFirst)
      FormattedOS << '\n';
    // Emit a line of comments.
    FormattedOS.PadToColumn(CommentColumn);
    size_t Position = Comments.find('\n');
    FormattedOS << CommentBegin << ' ' << Comments.substr(0, Position);
    // Move after the newline character.
    Comments = Comments.substr(Position+1);
    IsFirst = false;
  }
  FormattedOS.flush();

  // Tell the comment stream that the vector changed underneath it.
  DC->CommentsToEmit.clear();
  DC->CommentStream.resync();
}

/// \brief Gets latency information for \p Inst from the itinerary
/// scheduling model, based on \p DC information.
/// \return The maximum expected latency over all the operands or -1
/// if no information is available.
static int getItineraryLatency(LLVMDisasmContext *DC, const MCInst &Inst) {
  const int NoInformationAvailable = -1;

  // Check if we have a CPU to get the itinerary information.
  if (DC->getCPU().empty())
    return NoInformationAvailable;

  // Get itinerary information.
  const MCSubtargetInfo *STI = DC->getSubtargetInfo();
  InstrItineraryData IID = STI->getInstrItineraryForCPU(DC->getCPU());
  // Get the scheduling class of the requested instruction.
  const MCInstrDesc& Desc = DC->getInstrInfo()->get(Inst.getOpcode());
  unsigned SCClass = Desc.getSchedClass();

  int Latency = 0;
  for (unsigned OpIdx = 0, OpIdxEnd = Inst.getNumOperands(); OpIdx != OpIdxEnd;
       ++OpIdx)
    Latency = std::max(Latency, IID.getOperandCycle(SCClass, OpIdx));

  return Latency;
}

/// \brief Gets latency information for \p Inst, based on \p DC information.
/// \return The maximum expected latency over all the definitions or -1
/// if no information is available.
static int getLatency(LLVMDisasmContext *DC, const MCInst &Inst) {
  // Try to compute scheduling information.
  const MCSubtargetInfo *STI = DC->getSubtargetInfo();
  const MCSchedModel SCModel = STI->getSchedModel();
  const int NoInformationAvailable = -1;

  // Check if we have a scheduling model for instructions.
  if (!SCModel.hasInstrSchedModel())
    // Try to fall back to the itinerary model if the scheduling model doesn't
    // have a scheduling table.  Note the default does not have a table.
    return getItineraryLatency(DC, Inst);

  // Get the scheduling class of the requested instruction.
  const MCInstrDesc& Desc = DC->getInstrInfo()->get(Inst.getOpcode());
  unsigned SCClass = Desc.getSchedClass();
  const MCSchedClassDesc *SCDesc = SCModel.getSchedClassDesc(SCClass);
  // Resolving the variant SchedClass requires an MI to pass to
  // SubTargetInfo::resolveSchedClass.
  if (!SCDesc || !SCDesc->isValid() || SCDesc->isVariant())
    return NoInformationAvailable;

  // Compute output latency.
  int Latency = 0;
  for (unsigned DefIdx = 0, DefEnd = SCDesc->NumWriteLatencyEntries;
       DefIdx != DefEnd; ++DefIdx) {
    // Lookup the definition's write latency in SubtargetInfo.
    const MCWriteLatencyEntry *WLEntry = STI->getWriteLatencyEntry(SCDesc,
                                                                   DefIdx);
    Latency = std::max(Latency, WLEntry->Cycles);
  }

  return Latency;
}

/// \brief Emits latency information in DC->CommentStream for \p Inst, based
/// on the information available in \p DC.
static void emitLatency(LLVMDisasmContext *DC, const MCInst &Inst) {
  int Latency = getLatency(DC, Inst);

  // Report only interesting latencies.
  if (Latency < 2)
    return;

  DC->CommentStream << "Latency: " << Latency << '\n';
}

//
// LLVMDisasmInstruction() disassembles a single instruction using the
// disassembler context specified in the parameter DC.  The bytes of the
// instruction are specified in the parameter Bytes, and contains at least
// BytesSize number of bytes.  The instruction is at the address specified by
// the PC parameter.  If a valid instruction can be disassembled its string is
// returned indirectly in OutString which whos size is specified in the
// parameter OutStringSize.  This function returns the number of bytes in the
// instruction or zero if there was no valid instruction.  If this function
// returns zero the caller will have to pick how many bytes they want to step
// over by printing a .byte, .long etc. to continue.
//
size_t LLVMDisasmInstruction(LLVMDisasmContextRef DCR, uint8_t *Bytes,
                             uint64_t BytesSize, uint64_t PC, char *OutString,
                             size_t OutStringSize){
  LLVMDisasmContext *DC = (LLVMDisasmContext *)DCR;
  // Wrap the pointer to the Bytes, BytesSize and PC in a MemoryObject.
  ArrayRef<uint8_t> Data(Bytes, BytesSize);

  uint64_t Size;
  MCInst Inst;
  const MCDisassembler *DisAsm = DC->getDisAsm();
  MCInstPrinter *IP = DC->getIP();
  MCDisassembler::DecodeStatus S;
  SmallVector<char, 64> InsnStr;
  raw_svector_ostream Annotations(InsnStr);
  S = DisAsm->getInstruction(Inst, Size, Data, PC,
                             /*REMOVE*/ nulls(), Annotations);
  switch (S) {
  case MCDisassembler::Fail:
  case MCDisassembler::SoftFail:
    // FIXME: Do something different for soft failure modes?
    return 0;

  case MCDisassembler::Success: {
    Annotations.flush();
    StringRef AnnotationsStr = Annotations.str();

    SmallVector<char, 64> InsnStr;
    raw_svector_ostream OS(InsnStr);
    formatted_raw_ostream FormattedOS(OS);
    IP->printInst(&Inst, FormattedOS, AnnotationsStr);

    if (DC->getOptions() & LLVMDisassembler_Option_PrintLatency)
      emitLatency(DC, Inst);

    emitComments(DC, FormattedOS);
    OS.flush();

    assert(OutStringSize != 0 && "Output buffer cannot be zero size");
    size_t OutputSize = std::min(OutStringSize-1, InsnStr.size());
    std::memcpy(OutString, InsnStr.data(), OutputSize);
    OutString[OutputSize] = '\0'; // Terminate string.

    return Size;
  }
  }
  llvm_unreachable("Invalid DecodeStatus!");
}

//
// LLVMSetDisasmOptions() sets the disassembler's options.  It returns 1 if it
// can set all the Options and 0 otherwise.
//
int LLVMSetDisasmOptions(LLVMDisasmContextRef DCR, uint64_t Options){
  if (Options & LLVMDisassembler_Option_UseMarkup){
      LLVMDisasmContext *DC = (LLVMDisasmContext *)DCR;
      MCInstPrinter *IP = DC->getIP();
      IP->setUseMarkup(1);
      DC->addOptions(LLVMDisassembler_Option_UseMarkup);
      Options &= ~LLVMDisassembler_Option_UseMarkup;
  }
  if (Options & LLVMDisassembler_Option_PrintImmHex){
      LLVMDisasmContext *DC = (LLVMDisasmContext *)DCR;
      MCInstPrinter *IP = DC->getIP();
      IP->setPrintImmHex(1);
      DC->addOptions(LLVMDisassembler_Option_PrintImmHex);
      Options &= ~LLVMDisassembler_Option_PrintImmHex;
  }
  if (Options & LLVMDisassembler_Option_AsmPrinterVariant){
      LLVMDisasmContext *DC = (LLVMDisasmContext *)DCR;
      // Try to set up the new instruction printer.
      const MCAsmInfo *MAI = DC->getAsmInfo();
      const MCInstrInfo *MII = DC->getInstrInfo();
      const MCRegisterInfo *MRI = DC->getRegisterInfo();
      const MCSubtargetInfo *STI = DC->getSubtargetInfo();
      int AsmPrinterVariant = MAI->getAssemblerDialect();
      AsmPrinterVariant = AsmPrinterVariant == 0 ? 1 : 0;
      MCInstPrinter *IP = DC->getTarget()->createMCInstPrinter(
          AsmPrinterVariant, *MAI, *MII, *MRI, *STI);
      if (IP) {
        DC->setIP(IP);
        DC->addOptions(LLVMDisassembler_Option_AsmPrinterVariant);
        Options &= ~LLVMDisassembler_Option_AsmPrinterVariant;
      }
  }
  if (Options & LLVMDisassembler_Option_SetInstrComments) {
    LLVMDisasmContext *DC = (LLVMDisasmContext *)DCR;
    MCInstPrinter *IP = DC->getIP();
    IP->setCommentStream(DC->CommentStream);
    DC->addOptions(LLVMDisassembler_Option_SetInstrComments);
    Options &= ~LLVMDisassembler_Option_SetInstrComments;
  }
  if (Options & LLVMDisassembler_Option_PrintLatency) {
    LLVMDisasmContext *DC = (LLVMDisasmContext *)DCR;
    DC->addOptions(LLVMDisassembler_Option_PrintLatency);
    Options &= ~LLVMDisassembler_Option_PrintLatency;
  }
  return (Options == 0);
}
<|endoftext|>


<commit_before>// Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
#include "bstcluehunter.hh"
#include <string.h>

/* --- SfiProxy parameter editors --- */
typedef struct {
  Bse::ItemSeq iseq;
  gchar      **paths = NULL;
  gchar       *prefix = NULL;
} ParamProxyPopulation;
static void
param_proxy_free_population (gpointer p)
{
  ParamProxyPopulation *pop = (ParamProxyPopulation*) p;
  g_strfreev (pop->paths);
  g_free (pop->prefix);
  delete pop;
}

static void
param_proxy_populate (GtkWidget *chunter,
		      GxkParam  *param)
{
  BstClueHunter *ch = BST_CLUE_HUNTER (chunter);
  ParamProxyPopulation *pop = NULL;
  SfiProxy proxy;
  gchar *p;
  guint l;

  /* clear current list */
  bst_clue_hunter_remove_matches (ch, "*");

  /* list candidates */
  Bse::PropertyCandidates pc;
  proxy = bst_param_get_proxy (param);
  if (proxy)
    pc = Bse::ItemH::down_cast (bse_server.from_proxy (proxy)).get_property_candidates (param->pspec->name);
  if (pc.items.size())
    {
      pop = new ParamProxyPopulation();
      pop->iseq = pc.items;
      pop->paths = NULL;
      pop->prefix = NULL;
      /* go from object to path name */
      for (size_t i = 0; i < pop->iseq.size(); i++)
        {
          Bse::ItemH item = pop->iseq[i];
          pop->paths = g_straddv (pop->paths, g_strdup (item.get_uname_path().c_str()));
        }
      if (!pop->paths || !pop->paths[0])
	{
	  param_proxy_free_population (pop);
	  pop = NULL;
	}
    }
  g_object_set_data_full (G_OBJECT (ch), "pop", pop, param_proxy_free_population);
  if (!pop)
    return;

  /* figure common prefix, aligned to path segment boundaries (':') */
  pop->prefix = g_strdup (pop->paths[0]);
  /* intersect */
  for (size_t i = 0; pop->paths[i]; i++)
    {
      const gchar *m = pop->paths[i];
      /* strdiff prefix against current path */
      p = pop->prefix;
      while (*p && *m)
	{
	  if (*p != *m)
	    break;
	  p++;
	  m++;
	}
      *p = 0; /* tail cut prefix at mismatch */
    }
  /* cut at object boundary */
  p = strrchr (pop->prefix, ':');
  if (p)
    {
      *(++p) = 0;
      p = g_strdup (pop->prefix);
    }
  g_free (pop->prefix);
  pop->prefix = p;
  l = pop->prefix ? strlen (pop->prefix) : 0;

  /* add unprefixed names to clue hunter */
  for (size_t i = 0; pop->paths[i]; i++)
    bst_clue_hunter_add_string (ch, pop->paths[i] + l);
}

static void
param_proxy_changed (GtkWidget *entry,
                     GxkParam  *param)
{
  if (!param->updating)
    {
      GtkWidget *chunter = (GtkWidget*) bst_clue_hunter_from_entry (entry);
      ParamProxyPopulation *pop = (ParamProxyPopulation*) g_object_get_data (G_OBJECT (chunter), "pop");
      gchar *string = g_strdup_stripped (gtk_entry_get_text (GTK_ENTRY (entry)));
      Bse::ItemH item;
      if (pop)
	{
	  guint i, l = strlen (string);
	  if (pop->prefix && l)			/* try exact match with prefix */
	    {
	      guint j = strlen (pop->prefix);
	      for (i = 0; pop->paths[i]; i++)
		if (strcmp (string, pop->paths[i] + j) == 0)
		  {
		    item = pop->iseq[i];
		    break;
		  }
	    }
	  if (!item && l)
	    for (i = 0; pop->paths[i]; i++)	/* try tail matching path */
	      {
		guint j = strlen (pop->paths[i]);
		if (j >= l && strcmp (string, pop->paths[i] + j - l) == 0)
		  {
		    item = pop->iseq[i];
		    break;
		  }
	      }
	  if (!item && pop->prefix && l)        /* try case insensitive exact match with prefix */
	    {
	      guint j = strlen (pop->prefix);
	      for (i = 0; pop->paths[i]; i++)
		if (g_ascii_strcasecmp (string, pop->paths[i] + j) == 0)
		  {
		    item = pop->iseq[i];
		    break;
		  }
	    }
	  if (!item && l)
	    for (i = 0; pop->paths[i]; i++)	/* try case insensitive tail matching path */
	      {
		guint j = strlen (pop->paths[i]);
		if (j >= l && g_ascii_strcasecmp (string, pop->paths[i] + j - l) == 0)
		  {
		    item = pop->iseq[i];
		    break;
		  }
	      }
	}
      /* we get lots of notifications from focus-out, so try to optimize */
      if (sfi_value_get_proxy (&param->value) != item.proxy_id())
	{
	  sfi_value_set_proxy (&param->value, item.proxy_id());
	  gxk_param_apply_value (param);
	}
      else if (!item && string[0]) /* make sure the entry is correctly updated */
        gxk_param_update (param);
      g_free (string);
    }
}

SfiProxy
bst_item_seq_list_match (GSList      *item_seq_slist,
                         const gchar *text)
{
  SfiProxy cmatch = 0, tmatch = 0, tcmatch = 0;
  GSList *slist;
  guint l, i;
  if (!text || !text[0])
    return 0;
  l = strlen (text);
  for (slist = item_seq_slist; slist; slist = slist->next)
    {
      BseIt3mSeq *iseq = (BseIt3mSeq*) slist->data;
      for (i = 0; i < iseq->n_items; i++)
	{
          Bse::ItemH item = Bse::ItemH::down_cast (bse_server.from_proxy (iseq->items[i]));
	  const String path = item.get_uname_path();
	  uint j = path.size();
	  if (j == l && Bse::string_cmp (text, path) == 0)
	    return iseq->items[i];	/* found exact match */
	  else if (!cmatch && j == l && Bse::string_casecmp (text, path) == 0)
	    cmatch = iseq->items[i];	/* remember first case insensitive match */
	  else if (!tmatch && j > l && Bse::string_cmp (text, &path[0] + j - l) == 0)
	    tmatch = iseq->items[i];	/* remember first tail match */
	  else if (!tcmatch && j > l && Bse::string_casecmp (text, &path[0] + j - l) == 0)
	    tcmatch = iseq->items[i];	/* remember first case insensitive tail match */
	}
    }
  /* fallback to tail match, then case insensitive matches */
  return tmatch ? tmatch : cmatch ? cmatch : tcmatch;
}

static GtkWidget*
param_proxy_create (GxkParam    *param,
                    const gchar *tooltip,
                    guint        variant)
{
  GtkWidget *box = gtk_hbox_new (FALSE, 0);
  GtkWidget *widget = (GtkWidget*) g_object_new (GTK_TYPE_ENTRY,
				    "activates_default", TRUE,
                                    "parent", box,
                                    "width_chars", 0,
				    NULL);
  GtkWidget *chunter = (GtkWidget*) g_object_new (BST_TYPE_CLUE_HUNTER,
				     "keep_history", FALSE,
				     "entry", widget,
				     "user_data", param,
                                     "align-widget", box,
				     NULL);
  SfiProxy proxy = bst_param_get_proxy (param);
  if (proxy)
    {
      Bse::ItemH item = Bse::ItemH::down_cast (bse_server.from_proxy (proxy));
      Bse::PropertyCandidates pc = item.get_property_candidates (param->pspec->name);
      gxk_widget_set_tooltip (chunter, pc.tooltip.c_str());
    }
  gxk_widget_add_font_requisition (widget, 16, 2);
  gxk_param_entry_connect_handlers (param, widget, param_proxy_changed);
  g_object_connect (chunter,
		    "signal::poll_refresh", param_proxy_populate, param,
		    NULL);
  GtkWidget *arrow = bst_clue_hunter_create_arrow (BST_CLUE_HUNTER (chunter), TRUE);
  gtk_box_pack_end (GTK_BOX (box), arrow, FALSE, TRUE, 0);
  gtk_widget_show_all (box);
  gxk_widget_set_tooltip (widget, tooltip);
  gxk_widget_set_tooltip (arrow, tooltip);
  gxk_widget_add_option (box, "hexpand", "+");
  return box;
}

static void
param_proxy_update (GxkParam  *param,
		    GtkWidget *box)
{
  SfiProxy proxy = sfi_value_get_proxy (&param->value);
  Bse::ItemH item = Bse::ItemH::down_cast (bse_server.from_proxy (proxy));
  const String upath = item ? item.get_uname_path() : "";
  const char *cstring = upath.c_str();
  GtkWidget *entry = ((GtkBoxChild*) GTK_BOX (box)->children->data)->widget;
  GtkWidget *chunter = (GtkWidget*) bst_clue_hunter_from_entry (entry);

  if (cstring && chunter)
    {
      ParamProxyPopulation *pop = (ParamProxyPopulation*) g_object_get_data (G_OBJECT (chunter), "pop");
      if (!pop)
	{
	  /* try populating now */
	  param_proxy_populate (chunter, param);
	  pop = (ParamProxyPopulation*) g_object_get_data (G_OBJECT (chunter), "pop");
	}
      if (pop)
	{
	  /* strip common prefix */
	  if (pop->prefix)
	    {
	      guint l = strlen (pop->prefix);
	      if (strncmp (pop->prefix, cstring, l) == 0)
		cstring += l;
	      else
		{
		  /* prefix became invalid */
		  param_proxy_populate (chunter, param);
		  pop = (ParamProxyPopulation*) g_object_get_data (G_OBJECT (chunter), "pop");
		  if (pop && pop->prefix)
		    {
		      l = strlen (pop->prefix);
		      if (strncmp (pop->prefix, cstring, l) == 0)
			cstring += l;
		      else
			{
			  /* heck, prefix became invalid _again_? */
			  g_object_set_data (G_OBJECT (chunter), "pop", NULL);
			}
		    }
		}
	    }
	}
      if (strcmp (gtk_entry_get_text (GTK_ENTRY (entry)), cstring))
	gtk_entry_set_text (GTK_ENTRY (entry), cstring);
    }
  else if (strcmp (gtk_entry_get_text (GTK_ENTRY (entry)), ""))
    gtk_entry_set_text (GTK_ENTRY (entry), "");
  gtk_editable_set_editable (GTK_EDITABLE (entry), param->editable);
}

static GxkParamEditor param_proxy = {
  { "proxy",            N_("Object Drop Down Box"), },
  { G_TYPE_POINTER,     "SfiProxy", },
  { NULL,       +5,     TRUE, },        /* options, rating, editing */
  param_proxy_create,   param_proxy_update,
};
<commit_msg>BST: add missing NULL check before accessing item's proxy_id(), fixes #22<commit_after>// Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
#include "bstcluehunter.hh"
#include <string.h>

/* --- SfiProxy parameter editors --- */
typedef struct {
  Bse::ItemSeq iseq;
  gchar      **paths = NULL;
  gchar       *prefix = NULL;
} ParamProxyPopulation;
static void
param_proxy_free_population (gpointer p)
{
  ParamProxyPopulation *pop = (ParamProxyPopulation*) p;
  g_strfreev (pop->paths);
  g_free (pop->prefix);
  delete pop;
}

static void
param_proxy_populate (GtkWidget *chunter,
		      GxkParam  *param)
{
  BstClueHunter *ch = BST_CLUE_HUNTER (chunter);
  ParamProxyPopulation *pop = NULL;
  SfiProxy proxy;
  gchar *p;
  guint l;

  /* clear current list */
  bst_clue_hunter_remove_matches (ch, "*");

  /* list candidates */
  Bse::PropertyCandidates pc;
  proxy = bst_param_get_proxy (param);
  if (proxy)
    pc = Bse::ItemH::down_cast (bse_server.from_proxy (proxy)).get_property_candidates (param->pspec->name);
  if (pc.items.size())
    {
      pop = new ParamProxyPopulation();
      pop->iseq = pc.items;
      pop->paths = NULL;
      pop->prefix = NULL;
      /* go from object to path name */
      for (size_t i = 0; i < pop->iseq.size(); i++)
        {
          Bse::ItemH item = pop->iseq[i];
          pop->paths = g_straddv (pop->paths, g_strdup (item.get_uname_path().c_str()));
        }
      if (!pop->paths || !pop->paths[0])
	{
	  param_proxy_free_population (pop);
	  pop = NULL;
	}
    }
  g_object_set_data_full (G_OBJECT (ch), "pop", pop, param_proxy_free_population);
  if (!pop)
    return;

  /* figure common prefix, aligned to path segment boundaries (':') */
  pop->prefix = g_strdup (pop->paths[0]);
  /* intersect */
  for (size_t i = 0; pop->paths[i]; i++)
    {
      const gchar *m = pop->paths[i];
      /* strdiff prefix against current path */
      p = pop->prefix;
      while (*p && *m)
	{
	  if (*p != *m)
	    break;
	  p++;
	  m++;
	}
      *p = 0; /* tail cut prefix at mismatch */
    }
  /* cut at object boundary */
  p = strrchr (pop->prefix, ':');
  if (p)
    {
      *(++p) = 0;
      p = g_strdup (pop->prefix);
    }
  g_free (pop->prefix);
  pop->prefix = p;
  l = pop->prefix ? strlen (pop->prefix) : 0;

  /* add unprefixed names to clue hunter */
  for (size_t i = 0; pop->paths[i]; i++)
    bst_clue_hunter_add_string (ch, pop->paths[i] + l);
}

static void
param_proxy_changed (GtkWidget *entry,
                     GxkParam  *param)
{
  if (!param->updating)
    {
      GtkWidget *chunter = (GtkWidget*) bst_clue_hunter_from_entry (entry);
      ParamProxyPopulation *pop = (ParamProxyPopulation*) g_object_get_data (G_OBJECT (chunter), "pop");
      gchar *string = g_strdup_stripped (gtk_entry_get_text (GTK_ENTRY (entry)));
      Bse::ItemH item;
      if (pop)
	{
	  guint i, l = strlen (string);
	  if (pop->prefix && l)			/* try exact match with prefix */
	    {
	      guint j = strlen (pop->prefix);
	      for (i = 0; pop->paths[i]; i++)
		if (strcmp (string, pop->paths[i] + j) == 0)
		  {
		    item = pop->iseq[i];
		    break;
		  }
	    }
	  if (!item && l)
	    for (i = 0; pop->paths[i]; i++)	/* try tail matching path */
	      {
		guint j = strlen (pop->paths[i]);
		if (j >= l && strcmp (string, pop->paths[i] + j - l) == 0)
		  {
		    item = pop->iseq[i];
		    break;
		  }
	      }
	  if (!item && pop->prefix && l)        /* try case insensitive exact match with prefix */
	    {
	      guint j = strlen (pop->prefix);
	      for (i = 0; pop->paths[i]; i++)
		if (g_ascii_strcasecmp (string, pop->paths[i] + j) == 0)
		  {
		    item = pop->iseq[i];
		    break;
		  }
	    }
	  if (!item && l)
	    for (i = 0; pop->paths[i]; i++)	/* try case insensitive tail matching path */
	      {
		guint j = strlen (pop->paths[i]);
		if (j >= l && g_ascii_strcasecmp (string, pop->paths[i] + j - l) == 0)
		  {
		    item = pop->iseq[i];
		    break;
		  }
	      }
	}
      /* we get lots of notifications from focus-out, so try to optimize */
      if (sfi_value_get_proxy (&param->value) != (item ? item.proxy_id() : 0))
	{
	  sfi_value_set_proxy (&param->value, item.proxy_id());
	  gxk_param_apply_value (param);
	}
      else if (!item && string[0]) /* make sure the entry is correctly updated */
        gxk_param_update (param);
      g_free (string);
    }
}

SfiProxy
bst_item_seq_list_match (GSList      *item_seq_slist,
                         const gchar *text)
{
  SfiProxy cmatch = 0, tmatch = 0, tcmatch = 0;
  GSList *slist;
  guint l, i;
  if (!text || !text[0])
    return 0;
  l = strlen (text);
  for (slist = item_seq_slist; slist; slist = slist->next)
    {
      BseIt3mSeq *iseq = (BseIt3mSeq*) slist->data;
      for (i = 0; i < iseq->n_items; i++)
	{
          Bse::ItemH item = Bse::ItemH::down_cast (bse_server.from_proxy (iseq->items[i]));
	  const String path = item.get_uname_path();
	  uint j = path.size();
	  if (j == l && Bse::string_cmp (text, path) == 0)
	    return iseq->items[i];	/* found exact match */
	  else if (!cmatch && j == l && Bse::string_casecmp (text, path) == 0)
	    cmatch = iseq->items[i];	/* remember first case insensitive match */
	  else if (!tmatch && j > l && Bse::string_cmp (text, &path[0] + j - l) == 0)
	    tmatch = iseq->items[i];	/* remember first tail match */
	  else if (!tcmatch && j > l && Bse::string_casecmp (text, &path[0] + j - l) == 0)
	    tcmatch = iseq->items[i];	/* remember first case insensitive tail match */
	}
    }
  /* fallback to tail match, then case insensitive matches */
  return tmatch ? tmatch : cmatch ? cmatch : tcmatch;
}

static GtkWidget*
param_proxy_create (GxkParam    *param,
                    const gchar *tooltip,
                    guint        variant)
{
  GtkWidget *box = gtk_hbox_new (FALSE, 0);
  GtkWidget *widget = (GtkWidget*) g_object_new (GTK_TYPE_ENTRY,
				    "activates_default", TRUE,
                                    "parent", box,
                                    "width_chars", 0,
				    NULL);
  GtkWidget *chunter = (GtkWidget*) g_object_new (BST_TYPE_CLUE_HUNTER,
				     "keep_history", FALSE,
				     "entry", widget,
				     "user_data", param,
                                     "align-widget", box,
				     NULL);
  SfiProxy proxy = bst_param_get_proxy (param);
  if (proxy)
    {
      Bse::ItemH item = Bse::ItemH::down_cast (bse_server.from_proxy (proxy));
      Bse::PropertyCandidates pc = item.get_property_candidates (param->pspec->name);
      gxk_widget_set_tooltip (chunter, pc.tooltip.c_str());
    }
  gxk_widget_add_font_requisition (widget, 16, 2);
  gxk_param_entry_connect_handlers (param, widget, param_proxy_changed);
  g_object_connect (chunter,
		    "signal::poll_refresh", param_proxy_populate, param,
		    NULL);
  GtkWidget *arrow = bst_clue_hunter_create_arrow (BST_CLUE_HUNTER (chunter), TRUE);
  gtk_box_pack_end (GTK_BOX (box), arrow, FALSE, TRUE, 0);
  gtk_widget_show_all (box);
  gxk_widget_set_tooltip (widget, tooltip);
  gxk_widget_set_tooltip (arrow, tooltip);
  gxk_widget_add_option (box, "hexpand", "+");
  return box;
}

static void
param_proxy_update (GxkParam  *param,
		    GtkWidget *box)
{
  SfiProxy proxy = sfi_value_get_proxy (&param->value);
  Bse::ItemH item = Bse::ItemH::down_cast (bse_server.from_proxy (proxy));
  const String upath = item ? item.get_uname_path() : "";
  const char *cstring = upath.c_str();
  GtkWidget *entry = ((GtkBoxChild*) GTK_BOX (box)->children->data)->widget;
  GtkWidget *chunter = (GtkWidget*) bst_clue_hunter_from_entry (entry);

  if (cstring && chunter)
    {
      ParamProxyPopulation *pop = (ParamProxyPopulation*) g_object_get_data (G_OBJECT (chunter), "pop");
      if (!pop)
	{
	  /* try populating now */
	  param_proxy_populate (chunter, param);
	  pop = (ParamProxyPopulation*) g_object_get_data (G_OBJECT (chunter), "pop");
	}
      if (pop)
	{
	  /* strip common prefix */
	  if (pop->prefix)
	    {
	      guint l = strlen (pop->prefix);
	      if (strncmp (pop->prefix, cstring, l) == 0)
		cstring += l;
	      else
		{
		  /* prefix became invalid */
		  param_proxy_populate (chunter, param);
		  pop = (ParamProxyPopulation*) g_object_get_data (G_OBJECT (chunter), "pop");
		  if (pop && pop->prefix)
		    {
		      l = strlen (pop->prefix);
		      if (strncmp (pop->prefix, cstring, l) == 0)
			cstring += l;
		      else
			{
			  /* heck, prefix became invalid _again_? */
			  g_object_set_data (G_OBJECT (chunter), "pop", NULL);
			}
		    }
		}
	    }
	}
      if (strcmp (gtk_entry_get_text (GTK_ENTRY (entry)), cstring))
	gtk_entry_set_text (GTK_ENTRY (entry), cstring);
    }
  else if (strcmp (gtk_entry_get_text (GTK_ENTRY (entry)), ""))
    gtk_entry_set_text (GTK_ENTRY (entry), "");
  gtk_editable_set_editable (GTK_EDITABLE (entry), param->editable);
}

static GxkParamEditor param_proxy = {
  { "proxy",            N_("Object Drop Down Box"), },
  { G_TYPE_POINTER,     "SfiProxy", },
  { NULL,       +5,     TRUE, },        /* options, rating, editing */
  param_proxy_create,   param_proxy_update,
};
<|endoftext|>


<commit_before>//===- Version.cpp - Clang Version Number -----------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines several version-related utility functions for Clang.
//
//===----------------------------------------------------------------------===//

#include "clang/Basic/Version.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Config/config.h"
#include <cstring>
#include <cstdlib>

using namespace std;

namespace clang {

std::string getClangRepositoryPath() {
#ifdef SVN_REPOSITORY
  llvm::StringRef URL(SVN_REPOSITORY);
#else
  llvm::StringRef URL("");
#endif

  // Strip off version from a build from an integration branch.
  URL = URL.slice(0, URL.find("/src/tools/clang"));

  // Trim path prefix off, assuming path came from standard cfe path.
  size_t Start = URL.find("cfe/");
  if (Start != llvm::StringRef::npos)
    URL = URL.substr(Start + 4);

  return URL;
}

std::string getClangRevision() {
#ifdef SVN_REVISION
  return SVN_REVISION;
#else
  return "";
#endif
}

std::string getClangFullRepositoryVersion() {
  std::string buf;
  llvm::raw_string_ostream OS(buf);
  std::string Path = getClangRepositoryPath();
  std::string Revision = getClangRevision();
  if (!Path.empty())
    OS << Path;
  if (!Revision.empty()) {
    if (!Path.empty())
      OS << ' ';
    OS << Revision;
  }
  return OS.str();
}

std::string getClangFullVersion() {
  std::string buf;
  llvm::raw_string_ostream OS(buf);
#ifdef CLANG_VENDOR
  OS << CLANG_VENDOR;
#endif
  OS << "clang version " CLANG_VERSION_STRING " ("
     << getClangFullRepositoryVersion() << ')';

  // If vendor supplied, include the base LLVM version as well.
#ifdef CLANG_VENDOR
  OS << " (based on LLVM " << PACKAGE_VERSION << ")";
#endif

  return OS.str();
}

} // end namespace clang
<commit_msg>Basic: Attempt to make version tags work from 'svn export's again.<commit_after>//===- Version.cpp - Clang Version Number -----------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines several version-related utility functions for Clang.
//
//===----------------------------------------------------------------------===//

#include "clang/Basic/Version.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Config/config.h"
#include <cstring>
#include <cstdlib>

using namespace std;

namespace clang {

std::string getClangRepositoryPath() {
#ifdef SVN_REPOSITORY
  llvm::StringRef URL(SVN_REPOSITORY);
#else
  llvm::StringRef URL("");
#endif

  // If the SVN_REPOSITORY is empty, try to use the SVN keyword. This helps us
  // pick up a tag in an SVN export, for example.
  static llvm::StringRef SVNRepository("$URL$");
  if (URL.empty())
    URL = SVNRepository.split(':').second;

  // Strip off version from a build from an integration branch.
  URL = URL.slice(0, URL.find("/src/tools/clang"));

  // Trim path prefix off, assuming path came from standard cfe path.
  size_t Start = URL.find("cfe/");
  if (Start != llvm::StringRef::npos)
    URL = URL.substr(Start + 4);

  return URL;
}

std::string getClangRevision() {
#ifdef SVN_REVISION
  return SVN_REVISION;
#else
  return "";
#endif
}

std::string getClangFullRepositoryVersion() {
  std::string buf;
  llvm::raw_string_ostream OS(buf);
  std::string Path = getClangRepositoryPath();
  std::string Revision = getClangRevision();
  if (!Path.empty())
    OS << Path;
  if (!Revision.empty()) {
    if (!Path.empty())
      OS << ' ';
    OS << Revision;
  }
  return OS.str();
}

std::string getClangFullVersion() {
  std::string buf;
  llvm::raw_string_ostream OS(buf);
#ifdef CLANG_VENDOR
  OS << CLANG_VENDOR;
#endif
  OS << "clang version " CLANG_VERSION_STRING " ("
     << getClangFullRepositoryVersion() << ')';

  // If vendor supplied, include the base LLVM version as well.
#ifdef CLANG_VENDOR
  OS << " (based on LLVM " << PACKAGE_VERSION << ")";
#endif

  return OS.str();
}

} // end namespace clang
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////
//
// Copyright 2015 Realm Inc.
//
// 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.
//
////////////////////////////////////////////////////////////////////////////

#include "parser.hpp"

#include <iostream>

#include <pegtl.hh>
#include <pegtl/analyze.hh>
#include <pegtl/trace.hh>

using namespace pegtl;

namespace realm {
namespace parser {

// strings
struct unicode : list< seq< one< 'u' >, rep< 4, must< xdigit > > >, one< '\\' > > {};
struct escaped_char : one< '"', '\'', '\\', '/', 'b', 'f', 'n', 'r', 't', '0' > {};
struct escaped : sor< escaped_char, unicode > {};
struct unescaped : utf8::range< 0x20, 0x10FFFF > {};
struct chars : if_then_else< one< '\\' >, must< escaped >, unescaped > {};
struct dq_string_content : until< at< one< '"' > >, must< chars > > {};
struct dq_string : seq< one< '"' >, must< dq_string_content >, any > {};

struct sq_string_content : until< at< one< '\'' > >, must< chars > > {};
struct sq_string : seq< one< '\'' >, must< sq_string_content >, any > {};

// numbers
struct minus : opt< one< '-' > > {};
struct dot : one< '.' > {};

struct float_num : sor<
    seq< plus< digit >, dot, star< digit > >,
    seq< star< digit >, dot, plus< digit > >
> {};
struct hex_num : seq< one< '0' >, one< 'x', 'X' >, plus< xdigit > > {};
struct int_num : plus< digit > {};

struct number : seq< minus, sor< float_num, hex_num, int_num > > {};

struct true_value : pegtl_istring_t("true") {};
struct false_value : pegtl_istring_t("false") {};

// key paths
struct key_path : list< seq< sor< alpha, one< '_' > >, star< sor< alnum, one< '_', '-' > > > >, one< '.' > > {};

// argument
struct argument_index : plus< digit > {};
struct argument : seq< one< '$' >, must< argument_index > > {};

// expressions and operators
struct expr : sor< dq_string, sq_string, number, argument, true_value, false_value, key_path > {};

struct eq : sor< two< '=' >, one< '=' > > {};
struct noteq : pegtl::string< '!', '=' > {};
struct lteq : pegtl::string< '<', '=' > {};
struct lt : one< '<' > {};
struct gteq : pegtl::string< '>', '=' > {};
struct gt : one< '>' > {};
struct contains : pegtl_istring_t("contains") {};
struct begins : pegtl_istring_t("beginswith") {};
struct ends : pegtl_istring_t("endswith") {};

template<typename A, typename B>
struct pad_plus : seq< plus< B >, A, plus< B > > {};

struct padded_oper : pad_plus< sor< contains, begins, ends >, blank > {};
struct symbolic_oper : pad< sor< eq, noteq, lteq, lt, gteq, gt >, blank > {};

// predicates
struct comparison_pred : seq< expr, sor< padded_oper, symbolic_oper >, expr > {};

struct pred;
struct group_pred : if_must< one< '(' >, pad< pred, blank >, one< ')' > > {};
struct true_pred : pegtl_istring_t("truepredicate") {};
struct false_pred : pegtl_istring_t("falsepredicate") {};

struct not_pre : seq< sor< one< '!' >, pegtl_istring_t("not") > > {};
struct atom_pred : seq< opt< not_pre >, pad< sor< group_pred, true_pred, false_pred, comparison_pred >, blank > > {};

struct and_op : pad< sor< two< '&' >, pegtl_istring_t("and") >, blank > {};
struct or_op : pad< sor< two< '|' >, pegtl_istring_t("or") >, blank > {};

struct or_ext : if_must< or_op, pred > {};
struct and_ext : if_must< and_op, pred > {};
struct and_pred : seq< atom_pred, star< and_ext > > {};

struct pred : seq< and_pred, star< or_ext > > {};

// state
struct ParserState
{
    std::vector<Predicate *> predicate_stack;
    Predicate &current() {
        return *predicate_stack.back();
    }

    bool negate_next = false;

    void addExpression(Expression && exp)
    {
        if (current().type == Predicate::Type::Comparison) {
            current().cmpr.expr[1] = std::move(exp);
            predicate_stack.pop_back();
        }
        else {
            Predicate p(Predicate::Type::Comparison);
            p.cmpr.expr[0] = std::move(exp);
            if (negate_next) {
                p.negate = true;
                negate_next = false;
            }
            current().cpnd.sub_predicates.emplace_back(std::move(p));
            predicate_stack.push_back(&current().cpnd.sub_predicates.back());
        }
    }
};

// rules
template< typename Rule >
struct action : nothing< Rule > {};

#ifdef REALM_PARSER_PRINT_TOKENS
    #define DEBUG_PRINT_TOKEN(string) std::cout << string << std::endl
#else
    #define DEBUG_PRINT_TOKEN(string)
#endif

template<> struct action< and_ext >
{
    static void apply( const input & in, ParserState & state )
    {
        DEBUG_PRINT_TOKEN("<and>");

        // if we were put into an OR group we need to rearrange
        auto &current = state.current();
        if (current.type == Predicate::Type::Or) {
            auto &sub_preds = state.current().cpnd.sub_predicates;
            auto &second_last = sub_preds[sub_preds.size()-2];
            if (second_last.type == Predicate::Type::And) {
                // if we are in an OR group and second to last predicate group is
                // an AND group then move the last predicate inside
                second_last.cpnd.sub_predicates.push_back(std::move(sub_preds.back()));
                sub_preds.pop_back();
            }
            else {
                // otherwise combine last two into a new AND group
                Predicate pred(Predicate::Type::And);
                pred.cpnd.sub_predicates.emplace_back(std::move(second_last));
                pred.cpnd.sub_predicates.emplace_back(std::move(sub_preds.back()));
                sub_preds.pop_back();
                sub_preds.pop_back();
                sub_preds.push_back(std::move(pred));
            }
        }
    }
};

template<> struct action< or_ext >
{
    static void apply( const input & in, ParserState & state )
    {
        DEBUG_PRINT_TOKEN("<or>");

        // if already an OR group do nothing
        auto &current = state.current();
        if (current.type == Predicate::Type::Or) {
            return;
        }

        // if only two predicates in the group, then convert to OR
        auto &sub_preds = state.current().cpnd.sub_predicates;
        if (sub_preds.size()) {
            current.type = Predicate::Type::Or;
            return;
        }

        // split the current group into to groups which are ORed together
        Predicate pred1(Predicate::Type::And), pred2(Predicate::Type::And);
        pred1.cpnd.sub_predicates.insert(sub_preds.begin(), sub_preds.back());
        pred2.cpnd.sub_predicates.push_back(std::move(sub_preds.back()));

        current.type = Predicate::Type::Or;
        sub_preds.clear();
        sub_preds.emplace_back(std::move(pred1));
        sub_preds.emplace_back(std::move(pred2));
    }
};

#define EXPRESSION_ACTION(rule, type)                               \
template<> struct action< rule > {                                  \
    static void apply( const input & in, ParserState & state ) {    \
        DEBUG_PRINT_TOKEN(in.string());                             \
        state.addExpression(Expression(type, in.string())); }};

EXPRESSION_ACTION(dq_string_content, Expression::Type::String)
EXPRESSION_ACTION(sq_string_content, Expression::Type::String)
EXPRESSION_ACTION(key_path, Expression::Type::KeyPath)
EXPRESSION_ACTION(number, Expression::Type::Number)
EXPRESSION_ACTION(true_value, Expression::Type::True)
EXPRESSION_ACTION(false_value, Expression::Type::False)
EXPRESSION_ACTION(argument_index, Expression::Type::Argument)

template<> struct action< true_pred >
{
    static void apply( const input & in, ParserState & state )
    {
        DEBUG_PRINT_TOKEN(in.string());
        state.current().cpnd.sub_predicates.emplace_back(Predicate::Type::True);
    }
};

template<> struct action< false_pred >
{
    static void apply( const input & in, ParserState & state )
    {
        DEBUG_PRINT_TOKEN(in.string());
        state.current().cpnd.sub_predicates.emplace_back(Predicate::Type::False);
    }
};

#define OPERATOR_ACTION(rule, oper)                                 \
template<> struct action< rule > {                                  \
    static void apply( const input & in, ParserState & state ) {    \
        DEBUG_PRINT_TOKEN(in.string());                             \
        state.current().cmpr.op = oper; }};

OPERATOR_ACTION(eq, Predicate::Operator::Equal)
OPERATOR_ACTION(noteq, Predicate::Operator::NotEqual)
OPERATOR_ACTION(gteq, Predicate::Operator::GreaterThanOrEqual)
OPERATOR_ACTION(gt, Predicate::Operator::GreaterThan)
OPERATOR_ACTION(lteq, Predicate::Operator::LessThanOrEqual)
OPERATOR_ACTION(lt, Predicate::Operator::LessThan)
OPERATOR_ACTION(begins, Predicate::Operator::BeginsWith)
OPERATOR_ACTION(ends, Predicate::Operator::EndsWith)
OPERATOR_ACTION(contains, Predicate::Operator::Contains)

template<> struct action< one< '(' > >
{
    static void apply( const input & in, ParserState & state )
    {
        DEBUG_PRINT_TOKEN("<begin_group>");

        Predicate group(Predicate::Type::And);
        if (state.negate_next) {
            group.negate = true;
            state.negate_next = false;
        }

        state.current().cpnd.sub_predicates.emplace_back(std::move(group));
        state.predicate_stack.push_back(&state.current().cpnd.sub_predicates.back());
    }
};

template<> struct action< group_pred >
{
    static void apply( const input & in, ParserState & state )
    {
        DEBUG_PRINT_TOKEN("<end_group>");
        state.predicate_stack.pop_back();
    }
};

template<> struct action< not_pre >
{
    static void apply( const input & in, ParserState & state )
    {
        DEBUG_PRINT_TOKEN("<not>");
        state.negate_next = true;
    }
};

Predicate parse(const std::string &query)
{
    analyze< pred >();
    const std::string source = "user query";

    Predicate out_predicate(Predicate::Type::And);

    ParserState state;
    state.predicate_stack.push_back(&out_predicate);

    pegtl::parse< must< pred, eof >, action >(query, source, state);
    if (out_predicate.type == Predicate::Type::And && out_predicate.cpnd.sub_predicates.size() == 1) {
        return std::move(out_predicate.cpnd.sub_predicates.back());
    }
    return std::move(out_predicate);
}

}}

<commit_msg>first string tests and custom error messages<commit_after>////////////////////////////////////////////////////////////////////////////
//
// Copyright 2015 Realm Inc.
//
// 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.
//
////////////////////////////////////////////////////////////////////////////

#include "parser.hpp"

#include <iostream>

#include <pegtl.hh>
#include <pegtl/analyze.hh>
#include <pegtl/trace.hh>

using namespace pegtl;

namespace realm {
namespace parser {

// strings
struct unicode : list< seq< one< 'u' >, rep< 4, must< xdigit > > >, one< '\\' > > {};
struct escaped_char : one< '"', '\'', '\\', '/', 'b', 'f', 'n', 'r', 't', '0' > {};
struct escaped : sor< escaped_char, unicode > {};
struct unescaped : utf8::range< 0x20, 0x10FFFF > {};
struct chars : if_then_else< one< '\\' >, must< escaped >, unescaped > {};
struct dq_string_content : until< at< one< '"' > >, must< chars > > {};
struct dq_string : seq< one< '"' >, must< dq_string_content >, any > {};

struct sq_string_content : until< at< one< '\'' > >, must< chars > > {};
struct sq_string : seq< one< '\'' >, must< sq_string_content >, any > {};

// numbers
struct minus : opt< one< '-' > > {};
struct dot : one< '.' > {};

struct float_num : sor<
    seq< plus< digit >, dot, star< digit > >,
    seq< star< digit >, dot, plus< digit > >
> {};
struct hex_num : seq< one< '0' >, one< 'x', 'X' >, plus< xdigit > > {};
struct int_num : plus< digit > {};

struct number : seq< minus, sor< float_num, hex_num, int_num > > {};

struct true_value : pegtl_istring_t("true") {};
struct false_value : pegtl_istring_t("false") {};

// key paths
struct key_path : list< seq< sor< alpha, one< '_' > >, star< sor< alnum, one< '_', '-' > > > >, one< '.' > > {};

// argument
struct argument_index : plus< digit > {};
struct argument : seq< one< '$' >, must< argument_index > > {};

// expressions and operators
struct expr : sor< dq_string, sq_string, number, argument, true_value, false_value, key_path > {};

struct eq : sor< two< '=' >, one< '=' > > {};
struct noteq : pegtl::string< '!', '=' > {};
struct lteq : pegtl::string< '<', '=' > {};
struct lt : one< '<' > {};
struct gteq : pegtl::string< '>', '=' > {};
struct gt : one< '>' > {};
struct contains : pegtl_istring_t("contains") {};
struct begins : pegtl_istring_t("beginswith") {};
struct ends : pegtl_istring_t("endswith") {};

template<typename A, typename B>
struct pad_plus : seq< plus< B >, A, plus< B > > {};

struct padded_oper : pad_plus< sor< contains, begins, ends >, blank > {};
struct symbolic_oper : pad< sor< eq, noteq, lteq, lt, gteq, gt >, blank > {};

// predicates
struct comparison_pred : seq< expr, sor< padded_oper, symbolic_oper >, expr > {};

struct pred;
struct group_pred : if_must< one< '(' >, pad< pred, blank >, one< ')' > > {};
struct true_pred : pegtl_istring_t("truepredicate") {};
struct false_pred : pegtl_istring_t("falsepredicate") {};

struct not_pre : seq< sor< one< '!' >, pegtl_istring_t("not") > > {};
struct atom_pred : seq< opt< not_pre >, pad< sor< group_pred, true_pred, false_pred, comparison_pred >, blank > > {};

struct and_op : pad< sor< two< '&' >, pegtl_istring_t("and") >, blank > {};
struct or_op : pad< sor< two< '|' >, pegtl_istring_t("or") >, blank > {};

struct or_ext : if_must< or_op, pred > {};
struct and_ext : if_must< and_op, pred > {};
struct and_pred : seq< atom_pred, star< and_ext > > {};

struct pred : seq< and_pred, star< or_ext > > {};

// state
struct ParserState
{
    std::vector<Predicate *> predicate_stack;
    Predicate &current() {
        return *predicate_stack.back();
    }

    bool negate_next = false;

    void addExpression(Expression && exp)
    {
        if (current().type == Predicate::Type::Comparison) {
            current().cmpr.expr[1] = std::move(exp);
            predicate_stack.pop_back();
        }
        else {
            Predicate p(Predicate::Type::Comparison);
            p.cmpr.expr[0] = std::move(exp);
            if (negate_next) {
                p.negate = true;
                negate_next = false;
            }
            current().cpnd.sub_predicates.emplace_back(std::move(p));
            predicate_stack.push_back(&current().cpnd.sub_predicates.back());
        }
    }
};

// rules
template< typename Rule >
struct action : nothing< Rule > {};

#ifdef REALM_PARSER_PRINT_TOKENS
    #define DEBUG_PRINT_TOKEN(string) std::cout << string << std::endl
#else
    #define DEBUG_PRINT_TOKEN(string)
#endif

template<> struct action< and_ext >
{
    static void apply( const input & in, ParserState & state )
    {
        DEBUG_PRINT_TOKEN("<and>");

        // if we were put into an OR group we need to rearrange
        auto &current = state.current();
        if (current.type == Predicate::Type::Or) {
            auto &sub_preds = state.current().cpnd.sub_predicates;
            auto &second_last = sub_preds[sub_preds.size()-2];
            if (second_last.type == Predicate::Type::And) {
                // if we are in an OR group and second to last predicate group is
                // an AND group then move the last predicate inside
                second_last.cpnd.sub_predicates.push_back(std::move(sub_preds.back()));
                sub_preds.pop_back();
            }
            else {
                // otherwise combine last two into a new AND group
                Predicate pred(Predicate::Type::And);
                pred.cpnd.sub_predicates.emplace_back(std::move(second_last));
                pred.cpnd.sub_predicates.emplace_back(std::move(sub_preds.back()));
                sub_preds.pop_back();
                sub_preds.pop_back();
                sub_preds.push_back(std::move(pred));
            }
        }
    }
};

template<> struct action< or_ext >
{
    static void apply( const input & in, ParserState & state )
    {
        DEBUG_PRINT_TOKEN("<or>");

        // if already an OR group do nothing
        auto &current = state.current();
        if (current.type == Predicate::Type::Or) {
            return;
        }

        // if only two predicates in the group, then convert to OR
        auto &sub_preds = state.current().cpnd.sub_predicates;
        if (sub_preds.size()) {
            current.type = Predicate::Type::Or;
            return;
        }

        // split the current group into to groups which are ORed together
        Predicate pred1(Predicate::Type::And), pred2(Predicate::Type::And);
        pred1.cpnd.sub_predicates.insert(sub_preds.begin(), sub_preds.back());
        pred2.cpnd.sub_predicates.push_back(std::move(sub_preds.back()));

        current.type = Predicate::Type::Or;
        sub_preds.clear();
        sub_preds.emplace_back(std::move(pred1));
        sub_preds.emplace_back(std::move(pred2));
    }
};

#define EXPRESSION_ACTION(rule, type)                               \
template<> struct action< rule > {                                  \
    static void apply( const input & in, ParserState & state ) {    \
        DEBUG_PRINT_TOKEN(in.string());                             \
        state.addExpression(Expression(type, in.string())); }};

EXPRESSION_ACTION(dq_string_content, Expression::Type::String)
EXPRESSION_ACTION(sq_string_content, Expression::Type::String)
EXPRESSION_ACTION(key_path, Expression::Type::KeyPath)
EXPRESSION_ACTION(number, Expression::Type::Number)
EXPRESSION_ACTION(true_value, Expression::Type::True)
EXPRESSION_ACTION(false_value, Expression::Type::False)
EXPRESSION_ACTION(argument_index, Expression::Type::Argument)

template<> struct action< true_pred >
{
    static void apply( const input & in, ParserState & state )
    {
        DEBUG_PRINT_TOKEN(in.string());
        state.current().cpnd.sub_predicates.emplace_back(Predicate::Type::True);
    }
};

template<> struct action< false_pred >
{
    static void apply( const input & in, ParserState & state )
    {
        DEBUG_PRINT_TOKEN(in.string());
        state.current().cpnd.sub_predicates.emplace_back(Predicate::Type::False);
    }
};

#define OPERATOR_ACTION(rule, oper)                                 \
template<> struct action< rule > {                                  \
    static void apply( const input & in, ParserState & state ) {    \
        DEBUG_PRINT_TOKEN(in.string());                             \
        state.current().cmpr.op = oper; }};

OPERATOR_ACTION(eq, Predicate::Operator::Equal)
OPERATOR_ACTION(noteq, Predicate::Operator::NotEqual)
OPERATOR_ACTION(gteq, Predicate::Operator::GreaterThanOrEqual)
OPERATOR_ACTION(gt, Predicate::Operator::GreaterThan)
OPERATOR_ACTION(lteq, Predicate::Operator::LessThanOrEqual)
OPERATOR_ACTION(lt, Predicate::Operator::LessThan)
OPERATOR_ACTION(begins, Predicate::Operator::BeginsWith)
OPERATOR_ACTION(ends, Predicate::Operator::EndsWith)
OPERATOR_ACTION(contains, Predicate::Operator::Contains)

template<> struct action< one< '(' > >
{
    static void apply( const input & in, ParserState & state )
    {
        DEBUG_PRINT_TOKEN("<begin_group>");

        Predicate group(Predicate::Type::And);
        if (state.negate_next) {
            group.negate = true;
            state.negate_next = false;
        }

        state.current().cpnd.sub_predicates.emplace_back(std::move(group));
        state.predicate_stack.push_back(&state.current().cpnd.sub_predicates.back());
    }
};

template<> struct action< group_pred >
{
    static void apply( const input & in, ParserState & state )
    {
        DEBUG_PRINT_TOKEN("<end_group>");
        state.predicate_stack.pop_back();
    }
};

template<> struct action< not_pre >
{
    static void apply( const input & in, ParserState & state )
    {
        DEBUG_PRINT_TOKEN("<not>");
        state.negate_next = true;
    }
};

template< typename Rule >
struct error_message_control : pegtl::normal< Rule >
{
    static const std::string error_message;

    template< typename Input, typename ... States >
    static void raise( const Input & in, States && ... )
    {
        throw pegtl::parse_error( error_message, in );
    }
};

template<>
const std::string error_message_control< chars >::error_message = "Invalid characters in string constant.";

template< typename Rule>
const std::string error_message_control< Rule >::error_message = "Invalid predicate.";

Predicate parse(const std::string &query)
{
    analyze< pred >();

    Predicate out_predicate(Predicate::Type::And);

    ParserState state;
    state.predicate_stack.push_back(&out_predicate);

    pegtl::parse< must< pred, eof >, action, error_message_control >(query, query, state);
    if (out_predicate.type == Predicate::Type::And && out_predicate.cpnd.sub_predicates.size() == 1) {
        return std::move(out_predicate.cpnd.sub_predicates.back());
    }
    return std::move(out_predicate);
}

}}

<|endoftext|>